@crowdedkingdoms/crowdyjs 18.2.0 → 18.4.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/MIGRATION.md CHANGED
@@ -120,6 +120,43 @@ super-admin's session). There is no SDK replacement.
120
120
  `dev`'s SDL after #417 merged (`npm run schema:sync:paths -- --schema <that schema.gql>`, then
121
121
  `npm run codegen`).
122
122
 
123
+ ## 18.4.0: the terms and age gate
124
+
125
+ **What it needs.** ck-api `v2.35.0` (cks-game-api #437, 2026-10-07). Against an older API the
126
+ two new calls fail as GraphQL validation errors; nothing else changes.
127
+
128
+ Since `v2.35.0` no gameplay token is issued until the player has agreed to the current required
129
+ legal documents (Game Terms, API Terms, SDK Developer Terms, Free Tier and Billing Basis,
130
+ Overworld Privacy Policy) and attested that they are at least 18, or the age of majority where
131
+ they live if that is higher. `portal.mintAppToken`, `portal.createAuthorizationCode` and
132
+ `portal.refresh` answer `LEGAL_ACCEPTANCE_REQUIRED`; `isLegalAcceptanceRequiredError` reads it.
133
+
134
+ - **A browser game on its own domain** changes nothing for sign-in: Studio's `/authorize` asks
135
+ for both. A refresh refused this way cannot succeed on retry, so send the player back through
136
+ `portal.signIn`. That also happens when a required document gets a new version.
137
+ - **A first-party page or a client outside a browser** shows its own two checkboxes, linking
138
+ each document, then calls `client.auth.recordPlayerConsents({ acceptLegal: true,
139
+ attestAgeOfMajority: true })` before minting. `client.auth.playerLegalAcceptance()` says
140
+ whether that is still needed. Call it only for a player who ticked both boxes: it records
141
+ their agreement.
142
+ - `client.auth.register` takes `acceptLegal` and `attestAgeOfMajority`. A browser request must
143
+ send both `true` or it is refused before any account exists. A request with no browser origin
144
+ may omit them and record them later.
145
+
146
+ The schema is cks-game-api `dev`'s after #437 (`npm run schema:sync:paths`, then
147
+ `npm run codegen`).
148
+
149
+ ## 18.3.0: a game answers the page-held host calls
150
+
151
+ No API change. `createGridHostCalls` takes a `local.page(fn, args)` hook for the calls only the
152
+ page can answer: the player's input (`input_axes`, `input_look`, `input_key`), the player's own
153
+ body (`pose_get`, `pose_set`, `pose_release`, `teleport_request`), mod-owned actors
154
+ (`actor_spawn`, `actor_pose`, `actor_despawn`), the scene (`scene_catalog`, `scene_instances`),
155
+ presentation (`avatar_appearance`, `avatar_state_set`, `voice_set`, `video_set`) and the player's
156
+ own sends (`send_client_event`, `events_poll`, `send_text`, `send_actor_message`,
157
+ `send_channel_message`). Without the hook each is refused as not offered, as before. `clock` is
158
+ answered locally. The host catalog lists all of them as client calls the server refuses.
159
+
123
160
  ## 18.2.0: `ChunkStore` keeps the voxel edits it hydrated
124
161
 
125
162
  No API change. Every voxel write but a chunk write-back lands only in the chunk's edit log: a
package/README.md CHANGED
@@ -12,19 +12,23 @@ gameplay, minted per app through `client.portal`.
12
12
 
13
13
  Start here:
14
14
 
15
- - [SDK guide](https://docs.crowdedkingdoms.com/crowdyjs/readme) — the canonical
15
+ - [SDK guide](https://docs.dev.crowdedkingdoms.com/crowdyjs/readme) — the canonical
16
16
  walkthrough of everything in this README.
17
- - [Build a game](https://docs.crowdedkingdoms.com/build-a-game/intro) — a
17
+ - [Build a game](https://docs.dev.crowdedkingdoms.com/build-a-game/intro) — a
18
18
  hands-on tutorial from sign-in to a playable voxel game.
19
- - [Platform overview](https://docs.crowdedkingdoms.com/overview/client-workflow)
19
+ - [Platform overview](https://docs.dev.crowdedkingdoms.com/overview/client-workflow)
20
20
  — how a client session flows through the platform.
21
21
 
22
22
  ## Install
23
23
 
24
24
  ```bash
25
- npm install @crowdedkingdoms/crowdyjs
25
+ npm install @crowdedkingdoms/crowdyjs@dev
26
26
  ```
27
27
 
28
+ This README is the `dev` branch's: it documents the release on the `dev` dist-tag
29
+ (`npm view @crowdedkingdoms/crowdyjs dist-tags`), and its links go to the dev docs site. A
30
+ plain `npm install` resolves `latest`, the production release, which has no `client.exec`.
31
+
28
32
  CrowdyJS targets browsers by default and uses native `fetch`, `WebSocket`,
29
33
  `crypto`, `btoa`, and `atob`. Node tools can still use the SDK, but must
30
34
  provide browser-compatible globals when opening realtime connections (e.g.
@@ -98,6 +102,18 @@ sign-in mutations are refused from a non-first-party browser origin with
98
102
  customer's domain that collects it is indistinguishable, to the platform and to
99
103
  the player, from a phishing page.
100
104
 
105
+ **Every player stores the terms and an age attestation before playing** (ck-api
106
+ v2.35.0, 2026-10-07). Until they do, `portal.mintAppToken`,
107
+ `portal.createAuthorizationCode` and `portal.refresh` answer
108
+ `LEGAL_ACCEPTANCE_REQUIRED` (`isLegalAcceptanceRequiredError`). On the first row
109
+ Studio's `/authorize` asks for both, so a browser game only has to send the player
110
+ back through `portal.signIn` when a refresh is refused that way. On the other rows,
111
+ show your own two checkboxes linking each document, then call
112
+ `client.auth.recordPlayerConsents({ acceptLegal: true, attestAgeOfMajority: true })`
113
+ before minting; `client.auth.playerLegalAcceptance()` says whether that is still
114
+ needed. `auth.register` takes the same two fields, and a browser page must send both.
115
+ See [MIGRATION.md](MIGRATION.md#1840-the-terms-and-age-gate).
116
+
101
117
  **A game published to Crowdy Games takes the first row too, with one twist the SDK
102
118
  handles for you** (17.2.0). Such a game is reached at `https://<games host>/<slug>/`,
103
119
  which is a first-party *shell* page, and runs inside that page's iframe on its own
@@ -171,8 +187,8 @@ Notes:
171
187
  - Use `client.auth.setToken(token)` to seed a token externally (e.g. when
172
188
  restoring auth from a non-default storage).
173
189
 
174
- Deeper reading: [Portals & app-scoped tokens](https://docs.crowdedkingdoms.com/management-api/portals-and-app-tokens)
175
- and [Sign in](https://docs.crowdedkingdoms.com/management-api/authentication).
190
+ Deeper reading: [Portals & app-scoped tokens](https://docs.dev.crowdedkingdoms.com/management-api/portals-and-app-tokens)
191
+ and [Sign in](https://docs.dev.crowdedkingdoms.com/management-api/authentication).
176
192
 
177
193
  ### Token refresh during gameplay
178
194
 
@@ -295,7 +311,7 @@ query AppForRouting($appId: BigInt!) {
295
311
  `CrowdyClient` with `httpUrl: gameApiUrl` (and the matching `wsUrl`) holding
296
312
  that app's app-scoped token, then drive gameplay through that client. Apps
297
313
  with no `gameApiUrl` keep working against the default `httpUrl` you
298
- configured. See [Loading an app's Game API](https://docs.crowdedkingdoms.com/crowdyjs/shared-environment-routing).
314
+ configured. See [Loading an app's Game API](https://docs.dev.crowdedkingdoms.com/crowdyjs/shared-environment-routing).
299
315
 
300
316
  ## Realtime notifications
301
317
 
@@ -513,8 +529,10 @@ a CLIENT half's host calls through CrowdyJS confined to the grid. The ones only
513
529
  the game can answer need its knowledge: `local.actorsInChunk` for
514
530
  `actors_list*`, `local.avatarChunk` (where an avatar's live actor is) for
515
531
  `avatar_state_get`, `local.gridPermissionKeys` with the visiting player's
516
- `userId` for `grid_permission_check`, and `local.drainPointerClicks` for
517
- `pointer_clicks`; without its hook such a call is refused as not offered. The
532
+ `userId` for `grid_permission_check`, `local.drainPointerClicks` for
533
+ `pointer_clicks`, and `local.page(fn, args)` for the calls the page holds (the
534
+ player's input, body and sends, mod-owned actors, the scene and presentation;
535
+ 18.3.0); without its hook such a call is refused as not offered. The
518
536
  Game Model, sessions and grid state calls went with the legacy engines in
519
537
  18.0.0: the broker refuses them.
520
538
 
@@ -604,7 +622,7 @@ reach your bundle. Reads are synchronous snapshots and writes happen on
604
622
  WebSocket events (not `requestAnimationFrame`), so render loops read freely
605
623
  and a backgrounded tab keeps ingesting updates; pass `workerTicker()` to also
606
624
  keep timer-driven sends at full rate while hidden. See the
607
- [World Stores guide](https://docs.crowdedkingdoms.com/crowdyjs/stores).
625
+ [World Stores guide](https://docs.dev.crowdedkingdoms.com/crowdyjs/stores).
608
626
 
609
627
  ## Game Kit
610
628
 
@@ -687,7 +705,7 @@ exec.onReconnect((host) => console.log('moved to', host));
687
705
 
688
706
  Integers above 2^53 decode as `number` and lose precision unless you pass
689
707
  `{ decode: { useBigInt64: true } }`. The wire format is in the
690
- [ck-exec docs](https://docs.crowdedkingdoms.com/exec/intro).
708
+ [ck-exec docs](https://docs.dev.crowdedkingdoms.com/exec/intro).
691
709
 
692
710
  ### A mod's CLIENT half
693
711
 
@@ -758,7 +776,7 @@ counts what was dropped); `invoke` sends at most 256 KiB each way and is refused
758
776
  module is not running. `NOT_FOUND` holds a CLIENT half back 15 s and `RATE_LIMITED` 60 s. The
759
777
  grid's owner is asked about their own CLIENT halves like anyone; answer yes in `confirm` when
760
778
  `prompt.authorId` is the player. See
761
- [CLIENT halves](https://docs.crowdedkingdoms.com/exec/client-halves).
779
+ [CLIENT halves](https://docs.dev.crowdedkingdoms.com/exec/client-halves).
762
780
 
763
781
  ## Hosting a game on Crowdy Games
764
782
 
@@ -877,8 +895,8 @@ CLIENT project needs ck-api `v2.25.1` or later. A CLIENT crate still on the lega
877
895
  `mountCrowdyStudio` and the controller take `mods: client.exec`. Crowdy Studio runs nothing
878
896
  on legacy player compute since 18.0.0.
879
897
 
880
- See [CLIENT halves](https://docs.crowdedkingdoms.com/exec/client-halves), [mods](https://docs.crowdedkingdoms.com/exec/mods)
881
- and [Embed Crowdy Studio in your game](https://docs.crowdedkingdoms.com/crowdyjs/crowdy-studio-embed).
898
+ See [CLIENT halves](https://docs.dev.crowdedkingdoms.com/exec/client-halves), [mods](https://docs.dev.crowdedkingdoms.com/exec/mods)
899
+ and [Embed Crowdy Studio in your game](https://docs.dev.crowdedkingdoms.com/crowdyjs/crowdy-studio-embed).
882
900
 
883
901
  ### The Studio agent (DeepSeek Harness in the browser)
884
902
 
@@ -1056,7 +1074,7 @@ no other repositories and no network access required:
1056
1074
  - `src/generated/graphql.ts` — generated TypeScript operation types.
1057
1075
 
1058
1076
  Schema refresh is explicit, from the published
1059
- [SDL](https://docs.crowdedkingdoms.com/schema/game-api.graphql):
1077
+ [SDL](https://docs.dev.crowdedkingdoms.com/schema/game-api.graphql):
1060
1078
 
1061
1079
  ```bash
1062
1080
  npm run schema:sync:prod
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * GENERATED — do not edit. The operator tooling's
3
- * `sync-client-origins.mjs --write --tier prod` writes this file, and
3
+ * `sync-client-origins.mjs --write --tier dev` writes this file, and
4
4
  * `check-sdk-default-origin.mjs` refuses it when it names the wrong tier or a
5
5
  * host that declaration does not carry. Regenerate; never hand-edit.
6
6
  *
@@ -10,14 +10,14 @@
10
10
  * than no default at all. Every fallback this SDK ever removed named a host that
11
11
  * was already dead. A generated file plus a gate is what makes this one different.
12
12
  *
13
- * Source: the operator's per-tier public CK API origin declaration, tier 'prod'
13
+ * Source: the operator's per-tier public CK API origin declaration, tier 'dev'
14
14
  */
15
15
  /** The tier this build of the SDK is published for. */
16
- export declare const CROWDY_DEFAULT_TIER = "prod";
16
+ export declare const CROWDY_DEFAULT_TIER = "dev";
17
17
  /** The public CK API origin for that tier. */
18
- export declare const CROWDY_DEFAULT_HTTP_ORIGIN = "https://ck.prod.crowdedkingdoms.com";
18
+ export declare const CROWDY_DEFAULT_HTTP_ORIGIN = "https://ck.dev.crowdedkingdoms.com";
19
19
  /** The same host over WebSocket. A scheme is composed; a hostname is looked up. */
20
- export declare const CROWDY_DEFAULT_WS_ORIGIN = "wss://ck.prod.crowdedkingdoms.com";
20
+ export declare const CROWDY_DEFAULT_WS_ORIGIN = "wss://ck.dev.crowdedkingdoms.com";
21
21
  /** The bare hostname, for callers that need to compare rather than dial. */
22
- export declare const CROWDY_DEFAULT_HOST = "ck.prod.crowdedkingdoms.com";
22
+ export declare const CROWDY_DEFAULT_HOST = "ck.dev.crowdedkingdoms.com";
23
23
  //# sourceMappingURL=default-origin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"default-origin.d.ts","sourceRoot":"","sources":["../src/default-origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAE1C,8CAA8C;AAC9C,eAAO,MAAM,0BAA0B,wCAAwC,CAAC;AAEhF,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,sCAAsC,CAAC;AAE5E,4EAA4E;AAC5E,eAAO,MAAM,mBAAmB,gCAAgC,CAAC"}
1
+ {"version":3,"file":"default-origin.d.ts","sourceRoot":"","sources":["../src/default-origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC,8CAA8C;AAC9C,eAAO,MAAM,0BAA0B,uCAAuC,CAAC;AAE/E,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,qCAAqC,CAAC;AAE3E,4EAA4E;AAC5E,eAAO,MAAM,mBAAmB,+BAA+B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * GENERATED — do not edit. The operator tooling's
3
- * `sync-client-origins.mjs --write --tier prod` writes this file, and
3
+ * `sync-client-origins.mjs --write --tier dev` writes this file, and
4
4
  * `check-sdk-default-origin.mjs` refuses it when it names the wrong tier or a
5
5
  * host that declaration does not carry. Regenerate; never hand-edit.
6
6
  *
@@ -10,13 +10,13 @@
10
10
  * than no default at all. Every fallback this SDK ever removed named a host that
11
11
  * was already dead. A generated file plus a gate is what makes this one different.
12
12
  *
13
- * Source: the operator's per-tier public CK API origin declaration, tier 'prod'
13
+ * Source: the operator's per-tier public CK API origin declaration, tier 'dev'
14
14
  */
15
15
  /** The tier this build of the SDK is published for. */
16
- export const CROWDY_DEFAULT_TIER = 'prod';
16
+ export const CROWDY_DEFAULT_TIER = 'dev';
17
17
  /** The public CK API origin for that tier. */
18
- export const CROWDY_DEFAULT_HTTP_ORIGIN = 'https://ck.prod.crowdedkingdoms.com';
18
+ export const CROWDY_DEFAULT_HTTP_ORIGIN = 'https://ck.dev.crowdedkingdoms.com';
19
19
  /** The same host over WebSocket. A scheme is composed; a hostname is looked up. */
20
- export const CROWDY_DEFAULT_WS_ORIGIN = 'wss://ck.prod.crowdedkingdoms.com';
20
+ export const CROWDY_DEFAULT_WS_ORIGIN = 'wss://ck.dev.crowdedkingdoms.com';
21
21
  /** The bare hostname, for callers that need to compare rather than dial. */
22
- export const CROWDY_DEFAULT_HOST = 'ck.prod.crowdedkingdoms.com';
22
+ export const CROWDY_DEFAULT_HOST = 'ck.dev.crowdedkingdoms.com';
@@ -204,12 +204,47 @@ export declare class AuthAPI {
204
204
  * a password-less magic-link/social account gets the password attached
205
205
  * pending email confirmation. Use {@link isAlreadyRegisteredError} to detect
206
206
  * either and fall back to {@link login} or {@link requestLoginLink}.
207
+ *
208
+ * **The clickwrap (ck-api v2.35.0).** A request from a browser page must send
209
+ * `acceptLegal` and `attestAgeOfMajority` both `true` — the player ticked both
210
+ * boxes — or it is refused with `LEGAL_ACCEPTANCE_REQUIRED` before any account
211
+ * exists; the account then starts accepted. A client with no browser origin may
212
+ * omit them and call {@link recordPlayerConsents} before its first gameplay
213
+ * token.
207
214
  */
208
215
  register(input: {
209
216
  email: string;
210
217
  password: string;
211
218
  gamertag?: string;
219
+ /** The player agreed to the current required legal documents. */
220
+ acceptLegal?: boolean;
221
+ /** The player is at least 18, or the age of majority where they live if higher. */
222
+ attestAgeOfMajority?: boolean;
212
223
  }): Promise<AuthResponse>;
224
+ /**
225
+ * Store the signed-in player's agreement to the current required legal
226
+ * documents (Game Terms, API Terms, SDK Developer Terms, Free Tier and Billing
227
+ * Basis, Overworld Privacy Policy) and their attestation that they are at least
228
+ * 18, or the age of majority where they live if that is higher. Requires the
229
+ * identity session token; both must be `true`, and repeating it is harmless.
230
+ *
231
+ * Since ck-api v2.35.0 a gameplay token (`portal.mintAppToken`,
232
+ * `portal.createAuthorizationCode`, `portal.refresh`) is refused with
233
+ * `LEGAL_ACCEPTANCE_REQUIRED` ({@link isLegalAcceptanceRequiredError}) until
234
+ * this is stored. It records the PLAYER's agreement: call it only after they
235
+ * have ticked both boxes in your own UI, linking each document. A browser game
236
+ * never needs it, because Studio's hosted `/authorize` asks for both.
237
+ */
238
+ recordPlayerConsents(input: {
239
+ acceptLegal: boolean;
240
+ attestAgeOfMajority: boolean;
241
+ }): Promise<boolean>;
242
+ /**
243
+ * Whether the signed-in player has the current required documents and the age
244
+ * attestation stored, i.e. whether a gameplay token would be issued. Requires
245
+ * the identity session token. ck-api v2.35.0.
246
+ */
247
+ playerLegalAcceptance(): Promise<boolean>;
213
248
  /**
214
249
  * Email-first adaptive login: does this address have password sign-in enabled?
215
250
  * Public, and deliberately does not reveal whether the address is registered.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/domains/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/domains/auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAkCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKhE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGlE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKjE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAK5D;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKrE;AA4ID,qBAAa,OAAO;IAEhB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,SAAS;IAGrC,6EAA6E;IACvE,uBAAuB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAKlD;;;;;;;OAOG;IACG,gBAAgB,CAAC,KAAK,EAAE;QAC5B,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;IAK9B,0EAA0E;IACpE,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAS7D;;;OAGG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAOnD,iFAAiF;IAC3E,mBAAmB,CAAC,KAAK,EAAE;QAC/B,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,YAAY,CAAC;IASzB;;;;;;;;;;;;;OAaG;IACG,KAAK,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAQ9E;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,QAAQ,CAAC,KAAK,EAAE;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,iEAAiE;QACjE,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,mFAAmF;QACnF,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC/B,GAAG,OAAO,CAAC,YAAY,CAAC;IAQzB;;;;;;;;;;;;;OAaG;IACG,oBAAoB,CAAC,KAAK,EAAE;QAChC,WAAW,EAAE,OAAO,CAAC;QACrB,mBAAmB,EAAE,OAAO,CAAC;KAC9B,GAAG,OAAO,CAAC,OAAO,CAAC;IAKpB;;;;OAIG;IACG,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC;IAK/C;;;OAGG;IACG,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,OAAO,CAAA;KAAE,CAAC;IAOvE;;;;;;;;;;OAUG;IACG,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO3D;;;;;;;OAOG;IACG,aAAa,CAAC,KAAK,EAAE;QACzB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,OAAO,CAAC;IAOpB;;;;;;;;;;;;;;;;;;OAkBG;IACG,cAAc,CAAC,KAAK,EAAE;QAC1B,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,OAAO,CAAC;IAKpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACG,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO/D,0EAA0E;IACpE,YAAY,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAK7C,sEAAsE;IAChE,YAAY,CAAC,KAAK,EAAE;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,YAAY,CAAC;IAKzB,2EAA2E;IACrE,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO1D,mEAAmE;IAC7D,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAMhC,oEAAoE;IAC9D,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAK1C,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIpC,+CAA+C;IAC/C,QAAQ,IAAI,MAAM,GAAG,IAAI;CAG1B"}
@@ -129,6 +129,9 @@ const SocialLoginCompleteDocument = parse(`mutation SocialLoginComplete($input:
129
129
  // naming a field the caller never wrote.
130
130
  const LoginDocument = parse(`mutation Login($loginUserInput: LoginUserInput!) { login(loginUserInput: $loginUserInput) { ${AUTH_RESPONSE_FIELDS} } }`);
131
131
  const RegisterDocument = parse(`mutation Register($registerUserInput: RegisterUserInput!) { register(registerUserInput: $registerUserInput) { ${AUTH_RESPONSE_FIELDS} } }`);
132
+ // THE CLICKWRAP (ck-api v2.35.0). A gameplay token is refused until both are stored.
133
+ const RecordPlayerConsentsDocument = parse(`mutation RecordPlayerConsents($acceptLegal: Boolean!, $attestAgeOfMajority: Boolean!) { recordPlayerConsents(acceptLegal: $acceptLegal, attestAgeOfMajority: $attestAgeOfMajority) }`);
134
+ const PlayerLegalAcceptanceDocument = parse(`query PlayerLegalAcceptance { playerLegalAcceptance }`);
132
135
  // PASSWORD MANAGEMENT. Four mutations, and they are four rather than one or two
133
136
  // on purpose: each is defined by what the CALLER has already proven, and
134
137
  // collapsing any pair would delete the proof.
@@ -237,6 +240,13 @@ export class AuthAPI {
237
240
  * a password-less magic-link/social account gets the password attached
238
241
  * pending email confirmation. Use {@link isAlreadyRegisteredError} to detect
239
242
  * either and fall back to {@link login} or {@link requestLoginLink}.
243
+ *
244
+ * **The clickwrap (ck-api v2.35.0).** A request from a browser page must send
245
+ * `acceptLegal` and `attestAgeOfMajority` both `true` — the player ticked both
246
+ * boxes — or it is refused with `LEGAL_ACCEPTANCE_REQUIRED` before any account
247
+ * exists; the account then starts accepted. A client with no browser origin may
248
+ * omit them and call {@link recordPlayerConsents} before its first gameplay
249
+ * token.
240
250
  */
241
251
  async register(input) {
242
252
  const data = await this.graphql.request(RegisterDocument, {
@@ -246,6 +256,33 @@ export class AuthAPI {
246
256
  this.session.setToken(data.register.token);
247
257
  return data.register;
248
258
  }
259
+ /**
260
+ * Store the signed-in player's agreement to the current required legal
261
+ * documents (Game Terms, API Terms, SDK Developer Terms, Free Tier and Billing
262
+ * Basis, Overworld Privacy Policy) and their attestation that they are at least
263
+ * 18, or the age of majority where they live if that is higher. Requires the
264
+ * identity session token; both must be `true`, and repeating it is harmless.
265
+ *
266
+ * Since ck-api v2.35.0 a gameplay token (`portal.mintAppToken`,
267
+ * `portal.createAuthorizationCode`, `portal.refresh`) is refused with
268
+ * `LEGAL_ACCEPTANCE_REQUIRED` ({@link isLegalAcceptanceRequiredError}) until
269
+ * this is stored. It records the PLAYER's agreement: call it only after they
270
+ * have ticked both boxes in your own UI, linking each document. A browser game
271
+ * never needs it, because Studio's hosted `/authorize` asks for both.
272
+ */
273
+ async recordPlayerConsents(input) {
274
+ const data = await this.graphql.request(RecordPlayerConsentsDocument, input);
275
+ return data.recordPlayerConsents;
276
+ }
277
+ /**
278
+ * Whether the signed-in player has the current required documents and the age
279
+ * attestation stored, i.e. whether a gameplay token would be issued. Requires
280
+ * the identity session token. ck-api v2.35.0.
281
+ */
282
+ async playerLegalAcceptance() {
283
+ const data = await this.graphql.request(PlayerLegalAcceptanceDocument, {});
284
+ return data.playerLegalAcceptance;
285
+ }
249
286
  /**
250
287
  * Email-first adaptive login: does this address have password sign-in enabled?
251
288
  * Public, and deliberately does not reveal whether the address is registered.
@@ -190,6 +190,16 @@ export declare function defaultHostedSignInUrl(graphqlEndpoint: string): string;
190
190
  * ck-api v1.88.0.
191
191
  */
192
192
  export declare function isHostedSignInRequiredError(error: unknown): boolean;
193
+ /**
194
+ * `LEGAL_ACCEPTANCE_REQUIRED`: the player has not stored the current required
195
+ * legal documents and the age-of-majority attestation, so no gameplay token is
196
+ * issued ({@link PortalAPI.mintAppToken}, {@link PortalAPI.createAuthorizationCode},
197
+ * {@link PortalAPI.refresh}), and a browser `auth.register` without both boxes is
198
+ * refused. A browser game sends the player back through {@link PortalAPI.signIn},
199
+ * where Studio's `/authorize` asks; a native client shows its own clickwrap and
200
+ * calls `auth.recordPlayerConsents`. ck-api v2.35.0.
201
+ */
202
+ export declare function isLegalAcceptanceRequiredError(error: unknown): boolean;
193
203
  export declare class PortalAPI {
194
204
  private readonly api;
195
205
  private readonly session;
@@ -213,13 +223,16 @@ export declare class PortalAPI {
213
223
  * Native/direct mint: exchange the caller's identity session token for an
214
224
  * app-scoped gameplay token. Returns the token; it is NOT stored on this
215
225
  * client (build a per-game client with it). Free/open apps auto-grant access;
216
- * paid apps require an existing entitlement.
226
+ * paid apps require an existing entitlement. Refused with
227
+ * `LEGAL_ACCEPTANCE_REQUIRED` ({@link isLegalAcceptanceRequiredError}) until the
228
+ * player's consents are stored (`auth.recordPlayerConsents`, ck-api v2.35.0).
217
229
  */
218
230
  mintAppToken(appId: string): Promise<AppTokenResponse>;
219
231
  /**
220
232
  * Overworld/identity side: mint a one-time authorization code for a target
221
233
  * app, bound to the destination game's PKCE challenge + redirect URI.
222
- * Requires the identity session token.
234
+ * Requires the identity session token. Refused with `LEGAL_ACCEPTANCE_REQUIRED`
235
+ * until the player's consents are stored (ck-api v2.35.0).
223
236
  */
224
237
  createAuthorizationCode(params: {
225
238
  appId: string;
@@ -237,6 +250,11 @@ export declare class PortalAPI {
237
250
  * Same-app refresh: rotate the current app token for a fresh one (extended
238
251
  * TTL) and store it. Call before expiry to keep playing without bouncing
239
252
  * through the Overworld. Requires the current app token on this session.
253
+ *
254
+ * Refused with `LEGAL_ACCEPTANCE_REQUIRED` ({@link isLegalAcceptanceRequiredError})
255
+ * when the player's stored consents are missing or a required document has a
256
+ * new version (ck-api v2.35.0). Retrying cannot succeed: send a browser player
257
+ * back through {@link signIn}, where `/authorize` asks for them.
240
258
  */
241
259
  refresh(currentServer?: CurrentServer): Promise<AppTokenResponse>;
242
260
  /** Whether portaling into an app needs a consent prompt (Overworld side). */
@@ -1 +1 @@
1
- {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../src/domains/portal.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../src/domains/portal.ts"],"names":[],"mappings":"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"}
@@ -116,6 +116,27 @@ export function isHostedSignInRequiredError(error) {
116
116
  return true;
117
117
  return /HOSTED_SIGN_IN_REQUIRED|only available to first-party/i.test(typeof e?.message === 'string' ? e.message : '');
118
118
  }
119
+ /**
120
+ * `LEGAL_ACCEPTANCE_REQUIRED`: the player has not stored the current required
121
+ * legal documents and the age-of-majority attestation, so no gameplay token is
122
+ * issued ({@link PortalAPI.mintAppToken}, {@link PortalAPI.createAuthorizationCode},
123
+ * {@link PortalAPI.refresh}), and a browser `auth.register` without both boxes is
124
+ * refused. A browser game sends the player back through {@link PortalAPI.signIn},
125
+ * where Studio's `/authorize` asks; a native client shows its own clickwrap and
126
+ * calls `auth.recordPlayerConsents`. ck-api v2.35.0.
127
+ */
128
+ export function isLegalAcceptanceRequiredError(error) {
129
+ const e = error;
130
+ const codes = [
131
+ e?.code,
132
+ e?.extensions?.code,
133
+ ...(e?.graphQLErrors ?? []).map((g) => g.extensions?.code),
134
+ ...(e?.graphqlErrors ?? []).map((g) => g.extensions?.code),
135
+ ];
136
+ if (codes.includes('LEGAL_ACCEPTANCE_REQUIRED'))
137
+ return true;
138
+ return /LEGAL_ACCEPTANCE_REQUIRED/.test(typeof e?.message === 'string' ? e.message : '');
139
+ }
119
140
  export class PortalAPI {
120
141
  constructor(api, session, pkceStore = new BrowserSessionPkceStore(),
121
142
  /**
@@ -137,7 +158,9 @@ export class PortalAPI {
137
158
  * Native/direct mint: exchange the caller's identity session token for an
138
159
  * app-scoped gameplay token. Returns the token; it is NOT stored on this
139
160
  * client (build a per-game client with it). Free/open apps auto-grant access;
140
- * paid apps require an existing entitlement.
161
+ * paid apps require an existing entitlement. Refused with
162
+ * `LEGAL_ACCEPTANCE_REQUIRED` ({@link isLegalAcceptanceRequiredError}) until the
163
+ * player's consents are stored (`auth.recordPlayerConsents`, ck-api v2.35.0).
141
164
  */
142
165
  async mintAppToken(appId) {
143
166
  const data = await this.api.request(MintAppTokenDocument, {
@@ -148,7 +171,8 @@ export class PortalAPI {
148
171
  /**
149
172
  * Overworld/identity side: mint a one-time authorization code for a target
150
173
  * app, bound to the destination game's PKCE challenge + redirect URI.
151
- * Requires the identity session token.
174
+ * Requires the identity session token. Refused with `LEGAL_ACCEPTANCE_REQUIRED`
175
+ * until the player's consents are stored (ck-api v2.35.0).
152
176
  */
153
177
  async createAuthorizationCode(params) {
154
178
  const data = await this.api.request(CreatePortalAuthorizationCodeDocument, { input: params });
@@ -170,6 +194,11 @@ export class PortalAPI {
170
194
  * Same-app refresh: rotate the current app token for a fresh one (extended
171
195
  * TTL) and store it. Call before expiry to keep playing without bouncing
172
196
  * through the Overworld. Requires the current app token on this session.
197
+ *
198
+ * Refused with `LEGAL_ACCEPTANCE_REQUIRED` ({@link isLegalAcceptanceRequiredError})
199
+ * when the player's stored consents are missing or a required document has a
200
+ * new version (ck-api v2.35.0). Retrying cannot succeed: send a browser player
201
+ * back through {@link signIn}, where `/authorize` asks for them.
173
202
  */
174
203
  async refresh(currentServer) {
175
204
  // NATIVE CLIENTS NAME THEIR SERVER. A Buddy drops datagrams for a token it was
@@ -4551,9 +4551,11 @@ export type Mutation = {
4551
4551
  mintGridToken: GridTokenResponse;
4552
4552
  /** Publishes an app to the shared game-api environment. Free under the org's app-slot quota (result.free = true); beyond the quota, publish still succeeds and hourly usage is debited from the org wallet. Requires the 'manage_apps' permission on the app's org. Blocked when SHARED_GAME_API_URL is not configured. */
4553
4553
  publishAppToShared: PublishAppResult;
4554
+ /** Store acceptance of the current required legal documents (Game Terms, API Terms, SDK Developer Terms, Free Tier and Billing Basis, Overworld Privacy Policy) and the age-of-majority attestation. Both arguments must be true; a false value stores nothing and is refused with LEGAL_ACCEPTANCE_REQUIRED. Idempotent for a version already stored. Requires a session token. Gameplay tokens stay refused until this has succeeded for the current document set. */
4555
+ recordPlayerConsents: Scalars['Boolean']['output'];
4554
4556
  /** Rotate the calling app token for a fresh one (same app, extended TTL) and revoke the old. Call before the current token expires to keep playing without bouncing back through the Overworld. Allowed for app-scoped tokens; re-checks entitlement. NATIVE CLIENTS: pass `currentServer` (the ip4 + clientPort serverWithLeastClients gave you) and the new token is authorized on that same Buddy -- read `authorizedServer` on the response: when it is set, keep your UDP session and just switch tokens; when it is null, call serverWithLeastClients for a fresh placement. `authorizedServer` is null when the node is gone, draining, Full, on the wrong shard -- or when it is NearCapacity / running hot and a Ready sibling has room: a refresh is the cheapest moment to rebalance a resident, so expect to be moved occasionally under load. Without `currentServer` the new token is not known to any Buddy until you call serverWithLeastClients. */
4555
4557
  refreshAppToken: AppTokenResponse;
4556
- /** Registers a new email + password account: creates the (initially unconfirmed) account, emails a confirmation link, and returns an AuthResponse with a session `token` for immediate use (send as `Authorization: Bearer <token>`). If an account already exists for the email it is refused with extensions.code EMAIL_ALREADY_REGISTERED (409) and no session is returned: an account that already has a password is left exactly as it was (sign in, or use the emailed reset), and only a password-less account (created via magic link/social) gets the password attached pending email confirmation. It is a routine outcome rather than a fault, and it reached clients as INTERNAL_SERVER_ERROR before v1.60.0, which is why several of them match it by its message text. Public; first-party origins only (HOSTED_SIGN_IN_REQUIRED otherwise); rate-limited. */
4558
+ /** Registers a new email + password account: creates the (initially unconfirmed) account, emails a confirmation link, and returns an AuthResponse with a session `token` for immediate use (send as `Authorization: Bearer <token>`). If an account already exists for the email it is refused with extensions.code EMAIL_ALREADY_REGISTERED (409) and no session is returned: an account that already has a password is left exactly as it was (sign in, or use the emailed reset), and only a password-less account (created via magic link/social) gets the password attached pending email confirmation. It is a routine outcome rather than a fault, and it reached clients as INTERNAL_SERVER_ERROR before v1.60.0, which is why several of them match it by its message text. A browser request (Origin header present) must send acceptLegal and attestAgeOfMajority both true or it is refused with LEGAL_ACCEPTANCE_REQUIRED before an account is created; a request with no Origin may omit them, and gameplay tokens stay refused until the documents are stored. Public; first-party origins only (HOSTED_SIGN_IN_REQUIRED otherwise); rate-limited. */
4557
4559
  register: AuthResponse;
4558
4560
  /** OPERATOR ONLY. Reverses a retirement: the organization returns to status 'active', deleted_at is cleared, and the tombstone records who put it back and why rather than being deleted. Its apps are LEFT ARCHIVED — un-archiving is archiveApp's inverse and belongs to whoever decides which apps should serve traffic again. Refuses an organization that is not currently retired. */
4559
4561
  reinstateOrganization: OrgRetirementType;
@@ -5133,6 +5135,10 @@ export type MutationPublishAppToSharedArgs = {
5133
5135
  provider?: InputMaybe<PaymentProvider>;
5134
5136
  successUrl?: InputMaybe<Scalars['String']['input']>;
5135
5137
  };
5138
+ export type MutationRecordPlayerConsentsArgs = {
5139
+ acceptLegal: Scalars['Boolean']['input'];
5140
+ attestAgeOfMajority: Scalars['Boolean']['input'];
5141
+ };
5136
5142
  export type MutationRefreshAppTokenArgs = {
5137
5143
  currentServer?: InputMaybe<CurrentServerInput>;
5138
5144
  };
@@ -6552,6 +6558,8 @@ export type Query = {
6552
6558
  platformConfig: PlatformConfig;
6553
6559
  /** The caller's player-wallet auto-recharge settings (off-session card top-up before the player gate denies for funds). */
6554
6560
  playerAutoBilling: PlayerAutoBilling;
6561
+ /** Whether the signed-in account has stored the current required legal documents and the age-of-majority attestation. False means createPortalAuthorizationCode and mintAppToken will refuse with LEGAL_ACCEPTANCE_REQUIRED until recordPlayerConsents. Requires a session token. */
6562
+ playerLegalAcceptance: Scalars['Boolean']['output'];
6555
6563
  /** Live concurrent players for the org vs its all-time peak, a percentile comparison against other studios, and the site-wide total. Requires the 'view_usage' org permission. */
6556
6564
  playerPulse: PlayerPulse;
6557
6565
  /** The app's player rate-card markup in basis points on the platform base price (06 §4): the studio's usage-revenue stream, shown to players as a separate spend-history component. 0 = no markup (the BWF posture). Requires 'view_billing'. */
@@ -7215,6 +7223,10 @@ export type RealtimeConnectionEvent = {
7215
7223
  status: Scalars['String']['output'];
7216
7224
  };
7217
7225
  export type RegisterUserInput = {
7226
+ /** True when the player has agreed to the current required legal documents (Game Terms, API Terms, SDK Developer Terms, Free Tier and Billing Basis, Overworld Privacy Policy). A browser signup that omits this, or sends false, is refused with LEGAL_ACCEPTANCE_REQUIRED. Calls with no Origin header may omit it; gameplay tokens stay refused until the documents are stored. */
7227
+ acceptLegal?: InputMaybe<Scalars['Boolean']['input']>;
7228
+ /** True when the player attests they are at least 18, or the age of majority where they live if that is higher. Same requirement as acceptLegal: required on a browser signup, optional when the request has no Origin. */
7229
+ attestAgeOfMajority?: InputMaybe<Scalars['Boolean']['input']>;
7218
7230
  /** Email for the new account; the confirmation email is sent here. */
7219
7231
  email: Scalars['String']['input'];
7220
7232
  /** Optional initial public gamertag (min 3 characters). Can be set later via updateGamertag. */