diff --git a/convex/_generated/api.d.ts b/convex/_generated/api.d.ts index 3be9c511..a7f2c260 100644 --- a/convex/_generated/api.d.ts +++ b/convex/_generated/api.d.ts @@ -21,6 +21,7 @@ import type * as lib_cloudProtocol from "../lib/cloudProtocol.js"; import type * as lib_entities from "../lib/entities.js"; import type * as lib_errors from "../lib/errors.js"; import type * as lib_imageAssets from "../lib/imageAssets.js"; +import type * as lib_lineupItems from "../lib/lineupItems.js"; import type * as lib_opTypes from "../lib/opTypes.js"; import type * as lib_payloadValidators from "../lib/payloadValidators.js"; import type * as lib_profile from "../lib/profile.js"; @@ -59,6 +60,7 @@ declare const fullApi: ApiFromModules<{ "lib/entities": typeof lib_entities; "lib/errors": typeof lib_errors; "lib/imageAssets": typeof lib_imageAssets; + "lib/lineupItems": typeof lib_lineupItems; "lib/opTypes": typeof lib_opTypes; "lib/payloadValidators": typeof lib_payloadValidators; "lib/profile": typeof lib_profile; diff --git a/convex/error_codes.json b/convex/error_codes.json index 2bb029f9..0ea83da9 100644 --- a/convex/error_codes.json +++ b/convex/error_codes.json @@ -16,8 +16,6 @@ "INVALID_PAYLOAD", "INVITE_EXPIRED", "INVITE_REVOKED", - "LINEUP_END_IN_USE", - "LINEUP_LINK_END_MISSING", "LINEUP_PAGE_MISMATCH", "LINEUP_STRATEGY_MISMATCH", "MISSING_ADD_ELEMENT_ARGS", diff --git a/convex/function_spec.json b/convex/function_spec.json index fdd2f771..1a8a6711 100644 --- a/convex/function_spec.json +++ b/convex/function_spec.json @@ -41418,107 +41418,662 @@ }, "payload": { "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "data": { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "boolean" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "number" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -41687,37 +42242,343 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "boolean" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "number" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -41784,18 +42645,115 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -41812,9 +42770,65 @@ } ] }, - { - "type": "array", - "value": { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -41830,76 +42844,25 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -42068,15 +43031,118 @@ } } ] - } + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -42102,6 +43168,102 @@ "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -42118,9 +43280,167 @@ } ] }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -42136,47 +43456,195 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -42193,121 +43661,24 @@ } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] + }, + "optional": false + } + } + ] } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" }, { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -42476,40 +43847,137 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -42526,9 +43994,65 @@ } ] }, - { - "type": "array", - "value": { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -42544,47 +44068,93 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -42601,116 +44171,19 @@ } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -42777,331 +44250,25 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -43474,37 +44641,321 @@ } } ] - } + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "lineups" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Query", + "identifier": "lineups.js:listForStrategy", + "returns": { + "type": "array", + "value": { + "type": "object", + "value": { + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "deleted": { + "fieldType": { + "type": "boolean" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "payload": { + "fieldType": { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -43530,67 +44981,118 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] } @@ -43605,67 +45107,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -43707,67 +45158,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -43782,67 +45182,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -43938,67 +45287,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -44013,67 +45311,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -44115,67 +45362,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -44190,67 +45386,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -44319,67 +45464,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -44394,67 +45488,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -44496,67 +45539,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -44571,67 +45563,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -44654,157 +45595,262 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupOrigin" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", "value": [ { "type": "null" @@ -44947,37 +45993,139 @@ } } ] - } + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -45044,122 +46192,20 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -45328,15 +46374,118 @@ } } ] - } + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -45362,67 +46511,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -45437,67 +46535,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -45505,91 +46552,192 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] + ] + } }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { + { + "keys": { "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -45656,18 +46804,115 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -45684,92 +46929,41 @@ } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { @@ -45785,10 +46979,15 @@ "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -45804,47 +47003,93 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -45861,116 +47106,19 @@ } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -46037,95 +47185,96 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -46151,6 +47300,102 @@ "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -46167,65 +47412,167 @@ } ] }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -46242,126 +47589,29 @@ } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -46734,180 +47984,1006 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "lineups" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "paginationOpts": { + "fieldType": { + "type": "object", + "value": { + "cursor": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "endCursor": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": true + }, + "id": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "maximumBytesRead": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "maximumRowsRead": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "numItems": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "optional": false + }, + "table": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "elements" + }, + { + "type": "literal", + "value": "lineups" + } + ] + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "maintenance.js:backfillAssetReferences", + "returns": null, + "visibility": { + "kind": "internal" + } + }, + { + "args": { + "type": "object", + "value": {} + }, + "functionType": "Mutation", + "identifier": "maintenance.js:backfillStrategyAgentSummaries", + "returns": { + "type": "number" + }, + "visibility": { + "kind": "internal" + } + }, + { + "args": { + "type": "object", + "value": { + "paginationOpts": { + "fieldType": { + "type": "object", + "value": { + "cursor": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "endCursor": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": true + }, + "id": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "maximumBytesRead": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "maximumRowsRead": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "numItems": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "optional": false + }, + "table": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "elements" + }, + { + "type": "literal", + "value": "lineups" + } + ] + }, + "optional": false + } + } + }, + "functionType": "Query", + "identifier": "maintenance.js:checkAssetReferences", + "returns": null, + "visibility": { + "kind": "internal" + } + }, + { + "args": { + "type": "object", + "value": { + "paginationOpts": { + "fieldType": { + "type": "object", + "value": { + "cursor": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "endCursor": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": true + }, + "id": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "maximumBytesRead": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "maximumRowsRead": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "numItems": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "optional": false + }, + "table": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "elements" + }, + { + "type": "literal", + "value": "lineups" + } + ] + }, + "optional": false + } + } + }, + "functionType": "Query", + "identifier": "maintenance.js:findShownUnavailableAssets", + "returns": null, + "visibility": { + "kind": "internal" + } + }, + { + "args": { + "type": "object", + "value": { + "pageId": { + "fieldType": { + "tableName": "pages", + "type": "id" + }, + "optional": false + }, + "strategyId": { + "fieldType": { + "tableName": "strategies", + "type": "id" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "maintenance.js:purgeDeletedPageOrphans", + "returns": null, + "visibility": { + "kind": "internal" + } + }, + { + "args": { + "type": "object", + "value": {} + }, + "functionType": "Mutation", + "identifier": "maintenance.js:purgeOldOperationEvents", + "returns": null, + "visibility": { + "kind": "internal" + } + }, + { + "args": { + "type": "object", + "value": {} + }, + "functionType": "Mutation", + "identifier": "maintenance.js:purgeOldTombstones", + "returns": null, + "visibility": { + "kind": "internal" + } + }, + { + "args": { + "type": "object", + "value": {} + }, + "functionType": "Mutation", + "identifier": "maintenance.js:purgeTrashedPages", + "returns": null, + "visibility": { + "kind": "internal" + } + }, + { + "args": { + "type": "object", + "value": { + "accountSubject": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "checkLineupEndDeletes": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "checkLineupLinkEnds": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "checkTrashedPageDeletes": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "clientId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "ops": { + "fieldType": { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "expectedStrategyRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "payload": { + "fieldType": { + "type": "object", + "value": { + "clearThemeOverridePalette": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "clearThemeProfileId": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "mapData": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "themeOverridePalette": { + "fieldType": { + "type": "object", + "value": { + "base": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "detail": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "highlight": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "optional": true + }, + "themeProfileId": { + "fieldType": { + "type": "string" + }, + "optional": true + } + } + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "strategy.patch" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "expectedStrategyRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "payload": { + "fieldType": { + "type": "object", + "value": { + "isAttack": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "isAutoNamed": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "settings": { + "fieldType": { + "type": "object", + "value": { + "abilitySize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "agentSize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "useNeutralTeamColors": { + "fieldType": { + "type": "boolean" + }, + "optional": false + } + } + }, + "optional": true + } + } + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "page.add" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "expectedPageRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "payload": { + "fieldType": { + "type": "object", + "value": { + "isAttack": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "isAutoNamed": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "settings": { + "fieldType": { + "type": "object", + "value": { + "abilitySize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "agentSize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "useNeutralTeamColors": { + "fieldType": { + "type": "boolean" + }, + "optional": false + } + } + }, + "optional": true + } + } + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "page.patch" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "expectedStrategyRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "page.delete" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "expectedStrategyRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "page.reorder" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "expectedPageContentRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "settings": { + "fieldType": { + "type": "object", + "value": { + "abilitySize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "agentSize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "useNeutralTeamColors": { + "fieldType": { + "type": "boolean" + }, + "optional": false + } + } + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "pageContent.patch" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "elementPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "expectedElementRevision": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "payload": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -46924,167 +49000,9 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + "type": "array", + "value": { "type": "union", "value": [ { @@ -47100,136 +49018,33 @@ "type": "string" } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -47244,16 +49059,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -47295,16 +49161,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -47319,16 +49236,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -47397,16 +49365,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -47421,16 +49440,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -47472,16 +49542,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -47496,16 +49617,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -47601,16 +49773,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -47625,16 +49848,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -47676,16 +49950,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -47700,23 +50025,74 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - }, - "optional": false - } - } - ] + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] }, "optional": false } @@ -47778,16 +50154,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -47802,16 +50229,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -47853,16 +50331,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -47877,16 +50406,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -47909,114 +50489,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLanding" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -48086,16 +50567,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -48110,16 +50744,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] }, @@ -48161,118 +50948,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { + "keys": { "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] } @@ -48287,139 +51125,190 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -48467,16 +51356,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -48491,16 +51533,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] }, @@ -48542,16 +51737,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -48566,16 +51914,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] }, @@ -48588,16 +52089,115 @@ } } ] - } + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "agent" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { - "type": "union", + { + "type": "array", + "value": { + "type": "union", "value": [ { "type": "union", @@ -48644,102 +52244,6 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -48756,516 +52260,51 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" }, { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { + "keys": { "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" + "optional": false + } } ] } @@ -49280,16 +52319,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -49331,16 +52421,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -49355,16 +52496,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -49433,16 +52625,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -49457,16 +52700,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -49508,16 +52802,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -49532,16 +52877,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -49559,649 +52955,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -50249,16 +53033,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -50273,16 +53108,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -50324,16 +53210,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -50348,16 +53285,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -50370,343 +53358,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -50732,16 +53414,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -50756,16 +53489,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -50773,25 +53557,229 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -50861,16 +53849,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -50885,16 +53924,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -50936,16 +54026,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -50960,16 +54101,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -51038,16 +54230,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -51062,16 +54305,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -51113,16 +54407,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -51137,16 +54482,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -51164,397 +54560,6 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLink" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Query", - "identifier": "lineups.js:listForStrategy", - "returns": { - "type": "array", - "value": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "deleted": { - "fieldType": { - "type": "boolean" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "payload": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] } }, { @@ -51611,16 +54616,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -51635,16 +54793,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] }, @@ -51686,16 +54997,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -51710,26 +55174,179 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] }, @@ -51737,214 +55354,109 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "ability" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -51992,16 +55504,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -52016,16 +55579,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -52067,16 +55681,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -52091,16 +55756,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -52113,343 +55829,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -52475,16 +55885,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -52499,16 +55960,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -52516,166 +56028,18 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { "type": "union", "value": [ { @@ -52691,49 +56055,197 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -52781,16 +56293,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -52805,16 +56368,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -52856,16 +56470,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -52880,16 +56545,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -52902,118 +56618,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -53039,16 +56652,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -53063,255 +56829,6 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -53328,228 +56845,223 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -53597,16 +57109,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -53621,16 +57184,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -53672,16 +57286,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -53696,16 +57361,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -53718,343 +57434,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + "type": "array", + "value": { "type": "union", "value": [ { @@ -54080,16 +57490,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -54104,16 +57565,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -54121,166 +57633,18 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { "type": "union", "value": [ { @@ -54296,49 +57660,197 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -54386,16 +57898,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -54410,16 +57973,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -54461,16 +58075,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -54485,16 +58150,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -54507,416 +58223,11 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupOrigin" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" + } + }, + { + "keys": { + "type": "string" }, "type": "record", "values": { @@ -54946,16 +58257,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -54970,16 +58434,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] }, @@ -54997,134 +58614,131 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "drawing" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -55150,16 +58764,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -55174,526 +58839,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { + "keys": { "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] }, @@ -55735,220 +58941,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { + "keys": { "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] } @@ -55963,16 +59016,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -56041,16 +59145,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -56065,16 +59220,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -56116,40 +59322,142 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -56167,649 +59475,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -56857,16 +59553,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -56881,16 +59628,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -56932,16 +59730,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -56956,16 +59805,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -56978,343 +59878,37 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -57340,16 +59934,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -57364,16 +60009,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -57381,25 +60077,229 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -57469,16 +60369,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -57493,16 +60444,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -57544,16 +60546,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -57568,16 +60621,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -57646,16 +60750,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -57670,26 +60825,77 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { "keys": { "type": "string" }, @@ -57721,16 +60927,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -57745,16 +61002,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -57772,309 +61080,6 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLanding" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] } }, { @@ -58131,16 +61136,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -58155,16 +61313,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] }, @@ -58206,16 +61517,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -58230,220 +61694,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] }, @@ -58456,15 +61869,114 @@ } } ] - } + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "text" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -58512,16 +62024,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -58536,16 +62099,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -58587,16 +62201,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -58611,16 +62276,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -58633,137 +62349,40 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -58780,65 +62399,167 @@ } ] }, - "optional": false - } + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -58855,405 +62576,196 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } - } - ] - } - }, - { - "keys": { - "type": "string" + ] + } }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -59301,16 +62813,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -59325,16 +62888,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -59376,16 +62990,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -59400,16 +63065,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -59422,118 +63138,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -59559,102 +63172,6 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -59671,167 +63188,167 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { + "keys": { "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -59848,228 +63365,223 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -60117,16 +63629,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -60141,16 +63704,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -60192,16 +63806,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -60216,16 +63881,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -60238,343 +63954,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -60600,16 +64010,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -60624,16 +64085,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -60641,166 +64153,18 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { "type": "union", "value": [ { @@ -60816,49 +64180,197 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -60906,16 +64418,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -60930,16 +64493,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -60981,16 +64595,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -61005,16 +64670,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -61027,988 +64743,15 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLink" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "paginationOpts": { - "fieldType": { - "type": "object", - "value": { - "cursor": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "endCursor": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": true - }, - "id": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "maximumBytesRead": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "maximumRowsRead": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "numItems": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - "optional": false - }, - "table": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "elements" - }, - { - "type": "literal", - "value": "lineups" - } - ] - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "maintenance.js:backfillAssetReferences", - "returns": null, - "visibility": { - "kind": "internal" - } - }, - { - "args": { - "type": "object", - "value": {} - }, - "functionType": "Mutation", - "identifier": "maintenance.js:backfillStrategyAgentSummaries", - "returns": { - "type": "number" - }, - "visibility": { - "kind": "internal" - } - }, - { - "args": { - "type": "object", - "value": { - "paginationOpts": { - "fieldType": { - "type": "object", - "value": { - "cursor": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "endCursor": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": true - }, - "id": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "maximumBytesRead": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "maximumRowsRead": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "numItems": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - "optional": false - }, - "table": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "elements" - }, - { - "type": "literal", - "value": "lineups" - } - ] - }, - "optional": false - } - } - }, - "functionType": "Query", - "identifier": "maintenance.js:checkAssetReferences", - "returns": null, - "visibility": { - "kind": "internal" - } - }, - { - "args": { - "type": "object", - "value": { - "paginationOpts": { - "fieldType": { - "type": "object", - "value": { - "cursor": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "endCursor": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": true - }, - "id": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "maximumBytesRead": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "maximumRowsRead": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "numItems": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - "optional": false - }, - "table": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "elements" - }, - { - "type": "literal", - "value": "lineups" - } - ] - }, - "optional": false - } - } - }, - "functionType": "Query", - "identifier": "maintenance.js:findShownUnavailableAssets", - "returns": null, - "visibility": { - "kind": "internal" - } - }, - { - "args": { - "type": "object", - "value": { - "pageId": { - "fieldType": { - "tableName": "pages", - "type": "id" - }, - "optional": false - }, - "strategyId": { - "fieldType": { - "tableName": "strategies", - "type": "id" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "maintenance.js:purgeDeletedPageOrphans", - "returns": null, - "visibility": { - "kind": "internal" - } - }, - { - "args": { - "type": "object", - "value": {} - }, - "functionType": "Mutation", - "identifier": "maintenance.js:purgeOldOperationEvents", - "returns": null, - "visibility": { - "kind": "internal" - } - }, - { - "args": { - "type": "object", - "value": {} - }, - "functionType": "Mutation", - "identifier": "maintenance.js:purgeOldTombstones", - "returns": null, - "visibility": { - "kind": "internal" - } - }, - { - "args": { - "type": "object", - "value": {} - }, - "functionType": "Mutation", - "identifier": "maintenance.js:purgeTrashedPages", - "returns": null, - "visibility": { - "kind": "internal" - } - }, - { - "args": { - "type": "object", - "value": { - "accountSubject": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "checkLineupEndDeletes": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "checkLineupLinkEnds": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "checkTrashedPageDeletes": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "clientId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "ops": { - "fieldType": { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "expectedStrategyRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "payload": { - "fieldType": { - "type": "object", - "value": { - "clearThemeOverridePalette": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "clearThemeProfileId": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "mapData": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "themeOverridePalette": { - "fieldType": { - "type": "object", - "value": { - "base": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "detail": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "highlight": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "optional": true - }, - "themeProfileId": { - "fieldType": { - "type": "string" - }, - "optional": true - } - } - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "strategy.patch" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "expectedStrategyRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "payload": { - "fieldType": { - "type": "object", - "value": { - "isAttack": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "isAutoNamed": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "settings": { - "fieldType": { - "type": "object", - "value": { - "abilitySize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "agentSize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "useNeutralTeamColors": { - "fieldType": { - "type": "boolean" - }, - "optional": false - } - } - }, - "optional": true - } - } - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "page.add" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "expectedPageRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "payload": { - "fieldType": { - "type": "object", - "value": { - "isAttack": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "isAutoNamed": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "settings": { - "fieldType": { - "type": "object", - "value": { - "abilitySize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "agentSize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "useNeutralTeamColors": { - "fieldType": { - "type": "boolean" - }, - "optional": false - } - } - }, - "optional": true - } - } - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "page.patch" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "expectedStrategyRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "page.delete" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "expectedStrategyRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "page.reorder" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "expectedPageContentRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "settings": { - "fieldType": { - "type": "object", - "value": { - "abilitySize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "agentSize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "useNeutralTeamColors": { - "fieldType": { - "type": "boolean" - }, - "optional": false - } - } - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "pageContent.patch" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "elementPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "expectedElementRevision": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "payload": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -62056,16 +64799,523 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "image" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] } @@ -65158,7 +68408,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "agent" + "value": "utility" }, "optional": false }, @@ -65169,7 +68419,57 @@ "optional": false } } - }, + } + ] + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "element.add" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "elementPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "expectedElementRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "payload": { + "fieldType": { + "type": "union", + "value": [ { "type": "object", "value": { @@ -68418,7 +71718,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "ability" + "value": "agent" }, "optional": false }, @@ -71678,7 +74978,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "drawing" + "value": "ability" }, "optional": false }, @@ -74938,7 +78238,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "text" + "value": "drawing" }, "optional": false }, @@ -78198,7 +81498,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "image" + "value": "text" }, "optional": false }, @@ -81458,7 +84758,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "utility" + "value": "image" }, "optional": false }, @@ -81469,57 +84769,7 @@ "optional": false } } - } - ] - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "element.add" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "elementPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "expectedElementRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "payload": { - "fieldType": { - "type": "union", - "value": [ + }, { "type": "object", "value": { @@ -84768,7 +88018,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "agent" + "value": "utility" }, "optional": false }, @@ -84779,7 +88029,135 @@ "optional": false } } - }, + } + ] + }, + "optional": true + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "type": { + "fieldType": { + "type": "literal", + "value": "element.patch" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "elementPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "expectedElementRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "element.delete" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "elementPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "expectedElementRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "element.reorder" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "expectedLineupRevision": { + "fieldType": { + "type": "number" + }, + "optional": true + }, + "lineupPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "payload": { + "fieldType": { + "type": "union", + "value": [ { "type": "object", "value": { @@ -88028,7 +91406,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "ability" + "value": "lineups" }, "optional": false }, @@ -91288,7 +94666,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "drawing" + "value": "lineupOrigin" }, "optional": false }, @@ -94548,7 +97926,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "text" + "value": "lineupLanding" }, "optional": false }, @@ -97808,7 +101186,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "image" + "value": "lineupLink" }, "optional": false }, @@ -97819,7 +101197,57 @@ "optional": false } } - }, + } + ] + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "lineup.add" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "expectedLineupRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "lineupPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "payload": { + "fieldType": { + "type": "union", + "value": [ { "type": "object", "value": { @@ -101068,7 +104496,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "utility" + "value": "lineups" }, "optional": false }, @@ -101079,135 +104507,7 @@ "optional": false } } - } - ] - }, - "optional": true - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "type": { - "fieldType": { - "type": "literal", - "value": "element.patch" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "elementPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "expectedElementRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "element.delete" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "elementPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "expectedElementRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "element.reorder" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "expectedLineupRevision": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "lineupPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "payload": { - "fieldType": { - "type": "union", - "value": [ + }, { "type": "object", "value": { @@ -110990,18 +114290,54 @@ } ] }, - "optional": false + "optional": true }, "sortIndex": { "fieldType": { "type": "number" }, + "optional": true + }, + "type": { + "fieldType": { + "type": "literal", + "value": "lineup.patch" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "expectedLineupRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "lineupPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, "optional": false }, "type": { "fieldType": { "type": "literal", - "value": "lineup.add" + "value": "lineup.delete" }, "optional": false } @@ -111032,385 +114368,417 @@ "fieldType": { "type": "string" }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "lineup.reorder" + }, + "optional": false + } + } + } + ] + } + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "ops.js:applyBatch", + "returns": { + "type": "object", + "value": { + "results": { + "fieldType": { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "appliedRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "status": { + "fieldType": { + "type": "literal", + "value": "applied" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "currentRevision": { + "fieldType": { + "type": "number" + }, "optional": true }, - "payload": { + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "status": { + "fieldType": { + "type": "literal", + "value": "noop" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "current": { "fieldType": { "type": "union", "value": [ { "type": "object", "value": { - "data": { + "revision": { "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "strategy" + }, + "optional": false + }, + "value": { + "fieldType": { + "type": "object", + "value": { + "mapData": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "themeOverridePalette": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "base": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "detail": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "highlight": { + "fieldType": { + "type": "string" + }, + "optional": false + } } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "themeProfileId": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + } + } + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "page" + }, + "optional": false + }, + "value": { + "fieldType": { + "type": "object", + "value": { + "isAttack": { + "fieldType": { + "type": "boolean" + }, + "optional": false + }, + "isAutoNamed": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "pageContent" + }, + "optional": false + }, + "value": { + "fieldType": { + "type": "object", + "value": { + "settings": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "abilitySize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "agentSize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "useNeutralTeamColors": { + "fieldType": { + "type": "boolean" + }, + "optional": false + } + } + }, + { + "type": "null" + } + ] + }, + "optional": false + } + } + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "element" + }, + "optional": false + }, + "value": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -111436,322 +114804,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" }, { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { + "keys": { "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] } @@ -111766,16 +114879,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -111817,16 +114981,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -111841,16 +115056,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -111863,343 +115129,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -112225,16 +115185,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -112249,16 +115260,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -112266,166 +115328,18 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { "type": "union", "value": [ { @@ -112441,49 +115355,197 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -112531,16 +115593,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -112555,16 +115668,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -112606,16 +115770,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -112630,16 +115845,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -112652,118 +115918,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -112789,102 +115952,6 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -112901,371 +115968,167 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { + "keys": { "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -113282,24 +116145,223 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -113347,16 +116409,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -113371,16 +116484,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -113422,16 +116586,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -113446,16 +116661,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -113468,188 +116734,40 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { @@ -113665,181 +116783,74 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -113854,16 +116865,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -113871,166 +116933,18 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { "type": "union", "value": [ { @@ -114046,49 +116960,197 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -114136,16 +117198,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -114160,16 +117273,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -114211,16 +117375,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -114235,16 +117450,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -114257,420 +117523,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupOrigin" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -114696,16 +117557,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -114720,16 +117734,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] }, @@ -114747,214 +117914,109 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "agent" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -115002,16 +118064,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -115026,16 +118139,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -115077,19 +118241,70 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - } + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { "keys": { @@ -115101,16 +118316,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -115123,343 +118389,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -115485,16 +118445,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -115509,16 +118520,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -115526,166 +118588,18 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { "type": "union", "value": [ { @@ -115701,49 +118615,197 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -115791,16 +118853,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -115815,20 +118928,71 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - }, - "optional": false + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false } } ] @@ -115866,16 +119030,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -115890,16 +119105,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -115912,118 +119178,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -116049,16 +119212,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -116073,16 +119389,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] }, @@ -116090,192 +119559,91 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -116301,16 +119669,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -116325,322 +119744,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -116682,16 +119846,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -116706,16 +119921,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -116728,343 +119994,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -117090,16 +120050,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -117114,16 +120125,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -117131,166 +120193,18 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { "type": "union", "value": [ { @@ -117306,49 +120220,197 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" - }, + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -117396,16 +120458,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -117420,16 +120533,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -117471,16 +120635,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -117495,16 +120710,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -117517,411 +120783,6 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLanding" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] } }, { @@ -117956,16 +120817,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -117980,23 +120994,176 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - "optional": false - } - } - ] + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] }, "optional": false } @@ -118007,214 +121174,109 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "ability" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -118262,16 +121324,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -118286,16 +121399,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -118337,16 +121501,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -118361,16 +121576,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -118383,343 +121649,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -118745,16 +121705,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -118769,16 +121780,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -118786,166 +121848,18 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { "type": "union", "value": [ { @@ -118961,49 +121875,197 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -119051,16 +122113,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -119075,16 +122188,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -119126,16 +122290,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -119150,16 +122365,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -119172,118 +122438,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -119309,16 +122472,169 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } ] } @@ -119333,255 +122649,6 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -119598,228 +122665,223 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -119867,16 +122929,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -119891,16 +123004,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -119942,16 +123106,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -119966,16 +123181,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -119988,343 +123254,37 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + "type": "array", + "value": { "type": "union", "value": [ { @@ -120350,16 +123310,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -120374,16 +123385,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -120391,166 +123453,18 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { "type": "union", "value": [ { @@ -120566,49 +123480,197 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -120656,16 +123718,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -120680,16 +123793,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -120731,16 +123895,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] } @@ -120755,16 +123970,67 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] }, @@ -120777,439 +124043,423 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLink" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "optional": true - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "type": { - "fieldType": { - "type": "literal", - "value": "lineup.patch" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "expectedLineupRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "lineupPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "lineup.delete" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "expectedLineupRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "lineupPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "lineup.reorder" - }, - "optional": false - } - } - } - ] - } - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "ops.js:applyBatch", - "returns": { - "type": "object", - "value": { - "results": { - "fieldType": { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "appliedRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "status": { - "fieldType": { - "type": "literal", - "value": "applied" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "currentRevision": { - "fieldType": { - "type": "number" - }, - "optional": true - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "status": { - "fieldType": { - "type": "literal", - "value": "noop" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "current": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "strategy" - }, - "optional": false - }, - "value": { - "fieldType": { - "type": "object", - "value": { - "mapData": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "themeOverridePalette": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "base": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "detail": { - "fieldType": { - "type": "string" - }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] }, - "highlight": { - "fieldType": { - "type": "string" - }, - "optional": false - } + "optional": false } }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "themeProfileId": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "drawing" }, - { - "type": "null" - } - ] - }, - "optional": false - } - } - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "page" - }, - "optional": false - }, - "value": { - "fieldType": { - "type": "object", - "value": { - "isAttack": { - "fieldType": { - "type": "boolean" - }, - "optional": false - }, - "isAutoNamed": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "pageContent" - }, - "optional": false - }, - "value": { - "fieldType": { - "type": "object", - "value": { - "settings": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "abilitySize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "agentSize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "useNeutralTeamColors": { - "fieldType": { - "type": "boolean" - }, - "optional": false - } - } + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" }, - { - "type": "null" - } - ] - }, - "optional": false - } - } - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "element" - }, - "optional": false - }, - "value": { - "fieldType": { - "type": "union", - "value": [ + "optional": false + } + } + }, { "type": "object", "value": { @@ -124458,7 +127708,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "agent" + "value": "text" }, "optional": false }, @@ -127718,7 +130968,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "ability" + "value": "image" }, "optional": false }, @@ -130978,7 +134228,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "drawing" + "value": "utility" }, "optional": false }, @@ -130989,283 +134239,151 @@ "optional": false } } - }, - { - "type": "object", - "value": { - "data": { + } + ] + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "type": { + "fieldType": { + "type": "literal", + "value": "lineup" + }, + "optional": false + }, + "value": { + "fieldType": { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -131291,271 +134409,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] } @@ -131570,67 +134433,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -131672,67 +134484,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -131747,67 +134508,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -131820,241 +134530,37 @@ } } ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + } }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -132080,67 +134586,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -132155,67 +134610,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -132223,20 +134627,122 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -132284,67 +134790,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -132359,67 +134814,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -132461,67 +134865,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -132536,67 +134889,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -132609,113 +134911,112 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -132782,277 +135083,74 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -133100,67 +135198,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -133175,67 +135222,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -133277,67 +135273,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -133352,67 +135297,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -133425,430 +135319,22 @@ } } ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + } }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" + "type": "null" }, { "type": "boolean" @@ -133889,67 +135375,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -133964,67 +135399,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -134066,67 +135450,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -134141,67 +135474,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -134219,114 +135501,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "text" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -134699,62 +135882,159 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -134771,9 +136051,65 @@ } ] }, - { - "type": "array", - "value": { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -134789,66 +136125,168 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { "type": "string" } ] }, - { - "type": "array", - "value": { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -134864,71 +136302,326 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "boolean" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "number" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -134995,18 +136688,217 @@ } } ] - } + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -135023,9 +136915,167 @@ } ] }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -135041,81 +137091,30 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -135488,453 +137487,641 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "lineups" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "optional": false + } + } + } + ] + }, + "optional": true + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "reason": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "already_exists" + }, + { + "type": "literal", + "value": "deleted" + }, + { + "type": "literal", + "value": "element_strategy_mismatch" + }, + { + "type": "literal", + "value": "lineup_strategy_mismatch" + }, + { + "type": "literal", + "value": "missing_expected_revision" + }, + { + "type": "literal", + "value": "not_found" + }, + { + "type": "literal", + "value": "page_strategy_mismatch" + }, + { + "type": "literal", + "value": "revision_mismatch" + } + ] + }, + "optional": false + }, + "status": { + "fieldType": { + "type": "literal", + "value": "rejected" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "code": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "message": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "opId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "rawCode": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "status": { + "fieldType": { + "type": "literal", + "value": "failed" + }, + "optional": false + } + } + } + ] + } + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "shareToken": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Query", + "identifier": "page.js:getSnapshot", + "returns": { + "type": "object", + "value": { + "assets": { + "fieldType": { + "type": "array", + "value": { + "type": "object", + "value": { + "byteSize": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "fileExtension": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "height": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "legacyStoragePath": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "mimeType": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "provider": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "convex" + }, + { + "type": "literal", + "value": "r2" + } + ] + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "uploadedAt": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "uploadStatus": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "pending" + }, + { + "type": "literal", + "value": "active" + }, + { + "type": "literal", + "value": "failed" + }, + { + "type": "literal", + "value": "deleted" + } + ] + }, + "optional": false + }, + "url": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "width": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "optional": false + } + } + } + }, + "optional": false + }, + "content": { + "fieldType": { + "type": "object", + "value": { + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "settings": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "abilitySize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "agentSize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "useNeutralTeamColors": { + "fieldType": { + "type": "boolean" + }, + "optional": false + } + } + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "optional": false + }, + "elements": { + "fieldType": { + "type": "array", + "value": { + "type": "object", + "value": { + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "deleted": { + "fieldType": { + "type": "boolean" + }, + "optional": false + }, + "elementType": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "agent" + }, + { + "type": "literal", + "value": "ability" + }, + { + "type": "literal", + "value": "drawing" + }, + { + "type": "literal", + "value": "text" + }, + { + "type": "literal", + "value": "image" + }, + { + "type": "literal", + "value": "utility" + } + ] + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "payload": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -135951,175 +138138,537 @@ } ] }, - { - "type": "array", - "value": { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] } @@ -136134,169 +138683,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -136338,169 +138734,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -136515,169 +138758,628 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] }, @@ -136746,169 +139448,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -136923,169 +139472,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -137127,169 +139523,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -137304,169 +139547,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -137492,35 +139582,39 @@ }, "optional": false } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "image" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } + } + ] } }, { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -137612,169 +139706,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -137789,169 +139730,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -137993,169 +139781,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -138170,169 +139805,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -138401,169 +139883,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -138578,169 +139907,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -138782,169 +139958,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -138959,169 +139982,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -139217,169 +140087,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -139394,169 +140111,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -139598,169 +140162,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -139775,169 +140186,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -140006,169 +140264,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -140183,169 +140288,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -140387,169 +140339,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -140564,169 +140363,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -140749,152 +140395,333 @@ } } ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "utility" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "type": { - "fieldType": { - "type": "literal", - "value": "lineup" - }, - "optional": false - }, - "value": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" + } }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "boolean" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "number" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -140920,67 +140747,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -140995,67 +140771,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -141063,18 +140788,115 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -141091,191 +140913,196 @@ } ] }, - { - "type": "array", - "value": { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - } + } + ] + } + }, + { + "keys": { + "type": "string" }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -141301,67 +141128,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -141376,67 +141152,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -141444,6 +141169,462 @@ } } ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "agent" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] } }, { @@ -141456,169 +141637,220 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] }, @@ -141687,169 +141919,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -141864,169 +141943,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -142068,169 +141994,424 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] } @@ -142245,169 +142426,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -142503,6 +142531,102 @@ "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -142519,714 +142643,6 @@ } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, "optional": false } } @@ -143292,169 +142708,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -143469,169 +142732,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -143673,169 +142783,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -143850,169 +142807,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -144038,35 +142842,39 @@ }, "optional": false } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupOrigin" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } + } + ] } }, { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -144158,169 +142966,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -144335,169 +142990,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -144539,169 +143041,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -144716,169 +143065,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -144947,169 +143143,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -145124,169 +143167,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -145328,169 +143218,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -145505,169 +143242,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -145763,169 +143347,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -145940,169 +143371,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -146144,169 +143422,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -146321,169 +143446,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -146552,169 +143524,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -146729,169 +143548,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -146933,169 +143599,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -147110,169 +143623,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -147295,126 +143655,333 @@ } } ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLanding" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" + } }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "boolean" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "number" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -147440,67 +144007,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -147515,67 +144031,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -147583,18 +144048,115 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -147611,191 +144173,196 @@ } ] }, - { - "type": "array", - "value": { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - } + } + ] + } + }, + { + "keys": { + "type": "string" }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -147821,67 +144388,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -147896,67 +144412,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -147964,181 +144429,688 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "ability" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] }, @@ -148207,169 +145179,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -148384,169 +145203,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -148588,169 +145254,424 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] } @@ -148765,169 +145686,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -149023,6 +145791,102 @@ "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -149039,153 +145903,516 @@ } ] }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] } @@ -149200,169 +146427,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -149404,169 +146478,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -149581,169 +146502,220 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] }, @@ -149812,169 +146784,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -149989,169 +146808,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -150193,169 +146859,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -150370,169 +146883,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -150555,1114 +146915,59 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLink" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "optional": false - } - } - } - ] - }, - "optional": true - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "reason": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "already_exists" - }, - { - "type": "literal", - "value": "element_strategy_mismatch" - }, - { - "type": "literal", - "value": "lineup_strategy_mismatch" - }, - { - "type": "literal", - "value": "missing_expected_revision" - }, - { - "type": "literal", - "value": "not_found" - }, - { - "type": "literal", - "value": "page_strategy_mismatch" - }, - { - "type": "literal", - "value": "revision_mismatch" - } - ] - }, - "optional": false - }, - "status": { - "fieldType": { - "type": "literal", - "value": "rejected" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "code": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "message": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "opId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "rawCode": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "status": { - "fieldType": { - "type": "literal", - "value": "failed" - }, - "optional": false - } - } - } - ] - } - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "shareToken": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Query", - "identifier": "page.js:getSnapshot", - "returns": { - "type": "object", - "value": { - "assets": { - "fieldType": { - "type": "array", - "value": { - "type": "object", - "value": { - "byteSize": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "fileExtension": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "height": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "legacyStoragePath": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "mimeType": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "provider": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "convex" - }, - { - "type": "literal", - "value": "r2" - } - ] - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "uploadedAt": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "uploadStatus": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "pending" - }, - { - "type": "literal", - "value": "active" - }, - { - "type": "literal", - "value": "failed" - }, - { - "type": "literal", - "value": "deleted" - } - ] - }, - "optional": false - }, - "url": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "width": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "optional": false - } - } - } - }, - "optional": false - }, - "content": { - "fieldType": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "settings": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "abilitySize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "agentSize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "useNeutralTeamColors": { - "fieldType": { - "type": "boolean" - }, - "optional": false - } - } - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - "optional": false - }, - "elements": { - "fieldType": { - "type": "array", - "value": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "deleted": { - "fieldType": { - "type": "boolean" - }, - "optional": false - }, - "elementType": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "agent" - }, - { - "type": "literal", - "value": "ability" - }, - { - "type": "literal", - "value": "drawing" - }, - { - "type": "literal", - "value": "text" - }, - { - "type": "literal", - "value": "image" - }, - { - "type": "literal", - "value": "utility" - } - ] - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "payload": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -151831,343 +147136,37 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -152234,166 +147233,18 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { "type": "union", "value": [ { @@ -152409,15 +147260,10 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -152433,25 +147279,76 @@ "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -152620,118 +147517,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -152757,102 +147551,6 @@ "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -152869,167 +147567,65 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { + "keys": { "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { @@ -153046,73 +147642,472 @@ } ] }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false } - ] + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "drawing" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "boolean" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "number" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -153179,18 +148174,115 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -153207,92 +148299,41 @@ } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { @@ -153308,10 +148349,15 @@ "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -153327,178 +148373,25 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" }, { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -153667,40 +148560,137 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -153717,12 +148707,221 @@ } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "null" }, { @@ -153764,18 +148963,115 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -153792,9 +149088,65 @@ } ] }, - { - "type": "array", - "value": { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -153810,76 +149162,25 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -154048,500 +149349,96 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - }, - "optional": false + } + ] } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "agent" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -154710,212 +149607,8 @@ } } ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, + } + }, { "keys": { "type": "string" @@ -155096,161 +149789,59 @@ } } ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + } }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -155317,64 +149908,18 @@ } } ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + } }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { @@ -155390,15 +149935,10 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -155414,20 +149954,71 @@ "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -155494,25 +150085,127 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -155885,365 +150578,59 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -156310,929 +150697,11 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" + } + }, + { + "keys": { + "type": "string" }, "type": "record", "values": { @@ -157514,7 +150983,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "ability" + "value": "text" }, "optional": false }, @@ -160774,7 +154243,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "drawing" + "value": "image" }, "optional": false }, @@ -164034,7 +157503,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "text" + "value": "utility" }, "optional": false }, @@ -164045,283 +157514,192 @@ "optional": false } } - }, - { - "type": "object", - "value": { - "data": { + } + ] + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + }, + "optional": false + }, + "lineups": { + "fieldType": { + "type": "array", + "value": { + "type": "object", + "value": { + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "deleted": { + "fieldType": { + "type": "boolean" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "payload": { + "fieldType": { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -164347,271 +157725,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "boolean" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "number" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "string" } ] } @@ -164626,67 +157749,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -164728,67 +157800,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -164803,67 +157824,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -164876,241 +157846,37 @@ } } ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + } }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -165136,67 +157902,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -165211,67 +157926,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -165279,20 +157943,122 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -165340,67 +158106,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -165415,67 +158130,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -165517,67 +158181,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -165592,67 +158205,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -165665,113 +158227,112 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "number" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "string" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -165838,277 +158399,74 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -166156,67 +158514,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -166231,67 +158538,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -166333,67 +158589,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -166408,67 +158613,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -166481,430 +158635,22 @@ } } ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + } }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" + "type": "null" }, { "type": "boolean" @@ -166945,67 +158691,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -167020,67 +158715,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -167122,67 +158766,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -167197,67 +158790,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -167275,114 +158817,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "image" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -167755,62 +159198,159 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -167827,9 +159367,65 @@ } ] }, - { - "type": "array", - "value": { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -167845,66 +159441,168 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] }, - { - "type": "array", - "value": { + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -167920,71 +159618,326 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "boolean" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "number" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -168051,18 +160004,217 @@ } } ] - } + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -168079,9 +160231,167 @@ } ] }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -168097,81 +160407,30 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - }, - "optional": false - } + } + ] + }, + "optional": false } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -168544,2029 +160803,41 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "utility" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" + "optional": false + } + } + ] + }, + "optional": false + } + } + ] }, "optional": false } - } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "lineups" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false } - ] + } }, "optional": false }, @@ -170605,18911 +160876,2544 @@ }, "optional": false }, - "lineups": { + "page": { "fieldType": { - "type": "array", + "type": "object", "value": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false + "createdAt": { + "fieldType": { + "type": "number" }, - "deleted": { - "fieldType": { - "type": "boolean" - }, - "optional": false + "optional": false + }, + "isAttack": { + "fieldType": { + "type": "boolean" }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false + "optional": false + }, + "isAutoNamed": { + "fieldType": { + "type": "boolean" }, - "payload": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupOrigin" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLanding" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLink" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - }, - "optional": false - }, - "page": { - "fieldType": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "isAttack": { - "fieldType": { - "type": "boolean" - }, - "optional": false - }, - "isAutoNamed": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - "optional": false - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "expectedRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "isAttack": { - "fieldType": { - "type": "boolean" - }, - "optional": false - }, - "isAutoNamed": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "settings": { - "fieldType": { - "type": "object", - "value": { - "abilitySize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "agentSize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "useNeutralTeamColors": { - "fieldType": { - "type": "boolean" - }, - "optional": false - } - } - }, - "optional": true - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "pages.js:add", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "reused": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "expectedRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "pages.js:delete", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "reused": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Query", - "identifier": "pages.js:listForStrategy", - "returns": { - "type": "array", - "value": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "isAttack": { - "fieldType": { - "type": "boolean" - }, - "optional": false - }, - "isAutoNamed": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Query", - "identifier": "pages.js:listTrashed", - "returns": { - "type": "array", - "value": { - "type": "object", - "value": { - "deletedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "deletedByName": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "deletedByYou": { - "fieldType": { - "type": "boolean" - }, - "optional": false - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "restorableUntil": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "expectedRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "isAutoNamed": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "pages.js:rename", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "reused": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "expectedRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "orderedPagePublicIds": { - "fieldType": { - "type": "array", - "value": { - "type": "string" - } - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "pages.js:reorder", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "reused": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "pages.js:restore", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "reused": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "presence.js:issueRoomPass", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "expiresAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "pass": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "url": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - { - "type": "null" - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "role": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "viewer" - }, - { - "type": "literal", - "value": "editor" - } - ] - }, - "optional": false - }, - "targetPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "targetType": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "strategy" - }, - { - "type": "literal", - "value": "folder" - } - ] - }, - "optional": false - }, - "token": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "shares.js:create", - "returns": { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "targetPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "targetType": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "strategy" - }, - { - "type": "literal", - "value": "folder" - } - ] - }, - "optional": false - } - } - }, - "functionType": "Query", - "identifier": "shares.js:list", - "returns": { - "type": "array", - "value": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "revokedAt": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "role": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "viewer" - }, - { - "type": "literal", - "value": "editor" - } - ] - }, - "optional": false - }, - "token": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "token": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "shares.js:redeem", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "alreadyHadAccess": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "folderPublicId": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "role": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "owner" - }, - { - "type": "literal", - "value": "editor" - }, - { - "type": "literal", - "value": "viewer" - } - ] - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "targetType": { - "fieldType": { - "type": "literal", - "value": "strategy" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "alreadyHadAccess": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "folderPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "role": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "owner" - }, - { - "type": "literal", - "value": "editor" - }, - { - "type": "literal", - "value": "viewer" - } - ] - }, - "optional": false - }, - "targetType": { - "fieldType": { - "type": "literal", - "value": "folder" - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "token": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Query", - "identifier": "shares.js:resolve", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "role": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "viewer" - }, - { - "type": "literal", - "value": "editor" - } - ] - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "targetType": { - "fieldType": { - "type": "literal", - "value": "strategy" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "role": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "viewer" - }, - { - "type": "literal", - "value": "editor" - } - ] - }, - "optional": false - }, - "targetType": { - "fieldType": { - "type": "literal", - "value": "folder" - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "targetPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "targetType": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "strategy" - }, - { - "type": "literal", - "value": "folder" - } - ] - }, - "optional": false - }, - "token": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "shares.js:revoke", - "returns": { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "folderPublicId": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "mapData": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "themeOverridePalette": { - "fieldType": { - "type": "object", - "value": { - "base": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "detail": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "highlight": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "optional": true - }, - "themeProfileId": { - "fieldType": { - "type": "string" - }, - "optional": true - } - } - }, - "functionType": "Mutation", - "identifier": "strategies.js:create", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "reused": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "folderPublicId": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "initialPageIsAttack": { - "fieldType": { - "type": "boolean" - }, - "optional": false - }, - "initialPageIsAutoNamed": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "initialPageName": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "initialPagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "initialPageSettings": { - "fieldType": { - "type": "object", - "value": { - "abilitySize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "agentSize": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "useNeutralTeamColors": { - "fieldType": { - "type": "boolean" - }, - "optional": false - } - } - }, - "optional": true - }, - "mapData": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "themeOverridePalette": { - "fieldType": { - "type": "object", - "value": { - "base": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "detail": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "highlight": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "optional": true - }, - "themeProfileId": { - "fieldType": { - "type": "string" - }, - "optional": true - } - } - }, - "functionType": "Mutation", - "identifier": "strategies.js:createWithInitialPage", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "reused": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "expectedRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "strategies.js:delete", - "returns": { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "folderPublicId": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "sourceStrategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "strategies.js:duplicate", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "reused": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Query", - "identifier": "strategies.js:getHeader", - "returns": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "mapData": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "role": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "owner" - }, - { - "type": "literal", - "value": "editor" - }, - { - "type": "literal", - "value": "viewer" - } - ] - }, - "optional": false - }, - "themeOverridePalette": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "base": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "detail": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "highlight": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "themeProfileId": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "folderPublicId": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "scope": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "owned" - }, - { - "type": "literal", - "value": "shared" - }, - { - "type": "literal", - "value": "all" - } - ] - }, - "optional": true - } - } - }, - "functionType": "Query", - "identifier": "strategies.js:listForFolder", - "returns": { - "type": "array", - "value": { - "type": "object", - "value": { - "attackLabel": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "Unknown" - }, - { - "type": "literal", - "value": "Mixed" - }, - { - "type": "literal", - "value": "Attack" - }, - { - "type": "literal", - "value": "Defend" - } - ] - }, - "optional": false - }, - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "folderPublicId": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "mapData": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "role": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "owner" - }, - { - "type": "literal", - "value": "editor" - }, - { - "type": "literal", - "value": "viewer" - } - ] - }, - "optional": false - }, - "themeOverridePalette": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "base": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "detail": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "highlight": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "themeProfileId": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": {} - }, - "functionType": "Query", - "identifier": "strategies.js:listSharedWithMe", - "returns": { - "type": "array", - "value": { - "type": "object", - "value": { - "attackLabel": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "Unknown" - }, - { - "type": "literal", - "value": "Mixed" - }, - { - "type": "literal", - "value": "Attack" - }, - { - "type": "literal", - "value": "Defend" - } - ] - }, - "optional": false - }, - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "folderPublicId": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "mapData": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "role": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "owner" - }, - { - "type": "literal", - "value": "editor" - }, - { - "type": "literal", - "value": "viewer" - } - ] - }, - "optional": false - }, - "themeOverridePalette": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "base": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "detail": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "highlight": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "themeProfileId": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "expectedRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "folderPublicId": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Mutation", - "identifier": "strategies.js:move", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "reused": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "clearThemeOverridePalette": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "clearThemeProfileId": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "expectedRevision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "mapData": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "themeOverridePalette": { - "fieldType": { - "type": "object", - "value": { - "base": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "detail": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "highlight": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "optional": true - }, - "themeProfileId": { - "fieldType": { - "type": "string" - }, - "optional": true - } - } - }, - "functionType": "Mutation", - "identifier": "strategies.js:update", - "returns": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "ok": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "reused": { - "fieldType": { - "type": "literal", - "value": true - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - ] - }, - "visibility": { - "kind": "public" - } - }, - { - "args": { - "type": "object", - "value": { - "acceptsTrashedPagesLeftOut": { - "fieldType": { - "type": "boolean" - }, - "optional": true - }, - "clientProtocolVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "shareToken": { - "fieldType": { - "type": "string" - }, - "optional": true - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - "functionType": "Query", - "identifier": "strategy.js:getFullSnapshot", - "returns": { - "type": "object", - "value": { - "assets": { - "fieldType": { - "type": "array", - "value": { - "type": "object", - "value": { - "byteSize": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "fileExtension": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "height": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "legacyStoragePath": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "mimeType": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "provider": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "convex" - }, - { - "type": "literal", - "value": "r2" - } - ] - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "uploadedAt": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "uploadStatus": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "pending" - }, - { - "type": "literal", - "value": "active" - }, - { - "type": "literal", - "value": "failed" - }, - { - "type": "literal", - "value": "deleted" - } - ] - }, - "optional": false - }, - "url": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "width": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "number" - }, - { - "type": "null" - } - ] - }, - "optional": false - } - } - } - }, - "optional": false - }, - "elements": { - "fieldType": { - "type": "array", - "value": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "deleted": { - "fieldType": { - "type": "boolean" - }, - "optional": false - }, - "elementType": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "agent" - }, - { - "type": "literal", - "value": "ability" - }, - { - "type": "literal", - "value": "drawing" - }, - { - "type": "literal", - "value": "text" - }, - { - "type": "literal", - "value": "image" - }, - { - "type": "literal", - "value": "utility" - } - ] - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "payload": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "agent" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "ability" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } + "optional": true + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "optional": false + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "expectedRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "isAttack": { + "fieldType": { + "type": "boolean" + }, + "optional": false + }, + "isAutoNamed": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "settings": { + "fieldType": { + "type": "object", + "value": { + "abilitySize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "agentSize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "useNeutralTeamColors": { + "fieldType": { + "type": "boolean" + }, + "optional": false + } + } + }, + "optional": true + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "pages.js:add", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "reused": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "expectedRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "pages.js:delete", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "reused": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Query", + "identifier": "pages.js:listForStrategy", + "returns": { + "type": "array", + "value": { + "type": "object", + "value": { + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "isAttack": { + "fieldType": { + "type": "boolean" + }, + "optional": false + }, + "isAutoNamed": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Query", + "identifier": "pages.js:listTrashed", + "returns": { + "type": "array", + "value": { + "type": "object", + "value": { + "deletedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "deletedByName": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "deletedByYou": { + "fieldType": { + "type": "boolean" + }, + "optional": false + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "restorableUntil": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "expectedRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "isAutoNamed": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "pages.js:rename", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "reused": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "expectedRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "orderedPagePublicIds": { + "fieldType": { + "type": "array", + "value": { + "type": "string" + } + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "pages.js:reorder", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "reused": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "pages.js:restore", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "reused": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "presence.js:issueRoomPass", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "expiresAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "pass": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "url": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + { + "type": "null" + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "role": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "viewer" + }, + { + "type": "literal", + "value": "editor" + } + ] + }, + "optional": false + }, + "targetPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "targetType": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "strategy" + }, + { + "type": "literal", + "value": "folder" + } + ] + }, + "optional": false + }, + "token": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "shares.js:create", + "returns": { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "targetPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "targetType": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "strategy" + }, + { + "type": "literal", + "value": "folder" + } + ] + }, + "optional": false + } + } + }, + "functionType": "Query", + "identifier": "shares.js:list", + "returns": { + "type": "array", + "value": { + "type": "object", + "value": { + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "revokedAt": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "role": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "viewer" + }, + { + "type": "literal", + "value": "editor" + } + ] + }, + "optional": false + }, + "token": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "token": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "shares.js:redeem", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "alreadyHadAccess": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "folderPublicId": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "role": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "owner" + }, + { + "type": "literal", + "value": "editor" + }, + { + "type": "literal", + "value": "viewer" + } + ] + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "targetType": { + "fieldType": { + "type": "literal", + "value": "strategy" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "alreadyHadAccess": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "folderPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "role": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "owner" + }, + { + "type": "literal", + "value": "editor" + }, + { + "type": "literal", + "value": "viewer" + } + ] + }, + "optional": false + }, + "targetType": { + "fieldType": { + "type": "literal", + "value": "folder" + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "token": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Query", + "identifier": "shares.js:resolve", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "role": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "viewer" + }, + { + "type": "literal", + "value": "editor" + } + ] + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "targetType": { + "fieldType": { + "type": "literal", + "value": "strategy" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "role": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "viewer" + }, + { + "type": "literal", + "value": "editor" + } + ] + }, + "optional": false + }, + "targetType": { + "fieldType": { + "type": "literal", + "value": "folder" + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "targetPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "targetType": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "strategy" + }, + { + "type": "literal", + "value": "folder" + } + ] + }, + "optional": false + }, + "token": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "shares.js:revoke", + "returns": { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "folderPublicId": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "mapData": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "themeOverridePalette": { + "fieldType": { + "type": "object", + "value": { + "base": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "detail": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "highlight": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "optional": true + }, + "themeProfileId": { + "fieldType": { + "type": "string" + }, + "optional": true + } + } + }, + "functionType": "Mutation", + "identifier": "strategies.js:create", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "reused": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "folderPublicId": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "initialPageIsAttack": { + "fieldType": { + "type": "boolean" + }, + "optional": false + }, + "initialPageIsAutoNamed": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "initialPageName": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "initialPagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "initialPageSettings": { + "fieldType": { + "type": "object", + "value": { + "abilitySize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "agentSize": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "useNeutralTeamColors": { + "fieldType": { + "type": "boolean" + }, + "optional": false + } + } + }, + "optional": true + }, + "mapData": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "themeOverridePalette": { + "fieldType": { + "type": "object", + "value": { + "base": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "detail": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "highlight": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "optional": true + }, + "themeProfileId": { + "fieldType": { + "type": "string" + }, + "optional": true + } + } + }, + "functionType": "Mutation", + "identifier": "strategies.js:createWithInitialPage", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "reused": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "expectedRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "strategies.js:delete", + "returns": { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "folderPublicId": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "sourceStrategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "strategies.js:duplicate", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "reused": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Query", + "identifier": "strategies.js:getHeader", + "returns": { + "type": "object", + "value": { + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "mapData": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "role": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "owner" + }, + { + "type": "literal", + "value": "editor" + }, + { + "type": "literal", + "value": "viewer" + } + ] + }, + "optional": false + }, + "themeOverridePalette": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "base": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "detail": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "highlight": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "themeProfileId": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "folderPublicId": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "scope": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "owned" + }, + { + "type": "literal", + "value": "shared" + }, + { + "type": "literal", + "value": "all" + } + ] + }, + "optional": true + } + } + }, + "functionType": "Query", + "identifier": "strategies.js:listForFolder", + "returns": { + "type": "array", + "value": { + "type": "object", + "value": { + "attackLabel": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "Unknown" + }, + { + "type": "literal", + "value": "Mixed" + }, + { + "type": "literal", + "value": "Attack" + }, + { + "type": "literal", + "value": "Defend" + } + ] + }, + "optional": false + }, + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "folderPublicId": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "mapData": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "role": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "owner" + }, + { + "type": "literal", + "value": "editor" + }, + { + "type": "literal", + "value": "viewer" + } + ] + }, + "optional": false + }, + "themeOverridePalette": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "base": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "detail": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "highlight": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "themeProfileId": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": {} + }, + "functionType": "Query", + "identifier": "strategies.js:listSharedWithMe", + "returns": { + "type": "array", + "value": { + "type": "object", + "value": { + "attackLabel": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "Unknown" + }, + { + "type": "literal", + "value": "Mixed" + }, + { + "type": "literal", + "value": "Attack" + }, + { + "type": "literal", + "value": "Defend" + } + ] + }, + "optional": false + }, + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "folderPublicId": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "mapData": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "role": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "owner" + }, + { + "type": "literal", + "value": "editor" + }, + { + "type": "literal", + "value": "viewer" + } + ] + }, + "optional": false + }, + "themeOverridePalette": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "base": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "detail": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "highlight": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "themeProfileId": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "expectedRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "folderPublicId": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Mutation", + "identifier": "strategies.js:move", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "reused": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "clearThemeOverridePalette": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "clearThemeProfileId": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "expectedRevision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "mapData": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "themeOverridePalette": { + "fieldType": { + "type": "object", + "value": { + "base": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "detail": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "highlight": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "optional": true + }, + "themeProfileId": { + "fieldType": { + "type": "string" + }, + "optional": true + } + } + }, + "functionType": "Mutation", + "identifier": "strategies.js:update", + "returns": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + { + "type": "object", + "value": { + "ok": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "reused": { + "fieldType": { + "type": "literal", + "value": true + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + ] + }, + "visibility": { + "kind": "public" + } + }, + { + "args": { + "type": "object", + "value": { + "acceptsTrashedPagesLeftOut": { + "fieldType": { + "type": "boolean" + }, + "optional": true + }, + "clientProtocolVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "shareToken": { + "fieldType": { + "type": "string" + }, + "optional": true + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + "functionType": "Query", + "identifier": "strategy.js:getFullSnapshot", + "returns": { + "type": "object", + "value": { + "assets": { + "fieldType": { + "type": "array", + "value": { + "type": "object", + "value": { + "byteSize": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "fileExtension": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "height": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "legacyStoragePath": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "mimeType": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "provider": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "convex" + }, + { + "type": "literal", + "value": "r2" + } + ] + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "uploadedAt": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "uploadStatus": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "pending" + }, + { + "type": "literal", + "value": "active" + }, + { + "type": "literal", + "value": "failed" + }, + { + "type": "literal", + "value": "deleted" + } + ] + }, + "optional": false + }, + "url": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "width": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "optional": false + } + } + } + }, + "optional": false + }, + "elements": { + "fieldType": { + "type": "array", + "value": { + "type": "object", + "value": { + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "deleted": { + "fieldType": { + "type": "boolean" + }, + "optional": false + }, + "elementType": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "agent" + }, + { + "type": "literal", + "value": "ability" + }, + { + "type": "literal", + "value": "drawing" }, + { + "type": "literal", + "value": "text" + }, + { + "type": "literal", + "value": "image" + }, + { + "type": "literal", + "value": "utility" + } + ] + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "payload": { + "fieldType": { + "type": "union", + "value": [ { "type": "object", "value": { @@ -192758,7 +166662,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "drawing" + "value": "agent" }, "optional": false }, @@ -196018,7 +169922,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "text" + "value": "ability" }, "optional": false }, @@ -199278,7 +173182,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "image" + "value": "drawing" }, "optional": false }, @@ -202538,7 +176442,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "utility" + "value": "text" }, "optional": false }, @@ -202549,186 +176453,7 @@ "optional": false } } - } - ] - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "sortIndex": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "strategyPublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - } - }, - "optional": false - }, - "header": { - "fieldType": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "mapData": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "name": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "publicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "revision": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "role": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "literal", - "value": "owner" - }, - { - "type": "literal", - "value": "editor" - }, - { - "type": "literal", - "value": "viewer" - } - ] - }, - "optional": false - }, - "themeOverridePalette": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "object", - "value": { - "base": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "detail": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "highlight": { - "fieldType": { - "type": "string" - }, - "optional": false - } - } - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "themeProfileId": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "optional": false - }, - "updatedAt": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - "optional": false - }, - "lineups": { - "fieldType": { - "type": "array", - "value": { - "type": "object", - "value": { - "createdAt": { - "fieldType": { - "type": "number" - }, - "optional": false - }, - "deleted": { - "fieldType": { - "type": "boolean" - }, - "optional": false - }, - "pagePublicId": { - "fieldType": { - "type": "string" - }, - "optional": false - }, - "payload": { - "fieldType": { - "type": "union", - "value": [ + }, { "type": "object", "value": { @@ -205977,7 +179702,7 @@ "kind": { "fieldType": { "type": "literal", - "value": "lineupOrigin" + "value": "image" }, "optional": false }, @@ -206247,24 +179972,228 @@ } ] }, - "optional": false + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -206433,20 +180362,224 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -206819,20 +180952,428 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -207142,15 +181683,321 @@ } } ] - } - }, - { - "keys": { - "type": "string" + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -207217,25 +182064,127 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -207608,25 +182557,654 @@ } } ] + } + }, + { + "keys": { + "type": "string" }, - "optional": false + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } } - } - ] - }, - "optional": false + ] + }, + "optional": false + } } - } - ] + ] + }, + "optional": false } + } + ] + }, + "optional": false + } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "utility" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + ] + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "sortIndex": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "strategyPublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + } + }, + "optional": false + }, + "header": { + "fieldType": { + "type": "object", + "value": { + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "mapData": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "name": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "publicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "revision": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "role": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "literal", + "value": "owner" + }, + { + "type": "literal", + "value": "editor" + }, + { + "type": "literal", + "value": "viewer" + } + ] + }, + "optional": false + }, + "themeOverridePalette": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "object", + "value": { + "base": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "detail": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "highlight": { + "fieldType": { + "type": "string" + }, + "optional": false + } + } + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "themeProfileId": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "optional": false + }, + "updatedAt": { + "fieldType": { + "type": "number" + }, + "optional": false + } + } + }, + "optional": false + }, + "lineups": { + "fieldType": { + "type": "array", + "value": { + "type": "object", + "value": { + "createdAt": { + "fieldType": { + "type": "number" + }, + "optional": false + }, + "deleted": { + "fieldType": { + "type": "boolean" + }, + "optional": false + }, + "pagePublicId": { + "fieldType": { + "type": "string" + }, + "optional": false + }, + "payload": { + "fieldType": { + "type": "object", + "value": { + "data": { + "fieldType": { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -207718,67 +183296,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -207793,67 +183320,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -207895,142 +183371,40 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] }, @@ -208099,67 +183473,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -208174,67 +183497,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -208276,67 +183548,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -208351,67 +183572,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -208507,6 +183677,102 @@ "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -208523,9 +183789,167 @@ } ] }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -208541,33 +183965,136 @@ "type": "string" } ] - } + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] } @@ -208582,67 +184109,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -208684,67 +184160,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -208759,67 +184184,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -208888,67 +184262,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -208956,74 +184279,23 @@ { "keys": { "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" } ] }, @@ -209065,67 +184337,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -209140,67 +184361,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -209218,114 +184388,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLanding" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" - }, - "optional": false - } - } - }, - { - "type": "object", - "value": { - "data": { - "fieldType": { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -209698,59 +184769,365 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "boolean" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } }, { - "type": "number" + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -209817,18 +185194,115 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -209845,92 +185319,41 @@ } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { @@ -209946,10 +185369,15 @@ "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -209965,178 +185393,25 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" + "optional": false + } } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -210305,396 +185580,91 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + { + "type": "array", + "value": { "type": "union", "value": [ { @@ -210720,67 +185690,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] } @@ -210795,67 +185714,16 @@ "type": "union", "value": [ { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "type": "null" }, { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } + "type": "boolean" }, { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "type": "number" + }, + { + "type": "string" } ] }, @@ -210863,118 +185731,15 @@ } } ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + } }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -211041,120 +185806,64 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] + } + }, + { + "keys": { + "type": "string" }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { @@ -211170,10 +185879,15 @@ "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -211189,173 +185903,20 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + } + ] } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" }, { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -211422,18 +185983,115 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { "type": "union", "value": [ { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "array", + "value": { + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -211450,92 +186108,41 @@ } ] }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { + }, + { + "keys": { + "type": "string" + }, + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" + "type": "union", + "value": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { + "type": "array", + "value": { "type": "union", "value": [ { @@ -211551,10 +186158,15 @@ "type": "string" } ] + } + }, + { + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -211570,178 +186182,25 @@ "type": "string" } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false + } + } + ] } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" }, { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] + "keys": { + "type": "string" }, - { - "type": "array", - "value": { + "type": "record", + "values": { + "fieldType": { "type": "union", "value": [ { @@ -211910,606 +186369,46 @@ } } ] - } - }, - { - "keys": { - "type": "string" }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } + "optional": false } - ] - } + } + ] }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - { - "type": "array", - "value": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - { - "keys": { - "type": "string" - }, - "type": "record", - "values": { - "fieldType": { - "type": "union", - "value": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - } - ] - }, - "optional": false - } - }, - "optional": false - }, - "kind": { - "fieldType": { - "type": "literal", - "value": "lineupLink" - }, - "optional": false - }, - "payloadVersion": { - "fieldType": { - "type": "number" + "optional": false + } + } + ] + }, + "optional": false + } + } + ] + }, + "optional": false + } + } + ] }, "optional": false } - } + }, + "optional": false + }, + "kind": { + "fieldType": { + "type": "literal", + "value": "lineups" + }, + "optional": false + }, + "payloadVersion": { + "fieldType": { + "type": "number" + }, + "optional": false } - ] + } }, "optional": false }, diff --git a/convex/imageAssetLifecycle.test.ts b/convex/imageAssetLifecycle.test.ts index d6c919dc..d49f7c57 100644 --- a/convex/imageAssetLifecycle.test.ts +++ b/convex/imageAssetLifecycle.test.ts @@ -11,7 +11,11 @@ import { markAssetReferencesReady } from "./lib/assetReferences"; import { CURRENT_CLOUD_PROTOCOL_VERSION } from "./lib/cloudProtocol"; import { PAGE_TRASH_RETENTION_MS } from "./lib/entities"; import schema from "./schema"; -import { insertElement, insertLineup } from "./testContent.helpers"; +import { + insertElement, + insertLineup, + lineupsPayload, +} from "./testContent.helpers"; import { modules } from "./test.setup"; const ensureCurrentUser = makeFunctionReference<"mutation">( @@ -105,19 +109,6 @@ function imagePayload(assetPublicId: string) { }; } -function lineupPayload(assetPublicId: string) { - return { - kind: "lineupLink" as const, - payloadVersion: 1, - data: { - id: "remaining-lineup", - originId: "origin", - landingId: "landing", - images: [{ id: assetPublicId }], - }, - }; -} - function mockR2Deletes(statuses: number[] = [204]) { let callIndex = 0; const fetchMock = vi.fn( @@ -245,41 +236,37 @@ describe("image asset lifecycle", () => { updatedAt: now, }); } + // One lineup group whose two lineups each show an image. await insertLineup(ctx, { - publicId: "lineupLink:remaining-lineup", + publicId: "remaining-lineup", strategyId: strategy._id, pageId: pageBId, - payloadKind: "lineupLink", + payloadKind: "lineups", payloadVersion: 1, - payload: lineupPayload("still-used"), + payload: lineupsPayload("remaining-lineup", { + origins: [{ id: "origin" }], + landings: [{ id: "landing" }, { id: "other-landing" }], + links: [ + { + id: "remaining-lineup", + originId: "origin", + landingId: "landing", + images: [{ id: "still-used" }], + }, + { + id: "remaining-link", + originId: "origin", + landingId: "other-landing", + images: [{ id: "still-used-by-link", fileExtension: ".png" }], + }, + ], + }), sortIndex: 0, revision: 1, deleted: false, createdAt: now, updatedAt: now, }); - await insertLineup(ctx, { - publicId: "lineupLink:remaining-link", - strategyId: strategy._id, - pageId: pageBId, - payloadKind: "lineupLink", - payloadVersion: 1, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: "remaining-link", - originId: "origin", - landingId: "landing", - images: [{ id: "still-used-by-link", fileExtension: ".png" }], - }, - }, - sortIndex: 1, - revision: 1, - deleted: false, - createdAt: now, - updatedAt: now, - }); await insertElement(ctx, { publicId: "remaining-image-element", strategyId: strategy._id, diff --git a/convex/lib/cloudProtocol.ts b/convex/lib/cloudProtocol.ts index a820eea8..410181be 100644 --- a/convex/lib/cloudProtocol.ts +++ b/convex/lib/cloudProtocol.ts @@ -8,7 +8,12 @@ import { v } from "convex/values"; // public query that returns element or lineup payloads, and the shell the // editor opens with, takes the protocol too: a client that cannot read a // row must not see one. -export const CURRENT_CLOUD_PROTOCOL_VERSION = 4; +// 5: one row per lineup group, of kind "lineups": the lineups on a page +// joined through shared spots, with their origins, landings and links, +// replacing the origin, landing and link rows of 4. A client on 4 cannot +// read the new rows and writes rows the server no longer takes, so it is +// refused until it reloads into 5. +export const CURRENT_CLOUD_PROTOCOL_VERSION = 5; export const MAX_CLOUD_OPERATION_BYTES = 900 * 1024; export const MAX_CLOUD_ARRAY_ENTRIES = 8_000; export const CLOUD_OPERATION_TOO_LARGE_MESSAGE = diff --git a/convex/lib/errors.ts b/convex/lib/errors.ts index 534b9299..8d3897f4 100644 --- a/convex/lib/errors.ts +++ b/convex/lib/errors.ts @@ -18,8 +18,6 @@ export const errorCodes = [ "INVALID_PAYLOAD", "INVITE_EXPIRED", "INVITE_REVOKED", - "LINEUP_END_IN_USE", - "LINEUP_LINK_END_MISSING", "LINEUP_PAGE_MISMATCH", "LINEUP_STRATEGY_MISMATCH", "MISSING_ADD_ELEMENT_ARGS", diff --git a/convex/lib/imageAssets.ts b/convex/lib/imageAssets.ts index ed233310..38ad835a 100644 --- a/convex/lib/imageAssets.ts +++ b/convex/lib/imageAssets.ts @@ -52,40 +52,30 @@ export function collectAssetIdFromElementPayload( return typeof payload.data.id === "string" ? payload.data.id : null; } +/// The images a lineup group shows: links[*].images[*].id, across every +/// lineup in it. Its origins and landings hold none. export function collectAssetIdsFromLineupPayload( payload: Doc<"lineups">["payload"], ): Set { const assetIds = new Set(); - - const addImages = (rawImages: unknown) => { - if (!Array.isArray(rawImages)) { - return; - } - for (const image of rawImages) { - if ( - typeof image === "object" && - image !== null && - typeof (image as { id?: unknown }).id === "string" - ) { - assetIds.add((image as { id: string }).id); + const links = payload.data.links; + if (!Array.isArray(links)) return assetIds; + for (const link of links) { + const images = isObject(link) ? link.images : undefined; + if (!Array.isArray(images)) continue; + for (const image of images) { + if (isObject(image) && typeof image.id === "string") { + assetIds.add(image.id); } } - }; - - switch (payload.kind) { - case "lineupLink": - // A link holds its images: data.images[*].id. Origins and landings - // hold none. - addImages(payload.data.images); - break; - case "lineupOrigin": - case "lineupLanding": - break; } - return assetIds; } +function isObject(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + export function collectReferencedAssetIds( elements: Doc<"elements">[], lineups: Doc<"lineups">[], diff --git a/convex/lib/lineupItems.ts b/convex/lib/lineupItems.ts new file mode 100644 index 00000000..43cdee40 --- /dev/null +++ b/convex/lib/lineupItems.ts @@ -0,0 +1,95 @@ +import type { Doc, Id } from "../_generated/dataModel"; +import type { MutationCtx } from "../_generated/server"; +import { errorWithCode } from "./errors"; + +type LineupPayload = Doc<"lineups">["payload"]; + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +/// The lineups and spots a lineup group row holds, each kind of id in its +/// own namespace (a landing may share its lineup's id). +export function lineupGroupItems(payload: LineupPayload): Set { + const items = new Set(); + for (const [field, kind] of [ + ["origins", "origin"], + ["landings", "landing"], + ["links", "link"], + ] as const) { + const entries = payload.data[field]; + if (!Array.isArray(entries)) continue; + for (const entry of entries) { + if (isRecord(entry) && typeof entry.id === "string") { + items.add(`${kind}:${entry.id}`); + } + } + } + return items; +} + +/// Brings the lineupItems rows of one lineup group in step with it: one per +/// lineup and spot while the group is live, none otherwise. Call after every +/// write of a lineup row, with null once the row itself is gone. +export async function syncLineupItems( + ctx: MutationCtx, + lineupId: Id<"lineups">, + lineup: Pick, "pageId" | "deleted" | "payload"> | null, +): Promise { + const existing = await ctx.db + .query("lineupItems") + .withIndex("by_lineupId", (q) => q.eq("lineupId", lineupId)) + .collect(); + const wanted = + lineup === null || lineup.deleted + ? new Set() + : lineupGroupItems(lineup.payload); + for (const row of existing) { + if (lineup !== null && wanted.delete(row.item)) { + if (row.pageId !== lineup.pageId) { + await ctx.db.patch(row._id, { pageId: lineup.pageId }); + } + continue; + } + // An item the group no longer holds, a second row for one, or a row + // that is gone. + await ctx.db.delete(row._id); + } + if (lineup === null) return; + for (const item of wanted) { + await ctx.db.insert("lineupItems", { + pageId: lineup.pageId, + lineupId, + item, + }); + } +} + +/// Refuses a lineup group row ([lineupId], or a row about to be inserted +/// when null) that would hold a lineup or spot another live row of its page +/// holds. Clients never write one: a lineup stays in its group, and a new +/// one is aimed at one existing spot at most. Two rows sharing one would +/// each carry their own copy of it, which can drift apart, so the write +/// fails loudly instead. Reads only the small lineupItems rows, never the +/// lineup rows, whose image lists can be large. +export async function assertLineupGroupAlone( + ctx: MutationCtx, + pageId: Id<"pages">, + lineupId: Id<"lineups"> | null, + payload: LineupPayload, +): Promise { + for (const item of lineupGroupItems(payload)) { + const holders = await ctx.db + .query("lineupItems") + .withIndex("by_pageId_and_item", (q) => + q.eq("pageId", pageId).eq("item", item), + ) + .take(2); + if (holders.some((holder) => holder.lineupId !== lineupId)) { + throw errorWithCode( + "INVALID_LINEUP_PAYLOAD_DATA", + "A lineup or spot in this group is already in another group", + ); + } + } +} diff --git a/convex/lib/opTypes.ts b/convex/lib/opTypes.ts index 6f1b7c76..53e1edc5 100644 --- a/convex/lib/opTypes.ts +++ b/convex/lib/opTypes.ts @@ -1,6 +1,7 @@ import { v, type Infer } from "convex/values"; import { elementPayloadValidator, + lineupOpPayloadValidator, lineupPayloadValidator, mapThemePaletteValidator, pagePayloadValidator, @@ -97,7 +98,7 @@ const lineupAddOpValidator = v.object({ type: v.literal("lineup.add"), lineupPublicId: v.string(), pagePublicId: v.string(), - payload: lineupPayloadValidator, + payload: lineupOpPayloadValidator, sortIndex: v.number(), expectedLineupRevision: v.optional(v.number()), }); @@ -107,7 +108,7 @@ const lineupPatchOpValidator = v.object({ type: v.literal("lineup.patch"), lineupPublicId: v.string(), pagePublicId: v.optional(v.string()), - payload: v.optional(lineupPayloadValidator), + payload: v.optional(lineupOpPayloadValidator), sortIndex: v.optional(v.number()), expectedLineupRevision: v.number(), }); @@ -150,6 +151,9 @@ export type StrategyOp = Infer; export const opRejectionReasonValidator = v.union( v.literal("already_exists"), + // A patch or reorder of a row a teammate deleted: only an add with the + // tombstone's revision brings it back. + v.literal("deleted"), v.literal("element_strategy_mismatch"), v.literal("lineup_strategy_mismatch"), v.literal("missing_expected_revision"), diff --git a/convex/lib/payloadValidators.ts b/convex/lib/payloadValidators.ts index c92efdcc..17f0b112 100644 --- a/convex/lib/payloadValidators.ts +++ b/convex/lib/payloadValidators.ts @@ -114,16 +114,29 @@ export const elementPayloadValidator = v.union( }), ); -// A page's lineups are a graph, stored one row per entity: an origin (the -// agent), a landing (the ability) and a link between them (name, video, -// notes, images). Several links may share one landing. -export const lineupPayloadKindValidator = v.union( - v.literal("lineupOrigin"), - v.literal("lineupLanding"), - v.literal("lineupLink"), -); +// A lineup group is one row: the lineups on one page joined through shared +// spots, with each spot stored once. data holds the group's id (the row's +// key) and its origins (each placing an agent), landings (each placing an +// ability) and links (one per lineup: which origin to which landing, and its +// name, video, notes and images). See assertLineupPayload in ops.ts for the +// rules a row must meet. +export const lineupPayloadKindValidator = v.literal("lineups"); +export const LINEUPS_PAYLOAD_VERSION = 1; + +export const lineupPayloadValidator = v.object({ + kind: v.literal("lineups"), + payloadVersion: v.number(), + data: cloudJsonObjectValidator, +}); -export const lineupPayloadValidator = v.union( +// What a lineup op may carry as an argument: a lineup group, or a row of the +// graph clients on protocol 4 wrote. Convex checks arguments before +// the handler runs, so refusing the old kinds here would answer an old +// client with a validation error instead of CLIENT_UPGRADE_REQUIRED from the +// protocol gate. The handler refuses them (see assertLineupPayload in +// ops.ts) and storage takes only lineup groups. +export const lineupOpPayloadValidator = v.union( + lineupPayloadValidator, v.object({ kind: v.literal("lineupOrigin"), payloadVersion: v.number(), diff --git a/convex/lib/strategyAgentSummary.ts b/convex/lib/strategyAgentSummary.ts index 05f12457..097f1245 100644 --- a/convex/lib/strategyAgentSummary.ts +++ b/convex/lib/strategyAgentSummary.ts @@ -1,46 +1,113 @@ import type { Doc, Id } from "../_generated/dataModel"; import type { MutationCtx, QueryCtx } from "../_generated/server"; +import type { WithoutSystemFields } from "convex/server"; -/// Reads the agent type of one agent element or lineup payload. The client -/// stores the agent enum name under `type` (an element) or under -/// `agent.type` (a lineup origin); anything else, -/// landings and links included, is not an agent. +function asRecord(value: unknown): Record | null { + return typeof value === "object" && value !== null + ? (value as Record) + : null; +} + +/// Reads the agent type the client stores as the enum name under `type`, as +/// an agent element's data and a lineup origin's agent both do. function agentTypeOf(data: unknown): string | null { - if (typeof data !== "object" || data === null) return null; - const record = data as Record; - const direct = record.type; - if (typeof direct === "string" && direct.length > 0) return direct; - const agent = record.agent; - if (typeof agent === "object" && agent !== null) { - const nested = (agent as Record).type; - if (typeof nested === "string" && nested.length > 0) return nested; + const type = asRecord(data)?.type; + return typeof type === "string" && type.length > 0 ? type : null; +} + +/// The agents a lineup group starts from: each origin's id and agent type, +/// skipping an origin whose agent names no type. +export function lineupAgentsOf( + payload: Doc<"lineups">["payload"], +): { originId: string; agentType: string }[] { + const origins = payload.data.origins; + if (!Array.isArray(origins)) return []; + const agents: { originId: string; agentType: string }[] = []; + for (const origin of origins) { + const record = asRecord(origin); + const agentType = agentTypeOf(record?.agent); + if (record === null || typeof record.id !== "string" || agentType === null) { + continue; + } + agents.push({ originId: record.id, agentType }); + } + return agents; +} + +type LineupAgent = Pick< + Doc<"lineupAgents">, + "pageId" | "originId" | "agentType" +>; + +/// Brings the lineupAgents rows of one lineup group in step with it: one +/// row per origin while the group is live, none otherwise. Call after every +/// write of a lineup row, with null once the row itself is gone. +export async function syncLineupAgents( + ctx: MutationCtx, + lineupId: Id<"lineups">, + lineup: Pick< + Doc<"lineups">, + "strategyId" | "pageId" | "deleted" | "payload" + > | null, +): Promise { + const existing = await ctx.db + .query("lineupAgents") + .withIndex("by_lineupId", (q) => q.eq("lineupId", lineupId)) + .collect(); + // Keyed by origin id, which is unique within a group. + const wanted = new Map>>(); + if (lineup !== null && !lineup.deleted) { + for (const agent of lineupAgentsOf(lineup.payload)) { + wanted.set(agent.originId, { + strategyId: lineup.strategyId, + pageId: lineup.pageId, + lineupId, + ...agent, + }); + } + } + for (const row of existing) { + const want = wanted.get(row.originId); + if (want === undefined) { + // An origin the group no longer holds, or a second row for one. + await ctx.db.delete(row._id); + continue; + } + wanted.delete(row.originId); + if ( + row.strategyId !== want.strategyId || + row.pageId !== want.pageId || + row.agentType !== want.agentType + ) { + await ctx.db.patch(row._id, want); + } + } + for (const row of wanted.values()) { + await ctx.db.insert("lineupAgents", row); } - return null; } /// Recomputes which agents a strategy uses, from its live agent elements and -/// lineup origins on pages not in the trash, and stores the answer in its -/// own row. Content ops never -/// touch the strategy row itself; the summary is derived data that the -/// folder tree reads without scanning elements. +/// the origins of its live lineups on pages not in the trash, and stores the +/// answer in its own row. Content ops never touch the strategy row itself; +/// the summary is derived data that the folder tree reads without scanning +/// elements. export async function refreshStrategyAgentSummary( ctx: MutationCtx, strategyId: Id<"strategies">, ): Promise { - // Only agent elements and lineup origins carry an agent; reading just - // those keeps this cheap however large the strategy's other content is - // (it runs after every batch of content ops). + // Agent elements are small. Lineups are read through their lineupAgents + // rows, never the lineup rows themselves: those carry image lists and + // could take a strategy's reads past a transaction's limits. const agents = await ctx.db .query("elements") .withIndex("by_strategyId_and_elementType", (q) => q.eq("strategyId", strategyId).eq("elementType", "agent"), ) .collect(); - const origins = await ctx.db - .query("lineups") - .withIndex("by_strategyId_and_payloadKind", (q) => - q.eq("strategyId", strategyId).eq("payloadKind", "lineupOrigin"), - ) + const lineupAgents = await ctx.db + .query("lineupAgents") + .withIndex("by_strategyId", (q) => q.eq("strategyId", strategyId)) .collect(); const trashedPageIds = new Set( ( @@ -57,15 +124,16 @@ export async function refreshStrategyAgentSummary( await storeStrategyAgentSummary( ctx, strategyId, - agentTypesOf(agents.filter(onLivePage), origins.filter(onLivePage)), + agentTypesOf(agents.filter(onLivePage), lineupAgents.filter(onLivePage)), ); } /// The agents that live content uses, most used first. Takes any elements -/// and lineup rows; only live agent elements and lineup origins count. +/// and the agents of live lineup groups; live agent elements count, and +/// each lineup origin once per page, however many lineups share it. export function agentTypesOf( elements: Pick, "deleted" | "elementType" | "payload">[], - lineups: Pick, "deleted" | "payloadKind" | "payload">[], + lineupAgents: LineupAgent[], ): string[] { const counts = new Map(); const bump = (type: string | null) => { @@ -76,9 +144,12 @@ export function agentTypesOf( if (element.deleted || element.elementType !== "agent") continue; bump(agentTypeOf(element.payload.data)); } - for (const lineup of lineups) { - if (lineup.deleted || lineup.payloadKind !== "lineupOrigin") continue; - bump(agentTypeOf(lineup.payload.data)); + const countedOrigins = new Set(); + for (const { pageId, originId, agentType } of lineupAgents) { + const originKey = `${pageId}:${originId}`; + if (countedOrigins.has(originKey)) continue; + countedOrigins.add(originKey); + bump(agentType); } return [...counts.entries()] .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])) diff --git a/convex/lineupGraph.test.ts b/convex/lineupGraph.test.ts deleted file mode 100644 index 37d82c18..00000000 --- a/convex/lineupGraph.test.ts +++ /dev/null @@ -1,1014 +0,0 @@ -import { - convexTest, - type TestConvexForDataModel, - type TestConvexForDataModelAndIdentity, -} from "convex-test"; -import { makeFunctionReference } from "convex/server"; -import { beforeAll, describe, expect, test } from "vitest"; -import type { DataModel } from "./_generated/dataModel"; -import { CURRENT_CLOUD_PROTOCOL_VERSION } from "./lib/cloudProtocol"; -import schema from "./schema"; -import { modules } from "./test.setup"; - -const ensureCurrentUser = makeFunctionReference<"mutation">( - "users:ensureCurrentUser", -); -const createStrategy = makeFunctionReference<"mutation">( - "strategies:createWithInitialPage", -); -const createShare = makeFunctionReference<"mutation">("shares:create"); -const redeemShare = makeFunctionReference<"mutation">("shares:redeem"); -const addPage = makeFunctionReference<"mutation">("pages:add"); -const applyBatch = makeFunctionReference<"mutation">("ops:applyBatch"); -const getPageSnapshot = makeFunctionReference<"query">("page:getSnapshot"); -const getFullSnapshot = makeFunctionReference<"query">( - "strategy:getFullSnapshot", -); - -type Harness = TestConvexForDataModel; -type RootHarness = TestConvexForDataModelAndIdentity; -type Result = Record; -type LineupRow = { - publicId: string; - payload: { kind: string; data: Record }; - revision: number; - deleted: boolean; -}; - -const strategyPublicId = "lineup-graph-strategy"; -const pagePublicId = "lineup-graph-page"; - -function identity(subject: string) { - return { - issuer: "https://lineup-graph.test", - subject, - tokenIdentifier: `lineup-graph|${subject}`, - name: subject, - }; -} - -async function createHarness(): Promise<{ - t: RootHarness; - owner: Harness; - editor: Harness; - viewer: Harness; -}> { - const t = convexTest(schema, modules); - const owner = t.withIdentity(identity("owner")); - const editor = t.withIdentity(identity("editor")); - const viewer = t.withIdentity(identity("viewer")); - for (const user of [owner, editor, viewer]) { - await user.mutation(ensureCurrentUser, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - }); - } - await owner.mutation(createStrategy, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - publicId: strategyPublicId, - name: "Lineup graph", - mapData: "ascent", - initialPagePublicId: pagePublicId, - initialPageName: "Page 1", - initialPageIsAttack: true, - }); - for (const [user, role] of [ - [editor, "editor"], - [viewer, "viewer"], - ] as const) { - await owner.mutation(createShare, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - targetType: "strategy", - targetPublicId: strategyPublicId, - token: `${role}-token`, - role, - }); - await user.mutation(redeemShare, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - token: `${role}-token`, - }); - } - return { t, owner, editor, viewer }; -} - -function origin(id: string, agentType = "sova") { - return { - key: `lineupOrigin:${id}`, - payload: { - kind: "lineupOrigin" as const, - payloadVersion: 1, - data: { id, agent: { id: `agent-${id}`, type: agentType, lineUpID: id } }, - }, - }; -} - -function landing(id: string) { - return { - key: `lineupLanding:${id}`, - payload: { - kind: "lineupLanding" as const, - payloadVersion: 1, - data: { id, ability: { id: `ability-${id}`, lineUpID: id } }, - }, - }; -} - -function link( - id: string, - originId: string, - landingId: string, - details: Record = {}, -) { - return { - key: `lineupLink:${id}`, - payload: { - kind: "lineupLink" as const, - payloadVersion: 1, - data: { - id, - originId, - landingId, - name: "", - youtubeLink: "", - notes: "", - images: [], - ...details, - }, - }, - }; -} - -type Row = ReturnType; - -function addOp(row: Row, sortIndex: number, page = pagePublicId) { - return { - opId: `add-${row.key}`, - type: "lineup.add", - lineupPublicId: row.key, - pagePublicId: page, - payload: row.payload, - sortIndex, - }; -} - -function patchOp(opId: string, row: Row, expectedLineupRevision: number) { - return { - opId, - type: "lineup.patch", - lineupPublicId: row.key, - pagePublicId, - payload: row.payload, - expectedLineupRevision, - }; -} - -async function apply( - user: Harness, - clientId: string, - ops: Array>, - strategy = strategyPublicId, - checks: { - checkLineupLinkEnds?: boolean; - checkLineupEndDeletes?: boolean; - } = {}, -): Promise { - const response = (await user.mutation(applyBatch, { - strategyPublicId: strategy, - clientId, - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - ops, - ...checks, - })) as { results: Result[] }; - return response.results; -} - -/** - * [apply] as a current client sends it: link ends are checked, and so are - * deletes of an end a live link names. - */ -async function applyChecked( - user: Harness, - clientId: string, - ops: Array>, -): Promise { - return await apply(user, clientId, ops, strategyPublicId, { - checkLineupLinkEnds: true, - checkLineupEndDeletes: true, - }); -} - -async function pageLineups( - user: Harness, - strategy = strategyPublicId, - page = pagePublicId, -): Promise { - const snapshot = (await user.query(getPageSnapshot, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - strategyPublicId: strategy, - pagePublicId: page, - })) as { lineups: LineupRow[] }; - return snapshot.lineups; -} - -/** A second strategy owned by [owner], with one page. */ -async function createCopy(owner: Harness, publicId: string, page: string) { - await owner.mutation(createStrategy, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - publicId, - name: "Copy", - mapData: "ascent", - initialPagePublicId: page, - initialPageName: "Page 1", - initialPageIsAttack: true, - }); -} - -function byKey(rows: LineupRow[]): Map { - return new Map(rows.map((row) => [row.publicId, row])); -} - -beforeAll(() => { - // Page snapshots serialize asset URLs from the R2 public base. - process.env.R2_ACCOUNT_ID = "lineup-graph-account"; - process.env.R2_BUCKET = "lineup-graph-bucket"; - process.env.R2_ACCESS_KEY_ID = "lineup-graph-access-key"; - process.env.R2_SECRET_ACCESS_KEY = "lineup-graph-secret"; - process.env.R2_PUBLIC_BASE_URL = "https://assets.lineup-graph.test"; - process.env.R2_S3_ENDPOINT = "https://lineup-graph.r2.test"; -}); - -/** Two origins aiming at one shared landing, each link named. */ -const fanIn = [ - origin("origin-a"), - origin("origin-b"), - landing("shared"), - link("link-a", "origin-a", "shared", { name: "From heaven" }), - link("link-b", "origin-b", "shared", { name: "From mid" }), -]; - -describe("lineup graph rows", () => { - test("a fan-in lineup round-trips with its shared landing and link names", async () => { - const { owner } = await createHarness(); - const results = await apply( - owner, - "owner-client", - fanIn.map((row, index) => addOp(row, index)), - ); - expect(results.map((result) => result.status)).toEqual( - fanIn.map(() => "applied"), - ); - - const rows = await pageLineups(owner); - expect(rows.map((row) => row.payload.kind)).toEqual([ - "lineupOrigin", - "lineupOrigin", - "lineupLanding", - "lineupLink", - "lineupLink", - ]); - const links = rows.filter((row) => row.payload.kind === "lineupLink"); - expect(links.map((row) => row.payload.data)).toEqual([ - expect.objectContaining({ - originId: "origin-a", - landingId: "shared", - name: "From heaven", - }), - expect.objectContaining({ - originId: "origin-b", - landingId: "shared", - name: "From mid", - }), - ]); - const landings = rows.filter((row) => row.payload.kind === "lineupLanding"); - expect(landings).toHaveLength(1); - - const full = (await owner.query(getFullSnapshot, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - strategyPublicId, - })) as { lineups: LineupRow[] }; - expect(full.lineups.map((row) => row.publicId)).toEqual( - fanIn.map((row) => row.key), - ); - }); - - test("a landing and a link may share an entity id", async () => { - const { owner } = await createHarness(); - const rows = [ - origin("o"), - landing("same-id"), - link("same-id", "o", "same-id"), - ]; - const results = await apply( - owner, - "owner-client", - rows.map((row, index) => addOp(row, index)), - ); - expect(results.map((result) => result.status)).toEqual([ - "applied", - "applied", - "applied", - ]); - expect((await pageLineups(owner)).map((row) => row.publicId)).toEqual([ - "lineupOrigin:o", - "lineupLanding:same-id", - "lineupLink:same-id", - ]); - }); - - test("two users editing different links of one origin both land", async () => { - const { owner, editor } = await createHarness(); - const rows = [ - origin("o"), - landing("l1"), - landing("l2"), - link("k1", "o", "l1"), - link("k2", "o", "l2"), - ]; - await apply( - owner, - "owner-client", - rows.map((row, index) => addOp(row, index)), - ); - - // Both edit from the same loaded revision (1) of their own link. - const ownerResults = await apply(owner, "owner-client", [ - patchOp("owner-renames-k1", link("k1", "o", "l1", { name: "Owner" }), 1), - ]); - const editorResults = await apply(editor, "editor-client", [ - patchOp( - "editor-notes-k2", - link("k2", "o", "l2", { notes: "Editor notes" }), - 1, - ), - ]); - expect(ownerResults[0]).toMatchObject({ - status: "applied", - appliedRevision: 2, - }); - expect(editorResults[0]).toMatchObject({ - status: "applied", - appliedRevision: 2, - }); - - const after = byKey(await pageLineups(owner)); - expect(after.get("lineupLink:k1")?.payload.data).toMatchObject({ - name: "Owner", - notes: "", - }); - expect(after.get("lineupLink:k2")?.payload.data).toMatchObject({ - name: "", - notes: "Editor notes", - }); - // Neither edit touched the origin or the other link's revision. - expect(after.get("lineupOrigin:o")?.revision).toBe(1); - - // The same link edited from a stale revision is a conflict, not a - // silent overwrite. - const stale = await apply(editor, "editor-client", [ - patchOp("editor-renames-k1", link("k1", "o", "l1", { name: "Stale" }), 1), - ]); - expect(stale[0]).toMatchObject({ - status: "rejected", - reason: "revision_mismatch", - current: { type: "lineup", revision: 2 }, - }); - }); - - test("deleting one link leaves the shared landing and the other link", async () => { - const { owner } = await createHarness(); - await apply( - owner, - "owner-client", - fanIn.map((row, index) => addOp(row, index)), - ); - const results = await apply(owner, "owner-client", [ - { - opId: "delete-link-a", - type: "lineup.delete", - lineupPublicId: "lineupLink:link-a", - pagePublicId, - expectedLineupRevision: 1, - }, - { - opId: "delete-origin-a", - type: "lineup.delete", - lineupPublicId: "lineupOrigin:origin-a", - pagePublicId, - expectedLineupRevision: 1, - }, - ]); - expect(results.map((result) => result.status)).toEqual([ - "applied", - "applied", - ]); - const live = (await pageLineups(owner)) - .filter((row) => !row.deleted) - .map((row) => row.publicId); - expect(live).toEqual([ - "lineupOrigin:origin-b", - "lineupLanding:shared", - "lineupLink:link-b", - ]); - }); - - test("graph rows that could not be drawn are refused", async () => { - const { owner } = await createHarness(); - const mismatchedKey = { - ...addOp(link("k", "o", "l"), 0), - lineupPublicId: "lineupLink:other", - }; - const unqualifiedKey = { ...addOp(origin("o"), 0), lineupPublicId: "o" }; - const originWithoutAgent = { - ...addOp(origin("o2"), 0), - payload: { kind: "lineupOrigin", payloadVersion: 1, data: { id: "o2" } }, - }; - const linkWithoutLanding = { - ...addOp(link("k2", "o", "l"), 0), - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { id: "k2", originId: "o" }, - }, - }; - const results = await apply(owner, "owner-client", [ - mismatchedKey, - unqualifiedKey, - originWithoutAgent, - linkWithoutLanding, - ]); - for (const result of results) { - expect(result).toMatchObject({ - status: "failed", - code: "INVALID_LINEUP_PAYLOAD_DATA", - }); - } - expect(await pageLineups(owner)).toEqual([]); - }); - - test("a viewer cannot write lineup rows", async () => { - const { owner, viewer } = await createHarness(); - await apply(owner, "owner-client", [addOp(origin("o"), 0)]); - await expect( - apply(viewer, "viewer-client", [addOp(landing("l"), 1)]), - ).rejects.toThrow("Forbidden"); - await expect( - apply(viewer, "viewer-client", [ - patchOp("viewer-moves-origin", origin("o", "jett"), 1), - ]), - ).rejects.toThrow("Forbidden"); - // Viewers still read them. - expect((await pageLineups(viewer)).map((row) => row.publicId)).toEqual([ - "lineupOrigin:o", - ]); - }); - - test("images on a link are referenced assets of the page", async () => { - const { t, owner } = await createHarness(); - await t.run(async (ctx) => { - const strategy = await ctx.db - .query("strategies") - .withIndex("by_publicId", (q) => q.eq("publicId", strategyPublicId)) - .first(); - const now = Date.now(); - await ctx.db.insert("imageAssets", { - publicId: "link-image", - provider: "r2", - strategyId: strategy!._id, - objectKey: "tests/link-image.png", - uploadStatus: "active", - fileExtension: ".png", - createdAt: now, - updatedAt: now, - }); - }); - await apply(owner, "owner-client", [ - addOp(origin("o"), 0), - addOp(landing("l"), 1), - addOp( - link("k", "o", "l", { - images: [{ id: "link-image", fileExtension: ".png" }], - }), - 2, - ), - ]); - const snapshot = (await owner.query(getPageSnapshot, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - strategyPublicId, - pagePublicId, - })) as { assets: Array<{ publicId: string }> }; - expect(snapshot.assets.map((asset) => asset.publicId)).toEqual([ - "link-image", - ]); - }); -}); - -describe("lineup row keys belong to their strategy", () => { - /** A legacy group as a client wrote it before the graph synced. */ - test("strategies uploaded from a local duplicate keep the same row keys", async () => { - const { owner } = await createHarness(); - const copyId = "local-duplicate"; - const copyPage = "local-duplicate-page"; - await createCopy(owner, copyId, copyPage); - // A strategy duplicated on the device keeps every lineup id; each upload - // keeps them too (ids only need to be unique within a strategy). - for (const [strategy, page] of [ - [strategyPublicId, pagePublicId], - [copyId, copyPage], - ] as const) { - const results = await apply( - owner, - `upload-${strategy}`, - fanIn.map((row, index) => addOp(row, index, page)), - strategy, - ); - expect(results.map((result) => result.status)).toEqual( - fanIn.map(() => "applied"), - ); - } - // Editing one copy leaves the other untouched. - await apply( - owner, - "edit-copy", - [ - { - ...patchOp( - "rename-in-copy", - link("link-a", "origin-a", "shared", { name: "Copy name" }), - 1, - ), - pagePublicId: copyPage, - }, - ], - copyId, - ); - const original = byKey(await pageLineups(owner)); - const copy = byKey(await pageLineups(owner, copyId, copyPage)); - expect(original.get("lineupLink:link-a")?.payload.data.name).toBe( - "From heaven", - ); - expect(copy.get("lineupLink:link-a")?.payload.data.name).toBe("Copy name"); - }); - - test("a lineup row is never moved to another page by a patch", async () => { - const { owner } = await createHarness(); - const secondPage = "lineup-graph-page-2"; - await owner.mutation(addPage, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - strategyPublicId, - expectedRevision: 0, - pagePublicId: secondPage, - name: "Page 2", - sortIndex: 1, - isAttack: false, - }); - await apply(owner, "page-1-client", [addOp(link("k", "o", "l"), 0)]); - - // Another page wants the same key: the add is refused, and "Keep mine" - // would turn it into a patch naming the other page. - const clashing = link("k", "o2", "l2", { name: "Page 2 lineup" }); - const added = await apply(owner, "page-2-client", [ - addOp(clashing, 0, secondPage), - ]); - expect(added[0]).toMatchObject({ - status: "rejected", - reason: "already_exists", - }); - const moved = await apply(owner, "page-2-client", [ - { ...patchOp("keep-mine", clashing, 1), pagePublicId: secondPage }, - ]); - expect(moved[0]).toMatchObject({ - status: "failed", - code: "LINEUP_PAGE_MISMATCH", - }); - - // The row stays on its page, untouched. - const first = await pageLineups(owner); - expect(first.map((row) => row.publicId)).toEqual(["lineupLink:k"]); - expect(first[0]!.payload.data).toMatchObject({ originId: "o" }); - expect(await pageLineups(owner, strategyPublicId, secondPage)).toEqual([]); - }); - - test("the same row added twice with a different order is one add", async () => { - const { owner, editor } = await createHarness(); - const first = await apply(owner, "owner-client", [addOp(origin("o"), 3)]); - const second = await apply(editor, "editor-client", [addOp(origin("o"), 7)]); - expect(first[0]).toMatchObject({ status: "applied" }); - expect(second[0]).toMatchObject({ status: "noop" }); - const conflicting = await apply(editor, "editor-client", [ - { ...addOp(origin("o", "jett"), 7), opId: "different-content" }, - ]); - expect(conflicting[0]).toMatchObject({ - status: "rejected", - reason: "already_exists", - }); - }); -}); - -function deleteOp(opId: string, key: string, expectedLineupRevision: number) { - return { - opId, - type: "lineup.delete", - lineupPublicId: key, - pagePublicId, - expectedLineupRevision, - }; -} - -describe("a link needs both of its ends", () => { - test("a link placed from an origin a teammate deleted is refused", async () => { - const { owner, editor } = await createHarness(); - await apply( - owner, - "owner-client", - [origin("a"), landing("a"), link("a", "a", "a")].map((row, index) => - addOp(row, index), - ), - ); - // The editor deletes lineup "a" while the owner is placing a new - // lineup from its origin. - await apply(editor, "editor-client", [ - deleteOp("delete-link-a", "lineupLink:a", 1), - deleteOp("delete-landing-a", "lineupLanding:a", 1), - deleteOp("delete-origin-a", "lineupOrigin:a", 1), - ]); - - // The owner's client still had origin "a" as its base, so it sends only - // the new landing and link. - const results = await applyChecked(owner, "owner-client", [ - addOp(landing("b"), 3), - addOp(link("b", "a", "b"), 4), - ]); - expect(results[0]).toMatchObject({ status: "applied" }); - expect(results[1]).toMatchObject({ - status: "failed", - code: "LINEUP_LINK_END_MISSING", - }); - const rows = byKey(await pageLineups(owner)); - expect(rows.has("lineupLink:b")).toBe(false); - }); - - test("an older client's link a batch ahead of its origin still lands", async () => { - const { owner } = await createHarness(); - // An outbox reloaded after a restart lists its rows by key (landing, - // link, origin) and may cut the batch before the origin. - const first = await apply(owner, "old-client", [ - addOp(landing("l"), 0), - addOp(link("k", "o", "l"), 1), - ]); - const second = await apply(owner, "old-client", [addOp(origin("o"), 2)]); - expect([...first, ...second].map((result) => result.status)).toEqual([ - "applied", - "applied", - "applied", - ]); - // The same batch from a current client is refused. - const checked = await applyChecked(owner, "new-client", [ - addOp(link("k2", "o2", "l"), 3), - ]); - expect(checked[0]).toMatchObject({ - status: "failed", - code: "LINEUP_LINK_END_MISSING", - }); - }); - - test("an origin restored earlier in the same batch lets the link land", async () => { - const { owner, editor } = await createHarness(); - await apply( - owner, - "owner-client", - [origin("a"), landing("a"), link("a", "a", "a")].map((row, index) => - addOp(row, index), - ), - ); - await apply(editor, "editor-client", [ - deleteOp("delete-link-a", "lineupLink:a", 1), - deleteOp("delete-landing-a", "lineupLanding:a", 1), - deleteOp("delete-origin-a", "lineupOrigin:a", 1), - ]); - - const results = await applyChecked(owner, "owner-client", [ - { - ...addOp(origin("a"), 0), - opId: "restore-origin-a", - expectedLineupRevision: 2, - }, - addOp(landing("b"), 3), - addOp(link("b", "a", "b"), 4), - ]); - expect(results.map((result) => result.status)).toEqual([ - "applied", - "applied", - "applied", - ]); - const live = (await pageLineups(owner)) - .filter((row) => !row.deleted) - .map((row) => row.publicId); - expect(live).toEqual([ - "lineupOrigin:a", - "lineupLanding:b", - "lineupLink:b", - ]); - }); - - test("editing a link whose landing a teammate deleted is refused", async () => { - const { owner, editor } = await createHarness(); - await apply( - owner, - "owner-client", - [origin("o"), landing("l"), link("k", "o", "l")].map((row, index) => - addOp(row, index), - ), - ); - await apply(editor, "editor-client", [ - deleteOp("delete-landing", "lineupLanding:l", 1), - ]); - - const results = await applyChecked(owner, "owner-client", [ - patchOp("rename-k", link("k", "o", "l", { name: "Renamed" }), 1), - ]); - expect(results[0]).toMatchObject({ - status: "failed", - code: "LINEUP_LINK_END_MISSING", - }); - const row = byKey(await pageLineups(owner)).get("lineupLink:k"); - expect(row).toMatchObject({ revision: 1 }); - expect(row!.payload.data).toMatchObject({ name: "" }); - }); - - test("a link cannot use an end that lives on another page", async () => { - const { owner } = await createHarness(); - const secondPage = "lineup-graph-page-2"; - await owner.mutation(addPage, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - strategyPublicId, - expectedRevision: 0, - pagePublicId: secondPage, - name: "Page 2", - sortIndex: 1, - isAttack: false, - }); - await apply(owner, "owner-client", [ - addOp(origin("o"), 0), - addOp(landing("l"), 1), - ]); - - const results = await applyChecked(owner, "owner-client", [ - addOp(link("k", "o", "l"), 0, secondPage), - ]); - expect(results[0]).toMatchObject({ - status: "failed", - code: "LINEUP_LINK_END_MISSING", - }); - }); - - test("a link already stored without its origin still loads and deletes", async () => { - const { t, owner } = await createHarness(); - // Written before the server checked link ends. - await t.run(async (ctx) => { - const strategy = await ctx.db - .query("strategies") - .withIndex("by_publicId", (q) => q.eq("publicId", strategyPublicId)) - .unique(); - const page = await ctx.db - .query("pages") - .withIndex("by_publicId", (q) => q.eq("publicId", pagePublicId)) - .unique(); - const orphan = link("orphan", "gone", "gone"); - const now = Date.now(); - await ctx.db.insert("lineups", { - publicId: orphan.key, - strategyId: strategy!._id, - pageId: page!._id, - payloadKind: orphan.payload.kind, - payloadVersion: orphan.payload.payloadVersion, - payload: orphan.payload, - sortIndex: 0, - revision: 1, - deleted: false, - createdAt: now, - updatedAt: now, - }); - }); - - expect((await pageLineups(owner)).map((row) => row.publicId)).toEqual([ - "lineupLink:orphan", - ]); - const full = (await owner.query(getFullSnapshot, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - strategyPublicId, - })) as { lineups: LineupRow[] }; - expect(full.lineups.map((row) => row.publicId)).toEqual([ - "lineupLink:orphan", - ]); - const results = await applyChecked(owner, "owner-client", [ - deleteOp("delete-orphan", "lineupLink:orphan", 1), - ]); - expect(results[0]).toMatchObject({ status: "applied" }); - }); -}); - -describe("an origin or landing a live link names is not deleted", () => { - test("deleting an origin a teammate's new link uses is refused", async () => { - const { owner, editor } = await createHarness(); - await apply( - owner, - "owner-client", - [origin("a"), landing("a"), link("a", "a", "a")].map((row, index) => - addOp(row, index), - ), - ); - // The owner places a second lineup from origin "a", and it lands first. - await applyChecked(owner, "owner-client", [ - addOp(landing("b"), 3), - addOp(link("b", "a", "b"), 4), - ]); - - // The editor never saw lineup "b" and deletes lineup "a", which on - // their canvas takes origin "a" with it. - const results = await applyChecked(editor, "editor-client", [ - deleteOp("delete-link-a", "lineupLink:a", 1), - deleteOp("delete-landing-a", "lineupLanding:a", 1), - deleteOp("delete-origin-a", "lineupOrigin:a", 1), - ]); - expect(results.map((result) => result.status)).toEqual([ - "applied", - "applied", - "failed", - ]); - expect(results[2]).toMatchObject({ code: "LINEUP_END_IN_USE" }); - - const rows = byKey(await pageLineups(owner)); - expect(rows.get("lineupOrigin:a")).toMatchObject({ - deleted: false, - revision: 1, - }); - expect(rows.get("lineupLink:b")).toMatchObject({ deleted: false }); - expect(rows.get("lineupLink:a")).toMatchObject({ deleted: true }); - }); - - test("deleting a landing a live link uses is refused", async () => { - const { owner, editor } = await createHarness(); - await apply( - owner, - "owner-client", - [origin("o"), landing("l"), link("k", "o", "l")].map((row, index) => - addOp(row, index), - ), - ); - const results = await applyChecked(editor, "editor-client", [ - deleteOp("delete-landing", "lineupLanding:l", 1), - ]); - expect(results[0]).toMatchObject({ - status: "failed", - code: "LINEUP_END_IN_USE", - }); - const rows = byKey(await pageLineups(owner)); - expect(rows.get("lineupLanding:l")).toMatchObject({ deleted: false }); - }); - - test("a whole lineup deletes when its link goes first", async () => { - const { owner } = await createHarness(); - await apply( - owner, - "owner-client", - [origin("o"), landing("l"), link("k", "o", "l")].map((row, index) => - addOp(row, index), - ), - ); - const results = await applyChecked(owner, "owner-client", [ - deleteOp("delete-link", "lineupLink:k", 1), - deleteOp("delete-origin", "lineupOrigin:o", 1), - deleteOp("delete-landing", "lineupLanding:l", 1), - ]); - expect(results.map((result) => result.status)).toEqual([ - "applied", - "applied", - "applied", - ]); - }); - - test("a link on another page does not hold an end", async () => { - const { owner } = await createHarness(); - const secondPage = "lineup-graph-page-2"; - await owner.mutation(addPage, { - clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, - strategyPublicId, - expectedRevision: 0, - pagePublicId: secondPage, - name: "Page 2", - sortIndex: 1, - isAttack: false, - }); - // A link on page 2 names origin "o", which lives on page 1. Hydration - // reads each page on its own, so that link is never drawn from it. - await apply(owner, "owner-client", [ - addOp(origin("o"), 0), - addOp(landing("l2"), 1, secondPage), - addOp(link("k2", "o", "l2"), 2, secondPage), - ]); - const results = await applyChecked(owner, "owner-client", [ - deleteOp("delete-origin", "lineupOrigin:o", 1), - ]); - expect(results[0]).toMatchObject({ status: "applied" }); - }); - - test("a batch sees its own link writes after reading the page", async () => { - const { owner } = await createHarness(); - await apply( - owner, - "owner-client", - [ - origin("o"), - landing("l"), - link("k", "o", "l"), - origin("o2"), - landing("l2"), - landing("spare"), - ].map((row, index) => addOp(row, index)), - ); - const results = await applyChecked(owner, "owner-client", [ - // No link names this landing; checking it reads the page's links. - deleteOp("delete-spare", "lineupLanding:spare", 1), - // A link added after that read holds its origin... - addOp(link("k2", "o2", "l2"), 6), - deleteOp("delete-origin-o2", "lineupOrigin:o2", 1), - // ...and a link deleted after it no longer holds its ends. - deleteOp("delete-link-k", "lineupLink:k", 1), - deleteOp("delete-origin-o", "lineupOrigin:o", 1), - deleteOp("delete-landing-l", "lineupLanding:l", 1), - ]); - expect(results.map((result) => result.status)).toEqual([ - "applied", - "applied", - "failed", - "applied", - "applied", - "applied", - ]); - expect(results[2]).toMatchObject({ code: "LINEUP_END_IN_USE" }); - }); - - test("a patch to a deleted link after reading the page holds nothing", async () => { - const { owner } = await createHarness(); - await apply( - owner, - "owner-client", - [origin("o"), landing("l"), link("k", "o", "l"), landing("spare")].map( - (row, index) => addOp(row, index), - ), - ); - await apply(owner, "owner-client", [ - deleteOp("delete-link-k", "lineupLink:k", 1), - ]); - const results = await applyChecked(owner, "owner-client", [ - deleteOp("delete-spare", "lineupLanding:spare", 1), - patchOp("patch-deleted-k", link("k", "o", "l", { name: "Late" }), 2), - deleteOp("delete-origin-o", "lineupOrigin:o", 1), - ]); - expect(results[0]).toMatchObject({ status: "applied" }); - expect(results[2]).toMatchObject({ status: "applied" }); - }); - - test("an older client's end delete still lands ahead of its link", async () => { - const { owner, editor } = await createHarness(); - await apply( - owner, - "owner-client", - [origin("o"), landing("l"), link("k", "o", "l")].map((row, index) => - addOp(row, index), - ), - ); - // An outbox reloaded after a restart lists its rows by key (landing, - // link, origin); an older client does not reorder them. - const unflagged = await apply(editor, "old-client", [ - deleteOp("delete-landing", "lineupLanding:l", 1), - deleteOp("delete-link", "lineupLink:k", 1), - deleteOp("delete-origin", "lineupOrigin:o", 1), - ]); - expect(unflagged.map((result) => result.status)).toEqual([ - "applied", - "applied", - "applied", - ]); - }); - - test("a client that only checks link ends is not refused a delete", async () => { - const { owner, editor } = await createHarness(); - await apply( - owner, - "owner-client", - [origin("o"), landing("l"), link("k", "o", "l")].map((row, index) => - addOp(row, index), - ), - ); - // The web build that shipped checkLineupLinkEnds did not order its - // deletes yet. - const results = await apply( - editor, - "web-client", - [deleteOp("delete-origin", "lineupOrigin:o", 1)], - strategyPublicId, - { checkLineupLinkEnds: true }, - ); - expect(results[0]).toMatchObject({ status: "applied" }); - }); -}); diff --git a/convex/lineups.test.ts b/convex/lineups.test.ts new file mode 100644 index 00000000..b37008fe --- /dev/null +++ b/convex/lineups.test.ts @@ -0,0 +1,1643 @@ +import { + convexTest, + type TestConvexForDataModel, + type TestConvexForDataModelAndIdentity, +} from "convex-test"; +import { makeFunctionReference } from "convex/server"; +import { afterEach, beforeAll, describe, expect, test, vi } from "vitest"; +import type { DataModel } from "./_generated/dataModel"; +import { markAssetReferencesReady } from "./lib/assetReferences"; +import { CURRENT_CLOUD_PROTOCOL_VERSION } from "./lib/cloudProtocol"; +import schema from "./schema"; +import { + insertLineup, + lineupsPayload, + oneLineupPayload, + type TestLineup, + type TestLineupGroup, +} from "./testContent.helpers"; +import { modules } from "./test.setup"; + +const ensureCurrentUser = makeFunctionReference<"mutation">( + "users:ensureCurrentUser", +); +const createStrategy = makeFunctionReference<"mutation">( + "strategies:createWithInitialPage", +); +const createShare = makeFunctionReference<"mutation">("shares:create"); +const redeemShare = makeFunctionReference<"mutation">("shares:redeem"); +const addPage = makeFunctionReference<"mutation">("pages:add"); +const applyBatch = makeFunctionReference<"mutation">("ops:applyBatch"); +const getPageSnapshot = makeFunctionReference<"query">("page:getSnapshot"); +const getFullSnapshot = makeFunctionReference<"query">( + "strategy:getFullSnapshot", +); +const listForStrategy = makeFunctionReference<"query">( + "lineups:listForStrategy", +); +const listReferencedAssetIds = makeFunctionReference<"query">( + "images:listReferencedAssetIds", +); +const duplicateStrategy = makeFunctionReference<"mutation">( + "strategies:duplicate", +); +const restorePage = makeFunctionReference<"mutation">("pages:restore"); +const purgeOldTombstones = makeFunctionReference<"mutation">( + "maintenance:purgeOldTombstones", +); + +type Harness = TestConvexForDataModel; +type RootHarness = TestConvexForDataModelAndIdentity; +type Result = Record; +type LineupRow = { + publicId: string; + payload: { kind: string; data: Record }; + revision: number; + deleted: boolean; +}; + +const strategyPublicId = "lineups-strategy"; +const pagePublicId = "lineups-page"; + +function identity(subject: string) { + return { + issuer: "https://lineups.test", + subject, + tokenIdentifier: `lineups|${subject}`, + name: subject, + }; +} + +async function createHarness(): Promise<{ + t: RootHarness; + owner: Harness; + editor: Harness; + viewer: Harness; +}> { + const t = convexTest(schema, modules); + const owner = t.withIdentity(identity("owner")); + const editor = t.withIdentity(identity("editor")); + const viewer = t.withIdentity(identity("viewer")); + for (const user of [owner, editor, viewer]) { + await user.mutation(ensureCurrentUser, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + }); + } + await owner.mutation(createStrategy, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + publicId: strategyPublicId, + name: "Lineups", + mapData: "ascent", + initialPagePublicId: pagePublicId, + initialPageName: "Page 1", + initialPageIsAttack: true, + }); + for (const [user, role] of [ + [editor, "editor"], + [viewer, "viewer"], + ] as const) { + await owner.mutation(createShare, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + targetType: "strategy", + targetPublicId: strategyPublicId, + token: `${role}-token`, + role, + }); + await user.mutation(redeemShare, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + token: `${role}-token`, + }); + } + return { t, owner, editor, viewer }; +} + +/** A group row holding one lineup, as a test sends it: its key and payload. */ +function lineup(id: string, details: TestLineup = {}) { + return { key: id, payload: oneLineupPayload(id, details) }; +} + +/** A lineup group row as a test sends it: its key and its payload. */ +function group(id: string, lineups: TestLineupGroup) { + return { key: id, payload: lineupsPayload(id, lineups) }; +} + +type Row = { key: string; payload: { kind: string; data: object } }; + +function addOp(row: Row, sortIndex: number, page = pagePublicId) { + return { + opId: `add-${row.key}`, + type: "lineup.add", + lineupPublicId: row.key, + pagePublicId: page, + payload: row.payload, + sortIndex, + }; +} + +function patchOp(opId: string, row: Row, expectedLineupRevision: number) { + return { + opId, + type: "lineup.patch", + lineupPublicId: row.key, + pagePublicId, + payload: row.payload, + expectedLineupRevision, + }; +} + +function deleteOp(opId: string, key: string, expectedLineupRevision: number) { + return { + opId, + type: "lineup.delete", + lineupPublicId: key, + pagePublicId, + expectedLineupRevision, + }; +} + +async function apply( + user: Harness, + clientId: string, + ops: Array>, + strategy = strategyPublicId, +): Promise { + const response = (await user.mutation(applyBatch, { + strategyPublicId: strategy, + clientId, + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + ops, + })) as { results: Result[] }; + return response.results; +} + +async function pageLineups( + user: Harness, + strategy = strategyPublicId, + page = pagePublicId, +): Promise { + const snapshot = (await user.query(getPageSnapshot, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + strategyPublicId: strategy, + pagePublicId: page, + })) as { lineups: LineupRow[] }; + return snapshot.lineups; +} + +function byKey(rows: LineupRow[]): Map { + return new Map(rows.map((row) => [row.publicId, row])); +} + +function liveKeys(rows: LineupRow[]): string[] { + return rows.filter((row) => !row.deleted).map((row) => row.publicId); +} + +async function addSecondPage(owner: Harness, publicId: string) { + await owner.mutation(addPage, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + strategyPublicId, + expectedRevision: 0, + pagePublicId: publicId, + name: "Page 2", + sortIndex: 1, + isAttack: false, + }); +} + +async function agentSummary( + t: RootHarness, + strategy = strategyPublicId, +): Promise { + return await t.run(async (ctx) => { + const row = await ctx.db + .query("strategies") + .withIndex("by_publicId", (q) => q.eq("publicId", strategy)) + .unique(); + const summary = await ctx.db + .query("strategyAgentSummaries") + .withIndex("by_strategyId", (q) => q.eq("strategyId", row!._id)) + .unique(); + return summary?.agentTypes ?? []; + }); +} + +type LineupAgentRow = { + lineup: string; + page: string; + originId: string; + agentType: string; +}; + +/// A strategy's lineupAgents rows, each named by its group's and page's +/// public ids, ordered by group and origin. Fails on a row that names a +/// group gone or out of step with it (another strategy or page). +async function lineupAgentRows( + t: RootHarness, + strategy = strategyPublicId, +): Promise { + return await t.run(async (ctx) => { + const strategyRow = await ctx.db + .query("strategies") + .withIndex("by_publicId", (q) => q.eq("publicId", strategy)) + .unique(); + const rows = await ctx.db + .query("lineupAgents") + .withIndex("by_strategyId", (q) => q.eq("strategyId", strategyRow!._id)) + .collect(); + const described: LineupAgentRow[] = []; + for (const row of rows) { + const lineup = await ctx.db.get(row.lineupId); + const page = await ctx.db.get(row.pageId); + if ( + lineup === null || + page === null || + lineup.strategyId !== row.strategyId || + lineup.pageId !== row.pageId + ) { + throw new Error(`lineupAgents row ${row._id} is out of step`); + } + described.push({ + lineup: lineup.publicId, + page: page.publicId, + originId: row.originId, + agentType: row.agentType, + }); + } + return described.sort( + (a, b) => + a.lineup.localeCompare(b.lineup) || + a.originId.localeCompare(b.originId), + ); + }); +} + +async function strategyRevision(t: RootHarness): Promise { + return await t.run(async (ctx) => { + const strategy = await ctx.db + .query("strategies") + .withIndex("by_publicId", (q) => q.eq("publicId", strategyPublicId)) + .unique(); + return strategy!.revision; + }); +} + +beforeAll(() => { + // Page snapshots serialize asset URLs from the R2 public base. + process.env.R2_ACCOUNT_ID = "lineups-account"; + process.env.R2_BUCKET = "lineups-bucket"; + process.env.R2_ACCESS_KEY_ID = "lineups-access-key"; + process.env.R2_SECRET_ACCESS_KEY = "lineups-secret"; + process.env.R2_PUBLIC_BASE_URL = "https://assets.lineups.test"; + process.env.R2_S3_ENDPOINT = "https://lineups.r2.test"; +}); + +afterEach(() => { + vi.useRealTimers(); +}); + +/// One group: two lineups from different origins into one shared landing +/// (fan-in), and a third from the first one's origin to another landing +/// (fan-out). A fresh copy each call, for a test to change. +function siteLineups(): TestLineupGroup { + return { + origins: [ + { id: "heaven", agentType: "brimstone", position: { dx: 120, dy: 340 } }, + { id: "mid", agentType: "viper", position: { dx: 200, dy: 100 } }, + ], + landings: [ + { id: "site", position: { dx: 400, dy: 220 } }, + { id: "hell", position: { dx: 500, dy: 300 } }, + ], + links: [ + { + id: "from-heaven", + originId: "heaven", + landingId: "site", + name: "From heaven", + youtubeLink: "https://youtu.be/heaven", + notes: "Jump throw", + }, + { id: "from-mid", originId: "mid", landingId: "site", name: "From mid" }, + { + id: "heaven-to-hell", + originId: "heaven", + landingId: "hell", + name: "Hell", + }, + ], + }; +} + +const siteKey = "site-group"; + +function siteGroup(edit: (lineups: TestLineupGroup) => void = () => {}) { + const lineups = siteLineups(); + edit(lineups); + return group(siteKey, lineups); +} + +describe("one row per lineup group", () => { + test("a group round-trips with its origins, landings and links intact", async () => { + const { owner } = await createHarness(); + const row = siteGroup(); + const results = await apply(owner, "owner-client", [addOp(row, 0)]); + expect(results[0]).toMatchObject({ status: "applied", appliedRevision: 1 }); + + const rows = await pageLineups(owner); + expect(rows).toHaveLength(1); + expect(rows[0]).toMatchObject({ + publicId: siteKey, + revision: 1, + deleted: false, + }); + expect(rows[0]!.payload).toEqual(row.payload); + expect(rows[0]!.payload.kind).toBe("lineups"); + + const full = (await owner.query(getFullSnapshot, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + strategyPublicId, + })) as { lineups: LineupRow[] }; + expect(full.lineups.map((entry) => entry.payload)).toEqual([row.payload]); + + const listed = (await owner.query(listForStrategy, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + strategyPublicId, + })) as LineupRow[]; + expect(listed.map((entry) => entry.payload)).toEqual([row.payload]); + }); + + test("a group, its lineup and that lineup's landing may share one id", async () => { + const { owner } = await createHarness(); + const row = group("same-id", { + origins: [{ id: "origin" }], + landings: [{ id: "same-id" }], + links: [{ id: "same-id", originId: "origin", landingId: "same-id" }], + }); + const results = await apply(owner, "owner-client", [addOp(row, 0)]); + expect(results[0]).toMatchObject({ status: "applied" }); + expect((await pageLineups(owner))[0]!.payload).toEqual(row.payload); + }); + + test("moving a shared spot is one patch of its group, seen by every lineup in it", async () => { + const { owner } = await createHarness(); + await apply(owner, "owner-client", [addOp(siteGroup(), 0)]); + const moved = { dx: 10, dy: 20 }; + const edit = siteGroup((lineups) => { + lineups.landings[0]!.position = moved; + }); + + const results = await apply(owner, "owner-client", [ + patchOp("move-site", edit, 1), + ]); + expect(results[0]).toMatchObject({ status: "applied", appliedRevision: 2 }); + const rows = await pageLineups(owner); + expect(rows).toHaveLength(1); + expect(rows[0]).toMatchObject({ revision: 2 }); + expect(rows[0]!.payload).toEqual(edit.payload); + const data = rows[0]!.payload.data as { + landings: Array<{ id: string; ability: { position: unknown } }>; + links: Array<{ landingId: string }>; + }; + // The spot is stored once, and both lineups into it name it. + expect(data.landings.filter((landing) => landing.id === "site")).toEqual([ + { + id: "site", + ability: { id: "ability-site", position: moved, lineUpID: "site" }, + }, + ]); + expect(data.links.map((link) => link.landingId)).toEqual([ + "site", + "site", + "hell", + ]); + }); + + test("teammates editing different lineups of one group from the same revision: the second is a conflict, not a silent overwrite", async () => { + const { owner, editor } = await createHarness(); + await apply(owner, "owner-client", [addOp(siteGroup(), 0)]); + const ownerEdit = siteGroup((lineups) => { + lineups.links[0]!.name = "Owner name"; + }); + const ownerResults = await apply(owner, "owner-client", [ + patchOp("owner-renames", ownerEdit, 1), + ]); + expect(ownerResults[0]).toMatchObject({ + status: "applied", + appliedRevision: 2, + }); + + // The editor, still on revision 1, writes notes on another lineup of + // the same group. + const stale = await apply(editor, "editor-client", [ + patchOp( + "editor-notes", + siteGroup((lineups) => { + lineups.links[1]!.notes = "Editor notes"; + }), + 1, + ), + ]); + expect(stale[0]).toMatchObject({ + status: "rejected", + reason: "revision_mismatch", + current: { type: "lineup", revision: 2, value: ownerEdit.payload }, + }); + const row = byKey(await pageLineups(owner)).get(siteKey); + expect(row).toMatchObject({ revision: 2 }); + expect(row!.payload).toEqual(ownerEdit.payload); + }); + + test("a viewer reads lineup groups but cannot write them", async () => { + const { owner, viewer } = await createHarness(); + await apply(owner, "owner-client", [addOp(siteGroup(), 0)]); + await expect( + apply(viewer, "viewer-client", [addOp(lineup("viewer-lineup"), 1)]), + ).rejects.toThrow("Forbidden"); + await expect( + apply(viewer, "viewer-client", [ + patchOp( + "viewer-renames", + siteGroup((lineups) => { + lineups.links[0]!.name = "Viewer"; + }), + 1, + ), + ]), + ).rejects.toThrow("Forbidden"); + expect((await pageLineups(viewer)).map((row) => row.publicId)).toEqual([ + siteKey, + ]); + }); +}); + +describe("a lineup group row is checked whole", () => { + /// An add of the site group under [key] whose payload [edit] has changed. + function brokenAdd( + key: string, + edit: (payload: { + kind: string; + payloadVersion: number; + data: Record; + }) => void, + ) { + const payload = structuredClone(group(key, siteLineups()).payload) as { + kind: string; + payloadVersion: number; + data: Record; + }; + edit(payload); + return { ...addOp({ key, payload }, 0), opId: `add-${key}` }; + } + + test("each broken rule refuses the row with its code, and nothing is stored", async () => { + const { owner } = await createHarness(); + const cases: Array<{ + op: Record; + code: string; + }> = [ + { + op: brokenAdd("unknown-version", (payload) => { + payload.payloadVersion = 2; + }), + code: "INVALID_LINEUP_PAYLOAD_VERSION", + }, + { + op: brokenAdd("no-id", (payload) => { + delete payload.data.id; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: { ...brokenAdd("keyed", () => {}), lineupPublicId: "other-key" }, + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + ...(["origins", "landings", "links"] as const).flatMap((field) => [ + { + op: brokenAdd(`no-${field}`, (payload) => { + delete payload.data[field]; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd(`${field}-not-a-list`, (payload) => { + payload.data[field] = { [payload.data[field][0].id]: true }; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd(`${field}-entry-not-an-object`, (payload) => { + payload.data[field][0] = payload.data[field][0].id; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd(`${field}-entry-without-id`, (payload) => { + delete payload.data[field][0].id; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd(`${field}-entry-with-empty-id`, (payload) => { + payload.data[field][0].id = ""; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd(`${field}-repeat-an-id`, (payload) => { + payload.data[field][1].id = payload.data[field][0].id; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + ]), + { + op: brokenAdd("origin-without-agent", (payload) => { + delete payload.data.origins[0].agent; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd("landing-without-ability", (payload) => { + delete payload.data.landings[0].ability; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd("no-lineups", (payload) => { + payload.data.links = []; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd("link-to-missing-origin", (payload) => { + payload.data.links[0].originId = "nowhere"; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd("link-to-missing-landing", (payload) => { + payload.data.links[0].landingId = "nowhere"; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd("link-without-origin", (payload) => { + delete payload.data.links[0].originId; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + op: brokenAdd("link-without-landing", (payload) => { + delete payload.data.links[0].landingId; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + { + // A link may not name a landing as its origin. + op: brokenAdd("link-ends-swapped", (payload) => { + payload.data.links[0].originId = "site"; + payload.data.links[0].landingId = "heaven"; + }), + code: "INVALID_LINEUP_PAYLOAD_DATA", + }, + ]; + + const results = await apply( + owner, + "owner-client", + cases.map((entry) => entry.op), + ); + expect(results).toEqual( + cases.map((entry) => + expect.objectContaining({ + opId: entry.op.opId, + status: "failed", + code: entry.code, + }), + ), + ); + expect(await pageLineups(owner)).toEqual([]); + }); + + test("a spot no lineup uses is kept", async () => { + const { owner } = await createHarness(); + const row = siteGroup((lineups) => { + lineups.origins.push({ id: "unused-origin", agentType: "jett" }); + lineups.landings.push({ id: "unused-landing" }); + }); + const results = await apply(owner, "owner-client", [addOp(row, 0)]); + expect(results[0]).toMatchObject({ status: "applied" }); + expect((await pageLineups(owner))[0]!.payload).toEqual(row.payload); + }); + + test("a patch that breaks the group is refused and leaves the row as it was", async () => { + const { owner } = await createHarness(); + await apply(owner, "owner-client", [addOp(siteGroup(), 0)]); + // The landing two lineups aim at is gone, but they still name it. + const broken = siteGroup((lineups) => { + lineups.landings = lineups.landings.filter( + (landing) => landing.id !== "site", + ); + }); + const results = await apply(owner, "owner-client", [ + patchOp("drop-site", broken, 1), + ]); + expect(results[0]).toMatchObject({ + status: "failed", + code: "INVALID_LINEUP_PAYLOAD_DATA", + }); + const row = (await pageLineups(owner))[0]!; + expect(row).toMatchObject({ revision: 1 }); + expect(row.payload).toEqual(siteGroup().payload); + }); + + test("the graph kinds of protocol 4 are refused by the handler; lineup and lineupGroup by the contract", async () => { + const { owner } = await createHarness(); + // Protocol 4's graph rows get past argument validation so an old client + // reaches the protocol gate; on protocol 5 the handler refuses each op. + const graphKinds = ["lineupOrigin", "lineupLanding", "lineupLink"]; + const results = await apply( + owner, + "old-shapes", + graphKinds.map((kind) => ({ + opId: `add-${kind}`, + type: "lineup.add", + lineupPublicId: `${kind}:k`, + pagePublicId, + payload: { + kind, + payloadVersion: 1, + data: { id: "k", originId: "o", landingId: "l", images: [] }, + }, + sortIndex: 0, + })), + ); + expect(results).toHaveLength(graphKinds.length); + for (const [index, kind] of graphKinds.entries()) { + expect(results[index]).toMatchObject({ + opId: `add-${kind}`, + status: "failed", + code: "INVALID_LINEUP_PAYLOAD_KIND", + }); + } + // The group of protocol 3 and earlier, and the one-row-per-lineup shape + // this branch tried before groups, are refused whole: no client that + // could send them speaks protocol 5. + const retired = [ + { + kind: "lineupGroup", + payloadVersion: 1, + data: { id: "group", items: [{ id: "item" }] }, + }, + { + kind: "lineup", + payloadVersion: 1, + data: { + id: "group", + origin: { id: "o", agent: { type: "sova" } }, + landing: { id: "l", ability: {} }, + }, + }, + ]; + for (const payload of retired) { + await expect( + apply(owner, "old-client", [ + { + opId: `add-${payload.kind}`, + type: "lineup.add", + lineupPublicId: "group", + pagePublicId, + payload, + sortIndex: 0, + }, + ]), + ).rejects.toThrow(/Validator error|ArgumentValidationError/); + } + expect(await pageLineups(owner)).toEqual([]); + }); +}); + +describe("no lineup or spot is in two groups of a page", () => { + test("a new group holding a spot another group holds is refused, and nothing is stored", async () => { + const { owner } = await createHarness(); + await apply(owner, "owner-client", [ + addOp(lineup("k1", { landingId: "smoke" }), 0), + ]); + const results = await apply(owner, "owner-client", [ + addOp(lineup("k2", { landingId: "smoke" }), 1), + ]); + expect(results[0]).toMatchObject({ + status: "failed", + code: "INVALID_LINEUP_PAYLOAD_DATA", + }); + expect(liveKeys(await pageLineups(owner))).toEqual(["k1"]); + }); + + test("a patch taking a lineup another group holds is refused and leaves the row as it was", async () => { + const { owner } = await createHarness(); + await apply(owner, "owner-client", [ + addOp(lineup("k1"), 0), + addOp(lineup("k2"), 1), + ]); + // k2's row also claims k1's lineup, under its own spots. + const grabbing = group("k2", { + origins: [{ id: "k2-origin" }], + landings: [{ id: "k2-landing" }], + links: [ + { id: "k2", originId: "k2-origin", landingId: "k2-landing" }, + { id: "k1", originId: "k2-origin", landingId: "k2-landing" }, + ], + }); + const results = await apply(owner, "owner-client", [ + patchOp("grab-k1", grabbing, 1), + ]); + expect(results[0]).toMatchObject({ + status: "failed", + code: "INVALID_LINEUP_PAYLOAD_DATA", + }); + const rows = byKey(await pageLineups(owner)); + expect(rows.get("k2")).toMatchObject({ revision: 1 }); + expect(rows.get("k2")!.payload).toEqual(lineup("k2").payload); + }); + + test("ids only clash within a kind, within a page, among live rows", async () => { + const { owner } = await createHarness(); + await addSecondPage(owner, "page-2"); + await apply(owner, "owner-client", [ + addOp(lineup("k1", { landingId: "shared" }), 0), + ]); + const results = await apply(owner, "owner-client", [ + // A lineup named like another group's landing. + addOp(lineup("shared", { landingId: "other" }), 1), + // The same spot on another page. + addOp(lineup("k3", { landingId: "shared" }), 0, "page-2"), + ]); + expect(results.map((result) => result.status)).toEqual([ + "applied", + "applied", + ]); + + // Once k1's group is deleted, its spot is free for another group. + await apply(owner, "owner-client", [deleteOp("drop-k1", "k1", 1)]); + const reuse = await apply(owner, "owner-client", [ + addOp(lineup("k4", { landingId: "shared" }), 2), + ]); + expect(reuse[0]).toMatchObject({ status: "applied" }); + }); + + test("a duplicated strategy's groups hold their spots in the copy too", async () => { + const { owner } = await createHarness(); + await apply(owner, "owner-client", [addOp(lineup("k1"), 0)]); + await owner.mutation(duplicateStrategy, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + sourceStrategyPublicId: strategyPublicId, + publicId: "lineups-copy", + name: "Lineups (Copy)", + }); + const copy = (await owner.query(getFullSnapshot, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + strategyPublicId: "lineups-copy", + })) as { + pages: Array<{ publicId: string }>; + lineups: Array; + }; + const copied = copy.lineups[0]!; + const landingId = ( + copied.payload.data.landings as Array<{ id: string }> + )[0]!.id; + + const results = await apply( + owner, + "owner-client", + [addOp(lineup("k2", { landingId }), 1, copied.pagePublicId)], + "lineups-copy", + ); + expect(results[0]).toMatchObject({ + status: "failed", + code: "INVALID_LINEUP_PAYLOAD_DATA", + }); + }); + + test("restoring a deleted group over a spot another group took since is refused", async () => { + const { owner } = await createHarness(); + await apply(owner, "owner-client", [ + addOp(lineup("k1", { landingId: "smoke" }), 0), + ]); + await apply(owner, "owner-client", [deleteOp("drop-k1", "k1", 1)]); + await apply(owner, "owner-client", [ + addOp(lineup("k2", { landingId: "smoke" }), 1), + ]); + const results = await apply(owner, "owner-client", [ + { + ...addOp(lineup("k1", { landingId: "smoke" }), 0), + opId: "restore-k1", + expectedLineupRevision: 2, + }, + ]); + expect(results[0]).toMatchObject({ + status: "failed", + code: "INVALID_LINEUP_PAYLOAD_DATA", + }); + expect(liveKeys(await pageLineups(owner))).toEqual(["k2"]); + }); +}); + +describe("clients on protocol 4", () => { + test("a protocol 4 batch with its lineup options and a link row is told to upgrade", async () => { + const { owner } = await createHarness(); + const error = await owner + .mutation(applyBatch, { + strategyPublicId, + clientId: "protocol-4-client", + clientProtocolVersion: 4, + checkLineupLinkEnds: true, + checkLineupEndDeletes: true, + ops: [ + { + opId: "add-link", + type: "lineup.add", + lineupPublicId: "lineupLink:k", + pagePublicId, + payload: { + kind: "lineupLink", + payloadVersion: 1, + data: { id: "k", originId: "o", landingId: "l", images: [] }, + }, + sortIndex: 0, + }, + ], + }) + .then( + () => null, + (caught: unknown) => caught as { data?: unknown; message?: string }, + ); + expect(error).not.toBeNull(); + // The protocol gate answered, not argument validation. + expect(error?.message ?? "").not.toMatch( + /Validator error|ArgumentValidationError/, + ); + expect(typeof error?.data).toBe("string"); + expect(JSON.parse(error?.data as string)).toMatchObject({ + code: "CLIENT_UPGRADE_REQUIRED", + }); + expect(await pageLineups(owner)).toEqual([]); + }); + + test("a protocol 5 batch with an origin row fails that op and applies the rest", async () => { + const { owner } = await createHarness(); + const response = (await owner.mutation(applyBatch, { + strategyPublicId, + clientId: "mixed-client", + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + // Still accepted (and ignored) on protocol 5. + checkLineupLinkEnds: true, + checkLineupEndDeletes: true, + ops: [ + { + opId: "add-origin", + type: "lineup.add", + lineupPublicId: "lineupOrigin:o", + pagePublicId, + payload: { + kind: "lineupOrigin", + payloadVersion: 1, + data: { id: "o", agent: { type: "sova" } }, + }, + sortIndex: 0, + }, + { + opId: "add-text", + type: "element.add", + elementPublicId: "note", + pagePublicId, + payload: { + kind: "text", + payloadVersion: 1, + data: { id: "note", elementType: "text", text: "Default" }, + }, + sortIndex: 0, + }, + ], + })) as { results: Result[] }; + expect(response.results).toMatchObject([ + { + opId: "add-origin", + status: "failed", + code: "INVALID_LINEUP_PAYLOAD_KIND", + }, + { opId: "add-text", status: "applied", appliedRevision: 1 }, + ]); + const snapshot = (await owner.query(getPageSnapshot, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + strategyPublicId, + pagePublicId, + })) as { + elements: Array<{ publicId: string }>; + lineups: LineupRow[]; + }; + expect(snapshot.elements.map((row) => row.publicId)).toEqual(["note"]); + expect(snapshot.lineups).toEqual([]); + }); +}); + +describe("lineup row keys belong to their strategy and page", () => { + test("the same group ids in two strategies are separate rows", async () => { + const { owner } = await createHarness(); + const copyId = "local-duplicate"; + const copyPage = "local-duplicate-page"; + await owner.mutation(createStrategy, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + publicId: copyId, + name: "Copy", + mapData: "ascent", + initialPagePublicId: copyPage, + initialPageName: "Page 1", + initialPageIsAttack: true, + }); + // A strategy duplicated on the device keeps every lineup id; each upload + // keeps them too (ids only need to be unique within a strategy). + for (const [strategy, page] of [ + [strategyPublicId, pagePublicId], + [copyId, copyPage], + ] as const) { + const results = await apply( + owner, + `upload-${strategy}`, + [addOp(siteGroup(), 0, page)], + strategy, + ); + expect(results[0]).toMatchObject({ status: "applied" }); + } + // Editing one copy leaves the other untouched. + await apply( + owner, + "edit-copy", + [ + { + ...patchOp( + "rename-in-copy", + siteGroup((lineups) => { + lineups.links[0]!.name = "Copy name"; + }), + 1, + ), + pagePublicId: copyPage, + }, + ], + copyId, + ); + const firstLinkName = (row: LineupRow | undefined) => + (row!.payload.data as { links: Array<{ name: string }> }).links[0]!.name; + expect(firstLinkName(byKey(await pageLineups(owner)).get(siteKey))).toBe( + "From heaven", + ); + expect( + firstLinkName( + byKey(await pageLineups(owner, copyId, copyPage)).get(siteKey), + ), + ).toBe("Copy name"); + }); + + test("a lineup row is never moved to another page by a patch", async () => { + const { owner } = await createHarness(); + const secondPage = "lineups-page-2"; + await addSecondPage(owner, secondPage); + await apply(owner, "page-1-client", [addOp(lineup("k"), 0)]); + + // Another page wants the same key: the add is refused, and "Keep mine" + // would turn it into a patch naming the other page. + const clashing = lineup("k", { originId: "o2", name: "Page 2 lineup" }); + const added = await apply(owner, "page-2-client", [ + addOp(clashing, 0, secondPage), + ]); + expect(added[0]).toMatchObject({ + status: "rejected", + reason: "already_exists", + }); + const moved = await apply(owner, "page-2-client", [ + { ...patchOp("keep-mine", clashing, 1), pagePublicId: secondPage }, + ]); + expect(moved[0]).toMatchObject({ + status: "failed", + code: "LINEUP_PAGE_MISMATCH", + }); + + // The row stays on its page, untouched. + const first = await pageLineups(owner); + expect(first.map((row) => row.publicId)).toEqual(["k"]); + expect(first[0]!.payload).toEqual(lineup("k").payload); + expect(await pageLineups(owner, strategyPublicId, secondPage)).toEqual([]); + }); + + test("the same group added twice with a different order is one add", async () => { + const { owner, editor } = await createHarness(); + const first = await apply(owner, "owner-client", [addOp(siteGroup(), 3)]); + const second = await apply(editor, "editor-client", [ + addOp(siteGroup(), 7), + ]); + expect(first[0]).toMatchObject({ status: "applied" }); + expect(second[0]).toMatchObject({ status: "noop" }); + const conflicting = await apply(editor, "editor-client", [ + { + ...addOp( + siteGroup((lineups) => { + lineups.origins[0]!.agentType = "jett"; + }), + 7, + ), + opId: "different-content", + }, + ]); + expect(conflicting[0]).toMatchObject({ + status: "rejected", + reason: "already_exists", + }); + }); +}); + +describe("lineup images", () => { + test("a group references every image across its lineups while it lives, and releases them when it is deleted", async () => { + const { t, owner } = await createHarness(); + await t.run(markAssetReferencesReady); + const shots = ["shot-1", "shot-2", "shot-3"]; + await t.run(async (ctx) => { + const strategy = await ctx.db + .query("strategies") + .withIndex("by_publicId", (q) => q.eq("publicId", strategyPublicId)) + .unique(); + const now = Date.now(); + for (const publicId of shots) { + await ctx.db.insert("imageAssets", { + publicId, + provider: "r2", + strategyId: strategy!._id, + objectKey: `tests/${publicId}.png`, + uploadStatus: "active", + fileExtension: ".png", + mimeType: "image/png", + createdAt: now, + updatedAt: now, + }); + } + }); + // Two lineups of the group show images, one of them shared by both. + const withImages = (secondLinkShots: string[]) => + siteGroup((lineups) => { + lineups.links[0]!.images = [ + { id: "shot-1", fileExtension: ".png" }, + { id: "shot-2", fileExtension: ".png" }, + ]; + lineups.links[2]!.images = secondLinkShots.map((id) => ({ + id, + fileExtension: ".png", + })); + }); + await apply(owner, "owner-client", [ + addOp(withImages(["shot-2", "shot-3"]), 0), + ]); + + const snapshot = (await owner.query(getPageSnapshot, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + strategyPublicId, + pagePublicId, + })) as { assets: Array<{ publicId: string }> }; + expect(snapshot.assets.map((asset) => asset.publicId).sort()).toEqual( + shots, + ); + // One reference per image the row shows, however many lineups show it. + const lineupReferences = async () => + ( + await t.run(async (ctx) => await ctx.db.query("assetReferences").collect()) + ) + .filter((reference) => reference.lineupId !== undefined) + .map((reference) => reference.assetPublicId) + .sort(); + expect(await lineupReferences()).toEqual(shots); + const asked = { + strategyPublicId, + assetPublicIds: [...shots, "never-shown"], + }; + expect(await owner.query(listReferencedAssetIds, asked)).toEqual(shots); + + // Dropping an image one lineup still shows keeps it; dropping the last + // lineup showing an image releases only that one. + await apply(owner, "owner-client", [ + patchOp("drop-shared-shot", withImages(["shot-3"]), 1), + ]); + expect(await owner.query(listReferencedAssetIds, asked)).toEqual(shots); + await apply(owner, "owner-client", [ + patchOp("drop-shot-3", withImages([]), 2), + ]); + expect(await owner.query(listReferencedAssetIds, asked)).toEqual([ + "shot-1", + "shot-2", + ]); + expect(await lineupReferences()).toEqual(["shot-1", "shot-2"]); + + await apply(owner, "owner-client", [deleteOp("delete-site", siteKey, 3)]); + expect(await owner.query(listReferencedAssetIds, asked)).toEqual([]); + }); +}); + +describe("agent summary", () => { + test("an origin shared by several lineups counts once, distinct origins count each", async () => { + const { t, owner } = await createHarness(); + await apply(owner, "owner-client", [ + // One astra origin, thrown to two landings. + addOp( + group("astra", { + origins: [{ id: "astra-origin", agentType: "astra" }], + landings: [{ id: "a-site" }, { id: "b-site" }], + links: [ + { id: "astra-a", originId: "astra-origin", landingId: "a-site" }, + { id: "astra-b", originId: "astra-origin", landingId: "b-site" }, + ], + }), + 0, + ), + // Two viper origins into one landing. + addOp( + group("viper", { + origins: [ + { id: "viper-1", agentType: "viper" }, + { id: "viper-2", agentType: "viper" }, + ], + landings: [{ id: "wall" }], + links: [ + { id: "viper-a", originId: "viper-1", landingId: "wall" }, + { id: "viper-b", originId: "viper-2", landingId: "wall" }, + ], + }), + 1, + ), + ]); + // Counted per lineup, astra would tie viper and sort first by name; + // counted per origin, viper (2) leads astra (1). + expect(await agentSummary(t)).toEqual(["viper", "astra"]); + + // Deleting the group of an origin drops its agent. + await apply(owner, "owner-client", [deleteOp("delete-astra", "astra", 1)]); + expect(await agentSummary(t)).toEqual(["viper"]); + }); + + test("only a batch that may change the agents refreshes the summary", async () => { + const { t, owner } = await createHarness(); + // A lineup written straight to the table leaves the stored summary + // stale, so a refresh shows as the summary catching up with it. + await seedLineupRow(t, "seeded-viper", "viper"); + expect(await agentSummary(t)).toEqual([]); + + // Drawings, utilities and text never carry an agent: no refresh. + const plain = await apply(owner, "owner-client", [ + elementAdd("drawing-1", "drawing", 0), + elementAdd("utility-1", "utility", 1), + elementAdd("text-1", "text", 2), + { + opId: "patch-text-1", + type: "element.patch", + elementPublicId: "text-1", + pagePublicId, + payload: elementPayload("text-1", "text", { text: "Edited" }), + expectedElementRevision: 1, + }, + { + opId: "delete-drawing-1", + type: "element.delete", + elementPublicId: "drawing-1", + pagePublicId, + expectedElementRevision: 1, + }, + ]); + expect(plain.map((result) => result.status)).toEqual([ + "applied", + "applied", + "applied", + "applied", + "applied", + ]); + expect(await agentSummary(t)).toEqual([]); + + // Placing an agent does. + await apply(owner, "owner-client", [elementAdd("jett-1", "agent", 3)]); + expect(await agentSummary(t)).toEqual(["jett", "viper"]); + + // Deleting an agent does too, though the op carries no payload. + await seedLineupRow(t, "seeded-astra", "astra"); + expect(await agentSummary(t)).toEqual(["jett", "viper"]); + await apply(owner, "owner-client", [ + { + opId: "delete-jett-1", + type: "element.delete", + elementPublicId: "jett-1", + pagePublicId, + expectedElementRevision: 1, + }, + ]); + expect(await agentSummary(t)).toEqual(["astra", "viper"]); + + // And so does any lineup change. + await seedLineupRow(t, "seeded-kayo", "kayo"); + expect(await agentSummary(t)).toEqual(["astra", "viper"]); + await apply(owner, "owner-client", [ + addOp(lineup("placed-sova", { agentType: "sova" }), 9), + ]); + expect(await agentSummary(t)).toEqual(["astra", "kayo", "sova", "viper"]); + }); + + test("each live group keeps one agent row per origin in step with it, and the summary follows them", async () => { + const { t, owner } = await createHarness(); + const secondPage = "lineups-page-2"; + await addSecondPage(owner, secondPage); + const kayo = lineup("kayo-a", { originId: "kayo", agentType: "kayo" }); + const rawRows = async () => + await t.run(async (ctx) => await ctx.db.query("lineupAgents").collect()); + + // Adding a group adds a row for each of its origins. + await apply(owner, "owner-client", [ + addOp(siteGroup(), 0), + addOp(kayo, 0, secondPage), + ]); + expect(await lineupAgentRows(t)).toEqual([ + { lineup: "kayo-a", page: secondPage, originId: "kayo", agentType: "kayo" }, + { lineup: siteKey, page: pagePublicId, originId: "heaven", agentType: "brimstone" }, + { lineup: siteKey, page: pagePublicId, originId: "mid", agentType: "viper" }, + ]); + expect(await agentSummary(t)).toEqual(["brimstone", "kayo", "viper"]); + + // A patch that changes one origin's agent updates that row alone; the + // other origin's row is left exactly as it was. + const before = await rawRows(); + const heavenRow = before.find((row) => row.originId === "heaven")!; + const midRow = before.find((row) => row.originId === "mid")!; + const midToSova = siteGroup((lineups) => { + lineups.origins[1]!.agentType = "sova"; + }); + expect( + (await apply(owner, "owner-client", [patchOp("mid-to-sova", midToSova, 1)]))[0], + ).toMatchObject({ status: "applied" }); + let after = await rawRows(); + expect(after.find((row) => row.originId === "heaven")).toEqual(heavenRow); + expect(after.find((row) => row.originId === "mid")).toEqual({ + ...midRow, + agentType: "sova", + }); + expect(await agentSummary(t)).toEqual(["brimstone", "kayo", "sova"]); + + // A lineup from a new origin adds its row; dropping an origin (and its + // lineup) deletes its row, leaving the rest. + const reshaped = siteGroup((lineups) => { + lineups.origins[1]!.agentType = "sova"; + lineups.origins.push({ id: "garage", agentType: "astra" }); + lineups.links.push({ id: "from-garage", originId: "garage", landingId: "site" }); + }); + await apply(owner, "owner-client", [patchOp("add-garage", reshaped, 2)]); + expect( + (await lineupAgentRows(t)).filter((row) => row.lineup === siteKey), + ).toEqual([ + { lineup: siteKey, page: pagePublicId, originId: "garage", agentType: "astra" }, + { lineup: siteKey, page: pagePublicId, originId: "heaven", agentType: "brimstone" }, + { lineup: siteKey, page: pagePublicId, originId: "mid", agentType: "sova" }, + ]); + const withoutMid = siteGroup((lineups) => { + lineups.origins = lineups.origins.filter((origin) => origin.id !== "mid"); + lineups.origins.push({ id: "garage", agentType: "astra" }); + lineups.links = lineups.links.filter((link) => link.originId !== "mid"); + lineups.links.push({ id: "from-garage", originId: "garage", landingId: "site" }); + }); + await apply(owner, "owner-client", [patchOp("drop-mid", withoutMid, 3)]); + after = await rawRows(); + expect(after.find((row) => row.originId === "heaven")).toEqual(heavenRow); + expect( + (await lineupAgentRows(t)).filter((row) => row.lineup === siteKey), + ).toEqual([ + { lineup: siteKey, page: pagePublicId, originId: "garage", agentType: "astra" }, + { lineup: siteKey, page: pagePublicId, originId: "heaven", agentType: "brimstone" }, + ]); + expect(await agentSummary(t)).toEqual(["astra", "brimstone", "kayo"]); + + // Deleting a group removes all its rows; restoring it brings them back. + await apply(owner, "owner-client", [deleteOp("delete-site", siteKey, 4)]); + expect((await lineupAgentRows(t)).map((row) => row.lineup)).toEqual([ + "kayo-a", + ]); + expect(await agentSummary(t)).toEqual(["kayo"]); + const restored = await apply(owner, "owner-client", [ + { ...addOp(withoutMid, 0), opId: "restore-site", expectedLineupRevision: 5 }, + ]); + expect(restored[0]).toMatchObject({ status: "applied", appliedRevision: 6 }); + expect( + (await lineupAgentRows(t)).map((row) => `${row.lineup}:${row.originId}`), + ).toEqual(["kayo-a:kayo", `${siteKey}:garage`, `${siteKey}:heaven`]); + expect(await agentSummary(t)).toEqual(["astra", "brimstone", "kayo"]); + + // A page in the trash keeps its groups' rows for a restore, and the + // summary leaves them out until the page comes back. + const trashed = await apply(owner, "owner-client", [ + { + opId: "trash-page-2", + type: "page.delete", + pagePublicId: secondPage, + expectedStrategyRevision: await strategyRevision(t), + }, + ]); + expect(trashed[0]).toMatchObject({ status: "applied" }); + expect((await lineupAgentRows(t)).map((row) => row.lineup)).toEqual([ + "kayo-a", + siteKey, + siteKey, + ]); + expect(await agentSummary(t)).toEqual(["astra", "brimstone"]); + await owner.mutation(restorePage, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + strategyPublicId, + pagePublicId: secondPage, + }); + expect(await agentSummary(t)).toEqual(["astra", "brimstone", "kayo"]); + }); + + test("purging leaves no agent row behind, even one a tombstone kept", async () => { + vi.useFakeTimers(); + const { t, owner } = await createHarness(); + await t.run(markAssetReferencesReady); + await apply(owner, "owner-client", [ + addOp(siteGroup(), 0), + addOp(lineup("kept", { agentType: "viper" }), 1), + ]); + await apply(owner, "owner-client", [deleteOp("delete-site", siteKey, 1)]); + expect((await lineupAgentRows(t)).map((row) => row.lineup)).toEqual([ + "kept", + ]); + // A row left behind for the tombstone (say by a write before this + // table existed) goes with the tombstone. + await t.run(async (ctx) => { + const gone = (await ctx.db.query("lineups").collect()).find( + (row) => row.publicId === siteKey, + )!; + await ctx.db.insert("lineupAgents", { + strategyId: gone.strategyId, + pageId: gone.pageId, + lineupId: gone._id, + originId: "heaven", + agentType: "brimstone", + }); + }); + + vi.setSystemTime(Date.now() + 31 * 24 * 60 * 60 * 1000); + await t.mutation(purgeOldTombstones, {}); + await t.finishAllScheduledFunctions(vi.runAllTimers); + + const left = await t.run(async (ctx) => ({ + lineups: (await ctx.db.query("lineups").collect()).map( + (row) => row.publicId, + ), + lineupAgents: (await ctx.db.query("lineupAgents").collect()).length, + })); + expect(left).toEqual({ lineups: ["kept"], lineupAgents: 1 }); + expect((await lineupAgentRows(t)).map((row) => row.lineup)).toEqual([ + "kept", + ]); + }); + + test("a duplicate's groups get agent rows of their own, one per origin", async () => { + const { t, owner } = await createHarness(); + await apply(owner, "owner-client", [ + addOp(siteGroup(), 0), + addOp(lineup("astra-a", { originId: "astra", agentType: "astra" }), 1), + ]); + const sourceRows = await lineupAgentRows(t); + + await owner.mutation(duplicateStrategy, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + sourceStrategyPublicId: strategyPublicId, + publicId: "lineups-copy", + name: "Lineups (Copy)", + }); + + type Origin = { id: string; agent: { type: string } }; + const copy = (await owner.query(getFullSnapshot, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + strategyPublicId: "lineups-copy", + })) as { + pages: Array<{ publicId: string }>; + lineups: Array; + }; + const copyRows = await lineupAgentRows(t, "lineups-copy"); + expect(copyRows).toEqual( + copy.lineups + .flatMap((row) => + (row.payload.data.origins as Origin[]).map((origin) => ({ + lineup: row.publicId, + page: row.pagePublicId, + originId: origin.id, + agentType: origin.agent.type, + })), + ) + .sort( + (a, b) => + a.lineup.localeCompare(b.lineup) || + a.originId.localeCompare(b.originId), + ), + ); + expect(copyRows).toHaveLength(3); + expect(copyRows.map((row) => row.page)).toEqual( + copyRows.map(() => copy.pages[0]!.publicId), + ); + // The source keeps its rows untouched. + expect(await lineupAgentRows(t)).toEqual(sourceRows); + expect(await agentSummary(t, "lineups-copy")).toEqual([ + "astra", + "brimstone", + "viper", + ]); + + // Editing the copy moves only the copy's rows. + const copiedSite = copy.lineups.find( + (row) => (row.payload.data.origins as Origin[]).length === 2, + )!; + const data = structuredClone(copiedSite.payload.data) as { + origins: Origin[]; + }; + const viperOrigin = data.origins.find( + (origin) => origin.agent.type === "viper", + )!; + viperOrigin.agent.type = "jett"; + const edited = await apply( + owner, + "copy-client", + [ + { + opId: "copy-viper-to-jett", + type: "lineup.patch", + lineupPublicId: copiedSite.publicId, + pagePublicId: copiedSite.pagePublicId, + payload: { ...copiedSite.payload, data }, + expectedLineupRevision: 1, + }, + ], + "lineups-copy", + ); + expect(edited[0]).toMatchObject({ status: "applied" }); + expect( + (await lineupAgentRows(t, "lineups-copy")).find( + (row) => row.originId === viperOrigin.id, + ), + ).toMatchObject({ lineup: copiedSite.publicId, agentType: "jett" }); + expect(await agentSummary(t, "lineups-copy")).toEqual([ + "astra", + "brimstone", + "jett", + ]); + expect(await lineupAgentRows(t)).toEqual(sourceRows); + expect(await agentSummary(t)).toEqual(["astra", "brimstone", "viper"]); + }); +}); + +describe("a resent lineup op", () => { + test("reports the revision it landed at, so a successor cannot overwrite a teammate's later edit", async () => { + const { owner, editor } = await createHarness(); + await apply(owner, "owner-client", [addOp(siteGroup(), 0)]); + const mine = patchOp( + "owner-renames", + siteGroup((lineups) => { + lineups.links[0]!.name = "Owner name"; + }), + 1, + ); + const first = await apply(owner, "owner-client", [mine]); + expect(first[0]).toMatchObject({ status: "applied", appliedRevision: 2 }); + + // A teammate edits the same group after it. + const theirs = siteGroup((lineups) => { + lineups.links[0]!.name = "Editor name"; + }); + const teammate = await apply(editor, "editor-client", [ + patchOp("editor-renames", theirs, 2), + ]); + expect(teammate[0]).toMatchObject({ status: "applied", appliedRevision: 3 }); + + // The owner's ack was lost: it sends the op again, with the successor it + // queued on top of it (expecting the revision the first landed at). + const resent = await apply(owner, "owner-client", [ + mine, + patchOp( + "owner-notes", + siteGroup((lineups) => { + lineups.links[0]!.name = "Owner name"; + lineups.links[0]!.notes = "Owner notes"; + }), + 2, + ), + ]); + expect(resent[0]).toEqual({ + opId: "owner-renames", + status: "noop", + currentRevision: 2, + }); + expect(resent[1]).toMatchObject({ + status: "rejected", + reason: "revision_mismatch", + current: { type: "lineup", revision: 3, value: theirs.payload }, + }); + const row = byKey(await pageLineups(owner)).get(siteKey)!; + expect(row.revision).toBe(3); + expect(row.payload).toEqual(theirs.payload); + }); + + test("whose event recorded no revision replays with none, not the row's latest", async () => { + const { t, owner, editor } = await createHarness(); + const mine = addOp(siteGroup(), 0); + const first = await apply(owner, "owner-client", [mine]); + expect(first[0]).toMatchObject({ status: "applied", appliedRevision: 1 }); + // An event written without the revision its op landed at. + await t.run(async (ctx) => { + const event = (await ctx.db.query("operationEvents").collect()).find( + (row) => row.opId === mine.opId, + )!; + await ctx.db.patch(event._id, { appliedRevision: undefined }); + }); + // A teammate moves the row on. + const theirs = siteGroup((lineups) => { + lineups.links[0]!.name = "Editor name"; + }); + await apply(editor, "editor-client", [patchOp("editor-renames", theirs, 1)]); + + // The replay names no revision, so the client cannot rebase a successor + // onto the teammate's edit; the successor, still on 1, meets the usual + // revision check. + const resent = await apply(owner, "owner-client", [ + mine, + patchOp( + "owner-renames", + siteGroup((lineups) => { + lineups.links[0]!.name = "Owner name"; + }), + 1, + ), + ]); + expect(resent[0]).toEqual({ opId: mine.opId, status: "noop" }); + expect(resent[1]).toMatchObject({ + status: "rejected", + reason: "revision_mismatch", + current: { type: "lineup", revision: 2, value: theirs.payload }, + }); + }); +}); + +function elementPayload( + id: string, + kind: "agent" | "drawing" | "text" | "utility", + extra: Record = {}, +) { + return { + kind, + payloadVersion: 1, + data: { + id, + elementType: kind, + ...(kind === "agent" ? { type: "jett" } : {}), + ...extra, + }, + }; +} + +function elementAdd( + id: string, + kind: "agent" | "drawing" | "text" | "utility", + sortIndex: number, +) { + return { + opId: `add-${id}`, + type: "element.add", + elementPublicId: id, + pagePublicId, + payload: elementPayload(id, kind), + sortIndex, + }; +} + +/// Writes a live group of one lineup straight to the table, bypassing +/// applyBatch and so the agent summary refresh. +async function seedLineupRow(t: RootHarness, id: string, agentType: string) { + await t.run(async (ctx) => { + const strategy = await ctx.db + .query("strategies") + .withIndex("by_publicId", (q) => q.eq("publicId", strategyPublicId)) + .unique(); + const page = await ctx.db + .query("pages") + .withIndex("by_strategyId", (q) => q.eq("strategyId", strategy!._id)) + .first(); + const now = Date.now(); + await insertLineup(ctx, { + publicId: id, + strategyId: strategy!._id, + pageId: page!._id, + payloadKind: "lineups", + payloadVersion: 1, + payload: oneLineupPayload(id, { agentType }), + sortIndex: 0, + revision: 1, + deleted: false, + createdAt: now, + updatedAt: now, + }); + }); +} diff --git a/convex/maintenance.ts b/convex/maintenance.ts index e1d4180f..1cd01f07 100644 --- a/convex/maintenance.ts +++ b/convex/maintenance.ts @@ -19,8 +19,12 @@ import { queueAssetReclaim, sweepDeletedImageAssetsRef, } from "./images"; -import { refreshStrategyAgentSummary } from "./lib/strategyAgentSummary"; +import { + refreshStrategyAgentSummary, + syncLineupAgents, +} from "./lib/strategyAgentSummary"; import { PAGE_TRASH_RETENTION_MS } from "./lib/entities"; +import { syncLineupItems } from "./lib/lineupItems"; const MAINTENANCE_BATCH_SIZE = 200; // Content rows can each hold up to ~900 KB (the op size cap), so passes @@ -110,7 +114,13 @@ async function purgeContentRows( purgedAll = false; break; } - await ctx.db.delete("elementId" in row ? row.elementId : row.lineupId); + if ("lineupId" in row) { + await syncLineupAgents(ctx, row.lineupId, null); + await syncLineupItems(ctx, row.lineupId, null); + await ctx.db.delete(row.lineupId); + } else { + await ctx.db.delete(row.elementId); + } } for (const [strategyId, assetPublicIds] of assetIdsByStrategy) { await queueAssetReclaim(ctx, strategyId, assetPublicIds); diff --git a/convex/mediaLimits.test.ts b/convex/mediaLimits.test.ts index 83a67346..aa2c2542 100644 --- a/convex/mediaLimits.test.ts +++ b/convex/mediaLimits.test.ts @@ -12,11 +12,17 @@ import * as images from "./images"; import { processAssetReclaimBatch } from "./images"; import { markAssetReferencesReady } from "./lib/assetReferences"; import { CURRENT_CLOUD_PROTOCOL_VERSION } from "./lib/cloudProtocol"; +import { refreshStrategyAgentSummary } from "./lib/strategyAgentSummary"; import * as maintenance from "./maintenance"; +import * as ops from "./ops"; import schema from "./schema"; import * as strategies from "./strategies"; import { modules } from "./test.setup"; -import { insertElement, insertLineup } from "./testContent.helpers"; +import { + insertElement, + insertLineup, + oneLineupPayload, +} from "./testContent.helpers"; const ensureCurrentUser = makeFunctionReference<"mutation">( "users:ensureCurrentUser", @@ -360,18 +366,9 @@ describe("media cleanup stays within transaction limits", () => { { opId: "link-shows-old-image", type: "lineup.add", - lineupPublicId: "lineupLink:link", + lineupPublicId: "link", pagePublicId, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: "link", - originId: "o", - landingId: "l", - images: [{ id: "old-image" }], - }, - }, + payload: oneLineupPayload("link", { images: [{ id: "old-image" }] }), sortIndex: 0, }, ], @@ -417,13 +414,9 @@ describe("asset references follow their content", () => { { opId: "add-link", type: "lineup.add", - lineupPublicId: "lineupLink:k", + lineupPublicId: "k", pagePublicId, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { id: "k", originId: "o", landingId: "l", images: [{ id: "a" }, { id: "b" }] }, - }, + payload: oneLineupPayload("k", { images: [{ id: "a" }, { id: "b" }] }), sortIndex: 0, }, ], @@ -451,13 +444,9 @@ describe("asset references follow their content", () => { { opId: "drop-b", type: "lineup.patch", - lineupPublicId: "lineupLink:k", + lineupPublicId: "k", pagePublicId, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { id: "k", originId: "o", landingId: "l", images: [{ id: "a" }] }, - }, + payload: oneLineupPayload("k", { images: [{ id: "a" }] }), expectedLineupRevision: 1, }, ], @@ -520,21 +509,14 @@ describe("asset references follow their content", () => { }); for (let index = 0; index < 3; index++) { await ctx.db.insert("lineups", { - publicId: `lineupLink:before-${index}`, + publicId: `before-${index}`, strategyId, pageId, - payloadKind: "lineupLink", + payloadKind: "lineups", payloadVersion: 1, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: `before-${index}`, - originId: "o", - landingId: "l", - images: [{ id: `link-image-${index}` }], - }, - }, + payload: oneLineupPayload(`before-${index}`, { + images: [{ id: `link-image-${index}` }], + }), sortIndex: index, revision: 1, deleted: index === 2, @@ -559,10 +541,10 @@ describe("asset references follow their content", () => { ).mismatched, ]; expect((await mismatched()).sort()).toEqual([ + "before-0", + "before-1", + "before-2", "before-image", - "lineupLink:before-0", - "lineupLink:before-1", - "lineupLink:before-2", ]); await t.mutation(backfillAssetReferences, { @@ -632,21 +614,12 @@ describe("before the reference backfill", () => { }); } await ctx.db.insert("lineups", { - publicId: "lineupLink:live", + publicId: "live", strategyId, pageId, - payloadKind: "lineupLink", + payloadKind: "lineups", payloadVersion: 1, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: "live", - originId: "o", - landingId: "l", - images: [{ id: "lineup-shown" }], - }, - }, + payload: oneLineupPayload("live", { images: [{ id: "lineup-shown" }] }), sortIndex: 0, revision: 1, deleted: false, @@ -710,8 +683,8 @@ describe("before the reference backfill", () => { }); describe("the backfill and its gate", () => { - /// A lineup link showing [images] images, inserted without reference - /// rows, as the previous version wrote it. + /// A lineup showing [images] images, inserted without reference rows, as + /// the previous version wrote it. async function insertOldLineup( t: RootHarness, linkId: string, @@ -721,23 +694,16 @@ describe("the backfill and its gate", () => { await t.run(async (ctx) => { const now = Date.now(); await ctx.db.insert("lineups", { - publicId: `lineupLink:${linkId}`, + publicId: linkId, strategyId, pageId, - payloadKind: "lineupLink", + payloadKind: "lineups", payloadVersion: 1, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: linkId, - originId: "o", - landingId: "l", - images: Array.from({ length: images }, (_, index) => ({ - id: `${linkId}-${index}`, - })), - }, - }, + payload: oneLineupPayload(linkId, { + images: Array.from({ length: images }, (_, index) => ({ + id: `${linkId}-${index}`, + })), + }), sortIndex: 0, revision: 1, deleted: false, @@ -967,12 +933,12 @@ describe("the backfill and its gate", () => { }); expect(result.unavailable).toEqual([ { - content: "lineupLink:shown", + content: "shown", assetPublicId: "shown-1", statuses: ["deleted"], }, { - content: "lineupLink:shown", + content: "shown", assetPublicId: "shown-2", statuses: ["pending"], }, @@ -989,23 +955,16 @@ describe("purges stay within transaction limits", () => { await t.run(async (ctx) => { for (let lineup = 0; lineup < 5; lineup++) { await insertLineup(ctx, { - publicId: `lineupLink:many-${lineup}`, + publicId: `many-${lineup}`, strategyId, pageId, - payloadKind: "lineupLink", + payloadKind: "lineups", payloadVersion: 1, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: `many-${lineup}`, - originId: "o", - landingId: "l", - images: Array.from({ length: 850 }, (_, image) => ({ - id: `image-${lineup}-${image}`, - })), - }, - }, + payload: oneLineupPayload(`many-${lineup}`, { + images: Array.from({ length: 850 }, (_, image) => ({ + id: `image-${lineup}-${image}`, + })), + }), sortIndex: lineup, revision: 2, deleted: true, @@ -1231,28 +1190,100 @@ describe("duplicate stays within transaction limits", () => { expect(summary?.agentTypes).toEqual(["jett"]); }); + test("the agent summary never reads lineup rows, however large they are", async () => { + const { t, owner } = await createHarness(); + const { strategyId, pageId } = await ids(t); + // 25 lineups as large as the op size cap allows: more than the 16 MiB a + // transaction may read, were the summary to read them. + const agentTypes = ["sova", "kayo", "viper"]; + await t.run(async (ctx) => { + const now = Date.now(); + for (let index = 0; index < 25; index++) { + await insertLineup(ctx, { + publicId: `big-${index}`, + strategyId, + pageId, + payloadKind: "lineups", + payloadVersion: 1, + payload: oneLineupPayload(`big-${index}`, { + agentType: agentTypes[index % agentTypes.length], + notes: largeText, + }), + sortIndex: index, + revision: 1, + deleted: false, + createdAt: now, + updatedAt: now, + }); + } + }); + const lineupBytes = await t.run(async (ctx) => + (await ctx.db.query("lineups").collect()) + .map((row) => getConvexSize(row as any)) + .reduce((a, b) => a + b, 0), + ); + expect(lineupBytes).toBeGreaterThan(16 * 1024 * 1024); + + const refreshRead = await t.run(async (ctx) => { + const counted = countReads(ctx); + await refreshStrategyAgentSummary(counted.ctx, strategyId); + return counted.bytesRead(); + }); + expect(refreshRead).toBeLessThan(64 * 1024); + const summary = async () => + await t.run(async (ctx) => { + const row = await ctx.db + .query("strategyAgentSummaries") + .withIndex("by_strategyId", (q) => q.eq("strategyId", strategyId)) + .unique(); + return row?.agentTypes; + }); + // 9 sova origins, 8 kayo, 8 viper. + expect(await summary()).toEqual(["sova", "kayo", "viper"]); + + // A lineup edit, which refreshes the summary, reads the lineup it + // edits and not the others. + const batchRead = await owner.run(async (ctx) => { + const counted = countReads(ctx); + await (ops.applyBatch as any)._handler(counted.ctx, { + ...protocol, + strategyPublicId, + clientId: "big-editor", + ops: [ + { + opId: "big-0-to-jett", + type: "lineup.patch", + lineupPublicId: "big-0", + pagePublicId, + payload: oneLineupPayload("big-0", { + agentType: "jett", + notes: largeText, + }), + expectedLineupRevision: 1, + }, + ], + }); + return counted.bytesRead(); + }); + expect(batchRead).toBeLessThan(lineupBytes / 4); + expect(await summary()).toEqual(["kayo", "sova", "viper", "jett"]); + }); + async function seedLinkImages(t: RootHarness, count: number) { const { strategyId, pageId } = await ids(t); await t.run(async (ctx) => { const now = Date.now(); await insertLineup(ctx, { - publicId: "lineupLink:gallery", + publicId: "gallery", strategyId, pageId, - payloadKind: "lineupLink", + payloadKind: "lineups", payloadVersion: 1, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: "gallery", - originId: "o", - landingId: "l", - images: Array.from({ length: count }, (_, index) => ({ - id: `gallery-${index}`, - })), - }, - }, + payload: oneLineupPayload("gallery", { + images: Array.from({ length: count }, (_, index) => ({ + id: `gallery-${index}`, + })), + }), sortIndex: 0, revision: 1, deleted: false, diff --git a/convex/ops.ts b/convex/ops.ts index 1be82a06..f871506b 100644 --- a/convex/ops.ts +++ b/convex/ops.ts @@ -2,7 +2,10 @@ import { mutation, type MutationCtx } from "./_generated/server"; import { ConvexError, v, type Infer } from "convex/values"; import type { Doc, Id } from "./_generated/dataModel"; import { assertCallerIsAccount, assertStrategyRole } from "./lib/auth"; -import { refreshStrategyAgentSummary } from "./lib/strategyAgentSummary"; +import { + refreshStrategyAgentSummary, + syncLineupAgents, +} from "./lib/strategyAgentSummary"; import { expectAssets, referencedAssetIds, @@ -35,6 +38,8 @@ import { cloudProtocolArgs, } from "./lib/cloudProtocol"; import { valuesEqual } from "./lib/canonicalValues"; +import { assertLineupGroupAlone, syncLineupItems } from "./lib/lineupItems"; +import { LINEUPS_PAYLOAD_VERSION } from "./lib/payloadValidators"; import { errorWithCode, invalidPayloadError, @@ -335,20 +340,16 @@ function assertElementPayload(payload: unknown): ElementPayload { return payload as ElementPayload; } -const lineupGraphKinds = new Set([ - "lineupOrigin", - "lineupLanding", - "lineupLink", -]); - function invalidLineupData(message: string) { return errorWithCode("INVALID_LINEUP_PAYLOAD_DATA", message); } -/// Checks one lineup row before it is stored. A graph row (origin, landing -/// or link) is keyed `:`: entity ids repeat across -/// kinds (a landing made with a link shares the link's id), so the kind is -/// part of the key, and the key must name the entity the payload holds. +/// Checks one lineup group row before it is stored: a group keyed by its +/// id, whose origins, landings and links each have an id unique among their +/// kind, each origin placing an agent and each landing an ability, with at +/// least one link, and every link joining an origin and a landing the row +/// holds. A row that breaks any of these is refused whole, never stored. +/// A spot no link uses is allowed. function assertLineupPayload( payload: unknown, lineupPublicId: string, @@ -356,16 +357,16 @@ function assertLineupPayload( if (!isRecord(payload)) { throw errorWithCode("MISSING_LINEUP_PAYLOAD", "Missing lineup payload"); } - // Lineups are stored only as graph rows. The legacy `lineupGroup` shape is - // not part of the contract (argument validation already refuses it); this - // check keeps the rule where the row is written. - if (!lineupGraphKinds.has(payload.kind)) { + // Argument validation lets the graph rows of protocol 4 through, so an old + // client reaches the protocol gate (see lineupOpPayloadValidator); none is + // ever stored. + if (payload.kind !== "lineups") { throw errorWithCode( "INVALID_LINEUP_PAYLOAD_KIND", "Invalid lineup payload kind", ); } - if (typeof payload.payloadVersion !== "number") { + if (payload.payloadVersion !== LINEUPS_PAYLOAD_VERSION) { throw errorWithCode( "INVALID_LINEUP_PAYLOAD_VERSION", "Invalid lineup payload version", @@ -379,28 +380,83 @@ function assertLineupPayload( } const data = payload.data; if (typeof data.id !== "string" || data.id.length === 0) { - throw invalidLineupData("Lineup payload has no id"); + throw invalidLineupData("Lineup group has no id"); } - if (lineupPublicId !== `${payload.kind}:${data.id}`) { - throw invalidLineupData("Lineup key does not match its payload"); + if (lineupPublicId !== data.id) { + throw invalidLineupData("Lineup group key does not match its payload"); } - // Each entity must carry what hydration draws; a row without it would load - // as nothing and read as a deletion nobody made. - if (payload.kind === "lineupOrigin" && !isRecord(data.agent)) { - throw invalidLineupData("Lineup origin has no agent"); + const originIds = idsOfEntries(data.origins, "origins", "agent"); + const landingIds = idsOfEntries(data.landings, "landings", "ability"); + idsOfEntries(data.links, "links"); + const links = data.links as Array>; + // A group without a lineup would load as nothing and read as a deletion + // nobody made. + if (links.length === 0) { + throw invalidLineupData("Lineup group has no lineups"); } - if (payload.kind === "lineupLanding" && !isRecord(data.ability)) { - throw invalidLineupData("Lineup landing has no ability"); - } - if ( - payload.kind === "lineupLink" && - (typeof data.originId !== "string" || typeof data.landingId !== "string") - ) { - throw invalidLineupData("Lineup link does not name its origin and landing"); + for (const link of links) { + if ( + typeof link.originId !== "string" || + !originIds.has(link.originId) || + typeof link.landingId !== "string" || + !landingIds.has(link.landingId) + ) { + throw invalidLineupData( + "A lineup names an origin or landing its group does not hold", + ); + } } return payload as LineupPayload; } +/// The ids of a lineup group's [field] (its origins, landings or links), +/// refusing the row unless [entries] is a list of objects each with an id +/// no other entry in it shares, and, given a [markerKey], the object it +/// places there. +function idsOfEntries( + entries: unknown, + field: string, + markerKey?: "agent" | "ability", +): Set { + if (!Array.isArray(entries)) { + throw invalidLineupData(`Lineup group ${field} is not a list`); + } + const ids = new Set(); + for (const entry of entries) { + if ( + !isRecord(entry) || + typeof entry.id !== "string" || + entry.id.length === 0 + ) { + throw invalidLineupData(`Lineup group ${field} has an entry with no id`); + } + if (ids.has(entry.id)) { + throw invalidLineupData(`Two of a lineup group's ${field} share an id`); + } + if (markerKey !== undefined && !isRecord(entry[markerKey])) { + throw invalidLineupData( + `Lineup group ${field} has an entry with no ${markerKey}`, + ); + } + ids.add(entry.id); + } + return ids; +} + +/// A patch or reorder of a row a teammate deleted. Changing the tombstone +/// would ack an edit nobody sees, so it is refused; an add expecting the +/// tombstone's revision brings the row back instead ("Keep mine"). +function refuseChangeToDeleted( + row: Doc<"elements"> | Doc<"lineups">, +): OperationResult | null { + if (!row.deleted) return null; + return rejected( + "deleted", + { revision: row.revision, payload: row.payload }, + row.pageId, + ); +} + function setIfChanged( patch: Record, key: string, @@ -510,8 +566,7 @@ async function getElementByPublicIdOrNull( } /// A lineup row key is unique within its strategy only: a strategy copied -/// before the graph synced natively shares its original's item ids, so both -/// convert to the same `lineupLanding:` and `lineupLink:` keys. +/// on a device keeps its original's lineup ids, so both upload the same keys. async function getLineupByPublicIdOrNull( ctx: MutationCtx, strategyId: Id<"strategies">, @@ -525,122 +580,6 @@ async function getLineupByPublicIdOrNull( .unique(); } -/// A link is drawn only while its origin and landing are live rows on its -/// page (see lineUpGraphFromCloudRows on the client). Storing a link whose -/// end is gone, say one a teammate deleted while it was being placed, would -/// make the lineup vanish on the next load with nothing on screen, so it is -/// refused instead. Ends are read in this transaction: one added earlier in -/// the same batch counts. -async function assertLinkEndsLive( - ctx: MutationCtx, - strategyId: Id<"strategies">, - pageId: Id<"pages">, - payload: LineupPayload, -): Promise { - if (payload.kind !== "lineupLink") return; - const data = payload.data as { originId: string; landingId: string }; - for (const endKey of [ - `lineupOrigin:${data.originId}`, - `lineupLanding:${data.landingId}`, - ]) { - const end = await getLineupByPublicIdOrNull(ctx, strategyId, endKey); - if (end === null || end.deleted || end.pageId !== pageId) { - // The client matches this text (lineupLinkEndMissingMessage) to - // re-send the link as it was on "Keep mine". - throw errorWithCode( - "LINEUP_LINK_END_MISSING", - "This lineup's origin or landing spot is no longer on the page", - ); - } - } -} - -/// The origin and landing each live link names, per page, as this batch -/// has left them. A page's links are read once, when an end on it is first -/// deleted, and the batch's own link writes update that copy, so a batch -/// deleting many lineups reads each page's links once rather than once per -/// end. -class LiveLinkEnds { - private readonly byPage = new Map< - Id<"pages">, - Map - >(); - - async of(ctx: MutationCtx, pageId: Id<"pages">) { - let links = this.byPage.get(pageId); - if (links === undefined) { - const rows = await ctx.db - .query("lineups") - .withIndex("by_pageId_and_payloadKind_and_deleted", (q) => - q - .eq("pageId", pageId) - .eq("payloadKind", "lineupLink") - .eq("deleted", false), - ) - .collect(); - links = new Map(rows.map((row) => [row.publicId, linkEnds(row.payload)])); - this.byPage.set(pageId, links); - } - return links; - } - - /// Follows an accepted lineup op. A page not read yet needs nothing: its - /// read will see the write. - recordAccepted(op: StrategyOp, pageId: Id<"pages"> | undefined): void { - const links = pageId === undefined ? undefined : this.byPage.get(pageId); - const publicId = op.entityPublicId; - if (links === undefined || publicId === undefined) return; - if (!publicId.startsWith("lineupLink:")) return; - if (op.kind === "delete") { - links.delete(publicId); - } else if (op.kind === "add") { - // An accepted add inserts the link or restores its tombstone. - links.set(publicId, linkEnds(op.payload as LineupPayload)); - } else if (op.payload !== undefined && links.has(publicId)) { - // A patch never changes whether a link is live; one to a tombstone - // stays out. - links.set(publicId, linkEnds(op.payload as LineupPayload)); - } - } -} - -function linkEnds(payload: LineupPayload) { - const data = payload.data as Record; - return { originId: data.originId, landingId: data.landingId }; -} - -/// The mirror of assertLinkEndsLive: deleting an origin or landing that a -/// live link on its page still names would leave that link undrawable, so -/// its lineup would vanish on the next load while every chip says synced. -/// That happens when a teammate's new link lands first and this client -/// never saw it. The delete is refused instead. A link deleted earlier in -/// the same batch is already gone here, so a client deleting a whole -/// lineup sends its link first. -async function assertLineupEndUnused( - ctx: MutationCtx, - end: Doc<"lineups">, - liveLinkEnds: LiveLinkEnds, -): Promise { - const endField = - end.payloadKind === "lineupOrigin" - ? "originId" - : end.payloadKind === "lineupLanding" - ? "landingId" - : null; - if (endField === null) return; - const endId = (end.payload.data as { id: string }).id; - const links = await liveLinkEnds.of(ctx, end.pageId); - for (const ends of links.values()) { - if (ends[endField] === endId) { - // The client matches this text (lineupEndInUseMessage). - throw errorWithCode( - "LINEUP_END_IN_USE", - "Another lineup still uses this origin or landing spot", - ); - } - } -} - async function getPageContent( ctx: MutationCtx, pageId: Id<"pages">, @@ -747,6 +686,7 @@ function isRejectionReason( ): reason is Extract["reason"] { return ( reason === "already_exists" || + reason === "deleted" || reason === "element_strategy_mismatch" || reason === "lineup_strategy_mismatch" || reason === "missing_expected_revision" || @@ -1305,6 +1245,8 @@ async function applyElementOp( return rejected("not_found"); } await assertContentPageLive(ctx, existing.pageId); + const deleted = refuseChangeToDeleted(existing); + if (deleted !== null) return deleted; const patch: Record = {}; let eventPageId = existing.pageId; if (op.kind === "patch") { @@ -1367,10 +1309,7 @@ async function applyLineupOp( ctx: MutationCtx, strategy: Doc<"strategies">, op: StrategyOp, - checkLinkEnds: boolean, - checkEndDeletes: boolean, checkTrashedPageDeletes: boolean, - liveLinkEnds: LiveLinkEnds, ): Promise { const publicId = op.entityPublicId; if (publicId === undefined) { @@ -1399,9 +1338,7 @@ async function applyLineupOp( existing.pageId, ); } - if (checkLinkEnds) { - await assertLinkEndsLive(ctx, strategy._id, page._id, payload); - } + await assertLineupGroupAlone(ctx, page._id, existing._id, payload); const revision = existing.revision + 1; await ctx.db.patch(existing._id, { pageId: page._id, @@ -1419,9 +1356,9 @@ async function applyLineupOp( eventPageId: page._id, }; } - // The row already holds exactly this entity: two clients converted the - // same legacy group, or a retry landed twice. Order is not part of a - // lineup's content (each client places new rows after the highest it + // The row already holds exactly this lineup: a retry landed twice, or + // two devices uploaded the same copied strategy. Order is not part of + // a lineup's content (each client places new rows after the highest it // knows), so a different sortIndex alone is still the same add. const identical = existing.pageId === page._id && valuesEqual(existing.payload, payload); @@ -1432,9 +1369,7 @@ async function applyLineupOp( existing.pageId, ); } - if (checkLinkEnds) { - await assertLinkEndsLive(ctx, strategy._id, page._id, payload); - } + await assertLineupGroupAlone(ctx, page._id, null, payload); const now = Date.now(); await ctx.db.insert("lineups", { publicId, @@ -1470,9 +1405,6 @@ async function applyLineupOp( existing.pageId, ); } - if (checkEndDeletes) { - await assertLineupEndUnused(ctx, existing, liveLinkEnds); - } const revision = existing.revision + 1; await ctx.db.patch(existing._id, { deleted: true, @@ -1490,6 +1422,8 @@ async function applyLineupOp( return rejected("not_found"); } await assertContentPageLive(ctx, existing.pageId); + const deleted = refuseChangeToDeleted(existing); + if (deleted !== null) return deleted; const patch: Record = {}; let eventPageId = existing.pageId; if (op.kind === "patch") { @@ -1547,12 +1481,12 @@ async function applyLineupOp( existing.pageId, ); } - if (checkLinkEnds && op.kind === "patch" && op.payload !== undefined) { - await assertLinkEndsLive( + if (patch.payload !== undefined) { + await assertLineupGroupAlone( ctx, - strategy._id, existing.pageId, - op.payload as LineupPayload, + existing._id, + patch.payload as LineupPayload, ); } const revision = existing.revision + 1; @@ -1564,6 +1498,10 @@ async function applyLineupOp( return { status: "ack", appliedRevision: revision, eventPageId }; } +function isAgentRow(row: Doc<"elements"> | Doc<"lineups"> | null): boolean { + return row !== null && "elementType" in row && row.elementType === "agent"; +} + /// The element or lineup row an op targets in this strategy, if any. async function contentRowForOp( ctx: MutationCtx, @@ -1610,6 +1548,8 @@ async function reconcileExpectedAssets( await syncElementAssetReferences(ctx, row._id, row); } else { await syncLineupAssetReferences(ctx, row._id, row); + await syncLineupAgents(ctx, row._id, row); + await syncLineupItems(ctx, row._id, row); } const now = Date.now(); const assetsBefore = referencedAssetIds(rowBefore); @@ -1642,19 +1582,17 @@ export const applyBatch = mutation({ strategyPublicId: v.string(), clientId: v.string(), ops: v.array(strategyOpValidator), - // Set by clients that send a link only once its origin and landing are - // sent (see assertLinkEndsLive). Older clients may send a link a batch - // ahead of its ends, so their links are not checked. - checkLineupLinkEnds: v.optional(v.boolean()), - // Set by clients that send an origin or landing delete only after the - // link deletes on its page (see assertLineupEndUnused). Older clients - // may send them in any order, so their deletes are not checked. - checkLineupEndDeletes: v.optional(v.boolean()), // Set by clients that can restore a deleted page (pages:restore): a // delete of content on a page in the trash is refused, to be sent again // once the page is back. Older clients get the no-op a deleted page's // purged content gave them (see refuseDeleteOffLivePage). checkTrashedPageDeletes: v.optional(v.boolean()), + // Sent by clients on protocol 4, which stored lineups as origin, + // landing and link rows. Ignored: accepting them lets such a client + // reach the protocol gate (CLIENT_UPGRADE_REQUIRED) instead of failing + // argument validation. + checkLineupLinkEnds: v.optional(v.boolean()), + checkLineupEndDeletes: v.optional(v.boolean()), // Set by clients that bind a batch to the account whose outbox holds // it: that account's identity subject. A batch can reach the server // under a different sign-in than the one that queued it (the transport @@ -1673,11 +1611,13 @@ export const applyBatch = mutation({ const { user } = await assertStrategyRole(ctx, strategy, "editor"); const results: PublicOperationResult[] = []; let acceptedStrategyBatchBaseRevision: number | undefined; - let contentChanged = false; + // Whether an accepted op may have changed which agents the strategy + // uses: a page added, moved to or out of the trash, an agent element, + // or a lineup. + let agentsMayHaveChanged = false; // Images deleted elements showed, whose upload placeholders may go once // the whole batch has applied and nothing shows them any more. const placeholderCandidates = new Set(); - const liveLinkEnds = new LiveLinkEnds(); // Outcomes are per operation: accepted changes and visible rejections are // committed together by this single Convex transaction. One stale op must @@ -1695,6 +1635,11 @@ export const applyBatch = mutation({ .first(); if (existingEvent !== null) { const latest = await getTargetSnapshot(ctx, strategy, op); + // An accepted op replays at the revision it landed at, not the + // row's latest: a successor rebased onto a teammate's later edit + // would overwrite that edit unseen. An event that recorded no + // revision replays with none, for the same reason; the client then + // keeps its base revision and a later edit meets the usual check. const replayResult: OperationResult = existingEvent.status === "failed" ? { @@ -1710,7 +1655,7 @@ export const applyBatch = mutation({ latestRevision: latest?.revision, latestPayload: latest?.payload, } - : noop(latest?.revision); + : noop(existingEvent.appliedRevision); results.push(toPublicResult(op, replayResult)); continue; } @@ -1765,17 +1710,19 @@ export const applyBatch = mutation({ ctx, strategy, op, - args.checkLineupLinkEnds === true, - args.checkLineupEndDeletes === true, args.checkTrashedPageDeletes === true, - liveLinkEnds, ); - if (result.status === "ack") { - liveLinkEnds.recordAccepted(op, result.eventPageId); - } } - if (result.status === "ack" && op.entityType !== "strategy") { - contentChanged = true; + if ( + result.status === "ack" && + (op.entityType === "page" || + op.entityType === "lineup" || + (op.entityType === "element" && + (isAgentRow(rowBefore) || + (op.payload as { kind?: unknown } | undefined)?.kind === + "agent"))) + ) { + agentsMayHaveChanged = true; } if (result.status === "ack") { await reconcileExpectedAssets( @@ -1846,7 +1793,7 @@ export const applyBatch = mutation({ // Checked against the batch's final state, once. await removeUploadPlaceholders(ctx, strategy._id, placeholderCandidates); - if (contentChanged) { + if (agentsMayHaveChanged) { await refreshStrategyAgentSummary(ctx, strategy._id); } diff --git a/convex/pageTrash.test.ts b/convex/pageTrash.test.ts index bac15bf1..7b8012fd 100644 --- a/convex/pageTrash.test.ts +++ b/convex/pageTrash.test.ts @@ -11,6 +11,7 @@ import { CURRENT_CLOUD_PROTOCOL_VERSION } from "./lib/cloudProtocol"; import { PAGE_TRASH_RETENTION_MS } from "./lib/entities"; import { UNKNOWN_DISPLAY_NAME } from "./lib/profile"; import schema from "./schema"; +import { lineupsPayload, oneLineupPayload } from "./testContent.helpers"; import { modules } from "./test.setup"; const ensureCurrentUser = makeFunctionReference<"mutation">( @@ -107,30 +108,27 @@ function imagePayload(assetPublicId: string) { }; } +/// Two lineup groups: one of two lineups thrown from one sova origin, the +/// first showing an image, and one of a single lineup from another. const lineupRows = [ { - lineupPublicId: "lineupOrigin:o", - payload: { - kind: "lineupOrigin" as const, - payloadVersion: 1, - data: { id: "o", agent: { id: "agent-o", type: "sova", lineUpID: "o" } }, - }, - }, - { - lineupPublicId: "lineupLanding:l", - payload: { - kind: "lineupLanding" as const, - payloadVersion: 1, - data: { id: "l", ability: { id: "ability-l" } }, - }, + lineupPublicId: "k", + payload: lineupsPayload("k", { + origins: [{ id: "o", agentType: "sova" }], + landings: [{ id: "l" }, { id: "l2" }], + links: [ + { id: "k", originId: "o", landingId: "l", images: [{ id: "k-shot" }] }, + { id: "k-2", originId: "o", landingId: "l2" }, + ], + }), }, { - lineupPublicId: "lineupLink:k", - payload: { - kind: "lineupLink" as const, - payloadVersion: 1, - data: { id: "k", originId: "o", landingId: "l", images: [{ id: "k-shot" }] }, - }, + lineupPublicId: "k2", + payload: oneLineupPayload("k2", { + originId: "o2", + landingId: "l3", + agentType: "sova", + }), }, ]; @@ -327,6 +325,9 @@ async function rowsOnPage(t: RootHarness, pageId: Id<"pages">) { references: (await ctx.db.query("assetReferences").collect()).filter( (reference) => reference.pageId === pageId, ), + lineupAgents: (await ctx.db.query("lineupAgents").collect()).filter( + (row) => row.pageId === pageId, + ), })); } @@ -368,10 +369,15 @@ describe("page trash", () => { expect(trashed?.deletedAt).toEqual(expect.any(Number)); const kept = await rowsOnPage(t, trashed!._id); expect(kept.elements).toHaveLength(3); - expect(kept.lineups).toHaveLength(3); + expect(kept.lineups).toHaveLength(2); expect(kept.contents).toHaveLength(1); expect(kept.references.map((reference) => reference.assetPublicId).sort()) .toEqual(["b-image", "k-shot"]); + // The lineups' agent rows stay with them for a restore; the summary + // below leaves them out because their page is in the trash. + expect(kept.lineupAgents.map((row) => row.lineupId).sort()).toEqual( + kept.lineups.map((row) => row._id).sort(), + ); const shell = (await owner.query(getShell, { ...protocol, @@ -543,28 +549,30 @@ describe("page trash", () => { }, { type: "lineup.add", - lineupPublicId: "lineupLanding:l2", + lineupPublicId: "k3", pagePublicId: pageB, - payload: { - kind: "lineupLanding", - payloadVersion: 1, - data: { id: "l2", ability: { id: "ability-l2" } }, - }, + payload: oneLineupPayload("k3", { originId: "o3", landingId: "l4" }), sortIndex: 3, }, { type: "lineup.patch", - lineupPublicId: "lineupLink:k", + lineupPublicId: "k", pagePublicId: pageB, payload: { - ...lineupRows[2]!.payload, - data: { ...lineupRows[2]!.payload.data, name: "edited" }, + ...lineupRows[0]!.payload, + data: { + ...lineupRows[0]!.payload.data, + links: lineupRows[0]!.payload.data.links.map((link) => ({ + ...link, + name: "edited", + })), + }, }, expectedLineupRevision: 1, }, { type: "lineup.delete", - lineupPublicId: "lineupLink:k", + lineupPublicId: "k", pagePublicId: pageB, expectedLineupRevision: 1, }, @@ -785,7 +793,7 @@ describe("page trash", () => { }, { type: "lineup.delete", - lineupPublicId: "lineupLink:k", + lineupPublicId: "k", pagePublicId: pageB, expectedLineupRevision: 1, }, @@ -884,6 +892,7 @@ describe("page trash", () => { lineups: [], contents: [], references: [], + lineupAgents: [], }); expect(await rowsOnPage(t, liveA!._id)).toEqual(aRows); expect(await livePageIds(owner)).toEqual([pageA, pageC]); @@ -1068,6 +1077,7 @@ describe("page trash", () => { lineups: [], contents: [], references: [], + lineupAgents: [], }); }); }); diff --git a/convex/referencedAssetIds.test.ts b/convex/referencedAssetIds.test.ts index 5ca9b7b0..1dd3719e 100644 --- a/convex/referencedAssetIds.test.ts +++ b/convex/referencedAssetIds.test.ts @@ -9,6 +9,7 @@ import type { DataModel } from "./_generated/dataModel"; import { markAssetReferencesReady } from "./lib/assetReferences"; import { CURRENT_CLOUD_PROTOCOL_VERSION } from "./lib/cloudProtocol"; import schema from "./schema"; +import { oneLineupPayload } from "./testContent.helpers"; import { modules } from "./test.setup"; const ensureCurrentUser = makeFunctionReference<"mutation">( @@ -106,18 +107,9 @@ async function seed(t: RootHarness): Promise { }, { type: "lineup.add", - lineupPublicId: "lineupLink:k", + lineupPublicId: "k", pagePublicId, - payload: { - kind: "lineupLink" as const, - payloadVersion: 1, - data: { - id: "k", - originId: "o", - landingId: "l", - images: [{ id: "shot" }], - }, - }, + payload: oneLineupPayload("k", { images: [{ id: "shot" }] }), sortIndex: 0, }, ]); diff --git a/convex/schema.ts b/convex/schema.ts index fe3e1093..7d274020 100644 --- a/convex/schema.ts +++ b/convex/schema.ts @@ -105,9 +105,13 @@ export default defineSchema({ publicId: v.string(), strategyId: v.id("strategies"), pageId: v.id("pages"), - // Graph rows are keyed `:`; see ops.ts. A key is - // unique within its strategy, not across strategies: a copied strategy - // may reuse its original's entity ids. + // One row per lineup group: the lineups on one page joined through + // shared spots, holding its origins, landings and links. Keyed by the + // group's id (payload.data.id). A key is unique within its strategy, not + // across strategies: a strategy copied on a device keeps its original's + // lineup ids. + // This shape replaced the origin/landing/link rows with no migration: + // production and dev held no lineup rows when it shipped (2026-10-02). payloadKind: lineupPayloadKindValidator, payloadVersion: v.number(), payload: lineupPayloadValidator, @@ -119,16 +123,33 @@ export default defineSchema({ }) .index("by_strategyId_and_publicId", ["strategyId", "publicId"]) .index("by_pageId", ["pageId"]) - .index("by_strategyId", ["strategyId"]) - .index("by_strategyId_and_payloadKind", ["strategyId", "payloadKind"]) - // Live links on a page, read when an origin or landing is deleted (see - // assertLineupEndUnused in ops.ts). - .index("by_pageId_and_payloadKind_and_deleted", [ - "pageId", - "payloadKind", - "deleted", - ]) .index("by_deleted_and_updatedAt", ["deleted", "updatedAt"]), + // The agents a live lineup group starts from: one small row per origin in + // the group, kept in step with every lineup write (see + // lib/strategyAgentSummary.ts). The strategy's agent summary reads these + // instead of the lineup rows, whose image lists can make reading them all + // exceed a transaction's limits. + lineupAgents: defineTable({ + strategyId: v.id("strategies"), + pageId: v.id("pages"), + lineupId: v.id("lineups"), + originId: v.string(), + agentType: v.string(), + }) + .index("by_strategyId", ["strategyId"]) + .index("by_lineupId", ["lineupId"]), + // The lineups and spots each live lineup group holds, one small row per + // item (`origin:`, `landing:` or `link:`), kept in step with + // every lineup write (see lib/lineupItems.ts). A write is refused if it + // would put an item in two groups of a page; the check reads these rows + // instead of the lineup rows, whose image lists can be large. + lineupItems: defineTable({ + pageId: v.id("pages"), + lineupId: v.id("lineups"), + item: v.string(), + }) + .index("by_pageId_and_item", ["pageId", "item"]) + .index("by_lineupId", ["lineupId"]), // Which content rows show which images: one small row per (element or // lineup row, image id it shows), kept in step with every content write // (see lib/assetReferences.ts). Media cleanup checks an image's references diff --git a/convex/strategies.ts b/convex/strategies.ts index 17c9fbb6..11c7e7f5 100644 --- a/convex/strategies.ts +++ b/convex/strategies.ts @@ -3,6 +3,7 @@ import { getConvexSize, v, type Value } from "convex/values"; import { agentTypesOf, deleteStrategyAgentSummary, + lineupAgentsOf, refreshStrategyAgentSummary, storeStrategyAgentSummary, } from "./lib/strategyAgentSummary"; @@ -22,6 +23,7 @@ import { requireCurrentUser, } from "./lib/auth"; import type { StrategyRole } from "./lib/auth"; +import { lineupGroupItems } from "./lib/lineupItems"; import { getFolderByPublicId, getStrategyByPublicId, @@ -44,7 +46,6 @@ import { assetIdsOfRow, insertAssetReferences, type ReferencingElement, - type ReferencingLineup, } from "./lib/assetReferences"; import { purgeDeletedPageOrphansRef } from "./maintenance"; import { markDeletedStrategyImageAssetsRef } from "./images"; @@ -536,11 +537,10 @@ function isJsonObject(value: unknown): value is Record { type LineupPayload = Doc<"lineups">["payload"]; -/// New entity ids for a copied strategy's lineups: one map across every -/// kind, shared by every row. The source's lineups may share ids across -/// kinds (a landing may take its link's id), and the copy keeps that shape, -/// so a link still names its origin and landing whatever order the rows are -/// copied in. Keys stay unique through the kind prefix. +/// New ids for a copied strategy's lineups: one map shared by every row and +/// every id in it, so one source id always becomes one copy id. Ids the +/// source repeats within a group (a landing may take its lineup's id, a +/// link names its origin and landing) repeat in the copy the same way. function lineupIdMap() { const ids = new Map(); return (id: string): string => { @@ -550,63 +550,57 @@ function lineupIdMap() { }; } -/// A lineup row as the copy stores it: its `:` key and -/// payload under new ids, with every nested reference following its entity. +/// A lineup group row as the copy stores it: the group, its origins, +/// landings and links under new ids, each link naming its ends' new ids and +/// each marker's `lineUpID` following its spot. Everything else is kept as +/// it is. function copiedLineupRow( payload: LineupPayload, newId: (id: string) => string, ): { publicId: string; payload: LineupPayload } { const data = payload.data; const idOf = (value: unknown) => (typeof value === "string" ? value : ""); - switch (payload.kind) { - case "lineupOrigin": { - const id = newId(idOf(data.id)); - const agent = data.agent; - return { - publicId: `lineupOrigin:${id}`, - payload: { - ...payload, - data: { - ...data, - id, - ...(isJsonObject(agent) ? { agent: { ...agent, lineUpID: id } } : {}), - } as LineupData, - }, - }; - } - case "lineupLanding": { - const id = newId(idOf(data.id)); - const ability = data.ability; - return { - publicId: `lineupLanding:${id}`, - payload: { - ...payload, - data: { - ...data, - id, - ...(isJsonObject(ability) - ? { ability: { ...ability, lineUpID: id } } - : {}), - } as LineupData, - }, - }; - } - case "lineupLink": { - const id = newId(idOf(data.id)); - return { - publicId: `lineupLink:${id}`, - payload: { - ...payload, - data: { - ...data, - id, - originId: newId(idOf(data.originId)), - landingId: newId(idOf(data.landingId)), - } as LineupData, - }, - }; - } - } + const entries = (value: unknown): unknown[] => + Array.isArray(value) ? value : []; + const copiedSpot = (spot: unknown, markerKey: "agent" | "ability") => { + if (!isJsonObject(spot)) return spot; + const id = newId(idOf(spot.id)); + const marker = spot[markerKey]; + return { + ...spot, + id, + ...(isJsonObject(marker) + ? { [markerKey]: { ...marker, lineUpID: id } } + : {}), + }; + }; + const copiedLink = (link: unknown) => + isJsonObject(link) + ? { + ...link, + id: newId(idOf(link.id)), + originId: newId(idOf(link.originId)), + landingId: newId(idOf(link.landingId)), + } + : link; + const id = newId(idOf(data.id)); + return { + publicId: id, + payload: { + ...payload, + data: { + ...data, + id, + origins: entries(data.origins).map((origin) => + copiedSpot(origin, "agent"), + ), + landings: entries(data.landings).map((landing) => + copiedSpot(landing, "ability"), + ), + links: entries(data.links).map(copiedLink), + } as LineupData, + }, + }; } // A duplicate is one transaction, and Convex refuses a transaction past @@ -792,8 +786,10 @@ export const duplicate = mutation({ ); } const copiedElements: ReferencingElement[] = []; - const copiedLineups: (ReferencingLineup & - Pick, "payloadKind">)[] = []; + const copiedLineupAgents: Pick< + Doc<"lineupAgents">, + "pageId" | "originId" | "agentType" + >[] = []; for (const element of sourceElements) { const pageId = pageIdMap.get(element.pageId); if (element.deleted || pageId === undefined) continue; @@ -850,7 +846,21 @@ export const duplicate = mutation({ budget.spend({ documents: assetIdsOfRow(copiedLineup).size }); const lineupId = await ctx.db.insert("lineups", copiedLineup); await insertAssetReferences(ctx, { lineupId }, copiedLineup); - copiedLineups.push(copiedLineup); + for (const agent of lineupAgentsOf(copiedLineup.payload)) { + budget.spend({ documents: 1 }); + await ctx.db.insert("lineupAgents", { + strategyId, + pageId, + lineupId, + ...agent, + }); + copiedLineupAgents.push({ pageId, ...agent }); + } + const items = lineupGroupItems(copiedLineup.payload); + budget.spend({ documents: items.size }); + for (const item of items) { + await ctx.db.insert("lineupItems", { pageId, lineupId, item }); + } } for (const [targetAssetPublicId, sourceAssetPublicId] of @@ -877,7 +887,7 @@ export const duplicate = mutation({ await storeStrategyAgentSummary( ctx, strategyId, - agentTypesOf(copiedElements, copiedLineups), + agentTypesOf(copiedElements, copiedLineupAgents), ); return { ok: true } as const; }, diff --git a/convex/strategyDuplicate.test.ts b/convex/strategyDuplicate.test.ts index 627806cc..7f868d18 100644 --- a/convex/strategyDuplicate.test.ts +++ b/convex/strategyDuplicate.test.ts @@ -9,6 +9,7 @@ import type { DataModel } from "./_generated/dataModel"; import { markAssetReferencesReady } from "./lib/assetReferences"; import { CURRENT_CLOUD_PROTOCOL_VERSION } from "./lib/cloudProtocol"; import schema from "./schema"; +import { lineupsPayload, oneLineupPayload } from "./testContent.helpers"; import { modules } from "./test.setup"; const ensureCurrentUser = makeFunctionReference<"mutation">( @@ -71,6 +72,28 @@ async function createHarness(): Promise<{ return { t, owner, other }; } +// One lineup group holding one lineup. The group, its lineup and its +// landing share one id, as a landing made with its lineup does. +const seedLineupData = { + id: "item-1", + origins: [ + { id: "origin-1", agent: { type: "sova", lineUpID: "origin-1" } }, + ], + landings: [ + { id: "item-1", ability: { type: "shock_dart", lineUpID: "item-1" } }, + ], + links: [ + { + id: "item-1", + originId: "origin-1", + landingId: "item-1", + name: "Shock dart", + notes: "Two bounces", + images: [{ id: "lineup-image" }], + }, + ], +}; + /// A two-page strategy with a placed image, a lineup with an image, an agent, /// and one deleted element, backed by active R2 asset rows. async function seedSource(t: RootHarness, owner: Harness): Promise { @@ -170,25 +193,19 @@ async function seedSource(t: RootHarness, owner: Harness): Promise { pagePublicId: firstPage, expectedElementRevision: 1, }, - // One lineup: an origin, a landing and the link between them (the - // landing shares its link's id), the link showing an image. - ...( - [ - ["lineupOrigin", { id: "origin-1", agent: { type: "sova", lineUpID: "origin-1" } }], - ["lineupLanding", { id: "item-1", ability: { type: "shock_dart", lineUpID: "item-1" } }], - ["lineupLink", { - id: "item-1", originId: "origin-1", landingId: "item-1", - images: [{ id: "lineup-image" }], - }], - ] as Array<[string, Record]> - ).map(([kind, data], index) => ({ - opId: `add-${kind}`, + // One lineup group showing an image. + { + opId: "add-lineup", type: "lineup.add", - lineupPublicId: `${kind}:${data.id}`, + lineupPublicId: "item-1", pagePublicId: secondPage, - payload: { kind, payloadVersion: 1, data }, - sortIndex: index, - })), + payload: { + kind: "lineups", + payloadVersion: 1, + data: seedLineupData, + }, + sortIndex: 0, + }, ], }); } @@ -314,34 +331,33 @@ describe("strategies:duplicate", () => { expect(agent.publicId).not.toBe("placed-agent"); expect(agent.payload.data).toEqual({ id: agent.publicId, type: "jett" }); - expect(copy.lineups).toHaveLength(3); - for (const row of copy.lineups) { - expect(row.pagePublicId).toBe(copySecondPage); - } - const copied = (kind: string) => - copy.lineups.find((row) => row.payload.kind === kind)!.payload.data; - const origin = copied("lineupOrigin"); - const landing = copied("lineupLanding"); - const link = copied("lineupLink"); - // Fresh ids, still shared where the source shared them, with every - // reference following: the origin's agent, the landing's ability, and - // the link's ends. - expect(origin.id).not.toBe("origin-1"); - expect(landing.id).not.toBe("item-1"); - expect(link.id).toBe(landing.id); - expect(origin).toEqual({ - id: origin.id, - agent: { type: "sova", lineUpID: origin.id }, - }); - expect(landing).toEqual({ - id: landing.id, - ability: { type: "shock_dart", lineUpID: landing.id }, - }); - expect(link).toEqual({ - id: link.id, - originId: origin.id, - landingId: landing.id, - images: [{ id: "lineup-image" }], + expect(copy.lineups).toHaveLength(1); + const lineup = copy.lineups[0]!; + expect(lineup.pagePublicId).toBe(copySecondPage); + expect(lineup.payload.kind).toBe("lineups"); + // Fresh ids, still shared where the source shared them (the group, its + // lineup and its landing keep one id), with each link naming its ends' + // new ids and each marker following its spot. + const { id, origins } = lineup.payload.data; + const originId = origins[0].id; + expect(lineup.publicId).toBe(id); + expect(id).not.toBe("item-1"); + expect(originId).not.toBe("origin-1"); + expect(originId).not.toBe(id); + expect(lineup.payload.data).toEqual({ + id, + origins: [{ id: originId, agent: { type: "sova", lineUpID: originId } }], + landings: [{ id, ability: { type: "shock_dart", lineUpID: id } }], + links: [ + { + id, + originId, + landingId: id, + name: "Shock dart", + notes: "Two bounces", + images: [{ id: "lineup-image" }], + }, + ], }); expect(await imageUrls(owner, "duplicate-copy")).toEqual({ @@ -407,7 +423,7 @@ describe("strategies:duplicate", () => { ).toEqual([]); }); - test("a fan-in lineup graph copies whole, with its link image, and outlives the original", async () => { + test("a lineup group copies whole under new ids, with its shared spots, details and images, and outlives the original", async () => { vi.useFakeTimers(); const fetchMock = mockR2Deletes(); const { t, owner } = await createHarness(); @@ -418,54 +434,82 @@ describe("strategies:duplicate", () => { .withIndex("by_publicId", (q) => q.eq("publicId", source)) .unique(); const now = Date.now(); - await ctx.db.insert("imageAssets", { - publicId: "link-image", - provider: "r2", - strategyId: strategy!._id, - uploadAttemptPublicId: "link-image-attempt", - objectKey: `strategies/${source}/link-image.png`, - uploadStatus: "active", - fileExtension: ".png", - mimeType: "image/png", - width: 64, - height: 32, - byteSize: 100, - uploadedAt: now, - createdAt: now, - updatedAt: now, - }); + for (const publicId of ["link-image", "fan-out-image"]) { + await ctx.db.insert("imageAssets", { + publicId, + provider: "r2", + strategyId: strategy!._id, + uploadAttemptPublicId: `${publicId}-attempt`, + objectKey: `strategies/${source}/${publicId}.png`, + uploadStatus: "active", + fileExtension: ".png", + mimeType: "image/png", + width: 64, + height: 32, + byteSize: 100, + uploadedAt: now, + createdAt: now, + updatedAt: now, + }); + } + }); + // Two lineups from different origins into one landing (fan-in), and a + // third from the first one's origin to another landing (fan-out): one + // group. The shared landing takes the first lineup's id, as a landing + // made with its lineup does, and the group takes it too. A second group + // on the page holds one lineup. + const group = lineupsPayload("link-a", { + origins: [ + { id: "origin-a", position: { dx: 10, dy: 10 } }, + { id: "origin-b", agentType: "brimstone", position: { dx: 20, dy: 20 } }, + ], + landings: [ + { id: "link-a", position: { dx: 300, dy: 300 } }, + { id: "landing-c", position: { dx: 500, dy: 500 } }, + ], + links: [ + { + id: "link-a", + originId: "origin-a", + landingId: "link-a", + name: "From heaven", + notes: "Run and throw", + images: [{ id: "link-image", fileExtension: ".png" }], + }, + { + id: "link-b", + originId: "origin-b", + landingId: "link-a", + name: "From mid", + youtubeLink: "https://youtu.be/b", + }, + { + id: "link-c", + originId: "origin-a", + landingId: "landing-c", + name: "Fan out", + images: [{ id: "fan-out-image", fileExtension: ".png" }], + }, + ], }); - // Two origins into one landing. The landing shares an id with a link, - // as landings made before the graph synced natively do. - const rows: Array<[string, Record]> = [ - ["lineupOrigin", { id: "origin-a", agent: { type: "sova", lineUpID: "origin-a" } }], - ["lineupOrigin", { id: "origin-b", agent: { type: "sova", lineUpID: "origin-b" } }], - ["lineupLanding", { id: "link-a", ability: { type: "shock_dart", lineUpID: "link-a" } }], - ["lineupLink", { - id: "link-a", originId: "origin-a", landingId: "link-a", - name: "From heaven", images: [{ id: "link-image", fileExtension: ".png" }], - }], - ["lineupLink", { - id: "link-b", originId: "origin-b", landingId: "link-a", - name: "From mid", images: [], - }], - ]; + const lone = oneLineupPayload("lone", { name: "Lone" }); const added = (await owner.mutation(applyBatch, { ...protocol, strategyPublicId: source, - clientId: "graph", - ops: rows.map(([kind, data], index) => ({ - opId: `add-${kind}-${data.id}`, + clientId: "shared-spots", + ops: [group, lone].map((payload, index) => ({ + opId: `add-${payload.data.id}`, type: "lineup.add", - lineupPublicId: `${kind}:${data.id}`, + lineupPublicId: payload.data.id, pagePublicId: firstPage, - payload: { kind, payloadVersion: 1, data }, + payload, sortIndex: 10 + index, })), })) as { results: Array<{ status: string }> }; - expect(added.results.map((result) => result.status)).toEqual( - rows.map(() => "applied"), - ); + expect(added.results.map((result) => result.status)).toEqual([ + "applied", + "applied", + ]); await duplicate(owner); await deleteAndSweep(t, owner, source); @@ -473,52 +517,141 @@ describe("strategies:duplicate", () => { type Row = { publicId: string; pagePublicId: string; - payload: { kind: string; data: Record }; + sortIndex: number; + payload: { + kind: string; + payloadVersion: number; + data: Record; + }; }; const copy = (await owner.query(getFullSnapshot, { ...protocol, strategyPublicId: "duplicate-copy", - })) as { pages: Array<{ publicId: string; sortIndex: number }>; lineups: Row[] }; - // The fan-in sits on the first page (the seed's lineup is on the second). - const copyFirstPage = [...copy.pages].sort((a, b) => a.sortIndex - b.sortIndex)[0]! - .publicId; - const graph = copy.lineups.filter((row) => row.pagePublicId === copyFirstPage); - // Every graph row is keyed by its kind and its new entity id. - for (const row of graph) { - expect(row.publicId).toBe(`${row.payload.kind}:${row.payload.data.id}`); - } - const ofKind = (kind: string) => - graph.filter((row) => row.payload.kind === kind).map((row) => row.payload.data); - const origins = ofKind("lineupOrigin"); - const landings = ofKind("lineupLanding"); - const links = ofKind("lineupLink"); - expect(origins).toHaveLength(2); - expect(landings).toHaveLength(1); - expect(links).toHaveLength(2); - const oldIds = ["origin-a", "origin-b", "link-a", "link-b"]; - for (const entity of [...origins, ...landings, ...links]) { - expect(oldIds).not.toContain(entity.id); + })) as { + pages: Array<{ publicId: string; sortIndex: number }>; + lineups: Row[]; + }; + // These sit on the first page (the seed's group is on the second). + const copyFirstPage = [...copy.pages].sort( + (a, b) => a.sortIndex - b.sortIndex, + )[0]!.publicId; + const copied = copy.lineups + .filter((row) => row.pagePublicId === copyFirstPage) + .sort((a, b) => a.sortIndex - b.sortIndex); + expect(copied).toHaveLength(2); + const [copiedGroup, copiedLone] = copied as [Row, Row]; + + // Read the new ids off the copy, in the source's order. + const newIdOf = new Map(); + const remember = (sourceId: string, copyId: string) => { + // One source id always becomes one copy id. + expect(newIdOf.get(sourceId) ?? copyId).toBe(copyId); + newIdOf.set(sourceId, copyId); + }; + for (const [sourcePayload, row] of [ + [group, copiedGroup], + [lone, copiedLone], + ] as const) { + const data = row.payload.data; + expect(row.publicId).toBe(data.id); + remember(sourcePayload.data.id, data.id); + for (const field of ["origins", "landings", "links"] as const) { + expect(data[field]).toHaveLength(sourcePayload.data[field].length); + sourcePayload.data[field].forEach((entry, index) => + remember(entry.id, data[field][index].id), + ); + } } - for (const origin of origins) expect(origin.agent.lineUpID).toBe(origin.id); - expect(landings[0]!.ability.lineUpID).toBe(landings[0]!.id); - // Fan-in survives: both links name the one copied landing and their own - // copied origins, with their names and image. - const originIds = origins.map((origin) => origin.id); - expect(links.map((link) => [link.name, link.landingId])).toEqual([ - ["From heaven", landings[0]!.id], - ["From mid", landings[0]!.id], + // Ids that were apart stay apart, and none is reused from the source. + const sourceIds = [...newIdOf.keys()].sort(); + const copyIds = [...newIdOf.values()]; + expect(sourceIds).toEqual([ + "landing-c", + "link-a", + "link-b", + "link-c", + "lone", + "lone-landing", + "lone-origin", + "origin-a", + "origin-b", ]); - expect(links.map((link) => originIds.indexOf(link.originId))).toEqual([0, 1]); - expect(links[0]!.images).toEqual([{ id: "link-image", fileExtension: ".png" }]); - - // The copy's link image is its own reference and survived the original. + expect(new Set(copyIds).size).toBe(copyIds.length); + for (const copyId of copyIds) expect(sourceIds).not.toContain(copyId); + + // Each copy is its source row under the new ids: each link naming its + // ends' new ids, each marker following its spot, every place, detail + // and image as it was. + const renamed = (payload: typeof group) => { + const id = (old: string) => newIdOf.get(old)!; + return { + ...payload, + data: { + id: id(payload.data.id), + origins: payload.data.origins.map((origin) => ({ + ...origin, + id: id(origin.id), + agent: { ...origin.agent, lineUpID: id(origin.id) }, + })), + landings: payload.data.landings.map((landing) => ({ + ...landing, + id: id(landing.id), + ability: { ...landing.ability, lineUpID: id(landing.id) }, + })), + links: payload.data.links.map((link) => ({ + ...link, + id: id(link.id), + originId: id(link.originId), + landingId: id(link.landingId), + })), + }, + }; + }; + expect(copiedGroup.payload).toEqual(renamed(group)); + expect(copiedLone.payload).toEqual(renamed(lone)); + // Fan-in and fan-out survive: both lineups into the shared landing name + // one new id, still the group's and the first lineup's, and both + // lineups from the shared origin name one new id. + const links = copiedGroup.payload.data.links; + expect(links[1].landingId).toBe(links[0].landingId); + expect(links[0].landingId).toBe(copiedGroup.publicId); + expect(links[0].id).toBe(copiedGroup.publicId); + expect(links[2].originId).toBe(links[0].originId); + + // The copy's lineup images are its own references, one per image across + // every link, and survived the original. expect(fetchMock).not.toHaveBeenCalled(); const urls = await imageUrls(owner, "duplicate-copy"); expect(urls["link-image"]).toEqual(expect.stringContaining("link-image.png")); + expect(urls["fan-out-image"]).toEqual( + expect.stringContaining("fan-out-image.png"), + ); + const lineupReferences = await t.run(async (ctx) => { + const copyRow = await ctx.db + .query("strategies") + .withIndex("by_publicId", (q) => q.eq("publicId", "duplicate-copy")) + .unique(); + return (await ctx.db.query("assetReferences").collect()) + .filter( + (reference) => + reference.strategyId === copyRow!._id && + reference.lineupId !== undefined, + ) + .map((reference) => reference.assetPublicId) + .sort(); + }); + expect(lineupReferences).toEqual([ + "fan-out-image", + "lineup-image", + "link-image", + ]); await deleteAndSweep(t, owner, "duplicate-copy"); - expect(deletedKeys(fetchMock)).toContain( - `/duplicate-bucket/strategies/${source}/link-image.png`, + expect(deletedKeys(fetchMock)).toEqual( + expect.arrayContaining([ + `/duplicate-bucket/strategies/${source}/link-image.png`, + `/duplicate-bucket/strategies/${source}/fan-out-image.png`, + ]), ); }); @@ -600,8 +733,8 @@ describe("strategies:duplicate", () => { .filter((row) => row.publicId === "placed-image") .map((row) => row.uploadStatus); - // The placed image is deleted; a month later a lineup link shows the - // same image and is deleted too, so undo could still restore it. + // The placed image is deleted; a month later a lineup shows the same + // image and is deleted too, so undo could still restore it. await owner.mutation(applyBatch, { ...protocol, strategyPublicId: source, @@ -617,16 +750,9 @@ describe("strategies:duplicate", () => { ], }); vi.setSystemTime(Date.now() + 31 * day); - const showing = { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: "late-link", - originId: "o", - landingId: "l", - images: [{ id: "placed-image" }], - }, - }; + const showing = oneLineupPayload("late-link", { + images: [{ id: "placed-image" }], + }); await owner.mutation(applyBatch, { ...protocol, strategyPublicId: source, @@ -635,7 +761,7 @@ describe("strategies:duplicate", () => { { opId: "add-late-link", type: "lineup.add", - lineupPublicId: "lineupLink:late-link", + lineupPublicId: "late-link", pagePublicId: firstPage, payload: showing, sortIndex: 9, @@ -643,14 +769,14 @@ describe("strategies:duplicate", () => { { opId: "delete-late-link", type: "lineup.delete", - lineupPublicId: "lineupLink:late-link", + lineupPublicId: "late-link", pagePublicId: firstPage, expectedLineupRevision: 1, }, ], }); - // Purging the old element tombstone keeps the image: the link's + // Purging the old element tombstone keeps the image: the lineup's // tombstone is still inside its retention window. await t.mutation(purgeOldTombstones, {}); await t.finishAllScheduledFunctions(vi.runAllTimers); @@ -1084,7 +1210,7 @@ describe("images placed before their upload", () => { expect(rows[0]).toMatchObject({ uploadStatus: "active" }); }); - test("deleting an image keeps the placeholder while a lineup link still shows it", async () => { + test("deleting an image keeps the placeholder while a lineup still shows it", async () => { const { t, owner } = await createHarness(); await seedSource(t, owner); await placeImage(owner, "link-late-image"); @@ -1096,18 +1222,11 @@ describe("images placed before their upload", () => { { opId: "link-shows-shared", type: "lineup.add", - lineupPublicId: "lineupLink:link-shows-shared", + lineupPublicId: "link-shows-shared", pagePublicId: firstPage, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: "link-shows-shared", - originId: "o", - landingId: "l", - images: [{ id: "link-late-image", fileExtension: ".png" }], - }, - }, + payload: oneLineupPayload("link-shows-shared", { + images: [{ id: "link-late-image", fileExtension: ".png" }], + }), sortIndex: 2, }, ], @@ -1144,18 +1263,11 @@ describe("images placed before their upload", () => { { opId: "link-shows-b", type: "lineup.add", - lineupPublicId: "lineupLink:shows-b", + lineupPublicId: "shows-b", pagePublicId: firstPage, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: "shows-b", - originId: "o", - landingId: "l", - images: [{ id: "pending-b", fileExtension: ".png" }], - }, - }, + payload: oneLineupPayload("shows-b", { + images: [{ id: "pending-b", fileExtension: ".png" }], + }), sortIndex: 5, }, { @@ -1195,18 +1307,11 @@ describe("images placed before their upload", () => { { opId: "lineup-shows-batch", type: "lineup.add", - lineupPublicId: "lineupLink:lineup-shows-batch", + lineupPublicId: "lineup-shows-batch", pagePublicId: firstPage, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: "lineup-shows-batch", - originId: "o", - landingId: "l", - images: [{ id: "batch-shown" }], - }, - }, + payload: oneLineupPayload("lineup-shows-batch", { + images: [{ id: "batch-shown" }], + }), sortIndex: 3, }, ], @@ -1229,7 +1334,7 @@ describe("images placed before their upload", () => { expect(await rowsFor(t, "batch-alone")).toEqual([]); }); - test("a lineup link's image referenced before its upload is expected too", async () => { + test("a lineup's image referenced before its upload is expected too", async () => { const { t, owner } = await createHarness(); await seedSource(t, owner); await owner.mutation(applyBatch, { @@ -1240,18 +1345,11 @@ describe("images placed before their upload", () => { { opId: "late-link", type: "lineup.add", - lineupPublicId: "lineupLink:late-link", + lineupPublicId: "late-link", pagePublicId: firstPage, - payload: { - kind: "lineupLink", - payloadVersion: 1, - data: { - id: "late-link", - originId: "o", - landingId: "l", - images: [{ id: "late-link-image", fileExtension: ".png" }], - }, - }, + payload: oneLineupPayload("late-link", { + images: [{ id: "late-link-image", fileExtension: ".png" }], + }), sortIndex: 1, }, ], diff --git a/convex/syncBoundaries.test.ts b/convex/syncBoundaries.test.ts index f7944f2e..d5365f43 100644 --- a/convex/syncBoundaries.test.ts +++ b/convex/syncBoundaries.test.ts @@ -15,7 +15,11 @@ import { serializedConvexValueUtf8Bytes, } from "./lib/cloudProtocol"; import schema from "./schema"; -import { insertElement, insertLineup } from "./testContent.helpers"; +import { + insertElement, + insertLineup, + oneLineupPayload, +} from "./testContent.helpers"; import { modules } from "./test.setup"; const ensureCurrentUser = makeFunctionReference<"mutation">( @@ -75,19 +79,14 @@ function imagePayload(assetPublicId: string) { }; } -/// A lineup link showing one image; its row key is `lineupLink:`. -function lineupPayload(assetPublicId: string, linkId = "restorable") { - return { - kind: "lineupLink" as const, - payloadVersion: 1, - data: { - id: linkId, - originId: "origin", - landingId: "landing", - name: "B lineup", - images: [{ id: assetPublicId }], - }, - }; +/// A group of one lineup showing one image; its row key is [lineupId]. +function lineupShowing(assetPublicId: string, lineupId = "restorable") { + return oneLineupPayload(lineupId, { + originId: "origin", + landingId: "landing", + name: "B lineup", + images: [{ id: assetPublicId }], + }); } /** A ConvexError's code (convex-test passes its data as JSON text). */ @@ -353,12 +352,12 @@ async function seedTwoPageContent(t: Harness, owner: Harness) { updatedAt: now, }); await insertLineup(ctx, { - publicId: "lineupLink:lineup-b", + publicId: "lineup-b", strategyId: strategy._id, pageId: pageBId, - payloadKind: "lineupLink", + payloadKind: "lineups", payloadVersion: 1, - payload: lineupPayload(assetB, "lineup-b"), + payload: lineupShowing(assetB, "lineup-b"), sortIndex: 0, revision: 1, deleted: false, @@ -437,7 +436,7 @@ describe("page-scoped read contract", () => { "element-b", ]); expect(snapshot.lineups.map((item) => item.publicId)).toEqual([ - "lineupLink:lineup-b", + "lineup-b", ]); expect(snapshot.assets.map((item) => item.publicId).sort()).toEqual([ "asset-a", @@ -1064,7 +1063,7 @@ describe("record-scoped write contract", () => { test("soft-deleted elements and lineups can be restored with their ids", async () => { const elementId = "restorable-element"; - const lineupId = "lineupLink:restorable"; + const lineupId = "restorable"; const restoredText = "restored"; const restoredAsset = "restored-asset"; const { owner } = await createHarness(); @@ -1084,7 +1083,7 @@ describe("record-scoped write contract", () => { entityType: "lineup", entityPublicId: lineupId, pagePublicId: pageA, - payload: lineupPayload("before-delete-asset"), + payload: lineupShowing("before-delete-asset"), }, ]); await applyOps(owner, "undo-restore", [ @@ -1119,7 +1118,7 @@ describe("record-scoped write contract", () => { entityType: "lineup", entityPublicId: lineupId, pagePublicId: pageA, - payload: lineupPayload(restoredAsset), + payload: lineupShowing(restoredAsset), }, ]); expect(missingRevision.results).toMatchObject([ @@ -1151,7 +1150,7 @@ describe("record-scoped write contract", () => { entityType: "lineup", entityPublicId: lineupId, pagePublicId: pageA, - payload: lineupPayload(restoredAsset), + payload: lineupShowing(restoredAsset), expectedRevision: 1, }, ]); @@ -1185,14 +1184,24 @@ describe("record-scoped write contract", () => { entityType: "lineup", entityPublicId: lineupId, pagePublicId: pageA, - payload: lineupPayload("before-delete-asset"), + payload: lineupShowing("before-delete-asset"), sortIndex: 0, expectedRevision: 2, }, ]); + // A patch never touches a tombstone, even one that would change nothing: + // only an add expecting the tombstone's revision brings the row back. expect(misclassifiedPatch.results).toMatchObject([ - { status: "noop", currentRevision: 2 }, - { status: "noop", currentRevision: 2 }, + { + status: "rejected", + reason: "deleted", + current: { type: "element", revision: 2 }, + }, + { + status: "rejected", + reason: "deleted", + current: { type: "lineup", revision: 2 }, + }, ]); const stillDeleted = (await owner.query(getPageSnapshot, { clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, @@ -1225,7 +1234,7 @@ describe("record-scoped write contract", () => { entityType: "lineup", entityPublicId: lineupId, pagePublicId: pageA, - payload: lineupPayload(restoredAsset), + payload: lineupShowing(restoredAsset), expectedRevision: 2, }, ]); @@ -1249,7 +1258,7 @@ describe("record-scoped write contract", () => { publicId: string; revision: number; deleted: boolean; - payload: { data: { images: Array<{ id: string }> } }; + payload: { data: { links: Array<{ images: Array<{ id: string }> }> } }; }>; }; expect(snapshot.elements).toMatchObject([ @@ -1266,7 +1275,7 @@ describe("record-scoped write contract", () => { revision: 3, deleted: false, payload: { - data: { images: [{ id: restoredAsset }] }, + data: { links: [{ images: [{ id: restoredAsset }] }] }, }, }, ]); @@ -1389,30 +1398,34 @@ describe("record-scoped write contract", () => { expect(replayed).toMatchObject({ revision: 2, reused: true }); }); - test("a lineup link without its landing is refused", async () => { + test("a lineup group whose lineup names a landing it does not hold is refused", async () => { const { owner } = await createHarness(); await createBaseStrategy(owner); + const { landings: _landings, ...withoutLandings } = lineupShowing( + "asset-empty", + "lineup-empty", + ).data; const response = await applyOps(owner, "empty-lineup", [ { opId: "add-empty-lineup", kind: "add", entityType: "lineup", - entityPublicId: "lineupLink:lineup-empty", + entityPublicId: "lineup-empty", pagePublicId: pageA, payload: { - kind: "lineupLink" as const, + kind: "lineups", payloadVersion: 1, - data: { id: "lineup-empty", originId: "origin" }, + data: { ...withoutLandings, landings: [] }, }, }, { opId: "add-lineup", kind: "add", entityType: "lineup", - entityPublicId: "lineupLink:lineup-full", + entityPublicId: "lineup-full", pagePublicId: pageA, - payload: lineupPayload("asset-full", "lineup-full"), + payload: lineupShowing("asset-full", "lineup-full"), }, ]); @@ -1427,26 +1440,65 @@ describe("record-scoped write contract", () => { }); }); - test("a legacy lineup group is no longer part of the contract", async () => { + test("old lineup shapes are no longer part of the contract", async () => { const { owner } = await createHarness(); await createBaseStrategy(owner); - await expect( - applyOps(owner, "old-client", [ - { - opId: "add-legacy-group", - kind: "add", - entityType: "lineup", - entityPublicId: "legacy-group", - pagePublicId: pageA, - payload: { - kind: "lineupGroup", - payloadVersion: 1, - data: { id: "legacy-group", items: [{ id: "item" }] }, - }, + // A protocol 4 graph row (an origin, landing or link) passes argument + // validation, so an old client reaches the protocol gate, and the + // handler refuses it per op. + const graph = await applyOps(owner, "old-client", [ + { + opId: "add-lineupLink:k", + kind: "add", + entityType: "lineup", + entityPublicId: "lineupLink:k", + pagePublicId: pageA, + payload: { + kind: "lineupLink", + payloadVersion: 1, + data: { id: "k", originId: "o", landingId: "l", images: [] }, }, - ]), - ).rejects.toThrow(/lineupGroup|ArgumentValidationError|Validator/); + }, + ]); + expect(graph.results).toMatchObject([ + { + opId: "add-lineupLink:k", + status: "failed", + rawCode: "INVALID_LINEUP_PAYLOAD_KIND", + }, + ]); + // The legacy group before it, and the one-row-per-lineup shape tried + // before groups, are refused whole by argument validation. + for (const payload of [ + { + kind: "lineupGroup", + payloadVersion: 1, + data: { id: "legacy-group", items: [{ id: "item" }] }, + }, + { + kind: "lineup", + payloadVersion: 1, + data: { + id: "legacy-group", + origin: { id: "o", agent: { type: "sova" } }, + landing: { id: "l", ability: {} }, + }, + }, + ]) { + await expect( + applyOps(owner, "old-client", [ + { + opId: `add-legacy-${payload.kind}`, + kind: "add", + entityType: "lineup", + entityPublicId: "legacy-group", + pagePublicId: pageA, + payload, + }, + ]), + ).rejects.toThrow(/Validator error|ArgumentValidationError/); + } const snapshot = (await owner.query(getPageSnapshot, { clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, strategyPublicId, @@ -1493,6 +1545,285 @@ describe("record-scoped write contract", () => { }); }); +/// A text element or a lineup named [label], to check the element and the +/// lineup write paths with the same steps. +function contentPayload(entity: "element" | "lineup", id: string, label: string) { + return entity === "element" + ? textPayload(label) + : oneLineupPayload(id, { name: label }); +} + +type ContentRow = { + publicId: string; + revision: number; + deleted: boolean; + sortIndex: number; + payload: unknown; +}; + +async function contentRow( + owner: Harness, + entity: "element" | "lineup", + id: string, +): Promise { + const snapshot = (await owner.query(getPageSnapshot, { + clientProtocolVersion: CURRENT_CLOUD_PROTOCOL_VERSION, + strategyPublicId, + pagePublicId: pageA, + })) as { elements: ContentRow[]; lineups: ContentRow[] }; + const rows = entity === "element" ? snapshot.elements : snapshot.lineups; + return rows.find((row) => row.publicId === id); +} + +describe("a row a teammate deleted", () => { + for (const entity of ["element", "lineup"] as const) { + test(`a patch or reorder of a deleted ${entity} is refused whatever it expects; an add expecting the tombstone restores it`, async () => { + const { owner } = await createHarness(); + await createBaseStrategy(owner); + const id = `deleted-${entity}`; + const base = contentPayload(entity, id, "base"); + const mine = contentPayload(entity, id, "mine"); + await applyOps(owner, "me", [ + { + opId: "add", + kind: "add", + entityType: entity, + entityPublicId: id, + pagePublicId: pageA, + payload: base, + }, + ]); + const deleted = await applyOps(owner, "teammate", [ + { + opId: "teammate-deletes", + kind: "delete", + entityType: entity, + entityPublicId: id, + expectedRevision: 1, + }, + ]); + expect(deleted.results).toMatchObject([ + { status: "applied", appliedRevision: 2 }, + ]); + const tombstone = await contentRow(owner, entity, id); + expect(tombstone).toMatchObject({ revision: 2, deleted: true }); + + const refused = { + status: "rejected", + reason: "deleted", + current: { type: entity, revision: 2, value: base }, + }; + // The edit made before the delete arrived. + const stale = await applyOps(owner, "me", [ + { + opId: "patch-expecting-1", + kind: "patch", + entityType: entity, + entityPublicId: id, + payload: mine, + expectedRevision: 1, + }, + ]); + expect(stale.results).toMatchObject([refused]); + // What an old "Keep mine" sent: the same edit against the tombstone. + const keepMine = await applyOps(owner, "me", [ + { + opId: "patch-expecting-2", + kind: "patch", + entityType: entity, + entityPublicId: id, + payload: mine, + expectedRevision: 2, + }, + { + opId: "identical-patch-expecting-2", + kind: "patch", + entityType: entity, + entityPublicId: id, + payload: base, + expectedRevision: 2, + }, + { + opId: "reorder-expecting-1", + kind: "reorder", + entityType: entity, + entityPublicId: id, + sortIndex: 5, + expectedRevision: 1, + }, + { + opId: "reorder-expecting-2", + kind: "reorder", + entityType: entity, + entityPublicId: id, + sortIndex: 5, + expectedRevision: 2, + }, + ]); + expect(keepMine.results).toMatchObject([ + refused, + refused, + refused, + refused, + ]); + // None of it touched the tombstone. + expect(await contentRow(owner, entity, id)).toEqual(tombstone); + + const restored = await applyOps(owner, "me", [ + { + opId: "restore", + kind: "add", + entityType: entity, + entityPublicId: id, + pagePublicId: pageA, + payload: mine, + expectedRevision: 2, + }, + ]); + expect(restored.results).toMatchObject([ + { status: "applied", appliedRevision: 3 }, + ]); + const row = await contentRow(owner, entity, id); + expect(row).toMatchObject({ revision: 3, deleted: false }); + expect(row!.payload).toEqual(mine); + }); + } +}); + +describe("a write that changes nothing", () => { + for (const entity of ["element", "lineup"] as const) { + test(`two clients sending the same ${entity} patch from one revision: one applies, the other is a noop`, async () => { + const { owner } = await createHarness(); + await createBaseStrategy(owner); + const id = `same-${entity}`; + const base = contentPayload(entity, id, "base"); + const edited = contentPayload(entity, id, "edited"); + await applyOps(owner, "setup", [ + { + opId: "add", + kind: "add", + entityType: entity, + entityPublicId: id, + pagePublicId: pageA, + payload: base, + }, + ]); + const patch = { + kind: "patch", + entityType: entity, + entityPublicId: id, + payload: edited, + expectedRevision: 1, + }; + const first = await applyOps(owner, "client-a", [ + { ...patch, opId: "a-edits" }, + ]); + const second = await applyOps(owner, "client-b", [ + { ...patch, opId: "b-edits" }, + ]); + expect(first.results).toMatchObject([ + { status: "applied", appliedRevision: 2 }, + ]); + expect(second.results).toMatchObject([ + { status: "noop", currentRevision: 2 }, + ]); + + // An add of what the live row already holds, on its page and at its + // place, is a noop too, whatever revision it expects. + const added = await applyOps(owner, "client-c", [ + { + opId: "c-adds-stale", + kind: "add", + entityType: entity, + entityPublicId: id, + pagePublicId: pageA, + payload: edited, + expectedRevision: 1, + }, + { + opId: "c-adds-unversioned", + kind: "add", + entityType: entity, + entityPublicId: id, + pagePublicId: pageA, + payload: edited, + }, + ]); + expect(added.results).toMatchObject([ + { status: "noop", currentRevision: 2 }, + { status: "noop", currentRevision: 2 }, + ]); + const row = await contentRow(owner, entity, id); + expect(row).toMatchObject({ revision: 2, deleted: false }); + expect(row!.payload).toEqual(edited); + }); + } +}); + +describe("a resent op whose ack was lost", () => { + test("reports the revision it landed at, so a successor cannot overwrite a teammate's later edit", async () => { + const { t, owner } = await createHarness(); + await createBaseStrategy(owner); + await applyOps(owner, "first-client", [ + { + opId: "add", + type: "element.add", + elementPublicId: "element-a", + pagePublicId: pageA, + payload: textPayload("base"), + sortIndex: 0, + }, + ]); + const patch = (opId: string, text: string, expectedElementRevision: number) => ({ + opId, + type: "element.patch", + elementPublicId: "element-a", + pagePublicId: pageA, + payload: textPayload(text), + expectedElementRevision, + }); + const mine = patch("mine", "mine", 1); + const first = await applyOps(owner, "first-client", [mine]); + expect(first.results[0]).toMatchObject({ + status: "applied", + appliedRevision: 2, + }); + + // A teammate's device edits the element after it. + const teammate = await applyOps(owner, "teammate-client", [ + patch("theirs", "theirs", 2), + ]); + expect(teammate.results[0]).toMatchObject({ + status: "applied", + appliedRevision: 3, + }); + + // The first client never heard back: it sends the op again with the + // same id, and the successor it queued on top of it. + const resent = await applyOps(owner, "first-client", [ + mine, + patch("mine-next", "mine again", 2), + ]); + expect(resent.results[0]).toEqual({ + opId: "mine", + status: "noop", + currentRevision: 2, + }); + expect(resent.results[1]).toMatchObject({ + opId: "mine-next", + status: "rejected", + reason: "revision_mismatch", + current: { type: "element", revision: 3, value: textPayload("theirs") }, + }); + const row = await t.run(async (ctx) => + (await ctx.db.query("elements").collect()).find( + (element) => element.publicId === "element-a", + ), + ); + expect(row).toMatchObject({ revision: 3, payload: textPayload("theirs") }); + }); +}); + describe("replay safety after operation event expiry", () => { test("identical add acknowledges and different add rejects", async () => { const { t, owner } = await createHarness(); diff --git a/convex/testContent.helpers.ts b/convex/testContent.helpers.ts index 7e827ff1..b3f262ba 100644 --- a/convex/testContent.helpers.ts +++ b/convex/testContent.helpers.ts @@ -9,6 +9,8 @@ import { syncElementAssetReferences, syncLineupAssetReferences, } from "./lib/assetReferences"; +import { syncLineupAgents } from "./lib/strategyAgentSummary"; +import { syncLineupItems } from "./lib/lineupItems"; export async function insertElement( ctx: MutationCtx, @@ -25,5 +27,115 @@ export async function insertLineup( ): Promise> { const id = await ctx.db.insert("lineups", lineup); await syncLineupAssetReferences(ctx, id, lineup); + await syncLineupAgents(ctx, id, lineup); + await syncLineupItems(ctx, id, lineup); return id; } + +type Position = { dx: number; dy: number }; + +export type TestOrigin = { + id: string; + agentType?: string; + position?: Position; +}; + +export type TestLanding = { id: string; position?: Position }; + +export type TestLink = { + id: string; + originId: string; + landingId: string; + name?: string; + youtubeLink?: string; + notes?: string; + images?: Array<{ id: string; fileExtension?: string }>; +}; + +export type TestLineupGroup = { + origins: TestOrigin[]; + landings: TestLanding[]; + links: TestLink[]; +}; + +/// A lineup group row's payload as a client writes it: the group's id (the +/// row's key), its origins (each placing an agent), landings (each placing +/// an ability) and links, each in the shape of the Dart model's toJson() +/// (LineUpOrigin, LineUpLanding, LineUpLink), each marker's `lineUpID` +/// naming its spot. +export function lineupsPayload(id: string, group: TestLineupGroup) { + return { + kind: "lineups" as const, + payloadVersion: 1, + data: { + id, + origins: group.origins.map((origin) => ({ + id: origin.id, + agent: { + id: `agent-${origin.id}`, + type: origin.agentType ?? "sova", + position: origin.position ?? { dx: 0, dy: 0 }, + lineUpID: origin.id, + }, + })), + landings: group.landings.map((landing) => ({ + id: landing.id, + ability: { + id: `ability-${landing.id}`, + position: landing.position ?? { dx: 0, dy: 0 }, + lineUpID: landing.id, + }, + })), + links: group.links.map((link) => ({ + id: link.id, + originId: link.originId, + landingId: link.landingId, + name: link.name ?? "", + youtubeLink: link.youtubeLink ?? "", + notes: link.notes ?? "", + images: link.images ?? [], + })), + }, + }; +} + +export type TestLineup = { + originId?: string; + landingId?: string; + agentType?: string; + originPosition?: Position; + landingPosition?: Position; + name?: string; + youtubeLink?: string; + notes?: string; + images?: Array<{ id: string; fileExtension?: string }>; +}; + +/// A group row holding one lineup: one origin, one landing and the link +/// between them. The group and its link take [id]; the spots default to +/// `-origin` and `-landing`. +export function oneLineupPayload(id: string, lineup: TestLineup = {}) { + const originId = lineup.originId ?? `${id}-origin`; + const landingId = lineup.landingId ?? `${id}-landing`; + return lineupsPayload(id, { + origins: [ + { + id: originId, + agentType: lineup.agentType, + position: lineup.originPosition, + }, + ], + landings: [{ id: landingId, position: lineup.landingPosition }], + links: [ + { + id, + originId, + landingId, + name: lineup.name, + youtubeLink: lineup.youtubeLink, + notes: lineup.notes, + images: lineup.images, + }, + ], + }); +} diff --git a/lib/collab/cloud_lineup_rows.dart b/lib/collab/cloud_lineup_rows.dart index cad520f3..b1e41aaf 100644 --- a/lib/collab/cloud_lineup_rows.dart +++ b/lib/collab/cloud_lineup_rows.dart @@ -1,170 +1,315 @@ import 'package:icarus/collab/collab_models.dart'; import 'package:icarus/const/line_provider.dart'; +import 'package:uuid/uuid.dart'; -/// The payload kinds of the cloud rows that store a page's lineups. +/// One cloud row per lineup group: lineups that share a standing spot or a +/// landing spot, stored together with those spots. /// -/// A page's lineups are a graph, and the cloud stores it one row per entity -/// so that teammates editing different links, origins or landings never -/// touch the same row. -abstract final class CloudLineupKind { - static const origin = 'lineupOrigin'; - static const landing = 'lineupLanding'; - static const link = 'lineupLink'; -} - -/// One lineup row: an origin, a landing or a link. +/// A shared spot lives in its group's row, so it cannot disagree with +/// itself, and the row's one revision guards every lineup on it: two +/// clients changing the same group meet as an ordinary conflict. A row never +/// names anything outside itself. +/// +/// A lineup stays in the group it was first written to: deleting the lineup +/// that joined two halves leaves both halves in the row, and groups never +/// merge. That keeps every edit a write to exactly the row the user's +/// lineups already live in, and no row is ever deleted except by deleting +/// its last lineup. +/// +/// No two live rows of a page hold the same lineup or spot: the server +/// refuses a write that would make them (see assertLineupGroupAlone in +/// convex/ops.ts), so the work waits in attention rather than two rows +/// disagreeing about one spot. class CloudLineupRow { const CloudLineupRow({required this.publicId, required this.payload}); - /// `:`. Entity ids repeat across kinds (a landing - /// made with its link shares the link's id, and lineups from 3.x used one - /// id for all three), so the kind is part of the key. The entity's own id - /// is `payload.data.id`, exactly as on the canvas. + CloudLineupRow.remote(RemoteLineup lineup) + : this(publicId: lineup.publicId, payload: lineup.payload); + + /// The group's id, as in `payload.data.id`. final String publicId; final CloudPayload payload; } -String cloudLineupRowId(String kind, String entityId) => '$kind:$entityId'; +/// A page's lineups as cloud rows describe them, and the group each lineup +/// and spot was drawn from (lineup, origin or landing id to group id). +class CloudLineups { + const CloudLineups({required this.graph, this.groupOf = const {}}); -/// The rows that store [graph]: its origins, then its landings, then its -/// links. -List cloudLineupRows(LineUpGraph graph) { - CloudLineupRow row(String kind, String id, Map data) { - return CloudLineupRow( - publicId: cloudLineupRowId(kind, id), - payload: cloudLineupPayload(kind: kind, data: data), - ); - } - - return [ - for (final origin in graph.origins) - row(CloudLineupKind.origin, origin.id, origin.toJson()), - for (final landing in graph.landings) - row(CloudLineupKind.landing, landing.id, landing.toJson()), - for (final link in graph.links) - row(CloudLineupKind.link, link.id, link.toJson()), - ]; + final LineUpGraph graph; + final Map groupOf; } -/// A page's lineup graph as its cloud rows describe it. -class CloudLineupGraph { - const CloudLineupGraph({required this.graph, required this.drawnRowIds}); +/// The rows that store a page's lineups, and the group each lineup and spot +/// went into. +class CloudLineupRows { + const CloudLineupRows({required this.rows, required this.groupOf}); - final LineUpGraph graph; - - /// The rows [graph] was built from. Hydration draws only whole lineups: a - /// link whose origin and landing both exist, and the nodes such links use. - /// A row outside that (a link that arrived before its landing, an origin a - /// teammate's delete left without links) is never shown, so a client must - /// never author a change to it from what it hydrated. - final Set drawnRowIds; + final List rows; + final Map groupOf; } -/// Reads a page's live lineup rows, in their stored order, into the graph. +/// A page's lineups as its live [rows] describe them, rows in order. /// -/// Throws a [FormatException] naming the row when one cannot be read, -/// including a row of any kind other than origin, landing or link. -CloudLineupGraph lineUpGraphFromCloudRows(Iterable rows) { - final origins = {}; - final landings = {}; - final links = {}; - +/// Ids are unique within a row and, as the server keeps them, across the +/// page's rows. Should two rows name one anyway, the first draws it, and a +/// lineup in a later row aimed at that spot is drawn to it too. +/// +/// Throws a [FormatException] naming the row when one cannot be read. +CloudLineups lineUpGraphFromCloudRows(Iterable rows) { + final origins = {}; + final landings = {}; + final links = {}; + final groupOf = {}; for (final row in rows) { - final data = cloudPayloadData(row.payload); - try { - switch (row.payload['kind']) { - case CloudLineupKind.origin: - final origin = LineUpOrigin.fromJson(data); - origins[origin.id] = (origin, row.publicId); - case CloudLineupKind.landing: - final landing = LineUpLanding.fromJson(data); - landings[landing.id] = (landing, row.publicId); - case CloudLineupKind.link: - final link = LineUpLink.fromJson(data); - links[link.id] = (link, row.publicId); - case final kind: - throw FormatException('unknown lineup kind $kind'); - } - } catch (error, stackTrace) { - Error.throwWithStackTrace( - FormatException('Cloud lineup ${row.publicId} could not be read: ' - '$error'), - stackTrace, - ); + final group = _readGroupRow(row); + for (final origin in group.origins) { + if (origins.containsKey(origin.id)) continue; + origins[origin.id] = origin; + groupOf[origin.id] = row.publicId; + } + for (final landing in group.landings) { + if (landings.containsKey(landing.id)) continue; + landings[landing.id] = landing; + groupOf[landing.id] = row.publicId; + } + for (final link in group.links) { + if (links.containsKey(link.id)) continue; + links[link.id] = link; + groupOf[link.id] = row.publicId; } } - - final drawnLinks = [ - for (final entry in links.values) - if (origins.containsKey(entry.$1.originId) && - landings.containsKey(entry.$1.landingId)) - entry, - ]; - final usedOrigins = {for (final (link, _) in drawnLinks) link.originId}; - final usedLandings = {for (final (link, _) in drawnLinks) link.landingId}; - final drawnOrigins = [ - for (final entry in origins.values) - if (usedOrigins.contains(entry.$1.id)) entry, - ]; - final drawnLandings = [ - for (final entry in landings.values) - if (usedLandings.contains(entry.$1.id)) entry, - ]; - - return CloudLineupGraph( + return CloudLineups( graph: LineUpGraph( - origins: [for (final (origin, _) in drawnOrigins) origin], - landings: [for (final (landing, _) in drawnLandings) landing], - links: [for (final (link, _) in drawnLinks) link], + origins: origins.values.toList(), + landings: landings.values.toList(), + links: links.values.toList(), ), - drawnRowIds: { - for (final (_, rowId) in drawnOrigins) rowId, - for (final (_, rowId) in drawnLandings) rowId, - for (final (_, rowId) in drawnLinks) rowId, - }, + groupOf: groupOf, ); } -/// [graph] with every origin, landing and link id passed through [newId], -/// and every reference to them (a link's ends, the `lineUpID` of the agent -/// and ability) following along. Used where a copy must not collide with -/// the rows it came from. -LineUpGraph lineUpGraphWithIds( - LineUpGraph graph, - String Function(String kind, String id) newId, -) { - final originIds = { - for (final origin in graph.origins) - origin.id: newId(CloudLineupKind.origin, origin.id), +/// The rows that store [graph], given the group each lineup and spot was in +/// before ([groupOf], from the rows the canvas was drawn from and earlier +/// calls). +/// +/// A lineup stays in the group it was first written to, so a group never +/// splits, and no row is ever deleted to tidy groups up: a group's row goes +/// only when its last lineup does. New lineups that share a spot form one +/// component, which joins the group one of its spots is already in (the +/// smallest such group's id, when spots of two groups meet in it), or else +/// is a new group. A new group takes its smallest lineup id that is not +/// already a group's id, here, in [groupOf] or in [takenGroupIds] (or a +/// fresh id, when every one of them is). +/// +/// A row holds its lineups and every spot they aim at. The app only ever +/// aims a new lineup at one existing spot, so a spot is in one row. A +/// lineup aimed at spots of two groups would put a spot in two rows; the +/// server refuses that write, and the work waits in attention. +/// +/// A lineup whose origin or landing is missing draws nothing on the canvas, +/// so it is not written; neither is a spot no lineup is aimed at. Rows come +/// in the order of their first lineup, their contents in [graph]'s order. +CloudLineupRows cloudLineupRows( + LineUpGraph graph, { + Map groupOf = const {}, + Set takenGroupIds = const {}, +}) { + final originIds = {for (final origin in graph.origins) origin.id}; + final landingIds = {for (final landing in graph.landings) landing.id}; + final links = [ + for (final link in graph.links) + if (originIds.contains(link.originId) && + landingIds.contains(link.landingId)) + link, + ]; + + // The group of each lineup already in one, and so of the spots they aim + // at, as far as [groupOf] does not already say. + final linkGroup = { + for (final link in links) + if (groupOf[link.id] case final group?) link.id: group, }; - final landingIds = { - for (final landing in graph.landings) - landing.id: newId(CloudLineupKind.landing, landing.id), + final spotGroup = {}; + for (final link in links) { + for (final spot in ['o:${link.originId}', 'l:${link.landingId}']) { + final group = groupOf[spot.substring(2)] ?? linkGroup[link.id]; + if (group != null) spotGroup.putIfAbsent(spot, () => group); + } + } + + // New lineups, joined through the spots they share: each kind of id in + // its own namespace, so an origin and a landing with one id stay apart. + final parent = {}; + String find(String node) { + final up = parent[node] ?? node; + if (up == node) return node; + return parent[node] = find(up); + } + + void union(String a, String b) { + final rootA = find(a); + final rootB = find(b); + if (rootA != rootB) parent[rootA] = rootB; + } + + final newLinks = [ + for (final link in links) + if (!linkGroup.containsKey(link.id)) link, + ]; + for (final link in newLinks) { + union('k:${link.id}', 'o:${link.originId}'); + union('k:${link.id}', 'l:${link.landingId}'); + } + final componentLinks = >{}; + final componentGroups = >{}; + for (final link in newLinks) { + final root = find('k:${link.id}'); + (componentLinks[root] ??= []).add(link); + for (final spot in ['o:${link.originId}', 'l:${link.landingId}']) { + if (spotGroup[spot] case final group?) { + (componentGroups[root] ??= {}).add(group); + } + } + } + + String smallest(Iterable ids) => + ids.reduce((a, b) => a.compareTo(b) <= 0 ? a : b); + final used = { + ...takenGroupIds, + ...groupOf.values, + ...linkGroup.values, }; - return LineUpGraph( - origins: [ + for (final MapEntry(key: root, value: component) in componentLinks.entries) { + final String group; + if (componentGroups[root] case final groups?) { + group = smallest(groups); + } else { + final candidates = [for (final link in component) link.id]..sort(); + group = candidates.firstWhere( + (candidate) => !used.contains(candidate), + orElse: () => const Uuid().v4(), + ); + used.add(group); + } + for (final link in component) { + linkGroup[link.id] = group; + } + } + + final linksByGroup = >{}; + for (final link in links) { + (linksByGroup[linkGroup[link.id]!] ??= []).add(link); + } + final assigned = {}; + final rows = []; + for (final MapEntry(key: id, value: groupLinks) in linksByGroup.entries) { + final usedOrigins = {for (final link in groupLinks) link.originId}; + final usedLandings = {for (final link in groupLinks) link.landingId}; + final origins = [ for (final origin in graph.origins) - LineUpOrigin( - id: originIds[origin.id]!, - agent: origin.agent.copyWith(lineUpID: originIds[origin.id]!) - ..isDeleted = origin.agent.isDeleted, - ), - ], - landings: [ + if (usedOrigins.contains(origin.id)) origin, + ]; + final landings = [ for (final landing in graph.landings) - LineUpLanding( - id: landingIds[landing.id]!, - ability: landing.ability.copyWith(lineUpID: landingIds[landing.id]!) - ..isDeleted = landing.ability.isDeleted, - ), - ], - links: [ - for (final link in graph.links) - link.copyWith( - id: newId(CloudLineupKind.link, link.id), - originId: originIds[link.originId] ?? link.originId, - landingId: landingIds[link.landingId] ?? link.landingId, - ), - ], - ); + if (usedLandings.contains(landing.id)) landing, + ]; + for (final link in groupLinks) { + assigned[link.id] = id; + } + // A spot carried by two rows stays with the group it was in. + for (final spot in [...usedOrigins, ...usedLandings]) { + assigned.putIfAbsent(spot, () => groupOf[spot] ?? id); + } + rows.add( + CloudLineupRow( + publicId: id, + payload: cloudLineupsPayload({ + 'id': id, + 'origins': [for (final origin in origins) origin.toJson()], + 'landings': [for (final landing in landings) landing.toJson()], + 'links': [for (final link in groupLinks) link.toJson()], + }), + ), + ); + } + return CloudLineupRows(rows: rows, groupOf: assigned); +} + +/// A page's lineups as its [lineups] on the server describe them. Deleted +/// rows draw nothing. +LineUpGraph lineUpGraphFromRemoteLineups(Iterable lineups) { + return lineUpGraphFromCloudRows([ + for (final lineup in lineups) + if (!lineup.deleted) CloudLineupRow.remote(lineup), + ]).graph; +} + +/// Whether [op] is a lineup change in a cloud format before one row per +/// lineup group: an origin, landing or link row keyed `:`. An +/// outbox written by such a build can still hold one; it is never sent. +bool isRetiredCloudLineupOp(StrategyOp op) { + if (op.entityType != StrategyOpEntityType.lineup) return false; + final payload = op.payload; + return (payload is Map && payload['kind'] != cloudLineupsPayloadKind) || + _retiredLineupKey.hasMatch(op.entityPublicId ?? ''); +} + +final _retiredLineupKey = RegExp(r'^lineup(Origin|Landing|Link):'); + +({ + List origins, + List landings, + List links, +}) _readGroupRow(CloudLineupRow row) { + try { + final kind = row.payload['kind']; + if (kind != cloudLineupsPayloadKind) { + throw FormatException('unknown lineup kind $kind'); + } + final data = cloudPayloadData(row.payload); + if (data['id'] != row.publicId) { + throw FormatException('it holds group ${data['id']}'); + } + final group = ( + origins: [ + for (final json in _objects(data['origins'], 'origins')) + LineUpOrigin.fromJson(json), + ], + landings: [ + for (final json in _objects(data['landings'], 'landings')) + LineUpLanding.fromJson(json), + ], + links: [ + for (final json in _objects(data['links'], 'links')) + LineUpLink.fromJson(json), + ], + ); + final originIds = {for (final origin in group.origins) origin.id}; + final landingIds = {for (final landing in group.landings) landing.id}; + for (final link in group.links) { + if (!originIds.contains(link.originId) || + !landingIds.contains(link.landingId)) { + throw FormatException('lineup ${link.id} is aimed outside the row'); + } + } + return group; + } catch (error, stackTrace) { + Error.throwWithStackTrace( + FormatException('Cloud lineup group ${row.publicId} could not be read: ' + '$error'), + stackTrace, + ); + } +} + +List> _objects(Object? value, String name) { + if (value is! List) throw FormatException('it has no $name'); + return [ + for (final entry in value) + if (entry is Map) + Map.from(entry) + else + throw FormatException('its $name hold something other than objects'), + ]; } diff --git a/lib/collab/cloud_payload_upgrade.dart b/lib/collab/cloud_payload_upgrade.dart index fc230eb0..cedbd421 100644 --- a/lib/collab/cloud_payload_upgrade.dart +++ b/lib/collab/cloud_payload_upgrade.dart @@ -1,22 +1,26 @@ -import 'package:icarus/collab/cloud_lineup_rows.dart'; import 'package:icarus/collab/collab_models.dart'; import 'package:icarus/const/agents.dart'; import 'package:icarus/const/maps.dart'; import 'package:icarus/const/placed_classes.dart'; import 'package:icarus/migrations/paranoia_range_migration.dart'; -/// The payload version of a row holding a Paranoia, as an ability or a -/// lineup landing, drawn at its in-game size (data version 104). Every other -/// row stays at [currentCloudPayloadVersion]: nothing else changed shape. +/// The payload version of an ability row holding a Paranoia drawn at its +/// in-game size (data version 104). Every other row stays at +/// [currentCloudPayloadVersion]: nothing else changed shape. /// -/// A Paranoia row below this version was written by a client that drew the -/// old 25 m Paranoia. It is corrected as it is read, never rewritten on the -/// server, so every client reads it the same way until someone edits it. +/// A Paranoia ability row below this version was written by a client that +/// drew the old 25 m Paranoia. It is corrected as it is read, never +/// rewritten on the server, so every client reads it the same way until +/// someone edits it. +/// +/// Lineup rows are never corrected. The lineup group row (protocol 5) came +/// after data version 104, so every lineup row holds its Paranoia at the +/// in-game size already; correcting one would move it twice. const paranoiaCloudPayloadVersion = 2; -/// [payload] with its Paranoia, if any, at the in-game size on [map]. -/// Payloads without a Paranoia, and those already corrected, come back as -/// they are. +/// Ability [payload] with its Paranoia, if any, at the in-game size on +/// [map]. Payloads without a Paranoia, those already corrected, and those of +/// any other kind come back as they are. CloudPayload upgradeCloudPayload(CloudPayload payload, MapValue map) { final version = payload['payloadVersion']; if (version is num && version >= paranoiaCloudPayloadVersion) { @@ -24,11 +28,8 @@ CloudPayload upgradeCloudPayload(CloudPayload payload, MapValue map) { } final data = payload['data']; if (data is! Map) return payload; - final upgraded = switch (payload['kind']) { - 'ability' => _upgradeAbilityJson(data, map), - CloudLineupKind.landing => _upgradeLandingJson(data, map), - _ => data, - }; + if (payload['kind'] != 'ability') return payload; + final upgraded = _upgradeAbilityJson(data, map); if (identical(upgraded, data)) return payload; return { ...payload, @@ -37,14 +38,9 @@ CloudPayload upgradeCloudPayload(CloudPayload payload, MapValue map) { }; } -/// The version a client writes [data] of [kind] at. +/// The version a client writes element [data] of [kind] at. int cloudPayloadVersionFor(String kind, Map data) { - final ability = switch (kind) { - 'ability' => data, - CloudLineupKind.landing => data['ability'], - _ => null, - }; - return ability is Map && _isParanoiaJson(ability) + return kind == 'ability' && _isParanoiaJson(data) ? paranoiaCloudPayloadVersion : currentCloudPayloadVersion; } @@ -60,7 +56,7 @@ RemotePageSnapshot upgradeRemotePageSnapshot( page: page.page, content: page.content, elements: [for (final e in page.elements) _upgradeElement(e, map)], - lineups: [for (final l in page.lineups) _upgradeLineup(l, map)], + lineups: page.lineups, assetsById: page.assetsById, ); } @@ -78,10 +74,7 @@ RemoteFullStrategySnapshot upgradeRemoteFullSnapshot( for (final MapEntry(:key, :value) in snapshot.elementsByPage.entries) key: [for (final e in value) _upgradeElement(e, map)], }, - lineupsByPage: { - for (final MapEntry(:key, :value) in snapshot.lineupsByPage.entries) - key: [for (final l in value) _upgradeLineup(l, map)], - }, + lineupsByPage: snapshot.lineupsByPage, assetsById: snapshot.assetsById, ); } @@ -101,20 +94,6 @@ RemoteElement _upgradeElement(RemoteElement element, MapValue map) { ); } -RemoteLineup _upgradeLineup(RemoteLineup lineup, MapValue map) { - final payload = upgradeCloudPayload(lineup.payload, map); - if (identical(payload, lineup.payload)) return lineup; - return RemoteLineup( - publicId: lineup.publicId, - strategyPublicId: lineup.strategyPublicId, - pagePublicId: lineup.pagePublicId, - payload: payload, - sortIndex: lineup.sortIndex, - revision: lineup.revision, - deleted: lineup.deleted, - ); -} - /// A map this build does not know cannot be drawn, so its rows stay as the /// server holds them. MapValue? _mapValueOrNull(String wireName) { @@ -131,16 +110,6 @@ bool _isParanoiaJson(Map ability) { info['index'] == 1; } -Map _upgradeLandingJson( - Map landing, - MapValue map, -) { - final ability = landing['ability']; - if (ability is! Map) return landing; - final moved = _upgradeAbilityJson(ability, map); - return identical(moved, ability) ? landing : {...landing, 'ability': moved}; -} - /// [ability] with only its position moved, or [ability] itself when it is /// not a Paranoia. A Paranoia this build cannot read is left as it is; /// hydration skips it the same way. diff --git a/lib/collab/cloud_sync_error_message.dart b/lib/collab/cloud_sync_error_message.dart index a8aab76f..b2a2b3c2 100644 --- a/lib/collab/cloud_sync_error_message.dart +++ b/lib/collab/cloud_sync_error_message.dart @@ -32,8 +32,9 @@ bool isSpecificAttentionReason(String error) { final lower = error.toLowerCase(); return lower.contains('too large for cloud sync') || lower.contains(lineupPageMismatchMessage.toLowerCase()) || - lower.contains(lineupLinkEndMissingMessage.toLowerCase()) || - lower.contains(lineupEndInUseMessage.toLowerCase()) || + lower.contains(lineupOverlapMessage.toLowerCase()) || + lower.contains(retiredLineupOpMessage.toLowerCase()) || + lower.contains(teammateDeletedMessage.toLowerCase()) || lower.contains(pageDeletedMessage.toLowerCase()); } @@ -129,20 +130,29 @@ String friendlyCloudSyncError(String raw) { 'this device. Reduce it, then choose Keep mine to retry, or Use ' 'cloud to drop it.'; } + if (lower.contains(lineupOverlapMessage.toLowerCase())) { + return 'This lineup shares a spot with lineups saved separately, so it ' + 'was not saved to the cloud. It remains on this device. Keep mine ' + 'sends it again, and is refused while the spot is still shared; Use ' + 'cloud removes it here.'; + } if (lower.contains(lineupPageMismatchMessage.toLowerCase())) { return 'This lineup clashes with one on another page, so it was not ' 'saved to the cloud. It remains on this device; Use cloud removes ' 'it here.'; } - if (lower.contains(lineupLinkEndMissingMessage.toLowerCase())) { - return "This lineup's origin or landing spot isn't on this page in the " - 'cloud, so your change to it was not saved. Keep mine tries again; ' - 'Use cloud drops your change.'; + if (lower.contains(teammateDeletedCannotRestoreMessage.toLowerCase())) { + return 'A teammate deleted what this change edits, and this change ' + 'cannot bring it back. Use cloud to let it go.'; + } + if (lower.contains(teammateDeletedMessage.toLowerCase())) { + return 'A teammate deleted what you changed. Keep mine brings it back ' + 'as you have it; Use cloud lets it go.'; } - if (lower.contains(lineupEndInUseMessage.toLowerCase())) { - return 'Another lineup in the cloud still uses this origin or landing ' - 'spot, so it was not deleted. Keep mine tries again; Use cloud ' - 'brings back that lineup here.'; + if (lower.contains(retiredLineupOpMessage.toLowerCase())) { + return 'A lineup change saved by an older version of Icarus cannot be ' + 'sent to the cloud, so it is not in this strategy. Redo it, then ' + 'choose Use cloud to clear this.'; } if (lower.contains(pageDeletedMessage.toLowerCase())) { return 'The page these changes were on was deleted, so they were not ' diff --git a/lib/collab/collab_models.dart b/lib/collab/collab_models.dart index ae7d2c2b..2d95dd39 100644 --- a/lib/collab/collab_models.dart +++ b/lib/collab/collab_models.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'package:icarus/collab/cloud_payload_upgrade.dart'; import 'package:icarus/const/sort_index_order.dart'; -const currentCloudProtocolVersion = 4; +const currentCloudProtocolVersion = 5; const currentCloudPayloadVersion = 1; const maxCloudOperationBytes = 900 * 1024; const maxCloudBatchBytes = 15 * 1024 * 1024; @@ -18,22 +18,35 @@ const cloudOperationTooLargeMessage = const cloudStrategyDeletedMessage = 'This strategy was deleted, so its unsent changes cannot be saved.'; -/// The server's message when it refuses a lineup link whose origin or -/// landing is not live on its page (LINEUP_LINK_END_MISSING). "Keep mine" -/// re-sends such a link as it was. -const lineupLinkEndMissingMessage = - "This lineup's origin or landing spot is no longer on the page"; - /// The server's message when it refuses a lineup whose row already lives on /// another page (LINEUP_PAGE_MISMATCH). const lineupPageMismatchMessage = 'This lineup belongs to another page and cannot be moved'; -/// The server's message when it refuses to delete an origin or landing that -/// a live link on its page still names (LINEUP_END_IN_USE), such as a -/// teammate's lineup this device has not drawn yet. -const lineupEndInUseMessage = - 'Another lineup still uses this origin or landing spot'; +/// The server's message when it refuses a lineup group row holding a +/// lineup or spot another group of the page holds (see assertLineupGroupAlone +/// in convex/lib/lineupItems.ts). Sending it again cannot help. +const lineupOverlapMessage = + 'A lineup or spot in this group is already in another group'; + +/// Marks an outbox record holding a lineup change in the cloud format before +/// one row per lineup (an origin, landing or link row). No server takes it +/// any more, so it is never sent; it waits in attention until the user +/// discards it. +const retiredLineupOpMessage = + 'This lineup change was saved in an older cloud format and cannot be ' + 'sent'; + +/// Why saved work waits when the server refused it because a teammate +/// deleted what it edits (rejection reason `deleted`). Keep mine brings the +/// item back as the user has it. +const teammateDeletedMessage = 'A teammate deleted what this change edits'; + +/// Why such work stays after Keep mine: a reorder, say, holds nothing to +/// bring the item back with. +const teammateDeletedCannotRestoreMessage = + 'A teammate deleted what this change edits, and this change cannot ' + 'bring it back'; /// The server's message when it refuses a change to a page in its trash /// (PAGE_DELETED). Such a change lands if the page is restored and it is @@ -61,17 +74,17 @@ CloudPayload cloudElementPayload({ }; } -/// One lineup row's payload; [kind] is a [CloudLineupKind] (see -/// cloud_lineup_rows.dart). -CloudPayload cloudLineupPayload({ - required String kind, - required Map data, -}) { - final normalized = _normalizeCloudPayloadData(data); +/// The payload kind of a lineup group row (see cloud_lineup_rows.dart). +const cloudLineupsPayloadKind = 'lineups'; + +/// One lineup group row's payload. Lineup rows are never corrected on read +/// (see cloud_payload_upgrade.dart), so they all stay at the current +/// version. +CloudPayload cloudLineupsPayload(Map data) { return { - 'kind': kind, - 'payloadVersion': cloudPayloadVersionFor(kind, normalized), - 'data': normalized, + 'kind': cloudLineupsPayloadKind, + 'payloadVersion': currentCloudPayloadVersion, + 'data': _normalizeCloudPayloadData(data), }; } @@ -1039,6 +1052,7 @@ class PendingOp { enum OpRejectionReason { alreadyExists('already_exists'), + deleted('deleted'), elementStrategyMismatch('element_strategy_mismatch'), lineupStrategyMismatch('lineup_strategy_mismatch'), missingExpectedRevision('missing_expected_revision'), diff --git a/lib/collab/convex_payload_codecs.dart b/lib/collab/convex_payload_codecs.dart index 4e2e07c2..4d28deac 100644 --- a/lib/collab/convex_payload_codecs.dart +++ b/lib/collab/convex_payload_codecs.dart @@ -111,6 +111,25 @@ final class UtilityConvexCodec implements ConvexPayloadCodec { ConvexValue encode(CloudPayload value) => _encodePayload(value, 'utility'); } +// One lineup group: the lineups on a page joined through shared spots. +@ConvexPayload('lineups') +final class LineupsConvexCodec implements ConvexPayloadCodec { + const LineupsConvexCodec(); + + @override + CloudPayload decode(ConvexValue value) => _decodePayload(value, 'lineups'); + + @override + ConvexValue encode(CloudPayload value) => _encodePayload(value, 'lineups'); +} + +// The origin, landing and link rows of protocol 4. The server still takes +// them as lineup op arguments, so an old client reaches its protocol gate +// instead of failing argument validation, and refuses them in the handler +// (see lineupOpPayloadValidator in convex/lib/payloadValidators.ts). This +// build never sends them: an outbox record holding one waits in attention +// (see isRetiredCloudLineupOp). + @ConvexPayload('lineupOrigin') final class LineupOriginConvexCodec implements ConvexPayloadCodec { diff --git a/lib/collab/convex_strategy_repository.dart b/lib/collab/convex_strategy_repository.dart index d45886e1..89c6330b 100644 --- a/lib/collab/convex_strategy_repository.dart +++ b/lib/collab/convex_strategy_repository.dart @@ -349,12 +349,6 @@ class ConvexStrategyRepository { clientProtocolVersion: currentCloudProtocolVersion.toDouble(), ops: typedOps, accountSubject: _optional(accountSubject), - // Links are sent only with or after their origin and landing (see - // the outbox's batch claim), so the server may refuse an orphan. - checkLineupLinkEnds: const ConvexOptional.present(true), - // An origin or landing delete is sent only with or after the link - // deletes on its page, so the server may refuse one a live link names. - checkLineupEndDeletes: const ConvexOptional.present(true), // This client restores deleted pages, so it sends such a delete again. checkTrashedPageDeletes: const ConvexOptional.present(true), ); diff --git a/lib/collab/generated/convex_error_codes.dart b/lib/collab/generated/convex_error_codes.dart index cb5b8fe2..fb8b0bbb 100644 --- a/lib/collab/generated/convex_error_codes.dart +++ b/lib/collab/generated/convex_error_codes.dart @@ -22,8 +22,6 @@ enum ConvexErrorCode { invalidPayload('INVALID_PAYLOAD'), inviteExpired('INVITE_EXPIRED'), inviteRevoked('INVITE_REVOKED'), - lineupEndInUse('LINEUP_END_IN_USE'), - lineupLinkEndMissing('LINEUP_LINK_END_MISSING'), lineupPageMismatch('LINEUP_PAGE_MISMATCH'), lineupStrategyMismatch('LINEUP_STRATEGY_MISMATCH'), missingAddElementArgs('MISSING_ADD_ELEMENT_ARGS'), diff --git a/lib/collab/generated/convex_models.dart b/lib/collab/generated/convex_models.dart index 103f248e..e5c8d9a4 100644 --- a/lib/collab/generated/convex_models.dart +++ b/lib/collab/generated/convex_models.dart @@ -284,6 +284,7 @@ enum InvitesCreateArgsRole { enum OpsApplyBatchResultResultsItemRejectedReason { alreadyExists('already_exists'), + deleted('deleted'), elementStrategyMismatch('element_strategy_mismatch'), lineupStrategyMismatch('lineup_strategy_mismatch'), missingExpectedRevision('missing_expected_revision'), @@ -1285,8 +1286,10 @@ final class LineupsListForPageResultItem { object.value['pagePublicId'] ?? _missing(path, 'pagePublicId'), '$path.pagePublicId', ), - payload: _decodeLineupsListForPageResultItemPayload( - object.value['payload'] ?? _missing(path, 'payload'), + payload: _decodePayload( + () => const LineupsConvexCodec().decode( + object.value['payload'] ?? _missing(path, 'payload'), + ), '$path.payload', ), publicId: _decodeString( @@ -1317,8 +1320,8 @@ final class LineupsListForPageResultItem { 'createdAt': _encodeNumber(createdAt, '$path.createdAt'), 'deleted': ConvexBoolean(deleted), 'pagePublicId': ConvexString(pagePublicId), - 'payload': _encodeLineupsListForPageResultItemPayload( - payload, + 'payload': _encodePayload( + () => const LineupsConvexCodec().encode(payload), '$path.payload', ), 'publicId': ConvexString(publicId), @@ -2857,8 +2860,10 @@ final class OpsApplyBatchResultResultsItemRejectedCurrentLineup object.value['revision'] ?? _missing(path, 'revision'), '$path.revision', ), - value: _decodeOpsApplyBatchResultResultsItemRejectedCurrentLineupValue( - object.value['value'] ?? _missing(path, 'value'), + value: _decodePayload( + () => const LineupsConvexCodec().decode( + object.value['value'] ?? _missing(path, 'value'), + ), '$path.value', ), ); @@ -2869,8 +2874,8 @@ final class OpsApplyBatchResultResultsItemRejectedCurrentLineup return ConvexObject({ 'type': ConvexString('lineup'), 'revision': _encodeNumber(revision, '$path.revision'), - 'value': _encodeOpsApplyBatchResultResultsItemRejectedCurrentLineupValue( - value, + 'value': _encodePayload( + () => const LineupsConvexCodec().encode(value), '$path.value', ), }); @@ -4457,60 +4462,6 @@ ConvexValue _encodeElementsListForPageResultItemPayload( }; } -CloudPayload _decodeLineupsListForPageResultItemPayload( - ConvexValue value, - String path, -) { - final object = _decodeObject(value, path); - final tag = _decodeString( - object.value['kind'] ?? _missing(path, 'kind'), - '$path.kind', - ); - return switch (tag) { - 'lineupOrigin' => _decodePayload( - () => const LineupOriginConvexCodec().decode(value), - path, - ), - 'lineupLanding' => _decodePayload( - () => const LineupLandingConvexCodec().decode(value), - path, - ), - 'lineupLink' => _decodePayload( - () => const LineupLinkConvexCodec().decode(value), - path, - ), - _ => throw ConvexDecodingException( - '$path.kind', - 'unknown payload tag $tag', - ), - }; -} - -ConvexValue _encodeLineupsListForPageResultItemPayload( - CloudPayload value, - String path, -) { - final tag = value['kind']; - return switch (tag) { - 'lineupOrigin' => _encodePayload( - () => const LineupOriginConvexCodec().encode(value), - path, - ), - 'lineupLanding' => _encodePayload( - () => const LineupLandingConvexCodec().encode(value), - path, - ), - 'lineupLink' => _encodePayload( - () => const LineupLinkConvexCodec().encode(value), - path, - ), - _ => throw ConvexEncodingException( - '$path.kind', - 'unknown payload tag $tag', - ), - }; -} - CloudPayload _decodeOpsApplyBatchArgsOpsItemElementAddPayload( ConvexValue value, String path, @@ -4665,6 +4616,10 @@ CloudPayload _decodeOpsApplyBatchArgsOpsItemLineupAddPayload( '$path.kind', ); return switch (tag) { + 'lineups' => _decodePayload( + () => const LineupsConvexCodec().decode(value), + path, + ), 'lineupOrigin' => _decodePayload( () => const LineupOriginConvexCodec().decode(value), path, @@ -4690,6 +4645,10 @@ ConvexValue _encodeOpsApplyBatchArgsOpsItemLineupAddPayload( ) { final tag = value['kind']; return switch (tag) { + 'lineups' => _encodePayload( + () => const LineupsConvexCodec().encode(value), + path, + ), 'lineupOrigin' => _encodePayload( () => const LineupOriginConvexCodec().encode(value), path, @@ -4719,6 +4678,10 @@ CloudPayload _decodeOpsApplyBatchArgsOpsItemLineupPatchPayload( '$path.kind', ); return switch (tag) { + 'lineups' => _decodePayload( + () => const LineupsConvexCodec().decode(value), + path, + ), 'lineupOrigin' => _decodePayload( () => const LineupOriginConvexCodec().decode(value), path, @@ -4744,6 +4707,10 @@ ConvexValue _encodeOpsApplyBatchArgsOpsItemLineupPatchPayload( ) { final tag = value['kind']; return switch (tag) { + 'lineups' => _encodePayload( + () => const LineupsConvexCodec().encode(value), + path, + ), 'lineupOrigin' => _encodePayload( () => const LineupOriginConvexCodec().encode(value), path, @@ -4835,60 +4802,6 @@ ConvexValue _encodeOpsApplyBatchResultResultsItemRejectedCurrentElementValue( }; } -CloudPayload _decodeOpsApplyBatchResultResultsItemRejectedCurrentLineupValue( - ConvexValue value, - String path, -) { - final object = _decodeObject(value, path); - final tag = _decodeString( - object.value['kind'] ?? _missing(path, 'kind'), - '$path.kind', - ); - return switch (tag) { - 'lineupOrigin' => _decodePayload( - () => const LineupOriginConvexCodec().decode(value), - path, - ), - 'lineupLanding' => _decodePayload( - () => const LineupLandingConvexCodec().decode(value), - path, - ), - 'lineupLink' => _decodePayload( - () => const LineupLinkConvexCodec().decode(value), - path, - ), - _ => throw ConvexDecodingException( - '$path.kind', - 'unknown payload tag $tag', - ), - }; -} - -ConvexValue _encodeOpsApplyBatchResultResultsItemRejectedCurrentLineupValue( - CloudPayload value, - String path, -) { - final tag = value['kind']; - return switch (tag) { - 'lineupOrigin' => _encodePayload( - () => const LineupOriginConvexCodec().encode(value), - path, - ), - 'lineupLanding' => _encodePayload( - () => const LineupLandingConvexCodec().encode(value), - path, - ), - 'lineupLink' => _encodePayload( - () => const LineupLinkConvexCodec().encode(value), - path, - ), - _ => throw ConvexEncodingException( - '$path.kind', - 'unknown payload tag $tag', - ), - }; -} - bool _validateFoldersCreateResult(ConvexValue value) => (_matchesRaw0(value) || _matchesRaw2(value)); diff --git a/lib/const/line_provider.dart b/lib/const/line_provider.dart index af06eae2..3df9ada4 100644 --- a/lib/const/line_provider.dart +++ b/lib/const/line_provider.dart @@ -1438,6 +1438,29 @@ class LineUpProvider extends Notifier { ); } + /// Takes [graph] as the server's lineups merged with the ones the user + /// holds (see mergeHeldLineups). Held objects stay the ones on screen. + void mergeRemote(LineUpGraph graph) { + state = state.copyWith( + origins: [...graph.origins], + landings: [...graph.landings], + links: [...graph.links], + ); + } + + /// Puts [graph]'s lineups on the canvas beside the ones there: the user's + /// version of a conflicting lineup group, kept as a copy (see + /// forkLineUpGraph). A recovery step rather than an edit, so it is not + /// undoable, as taking the cloud's version is not. + void addRecovered(LineUpGraph graph) { + final copy = graph.deepCopy(); + state = state.copyWith( + origins: [...state.origins, ...copy.origins], + landings: [...state.landings, ...copy.landings], + links: [...state.links, ...copy.links], + ); + } + static String objectToJson(LineUpGraph graph) { return jsonEncode(graph.toJson()); } diff --git a/lib/providers/collab/active_page_live_sync_provider.dart b/lib/providers/collab/active_page_live_sync_provider.dart index 921fc1dc..dc713d65 100644 --- a/lib/providers/collab/active_page_live_sync_provider.dart +++ b/lib/providers/collab/active_page_live_sync_provider.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:math' show max; @@ -5,7 +6,6 @@ import 'dart:math' show max; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:icarus/collab/canonical_json.dart'; import 'package:icarus/const/sort_index_order.dart'; -import 'package:icarus/services/app_error_reporter.dart'; import 'package:icarus/const/weapons.dart'; import 'package:icarus/collab/collab_models.dart'; import 'package:icarus/collab/cloud_lineup_rows.dart'; @@ -15,6 +15,7 @@ import 'package:icarus/providers/ability_provider.dart'; import 'package:icarus/providers/agent_provider.dart'; import 'package:icarus/providers/collab/active_page_live_sync_models.dart'; import 'package:icarus/providers/collab/remote_strategy_snapshot_provider.dart'; +import 'package:icarus/providers/collab/strategy_conflict_provider.dart'; import 'package:icarus/providers/collab/strategy_op_queue_provider.dart'; import 'package:icarus/providers/drawing_provider.dart'; import 'package:icarus/providers/image_provider.dart'; @@ -33,7 +34,6 @@ class ActivePageLiveSyncState { this.remoteBaseRevisionByEntity = const {}, this.overlayByEntityKey = const {}, this.lastAckBatch = const [], - this.unsyncableLineupKeys = const {}, }); final String? strategyPublicId; @@ -44,14 +44,6 @@ class ActivePageLiveSyncState { final Map overlayByEntityKey; final List lastAckBatch; - /// Lineup rows live sync refused to send because the canvas holds a broken - /// lineup: rows hydration would not draw back (a link whose origin or - /// landing is missing, an origin or landing no link uses) and the missing - /// ends themselves. Sending them would store rows every reader skips or - /// half-delete the lineup, so the sync status shows attention while any - /// remain. - final Set unsyncableLineupKeys; - ActivePageLiveSyncState copyWith({ String? strategyPublicId, String? activePageId, @@ -62,7 +54,6 @@ class ActivePageLiveSyncState { Map? remoteBaseRevisionByEntity, Map? overlayByEntityKey, List? lastAckBatch, - Set? unsyncableLineupKeys, }) { return ActivePageLiveSyncState( strategyPublicId: strategyPublicId ?? this.strategyPublicId, @@ -75,7 +66,6 @@ class ActivePageLiveSyncState { remoteBaseRevisionByEntity ?? this.remoteBaseRevisionByEntity, overlayByEntityKey: overlayByEntityKey ?? this.overlayByEntityKey, lastAckBatch: lastAckBatch ?? this.lastAckBatch, - unsyncableLineupKeys: unsyncableLineupKeys ?? this.unsyncableLineupKeys, ); } } @@ -99,6 +89,36 @@ class ActivePageLiveSyncNotifier extends Notifier { /// hold ends, but no longer ordered against anything on the server. final Set _heldDeletedKeys = {}; + /// Per page, the lineup group each lineup and spot was last drawn from or + /// written to (see cloudLineupRows), so a group keeps its id and its + /// lineups while the canvas changes under it. Per page because a page + /// duplicated before cloud sync repeats its lineup ids. Never forgotten: + /// an undo can bring back a lineup long after its row moved on. + final Map> _lineupGroupOfByPage = {}; + + /// Records the groups a canvas of [pageId] about to be drawn from cloud + /// rows uses. + void noteLineupGroups(String pageId, Map groupOf) { + (_lineupGroupOfByPage[pageId] ??= {}).addAll(groupOf); + } + + /// The server's version of [key] the canvas was drawn from, which local + /// edits to it were made against: its revision, and its payload (null + /// when it was deleted). Null when the canvas was drawn without it. + ({int revision, Object? payload})? hydratedBase(EntitySyncKey key) { + final base = _hydratedBaseByEntityKey[key]; + if (base == null) return null; + return ( + revision: base.revision, + payload: base.deleted ? null : base.payload + ); + } + + /// The lineup group [itemId] (a lineup, origin or landing) on [pageId] + /// was last in. + String? lineupGroupOf(String pageId, String itemId) => + _lineupGroupOfByPage[pageId]?[itemId]; + @override ActivePageLiveSyncState build() { return const ActivePageLiveSyncState(); @@ -173,15 +193,8 @@ class ActivePageLiveSyncNotifier extends Notifier { setContext(strategyPublicId: strategyPublicId, activePageId: pageId); final matchesPage = snapshot.header.publicId == strategyPublicId && snapshot.activePage?.page.publicId == pageId; - // The base is what the canvas drew. A lineup row hydration skipped was - // never shown, so no outbound diff may change or delete it. - final undrawnLineups = matchesPage - ? _undrawnRemoteLineups(snapshot, pageId) - : const {}; final remoteEntities = { - if (matchesPage) - for (final entry in _normalizedRemoteEntities(snapshot, pageId).entries) - if (!undrawnLineups.contains(entry.key)) entry.key: entry.value, + if (matchesPage) ..._normalizedRemoteEntities(snapshot, pageId), }; _heldDeletedKeys ..removeWhere((key) => key.pageId == pageId) @@ -248,7 +261,6 @@ class ActivePageLiveSyncNotifier extends Notifier { RemoteEditorSnapshot snapshot, String pageId, ) { - final undrawn = _undrawnRemoteLineups(snapshot, pageId); _NormalizedEntity? live(_NormalizedEntity? entity) => entity == null || entity.deleted ? null : entity; final remote = _normalizedRemoteEntities(snapshot, pageId); @@ -258,10 +270,10 @@ class ActivePageLiveSyncNotifier extends Notifier { }; return { for (final key in keys) - // A row the canvas cannot draw counts as gone on the server side - // only: the base is what the canvas did draw. - if (undrawn.contains(key) ? null : live(remote[key]) case final now - when !_sameLiveEntity(now, live(_hydratedBaseByEntityKey[key]))) + if (!_sameLiveEntity( + live(remote[key]), + live(_hydratedBaseByEntityKey[key]), + )) key, }; } @@ -536,13 +548,7 @@ class ActivePageLiveSyncNotifier extends Notifier { state.overlayByEntityKey, ); final retainedDesiredOps = {}; - final heldBackLineups = _heldBackLineups(pageId); - final restoredLineupEnds = _lineupEndsToRestore( - pageId: pageId, - localEntities: localEntities, - remoteEntities: remoteEntities, - ); - final unsyncableLineups = {}; + final settledAttention = {}; for (final key in pageKeys) { if (_remoteAdoptionPending.contains(key)) { @@ -561,41 +567,6 @@ class ActivePageLiveSyncNotifier extends Notifier { queueState.inFlightByEntityKey[key]?.pending.op ?? queueState.queuedByEntityKey[key]?.pending.op; - // Never author a lineup row that hydration would not draw (every - // reader skips it, so it reads as a deletion nobody made), nor delete - // an end a local link still names. Keep what is already overlaid or - // queued for it and show attention instead. - if (heldBackLineups.contains(key)) { - unsyncableLineups.add(key); - if (!state.unsyncableLineupKeys.contains(key)) { - AppErrorReporter.reportError( - 'A lineup could not be synced because its origin or landing ' - 'spot is missing ($key).', - source: 'active_page_live_sync:empty_lineup', - promptUser: false, - ); - } - if (existingOverlay == null && retainedOp != null) { - retainedDesiredOps[key] = retainedOp; - } - continue; - } - - if (restoredLineupEnds.contains(key)) { - nextOverlay[key] = ActivePageOverlayEntry( - entityKey: key, - entityType: ActivePageOverlayEntityType.lineup, - desiredPayload: local!.payload, - desiredSortIndex: local.sortIndex, - deletion: false, - baseRevision: remote?.revision, - baseDeleted: true, - dirtyAt: DateTime.now(), - ); - _debugLog('overlay.upsert $key reason=restore_deleted_lineup_end'); - continue; - } - final shouldPreserveTouched = hasQueued || hasInFlight || hasSuccessor; final matchesRemote = _entitiesEquivalent(local, remote); final matchesHydratedBase = _entitiesEquivalent(local, hydratedBase); @@ -612,6 +583,18 @@ class ActivePageLiveSyncNotifier extends Notifier { continue; } + // The user deleted, on the canvas, an item whose change the server + // refused because a teammate deleted it: both sides have it deleted, + // so the refused change has nothing left to keep, and Keep mine must + // not bring the item back. + if (local == null && + existingOverlay != null && + (remote == null || remote.deleted) && + queueState.attentionByEntityKey.containsKey(key) && + ref.read(strategyOpQueueProvider.notifier).refusedAsDeleted(key)) { + settledAttention.add(key); + } + if (matchesHydratedBase && !shouldPreserveTouched) { if (nextOverlay.remove(key) != null) { _debugLog('overlay.remove $key reason=unchanged_since_hydration'); @@ -696,6 +679,20 @@ class ActivePageLiveSyncNotifier extends Notifier { ); } + if (settledAttention.isNotEmpty) { + // A refusal still waiting to be announced is moot too, as when the + // user chooses Use cloud. + for (final key in settledAttention) { + final refused = queueState.attentionByEntityKey[key]!.pending.op.opId; + ref.read(strategyConflictProvider.notifier).clear(refused); + } + unawaited( + ref + .read(strategyOpQueueProvider.notifier) + .settleAttention(settledAttention), + ); + } + final desiredOpsByEntityKey = { ...retainedDesiredOps, }; @@ -725,10 +722,6 @@ class ActivePageLiveSyncNotifier extends Notifier { strategyPublicId: strategyPublicId, activePageId: pageId, overlayByEntityKey: nextOverlay, - unsyncableLineupKeys: { - ...state.unsyncableLineupKeys.where((key) => key.pageId != pageId), - ...unsyncableLineups, - }, ); return desiredOpsByEntityKey; @@ -1027,9 +1020,26 @@ class ActivePageLiveSyncNotifier extends Notifier { ); } - // One row per origin, landing and link. + // One row per lineup group, holding its lineups and their spots as the + // canvas draws them. A group nobody changed matches its stored row, so + // it is never written. A new group never takes the id of a row this page + // has or had, so it never lands on a teammate's group or a deleted one. final freshLineupSortIndex = freshSortIndexes(EntitySyncKeyKind.lineup); - for (final row in cloudLineupRows(ref.read(lineUpProvider).graph)) { + final lineupGroupOf = _lineupGroupOfByPage[pageId] ??= {}; + final lineupRows = cloudLineupRows( + ref.read(lineUpProvider).graph, + groupOf: lineupGroupOf, + takenGroupIds: { + for (final key in [ + ..._hydratedBaseByEntityKey.keys, + ...state.overlayByEntityKey.keys, + ]) + if (key.pageId == pageId && key.kind == EntitySyncKeyKind.lineup) + key.entityId!, + }, + ); + lineupGroupOf.addAll(lineupRows.groupOf); + for (final row in lineupRows.rows) { final key = EntitySyncKey.lineup(pageId, row.publicId); entities[key] = _NormalizedEntity( key: key, @@ -1040,93 +1050,9 @@ class ActivePageLiveSyncNotifier extends Notifier { deleted: false, ); } - return entities; } - /// Lineup rows live sync holds back from a broken local graph: rows the - /// canvas holds that hydration would not draw back (a link whose origin or - /// landing is missing, an origin or landing no link uses), judged by the - /// reader hydration uses, and the missing ends such a link still names, so - /// a broken lineup is neither half-written nor half-deleted. - Set _heldBackLineups(String pageId) { - EntitySyncKey key(String rowId) => EntitySyncKey.lineup(pageId, rowId); - final graph = ref.read(lineUpProvider).graph; - final rows = cloudLineupRows(graph); - final drawn = lineUpGraphFromCloudRows(rows).drawnRowIds; - final originIds = {for (final origin in graph.origins) origin.id}; - final landingIds = {for (final landing in graph.landings) landing.id}; - return { - for (final row in rows) - if (!drawn.contains(row.publicId)) key(row.publicId), - for (final link in graph.links) ...[ - if (!originIds.contains(link.originId)) - key(cloudLineupRowId(CloudLineupKind.origin, link.originId)), - if (!landingIds.contains(link.landingId)) - key(cloudLineupRowId(CloudLineupKind.landing, link.landingId)), - ], - }; - } - - /// Origins and landings a teammate deleted after this canvas drew them, - /// which a link the user is placing or editing still names. They are added - /// back with the link: the server refuses a link whose ends are gone, and - /// the lineup the user just made would not save. A link the teammate - /// deleted too is left to the conflict flow. - Set _lineupEndsToRestore({ - required String pageId, - required Map localEntities, - required Map remoteEntities, - }) { - EntitySyncKey key(String kind, String id) => - EntitySyncKey.lineup(pageId, cloudLineupRowId(kind, id)); - bool deletedSinceDrawn(EntitySyncKey endKey) { - final drawn = _hydratedBaseByEntityKey[endKey]; - final remote = remoteEntities[endKey]; - return localEntities.containsKey(endKey) && - drawn != null && - !drawn.deleted && - (remote == null || remote.deleted); - } - - final ends = {}; - for (final link in ref.read(lineUpProvider).graph.links) { - final linkKey = key(CloudLineupKind.link, link.id); - final isAuthored = !_entitiesEquivalent( - localEntities[linkKey], - _hydratedBaseByEntityKey[linkKey], - ); - final isDeletedRemotely = remoteEntities[linkKey]?.deleted ?? false; - if (!isAuthored || isDeletedRemotely) continue; - for (final endKey in [ - key(CloudLineupKind.origin, link.originId), - key(CloudLineupKind.landing, link.landingId), - ]) { - if (deletedSinceDrawn(endKey)) ends.add(endKey); - } - } - return ends; - } - - /// The page's live lineup rows that hydration skipped. - Set _undrawnRemoteLineups( - RemoteEditorSnapshot snapshot, - String pageId, - ) { - final live = [ - for (final lineup - in snapshot.lineupsByPage[pageId] ?? const []) - if (!lineup.deleted) - CloudLineupRow(publicId: lineup.publicId, payload: lineup.payload), - ]; - final drawn = lineUpGraphFromCloudRows(live).drawnRowIds; - return { - for (final row in live) - if (!drawn.contains(row.publicId)) - EntitySyncKey.lineup(pageId, row.publicId), - }; - } - List<_CollabElementEnvelope> _collectLocalElementEnvelopes() { final envelopes = <_CollabElementEnvelope>[]; diff --git a/lib/providers/collab/cloud_sync_status_provider.dart b/lib/providers/collab/cloud_sync_status_provider.dart index 23acc5e0..082b5d26 100644 --- a/lib/providers/collab/cloud_sync_status_provider.dart +++ b/lib/providers/collab/cloud_sync_status_provider.dart @@ -1,5 +1,4 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:icarus/providers/collab/active_page_live_sync_provider.dart'; import 'package:icarus/providers/collab/client_upgrade_required_provider.dart'; import 'package:icarus/providers/collab/cloud_media_upload_queue_provider.dart'; import 'package:icarus/providers/collab/convex_connection_provider.dart'; @@ -49,9 +48,6 @@ final cloudSyncStatusProvider = Provider((ref) { } if (opQueueState.needsAttention || opQueueState.accountOutbox.needsAttention || - ref.watch(activePageLiveSyncProvider.select( - (liveSync) => liveSync.unsyncableLineupKeys.isNotEmpty, - )) || saveState.mediaSyncErrorCount > 0 || accountMediaErrorCount > 0) { return CloudSyncStatus.attention; diff --git a/lib/providers/collab/lineup_conflicts_provider.dart b/lib/providers/collab/lineup_conflicts_provider.dart new file mode 100644 index 00000000..9ae437f0 --- /dev/null +++ b/lib/providers/collab/lineup_conflicts_provider.dart @@ -0,0 +1,125 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:icarus/collab/cloud_lineup_rows.dart'; +import 'package:icarus/collab/collab_models.dart'; +import 'package:icarus/const/line_provider.dart'; +import 'package:icarus/providers/collab/active_page_live_sync_models.dart'; +import 'package:icarus/providers/collab/active_page_live_sync_provider.dart'; +import 'package:icarus/providers/collab/remote_strategy_snapshot_provider.dart'; +import 'package:icarus/providers/collab/strategy_op_queue_provider.dart'; +import 'package:icarus/strategy/lineup_group_changes.dart'; + +/// A lineup group whose change the server refused, and what each side did +/// to it since the version both started from. +class LineupGroupConflict { + const LineupGroupConflict({ + required this.key, + required this.yours, + required this.cloud, + }); + + final EntitySyncKey key; + + /// The user's waiting version against the version it was made from, or, + /// when [cloud] is null, against the cloud's version. + final List yours; + + /// The cloud's version against the one the user's was made from. Null + /// when that version is no longer on this device (the page was drawn + /// again since): then who changed what cannot be told apart. + final List? cloud; +} + +/// What the active strategy's refused work does to its lineup groups, when +/// that work is all lineup groups on the page on screen: the case Keep both +/// covers. Null otherwise, and the sync popover offers Keep mine and Use +/// cloud alone. +/// +/// Every version is read from what this device already has: the user's +/// newest waiting change, the server's version the canvas was drawn from, +/// and the live copy of the page. The version drawn from tells the sides' +/// changes apart only while it is the one the refused change was made +/// against; once the page is drawn again it is the cloud's, so every +/// conflict then lists only how the user's version differs from the +/// cloud's. When a version cannot be read, there is nothing trustworthy to +/// show, so this is null too. +final lineupConflictsProvider = Provider?>((ref) { + final queue = ref.watch(strategyOpQueueProvider); + final attention = queue.attentionByEntityKey; + final page = ref.watch(remoteEditorSnapshotProvider).valueOrNull?.activePage; + // Keep both saves a copy; while outbox records cannot be saved it is not + // offered. + if (attention.isEmpty || page == null || queue.hasDurabilityFailure) { + return null; + } + final pageId = page.page.publicId; + if (attention.keys.any( + (key) => key.kind != EntitySyncKeyKind.lineup || key.pageId != pageId, + )) { + return null; + } + + final liveSync = ref.read(activePageLiveSyncProvider.notifier); + final cloudRows = {for (final row in page.lineups) row.publicId: row}; + final versions = <(EntitySyncKey, LineUpGraph, LineUpGraph, LineUpGraph)>[]; + var basesHold = true; + for (final MapEntry(:key, value: refused) in attention.entries) { + final base = liveSync.hydratedBase(key); + final refusedOp = refused.pending.op; + final madeAgainst = switch (refusedOp) { + LineupAddOp(:final expectedLineupRevision) => expectedLineupRevision, + LineupPatchOp(:final expectedLineupRevision) => expectedLineupRevision, + LineupDeleteOp(:final expectedLineupRevision) => expectedLineupRevision, + LineupReorderOp(:final expectedLineupRevision) => expectedLineupRevision, + _ => null, + }; + if (base?.revision != madeAgainst) basesHold = false; + final newest = (queue.successorByEntityKey[key] ?? refused).pending.op; + final yoursPayload = switch (newest) { + LineupAddOp(:final payload) => payload, + LineupPatchOp(:final payload?) => payload, + LineupDeleteOp() => null, + _ => base?.payload, + }; + final cloudRow = cloudRows[key.entityId]; + final yours = _groupGraph(key, yoursPayload); + final cloud = _groupGraph( + key, + cloudRow == null || cloudRow.deleted ? null : cloudRow.payload, + ); + final from = + base == null ? LineUpGraph.empty : _groupGraph(key, base.payload); + if (yours == null || cloud == null || from == null) return null; + versions.add((key, yours, cloud, from)); + } + final conflicts = [ + for (final (key, yours, cloud, from) in versions) + basesHold + ? LineupGroupConflict( + key: key, + yours: lineupChanges(from: from, to: yours), + cloud: lineupChanges(from: from, to: cloud), + ) + : LineupGroupConflict( + key: key, + yours: lineupChanges(from: cloud, to: yours), + cloud: null, + ), + ]; + return conflicts; +}); + +/// The lineups one group row's [payload] holds; empty for no row, null when +/// the row cannot be read. +LineUpGraph? _groupGraph(EntitySyncKey key, Object? payload) { + if (payload == null) return LineUpGraph.empty; + try { + return lineUpGraphFromCloudRows([ + CloudLineupRow( + publicId: key.entityId!, + payload: cloudObjectPayload(payload), + ), + ]).graph; + } on FormatException { + return null; + } +} diff --git a/lib/providers/collab/strategy_op_queue_provider.dart b/lib/providers/collab/strategy_op_queue_provider.dart index 39e85003..14aacf0c 100644 --- a/lib/providers/collab/strategy_op_queue_provider.dart +++ b/lib/providers/collab/strategy_op_queue_provider.dart @@ -239,7 +239,7 @@ class StrategyOpQueueNotifier extends Notifier { final loaded = _store.load(); _recordsByStorageKey = { for (final record in loaded.records) - record.storageKey: _resumedAfterUpgrade(record), + record.storageKey: _retiredAsAttention(_resumedAfterUpgrade(record)), }; ref.onDispose(() { _isDisposed = true; @@ -289,6 +289,24 @@ class StrategyOpQueueNotifier extends Notifier { ); } + /// [record] waiting in attention when it holds a lineup change in the + /// cloud format before one row per lineup, whatever state an older build + /// left it in (queued, paused, refused for another reason). It can never + /// be sent; in attention it is shown, with its reason, and nothing but the + /// user's discard removes it: reconciling the canvas's work never touches + /// attention. Like [_resumedAfterUpgrade], only the copy in memory changes. + static DurableOutboxRecord _retiredAsAttention(DurableOutboxRecord record) { + if (!isRetiredCloudLineupOp(record.pending.op) || + (record.status == DurableOutboxStatus.attention && + record.lastError == retiredLineupOpMessage)) { + return record; + } + return record.copyWith( + status: DurableOutboxStatus.attention, + lastError: retiredLineupOpMessage, + ); + } + /// [record] as this build sends it. Work a build the server refused kept /// failing through no fault of its own, and may have been paused for it; /// it goes back in the queue with no failures counted. Only the copy in @@ -975,17 +993,16 @@ class StrategyOpQueueNotifier extends Notifier { final rejectedOp = rejected.op; final successor = record?.successorPending; final retryOp = successor?.op ?? rejectedOp; + // No server takes a lineup change in the old cloud format; sending + // it again would only bring it back here. + if (isRetiredCloudLineupOp(retryOp)) continue; final isPayloadPolicyAttention = record?.lastError == cloudOperationTooLargeMessage || cloudOperationExceedsPolicy(rejectedOp); - // Nothing moved on the server: the link is re-sent as it was, - // add or patch, once its ends are back; a change to a page in the - // trash, once the page is restored. - final isMissingLinkEnd = - record?.lastError == lineupLinkEndMissingMessage; + // Nothing moved on the server: a change to a page in the trash is + // re-sent as it was once the page is restored. final isOnDeletedPage = record?.lastError == pageDeletedMessage; - final retriesAsSent = - isPayloadPolicyAttention || isMissingLinkEnd || isOnDeletedPage; + final retriesAsSent = isPayloadPolicyAttention || isOnDeletedPage; final retryRevision = record?.latestServerRevision ?? rejectedOp.expectedRevision; if (!retriesAsSent && retryRevision == null) continue; @@ -993,13 +1010,24 @@ class StrategyOpQueueNotifier extends Notifier { (retryOp is ElementAddOp || retryOp is LineupAddOp) && (record?.lastError == 'missing_expected_revision' || record?.lastError == 'revision_mismatch'); - final rebasedOp = retriesAsSent - ? retryOp.withOpId(const Uuid().v4()) - : _rebaseRejectedOp( - retryOp, - retryRevision!, - preserveAdd: isTombstoneRestore, - ); + // A teammate deleted what this change edits. Keeping mine brings + // it back as the user has it: an add over the tombstone. + final restoresDeleted = + record?.lastError == OpRejectionReason.deleted.wireName; + final StrategyOp rebasedOp; + if (retriesAsSent) { + rebasedOp = retryOp.withOpId(const Uuid().v4()); + } else if (restoresDeleted) { + final restore = _restoreOp(retryOp, retryRevision!); + if (restore == null) continue; + rebasedOp = restore; + } else { + rebasedOp = _rebaseRejectedOp( + retryOp, + retryRevision!, + preserveAdd: isTombstoneRestore, + ); + } _keepCanvasWritten(retryOp, rebasedOp); final pending = PendingOp( op: rebasedOp, @@ -1042,9 +1070,30 @@ class StrategyOpQueueNotifier extends Notifier { } if (!changed) { if (only != null) return; + // Old-format lineup changes are skipped on purpose, and keep their + // own reason. + final onlyRetired = attention.values.every( + (intent) => isRetiredCloudLineupOp(intent.pending.op), + ); + // Changes a teammate's delete refused that hold nothing to bring + // the item back with. + final cannotRestore = attention.keys.any( + (key) => + _recordForActiveKey(key)?.lastError == + OpRejectionReason.deleted.wireName, + ); state = state.copyWith( - lastError: 'Some retained cloud work cannot be retried ' - 'automatically because the server has no matching revision.', + lastError: onlyRetired + ? _loadedAttentionMessage( + loadIssues: state.loadIssues, + paused: state.pausedByEntityKey, + attention: attention, + ) + : cannotRestore + ? teammateDeletedCannotRestoreMessage + : 'Some retained cloud work cannot be retried ' + 'automatically because the server has no matching ' + 'revision.', ); return; } @@ -1074,9 +1123,43 @@ class StrategyOpQueueNotifier extends Notifier { /// Each durable record contains both the rejected predecessor and any newer /// successor for that entity. Removing the record discards both, without /// changing unrelated queued, in-flight, paused, or rejected work. + /// + /// Given [onlyIf] (the refused op id and successor op id of each key, as + /// the user last saw them), a key whose waiting work has changed since is + /// left as it is: the user chose to discard that work, not a newer edit. Future> discardRejected( - Set entityKeys, - ) { + Set entityKeys, { + Map? onlyIf, + }) => + _dropAttention(entityKeys, adoptRemote: true, onlyIf: onlyIf); + + /// Whether the server refused [key]'s waiting work because a teammate + /// deleted what it edits (rejection reason `deleted`). + bool refusedAsDeleted(EntitySyncKey key) => + _recordForActiveKey(key)?.lastError == OpRejectionReason.deleted.wireName; + + /// Drops the refused work of entities the user has since deleted on the + /// canvas, when the server refused it because a teammate deleted them + /// ([refusedAsDeleted]). Both sides agree they are gone, so nothing is + /// left to keep, and Keep mine must not bring them back. Work refused for + /// any other reason stays: only that refusal says the server deleted the + /// item, rather than never having it or holding it elsewhere. Unlike + /// [discardRejected] the canvas is already the truth: there is nothing to + /// adopt. + Future> settleAttention(Set entityKeys) => + _dropAttention( + { + for (final key in entityKeys) + if (refusedAsDeleted(key)) key + }, + adoptRemote: false, + ); + + Future> _dropAttention( + Set entityKeys, { + required bool adoptRemote, + Map? onlyIf, + }) { return _serializeWrite(() async { final attention = Map.from( state.attentionByEntityKey, @@ -1095,6 +1178,14 @@ class StrategyOpQueueNotifier extends Notifier { if (rejected == null || accountId == null || strategyPublicId == null) { continue; } + if (onlyIf != null && + onlyIf[key] != + ( + rejected.pending.op.opId, + successors[key]?.pending.op.opId, + )) { + continue; + } final storageKey = DurableOutboxRecord.createStorageKey( accountId: accountId, strategyPublicId: strategyPublicId, @@ -1119,7 +1210,7 @@ class StrategyOpQueueNotifier extends Notifier { _uncertainOversizedParking.remove(storageKey); attention.remove(key); successors.remove(key); - _awaitingRemoteAdoption.add(key); + if (adoptRemote) _awaitingRemoteAdoption.add(key); discarded.add(key); } catch (error, stackTrace) { persistenceError = error; @@ -1425,75 +1516,6 @@ class StrategyOpQueueNotifier extends Notifier { } } - /// The origin and landing rows a lineup link add or patch names; empty - /// for any other op. - static Set _lineupLinkEndKeys(StrategyOp op) { - final pageId = op.pagePublicId; - final payload = op.payload; - final data = payload is Map ? payload['data'] : null; - if (op.entityType != StrategyOpEntityType.lineup || - payload is! Map || - payload['kind'] != CloudLineupKind.link || - pageId == null || - data is! Map) { - return const {}; - } - return { - EntitySyncKey.lineup( - pageId, - cloudLineupRowId(CloudLineupKind.origin, '${data['originId']}'), - ), - EntitySyncKey.lineup( - pageId, - cloudLineupRowId(CloudLineupKind.landing, '${data['landingId']}'), - ), - }; - } - - /// Whether [op] deletes a lineup row of one of [kinds]. - static bool _deletesLineupRow(StrategyOp op, List kinds) => - op is LineupDeleteOp && - kinds.any((kind) => op.lineupPublicId.startsWith('$kind:')); - - /// Whether [record] is a lineup op that must wait for another one still - /// queued or in flight (queued behind it, past a batch cap, under another - /// client id, backing off) outside [sentWith], the batch being claimed. - /// The server refuses a link whose origin or landing is not live, so a - /// link add or patch waits for the records of the ends it names. It also - /// refuses deleting an origin or landing a live link names, so an end - /// delete waits for every link delete on its page. Either is due once the - /// record it waits for has been sent. - bool _waitsForLineupOrder( - DurableOutboxRecord record, { - Set sentWith = const {}, - }) { - bool isUnsent(DurableOutboxRecord other) => - !sentWith.contains(other.entityKey) && - (other.status == DurableOutboxStatus.queued || - other.status == DurableOutboxStatus.inFlight); - - final op = record.pending.op; - if (_deletesLineupRow( - op, - const [CloudLineupKind.origin, CloudLineupKind.landing], - )) { - return _recordsByStorageKey.values.any((other) => - other.accountId == record.accountId && - other.strategyPublicId == record.strategyPublicId && - other.entityKey.pageId == record.entityKey.pageId && - _deletesLineupRow(other.pending.op, const [CloudLineupKind.link]) && - isUnsent(other)); - } - return _lineupLinkEndKeys(op).any((endKey) { - final end = _recordsByStorageKey[DurableOutboxRecord.createStorageKey( - accountId: record.accountId, - strategyPublicId: record.strategyPublicId, - entityKey: endKey, - )]; - return end != null && isUnsent(end); - }); - } - Future> _claimBatch({ required String accountId, required String strategyPublicId, @@ -1512,26 +1534,10 @@ class StrategyOpQueueNotifier extends Notifier { (ignoreBackoff || !_nextAttemptAt(record).isAfter(now))) .toList(growable: false); if (candidates.isEmpty) return const []; - // Link deletes go first, so the origin and landing deletes of a whole - // lineup can follow them in the same batch. - bool deletesLink(DurableOutboxRecord record) => _deletesLineupRow( - record.pending.op, - const [CloudLineupKind.link], - ); - final ordered = [ - ...candidates.where(deletesLink), - ...candidates.where((record) => !deletesLink(record)), - ]; final selected = []; - final selectedKeys = {}; - bool mustWait(DurableOutboxRecord record) => - _waitsForLineupOrder(record, sentWith: selectedKeys); - final sendable = ordered.where((record) => !mustWait(record)); - if (sendable.isEmpty) return const []; - final batchClientId = sendable.first.pending.clientId; - for (final candidate in ordered) { + final batchClientId = candidates.first.pending.clientId; + for (final candidate in candidates) { if (candidate.pending.clientId != batchClientId) continue; - if (mustWait(candidate)) continue; if (selected.length >= _maxBatchSize) break; final nextSelection = [...selected, candidate]; final byteSize = serializedCloudBatchUtf8Bytes( @@ -1541,7 +1547,6 @@ class StrategyOpQueueNotifier extends Notifier { ); if (byteSize > maxCloudBatchBytes) break; selected.add(candidate); - selectedKeys.add(candidate.entityKey); } final claimed = []; for (final record in selected) { @@ -2354,7 +2359,13 @@ class StrategyOpQueueNotifier extends Notifier { bool get _hasDurabilityFailureForCurrentAccount => _hasDurabilityFailureForAccount(state.accountId); + /// How many times writing the outbox has failed, so a caller can tell + /// whether its own save failed rather than an earlier one. + int get persistenceFailureCount => _persistenceFailureCount; + int _persistenceFailureCount = 0; + void _recordPersistenceFailure(Object error, StackTrace stackTrace) { + _persistenceFailureCount++; log('Durable outbox persistence failed: $error', name: 'strategy_outbox', error: error, stackTrace: stackTrace); if (_isDisposed) return; @@ -2424,8 +2435,7 @@ class StrategyOpQueueNotifier extends Notifier { (record.status == DurableOutboxStatus.queued || record.status == DurableOutboxStatus.inFlight) && !_uncertainDurableRecords.contains(record.storageKey) && - !cloudOperationExceedsPolicy(record.pending.op) && - !_waitsForLineupOrder(record)) + !cloudOperationExceedsPolicy(record.pending.op)) .toList(growable: false); if (candidates.isEmpty) return; final nextAttempt = candidates @@ -2469,7 +2479,6 @@ class StrategyOpQueueNotifier extends Notifier { record.status == DurableOutboxStatus.inFlight) && !_uncertainDurableRecords.contains(record.storageKey) && !cloudOperationExceedsPolicy(record.pending.op) && - !_waitsForLineupOrder(record) && (ignoreBackoff || !_nextAttemptAt(record).isAfter(now))) .toList(growable: false) ..sort((left, right) => left.updatedAt.compareTo(right.updatedAt)); @@ -2634,6 +2643,57 @@ class StrategyOpQueueNotifier extends Notifier { }); } + /// [op] as an add bringing its element or lineup back over the tombstone + /// at [revision], with the payload and place the user has. Null for a + /// change that does not hold them (a reorder, a delete); live sync's + /// patches always do. + static StrategyOp? _restoreOp(StrategyOp op, int revision) { + final opId = const Uuid().v4(); + return switch (op) { + ElementAddOp( + :final elementPublicId, + :final pagePublicId, + :final payload, + :final sortIndex, + ) || + ElementPatchOp( + :final elementPublicId, + pagePublicId: final pagePublicId?, + payload: final payload?, + sortIndex: final sortIndex?, + ) => + ElementAddOp( + opId: opId, + elementPublicId: elementPublicId, + pagePublicId: pagePublicId, + payload: payload, + sortIndex: sortIndex, + expectedElementRevision: revision, + ), + LineupAddOp( + :final lineupPublicId, + :final pagePublicId, + :final payload, + :final sortIndex, + ) || + LineupPatchOp( + :final lineupPublicId, + pagePublicId: final pagePublicId?, + payload: final payload?, + sortIndex: final sortIndex?, + ) => + LineupAddOp( + opId: opId, + lineupPublicId: lineupPublicId, + pagePublicId: pagePublicId, + payload: payload, + sortIndex: sortIndex, + expectedLineupRevision: revision, + ), + _ => null, + }; + } + StrategyOp _rebaseRejectedOp( StrategyOp op, int revision, { @@ -2840,13 +2900,22 @@ class StrategyOpQueueNotifier extends Notifier { var hasOtherWork = false; for (final entry in attention.entries) { final record = recordFor(entry.key); - final reason = record?.pending.op.opId == entry.value.pending.op.opId + final lastError = record?.pending.op.opId == entry.value.pending.op.opId ? record?.lastError : null; - if (reason == lineupLinkEndMissingMessage || - reason == lineupPageMismatchMessage || - reason == lineupEndInUseMessage || + final reason = lastError == OpRejectionReason.deleted.wireName + ? teammateDeletedMessage + : lastError; + if (reason == lineupPageMismatchMessage || + reason == lineupOverlapMessage || + reason == teammateDeletedMessage || + reason == retiredLineupOpMessage || reason == pageDeletedMessage) { + // A second, different reason is other work too: one explanation + // must not stand for both. + if (specificReason != null && reason != specificReason) { + hasOtherWork = true; + } specificReason ??= reason; } else { hasOtherWork = true; diff --git a/lib/providers/strategy_page_session_provider.dart b/lib/providers/strategy_page_session_provider.dart index 084108c1..14afcc7a 100644 --- a/lib/providers/strategy_page_session_provider.dart +++ b/lib/providers/strategy_page_session_provider.dart @@ -6,7 +6,9 @@ import 'package:flutter/foundation.dart' show listEquals; import 'package:flutter/widgets.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hive_ce/hive.dart'; +import 'package:icarus/collab/cloud_lineup_rows.dart'; import 'package:icarus/collab/collab_models.dart'; +import 'package:icarus/const/line_provider.dart'; import 'package:icarus/collab/convex_strategy_repository.dart'; import 'package:icarus/const/coordinate_system.dart'; import 'package:icarus/const/maps.dart'; @@ -41,6 +43,7 @@ import 'package:icarus/providers/navigation_geometry_provider.dart'; import 'package:icarus/providers/view_cone_geometry_provider.dart'; import 'package:icarus/services/app_error_reporter.dart'; import 'package:icarus/strategy/strategy_page_apply.dart'; +import 'package:icarus/strategy/lineup_group_changes.dart'; import 'package:icarus/strategy/strategy_page_models.dart'; import 'package:icarus/strategy/strategy_page_source.dart'; import 'package:icarus/view_cone/vision_geometry.dart'; @@ -57,6 +60,21 @@ enum PageSwitchDirection { next, previous } /// never got. [name] is its name when it was last loaded. typedef DeletedPage = ({String pageId, String name}); +/// How Keep both ended (see StrategyPageSessionNotifier.keepBothForRejected). +enum KeepBothOutcome { + /// The cloud's versions stand, and the user's are beside them as copies. + kept, + + /// The cloud's versions could not be loaded. Nothing changed. + unchanged, + + /// The user's versions were added as copies, but something failed before + /// the conflicts were resolved (the cloud's versions stopped loading, a + /// copy could not be saved, or the waiting work changed), so they still + /// wait. + copiesOnly, +} + /// How an attempt to restore a deleted page ended. enum DeletedPageRestore { /// The page is back on the server, and the work on it is saving as usual. @@ -163,6 +181,13 @@ class StrategyPageSessionNotifier extends Notifier { /// The latest strategy revision at which each page was seen live. final Map _pagesSeenLiveAt = {}; + /// Waiting work Keep both already put a copy of on the canvas, by + /// [_waitingWork] entry: pressing it again finishes the job instead of + /// copying the same version twice. + /// The copy's lineup ids, by entry, so every press can check the copy + /// is saved before anything is discarded. + final Map<(EntitySyncKey, (String, String?)), List> _keptAsCopy = {}; + @override StrategyPageSessionState build() { ref.onDispose(() => _disposed = true); @@ -544,28 +569,225 @@ class StrategyPageSessionNotifier extends Notifier { } } + /// Keeps both versions of every conflicting lineup group: the cloud's + /// stays the group, and the user's goes beside it as a copy under fresh + /// ids (see forkLineUpGraph), so neither side's work is lost. A version + /// that deletes the group, or only reorders it, holds nothing to copy. + /// + /// Only for conflicts that are all lineup groups on the page on screen + /// (see lineupConflictsProvider); anything else is a [StateError]. + /// + /// Nothing is discarded unless everything still matches what was copied: + /// the cloud's version loads, the page on screen is the same one, the + /// waiting work is the same (an edit made meanwhile would not be in the + /// copy), and the copy itself saved. When the cloud's version cannot be + /// loaded, or the work changed before the copy was made, nothing changes. + /// When something fails after, the copy stays and the conflicts still + /// wait; pressing Keep both again resolves them without a second copy. + Future keepBothForRejected() async { + final strategyState = ref.read(strategyProvider); + final strategyId = strategyState.strategyId; + final queue = ref.read(strategyOpQueueProvider); + final attention = queue.attentionByEntityKey; + final activePageId = state.activePageId; + if (strategyState.source != StrategySource.cloud || + strategyId == null || + attention.isEmpty || + attention.keys.any((key) => + key.kind != EntitySyncKeyKind.lineup || + key.pageId != activePageId)) { + throw StateError('Keep both is only for lineup groups on this page'); + } + // A copy is only kept if it can be saved; while this device cannot + // save outbox records, nothing is copied and nothing discarded. + if (queue.hasDurabilityFailure) return KeepBothOutcome.unchanged; + final generation = _pageSessionGeneration; + final waiting = _waitingWork(attention.keys); + final copies = []; + final copied = <(EntitySyncKey, (String, String?)), List>{}; + for (final MapEntry(:key, value: refused) in attention.entries) { + final newest = (queue.successorByEntityKey[key] ?? refused).pending.op; + final payload = switch (newest) { + LineupAddOp(:final payload) => payload, + LineupPatchOp(:final payload?) => payload, + _ => null, + }; + final entry = (key, waiting[key]!); + if (payload == null) continue; + // A copy made by an earlier press stands while any of its lineups is + // on the canvas; once the user deleted it all, this press makes it + // again. + if (_keptAsCopy[entry] case final copyIds? + when copyIds.any( + (id) => ref.read(lineUpProvider).linkById(id) != null, + )) { + continue; + } + final copy = forkLineUpGraph(lineUpGraphFromCloudRows([ + CloudLineupRow(publicId: key.entityId!, payload: payload), + ]).graph); + if (copy.links.isEmpty) continue; + copies.add(copy); + copied[entry] = [for (final link in copy.links) link.id]; + } + bool unchangedSince() => + !_disposed && + generation == _pageSessionGeneration && + _sameWaitingWork(waiting); + + await ref.read(remoteEditorSnapshotProvider.notifier).refresh(); + final snapshot = ref.read(remoteEditorSnapshotProvider).valueOrNull; + if (snapshot == null || snapshot.header.publicId != strategyId) { + return KeepBothOutcome.unchanged; + } + // Edits made while the cloud's version loaded are saved first; one to + // a conflicting group is newer than the copy, so nothing goes ahead. + final pageSource = _resolvePageSource(strategyId, StrategySource.cloud); + await pageSource.flushCurrentPage(); + if (!unchangedSince()) return KeepBothOutcome.unchanged; + + final lineUps = ref.read(lineUpProvider.notifier); + for (final copy in copies) { + lineUps.addRecovered(copy); + } + _keptAsCopy.addAll(copied); + // Every copy of this work, made now or by an earlier press. + final lineUpState = ref.read(lineUpProvider); + final copyLineupIds = [ + for (final MapEntry(:key, :value) in waiting.entries) + if (_keptAsCopy[(key, value)] case final ids?) + // One surviving lineup names the copy's group. + ids.firstWhere( + (id) => lineUpState.linkById(id) != null, + orElse: () => ids.first, + ), + ]; + await pageSource.flushCurrentPage(); + // A copy that could not be saved leaves the outbox failing (and waits in + // attention itself): nothing may be discarded on its behalf. + final afterCopy = ref.read(strategyOpQueueProvider); + final liveSync = ref.read(activePageLiveSyncProvider.notifier); + final queuedKeys = { + for (final pending in afterCopy.pending) + EntitySyncKey.forStrategyOp(pending.op), + }; + // Each copy's group must be queued (or already on the server): a save + // skipped without failing, say after edit access was lost, leaves the + // copy on the canvas alone. + final copiesQueued = copyLineupIds.every((lineupId) { + final group = liveSync.lineupGroupOf(activePageId!, lineupId); + if (group == null) return false; + final key = EntitySyncKey.lineup(activePageId, group); + return queuedKeys.contains(key) || liveSync.hydratedBase(key) != null; + }); + final saved = copiesQueued && + !afterCopy.hasDurabilityFailure && + afterCopy.attentionByEntityKey.keys.every(waiting.containsKey); + if (!saved || !unchangedSince()) return KeepBothOutcome.copiesOnly; + return await _useCloudVersionsFor(waiting) + ? KeepBothOutcome.kept + : KeepBothOutcome.copiesOnly; + } + + /// The refused op, and the newer one queued behind it if any, of each of + /// [keys]: what is waiting for the user's choice. + Map _waitingWork( + Iterable keys, + ) { + final queue = ref.read(strategyOpQueueProvider); + return { + for (final key in keys) + if (queue.attentionByEntityKey[key] case final refused?) + key: ( + refused.pending.op.opId, + queue.successorByEntityKey[key]?.pending.op.opId, + ), + }; + } + + /// The canvas's content, one state object per kind of item on it. Every + /// edit replaces its kind's object, so comparing them by identity tells + /// whether anything changed in between. + List _canvasStates() => [ + ref.read(agentProvider), + ref.read(abilityProvider), + ref.read(drawingProvider), + ref.read(textProvider), + ref.read(placedImageProvider), + ref.read(utilityProvider), + ref.read(lineUpProvider), + ]; + + bool _sameCanvas(List saved) { + final now = _canvasStates(); + for (var i = 0; i < saved.length; i++) { + if (!identical(saved[i], now[i])) return false; + } + return true; + } + + /// Whether exactly [waiting] still waits, nothing changed or gone. + bool _sameWaitingWork(Map waiting) { + final now = _waitingWork(waiting.keys); + return now.length == waiting.length && + waiting.entries.every((entry) => now[entry.key] == entry.value); + } + /// Adopts the cloud version for every current conflict in this strategy. /// /// The authoritative page is loaded before any local intent is discarded. /// A failed load therefore leaves the durable conflict available to retry. - Future useCloudVersionsForRejected() async { + Future useCloudVersionsForRejected() => _useCloudVersionsFor(null); + + /// [useCloudVersionsForRejected], for exactly the conflicts in [waiting] + /// (by default, every conflict once the page's edits are saved). If they + /// no longer wait as they were, or the canvas changed after its last + /// save, nothing is discarded or redrawn: the newer work stays. + Future _useCloudVersionsFor( + Map? waiting, + ) async { final strategyState = ref.read(strategyProvider); final strategyId = strategyState.strategyId; if (strategyState.source != StrategySource.cloud || strategyId == null) { return false; } + final generation = _pageSessionGeneration; + late Map resolving; + bool waitingChanged() => + _disposed || + generation != _pageSessionGeneration || + !_sameWaitingWork(resolving); + _isResolvingConflicts = true; try { - await _resolvePageSource(strategyId, StrategySource.cloud) - .flushCurrentPage(); + final conflictKeys = { + ...ref.read(strategyOpQueueProvider).attentionByEntityKey.keys, + }; + final currentPageSource = + _resolvePageSource(strategyId, StrategySource.cloud); + await currentPageSource.flushCurrentPage(); final strategyNotifier = ref.read(strategyProvider.notifier); strategyNotifier.consumeScheduledCloudPageSync(); strategyNotifier.consumeScheduledCloudStrategySync(); + resolving = waiting ?? + _waitingWork( + ref.read(strategyOpQueueProvider).attentionByEntityKey.keys, + ); + if (waitingChanged()) return false; final rejected = Map.from( ref.read(strategyOpQueueProvider).attentionByEntityKey, - ); - if (rejected.isEmpty) return true; + )..removeWhere((key, _) => !resolving.containsKey(key)); + // Conflicts the save turned back into queued work (a record whose + // removal failed before, say) were not resolved: that is no success. + // Ones it settled (gone on both sides) are. + if (rejected.isEmpty) { + final pending = { + for (final work in ref.read(strategyOpQueueProvider).pending) + EntitySyncKey.forStrategyOp(work.op), + }; + return !conflictKeys.any(pending.contains); + } await ref.read(remoteEditorSnapshotProvider.notifier).refresh(); final snapshot = ref.read(remoteEditorSnapshotProvider).valueOrNull; @@ -573,6 +795,22 @@ class StrategyPageSessionNotifier extends Notifier { return false; } + // Edits made while the cloud's version loaded are saved, and one to + // the waiting work stops the resolution: the page drawn next would + // replace that edit on screen. The canvas is noted before that save, + // so an edit made while it is being written counts as a change too. + final savedCanvas = _canvasStates(); + final queueNotifier = ref.read(strategyOpQueueProvider.notifier); + final failuresBefore = queueNotifier.persistenceFailureCount; + await currentPageSource.flushCurrentPage(); + // A save that failed just now may have dropped a newer edit the queue + // never recorded; nothing is discarded or redrawn over it. (A failure + // left from before, say a discard that did not finish, does not stop + // the discard that can clear it.) + if (waitingChanged() || + queueNotifier.persistenceFailureCount != failuresBefore) { + return false; + } final targetPageId = _resolveHydrationTargetPage(snapshot); final localMetadata = _unsentLocalMetadata(); if (targetPageId != null) { @@ -585,10 +823,17 @@ class StrategyPageSessionNotifier extends Notifier { targetPageId, discardedEntities: rejected.keys.toSet(), ); + // An edit since the last save is still only on the canvas, and + // stops the redraw; checked again where the redraw happens, after + // the page list it awaits. + bool unchangedCanvas() => !waitingChanged() && _sameCanvas(savedCanvas); + if (!unchangedCanvas()) return false; + var redrawn = false; await _applyLoadedPageData( pageData, strategyId: strategyId, source: StrategySource.cloud, + canApply: () => redrawn = unchangedCanvas(), hydrationKey: _buildRemotePageHydrationKey(snapshot, targetPageId), preserveTextDrafts: true, loadedRemoteSnapshot: pageSource.loadedRemoteSnapshot, @@ -597,11 +842,15 @@ class StrategyPageSessionNotifier extends Notifier { ? null : localMetadata, ); + if (!redrawn) return false; } + // What the first redraw left: a redraw after a partial discard below + // draws only over this, never over an edit made while discarding. + final redrawnCanvas = _canvasStates(); final discarded = await ref .read(strategyOpQueueProvider.notifier) - .discardRejected(rejected.keys.toSet()); + .discardRejected(rejected.keys.toSet(), onlyIf: resolving); // A failed durable delete keeps its overlay and conflict. Restore those // entities if only part of the requested adoption could be saved. if (discarded.length != rejected.length && targetPageId != null) { @@ -610,6 +859,7 @@ class StrategyPageSessionNotifier extends Notifier { strategyId: strategyId, activePageId: () => state.activePageId, ); + // Redrawn only if nothing was edited since the first redraw. final pageData = await pageSource.loadAuthoritativePage( targetPageId, discardedEntities: discarded, @@ -618,6 +868,10 @@ class StrategyPageSessionNotifier extends Notifier { pageData, strategyId: strategyId, source: StrategySource.cloud, + canApply: () => + !_disposed && + generation == _pageSessionGeneration && + _sameCanvas(redrawnCanvas), preserveTextDrafts: true, loadedRemoteSnapshot: pageSource.loadedRemoteSnapshot, preservedMetadata: discarded.contains(const EntitySyncKey.strategy()) diff --git a/lib/strategy/lineup_group_changes.dart b/lib/strategy/lineup_group_changes.dart new file mode 100644 index 00000000..12f8ddc8 --- /dev/null +++ b/lib/strategy/lineup_group_changes.dart @@ -0,0 +1,136 @@ +import 'dart:convert'; + +import 'package:icarus/collab/canonical_json.dart'; +import 'package:icarus/const/agents.dart'; +import 'package:icarus/const/line_provider.dart'; +import 'package:uuid/uuid.dart'; + +/// What happened to one lineup between two versions of its group. +class LineupChange { + const LineupChange({required this.label, required this.description}); + + /// The lineup as the user knows it: its name, or its agent's. + final String label; + + /// What changed, e.g. "added" or "notes edited, landing moved". + final String description; +} + +/// The lineups that differ between [from] and [to], one entry each, in +/// [to]'s order and then the lineups only [from] has. +List lineupChanges({ + required LineUpGraph from, + required LineUpGraph to, +}) { + final before = _Lookup(from); + final after = _Lookup(to); + final changes = []; + for (final link in to.links) { + final old = before.links[link.id]; + if (old == null) { + changes.add(LineupChange(label: after.label(link), description: 'added')); + continue; + } + final what = [ + if (old.name != link.name) 'renamed', + if (old.notes != link.notes) 'notes edited', + if (old.youtubeLink != link.youtubeLink) 'video changed', + if (!_sameJson( + [for (final image in old.images) image.toJson()], + [for (final image in link.images) image.toJson()], + )) + 'images changed', + if (!_sameJson( + before.origins[old.originId]?.toJson(), + after.origins[link.originId]?.toJson(), + )) + 'standing spot moved', + if (!_sameJson( + before.landings[old.landingId]?.toJson(), + after.landings[link.landingId]?.toJson(), + )) + 'landing moved', + ]; + if (what.isNotEmpty) { + changes.add( + LineupChange(label: after.label(link), description: what.join(', ')), + ); + } + } + for (final link in from.links) { + if (!after.links.containsKey(link.id)) { + changes.add( + LineupChange(label: before.label(link), description: 'deleted'), + ); + } + } + return changes; +} + +/// A copy of [graph] under fresh ids, for keeping it beside the version it +/// conflicted with: its lineups, spots, and the agent and ability on each +/// spot are all new, so nothing in it is the original. Images stay the same +/// images. +LineUpGraph forkLineUpGraph(LineUpGraph graph) { + const uuid = Uuid(); + final originIds = {for (final origin in graph.origins) origin.id: uuid.v4()}; + final landingIds = { + for (final landing in graph.landings) landing.id: uuid.v4(), + }; + return LineUpGraph( + origins: [ + for (final origin in graph.origins) + LineUpOrigin( + id: originIds[origin.id]!, + agent: origin.agent.copyWith( + id: uuid.v4(), + lineUpID: originIds[origin.id], + )..isDeleted = origin.agent.isDeleted, + ), + ], + landings: [ + for (final landing in graph.landings) + LineUpLanding( + id: landingIds[landing.id]!, + ability: landing.ability.copyWith( + id: uuid.v4(), + lineUpID: landingIds[landing.id], + )..isDeleted = landing.ability.isDeleted, + ), + ], + links: [ + for (final link in graph.links) + if ((originIds[link.originId], landingIds[link.landingId]) + case (final originId?, final landingId?)) + link.copyWith( + id: uuid.v4(), + originId: originId, + landingId: landingId, + ), + ], + ); +} + +/// Model `toJson()` output can nest objects with their own `toJson`, so it +/// goes through a plain JSON round trip before the canonical comparison. +bool _sameJson(Object? a, Object? b) => + canonicalCloudJsonEncode(jsonDecode(jsonEncode(a))) == + canonicalCloudJsonEncode(jsonDecode(jsonEncode(b))); + +class _Lookup { + _Lookup(LineUpGraph graph) + : origins = {for (final origin in graph.origins) origin.id: origin}, + landings = {for (final landing in graph.landings) landing.id: landing}, + links = {for (final link in graph.links) link.id: link}; + + final Map origins; + final Map landings; + final Map links; + + String label(LineUpLink link) { + final name = link.name.trim(); + if (name.isNotEmpty) return name; + final agent = AgentData.agents[origins[link.originId]?.agent.type]?.name; + return agent == null ? 'Unnamed lineup' : '$agent lineup'; + } +} diff --git a/lib/strategy/remote_page_merge.dart b/lib/strategy/remote_page_merge.dart index 9bd0195a..c11d1b67 100644 --- a/lib/strategy/remote_page_merge.dart +++ b/lib/strategy/remote_page_merge.dart @@ -1,5 +1,7 @@ import 'dart:math' show min; +import 'package:icarus/const/line_provider.dart'; + /// The server's copy of a page's items ([incoming]), except the ones [keep] /// names: those stay the object on screen, so the widget keeps whatever /// in-progress state it holds, and stay even when the server removed them. @@ -29,3 +31,89 @@ List mergeRemoteItems({ } return merged; } + +/// The server's lineups ([remote]), except the ones the user is holding: +/// those stay as the canvas ([local]) has them, as [mergeRemoteItems] keeps +/// held items. Returns the merged graph and the lineup groups held. +/// +/// The user holds a lineup group by holding one of its lineups or spots; +/// [groupOf] names the group of a lineup or spot, local or remote. A group +/// is one cloud row, so it takes one side whole: every lineup in a held +/// group, and every lineup sharing a spot with one, stays as the canvas has +/// it. The other lineups take the server's copy. A held lineup only the +/// server has (a teammate's new lineup in a held group) waits off the +/// canvas until the hold ends, like a held lineup the server removed waits +/// on it. +(LineUpGraph, Set) mergeHeldLineups({ + required LineUpGraph local, + required LineUpGraph remote, + required Set holding, + required String? Function(String id) groupOf, +}) { + final allLinks = [...local.links, ...remote.links]; + final held = {}; + final heldIds = {...holding}; + final heldGroups = { + for (final id in holding) + if (groupOf(id) case final group?) group, + }; + for (var grew = true; grew;) { + grew = false; + for (final link in allLinks) { + if (held.contains(link.id)) continue; + final group = groupOf(link.id); + if (heldIds.contains(link.id) || + heldIds.contains(link.originId) || + heldIds.contains(link.landingId) || + heldGroups.contains(group)) { + held.add(link.id); + heldIds.addAll([link.originId, link.landingId]); + if (group != null) heldGroups.add(group); + grew = true; + } + } + } + if (held.isEmpty) return (remote, heldGroups); + + final localLinks = {for (final link in local.links) link.id: link}; + final remoteLinkIds = {for (final link in remote.links) link.id}; + final links = [ + for (final link in remote.links) + if (!held.contains(link.id)) + link + else if (localLinks[link.id] case final onScreen?) + onScreen, + ]; + for (final (index, link) in local.links.indexed) { + if (held.contains(link.id) && !remoteLinkIds.contains(link.id)) { + links.insert(min(index, links.length), link); + } + } + + final originIds = {for (final link in links) link.originId}; + final landingIds = {for (final link in links) link.landingId}; + return ( + LineUpGraph( + origins: [ + for (final origin in mergeRemoteItems( + current: local.origins, + incoming: remote.origins, + idOf: (origin) => origin.id, + keep: heldIds.contains, + )) + if (originIds.contains(origin.id)) origin, + ], + landings: [ + for (final landing in mergeRemoteItems( + current: local.landings, + incoming: remote.landings, + idOf: (landing) => landing.id, + keep: heldIds.contains, + )) + if (landingIds.contains(landing.id)) landing, + ], + links: links, + ), + heldGroups, + ); +} diff --git a/lib/strategy/strategy_cloud_migration.dart b/lib/strategy/strategy_cloud_migration.dart index cc03d4fd..e225702e 100644 --- a/lib/strategy/strategy_cloud_migration.dart +++ b/lib/strategy/strategy_cloud_migration.dart @@ -73,15 +73,17 @@ void appendMigratedPageOps( buildMigratedElementOp(page.id, elementId, payload, elementOrder++)); } - // [usedLineupIds] holds row ids. An entity whose row id another page - // already took (a page duplicated before cloud sync) gets a fresh id, and - // the links and markers that name it follow along. - final graph = lineUpGraphWithIds( + // One row per lineup group. A group's id must be unique in the strategy, + // so one whose id another page already took (a page duplicated before + // cloud sync repeats its lineup ids) takes another of its lineup ids. + // Ids inside a row only need to be unique in the row, so they stay. + final rows = cloudLineupRows( page.lineUpGraph, - (kind, id) => _uniqueLineupEntityId(kind, id, usedLineupIds), - ); + takenGroupIds: usedLineupIds, + ).rows; + usedLineupIds.addAll([for (final row in rows) row.publicId]); var lineupOrder = 0; - for (final row in cloudLineupRows(graph)) { + for (final row in rows) { ops.add( LineupAddOp( opId: const Uuid().v4(), @@ -94,14 +96,6 @@ void appendMigratedPageOps( } } -String _uniqueLineupEntityId(String kind, String id, Set usedRowIds) { - var candidate = id; - while (!usedRowIds.add(cloudLineupRowId(kind, candidate))) { - candidate = const Uuid().v4(); - } - return candidate; -} - String nextUniqueMigrationId(String preferredId, Set usedIds) { if (usedIds.add(preferredId)) { return preferredId; diff --git a/lib/strategy/strategy_import_export.dart b/lib/strategy/strategy_import_export.dart index 5f23a826..ae49dd8f 100644 --- a/lib/strategy/strategy_import_export.dart +++ b/lib/strategy/strategy_import_export.dart @@ -16,7 +16,6 @@ import 'package:icarus/collab/convex_strategy_repository.dart'; import 'package:icarus/const/drawing_element.dart'; import 'package:icarus/const/folder_icons.dart'; import 'package:icarus/const/hive_boxes.dart'; -import 'package:icarus/const/line_provider.dart'; import 'package:icarus/const/maps.dart'; import 'package:icarus/const/placed_classes.dart'; import 'package:icarus/const/settings.dart'; @@ -2398,7 +2397,7 @@ class StrategyImportExportService { assetIds.add(element.publicId); } - final lineups = _cloudLineupGraph( + final lineups = lineUpGraphFromRemoteLineups( snapshot.lineupsByPage[page.publicId] ?? const [], ); for (final link in lineups.links) { @@ -2516,7 +2515,7 @@ class StrategyImportExportService { } } - final lineUpGraph = _cloudLineupGraph(lineups); + final lineUpGraph = lineUpGraphFromRemoteLineups(lineups); StrategySettings settings = StrategySettings(); final settingsPayload = fullPage.content.settings; @@ -2585,12 +2584,3 @@ class StrategyImportExportService { ); } } - -/// A cloud page's live lineup rows as the graph its canvas draws. -LineUpGraph _cloudLineupGraph(Iterable lineups) { - return lineUpGraphFromCloudRows([ - for (final lineup in lineups) - if (!lineup.deleted) - CloudLineupRow(publicId: lineup.publicId, payload: lineup.payload), - ]).graph; -} diff --git a/lib/strategy/strategy_page_apply.dart b/lib/strategy/strategy_page_apply.dart index c990dd43..5fc118f6 100644 --- a/lib/strategy/strategy_page_apply.dart +++ b/lib/strategy/strategy_page_apply.dart @@ -14,6 +14,8 @@ import 'package:icarus/providers/text_provider.dart'; import 'package:icarus/providers/utility_provider.dart'; import 'package:icarus/const/line_provider.dart'; import 'package:icarus/providers/collab/active_page_live_sync_models.dart'; +import 'package:icarus/providers/collab/active_page_live_sync_provider.dart'; +import 'package:icarus/strategy/remote_page_merge.dart'; import 'package:icarus/strategy/strategy_page_models.dart'; Future applyStrategyEditorPageData( @@ -91,23 +93,20 @@ Set mergeRemoteStrategyEditorPageData( ref.read(placedImageProvider.notifier).mergeRemote(data.images, keep); ref.read(utilityProvider.notifier).mergeRemote(data.utilities, keep); - // Links name their origin and landing, so the lineup graph changes as one - // piece: all of it, or none while the user holds part of it. - final lineupChanges = { + final liveSync = ref.read(activePageLiveSyncProvider.notifier); + final (lineUpGraph, heldGroups) = mergeHeldLineups( + local: ref.read(lineUpProvider).graph, + remote: data.lineUpGraph.deepCopy(), + holding: holding, + groupOf: (id) => liveSync.lineupGroupOf(data.pageId, id), + ); + ref.read(lineUpProvider.notifier).mergeRemote(lineUpGraph); + heldBack.addAll({ for (final key in changed) - if (key.kind == EntitySyncKeyKind.lineup) key, - }; - final graph = ref.read(lineUpProvider).graph; - final lineupIds = { - for (final origin in graph.origins) origin.id, - for (final landing in graph.landings) landing.id, - for (final link in graph.links) link.id, - }; - if (!holding.any(lineupIds.contains)) { - ref.read(lineUpProvider.notifier).fromHive(data.lineUpGraph); - } else { - heldBack.addAll(lineupChanges); - } + if (key.kind == EntitySyncKeyKind.lineup && + heldGroups.contains(key.entityId)) + key, + }); ref .read(mapProvider.notifier) diff --git a/lib/strategy/strategy_page_source.dart b/lib/strategy/strategy_page_source.dart index e4b8a80d..3cb26005 100644 --- a/lib/strategy/strategy_page_source.dart +++ b/lib/strategy/strategy_page_source.dart @@ -280,11 +280,13 @@ class CloudStrategyPageSource implements StrategyPageSource { } } - final lineUpGraph = lineUpGraphFromCloudRows([ + final cloudLineups = lineUpGraphFromCloudRows([ for (final lineup in lineups) - if (!lineup.deleted) - CloudLineupRow(publicId: lineup.publicId, payload: lineup.payload), - ]).graph; + if (!lineup.deleted) CloudLineupRow.remote(lineup), + ]); + ref + .read(activePageLiveSyncProvider.notifier) + .noteLineupGroups(page.publicId, cloudLineups.groupOf); final mapValue = Maps.mapNames.entries.firstWhere( (entry) => entry.value == snapshot.header.mapData, @@ -313,7 +315,7 @@ class CloudStrategyPageSource implements StrategyPageSource { texts: texts, images: images, utilities: utilities, - lineUpGraph: lineUpGraph, + lineUpGraph: cloudLineups.graph, ); } @@ -453,10 +455,13 @@ class CloudStrategyPageSource implements StrategyPageSource { } } - final lineUpGraph = lineUpGraphFromCloudRows([ + final cloudLineups = lineUpGraphFromCloudRows([ for (final lineup in projected.lineups) CloudLineupRow(publicId: lineup.publicId, payload: lineup.payload), - ]).graph; + ]); + ref + .read(activePageLiveSyncProvider.notifier) + .noteLineupGroups(page.publicId, cloudLineups.groupOf); final mapValue = Maps.mapNames.entries.firstWhere( (entry) => entry.value == snapshot.header.mapData, @@ -477,7 +482,7 @@ class CloudStrategyPageSource implements StrategyPageSource { texts: texts, images: images, utilities: utilities, - lineUpGraph: lineUpGraph, + lineUpGraph: cloudLineups.graph, ); } diff --git a/lib/widgets/cloud_sync_button.dart b/lib/widgets/cloud_sync_button.dart index 35fa983b..b6df1dd7 100644 --- a/lib/widgets/cloud_sync_button.dart +++ b/lib/widgets/cloud_sync_button.dart @@ -8,12 +8,14 @@ import 'package:icarus/const/settings.dart'; import 'package:icarus/providers/collab/client_upgrade_required_provider.dart'; import 'package:icarus/providers/collab/cloud_media_upload_queue_provider.dart'; import 'package:icarus/providers/collab/cloud_sync_status_provider.dart'; +import 'package:icarus/providers/collab/lineup_conflicts_provider.dart'; import 'package:icarus/providers/collab/strategy_capabilities_provider.dart'; import 'package:icarus/providers/collab/strategy_conflict_provider.dart'; import 'package:icarus/providers/collab/strategy_op_queue_provider.dart'; import 'package:icarus/providers/strategy_page_session_provider.dart'; import 'package:icarus/providers/strategy_provider.dart'; import 'package:icarus/providers/strategy_save_state_provider.dart'; +import 'package:icarus/strategy/lineup_group_changes.dart'; import 'package:icarus/strategy/strategy_page_models.dart'; import 'package:icarus/widgets/client_upgrade_button.dart'; import 'package:icarus/widgets/dialogs/deleted_page_dialog.dart'; @@ -189,6 +191,45 @@ class _CloudSyncButtonState extends ConsumerState { } } + Future _keepBoth() async { + if (_isResolving) return; + setState(() { + _isResolving = true; + _resolutionError = null; + }); + String? resolutionError; + try { + switch (await ref + .read(strategyPageSessionProvider.notifier) + .keepBothForRejected()) { + case KeepBothOutcome.kept: + _popoverController.hide(); + case KeepBothOutcome.unchanged: + resolutionError = 'Could not load the cloud version. ' + 'Nothing was changed.'; + case KeepBothOutcome.copiesOnly: + resolutionError = 'Your version was added as a copy, but the ' + 'conflict is still open.'; + } + } catch (error, stackTrace) { + log( + 'Failed to keep both versions: $error', + name: 'cloud_conflict_resolution', + error: error, + stackTrace: stackTrace, + ); + resolutionError = 'Could not keep both versions. ' + 'Your version is still saved on this device.'; + } finally { + if (mounted) { + setState(() { + _isResolving = false; + _resolutionError = resolutionError; + }); + } + } + } + @override Widget build(BuildContext context) { final source = ref.watch(strategyProvider.select((state) => state.source)); @@ -263,6 +304,7 @@ class _CloudSyncButtonState extends ConsumerState { upgradeRequired: upgradeRequired, saveState: saveState, rejectedCount: opQueueState.attentionByEntityKey.length, + lineupConflicts: ref.watch(lineupConflictsProvider), hasOtherStrategyWork: hasOtherStrategyWork, hasOtherStrategyAttention: hasOtherStrategyAttention, hasActiveStrategyAttention: hasActiveStrategyAttention, @@ -270,6 +312,7 @@ class _CloudSyncButtonState extends ConsumerState { resolutionError: _resolutionError, onRetry: _retry, onUseCloudVersions: _useCloudVersions, + onKeepBoth: _keepBoth, ), child: EditorToolbarButton( key: ValueKey('cloud-sync-button-${status.name}'), @@ -361,6 +404,7 @@ class _SyncStatusPopover extends StatelessWidget { required this.upgradeRequired, required this.saveState, required this.rejectedCount, + required this.lineupConflicts, required this.hasOtherStrategyWork, required this.hasOtherStrategyAttention, required this.hasActiveStrategyAttention, @@ -368,6 +412,7 @@ class _SyncStatusPopover extends StatelessWidget { required this.resolutionError, required this.onRetry, required this.onUseCloudVersions, + required this.onKeepBoth, }); final _SyncStatus status; @@ -377,6 +422,11 @@ class _SyncStatusPopover extends StatelessWidget { final bool upgradeRequired; final StrategySaveState saveState; final int rejectedCount; + + /// What each side did to the lineup groups in conflict, when the refused + /// work is all lineup groups on this page (see lineupConflictsProvider). + /// Then the popover lists the changes and offers Keep both. + final List? lineupConflicts; final bool hasOtherStrategyWork; final bool hasOtherStrategyAttention; final bool hasActiveStrategyAttention; @@ -384,9 +434,18 @@ class _SyncStatusPopover extends StatelessWidget { final String? resolutionError; final Future Function() onRetry; final Future Function() onUseCloudVersions; + final Future Function() onKeepBoth; bool get hasRejectedWork => rejectedCount > 0; + /// The lineup changes to list, when there is no more specific reason to + /// show instead (a deleted page, an oversized change). + List? get _shownLineupConflicts { + final error = saveState.cloudSyncError; + if (error != null && isSpecificAttentionReason(error)) return null; + return lineupConflicts; + } + @override Widget build(BuildContext context) { if (upgradeRequired) { @@ -418,6 +477,13 @@ class _SyncStatusPopover extends StatelessWidget { onPressed: isResolving ? null : onUseCloudVersions, child: const Text('Use cloud'), ), + if (_shownLineupConflicts != null) + ShadButton.secondary( + size: ShadButtonSize.sm, + expands: false, + onPressed: isResolving ? null : onKeepBoth, + child: const Text('Keep both'), + ), ShadButton( size: ShadButtonSize.sm, expands: false, @@ -464,6 +530,8 @@ class _SyncStatusPopover extends StatelessWidget { height: 1.35, ), ), + if (_shownLineupConflicts case final conflicts?) + _LineupConflictList(conflicts: conflicts), if (resolutionError != null) ...[ const SizedBox(height: 8), Text( @@ -542,7 +610,16 @@ class _SyncStatusPopover extends StatelessWidget { final parts = []; final error = saveState.cloudSyncError; final hasSpecificReason = error != null && isSpecificAttentionReason(error); - if (hasRejectedWork && !hasSpecificReason) { + if (_shownLineupConflicts != null) { + parts.add( + 'A teammate changed these lineups while you were working on them. ' + 'Your version remains saved on this device.', + ); + parts.add( + 'Keep mine replaces their changes, Use cloud replaces yours, and ' + 'Keep both adds yours beside theirs as a copy.', + ); + } else if (hasRejectedWork && !hasSpecificReason) { parts.add( 'Another edit reached the cloud first. Your version remains saved ' 'on this device.', @@ -592,3 +669,91 @@ class _SyncStatusPopover extends StatelessWidget { return '$hour:$minute'; } } + +/// The lineups each side changed in the conflicting lineup groups: what +/// Keep mine would replace (the cloud's changes) and what Use cloud would +/// (the user's), so neither choice drops work the user cannot see. +class _LineupConflictList extends StatelessWidget { + const _LineupConflictList({required this.conflicts}); + + final List conflicts; + + /// More lines than this read as a wall; the rest are counted instead. + static const _maxLines = 4; + + @override + Widget build(BuildContext context) { + final yours = [for (final conflict in conflicts) ...conflict.yours]; + // Without the version both sides started from, only the difference + // between them can be shown, not who made it. + if (conflicts.any((conflict) => conflict.cloud == null)) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 10), + _section(context, 'How your version differs from the cloud', yours), + ], + ); + } + final cloud = [for (final conflict in conflicts) ...?conflict.cloud]; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 10), + _section(context, 'Your changes', yours), + const SizedBox(height: 8), + _section(context, 'Cloud changes', cloud), + ], + ); + } + + Widget _section( + BuildContext context, + String title, + List changes, + ) { + final theme = ShadTheme.of(context); + final lineStyle = theme.textTheme.small.copyWith( + color: theme.colorScheme.foreground, + fontSize: 12, + height: 1.35, + ); + final mutedStyle = lineStyle.copyWith( + color: theme.colorScheme.mutedForeground, + ); + final shown = changes.take(_maxLines).toList(); + final hidden = changes.length - shown.length; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: theme.textTheme.small.copyWith( + color: theme.colorScheme.mutedForeground, + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 4), + if (changes.isEmpty) Text('No lineup changes', style: mutedStyle), + for (final change in shown) + Text.rich( + TextSpan( + children: [ + TextSpan(text: change.label), + TextSpan(text: ' · ${change.description}', style: mutedStyle), + ], + ), + style: lineStyle, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + if (hidden > 0) + Text( + hidden == 1 ? 'and 1 more lineup' : 'and $hidden more lineups', + style: mutedStyle, + ), + ], + ); + } +} diff --git a/test/cloud_lineup_rows_test.dart b/test/cloud_lineup_rows_test.dart index 071e808f..24c99dc1 100644 --- a/test/cloud_lineup_rows_test.dart +++ b/test/cloud_lineup_rows_test.dart @@ -1,117 +1,421 @@ import 'dart:convert'; import 'package:flutter_test/flutter_test.dart'; +import 'package:icarus/collab/canonical_json.dart'; import 'package:icarus/collab/cloud_lineup_rows.dart'; +import 'package:icarus/collab/collab_models.dart'; import 'package:icarus/const/agents.dart'; import 'package:icarus/const/line_provider.dart'; import 'package:icarus/const/placed_classes.dart'; -LineUpOrigin _origin(String id) => LineUpOrigin( +LineUpOrigin _origin(String id, {Offset position = const Offset(10, 20)}) => + LineUpOrigin( id: id, agent: PlacedAgent( id: 'agent-$id', type: AgentType.sova, - position: const Offset(10, 20), + position: position, lineUpID: id, ), ); -LineUpLanding _landing(String id) => LineUpLanding( +LineUpLanding _landing(String id, {Offset position = const Offset(30, 40)}) => + LineUpLanding( id: id, ability: PlacedAbility( id: 'ability-$id', data: AgentData.agents[AgentType.sova]!.abilities[2], - position: const Offset(30, 40), + position: position, lineUpID: id, ), ); -LineUpGraph _fanIn() => LineUpGraph( - origins: [_origin('a'), _origin('b')], - landings: [_landing('shared')], +LineUpLink _link(String id, String originId, String landingId) => + LineUpLink(id: id, originId: originId, landingId: landingId, name: id); + +/// One group: two origins into landing `shared` (fan-in), and a second +/// lineup out of origin a (fan-out). And a second group, k9 alone. +LineUpGraph _page() => LineUpGraph( + origins: [_origin('a'), _origin('b'), _origin('z')], + landings: [_landing('shared'), _landing('other'), _landing('far')], links: [ - LineUpLink(id: 'k1', originId: 'a', landingId: 'shared', name: 'A'), - LineUpLink(id: 'k2', originId: 'b', landingId: 'shared', name: 'B'), + LineUpLink( + id: 'k1', + originId: 'a', + landingId: 'shared', + name: 'A', + notes: 'jump throw', + images: [SimpleImageData(id: 'img-1', fileExtension: '.png')], + ), + _link('k2', 'b', 'shared'), + _link('k9', 'z', 'far'), + _link('k3', 'a', 'other'), ], ); +String _json(LineUpGraph graph) => jsonEncode(graph.toJson()); + +/// [rows] as canonical JSON, to compare them exactly. +String _canonical(Iterable rows) => + canonicalCloudJsonEncode(jsonDecode(jsonEncode([ + for (final row in rows) + {'publicId': row.publicId, 'payload': row.payload}, + ]))); + +Map _data(CloudLineupRow row) => + Map.from(row.payload['data'] as Map); + +List _ids(Object? entries) => [ + for (final entry in entries as List) (entry as Map)['id'] as String, + ]; + void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - test('rows are keyed by kind and entity id and read back whole', () { - final rows = cloudLineupRows(_fanIn()); - - expect(rows.map((row) => row.publicId), [ - 'lineupOrigin:a', - 'lineupOrigin:b', - 'lineupLanding:shared', - 'lineupLink:k1', - 'lineupLink:k2', - ]); - final read = lineUpGraphFromCloudRows(rows); - expect(read.drawnRowIds, rows.map((row) => row.publicId).toSet()); - expect(jsonEncode(read.graph.toJson()), jsonEncode(_fanIn().toJson())); + test('lineups connected through a spot share one row with their spots', () { + final written = cloudLineupRows(_page()); + + expect(written.rows.map((row) => row.publicId), ['k1', 'k9']); + final group = written.rows.first; + expect(group.payload['kind'], cloudLineupsPayloadKind); + expect(group.payload['payloadVersion'], currentCloudPayloadVersion); + final data = _data(group); + expect(data['id'], 'k1'); + expect(_ids(data['origins']), ['a', 'b']); + expect(_ids(data['landings']), ['shared', 'other']); + expect(_ids(data['links']), ['k1', 'k2', 'k3']); + expect( + (data['links'] as List).first, + jsonDecode(jsonEncode(_page().links.first.toJson())), + reason: 'a lineup is stored as the canvas has it', + ); + expect(_ids(_data(written.rows.last)['links']), ['k9']); + expect(written.groupOf, { + for (final id in ['a', 'b', 'shared', 'other', 'k1', 'k2', 'k3']) + id: 'k1', + for (final id in ['z', 'far', 'k9']) id: 'k9', + }); + }); + + test('rows draw back the page exactly, and write back the same rows', () { + final written = cloudLineupRows(_page()); + final read = lineUpGraphFromCloudRows(written.rows); + + expect(read.groupOf, written.groupOf); + final rewritten = cloudLineupRows(read.graph, groupOf: read.groupOf); + expect(_canonical(rewritten.rows), _canonical(written.rows)); + // Graph order is rows' order: the round trip keeps every lineup, spot + // and field. + expect( + _json(read.graph), + _json(LineUpGraph( + origins: [_origin('a'), _origin('b'), _origin('z')], + landings: [_landing('shared'), _landing('other'), _landing('far')], + links: [_page().links[0], _page().links[1], _page().links[3]] + + [_page().links[2]], + )), + ); + }); + + test('a group keeps its id when the lineup it was named after goes', () { + final read = lineUpGraphFromCloudRows(cloudLineupRows(_page()).rows); + final withoutK1 = LineUpGraph( + origins: read.graph.origins, + landings: read.graph.landings, + links: [ + for (final link in read.graph.links) + if (link.id != 'k1') link, + ], + ); + + final rows = cloudLineupRows(withoutK1, groupOf: read.groupOf).rows; + expect(rows.map((row) => row.publicId), ['k1', 'k9']); + expect(_ids(_data(rows.first)['links']), ['k2', 'k3']); }); - test('only whole lineups are drawn', () { + test('a group never splits: halves stay in its row', () { + // k1 (a -> shared) and k3 (b -> l2) connect only through k2 + // (b -> shared). + final graph = LineUpGraph( + origins: [_origin('a'), _origin('b')], + landings: [_landing('shared'), _landing('l2')], + links: [ + _link('k1', 'a', 'shared'), + _link('k2', 'b', 'shared'), + _link('k3', 'b', 'l2'), + ], + ); + final read = lineUpGraphFromCloudRows(cloudLineupRows(graph).rows); + + // Deleting k2 leaves {k1} and {k3} unconnected. + final split = LineUpGraph( + origins: graph.origins, + landings: graph.landings, + links: [graph.links[0], graph.links[2]], + ); + final rows = cloudLineupRows(split, groupOf: read.groupOf).rows; + expect(rows.map((row) => row.publicId), ['k1']); + expect(_ids(_data(rows.single)['links']), ['k1', 'k3']); + + // Without what the rows said, the halves would be two new groups. + expect( + cloudLineupRows(split).rows.map((row) => row.publicId), + ['k1', 'k3'], + ); + }); + + test('a new lineup on a spot joins that spot\'s group', () { + final read = lineUpGraphFromCloudRows(cloudLineupRows(_page()).rows); + final added = LineUpGraph( + origins: [...read.graph.origins, _origin('c')], + landings: read.graph.landings, + links: [...read.graph.links, _link('k0', 'c', 'far')], + ); + + final written = cloudLineupRows(added, groupOf: read.groupOf); + expect(written.rows.map((row) => row.publicId), ['k1', 'k9']); + expect(_ids(_data(written.rows.last)['links']), ['k9', 'k0']); + expect(written.groupOf['k0'], 'k9'); + expect(written.groupOf['c'], 'k9'); + }); + + test( + 'a lineup joining two groups goes to one, carrying the other\'s spot ' + '(a write the server refuses), and neither row goes', () { + final read = lineUpGraphFromCloudRows(cloudLineupRows(_page()).rows); + final bridged = LineUpGraph( + origins: read.graph.origins, + landings: read.graph.landings, + links: [...read.graph.links, _link('k5', 'z', 'shared')], + ); + + final written = cloudLineupRows(bridged, groupOf: read.groupOf); + // k5 joins the smaller group, k1, and carries origin z with it; k9's + // row keeps z too, and nothing is deleted. + expect(written.rows.map((row) => row.publicId), ['k1', 'k9']); + expect(_ids(_data(written.rows.first)['links']), ['k1', 'k2', 'k3', 'k5']); + expect(_ids(_data(written.rows.first)['origins']), ['a', 'b', 'z']); + expect(_ids(_data(written.rows.last)['links']), ['k9']); + expect(_ids(_data(written.rows.last)['origins']), ['z']); + expect(written.groupOf['z'], 'k9', reason: 'a spot stays in its group'); + expect(written.groupOf['k5'], 'k1'); + }); + + test('a lineup two rows name is drawn from the first, and kept there', () { + // The server keeps rows from overlapping; should two name k9 anyway, + // the reader draws one k9, from the first. + CloudLineupRow row(String id, LineUpGraph graph) => CloudLineupRow( + publicId: id, + payload: cloudLineupsPayload({ + 'id': id, + 'origins': [for (final origin in graph.origins) origin.toJson()], + 'landings': [ + for (final landing in graph.landings) landing.toJson(), + ], + 'links': [for (final link in graph.links) link.toJson()], + }), + ); + final merged = row( + 'k1', + LineUpGraph( + origins: [_origin('a'), _origin('z')], + landings: [_landing('shared'), _landing('far')], + links: [ + _link('k1', 'a', 'shared'), + _link('k9', 'z', 'far').copyWith(notes: 'old'), + ], + ), + ); + final teammates = row( + 'k9', + LineUpGraph( + origins: [_origin('z')], + landings: [_landing('far')], + links: [_link('k9', 'z', 'far').copyWith(notes: 'newer')], + ), + ); + + final read = lineUpGraphFromCloudRows([merged, teammates]); + expect(read.graph.links.map((link) => link.id), ['k1', 'k9']); + expect(read.graph.links.last.notes, 'old'); + expect(read.groupOf['k9'], 'k1'); + expect( + cloudLineupRows(read.graph, groupOf: read.groupOf) + .rows + .map((row) => row.publicId), + ['k1'], + ); + }); + + test('a new group never takes a group id already in use', () { + final graph = LineUpGraph( + origins: [_origin('a')], + landings: [_landing('l')], + links: [_link('k1', 'a', 'l'), _link('k2', 'a', 'l')], + ); + + expect( + cloudLineupRows(graph, takenGroupIds: {'k1'}).rows.single.publicId, + 'k2', + ); + // A group id remembered for a lineup elsewhere is in use too. + expect( + cloudLineupRows(graph, groupOf: {'gone': 'k1'}).rows.single.publicId, + 'k2', + ); + // Every lineup id taken: a fresh id. + final fresh = cloudLineupRows(graph, takenGroupIds: {'k1', 'k2'}); + expect(fresh.rows.single.publicId, isNot(anyOf('k1', 'k2'))); + expect(fresh.groupOf['k1'], fresh.rows.single.publicId); + }); + + test('a lineup missing a spot, and a spot no lineup uses, are not written', + () { final rows = cloudLineupRows(LineUpGraph( origins: [_origin('a'), _origin('lonely')], landings: [_landing('l')], links: [ - LineUpLink(id: 'k1', originId: 'a', landingId: 'l'), - LineUpLink(id: 'dangling', originId: 'a', landingId: 'missing'), + _link('k1', 'a', 'l'), + _link('dangling', 'a', 'missing'), ], - )); + )).rows; - final read = lineUpGraphFromCloudRows(rows); + expect(rows.map((row) => row.publicId), ['k1']); + expect(_ids(_data(rows.single)['origins']), ['a']); + expect(_ids(_data(rows.single)['links']), ['k1']); + }); - expect(read.drawnRowIds, { - 'lineupOrigin:a', - 'lineupLanding:l', - 'lineupLink:k1', - }); - expect(read.graph.origins.map((origin) => origin.id), ['a']); - expect(read.graph.links.map((link) => link.id), ['k1']); + test('the first row naming a spot or lineup draws it', () { + // Two clients put lineups on spot `shared` into different groups. + final first = cloudLineupRows(LineUpGraph( + origins: [_origin('a')], + landings: [_landing('shared')], + links: [_link('k1', 'a', 'shared')], + )).rows.single; + final second = cloudLineupRows(LineUpGraph( + origins: [_origin('b')], + landings: [_landing('shared', position: const Offset(99, 99))], + links: [_link('k2', 'b', 'shared')], + )).rows.single; + + final read = lineUpGraphFromCloudRows([first, second]); + expect(read.graph.landings.map((l) => l.id), ['shared']); + expect(read.graph.landings.single.ability.position, const Offset(30, 40)); + expect(read.graph.links.map((l) => l.landingId), ['shared', 'shared']); + expect(read.groupOf['shared'], 'k1'); + + // Written back, both rows stay, each carrying the spot as drawn: no + // lineup moves rows and no row is deleted. + final rows = cloudLineupRows(read.graph, groupOf: read.groupOf).rows; + expect(rows.map((row) => row.publicId), ['k1', 'k2']); + expect(_ids(_data(rows.last)['links']), ['k2']); + expect(_ids(_data(rows.last)['landings']), ['shared']); }); - test('a row of any other kind fails loudly, naming the row', () { - // Legacy lineup groups included: they are not part of the cloud format. - for (final kind in ['lineupSomething', 'lineupGroup']) { + test('a row of any other shape fails loudly, naming the row', () { + final valid = cloudLineupRows(_page()).rows.first.payload; + final data = Map.from(valid['data'] as Map); + final broken = { + // Protocol 4's graph rows, the legacy group, and the per-lineup row + // this replaced are not groups. + 'lineupLink': {...valid, 'kind': 'lineupLink'}, + 'lineupGroup': {...valid, 'kind': 'lineupGroup'}, + 'lineup': {...valid, 'kind': 'lineup'}, + 'no origins': { + ...valid, + 'data': {...data}..remove('origins'), + }, + 'no links': { + ...valid, + 'data': {...data}..remove('links'), + }, + 'a lineup aimed outside the row': { + ...valid, + 'data': { + ...data, + 'landings': [ + for (final landing in data['landings'] as List) + if ((landing as Map)['id'] != 'other') landing, + ], + }, + }, + 'not objects': { + ...valid, + 'data': { + ...data, + 'origins': ['a'], + }, + }, + }; + for (final MapEntry(key: reason, value: payload) in broken.entries) { expect( () => lineUpGraphFromCloudRows([ - CloudLineupRow( - publicId: 'odd', - payload: {'kind': kind, 'payloadVersion': 1, 'data': {}}, - ), + CloudLineupRow(publicId: 'k1', payload: payload), ]), throwsA(isA().having( (error) => error.message, 'message', - contains('Cloud lineup odd could not be read'), + contains('Cloud lineup group k1 could not be read'), )), + reason: reason, ); } + expect( + () => lineUpGraphFromCloudRows([ + CloudLineupRow(publicId: 'someone-else', payload: valid), + ]), + throwsA(isA().having( + (error) => error.message, + 'message', + contains('Cloud lineup group someone-else could not be read'), + )), + reason: 'a row keyed apart from its group', + ); }); - test('new ids carry every reference with them', () { - var next = 0; - final copy = lineUpGraphWithIds(_fanIn(), (kind, id) => '$kind-${next++}'); - - final originIds = copy.origins.map((origin) => origin.id).toSet(); - final landingId = copy.landings.single.id; - expect(originIds.intersection({'a', 'b'}), isEmpty); - for (final origin in copy.origins) { - expect(origin.agent.lineUpID, origin.id); + test('ops in a cloud format before lineup group rows are retired', () { + final payload = cloudLineupRows(_page()).rows.first.payload; + expect( + isRetiredCloudLineupOp(LineupAddOp( + opId: 'op', + lineupPublicId: 'k1', + pagePublicId: 'p', + payload: payload, + sortIndex: 0, + )), + isFalse, + ); + for (final kind in ['lineupLink', 'lineup']) { + expect( + isRetiredCloudLineupOp(LineupAddOp( + opId: 'op', + lineupPublicId: 'k1', + pagePublicId: 'p', + payload: {...payload, 'kind': kind}, + sortIndex: 0, + )), + isTrue, + reason: kind, + ); } - expect(copy.landings.single.ability.lineUpID, landingId); - for (final link in copy.links) { - expect(originIds, contains(link.originId)); - expect(link.landingId, landingId); + for (final key in ['lineupOrigin:a', 'lineupLanding:l', 'lineupLink:k']) { + expect( + isRetiredCloudLineupOp(LineupDeleteOp( + opId: 'op', + lineupPublicId: key, + pagePublicId: 'p', + expectedLineupRevision: 1, + )), + isTrue, + reason: key, + ); } - expect(copy.links.map((link) => link.name), ['A', 'B']); expect( - lineUpGraphFromCloudRows(cloudLineupRows(copy)).graph.links, - hasLength(2), + isRetiredCloudLineupOp(const ElementDeleteOp( + opId: 'op', + elementPublicId: 'lineupLink:not-a-lineup', + pagePublicId: 'p', + expectedElementRevision: 1, + )), + isFalse, ); }); } diff --git a/test/cloud_payload_upgrade_test.dart b/test/cloud_payload_upgrade_test.dart index dcb9af1e..5ec670b1 100644 --- a/test/cloud_payload_upgrade_test.dart +++ b/test/cloud_payload_upgrade_test.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:icarus/collab/cloud_lineup_rows.dart'; import 'package:icarus/collab/cloud_payload_upgrade.dart'; @@ -94,24 +93,34 @@ void main() { expect(expected.position, isNot(paranoia.position)); }); - test('a version 1 lineup landing moves its Paranoia', () { - final landing = LineUpLanding(id: 'landing', ability: _placed('l', 1)); - final upgraded = upgradeCloudPayload( - { - ...cloudLineupPayload( - kind: CloudLineupKind.landing, - data: landing.toJson(), + test('a lineup carrying a Paranoia is never moved', () { + // Every lineup row was written at the in-game size: correcting one would + // move its Paranoia twice. + final lineup = cloudLineupRows(LineUpGraph( + origins: [ + LineUpOrigin( + id: 'origin', + agent: PlacedAgent( + id: 'omen', + type: AgentType.omen, + position: const Offset(340, 210), + lineUpID: 'origin', + ), ), - 'payloadVersion': 1, - }, - _map, - ); - - expect(upgraded['payloadVersion'], paranoiaCloudPayloadVersion); - expect( - LineUpLanding.fromJson(cloudPayloadData(upgraded)).ability.position, - ParanoiaRangeMigration.migrateAbility(landing.ability, _map).position, + ], + landings: [LineUpLanding(id: 'landing', ability: _placed('l', 1))], + links: [ + LineUpLink(id: 'lineup', originId: 'origin', landingId: 'landing'), + ], + )).rows.single.payload; + + expect(lineup['payloadVersion'], currentCloudPayloadVersion); + expect(identical(upgradeCloudPayload(lineup, _map), lineup), isTrue); + final page = upgradeRemotePageSnapshot( + _page([_v1('ability', _placed('paranoia', 1).toJson())], [lineup]), + Maps.mapNames[_map]!, ); + expect(identical(page.lineups.single.payload, lineup), isTrue); }); test('rows without a Paranoia are left exactly as the server holds them', () { diff --git a/test/collab/cloud_sync_error_message_test.dart b/test/collab/cloud_sync_error_message_test.dart index 102eb60a..bf96130b 100644 --- a/test/collab/cloud_sync_error_message_test.dart +++ b/test/collab/cloud_sync_error_message_test.dart @@ -30,23 +30,56 @@ void main() { expect(message, isNot(contains('LINEUP_PAGE_MISMATCH'))); }); - test('explains a lineup whose origin or landing is gone', () { - final message = friendlyCloudSyncError( - "ConvexFunctionException(LINEUP_LINK_END_MISSING, This lineup's origin " - 'or landing spot is no longer on the page)', - ); + test('explains a change to something a teammate deleted', () { + final message = friendlyCloudSyncError(teammateDeletedMessage); + + expect(message, contains('A teammate deleted what you changed')); + expect(message, contains('Keep mine brings it back')); + expect(message, contains('Use cloud lets it go')); + }); + + test('says when Keep mine cannot bring a deleted item back', () { + final message = friendlyCloudSyncError(teammateDeletedCannotRestoreMessage); - expect(message, contains("origin or landing spot isn't on this page")); - expect(message, contains('was not saved')); - expect(message, contains('Keep mine tries again')); - expect(message, contains('Use cloud drops your change')); - expect(message, isNot(contains('LINEUP_LINK_END_MISSING'))); + expect(message, contains('cannot bring it back')); + expect(message, contains('Use cloud')); + expect(message, isNot(contains('Keep mine'))); + expect(message, isNot(contains('matching revision'))); + }); + + test('explains a lineup change saved in the old cloud format', () { + final message = friendlyCloudSyncError(retiredLineupOpMessage); + + expect(message, contains('older version of Icarus')); + expect(message, contains('cannot be sent')); + expect(message, contains('Use cloud')); + expect(message, isNot(contains('Keep mine'))); + }); + + test('explains a lineup group refused for overlapping another', () { + final message = friendlyCloudSyncError(lineupOverlapMessage); + + expect(message, contains('shares a spot')); + expect(message, contains('not saved to the cloud')); + expect(message, contains('Use cloud')); + expect(message, isNot(contains(lineupOverlapMessage))); + expect(isSpecificAttentionReason(lineupOverlapMessage), isTrue); + // As the queue reports it beside other refused work. + expect( + isSpecificAttentionReason( + '$lineupOverlapMessage. $otherWorkNeedsAttentionNote'), + isTrue, + ); }); test('lineup refusals and oversized work are specific attention reasons', () { - expect(isSpecificAttentionReason(lineupLinkEndMissingMessage), isTrue); expect(isSpecificAttentionReason(lineupPageMismatchMessage), isTrue); - expect(isSpecificAttentionReason(lineupEndInUseMessage), isTrue); + expect(isSpecificAttentionReason(retiredLineupOpMessage), isTrue); + expect(isSpecificAttentionReason(teammateDeletedMessage), isTrue); + expect( + isSpecificAttentionReason(teammateDeletedCannotRestoreMessage), + isTrue, + ); expect(isSpecificAttentionReason(pageDeletedMessage), isTrue); expect(isSpecificAttentionReason(cloudOperationTooLargeMessage), isTrue); for (final reason in [ @@ -58,19 +91,6 @@ void main() { } }); - test('explains an origin or landing another lineup still uses', () { - final message = friendlyCloudSyncError( - 'ConvexFunctionException(LINEUP_END_IN_USE, Another lineup still uses ' - 'this origin or landing spot)', - ); - - expect(message, contains('still uses this origin or landing spot')); - expect(message, contains('was not deleted')); - expect(message, contains('Keep mine tries again')); - expect(message, contains('Use cloud brings back that lineup')); - expect(message, isNot(contains('LINEUP_END_IN_USE'))); - }); - test('does not expose unknown transport details', () { final message = friendlyCloudSyncError('socket exploded at 10.0.0.4'); diff --git a/test/collab_sync_models_test.dart b/test/collab_sync_models_test.dart index 5bf4ba94..65e975c3 100644 --- a/test/collab_sync_models_test.dart +++ b/test/collab_sync_models_test.dart @@ -1,9 +1,9 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:icarus/collab/canonical_json.dart'; +import 'package:icarus/collab/cloud_lineup_rows.dart'; import 'package:icarus/collab/cloud_media_models.dart'; import 'package:icarus/collab/collab_models.dart'; import 'package:icarus/const/json_converters.dart'; -import 'package:icarus/const/line_provider.dart'; import 'package:icarus/providers/collab/cloud_collab_provider.dart'; import 'package:icarus/strategy/strategy_import_export.dart'; @@ -55,7 +55,7 @@ void main() { ); final json = op.toConvexJson(); - expect(currentCloudProtocolVersion, 4); + expect(currentCloudProtocolVersion, 5); expect(json['type'], 'pageContent.patch'); expect(json['expectedPageContentRevision'], 4); expect(json.containsKey('expectedSequence'), isFalse); @@ -395,24 +395,55 @@ void main() { test('cloud payload data normalizes nested bridge maps for lineup parsing', () { final payload = { - 'kind': 'lineupLanding', + 'kind': cloudLineupsPayloadKind, 'payloadVersion': 1, 'data': { - 'id': 'landing-1', - 'ability': { - 'id': 'ability-1', - 'data': {'type': 'sova', 'index': 2.0}, - 'position': {'dx': 30, 'dy': 40}, - 'lineUpID': 'landing-1', - }, + 'id': 'group-1', + 'origins': [ + { + 'id': 'origin-1', + 'agent': { + 'id': 'agent-1', + 'type': 'sova', + 'position': {'dx': 10, 'dy': 20}, + 'lineUpID': 'origin-1', + }, + }, + ], + 'landings': [ + { + 'id': 'landing-1', + 'ability': { + 'id': 'ability-1', + 'data': {'type': 'sova', 'index': 2.0}, + 'position': {'dx': 30, 'dy': 40}, + 'lineUpID': 'landing-1', + }, + }, + ], + 'links': [ + { + 'id': 'lineup-1', + 'originId': 'origin-1', + 'landingId': 'landing-1', + 'name': 'Garage smoke', + }, + ], }, }; - final landing = LineUpLanding.fromJson(cloudPayloadData(payload)); + final read = lineUpGraphFromCloudRows([ + CloudLineupRow(publicId: 'group-1', payload: payload), + ]); + final graph = read.graph; + final landing = graph.landings.single; + expect(graph.links.single.name, 'Garage smoke'); + expect(graph.origins.single.agent.lineUpID, 'origin-1'); expect(landing.id, 'landing-1'); expect(landing.ability.lineUpID, 'landing-1'); expect(landing.ability.position, const Offset(30, 40)); + expect(read.groupOf['lineup-1'], 'group-1'); }); test('ability info accepts Convex float64 integers and rejects fractions', @@ -485,13 +516,13 @@ void main() { ); expect( - () => StrategyImportExportService.strategyDataFromRemoteSnapshot( - snapshot), + () => + StrategyImportExportService.strategyDataFromRemoteSnapshot(snapshot), throwsA( isA().having( (error) => error.message, 'message', - contains('Cloud lineup lineup-1 could not be read'), + contains('Cloud lineup group lineup-1 could not be read'), ), ), ); diff --git a/test/global_strategy_outbox_test.dart b/test/global_strategy_outbox_test.dart index 334ee03d..c7ce9831 100644 --- a/test/global_strategy_outbox_test.dart +++ b/test/global_strategy_outbox_test.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:icarus/collab/cloud_lineup_rows.dart'; import 'package:icarus/collab/collab_models.dart'; import 'package:icarus/collab/convex_strategy_repository.dart'; import 'package:icarus/collab/durable_strategy_outbox.dart'; @@ -244,53 +243,44 @@ void main() { expect(finalOp.expectedElementRevision, 2); }); - test('a link waiting for a backing-off origin does not hold up the drain', - () async { + test('a lineup backing off does not hold up the drain', () async { final store = MemoryDurableStrategyOutboxStore(); - DurableOutboxRecord lineup( - String kind, - Map data, { - required DateTime updatedAt, - int attempts = 0, - }) { - final op = LineupAddOp( - opId: 'add-$kind', - lineupPublicId: cloudLineupRowId(kind, data['id'] as String), - pagePublicId: 'page-one', - payload: cloudLineupPayload(kind: kind, data: data), - sortIndex: 0, - ); - return DurableOutboxRecord( - accountId: 'account-a', - strategyPublicId: 'blocked', - entityKey: EntitySyncKey.forStrategyOp(op)!, - pending: PendingOp( - op: op, - clientId: 'client-blocked', - attempts: attempts, - lastAttemptAt: attempts == 0 ? null : DateTime.now(), - ), - status: DurableOutboxStatus.queued, - createdAt: updatedAt, - updatedAt: updatedAt, - ); - } - - // The oldest work is a link whose origin just failed to send and is - // backing off; the link must wait for it. - await store.put(lineup( - CloudLineupKind.link, - {'id': 'k', 'originId': 'o', 'landingId': 'l'}, - updatedAt: DateTime(2025), - )); - await store.put(lineup( - CloudLineupKind.origin, - {'id': 'o', 'agent': {}}, + final lineup = LineupAddOp( + opId: 'add-lineup', + lineupPublicId: 'k', + pagePublicId: 'page-one', + payload: cloudLineupsPayload({ + 'id': 'k', + 'origins': [ + {'id': 'o', 'agent': {}}, + ], + 'landings': [ + {'id': 'l', 'ability': {}}, + ], + 'links': [ + {'id': 'k', 'originId': 'o', 'landingId': 'l'}, + ], + }), + sortIndex: 0, + ); + // The oldest work is a lineup that just failed to send and is backing + // off. + await store.put(DurableOutboxRecord( + accountId: 'account-a', + strategyPublicId: 'blocked', + entityKey: EntitySyncKey.forStrategyOp(lineup)!, + pending: PendingOp( + op: lineup, + clientId: 'client-blocked', + attempts: 3, + lastAttemptAt: DateTime.now(), + ), + status: DurableOutboxStatus.queued, + createdAt: DateTime(2025), updatedAt: DateTime(2025), - attempts: 3, )); // The first drain after sign-in ignores backoff; this older work takes - // it, so the drains after it honour the origin's backoff. + // it, so the drains after it honour the lineup's backoff. await store.put(_record(strategyId: 'first', opId: 'first') .copyWith(updatedAt: DateTime(2024))); await store.put(_record(strategyId: 'open', opId: 'open')); @@ -305,8 +295,8 @@ void main() { await _waitUntil(() => repository.calls.length == 2); expect(repository.calls.map((call) => call.strategyId), ['first', 'open']); expect( - store.load().records.map((record) => record.pending.op.opId).toSet(), - {'add-${CloudLineupKind.link}', 'add-${CloudLineupKind.origin}'}, + store.load().records.map((record) => record.pending.op.opId), + ['add-lineup'], ); }); diff --git a/test/lineup_group_changes_test.dart b/test/lineup_group_changes_test.dart new file mode 100644 index 00000000..3c9bbd24 --- /dev/null +++ b/test/lineup_group_changes_test.dart @@ -0,0 +1,139 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:icarus/const/agents.dart'; +import 'package:icarus/const/line_provider.dart'; +import 'package:icarus/const/placed_classes.dart'; +import 'package:icarus/strategy/lineup_group_changes.dart'; + +LineUpOrigin _origin(String id, {Offset position = const Offset(10, 20)}) => + LineUpOrigin( + id: id, + agent: PlacedAgent( + id: 'agent-$id', + type: AgentType.brimstone, + position: position, + lineUpID: id, + ), + ); + +LineUpLanding _landing(String id, {Offset position = const Offset(30, 40)}) => + LineUpLanding( + id: id, + ability: PlacedAbility( + id: 'ability-$id', + data: AgentData.agents[AgentType.brimstone]!.abilities[2], + position: position, + lineUpID: id, + ), + ); + +/// Three smokes from o1, o2, o3 onto one landing; k3 has no name. +LineUpGraph _group({ + Offset landingAt = const Offset(30, 40), + String k1Notes = '', + List extra = const [], + bool withoutK2 = false, +}) => + LineUpGraph( + origins: [_origin('o1'), _origin('o2'), _origin('o3')], + landings: [_landing('l1', position: landingAt)], + links: [ + LineUpLink( + id: 'k1', + originId: 'o1', + landingId: 'l1', + name: 'B Main 1', + notes: k1Notes, + ), + if (!withoutK2) + LineUpLink( + id: 'k2', originId: 'o2', landingId: 'l1', name: 'B Main 2'), + LineUpLink(id: 'k3', originId: 'o3', landingId: 'l1'), + ...extra, + ], + ); + +Map _described(List changes) => { + for (final change in changes) change.label: change.description, + }; + +void main() { + test('nothing changed lists nothing', () { + expect(lineupChanges(from: _group(), to: _group()), isEmpty); + }); + + test('each changed lineup is listed once, with everything that changed', () { + final changes = lineupChanges( + from: _group(), + to: _group(landingAt: const Offset(99, 99), k1Notes: 'jump throw'), + ); + + // Moving the shared landing moves every lineup on it. + expect(_described(changes), { + 'B Main 1': 'notes edited, landing moved', + 'B Main 2': 'landing moved', + 'Brimstone lineup': 'landing moved', + }); + }); + + test('added and deleted lineups are named as such', () { + final changes = lineupChanges( + from: _group(), + to: _group( + withoutK2: true, + extra: [ + LineUpLink(id: 'k4', originId: 'o1', landingId: 'l1', name: 'New'), + ], + ), + ); + + expect(_described(changes), {'New': 'added', 'B Main 2': 'deleted'}); + expect(changes.last.label, 'B Main 2', reason: 'deletions come last'); + }); + + test('a deleted group lists every lineup as deleted', () { + final changes = lineupChanges(from: _group(), to: LineUpGraph.empty); + + expect(changes.map((change) => change.description).toSet(), {'deleted'}); + expect(changes, hasLength(3)); + }); + + test('a fork has fresh ids everywhere and the same lineups', () { + final original = _group(k1Notes: 'jump throw'); + final fork = forkLineUpGraph(original); + + final originalIds = { + for (final origin in original.origins) ...[origin.id, origin.agent.id], + for (final landing in original.landings) ...[ + landing.id, + landing.ability.id, + ], + for (final link in original.links) link.id, + }; + final forkIds = { + for (final origin in fork.origins) ...[origin.id, origin.agent.id], + for (final landing in fork.landings) ...[landing.id, landing.ability.id], + for (final link in fork.links) link.id, + }; + expect(forkIds.intersection(originalIds), isEmpty); + expect(forkIds, hasLength(originalIds.length)); + + // The fork is wired like the original: three lineups on one landing, + // each marker naming its own spot. + expect(fork.links.map((link) => link.landingId).toSet(), { + fork.landings.single.id, + }); + for (final origin in fork.origins) { + expect(origin.agent.lineUpID, origin.id); + } + expect(fork.landings.single.ability.lineUpID, fork.landings.single.id); + + // And otherwise the same: nothing a user sees differs. + String described(LineUpGraph graph) => [ + for (final link in graph.links) + '${link.name}|${link.notes}|' + '${graph.origins.firstWhere((o) => o.id == link.originId).agent.position}|' + '${graph.landings.firstWhere((l) => l.id == link.landingId).ability.position}', + ].join(';'); + expect(described(fork), described(original)); + }); +} diff --git a/test/remote_page_merge_test.dart b/test/remote_page_merge_test.dart index bd8935c0..df2c7a58 100644 --- a/test/remote_page_merge_test.dart +++ b/test/remote_page_merge_test.dart @@ -1,6 +1,38 @@ import 'package:flutter_test/flutter_test.dart'; +import 'package:icarus/const/agents.dart'; +import 'package:icarus/const/line_provider.dart'; +import 'package:icarus/const/placed_classes.dart'; import 'package:icarus/strategy/remote_page_merge.dart'; +LineUpOrigin _origin(String id, double x) => LineUpOrigin( + id: id, + agent: PlacedAgent( + id: 'agent-$id', + type: AgentType.sova, + position: Offset(x, 0), + lineUpID: id, + ), + ); + +LineUpLanding _landing(String id, double x) => LineUpLanding( + id: id, + ability: PlacedAbility( + id: 'ability-$id', + data: AgentData.agents[AgentType.sova]!.abilities[2], + position: Offset(x, 0), + lineUpID: id, + ), + ); + +LineUpLink _link(String id, String originId, String landingId, + [String? name]) => + LineUpLink( + id: id, + originId: originId, + landingId: landingId, + name: name ?? id, + ); + void main() { List merge( List current, List incoming, Set held) => @@ -30,4 +62,152 @@ void main() { test('an unheld item the server removed goes', () { expect(merge(['a:1', 'b:1'], ['b:1'], {'b'}), ['b:1']); }); + + group('held lineups', () { + // On screen: k1 (o1 → shared) and k2 (o2 → shared) share a landing; k3 + // (o3 → l3) stands apart. The server moved every spot to 9 and renamed + // every lineup. + final local = LineUpGraph( + origins: [_origin('o1', 1), _origin('o2', 1), _origin('o3', 1)], + landings: [_landing('shared', 1), _landing('l3', 1)], + links: [ + _link('k1', 'o1', 'shared'), + _link('k2', 'o2', 'shared'), + _link('k3', 'o3', 'l3'), + ], + ); + final remote = LineUpGraph( + origins: [_origin('o1', 9), _origin('o2', 9), _origin('o3', 9)], + landings: [_landing('shared', 9), _landing('l3', 9)], + links: [ + _link('k1', 'o1', 'shared', 'k1 renamed'), + _link('k2', 'o2', 'shared', 'k2 renamed'), + _link('k3', 'o3', 'l3', 'k3 renamed'), + ], + ); + // The group rows: g1 holds k1 and k2 with their spots, g3 holds k3 (and + // a teammate's k4, when there is one). + const groups = { + 'k1': 'g1', + 'o1': 'g1', + 'k2': 'g1', + 'o2': 'g1', + 'shared': 'g1', + 'k3': 'g3', + 'o3': 'g3', + 'l3': 'g3', + 'k4': 'g3', + 'o4': 'g3', + }; + String? groupOf(String id) => groups[id]; + Map names(LineUpGraph graph) => + {for (final link in graph.links) link.id: link.name}; + Map spots(LineUpGraph graph) => { + for (final origin in graph.origins) + origin.id: origin.agent.position.dx, + for (final landing in graph.landings) + landing.id: landing.ability.position.dx, + }; + + test('nothing held takes the server copy whole', () { + final (graph, held) = mergeHeldLineups( + local: local, + remote: remote, + holding: {'x'}, + groupOf: groupOf, + ); + + expect(held, isEmpty); + expect(identical(graph, remote), isTrue); + }); + + test('holding a spot holds its whole group, and only that', () { + final (graph, held) = mergeHeldLineups( + local: local, + remote: remote, + holding: {'o1'}, + groupOf: groupOf, + ); + + // o1 holds group g1, so k2 waits with k1. + expect(held, {'g1'}); + expect(names(graph), {'k1': 'k1', 'k2': 'k2', 'k3': 'k3 renamed'}); + expect(spots(graph), { + 'o1': 1, + 'o2': 1, + 'o3': 9, + 'shared': 1, + 'l3': 9, + }); + // Held objects stay the ones on screen. + expect(identical(graph.origins.first, local.origins.first), isTrue); + }); + + test('a teammate lineup new on a held spot waits off the canvas', () { + final withNew = LineUpGraph( + origins: [...remote.origins, _origin('o4', 9)], + landings: remote.landings, + links: [...remote.links, _link('k4', 'o4', 'l3')], + ); + + final (graph, held) = mergeHeldLineups( + local: local, + remote: withNew, + holding: {'l3'}, + groupOf: groupOf, + ); + + expect(held, {'g3'}); + expect(graph.links.map((link) => link.id), ['k1', 'k2', 'k3']); + expect(graph.origins.map((origin) => origin.id), ['o1', 'o2', 'o3']); + expect(spots(graph)['l3'], 1); + }); + + test('a held lineup the server removed stays in its place', () { + final without = LineUpGraph( + origins: [remote.origins[1], remote.origins[2]], + landings: remote.landings, + links: [remote.links[1], remote.links[2]], + ); + + final (graph, held) = mergeHeldLineups( + local: local, + remote: without, + holding: {'k1'}, + groupOf: groupOf, + ); + + expect(held, {'g1'}); + expect(graph.links.map((link) => link.id), ['k1', 'k2', 'k3']); + expect(spots(graph)['o1'], 1); + }); + + test('a group holds lineups no spot connects any more', () { + // k3 is in g1 too: the lineup that joined it to k1 was deleted, and + // a group never splits. + String? oneGroup(String id) => id == 'x' ? null : 'g1'; + + final (graph, held) = mergeHeldLineups( + local: local, + remote: remote, + holding: {'k1'}, + groupOf: oneGroup, + ); + + expect(held, {'g1'}); + expect(names(graph), {'k1': 'k1', 'k2': 'k2', 'k3': 'k3'}); + }); + + test('a lineup in no group yet holds what shares its spots', () { + final (graph, held) = mergeHeldLineups( + local: local, + remote: remote, + holding: {'o1'}, + groupOf: (_) => null, + ); + + expect(held, isEmpty); + expect(names(graph), {'k1': 'k1', 'k2': 'k2', 'k3': 'k3 renamed'}); + }); + }); } diff --git a/test/strategy_cloud_migration_test.dart b/test/strategy_cloud_migration_test.dart index e9e1db1e..ec5ca212 100644 --- a/test/strategy_cloud_migration_test.dart +++ b/test/strategy_cloud_migration_test.dart @@ -76,14 +76,17 @@ List _upload( /// What a client hydrates from the uploaded rows, JSON round-tripped as the /// server returns them. -LineUpGraph _hydrate(List adds) { +LineUpGraph _hydrate(List adds) => _hydrated(adds).graph; + +/// [_hydrate], with the group each lineup and spot was drawn from. +CloudLineups _hydrated(List adds) { return lineUpGraphFromCloudRows([ for (final add in adds) CloudLineupRow( publicId: add.lineupPublicId, payload: jsonDecode(jsonEncode(add.payload)) as Map, ), - ]).graph; + ]); } String _canonical(Object? value) => @@ -92,20 +95,16 @@ String _canonical(Object? value) => void main() { TestWidgetsFlutterBinding.ensureInitialized(); - test('a lineup is uploaded as one row per origin, landing and link', () { + test('a lineup is uploaded as a group row holding it and its spots', () { final adds = _upload(_sharedIdLineup()); - expect(adds.map((add) => add.lineupPublicId), [ - 'lineupOrigin:origin-1', - 'lineupLanding:link-1', - 'lineupLink:link-1', - ]); - expect(adds.map((add) => add.payload['kind']), [ - 'lineupOrigin', - 'lineupLanding', - 'lineupLink', - ]); - expect(adds.map((add) => add.sortIndex), [0, 1, 2]); + expect(adds.map((add) => add.lineupPublicId), ['link-1']); + expect(adds.single.payload['kind'], cloudLineupsPayloadKind); + expect(adds.single.sortIndex, 0); + final data = cloudPayloadData(adds.single.payload); + expect((data['origins'] as List).single['id'], 'origin-1'); + expect((data['landings'] as List).single['id'], 'link-1'); + expect((data['links'] as List).single['id'], 'link-1'); // Hydrating the upload gives back the page's graph, ids and all, so the // page never authors a patch for a lineup nobody touched. expect( @@ -114,38 +113,39 @@ void main() { ); }); - test('an id another page already took is reassigned with its references', () { + test('a group id another page already took is not reused', () { + final usedLineupIds = {'link-1'}; final adds = _upload( _sharedIdLineup(), - // A page duplicated from page 1 already uploaded this origin. - usedLineupIds: {'lineupOrigin:origin-1'}, + // A page duplicated from page 1 already uploaded this group. + usedLineupIds: usedLineupIds, ); - final origin = cloudPayloadData(adds[0].payload); - final newOriginId = origin['id'] as String; - expect(newOriginId, isNot('origin-1')); - expect(adds[0].lineupPublicId, 'lineupOrigin:$newOriginId'); - expect((origin['agent'] as Map)['lineUpID'], newOriginId); - // The landing and link ids were free, so they stay. - expect(adds[1].lineupPublicId, 'lineupLanding:link-1'); - expect(adds[2].lineupPublicId, 'lineupLink:link-1'); - expect(cloudPayloadData(adds[2].payload)['originId'], newOriginId); + final newId = adds.single.lineupPublicId; + expect(newId, isNot('link-1')); + expect(usedLineupIds, {'link-1', newId}); + final data = cloudPayloadData(adds.single.payload); + expect(data['id'], newId); + // Ids inside a row only need to be unique in the row, so they stay. + expect((data['links'] as List).single['id'], 'link-1'); + expect((data['origins'] as List).single['id'], 'origin-1'); // And the rows reproduce exactly when the hydrated graph is sent again. - final resent = cloudLineupRows(_hydrate(adds)); + final hydrated = _hydrated(adds); + final resent = cloudLineupRows(hydrated.graph, groupOf: hydrated.groupOf); expect( - _canonical([for (final row in resent) row.payload]), + _canonical([for (final row in resent.rows) row.payload]), _canonical([for (final add in adds) add.payload]), ); }); - test('a fan-in lineup uploads with its shared landing and link names', () { + test('fan-in and fan-out upload with their shared spots and names', () { final fanIn = LineUpGraph( origins: [ _origin('origin-a', const Offset(10, 20)), _origin('origin-b', const Offset(50, 60)), ], - landings: [_landing('shared')], + landings: [_landing('shared'), _landing('other')], links: [ LineUpLink( id: 'link-a', @@ -160,17 +160,34 @@ void main() { landingId: 'shared', name: 'From mid', ), + LineUpLink( + id: 'link-c', + originId: 'origin-a', + landingId: 'other', + name: 'From heaven, long', + ), ], ); final adds = _upload(fanIn); - expect(adds, hasLength(5)); + // Connected through their spots, the three lineups are one group. + expect(adds.map((add) => add.lineupPublicId), ['link-a']); final hydrated = _hydrate(adds); - expect(hydrated.landings.single.id, 'shared'); + expect(hydrated.landings.map((landing) => landing.id), [ + 'shared', + 'other', + ]); expect( - [for (final link in hydrated.links) (link.landingId, link.name)], - [('shared', 'From heaven'), ('shared', 'From mid')], + [ + for (final link in hydrated.links) + (link.originId, link.landingId, link.name), + ], + [ + ('origin-a', 'shared', 'From heaven'), + ('origin-b', 'shared', 'From mid'), + ('origin-a', 'other', 'From heaven, long'), + ], ); expect(hydrated.links.first.images.single.id, 'image-a'); expect(_canonical(hydrated.toJson()), _canonical(fanIn.toJson())); diff --git a/test/strategy_op_queue_provider_test.dart b/test/strategy_op_queue_provider_test.dart index eb845888..5765c61f 100644 --- a/test/strategy_op_queue_provider_test.dart +++ b/test/strategy_op_queue_provider_test.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:icarus/collab/cloud_lineup_rows.dart'; import 'package:icarus/collab/cloud_sync_error_message.dart'; import 'package:icarus/collab/collab_models.dart'; import 'package:icarus/collab/convex_strategy_repository.dart'; @@ -937,180 +936,73 @@ void main() { expect(store.load().records.single.pending.op.opId, op.opId); }); - test('a lineup link waits for the origin and landing still to be sent', + test('a lineup refused for another page stays saved and keeps that reason', () async { final store = MemoryDurableStrategyOutboxStore(); - DurableOutboxRecord record(StrategyOp op, String clientId) => - DurableOutboxRecord( - accountId: 'account-a', - strategyPublicId: 'strategy-1', - entityKey: EntitySyncKey.forStrategyOp(op)!, - pending: PendingOp(op: op, clientId: clientId), - status: DurableOutboxStatus.queued, - createdAt: DateTime(2026), - updatedAt: DateTime(2026), - ); - LineupAddOp add(String kind, Map data) => LineupAddOp( - opId: 'add-$kind', - lineupPublicId: cloudLineupRowId(kind, data['id'] as String), - pagePublicId: 'page-1', - payload: cloudLineupPayload(kind: kind, data: data), - sortIndex: 0, - ); - // As an outbox reloads after a restart: by key, so the link comes - // before the origin, and the origin was queued by an earlier session - // under another client id. - await store.put(record(_cloudElementOp(), 'client-b')); - await store.put(record( - add(CloudLineupKind.landing, {'id': 'l', 'ability': {}}), - 'client-b', - )); - await store.put(record( - add(CloudLineupKind.link, { - 'id': 'k', - 'originId': 'o', - 'landingId': 'l', - }), - 'client-b', - )); - await store.put(record( - add(CloudLineupKind.origin, {'id': 'o', 'agent': {}}), - 'client-a', - )); - final repository = _RecordingAckRepository(); final container = _cloudQueueContainer( store: store, - repository: repository, + repository: _FailingLineupRepository(), ); addTearDown(container.dispose); final notifier = container.read(strategyOpQueueProvider.notifier) ..setActiveStrategy('strategy-1', accountId: 'account-a'); + final lineup = _lineupAdd(opId: 'add-lineup', pageId: 'page-2'); + final key = EntitySyncKey.forStrategyOp(lineup)!; + await notifier.enqueue(lineup, flushImmediately: false); await notifier.flushNow(); - for (var i = 0; i < 50 && repository.calls.length < 3; i++) { - await Future.delayed(Duration.zero); - } + final current = container.read(strategyOpQueueProvider); + expect(current.attentionByEntityKey[key]!.pending.op.opId, 'add-lineup'); + expect(current.needsAttention, isTrue); + // The sync button explains the refusal, not a generic conflict. + expect(current.lastError, lineupPageMismatchMessage); + expect(isSpecificAttentionReason(current.lastError!), isTrue); + final durable = store.load().records.single; + expect(durable.status, DurableOutboxStatus.attention); expect( - repository.calls.map((ops) => ops.map((op) => op.opId).toList()), - [ - ['op-1', 'add-${CloudLineupKind.landing}'], - ['add-${CloudLineupKind.origin}'], - ['add-${CloudLineupKind.link}'], - ], - ); - expect(store.load().records, isEmpty); - }); - - test('keep mine re-sends a link refused for a missing end as it was', - () async { - final store = MemoryDurableStrategyOutboxStore(); - LineupAddOp link(String id, {int? expectedRevision}) => LineupAddOp( - opId: 'refused-$id', - lineupPublicId: cloudLineupRowId(CloudLineupKind.link, id), - pagePublicId: 'page-1', - payload: cloudLineupPayload( - kind: CloudLineupKind.link, - data: {'id': id, 'originId': 'o', 'landingId': 'l'}, - ), - sortIndex: 0, - expectedLineupRevision: expectedRevision, - ); - // A new link, and a deleted one being restored. - final refused = [link('new'), link('restored', expectedRevision: 3)]; - for (final op in refused) { - await store.put(DurableOutboxRecord( - accountId: 'account-a', - strategyPublicId: 'strategy-1', - entityKey: EntitySyncKey.forStrategyOp(op)!, - pending: PendingOp(op: op, clientId: 'client-a'), - status: DurableOutboxStatus.attention, - createdAt: DateTime(2026), - updatedAt: DateTime(2026), - lastError: lineupLinkEndMissingMessage, - )); - } - final container = _cloudQueueContainer( - store: store, - repository: _RecordingAckRepository(), + friendlyCloudSyncError(durable.lastError!), + contains('clashes with one on another page'), ); - addTearDown(container.dispose); - final notifier = container.read(strategyOpQueueProvider.notifier) - ..setActiveStrategy('strategy-1', accountId: 'account-a'); - - await notifier.retryRejected(flushImmediately: false); - - final current = container.read(strategyOpQueueProvider); - expect(current.attentionByEntityKey, isEmpty); - for (final op in refused) { - final retried = current - .queuedByEntityKey[EntitySyncKey.forStrategyOp(op)!]!.pending.op; - expect(retried, isA()); - expect(retried.opId, isNot(op.opId)); - expect(retried.expectedRevision, op.expectedRevision); - expect(retried.payload, op.payload); - } }); - test('a link refused for a missing end stays saved and needs attention', - () async { + test( + 'a lineup group refused for overlapping another stays saved and keeps ' + 'that reason', () async { final store = MemoryDurableStrategyOutboxStore(); final container = _cloudQueueContainer( store: store, - repository: _MissingLinkEndRepository(), + repository: _FailingLineupRepository( + code: 'INVALID_LINEUP_PAYLOAD_DATA', + message: lineupOverlapMessage, + ), ); addTearDown(container.dispose); final notifier = container.read(strategyOpQueueProvider.notifier) ..setActiveStrategy('strategy-1', accountId: 'account-a'); - final link = LineupAddOp( - opId: 'add-link', - lineupPublicId: cloudLineupRowId(CloudLineupKind.link, 'k'), - pagePublicId: 'page-1', - payload: cloudLineupPayload( - kind: CloudLineupKind.link, - data: {'id': 'k', 'originId': 'deleted', 'landingId': 'l'}, - ), - sortIndex: 0, - ); - final key = EntitySyncKey.forStrategyOp(link)!; + final lineup = _lineupAdd(opId: 'add-group'); + final key = EntitySyncKey.forStrategyOp(lineup)!; - await notifier.enqueue(link, flushImmediately: false); + await notifier.enqueue(lineup, flushImmediately: false); await notifier.flushNow(); final current = container.read(strategyOpQueueProvider); - expect(current.attentionByEntityKey[key]!.pending.op.opId, 'add-link'); - expect(current.needsAttention, isTrue); - // The sync button explains the refusal, not a generic conflict. - expect(current.lastError, lineupLinkEndMissingMessage); + expect(current.attentionByEntityKey[key]!.pending.op.opId, 'add-group'); + expect(current.lastError, lineupOverlapMessage); + expect(isSpecificAttentionReason(current.lastError!), isTrue); final durable = store.load().records.single; expect(durable.status, DurableOutboxStatus.attention); - expect( - friendlyCloudSyncError(durable.lastError!), - contains('on this page in the cloud'), - ); + expect(durable.lastError, lineupOverlapMessage); + expect(friendlyCloudSyncError(durable.lastError!), + contains('shares a spot')); }); test('opening a strategy shows its saved lineup refusal', () async { final store = MemoryDurableStrategyOutboxStore(); - final link = LineupAddOp( - opId: 'refused-link', - lineupPublicId: cloudLineupRowId(CloudLineupKind.link, 'k'), - pagePublicId: 'page-1', - payload: cloudLineupPayload( - kind: CloudLineupKind.link, - data: {'id': 'k', 'originId': 'o', 'landingId': 'l'}, - ), - sortIndex: 0, - ); - await store.put(DurableOutboxRecord( - accountId: 'account-a', - strategyPublicId: 'strategy-1', - entityKey: EntitySyncKey.forStrategyOp(link)!, - pending: PendingOp(op: link, clientId: 'client-a'), + await store.put(_savedRecord( + _lineupAdd(opId: 'refused-lineup'), status: DurableOutboxStatus.attention, - createdAt: DateTime(2026), - updatedAt: DateTime(2026), - lastError: lineupLinkEndMissingMessage, + lastError: lineupPageMismatchMessage, )); final container = _cloudQueueContainer( store: store, @@ -1123,13 +1015,13 @@ void main() { notifier.setActiveStrategy('strategy-1', accountId: 'account-a'); expect( container.read(strategyOpQueueProvider).lastError, - lineupLinkEndMissingMessage, + lineupPageMismatchMessage, ); notifier.setActiveStrategy('strategy-2', accountId: 'account-a'); notifier.setActiveStrategy('strategy-1', accountId: 'account-a'); expect( container.read(strategyOpQueueProvider).lastError, - lineupLinkEndMissingMessage, + lineupPageMismatchMessage, ); }); @@ -1138,52 +1030,32 @@ void main() { final store = MemoryDurableStrategyOutboxStore(); final container = _cloudQueueContainer( store: store, - repository: _MissingLinkEndRepository(), + repository: _FailingLineupRepository(), ); addTearDown(container.dispose); final notifier = container.read(strategyOpQueueProvider.notifier) ..setActiveStrategy('strategy-1', accountId: 'account-a'); - LineupAddOp link(String name) => LineupAddOp( - opId: 'add-$name', - lineupPublicId: cloudLineupRowId(CloudLineupKind.link, 'k'), - pagePublicId: 'page-1', - payload: cloudLineupPayload( - kind: CloudLineupKind.link, - data: { - 'id': 'k', - 'originId': 'o', - 'landingId': 'l', - 'name': name, - }, - ), - sortIndex: 0, - ); - final key = EntitySyncKey.forStrategyOp(link('first'))!; + LineupAddOp lineup(String name) => + _lineupAdd(opId: 'add-$name', name: name); + final key = EntitySyncKey.forStrategyOp(lineup('first'))!; - await notifier.enqueue(link('first'), flushImmediately: false); + await notifier.enqueue(lineup('first'), flushImmediately: false); await notifier.flushNow(); await notifier.syncDesiredGenericOp( entityKey: key, - desiredOp: link('edited'), + desiredOp: lineup('edited'), ); expect(container.read(strategyOpQueueProvider).successorByEntityKey, contains(key)); await notifier.syncDesiredGenericOp( entityKey: key, - desiredOp: link('first'), + desiredOp: lineup('first'), ); final current = container.read(strategyOpQueueProvider); expect(current.successorByEntityKey, isEmpty); - expect(current.lastError, lineupLinkEndMissingMessage); - expect( - store.load().records.single.lastError, lineupLinkEndMissingMessage); - - // Keep mine still re-sends it as it was. - await notifier.retryRejected(flushImmediately: false); - final retried = container.read(strategyOpQueueProvider); - expect(retried.attentionByEntityKey, isEmpty); - expect(retried.queuedByEntityKey[key]!.pending.op, isA()); + expect(current.lastError, lineupPageMismatchMessage); + expect(store.load().records.single.lastError, lineupPageMismatchMessage); }); // A conflict, and a failed validation that is not one. @@ -1194,16 +1066,6 @@ void main() { test('a lineup refusal beside other refused work notes it ($otherReason)', () async { final store = MemoryDurableStrategyOutboxStore(); - final link = LineupAddOp( - opId: 'refused-link', - lineupPublicId: cloudLineupRowId(CloudLineupKind.link, 'k'), - pagePublicId: 'page-1', - payload: cloudLineupPayload( - kind: CloudLineupKind.link, - data: {'id': 'k', 'originId': 'o', 'landingId': 'l'}, - ), - sortIndex: 0, - ); const element = ElementPatchOp( opId: 'stale-element', elementPublicId: 'element-1', @@ -1212,17 +1074,12 @@ void main() { expectedElementRevision: 1, ); for (final (StrategyOp op, reason) in [ - (link, lineupLinkEndMissingMessage), + (_lineupAdd(opId: 'refused-lineup'), lineupPageMismatchMessage), (element, otherReason), ]) { - await store.put(DurableOutboxRecord( - accountId: 'account-a', - strategyPublicId: 'strategy-1', - entityKey: EntitySyncKey.forStrategyOp(op)!, - pending: PendingOp(op: op, clientId: 'client-a'), + await store.put(_savedRecord( + op, status: DurableOutboxStatus.attention, - createdAt: DateTime(2026), - updatedAt: DateTime(2026), lastError: reason, latestServerRevision: 2, )); @@ -1238,125 +1095,184 @@ void main() { .setActiveStrategy('strategy-1', accountId: 'account-a'); final error = container.read(strategyOpQueueProvider).lastError!; - expect(error, contains(lineupLinkEndMissingMessage)); + expect(error, contains(lineupPageMismatchMessage)); expect(error, contains(otherWorkNeedsAttentionNote)); }); } - test('a lineup refused for another page keeps that reason', () async { - final container = _cloudQueueContainer( - store: MemoryDurableStrategyOutboxStore(), - repository: _MissingLinkEndRepository( - code: 'LINEUP_PAGE_MISMATCH', - message: lineupPageMismatchMessage, - ), + test('an old-format lineup add is shown, never sent, and kept on restart', + () async { + final store = MemoryDurableStrategyOutboxStore(); + final retired = _retiredLinkAdd(); + final retiredKey = EntitySyncKey.forStrategyOp(retired)!; + await store.put(_savedRecord(_cloudElementOp())); + await store.put(_savedRecord(retired)); + var repository = _RecordingAckRepository(); + var container = _cloudQueueContainer( + store: store, + repository: repository, ); - addTearDown(container.dispose); - final notifier = container.read(strategyOpQueueProvider.notifier) + var notifier = container.read(strategyOpQueueProvider.notifier) ..setActiveStrategy('strategy-1', accountId: 'account-a'); - await notifier.enqueue( - LineupPatchOp( - opId: 'patch-origin', - lineupPublicId: cloudLineupRowId(CloudLineupKind.origin, 'o'), - pagePublicId: 'page-2', - payload: cloudLineupPayload( - kind: CloudLineupKind.origin, - data: {'id': 'o', 'agent': {}}, - ), - expectedLineupRevision: 1, - ), - flushImmediately: false, - ); + // Shown from the moment the strategy opens, before anything is sent. + var current = container.read(strategyOpQueueProvider); + expect(current.queuedByEntityKey.keys, [ + EntitySyncKey.forStrategyOp(_cloudElementOp()), + ]); + expect(current.attentionByEntityKey.keys, [retiredKey]); + expect(current.lastError, retiredLineupOpMessage); + await notifier.flushNow(); + await _settle(); - final current = container.read(strategyOpQueueProvider); + // The rest of the strategy's work lands; the old change never leaves + // the device. + expect( + repository.calls.map((ops) => ops.map((op) => op.opId).toList()), + [ + ['op-1'], + ], + ); + current = container.read(strategyOpQueueProvider); + expect(current.queuedByEntityKey, isEmpty); + expect(current.attentionByEntityKey.keys, [retiredKey]); expect(current.needsAttention, isTrue); - expect(current.lastError, lineupPageMismatchMessage); + expect(current.lastError, retiredLineupOpMessage); + expect(isSpecificAttentionReason(current.lastError!), isTrue); + expect( + friendlyCloudSyncError(current.lastError!), + contains('older version of Icarus'), + ); + // Only the copy in memory changed: the saved record is as the older + // build left it. + final durable = store.load().records.single; + expect(durable.status, DurableOutboxStatus.queued); + expect(durable.pending.op.opId, retired.opId); + expect(durable.pending.op.payload, retired.payload); + + // After a restart it is still there, still explained, still unsent. + container.dispose(); + repository = _RecordingAckRepository(); + container = _cloudQueueContainer(store: store, repository: repository); + addTearDown(container.dispose); + notifier = container.read(strategyOpQueueProvider.notifier) + ..setActiveStrategy('strategy-1', accountId: 'account-a'); + await notifier.flushNow(); + await _settle(); + + current = container.read(strategyOpQueueProvider); + expect(current.attentionByEntityKey.keys, [retiredKey]); + expect(current.lastError, retiredLineupOpMessage); + expect(repository.calls, isEmpty); + expect(store.load().records.single.pending.op.opId, retired.opId); }); - test('a lineup delete sends its link before its origin and landing', - () async { - final store = MemoryDurableStrategyOutboxStore(); - LineupDeleteOp delete(String kind, String id) => LineupDeleteOp( - opId: 'delete-$kind', - lineupPublicId: cloudLineupRowId(kind, id), - pagePublicId: 'page-1', - expectedLineupRevision: 1, - ); - // As an outbox reloads after a restart: by key, so the landing comes - // before the link. - for (final op in [ - delete(CloudLineupKind.landing, 'l'), - delete(CloudLineupKind.link, 'k'), - delete(CloudLineupKind.origin, 'o'), - ]) { + // B4: whatever state an older build left an old-format record in, it + // waits in attention from the moment the outbox loads, where the + // canvas's reconciliation never reaches it. Left queued, paused or in + // flight it would otherwise be reconciled away (or sent) by the first + // sync of its page. + for (final (status, attempts, lastError) in [ + (DurableOutboxStatus.queued, 0, null), + // Paused after transport failures, with no successor. + (DurableOutboxStatus.paused, 8, 'Connection lost while sending'), + (DurableOutboxStatus.inFlight, 1, null), + // Refused by an older build for a reason of its own. + ( + DurableOutboxStatus.attention, + 1, + "This lineup's origin or landing spot is no longer on the page", + ), + ]) { + test( + 'an old-format lineup add left ${status.name} waits in attention ' + 'from load, through a sync of its page', () async { + final store = MemoryDurableStrategyOutboxStore(); + final retired = _retiredLinkAdd(); + final retiredKey = EntitySyncKey.forStrategyOp(retired)!; await store.put(DurableOutboxRecord( accountId: 'account-a', strategyPublicId: 'strategy-1', - entityKey: EntitySyncKey.forStrategyOp(op)!, - pending: PendingOp(op: op, clientId: 'client-a'), - status: DurableOutboxStatus.queued, + entityKey: retiredKey, + pending: PendingOp( + op: retired, + clientId: 'client-a', + attempts: attempts, + lastAttemptAt: attempts == 0 ? null : DateTime(2026), + ), + status: status, createdAt: DateTime(2026), updatedAt: DateTime(2026), + lastError: lastError, )); - } - final repository = _RecordingAckRepository(); - final container = _cloudQueueContainer( - store: store, - repository: repository, - ); - addTearDown(container.dispose); - final notifier = container.read(strategyOpQueueProvider.notifier) - ..setActiveStrategy('strategy-1', accountId: 'account-a'); + final repository = _RecordingAckRepository(); + final container = _cloudQueueContainer( + store: store, + repository: repository, + ); + addTearDown(container.dispose); + final notifier = container.read(strategyOpQueueProvider.notifier) + ..setActiveStrategy('strategy-1', accountId: 'account-a'); - await notifier.flushNow(); - for (var i = 0; i < 50 && repository.calls.isEmpty; i++) { - await Future.delayed(Duration.zero); - } + var current = container.read(strategyOpQueueProvider); + expect(current.attentionByEntityKey.keys, [retiredKey]); + expect(current.queuedByEntityKey, isEmpty); + expect(current.pausedByEntityKey, isEmpty); + expect(current.inFlightByEntityKey, isEmpty); + expect(current.lastError, retiredLineupOpMessage); - expect( - repository.calls.map((ops) => ops.map((op) => op.opId).toList()), - [ - [ - 'delete-${CloudLineupKind.link}', - 'delete-${CloudLineupKind.landing}', - 'delete-${CloudLineupKind.origin}', - ], - ], - ); - expect(store.load().records, isEmpty); - }); + // The canvas syncs the page with other work, clearing what it no + // longer has. + const element = ElementAddOp( + opId: 'element-add', + elementPublicId: 'element-1', + pagePublicId: 'page-1', + payload: {'value': 'new'}, + sortIndex: 0, + ); + await notifier.syncDesiredOpsForPage( + pageId: 'page-1', + desiredOpsByEntityKey: { + EntitySyncKey.forStrategyOp(element)!: element, + }, + clearMissing: true, + ); + await notifier.flushNow(); + await _settle(); + + current = container.read(strategyOpQueueProvider); + expect(current.attentionByEntityKey.keys, [retiredKey]); + expect( + current.attentionByEntityKey[retiredKey]!.pending.op.opId, + retired.opId, + ); + expect(current.lastError, retiredLineupOpMessage); + expect( + repository.calls.expand((ops) => ops).map((op) => op.opId), + ['element-add'], + ); + // The element landed and left the outbox; the old change is still + // saved, exactly as the older build saved it. + final durable = store.load().records.single; + expect(durable.entityKey, retiredKey); + expect(durable.pending.op.opId, retired.opId); + expect(durable.pending.op.payload, retired.payload); + expect(durable.status, status); + }); + } - test('an origin delete waits for a link delete still to be sent', () async { + test('an old-format lineup delete is shown, and alone sends nothing', + () async { final store = MemoryDurableStrategyOutboxStore(); - DurableOutboxRecord record(StrategyOp op, String clientId) => - DurableOutboxRecord( - accountId: 'account-a', - strategyPublicId: 'strategy-1', - entityKey: EntitySyncKey.forStrategyOp(op)!, - pending: PendingOp(op: op, clientId: clientId), - status: DurableOutboxStatus.queued, - createdAt: DateTime(2026), - updatedAt: DateTime(2026), - ); - LineupDeleteOp delete(String kind, String id, {String? pageId}) => - LineupDeleteOp( - opId: 'delete-$kind-$id', - lineupPublicId: cloudLineupRowId(kind, id), - pagePublicId: pageId ?? 'page-1', - expectedLineupRevision: 1, - ); - // The link delete was queued by an earlier session under another - // client id, so it cannot share the origin's batch. An origin on - // another page does not wait for it. - await store.put(record(_cloudElementOp(), 'client-a')); - await store.put(record(delete(CloudLineupKind.origin, 'o'), 'client-a')); - await store.put(record( - delete(CloudLineupKind.origin, 'p2', pageId: 'page-2'), - 'client-a', - )); - await store.put(record(delete(CloudLineupKind.link, 'k'), 'client-b')); + const retired = LineupDeleteOp( + opId: 'old-origin-delete', + lineupPublicId: 'lineupOrigin:o', + pagePublicId: 'page-1', + expectedLineupRevision: 1, + ); + final retiredKey = EntitySyncKey.forStrategyOp(retired)!; + await store.put(_savedRecord(retired)); final repository = _RecordingAckRepository(); final container = _cloudQueueContainer( store: store, @@ -1367,69 +1283,89 @@ void main() { ..setActiveStrategy('strategy-1', accountId: 'account-a'); await notifier.flushNow(); - for (var i = 0; i < 50 && repository.calls.length < 2; i++) { - await Future.delayed(Duration.zero); - } + await _settle(); - expect( - repository.calls.map((ops) => ops.map((op) => op.opId).toList()), - [ - ['delete-${CloudLineupKind.link}-k'], - [ - 'op-1', - 'delete-${CloudLineupKind.origin}-o', - 'delete-${CloudLineupKind.origin}-p2', - ], - ], - ); - expect(store.load().records, isEmpty); + expect(repository.calls, isEmpty); + final current = container.read(strategyOpQueueProvider); + expect(current.queuedByEntityKey, isEmpty); + expect(current.attentionByEntityKey.keys, [retiredKey]); + expect(current.lastError, retiredLineupOpMessage); + final durable = store.load().records.single; + expect(durable.pending.op.opId, retired.opId); }); - test('an end delete refused because a lineup uses it needs attention', + test('keep mine leaves an old-format lineup change waiting; discard drops', () async { final store = MemoryDurableStrategyOutboxStore(); + final retired = _retiredLinkAdd(); + final retiredKey = EntitySyncKey.forStrategyOp(retired)!; + const element = ElementPatchOp( + opId: 'stale-element', + elementPublicId: 'element-1', + pagePublicId: 'page-1', + payload: {'value': 'mine'}, + expectedElementRevision: 1, + ); + final elementKey = EntitySyncKey.forStrategyOp(element)!; + await store.put(_savedRecord( + element, + status: DurableOutboxStatus.attention, + lastError: 'revision_mismatch', + latestServerRevision: 2, + )); + await store.put(_savedRecord(retired)); + final repository = _RecordingAckRepository(); final container = _cloudQueueContainer( store: store, - repository: _MissingLinkEndRepository( - code: 'LINEUP_END_IN_USE', - message: lineupEndInUseMessage, - ), + repository: repository, ); addTearDown(container.dispose); final notifier = container.read(strategyOpQueueProvider.notifier) ..setActiveStrategy('strategy-1', accountId: 'account-a'); - final delete = LineupDeleteOp( - opId: 'delete-origin', - lineupPublicId: cloudLineupRowId(CloudLineupKind.origin, 'o'), - pagePublicId: 'page-1', - expectedLineupRevision: 1, - ); - final key = EntitySyncKey.forStrategyOp(delete)!; - - await notifier.enqueue(delete, flushImmediately: false); await notifier.flushNow(); + await _settle(); + expect(repository.calls, isEmpty); + expect( + container.read(strategyOpQueueProvider).lastError, + '$retiredLineupOpMessage. $otherWorkNeedsAttentionNote', + ); + // Keep mine re-sends the conflict and leaves the old change, however + // often it is chosen. + await notifier.retryRejected(flushImmediately: false); var current = container.read(strategyOpQueueProvider); - expect(current.attentionByEntityKey[key]!.pending.op.opId, delete.opId); - expect(current.needsAttention, isTrue); - // The sync button explains the refusal, not a generic conflict. - expect(current.lastError, lineupEndInUseMessage); - expect(isSpecificAttentionReason(current.lastError!), isTrue); - final durable = store.load().records.single; - expect(durable.status, DurableOutboxStatus.attention); + expect(current.queuedByEntityKey.keys, [elementKey]); + expect(current.attentionByEntityKey.keys, [retiredKey]); + expect(current.lastError, retiredLineupOpMessage); + await notifier.retryRejected(flushImmediately: false); + current = container.read(strategyOpQueueProvider); + expect(current.queuedByEntityKey, isNot(contains(retiredKey))); + // Alone in attention it still says why, not that no revision matched. + expect(current.lastError, retiredLineupOpMessage); expect( - friendlyCloudSyncError(durable.lastError!), - contains('still uses this origin or landing spot'), + current.attentionByEntityKey[retiredKey]!.pending.op.opId, + retired.opId, + ); + final durable = store.load().records.singleWhere( + (record) => record.entityKey == retiredKey, + ); + expect(durable.pending.op.opId, retired.opId); + expect(durable.pending.op.payload, retired.payload); + expect( + repository.calls.expand((ops) => ops).map((op) => op.opId), + isNot(contains(retired.opId)), ); - // Keep mine asks again: the delete lands once that lineup is gone. - await notifier.retryRejected(flushImmediately: false); + final discarded = await notifier.discardRejected({retiredKey}); + expect(discarded, {retiredKey}); current = container.read(strategyOpQueueProvider); - final retried = current.queuedByEntityKey[key]!.pending.op; - expect(retried, isA()); - expect(retried.opId, isNot(delete.opId)); - expect(retried.expectedRevision, delete.expectedRevision); + expect(current.attentionByEntityKey, isEmpty); + expect(current.lastError, isNull); + expect( + store.load().records.map((record) => record.entityKey), + isNot(contains(retiredKey)), + ); }); test('an oversized op is durably parked while independent work lands', @@ -2238,20 +2174,97 @@ void main() { expect(store.values, isEmpty); }); - test('restart replays an element predecessor before its successor', + test('a replayed predecessor rebases its successor where it was applied', () async { final store = MemoryDurableStrategyOutboxStore(); - final firstRepository = _SequencedAckRepository(); - var container = _cloudQueueContainer( + final repository = _SequencedAckRepository(); + final container = _cloudQueueContainer( store: store, - repository: firstRepository, + repository: repository, ); - var notifier = container.read(strategyOpQueueProvider.notifier) + addTearDown(container.dispose); + final notifier = container.read(strategyOpQueueProvider.notifier) ..setActiveStrategy('strategy-1', accountId: 'account-a'); const key = EntitySyncKey.element('page-1', 'element-1'); await notifier.enqueue(_elementPatch( - opId: 'first-before-restart', + opId: 'first-edit', + value: 'first', + expectedRevision: 1, + )); + final firstFlush = notifier.flushNow(); + await repository.firstStarted.future; + await notifier.syncDesiredOpsForPage( + pageId: 'page-1', + desiredOpsByEntityKey: { + key: _elementPatch( + opId: 'second-edit', + value: 'second', + expectedRevision: 1, + ), + }, + ); + + // The server applied first-edit at 2, its ack was lost, and a + // teammate's edit took the row to 3 before first-edit was sent again. + // The replay is answered as a noop at the revision first-edit was + // applied at, not the row's revision now. + repository.completeFirst(const NoopOpAck( + opId: 'first-edit', + currentRevision: 2, + )); + await firstFlush; + await repository.secondStarted.future; + + final promoted = repository.calls[1].single as ElementPatchOp; + expect(promoted.payload, {'value': 'second'}); + expect(promoted.expectedElementRevision, 2); + + // So the server, its row at 3, refuses it rather than letting it + // overwrite the teammate's edit unseen. + repository.completeSecond( + promoted.expectedElementRevision == 3 + ? AppliedOpAck(opId: promoted.opId, revision: 4) + : RejectedOpAck( + opId: promoted.opId, + rejectionReason: OpRejectionReason.revisionMismatch, + current: const ElementCurrentSnapshot( + revision: 3, + value: {'value': 'teammate'}, + ), + ), + ); + await repository.secondCompleted.future; + await _settle(); + + final current = container.read(strategyOpQueueProvider); + expect(current.queuedByEntityKey, isEmpty); + expect(current.successorByEntityKey, isEmpty); + expect( + current.attentionByEntityKey[key]!.pending.op.payload, + {'value': 'second'}, + ); + final record = store.load().records.single; + expect(record.status, DurableOutboxStatus.attention); + expect(record.pending.op.opId, promoted.opId); + expect(record.lastError, OpRejectionReason.revisionMismatch.wireName); + expect(record.latestServerRevision, 3); + }); + + test('restart replays an element predecessor before its successor', + () async { + final store = MemoryDurableStrategyOutboxStore(); + final firstRepository = _SequencedAckRepository(); + var container = _cloudQueueContainer( + store: store, + repository: firstRepository, + ); + var notifier = container.read(strategyOpQueueProvider.notifier) + ..setActiveStrategy('strategy-1', accountId: 'account-a'); + const key = EntitySyncKey.element('page-1', 'element-1'); + + await notifier.enqueue(_elementPatch( + opId: 'first-before-restart', value: 'first', expectedRevision: 4, )); @@ -2730,26 +2743,22 @@ void main() { ..setActiveStrategy('strategy-1', accountId: 'account-a'); const key = EntitySyncKey.lineup('page-1', 'lineup-1'); - await notifier.enqueue(const LineupAddOp( + final successor = _lineupAdd( + opId: 'lineup-add-successor', + id: 'lineup-1', + name: 'second', + ); + + await notifier.enqueue(_lineupAdd( opId: 'lineup-add-in-flight', - lineupPublicId: 'lineup-1', - pagePublicId: 'page-1', - payload: {'value': 'first'}, - sortIndex: 0, + id: 'lineup-1', + name: 'first', )); final firstFlush = notifier.flushNow(); await repository.firstStarted.future; await notifier.syncDesiredOpsForPage( pageId: 'page-1', - desiredOpsByEntityKey: { - key: const LineupAddOp( - opId: 'lineup-add-successor', - lineupPublicId: 'lineup-1', - pagePublicId: 'page-1', - payload: {'value': 'second'}, - sortIndex: 0, - ), - }, + desiredOpsByEntityKey: {key: successor}, ); repository.completeFirst(const AppliedOpAck( @@ -2760,7 +2769,8 @@ void main() { await repository.secondStarted.future; final finalEdit = repository.calls[1].single as LineupPatchOp; - expect(finalEdit.payload, {'value': 'second'}); + expect(finalEdit.lineupPublicId, 'lineup-1'); + expect(finalEdit.payload, successor.payload); expect(finalEdit.expectedLineupRevision, 1); repository.completeSecond(AppliedOpAck( opId: finalEdit.opId, @@ -2900,12 +2910,10 @@ void main() { ..setActiveStrategy('strategy-1', accountId: 'account-a'); const key = EntitySyncKey.lineup('page-1', 'lineup-1'); - await notifier.enqueue(const LineupAddOp( + await notifier.enqueue(_lineupAdd( opId: 'lineup-add-in-flight', - lineupPublicId: 'lineup-1', - pagePublicId: 'page-1', - payload: {'value': 'first'}, - sortIndex: 0, + id: 'lineup-1', + name: 'first', )); final firstFlush = notifier.flushNow(); await repository.firstStarted.future; @@ -2913,12 +2921,10 @@ void main() { await notifier.syncDesiredOpsForPage( pageId: 'page-1', desiredOpsByEntityKey: { - key: const LineupAddOp( + key: _lineupAdd( opId: 'lineup-add-successor', - lineupPublicId: 'lineup-1', - pagePublicId: 'page-1', - payload: {'value': 'second'}, - sortIndex: 0, + id: 'lineup-1', + name: 'second', ), }, ); @@ -2957,6 +2963,469 @@ void main() { }); }); + group('keep mine after a teammate deleted the row', () { + Future<(ProviderContainer, StrategyOpQueueNotifier)> refused( + _TombstoneRepository repository, + MemoryDurableStrategyOutboxStore store, + List ops, + ) async { + final container = _cloudQueueContainer( + store: store, + repository: repository, + ); + addTearDown(container.dispose); + final notifier = container.read(strategyOpQueueProvider.notifier) + ..setActiveStrategy('strategy-1', accountId: 'account-a'); + for (final op in ops) { + await notifier.enqueue(op, flushImmediately: false); + } + await notifier.flushNow(); + await _settle(); + + final current = container.read(strategyOpQueueProvider); + expect( + current.attentionByEntityKey.keys, + unorderedEquals( + [for (final op in ops) EntitySyncKey.forStrategyOp(op)]), + ); + for (final record in store.load().records) { + expect(record.status, DurableOutboxStatus.attention); + expect(record.lastError, OpRejectionReason.deleted.wireName); + expect(record.latestServerRevision, 2); + } + return (container, notifier); + } + + test('an element edit comes back as an add over the tombstone', () async { + final store = MemoryDurableStrategyOutboxStore(); + final repository = _TombstoneRepository(); + const patch = ElementPatchOp( + opId: 'move-element', + elementPublicId: 'element-1', + pagePublicId: 'page-1', + payload: {'value': 'moved'}, + sortIndex: 4, + expectedElementRevision: 1, + ); + final key = EntitySyncKey.forStrategyOp(patch)!; + final (container, notifier) = await refused(repository, store, [patch]); + + await notifier.retryRejected(flushImmediately: false); + + final restore = + container.read(strategyOpQueueProvider).queuedByEntityKey[key]!; + expect( + restore.pending.op, + isA() + .having((op) => op.elementPublicId, 'elementPublicId', 'element-1') + .having((op) => op.pagePublicId, 'pagePublicId', 'page-1') + .having((op) => op.payload, 'payload', {'value': 'moved'}) + .having((op) => op.sortIndex, 'sortIndex', 4) + .having( + (op) => op.expectedElementRevision, + 'expectedElementRevision', + 2, + ), + ); + expect(restore.pending.op.opId, isNot(patch.opId)); + expect( + store.load().records.single.pending.op.opId, + restore.pending.op.opId, + ); + + await notifier.flushNow(); + await _settle(); + + expect(repository.restored.keys, ['element-1']); + expect(repository.restored['element-1']!.opId, restore.pending.op.opId); + final current = container.read(strategyOpQueueProvider); + expect(current.attentionByEntityKey, isEmpty); + expect(current.queuedByEntityKey, isEmpty); + expect(current.lastError, isNull); + expect(store.load().records, isEmpty); + }); + + test('a lineup edit comes back as an add over the tombstone', () async { + final store = MemoryDurableStrategyOutboxStore(); + final repository = _TombstoneRepository(); + final payload = _lineupAdd(opId: 'unused', name: 'moved').payload; + final patch = LineupPatchOp( + opId: 'move-lineup', + lineupPublicId: 'k', + pagePublicId: 'page-1', + payload: payload, + sortIndex: 3, + expectedLineupRevision: 1, + ); + final key = EntitySyncKey.forStrategyOp(patch)!; + final (container, notifier) = await refused(repository, store, [patch]); + + await notifier.retryRejected(flushImmediately: false); + + final restore = + container.read(strategyOpQueueProvider).queuedByEntityKey[key]!; + expect( + restore.pending.op, + isA() + .having((op) => op.lineupPublicId, 'lineupPublicId', 'k') + .having((op) => op.pagePublicId, 'pagePublicId', 'page-1') + .having((op) => op.payload, 'payload', payload) + .having((op) => op.sortIndex, 'sortIndex', 3) + .having( + (op) => op.expectedLineupRevision, + 'expectedLineupRevision', + 2, + ), + ); + expect(restore.pending.op.opId, isNot(patch.opId)); + + await notifier.flushNow(); + await _settle(); + + expect(repository.restored.keys, ['k']); + expect(repository.restored['k']!.opId, restore.pending.op.opId); + final current = container.read(strategyOpQueueProvider); + expect(current.attentionByEntityKey, isEmpty); + expect(current.queuedByEntityKey, isEmpty); + expect(store.load().records, isEmpty); + }); + + test('a reorder, or an edit without its place, cannot come back', () async { + final store = MemoryDurableStrategyOutboxStore(); + final repository = _TombstoneRepository(); + final ops = [ + const ElementReorderOp( + opId: 'reorder-element', + elementPublicId: 'element-1', + pagePublicId: 'page-1', + sortIndex: 2, + expectedElementRevision: 1, + ), + const LineupReorderOp( + opId: 'reorder-lineup', + lineupPublicId: 'k', + pagePublicId: 'page-1', + sortIndex: 2, + expectedLineupRevision: 1, + ), + // A patch that does not say where the element sits. + const ElementPatchOp( + opId: 'patch-no-sort', + elementPublicId: 'element-2', + pagePublicId: 'page-1', + payload: {'value': 'moved'}, + expectedElementRevision: 1, + ), + ]; + final (container, notifier) = await refused(repository, store, ops); + + await notifier.retryRejected(flushImmediately: false); + // Keep mine says why it could not help, not that a revision is missing. + expect( + container.read(strategyOpQueueProvider).lastError, + teammateDeletedCannotRestoreMessage, + ); + await notifier.flushNow(); + await _settle(); + + final current = container.read(strategyOpQueueProvider); + expect(current.queuedByEntityKey, isEmpty); + expect( + { + for (final intent in current.attentionByEntityKey.values) + intent.pending.op.opId, + }, + {for (final op in ops) op.opId}, + ); + expect(current.lastError, isNotNull); + expect(repository.calls, hasLength(1)); + expect(repository.restored, isEmpty); + final durable = store.load().records; + expect( + {for (final record in durable) record.pending.op.opId}, + {for (final op in ops) op.opId}, + ); + for (final record in durable) { + expect(record.status, DurableOutboxStatus.attention); + expect(record.lastError, OpRejectionReason.deleted.wireName); + } + }); + + test( + 'work deleted on both sides is settled, and keep mine cannot revive it', + () async { + final store = MemoryDurableStrategyOutboxStore(); + final repository = _TombstoneRepository(); + const elementPatch = ElementPatchOp( + opId: 'move-element', + elementPublicId: 'element-1', + pagePublicId: 'page-1', + payload: {'value': 'moved'}, + sortIndex: 4, + expectedElementRevision: 1, + ); + final lineupPatch = LineupPatchOp( + opId: 'move-lineup', + lineupPublicId: 'k', + pagePublicId: 'page-1', + payload: _lineupAdd(opId: 'unused', name: 'moved').payload, + sortIndex: 3, + expectedLineupRevision: 1, + ); + // Refused alongside them, and not deleted on the canvas. + const unrelatedPatch = ElementPatchOp( + opId: 'move-other', + elementPublicId: 'element-2', + pagePublicId: 'page-1', + payload: {'value': 'other'}, + sortIndex: 5, + expectedElementRevision: 1, + ); + final elementKey = EntitySyncKey.forStrategyOp(elementPatch)!; + final lineupKey = EntitySyncKey.forStrategyOp(lineupPatch)!; + final unrelatedKey = EntitySyncKey.forStrategyOp(unrelatedPatch)!; + final (container, notifier) = await refused( + repository, + store, + [elementPatch, lineupPatch, unrelatedPatch], + ); + + // The user deleted element-1 and lineup k on the canvas. + final settled = await notifier.settleAttention({elementKey, lineupKey}); + + expect(settled, {elementKey, lineupKey}); + expect( + container.read(strategyOpQueueProvider).attentionByEntityKey.keys, + [unrelatedKey], + ); + expect( + [for (final record in store.load().records) record.entityKey], + [unrelatedKey], + ); + + // Keep mine brings back only the work still in attention. + await notifier.retryRejected(flushImmediately: false); + expect( + container.read(strategyOpQueueProvider).queuedByEntityKey.keys, + [unrelatedKey], + ); + await notifier.flushNow(); + await _settle(); + expect(repository.restored.keys, ['element-2']); + expect(repository.calls, hasLength(2)); + expect( + [for (final op in repository.calls.last) op.entityPublicId], + ['element-2'], + ); + + // Settling adopts nothing from the server: a later edit to a settled + // entity is queued and sent as any other. + const restore = ElementAddOp( + opId: 'add-again', + elementPublicId: 'element-1', + pagePublicId: 'page-1', + payload: {'value': 'again'}, + sortIndex: 4, + expectedElementRevision: 2, + ); + await notifier.syncDesiredOpsForPage( + pageId: 'page-1', + desiredOpsByEntityKey: {elementKey: restore}, + clearMissing: false, + ); + expect( + container + .read(strategyOpQueueProvider) + .queuedByEntityKey[elementKey]! + .pending + .op + .payload, + {'value': 'again'}, + ); + await notifier.flushNow(); + await _settle(); + expect(repository.restored.keys, ['element-2', 'element-1']); + final current = container.read(strategyOpQueueProvider); + expect(current.attentionByEntityKey, isEmpty); + expect(current.queuedByEntityKey, isEmpty); + expect(store.load().records, isEmpty); + }); + + test( + 'work deleted on both sides stays in attention when its refusal was ' + 'not a deletion', () async { + final store = MemoryDurableStrategyOutboxStore(); + final repository = _TombstoneRepository(); + // Refused as deleted: a teammate deleted element-1. + const elementPatch = ElementPatchOp( + opId: 'move-element', + elementPublicId: 'element-1', + pagePublicId: 'page-1', + payload: {'value': 'moved'}, + sortIndex: 4, + expectedElementRevision: 1, + ); + // Refused as a revision mismatch: an add of lineup group k against a + // revision it no longer has. That says nothing about whether the + // server deleted k, never had it, or holds it elsewhere. + final staleAdd = LineupAddOp( + opId: 'stale-add', + lineupPublicId: 'k', + pagePublicId: 'page-1', + payload: _lineupAdd(opId: 'unused').payload, + sortIndex: 0, + expectedLineupRevision: 1, + ); + final elementKey = EntitySyncKey.forStrategyOp(elementPatch)!; + final lineupKey = EntitySyncKey.forStrategyOp(staleAdd)!; + final container = _cloudQueueContainer( + store: store, + repository: repository, + ); + addTearDown(container.dispose); + final notifier = container.read(strategyOpQueueProvider.notifier) + ..setActiveStrategy('strategy-1', accountId: 'account-a'); + await notifier.enqueue(elementPatch, flushImmediately: false); + await notifier.enqueue(staleAdd, flushImmediately: false); + await notifier.flushNow(); + await _settle(); + expect( + container.read(strategyOpQueueProvider).attentionByEntityKey.keys, + unorderedEquals([elementKey, lineupKey]), + ); + expect(notifier.refusedAsDeleted(elementKey), isTrue); + expect(notifier.refusedAsDeleted(lineupKey), isFalse); + + // The user deleted both on the canvas. + final settled = await notifier.settleAttention({elementKey, lineupKey}); + + // Only the work refused as deleted is dropped; the other still waits, + // in memory and on disk, for the user to choose. + expect(settled, {elementKey}); + expect( + container.read(strategyOpQueueProvider).attentionByEntityKey.keys, + [lineupKey], + ); + expect(container.read(strategyOpQueueProvider).needsAttention, isTrue); + final records = store.load().records; + expect([for (final record in records) record.entityKey], [lineupKey]); + expect(records.single.status, DurableOutboxStatus.attention); + expect(records.single.lastError, + OpRejectionReason.revisionMismatch.wireName); + }); + + test('a conditional discard drops only the work still as the user saw it', + () async { + final store = MemoryDurableStrategyOutboxStore(); + final repository = _TombstoneRepository(); + const first = ElementPatchOp( + opId: 'move-1', + elementPublicId: 'element-1', + pagePublicId: 'page-1', + payload: {'value': 'moved'}, + sortIndex: 4, + expectedElementRevision: 1, + ); + const second = ElementPatchOp( + opId: 'move-2', + elementPublicId: 'element-2', + pagePublicId: 'page-1', + payload: {'value': 'moved'}, + sortIndex: 5, + expectedElementRevision: 1, + ); + final firstKey = EntitySyncKey.forStrategyOp(first)!; + final secondKey = EntitySyncKey.forStrategyOp(second)!; + final (container, notifier) = + await refused(repository, store, [first, second]); + // What the user chose to discard: both refused edits, nothing behind. + final seen = { + firstKey: ('move-1', null), + secondKey: ('move-2', null), + }; + + // Then the user edits element-2 again; it waits behind the refusal. + await notifier.syncDesiredOpsForPage( + pageId: 'page-1', + desiredOpsByEntityKey: { + secondKey: const ElementPatchOp( + opId: 'newer', + elementPublicId: 'element-2', + pagePublicId: 'page-1', + payload: {'value': 'newer'}, + sortIndex: 5, + expectedElementRevision: 1, + ), + }, + clearMissing: false, + ); + expect( + container + .read(strategyOpQueueProvider) + .successorByEntityKey[secondKey]! + .pending + .op + .opId, + 'newer', + ); + + final discarded = + await notifier.discardRejected({firstKey, secondKey}, onlyIf: seen); + + // element-1's work is as seen, so it goes; element-2's changed, so it + // stays, the newer edit with it, in memory and on disk. + expect(discarded, {firstKey}); + final current = container.read(strategyOpQueueProvider); + expect(current.attentionByEntityKey.keys, [secondKey]); + expect(current.successorByEntityKey[secondKey]!.pending.op.opId, 'newer'); + final records = store.load().records; + expect([for (final record in records) record.entityKey], [secondKey]); + expect(records.single.pending.op.opId, 'move-2'); + expect(records.single.successorPending!.op.opId, 'newer'); + }); + + test('discarding instead waits for the server copy to be adopted', + () async { + // The contrast that makes settling distinct: after Use cloud the + // canvas is about to be redrawn from the server, so desired work for + // the entity is ignored until adoption completes. + final store = MemoryDurableStrategyOutboxStore(); + final repository = _TombstoneRepository(); + const elementPatch = ElementPatchOp( + opId: 'move-element', + elementPublicId: 'element-1', + pagePublicId: 'page-1', + payload: {'value': 'moved'}, + sortIndex: 4, + expectedElementRevision: 1, + ); + final key = EntitySyncKey.forStrategyOp(elementPatch)!; + final (container, notifier) = + await refused(repository, store, [elementPatch]); + + await notifier.discardRejected({key}); + await notifier.syncDesiredOpsForPage( + pageId: 'page-1', + desiredOpsByEntityKey: { + key: const ElementAddOp( + opId: 'add-again', + elementPublicId: 'element-1', + pagePublicId: 'page-1', + payload: {'value': 'again'}, + sortIndex: 4, + expectedElementRevision: 2, + ), + }, + clearMissing: false, + ); + + expect( + container.read(strategyOpQueueProvider).queuedByEntityKey, + isEmpty, + ); + }); + }); + group('a server that needs a newer Icarus', () { const key = EntitySyncKey.element('page-1', 'element-1'); @@ -3182,6 +3651,69 @@ ElementPatchOp _cloudElementOp() { ); } +/// An add of lineup [id] as one row, the shape this build sends. +LineupAddOp _lineupAdd({ + required String opId, + String id = 'k', + String pageId = 'page-1', + String name = 'lineup', +}) { + return LineupAddOp( + opId: opId, + lineupPublicId: id, + pagePublicId: pageId, + payload: cloudLineupsPayload({ + 'id': id, + 'origins': [ + {'id': 'o', 'agent': {}}, + ], + 'landings': [ + {'id': 'l', 'ability': {}}, + ], + 'links': [ + {'id': id, 'originId': 'o', 'landingId': 'l', 'name': name}, + ], + }), + sortIndex: 0, + ); +} + +/// A link add as builds before one row per lineup wrote it to their outbox: +/// its own row, keyed `lineupLink:`, naming its origin and landing. +LineupAddOp _retiredLinkAdd() { + return const LineupAddOp( + opId: 'old-link-add', + lineupPublicId: 'lineupLink:k', + pagePublicId: 'page-1', + payload: { + 'kind': 'lineupLink', + 'payloadVersion': 1, + 'data': {'id': 'k', 'originId': 'o', 'landingId': 'l'}, + }, + sortIndex: 0, + ); +} + +/// [op] as saved in the durable outbox of account-a's strategy-1. +DurableOutboxRecord _savedRecord( + StrategyOp op, { + DurableOutboxStatus status = DurableOutboxStatus.queued, + String? lastError, + int? latestServerRevision, +}) { + return DurableOutboxRecord( + accountId: 'account-a', + strategyPublicId: 'strategy-1', + entityKey: EntitySyncKey.forStrategyOp(op)!, + pending: PendingOp(op: op, clientId: 'client-a'), + status: status, + createdAt: DateTime(2026), + updatedAt: DateTime(2026), + lastError: lastError, + latestServerRevision: latestServerRevision, + ); +} + PagePatchOp _pageSideOp({ required String opId, required bool isAttack, @@ -3305,12 +3837,12 @@ class _RecordingAckRepository extends ConvexStrategyRepository { } } -/// Refuses every op as the server refuses a link whose origin or landing is -/// gone, or with another lineup refusal. -class _MissingLinkEndRepository extends ConvexStrategyRepository { - _MissingLinkEndRepository({ - this.code = 'LINEUP_LINK_END_MISSING', - this.message = lineupLinkEndMissingMessage, +/// Refuses every op as the server refuses a lineup whose row lives on +/// another page. +class _FailingLineupRepository extends ConvexStrategyRepository { + _FailingLineupRepository({ + this.code = 'LINEUP_PAGE_MISMATCH', + this.message = lineupPageMismatchMessage, }) : super(IcarusConvexApi(_UnusedTransport())); final String code; @@ -3335,6 +3867,50 @@ class _MissingLinkEndRepository extends ConvexStrategyRepository { } } +/// A server on which a teammate deleted elements element-1 and element-2 and +/// lineup k, each tombstone at revision 2. A patch or reorder of a deleted +/// row is refused as deleted; an add expecting the tombstone's revision +/// brings the row back. +class _TombstoneRepository extends ConvexStrategyRepository { + _TombstoneRepository() : super(IcarusConvexApi(_UnusedTransport())); + + final List> calls = []; + final _deleted = {'element-1', 'element-2', 'k'}; + + /// The add that restored each row, by its id. + final Map restored = {}; + + @override + Future> applyBatch({ + required String strategyPublicId, + required String clientId, + required List ops, + String? accountSubject, + }) async { + calls.add(List.from(ops)); + return [for (final op in ops) _apply(op)]; + } + + OpAck _apply(StrategyOp op) { + final id = op.entityPublicId!; + if (!_deleted.contains(id)) return AppliedOpAck(opId: op.opId, revision: 2); + if (op.kind == StrategyOpKind.add && op.expectedRevision == 2) { + _deleted.remove(id); + restored[id] = op; + return AppliedOpAck(opId: op.opId, revision: 3); + } + return RejectedOpAck( + opId: op.opId, + rejectionReason: op.kind == StrategyOpKind.add + ? OpRejectionReason.revisionMismatch + : OpRejectionReason.deleted, + current: op.entityType == StrategyOpEntityType.lineup + ? const LineupCurrentSnapshot(revision: 2, value: {}) + : const ElementCurrentSnapshot(revision: 2, value: {}), + ); + } +} + class _SequencedAckRepository extends ConvexStrategyRepository { _SequencedAckRepository() : super(IcarusConvexApi(_UnusedTransport())); diff --git a/test/strategy_page_session_provider_test.dart b/test/strategy_page_session_provider_test.dart index 4411014e..484da0f6 100644 --- a/test/strategy_page_session_provider_test.dart +++ b/test/strategy_page_session_provider_test.dart @@ -3,10 +3,12 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:hive_ce/hive.dart'; import 'package:icarus/collab/cloud_lineup_rows.dart'; +import 'package:icarus/collab/canonical_json.dart'; import 'package:icarus/collab/cloud_media_models.dart'; import 'package:icarus/collab/collab_models.dart'; import 'package:icarus/collab/convex_strategy_repository.dart'; @@ -39,6 +41,7 @@ import 'package:icarus/providers/collab/active_page_live_sync_models.dart'; import 'package:icarus/providers/collab/active_page_live_sync_provider.dart'; import 'package:icarus/providers/collab/cloud_collab_provider.dart'; import 'package:icarus/providers/collab/cloud_media_upload_queue_provider.dart'; +import 'package:icarus/providers/collab/lineup_conflicts_provider.dart'; import 'package:icarus/providers/collab/remote_strategy_snapshot_provider.dart'; import 'package:icarus/providers/collab/strategy_conflict_provider.dart'; import 'package:icarus/providers/collab/strategy_op_queue_provider.dart'; @@ -54,6 +57,8 @@ import 'package:icarus/providers/text_provider.dart'; import 'package:icarus/providers/transition_provider.dart' hide PageTransitionState; import 'package:icarus/providers/user_preferences_provider.dart'; +import 'package:icarus/strategy/lineup_group_changes.dart'; +import 'package:icarus/strategy/strategy_import_export.dart'; import 'package:icarus/strategy/strategy_page_models.dart'; import 'package:supabase_flutter/supabase_flutter.dart' show User; @@ -86,9 +91,13 @@ class _FakeRemoteEditorNotifier extends RemoteEditorSnapshotNotifier { state = AsyncData(snapshot); } + /// Runs as each page is asked for, before it is read. + void Function(String? pagePublicId)? onSetActivePage; + @override Future setActivePage(String? pagePublicId) async { selectedPageIds.add(pagePublicId); + onSetActivePage?.call(pagePublicId); if (pagePublicId == failingPageId) { throw StateError('Failed to load $pagePublicId'); } @@ -101,10 +110,28 @@ class _FakeRemoteEditorNotifier extends RemoteEditorSnapshotNotifier { return page; } + /// While set, a refresh reads nothing, as a read refused or cut off. + bool readFails = false; + + /// While set, a refresh reads nothing when this holds for its count. + bool Function(int refreshCount)? readFailsWhen; + + /// While set, the next refresh waits for it, then reads [initialSnapshot] + /// as it is by then: a read still on its way. + Completer? refreshGate; + + /// While set, only a refresh made while this holds takes [refreshGate]. + bool Function()? gateWhen; + @override Future refresh() async { refreshCount += 1; - state = AsyncData(initialSnapshot); + final count = refreshCount; + final gate = (gateWhen?.call() ?? true) ? refreshGate : null; + if (gate != null) refreshGate = null; + await gate?.future; + final fails = readFails || (readFailsWhen?.call(count) ?? false); + state = fails ? const AsyncData(null) : AsyncData(initialSnapshot); } @override @@ -159,10 +186,7 @@ class _FakeStrategyOpQueueNotifier extends StrategyOpQueueNotifier { ); if (desiredOp != null && state.attentionByEntityKey.containsKey(entityKey)) { - successors[entityKey] = QueuedEntityIntent( - entityKey: entityKey, - pending: PendingOp(op: desiredOp, clientId: 'test-client'), - ); + _keepBehindRefusal(successors, entityKey, desiredOp); state = state.copyWith(successorByEntityKey: successors); return; } @@ -200,10 +224,7 @@ class _FakeStrategyOpQueueNotifier extends StrategyOpQueueNotifier { } for (final entry in desiredOpsByEntityKey.entries) { if (state.attentionByEntityKey.containsKey(entry.key)) { - successors[entry.key] = QueuedEntityIntent( - entityKey: entry.key, - pending: PendingOp(op: entry.value, clientId: 'test-client'), - ); + _keepBehindRefusal(successors, entry.key, entry.value); continue; } queued[entry.key] = QueuedEntityIntent( @@ -217,6 +238,34 @@ class _FakeStrategyOpQueueNotifier extends StrategyOpQueueNotifier { ); } + /// Like the real queue, keeps [desired] behind [key]'s refused op: work + /// the same as the refused op needs nothing behind it, and work the same + /// as the one already behind it leaves that one, op id and all. + void _keepBehindRefusal( + Map successors, + EntitySyncKey key, + StrategyOp desired, + ) { + bool same(StrategyOp left, StrategyOp right) => + left.kind == right.kind && + left.entityType == right.entityType && + left.entityPublicId == right.entityPublicId && + left.pagePublicId == right.pagePublicId && + cloudJsonEquivalent(left.payload, right.payload) && + left.sortIndex == right.sortIndex && + left.expectedRevision == right.expectedRevision; + if (same(state.attentionByEntityKey[key]!.pending.op, desired)) { + successors.remove(key); + return; + } + final behind = successors[key]?.pending.op; + if (behind != null && same(behind, desired)) return; + successors[key] = QueuedEntityIntent( + entityKey: key, + pending: PendingOp(op: desired, clientId: 'test-client'), + ); + } + @override Future flushNow() async { flushNowCount += 1; @@ -244,10 +293,46 @@ class _FakeStrategyOpQueueNotifier extends StrategyOpQueueNotifier { ); } + /// Takes the server's [acks] for the ops [sent], as the real queue does, + /// in one update: an op the server took leaves the queue, a refused one + /// waits in attention, and one it never answered (its send failed) stays + /// queued. + void answer(Map sent, List acks) { + final ackByOpId = {for (final ack in acks) ack.opId: ack}; + final queued = Map.from( + state.queuedByEntityKey, + ); + final attention = Map.from( + state.attentionByEntityKey, + ); + final answered = []; + for (final MapEntry(:key, value: op) in sent.entries) { + final ack = ackByOpId[op.opId]; + if (ack == null) continue; + if (queued[key]?.pending.op.opId == op.opId) queued.remove(key); + if (!ack.isAck) { + attention[key] = QueuedEntityIntent( + entityKey: key, + pending: PendingOp(op: op, clientId: 'test-client'), + ); + } + answered.add(AckedEntityIntent(entityKey: key, op: op, ack: ack)); + } + state = state.copyWith( + queuedByEntityKey: queued, + attentionByEntityKey: attention, + lastError: attention.isEmpty ? null : 'Some saved work needs attention.', + clearError: attention.isEmpty, + lastAcks: [for (final acked in answered) acked.ack], + lastAckBatch: answered, + ); + } + @override Future> discardRejected( - Set entityKeys, - ) async { + Set entityKeys, { + Map? onlyIf, + }) async { if (failDiscard) return {}; final attention = Map.from( state.attentionByEntityKey, @@ -255,7 +340,16 @@ class _FakeStrategyOpQueueNotifier extends StrategyOpQueueNotifier { final successors = Map.from( state.successorByEntityKey, ); - final discarded = attention.keys.toSet().intersection(entityKeys); + final discarded = { + for (final key in attention.keys.toSet().intersection(entityKeys)) + if (onlyIf == null || + onlyIf[key] == + ( + attention[key]!.pending.op.opId, + successors[key]?.pending.op.opId, + )) + key, + }; for (final key in discarded) { attention.remove(key); successors.remove(key); @@ -363,6 +457,42 @@ class _FakeStrategyOpQueueNotifier extends StrategyOpQueueNotifier { } } +/// An outbox whose writes fail while [failPut] holds for the record, as a +/// full or locked disk. +class _FailingOutboxStore extends MemoryDurableStrategyOutboxStore { + bool Function(DurableOutboxRecord record)? failPut; + + /// Runs as each write starts, before it lands: while it is on its way. + void Function(DurableOutboxRecord record)? onPut; + + @override + Future put(DurableOutboxRecord record) async { + onPut?.call(record); + // A real write leaves the event loop; so does this one. + await Future.delayed(Duration.zero); + if (failPut?.call(record) ?? false) { + throw const FileSystemException('The disk is full.'); + } + await super.put(record); + } + + /// While set, a removal fails when this holds for its storage key. + bool Function(String storageKey)? failRemove; + + /// Runs as each removal starts, before it lands. + void Function(String storageKey)? onRemove; + + @override + Future remove(String storageKey) async { + onRemove?.call(storageKey); + await Future.delayed(Duration.zero); + if (failRemove?.call(storageKey) ?? false) { + throw const FileSystemException('The disk is locked.'); + } + await super.remove(storageKey); + } +} + /// Plays the server's page restore: [onRestore] runs for each call, and /// may throw as the server would. class _RestoringRepository implements ConvexStrategyRepository { @@ -453,11 +583,71 @@ class _RecordingMediaQueue extends CloudMediaUploadQueueNotifier { } } +/// Whether this device can reach the server, for tests that go offline. +final _online = StateProvider((ref) => true); + Future _settle() async { await Future.delayed(Duration.zero); await Future.delayed(Duration.zero); } +/// Waits, in real time, until [condition] holds. +Future _until(bool Function() condition) async { + final deadline = DateTime.now().add(const Duration(seconds: 5)); + while (!condition()) { + if (DateTime.now().isAfter(deadline)) { + throw TimeoutException('The condition never held.'); + } + await Future.delayed(const Duration(milliseconds: 10)); + } +} + +/// Plays the server for the real queue: [server] answers every batch, and +/// [afterBatch] runs once it has, before the answers reach the queue (as +/// the live read showing the batch can arrive before its answers). +class _ServerRepository implements ConvexStrategyRepository { + _ServerRepository(this.server, {required this.afterBatch}); + + final _FakeServer server; + final void Function() afterBatch; + final List> batches = []; + + /// While set, a batch waits for it before it reaches the server. + Completer? hold; + + /// While set, the next batch reaches the server, then this runs and the + /// answer is lost on its way back: the send fails as if offline. + void Function()? loseNextAnswer; + + /// While set, an op it answers for never reaches [server]; that answer + /// is returned instead, as a validation the server fails. + OpAck? Function(StrategyOp op)? refuse; + + @override + Future> applyBatch({ + required String strategyPublicId, + required String clientId, + required List ops, + String? accountSubject, + }) async { + batches.add(ops); + await hold?.future; + final acks = [ + for (final op in ops) refuse?.call(op) ?? server.apply(op), + ]; + if (loseNextAnswer case final lose?) { + loseNextAnswer = null; + lose(); + throw const SocketException('The answer was lost.'); + } + afterBatch(); + return acks; + } + + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + RemotePage _page(String id, int index, {int revision = 1, String? name, bool isAttack = true}) { final now = DateTime.utc(2026); @@ -535,11 +725,15 @@ Map _agentJson(String id, Offset position) => { 'lineUpID': id, }; -Map _abilityJson(String id) => { +Map _abilityJson( + String id, [ + Offset position = const Offset(30, 40), +]) => + { 'id': 'ability-$id', 'isDeleted': false, 'data': {'type': 'sova', 'index': 2.0}, - 'position': {'dx': 30, 'dy': 40}, + 'position': {'dx': position.dx, 'dy': position.dy}, 'isAlly': true, 'rotation': 0, 'length': 0, @@ -553,27 +747,71 @@ Map _abilityJson(String id) => { 'armLengthsMeters': [10, 10, 10, 10], }; -RemoteLineup _lineupRow( +/// Origin [id] as a lineup group row carries it. +Map _originJson( + String id, [ + Offset position = const Offset(10, 20), +]) => + {'id': id, 'agent': _agentJson(id, position)}; + +/// Landing [id] as a lineup group row carries it. +Map _landingJson( + String id, [ + Offset position = const Offset(30, 40), +]) => + {'id': id, 'ability': _abilityJson(id, position)}; + +/// Lineup [id], from origin [originId] to landing [landingId], as a lineup +/// group row carries it. +Map _linkJson( + String id, { + required String originId, + required String landingId, + String name = '', + String notes = 'remote lineup', +}) => + { + 'id': id, + 'originId': originId, + 'landingId': landingId, + 'name': name, + 'youtubeLink': '', + 'notes': notes, + 'images': [], + }; + +/// One lineup group as the server stores it: the row [id], holding the +/// group's [origins], [landings] and [links]. +RemoteLineup _groupRow( String pageId, - String kind, - Map data, { + String id, { + required List> origins, + required List> landings, + required List> links, int revision = 1, int sortIndex = 0, + bool deleted = false, }) { return RemoteLineup( - publicId: cloudLineupRowId(kind, data['id'] as String), + publicId: id, strategyPublicId: 'cloud-strategy', pagePublicId: pageId, - payload: cloudLineupPayload(kind: kind, data: data), + payload: cloudLineupsPayload({ + 'id': id, + 'origins': origins, + 'landings': landings, + 'links': links, + }), sortIndex: sortIndex, revision: revision, - deleted: false, + deleted: deleted, ); } -/// One whole lineup as the server stores it: the origin [id], the landing -/// `landing-[id]` and the link `link-[id]` between them. -List _lineupRows( +/// A lineup on spots of its own, alone in its group: the link `link-[id]` +/// from the origin [id] to the landing `landing-[id]`, in the group named +/// after it. +RemoteLineup _lineup( String pageId, String id, { Offset agentPosition = const Offset(10, 20), @@ -581,51 +819,394 @@ List _lineupRows( int revision = 1, int sortIndex = 0, }) { - final landingId = 'landing-$id'; - return [ - _lineupRow( - pageId, - CloudLineupKind.origin, - {'id': id, 'agent': _agentJson(id, agentPosition)}, - revision: revision, - sortIndex: sortIndex, - ), - _lineupRow( - pageId, - CloudLineupKind.landing, - {'id': landingId, 'ability': _abilityJson(landingId)}, - revision: revision, - sortIndex: sortIndex + 1, - ), - _lineupRow( - pageId, - CloudLineupKind.link, - { - 'id': 'link-$id', - 'originId': id, - 'landingId': landingId, - 'name': linkName, - 'youtubeLink': '', - 'notes': 'remote lineup', - 'images': [], - }, - revision: revision, - sortIndex: sortIndex + 2, - ), - ]; + return _groupRow( + pageId, + 'link-$id', + origins: [_originJson(id, agentPosition)], + landings: [_landingJson('landing-$id')], + links: [ + _linkJson('link-$id', + originId: id, landingId: 'landing-$id', name: linkName), + ], + revision: revision, + sortIndex: sortIndex, + ); +} + +/// The key of the group row [_lineup] builds for [id]. +EntitySyncKey _lineupKey(String pageId, String id) => + EntitySyncKey.lineup(pageId, 'link-$id'); + +/// The entries of lineup group [data] under [field] (`origins`, +/// `landings` or `links`), to read or to edit in place. +List _entries(Map data, String field) => + [for (final entry in data[field] as List) entry as Map]; + +/// Entry [id] of lineup group [data] under [field]. +Map _entry(Map data, String field, String id) => + _entries(data, field).singleWhere((entry) => entry['id'] == id); + +/// [edit] applied to every lineup in a group's data. +void Function(Map data) _eachLink( + void Function(Map link) edit, +) => + (data) => _entries(data, 'links').forEach(edit); + +/// [edit] applied to every origin's agent in a group's data. +void Function(Map data) _eachAgent( + void Function(Map agent) edit, +) => + (data) => [ + for (final origin in _entries(data, 'origins')) + origin['agent'] as Map, + ].forEach(edit); + +/// [edit] applied to every landing's ability in a group's data. +void Function(Map data) _eachAbility( + void Function(Map ability) edit, +) => + (data) => [ + for (final landing in _entries(data, 'landings')) + landing['ability'] as Map, + ].forEach(edit); + +/// Lineup [id] in the group [payload] carries. +Map _linkIn(CloudPayload? payload, String id) => + _entry(cloudPayloadData(payload!), 'links', id); + +/// The one lineup in the group [payload] carries. +Map _onlyLinkIn(CloudPayload? payload) => + _entries(cloudPayloadData(payload!), 'links').single; + +/// [row] as a teammate left it: its group data changed by [edit], one +/// revision on. +RemoteLineup _editedGroup( + RemoteLineup row, + void Function(Map data) edit, { + bool deleted = false, +}) { + final payload = jsonDecode(jsonEncode(row.payload)) as CloudPayload; + edit(payload['data'] as Map); + return RemoteLineup( + publicId: row.publicId, + strategyPublicId: row.strategyPublicId, + pagePublicId: row.pagePublicId, + payload: payload, + sortIndex: row.sortIndex, + revision: row.revision + 1, + deleted: deleted, + ); } -EntitySyncKey _originKey(String pageId, String id) => - EntitySyncKey.lineup(pageId, cloudLineupRowId(CloudLineupKind.origin, id)); +/// [row] as a teammate left it: its one lineup changed by [edit], one +/// revision on. +RemoteLineup _editedLineup(RemoteLineup row, void Function(Map link) edit) => + _editedGroup(row, (data) => edit(_entries(data, 'links').single)); + +/// What each of [rows] holds, by group id: its origin, landing and lineup +/// ids, in order. +Map>> _groupsOf( + Iterable rows) => + { + for (final row in rows) + row.publicId: { + for (final field in ['origins', 'landings', 'links']) + field: [ + for (final entry + in _entries(cloudPayloadData(row.payload), field)) + entry['id'], + ], + }, + }; + +/// Plays the server's element and lineup rows of one page as convex/ops.ts +/// keeps them (applyElementOp, applyLineupOp). +/// +/// Every row has its own revision, which each change it takes moves on by +/// one. A delete leaves a tombstone: still listed, deleted, one revision on. +/// A write expecting another revision than the row's is refused with the +/// row as it is. A patch or reorder of a tombstone is refused as `deleted`; +/// an add expecting the tombstone's revision brings the row back. A write +/// that would change nothing is a noop, whatever revision it expected. An op +/// sent again (its answer lost) is answered as a noop at the revision it +/// landed at, or refused again. While [recordsRevisions] is off, an op taken +/// is recorded with no revision (as events written before the server kept +/// one), and sent again it is answered as a noop with none. +class _FakeServer { + _FakeServer( + this.pageId, { + Iterable lineups = const [], + Iterable elements = const [], + }) { + for (final row in lineups) { + _lineups[row.publicId] = _Row.lineup(row); + } + for (final row in elements) { + _elements[row.publicId] = _Row.element(row); + } + } + + final String pageId; + final Map _lineups = {}; + final Map _elements = {}; + + /// The answer to each element and lineup op taken, by op id. + final Map _answers = {}; + + /// Whether an op taken is recorded with the revision it landed at. + bool recordsRevisions = true; + + /// Ops taken while [recordsRevisions] was off. + final Set _unrecorded = {}; + + /// Every lineup op this server answered, in order. + final List received = []; + + /// Every lineup row, tombstones included, in stored order. + List get rows => [ + for (final MapEntry(:key, :value) in _sorted(_lineups)) + RemoteLineup( + publicId: key, + strategyPublicId: 'cloud-strategy', + pagePublicId: pageId, + payload: value.payload, + sortIndex: value.sortIndex, + revision: value.revision, + deleted: value.deleted, + ), + ]; + + /// The lineup rows lineups are drawn from. + List get liveRows => [ + for (final row in rows) + if (!row.deleted) row, + ]; + + RemoteLineup row(String id) => rows.singleWhere((row) => row.publicId == id); + + /// Every element row, tombstones included, in stored order. + List get elements => [ + for (final MapEntry(:key, :value) in _sorted(_elements)) + RemoteElement( + publicId: key, + strategyPublicId: 'cloud-strategy', + pagePublicId: pageId, + elementType: value.elementType!, + payload: value.payload, + sortIndex: value.sortIndex, + revision: value.revision, + deleted: value.deleted, + ), + ]; + + RemoteElement element(String id) => + elements.singleWhere((element) => element.publicId == id); -/// Every row key of the lineup [_lineupRows] builds for [id]. -Set _lineupRowKeys(String pageId, String id) => { - _originKey(pageId, id), - EntitySyncKey.lineup( - pageId, cloudLineupRowId(CloudLineupKind.landing, 'landing-$id')), - EntitySyncKey.lineup( - pageId, cloudLineupRowId(CloudLineupKind.link, 'link-$id')), + /// The server's answer to each of [ops], applied in order. An op on + /// anything but an element or a lineup is applied as sent. + List applyBatch(Iterable ops) => + [for (final op in ops) apply(op)]; + + OpAck apply(StrategyOp op) { + final (rows, change) = switch (op) { + LineupAddOp(:final payload, :final sortIndex) => ( + _lineups, + (kind: StrategyOpKind.add, payload: payload, sortIndex: sortIndex), + ), + LineupPatchOp(:final payload, :final sortIndex) => ( + _lineups, + (kind: StrategyOpKind.patch, payload: payload, sortIndex: sortIndex), + ), + LineupReorderOp(:final sortIndex) => ( + _lineups, + (kind: StrategyOpKind.reorder, payload: null, sortIndex: sortIndex), + ), + LineupDeleteOp() => ( + _lineups, + (kind: StrategyOpKind.delete, payload: null, sortIndex: null), + ), + ElementAddOp(:final payload, :final sortIndex) => ( + _elements, + (kind: StrategyOpKind.add, payload: payload, sortIndex: sortIndex), + ), + ElementPatchOp(:final payload, :final sortIndex) => ( + _elements, + (kind: StrategyOpKind.patch, payload: payload, sortIndex: sortIndex), + ), + ElementReorderOp(:final sortIndex) => ( + _elements, + (kind: StrategyOpKind.reorder, payload: null, sortIndex: sortIndex), + ), + ElementDeleteOp() => ( + _elements, + (kind: StrategyOpKind.delete, payload: null, sortIndex: null), + ), + _ => (null, null), }; + if (rows == null || change == null) { + return AppliedOpAck( + opId: op.opId, + revision: (op.expectedRevision ?? 0) + 1, + ); + } + if (identical(rows, _lineups)) received.add(op); + final id = op.entityPublicId!; + final existing = rows[id]; + OpAck refused(OpRejectionReason reason) => RejectedOpAck( + opId: op.opId, + rejectionReason: reason, + current: existing == null + ? null + : identical(rows, _lineups) + ? LineupCurrentSnapshot( + revision: existing.revision, + value: existing.payload, + ) + : ElementCurrentSnapshot( + revision: existing.revision, + value: existing.payload, + ), + ); + OpAck? stale() => op.expectedRevision == null + ? refused(OpRejectionReason.missingExpectedRevision) + : op.expectedRevision != existing!.revision + ? refused(OpRejectionReason.revisionMismatch) + : null; + OpAck store(CloudPayload payload, int sortIndex, {bool deleted = false}) { + final revision = (existing?.revision ?? 0) + 1; + rows[id] = _Row( + payload: payload, + sortIndex: sortIndex, + revision: revision, + deleted: deleted, + elementType: identical(rows, _lineups) + ? null + : existing?.elementType ?? payload['kind'] as String, + ); + return AppliedOpAck(opId: op.opId, revision: revision); + } + + OpAck noop() => + NoopOpAck(opId: op.opId, currentRevision: existing?.revision); + + // An op already answered is answered again as it was: an accepted one + // as a noop at the revision it landed at, not the row's latest. + switch (_answers[op.opId]) { + case RejectedOpAck(:final rejectionReason): + return refused(rejectionReason); + case final OpAck accepted?: + return NoopOpAck( + opId: op.opId, + currentRevision: + _unrecorded.contains(op.opId) ? null : accepted.appliedRevision, + ); + case null: + break; + } + + OpAck answer() { + switch (change.kind) { + case StrategyOpKind.add: + final payload = change.payload!; + final sortIndex = change.sortIndex!; + if (existing == null) return store(payload, sortIndex); + if (existing.deleted) return stale() ?? store(payload, sortIndex); + return _sameJson(existing.payload, payload) + ? noop() + : refused(OpRejectionReason.alreadyExists); + case StrategyOpKind.delete: + if (existing == null || existing.deleted) return noop(); + return stale() ?? + store(existing.payload, existing.sortIndex, deleted: true); + case StrategyOpKind.patch || StrategyOpKind.reorder: + if (existing == null) return refused(OpRejectionReason.notFound); + if (existing.deleted) return refused(OpRejectionReason.deleted); + final payload = change.payload ?? existing.payload; + final sortIndex = change.sortIndex ?? existing.sortIndex; + if (_sameJson(payload, existing.payload) && + sortIndex == existing.sortIndex) { + return noop(); + } + return stale() ?? store(payload, sortIndex); + } + } + + if (!recordsRevisions) _unrecorded.add(op.opId); + return _answers[op.opId] = answer(); + } + + /// A teammate's change to lineup group row [id] lands: [edit] changes its + /// data, one revision on. + void teammateEdit(String id, void Function(Map data) edit) { + final row = _lineups[id]!; + final payload = jsonDecode(jsonEncode(row.payload)) as CloudPayload; + edit(payload['data'] as Map); + if (_sameJson(payload, row.payload)) return; + _lineups[id] = row.next(payload: payload); + } + + /// A teammate's delete of lineup group row [id] lands. + void teammateDelete(String id) => + _lineups[id] = _lineups[id]!.next(deleted: true); + + /// A teammate's delete of element row [id] lands. + void teammateDeleteElement(String id) => + _elements[id] = _elements[id]!.next(deleted: true); + + static Iterable> _sorted(Map rows) => + rows.entries.toList() + ..sort((a, b) => a.value.sortIndex != b.value.sortIndex + ? a.value.sortIndex.compareTo(b.value.sortIndex) + : a.key.compareTo(b.key)); + + static bool _sameJson(Object? left, Object? right) => + canonicalCloudJsonEncode(jsonDecode(jsonEncode(left))) == + canonicalCloudJsonEncode(jsonDecode(jsonEncode(right))); +} + +/// One row as [_FakeServer] stores it. +class _Row { + _Row({ + required CloudPayload payload, + required this.sortIndex, + required this.revision, + required this.deleted, + this.elementType, + }) : payload = jsonDecode(jsonEncode(payload)) as CloudPayload; + + _Row.lineup(RemoteLineup row) + : this( + payload: row.payload, + sortIndex: row.sortIndex, + revision: row.revision, + deleted: row.deleted, + ); + + _Row.element(RemoteElement row) + : this( + payload: row.payload, + sortIndex: row.sortIndex, + revision: row.revision, + deleted: row.deleted, + elementType: row.elementType, + ); + + final CloudPayload payload; + final int sortIndex; + final int revision; + final bool deleted; + final String? elementType; + + /// This row one revision on, as a teammate's write leaves it. + _Row next({CloudPayload? payload, bool? deleted}) => _Row( + payload: payload ?? this.payload, + sortIndex: sortIndex, + revision: revision + 1, + deleted: deleted ?? this.deleted, + elementType: elementType, + ); +} + RemoteEditorSnapshot _editorSnapshot({ required List pages, required RemotePageSnapshot activePage, @@ -881,10 +1462,10 @@ void main() { ); }); - QueuedEntityIntent refusedOnPage2() => QueuedEntityIntent( - entityKey: const EntitySyncKey.element('page-2', 'text-2'), + QueuedEntityIntent refusedOnPage2() => const QueuedEntityIntent( + entityKey: EntitySyncKey.element('page-2', 'text-2'), pending: PendingOp( - op: const ElementDeleteOp( + op: ElementDeleteOp( opId: 'refused-op', pagePublicId: 'page-2', elementPublicId: 'text-2', @@ -976,7 +1557,7 @@ void main() { ); const key = EntitySyncKey.element('page-2', 'text-2'); queue.state = queue.state.copyWith(attentionByEntityKey: { - key: QueuedEntityIntent( + key: const QueuedEntityIntent( entityKey: key, pending: PendingOp(op: refused, clientId: 'test-client'), ), @@ -1663,10 +2244,10 @@ void main() { final (:container, :queue, :two, one: _, remote: _, strokeId: _) = await strokeOnDeletedPage(); // Another page's edit, waiting on the server (paused, say). - final otherKey = EntitySyncKey.element('page-3', 'other'); + const otherKey = EntitySyncKey.element('page-3', 'other'); await queue.syncDesiredGenericOp( entityKey: otherKey, - desiredOp: ElementDeleteOp( + desiredOp: const ElementDeleteOp( opId: 'other-op', pagePublicId: 'page-3', elementPublicId: 'other', @@ -2391,13 +2972,13 @@ void main() { expect(container.read(strategySaveStateProvider).isDirty, isFalse); }); - test('a held lineup origin a teammate made undrawable keeps its base', + test('an edit to a held lineup is checked against the version the user saw', () async { final page = _page('page-1', 0); - final rows = _lineupRows(page.publicId, 'a'); + final row = _lineup(page.publicId, 'a'); final remote = _FakeRemoteEditorNotifier(_editorSnapshot( pages: [page], - activePage: _pageSnapshot(page, text: 'before', lineups: rows), + activePage: _pageSnapshot(page, text: 'before', lineups: [row]), )); final container = await _cloudContainer( remote: remote, @@ -2413,27 +2994,17 @@ void main() { container.read(editorPointersProvider.notifier) ..holdEntity(1, 'a') ..down(1); - // The teammate's landing deletion lands first; the origin and link are - // still live but can no longer be drawn. - final landing = rows[1]; + // A teammate's notes edit to the same lineup lands mid-drag. remote.setSnapshot(_editorSnapshot( pages: [page], activePage: _pageSnapshot(page, text: 'after', contentRevision: 2, lineups: [ - rows[0], - RemoteLineup( - publicId: landing.publicId, - strategyPublicId: landing.strategyPublicId, - pagePublicId: landing.pagePublicId, - payload: landing.payload, - sortIndex: landing.sortIndex, - revision: 2, - deleted: true, - ), - rows[2], + _editedLineup(row, (link) => link['notes'] = 'teammate notes'), ]), )); await _settle(); + expect(container.read(textProvider).single.text, 'after'); + expect(container.read(lineUpProvider).links.single.notes, 'remote lineup'); container .read(lineUpProvider.notifier) .updateOriginAgentPosition('a', const Offset(400, 400)); @@ -2441,10 +3012,11 @@ void main() { .read(activePageLiveSyncProvider.notifier) .syncLocalPage( strategyPublicId: 'cloud-strategy', pageId: page.publicId)!; - final originOp = ops[EntitySyncKey.lineup(page.publicId, rows[0].publicId)]; - // A patch against the version the user saw, not a re-add. - expect(originOp, isA()); - expect(originOp!.expectedRevision, 1); + final op = ops[_lineupKey(page.publicId, 'a')]; + // Revision 1, not the teammate's 2: the server refuses it as a conflict + // instead of the move silently overwriting their notes. + expect(op, isA()); + expect(op!.expectedRevision, 1); await _settle(); }); @@ -3198,55 +3770,61 @@ void main() { }); }); - test('a lineup origin placement starts from holds back lineup changes', - () async { - final page = _page('page-1', 0); - final remote = _FakeRemoteEditorNotifier(_editorSnapshot( - pages: [page], - activePage: _pageSnapshot(page, - text: 'before', lineups: _lineupRows(page.publicId, 'a')), - )); - final container = await _cloudContainer( - remote: remote, - queue: _FakeStrategyOpQueueNotifier(), - ); - await container - .read(strategyPageSessionProvider.notifier) - .initializeForStrategy( - strategyId: 'cloud-strategy', - source: StrategySource.cloud, - selectFirstPageIfNeeded: true, - ); - container.read(lineUpProvider.notifier).startFromOrigin('a'); - remote.setSnapshot(_editorSnapshot( - pages: [page], - activePage: _pageSnapshot(page, - text: 'after', - contentRevision: 2, - lineups: _lineupRows(page.publicId, 'a', - agentPosition: const Offset(500, 500), revision: 2)), - )); - await _settle(); - expect(container.read(textProvider).single.text, 'after'); - expect(container.read(lineUpProvider).origins.single.agent.position, - const Offset(10, 20)); - expect(container.read(lineUpProvider).placement?.pinnedOriginId, 'a'); + group('holding a lineup spot while a teammate edits the page', () { + const moved = Offset(500, 500); - container.read(lineUpProvider.notifier).clearPlacement(); - await _settle(); - expect(container.read(lineUpProvider).origins.single.agent.position, - const Offset(500, 500)); - expect(container.read(strategyOpQueueProvider).pending, isEmpty); - }); + /// Lineup `link-a` from origin `a` and lineup `link-a2` from the same + /// origin, one group, and lineup `link-b` on spots of its own, its own + /// group; each origin at [at]. With [teammateLineup], a teammate's + /// lineup `link-c` from origin `a` has joined `a`'s group. + List lineups( + RemotePage page, { + Offset at = const Offset(10, 20), + int revision = 1, + String notes = 'remote lineup', + bool teammateLineup = false, + }) => + [ + _groupRow( + page.publicId, + 'link-a', + origins: [_originJson('a', at)], + landings: [ + _landingJson('landing-a'), + _landingJson('landing-a2', const Offset(60, 60)), + if (teammateLineup) + _landingJson('landing-c', const Offset(90, 90)), + ], + links: [ + _linkJson('link-a', + originId: 'a', landingId: 'landing-a', notes: notes), + _linkJson('link-a2', + originId: 'a', landingId: 'landing-a2', notes: notes), + if (teammateLineup) + _linkJson('link-c', originId: 'a', landingId: 'landing-c'), + ], + revision: revision, + ), + _groupRow( + page.publicId, + 'link-b', + origins: [_originJson('b', at)], + landings: [_landingJson('landing-b')], + links: [ + _linkJson('link-b', + originId: 'b', landingId: 'landing-b', notes: notes), + ], + revision: revision, + sortIndex: 1, + ), + ]; - for (final startDuringLoad in [false, true]) { - test( - 'remote hydration waits for pointer, started during load=$startDuringLoad', - () async { + Future<(ProviderContainer, _FakeRemoteEditorNotifier, RemotePage)> + open() async { final page = _page('page-1', 0); final remote = _FakeRemoteEditorNotifier(_editorSnapshot( pages: [page], - activePage: _pageSnapshot(page, text: 'before'), + activePage: _pageSnapshot(page, text: 'before', lineups: lineups(page)), )); final container = await _cloudContainer( remote: remote, @@ -3259,31 +3837,127 @@ void main() { source: StrategySource.cloud, selectFirstPageIfNeeded: true, ); - final pointers = container.read(editorPointersProvider.notifier); - if (!startDuringLoad) pointers.down(1); + return (container, remote, page); + } + + Offset originAt(ProviderContainer container, String id) => + container.read(lineUpProvider).originById(id)!.agent.position; + + test('dragging a spot holds only its lineup group until release', () async { + final (container, remote, page) = await open(); + container.read(editorPointersProvider.notifier) + ..holdEntity(1, 'landing-a') + ..down(1); + + // A teammate moves every origin, edits every lineup's notes, and adds + // a lineup to the held lineup's origin, so to its group. remote.setSnapshot(_editorSnapshot( pages: [page], - activePage: _pageSnapshot(page, text: 'after', contentRevision: 2), + activePage: _pageSnapshot(page, + text: 'after', + contentRevision: 2, + lineups: lineups(page, + at: moved, + revision: 2, + notes: 'teammate notes', + teammateLineup: true)), )); - if (startDuringLoad) pointers.down(1); await _settle(); - expect(container.read(textProvider).single.text, 'before'); - expect(container.read(activePageLiveSyncProvider).hydratedPageId, - page.publicId); + + // The dragged landing's lineup waits, and so does every lineup in its + // group: the group is one row, so it takes one side whole. + final lineUps = container.read(lineUpProvider); + expect(container.read(textProvider).single.text, 'after'); + expect(originAt(container, 'a'), const Offset(10, 20)); + expect(lineUps.linkById('link-a')!.notes, 'remote lineup'); + expect(lineUps.linkById('link-a2')!.notes, 'remote lineup'); + expect(lineUps.linkById('link-c'), isNull); + // The unrelated lineup on the same page takes the change at once. + expect(originAt(container, 'b'), moved); + expect(lineUps.linkById('link-b')!.notes, 'teammate notes'); + + container.read(editorPointersProvider.notifier).release(1); + await _settle(); + + final released = container.read(lineUpProvider); + expect(originAt(container, 'a'), moved); + expect(released.linkById('link-a')!.notes, 'teammate notes'); + expect(released.linkById('link-a2')!.notes, 'teammate notes'); + expect(released.links.map((link) => link.id), + ['link-a', 'link-a2', 'link-c', 'link-b']); + expect(released.origins, hasLength(2)); + expect(container.read(strategyOpQueueProvider).pending, isEmpty); + }); + + test('a placement pinned to an origin holds only that origin\'s group', + () async { + final (container, remote, page) = await open(); + container.read(lineUpProvider.notifier).startFromOrigin('a'); remote.setSnapshot(_editorSnapshot( pages: [page], - activePage: _pageSnapshot(page, text: 'latest', contentRevision: 3), + activePage: _pageSnapshot(page, + text: 'after', + contentRevision: 2, + lineups: lineups(page, at: moved, revision: 2)), )); await _settle(); - expect(container.read(textProvider).single.text, 'before'); - pointers.release(1); + expect(container.read(textProvider).single.text, 'after'); + expect(originAt(container, 'a'), const Offset(10, 20)); + expect(originAt(container, 'b'), moved); + expect(container.read(lineUpProvider).placement?.pinnedOriginId, 'a'); + + container.read(lineUpProvider.notifier).clearPlacement(); await _settle(); - expect(container.read(textProvider).single.text, 'latest'); + expect(originAt(container, 'a'), moved); expect(container.read(strategyOpQueueProvider).pending, isEmpty); }); - } + }); - test('a page switch supersedes a remote reload already in progress', + for (final startDuringLoad in [false, true]) { + test( + 'remote hydration waits for pointer, started during load=$startDuringLoad', + () async { + final page = _page('page-1', 0); + final remote = _FakeRemoteEditorNotifier(_editorSnapshot( + pages: [page], + activePage: _pageSnapshot(page, text: 'before'), + )); + final container = await _cloudContainer( + remote: remote, + queue: _FakeStrategyOpQueueNotifier(), + ); + await container + .read(strategyPageSessionProvider.notifier) + .initializeForStrategy( + strategyId: 'cloud-strategy', + source: StrategySource.cloud, + selectFirstPageIfNeeded: true, + ); + final pointers = container.read(editorPointersProvider.notifier); + if (!startDuringLoad) pointers.down(1); + remote.setSnapshot(_editorSnapshot( + pages: [page], + activePage: _pageSnapshot(page, text: 'after', contentRevision: 2), + )); + if (startDuringLoad) pointers.down(1); + await _settle(); + expect(container.read(textProvider).single.text, 'before'); + expect(container.read(activePageLiveSyncProvider).hydratedPageId, + page.publicId); + remote.setSnapshot(_editorSnapshot( + pages: [page], + activePage: _pageSnapshot(page, text: 'latest', contentRevision: 3), + )); + await _settle(); + expect(container.read(textProvider).single.text, 'before'); + pointers.release(1); + await _settle(); + expect(container.read(textProvider).single.text, 'latest'); + expect(container.read(strategyOpQueueProvider).pending, isEmpty); + }); + } + + test('a page switch supersedes a remote reload already in progress', () async { final one = _page('page-1', 0); final two = _page('page-2', 1); @@ -3635,13 +4309,13 @@ void main() { .map((pending) => pending.op) .firstWhere((op) => op.entityPublicId == textId); final malformedLineup = RemoteLineup( - publicId: 'lineupLink:bad-lineup', + publicId: 'bad-lineup', strategyPublicId: 'cloud-strategy', pagePublicId: page.publicId, payload: const { - 'kind': 'lineupLink', + 'kind': 'lineup', 'payloadVersion': 1, - 'data': {'broken': true}, + 'data': {'id': 'bad-lineup', 'broken': true}, }, sortIndex: 0, revision: 1, @@ -4290,7 +4964,7 @@ void main() { () async { final page = _page('page-1', 0); final container = - await openCloudPage(page, _lineupRows(page.publicId, 'lineup-1')); + await openCloudPage(page, [_lineup(page.publicId, 'lineup-1')]); final lineUps = container.read(lineUpProvider); expect(lineUps.origins.single.id, 'lineup-1'); @@ -4301,16 +4975,197 @@ void main() { await _settle(); }); - test('a link that arrived before its landing is neither drawn nor deleted', - () async { + test( + 'a group row draws its shared spots once, opening the page writes ' + 'nothing, and an edit writes the whole group', () async { final page = _page('page-1', 0); - final rows = _lineupRows(page.publicId, 'lineup-1'); - // A teammate's origin and link landed; their landing is still in flight. - final container = await openCloudPage(page, [rows[0], rows[2]]); + // link-1 and link-2 share an origin, link-2 and link-3 a landing: one + // group, one row. + final container = await openCloudPage(page, [ + _groupRow( + page.publicId, + 'link-1', + origins: [ + _originJson('origin', const Offset(100, 100)), + _originJson('origin-3'), + ], + landings: [ + _landingJson('landing-1'), + _landingJson('landing', const Offset(220, 220)), + ], + links: [ + _linkJson('link-1', originId: 'origin', landingId: 'landing-1'), + _linkJson('link-2', originId: 'origin', landingId: 'landing'), + _linkJson('link-3', originId: 'origin-3', landingId: 'landing'), + ], + revision: 9, + ), + ]); + + final lineUps = container.read(lineUpProvider); + expect(lineUps.origins.map((origin) => origin.id), ['origin', 'origin-3']); + expect(lineUps.landings.map((landing) => landing.id), + ['landing-1', 'landing']); + expect([ + for (final link in lineUps.links) (link.id, link.originId, link.landingId) + ], [ + ('link-1', 'origin', 'landing-1'), + ('link-2', 'origin', 'landing'), + ('link-3', 'origin-3', 'landing'), + ]); + expect( + lineUps.originById('origin')!.agent.position, const Offset(100, 100)); + expect(lineUps.landingById('landing')!.ability.position, + const Offset(220, 220)); - expect(container.read(lineUpProvider).links, isEmpty); - expect(container.read(lineUpProvider).origins, isEmpty); + // Opening the page writes no lineup, nor does an unrelated edit. + await _settle(); + Map queuedLineupOps() => { + for (final entry in container + .read(strategyOpQueueProvider) + .queuedByEntityKey + .entries) + if (entry.key.kind == EntitySyncKeyKind.lineup) + entry.key: entry.value.pending.op, + }; + expect(queuedLineupOps(), isEmpty); expect(lineupOpsAfterTextEdit(container, page), isEmpty); + + // An edit to link-2 writes the group's row, every lineup and spot in it + // under the same ids, against the group's revision. + container + .read(lineUpProvider.notifier) + .updateLink(lineUps.linkById('link-2')!.copyWith(notes: 'jump throw')); + await _settle(); + final group = EntitySyncKey.lineup(page.publicId, 'link-1'); + expect(queuedLineupOps().keys, [group]); + final patch = queuedLineupOps()[group]! as LineupPatchOp; + expect(patch.expectedLineupRevision, 9); + final data = cloudPayloadData(patch.payload); + expect(data['id'], 'link-1'); + expect(_entries(data, 'links').map((link) => link['id']), + ['link-1', 'link-2', 'link-3']); + expect(_entry(data, 'links', 'link-2')['notes'], 'jump throw'); + expect(_entry(data, 'links', 'link-1')['notes'], 'remote lineup'); + final origin = _entry(data, 'origins', 'origin'); + expect((origin['agent'] as Map)['lineUpID'], 'origin'); + expect((origin['agent'] as Map)['position'], {'dx': 100.0, 'dy': 100.0}); + final landing = _entry(data, 'landings', 'landing'); + expect((landing['ability'] as Map)['lineUpID'], 'landing'); + expect((landing['ability'] as Map)['position'], {'dx': 220.0, 'dy': 220.0}); + await _settle(); + }); + + test( + 'a page duplicated before cloud sync writes its lineups to its own ' + 'group rows, never the other page\'s', () async { + final one = _page('page-1', 0); + final two = _page('page-2', 1); + // Page 2 repeats page 1's lineup ids. A group's id is unique in the + // strategy, so its group took another id. It also has a group a + // teammate deleted, named after a lineup id. + final oneSnapshot = + _pageSnapshot(one, lineups: [_lineup(one.publicId, 'a')]); + final twoSnapshot = _pageSnapshot(two, lineups: [ + _groupRow( + two.publicId, + 'dup-group', + origins: [_originJson('a', const Offset(50, 50))], + landings: [_landingJson('landing-a')], + links: [_linkJson('link-a', originId: 'a', landingId: 'landing-a')], + ), + _groupRow( + two.publicId, + 'link-b', + origins: [_originJson('b')], + landings: [_landingJson('landing-b')], + links: [_linkJson('link-b', originId: 'b', landingId: 'landing-b')], + revision: 2, + sortIndex: 1, + deleted: true, + ), + ]); + final remote = _FakeRemoteEditorNotifier( + _editorSnapshot(pages: [one, two], activePage: oneSnapshot), + pageCatalog: {one.publicId: oneSnapshot, two.publicId: twoSnapshot}, + ); + final queue = _FakeStrategyOpQueueNotifier(); + final container = await _cloudContainer(remote: remote, queue: queue); + final session = container.read(strategyPageSessionProvider.notifier); + await session.initializeForStrategy( + strategyId: 'cloud-strategy', + source: StrategySource.cloud, + selectFirstPageIfNeeded: true, + ); + final liveSync = container.read(activePageLiveSyncProvider.notifier); + Map lineupOps() => { + for (final MapEntry(:key, :value) + in queue.state.queuedByEntityKey.entries) + if (key.kind == EntitySyncKeyKind.lineup) key: value.pending.op, + }; + void editNotes(String notes) { + container.read(lineUpProvider.notifier).updateLink(container + .read(lineUpProvider) + .linkById('link-a')! + .copyWith(notes: notes)); + } + + final oneKey = EntitySyncKey.lineup(one.publicId, 'link-a'); + final twoKey = EntitySyncKey.lineup(two.publicId, 'dup-group'); + + // An edit on page 1 writes page 1's group. + editNotes('on one'); + await _settle(); + expect(lineupOps().keys, [oneKey]); + + // On page 2, the same lineup id is page 2's lineup, in page 2's group. + await session.setActivePage(two.publicId); + await _settle(); + expect(container.read(lineUpProvider).originById('a')!.agent.position, + const Offset(50, 50)); + editNotes('on two'); + await _settle(); + expect(lineupOps().keys, unorderedEquals([oneKey, twoKey])); + final patch = lineupOps()[twoKey]! as LineupPatchOp; + expect(cloudPayloadData(patch.payload)['id'], 'dup-group'); + expect(_onlyLinkIn(patch.payload)['notes'], 'on two'); + expect(_onlyLinkIn(lineupOps()[oneKey]!.payload as CloudPayload)['notes'], + 'on one'); + expect(liveSync.lineupGroupOf(one.publicId, 'link-a'), 'link-a'); + expect(liveSync.lineupGroupOf(two.publicId, 'link-a'), 'dup-group'); + + // Back on page 1, its lineup still writes page 1's group. + await session.setActivePage(one.publicId); + await _settle(); + expect(container.read(lineUpProvider).originById('a')!.agent.position, + const Offset(10, 20)); + editNotes('on one again'); + await _settle(); + expect(_onlyLinkIn(lineupOps()[oneKey]!.payload as CloudPayload)['notes'], + 'on one again'); + expect(lineupOps().keys, unorderedEquals([oneKey, twoKey])); + + // On page 2, lineups added under an id a group this page deleted is + // named after (an old copy brought back, say) start a new group under + // another id, never landing on the teammate's deleted group. + await session.setActivePage(two.publicId); + await _settle(); + container.read(lineUpProvider.notifier).addRecovered( + lineUpGraphFromRemoteLineups([_lineup(two.publicId, 'b')])); + final desired = liveSync.syncLocalPage( + strategyPublicId: 'cloud-strategy', + pageId: two.publicId, + )!; + final added = { + for (final MapEntry(:key, :value) in desired.entries) + if (key.kind == EntitySyncKeyKind.lineup && value is LineupAddOp) + key: value, + }; + final newKey = added.keys.single; + expect(newKey.pageId, two.publicId); + expect(newKey.entityId, isNot(anyOf('link-b', 'link-a', 'dup-group'))); + expect(added[newKey]!.expectedLineupRevision, isNull); + expect(_onlyLinkIn(added[newKey]!.payload)['id'], 'link-b'); await _settle(); }); @@ -4482,18 +5337,23 @@ void main() { group('lineup history through cloud sync', () { const placedAt = Offset(100, 100); late _FakeStrategyOpQueueNotifier queue; + late _FakeServer server; + late _ServerRepository repository; /// Page settings that round-trip exactly, so live sync authors nothing /// for them; the agent size marks which server revision is on screen. CloudPayload settingsFor(int contentRevision) => StrategySettings(agentSize: 30 + contentRevision.toDouble()).toJson(); + /// Opens page-1 with the lineup [rows] the server holds. Future<(ProviderContainer, _FakeRemoteEditorNotifier, RemotePage)> - openEmpty() async { + openEmpty([List rows = const []]) async { final page = _page('page-1', 0); + server = _FakeServer(page.publicId, lineups: rows); final remote = _FakeRemoteEditorNotifier(_editorSnapshot( pages: [page], - activePage: _pageSnapshot(page, settings: settingsFor(1)), + activePage: + _pageSnapshot(page, settings: settingsFor(1), lineups: server.rows), )); queue = _FakeStrategyOpQueueNotifier(); final container = await _cloudContainer(remote: remote, queue: queue); @@ -4534,67 +5394,6 @@ void main() { const {}; } - /// The lineup rows the server stores once [ops] apply to [previous]: - /// exactly the rows the client sent, JSON round-tripped, in stored - /// order. [teammate] edits each stored row's data (given its payload - /// kind) in the same round, as a teammate's change landing alongside - /// ours would. - List apply( - Iterable ops, - RemotePage page, { - required int revision, - required List previous, - void Function(String kind, Map data)? teammate, - }) { - final byId = {for (final lineup in previous) lineup.publicId: lineup}; - for (final op in ops) { - final (id, payload, sortIndex) = switch (op) { - LineupAddOp( - :final lineupPublicId, - :final payload, - :final sortIndex - ) => - (lineupPublicId, payload, sortIndex), - LineupPatchOp( - :final lineupPublicId, - :final payload, - :final sortIndex - ) => - ( - lineupPublicId, - payload ?? byId[lineupPublicId]!.payload, - sortIndex ?? byId[lineupPublicId]!.sortIndex, - ), - LineupDeleteOp(:final lineupPublicId) => (lineupPublicId, null, 0), - _ => (null, null, 0), - }; - if (id == null) continue; - if (payload == null) { - byId.remove(id); - continue; - } - byId[id] = RemoteLineup( - publicId: id, - strategyPublicId: 'cloud-strategy', - pagePublicId: page.publicId, - payload: jsonDecode(jsonEncode(payload)) as Map, - sortIndex: sortIndex, - revision: revision, - deleted: false, - ); - } - if (teammate != null) { - for (final lineup in byId.values) { - teammate(lineup.payload['kind'] as String, - lineup.payload['data'] as Map); - } - } - return byId.values.toList() - ..sort((a, b) => a.sortIndex != b.sortIndex - ? a.sortIndex.compareTo(b.sortIndex) - : a.publicId.compareTo(b.publicId)); - } - RemoteEditorSnapshot serverSnapshot( RemotePage page, List lineups, @@ -4630,69 +5429,88 @@ void main() { entry.key: entry.value.pending.op, }; - /// One queue update drains [ops] and publishes their acks. - void publishAcks(Map ops, int revision) { - final acks = [ - for (final entry in ops.entries) - AckedEntityIntent( - entityKey: entry.key, - op: entry.value, - ack: AppliedOpAck(opId: entry.value.opId, revision: revision), - ), - ]; - queue.state = queue.state.copyWith( - queuedByEntityKey: const {}, - lastAcks: [for (final intent in acks) intent.ack], - lastAckBatch: acks, - ); - } + /// The lineup writes in [ops]. + Map lineupOps( + Map ops) => + { + for (final entry in ops.entries) + if (entry.key.kind == EntitySyncKeyKind.lineup) + entry.key: entry.value, + }; - /// Each row of [kind] in [lineups]. - List rowsOf(List lineups, String kind) => [ - for (final row in lineups) - if (row.payload['kind'] == kind) row - ]; + /// The key of lineup group [id]'s row. + EntitySyncKey keyOf(RemotePage page, String id) => + EntitySyncKey.lineup(page.publicId, id); + + /// The group lineup or spot [id] was last drawn from or written to. + String groupOf(ProviderContainer container, RemotePage page, String id) => + container + .read(activePageLiveSyncProvider.notifier) + .lineupGroupOf(page.publicId, id)!; - EntitySyncKey keyOf(RemotePage page, String kind, String id) => - EntitySyncKey.lineup(page.publicId, cloudLineupRowId(kind, id)); + /// The id a group of lineups [ids], new together, is named after. + String firstOf(Iterable ids) => + ids.reduce((a, b) => a.compareTo(b) <= 0 ? a : b); - /// The server never holds a lineup row hydration would skip (the graph - /// form of "no empty groups"). + /// Every row the server holds reads back whole: each lineup in it is + /// drawn, from that row. void expectEveryRowDrawn(List lineups) { - final drawn = lineUpGraphFromCloudRows([ - for (final row in lineups) - CloudLineupRow(publicId: row.publicId, payload: row.payload), - ]).drawnRowIds; - expect(drawn, {for (final row in lineups) row.publicId}); + final drawn = lineUpGraphFromCloudRows( + [for (final row in lineups) CloudLineupRow.remote(row)]); + expect( + {for (final link in drawn.graph.links) link.id: drawn.groupOf[link.id]}, + { + for (final MapEntry(key: group, value: held) + in _groupsOf(lineups).entries) + for (final id in held['links']!) id: group, + }, + ); + } + + /// The server answers [sent]; the session's refresh after the answers + /// reads the server as it then is, at [contentRevision]. [teammate] + /// edits every live row's lineup data in the same round, as a teammate's + /// change landing alongside ours would. One queue update then takes the + /// answers (which also marks the page saved once nothing is left). + void send( + _FakeRemoteEditorNotifier remote, + RemotePage page, + Map sent, { + required int contentRevision, + void Function(Map data)? teammate, + }) { + final acks = server.applyBatch(sent.values); + if (teammate != null) { + for (final row in server.liveRows) { + server.teammateEdit(row.publicId, teammate); + } + } + expectEveryRowDrawn(server.liveRows); + remote.initialSnapshot = + serverSnapshot(page, server.rows, contentRevision); + queue.answer(sent, acks); } - /// The edits' scheduled sync queues ops; one queue update then drains - /// them and publishes their acks (which also marks the page saved), and - /// the session reconciles the acks, refreshes from the server and - /// rehydrates, as in production. Returns what the server holds. + /// The edits' scheduled sync queues ops; the server answers all of them + /// ([send]), and the session reconciles the answers, refreshes from the + /// server and rehydrates, as in production. Returns the live rows the + /// server holds. Future> land( ProviderContainer container, _FakeRemoteEditorNotifier remote, RemotePage page, { - required List previous, - required int revision, required int contentRevision, - void Function(String kind, Map data)? teammate, + void Function(Map data)? teammate, }) async { await _settle(); - final pending = queuedOps(); - final lineups = apply(pending.values, page, - revision: revision, previous: previous, teammate: teammate); - expectEveryRowDrawn(lineups); - // The session fetches this on the refresh that follows the acks. - remote.initialSnapshot = serverSnapshot(page, lineups, contentRevision); - publishAcks(pending, revision); + send(remote, page, queuedOps(), + contentRevision: contentRevision, teammate: teammate); await settleSync(container, contentRevision); - return lineups; + return server.liveRows; } - /// Only graph rows are written: never a legacy group. - void expectOnlyGraphRows(Map ops) { + /// Every lineup write is one whole group row, keyed by its group. + void expectLineupRows(Map ops) { for (final op in ops.values) { final payload = switch (op) { LineupAddOp(:final payload) => payload, @@ -4700,15 +5518,9 @@ void main() { _ => null, }; if (payload == null) continue; - expect( - payload['kind'], - isIn(const [ - CloudLineupKind.origin, - CloudLineupKind.landing, - CloudLineupKind.link, - ]), - reason: '$op', - ); + expect(payload['kind'], cloudLineupsPayloadKind, reason: '$op'); + expect(cloudPayloadData(payload)['id'], op.entityPublicId, + reason: '$op'); } } @@ -4718,8 +5530,7 @@ void main() { container .read(lineUpProvider.notifier) .updateLink(link.copyWith(notes: 'jump throw')); - await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); + await land(container, remote, page, contentRevision: 2); container.read(actionProvider.notifier).undoAction(); @@ -4728,13 +5539,10 @@ void main() { expect(lineUps.landingById(lineUps.links.single.landingId), isNotNull); expect(lineUps.landings, hasLength(1)); final afterUndo = desiredOps(container, page); - expectOnlyGraphRows(afterUndo); + expectLineupRows(afterUndo); expect(afterUndo.values.whereType(), isEmpty); expect(afterUndo.values.whereType(), hasLength(1)); - expect( - afterUndo.keys.single, - keyOf(page, CloudLineupKind.link, link.id), - ); + expect(afterUndo.keys.single, keyOf(page, link.id)); await _settle(); }); @@ -4744,8 +5552,7 @@ void main() { container .read(lineUpProvider.notifier) .updateLandingPosition(link.landingId, const Offset(320, 340)); - await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); + await land(container, remote, page, contentRevision: 2); expect(container.read(lineUpProvider).landings.single.id, link.landingId); @@ -4767,36 +5574,16 @@ void main() { test('undoing a move keeps a teammate weapon on the same origin', () async { final (container, remote, page) = await openEmpty(); final link = place(container); - var lineups = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); + await land(container, remote, page, contentRevision: 2); container .read(lineUpProvider.notifier) .updateOriginAgentPosition(link.originId, const Offset(500, 500)); - lineups = await land(container, remote, page, - previous: lineups, revision: 2, contentRevision: 3); + await land(container, remote, page, contentRevision: 3); // Then a teammate arms the same origin. - final originRow = rowsOf(lineups, CloudLineupKind.origin).single; - final armed = - jsonDecode(jsonEncode(originRow.payload)) as Map; - ((armed['data'] as Map)['agent'] as Map)['weapon'] = 'vandal'; - remote.setSnapshot(serverSnapshot( - page, - [ - for (final row in lineups) - row == originRow - ? RemoteLineup( - publicId: row.publicId, - strategyPublicId: 'cloud-strategy', - pagePublicId: page.publicId, - payload: armed, - sortIndex: row.sortIndex, - revision: 3, - deleted: false, - ) - : row, - ], - 4)); + server.teammateEdit( + link.id, _eachAgent((agent) => agent['weapon'] = 'vandal')); + remote.setSnapshot(serverSnapshot(page, server.rows, 4)); await settleSync(container, 4); expect( container.read(lineUpProvider).originById(link.originId)!.agent.weapon, @@ -4810,8 +5597,9 @@ void main() { expect(origin.agent.weapon, WeaponType.vandal); final patch = desiredOps(container, page).values.whereType().single; - final agent = cloudPayloadData(patch.payload)['agent'] as Map; - expect(agent['weapon'], 'vandal'); + final sent = + _entry(cloudPayloadData(patch.payload), 'origins', link.originId); + expect((sent['agent'] as Map)['weapon'], 'vandal'); await _settle(); }); @@ -4819,16 +5607,16 @@ void main() { () async { final (container, remote, page) = await openEmpty(); final link = place(container); - final lineups = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); + await land(container, remote, page, contentRevision: 2); final lineUps = container.read(lineUpProvider.notifier); const moved = Offset(500, 500); lineUps.updateOriginAgentPosition(link.originId, moved); lineUps.deleteOrigin(link.originId); - final after = await land(container, remote, page, - previous: lineups, revision: 2, contentRevision: 3); + final after = await land(container, remote, page, contentRevision: 3); expect(after, isEmpty); + // The server keeps the deleted lineup as a tombstone. + expect(server.row(link.id).deleted, isTrue); final history = container.read(actionProvider.notifier); Offset? originPosition() => container @@ -4865,6 +5653,23 @@ void main() { return (container.read(lineUpProvider).linkById(a.id)!, b); } + /// Places lineup A, then B from A's origin to a second landing, each + /// link named, the way the editor does. + (LineUpLink, LineUpLink) placeFanOut(ProviderContainer container) { + final a = place(container); + final lineUps = container.read(lineUpProvider.notifier) + ..updateLink(a.copyWith(name: 'Short')) + ..startFromOrigin(a.originId); + lineUps.setDraftAbility(PlacedAbility( + id: 'ability-y', + data: AgentData.agents[AgentType.sova]!.abilities[2], + position: const Offset(450, 450), + )); + final b = lineUps.commitPlacement(name: 'Long')!; + expect(b.originId, a.originId, reason: 'B fans out from A\'s origin'); + return (container.read(lineUpProvider).linkById(a.id)!, b); + } + List<(String, String, String, String)> linkShape(LineUpState state) => [ for (final link in state.links) (link.id, link.originId, link.landingId, link.name), @@ -4876,16 +5681,21 @@ void main() { final before = container.read(lineUpProvider); final originIds = before.origins.map((origin) => origin.id).toList(); - final lineups = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); + final lineups = await land(container, remote, page, contentRevision: 2); - expect(rowsOf(lineups, CloudLineupKind.origin), hasLength(2)); - expect( - rowsOf(lineups, CloudLineupKind.landing).single.publicId, - cloudLineupRowId(CloudLineupKind.landing, a.landingId), - ); - expect(rowsOf(lineups, CloudLineupKind.link), hasLength(2)); + // One row for the group, holding the landing once, named after its + // smaller lineup id. + final group = firstOf([a.id, b.id]); + expect(_groupsOf(lineups), { + group: { + 'origins': [a.originId, b.originId], + 'landings': [a.landingId], + 'links': [a.id, b.id], + }, + }); + expect(groupOf(container, page, b.id), group); + // Hydration draws the shared landing once. final hydrated = container.read(lineUpProvider); expect(hydrated.origins.map((origin) => origin.id), originIds); expect(hydrated.landings.single.id, a.landingId); @@ -4897,22 +5707,108 @@ void main() { await _settle(); }); + test('a fan-out lineup keeps its shared origin, ids and names', () async { + final (container, remote, page) = await openEmpty(); + final (a, b) = placeFanOut(container); + final landingIds = container + .read(lineUpProvider) + .landings + .map((landing) => landing.id) + .toList(); + + final lineups = await land(container, remote, page, contentRevision: 2); + + expect(_groupsOf(lineups), { + firstOf([a.id, b.id]): { + 'origins': [a.originId], + 'landings': [a.landingId, b.landingId], + 'links': [a.id, b.id], + }, + }); + + final hydrated = container.read(lineUpProvider); + expect(hydrated.origins.single.id, a.originId); + expect(hydrated.origins.single.agent.position, placedAt); + expect(hydrated.landings.map((landing) => landing.id), landingIds); + expect(linkShape(hydrated), [ + (a.id, a.originId, a.landingId, 'Short'), + (b.id, a.originId, b.landingId, 'Long'), + ]); + expect(desiredOps(container, page), isEmpty); + await _settle(); + }); + + test('moving a shared spot patches its group and nothing else', () async { + final (container, remote, page) = await openEmpty(); + final (a, b) = placeFanIn(container); + final other = place(container); + var lineups = await land(container, remote, page, contentRevision: 2); + final group = firstOf([a.id, b.id]); + // The group's row moves on to revision 2; the other's stays at 1. + container.read(lineUpProvider.notifier).updateLink( + container.read(lineUpProvider).linkById(a.id)!.copyWith(notes: 'x')); + lineups = await land(container, remote, page, contentRevision: 3); + expect( + {for (final row in lineups) row.publicId: row.revision}, + {group: 2, other.id: 1}, + ); + + const moved = Offset(320, 340); + container + .read(lineUpProvider.notifier) + .updateLandingPosition(a.landingId, moved); + + // One patch, of the group, against its revision, carrying the moved + // landing once for both its lineups. + final ops = desiredOps(container, page); + expectLineupRows(ops); + expect(ops.keys, [keyOf(page, group)]); + final patch = ops.values.single as LineupPatchOp; + expect(patch.expectedLineupRevision, 2); + final landing = + _entry(cloudPayloadData(patch.payload), 'landings', a.landingId); + expect((landing['ability'] as Map)['position'], + {'dx': moved.dx, 'dy': moved.dy}); + + lineups = await land(container, remote, page, contentRevision: 4); + expect( + {for (final row in lineups) row.publicId: row.revision}, + {group: 3, other.id: 1}, + ); + Offset landingAt(RemoteLineup row) { + final ability = _entries(cloudPayloadData(row.payload), 'landings') + .single['ability'] as Map; + final position = ability['position'] as Map; + return Offset((position['dx'] as num).toDouble(), + (position['dy'] as num).toDouble()); + } + + expect( + {for (final row in lineups) row.publicId: landingAt(row)}, + {group: moved, other.id: const Offset(300, 300)}, + ); + final hydrated = container.read(lineUpProvider); + expect(hydrated.landingById(a.landingId)!.ability.position, moved); + expect(hydrated.landings, hasLength(2)); + expect(desiredOps(container, page), isEmpty); + await _settle(); + }); + test('undoing a deletion rejoins the surviving shared landing', () async { final (container, remote, page) = await openEmpty(); final (a, b) = placeFanIn(container); - var lineups = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); + var lineups = await land(container, remote, page, contentRevision: 2); + final group = firstOf([a.id, b.id]); container.read(lineUpProvider.notifier).deleteOrigin(a.originId); - lineups = await land(container, remote, page, - previous: lineups, revision: 2, contentRevision: 3); - expect( - lineups.map((row) => row.publicId).toSet(), - { - cloudLineupRowId(CloudLineupKind.landing, a.landingId), - cloudLineupRowId(CloudLineupKind.origin, b.originId), - cloudLineupRowId(CloudLineupKind.link, b.id), + lineups = await land(container, remote, page, contentRevision: 3); + // The group keeps its row, now holding B alone. + expect(_groupsOf(lineups), { + group: { + 'origins': [b.originId], + 'landings': [a.landingId], + 'links': [b.id], }, - ); + }); container.read(actionProvider.notifier).undoAction(); @@ -4922,194 +5818,229 @@ void main() { (b.id, b.originId, a.landingId, 'From mid'), (a.id, a.originId, a.landingId, 'From heaven'), ]); + // A patch of the group's row, expecting its revision. final ops = desiredOps(container, page); - expectOnlyGraphRows(ops); - expect(ops.keys.toSet(), { - keyOf(page, CloudLineupKind.origin, a.originId), - keyOf(page, CloudLineupKind.link, a.id), - }); - expect(ops.values, everyElement(isA())); + expectLineupRows(ops); + expect(ops.keys, [keyOf(page, group)]); expect( - container.read(activePageLiveSyncProvider).unsyncableLineupKeys, - isEmpty, + (ops.values.single as LineupPatchOp).expectedLineupRevision, + server.row(group).revision, ); - lineups = await land(container, remote, page, - previous: lineups, revision: 3, contentRevision: 4); + lineups = await land(container, remote, page, contentRevision: 4); + expect(_groupsOf(lineups)[group]!['links'], [b.id, a.id]); + expect(_groupsOf(lineups)[group]!['landings'], [a.landingId]); + expect(server.row(group).revision, 3); expect(linkShape(container.read(lineUpProvider)), hasLength(2)); await _settle(); }); - test('deleting one origin of a fan-in writes only its own rows', () async { + test( + 'deleting a lineup takes the spots nothing else uses and keeps a ' + 'shared one', () async { final (container, remote, page) = await openEmpty(); - final (a, _) = placeFanIn(container); - await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); + final (a, b) = placeFanIn(container); + var lineups = await land(container, remote, page, contentRevision: 2); + final group = firstOf([a.id, b.id]); - container.read(lineUpProvider.notifier).deleteOrigin(a.originId); + container.read(lineUpProvider.notifier).deleteLink(a.id); + // A's origin went with it; the landing B still uses stayed. + var graph = container.read(lineUpProvider).graph; + expect(graph.origins.map((origin) => origin.id), [b.originId]); + expect(graph.landings.map((landing) => landing.id), [a.landingId]); + // The group's row is patched to hold B alone. final ops = desiredOps(container, page); - expect(ops.keys.toSet(), { - keyOf(page, CloudLineupKind.origin, a.originId), - keyOf(page, CloudLineupKind.link, a.id), + expect(ops.keys, [keyOf(page, group)]); + expect(ops.values.single, isA()); + lineups = await land(container, remote, page, contentRevision: 3); + expect(_groupsOf(lineups), { + group: { + 'origins': [b.originId], + 'landings': [a.landingId], + 'links': [b.id], + }, }); - expect(ops.values, everyElement(isA())); + graph = container.read(lineUpProvider).graph; + expect(graph.links.map((link) => link.id), [b.id]); + expect(graph.landings.map((landing) => landing.id), [a.landingId]); + + // Deleting the group's last lineup deletes its row, landing and all. + container.read(lineUpProvider.notifier).deleteLink(b.id); + graph = container.read(lineUpProvider).graph; + expect(graph.origins, isEmpty); + expect(graph.landings, isEmpty); + expect(desiredOps(container, page).values.single, isA()); + lineups = await land(container, remote, page, contentRevision: 4); + expect(lineups, isEmpty); + expect(server.row(group).deleted, isTrue); + expect(container.read(lineUpProvider).graph.landings, isEmpty); await _settle(); }); - test('a teammate editing the other link of a fan-in keeps both edits', - () async { + test( + 'a teammate editing the other lineup of a group first makes my edit ' + 'a conflict that overwrites neither', () async { final (container, remote, page) = await openEmpty(); final (a, b) = placeFanIn(container); - var lineups = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); + await land(container, remote, page, contentRevision: 2); + final group = firstOf([a.id, b.id]); + final key = keyOf(page, group); container .read(lineUpProvider.notifier) .updateLink(container.read(lineUpProvider).linkById(a.id)!.copyWith( notes: 'jump throw', )); await _settle(); + // The group's row is written, against the revision both started from. + final mine = queuedOps(); expect( - queuedOps().keys.where((key) => key.kind == EntitySyncKeyKind.lineup), - [keyOf(page, CloudLineupKind.link, a.id)], + mine.keys.where((key) => key.kind == EntitySyncKeyKind.lineup), + [key], ); + expect((mine[key]! as LineupPatchOp).expectedLineupRevision, 1); - lineups = await land( - container, - remote, - page, - previous: lineups, - revision: 2, - contentRevision: 3, - teammate: (kind, data) { - if (kind == CloudLineupKind.link && data['id'] == b.id) { - data['notes'] = 'teammate notes'; - } - }, - ); + // A teammate's edit to B, in the same group, lands first. + server.teammateEdit(group, + (data) => _entry(data, 'links', b.id)['notes'] = 'teammate notes'); + send(remote, page, queuedOps(), contentRevision: 3); + for (var i = 0; i < 10; i++) { + await _settle(); + } - final hydrated = container.read(lineUpProvider); - expect(hydrated.linkById(a.id)!.notes, 'jump throw'); - expect(hydrated.linkById(b.id)!.notes, 'teammate notes'); - expect(desiredOps(container, page), isEmpty); + // Refused: the server keeps the teammate's version, and mine waits. + expect( + queue.state.lastAckBatch + .singleWhere((acked) => acked.entityKey == key) + .ack, + isA().having((ack) => ack.rejectionReason, 'reason', + OpRejectionReason.revisionMismatch), + ); + final stored = server.row(group); + expect(stored.revision, 2); + expect(_linkIn(stored.payload, b.id)['notes'], 'teammate notes'); + expect(_linkIn(stored.payload, a.id)['notes'], ''); + expect( + container.read(lineUpProvider).linkById(a.id)!.notes, 'jump throw'); + expect(queue.state.attentionByEntityKey.keys, [key]); + expect(container.read(strategyConflictProvider), hasLength(1)); await _settle(); }); - test( - "deleting a lineup whose origin a teammate's new lineup uses keeps " - 'theirs', () async { + test('a stale edit to a lineup a teammate changed conflicts', () async { final (container, remote, page) = await openEmpty(); - final first = place(container); - final landed = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); - final originKey = keyOf(page, CloudLineupKind.origin, first.originId); - - // A teammate's lineup from the same origin lands, but this canvas has - // not drawn it yet. - RemoteLineup teammateRow(String kind, Map data) => - RemoteLineup( - publicId: cloudLineupRowId(kind, data['id'] as String), - strategyPublicId: 'cloud-strategy', - pagePublicId: page.publicId, - payload: cloudLineupPayload(kind: kind, data: data), - sortIndex: 10, - revision: 1, - deleted: false, - ); - Map dataOf(String kind) => Map.from( - rowsOf(landed, kind).single.payload['data'] as Map); - final theirLanding = dataOf(CloudLineupKind.landing) - ..['id'] = 'their-landing' - ..['ability'] = { - ...(dataOf(CloudLineupKind.landing)['ability'] as Map), - 'id': 'their-ability', - 'lineUpID': 'their-landing', - }; - final theirLink = dataOf(CloudLineupKind.link) - ..['id'] = 'their-link' - ..['landingId'] = 'their-landing'; + final link = place(container); + await land(container, remote, page, contentRevision: 2); + container + .read(lineUpProvider.notifier) + .updateLink(link.copyWith(notes: 'mine')); + await _settle(); + final key = keyOf(page, link.id); + final mine = queuedOps()[key]! as LineupPatchOp; + expect(mine.expectedLineupRevision, 1); + + // A teammate's notes edit to the same lineup lands first. + server.teammateEdit( + link.id, _eachLink((link) => link['notes'] = 'theirs')); + remote.setSnapshot(serverSnapshot(page, server.rows, 3)); + await _settle(); + // Still checked against the version the user saw: never re-based onto + // theirs, which would overwrite it in silence. + expect( + (queuedOps()[key]! as LineupPatchOp).expectedLineupRevision, + 1, + ); - // The user deletes their lineup, which takes its origin with it. - container.read(lineUpProvider.notifier).deleteLink(first.id); + // The server refuses it; the user sees their work and a conflict. + send(remote, page, queuedOps(), contentRevision: 3); await _settle(); - final sent = queuedOps(); - expect(sent[originKey], isA()); - - // The server applies the link and landing deletes and refuses the - // origin's, since the teammate's link still names it. - final onServer = [ - for (final row in landed) - if (row.payload['kind'] == CloudLineupKind.origin) row, - teammateRow(CloudLineupKind.landing, theirLanding), - teammateRow(CloudLineupKind.link, theirLink), - ]; - remote.initialSnapshot = serverSnapshot(page, onServer, 3); - final acks = [ - for (final entry in sent.entries) - AckedEntityIntent( - entityKey: entry.key, - op: entry.value, - ack: entry.key == originKey - ? FailedOpAck( - opId: entry.value.opId, - code: 'LINEUP_END_IN_USE', - rawCode: 'LINEUP_END_IN_USE', - message: lineupEndInUseMessage, - ) - : AppliedOpAck(opId: entry.value.opId, revision: 2), - ), - ]; - queue.state = queue.state.copyWith( - queuedByEntityKey: const {}, - attentionByEntityKey: { - originKey: QueuedEntityIntent( - entityKey: originKey, - pending: PendingOp(op: sent[originKey]!, clientId: 'test-client'), - ), - }, - lastError: 'Some saved work needs attention.', - lastAcks: [for (final intent in acks) intent.ack], - lastAckBatch: acks, + expect( + queue.state.lastAckBatch + .singleWhere((acked) => acked.entityKey == key) + .ack, + isA().having((ack) => ack.rejectionReason, 'reason', + OpRejectionReason.revisionMismatch), ); - remote.setSnapshot(serverSnapshot(page, onServer, 3)); - for (var i = 0; i < 10; i++) { - await _settle(); - } + expect(_onlyLinkIn(server.row(link.id).payload)['notes'], 'theirs'); + expect(container.read(lineUpProvider).links.single.notes, 'mine'); + expect(queue.state.needsAttention, isTrue); + expect(queue.state.attentionByEntityKey.keys, [key]); + expect(container.read(strategyConflictProvider), hasLength(1)); - // Until the user chooses, their delete still shows, the teammate's - // lineup is not deleted behind their back, and the work needs - // attention. - expect(container.read(lineUpProvider).graph.links, isEmpty); + // Using theirs shows the teammate's notes and sends nothing. + final resolved = await container + .read(strategyPageSessionProvider.notifier) + .useCloudVersionsForRejected(); + await _settle(); + expect(resolved, isTrue); + expect(container.read(lineUpProvider).links.single.notes, 'theirs'); + expect(queue.state.attentionByEntityKey, isEmpty); expect( - queuedOps().values.whereType(), + queuedOps().keys.where((key) => key.kind == EntitySyncKeyKind.lineup), isEmpty, ); - expect(queue.state.attentionByEntityKey.keys, [originKey]); + }); + + test( + 'deleting a spot while a teammate adds a lineup to its group is ' + 'refused, and theirs stays whole', () async { + final (container, remote, page) = await openEmpty(); + final first = place(container); + await land(container, remote, page, contentRevision: 2); + final key = keyOf(page, first.id); + + // A teammate's lineup from the same origin lands in the origin's + // group; this canvas has not drawn it yet. + server.teammateEdit(first.id, (data) { + (data['landings'] as List) + .add(_landingJson('their-landing', const Offset(80, 80))); + (data['links'] as List).add(_linkJson('their-link', + originId: first.originId, + landingId: 'their-landing', + name: 'Theirs')); + }); + + // The user deletes the origin, which takes their only lineup on it: + // the group, as they see it, is gone. + container.read(lineUpProvider.notifier).deleteOrigin(first.originId); + await _settle(); + final sent = queuedOps(); + expect(lineupOps(sent).keys, [key]); + expect(lineupOps(sent).values.single, isA()); + + // The server refuses the delete: the group changed since. Their + // lineup is untouched and the user's delete waits. + send(remote, page, sent, contentRevision: 3); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(server.row(first.id).deleted, isFalse); + expect(server.row(first.id).revision, 2); + expect(queue.state.attentionByEntityKey.keys, [key]); - // Using theirs brings back the origin with the teammate's lineup. + // Taking the cloud's version draws their lineup whole, on the origin. final resolved = await container .read(strategyPageSessionProvider.notifier) .useCloudVersionsForRejected(); await _settle(); - expect(resolved, isTrue); final graph = container.read(lineUpProvider).graph; - expect(graph.links.map((link) => link.id), ['their-link']); + expect(graph.links.map((link) => link.id), [first.id, 'their-link']); expect(graph.origins.map((origin) => origin.id), [first.originId]); + expect(graph.origins.single.agent.position, placedAt); + expect(graph.landings.map((landing) => landing.id), + [first.landingId, 'their-landing']); expect(queue.state.attentionByEntityKey, isEmpty); - expect( - queuedOps().keys.where((key) => key.kind == EntitySyncKeyKind.lineup), - isEmpty, - ); + expect(desiredOps(container, page), isEmpty); await _settle(); }); - test('a lineup placed from an origin a teammate deleted re-adds it', - () async { + test( + 'a lineup placed from an origin whose group a teammate deleted ' + 'meanwhile waits in attention, nothing lost', () async { final (container, remote, page) = await openEmpty(); final first = place(container); - final landed = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); - final originKey = keyOf(page, CloudLineupKind.origin, first.originId); + await land(container, remote, page, contentRevision: 2); + final key = keyOf(page, first.id); // The user starts a new lineup from the landed origin... final lineUps = container.read(lineUpProvider.notifier) @@ -5119,72 +6050,59 @@ void main() { data: AgentData.agents[AgentType.sova]!.abilities[2], position: const Offset(500, 500), )); - // ...while a teammate deletes that lineup, origin included. - remote.setSnapshot(serverSnapshot( - page, - [ - for (final row in landed) - RemoteLineup( - publicId: row.publicId, - strategyPublicId: row.strategyPublicId, - pagePublicId: row.pagePublicId, - payload: row.payload, - sortIndex: row.sortIndex, - revision: 2, - deleted: true, - ), - ], - 3, - )); + // ...while a teammate deletes that lineup's group, origin included. + // The placement holds the group, so the canvas keeps it as it was. + server.teammateDelete(first.id); + remote.setSnapshot(serverSnapshot(page, server.rows, 3)); await _settle(); - // Nothing the user has made names the origin yet, so the teammate's - // delete stands. - expect(desiredOps(container, page), isNot(contains(originKey))); + expect(container.read(lineUpProvider).linkById(first.id), isNotNull); + expect(desiredOps(container, page), isNot(contains(key))); final second = lineUps.commitPlacement()!; await _settle(); - // The origin goes back with the new landing and link, restoring the - // teammate's tombstone (revision 2) rather than orphaning the link. - final queued = queuedOps(); - expect( - queued[originKey], - isA() - .having((op) => op.expectedLineupRevision, 'revision', 2), - ); + // The new lineup joins the origin's group: the group's row, as the user + // has it, against the revision they saw, not the teammate's tombstone. + final queued = lineupOps(queuedOps()); + expect(groupOf(container, page, second.id), first.id); + expect(queued.keys, [key]); + final patch = queued.values.single as LineupPatchOp; + expect(patch.expectedLineupRevision, 1); + final data = cloudPayloadData(patch.payload); + expect(_entries(data, 'origins').single['id'], first.originId); + expect(_entries(data, 'links').map((link) => link['id']), + [first.id, second.id]); + + // The server refuses it as deleted: the teammate's delete stands, and + // the user's lineups wait, still on screen, for them to choose. + send(remote, page, queuedOps(), contentRevision: 4); + for (var i = 0; i < 10; i++) { + await _settle(); + } expect( - queued.keys, - containsAll([ - keyOf(page, CloudLineupKind.landing, second.landingId), - keyOf(page, CloudLineupKind.link, second.id), - ]), + queue.state.lastAckBatch + .singleWhere((acked) => acked.entityKey == key) + .ack, + isA().having( + (ack) => ack.rejectionReason, 'reason', OpRejectionReason.deleted), ); - expect( - queued, isNot(contains(keyOf(page, CloudLineupKind.link, first.id)))); - - // The server holds the new lineup whole, and it loads back. - await land(container, remote, page, - previous: const [], revision: 3, contentRevision: 4); - final hydrated = container.read(lineUpProvider).graph; - expect(hydrated.links.map((link) => link.id), [second.id]); - expect(hydrated.origins.map((origin) => origin.id), [first.originId]); + expect(server.row(first.id).deleted, isTrue); + expect(server.liveRows, isEmpty); + expect(queue.state.attentionByEntityKey.keys, [key]); + expect(container.read(lineUpProvider).links.map((link) => link.id), + [first.id, second.id]); await _settle(); }); - test('each lineup action undoes after hydration, one row at a time', + test('each lineup action undoes after hydration, one write at a time', () async { final (container, remote, page) = await openEmpty(); final link = place(container); - var revision = 1; var contentRevision = 2; var lineups = await land(container, remote, page, - previous: const [], - revision: revision++, contentRevision: contentRevision++); Future landNext() async { lineups = await land(container, remote, page, - previous: lineups, - revision: revision++, contentRevision: contentRevision++); } @@ -5209,22 +6127,22 @@ void main() { await landNext(); expect(state().linkById(link.id)!.name, 'Heaven'); - final origin = keyOf(page, CloudLineupKind.origin, link.originId); - final landing = keyOf(page, CloudLineupKind.landing, link.landingId); - final linkKey = keyOf(page, CloudLineupKind.link, link.id); + final key = keyOf(page, link.id); final history = container.read(actionProvider.notifier); - Future> undoAndLand() async { + // Undoes one step and lands it; returns the one write it made. + Future undoAndLand() async { history.undoAction(); final ops = desiredOps(container, page); - expectOnlyGraphRows(ops); + expectLineupRows(ops); + expect(ops.keys, [key]); await landNext(); - return ops.keys.toSet(); + return ops.values.single; } - expect(await undoAndLand(), {origin}); + expect(await undoAndLand(), isA()); expect(state().originById(link.originId)!.agent.weapon, isNot(WeaponType.vandal)); - expect(await undoAndLand(), {landing}); + expect(await undoAndLand(), isA()); expect( state() .landingById(link.landingId)! @@ -5233,14 +6151,14 @@ void main() { .showRangeOutline, isTrue, ); - expect(await undoAndLand(), {landing}); + expect(await undoAndLand(), isA()); expect(state().landingById(link.landingId)!.ability.position, const Offset(300, 300)); - expect(await undoAndLand(), {origin}); + expect(await undoAndLand(), isA()); expect(state().originById(link.originId)!.agent.position, placedAt); - expect(await undoAndLand(), {linkKey}); + expect(await undoAndLand(), isA()); expect(state().linkById(link.id)!.name, ''); - expect(await undoAndLand(), {origin, landing, linkKey}); + expect(await undoAndLand(), isA()); expect(state().links, isEmpty); expect(lineups, isEmpty); @@ -5251,65 +6169,23 @@ void main() { await _settle(); }); - test('a lineup whose landing is missing is refused, loudly', () async { - final (container, remote, page) = await openEmpty(); - final link = place(container); - await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); - final graph = container.read(lineUpProvider).graph; - // A graph whose link names a landing the canvas no longer has. - container.read(lineUpProvider.notifier).fromHive( - LineUpGraph(origins: graph.origins, links: graph.links), - ); - - final ops = desiredOps(container, page); - - // Neither half-written nor half-deleted: the origin and link are not - // sent, and the landing row they need is not deleted. - final held = { - keyOf(page, CloudLineupKind.origin, link.originId), - keyOf(page, CloudLineupKind.landing, link.landingId), - keyOf(page, CloudLineupKind.link, link.id), - }; - expect(ops.keys.where(held.contains), isEmpty); - expect(ops.values.whereType(), isEmpty); - // Drives the attention status (see cloud_sync_button_test). - expect( - container.read(activePageLiveSyncProvider).unsyncableLineupKeys, - held, - ); - - // Restoring the landing clears the refusal. - container.read(lineUpProvider.notifier).fromHive(graph); - desiredOps(container, page); - expect( - container.read(activePageLiveSyncProvider).unsyncableLineupKeys, - isEmpty, - ); - await _settle(); - }); - test('undoing a notes edit keeps an image a teammate added', () async { final (container, remote, page) = await openEmpty(); final link = place(container); - var lineups = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); + await land(container, remote, page, contentRevision: 2); container .read(lineUpProvider.notifier) .updateLink(link.copyWith(notes: 'jump throw')); - lineups = await land( + await land( container, remote, page, - previous: lineups, - revision: 2, contentRevision: 3, - teammate: (kind, data) { - if (kind != CloudLineupKind.link) return; - data['images'] = [ + teammate: _eachLink((link) { + link['images'] = [ {'id': 'teammate-image', 'fileExtension': '.png'}, ]; - }, + }), ); expect( container.read(lineUpProvider).links.single.images.map((i) => i.id), @@ -5323,9 +6199,8 @@ void main() { expect(restored.images.map((image) => image.id), ['teammate-image']); final patch = desiredOps(container, page).values.whereType().single; - final item = cloudPayloadData(patch.payload); - expect(patch.lineupPublicId, - cloudLineupRowId(CloudLineupKind.link, link.id)); + final item = _linkIn(patch.payload, link.id); + expect(patch.lineupPublicId, link.id); expect(item['notes'], ''); expect( (item['images'] as List).map((image) => (image as Map)['id']), @@ -5351,8 +6226,7 @@ void main() { final placed = place(container); final lineUps = container.read(lineUpProvider.notifier); lineUps.updateLink(placed.copyWith(images: images(['a', 'b', 'c', 'd']))); - var lineups = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); + await land(container, remote, page, contentRevision: 2); // Remove the first image, then two from the middle. lineUps.updateLink(container .read(lineUpProvider) @@ -5364,8 +6238,7 @@ void main() { .links .single .copyWith(images: images(['d']))); - lineups = await land(container, remote, page, - previous: lineups, revision: 2, contentRevision: 3); + await land(container, remote, page, contentRevision: 3); final history = container.read(actionProvider.notifier); history.undoAction(); @@ -5375,7 +6248,7 @@ void main() { final patch = desiredOps(container, page).values.whereType().single; expect( - (cloudPayloadData(patch.payload)['images'] as List) + (_onlyLinkIn(patch.payload)['images'] as List) .map((image) => (image as Map)['id']), ['a', 'b', 'c', 'd'], ); @@ -5389,194 +6262,2294 @@ void main() { await _settle(); }); - test('undoing an image removal keeps an image a teammate added between', - () async { - final (container, remote, page) = await openEmpty(); - final placed = place(container); + test('undoing an image removal keeps an image a teammate added between', + () async { + final (container, remote, page) = await openEmpty(); + final placed = place(container); + final lineUps = container.read(lineUpProvider.notifier); + lineUps.updateLink(placed.copyWith(images: images(['a', 'b', 'c']))); + await land(container, remote, page, contentRevision: 2); + lineUps.updateLink(container + .read(lineUpProvider) + .links + .single + .copyWith(images: images(['a', 'c']))); + // Our removal of b lands, and a teammate adds x right after a. + await land( + container, + remote, + page, + contentRevision: 3, + teammate: _eachLink((link) { + (link['images'] as List) + .insert(1, {'id': 'x', 'fileExtension': '.png'}); + }), + ); + expect(imageIds(container), ['a', 'x', 'c']); + final history = container.read(actionProvider.notifier); + + history.undoAction(); + expect(imageIds(container), ['a', 'x', 'b', 'c']); + history.redoAction(); + expect(imageIds(container), ['a', 'x', 'c']); + history.undoAction(); + expect(imageIds(container), ['a', 'x', 'b', 'c']); + await _settle(); + }); + + test('undoing a visibility toggle keeps a teammate toggle', () async { + final (container, remote, page) = await openEmpty(); + final link = place(container); + await land(container, remote, page, contentRevision: 2); + final landing = container.read(lineUpProvider).landings.single; + container.read(lineUpProvider.notifier).updateLandingAbilityVisualState( + landingId: link.landingId, + visualState: + landing.ability.visualState.copyWith(showRangeOutline: false), + ); + await land( + container, + remote, + page, + contentRevision: 3, + teammate: _eachAbility((ability) { + (ability['visualState'] as Map)['showRangeFill'] = false; + }), + ); + + container.read(actionProvider.notifier).undoAction(); + + final visual = container + .read(lineUpProvider) + .landingById(link.landingId)! + .ability + .visualState; + expect(visual.showRangeOutline, isTrue); + expect(visual.showRangeFill, isFalse); + await _settle(); + }); + + test('an ack refresh that already holds a teammate change shows it', + () async { + final (container, remote, page) = await openEmpty(); + final link = place(container); + await land(container, remote, page, contentRevision: 2); + const moved = Offset(500, 500); + container + .read(lineUpProvider.notifier) + .updateOriginAgentPosition(link.originId, moved); + // Our move lands and, in the same server state, a teammate arms it. + await land( + container, + remote, + page, + contentRevision: 3, + teammate: _eachAgent((agent) => agent['weapon'] = 'vandal'), + ); + + final origin = container.read(lineUpProvider).originById(link.originId)!; + expect(origin.agent.position, moved); + expect(origin.agent.weapon, WeaponType.vandal); + final ops = desiredOps(container, page); + expect(ops[keyOf(page, link.id)], isNull); + await _settle(); + }); + + test('an ack while another page is active does not revive the old lineup', + () async { + final first = _page('page-1', 0); + final second = _page('page-2', 1); + final secondSnapshot = _pageSnapshot(second, settings: settingsFor(9)); + final remote = _FakeRemoteEditorNotifier( + _editorSnapshot( + pages: [first, second], + activePage: _pageSnapshot(first, settings: settingsFor(1)), + ), + pageCatalog: { + first.publicId: _pageSnapshot(first, settings: settingsFor(1)), + second.publicId: secondSnapshot, + }, + ); + queue = _FakeStrategyOpQueueNotifier(); + server = _FakeServer(first.publicId); + final container = await _cloudContainer(remote: remote, queue: queue); + final session = container.read(strategyPageSessionProvider.notifier); + await session.initializeForStrategy( + strategyId: 'cloud-strategy', + source: StrategySource.cloud, + selectFirstPageIfNeeded: true, + ); + final link = place(container); + await _settle(); + var ops = queuedOps(); + var acks = server.applyBatch(ops.values); + remote.initialSnapshot = + serverSnapshot(first, server.rows, 2, pages: [first, second]); + remote.pageCatalog[first.publicId] = remote.initialSnapshot.activePage!; + queue.answer(ops, acks); + await settleSync(container, 2); + + const moved = Offset(500, 500); + container + .read(lineUpProvider.notifier) + .updateOriginAgentPosition(link.originId, moved); + await session.setActivePage(second.publicId); + await _settle(); + expect(container.read(strategySettingsProvider).agentSize, 39); + + // Page 1's move lands with a teammate's weapon change while page 2 is + // on screen. + ops = queuedOps(); + expect(ops.keys.where((key) => key.pageId == first.publicId), isNotEmpty); + acks = server.applyBatch(ops.values); + server.teammateEdit( + link.id, _eachAgent((agent) => agent['weapon'] = 'vandal')); + remote.pageCatalog[first.publicId] = _pageSnapshot( + first, + settings: settingsFor(3), + contentRevision: 3, + lineups: server.rows, + ); + remote.initialSnapshot = _editorSnapshot( + pages: [first, second], + activePage: secondSnapshot, + ); + queue.answer(ops, acks); + await settleSync(container, 9); + + await session.setActivePage(first.publicId); + await settleSync(container, 3); + + final origin = container.read(lineUpProvider).originById(link.originId)!; + expect(origin.agent.position, moved); + expect(origin.agent.weapon, WeaponType.vandal); + expect( + desiredOps(container, first)[keyOf(first, link.id)], + isNull, + ); + await _settle(); + }); + + const newer = Offset(330, 330); + + /// Lineups A ('Heaven') and B ('Mid') from their own origins into one + /// landing at [newer]: one group, its row `link-a` at revision 7. + RemoteLineup fanIn(String pageId) => _groupRow( + pageId, + 'link-a', + origins: [ + _originJson('origin-a'), + _originJson('origin-b', const Offset(60, 20)), + ], + landings: [_landingJson('landing', newer)], + links: [ + _linkJson('link-a', + originId: 'origin-a', landingId: 'landing', name: 'Heaven'), + _linkJson('link-b', + originId: 'origin-b', landingId: 'landing', name: 'Mid'), + ], + revision: 7, + ); + + /// Each lineup drawn, with the spot ids it is attached to. + List<(String, String, String)> drawnLinks(ProviderContainer container) => [ + for (final link in container.read(lineUpProvider).links) + (link.id, link.originId, link.landingId), + ]; + + test('opening a page with a shared landing writes no lineup', () async { + final (container, remote, page) = await openEmpty([fanIn('page-1')]); + await _settle(); + expect(container.read(lineUpProvider).landings.map((l) => l.id), + ['landing']); + expect(drawnLinks(container), [ + ('link-a', 'origin-a', 'landing'), + ('link-b', 'origin-b', 'landing'), + ]); + expect(lineupOps(queuedOps()), isEmpty); + + // Nor does the next hydration. + remote.setSnapshot(serverSnapshot(page, server.rows, 2)); + await settleSync(container, 2); + expect(lineupOps(queuedOps()), isEmpty); + expect(server.received, isEmpty); + }); + + /// The live read of the page [openOnRealQueue] opened. + late _FakeRemoteEditorNotifier liveRead; + + /// Shows the page as [server] now holds it, as the live read would. + late void Function() showServer; + + /// Has the live read show [pageId] from now on, as it does once the + /// session selects that page. + late void Function(String pageId) readPage; + + /// Opens [page] on the real queue, its outbox kept in [store], which + /// sends to [server] through [repository] and reads it back after every + /// batch. A batch waits for [hold] while it is set. The queue reaches + /// the server while [_online] holds. Returns the container and the + /// batches sent. + Future<(ProviderContainer, List>)> openOnRealQueue( + RemotePage page, { + DurableStrategyOutboxStore? store, + Completer? hold, + List otherPages = const [], + }) async { + final others = { + for (final other in otherPages) + other.publicId: _pageSnapshot(other, settings: settingsFor(1)), + }; + var shown = page.publicId; + RemoteEditorSnapshot read() => _editorSnapshot( + pages: [page, ...otherPages], + activePage: others[shown] ?? + _pageSnapshot( + page, + settings: settingsFor(1), + elements: server.elements, + lineups: server.rows, + ), + ); + final remote = liveRead = _FakeRemoteEditorNotifier(read(), pageCatalog: { + page.publicId: read().activePage!, + ...others, + }); + void reread() { + final shownBefore = shown; + shown = page.publicId; + remote.pageCatalog[page.publicId] = read().activePage!; + shown = shownBefore; + remote.initialSnapshot = read(); + } + + showServer = () { + reread(); + remote.setSnapshot(remote.initialSnapshot); + }; + readPage = (pageId) { + shown = pageId; + reread(); + }; + repository = _ServerRepository(server, afterBatch: reread)..hold = hold; + final container = ProviderContainer(overrides: [ + remoteEditorSnapshotProvider.overrideWith(() => remote), + durableStrategyOutboxStoreProvider + .overrideWithValue(store ?? MemoryDurableStrategyOutboxStore()), + convexStrategyRepositoryProvider.overrideWithValue(repository), + authProvider.overrideWith(_CloudReadyAuthProvider.new), + convexConnectionSnapshotProvider + .overrideWith((ref) => ref.watch(_online)), + cloudMediaAccountIdProvider.overrideWithValue('account-a'), + cloudMediaUploadQueueProvider + .overrideWith(() => _RecordingMediaQueue()), + ]); + addTearDown(container.dispose); + container.listen(strategyPageSessionProvider, (_, __) {}); + await container.read(remoteEditorSnapshotProvider.future); + container + .read(strategyOpQueueProvider.notifier) + .setActiveStrategy('cloud-strategy', accountId: 'account-a'); + container + .read(strategyProvider.notifier) + .setFromState(const StrategyState( + strategyId: 'cloud-strategy', + strategyName: 'Cloud Strategy', + source: StrategySource.cloud, + storageDirectory: null, + isOpen: true, + )); + await container + .read(strategyPageSessionProvider.notifier) + .initializeForStrategy( + strategyId: 'cloud-strategy', + source: StrategySource.cloud, + selectFirstPageIfNeeded: true, + ); + return (container, repository.batches); + } + + /// Every op sent for [key] in [batches], in order. + List sentFor( + List> batches, + EntitySyncKey key, + ) => + [ + for (final batch in batches) + ...batch.where((op) => EntitySyncKey.forStrategyOp(op) == key), + ]; + + /// The edit to [key] the server refused as deleted waits in attention, + /// with its conflict. + Future refusedAsDeleted( + ProviderContainer container, + List> batches, + EntitySyncKey key, + ) async { + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + await _until(() => queueState().attentionByEntityKey.containsKey(key)); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(sentFor(batches, key).single.kind, StrategyOpKind.patch); + expect( + queueState() + .lastAckBatch + .singleWhere((acked) => acked.entityKey == key) + .ack, + isA().having( + (ack) => ack.rejectionReason, 'reason', OpRejectionReason.deleted), + ); + expect(container.read(strategyConflictProvider), hasLength(1)); + } + + /// The edit to [key] the server refused as deleted waits in attention, + /// with its conflict; Keep mine then sends it again. Returns the op it + /// sent, once it has landed. + Future refusedThenKeptMine( + ProviderContainer container, + List> batches, + EntitySyncKey key, + ) async { + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + List sent() => sentFor(batches, key); + await refusedAsDeleted(container, batches, key); + + final opQueue = container.read(strategyOpQueueProvider.notifier); + await opQueue.retryRejected(flushImmediately: false); + await opQueue.flushNow(); + await _until(() => queueState().pending.isEmpty && sent().length == 2); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(queueState().attentionByEntityKey, isEmpty); + expect(queueState().needsAttention, isFalse); + return sent().last; + } + + test( + 'Keep mine restores a lineup a teammate deleted while the user ' + 'edited it', () async { + final page = _page('page-1', 0); + server = + _FakeServer(page.publicId, lineups: [_lineup(page.publicId, 'a')]); + final (container, batches) = await openOnRealQueue(page); + LineUpLink? onScreen() => + container.read(lineUpProvider).linkById('link-a'); + expect(onScreen(), isNotNull); + + // A teammate deletes the lineup; this canvas has not read that yet. + server.teammateDelete('link-a'); + expect(server.row('link-a').revision, 2); + + // The user edits its notes. The server refuses the change to the + // tombstone rather than store an edit nobody would see; the user still + // sees their work. + container + .read(lineUpProvider.notifier) + .updateLink(onScreen()!.copyWith(notes: 'mine')); + final restore = await refusedThenKeptMine( + container, batches, _lineupKey(page.publicId, 'a')); + + // Keep mine brought it back over the tombstone, as the user has it. + expect(restore, isA()); + expect((restore as LineupAddOp).expectedLineupRevision, 2); + expect(_onlyLinkIn(restore.payload)['notes'], 'mine'); + final row = server.row('link-a'); + expect(row.deleted, isFalse); + expect(row.revision, 3); + expect(_onlyLinkIn(row.payload)['notes'], 'mine'); + expect(lineUpGraphFromRemoteLineups(server.liveRows).links.single.notes, + 'mine'); + expect(onScreen()?.notes, 'mine'); + }); + + test( + 'Keep mine restores an element a teammate deleted while the user ' + 'moved it', () async { + final page = _page('page-1', 0); + server = _FakeServer(page.publicId, + elements: [_textElement(page.publicId, 'text-a', 'hello')]); + final (container, batches) = await openOnRealQueue(page); + PlacedText? onScreen() => container + .read(textProvider) + .where((text) => text.id == 'text-a') + .firstOrNull; + expect(onScreen(), isNotNull); + + // A teammate deletes the text; this canvas has not read that yet. + server.teammateDeleteElement('text-a'); + + // The user moves it. + container + .read(textProvider.notifier) + .updatePosition(const Offset(300, 300), 'text-a'); + final restore = await refusedThenKeptMine( + container, batches, EntitySyncKey.element(page.publicId, 'text-a')); + + // Keep mine brought it back over the tombstone, where the user put it. + expect(restore, isA()); + expect((restore as ElementAddOp).expectedElementRevision, 2); + final element = server.element('text-a'); + expect(element.deleted, isFalse); + expect(element.revision, 3); + expect(element.payload, restore.payload); + expect(onScreen()?.position, const Offset(300, 300)); + expect(onScreen()?.text, 'hello'); + }); + + /// After [refusedAsDeleted], the user deletes the item on the canvas + /// with [delete]. Both sides agree it is gone, so the refused change is + /// settled, in the queue and in [store], and Keep mine then brings + /// nothing back. + Future deletedAfterRefusal( + ProviderContainer container, + List> batches, + MemoryDurableStrategyOutboxStore store, + EntitySyncKey key, + void Function() delete, + ) async { + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + Iterable stored() => + store.load().records.where((record) => record.entityKey == key); + await refusedAsDeleted(container, batches, key); + expect(stored().single.status, DurableOutboxStatus.attention); + + delete(); + await _until(() => + !queueState().attentionByEntityKey.containsKey(key) && + queueState().pending.isEmpty); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(queueState().attentionByEntityKey, isEmpty); + expect(queueState().successorByEntityKey, isEmpty); + expect(queueState().needsAttention, isFalse); + expect(stored(), isEmpty); + // Its refusal is not announced after the fact either. + expect(container.read(strategyConflictProvider), isEmpty); + + // Keep mine has nothing left to send. + final opQueue = container.read(strategyOpQueueProvider.notifier); + await opQueue.retryRejected(flushImmediately: false); + await opQueue.flushNow(); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect( + sentFor(batches, key).where((op) => op.kind == StrategyOpKind.add), + isEmpty, + ); + expect(queueState().pending, isEmpty); + expect(stored(), isEmpty); + } + + test( + 'a lineup the user deletes after a teammate deleted it and their ' + 'edit was refused stays deleted through Keep mine', () async { + final page = _page('page-1', 0); + server = + _FakeServer(page.publicId, lineups: [_lineup(page.publicId, 'a')]); + final store = MemoryDurableStrategyOutboxStore(); + final (container, batches) = await openOnRealQueue(page, store: store); + LineUpLink? onScreen() => + container.read(lineUpProvider).linkById('link-a'); + + // A teammate deletes the lineup while the user edits its notes. + server.teammateDelete('link-a'); + container + .read(lineUpProvider.notifier) + .updateLink(onScreen()!.copyWith(notes: 'mine')); + await deletedAfterRefusal( + container, + batches, + store, + _lineupKey(page.publicId, 'a'), + () => container.read(lineUpProvider.notifier).deleteLink('link-a'), + ); + + expect(onScreen(), isNull); + expect(server.row('link-a').deleted, isTrue); + expect(server.row('link-a').revision, 2); + expect(server.liveRows, isEmpty); + }); + + test( + 'an element the user deletes after a teammate deleted it and their ' + 'move was refused stays deleted through Keep mine', () async { + final page = _page('page-1', 0); + server = _FakeServer(page.publicId, + elements: [_textElement(page.publicId, 'text-a', 'hello')]); + final store = MemoryDurableStrategyOutboxStore(); + final (container, batches) = await openOnRealQueue(page, store: store); + PlacedText? onScreen() => container + .read(textProvider) + .where((text) => text.id == 'text-a') + .firstOrNull; + + // A teammate deletes the text while the user moves it. + server.teammateDeleteElement('text-a'); + container + .read(textProvider.notifier) + .updatePosition(const Offset(300, 300), 'text-a'); + await deletedAfterRefusal( + container, + batches, + store, + EntitySyncKey.element(page.publicId, 'text-a'), + () => + container.read(textProvider.notifier).removeTextAsAction('text-a'), + ); + + expect(onScreen(), isNull); + expect(server.element('text-a').deleted, isTrue); + expect(server.element('text-a').revision, 2); + }); + + test( + 'a recovered edit to a lineup group is sent as it was, and opening ' + 'the page writes nothing else', () async { + final page = _page('page-1', 0); + server = _FakeServer(page.publicId, lineups: [ + fanIn(page.publicId), + _lineup(page.publicId, 'd', sortIndex: 1), + ]); + final group = server.row('link-a'); + final other = server.row('link-d'); + final key = keyOf(page, 'link-a'); + // Before a restart, the user's notes edit to B was saved to the outbox + // but never sent. + final recovered = LineupPatchOp( + opId: 'recovered-notes', + lineupPublicId: 'link-a', + pagePublicId: page.publicId, + payload: _editedGroup( + group, + (data) => _entry(data, 'links', 'link-b')['notes'] = 'recovered', + ).payload, + expectedLineupRevision: group.revision, + ); + final store = MemoryDurableStrategyOutboxStore(); + await store.put(DurableOutboxRecord( + accountId: 'account-a', + strategyPublicId: 'cloud-strategy', + entityKey: key, + pending: PendingOp(op: recovered, clientId: 'client-before-restart'), + status: DurableOutboxStatus.queued, + createdAt: DateTime.utc(2026), + updatedAt: DateTime.utc(2026), + )); + + // Its send waits while the page opens. + final hold = Completer(); + final (container, batches) = + await openOnRealQueue(page, store: store, hold: hold); + for (var i = 0; i < 10; i++) { + await _settle(); + } + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + bool isLineup(StrategyOp op) => + EntitySyncKey.forStrategyOp(op)?.kind == EntitySyncKeyKind.lineup; + + // The page draws both groups, and the recovered edit is the only + // lineup work: nothing replaced it, nothing joined it. + expect(container.read(lineUpProvider).landings.map((l) => l.id), + ['landing', 'landing-d']); + expect( + [ + for (final pending in queueState().pending) + if (isLineup(pending.op)) pending.op.opId, + ], + ['recovered-notes'], + ); + expect( + [for (final record in store.load().records) record.pending.op.opId], + ['recovered-notes'], + ); + + hold.complete(); + await _until(() => queueState().pending.isEmpty); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + // Only the recovered edit was ever sent for a lineup, as it was saved. + expect( + [ + for (final batch in batches) + for (final op in batch) + if (isLineup(op)) op.opId, + ], + ['recovered-notes'], + ); + expect(server.received.single.payload, recovered.payload); + expect(server.row('link-a').revision, group.revision + 1); + expect(_linkIn(server.row('link-a').payload, 'link-b')['notes'], + 'recovered'); + expect(server.row('link-d').revision, other.revision); + expect( + canonicalCloudJsonEncode(server.row('link-d').payload), + canonicalCloudJsonEncode(other.payload), + ); + expect( + container.read(lineUpProvider).linkById('link-b')!.notes, + 'recovered', + ); + expect( + container.read(lineUpProvider).landingById('landing')!.ability.position, + newer, + ); + }); + + test( + 'an edit whose answer was lost is answered at the revision it landed ' + 'at, so the edit behind it cannot overwrite a teammate', () async { + final page = _page('page-1', 0); + server = + _FakeServer(page.publicId, lineups: [_lineup(page.publicId, 'a')]); + final hold = Completer(); + final (container, batches) = await openOnRealQueue(page, hold: hold); + final key = _lineupKey(page.publicId, 'a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + LineUpLink onScreen() => + container.read(lineUpProvider).linkById('link-a')!; + + // The user's notes edit reaches the server, which takes it at + // revision 2, but the answer is lost; a teammate renames the lineup + // right after. + repository.loseNextAnswer = () => server.teammateEdit( + 'link-a', _eachLink((link) => link['name'] = 'theirs')); + container + .read(lineUpProvider.notifier) + .updateLink(onScreen().copyWith(notes: 'one')); + await _until(() => queueState().inFlightByEntityKey.containsKey(key)); + // While it is on its way, the user edits again; that waits behind it. + container + .read(lineUpProvider.notifier) + .updateLink(onScreen().copyWith(notes: 'two')); + await _until(() => queueState().successorByEntityKey.containsKey(key)); + hold.complete(); + + // The first edit is sent again and answered as landed at revision 2, + // so the second goes against revision 2: refused, not stored over the + // teammate's name. + await _until(() => queueState().attentionByEntityKey.containsKey(key)); + for (var i = 0; i < 10; i++) { + await _settle(); + } + final sent = sentFor(batches, key); + expect(sent, hasLength(3)); + expect(sent[1].opId, sent[0].opId); + expect(_onlyLinkIn((sent[2] as LineupPatchOp).payload)['notes'], 'two'); + expect((sent[2] as LineupPatchOp).expectedLineupRevision, 2); + final row = server.row('link-a'); + expect(row.revision, 3); + expect(_onlyLinkIn(row.payload)['name'], 'theirs'); + expect(_onlyLinkIn(row.payload)['notes'], 'one'); + expect(container.read(strategyConflictProvider), hasLength(1)); + }); + + /// Every id in [graph]: its lineups, spots, and the agent and ability on + /// each spot. + Set idsIn(LineUpGraph graph) => { + for (final origin in graph.origins) ...[origin.id, origin.agent.id], + for (final landing in graph.landings) ...[ + landing.id, + landing.ability.id, + ], + for (final link in graph.links) link.id, + }; + + /// The lineups [rows] draw, each as `name: notes`. + List lineupsIn(Iterable rows) => [ + for (final link in lineUpGraphFromRemoteLineups(rows).links) + '${link.name}: ${link.notes}', + ]; + + /// The changes [changes] lists, each as `label: description`. + List described(List changes) => [ + for (final change in changes) + '${change.label}: ${change.description}', + ]; + + /// The fan-in group is on the server and on screen; a teammate's notes + /// edit to B lands, then this client's notes edit to A, made against the + /// same revision, is refused and waits. Returns the container, the + /// batches sent and the outbox. + Future< + ( + ProviderContainer, + List>, + MemoryDurableStrategyOutboxStore, + )> refusedBesideTeammate( + RemotePage page, { + MemoryDurableStrategyOutboxStore? store, + List otherPages = const [], + List elements = const [], + }) async { + server = _FakeServer(page.publicId, + lineups: [fanIn(page.publicId)], elements: elements); + store ??= MemoryDurableStrategyOutboxStore(); + final (container, batches) = + await openOnRealQueue(page, store: store, otherPages: otherPages); + final key = keyOf(page, 'link-a'); + + // Both clients start from revision 7; the teammate's save lands first. + server.teammateEdit('link-a', + (data) => _entry(data, 'links', 'link-b')['notes'] = 'theirs'); + container.read(lineUpProvider.notifier).updateLink(container + .read(lineUpProvider) + .linkById('link-a')! + .copyWith(notes: 'mine')); + await _until(() => container + .read(strategyOpQueueProvider) + .attentionByEntityKey + .containsKey(key)); + for (var i = 0; i < 10; i++) { + await _settle(); + } + return (container, batches, store); + } + + test( + 'two clients changing different lineups of one group from the same ' + 'revision: the second is refused and waits, nothing overwritten', + () async { + final page = _page('page-1', 0); + final (container, batches, store) = await refusedBesideTeammate(page); + final key = keyOf(page, 'link-a'); + final queueState = container.read(strategyOpQueueProvider); + + final sent = sentFor(batches, key); + expect(sent.single, isA()); + expect((sent.single as LineupPatchOp).expectedLineupRevision, 7); + expect( + queueState.lastAckBatch + .singleWhere((acked) => acked.entityKey == key) + .ack, + isA().having((ack) => ack.rejectionReason, 'reason', + OpRejectionReason.revisionMismatch), + ); + + // The server keeps the teammate's version; the user's waits, on + // screen and in the outbox, for them to choose. + expect(server.row('link-a').revision, 8); + expect( + lineupsIn(server.liveRows), ['Heaven: remote lineup', 'Mid: theirs']); + expect(container.read(lineUpProvider).linkById('link-a')!.notes, 'mine'); + expect(queueState.attentionByEntityKey.keys, [key]); + expect(store.load().records.single.status, DurableOutboxStatus.attention); + expect(container.read(strategyConflictProvider), hasLength(1)); + + // The sync popover lists what each side changed. + final conflict = container.read(lineupConflictsProvider)!.single; + expect(conflict.key, key); + expect(described(conflict.yours), ['Heaven: notes edited']); + expect(described(conflict.cloud!), ['Mid: notes edited']); + }); + + test( + 'offline edits to a group a teammate changed meanwhile wait in ' + 'attention on reconnect', () async { + final page = _page('page-1', 0); + server = _FakeServer(page.publicId, lineups: [fanIn(page.publicId)]); + final store = MemoryDurableStrategyOutboxStore(); + final (container, batches) = await openOnRealQueue(page, store: store); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + const moved = Offset(400, 400); + + container.read(_online.notifier).state = false; + final lineUps = container.read(lineUpProvider.notifier); + lineUps.updateLink(container + .read(lineUpProvider) + .linkById('link-a')! + .copyWith(notes: 'offline')); + lineUps.updateOriginAgentPosition('origin-a', moved); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(sentFor(batches, key), isEmpty); + expect(queueState().queuedByEntityKey.keys, contains(key)); + + // Meanwhile a teammate renames B. + server.teammateEdit( + 'link-a', (data) => _entry(data, 'links', 'link-b')['name'] = 'B'); + + container.read(_online.notifier).state = true; + await container.read(strategyOpQueueProvider.notifier).flushNow(); + await _until(() => queueState().attentionByEntityKey.containsKey(key)); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + // Everything made offline went as one write, against the revision the + // user saw, and was refused rather than stored over the rename. + final sent = sentFor(batches, key).single as LineupPatchOp; + expect(sent.expectedLineupRevision, 7); + expect(_linkIn(sent.payload, 'link-a')['notes'], 'offline'); + expect(_linkIn(sent.payload, 'link-b')['name'], 'Mid'); + expect(server.row('link-a').revision, 8); + expect(lineupsIn(server.liveRows), + ['Heaven: remote lineup', 'B: remote lineup']); + expect( + ((_entry(cloudPayloadData(server.row('link-a').payload), 'origins', + 'origin-a')['agent'] as Map)['position'] as Map)['dx'], + 10, + ); + final onScreen = container.read(lineUpProvider); + expect(onScreen.linkById('link-a')!.notes, 'offline'); + expect(onScreen.originById('origin-a')!.agent.position, moved); + expect(store.load().records.single.status, DurableOutboxStatus.attention); + expect(container.read(strategyConflictProvider), hasLength(1)); + }); + + test('offline edits to a group nobody changed land on reconnect', () async { + final page = _page('page-1', 0); + server = _FakeServer(page.publicId, lineups: [fanIn(page.publicId)]); + final store = MemoryDurableStrategyOutboxStore(); + final (container, batches) = await openOnRealQueue(page, store: store); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + const moved = Offset(400, 400); + + container.read(_online.notifier).state = false; + final lineUps = container.read(lineUpProvider.notifier); + lineUps.updateLink(container + .read(lineUpProvider) + .linkById('link-a')! + .copyWith(notes: 'offline')); + lineUps.updateOriginAgentPosition('origin-a', moved); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(sentFor(batches, key), isEmpty); + + container.read(_online.notifier).state = true; + await container.read(strategyOpQueueProvider.notifier).flushNow(); + await _until(() => + queueState().pending.isEmpty && sentFor(batches, key).isNotEmpty); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + expect(sentFor(batches, key).single, isA()); + final row = server.row('link-a'); + expect(row.revision, 8); + expect(lineupsIn([row]), ['Heaven: offline', 'Mid: remote lineup']); + expect( + ((_entry(cloudPayloadData(row.payload), 'origins', 'origin-a')['agent'] + as Map)['position'] as Map)['dx'], + moved.dx, + ); + expect(queueState().attentionByEntityKey, isEmpty); + expect(queueState().needsAttention, isFalse); + expect(store.load().records, isEmpty); + expect(container.read(strategyConflictProvider), isEmpty); + }); + + test( + 'an edit behind one replayed with no revision waits in attention ' + 'instead of going out on a guessed revision', () async { + final page = _page('page-1', 0); + // The server takes the first edit but records no revision for it, as + // events written before it kept one. + server = + _FakeServer(page.publicId, lineups: [_lineup(page.publicId, 'a')]) + ..recordsRevisions = false; + final hold = Completer(); + final store = MemoryDurableStrategyOutboxStore(); + final (container, batches) = + await openOnRealQueue(page, store: store, hold: hold); + final key = _lineupKey(page.publicId, 'a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + LineUpLink onScreen() => + container.read(lineUpProvider).linkById('link-a')!; + + // The first edit lands at revision 2, but its answer is lost; a + // teammate renames the lineup right after. + repository.loseNextAnswer = () => server.teammateEdit( + 'link-a', _eachLink((link) => link['name'] = 'theirs')); + container + .read(lineUpProvider.notifier) + .updateLink(onScreen().copyWith(notes: 'one')); + await _until(() => queueState().inFlightByEntityKey.containsKey(key)); + // The user edits again; that waits behind it. + container + .read(lineUpProvider.notifier) + .updateLink(onScreen().copyWith(notes: 'two')); + await _until(() => queueState().successorByEntityKey.containsKey(key)); + hold.complete(); + + await _until(() => queueState().attentionByEntityKey.containsKey(key)); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + // The replay is answered as a noop with no revision... + final sent = sentFor(batches, key); + expect(sent, hasLength(2)); + expect(sent[1].opId, sent[0].opId); + final replayed = queueState() + .lastAckBatch + .where((acked) => acked.entityKey == key) + .map((acked) => acked.ack); + expect( + replayed, + everyElement(isA() + .having((ack) => ack.currentRevision, 'revision', isNull)), + ); + // ...so the edit behind it is never sent on a revision the client + // would have had to guess, which would store it over the teammate's + // rename. It waits for the user to choose. + expect( + _onlyLinkIn(queueState().successorByEntityKey[key]!.pending.op.payload + as CloudPayload)['notes'], + 'two', + ); + expect( + store.load().records.singleWhere((r) => r.entityKey == key).status, + DurableOutboxStatus.attention, + ); + final row = server.row('link-a'); + expect(row.revision, 3); + expect(_onlyLinkIn(row.payload)['name'], 'theirs'); + expect(_onlyLinkIn(row.payload)['notes'], 'one'); + expect(onScreen().notes, 'two'); + }); + + /// The fan-in group is on the server and on screen. Offline, the user + /// edits A's notes while a teammate deletes the group; on reconnect the + /// edit is refused as deleted and waits. Returns the container and the + /// batches sent. + Future<(ProviderContainer, List>)> deletedWhileOffline( + RemotePage page, + ) async { + server = _FakeServer(page.publicId, lineups: [fanIn(page.publicId)]); + final (container, batches) = await openOnRealQueue(page); + container.read(_online.notifier).state = false; + container.read(lineUpProvider.notifier).updateLink(container + .read(lineUpProvider) + .linkById('link-a')! + .copyWith(notes: 'mine')); + for (var i = 0; i < 10; i++) { + await _settle(); + } + server.teammateDelete('link-a'); + expect(server.row('link-a').revision, 8); + + container.read(_online.notifier).state = true; + await container.read(strategyOpQueueProvider.notifier).flushNow(); + await refusedAsDeleted(container, batches, keyOf(page, 'link-a')); + // The user's version is still on screen. + expect(container.read(lineUpProvider).links.map((link) => link.notes), + ['mine', 'remote lineup']); + return (container, batches); + } + + test( + 'Keep mine brings back a group a teammate deleted while the user ' + 'edited it offline, as the user has it', () async { + final page = _page('page-1', 0); + final (container, batches) = await deletedWhileOffline(page); + + final restore = + await refusedThenKeptMine(container, batches, keyOf(page, 'link-a')); + + expect(restore, isA()); + expect((restore as LineupAddOp).expectedLineupRevision, 8); + final row = server.row('link-a'); + expect(row.deleted, isFalse); + expect(row.revision, 9); + expect(_groupsOf([row]), { + 'link-a': { + 'origins': ['origin-a', 'origin-b'], + 'landings': ['landing'], + 'links': ['link-a', 'link-b'], + }, + }); + expect(lineupsIn([row]), ['Heaven: mine', 'Mid: remote lineup']); + expect(container.read(lineUpProvider).links.map((link) => link.notes), + ['mine', 'remote lineup']); + }); + + test( + 'Keep both after a teammate deleted the group leaves it deleted and ' + 'adds the user\'s version as a copy', () async { + final page = _page('page-1', 0); + final (container, batches) = await deletedWhileOffline(page); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + final original = idsIn(container.read(lineUpProvider).graph); + expect(container.read(lineupConflictsProvider), isNotNull); + + final kept = await container + .read(strategyPageSessionProvider.notifier) + .keepBothForRejected(); + expect(kept, KeepBothOutcome.kept); + await _until(() => queueState().pending.isEmpty); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + // The group stays deleted, as the teammate left it, and was never + // written again. + expect(server.row('link-a').deleted, isTrue); + expect(server.row('link-a').revision, 8); + expect(sentFor(batches, keyOf(page, 'link-a')), hasLength(1)); + // The user's version is beside it as a group of its own, nothing in it + // the original. + final copy = server.liveRows.single; + final copyGraph = lineUpGraphFromRemoteLineups([copy]); + expect(idsIn(copyGraph).intersection(original), isEmpty); + expect(lineupsIn([copy]), ['Heaven: mine', 'Mid: remote lineup']); + expect(copyGraph.landings, hasLength(1)); + expect(copyGraph.origins, hasLength(2)); + expect(sentFor(batches, keyOf(page, copy.publicId)).single, + isA()); + // On screen, the copy alone; nothing waits. + expect(idsIn(container.read(lineUpProvider).graph), idsIn(copyGraph)); + expect(queueState().attentionByEntityKey, isEmpty); + expect(queueState().needsAttention, isFalse); + expect(container.read(strategyConflictProvider), isEmpty); + expect(container.read(lineupConflictsProvider), isNull); + }); + + test( + 'Keep both keeps the cloud\'s group as the server has it and queues ' + 'the user\'s version as a new group under fresh ids', () async { + final page = _page('page-1', 0); + final (container, batches, store) = await refusedBesideTeammate(page); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + final original = idsIn(container.read(lineUpProvider).graph); + + final kept = await container + .read(strategyPageSessionProvider.notifier) + .keepBothForRejected(); + expect(kept, KeepBothOutcome.kept); + await _until(() => queueState().pending.isEmpty); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + // The cloud's group is untouched: the teammate's version, revision 8. + final group = server.row('link-a'); + expect(group.revision, 8); + expect(lineupsIn([group]), ['Heaven: remote lineup', 'Mid: theirs']); + expect(sentFor(batches, keyOf(page, 'link-a')), hasLength(1)); + // The user's version went to the server as a new group row. + final copy = + server.liveRows.singleWhere((row) => row.publicId != 'link-a'); + final copyGraph = lineUpGraphFromRemoteLineups([copy]); + expect(idsIn(copyGraph).intersection(original), isEmpty); + expect(lineupsIn([copy]), ['Heaven: mine', 'Mid: remote lineup']); + expect(sentFor(batches, keyOf(page, copy.publicId)).single, + isA()); + // Both are on screen, and nothing waits. + final onScreen = container.read(lineUpProvider); + expect( + [for (final link in onScreen.links) '${link.name}: ${link.notes}'], + unorderedEquals([ + 'Heaven: remote lineup', + 'Mid: theirs', + 'Heaven: mine', + 'Mid: remote lineup', + ])); + expect(queueState().attentionByEntityKey, isEmpty); + expect(queueState().needsAttention, isFalse); + expect(store.load().records, isEmpty); + expect(container.read(strategyConflictProvider), isEmpty); + expect(container.read(lineupConflictsProvider), isNull); + }); + + test( + 'Keep both whose cloud version cannot be loaded changes nothing, so ' + 'pressing it again cannot copy twice', () async { + final page = _page('page-1', 0); + final (container, batches, store) = await refusedBesideTeammate(page); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + final before = [ + for (final link in container.read(lineUpProvider).links) link.id, + ]; + liveRead.readFails = true; + + final outcome = await container + .read(strategyPageSessionProvider.notifier) + .keepBothForRejected(); + expect(outcome, KeepBothOutcome.unchanged); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + // No copy, on screen or on the server... + expect( + [for (final link in container.read(lineUpProvider).links) link.id], + before, + ); + expect(server.liveRows, hasLength(1)); + // ...and the original work still waits for the user to choose. + expect(queueState().attentionByEntityKey.keys, [key]); + expect( + store.load().records.singleWhere((r) => r.entityKey == key).status, + DurableOutboxStatus.attention, + ); + expect(sentFor(batches, key), hasLength(1)); + expect(container.read(strategyConflictProvider), hasLength(1)); + }); + + /// The lineups on screen, each as `name: notes`. + List onScreenOf(ProviderContainer container) => [ + for (final link in container.read(lineUpProvider).links) + '${link.name}: ${link.notes}', + ]; + + test( + 'Keep both whose copy cannot be saved discards nothing: the copy and ' + 'the waiting work both stay', () async { + final page = _page('page-1', 0); + final store = _FailingOutboxStore(); + final (container, batches, _) = + await refusedBesideTeammate(page, store: store); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + final waiting = queueState().attentionByEntityKey[key]!.pending.op.opId; + // The copy's outbox write fails; the waiting work's record is kept. + store.failPut = (record) => record.entityKey != key; + + final outcome = await container + .read(strategyPageSessionProvider.notifier) + .keepBothForRejected(); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + expect(outcome, KeepBothOutcome.copiesOnly); + // The original still waits, in memory and on disk, as it was. + expect(queueState().attentionByEntityKey[key]!.pending.op.opId, waiting); + expect( + store.load().records.singleWhere((r) => r.entityKey == key).status, + DurableOutboxStatus.attention, + ); + expect(sentFor(batches, key), hasLength(1)); + // The copy is still on screen beside the user's version; the cloud's + // version was not taken. + expect( + onScreenOf(container), + [ + 'Heaven: mine', + 'Mid: remote lineup', + 'Heaven: mine', + 'Mid: remote lineup' + ], + ); + // The server has only the teammate's version; nothing was discarded. + expect(server.liveRows.map((row) => row.publicId), ['link-a']); + expect( + lineupsIn(server.liveRows), ['Heaven: remote lineup', 'Mid: theirs']); + expect(queueState().hasDurabilityFailure, isTrue); + }); + + test( + 'an edit to the conflicting group while Keep both loads the cloud ' + 'version stops it: no copy, and the newer edit still waits', () async { + final page = _page('page-1', 0); + final (container, _, store) = await refusedBesideTeammate(page); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + final refreshes = liveRead.refreshCount; + final gate = liveRead.refreshGate = Completer(); + + final keepBoth = container + .read(strategyPageSessionProvider.notifier) + .keepBothForRejected(); + await _until(() => liveRead.refreshCount > refreshes); + // While the cloud's version is on its way, the user edits the group. + container.read(lineUpProvider.notifier).updateLink(container + .read(lineUpProvider) + .linkById('link-b')! + .copyWith(notes: 'newer')); + gate.complete(); + + expect(await keepBoth, KeepBothOutcome.unchanged); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + // No copy was made of the version the edit replaced... + expect(onScreenOf(container), ['Heaven: mine', 'Mid: newer']); + expect(server.liveRows.map((row) => row.publicId), ['link-a']); + // ...and the newer edit waits behind the refused one, for the user. + expect(queueState().attentionByEntityKey.keys, [key]); + final newer = queueState().successorByEntityKey[key]!.pending.op; + expect( + _linkIn(newer.payload as CloudPayload, 'link-b')['notes'], 'newer'); + expect(_linkIn(newer.payload as CloudPayload, 'link-a')['notes'], 'mine'); + expect( + store.load().records.singleWhere((r) => r.entityKey == key).status, + DurableOutboxStatus.attention, + ); + }); + + test( + 'switching page while Keep both loads the cloud version stops it: ' + 'no copy on either page', () async { + final page = _page('page-1', 0); + final other = _page('page-2', 1); + final (container, _, _) = + await refusedBesideTeammate(page, otherPages: [other]); + final key = keyOf(page, 'link-a'); + final session = container.read(strategyPageSessionProvider.notifier); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + bool copyQueued() => queueState().pending.any((pending) => + pending.op is LineupAddOp || + EntitySyncKey.forStrategyOp(pending.op)?.pageId == other.publicId); + final refreshes = liveRead.refreshCount; + final gate = liveRead.refreshGate = Completer(); + + final keepBoth = session.keepBothForRejected(); + await _until(() => liveRead.refreshCount > refreshes); + // While the cloud's version is on its way, the user opens page 2. + await session.setActivePage(other.publicId); + readPage(other.publicId); + gate.complete(); + + expect(await keepBoth, KeepBothOutcome.unchanged); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(container.read(strategyPageSessionProvider).activePageId, + other.publicId); + expect(container.read(lineUpProvider).links, isEmpty); + expect(copyQueued(), isFalse); + + // Back on page 1: the user's version, and no copy of it. + await session.setActivePage(page.publicId); + readPage(page.publicId); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(onScreenOf(container), ['Heaven: mine', 'Mid: remote lineup']); + expect(copyQueued(), isFalse); + expect(server.liveRows.map((row) => row.publicId), ['link-a']); + expect(queueState().attentionByEntityKey.keys, [key]); + }); + + test( + 'once the page is drawn again, the conflict lists how the user\'s ' + 'version differs from the cloud\'s, not who changed what', () async { + final page = _page('page-1', 0); + final other = _page('page-2', 1); + final (container, _, _) = + await refusedBesideTeammate(page, otherPages: [other]); + final key = keyOf(page, 'link-a'); + final session = container.read(strategyPageSessionProvider.notifier); + expect(container.read(lineupConflictsProvider)!.single.cloud, isNotNull); + + // The user leaves the page and comes back while the conflict waits: + // the page is drawn from the cloud's version, revision 8. + await session.setActivePage(other.publicId); + readPage(other.publicId); + await _settle(); + await session.setActivePage(page.publicId); + readPage(page.publicId); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect( + container + .read(activePageLiveSyncProvider.notifier) + .hydratedBase(key) + ?.revision, + 8, + ); + + final conflict = container.read(lineupConflictsProvider)!.single; + expect(conflict.key, key); + // Against revision 8, the teammate's notes on Mid would read as the + // user's, so the sides are not told apart: only the difference. + expect(conflict.cloud, isNull); + expect(described(conflict.yours), + ['Heaven: notes edited', 'Mid: notes edited']); + expect( + described(conflict.yours), + described(lineupChanges( + from: lineUpGraphFromRemoteLineups([server.row('link-a')]), + to: lineUpGraphFromCloudRows([ + CloudLineupRow( + publicId: 'link-a', + payload: container + .read(strategyOpQueueProvider) + .attentionByEntityKey[key]! + .pending + .op + .payload as CloudPayload, + ), + ]).graph, + )), + ); + }); + + test( + 'Keep both pressed again after it copied but could not resolve ' + 'finishes without a second copy', () async { + final page = _page('page-1', 0); + final (container, batches, store) = await refusedBesideTeammate(page); + final key = keyOf(page, 'link-a'); + final session = container.read(strategyPageSessionProvider.notifier); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + List copies() => [ + for (final row in server.liveRows) + if (row.publicId != 'link-a') row, + ]; + + // The first read, before the copy, works; the cloud's version then + // stops loading. + final first = liveRead.refreshCount + 1; + liveRead.readFailsWhen = (count) => count > first; + expect(await session.keepBothForRejected(), KeepBothOutcome.copiesOnly); + // The copy goes out; the waiting work stays. + await _until(() => + queueState().queuedByEntityKey.isEmpty && + queueState().inFlightByEntityKey.isEmpty && + server.liveRows.length == 2); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(copies(), hasLength(1)); + expect(queueState().attentionByEntityKey.keys, [key]); + + // Pressed again with the cloud reachable, it only resolves. + liveRead.readFailsWhen = null; + expect(await session.keepBothForRejected(), KeepBothOutcome.kept); + await _until(() => queueState().pending.isEmpty); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + final copy = copies().single; + expect(lineupsIn([copy]), ['Heaven: mine', 'Mid: remote lineup']); + expect(sentFor(batches, keyOf(page, copy.publicId)), hasLength(1)); + expect(lineupsIn([server.row('link-a')]), + ['Heaven: remote lineup', 'Mid: theirs']); + expect( + onScreenOf(container), + unorderedEquals([ + 'Heaven: remote lineup', + 'Mid: theirs', + 'Heaven: mine', + 'Mid: remote lineup', + ]), + ); + expect(queueState().attentionByEntityKey, isEmpty); + expect(queueState().needsAttention, isFalse); + expect(store.load().records, isEmpty); + }); + + test( + 'an edit to the conflicting group during Keep both\'s second cloud ' + 'read, after the copy, is neither discarded nor replaced', () async { + final page = _page('page-1', 0); + final (container, _, store) = await refusedBesideTeammate(page); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + List copies() => [ + for (final row in server.liveRows) + if (row.publicId != 'link-a') row, + ]; + // The copy's send waits, so no answer brings a read of its own; the + // read held is the one that loads the cloud's version to take it. + final send = repository.hold = Completer(); + final gate = liveRead.refreshGate = Completer(); + liveRead.gateWhen = + () => container.read(lineUpProvider).links.length == 4; + + final keepBoth = container + .read(strategyPageSessionProvider.notifier) + .keepBothForRejected(); + await _until(() => liveRead.refreshGate == null); + expect(onScreenOf(container), hasLength(4), reason: 'the copy is made'); + // While the cloud's version is on its way, the user edits the group. + container.read(lineUpProvider.notifier).updateLink(container + .read(lineUpProvider) + .linkById('link-b')! + .copyWith(notes: 'newer')); + // From here the canvas never shows the cloud's version in place of + // the edit, even for a moment. + var replaced = false; + container.listen(lineUpProvider, (_, next) { + if (next.linkById('link-b')?.notes != 'newer') replaced = true; + }); + gate.complete(); + + expect(await keepBoth, KeepBothOutcome.copiesOnly); + expect(replaced, isFalse); + send.complete(); + await _until(() => + queueState().queuedByEntityKey.isEmpty && + queueState().inFlightByEntityKey.isEmpty && + copies().length == 1); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + // The newer edit is on screen and waits behind the refused one... + expect(container.read(lineUpProvider).linkById('link-b')!.notes, 'newer'); + expect(queueState().attentionByEntityKey.keys, [key]); + final newer = queueState().successorByEntityKey[key]!.pending.op; + expect( + _linkIn(newer.payload as CloudPayload, 'link-b')['notes'], 'newer'); + expect( + store.load().records.singleWhere((r) => r.entityKey == key).status, + DurableOutboxStatus.attention, + ); + // ...the cloud's group is untouched, and there is one copy. + expect(lineupsIn([server.row('link-a')]), + ['Heaven: remote lineup', 'Mid: theirs']); + expect(lineupsIn(copies()), ['Heaven: mine', 'Mid: remote lineup']); + expect(onScreenOf(container), [ + 'Heaven: mine', + 'Mid: newer', + 'Heaven: mine', + 'Mid: remote lineup', + ]); + }); + + test( + 'Keep both while the outbox still cannot save is not offered and ' + 'changes nothing', () async { + final page = _page('page-1', 0); + final store = _FailingOutboxStore(); + final (container, batches, _) = + await refusedBesideTeammate(page, store: store); + final key = keyOf(page, 'link-a'); + final session = container.read(strategyPageSessionProvider.notifier); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + final waiting = queueState().attentionByEntityKey[key]!.pending.op.opId; + // Only the copy's write fails, so nothing but lineup groups waits. + store.failPut = (record) => + record.entityKey.kind == EntitySyncKeyKind.lineup && + record.entityKey != key; + expect(await session.keepBothForRejected(), KeepBothOutcome.copiesOnly); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(queueState().hasDurabilityFailure, isTrue); + final onScreen = onScreenOf(container); + expect(onScreen, hasLength(4)); + + // While writes still fail, the popover does not offer it... + expect(container.read(lineupConflictsProvider), isNull); + // ...and pressed anyway, it changes nothing. + expect( + queueState().attentionByEntityKey.keys, + everyElement(predicate( + (key) => key.kind == EntitySyncKeyKind.lineup))); + expect(await session.keepBothForRejected(), KeepBothOutcome.unchanged); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(onScreenOf(container), onScreen); + expect( + queueState().pending.where((pending) => pending.op is LineupAddOp), + hasLength(1), + reason: 'only the first copy waits to be saved', + ); + expect(queueState().attentionByEntityKey[key]!.pending.op.opId, waiting); + expect(sentFor(batches, key), hasLength(1)); + expect(server.liveRows.map((row) => row.publicId), ['link-a']); + expect(container.read(lineupConflictsProvider), isNull); + }); + + test( + 'an edit to the conflicting group while Use cloud loads the cloud ' + 'version is neither discarded nor replaced', () async { + final page = _page('page-1', 0); + final (container, _, store) = await refusedBesideTeammate(page); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + final refreshes = liveRead.refreshCount; + final gate = liveRead.refreshGate = Completer(); + + final useCloud = container + .read(strategyPageSessionProvider.notifier) + .useCloudVersionsForRejected(); + await _until(() => liveRead.refreshCount > refreshes); + // While the cloud's version is on its way, the user edits the group. + container.read(lineUpProvider.notifier).updateLink(container + .read(lineUpProvider) + .linkById('link-b')! + .copyWith(notes: 'newer')); + var replaced = false; + container.listen(lineUpProvider, (_, next) { + if (next.linkById('link-b')?.notes != 'newer') replaced = true; + }); + gate.complete(); + + expect(await useCloud, isFalse); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(replaced, isFalse); + expect(onScreenOf(container), ['Heaven: mine', 'Mid: newer']); + // The refused work and the newer edit behind it both still wait. + expect(queueState().attentionByEntityKey.keys, [key]); + final newer = queueState().successorByEntityKey[key]!.pending.op; + expect( + _linkIn(newer.payload as CloudPayload, 'link-b')['notes'], 'newer'); + final record = + store.load().records.singleWhere((r) => r.entityKey == key); + expect(record.status, DurableOutboxStatus.attention); + expect(record.successorPending!.op.opId, newer.opId); + expect( + lineupsIn(server.liveRows), ['Heaven: remote lineup', 'Mid: theirs']); + }); + + test( + 'Keep both whose copy is not saved because edit access went away ' + 'discards nothing', () async { + final page = _page('page-1', 0); + final (container, batches, store) = await refusedBesideTeammate(page); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + final waiting = queueState().attentionByEntityKey[key]!.pending.op.opId; + // The cloud read Keep both makes finds the user is a viewer now, so + // the page's edits, the copy included, are no longer saved. + final now = liveRead.initialSnapshot; + liveRead.initialSnapshot = _editorSnapshot( + pages: now.pages, + activePage: now.activePage!, + role: 'viewer', + ); + + final outcome = await container + .read(strategyPageSessionProvider.notifier) + .keepBothForRejected(); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + expect(outcome, KeepBothOutcome.copiesOnly); + expect(queueState().hasDurabilityFailure, isFalse); + expect( + queueState().pending.where((pending) => pending.op is LineupAddOp), + isEmpty, + reason: 'the copy was never queued', + ); + // The waiting work is untouched, in memory and on disk. + expect(queueState().attentionByEntityKey[key]!.pending.op.opId, waiting); + expect( + store.load().records.singleWhere((r) => r.entityKey == key).status, + DurableOutboxStatus.attention, + ); + expect(sentFor(batches, key), hasLength(1)); + expect( + lineupsIn(server.liveRows), ['Heaven: remote lineup', 'Mid: theirs']); + expect(onScreenOf(container), contains('Heaven: mine')); + }); + + test( + 'a canvas edit after Use cloud\'s last save, while it loads the page, ' + 'stops the redraw', () async { + final page = _page('page-1', 0); + final (container, _, store) = await refusedBesideTeammate(page); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + // The cloud read comes back before the page itself, so loading the + // page waits for it: the one wait between the last save and the + // redraw. The user's edit lands there. + final now = liveRead.initialSnapshot; + liveRead.initialSnapshot = + RemoteEditorSnapshot(shell: now.shell, activePage: null); + var replaced = false; + var edited = false; + liveRead.onSetActivePage = (pageId) { + if (edited || pageId != page.publicId) return; + edited = true; + container.read(lineUpProvider.notifier).updateLink(container + .read(lineUpProvider) + .linkById('link-b')! + .copyWith(notes: 'later')); + container.listen(lineUpProvider, (_, next) { + if (next.linkById('link-b')?.notes != 'later') replaced = true; + }); + }; + + final resolved = await container + .read(strategyPageSessionProvider.notifier) + .useCloudVersionsForRejected(); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + expect(edited, isTrue, reason: 'the edit landed in the window'); + expect(resolved, isFalse); + expect(replaced, isFalse); + expect(onScreenOf(container), ['Heaven: mine', 'Mid: later']); + expect(queueState().attentionByEntityKey.keys, [key]); + expect( + store.load().records.singleWhere((r) => r.entityKey == key).status, + DurableOutboxStatus.attention, + ); + expect( + lineupsIn(server.liveRows), ['Heaven: remote lineup', 'Mid: theirs']); + }); + + test( + 'an edit made while Use cloud\'s last save is being written stops the ' + 'redraw', () async { + final page = _page('page-1', 0); + final store = _FailingOutboxStore(); + final (container, _, _) = + await refusedBesideTeammate(page, store: store, elements: [ + _textElement(page.publicId, 'text-a', 'a'), + _textElement(page.publicId, 'text-b', 'b', sortIndex: 1), + ]); + String textOf(String id) => + container.read(textProvider).singleWhere((t) => t.id == id).text; + final refreshes = liveRead.refreshCount; + final gate = liveRead.refreshGate = Completer(); + + final useCloud = container + .read(strategyPageSessionProvider.notifier) + .useCloudVersionsForRejected(); + await _until(() => liveRead.refreshCount > refreshes); + // An edit made while the cloud's version loads gives the last save + // something to write... + container + .read(textProvider.notifier) + .updatePosition(const Offset(300, 300), 'text-a'); + // ...and while that write is on its way, the user types elsewhere. + var typed = false; + var replaced = false; + store.onPut = (record) { + if (typed || record.entityKey.entityId != 'text-a') return; + typed = true; + container.read(textProvider.notifier).commitText('text-b', 'typed'); + container.listen(textProvider, (_, next) { + if (next.singleWhere((t) => t.id == 'text-b').text != 'typed') { + replaced = true; + } + }); + }; + gate.complete(); + + final resolved = await useCloud; + for (var i = 0; i < 10; i++) { + await _settle(); + } + + expect(typed, isTrue, reason: 'the edit landed during the write'); + expect(replaced, isFalse, reason: 'the redraw put back the old text'); + expect(textOf('text-b'), 'typed'); + expect(resolved, isFalse); + }); + + test( + 'Keep both pressed again while the copy still cannot be saved ' + 'discards nothing and redraws nothing', () async { + final page = _page('page-1', 0); + final (container, batches, store) = await refusedBesideTeammate(page); + final key = keyOf(page, 'link-a'); + final session = container.read(strategyPageSessionProvider.notifier); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + final waiting = queueState().attentionByEntityKey[key]!.pending.op.opId; + // Keep both's reads find the user is a viewer now, so nothing they + // edit is saved, the copy included. + final now = liveRead.initialSnapshot; + liveRead.initialSnapshot = _editorSnapshot( + pages: now.pages, + activePage: now.activePage!, + role: 'viewer', + ); + expect(await session.keepBothForRejected(), KeepBothOutcome.copiesOnly); + for (var i = 0; i < 10; i++) { + await _settle(); + } + final withCopy = onScreenOf(container); + expect(withCopy, hasLength(4)); + + // Pressed again, still a viewer: the copy it remembers is still not + // saved, so the original is not discarded on its behalf. + var redrawn = false; + container.listen(lineUpProvider, (_, __) => redrawn = true); + expect(await session.keepBothForRejected(), KeepBothOutcome.copiesOnly); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + expect(redrawn, isFalse); + expect(onScreenOf(container), withCopy); + expect(queueState().attentionByEntityKey[key]!.pending.op.opId, waiting); + expect( + store.load().records.singleWhere((r) => r.entityKey == key).status, + DurableOutboxStatus.attention, + ); + expect( + queueState().pending.where((pending) => pending.op is LineupAddOp), + isEmpty, + ); + expect(sentFor(batches, key), hasLength(1)); + expect( + lineupsIn(server.liveRows), ['Heaven: remote lineup', 'Mid: theirs']); + }); + + test( + 'an edit whose save fails while Use cloud loads the cloud version ' + 'stops it: the edit stays on screen and nothing is discarded', + () async { + final page = _page('page-1', 0); + final store = _FailingOutboxStore(); + final (container, batches, _) = + await refusedBesideTeammate(page, store: store); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + final waiting = queueState().attentionByEntityKey[key]!.pending.op.opId; + final refreshes = liveRead.refreshCount; + final gate = liveRead.refreshGate = Completer(); + + final useCloud = container + .read(strategyPageSessionProvider.notifier) + .useCloudVersionsForRejected(); + await _until(() => liveRead.refreshCount > refreshes); + // While the cloud's version is on its way, the user edits the group, + // and that edit cannot be written to the outbox. + store.failPut = (record) => record.entityKey == key; + container.read(lineUpProvider.notifier).updateLink(container + .read(lineUpProvider) + .linkById('link-b')! + .copyWith(notes: 'newer')); + var replaced = false; + container.listen(lineUpProvider, (_, next) { + if (next.linkById('link-b')?.notes != 'newer') replaced = true; + }); + gate.complete(); + + expect(await useCloud, isFalse); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(queueState().hasDurabilityFailure, isTrue); + expect(replaced, isFalse); + expect(onScreenOf(container), ['Heaven: mine', 'Mid: newer']); + // The refused work is not discarded, in memory or on disk. + expect(queueState().attentionByEntityKey[key]!.pending.op.opId, waiting); + final record = + store.load().records.singleWhere((r) => r.entityKey == key); + expect(record.status, DurableOutboxStatus.attention); + expect(record.pending.op.opId, waiting); + expect(sentFor(batches, key), hasLength(1)); + expect( + lineupsIn(server.liveRows), ['Heaven: remote lineup', 'Mid: theirs']); + }); + + /// The server's refusal of lineup group [key] for overlapping another. + OpAck? Function(StrategyOp op) refuseAsOverlapping(EntitySyncKey key) => + (op) => EntitySyncKey.forStrategyOp(op) == key + ? FailedOpAck( + opId: op.opId, + code: 'INVALID_LINEUP_PAYLOAD_DATA', + rawCode: 'INVALID_LINEUP_PAYLOAD_DATA', + message: lineupOverlapMessage, + ) + : null; + + test( + 'a lineup group refused for overlapping another, alone, reaches the ' + 'sync button as exactly that reason', () async { + final page = _page('page-1', 0); + server = _FakeServer(page.publicId, lineups: [fanIn(page.publicId)]); + final (container, _) = await openOnRealQueue(page); + final key = keyOf(page, 'link-a'); + repository.refuse = refuseAsOverlapping(key); + + container.read(lineUpProvider.notifier).updateLink(container + .read(lineUpProvider) + .linkById('link-a')! + .copyWith(notes: 'mine')); + await _until(() => container + .read(strategyOpQueueProvider) + .attentionByEntityKey + .containsKey(key)); + for (var i = 0; i < 10; i++) { + await _settle(); + } + + expect(container.read(strategyOpQueueProvider).lastError, + lineupOverlapMessage); + expect(container.read(strategySaveStateProvider).cloudSyncError, + lineupOverlapMessage); + }); + + test( + 'an overlap refusal beside a teammate deletion Keep mine can restore ' + 'is not reported as the only reason', () async { + final page = _page('page-1', 0); + server = _FakeServer(page.publicId, lineups: [ + fanIn(page.publicId), + _lineup(page.publicId, 'd', sortIndex: 1), + ]); + final (container, _) = await openOnRealQueue(page); + final overlapping = keyOf(page, 'link-a'); + final deleted = keyOf(page, 'link-d'); + repository.refuse = refuseAsOverlapping(overlapping); + // A teammate deletes lineup d; the user edits both groups. + server.teammateDelete('link-d'); final lineUps = container.read(lineUpProvider.notifier); - lineUps.updateLink(placed.copyWith(images: images(['a', 'b', 'c']))); - var lineups = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); lineUps.updateLink(container .read(lineUpProvider) - .links - .single - .copyWith(images: images(['a', 'c']))); - // Our removal of b lands, and a teammate adds x right after a. - lineups = await land( - container, - remote, - page, - previous: lineups, - revision: 2, - contentRevision: 3, - teammate: (kind, data) { - if (kind != CloudLineupKind.link) return; - (data['images'] as List) - .insert(1, {'id': 'x', 'fileExtension': '.png'}); - }, + .linkById('link-a')! + .copyWith(notes: 'mine')); + lineUps.updateLink(container + .read(lineUpProvider) + .linkById('link-d')! + .copyWith(notes: 'mine')); + await _until(() => + container.read(strategyOpQueueProvider).attentionByEntityKey.length == + 2); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect( + container.read(strategyOpQueueProvider).attentionByEntityKey.keys, + unorderedEquals([overlapping, deleted]), ); - expect(imageIds(container), ['a', 'x', 'c']); - final history = container.read(actionProvider.notifier); - history.undoAction(); - expect(imageIds(container), ['a', 'x', 'b', 'c']); - history.redoAction(); - expect(imageIds(container), ['a', 'x', 'c']); - history.undoAction(); - expect(imageIds(container), ['a', 'x', 'b', 'c']); - await _settle(); + // Keep mine can bring lineup d back, so the overlap is not the only + // reason, and the sync button must not read as if it were. + expect(container.read(strategySaveStateProvider).cloudSyncError, + isNot(lineupOverlapMessage)); }); - test('undoing a visibility toggle keeps a teammate toggle', () async { - final (container, remote, page) = await openEmpty(); - final link = place(container); - var lineups = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); - final landing = container.read(lineUpProvider).landings.single; - container.read(lineUpProvider.notifier).updateLandingAbilityVisualState( - landingId: link.landingId, - visualState: - landing.ability.visualState.copyWith(showRangeOutline: false), - ); - lineups = await land( - container, - remote, - page, - previous: lineups, - revision: 2, - contentRevision: 3, - teammate: (kind, data) { - if (kind != CloudLineupKind.landing) return; - ((data['ability'] as Map)['visualState'] as Map)['showRangeFill'] = - false; - }, + test( + 'a move made while Use cloud discards, when the discard partly ' + 'fails, is not drawn over by the redraw that follows', () async { + final page = _page('page-1', 0); + final store = _FailingOutboxStore(); + final (container, _, _) = await refusedBesideTeammate(page, + store: store, elements: [_textElement(page.publicId, 'text-a', 'a')]); + final key = keyOf(page, 'link-a'); + Offset textAt() => container + .read(textProvider) + .singleWhere((text) => text.id == 'text-a') + .position; + const moved = Offset(300, 300); + // Removing the refused work from the outbox fails; while it is on its + // way, the user moves the text. + var movedDuringDiscard = false; + store.onRemove = (storageKey) { + if (movedDuringDiscard) return; + movedDuringDiscard = true; + container.read(textProvider.notifier).updatePosition(moved, 'text-a'); + }; + store.failRemove = (storageKey) => true; + var redrawnOver = false; + + final useCloud = container + .read(strategyPageSessionProvider.notifier) + .useCloudVersionsForRejected(); + await _until(() => movedDuringDiscard); + container.listen(textProvider, (_, next) { + if (next.singleWhere((text) => text.id == 'text-a').position != moved) { + redrawnOver = true; + } + }); + + expect(await useCloud, isFalse); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(redrawnOver, isFalse); + expect(textAt(), moved); + // The refused work still waits: its record could not be removed. + expect(container.read(strategyOpQueueProvider).attentionByEntityKey.keys, + [key]); + }); + + test( + 'Use cloud after storage recovers from a failed discard does not ' + 'claim success while the work goes out again, and the next press ' + 'resolves it', () async { + final page = _page('page-1', 0); + final store = _FailingOutboxStore(); + final (container, batches, _) = + await refusedBesideTeammate(page, store: store); + final key = keyOf(page, 'link-a'); + final session = container.read(strategyPageSessionProvider.notifier); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + + // The first press cannot remove the refused work from the outbox. + store.failRemove = (storageKey) => true; + expect(await session.useCloudVersionsForRejected(), isFalse); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(queueState().attentionByEntityKey.keys, [key]); + expect(queueState().lastError, contains('could not be removed')); + expect(onScreenOf(container), ['Heaven: mine', 'Mid: remote lineup']); + + // Storage recovers. The record the removal left uncertain goes back + // to the send queue on the next save, so this press finds nothing to + // resolve; it says so rather than claim the cloud's version is shown. + store.failRemove = null; + expect(await session.useCloudVersionsForRejected(), isFalse); + expect(onScreenOf(container), ['Heaven: mine', 'Mid: remote lineup']); + + // The refused work goes out once more and is refused again: the + // teammate's version stands. + await _until(() => + sentFor(batches, key).length == 2 && + queueState().attentionByEntityKey.containsKey(key)); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(sentFor(batches, key)[1].opId, sentFor(batches, key)[0].opId); + expect( + queueState() + .lastAckBatch + .singleWhere((acked) => acked.entityKey == key) + .ack, + isA().having((ack) => ack.rejectionReason, 'reason', + OpRejectionReason.revisionMismatch), ); + expect(server.row('link-a').revision, 8); + expect( + lineupsIn(server.liveRows), ['Heaven: remote lineup', 'Mid: theirs']); - container.read(actionProvider.notifier).undoAction(); + // A further press takes the cloud's version. (The strategy's own + // details it saves on the way land too.) + expect(await session.useCloudVersionsForRejected(), isTrue); + await _until(() => queueState().pending.isEmpty); + for (var i = 0; i < 10; i++) { + await _settle(); + } + expect(onScreenOf(container), ['Heaven: remote lineup', 'Mid: theirs']); + expect(queueState().attentionByEntityKey, isEmpty); + expect(queueState().needsAttention, isFalse); + expect(queueState().pending, isEmpty); + expect(store.load().records, isEmpty); + expect(sentFor(batches, key), hasLength(2)); + }); - final visual = container - .read(lineUpProvider) - .landingById(link.landingId)! - .ability - .visualState; - expect(visual.showRangeOutline, isTrue); - expect(visual.showRangeFill, isFalse); + test( + 'Keep both after the user deleted the copy an earlier press made ' + 'copies again and resolves, one copy in all', () async { + final page = _page('page-1', 0); + final (container, _, store) = await refusedBesideTeammate(page); + final session = container.read(strategyPageSessionProvider.notifier); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + List copies() => [ + for (final row in server.liveRows) + if (row.publicId != 'link-a') row, + ]; + List copyLinkIds() => [ + for (final link in container.read(lineUpProvider).links) + if (link.id != 'link-a' && link.id != 'link-b') link.id, + ]; + Future landed() async { + await _until(() => + queueState().queuedByEntityKey.isEmpty && + queueState().inFlightByEntityKey.isEmpty); + for (var i = 0; i < 10; i++) { + await _settle(); + } + } + + // The first press copies, then cannot load the cloud's version. + final first = liveRead.refreshCount + 1; + liveRead.readFailsWhen = (count) => count > first; + expect(await session.keepBothForRejected(), KeepBothOutcome.copiesOnly); + await landed(); + expect(copies(), hasLength(1)); + final firstCopy = copyLinkIds(); + expect(firstCopy, hasLength(2)); + + // The cloud is reachable again; the user deletes the copy, and the + // deletion lands. + liveRead.readFailsWhen = null; + showServer(); + await _settle(); + final lineUps = container.read(lineUpProvider.notifier); + for (final id in firstCopy) { + lineUps.deleteLink(id); + } await _settle(); + await container.read(strategyOpQueueProvider.notifier).flushNow(); + await _until(() => copies().isEmpty); + await landed(); + expect(copyLinkIds(), isEmpty); + + // Pressed again with the cloud reachable: a fresh copy, and resolved. + expect(await session.keepBothForRejected(), KeepBothOutcome.kept); + await landed(); + + final copy = copies().single; + expect(lineupsIn([copy]), ['Heaven: mine', 'Mid: remote lineup']); + expect(copyLinkIds(), hasLength(2)); + expect(copyLinkIds().toSet().intersection(firstCopy.toSet()), isEmpty); + expect( + onScreenOf(container), + unorderedEquals([ + 'Heaven: remote lineup', + 'Mid: theirs', + 'Heaven: mine', + 'Mid: remote lineup', + ]), + ); + expect(queueState().attentionByEntityKey, isEmpty); + expect(store.load().records, isEmpty); }); - test('an ack refresh that already holds a teammate change shows it', - () async { - final (container, remote, page) = await openEmpty(); - final link = place(container); - var lineups = await land(container, remote, page, - previous: const [], revision: 1, contentRevision: 2); - const moved = Offset(500, 500); - container - .read(lineUpProvider.notifier) - .updateOriginAgentPosition(link.originId, moved); - // Our move lands and, in the same server state, a teammate arms it. - lineups = await land( - container, - remote, - page, - previous: lineups, - revision: 2, - contentRevision: 3, - teammate: (kind, data) { - if (kind != CloudLineupKind.origin) return; - (data['agent'] as Map)['weapon'] = 'vandal'; - }, - ); + test( + 'Keep both after the user deleted one lineup of the copy keeps the ' + 'rest of it and resolves without a second copy', () async { + final page = _page('page-1', 0); + final (container, _, store) = await refusedBesideTeammate(page); + final session = container.read(strategyPageSessionProvider.notifier); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + List copies() => [ + for (final row in server.liveRows) + if (row.publicId != 'link-a') row, + ]; + List copiedLinks() => [ + for (final link in container.read(lineUpProvider).links) + if (link.id != 'link-a' && link.id != 'link-b') link, + ]; + Future landed() async { + await _until(() => queueState() + .pending + .where((work) => !queueState() + .attentionByEntityKey + .values + .any((waiting) => waiting.pending.op.opId == work.op.opId)) + .isEmpty); + for (var i = 0; i < 10; i++) { + await _settle(); + } + } - final origin = container.read(lineUpProvider).originById(link.originId)!; - expect(origin.agent.position, moved); - expect(origin.agent.weapon, WeaponType.vandal); - final ops = desiredOps(container, page); - expect(ops[keyOf(page, CloudLineupKind.origin, link.originId)], isNull); + // The first press copies both lineups, then cannot load the cloud's + // version. + final first = liveRead.refreshCount + 1; + liveRead.readFailsWhen = (count) => count > first; + expect(await session.keepBothForRejected(), KeepBothOutcome.copiesOnly); + await landed(); + expect(lineupsIn(copies()), ['Heaven: mine', 'Mid: remote lineup']); + + // The cloud is reachable again; the user deletes one copied lineup. + liveRead.readFailsWhen = null; + showServer(); + await _settle(); + final heaven = copiedLinks().singleWhere((link) => link.name == 'Heaven'); + final mid = copiedLinks().singleWhere((link) => link.name == 'Mid'); + container.read(lineUpProvider.notifier).deleteLink(heaven.id); await _settle(); + await container.read(strategyOpQueueProvider.notifier).flushNow(); + await _until(() => lineupsIn(copies()).length == 1); + await landed(); + + // Pressed again: the rest of the copy stands, nothing is copied again. + expect(await session.keepBothForRejected(), KeepBothOutcome.kept); + await landed(); + + expect(lineupsIn(copies()), ['Mid: remote lineup']); + expect(copiedLinks().map((link) => link.id), [mid.id]); + expect( + onScreenOf(container), + unorderedEquals( + ['Heaven: remote lineup', 'Mid: theirs', 'Mid: remote lineup']), + ); + expect(queueState().attentionByEntityKey, isEmpty); + expect(queueState().needsAttention, isFalse); + expect(store.load().records, isEmpty); }); - test('an ack while another page is active does not revive the old lineup', - () async { - final first = _page('page-1', 0); - final second = _page('page-2', 1); - final secondSnapshot = _pageSnapshot(second, settings: settingsFor(9)); - final remote = _FakeRemoteEditorNotifier( - _editorSnapshot( - pages: [first, second], - activePage: _pageSnapshot(first, settings: settingsFor(1)), - ), - pageCatalog: { - first.publicId: _pageSnapshot(first, settings: settingsFor(1)), - second.publicId: secondSnapshot, - }, + test( + 'Use cloud pressed before a deleted-on-both-sides refusal settles ' + 'counts its settling as resolved', () async { + final page = _page('page-1', 0); + server = + _FakeServer(page.publicId, lineups: [_lineup(page.publicId, 'a')]); + final store = MemoryDurableStrategyOutboxStore(); + final (container, batches) = await openOnRealQueue(page, store: store); + final key = _lineupKey(page.publicId, 'a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + + // A teammate deletes the lineup while the user edits it: refused as + // deleted. + server.teammateDelete('link-a'); + container.read(lineUpProvider.notifier).updateLink(container + .read(lineUpProvider) + .linkById('link-a')! + .copyWith(notes: 'mine')); + await refusedAsDeleted(container, batches, key); + + // The user deletes it too and, before that is saved, presses Use + // cloud: its save settles the refusal, both sides having it gone. + container.read(lineUpProvider.notifier).deleteLink('link-a'); + expect(queueState().attentionByEntityKey.keys, [key]); + expect( + await container + .read(strategyPageSessionProvider.notifier) + .useCloudVersionsForRejected(), + isTrue, ); - queue = _FakeStrategyOpQueueNotifier(); - final container = await _cloudContainer(remote: remote, queue: queue); - final session = container.read(strategyPageSessionProvider.notifier); - await session.initializeForStrategy( - strategyId: 'cloud-strategy', - source: StrategySource.cloud, - selectFirstPageIfNeeded: true, + for (var i = 0; i < 10; i++) { + await _settle(); + } + + expect(queueState().attentionByEntityKey, isEmpty); + expect(queueState().needsAttention, isFalse); + expect( + [for (final record in store.load().records) record.entityKey], + isNot(contains(key)), ); - final link = place(container); - await _settle(); - var ops = queuedOps(); - var lineups = apply(ops.values, first, revision: 1, previous: const []); - remote.initialSnapshot = - serverSnapshot(first, lineups, 2, pages: [first, second]); - remote.pageCatalog[first.publicId] = remote.initialSnapshot.activePage!; - publishAcks(ops, 1); - await settleSync(container, 2); + expect(container.read(lineUpProvider).links, isEmpty); + expect(server.row('link-a').deleted, isTrue); + expect(sentFor(batches, key), hasLength(1)); + }); - const moved = Offset(500, 500); - container - .read(lineUpProvider.notifier) - .updateOriginAgentPosition(link.originId, moved); - await session.setActivePage(second.publicId); - await _settle(); - expect(container.read(strategySettingsProvider).agentSize, 39); + test( + 'after Keep both, exporting the strategy to .ica and importing it ' + 'brings back both versions', () async { + final page = _page('page-1', 0); + final (container, _, _) = await refusedBesideTeammate(page); + final kept = await container + .read(strategyPageSessionProvider.notifier) + .keepBothForRejected(); + expect(kept, KeepBothOutcome.kept); + await _until(() => + container.read(strategyOpQueueProvider).pending.isEmpty && + server.liveRows.length == 2); + + // Exported from the server's copy, as the cloud library exports. + final now = DateTime.utc(2026); + final exported = + StrategyImportExportService.strategyDataFromRemoteSnapshot( + RemoteFullStrategySnapshot( + header: RemoteStrategyHeader( + publicId: 'cloud-strategy', + name: 'Cloud Strategy', + mapData: Maps.mapNames[MapValue.ascent]!, + revision: 1, + createdAt: now, + updatedAt: now, + ), + pages: [ + RemoteFullPage( + page: page, + content: RemotePageContent( + settings: settingsFor(1), + revision: 1, + createdAt: now, + updatedAt: now, + ), + ), + ], + elementsByPage: const {}, + lineupsByPage: {page.publicId: server.rows}, + assetsById: const {}, + ), + ); - // Page 1's move lands with a teammate's weapon change while page 2 is - // on screen. - ops = queuedOps(); - expect(ops.keys.where((key) => key.pageId == first.publicId), isNotEmpty); - lineups = apply( - ops.values, - first, - revision: 2, - previous: lineups, - teammate: (kind, data) { - if (kind != CloudLineupKind.origin) return; - (data['agent'] as Map)['weapon'] = 'vandal'; - }, + final box = await _openStrategyBox(); + await Hive.openBox(HiveBoxNames.mapThemeProfilesBox); + final files = await Directory.systemTemp.createTemp('icarus-keep-both-'); + addTearDown(() => files.delete(recursive: true)); + final messenger = + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger; + const pathProvider = MethodChannel('plugins.flutter.io/path_provider'); + messenger.setMockMethodCallHandler( + pathProvider, (call) async => files.path); + addTearDown(() => messenger.setMockMethodCallHandler(pathProvider, null)); + + final service = StrategyImportExportService(container); + final archive = await service.zipStrategyData( + strategy: exported, + outputFilePath: '${files.path}${Platform.pathSeparator}Keep both.ica', ); - remote.pageCatalog[first.publicId] = _pageSnapshot( - first, - settings: settingsFor(3), - contentRevision: 3, - lineups: lineups, + await service.loadFromFilePath(archive); + + final imported = box.values.single; + final graph = imported.pages.single.lineUpGraph; + List described(LineUpGraph graph) => [ + for (final link in graph.links) '${link.name}: ${link.notes}', + ]; + expect( + described(graph), + described(exported.pages.single.lineUpGraph), ); - remote.initialSnapshot = _editorSnapshot( - pages: [first, second], - activePage: secondSnapshot, + expect(described(graph), [ + 'Heaven: remote lineup', + 'Mid: theirs', + 'Heaven: mine', + 'Mid: remote lineup', + ]); + expect(graph.origins, hasLength(4)); + expect(graph.landings, hasLength(2)); + expect( + jsonEncode(graph.toJson()), + jsonEncode(exported.pages.single.lineUpGraph.toJson()), ); - publishAcks(ops, 2); - await settleSync(container, 9); + }); - await session.setActivePage(first.publicId); - await settleSync(container, 3); + test( + 'refused work the user then deletes on canvas stays in attention ' + 'unless the refusal said the item was deleted', () async { + final page = _page('page-1', 0); + final (container, batches, store) = await refusedBesideTeammate(page); + final key = keyOf(page, 'link-a'); + StrategyOpQueueState queueState() => + container.read(strategyOpQueueProvider); + + // The teammate then deletes the group, and the user deletes both its + // lineups on the canvas: both sides have it gone, but the refusal was + // a revision mismatch, not a deletion. + server.teammateDelete('link-a'); + showServer(); + final lineUps = container.read(lineUpProvider.notifier); + lineUps.deleteLink('link-a'); + lineUps.deleteLink('link-b'); + expect(container.read(lineUpProvider).links, isEmpty); + for (var i = 0; i < 20; i++) { + await _settle(); + } - final origin = container.read(lineUpProvider).originById(link.originId)!; - expect(origin.agent.position, moved); - expect(origin.agent.weapon, WeaponType.vandal); + // Nothing about the refusal says the server deleted what it edits, so + // the work is not dropped in silence: it still waits. + expect(queueState().attentionByEntityKey.keys, [key]); + expect(queueState().needsAttention, isTrue); expect( - desiredOps(container, first)[ - keyOf(first, CloudLineupKind.origin, link.originId)], - isNull, + store.load().records.singleWhere((r) => r.entityKey == key).status, + DurableOutboxStatus.attention, ); - await _settle(); + expect(container.read(strategyConflictProvider), hasLength(1)); + expect(sentFor(batches, key), hasLength(1)); }); }); @@ -5588,7 +8561,7 @@ void main() { pages: [page], activePage: _pageSnapshot( page, - lineups: _lineupRows(page.publicId, 'lineup-a'), + lineups: [_lineup(page.publicId, 'lineup-a')], ), )); final container = await _cloudContainer( @@ -5652,9 +8625,8 @@ void main() { .updateOriginAgentPosition('lineup-a', moved); // The move lands and a teammate's lineup B arrives with it. await ackAndRehydrate(container, remote, page, [ - ..._lineupRows(page.publicId, 'lineup-a', - agentPosition: moved, revision: 2), - ..._lineupRows(page.publicId, 'lineup-b', sortIndex: 3), + _lineup(page.publicId, 'lineup-a', agentPosition: moved, revision: 2), + _lineup(page.publicId, 'lineup-b', sortIndex: 1), ]); expect( container.read(lineUpProvider).origins.map((origin) => origin.id), @@ -5680,7 +8652,7 @@ void main() { expect(desired, isNotNull); expect(desired!.values.whereType(), isEmpty); expect( - desired[_originKey(page.publicId, 'lineup-a')], + desired[_lineupKey(page.publicId, 'lineup-a')], isA(), ); expect( @@ -5699,7 +8671,7 @@ void main() { pages: [page], activePage: _pageSnapshot( page, - lineups: _lineupRows(page.publicId, 'lineup-1'), + lineups: [_lineup(page.publicId, 'lineup-1')], ), )), queue: _FakeStrategyOpQueueNotifier(), @@ -5744,7 +8716,7 @@ void main() { page, text: 'remote', contentRevision: 2, - lineups: _lineupRows(page.publicId, 'lineup-1'), + lineups: [_lineup(page.publicId, 'lineup-1')], ), )); @@ -6715,31 +9687,15 @@ void main() { expect(container.read(textProvider), isEmpty); }); - /// [lineup]'s rows as a teammate left them with [notes] on its link. - List withNotes(List lineup, String notes) { - return [ - for (final row in lineup) - if (row.payload['kind'] != CloudLineupKind.link) - row - else - RemoteLineup( - publicId: row.publicId, - strategyPublicId: row.strategyPublicId, - pagePublicId: row.pagePublicId, - payload: (jsonDecode(jsonEncode(row.payload)) as CloudPayload) - ..['data']['notes'] = notes, - sortIndex: row.sortIndex, - revision: row.revision + 1, - deleted: false, - ), - ]; - } + /// [lineup]'s row as a teammate left it, with [notes]. + List withNotes(RemoteLineup lineup, String notes) => + [_editedLineup(lineup, (link) => link['notes'] = notes)]; test( 'redoing a lineup clear a teammate already undid by deleting ' 'does not resurrect it on the next undo', () async { - final mine = _lineupRows('page-1', 'mine'); - final (container, remote, page) = await open(const [], lineups: mine); + final mine = _lineup('page-1', 'mine'); + final (container, remote, page) = await open(const [], lineups: [mine]); history(container).clearGroupAsAction(ActionGroup.lineUp); history(container).undoAction(); @@ -6753,15 +9709,15 @@ void main() { expect( desiredOps(container, page) .keys - .where(_lineupRowKeys(page.publicId, 'mine').contains), + .where((key) => key == _lineupKey(page.publicId, 'mine')), isEmpty, ); }); test('a lineup clear redone and undone keeps a teammate notes edit', () async { - final mine = _lineupRows('page-1', 'mine'); - final (container, remote, page) = await open(const [], lineups: mine); + final mine = _lineup('page-1', 'mine'); + final (container, remote, page) = await open(const [], lineups: [mine]); history(container).clearGroupAsAction(ActionGroup.lineUp); history(container).undoAction(); @@ -6782,8 +9738,8 @@ void main() { test( 'undoing a lineup clear leaves a lineup a teammate restored, ' 'and redo does not remove it', () async { - final mine = _lineupRows('page-1', 'mine'); - final (container, remote, page) = await open(const [], lineups: mine); + final mine = _lineup('page-1', 'mine'); + final (container, remote, page) = await open(const [], lineups: [mine]); history(container).clearGroupAsAction(ActionGroup.lineUp); await land(container, remote, page, lineups: withNotes(mine, 'restored')); @@ -6802,8 +9758,8 @@ void main() { test( 'redoing a lineup deletion a teammate already made removes nothing ' 'and the next undo does not resurrect it', () async { - final mine = _lineupRows('page-1', 'mine'); - final (container, remote, page) = await open(const [], lineups: mine); + final mine = _lineup('page-1', 'mine'); + final (container, remote, page) = await open(const [], lineups: [mine]); container.read(lineUpProvider.notifier).deleteOrigin('mine'); history(container).undoAction(); @@ -6818,7 +9774,7 @@ void main() { expect( desiredOps(container, page) .keys - .where(_lineupRowKeys(page.publicId, 'mine').contains), + .where((key) => key == _lineupKey(page.publicId, 'mine')), isEmpty, ); }); @@ -6861,8 +9817,8 @@ void main() { }); test('a lineup weapon change a teammate deleted leaves history', () async { - final mine = _lineupRows('page-1', 'mine'); - final (container, remote, page) = await open(const [], lineups: mine); + final mine = _lineup('page-1', 'mine'); + final (container, remote, page) = await open(const [], lineups: [mine]); container .read(lineUpProvider.notifier) @@ -6874,8 +9830,8 @@ void main() { test('undoing a lineup weapon change a teammate deleted does nothing', () async { - final mine = _lineupRows('page-1', 'mine'); - final (container, remote, page) = await open(const [], lineups: mine); + final mine = _lineup('page-1', 'mine'); + final (container, remote, page) = await open(const [], lineups: [mine]); container .read(lineUpProvider.notifier) @@ -6891,8 +9847,8 @@ void main() { test( 'undoing a lineup notes edit whose link a teammate deleted does ' 'nothing', () async { - final mine = _lineupRows('page-1', 'mine'); - final (container, remote, page) = await open(const [], lineups: mine); + final mine = _lineup('page-1', 'mine'); + final (container, remote, page) = await open(const [], lineups: [mine]); final lineUps = container.read(lineUpProvider.notifier); lineUps.updateLink( @@ -6912,32 +9868,6 @@ void main() { expect(container.read(lineUpProvider).links, isEmpty); }); - /// [lineup]'s rows with the link's data changed by [edit], as a teammate - /// left them. - List editLink( - List lineup, - void Function(Map link) edit, - ) { - RemoteLineup edited(RemoteLineup row) { - final payload = jsonDecode(jsonEncode(row.payload)) as CloudPayload; - edit(payload['data'] as Map); - return RemoteLineup( - publicId: row.publicId, - strategyPublicId: row.strategyPublicId, - pagePublicId: row.pagePublicId, - payload: payload, - sortIndex: row.sortIndex, - revision: row.revision + 1, - deleted: false, - ); - } - - return [ - for (final row in lineup) - row.payload['kind'] == CloudLineupKind.link ? edited(row) : row, - ]; - } - Map image(String id) => {'id': id, 'fileExtension': '.png'}; @@ -6950,11 +9880,11 @@ void main() { test( 'redoing an image removal a teammate already made, then undoing, ' 'does not bring the image back', () async { - final mine = editLink( - _lineupRows('page-1', 'mine'), + final mine = _editedLineup( + _lineup('page-1', 'mine'), (link) => link['images'] = [image('x'), image('y')], ); - final (container, remote, page) = await open(const [], lineups: mine); + final (container, remote, page) = await open(const [], lineups: [mine]); final link = container.read(lineUpProvider).links.single; container.read(lineUpProvider.notifier).updateLink( @@ -6965,8 +9895,9 @@ void main() { history(container).undoAction(); expect(linkImages(container), ['x', 'y']); // A teammate removes x too. - await land(container, remote, page, - lineups: editLink(mine, (link) => link['images'] = [image('y')])); + await land(container, remote, page, lineups: [ + _editedLineup(mine, (link) => link['images'] = [image('y')]), + ]); expect(linkImages(container), ['y']); history(container).redoAction(); @@ -6978,11 +9909,11 @@ void main() { test( 'an edit that removed an image and changed notes replays only the ' 'notes once a teammate removed the image', () async { - final mine = editLink( - _lineupRows('page-1', 'mine'), + final mine = _editedLineup( + _lineup('page-1', 'mine'), (link) => link['images'] = [image('x'), image('y')], ); - final (container, remote, page) = await open(const [], lineups: mine); + final (container, remote, page) = await open(const [], lineups: [mine]); final link = container.read(lineUpProvider).links.single; container.read(lineUpProvider.notifier).updateLink( @@ -6992,8 +9923,9 @@ void main() { ), ); history(container).undoAction(); - await land(container, remote, page, - lineups: editLink(mine, (link) => link['images'] = [image('y')])); + await land(container, remote, page, lineups: [ + _editedLineup(mine, (link) => link['images'] = [image('y')]), + ]); history(container).redoAction(); expect(container.read(lineUpProvider).links.single.notes, 'mine'); @@ -7266,12 +10198,12 @@ void main() { test('undoing a lineup clear keeps a lineup a teammate added', () async { final (container, remote, page) = - await open(const [], lineups: _lineupRows('page-1', 'mine')); + await open(const [], lineups: [_lineup('page-1', 'mine')]); history(container).clearGroupAsAction(ActionGroup.lineUp); expect(container.read(lineUpProvider).origins, isEmpty); await land(container, remote, page, - lineups: _lineupRows(page.publicId, 'theirs')); + lineups: [_lineup(page.publicId, 'theirs')]); history(container).undoAction(); expect( diff --git a/test/unsaved_strategy_guard_test.dart b/test/unsaved_strategy_guard_test.dart index c37000ec..f77e8b51 100644 --- a/test/unsaved_strategy_guard_test.dart +++ b/test/unsaved_strategy_guard_test.dart @@ -594,7 +594,7 @@ void main() { clientId: 'guard-client', attentionByEntityKey: {_guardEntityKey: _guardPendingIntent}, durableLoaded: true, - lastError: lineupLinkEndMissingMessage, + lastError: lineupPageMismatchMessage, ), ); container = ProviderContainer( @@ -618,7 +618,7 @@ void main() { await tester.pumpAndSettle(); expect(find.text('Leave anyway'), findsOneWidget); - expect(find.textContaining('on this page in the cloud'), findsOneWidget); + expect(find.textContaining('another page'), findsOneWidget); expect(find.textContaining('from the sync button'), findsOneWidget); expect(find.textContaining('retry it later'), findsNothing); await tester.tap(find.text('Leave anyway')); diff --git a/test/widgets/cloud_sync_button_test.dart b/test/widgets/cloud_sync_button_test.dart index 605d0810..a5e38be7 100644 --- a/test/widgets/cloud_sync_button_test.dart +++ b/test/widgets/cloud_sync_button_test.dart @@ -13,6 +13,7 @@ import 'package:icarus/providers/collab/client_upgrade_required_provider.dart'; import 'package:icarus/providers/collab/cloud_media_upload_queue_provider.dart'; import 'package:icarus/providers/collab/cloud_sync_status_provider.dart'; import 'package:icarus/providers/collab/convex_connection_provider.dart'; +import 'package:icarus/providers/collab/lineup_conflicts_provider.dart'; import 'package:icarus/providers/collab/strategy_conflict_provider.dart'; import 'package:icarus/providers/collab/strategy_op_queue_provider.dart'; import 'package:icarus/providers/desktop_update_provider.dart'; @@ -21,6 +22,7 @@ import 'package:icarus/providers/strategy_provider.dart'; import 'package:icarus/providers/strategy_save_state_provider.dart'; import 'package:icarus/providers/text_draft_provider.dart'; import 'package:icarus/providers/update_status_provider.dart'; +import 'package:icarus/strategy/lineup_group_changes.dart'; import 'package:icarus/strategy/strategy_page_models.dart'; import 'package:icarus/widgets/client_upgrade_button.dart'; import 'package:icarus/widgets/cloud_sync_button.dart'; @@ -188,11 +190,15 @@ class _AttentionOpQueue extends StrategyOpQueueNotifier { } class _ConflictSession extends StrategyPageSessionNotifier { - _ConflictSession({this.result = true, this.failure}); + _ConflictSession({this.result = true, this.failure, this.keepBoth}); final bool result; final Object? failure; + + /// What Keep both answers; by default what [result] says. + final KeepBothOutcome? keepBoth; int useCloudCount = 0; + int keepBothCount = 0; @override StrategyPageSessionState build() => const StrategyPageSessionState( @@ -208,6 +214,14 @@ class _ConflictSession extends StrategyPageSessionNotifier { if (failure != null) throw failure!; return result; } + + @override + Future keepBothForRejected() async { + keepBothCount += 1; + if (failure != null) throw failure!; + return keepBoth ?? + (result ? KeepBothOutcome.kept : KeepBothOutcome.unchanged); + } } class _DeletedPageSession extends StrategyPageSessionNotifier { @@ -295,12 +309,14 @@ ProviderContainer _createContainer({ ProviderContainer _createConflictContainer({ required _AttentionOpQueue queue, required _ConflictSession session, + List? lineupConflicts, }) { return ProviderContainer( overrides: [ strategyProvider.overrideWith(_CloudStrategyProvider.new), strategyOpQueueProvider.overrideWith(() => queue), strategyPageSessionProvider.overrideWith(() => session), + lineupConflictsProvider.overrideWithValue(lineupConflicts), cloudMediaUploadQueueProvider.overrideWith(_EmptyMediaQueue.new), cloudMediaAccountIdProvider.overrideWithValue('account-a'), convexConnectionProvider.overrideWith((ref) => Stream.value(true)), @@ -377,20 +393,6 @@ void main() { expect(container.read(cloudSyncStatusProvider), CloudSyncStatus.attention); }); - test('a lineup live sync refused to send shows attention', () async { - final container = _createContainer( - liveSyncState: ActivePageLiveSyncState( - unsyncableLineupKeys: { - const EntitySyncKey.lineup('page-1', 'lineup-1') - }, - ), - ); - addTearDown(container.dispose); - await container.read(convexConnectionProvider.future); - - expect(container.read(cloudSyncStatusProvider), CloudSyncStatus.attention); - }); - testWidgets('an active text draft can never appear synced', (tester) async { final container = _createContainer(); addTearDown(container.dispose); @@ -925,6 +927,10 @@ void main() { find.textContaining('applies to all 2 conflicting changes'), findsOneWidget, ); + // An element conflict has no lineup changes to list and nothing to keep + // beside the cloud's version. + expect(find.text('Keep both'), findsNothing); + expect(find.text('Your changes'), findsNothing); await tester.tap(find.text('Use cloud')); await tester.pumpAndSettle(); @@ -934,6 +940,173 @@ void main() { expect(queue.flushNowCount, 0); }); + group('lineup conflicts', () { + LineupChange change(String label, String description) => + LineupChange(label: label, description: description); + + final conflicts = [ + LineupGroupConflict( + key: const EntitySyncKey.lineup('page-1', 'link-a'), + yours: [change('Heaven', 'notes edited')], + cloud: [ + change('Mid', 'renamed'), + change('Short', 'added'), + change('Long', 'landing moved'), + change('Deep', 'deleted'), + change('Sova lineup', 'images changed'), + ], + ), + ]; + + Future openPopover( + WidgetTester tester, ProviderContainer container) async { + // The test font sets every glyph a full em wide, so the lists wrap far + // more than in the app; a desktop-sized window gives them the room. + tester.view.physicalSize = const Size(1280, 1024); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.reset); + await tester.pumpWidget( + UncontrolledProviderScope( + container: container, + child: const ShadApp( + home: Scaffold( + body: CloudSyncButton(style: kEditorToolbarButtonStyle)), + ), + ), + ); + await tester.pump(); + await tester.tap(_syncButton('attention')); + await tester.pumpAndSettle(); + } + + Finder line(String text) => find.text(text, findRichText: true); + + testWidgets( + 'without the version both sides started from, list one section of ' + 'how yours differs from the cloud', (tester) async { + final queue = _AttentionOpQueue(1); + final session = _ConflictSession(); + final container = _createConflictContainer( + queue: queue, + session: session, + lineupConflicts: [ + LineupGroupConflict( + key: const EntitySyncKey.lineup('page-1', 'link-a'), + yours: [ + change('Heaven', 'notes edited'), + change('Mid', 'notes edited'), + ], + cloud: null, + ), + // One conflict without that version is enough to show none of + // the sides' changes apart. + LineupGroupConflict( + key: const EntitySyncKey.lineup('page-1', 'link-z'), + yours: [change('Long', 'landing moved')], + cloud: [change('Short', 'added')], + ), + ], + ); + addTearDown(container.dispose); + await openPopover(tester, container); + + expect( + find.text('How your version differs from the cloud'), findsOneWidget); + expect(line('Heaven · notes edited'), findsOneWidget); + expect(line('Mid · notes edited'), findsOneWidget); + expect(line('Long · landing moved'), findsOneWidget); + expect(find.text('Your changes'), findsNothing); + expect(find.text('Cloud changes'), findsNothing); + expect(line('Short · added'), findsNothing); + expect(find.text('Keep both'), findsOneWidget); + }); + + testWidgets('list what each side changed and offer Keep both', + (tester) async { + final queue = _AttentionOpQueue(1); + final session = _ConflictSession(); + final container = _createConflictContainer( + queue: queue, + session: session, + lineupConflicts: conflicts, + ); + addTearDown(container.dispose); + await openPopover(tester, container); + + expect( + find.textContaining('A teammate changed these lineups'), + findsOneWidget, + ); + expect(find.text('Your changes'), findsOneWidget); + expect(line('Heaven · notes edited'), findsOneWidget); + expect(find.text('Cloud changes'), findsOneWidget); + expect(line('Mid · renamed'), findsOneWidget); + expect(line('Short · added'), findsOneWidget); + expect(line('Long · landing moved'), findsOneWidget); + expect(line('Deep · deleted'), findsOneWidget); + // Past four lines the rest are counted. + expect(line('Sova lineup · images changed'), findsNothing); + expect(find.text('and 1 more lineup'), findsOneWidget); + expect(find.text('Use cloud'), findsOneWidget); + expect(find.text('Keep mine'), findsOneWidget); + expect(find.text('Keep both'), findsOneWidget); + + await tester.tap(find.text('Keep both')); + await tester.pumpAndSettle(); + + expect(session.keepBothCount, 1); + expect(session.useCloudCount, 0); + expect(queue.retryRejectedCount, 0); + expect(queue.flushNowCount, 0); + }); + + testWidgets('a Keep both that cannot load the cloud version says so', + (tester) async { + final queue = _AttentionOpQueue(1); + final session = _ConflictSession(result: false); + final container = _createConflictContainer( + queue: queue, + session: session, + lineupConflicts: conflicts, + ); + addTearDown(container.dispose); + await openPopover(tester, container); + + await tester.tap(find.text('Keep both')); + await tester.pumpAndSettle(); + + expect(session.keepBothCount, 1); + expect( + find.text('Could not load the cloud version. Nothing was changed.'), + findsOneWidget, + ); + expect(find.text('Keep both'), findsOneWidget); + }); + + testWidgets( + 'a Keep both that copied but could not resolve says the conflict ' + 'is still open', (tester) async { + final queue = _AttentionOpQueue(1); + final session = _ConflictSession(keepBoth: KeepBothOutcome.copiesOnly); + final container = _createConflictContainer( + queue: queue, + session: session, + lineupConflicts: conflicts, + ); + addTearDown(container.dispose); + await openPopover(tester, container); + + await tester.tap(find.text('Keep both')); + await tester.pumpAndSettle(); + + expect( + find.textContaining('Your version was added as a copy'), + findsOneWidget, + ); + expect(find.textContaining('the conflict is still open'), findsOneWidget); + }); + }); + testWidgets( 'active conflict controls remain when another strategy needs attention', (tester) async { @@ -1040,20 +1213,15 @@ void main() { }); for (final (name, reason, expected) in [ - ( - 'a missing origin or landing', - lineupLinkEndMissingMessage, - "origin or landing spot isn't on this page in the cloud", - ), ( 'another page', lineupPageMismatchMessage, 'clashes with one on another page', ), ( - 'an origin or landing another lineup uses', - lineupEndInUseMessage, - 'still uses this origin or landing spot, so it was not deleted', + 'its old cloud format', + retiredLineupOpMessage, + 'saved by an older version of Icarus', ), ]) { testWidgets('a lineup refused for $name says why, not "another edit"', @@ -1090,6 +1258,107 @@ void main() { }); } + testWidgets( + 'a lineup group the server refused as overlapping another says why, ' + 'not that a teammate changed it', (tester) async { + tester.view.physicalSize = const Size(1280, 1024); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.reset); + final queue = _AttentionOpQueue(1); + final container = _createConflictContainer( + queue: queue, + session: _ConflictSession(), + // Even with lineup changes to list, the specific reason comes first. + lineupConflicts: const [ + LineupGroupConflict( + key: EntitySyncKey.lineup('page-1', 'link-a'), + yours: [LineupChange(label: 'Heaven', description: 'added')], + cloud: [], + ), + ], + ); + addTearDown(container.dispose); + container + .read(strategySaveStateProvider.notifier) + .setCloudSyncError(lineupOverlapMessage); + + await tester.pumpWidget( + UncontrolledProviderScope( + container: container, + child: const ShadApp( + home: + Scaffold(body: CloudSyncButton(style: kEditorToolbarButtonStyle)), + ), + ), + ); + await tester.pump(); + await tester.tap(_syncButton('attention')); + await tester.pumpAndSettle(); + + expect( + find.textContaining('shares a spot with lineups saved separately'), + findsOneWidget, + ); + expect( + find.textContaining('Keep mine replaces their changes'), findsNothing); + expect( + find.textContaining('A teammate changed these lineups'), findsNothing); + expect(find.textContaining('Another edit reached'), findsNothing); + expect(find.text('Your changes'), findsNothing); + expect(find.text('Keep both'), findsNothing); + expect(find.text('Use cloud'), findsOneWidget); + }); + + for (final (name, error, keepMine) in [ + ('alone', lineupOverlapMessage, true), + ( + 'beside other work', + '$lineupOverlapMessage. $otherWorkNeedsAttentionNote', + true, + ), + ]) { + testWidgets( + 'an overlap refusal $name still offers Keep mine, saying when it ' + 'helps', (tester) async { + final queue = _AttentionOpQueue(keepMine ? 2 : 1); + final container = _createConflictContainer( + queue: queue, + session: _ConflictSession(), + ); + addTearDown(container.dispose); + container.read(strategySaveStateProvider.notifier).setCloudSyncError( + error, + ); + + await tester.pumpWidget( + UncontrolledProviderScope( + container: container, + child: const ShadApp( + home: Scaffold( + body: CloudSyncButton(style: kEditorToolbarButtonStyle), + ), + ), + ), + ); + await tester.pump(); + await tester.tap(_syncButton('attention')); + await tester.pumpAndSettle(); + + expect( + find.textContaining('shares a spot with lineups saved separately'), + findsOneWidget, + ); + expect( + find.textContaining('refused while the spot is still shared'), + findsOneWidget, + ); + expect(find.text('Use cloud'), findsOneWidget); + expect(find.text('Keep mine'), keepMine ? findsOneWidget : findsNothing); + expect(find.text('Retry sync'), findsNothing); + expect(find.text('Keep both'), findsNothing); + }); + } + testWidgets( 'a lineup refusal among several changes says the choice covers all ' 'of them', (tester) async { @@ -1101,7 +1370,7 @@ void main() { addTearDown(container.dispose); container .read(strategySaveStateProvider.notifier) - .setCloudSyncError(lineupLinkEndMissingMessage); + .setCloudSyncError(lineupPageMismatchMessage); await tester.pumpWidget( UncontrolledProviderScope( @@ -1116,7 +1385,7 @@ void main() { await tester.tap(_syncButton('attention')); await tester.pumpAndSettle(); - expect(find.textContaining('on this page in the cloud'), findsOneWidget); + expect(find.textContaining('another page'), findsOneWidget); expect( find.textContaining('applies to all 2 changes that need attention'), findsOneWidget, @@ -1132,7 +1401,7 @@ void main() { ); addTearDown(container.dispose); container.read(strategySaveStateProvider.notifier).setCloudSyncError( - '$lineupLinkEndMissingMessage. $otherWorkNeedsAttentionNote', + '$lineupPageMismatchMessage. $otherWorkNeedsAttentionNote', ); await tester.pumpWidget( @@ -1148,7 +1417,7 @@ void main() { await tester.tap(_syncButton('attention')); await tester.pumpAndSettle(); - expect(find.textContaining('on this page in the cloud'), findsOneWidget); + expect(find.textContaining('another page'), findsOneWidget); expect( find.textContaining('Other changes here were not saved either'), findsOneWidget, @@ -1201,14 +1470,14 @@ void main() { const ConflictResolution( type: ConflictResolutionType.rebase, opId: 'refused-link', - message: lineupLinkEndMissingMessage, + message: lineupPageMismatchMessage, ), ); await tester.pump(); await tester.pump(const Duration(milliseconds: 300)); expect( - toast(friendlyCloudSyncError(lineupLinkEndMissingMessage)), + toast(friendlyCloudSyncError(lineupPageMismatchMessage)), findsOneWidget, ); expect( diff --git a/tool/convex_client_gauntlet/runtime/lib/workload.dart b/tool/convex_client_gauntlet/runtime/lib/workload.dart index bd78ca06..37130caa 100644 --- a/tool/convex_client_gauntlet/runtime/lib/workload.dart +++ b/tool/convex_client_gauntlet/runtime/lib/workload.dart @@ -4,7 +4,7 @@ import 'package:crypto/crypto.dart'; const operationsPerSeed = 1000; const operationBatchSize = 50; -const cloudProtocolVersion = 4; +const cloudProtocolVersion = 5; const payloadVersion = 1; const baseFixturePath = 'test/fixtures/strategy_integrity/base-test-v43.ica'; const baseFixtureSha256 = @@ -47,9 +47,9 @@ List> buildOperationTrace(int seed) { _addRevisionCycle( add: add, entity: _ContentEntity.lineup, - // Lineup rows are keyed `:`. + // A lineup row is keyed by the lineup's id. publicId: - 'lineupOrigin:${seedPrefix(seed)}lineup-${cycle.toString().padLeft(3, '0')}', + '${seedPrefix(seed)}lineup-${cycle.toString().padLeft(3, '0')}', pagePublicId: initialPageId(seed), payloadBuilder: (variant) => _lineupPayload(seed, cycle, variant), initialSortIndex: 1000 + cycle, @@ -262,21 +262,42 @@ Map _utilityPayload(int seed, int cycle, int variant) { Map _lineupPayload(int seed, int cycle, int variant) { final id = '${seedPrefix(seed)}lineup-${cycle.toString().padLeft(3, '0')}'; - // One lineup origin row; each revision cycle moves its agent. + // One lineup with its origin and landing; each revision cycle moves its + // agent. return { - 'kind': 'lineupOrigin', + 'kind': 'lineup', 'payloadVersion': payloadVersion, 'data': { 'id': id, - 'agent': { - 'id': '$id-agent', - 'isDeleted': false, - 'position': {'dx': 10 + cycle, 'dy': 20 + variant}, - 'type': 'sova', - 'isAlly': true, - 'state': 'none', - 'kind': 'plain', - 'lineUpID': id, + 'name': 'Lineup $cycle', + 'youtubeLink': '', + 'notes': '', + 'images': [], + 'origin': { + 'id': '$id-origin', + 'agent': { + 'id': '$id-agent', + 'isDeleted': false, + 'position': {'dx': 10 + cycle, 'dy': 20 + variant}, + 'type': 'sova', + 'isAlly': true, + 'state': 'none', + 'kind': 'plain', + 'lineUpID': '$id-origin', + }, + }, + 'landing': { + 'id': '$id-landing', + 'ability': { + 'id': '$id-ability', + 'isDeleted': false, + 'position': {'dx': 40 + cycle, 'dy': 50}, + 'data': {'type': 'sova', 'index': 1}, + 'isAlly': true, + 'rotation': 0, + 'length': 0, + 'lineUpID': '$id-landing', + }, }, }, };