@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,128 @@
1
+ /**
2
+ * The game kit protocol: what kit hubs (ck-exec's starter packs, built on `ckx_sdk::kit`)
3
+ * send the kit's clients, read without I/O.
4
+ *
5
+ * A kit hub's topics carry **kit messages**: MessagePack maps with the hub's data and four
6
+ * reserved fields beside it: `v` (the protocol version, {@link KIT_PROTOCOL}), `epoch` (the
7
+ * publishing instance's epoch, which changes whenever it is placed again: a move, a restart or
8
+ * a crash), `seq` (one more than the topic's last message) and `kind`:
9
+ *
10
+ * - `snapshot`: the topic's whole public state; it replaces what the client holds.
11
+ * - `delta`: one change to a collection (`id`, then `type_name` and `props`, or `removed`),
12
+ * applied in `seq` order. A gap in `seq`, or another `epoch`, means a resync.
13
+ * - `changed`: something private changed for the players in `who` (`what` names it); they read
14
+ * it back with a call the hub answers for its caller alone. Topics have no access control,
15
+ * so kit hubs never publish anything private.
16
+ * - `event`: something that happened, with nothing to keep.
17
+ *
18
+ * Every kit hub answers `snapshot { topic }` with a `snapshot` message whose `seq` is the
19
+ * topic's last. A call that changes something may carry an `action_id`; the hub answers a call
20
+ * sent again with the first answer. A refusal's message is `kit:<code>: <text>`.
21
+ */
22
+ import { CrowdyExecError } from '../domains/exec.js';
23
+ /** The protocol version kit messages carry in `v`. */
24
+ export declare const KIT_PROTOCOL = 1;
25
+ /** The method every kit hub answers with a topic's snapshot. */
26
+ export declare const KIT_SNAPSHOT_METHOD = "snapshot";
27
+ /** The longest `action_id` a hub takes, in bytes. */
28
+ export declare const KIT_ACTION_ID_MAX = 64;
29
+ export type KitMessageKind = 'snapshot' | 'delta' | 'changed' | 'event';
30
+ /** The reserved fields of a kit message. */
31
+ export interface KitHeader {
32
+ v: number;
33
+ epoch: number;
34
+ seq: number;
35
+ kind: KitMessageKind;
36
+ }
37
+ /** The body of a `changed` message. */
38
+ export interface KitChanged {
39
+ /** The players who should read again (player ids). */
40
+ who: number[];
41
+ /** What changed for them, as the hub's endpoints name it. */
42
+ what: string;
43
+ }
44
+ /** One member of a collection, as a `delta` or a collection snapshot carries it. */
45
+ export interface KitContainer {
46
+ id: number;
47
+ type_name: string;
48
+ /** Its public properties, all of them: a delta replaces what the client held. */
49
+ props: Record<string, unknown>;
50
+ }
51
+ /** A collection delta's body. */
52
+ export interface KitDelta {
53
+ id: number;
54
+ type_name?: string;
55
+ props?: Record<string, unknown>;
56
+ removed?: boolean;
57
+ }
58
+ /** Whether `value` is a kit message: a map with the four reserved fields. */
59
+ export declare function isKitMessage(value: unknown): value is KitHeader & Record<string, unknown>;
60
+ /**
61
+ * A kit message split into its header and its body (every other field), or null when
62
+ * `value` is not one.
63
+ */
64
+ export declare function splitKitMessage<T = Record<string, unknown>>(value: unknown): {
65
+ header: KitHeader;
66
+ body: T;
67
+ } | null;
68
+ /** The code and text of a kit refusal's message, or null for any other message. */
69
+ export declare function parseKitRefusal(message: string): {
70
+ code: string;
71
+ text: string;
72
+ } | null;
73
+ /** The refusal codes kit hubs share; a hub may add its own (lowercase, digits, `_`). */
74
+ export declare const KIT_CODES: {
75
+ readonly BAD_REQUEST: "bad_request";
76
+ readonly NOT_FOUND: "not_found";
77
+ readonly FORBIDDEN: "forbidden";
78
+ readonly CONFLICT: "conflict";
79
+ readonly FULL: "full";
80
+ readonly LIMIT: "limit";
81
+ readonly COOLDOWN: "cooldown";
82
+ readonly NOT_YOUR_TURN: "not_your_turn";
83
+ readonly NOT_MEMBER: "not_member";
84
+ readonly STARTED: "started";
85
+ readonly FINISHED: "finished";
86
+ readonly NOT_READY: "not_ready";
87
+ readonly RESERVED: "reserved";
88
+ readonly EMPTY: "empty";
89
+ readonly OUT_OF_REACH: "out_of_reach";
90
+ readonly EXPIRED: "expired";
91
+ readonly INSUFFICIENT: "insufficient";
92
+ readonly ALREADY_DONE: "already_done";
93
+ };
94
+ /**
95
+ * A kit hub refused the call (`AppError` with a `kit:<code>:` message): `code` is what to
96
+ * branch on, `text` what to show. It is a {@link CrowdyExecError} with status `AppError`, so
97
+ * code that handles exec errors handles it.
98
+ */
99
+ export declare class KitError extends CrowdyExecError {
100
+ readonly code: string;
101
+ readonly text: string;
102
+ constructor(code: string, text: string, cause?: unknown);
103
+ /** `error` as a {@link KitError} when it is a coded refusal; otherwise `error` itself. */
104
+ static from(error: unknown): unknown;
105
+ }
106
+ /** The refusal code of `error`, when it is a kit refusal. */
107
+ export declare function kitErrorCode(error: unknown): string | null;
108
+ /** A fresh `action_id`: unique per attempt, the same for every resend of that attempt. */
109
+ export declare function newActionId(): string;
110
+ /**
111
+ * `args` with `action_id` beside them: a plain object gains the field, `undefined` or `null`
112
+ * becomes `{ action_id }`. Anything else (an array, a number) cannot carry one and is
113
+ * returned as it is.
114
+ */
115
+ export declare function withActionId(args: unknown, actionId: string): unknown;
116
+ /**
117
+ * The centre chunk of the shard holding chunk `(x, z)`: shards are `size` by `size` chunks,
118
+ * keyed by their centre. The same function as `ckx_sdk::kit::shard`, so a client finds the
119
+ * hub for where it stands without asking. `x` and `z` are chunk coordinates (integers).
120
+ */
121
+ export declare function shardCentre(x: number, z: number, size: number): [number, number];
122
+ /** The key of the shard holding chunk `(x, z)`: `"<x>,<z>"` of its centre. */
123
+ export declare function shardKey(x: number, z: number, size: number): string;
124
+ /** The centre chunk a shard key names, or null when it is not `"<x>,<z>"`. */
125
+ export declare function parseShardKey(key: string): [number, number] | null;
126
+ /** The keys of the shards within `radius` shards of the one holding `(x, z)`, its own first. */
127
+ export declare function shardKeysAround(x: number, z: number, size: number, radius: number): string[];
128
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/kit/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,sDAAsD;AACtD,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,gEAAgE;AAChE,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAC9C,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAExE,4CAA4C;AAC5C,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,cAAc,CAAC;CACtB;AAED,uCAAuC;AACvC,MAAM,WAAW,UAAU;IACzB,sDAAsD;IACtD,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,iCAAiC;AACjC,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAKD,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzD,KAAK,EAAE,OAAO,GACb;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAAG,IAAI,CAQvC;AAMD,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAGtF;AAED,wFAAwF;AACxF,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;CAmBZ,CAAC;AAEX;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,eAAe;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;IAOvD,0FAA0F;IAC1F,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;CAWrC;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAG1D;AAID,0FAA0F;AAC1F,wBAAgB,WAAW,IAAI,MAAM,CAIpC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAMrE;AAID;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAIhF;AAED,8EAA8E;AAC9E,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGnE;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAGlE;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAU5F"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * The game kit protocol: what kit hubs (ck-exec's starter packs, built on `ckx_sdk::kit`)
3
+ * send the kit's clients, read without I/O.
4
+ *
5
+ * A kit hub's topics carry **kit messages**: MessagePack maps with the hub's data and four
6
+ * reserved fields beside it: `v` (the protocol version, {@link KIT_PROTOCOL}), `epoch` (the
7
+ * publishing instance's epoch, which changes whenever it is placed again: a move, a restart or
8
+ * a crash), `seq` (one more than the topic's last message) and `kind`:
9
+ *
10
+ * - `snapshot`: the topic's whole public state; it replaces what the client holds.
11
+ * - `delta`: one change to a collection (`id`, then `type_name` and `props`, or `removed`),
12
+ * applied in `seq` order. A gap in `seq`, or another `epoch`, means a resync.
13
+ * - `changed`: something private changed for the players in `who` (`what` names it); they read
14
+ * it back with a call the hub answers for its caller alone. Topics have no access control,
15
+ * so kit hubs never publish anything private.
16
+ * - `event`: something that happened, with nothing to keep.
17
+ *
18
+ * Every kit hub answers `snapshot { topic }` with a `snapshot` message whose `seq` is the
19
+ * topic's last. A call that changes something may carry an `action_id`; the hub answers a call
20
+ * sent again with the first answer. A refusal's message is `kit:<code>: <text>`.
21
+ */
22
+ import { CrowdyExecError } from '../domains/exec.js';
23
+ /** The protocol version kit messages carry in `v`. */
24
+ export const KIT_PROTOCOL = 1;
25
+ /** The method every kit hub answers with a topic's snapshot. */
26
+ export const KIT_SNAPSHOT_METHOD = 'snapshot';
27
+ /** The longest `action_id` a hub takes, in bytes. */
28
+ export const KIT_ACTION_ID_MAX = 64;
29
+ const KINDS = new Set(['snapshot', 'delta', 'changed', 'event']);
30
+ const RESERVED = ['v', 'epoch', 'seq', 'kind'];
31
+ /** Whether `value` is a kit message: a map with the four reserved fields. */
32
+ export function isKitMessage(value) {
33
+ if (!value || typeof value !== 'object' || Array.isArray(value))
34
+ return false;
35
+ const v = value;
36
+ return (typeof v.v === 'number' &&
37
+ typeof v.epoch === 'number' &&
38
+ typeof v.seq === 'number' &&
39
+ typeof v.kind === 'string' &&
40
+ KINDS.has(v.kind));
41
+ }
42
+ /**
43
+ * A kit message split into its header and its body (every other field), or null when
44
+ * `value` is not one.
45
+ */
46
+ export function splitKitMessage(value) {
47
+ if (!isKitMessage(value))
48
+ return null;
49
+ const body = { ...value };
50
+ for (const k of RESERVED)
51
+ delete body[k];
52
+ return {
53
+ header: { v: value.v, epoch: value.epoch, seq: value.seq, kind: value.kind },
54
+ body: body,
55
+ };
56
+ }
57
+ // ---- refusals ----
58
+ const CODED = /^kit:([a-z0-9_]{1,64}): ([\s\S]*)$/;
59
+ /** The code and text of a kit refusal's message, or null for any other message. */
60
+ export function parseKitRefusal(message) {
61
+ const m = CODED.exec(message);
62
+ return m ? { code: m[1], text: m[2] } : null;
63
+ }
64
+ /** The refusal codes kit hubs share; a hub may add its own (lowercase, digits, `_`). */
65
+ export const KIT_CODES = {
66
+ BAD_REQUEST: 'bad_request',
67
+ NOT_FOUND: 'not_found',
68
+ FORBIDDEN: 'forbidden',
69
+ CONFLICT: 'conflict',
70
+ FULL: 'full',
71
+ LIMIT: 'limit',
72
+ COOLDOWN: 'cooldown',
73
+ NOT_YOUR_TURN: 'not_your_turn',
74
+ NOT_MEMBER: 'not_member',
75
+ STARTED: 'started',
76
+ FINISHED: 'finished',
77
+ NOT_READY: 'not_ready',
78
+ RESERVED: 'reserved',
79
+ EMPTY: 'empty',
80
+ OUT_OF_REACH: 'out_of_reach',
81
+ EXPIRED: 'expired',
82
+ INSUFFICIENT: 'insufficient',
83
+ ALREADY_DONE: 'already_done',
84
+ };
85
+ /**
86
+ * A kit hub refused the call (`AppError` with a `kit:<code>:` message): `code` is what to
87
+ * branch on, `text` what to show. It is a {@link CrowdyExecError} with status `AppError`, so
88
+ * code that handles exec errors handles it.
89
+ */
90
+ export class KitError extends CrowdyExecError {
91
+ constructor(code, text, cause) {
92
+ super('AppError', `kit:${code}: ${text}`, cause);
93
+ this.name = 'KitError';
94
+ this.code = code;
95
+ this.text = text;
96
+ }
97
+ /** `error` as a {@link KitError} when it is a coded refusal; otherwise `error` itself. */
98
+ static from(error) {
99
+ if (error instanceof KitError)
100
+ return error;
101
+ if (error instanceof CrowdyExecError && error.status === 'AppError') {
102
+ // A CrowdyExecError's message leads with its status.
103
+ const prefix = `${error.status}: `;
104
+ const raw = error.message.startsWith(prefix) ? error.message.slice(prefix.length) : error.message;
105
+ const coded = parseKitRefusal(raw);
106
+ if (coded)
107
+ return new KitError(coded.code, coded.text, error);
108
+ }
109
+ return error;
110
+ }
111
+ }
112
+ /** The refusal code of `error`, when it is a kit refusal. */
113
+ export function kitErrorCode(error) {
114
+ const e = KitError.from(error);
115
+ return e instanceof KitError ? e.code : null;
116
+ }
117
+ // ---- action ids ----
118
+ /** A fresh `action_id`: unique per attempt, the same for every resend of that attempt. */
119
+ export function newActionId() {
120
+ const c = globalThis.crypto;
121
+ if (c?.randomUUID)
122
+ return c.randomUUID();
123
+ return `a-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
124
+ }
125
+ /**
126
+ * `args` with `action_id` beside them: a plain object gains the field, `undefined` or `null`
127
+ * becomes `{ action_id }`. Anything else (an array, a number) cannot carry one and is
128
+ * returned as it is.
129
+ */
130
+ export function withActionId(args, actionId) {
131
+ if (args === undefined || args === null)
132
+ return { action_id: actionId };
133
+ if (typeof args === 'object' && !Array.isArray(args) && !(args instanceof Uint8Array)) {
134
+ return { ...args, action_id: actionId };
135
+ }
136
+ return args;
137
+ }
138
+ // ---- shard keys ----
139
+ /**
140
+ * The centre chunk of the shard holding chunk `(x, z)`: shards are `size` by `size` chunks,
141
+ * keyed by their centre. The same function as `ckx_sdk::kit::shard`, so a client finds the
142
+ * hub for where it stands without asking. `x` and `z` are chunk coordinates (integers).
143
+ */
144
+ export function shardCentre(x, z, size) {
145
+ const s = Math.max(1, Math.trunc(size));
146
+ const half = Math.floor(s / 2);
147
+ return [Math.floor(Math.trunc(x) / s) * s + half, Math.floor(Math.trunc(z) / s) * s + half];
148
+ }
149
+ /** The key of the shard holding chunk `(x, z)`: `"<x>,<z>"` of its centre. */
150
+ export function shardKey(x, z, size) {
151
+ const [cx, cz] = shardCentre(x, z, size);
152
+ return `${cx},${cz}`;
153
+ }
154
+ /** The centre chunk a shard key names, or null when it is not `"<x>,<z>"`. */
155
+ export function parseShardKey(key) {
156
+ const m = /^\s*(-?\d+)\s*,\s*(-?\d+)\s*$/.exec(key);
157
+ return m ? [Number(m[1]), Number(m[2])] : null;
158
+ }
159
+ /** The keys of the shards within `radius` shards of the one holding `(x, z)`, its own first. */
160
+ export function shardKeysAround(x, z, size, radius) {
161
+ const s = Math.max(1, Math.trunc(size));
162
+ const [cx, cz] = shardCentre(x, z, s);
163
+ const keys = [`${cx},${cz}`];
164
+ for (let dz = -radius; dz <= radius; dz++) {
165
+ for (let dx = -radius; dx <= radius; dx++) {
166
+ if (dx !== 0 || dz !== 0)
167
+ keys.push(`${cx + dx * s},${cz + dz * s}`);
168
+ }
169
+ }
170
+ return keys;
171
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * What kit hubs show players near them through the realtime tier (UDP), decoded for World
3
+ * Stores: server-driven actors (mobs, NPCs, pets, a ball) and server events.
4
+ *
5
+ * A server-driven actor's state is {@link KitActorState} as MessagePack (`ckx_sdk::kit::wire`
6
+ * `ActorState`). A server event is an `eventType` from the registry in `wire.ts` with a JSON
7
+ * body; `ServerEventNotification.state` is that body, base64.
8
+ */
9
+ import { type StateCodec } from '../stores/codec.js';
10
+ /** A server-driven actor as a kit hub shows it. */
11
+ export interface KitActorState {
12
+ /** What it is: `mob`, `npc`, `pet`, `ball`, `ghost`, or a game's own word. */
13
+ kind: string;
14
+ /** Its id within the hub that shows it. */
15
+ id: number;
16
+ /** Where it is, in chunks. */
17
+ x: number;
18
+ y: number;
19
+ z: number;
20
+ hp: number | null;
21
+ max_hp?: number;
22
+ mode?: string;
23
+ /** The player it belongs to (a pet, a summon). */
24
+ owner?: number;
25
+ yaw?: number;
26
+ name?: string;
27
+ }
28
+ /** Whether a decoded value is a kit actor's state. */
29
+ export declare function isKitActorState(value: unknown): value is KitActorState;
30
+ /** A kit actor's state from its MessagePack bytes, or null when they are not one. */
31
+ export declare function decodeKitActorState(bytes: Uint8Array): KitActorState | null;
32
+ /**
33
+ * A {@link StateCodec} for the actors kit hubs show, for `createWorldSession`'s `actors`
34
+ * config. A state that is not a kit actor's decodes to null (a player's, say).
35
+ */
36
+ export declare const kitActorCodec: StateCodec<KitActorState | null>;
37
+ /** A player's actor in a world with kit hubs, with the game's own state. */
38
+ export interface KitPlayerActor<P> {
39
+ kind: 'player';
40
+ player: P;
41
+ }
42
+ /** A remote actor in a world with kit hubs: a player's, or a server-driven one. */
43
+ export type KitWorldActor<P> = KitPlayerActor<P> | KitActorState;
44
+ /** Whether a remote actor is a player's (rather than one a hub shows). */
45
+ export declare function isKitPlayerActor<P>(actor: KitWorldActor<P>): actor is KitPlayerActor<P>;
46
+ /**
47
+ * One codec for a world where players and kit hubs both show actors: a kit actor's state
48
+ * decodes as itself, anything else through `playerCodec` as `{ kind: 'player', player }`.
49
+ * A game's own player state must not be a MessagePack map with `kind`, `id`, `x` and `z`.
50
+ */
51
+ export declare function withKitActors<P>(playerCodec: StateCodec<P>): StateCodec<KitWorldActor<P>>;
52
+ /**
53
+ * Lane predicates for `createWorldSession`'s `actors.lanes` with {@link withKitActors}:
54
+ * `players`, `mobs`, `npcs`, `pets`, and `others` for any other kind a hub shows.
55
+ */
56
+ export declare function kitActorLanes<P>(): Record<'players' | 'mobs' | 'npcs' | 'pets' | 'others', (a: KitWorldActor<P>) => boolean>;
57
+ /** The event types of the kit's registry, each with the JSON codec its body takes. */
58
+ export declare const KIT_EVENT_TYPES: readonly number[];
59
+ /** Codecs for World Stores' `EventRouter`, one per kit event type: the bodies are JSON. */
60
+ export declare function kitEventCodecs(): Map<number, StateCodec<Record<string, unknown>>>;
61
+ /**
62
+ * A server event a kit hub sent, from its notification (`eventType` and the base64 `state`),
63
+ * or null when the body is not JSON.
64
+ */
65
+ export declare function parseKitServerEvent(notification: {
66
+ eventType: number;
67
+ state: string;
68
+ }): {
69
+ eventType: number;
70
+ body: Record<string, unknown>;
71
+ } | null;
72
+ //# sourceMappingURL=realtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../src/kit/realtime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAkBhE,mDAAmD;AACnD,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,8BAA8B;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAItE;AAED,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,GAAG,IAAI,CAQ3E;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,UAAU,CAAC,aAAa,GAAG,IAAI,CAG1D,CAAC;AAEF,4EAA4E;AAC5E,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,CAAC,CAAC;CACX;AAED,mFAAmF;AACnF,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC;AAEjE,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,cAAc,CAAC,CAAC,CAAC,CAEvF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAQzF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,KAAK,MAAM,CAAC,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAS5H;AAED,sFAAsF;AACtF,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAc5C,CAAC;AAEF,2FAA2F;AAC3F,wBAAgB,cAAc,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAGjF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAAI,CAS9D"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * What kit hubs show players near them through the realtime tier (UDP), decoded for World
3
+ * Stores: server-driven actors (mobs, NPCs, pets, a ball) and server events.
4
+ *
5
+ * A server-driven actor's state is {@link KitActorState} as MessagePack (`ckx_sdk::kit::wire`
6
+ * `ActorState`). A server event is an `eventType` from the registry in `wire.ts` with a JSON
7
+ * body; `ServerEventNotification.state` is that body, base64.
8
+ */
9
+ import { decode, encode } from '@msgpack/msgpack';
10
+ import { jsonCodec } from '../stores/codec.js';
11
+ import { decodeBase64, encodeBase64 } from '../utils.js';
12
+ import { EVENT_ABILITY, EVENT_CONTACT_DAMAGE, EVENT_CONTROL_POINT, EVENT_EMOTE, EVENT_ENCOUNTER, EVENT_MOVEMENT_VIOLATION, EVENT_POSSESSION, EVENT_PROPOSAL, EVENT_RACE_TIMING, EVENT_SCORE, EVENT_TURN, EVENT_WEATHER, EVENT_ZONE_CHANGE, } from './wire.js';
13
+ /** Whether a decoded value is a kit actor's state. */
14
+ export function isKitActorState(value) {
15
+ if (!value || typeof value !== 'object' || Array.isArray(value))
16
+ return false;
17
+ const v = value;
18
+ return typeof v.kind === 'string' && typeof v.id === 'number' && typeof v.x === 'number' && typeof v.z === 'number';
19
+ }
20
+ /** A kit actor's state from its MessagePack bytes, or null when they are not one. */
21
+ export function decodeKitActorState(bytes) {
22
+ try {
23
+ const v = decode(bytes);
24
+ if (!isKitActorState(v))
25
+ return null;
26
+ return { ...v, y: typeof v.y === 'number' ? v.y : 0, hp: typeof v.hp === 'number' ? v.hp : null };
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ /**
33
+ * A {@link StateCodec} for the actors kit hubs show, for `createWorldSession`'s `actors`
34
+ * config. A state that is not a kit actor's decodes to null (a player's, say).
35
+ */
36
+ export const kitActorCodec = {
37
+ encode: (state) => encodeBase64(state ? encode(state) : new Uint8Array()),
38
+ decode: (data) => (data ? decodeKitActorState(decodeBase64(data)) : null),
39
+ };
40
+ /** Whether a remote actor is a player's (rather than one a hub shows). */
41
+ export function isKitPlayerActor(actor) {
42
+ return actor.kind === 'player' && 'player' in actor;
43
+ }
44
+ /**
45
+ * One codec for a world where players and kit hubs both show actors: a kit actor's state
46
+ * decodes as itself, anything else through `playerCodec` as `{ kind: 'player', player }`.
47
+ * A game's own player state must not be a MessagePack map with `kind`, `id`, `x` and `z`.
48
+ */
49
+ export function withKitActors(playerCodec) {
50
+ return {
51
+ encode: (actor) => (isKitPlayerActor(actor) ? playerCodec.encode(actor.player) : kitActorCodec.encode(actor)),
52
+ decode: (data) => {
53
+ const kit = data ? decodeKitActorState(decodeBase64(data)) : null;
54
+ return kit ?? { kind: 'player', player: playerCodec.decode(data) };
55
+ },
56
+ };
57
+ }
58
+ /**
59
+ * Lane predicates for `createWorldSession`'s `actors.lanes` with {@link withKitActors}:
60
+ * `players`, `mobs`, `npcs`, `pets`, and `others` for any other kind a hub shows.
61
+ */
62
+ export function kitActorLanes() {
63
+ const known = new Set(['player', 'mob', 'npc', 'pet']);
64
+ return {
65
+ players: (a) => a.kind === 'player',
66
+ mobs: (a) => a.kind === 'mob',
67
+ npcs: (a) => a.kind === 'npc',
68
+ pets: (a) => a.kind === 'pet',
69
+ others: (a) => !known.has(a.kind),
70
+ };
71
+ }
72
+ /** The event types of the kit's registry, each with the JSON codec its body takes. */
73
+ export const KIT_EVENT_TYPES = [
74
+ EVENT_CONTACT_DAMAGE,
75
+ EVENT_WEATHER,
76
+ EVENT_TURN,
77
+ EVENT_SCORE,
78
+ EVENT_PROPOSAL,
79
+ EVENT_ABILITY,
80
+ EVENT_MOVEMENT_VIOLATION,
81
+ EVENT_CONTROL_POINT,
82
+ EVENT_RACE_TIMING,
83
+ EVENT_ZONE_CHANGE,
84
+ EVENT_ENCOUNTER,
85
+ EVENT_POSSESSION,
86
+ EVENT_EMOTE,
87
+ ];
88
+ /** Codecs for World Stores' `EventRouter`, one per kit event type: the bodies are JSON. */
89
+ export function kitEventCodecs() {
90
+ const codec = jsonCodec();
91
+ return new Map(KIT_EVENT_TYPES.map((t) => [t, codec]));
92
+ }
93
+ /**
94
+ * A server event a kit hub sent, from its notification (`eventType` and the base64 `state`),
95
+ * or null when the body is not JSON.
96
+ */
97
+ export function parseKitServerEvent(notification) {
98
+ try {
99
+ const text = new TextDecoder().decode(decodeBase64(notification.state));
100
+ const body = text ? JSON.parse(text) : {};
101
+ if (!body || typeof body !== 'object' || Array.isArray(body))
102
+ return null;
103
+ return { eventType: notification.eventType, body: body };
104
+ }
105
+ catch {
106
+ return null;
107
+ }
108
+ }
@@ -0,0 +1,90 @@
1
+ import { type ExecAPI, type ExecConnectOptions, type ExecConnection, type ExecPushHandler } from '../domains/exec.js';
2
+ /** Subscriptions one connection holds at most (the gateway refuses the next). */
3
+ export declare const KIT_SUBSCRIPTIONS_MAX = 256;
4
+ /** How a {@link KitRuntime} reaches the app's hubs. */
5
+ export interface KitRuntimeOptions {
6
+ /** Use this connection rather than opening one. The kit does not close it. */
7
+ connection?: ExecConnection;
8
+ /** How the kit opens its connection: affinity (`nodeType`, `key`), timeouts, a WebSocket. */
9
+ connect?: ExecConnectOptions;
10
+ /**
11
+ * Connect as one of the app's developers (`exec.connectAsDeveloper`, the org's
12
+ * `manage_compute`, an identity session rather than an app token): what admin endpoints
13
+ * (`configure`, `schedule`, ...) need.
14
+ */
15
+ developer?: boolean;
16
+ /**
17
+ * Calls, subscriptions and unsubscriptions the kit sends in one window at most. The gateway
18
+ * takes 120 per 10 s from a player and refuses the rest `Busy`; the default, 100, keeps the
19
+ * kit under it with room for the game's own calls.
20
+ */
21
+ callBudget?: number;
22
+ /** The budget's window, in milliseconds. Default 10 000. */
23
+ budgetWindowMs?: number;
24
+ /**
25
+ * Times a call is sent again when it did not run (`Busy`, `RateLimited`), or, when it
26
+ * carries an action id, after an unknown outcome (`DeadlineExceeded`, `Unavailable`,
27
+ * `Moved`). Default 2.
28
+ */
29
+ retries?: number;
30
+ /** The player's id, to match `changed` messages; asked of `users.me` when absent. */
31
+ playerId?: string | number;
32
+ }
33
+ /** Per call: the action id, and the reply timeout. */
34
+ export interface KitCallOptions {
35
+ /**
36
+ * Send an `action_id` so a resend is answered once: `true` for a fresh one, or the id to
37
+ * use (for a deliberate retry of an earlier attempt).
38
+ */
39
+ action?: boolean | string;
40
+ /** How long to wait for the reply, in milliseconds (the connection's default otherwise). */
41
+ timeoutMs?: number;
42
+ }
43
+ /**
44
+ * The kit's way to the app's hubs: one {@link ExecConnection} shared by every kit module,
45
+ * opened when first needed. It paces what it sends to a budget below the gateway's limit,
46
+ * sends a call again when that is safe (it did not run, or it carries an action id the hub
47
+ * answers once), counts subscriptions under the gateway's cap, and turns a hub's coded
48
+ * refusal into a {@link KitError}.
49
+ */
50
+ export declare class KitRuntime {
51
+ readonly appId: string;
52
+ private readonly exec;
53
+ private readonly options;
54
+ private readonly whoAmI?;
55
+ private conn;
56
+ private connecting;
57
+ private ended;
58
+ private readonly budget;
59
+ private readonly retries;
60
+ private readonly subs;
61
+ private readonly reconnectListeners;
62
+ private readonly endedListeners;
63
+ private me;
64
+ constructor(appId: string, exec: ExecAPI | undefined, options?: KitRuntimeOptions, whoAmI?: (() => Promise<string | null>) | undefined);
65
+ /** The connection, opened on first use. */
66
+ connection(): Promise<ExecConnection>;
67
+ private open;
68
+ /** The player's id, from the options or `users.me`; null when neither knows it. */
69
+ playerId(): Promise<string | null>;
70
+ /**
71
+ * Calls a hub's endpoint, `args` as MessagePack, and returns the decoded reply.
72
+ * @throws {KitError} for a hub's coded refusal; {@link CrowdyExecError} for the platform's.
73
+ */
74
+ call<T = unknown>(nodeType: string, key: string, method: string, args?: unknown, options?: KitCallOptions): Promise<T>;
75
+ /**
76
+ * Receives what a hub publishes on `topic`. Returns the function that stops this handler
77
+ * (and the subscription with the last one).
78
+ * @throws {KitError} `limit` past {@link KIT_SUBSCRIPTIONS_MAX} subscriptions.
79
+ */
80
+ subscribe<T = unknown>(nodeType: string, key: string, topic: string, onPush: ExecPushHandler<T>): Promise<() => Promise<void>>;
81
+ /** How many distinct topics the kit subscribes to. */
82
+ get subscriptions(): number;
83
+ /** Called with the new host after the connection reconnects; kit mirrors resync then. */
84
+ onReconnect(listener: (host: string) => void): () => void;
85
+ /** Called once when the player's access ended (close code 4403); nothing reconnects. */
86
+ onAccessEnded(listener: (reason: string) => void): () => void;
87
+ /** Closes the connection the kit opened (not one it was given). */
88
+ close(): void;
89
+ }
90
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/kit/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAG5B,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,uDAAuD;AACvD,MAAM,WAAW,iBAAiB;IAChC,8EAA8E;IAC9E,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,6FAA6F;IAC7F,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAED,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA8CD;;;;;;GAMG;AACH,qBAAa,UAAU;IAYnB,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAd1B,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,UAAU,CAAwC;IAC1D,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAClD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqC;IACxE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAuC;IACtE,OAAO,CAAC,EAAE,CAAuC;gBAGtC,KAAK,EAAE,MAAM,EACL,IAAI,EAAE,OAAO,GAAG,SAAS,EACzB,OAAO,GAAE,iBAAsB,EAC/B,MAAM,CAAC,GAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,aAAA;IAMxD,2CAA2C;IACrC,UAAU,IAAI,OAAO,CAAC,cAAc,CAAC;YAY7B,IAAI;IAmBlB,mFAAmF;IAC7E,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQxC;;;OAGG;IACG,IAAI,CAAC,CAAC,GAAG,OAAO,EACpB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,CAAC,CAAC;IA2Bb;;;;OAIG;IACG,SAAS,CAAC,CAAC,GAAG,OAAO,EACzB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IA2B/B,sDAAsD;IACtD,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,yFAAyF;IACzF,WAAW,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAKzD,wFAAwF;IACxF,aAAa,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAK7D,mEAAmE;IACnE,KAAK,IAAI,IAAI;CAMd"}