@crowdedkingdoms/crowdyjs 18.10.0 → 18.11.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.
Files changed (63) hide show
  1. package/MIGRATION.md +43 -0
  2. package/README.md +79 -30
  3. package/dist/crowdy-client.d.ts +11 -3
  4. package/dist/crowdy-client.d.ts.map +1 -1
  5. package/dist/crowdy-client.js +25 -4
  6. package/dist/default-origin.d.ts +6 -6
  7. package/dist/default-origin.d.ts.map +1 -1
  8. package/dist/default-origin.js +6 -6
  9. package/dist/domains/exec.d.ts +6 -0
  10. package/dist/domains/exec.d.ts.map +1 -1
  11. package/dist/domains/exec.js +28 -2
  12. package/dist/generated/graphql-schema.d.ts +1 -1
  13. package/dist/generated/graphql-schema.d.ts.map +1 -1
  14. package/dist/index.d.ts +3 -3
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +5 -3
  17. package/dist/kit/index.d.ts +13 -2
  18. package/dist/kit/index.d.ts.map +1 -1
  19. package/dist/kit/index.js +13 -2
  20. package/dist/kit/kit.d.ts +83 -7
  21. package/dist/kit/kit.d.ts.map +1 -1
  22. package/dist/kit/kit.js +82 -4
  23. package/dist/kit/mirror.d.ts +111 -0
  24. package/dist/kit/mirror.d.ts.map +1 -0
  25. package/dist/kit/mirror.js +295 -0
  26. package/dist/kit/modules/matchmaking.d.ts +107 -0
  27. package/dist/kit/modules/matchmaking.d.ts.map +1 -0
  28. package/dist/kit/modules/matchmaking.js +109 -0
  29. package/dist/kit/modules/npcs.d.ts +80 -0
  30. package/dist/kit/modules/npcs.d.ts.map +1 -0
  31. package/dist/kit/modules/npcs.js +102 -0
  32. package/dist/kit/modules/presence.d.ts +81 -0
  33. package/dist/kit/modules/presence.d.ts.map +1 -0
  34. package/dist/kit/modules/presence.js +99 -0
  35. package/dist/kit/modules/sessions.d.ts +91 -0
  36. package/dist/kit/modules/sessions.d.ts.map +1 -0
  37. package/dist/kit/modules/sessions.js +84 -0
  38. package/dist/kit/modules/world.d.ts +69 -0
  39. package/dist/kit/modules/world.d.ts.map +1 -0
  40. package/dist/kit/modules/world.js +35 -0
  41. package/dist/kit/protocol.d.ts +128 -0
  42. package/dist/kit/protocol.d.ts.map +1 -0
  43. package/dist/kit/protocol.js +171 -0
  44. package/dist/kit/realtime.d.ts +72 -0
  45. package/dist/kit/realtime.d.ts.map +1 -0
  46. package/dist/kit/realtime.js +108 -0
  47. package/dist/kit/runtime.d.ts +90 -0
  48. package/dist/kit/runtime.d.ts.map +1 -0
  49. package/dist/kit/runtime.js +194 -0
  50. package/dist/kit/store.d.ts +20 -0
  51. package/dist/kit/store.d.ts.map +1 -0
  52. package/dist/kit/store.js +25 -0
  53. package/dist/kit/topology.d.ts +69 -0
  54. package/dist/kit/topology.d.ts.map +1 -0
  55. package/dist/kit/topology.js +156 -0
  56. package/dist/kit/wire.d.ts +45 -5
  57. package/dist/kit/wire.d.ts.map +1 -1
  58. package/dist/kit/wire.js +51 -5
  59. package/dist/live-coding/assets/browser-authoring-index.json +1 -1
  60. package/dist/live-coding/assets/manifest.json +1 -1
  61. package/dist/live-coding/browser-authoring-index.generated.d.ts.map +1 -1
  62. package/dist/live-coding/browser-authoring-index.generated.js +1935 -45
  63. package/package.json +1 -1
@@ -0,0 +1,194 @@
1
+ import { CrowdyExecError, } from '../domains/exec.js';
2
+ import { KitError, newActionId, withActionId } from './protocol.js';
3
+ /** Subscriptions one connection holds at most (the gateway refuses the next). */
4
+ export const KIT_SUBSCRIPTIONS_MAX = 256;
5
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
6
+ /** A token bucket: `capacity` tokens a window, refilled continuously. */
7
+ class Budget {
8
+ constructor(capacity, windowMs) {
9
+ this.capacity = capacity;
10
+ this.windowMs = windowMs;
11
+ this.last = Date.now();
12
+ this.blockedUntil = 0;
13
+ this.tokens = capacity;
14
+ }
15
+ refill() {
16
+ const now = Date.now();
17
+ this.tokens = Math.min(this.capacity, this.tokens + ((now - this.last) * this.capacity) / this.windowMs);
18
+ this.last = now;
19
+ }
20
+ async take() {
21
+ for (;;) {
22
+ const wait = this.blockedUntil - Date.now();
23
+ if (wait > 0) {
24
+ await sleep(wait);
25
+ continue;
26
+ }
27
+ this.refill();
28
+ if (this.tokens >= 1) {
29
+ this.tokens -= 1;
30
+ return;
31
+ }
32
+ await sleep(Math.ceil(((1 - this.tokens) * this.windowMs) / this.capacity));
33
+ }
34
+ }
35
+ /** The gateway said to wait: nothing is sent until `ms` from now. */
36
+ hold(ms) {
37
+ this.blockedUntil = Math.max(this.blockedUntil, Date.now() + ms);
38
+ this.tokens = 0;
39
+ }
40
+ }
41
+ /**
42
+ * The kit's way to the app's hubs: one {@link ExecConnection} shared by every kit module,
43
+ * opened when first needed. It paces what it sends to a budget below the gateway's limit,
44
+ * sends a call again when that is safe (it did not run, or it carries an action id the hub
45
+ * answers once), counts subscriptions under the gateway's cap, and turns a hub's coded
46
+ * refusal into a {@link KitError}.
47
+ */
48
+ export class KitRuntime {
49
+ constructor(appId, exec, options = {}, whoAmI) {
50
+ this.appId = appId;
51
+ this.exec = exec;
52
+ this.options = options;
53
+ this.whoAmI = whoAmI;
54
+ this.conn = null;
55
+ this.connecting = null;
56
+ this.ended = null;
57
+ this.subs = new Map();
58
+ this.reconnectListeners = new Set();
59
+ this.endedListeners = new Set();
60
+ this.me = null;
61
+ this.budget = new Budget(Math.max(1, options.callBudget ?? 100), Math.max(1, options.budgetWindowMs ?? 10000));
62
+ this.retries = Math.max(0, options.retries ?? 2);
63
+ }
64
+ /** The connection, opened on first use. */
65
+ async connection() {
66
+ if (this.ended !== null)
67
+ throw new CrowdyExecError('Denied', `access ended: ${this.ended}`);
68
+ if (this.conn)
69
+ return this.conn;
70
+ if (!this.connecting) {
71
+ this.connecting = this.open().catch((e) => {
72
+ this.connecting = null;
73
+ throw e;
74
+ });
75
+ }
76
+ return this.connecting;
77
+ }
78
+ async open() {
79
+ let c = this.options.connection;
80
+ if (!c) {
81
+ if (!this.exec)
82
+ throw new CrowdyExecError('Unavailable', 'the kit has no exec client to connect with');
83
+ c = this.options.developer
84
+ ? await this.exec.connectAsDeveloper(this.appId, this.options.connect)
85
+ : await this.exec.connect(this.appId, this.options.connect);
86
+ }
87
+ c.onReconnect((host) => {
88
+ for (const l of [...this.reconnectListeners])
89
+ l(host);
90
+ });
91
+ c.onAccessEnded((reason) => {
92
+ this.ended = reason;
93
+ for (const l of [...this.endedListeners])
94
+ l(reason);
95
+ });
96
+ this.conn = c;
97
+ return c;
98
+ }
99
+ /** The player's id, from the options or `users.me`; null when neither knows it. */
100
+ async playerId() {
101
+ if (this.options.playerId !== undefined)
102
+ return String(this.options.playerId);
103
+ if (!this.me) {
104
+ this.me = this.whoAmI ? this.whoAmI().catch(() => null) : Promise.resolve(null);
105
+ }
106
+ return this.me;
107
+ }
108
+ /**
109
+ * Calls a hub's endpoint, `args` as MessagePack, and returns the decoded reply.
110
+ * @throws {KitError} for a hub's coded refusal; {@link CrowdyExecError} for the platform's.
111
+ */
112
+ async call(nodeType, key, method, args, options = {}) {
113
+ const actionId = options.action === true ? newActionId() : typeof options.action === 'string' ? options.action : undefined;
114
+ const sent = actionId ? withActionId(args, actionId) : args;
115
+ for (let attempt = 0;; attempt++) {
116
+ await this.budget.take();
117
+ const conn = await this.connection();
118
+ try {
119
+ return await conn.call(nodeType, key, method, sent, { timeoutMs: options.timeoutMs });
120
+ }
121
+ catch (e) {
122
+ const err = KitError.from(e);
123
+ if (attempt < this.retries && err instanceof CrowdyExecError && !(err instanceof KitError)) {
124
+ if (err.status === 'Busy' && err.rateLimited) {
125
+ this.budget.hold(err.retryAfterMs ?? 1000);
126
+ continue;
127
+ }
128
+ const didNotRun = err.status === 'Busy' || err.status === 'RateLimited';
129
+ const unknown = err.status === 'DeadlineExceeded' || err.status === 'Unavailable' || err.status === 'Moved';
130
+ if (didNotRun || (actionId && unknown)) {
131
+ await sleep(Math.min(2000, 200 * 2 ** attempt) * (0.5 + Math.random() / 2));
132
+ continue;
133
+ }
134
+ }
135
+ throw err;
136
+ }
137
+ }
138
+ }
139
+ /**
140
+ * Receives what a hub publishes on `topic`. Returns the function that stops this handler
141
+ * (and the subscription with the last one).
142
+ * @throws {KitError} `limit` past {@link KIT_SUBSCRIPTIONS_MAX} subscriptions.
143
+ */
144
+ async subscribe(nodeType, key, topic, onPush) {
145
+ const k = `${nodeType}\u0000${key}\u0000${topic}`;
146
+ const held = this.subs.get(k) ?? 0;
147
+ if (held === 0) {
148
+ if (this.subs.size >= KIT_SUBSCRIPTIONS_MAX) {
149
+ throw new KitError('limit', `a connection holds at most ${KIT_SUBSCRIPTIONS_MAX} subscriptions`);
150
+ }
151
+ await this.budget.take();
152
+ }
153
+ const conn = await this.connection();
154
+ const stop = await conn.subscribe(nodeType, key, topic, onPush);
155
+ this.subs.set(k, (this.subs.get(k) ?? 0) + 1);
156
+ let stopped = false;
157
+ return async () => {
158
+ if (stopped)
159
+ return;
160
+ stopped = true;
161
+ const left = (this.subs.get(k) ?? 1) - 1;
162
+ if (left > 0) {
163
+ this.subs.set(k, left);
164
+ }
165
+ else {
166
+ this.subs.delete(k);
167
+ await this.budget.take();
168
+ }
169
+ await stop();
170
+ };
171
+ }
172
+ /** How many distinct topics the kit subscribes to. */
173
+ get subscriptions() {
174
+ return this.subs.size;
175
+ }
176
+ /** Called with the new host after the connection reconnects; kit mirrors resync then. */
177
+ onReconnect(listener) {
178
+ this.reconnectListeners.add(listener);
179
+ return () => this.reconnectListeners.delete(listener);
180
+ }
181
+ /** Called once when the player's access ended (close code 4403); nothing reconnects. */
182
+ onAccessEnded(listener) {
183
+ this.endedListeners.add(listener);
184
+ return () => this.endedListeners.delete(listener);
185
+ }
186
+ /** Closes the connection the kit opened (not one it was given). */
187
+ close() {
188
+ if (this.conn && !this.options.connection)
189
+ this.conn.close();
190
+ this.conn = null;
191
+ this.connecting = null;
192
+ this.subs.clear();
193
+ }
194
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The kit's observable value: `get` the current value, `subscribe` to hear each new one. The
3
+ * shape React's `useSyncExternalStore(store.subscribe, store.get)` takes, and that any other
4
+ * framework wraps in a line.
5
+ */
6
+ export interface KitStore<T> {
7
+ get(): T;
8
+ /** Calls `listener` with every new value; returns the function that stops it. */
9
+ subscribe(listener: (value: T) => void): () => void;
10
+ }
11
+ /** A {@link KitStore} its owner sets. */
12
+ export declare class WritableKitStore<T> implements KitStore<T> {
13
+ private value;
14
+ private readonly listeners;
15
+ constructor(initial: T);
16
+ get(): T;
17
+ subscribe(listener: (value: T) => void): () => void;
18
+ set(value: T): void;
19
+ }
20
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/kit/store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,GAAG,IAAI,CAAC,CAAC;IACT,iFAAiF;IACjF,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACrD;AAED,yCAAyC;AACzC,qBAAa,gBAAgB,CAAC,CAAC,CAAE,YAAW,QAAQ,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,KAAK,CAAI;IACjB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;gBAE/C,OAAO,EAAE,CAAC;IAItB,GAAG,IAAI,CAAC;IAIR,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;IAKnD,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;CAUpB"}
@@ -0,0 +1,25 @@
1
+ /** A {@link KitStore} its owner sets. */
2
+ export class WritableKitStore {
3
+ constructor(initial) {
4
+ this.listeners = new Set();
5
+ this.value = initial;
6
+ }
7
+ get() {
8
+ return this.value;
9
+ }
10
+ subscribe(listener) {
11
+ this.listeners.add(listener);
12
+ return () => this.listeners.delete(listener);
13
+ }
14
+ set(value) {
15
+ this.value = value;
16
+ for (const l of [...this.listeners]) {
17
+ try {
18
+ l(value);
19
+ }
20
+ catch {
21
+ /* a listener's exception is its own */
22
+ }
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,69 @@
1
+ import type { ExecAPI, ExecBuild, ExecManifestType, ExecNodeTypeInput, ExecStarterPack } from '../domains/exec.js';
2
+ /** The crates one build takes at most (the game API's `execBuild`). */
3
+ export declare const KIT_BUILD_MAX_CRATES = 16;
4
+ /** The node API scopes a manifest may declare (ck-exec `bounds::NODE_API_SCOPES`). */
5
+ export declare const KIT_NODE_API_SCOPES: readonly string[];
6
+ /** A manifest as the kit composes it: the root hub and each node type. */
7
+ export interface KitManifest {
8
+ root: string;
9
+ types: Record<string, ExecNodeTypeInput | ExecManifestType>;
10
+ }
11
+ /** What {@link KitTopology.plan} composes: a manifest, and the starter crates it builds. */
12
+ export interface KitTopologyPlan {
13
+ root: string;
14
+ types: Record<string, ExecNodeTypeInput>;
15
+ /** The starter crates the types name, each built once. */
16
+ crates: string[];
17
+ }
18
+ /** Changes to a planned type: a seed, limits, replicas, scopes, `client`, ... */
19
+ export interface KitPlanOptions {
20
+ overrides?: Record<string, Partial<ExecNodeTypeInput>>;
21
+ }
22
+ /** How {@link KitTopology.deploy} waits for its build. */
23
+ export interface KitDeployOptions {
24
+ /** Default 10 minutes. */
25
+ timeoutMs?: number;
26
+ /** Called with the build once it is done. */
27
+ onBuild?: (build: ExecBuild) => void;
28
+ }
29
+ /**
30
+ * What the execution manager would refuse in `manifest`, in its words (ck-exec
31
+ * `Manifest::problems`, less the digests, which the build fills in): the root is a hub
32
+ * without a parent, every other type has a defined parent, `calls` name defined types or `*`,
33
+ * replicas are for spokes, scopes are known. Empty when it deploys.
34
+ */
35
+ export declare function kitManifestProblems(manifest: KitManifest): string[];
36
+ /**
37
+ * An app's tree of kit hubs, composed from the starter packs (`exec.starters`): pick the node
38
+ * types a game uses, and {@link plan} adds the hubs they hang under and the ones they call,
39
+ * checks the tree, and {@link deploy} builds the crates on the platform and deploys them.
40
+ * For the app's developers (the org's `manage_compute`), from an identity session.
41
+ */
42
+ export declare class KitTopology {
43
+ private readonly appId;
44
+ private readonly exec;
45
+ private packed;
46
+ constructor(appId: string, exec: ExecAPI | undefined);
47
+ private api;
48
+ /** The starter packs this tier's toolchain carries (fetched once). */
49
+ pack(): Promise<ExecStarterPack>;
50
+ /** The node types the packs offer. */
51
+ types(): Promise<string[]>;
52
+ /**
53
+ * A manifest with the types in `select`, the types they hang under up to the root, and the
54
+ * types they call (by name, not `*`), from the packs' manifest.
55
+ * @throws {CrowdyError} for a type the packs do not have, a tree the manager would refuse,
56
+ * or more crates than one build takes.
57
+ */
58
+ plan(select: readonly string[], options?: KitPlanOptions): Promise<KitTopologyPlan>;
59
+ /**
60
+ * Builds the plan's crates on the platform, waits, and deploys the manifest with the build.
61
+ * Resolves with the deployed version and the build id.
62
+ * @throws {CrowdyError} when the build fails (its log in the message).
63
+ */
64
+ deploy(plan: KitTopologyPlan, options?: KitDeployOptions): Promise<{
65
+ version: number;
66
+ buildId: string;
67
+ }>;
68
+ }
69
+ //# sourceMappingURL=topology.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topology.d.ts","sourceRoot":"","sources":["../../src/kit/topology.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EAET,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAE5B,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,sFAAsF;AACtF,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAUhD,CAAC;AAEF,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,gBAAgB,CAAC,CAAC;CAC7D;AAED,4FAA4F;AAC5F,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACzC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;CACxD;AAED,0DAA0D;AAC1D,MAAM,WAAW,gBAAgB;IAC/B,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CACtC;AAID;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,EAAE,CA0BnE;AAED;;;;;GAKG;AACH,qBAAa,WAAW;IAIpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJvB,OAAO,CAAC,MAAM,CAAyC;gBAGpC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,OAAO,GAAG,SAAS;IAG5C,OAAO,CAAC,GAAG;IAKX,sEAAsE;IACtE,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC;IAYhC,sCAAsC;IAChC,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIhC;;;;;OAKG;IACG,IAAI,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,eAAe,CAAC;IA8B7F;;;;OAIG;IACG,MAAM,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAiBnH"}
@@ -0,0 +1,156 @@
1
+ import { CrowdyError } from '../errors.js';
2
+ /** The crates one build takes at most (the game API's `execBuild`). */
3
+ export const KIT_BUILD_MAX_CRATES = 16;
4
+ /** The node API scopes a manifest may declare (ck-exec `bounds::NODE_API_SCOPES`). */
5
+ export const KIT_NODE_API_SCOPES = [
6
+ 'players.read',
7
+ 'players.write',
8
+ 'world.read',
9
+ 'world.write',
10
+ 'grids.read',
11
+ 'permissions.write',
12
+ 'grids.write',
13
+ 'access.read',
14
+ 'access.write',
15
+ ];
16
+ const NAME = /^[A-Za-z0-9_-]{1,64}$/;
17
+ /**
18
+ * What the execution manager would refuse in `manifest`, in its words (ck-exec
19
+ * `Manifest::problems`, less the digests, which the build fills in): the root is a hub
20
+ * without a parent, every other type has a defined parent, `calls` name defined types or `*`,
21
+ * replicas are for spokes, scopes are known. Empty when it deploys.
22
+ */
23
+ export function kitManifestProblems(manifest) {
24
+ const out = [];
25
+ const types = manifest.types;
26
+ const root = types[manifest.root];
27
+ if (!root)
28
+ out.push(`root type \`${manifest.root}\` is not defined`);
29
+ else if (root.kind !== 'hub')
30
+ out.push('the root type must be a hub');
31
+ else if (root.parent)
32
+ out.push('the root type has no parent');
33
+ for (const [name, t] of Object.entries(types)) {
34
+ if (!NAME.test(name))
35
+ out.push(`type name \`${name}\` must be 1-64 letters, digits, \`-\` or \`_\``);
36
+ if (name !== manifest.root) {
37
+ if (!t.parent)
38
+ out.push(`\`${name}\` needs a parent`);
39
+ else if (!types[t.parent])
40
+ out.push(`\`${name}\`: parent \`${t.parent}\` is not defined`);
41
+ }
42
+ for (const c of t.calls ?? []) {
43
+ if (c !== '*' && !types[c])
44
+ out.push(`\`${name}\` calls \`${c}\`, which is not defined`);
45
+ }
46
+ if (t.kind === 'hub' && (t.replicas !== undefined || t.max_replicas !== undefined || t.concurrency !== undefined)) {
47
+ out.push(`\`${name}\`: replicas, max_replicas and concurrency are for spokes`);
48
+ }
49
+ for (const s of t.scopes ?? []) {
50
+ if (!KIT_NODE_API_SCOPES.includes(s)) {
51
+ out.push(`\`${name}\`: unknown node API scope \`${s}\` (allowed: ${KIT_NODE_API_SCOPES.join(', ')})`);
52
+ }
53
+ }
54
+ }
55
+ return out;
56
+ }
57
+ /**
58
+ * An app's tree of kit hubs, composed from the starter packs (`exec.starters`): pick the node
59
+ * types a game uses, and {@link plan} adds the hubs they hang under and the ones they call,
60
+ * checks the tree, and {@link deploy} builds the crates on the platform and deploys them.
61
+ * For the app's developers (the org's `manage_compute`), from an identity session.
62
+ */
63
+ export class KitTopology {
64
+ constructor(appId, exec) {
65
+ this.appId = appId;
66
+ this.exec = exec;
67
+ this.packed = null;
68
+ }
69
+ api() {
70
+ if (!this.exec)
71
+ throw new CrowdyError({ message: 'the kit has no exec client' });
72
+ return this.exec;
73
+ }
74
+ /** The starter packs this tier's toolchain carries (fetched once). */
75
+ pack() {
76
+ if (!this.packed) {
77
+ this.packed = this.api()
78
+ .starters(this.appId)
79
+ .catch((e) => {
80
+ this.packed = null;
81
+ throw e;
82
+ });
83
+ }
84
+ return this.packed;
85
+ }
86
+ /** The node types the packs offer. */
87
+ async types() {
88
+ return Object.keys((await this.pack()).manifest.types);
89
+ }
90
+ /**
91
+ * A manifest with the types in `select`, the types they hang under up to the root, and the
92
+ * types they call (by name, not `*`), from the packs' manifest.
93
+ * @throws {CrowdyError} for a type the packs do not have, a tree the manager would refuse,
94
+ * or more crates than one build takes.
95
+ */
96
+ async plan(select, options = {}) {
97
+ const pack = await this.pack();
98
+ const all = pack.manifest.types;
99
+ const chosen = new Set();
100
+ const add = (name) => {
101
+ if (chosen.has(name))
102
+ return;
103
+ const t = all[name];
104
+ if (!t)
105
+ throw new CrowdyError({ message: `the starter packs have no node type '${name}' (they have ${Object.keys(all).join(', ')})` });
106
+ chosen.add(name);
107
+ if (t.parent)
108
+ add(t.parent);
109
+ for (const c of t.calls ?? [])
110
+ if (c !== '*')
111
+ add(c);
112
+ };
113
+ add(pack.manifest.root);
114
+ for (const name of select)
115
+ add(name);
116
+ const types = {};
117
+ for (const name of chosen) {
118
+ const merged = { ...all[name], ...(options.overrides?.[name] ?? {}) };
119
+ // A type calls only what the plan holds.
120
+ if (merged.calls)
121
+ merged.calls = merged.calls.filter((c) => c === '*' || chosen.has(c));
122
+ types[name] = merged;
123
+ }
124
+ const problems = kitManifestProblems({ root: pack.manifest.root, types });
125
+ if (problems.length)
126
+ throw new CrowdyError({ message: `the composed manifest would be refused: ${problems.join('; ')}` });
127
+ const crates = [...new Set(Object.values(types).map((t) => t.crate).filter((c) => typeof c === 'string'))];
128
+ if (crates.length > KIT_BUILD_MAX_CRATES) {
129
+ throw new CrowdyError({ message: `${crates.length} crates are more than one build takes (${KIT_BUILD_MAX_CRATES})` });
130
+ }
131
+ return { root: pack.manifest.root, types, crates };
132
+ }
133
+ /**
134
+ * Builds the plan's crates on the platform, waits, and deploys the manifest with the build.
135
+ * Resolves with the deployed version and the build id.
136
+ * @throws {CrowdyError} when the build fails (its log in the message).
137
+ */
138
+ async deploy(plan, options = {}) {
139
+ const pack = await this.pack();
140
+ const crates = plan.crates.map((name) => {
141
+ const s = pack.starters.find((x) => x.crate === name);
142
+ if (!s)
143
+ throw new CrowdyError({ message: `the starter packs have no crate '${name}'` });
144
+ return { name, files: s.files };
145
+ });
146
+ const exec = this.api();
147
+ const queued = await exec.build(this.appId, crates);
148
+ const done = await exec.waitForBuild(this.appId, queued.buildId, { timeoutMs: options.timeoutMs });
149
+ options.onBuild?.(done);
150
+ if (done.status !== 'succeeded') {
151
+ throw new CrowdyError({ message: `build ${done.buildId} ${done.status}: ${(done.log ?? '').slice(-2000)}` });
152
+ }
153
+ const { version } = await exec.deploy({ appId: this.appId, root: plan.root, types: plan.types, buildId: done.buildId });
154
+ return { version, buildId: done.buildId };
155
+ }
156
+ }
@@ -1,9 +1,11 @@
1
1
  /**
2
- * Engine wire registry — the client mirror of `crowdy-game-kit-core::wire`
3
- * (the actor pose layout and flag-bit registry the game engines emit, and
4
- * hubs that keep a game's client parsers still send). Parity with the Rust
5
- * crate is checked by the kit wire unit suite: any change here must land in
6
- * kit-core first.
2
+ * The kit's realtime wire: the server-event registry kit hubs emit through
3
+ * the realtime tier (`ckx_sdk::kit::wire` is its source: ids 77 and 90-101,
4
+ * JSON bodies with camelCase keys, an app's own from 1000), and the 48-byte
5
+ * engine pose layout with its flag bits, for hubs that show actors with it
6
+ * rather than with `KitActorState` (`realtime.ts`). The registry's bodies are
7
+ * held to ck-exec's `kit-protocol.json` by the kit protocol unit suite: a
8
+ * change lands in `ckx_sdk::kit::wire` first.
7
9
  *
8
10
  * 48-byte little-endian pose: pos f32 x3 (0..11), yaw/pitch f32 (12..19),
9
11
  * velocity f32 x3 (20..31), flags u8 (32), held u8 (33), 34-35 reserved,
@@ -76,6 +78,14 @@ export declare const EVENT_CONTROL_POINT = 96;
76
78
  export declare const EVENT_RACE_TIMING = 97;
77
79
  /** Zone change: shrinking circles, event areas (kit-sim zones). */
78
80
  export declare const EVENT_ZONE_CHANGE = 98;
81
+ /** Encounter: a wave began or was cleared, a boss changed phase (directors). */
82
+ export declare const EVENT_ENCOUNTER = 99;
83
+ /** Possession: the contested object (a ball) changed hands, or a goal was scored. */
84
+ export declare const EVENT_POSSESSION = 100;
85
+ /** An emote: a client event players send, the kit's convention ({@link EmotesKit}). */
86
+ export declare const EVENT_EMOTE = 101;
87
+ /** The first event type an app's own events may use. */
88
+ export declare const EVENT_APP_FIRST = 1000;
79
89
  /** Split an engine server-event payload into its type + JSON body. */
80
90
  export declare function parseEngineEvent(bytes: Uint8Array): {
81
91
  eventType: number;
@@ -183,4 +193,34 @@ export interface ZoneChangeEvent {
183
193
  }
184
194
  /** Parse a zone-change event; null when the payload is another type. */
185
195
  export declare function parseZoneChangeEvent(bytes: Uint8Array): ZoneChangeEvent | null;
196
+ /** A parsed type-99 encounter event (a wave began or was cleared, a boss changed phase). */
197
+ export interface EncounterEvent {
198
+ /** `'wave_started'`, `'wave_cleared'`, `'boss_phase'` or `'finished'`. */
199
+ kind: string;
200
+ encounterId: string;
201
+ wave: number;
202
+ phase: number;
203
+ body: Record<string, unknown>;
204
+ }
205
+ /** Parse an encounter event; null when the payload is another type. */
206
+ export declare function parseEncounterEvent(bytes: Uint8Array): EncounterEvent | null;
207
+ /** A parsed type-100 possession event (the contested object changed hands, or a goal). */
208
+ export interface PossessionEvent {
209
+ /** `'claimed'`, `'passed'`, `'loose'` or `'goal'`. */
210
+ kind: string;
211
+ holderId: string | null;
212
+ team: string | null;
213
+ body: Record<string, unknown>;
214
+ }
215
+ /** Parse a possession event; null when the payload is another type. */
216
+ export declare function parsePossessionEvent(bytes: Uint8Array): PossessionEvent | null;
217
+ /** A parsed type-101 emote (a client event, the kit's convention). */
218
+ export interface EmoteEvent {
219
+ emote: string;
220
+ /** The actor the emote is aimed at, if any. */
221
+ targetUuid: string | null;
222
+ body: Record<string, unknown>;
223
+ }
224
+ /** Parse an emote; null when the payload is another type. */
225
+ export declare function parseEmoteEvent(bytes: Uint8Array): EmoteEvent | null;
186
226
  //# sourceMappingURL=wire.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/kit/wire.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/kit/wire.ts"],"names":[],"mappings":"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"}
package/dist/kit/wire.js CHANGED
@@ -1,9 +1,11 @@
1
1
  /**
2
- * Engine wire registry — the client mirror of `crowdy-game-kit-core::wire`
3
- * (the actor pose layout and flag-bit registry the game engines emit, and
4
- * hubs that keep a game's client parsers still send). Parity with the Rust
5
- * crate is checked by the kit wire unit suite: any change here must land in
6
- * kit-core first.
2
+ * The kit's realtime wire: the server-event registry kit hubs emit through
3
+ * the realtime tier (`ckx_sdk::kit::wire` is its source: ids 77 and 90-101,
4
+ * JSON bodies with camelCase keys, an app's own from 1000), and the 48-byte
5
+ * engine pose layout with its flag bits, for hubs that show actors with it
6
+ * rather than with `KitActorState` (`realtime.ts`). The registry's bodies are
7
+ * held to ck-exec's `kit-protocol.json` by the kit protocol unit suite: a
8
+ * change lands in `ckx_sdk::kit::wire` first.
7
9
  *
8
10
  * 48-byte little-endian pose: pos f32 x3 (0..11), yaw/pitch f32 (12..19),
9
11
  * velocity f32 x3 (20..31), flags u8 (32), held u8 (33), 34-35 reserved,
@@ -130,6 +132,14 @@ export const EVENT_CONTROL_POINT = 96;
130
132
  export const EVENT_RACE_TIMING = 97;
131
133
  /** Zone change: shrinking circles, event areas (kit-sim zones). */
132
134
  export const EVENT_ZONE_CHANGE = 98;
135
+ /** Encounter: a wave began or was cleared, a boss changed phase (directors). */
136
+ export const EVENT_ENCOUNTER = 99;
137
+ /** Possession: the contested object (a ball) changed hands, or a goal was scored. */
138
+ export const EVENT_POSSESSION = 100;
139
+ /** An emote: a client event players send, the kit's convention ({@link EmotesKit}). */
140
+ export const EVENT_EMOTE = 101;
141
+ /** The first event type an app's own events may use. */
142
+ export const EVENT_APP_FIRST = 1000;
133
143
  /** Split an engine server-event payload into its type + JSON body. */
134
144
  export function parseEngineEvent(bytes) {
135
145
  if (bytes.length < 2)
@@ -278,3 +288,39 @@ export function parseZoneChangeEvent(bytes) {
278
288
  body: parsed.body,
279
289
  };
280
290
  }
291
+ /** Parse an encounter event; null when the payload is another type. */
292
+ export function parseEncounterEvent(bytes) {
293
+ const parsed = parseEngineEvent(bytes);
294
+ if (!parsed || parsed.eventType !== EVENT_ENCOUNTER)
295
+ return null;
296
+ return {
297
+ kind: String(parsed.body.kind ?? ''),
298
+ encounterId: String(parsed.body.encounterId ?? ''),
299
+ wave: Number(parsed.body.wave ?? 0),
300
+ phase: Number(parsed.body.phase ?? 0),
301
+ body: parsed.body,
302
+ };
303
+ }
304
+ /** Parse a possession event; null when the payload is another type. */
305
+ export function parsePossessionEvent(bytes) {
306
+ const parsed = parseEngineEvent(bytes);
307
+ if (!parsed || parsed.eventType !== EVENT_POSSESSION)
308
+ return null;
309
+ return {
310
+ kind: String(parsed.body.kind ?? ''),
311
+ holderId: parsed.body.holderId != null ? String(parsed.body.holderId) : null,
312
+ team: parsed.body.team != null ? String(parsed.body.team) : null,
313
+ body: parsed.body,
314
+ };
315
+ }
316
+ /** Parse an emote; null when the payload is another type. */
317
+ export function parseEmoteEvent(bytes) {
318
+ const parsed = parseEngineEvent(bytes);
319
+ if (!parsed || parsed.eventType !== EVENT_EMOTE)
320
+ return null;
321
+ return {
322
+ emote: String(parsed.body.emote ?? ''),
323
+ targetUuid: parsed.body.targetUuid != null ? String(parsed.body.targetUuid) : null,
324
+ body: parsed.body,
325
+ };
326
+ }