@amalgm/core 0.1.0 → 0.1.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/PURPOSE.md CHANGED
@@ -72,6 +72,12 @@ source until each module is cut over.
72
72
  10. **Amalgm's own surfaces use this SDK.** A private shortcut in the CLI,
73
73
  gateway, or runtime means the SDK is incomplete — fix the SDK, not the
74
74
  caller.
75
+ 11. **The local rail is ordered truth, not durable history.** Every published
76
+ state event receives one monotonic sequence, reconnects replay only a
77
+ bounded retained tail, and a missing tail requires a fresh snapshot.
78
+ 12. **A snapshot names its resume point.** Resource readers share one
79
+ per-attempt context and a snapshot is stable only when its sequence is
80
+ unchanged across the read; a racing write causes a complete retry.
75
81
 
76
82
  ## Five surfaces, one behavior
77
83
 
@@ -16,6 +16,7 @@
16
16
  export * from './auth.js';
17
17
  export * from './routing.js';
18
18
  export * from './shipped-routes.js';
19
+ export * from './state/index.js';
19
20
  export * from './admission.js';
20
21
  export * from './ingress.js';
21
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC"}
@@ -16,6 +16,7 @@
16
16
  export * from './auth.js';
17
17
  export * from './routing.js';
18
18
  export * from './shipped-routes.js';
19
+ export * from './state/index.js';
19
20
  export * from './admission.js';
20
21
  export * from './ingress.js';
21
22
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { StateRail } from './rail.js';
2
+ export declare function createStateApi(rail: StateRail): (request: Request) => Promise<Response>;
3
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/transport/state/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAKtC,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAqBvF"}
@@ -0,0 +1,106 @@
1
+ import { StateRail } from './rail.js';
2
+ const JSON_HEADERS = { 'content-type': 'application/json', 'cache-control': 'no-store' };
3
+ const encoder = new TextEncoder();
4
+ export function createStateApi(rail) {
5
+ return async (request) => {
6
+ const url = new URL(request.url);
7
+ if (request.method === 'GET' && url.pathname === '/state') {
8
+ return json(200, { service: 'state', seq: rail.currentSeq(), resources: rail.resources.names() });
9
+ }
10
+ if (request.method === 'GET' && url.pathname === '/state/resources') {
11
+ return json(200, { resources: rail.resources.names(), defaults: rail.resources.defaults() });
12
+ }
13
+ if (request.method === 'GET' && url.pathname === '/state/snapshot') {
14
+ return json(200, await rail.snapshot(url.searchParams.get('resources') ?? undefined));
15
+ }
16
+ if (request.method === 'GET' && url.pathname === '/state/events') {
17
+ const result = rail.eventsAfter(url.searchParams.get('after'), url.searchParams.get('limit'));
18
+ return json(result.reset ? 409 : 200, result);
19
+ }
20
+ if (request.method === 'GET' && url.pathname === '/state/stream') {
21
+ return stateStream(rail, request, url.searchParams);
22
+ }
23
+ return json(404, { error: 'not found' });
24
+ };
25
+ }
26
+ function json(status, body) {
27
+ return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS });
28
+ }
29
+ function stateStream(rail, request, query) {
30
+ let unsubscribe = () => { };
31
+ const body = new ReadableStream({
32
+ start(controller) {
33
+ let open = true;
34
+ let held = query.get('bootstrap') === '1' ? [] : null;
35
+ const send = (text) => {
36
+ if (open)
37
+ controller.enqueue(encoder.encode(text));
38
+ };
39
+ const close = () => {
40
+ if (!open)
41
+ return;
42
+ open = false;
43
+ unsubscribe();
44
+ controller.close();
45
+ };
46
+ const eventFrame = (event) => `id: ${event.seq}\nevent: state\ndata: ${JSON.stringify(event)}\n\n`;
47
+ send(': local-live-store connected\n\n');
48
+ let floor = Math.max(0, Number(query.get('after')) || 0);
49
+ unsubscribe = rail.subscribe((event) => {
50
+ if (held)
51
+ held.push(event);
52
+ else if (event.seq > floor)
53
+ send(eventFrame(event));
54
+ });
55
+ request.signal.addEventListener('abort', close, { once: true });
56
+ void (async () => {
57
+ if (held) {
58
+ try {
59
+ const snapshot = await rail.snapshot(query.get('resources') ?? undefined);
60
+ floor = snapshot.seq;
61
+ send(`event: snapshot\ndata: ${JSON.stringify(snapshot)}\n\n`);
62
+ const buffered = held;
63
+ held = null;
64
+ for (const event of buffered)
65
+ if (event.seq > floor)
66
+ send(eventFrame(event));
67
+ }
68
+ catch (error) {
69
+ send(`event: error\ndata: ${JSON.stringify({
70
+ status: 500,
71
+ error: error instanceof Error ? error.message : 'internal error',
72
+ })}\n\n`);
73
+ close();
74
+ }
75
+ return;
76
+ }
77
+ const replay = rail.eventsAfter(floor, 1001);
78
+ if (replay.reset || replay.events.length > 1000) {
79
+ send(`event: reset\ndata: ${JSON.stringify(replay.reset ? replay : {
80
+ code: 'state_replay_too_large',
81
+ message: 'Too many missed events to replay; fetch a fresh snapshot.',
82
+ after: floor,
83
+ reset: true,
84
+ })}\n\n`);
85
+ close();
86
+ return;
87
+ }
88
+ for (const event of replay.events)
89
+ send(eventFrame(event));
90
+ })();
91
+ },
92
+ cancel() {
93
+ unsubscribe();
94
+ },
95
+ });
96
+ return new Response(body, {
97
+ status: 200,
98
+ headers: {
99
+ 'content-type': 'text/event-stream; charset=utf-8',
100
+ 'cache-control': 'no-cache, no-transform',
101
+ connection: 'keep-alive',
102
+ 'x-accel-buffering': 'no',
103
+ },
104
+ });
105
+ }
106
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/transport/state/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { createStateApi } from './api.js';
2
+ export { MemoryStateEventStore } from './memory-store.js';
3
+ export { StateRail } from './rail.js';
4
+ export type { StateRailOptions } from './rail.js';
5
+ export { StateResourceRegistry } from './registry.js';
6
+ export type * from './types.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transport/state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,mBAAmB,YAAY,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { createStateApi } from './api.js';
2
+ export { MemoryStateEventStore } from './memory-store.js';
3
+ export { StateRail } from './rail.js';
4
+ export { StateResourceRegistry } from './registry.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transport/state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { StateEvent, StateEventInput, StateEventStore } from './types.js';
2
+ /** A bounded host adapter useful for embedded runtimes and tests. */
3
+ export declare class MemoryStateEventStore implements StateEventStore {
4
+ #private;
5
+ constructor(options?: {
6
+ maxEvents?: number;
7
+ });
8
+ currentSeq(): number;
9
+ append(input: StateEventInput, ts: string): StateEvent;
10
+ listAfter(after: number, limit: number): readonly StateEvent[];
11
+ bounds(): {
12
+ minSeq: number;
13
+ maxSeq: number;
14
+ };
15
+ }
16
+ //# sourceMappingURL=memory-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../../src/transport/state/memory-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/E,qEAAqE;AACrE,qBAAa,qBAAsB,YAAW,eAAe;;gBAK/C,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO;IAIhD,UAAU,IAAI,MAAM;IAIpB,MAAM,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU;IAStD,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,UAAU,EAAE;IAI9D,MAAM,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;CAM7C"}
@@ -0,0 +1,30 @@
1
+ /** A bounded host adapter useful for embedded runtimes and tests. */
2
+ export class MemoryStateEventStore {
3
+ #events = [];
4
+ #maxEvents;
5
+ #seq = 0;
6
+ constructor(options = {}) {
7
+ this.#maxEvents = Math.max(1, Math.floor(options.maxEvents ?? 5000));
8
+ }
9
+ currentSeq() {
10
+ return this.#seq;
11
+ }
12
+ append(input, ts) {
13
+ const event = { seq: ++this.#seq, ts, ...input };
14
+ this.#events.push(event);
15
+ if (this.#events.length > this.#maxEvents) {
16
+ this.#events.splice(0, this.#events.length - this.#maxEvents);
17
+ }
18
+ return event;
19
+ }
20
+ listAfter(after, limit) {
21
+ return this.#events.filter((event) => event.seq > after).slice(0, limit);
22
+ }
23
+ bounds() {
24
+ return {
25
+ minSeq: this.#events[0]?.seq ?? 0,
26
+ maxSeq: this.#events.at(-1)?.seq ?? 0,
27
+ };
28
+ }
29
+ }
30
+ //# sourceMappingURL=memory-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../../../src/transport/state/memory-store.ts"],"names":[],"mappings":"AAEA,qEAAqE;AACrE,MAAM,OAAO,qBAAqB;IACvB,OAAO,GAAiB,EAAE,CAAC;IAC3B,UAAU,CAAS;IAC5B,IAAI,GAAG,CAAC,CAAC;IAET,YAAY,UAAkC,EAAE;QAC9C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,MAAM,CAAC,KAAsB,EAAE,EAAU;QACvC,MAAM,KAAK,GAAe,EAAE,GAAG,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,SAAS,CAAC,KAAa,EAAE,KAAa;QACpC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM;QACJ,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;YACjC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;SACtC,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,27 @@
1
+ import { StateResourceRegistry } from './registry.js';
2
+ import type { StateEvent, StateEventInput, StateEventStore, StateResourceSpec, StateSnapshot } from './types.js';
3
+ export interface StateRailOptions {
4
+ readonly store: StateEventStore;
5
+ readonly now?: () => Date;
6
+ }
7
+ export declare class StateRail {
8
+ #private;
9
+ readonly resources: StateResourceRegistry;
10
+ constructor(options: StateRailOptions);
11
+ currentSeq(): number;
12
+ registerResource(name: string, spec: StateResourceSpec): void;
13
+ registerResourcePrefix(prefix: string, spec: StateResourceSpec): void;
14
+ append(input: StateEventInput): StateEvent;
15
+ eventsAfter(afterInput: unknown, limitInput?: unknown): {
16
+ readonly events: readonly StateEvent[];
17
+ readonly seq: number;
18
+ readonly reset?: true;
19
+ readonly code?: 'state_event_gap';
20
+ readonly message?: string;
21
+ readonly minSeq?: number;
22
+ readonly maxSeq?: number;
23
+ };
24
+ snapshot(resourcesInput?: string | readonly string[]): Promise<StateSnapshot>;
25
+ subscribe(listener: (event: StateEvent) => void): () => void;
26
+ }
27
+ //# sourceMappingURL=rail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rail.d.ts","sourceRoot":"","sources":["../../../src/transport/state/rail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,qBAAa,SAAS;;IACpB,QAAQ,CAAC,SAAS,wBAA+B;gBAKrC,OAAO,EAAE,gBAAgB;IAKrC,UAAU,IAAI,MAAM;IAIpB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAI7D,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAIrE,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,UAAU;IAS1C,WAAW,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,GAAE,OAAc,GAAG;QAC5D,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;QACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;QACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC;QAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;KAC1B;IAeK,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC;IAoBnF,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI;CAI7D"}
@@ -0,0 +1,79 @@
1
+ import { StateResourceRegistry } from './registry.js';
2
+ export class StateRail {
3
+ resources = new StateResourceRegistry();
4
+ #store;
5
+ #now;
6
+ #listeners = new Set();
7
+ constructor(options) {
8
+ this.#store = options.store;
9
+ this.#now = options.now ?? (() => new Date());
10
+ }
11
+ currentSeq() {
12
+ return this.#store.currentSeq();
13
+ }
14
+ registerResource(name, spec) {
15
+ this.resources.register(name, spec);
16
+ }
17
+ registerResourcePrefix(prefix, spec) {
18
+ this.resources.registerPrefix(prefix, spec);
19
+ }
20
+ append(input) {
21
+ if (!input || typeof input.resource !== 'string' || typeof input.op !== 'string') {
22
+ throw new Error('state event requires resource and op');
23
+ }
24
+ const event = this.#store.append(input, this.#now().toISOString());
25
+ for (const listener of this.#listeners)
26
+ listener(event);
27
+ return event;
28
+ }
29
+ eventsAfter(afterInput, limitInput = 1000) {
30
+ const after = nonNegativeInteger(afterInput, 0);
31
+ const limit = Math.min(nonNegativeInteger(limitInput, 1000), 5000);
32
+ const { minSeq, maxSeq } = this.#store.bounds();
33
+ if (after > 0 && minSeq > after + 1) {
34
+ return {
35
+ events: [], seq: after, reset: true, code: 'state_event_gap',
36
+ message: 'State event history has been compacted; fetch a fresh snapshot.',
37
+ minSeq, maxSeq,
38
+ };
39
+ }
40
+ const events = this.#store.listAfter(after, Math.max(1, limit));
41
+ return { events, seq: events.at(-1)?.seq ?? after };
42
+ }
43
+ async snapshot(resourcesInput) {
44
+ const resources = normalizeResources(resourcesInput, this.resources.defaults());
45
+ let last = null;
46
+ for (let attempt = 0; attempt < 3; attempt += 1) {
47
+ const before = this.currentSeq();
48
+ const context = {};
49
+ const data = {};
50
+ for (const resource of resources) {
51
+ const spec = this.resources.spec(resource);
52
+ if (!spec)
53
+ continue;
54
+ const value = await spec.read(context, resource);
55
+ if (value !== undefined)
56
+ data[resource] = value;
57
+ }
58
+ const after = this.currentSeq();
59
+ if (before === after)
60
+ return { seq: after, stable: true, resources: data };
61
+ last = { seq: before, stable: false, resources: data };
62
+ }
63
+ return last;
64
+ }
65
+ subscribe(listener) {
66
+ this.#listeners.add(listener);
67
+ return () => this.#listeners.delete(listener);
68
+ }
69
+ }
70
+ function nonNegativeInteger(value, fallback) {
71
+ const parsed = Number(value);
72
+ return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
73
+ }
74
+ function normalizeResources(input, defaults) {
75
+ const values = Array.isArray(input) ? input : input ? String(input).split(',') : defaults;
76
+ const clean = values.map((value) => String(value ?? '').trim()).filter(Boolean);
77
+ return clean.length > 0 ? [...new Set(clean)] : defaults;
78
+ }
79
+ //# sourceMappingURL=rail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rail.js","sourceRoot":"","sources":["../../../src/transport/state/rail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { StateResourceSpec } from './types.js';
2
+ export declare class StateResourceRegistry {
3
+ #private;
4
+ register(name: string, spec: StateResourceSpec): void;
5
+ registerPrefix(prefix: string, spec: StateResourceSpec): void;
6
+ unregister(name: string): boolean;
7
+ spec(name: string): Required<StateResourceSpec> | undefined;
8
+ names(): string[];
9
+ defaults(): string[];
10
+ }
11
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/transport/state/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,qBAAa,qBAAqB;;IAIhC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAMrD,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAM7D,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC,iBAAiB,CAAC,GAAG,SAAS;IAS3D,KAAK,IAAI,MAAM,EAAE;IAIjB,QAAQ,IAAI,MAAM,EAAE;CAcrB"}
@@ -0,0 +1,46 @@
1
+ export class StateResourceRegistry {
2
+ #resources = new Map();
3
+ #prefixes = new Map();
4
+ register(name, spec) {
5
+ this.#assert(name, spec);
6
+ if (this.#resources.has(name))
7
+ throw new Error(`resource "${name}" is already registered`);
8
+ this.#resources.set(name, { snapshotDefault: false, ...spec });
9
+ }
10
+ registerPrefix(prefix, spec) {
11
+ this.#assert(prefix, spec);
12
+ if (this.#prefixes.has(prefix))
13
+ throw new Error(`resource prefix "${prefix}" is already registered`);
14
+ this.#prefixes.set(prefix, { snapshotDefault: false, ...spec });
15
+ }
16
+ unregister(name) {
17
+ return this.#resources.delete(name);
18
+ }
19
+ spec(name) {
20
+ const direct = this.#resources.get(name);
21
+ if (direct)
22
+ return direct;
23
+ for (const [prefix, spec] of this.#prefixes) {
24
+ if (name.startsWith(prefix))
25
+ return spec;
26
+ }
27
+ return undefined;
28
+ }
29
+ names() {
30
+ return [...this.#resources.keys()];
31
+ }
32
+ defaults() {
33
+ return [...this.#resources]
34
+ .filter(([, spec]) => spec.snapshotDefault)
35
+ .map(([name]) => name);
36
+ }
37
+ #assert(name, spec) {
38
+ if (!name || typeof name !== 'string') {
39
+ throw new Error('registerResource requires a non-empty string name');
40
+ }
41
+ if (!spec || typeof spec.read !== 'function') {
42
+ throw new Error(`resource "${name}" requires a read() function`);
43
+ }
44
+ }
45
+ }
46
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/transport/state/registry.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,qBAAqB;IACvB,UAAU,GAAG,IAAI,GAAG,EAAuC,CAAC;IAC5D,SAAS,GAAG,IAAI,GAAG,EAAuC,CAAC;IAEpE,QAAQ,CAAC,IAAY,EAAE,IAAuB;QAC5C,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,yBAAyB,CAAC,CAAC;QAC3F,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,cAAc,CAAC,MAAc,EAAE,IAAuB;QACpD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,yBAAyB,CAAC,CAAC;QACrG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,CAAC,IAAY;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;QAC1B,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC5C,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC3C,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK;QACH,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,QAAQ;QACN,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;aACxB,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC;aAC1C,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,CAAC,IAAY,EAAE,IAAuB;QAC3C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,8BAA8B,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,37 @@
1
+ /** Engine reference: runtime/scripts/amalgm-mcp/state/{events,registry,snapshot}.js. */
2
+ export interface StateEventInput {
3
+ readonly resource: string;
4
+ readonly op: string;
5
+ readonly id?: string;
6
+ readonly value?: unknown;
7
+ readonly patch?: unknown;
8
+ readonly clientMutationId?: string;
9
+ readonly mutationId?: string;
10
+ readonly sharedResourceId?: string;
11
+ readonly source?: string;
12
+ readonly version?: number;
13
+ }
14
+ export interface StateEvent extends StateEventInput {
15
+ readonly seq: number;
16
+ readonly ts: string;
17
+ }
18
+ export interface StateEventStore {
19
+ currentSeq(): number;
20
+ append(input: StateEventInput, ts: string): StateEvent;
21
+ listAfter(after: number, limit: number): readonly StateEvent[];
22
+ bounds(): {
23
+ readonly minSeq: number;
24
+ readonly maxSeq: number;
25
+ };
26
+ }
27
+ export type StateResourceReader = (context: Record<string, unknown>, resource: string) => unknown | Promise<unknown>;
28
+ export interface StateResourceSpec {
29
+ readonly read: StateResourceReader;
30
+ readonly snapshotDefault?: boolean;
31
+ }
32
+ export interface StateSnapshot {
33
+ readonly seq: number;
34
+ readonly stable: boolean;
35
+ readonly resources: Readonly<Record<string, unknown>>;
36
+ }
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/transport/state/types.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAW,SAAQ,eAAe;IACjD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,IAAI,MAAM,CAAC;IACrB,MAAM,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,CAAC;IACvD,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,UAAU,EAAE,CAAC;IAC/D,MAAM,IAAI;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAChE;AAED,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,QAAQ,EAAE,MAAM,KACb,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/transport/state/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amalgm/core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "The Amalgm kernel SDK — identity, transport, supervision, and host capability contracts behind host-injected adapters.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -24,6 +24,10 @@
24
24
  "types": "./dist/transport/index.d.ts",
25
25
  "default": "./dist/transport/index.js"
26
26
  },
27
+ "./state": {
28
+ "types": "./dist/transport/state/index.d.ts",
29
+ "default": "./dist/transport/state/index.js"
30
+ },
27
31
  "./supervision": {
28
32
  "types": "./dist/supervision/index.d.ts",
29
33
  "default": "./dist/supervision/index.js"