koota-kit 0.6.2 → 0.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.1 (2026-10-14)
4
+
5
+ <!-- Release notes generated using configuration in .github/release.yml at main -->
6
+
7
+ ## What's Changed
8
+ * fix(test): restore explicit Node type visibility for dependency-update verification by @jbdevprimary in https://github.com/jbcom/koota-kit/pull/58
9
+
10
+
11
+ **Full Changelog**: https://github.com/jbcom/koota-kit/compare/v0.7.0...v0.7.1
12
+
13
+ ## 0.7.0 (2026-10-14)
14
+
15
+ <!-- Release notes generated using configuration in .github/release.yml at main -->
16
+
17
+ ## What's Changed
18
+ * feat: add borrowed-world coordination by @jbdevprimary in https://github.com/jbcom/koota-kit/pull/54
19
+
20
+
21
+ **Full Changelog**: https://github.com/jbcom/koota-kit/compare/v0.6.2...v0.7.0
22
+
3
23
  ## 0.6.2 (2026-10-14)
4
24
 
5
25
  <!-- Release notes generated using configuration in .github/release.yml at main -->
package/README.md CHANGED
@@ -25,6 +25,7 @@ Full documentation: **[jonbogaty.com/koota-kit](https://jonbogaty.com/koota-kit/
25
25
  | Object state leaks between entities | `defineTrait` requires per-entity factories |
26
26
  | A HUD or test consumes an event before its real system sees it | Single-consumer `drain`, non-consuming `peek` |
27
27
  | Replaced worlds retain caches or process-global Koota IDs | `createSimWorld` / idempotent `destroySimWorld` lifecycle |
28
+ | Two producers publish half-updated model facts | `koota-kit/coordination` commits an immutable completed metadata projection |
28
29
 
29
30
  ## Install
30
31
 
@@ -100,6 +101,43 @@ The scratch map is for derived, non-serializable caches and short-lived
100
101
  coordination state. Namespace keys by system, for example `pathfinding:grid`
101
102
  or `combat:hits`.
102
103
 
104
+ ### Coordinate existing model entities without another World
105
+
106
+ `koota-kit/coordination` binds to a caller-owned raw Koota `World`; it does
107
+ not create, reset, or destroy one. Register existing entities with stable
108
+ caller-authored IDs and capability labels, then publish completed producer
109
+ revisions as a batch. The snapshot is immutable, ordered by ID, and changes
110
+ only after the complete batch validates and its raw Koota trait writes succeed.
111
+ Producers needing one atomic cohort publish through the same binding; disjoint
112
+ bindings are independent cohorts.
113
+
114
+ ```ts
115
+ import { bindCoordination } from "koota-kit/coordination";
116
+
117
+ const coordination = bindCoordination(sim.world);
118
+ const ava = sim.world.spawn(Position({ x: 4, y: 9 }));
119
+ const token = coordination.register(ava, {
120
+ id: "figure:ava",
121
+ capabilities: ["presence", "geometry"],
122
+ });
123
+
124
+ coordination.publish(token, {
125
+ revisions: { geometry: 12, pose: 8, transform: 31 },
126
+ });
127
+
128
+ const completed = coordination.getSnapshot();
129
+ coordination.dispose(); // removes only koota-kit's coordination traits
130
+ ```
131
+
132
+ The three producer revisions are independent values; a coordination snapshot
133
+ revision only identifies a committed observer view. This entry does not copy
134
+ or freeze provider buffers, choose a geometry backend, evaluate a pose, or
135
+ answer spatial queries. Those facts belong to later producer/query adapters.
136
+ Call `prune()` after an entity is removed externally before reusing its stable
137
+ ID. Listener errors occur after a committed publication; retrieve a token with
138
+ `getRegistration(id)` if registration notification threw before `register`
139
+ could return it.
140
+
103
141
  ### Randomness has two jobs
104
142
 
105
143
  - `rng.gen` defines stable world content: terrain, layouts, initial spawns.
@@ -0,0 +1,412 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CoordinationRegistration = exports.CoordinationBinding = void 0;
4
+ exports.bindCoordination = bindCoordination;
5
+ /**
6
+ * Borrowed-World coordination for completed model metadata.
7
+ *
8
+ * The caller owns the Koota World and its entities. This module only adds its
9
+ * own marker traits and exposes a committed, immutable projection. It does
10
+ * not create a World, run systems, serialize entities, or read geometry.
11
+ */
12
+ const koota_1 = require("koota");
13
+ /**
14
+ * World-held ownership markers for live bindings. Each binding appends one
15
+ * opaque marker and removes only that marker at disposal, so no module-global
16
+ * registry or per-bind Koota trait allocation is needed.
17
+ */
18
+ exports.CoordinationBinding = (0, koota_1.trait)({ markers: () => [] });
19
+ /**
20
+ * The only trait this module places on caller-owned model entities. Its
21
+ * fields are a diagnostic mirror of the binding's committed projection;
22
+ * callers must use `getSnapshot` for an immutable completed view.
23
+ */
24
+ exports.CoordinationRegistration = (0, koota_1.trait)({
25
+ marker: () => ({}),
26
+ generation: 0,
27
+ id: "",
28
+ geometryRevision: 0,
29
+ poseRevision: 0,
30
+ transformRevision: 0,
31
+ });
32
+ const tokenMarker = Symbol("koota-kit.coordination.token");
33
+ function fail(message) {
34
+ throw new Error(`coordination: ${message}`);
35
+ }
36
+ function isObject(value) {
37
+ return typeof value === "object" && value !== null;
38
+ }
39
+ function requireNonEmptyString(value, name) {
40
+ if (typeof value !== "string" || value.trim().length === 0) {
41
+ throw new TypeError(`coordination: ${name} must be a non-empty string.`);
42
+ }
43
+ return value;
44
+ }
45
+ function copyCapabilities(value) {
46
+ if (!Array.isArray(value)) {
47
+ throw new TypeError("coordination: descriptor.capabilities must be an array of non-empty strings.");
48
+ }
49
+ const capabilities = value.map((capability) => requireNonEmptyString(capability, "capability"));
50
+ capabilities.sort((left, right) => Number(left > right) - Number(left < right));
51
+ for (let index = 1; index < capabilities.length; index += 1) {
52
+ if (capabilities[index] === capabilities[index - 1]) {
53
+ throw new TypeError(`coordination: duplicate capability "${capabilities[index]}".`);
54
+ }
55
+ }
56
+ return Object.freeze(capabilities);
57
+ }
58
+ function copyRevisions(value) {
59
+ if (!isObject(value)) {
60
+ throw new TypeError("coordination: completed.revisions must be an object.");
61
+ }
62
+ const names = ["geometry", "pose", "transform"];
63
+ const values = names.map((name) => value[name]);
64
+ for (const [index, revision] of values.entries()) {
65
+ if (!Number.isSafeInteger(revision) || revision < 0) {
66
+ throw new RangeError(`coordination: completed.revisions.${names[index]} must be a non-negative safe integer.`);
67
+ }
68
+ }
69
+ return Object.freeze({
70
+ geometry: values[0],
71
+ pose: values[1],
72
+ transform: values[2],
73
+ });
74
+ }
75
+ function copyCompleted(value) {
76
+ if (!isObject(value)) {
77
+ throw new TypeError("coordination: completed metadata must be an object.");
78
+ }
79
+ return Object.freeze({ revisions: copyRevisions(value.revisions) });
80
+ }
81
+ function sameRevisions(left, right) {
82
+ return (left.geometry === right.geometry &&
83
+ left.pose === right.pose &&
84
+ left.transform === right.transform);
85
+ }
86
+ function assertNoRegression(previous, next) {
87
+ if (!previous)
88
+ return;
89
+ for (const name of ["geometry", "pose", "transform"]) {
90
+ if (next.revisions[name] < previous.revisions[name]) {
91
+ throw new RangeError(`coordination: completed revision ${name} may not decrease.`);
92
+ }
93
+ }
94
+ }
95
+ function makeSnapshot(revision, registrations) {
96
+ const entries = [...registrations]
97
+ .map((registration) => Object.freeze({
98
+ id: registration.id,
99
+ capabilities: registration.capabilities,
100
+ completed: registration.completed,
101
+ }))
102
+ .sort((left, right) => Number(left.id > right.id) - Number(left.id < right.id));
103
+ return Object.freeze({ revision, entries: Object.freeze(entries) });
104
+ }
105
+ function stateIsOwned(state, marker, generation) {
106
+ return state?.marker === marker && state.generation === generation;
107
+ }
108
+ /**
109
+ * Bind to a caller-owned Koota World. A live binding writes its opaque marker
110
+ * onto that same World, without a hidden module-global World registry. Several
111
+ * bindings may coexist only while they register disjoint caller entities.
112
+ */
113
+ function bindCoordination(world) {
114
+ if (!world?.isInitialized) {
115
+ fail("a live Koota World is required.");
116
+ }
117
+ const marker = Object.freeze({});
118
+ const existingMarkers = world.get(exports.CoordinationBinding)?.markers ?? [];
119
+ const markers = [...existingMarkers, marker];
120
+ try {
121
+ if (world.has(exports.CoordinationBinding))
122
+ world.set(exports.CoordinationBinding, { markers });
123
+ else
124
+ world.add((0, exports.CoordinationBinding)({ markers }));
125
+ }
126
+ catch (error) {
127
+ const currentMarkers = world.get(exports.CoordinationBinding)?.markers;
128
+ if (world.isInitialized && currentMarkers?.includes(marker)) {
129
+ const remaining = currentMarkers.filter((candidate) => candidate !== marker);
130
+ if (remaining.length === 0)
131
+ world.remove(exports.CoordinationBinding);
132
+ else
133
+ world.set(exports.CoordinationBinding, { markers: remaining });
134
+ }
135
+ throw error;
136
+ }
137
+ let disposed = false;
138
+ let notifying = false;
139
+ let mutating = false;
140
+ let nextRegistrationGeneration = 0;
141
+ let nextSnapshotRevision = 0;
142
+ const registrationsById = new Map();
143
+ const registrationsByToken = new Map();
144
+ const listeners = new Set();
145
+ let snapshot = makeSnapshot(nextSnapshotRevision, registrationsById.values());
146
+ const assertActive = () => {
147
+ if (disposed)
148
+ fail("the binding has been disposed.");
149
+ if (notifying || mutating)
150
+ fail("mutating a binding while it notifies listeners is not allowed.");
151
+ };
152
+ const assertMutable = () => {
153
+ assertActive();
154
+ if (!world.isInitialized || !world.get(exports.CoordinationBinding)?.markers.includes(marker)) {
155
+ fail("the binding no longer owns its World marker.");
156
+ }
157
+ };
158
+ const isCurrent = (registration) => {
159
+ if (!world.isInitialized || !world.has(registration.entity))
160
+ return false;
161
+ return stateIsOwned(registration.entity.get(exports.CoordinationRegistration), marker, registration.state.generation);
162
+ };
163
+ const registrationFor = (token) => {
164
+ const registration = registrationsByToken.get(token);
165
+ if (!registration || token[tokenMarker] !== marker) {
166
+ fail("the registration token does not belong to this binding.");
167
+ }
168
+ if (!isCurrent(registration)) {
169
+ fail("the registration token is stale; call prune before re-registering its id.");
170
+ }
171
+ return registration;
172
+ };
173
+ const notify = () => {
174
+ const deliveries = [...listeners];
175
+ const errors = [];
176
+ notifying = true;
177
+ try {
178
+ for (const listener of deliveries) {
179
+ try {
180
+ listener(snapshot);
181
+ }
182
+ catch (error) {
183
+ errors.push(error);
184
+ }
185
+ }
186
+ }
187
+ finally {
188
+ notifying = false;
189
+ }
190
+ if (errors.length === 1)
191
+ throw errors[0];
192
+ if (errors.length > 1) {
193
+ const error = Object.assign(new Error("coordination: listener failures after commit."), {
194
+ errors: Object.freeze(errors),
195
+ });
196
+ throw error;
197
+ }
198
+ };
199
+ const nextCounter = (value, name) => {
200
+ const next = value + 1;
201
+ if (!Number.isSafeInteger(next)) {
202
+ throw new RangeError(`coordination: ${name} exceeded the safe integer range.`);
203
+ }
204
+ return next;
205
+ };
206
+ const commit = (revision) => {
207
+ nextSnapshotRevision = revision;
208
+ snapshot = makeSnapshot(revision, registrationsById.values());
209
+ notify();
210
+ return snapshot;
211
+ };
212
+ const register = (entity, descriptor) => {
213
+ assertMutable();
214
+ if (!world.has(entity))
215
+ fail("entity must be live in this binding's World.");
216
+ if (!isObject(descriptor))
217
+ throw new TypeError("coordination: descriptor must be an object.");
218
+ const id = requireNonEmptyString(descriptor.id, "descriptor.id");
219
+ const capabilities = copyCapabilities(descriptor.capabilities);
220
+ if (registrationsById.has(id))
221
+ fail(`stable id "${id}" is already registered.`);
222
+ if (entity.has(exports.CoordinationRegistration)) {
223
+ fail("entity already carries a coordination registration trait.");
224
+ }
225
+ const registrationGeneration = nextCounter(nextRegistrationGeneration, "registration generation");
226
+ const snapshotRevision = nextCounter(nextSnapshotRevision, "snapshot revision");
227
+ const state = Object.freeze({
228
+ marker,
229
+ generation: registrationGeneration,
230
+ id,
231
+ geometryRevision: 0,
232
+ poseRevision: 0,
233
+ transformRevision: 0,
234
+ });
235
+ const token = Object.freeze({ [tokenMarker]: marker });
236
+ const registration = {
237
+ entity,
238
+ token,
239
+ state,
240
+ id,
241
+ capabilities,
242
+ completed: undefined,
243
+ };
244
+ // Every validation above happens before the Koota marker or this binding's
245
+ // projection changes. Koota callbacks can observe this raw trait; they are
246
+ // deliberately outside the atomic committed-snapshot contract.
247
+ mutating = true;
248
+ try {
249
+ try {
250
+ entity.add((0, exports.CoordinationRegistration)(state));
251
+ }
252
+ catch (error) {
253
+ const current = entity.get(exports.CoordinationRegistration);
254
+ if (stateIsOwned(current, marker, registrationGeneration)) {
255
+ entity.remove(exports.CoordinationRegistration);
256
+ }
257
+ throw error;
258
+ }
259
+ nextRegistrationGeneration = registrationGeneration;
260
+ registrationsById.set(id, registration);
261
+ registrationsByToken.set(token, registration);
262
+ commit(snapshotRevision);
263
+ }
264
+ finally {
265
+ mutating = false;
266
+ }
267
+ return token;
268
+ };
269
+ const publishBatch = (updates) => {
270
+ assertMutable();
271
+ if (!Array.isArray(updates)) {
272
+ throw new TypeError("coordination: publishBatch updates must be an array.");
273
+ }
274
+ const prepared = [];
275
+ const seen = new Set();
276
+ for (const update of updates) {
277
+ if (!isObject(update))
278
+ throw new TypeError("coordination: each update must be an object.");
279
+ const candidate = update;
280
+ if (seen.has(candidate.token))
281
+ fail("publishBatch contains a duplicate registration token.");
282
+ seen.add(candidate.token);
283
+ const registration = registrationFor(candidate.token);
284
+ const completed = copyCompleted(candidate.completed);
285
+ assertNoRegression(registration.completed, completed);
286
+ prepared.push({ registration, completed });
287
+ }
288
+ const changed = prepared.some(({ registration, completed }) => !registration.completed ||
289
+ !sameRevisions(registration.completed.revisions, completed.revisions));
290
+ if (!changed)
291
+ return snapshot;
292
+ const snapshotRevision = nextCounter(nextSnapshotRevision, "snapshot revision");
293
+ // Raw traits can expose individual mirror writes to Koota callbacks, but
294
+ // the committed projection changes only after every mirror write succeeds.
295
+ const preparedStates = prepared.map(({ registration, completed }) => ({
296
+ registration,
297
+ completed,
298
+ state: Object.freeze({
299
+ ...registration.state,
300
+ geometryRevision: completed.revisions.geometry,
301
+ poseRevision: completed.revisions.pose,
302
+ transformRevision: completed.revisions.transform,
303
+ }),
304
+ }));
305
+ mutating = true;
306
+ try {
307
+ for (const { registration, state } of preparedStates) {
308
+ registration.entity.set(exports.CoordinationRegistration, state);
309
+ }
310
+ for (const { registration, completed } of preparedStates) {
311
+ registration.completed = completed;
312
+ }
313
+ return commit(snapshotRevision);
314
+ }
315
+ finally {
316
+ mutating = false;
317
+ }
318
+ };
319
+ const unregister = (token) => {
320
+ assertMutable();
321
+ const registration = registrationFor(token);
322
+ const snapshotRevision = nextCounter(nextSnapshotRevision, "snapshot revision");
323
+ mutating = true;
324
+ try {
325
+ registration.entity.remove(exports.CoordinationRegistration);
326
+ registrationsById.delete(registration.id);
327
+ registrationsByToken.delete(token);
328
+ return commit(snapshotRevision);
329
+ }
330
+ finally {
331
+ mutating = false;
332
+ }
333
+ };
334
+ const prune = () => {
335
+ assertActive();
336
+ const stale = [...registrationsById.values()].filter((registration) => !isCurrent(registration));
337
+ if (stale.length === 0)
338
+ return snapshot;
339
+ const snapshotRevision = nextCounter(nextSnapshotRevision, "snapshot revision");
340
+ mutating = true;
341
+ try {
342
+ for (const registration of stale) {
343
+ registrationsById.delete(registration.id);
344
+ registrationsByToken.delete(registration.token);
345
+ }
346
+ return commit(snapshotRevision);
347
+ }
348
+ finally {
349
+ mutating = false;
350
+ }
351
+ };
352
+ const getEntity = (id) => {
353
+ const registration = registrationsById.get(id);
354
+ return registration && isCurrent(registration) ? registration.entity : undefined;
355
+ };
356
+ const getRegistration = (id) => {
357
+ const registration = registrationsById.get(id);
358
+ return registration && isCurrent(registration) ? registration.token : undefined;
359
+ };
360
+ const getSnapshot = () => snapshot;
361
+ const subscribe = (listener) => {
362
+ if (disposed)
363
+ fail("the binding has been disposed.");
364
+ if (typeof listener !== "function")
365
+ throw new TypeError("coordination: listener must be a function.");
366
+ listeners.add(listener);
367
+ return () => listeners.delete(listener);
368
+ };
369
+ const dispose = () => {
370
+ if (disposed)
371
+ return;
372
+ assertActive();
373
+ const snapshotRevision = nextCounter(nextSnapshotRevision, "snapshot revision");
374
+ mutating = true;
375
+ try {
376
+ listeners.clear();
377
+ for (const registration of registrationsById.values()) {
378
+ if (isCurrent(registration))
379
+ registration.entity.remove(exports.CoordinationRegistration);
380
+ }
381
+ registrationsById.clear();
382
+ registrationsByToken.clear();
383
+ const markerState = world.get(exports.CoordinationBinding);
384
+ if (world.isInitialized && markerState?.markers.includes(marker)) {
385
+ const remaining = markerState.markers.filter((candidate) => candidate !== marker);
386
+ if (remaining.length === 0)
387
+ world.remove(exports.CoordinationBinding);
388
+ else
389
+ world.set(exports.CoordinationBinding, { markers: remaining });
390
+ }
391
+ nextSnapshotRevision = snapshotRevision;
392
+ snapshot = makeSnapshot(nextSnapshotRevision, []);
393
+ disposed = true;
394
+ }
395
+ finally {
396
+ mutating = false;
397
+ }
398
+ };
399
+ return Object.freeze({
400
+ world,
401
+ register,
402
+ publish: (token, completed) => publishBatch([{ token, completed }]),
403
+ publishBatch,
404
+ unregister,
405
+ prune,
406
+ getRegistration,
407
+ getEntity,
408
+ getSnapshot,
409
+ subscribe,
410
+ dispose,
411
+ });
412
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Borrowed-World coordination for completed model metadata.
3
+ *
4
+ * The caller owns the Koota World and its entities. This module only adds its
5
+ * own marker traits and exposes a committed, immutable projection. It does
6
+ * not create a World, run systems, serialize entities, or read geometry.
7
+ */
8
+ import { type Entity, type World } from "koota";
9
+ type BindingMarker = object;
10
+ /**
11
+ * World-held ownership markers for live bindings. Each binding appends one
12
+ * opaque marker and removes only that marker at disposal, so no module-global
13
+ * registry or per-bind Koota trait allocation is needed.
14
+ */
15
+ export declare const CoordinationBinding: import("koota").Trait<{
16
+ markers: () => BindingMarker[];
17
+ }>;
18
+ /**
19
+ * The only trait this module places on caller-owned model entities. Its
20
+ * fields are a diagnostic mirror of the binding's committed projection;
21
+ * callers must use `getSnapshot` for an immutable completed view.
22
+ */
23
+ export declare const CoordinationRegistration: import("koota").Trait<{
24
+ marker: () => BindingMarker;
25
+ generation: number;
26
+ id: string;
27
+ geometryRevision: number;
28
+ poseRevision: number;
29
+ transformRevision: number;
30
+ }>;
31
+ declare const registrationTokenBrand: unique symbol;
32
+ /** An opaque capability token returned only by `Coordination.register`. */
33
+ export type RegistrationToken = {
34
+ readonly [registrationTokenBrand]: never;
35
+ };
36
+ export type CompletedRevisions = Readonly<{
37
+ geometry: number;
38
+ pose: number;
39
+ transform: number;
40
+ }>;
41
+ export type CompletedMetadata = Readonly<{
42
+ revisions: CompletedRevisions;
43
+ }>;
44
+ export type CoordinationDescriptor = Readonly<{
45
+ /** A non-empty caller-authored identity, never a packed Koota entity ID. */
46
+ id: string;
47
+ /** Stable, sorted capability labels. Change them by unregistering first. */
48
+ capabilities: readonly string[];
49
+ }>;
50
+ export type CoordinationEntry = Readonly<{
51
+ id: string;
52
+ capabilities: readonly string[];
53
+ /** Undefined until the producer has explicitly published completed facts. */
54
+ completed: CompletedMetadata | undefined;
55
+ }>;
56
+ export type CoordinationSnapshot = Readonly<{
57
+ /** A binding-local publication generation, not a producer content revision. */
58
+ revision: number;
59
+ /** Entries sorted lexically by stable caller-authored id. */
60
+ entries: readonly CoordinationEntry[];
61
+ }>;
62
+ export type CoordinationUpdate = Readonly<{
63
+ token: RegistrationToken;
64
+ completed: CompletedMetadata;
65
+ }>;
66
+ export type CoordinationListener = (snapshot: CoordinationSnapshot) => void;
67
+ export type Coordination = Readonly<{
68
+ readonly world: World;
69
+ register: (entity: Entity, descriptor: CoordinationDescriptor) => RegistrationToken;
70
+ publish: (token: RegistrationToken, completed: CompletedMetadata) => CoordinationSnapshot;
71
+ publishBatch: (updates: readonly CoordinationUpdate[]) => CoordinationSnapshot;
72
+ unregister: (token: RegistrationToken) => CoordinationSnapshot;
73
+ /** Remove registrations whose entity or owned trait is no longer current. */
74
+ prune: () => CoordinationSnapshot;
75
+ /** Recover a current token after a listener threw during registration. */
76
+ getRegistration: (id: string) => RegistrationToken | undefined;
77
+ /** Resolve a stable identity only while its registered entity remains live. */
78
+ getEntity: (id: string) => Entity | undefined;
79
+ getSnapshot: () => CoordinationSnapshot;
80
+ subscribe: (listener: CoordinationListener) => () => void;
81
+ /** Idempotently remove this module's traits; never destroys the borrowed World. */
82
+ dispose: () => void;
83
+ }>;
84
+ /**
85
+ * Bind to a caller-owned Koota World. A live binding writes its opaque marker
86
+ * onto that same World, without a hidden module-global World registry. Several
87
+ * bindings may coexist only while they register disjoint caller entities.
88
+ */
89
+ export declare function bindCoordination(world: World): Coordination;
90
+ export {};
91
+ //# sourceMappingURL=coordination.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coordination.d.ts","sourceRoot":"","sources":["../../src/coordination.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAS,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAEvD,KAAK,aAAa,GAAG,MAAM,CAAC;AAW5B;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;mBAAgC,aAAa,EAAE;EAAG,CAAC;AAEnF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;kBACb,aAAa;;;;;;EAMnC,CAAC;AAEH,OAAO,CAAC,MAAM,sBAAsB,EAAE,OAAO,MAAM,CAAC;AAEpD,2EAA2E;AAC3E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,CAAC,sBAAsB,CAAC,EAAE,KAAK,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,SAAS,EAAE,kBAAkB,CAAC;CAC/B,CAAC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAC;IACX,4EAA4E;IAC5E,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC,CAAC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,6EAA6E;IAC7E,SAAS,EAAE,iBAAiB,GAAG,SAAS,CAAC;CAC1C,CAAC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,KAAK,EAAE,iBAAiB,CAAC;IACzB,SAAS,EAAE,iBAAiB,CAAC;CAC9B,CAAC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,QAAQ,EAAE,oBAAoB,KAAK,IAAI,CAAC;AAE5E,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,sBAAsB,KAAK,iBAAiB,CAAC;IACpF,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,iBAAiB,KAAK,oBAAoB,CAAC;IAC1F,YAAY,EAAE,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,KAAK,oBAAoB,CAAC;IAC/E,UAAU,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,oBAAoB,CAAC;IAC/D,6EAA6E;IAC7E,KAAK,EAAE,MAAM,oBAAoB,CAAC;IAClC,0EAA0E;IAC1E,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,iBAAiB,GAAG,SAAS,CAAC;IAC/D,+EAA+E;IAC/E,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC9C,WAAW,EAAE,MAAM,oBAAoB,CAAC;IACxC,SAAS,EAAE,CAAC,QAAQ,EAAE,oBAAoB,KAAK,MAAM,IAAI,CAAC;IAC1D,mFAAmF;IACnF,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC,CAAC;AAwHH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,YAAY,CAgT3D"}
@@ -13,7 +13,7 @@
13
13
  // ./eventLog — scratch-backed publish/drain event logs with a peek seam for
14
14
  // observers (harnesses, tests, HUDs)
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.defineTrait = exports.defineEventLog = exports.createSchedule = exports.MASTER_SEED_BYTES = exports.isMasterSeed = exports.deriveSeed = exports.createMasterSeed = exports.substream = exports.snapshotSubstreams = exports.snapshotStream = exports.snapshotLayers = exports.shuffle = exports.restoreSubstreams = exports.restoreStream = exports.restoreLayers = exports.pick = exports.nextU32 = exports.nextInt = exports.nextFloat = exports.getSubstream = exports.createSubstreams = exports.createRng = exports.chance = exports.trait = exports.snapshotWorld = exports.restoreWorldHeader = exports.relation = exports.destroySimWorld = exports.createSimWorld = exports.createActions = exports.advanceClock = void 0;
16
+ exports.CoordinationRegistration = exports.CoordinationBinding = exports.bindCoordination = exports.defineTrait = exports.defineEventLog = exports.createSchedule = exports.MASTER_SEED_BYTES = exports.isMasterSeed = exports.deriveSeed = exports.createMasterSeed = exports.substream = exports.snapshotSubstreams = exports.snapshotStream = exports.snapshotLayers = exports.shuffle = exports.restoreSubstreams = exports.restoreStream = exports.restoreLayers = exports.pick = exports.nextU32 = exports.nextInt = exports.nextFloat = exports.getSubstream = exports.createSubstreams = exports.createRng = exports.chance = exports.trait = exports.snapshotWorld = exports.restoreWorldHeader = exports.relation = exports.destroySimWorld = exports.createSimWorld = exports.createActions = exports.advanceClock = void 0;
17
17
  var world_js_1 = require("./world.cjs");
18
18
  Object.defineProperty(exports, "advanceClock", { enumerable: true, get: function () { return world_js_1.advanceClock; } });
19
19
  Object.defineProperty(exports, "createActions", { enumerable: true, get: function () { return world_js_1.createActions; } });
@@ -51,3 +51,7 @@ var eventLog_js_1 = require("./eventLog.cjs");
51
51
  Object.defineProperty(exports, "defineEventLog", { enumerable: true, get: function () { return eventLog_js_1.defineEventLog; } });
52
52
  var index_js_1 = require("./traits/index.cjs");
53
53
  Object.defineProperty(exports, "defineTrait", { enumerable: true, get: function () { return index_js_1.defineTrait; } });
54
+ var coordination_js_1 = require("./coordination.cjs");
55
+ Object.defineProperty(exports, "bindCoordination", { enumerable: true, get: function () { return coordination_js_1.bindCoordination; } });
56
+ Object.defineProperty(exports, "CoordinationBinding", { enumerable: true, get: function () { return coordination_js_1.CoordinationBinding; } });
57
+ Object.defineProperty(exports, "CoordinationRegistration", { enumerable: true, get: function () { return coordination_js_1.CoordinationRegistration; } });
@@ -10,4 +10,6 @@ export { defineEventLog } from "./eventLog.cjs";
10
10
  export type { EventLog } from "./eventLog.cjs";
11
11
  export { defineTrait } from "./traits/index.cjs";
12
12
  export type { SafeSchema } from "./traits/index.cjs";
13
+ export { bindCoordination, CoordinationBinding, CoordinationRegistration, } from "./coordination.cjs";
14
+ export type { CompletedMetadata, CompletedRevisions, Coordination, CoordinationDescriptor, CoordinationEntry, CoordinationListener, CoordinationSnapshot, CoordinationUpdate, RegistrationToken, } from "./coordination.cjs";
13
15
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,KAAK,GACN,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EACL,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,OAAO,EACP,OAAO,EACP,IAAI,EACJ,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,OAAO,EACP,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC1F,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,KAAK,GACN,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EACL,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,OAAO,EACP,OAAO,EACP,IAAI,EACJ,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,OAAO,EACP,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC1F,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC"}