@amalgm/live 0.1.0

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 (159) hide show
  1. package/PURPOSE.md +103 -0
  2. package/README.md +45 -0
  3. package/dist/contracts/binding.d.ts +49 -0
  4. package/dist/contracts/binding.d.ts.map +1 -0
  5. package/dist/contracts/binding.js +23 -0
  6. package/dist/contracts/binding.js.map +1 -0
  7. package/dist/contracts/content.d.ts +42 -0
  8. package/dist/contracts/content.d.ts.map +1 -0
  9. package/dist/contracts/content.js +72 -0
  10. package/dist/contracts/content.js.map +1 -0
  11. package/dist/contracts/docs.d.ts +64 -0
  12. package/dist/contracts/docs.d.ts.map +1 -0
  13. package/dist/contracts/docs.js +51 -0
  14. package/dist/contracts/docs.js.map +1 -0
  15. package/dist/contracts/events.d.ts +45 -0
  16. package/dist/contracts/events.d.ts.map +1 -0
  17. package/dist/contracts/events.js +38 -0
  18. package/dist/contracts/events.js.map +1 -0
  19. package/dist/contracts/frames/gateway.d.ts +83 -0
  20. package/dist/contracts/frames/gateway.d.ts.map +1 -0
  21. package/dist/contracts/frames/gateway.js +35 -0
  22. package/dist/contracts/frames/gateway.js.map +1 -0
  23. package/dist/contracts/frames/stream.d.ts +59 -0
  24. package/dist/contracts/frames/stream.d.ts.map +1 -0
  25. package/dist/contracts/frames/stream.js +17 -0
  26. package/dist/contracts/frames/stream.js.map +1 -0
  27. package/dist/contracts/frames/tunnel.d.ts +78 -0
  28. package/dist/contracts/frames/tunnel.d.ts.map +1 -0
  29. package/dist/contracts/frames/tunnel.js +55 -0
  30. package/dist/contracts/frames/tunnel.js.map +1 -0
  31. package/dist/contracts/index.d.ts +19 -0
  32. package/dist/contracts/index.d.ts.map +1 -0
  33. package/dist/contracts/index.js +19 -0
  34. package/dist/contracts/index.js.map +1 -0
  35. package/dist/contracts/mutation.d.ts +51 -0
  36. package/dist/contracts/mutation.d.ts.map +1 -0
  37. package/dist/contracts/mutation.js +55 -0
  38. package/dist/contracts/mutation.js.map +1 -0
  39. package/dist/contracts/presence.d.ts +46 -0
  40. package/dist/contracts/presence.d.ts.map +1 -0
  41. package/dist/contracts/presence.js +34 -0
  42. package/dist/contracts/presence.js.map +1 -0
  43. package/dist/contracts/resources.d.ts +52 -0
  44. package/dist/contracts/resources.d.ts.map +1 -0
  45. package/dist/contracts/resources.js +105 -0
  46. package/dist/contracts/resources.js.map +1 -0
  47. package/dist/contracts/snapshot.d.ts +24 -0
  48. package/dist/contracts/snapshot.d.ts.map +1 -0
  49. package/dist/contracts/snapshot.js +28 -0
  50. package/dist/contracts/snapshot.js.map +1 -0
  51. package/dist/contracts/validate.d.ts +32 -0
  52. package/dist/contracts/validate.d.ts.map +1 -0
  53. package/dist/contracts/validate.js +25 -0
  54. package/dist/contracts/validate.js.map +1 -0
  55. package/dist/detection/adapter-contract.d.ts +134 -0
  56. package/dist/detection/adapter-contract.d.ts.map +1 -0
  57. package/dist/detection/adapter-contract.js +162 -0
  58. package/dist/detection/adapter-contract.js.map +1 -0
  59. package/dist/detection/classify.d.ts +31 -0
  60. package/dist/detection/classify.d.ts.map +1 -0
  61. package/dist/detection/classify.js +28 -0
  62. package/dist/detection/classify.js.map +1 -0
  63. package/dist/detection/continuity.d.ts +54 -0
  64. package/dist/detection/continuity.d.ts.map +1 -0
  65. package/dist/detection/continuity.js +85 -0
  66. package/dist/detection/continuity.js.map +1 -0
  67. package/dist/detection/coverage.d.ts +43 -0
  68. package/dist/detection/coverage.d.ts.map +1 -0
  69. package/dist/detection/coverage.js +60 -0
  70. package/dist/detection/coverage.js.map +1 -0
  71. package/dist/detection/diff.d.ts +144 -0
  72. package/dist/detection/diff.d.ts.map +1 -0
  73. package/dist/detection/diff.js +187 -0
  74. package/dist/detection/diff.js.map +1 -0
  75. package/dist/detection/enrollment.d.ts +16 -0
  76. package/dist/detection/enrollment.d.ts.map +1 -0
  77. package/dist/detection/enrollment.js +70 -0
  78. package/dist/detection/enrollment.js.map +1 -0
  79. package/dist/detection/index.d.ts +29 -0
  80. package/dist/detection/index.d.ts.map +1 -0
  81. package/dist/detection/index.js +29 -0
  82. package/dist/detection/index.js.map +1 -0
  83. package/dist/detection/refusal.d.ts +33 -0
  84. package/dist/detection/refusal.d.ts.map +1 -0
  85. package/dist/detection/refusal.js +40 -0
  86. package/dist/detection/refusal.js.map +1 -0
  87. package/dist/entities/bytes.d.ts +18 -0
  88. package/dist/entities/bytes.d.ts.map +1 -0
  89. package/dist/entities/bytes.js +61 -0
  90. package/dist/entities/bytes.js.map +1 -0
  91. package/dist/entities/cloud.d.ts +82 -0
  92. package/dist/entities/cloud.d.ts.map +1 -0
  93. package/dist/entities/cloud.js +136 -0
  94. package/dist/entities/cloud.js.map +1 -0
  95. package/dist/entities/index.d.ts +23 -0
  96. package/dist/entities/index.d.ts.map +1 -0
  97. package/dist/entities/index.js +23 -0
  98. package/dist/entities/index.js.map +1 -0
  99. package/dist/entities/moves.d.ts +42 -0
  100. package/dist/entities/moves.d.ts.map +1 -0
  101. package/dist/entities/moves.js +82 -0
  102. package/dist/entities/moves.js.map +1 -0
  103. package/dist/entities/repo-states.d.ts +121 -0
  104. package/dist/entities/repo-states.d.ts.map +1 -0
  105. package/dist/entities/repo-states.js +127 -0
  106. package/dist/entities/repo-states.js.map +1 -0
  107. package/dist/entities/rules.d.ts +104 -0
  108. package/dist/entities/rules.d.ts.map +1 -0
  109. package/dist/entities/rules.js +200 -0
  110. package/dist/entities/rules.js.map +1 -0
  111. package/dist/entities/types.d.ts +94 -0
  112. package/dist/entities/types.d.ts.map +1 -0
  113. package/dist/entities/types.js +40 -0
  114. package/dist/entities/types.js.map +1 -0
  115. package/dist/index.d.ts +17 -0
  116. package/dist/index.d.ts.map +1 -0
  117. package/dist/index.js +17 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/machines/arbitration.d.ts +36 -0
  120. package/dist/machines/arbitration.d.ts.map +1 -0
  121. package/dist/machines/arbitration.js +37 -0
  122. package/dist/machines/arbitration.js.map +1 -0
  123. package/dist/machines/backoff.d.ts +36 -0
  124. package/dist/machines/backoff.d.ts.map +1 -0
  125. package/dist/machines/backoff.js +34 -0
  126. package/dist/machines/backoff.js.map +1 -0
  127. package/dist/machines/bootstrap.d.ts +65 -0
  128. package/dist/machines/bootstrap.d.ts.map +1 -0
  129. package/dist/machines/bootstrap.js +105 -0
  130. package/dist/machines/bootstrap.js.map +1 -0
  131. package/dist/machines/chunks.d.ts +51 -0
  132. package/dist/machines/chunks.d.ts.map +1 -0
  133. package/dist/machines/chunks.js +67 -0
  134. package/dist/machines/chunks.js.map +1 -0
  135. package/dist/machines/index.d.ts +14 -0
  136. package/dist/machines/index.d.ts.map +1 -0
  137. package/dist/machines/index.js +14 -0
  138. package/dist/machines/index.js.map +1 -0
  139. package/dist/machines/journal.d.ts +63 -0
  140. package/dist/machines/journal.d.ts.map +1 -0
  141. package/dist/machines/journal.js +71 -0
  142. package/dist/machines/journal.js.map +1 -0
  143. package/dist/machines/ordering.d.ts +53 -0
  144. package/dist/machines/ordering.d.ts.map +1 -0
  145. package/dist/machines/ordering.js +87 -0
  146. package/dist/machines/ordering.js.map +1 -0
  147. package/dist/machines/presence.d.ts +26 -0
  148. package/dist/machines/presence.d.ts.map +1 -0
  149. package/dist/machines/presence.js +49 -0
  150. package/dist/machines/presence.js.map +1 -0
  151. package/dist/merge/index.d.ts +9 -0
  152. package/dist/merge/index.d.ts.map +1 -0
  153. package/dist/merge/index.js +9 -0
  154. package/dist/merge/index.js.map +1 -0
  155. package/dist/merge/merge3.d.ts +39 -0
  156. package/dist/merge/merge3.d.ts.map +1 -0
  157. package/dist/merge/merge3.js +188 -0
  158. package/dist/merge/merge3.js.map +1 -0
  159. package/package.json +48 -0
@@ -0,0 +1,200 @@
1
+ /**
2
+ * The registry's pure rule surface — the laws of the entity model (engine
3
+ * docs/entity-model.md) with every store lookup behind the injected
4
+ * {@link EntityReadPort} and every hash behind {@link Sha256Hex}:
5
+ *
6
+ * - the ratified version formula: version = hash(type, parentUUID, name,
7
+ * status, adapterPayloadVersion) — DERIVED, never stored;
8
+ * - container payloads as sorted active direct membership;
9
+ * - lifecycle inheritance DOWN the ancestor chain as derived effective
10
+ * status (deleted > trashed > own stored status);
11
+ * - one active owner per (parentUUID, name) slot; only containers hold
12
+ * active children; the parent graph is acyclic;
13
+ * - what an attestation may say (leaf ground attests bytes; membership and
14
+ * reference identity are never observed);
15
+ * - the record / syncRecord shapes and the cloud-record normalizer.
16
+ *
17
+ * Refusal messages are ported verbatim from the engine registry — they are
18
+ * the ratified refusal text its exams pin.
19
+ */
20
+ import { CONTAINERS, DERIVED_PAYLOAD, ROOT_TYPES, TYPES, UUID_PATTERN, } from './types.js';
21
+ /** The row a UUID must name; absence is the caller's bug, said plainly. */
22
+ export function mustGet(uuid, byUuid) {
23
+ const row = byUuid(uuid);
24
+ if (!row)
25
+ throw new Error(`no entity ${uuid}`);
26
+ return row;
27
+ }
28
+ /**
29
+ * What an attestation may say — asked of both the type a record wears now
30
+ * and the type its new bytes claim, because an attestation may carry a
31
+ * record across leaf kinds (a pointer replaced by bytes) and both ends
32
+ * must be ground an observation can speak for.
33
+ */
34
+ export function attestable(type) {
35
+ if (DERIVED_PAYLOAD.has(type)) {
36
+ throw new Error(`${type} payload is derived membership, never attested`);
37
+ }
38
+ if (type === 'reference') {
39
+ throw new Error('a reference\'s payload is the target\'s identity, set by the deliberate act that created it — never an attestation; the rendered symlink is derived state, not evidence');
40
+ }
41
+ if (!TYPES.has(type))
42
+ throw new Error(`unknown entity type ${JSON.stringify(type)}`);
43
+ }
44
+ /** The ratified formula: version = hash(type, parentUUID, name, status, payloadVersion). */
45
+ export function canonicalVersion({ type, parentUUID = null, name, status, payloadVersion = null }, sha256Hex) {
46
+ return sha256Hex(JSON.stringify([type, parentUUID, name, status, payloadVersion]));
47
+ }
48
+ /** A name is one non-empty path segment: never '', '.', '..', a '/' or NUL. */
49
+ export function validName(name) {
50
+ if (typeof name !== 'string' || name === '' || name === '.' || name === '..'
51
+ || name.includes('/') || name.includes('\0')) {
52
+ throw new Error(`invalid entity name ${JSON.stringify(name)}: a name is one non-empty path segment`);
53
+ }
54
+ }
55
+ /** A UUID may arrive only through a trusted identity binding (for example
56
+ * a cloud user-home bootstrap). The registry still owns the actual insert:
57
+ * accepting a caller-supplied UUID is not accepting a caller-supplied
58
+ * record, parent, status, or version. */
59
+ export function mintOrValidateUuid(uuid, ports) {
60
+ if (uuid === undefined || uuid === null)
61
+ return ports.mintUuid();
62
+ if (typeof uuid !== 'string' || !UUID_PATTERN.test(uuid)) {
63
+ throw new Error(`entity identity must be a UUID, got ${JSON.stringify(uuid)}`);
64
+ }
65
+ if (ports.byUuid(uuid))
66
+ throw new Error(`entity identity ${uuid} is already registered`);
67
+ return uuid.toLowerCase();
68
+ }
69
+ /** Ancestor uuids from the given parent up to the root. */
70
+ export function ancestorsOf(parentUuid, byUuid) {
71
+ const chain = [];
72
+ const seen = new Set();
73
+ let cursor = parentUuid;
74
+ while (cursor !== null) {
75
+ if (seen.has(cursor))
76
+ throw new Error(`registry corrupt: parent cycle at ${cursor}`);
77
+ seen.add(cursor);
78
+ chain.push(cursor);
79
+ cursor = mustGet(cursor, byUuid).parentUuid;
80
+ }
81
+ return chain;
82
+ }
83
+ /** Lifecycle inherits down: deleted if any ancestor is deleted, trashed if
84
+ * any is trashed, otherwise the entity's own stored status — one flip on a
85
+ * folder, no descendant record rewritten. */
86
+ export function effectiveStatusOf(row, byUuid) {
87
+ const statuses = [row.status, ...ancestorsOf(row.parentUuid, byUuid)
88
+ .map((uuid) => mustGet(uuid, byUuid).status)];
89
+ if (statuses.includes('deleted'))
90
+ return 'deleted';
91
+ if (statuses.includes('trashed'))
92
+ return 'trashed';
93
+ return row.status;
94
+ }
95
+ const byUuidOrder = (left, right) => (left < right ? -1 : left > right ? 1 : 0);
96
+ /**
97
+ * Container payload: the sorted active direct membership (childUUID, name).
98
+ * Children are sorted here by uuid, codepoint order — the same order the
99
+ * engine's `ORDER BY uuid` (BINARY collation over lowercase-hex uuids)
100
+ * produces — so the hash input is byte-identical however the port returns
101
+ * them. Membership counts direct children by their STORED status, never
102
+ * effective status: effective-status membership would ripple a version
103
+ * change through the entire subtree and defeat the one-flip lifecycle.
104
+ */
105
+ export function membershipHash(activeChildren, sha256Hex) {
106
+ const pairs = [...activeChildren]
107
+ .sort((left, right) => byUuidOrder(left.uuid, right.uuid))
108
+ .map((child) => [child.uuid, child.name]);
109
+ return sha256Hex(JSON.stringify(pairs));
110
+ }
111
+ const payloadFor = (row, ports) => (DERIVED_PAYLOAD.has(row.type) ? ports.membershipHashOf(row.uuid) : row.payloadVersion);
112
+ /** The public record: exactly the six ratified fields, version derived. */
113
+ export function entityRecordOf(row, ports) {
114
+ return {
115
+ uuid: row.uuid,
116
+ type: row.type,
117
+ parentUUID: row.parentUuid,
118
+ name: row.name,
119
+ version: canonicalVersion({
120
+ type: row.type, parentUUID: row.parentUuid, name: row.name,
121
+ status: row.status, payloadVersion: payloadFor(row, ports),
122
+ }, ports.sha256Hex),
123
+ status: row.status,
124
+ };
125
+ }
126
+ /** The cloud form contains identity and the content/head token, never an
127
+ * address, watcher, inode, or SQLite bytes. `payloadVersion` is the
128
+ * unambiguous current head for leaf types; containers derive theirs from
129
+ * membership and retain null here; a repo.git retains its immutable
130
+ * Card/Checkpoint head. */
131
+ export function syncRecordOf(row, ports) {
132
+ return {
133
+ ...entityRecordOf(row, ports),
134
+ payloadVersion: row.payloadVersion,
135
+ };
136
+ }
137
+ /** Validate and normalize a record arriving from the cloud: six fields plus
138
+ * payloadVersion, UUIDs lowercased, root laws enforced. */
139
+ export function normalizeCloudRecord(value) {
140
+ const record = value;
141
+ if (!record || typeof record !== 'object'
142
+ || typeof record.uuid !== 'string' || !UUID_PATTERN.test(record.uuid)
143
+ || typeof record.type !== 'string' || !TYPES.has(record.type)
144
+ || (record.parentUUID !== null && (typeof record.parentUUID !== 'string' || !UUID_PATTERN.test(record.parentUUID)))
145
+ || typeof record.name !== 'string'
146
+ || !['active', 'trashed', 'deleted'].includes(record.status)
147
+ || (record.payloadVersion !== null && typeof record.payloadVersion !== 'string')
148
+ || typeof record.version !== 'string' || !/^[0-9a-f]{64}$/i.test(record.version)) {
149
+ throw new Error('cloud entity operation has an invalid record');
150
+ }
151
+ validName(record.name);
152
+ if (record.parentUUID === null && !ROOT_TYPES.has(record.type)) {
153
+ throw new Error(`cloud entity ${record.uuid} is not a valid tree root`);
154
+ }
155
+ if (record.parentUUID !== null && record.type === 'workspace') {
156
+ throw new Error('cloud entity workspace is the root type only');
157
+ }
158
+ return {
159
+ uuid: record.uuid.toLowerCase(),
160
+ type: record.type,
161
+ parentUuid: record.parentUUID === null ? null : record.parentUUID.toLowerCase(),
162
+ name: record.name,
163
+ status: record.status,
164
+ payloadVersion: record.payloadVersion,
165
+ expectedVersion: record.version.toLowerCase(),
166
+ };
167
+ }
168
+ /** Equality over the five stored facts plus payload — everything the
169
+ * version fingerprints except the fingerprint itself. */
170
+ export function sameLogicalRecord(left, right) {
171
+ return left.uuid === right.uuid
172
+ && left.type === right.type
173
+ && left.parentUuid === right.parentUuid
174
+ && left.name === right.name
175
+ && left.status === right.status
176
+ && left.payloadVersion === right.payloadVersion;
177
+ }
178
+ /** Only containers — workspace, folder, repo.git — hold active children,
179
+ * and only while effectively active themselves. */
180
+ export function requireActiveContainerParent(parentUuid, port) {
181
+ const parent = mustGet(parentUuid, port.byUuid.bind(port));
182
+ if (!CONTAINERS.has(parent.type)) {
183
+ throw new Error(`only containers hold active children: ${parentUuid} is ${parent.type}, not workspace/folder/repo.git`);
184
+ }
185
+ if (effectiveStatusOf(parent, port.byUuid.bind(port)) !== 'active') {
186
+ throw new Error(`parent ${parentUuid} is not effectively active — restore it before putting entities under it`);
187
+ }
188
+ return parent;
189
+ }
190
+ /** One active owner per (parentUUID, name) slot. Parentless records are
191
+ * exempt: a top-level tree is placed by its machine binding, never by name. */
192
+ export function requireFreeSlot(parentUuid, name, port, forUuid = null) {
193
+ if (parentUuid === null)
194
+ return; // top level: address places a tree, never its name
195
+ const occupant = port.activeChildByName(parentUuid, name);
196
+ if (occupant && occupant.uuid !== forUuid) {
197
+ throw new Error(`slot taken: active entity ${occupant.uuid} already owns (${parentUuid}, ${name}) — move or trash it first`);
198
+ }
199
+ }
200
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/entities/rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The entity alphabet and the six-field universal record — the value
3
+ * vocabulary of the entity model (engine docs/entity-model.md, "The entity
4
+ * record"). Every enrolled entity, of every type, is exactly six fields:
5
+ * UUID, type, parentUUID, name, version, status. Paths are derived from the
6
+ * parentUUID + name chain and are never identity; version is derived on
7
+ * read, never stored.
8
+ *
9
+ * The alphabet is PHYSICAL kinds only. Constructs — agents, apps,
10
+ * automations, tools, skills — are folder-and-file ground with a known
11
+ * structure, their meaning layered ABOVE the physical type, never encoded
12
+ * as one.
13
+ *
14
+ * This module also names the two ports the pure rules receive instead of a
15
+ * database or node:crypto: a read port over the host's identity store, and
16
+ * a SHA-256 hex function.
17
+ */
18
+ /** `link` is a filesystem symlink: payload = the literal target text.
19
+ * `reference` is the OTHER link kind, never conflated: Amalgm-created by a
20
+ * deliberate act, its payload the TARGET ENTITY'S UUID — identity, not an
21
+ * address. */
22
+ export type EntityType = 'workspace' | 'folder' | 'repo.git' | 'file.text' | 'file.binary' | 'link' | 'reference';
23
+ export type ContainerType = 'workspace' | 'folder' | 'repo.git';
24
+ /** active — exists normally; trashed — recoverable, UUID survives;
25
+ * deleted — content permanently gone, the record IS the tombstone. */
26
+ export type EntityStatus = 'active' | 'trashed' | 'deleted';
27
+ export declare const TYPES: ReadonlySet<string>;
28
+ /** Only containers hold active children. */
29
+ export declare const CONTAINERS: ReadonlySet<string>;
30
+ /** The types a parentless record (a tree root) may wear. `folder` is
31
+ * deliberately absent: a folder inside no workspace is not a thing amalgm
32
+ * registers. `reference` is absent too — a managed pointer is always
33
+ * created inside a tree. */
34
+ export declare const ROOT_TYPES: ReadonlySet<string>;
35
+ /** Types whose payload IS their membership: derived from the records
36
+ * beneath them, so no observation may attest one. */
37
+ export declare const DERIVED_PAYLOAD: ReadonlySet<string>;
38
+ /** The one entity alphabet, published sorted for the layers that map onto
39
+ * it — read from here, never restated, so it cannot drift. */
40
+ export declare const ENTITY_TYPES: readonly EntityType[];
41
+ export declare const isEntityType: (value: unknown) => value is EntityType;
42
+ /** RFC-4122 UUID shape (versions 1–8), the permanent identity and realtime
43
+ * channel of every enrolled entity. */
44
+ export declare const UUID_PATTERN: RegExp;
45
+ /**
46
+ * A stored identity row as the host's store holds it — the six fields with
47
+ * the payload attestation beside them and no derived version. The rules in
48
+ * this layer read rows through {@link EntityReadPort} and never write one.
49
+ */
50
+ export interface EntityRow {
51
+ readonly uuid: string;
52
+ readonly type: EntityType;
53
+ readonly parentUuid: string | null;
54
+ readonly name: string;
55
+ readonly status: EntityStatus;
56
+ readonly payloadVersion: string | null;
57
+ }
58
+ /** The public record: exactly the six ratified fields, version derived by
59
+ * the canonical formula. Payload attestations are evidence inputs, never a
60
+ * seventh public field. */
61
+ export interface EntityRecord {
62
+ readonly uuid: string;
63
+ readonly type: EntityType;
64
+ readonly parentUUID: string | null;
65
+ readonly name: string;
66
+ readonly version: string;
67
+ readonly status: EntityStatus;
68
+ }
69
+ /** The cloud form: the record plus the unambiguous current head for leaf
70
+ * types. Containers derive their payload from membership and retain null
71
+ * here; a repo.git retains its immutable Card/Checkpoint stateId. */
72
+ export interface EntitySyncRecord extends EntityRecord {
73
+ readonly payloadVersion: string | null;
74
+ }
75
+ /**
76
+ * SHA-256 as lowercase hex over the given bytes; string input is hashed as
77
+ * its UTF-8 encoding (exactly node:crypto's `createHash('sha256')
78
+ * .update(input).digest('hex')`). Injected by the host — src/ owns hash
79
+ * INPUTS byte for byte, never the hash implementation.
80
+ */
81
+ export type Sha256Hex = (input: Uint8Array | string) => string;
82
+ /**
83
+ * The minimal read surface the rules need over the host's identity store.
84
+ * Lookups are by permanent identity or by (parentUUID, name) slot; the
85
+ * rules never enumerate, never write, and never see a path.
86
+ */
87
+ export interface EntityReadPort {
88
+ /** The row wearing this UUID, or null/undefined when none does. */
89
+ byUuid(uuid: string): EntityRow | null | undefined;
90
+ /** The ACTIVE row owning the (parentUuid, name) slot, or null/undefined
91
+ * when the slot is free. */
92
+ activeChildByName(parentUuid: string, name: string): EntityRow | null | undefined;
93
+ }
94
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/entities/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;cAGc;AACd,MAAM,MAAM,UAAU,GAClB,WAAW,GAAG,QAAQ,GAAG,UAAU,GACnC,WAAW,GAAG,aAAa,GAC3B,MAAM,GAAG,WAAW,CAAC;AAEzB,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEhE;sEACsE;AACtE,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAO5D,eAAO,MAAM,KAAK,EAAE,WAAW,CAAC,MAAM,CAAqB,CAAC;AAE5D,4CAA4C;AAC5C,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,MAAM,CAE1C,CAAC;AAEF;;;4BAG4B;AAC5B,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,MAAM,CAE1C,CAAC;AAEF;qDACqD;AACrD,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAE/C,CAAC;AAEF;8DAC8D;AAC9D,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAAwC,CAAC;AAEvF,eAAO,MAAM,YAAY,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,UACR,CAAC;AAEhD;uCACuC;AACvC,eAAO,MAAM,YAAY,QACqD,CAAC;AAE/E;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED;;2BAE2B;AAC3B,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CAC/B;AAED;;qEAEqE;AACrE,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,KAAK,MAAM,CAAC;AAE/D;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;IACnD;gCAC4B;IAC5B,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;CACnF"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The entity alphabet and the six-field universal record — the value
3
+ * vocabulary of the entity model (engine docs/entity-model.md, "The entity
4
+ * record"). Every enrolled entity, of every type, is exactly six fields:
5
+ * UUID, type, parentUUID, name, version, status. Paths are derived from the
6
+ * parentUUID + name chain and are never identity; version is derived on
7
+ * read, never stored.
8
+ *
9
+ * The alphabet is PHYSICAL kinds only. Constructs — agents, apps,
10
+ * automations, tools, skills — are folder-and-file ground with a known
11
+ * structure, their meaning layered ABOVE the physical type, never encoded
12
+ * as one.
13
+ *
14
+ * This module also names the two ports the pure rules receive instead of a
15
+ * database or node:crypto: a read port over the host's identity store, and
16
+ * a SHA-256 hex function.
17
+ */
18
+ const ALPHABET = [
19
+ 'workspace', 'folder', 'repo.git', 'file.text', 'file.binary',
20
+ 'link', 'reference',
21
+ ];
22
+ export const TYPES = new Set(ALPHABET);
23
+ /** Only containers hold active children. */
24
+ export const CONTAINERS = new Set(['workspace', 'folder', 'repo.git']);
25
+ /** The types a parentless record (a tree root) may wear. `folder` is
26
+ * deliberately absent: a folder inside no workspace is not a thing amalgm
27
+ * registers. `reference` is absent too — a managed pointer is always
28
+ * created inside a tree. */
29
+ export const ROOT_TYPES = new Set(['workspace', 'repo.git', 'file.text', 'file.binary', 'link']);
30
+ /** Types whose payload IS their membership: derived from the records
31
+ * beneath them, so no observation may attest one. */
32
+ export const DERIVED_PAYLOAD = new Set(['workspace', 'folder']);
33
+ /** The one entity alphabet, published sorted for the layers that map onto
34
+ * it — read from here, never restated, so it cannot drift. */
35
+ export const ENTITY_TYPES = Object.freeze([...ALPHABET].sort());
36
+ export const isEntityType = (value) => typeof value === 'string' && TYPES.has(value);
37
+ /** RFC-4122 UUID shape (versions 1–8), the permanent identity and realtime
38
+ * channel of every enrolled entity. */
39
+ export const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
40
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/entities/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAiBH,MAAM,QAAQ,GAA0B;IACtC,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa;IAC7D,MAAM,EAAE,WAAW;CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,KAAK,GAAwB,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;AAE5D,4CAA4C;AAC5C,MAAM,CAAC,MAAM,UAAU,GAAwB,IAAI,GAAG,CACpD,CAAC,WAAW,EAAE,QAAQ,EAAE,UAAU,CAA2B,CAC9D,CAAC;AAEF;;;4BAG4B;AAC5B,MAAM,CAAC,MAAM,UAAU,GAAwB,IAAI,GAAG,CACpD,CAAC,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,CAAwB,CACrF,CAAC;AAEF;qDACqD;AACrD,MAAM,CAAC,MAAM,eAAe,GAAwB,IAAI,GAAG,CACzD,CAAC,WAAW,EAAE,QAAQ,CAAwB,CAC/C,CAAC;AAEF;8DAC8D;AAC9D,MAAM,CAAC,MAAM,YAAY,GAA0B,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AAEvF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAc,EAAuB,EAAE,CAClE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAEhD;uCACuC;AACvC,MAAM,CAAC,MAAM,YAAY,GACvB,4EAA4E,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @amalgm/live — the portable realtime SDK for the Amalgm platform.
3
+ *
4
+ * Three layers, one rule each:
5
+ *
6
+ * - `contracts/` every wire shape and identity rule, as types + validators
7
+ * - `machines/` the protocol's behavior, as pure state machines
8
+ * - `adapters/` the ports a host injects (transport, journal, clock, crypto)
9
+ *
10
+ * Start at PURPOSE.md for the axioms; docs/ holds the normative specs.
11
+ */
12
+ export * from './contracts/index.js';
13
+ export * from './machines/index.js';
14
+ export * from './entities/index.js';
15
+ export * from './detection/index.js';
16
+ export * from './merge/index.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @amalgm/live — the portable realtime SDK for the Amalgm platform.
3
+ *
4
+ * Three layers, one rule each:
5
+ *
6
+ * - `contracts/` every wire shape and identity rule, as types + validators
7
+ * - `machines/` the protocol's behavior, as pure state machines
8
+ * - `adapters/` the ports a host injects (transport, journal, clock, crypto)
9
+ *
10
+ * Start at PURPOSE.md for the axioms; docs/ holds the normative specs.
11
+ */
12
+ export * from './contracts/index.js';
13
+ export * from './machines/index.js';
14
+ export * from './entities/index.js';
15
+ export * from './detection/index.js';
16
+ export * from './merge/index.js';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Tunnel slot arbitration — who owns `(computer_id, runtime_label)`.
3
+ *
4
+ * The gateway holds one slot per runtime identity; a newcomer's first
5
+ * identity-bearing hello decides the winner (local-live-protocol.md §5).
6
+ * This is the pure decision. The gateway supplies sockets and timers; the
7
+ * fencing rule — mark the loser superseded BEFORE closing it, drop its
8
+ * in-flight frames — is part of the contract and encoded in the verdict.
9
+ */
10
+ import { CLOSE_CODES, type TunnelHello } from '../contracts/frames/tunnel.js';
11
+ /** A newcomer with a holder present buffers unrouted until its first identity-bearing hello, bounded by this deadline (AMALGM_TUNNEL_HELLO_ARBITRATION_MS). */
12
+ export declare const ARBITRATION_DEADLINE_MS = 3000;
13
+ export type SlotIdentity = Pick<TunnelHello, 'instance_id' | 'boot_ts'>;
14
+ export type SlotVerdict =
15
+ /** Free slot, or the newcomer won: install it. `fenceHolder` demands the holder be superseded-then-closed (4000) with its frames dropped. */
16
+ {
17
+ readonly install: true;
18
+ readonly fenceHolder: boolean;
19
+ readonly rule: 'free-slot' | 'same-instance-reconnect' | 'newer-boot' | 'legacy-last-connect-wins';
20
+ }
21
+ /** The newcomer lost: refuse with 4009. The holder is untouched. */
22
+ | {
23
+ readonly install: false;
24
+ readonly closeCode: typeof CLOSE_CODES.supersededInstance;
25
+ readonly rule: 'older-or-equal-boot';
26
+ };
27
+ /**
28
+ * Decide a contested slot.
29
+ *
30
+ * - same `instance_id` → newer socket wins (the same process reconnecting)
31
+ * - different `instance_id` → strictly newer `boot_ts` wins; older or EQUAL loses
32
+ * - unusable identity on either side (or the deadline expired — pass
33
+ * `holder: null` identity via `legacyFallback`) → last-connect-wins, logged as such by the caller
34
+ */
35
+ export declare function decideSlot(holder: SlotIdentity | null, newcomer: Partial<SlotIdentity>): SlotVerdict;
36
+ //# sourceMappingURL=arbitration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arbitration.d.ts","sourceRoot":"","sources":["../../src/machines/arbitration.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAqB,KAAK,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEjG,+JAA+J;AAC/J,eAAO,MAAM,uBAAuB,OAAQ,CAAC;AAE7C,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,SAAS,CAAC,CAAC;AAExE,MAAM,MAAM,WAAW;AACrB,6IAA6I;AAC3I;IAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,yBAAyB,GAAG,YAAY,GAAG,0BAA0B,CAAA;CAAE;AAC/J,oEAAoE;GAClE;IAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,WAAW,CAAC,kBAAkB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAEjI;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,WAAW,CAepG"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Tunnel slot arbitration — who owns `(computer_id, runtime_label)`.
3
+ *
4
+ * The gateway holds one slot per runtime identity; a newcomer's first
5
+ * identity-bearing hello decides the winner (local-live-protocol.md §5).
6
+ * This is the pure decision. The gateway supplies sockets and timers; the
7
+ * fencing rule — mark the loser superseded BEFORE closing it, drop its
8
+ * in-flight frames — is part of the contract and encoded in the verdict.
9
+ */
10
+ import { CLOSE_CODES, hasUsableIdentity } from '../contracts/frames/tunnel.js';
11
+ /** A newcomer with a holder present buffers unrouted until its first identity-bearing hello, bounded by this deadline (AMALGM_TUNNEL_HELLO_ARBITRATION_MS). */
12
+ export const ARBITRATION_DEADLINE_MS = 3_000;
13
+ /**
14
+ * Decide a contested slot.
15
+ *
16
+ * - same `instance_id` → newer socket wins (the same process reconnecting)
17
+ * - different `instance_id` → strictly newer `boot_ts` wins; older or EQUAL loses
18
+ * - unusable identity on either side (or the deadline expired — pass
19
+ * `holder: null` identity via `legacyFallback`) → last-connect-wins, logged as such by the caller
20
+ */
21
+ export function decideSlot(holder, newcomer) {
22
+ if (holder === null) {
23
+ return { install: true, fenceHolder: false, rule: 'free-slot' };
24
+ }
25
+ if (!hasUsableIdentity(newcomer) || !hasUsableIdentity(holder)) {
26
+ return { install: true, fenceHolder: true, rule: 'legacy-last-connect-wins' };
27
+ }
28
+ const contender = newcomer;
29
+ if (contender.instance_id === holder.instance_id) {
30
+ return { install: true, fenceHolder: true, rule: 'same-instance-reconnect' };
31
+ }
32
+ if (contender.boot_ts > holder.boot_ts) {
33
+ return { install: true, fenceHolder: true, rule: 'newer-boot' };
34
+ }
35
+ return { install: false, closeCode: CLOSE_CODES.supersededInstance, rule: 'older-or-equal-boot' };
36
+ }
37
+ //# sourceMappingURL=arbitration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arbitration.js","sourceRoot":"","sources":["../../src/machines/arbitration.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAoB,MAAM,+BAA+B,CAAC;AAEjG,+JAA+J;AAC/J,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAU7C;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,MAA2B,EAAE,QAA+B;IACrF,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAClE,CAAC;IACD,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,0BAA0B,EAAE,CAAC;IAChF,CAAC;IACD,MAAM,SAAS,GAAG,QAAwB,CAAC;IAC3C,IAAI,SAAS,CAAC,WAAW,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC;QACjD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,yBAAyB,EAAE,CAAC;IAC/E,CAAC;IACD,IAAI,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAClE,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC,kBAAkB,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC;AACpG,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Tunnel reconnect policy (local-live-protocol.md §5, runtime client
3
+ * behavior).
4
+ *
5
+ * Two rules keep a two-instance fight from becoming a reconnect war:
6
+ *
7
+ * 1. Exponential backoff resets to 1s only after a connection SURVIVED the
8
+ * stable window; a connection that dies younger keeps (and grows) the
9
+ * previous backoff.
10
+ * 2. A 4009 refusal ("superseded instance") retries after a fixed long
11
+ * delay — never a full stop, because a wrongly-refused instance must
12
+ * still recover once the true holder dies.
13
+ */
14
+ /** AMALGM_TUNNEL_SUPERSEDED_RETRY_MS */
15
+ export declare const SUPERSEDED_RETRY_MS: number;
16
+ /** AMALGM_TUNNEL_STABLE_RESET_MS — survival time that earns a reset to the base delay. */
17
+ export declare const STABLE_RESET_MS = 30000;
18
+ export declare const BASE_DELAY_MS = 1000;
19
+ export declare const MAX_DELAY_MS = 60000;
20
+ export interface BackoffState {
21
+ /** The delay the NEXT failure will use. */
22
+ readonly delayMs: number;
23
+ }
24
+ export declare const initialBackoff: BackoffState;
25
+ export interface Disconnect {
26
+ readonly closeCode?: number;
27
+ /** How long the connection lived before dying. */
28
+ readonly connectedForMs: number;
29
+ }
30
+ export interface ReconnectPlan {
31
+ readonly waitMs: number;
32
+ readonly next: BackoffState;
33
+ readonly rule: 'superseded-fixed-retry' | 'stable-reset' | 'exponential';
34
+ }
35
+ export declare function planReconnect(state: BackoffState, disconnect: Disconnect): ReconnectPlan;
36
+ //# sourceMappingURL=backoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backoff.d.ts","sourceRoot":"","sources":["../../src/machines/backoff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,wCAAwC;AACxC,eAAO,MAAM,mBAAmB,QAAa,CAAC;AAC9C,0FAA0F;AAC1F,eAAO,MAAM,eAAe,QAAS,CAAC;AACtC,eAAO,MAAM,aAAa,OAAQ,CAAC;AACnC,eAAO,MAAM,YAAY,QAAS,CAAC;AAEnC,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,cAAc,EAAE,YAAyC,CAAC;AAEvE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,kDAAkD;IAClD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,wBAAwB,GAAG,cAAc,GAAG,aAAa,CAAC;CAC1E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,GAAG,aAAa,CAWxF"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Tunnel reconnect policy (local-live-protocol.md §5, runtime client
3
+ * behavior).
4
+ *
5
+ * Two rules keep a two-instance fight from becoming a reconnect war:
6
+ *
7
+ * 1. Exponential backoff resets to 1s only after a connection SURVIVED the
8
+ * stable window; a connection that dies younger keeps (and grows) the
9
+ * previous backoff.
10
+ * 2. A 4009 refusal ("superseded instance") retries after a fixed long
11
+ * delay — never a full stop, because a wrongly-refused instance must
12
+ * still recover once the true holder dies.
13
+ */
14
+ import { CLOSE_CODES } from '../contracts/frames/tunnel.js';
15
+ /** AMALGM_TUNNEL_SUPERSEDED_RETRY_MS */
16
+ export const SUPERSEDED_RETRY_MS = 5 * 60_000;
17
+ /** AMALGM_TUNNEL_STABLE_RESET_MS — survival time that earns a reset to the base delay. */
18
+ export const STABLE_RESET_MS = 30_000;
19
+ export const BASE_DELAY_MS = 1_000;
20
+ export const MAX_DELAY_MS = 60_000;
21
+ export const initialBackoff = { delayMs: BASE_DELAY_MS };
22
+ export function planReconnect(state, disconnect) {
23
+ if (disconnect.closeCode === CLOSE_CODES.supersededInstance) {
24
+ // Fixed, slow, and does not disturb the exponential state: an instance
25
+ // alternating between refusals and crashes must not launder its backoff.
26
+ return { waitMs: SUPERSEDED_RETRY_MS, next: state, rule: 'superseded-fixed-retry' };
27
+ }
28
+ if (disconnect.connectedForMs >= STABLE_RESET_MS) {
29
+ return { waitMs: BASE_DELAY_MS, next: initialBackoff, rule: 'stable-reset' };
30
+ }
31
+ const grown = Math.min(state.delayMs * 2, MAX_DELAY_MS);
32
+ return { waitMs: state.delayMs, next: { delayMs: grown }, rule: 'exponential' };
33
+ }
34
+ //# sourceMappingURL=backoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backoff.js","sourceRoot":"","sources":["../../src/machines/backoff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAE5D,wCAAwC;AACxC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,GAAG,MAAM,CAAC;AAC9C,0FAA0F;AAC1F,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AACtC,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC;AACnC,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;AAOnC,MAAM,CAAC,MAAM,cAAc,GAAiB,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;AAcvE,MAAM,UAAU,aAAa,CAAC,KAAmB,EAAE,UAAsB;IACvE,IAAI,UAAU,CAAC,SAAS,KAAK,WAAW,CAAC,kBAAkB,EAAE,CAAC;QAC5D,uEAAuE;QACvE,yEAAyE;QACzE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,wBAAwB,EAAE,CAAC;IACtF,CAAC;IACD,IAAI,UAAU,CAAC,cAAc,IAAI,eAAe,EAAE,CAAC;QACjD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAC/E,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC;IACxD,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;AAClF,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The bootstrap machine — how a client reaches `live` truthfully.
3
+ *
4
+ * Ordered-bootstrap mode (local-live-protocol.md §3): the snapshot is the
5
+ * first data frame and everything after it is ordered on the same channel,
6
+ * so the machine simply installs and follows. Legacy mode: the snapshot
7
+ * travels out-of-band, so the machine holds events while the snapshot body
8
+ * is in flight and replays only those past its seq — the full-snapshot
9
+ * barrier (§6).
10
+ *
11
+ * Feature detection (§3): a bootstrap request against a legacy engine
12
+ * yields no `snapshot` frame. The client falls back to the legacy path
13
+ * when the first data frame is a `state` event, a `ping` arrives, or the
14
+ * timeout passes — whichever comes first.
15
+ */
16
+ import type { StateEvent } from '../contracts/events.js';
17
+ import type { Snapshot } from '../contracts/snapshot.js';
18
+ import { type StreamFrame } from '../contracts/frames/stream.js';
19
+ export type BootstrapCommand =
20
+ /** Install the snapshot, then apply the events in order, then follow live from the snapshot's seq. */
21
+ {
22
+ readonly command: 'install';
23
+ readonly snapshot: Snapshot;
24
+ readonly replay: readonly StateEvent[];
25
+ }
26
+ /** The peer is legacy: fetch a REST snapshot and run the full-snapshot barrier. Buffered events are handed back. */
27
+ | {
28
+ readonly command: 'fallback-legacy';
29
+ readonly held: readonly StateEvent[];
30
+ readonly reason: 'state-before-snapshot' | 'ping-before-snapshot' | 'timeout';
31
+ }
32
+ /** Bootstrap snapshot build failed server-side; the stream is ending. Fall back to the REST path. */
33
+ | {
34
+ readonly command: 'fallback-error';
35
+ readonly status?: number;
36
+ } | {
37
+ readonly command: 'none';
38
+ };
39
+ /** One instance per bootstrap-mode connection attempt; discard after it resolves. */
40
+ export declare class BootstrapMachine {
41
+ #private;
42
+ readonly timeoutMs = 5000;
43
+ /** Feed each stream frame until a command other than `none` resolves the machine. */
44
+ accept(frame: StreamFrame): BootstrapCommand;
45
+ /** The host's timer fired without a snapshot frame. */
46
+ expire(): BootstrapCommand;
47
+ }
48
+ /**
49
+ * The legacy full-snapshot barrier (§6): hold events while a full snapshot
50
+ * body is in flight; on arrival, replay only those past its seq. Partial
51
+ * snapshots (resources added on a live connection) never pass through
52
+ * here — they hold per-resource and never bump the connection seq.
53
+ */
54
+ export declare class SnapshotBarrier {
55
+ #private;
56
+ get inFlight(): boolean;
57
+ begin(): void;
58
+ /** Returns true when the event was held (a snapshot body is in flight). */
59
+ hold(event: StateEvent): boolean;
60
+ /** The snapshot body landed: install it, then apply the returned events in order. */
61
+ complete(snapshot: Snapshot): StateEvent[];
62
+ /** The snapshot fetch failed: release nothing; the caller re-syncs. */
63
+ abandon(): void;
64
+ }
65
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/machines/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAiC,KAAK,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEhG,MAAM,MAAM,gBAAgB;AAC1B,sGAAsG;AACpG;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAA;CAAE;AACtG,oHAAoH;GAClH;IAAE,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,uBAAuB,GAAG,sBAAsB,GAAG,SAAS,CAAA;CAAE;AAC9J,qGAAqG;GACnG;IAAE,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjC,qFAAqF;AACrF,qBAAa,gBAAgB;;IAI3B,QAAQ,CAAC,SAAS,QAAiC;IAEnD,qFAAqF;IACrF,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,gBAAgB;IAoC5C,uDAAuD;IACvD,MAAM,IAAI,gBAAgB;CAO3B;AAED;;;;;GAKG;AACH,qBAAa,eAAe;;IAI1B,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,KAAK,IAAI,IAAI;IAKb,2EAA2E;IAC3E,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IAMhC,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,UAAU,EAAE;IAO1C,uEAAuE;IACvE,OAAO,IAAI,IAAI;CAIhB"}