@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,16 @@
1
+ /**
2
+ * Amalgm's default enrollment policy: which relative paths receive
3
+ * workspace identities. Ratified by entity-model.md axiom 2 — amalgm's
4
+ * manual enrollment policy decides what enrolls; external conventions
5
+ * (gitignore) may inform it, never decide it implicitly.
6
+ *
7
+ * Machine-local metadata, dependencies, generated caches, and secrets
8
+ * never receive workspace identities. The rule applies at every depth.
9
+ * Pure string policy: a host may inject its own `EnrollmentPolicy`
10
+ * everywhere this default is accepted.
11
+ */
12
+ /** The injected policy shape: relative path in, verdict out. */
13
+ export type EnrollmentPolicy = (relPath: string) => boolean;
14
+ /** The default policy. Both separators are path separators; '' never enrolls. */
15
+ export declare const defaultShouldEnroll: EnrollmentPolicy;
16
+ //# sourceMappingURL=enrollment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrollment.d.ts","sourceRoot":"","sources":["../../src/detection/enrollment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,gEAAgE;AAChE,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;AAgD5D,iFAAiF;AACjF,eAAO,MAAM,mBAAmB,EAAE,gBAMjC,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Amalgm's default enrollment policy: which relative paths receive
3
+ * workspace identities. Ratified by entity-model.md axiom 2 — amalgm's
4
+ * manual enrollment policy decides what enrolls; external conventions
5
+ * (gitignore) may inform it, never decide it implicitly.
6
+ *
7
+ * Machine-local metadata, dependencies, generated caches, and secrets
8
+ * never receive workspace identities. The rule applies at every depth.
9
+ * Pure string policy: a host may inject its own `EnrollmentPolicy`
10
+ * everywhere this default is accepted.
11
+ */
12
+ const EXCLUDED_DIRECTORIES = new Set([
13
+ '.amalgm',
14
+ '.aws',
15
+ '.cache',
16
+ '.docker',
17
+ '.git',
18
+ '.gnupg',
19
+ '.gradle',
20
+ '.hg',
21
+ '.kube',
22
+ '.mypy_cache',
23
+ '.next',
24
+ '.nyc_output',
25
+ '.parcel-cache',
26
+ '.pytest_cache',
27
+ '.ruff_cache',
28
+ '.ssh',
29
+ '.svn',
30
+ '.svelte-kit',
31
+ '.turbo',
32
+ '.venv',
33
+ '.vite',
34
+ '__pycache__',
35
+ 'coverage',
36
+ 'node_modules',
37
+ ]);
38
+ const EXCLUDED_FILES = new Set([
39
+ '.DS_Store',
40
+ 'Thumbs.db',
41
+ 'desktop.ini',
42
+ 'npm-debug.log',
43
+ 'pnpm-debug.log',
44
+ 'yarn-debug.log',
45
+ 'yarn-error.log',
46
+ ]);
47
+ function isPrivateFile(name) {
48
+ if (/^\.env(?:\..+)?$/i.test(name) && !/\.example$/i.test(name))
49
+ return true;
50
+ if (/^(?:credentials?|secrets?)\.(?:json|ya?ml|toml|ini|conf)$/i.test(name))
51
+ return true;
52
+ if (/^id_(?:dsa|ecdsa|ed25519|rsa)$/i.test(name))
53
+ return true;
54
+ if (/^(?:\.git-credentials|\.netrc|\.npmrc|\.pypirc|auth\.json|kubeconfig)$/i.test(name))
55
+ return true;
56
+ if (/^(?:service[-_]?account|firebase[-_]?adminsdk).*\.json$/i.test(name))
57
+ return true;
58
+ return /\.(?:key|keystore|kdbx|p12|pfx|pem|ppk|tfstate(?:\.backup)?)$/i.test(name);
59
+ }
60
+ /** The default policy. Both separators are path separators; '' never enrolls. */
61
+ export const defaultShouldEnroll = (relPath) => {
62
+ const parts = relPath.split(/[\\/]/).filter(Boolean);
63
+ const name = parts.at(-1);
64
+ if (name === undefined || parts.some((part) => EXCLUDED_DIRECTORIES.has(part)))
65
+ return false;
66
+ if (EXCLUDED_FILES.has(name) || isPrivateFile(name))
67
+ return false;
68
+ return !name.startsWith('.#') && !name.endsWith('~') && !/\.(?:swp|swo)$/i.test(name);
69
+ };
70
+ //# sourceMappingURL=enrollment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrollment.js","sourceRoot":"","sources":["../../src/detection/enrollment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,SAAS;IACT,MAAM;IACN,QAAQ;IACR,SAAS;IACT,MAAM;IACN,QAAQ;IACR,SAAS;IACT,KAAK;IACL,OAAO;IACP,aAAa;IACb,OAAO;IACP,aAAa;IACb,eAAe;IACf,eAAe;IACf,aAAa;IACb,MAAM;IACN,MAAM;IACN,aAAa;IACb,QAAQ;IACR,OAAO;IACP,OAAO;IACP,aAAa;IACb,UAAU;IACV,cAAc;CACf,CAAC,CAAC;AAEH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,WAAW;IACX,WAAW;IACX,aAAa;IACb,eAAe;IACf,gBAAgB;IAChB,gBAAgB;IAChB,gBAAgB;CACjB,CAAC,CAAC;AAEH,SAAS,aAAa,CAAC,IAAY;IACjC,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7E,IAAI,4DAA4D,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACzF,IAAI,iCAAiC,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9D,IAAI,yEAAyE,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtG,IAAI,0DAA0D,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACvF,OAAO,gEAAgE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrF,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,MAAM,mBAAmB,GAAqB,CAAC,OAAO,EAAE,EAAE;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7F,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAClE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxF,CAAC,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Detection — the pure cores of the Watch/Detect rails, ported from the
3
+ * engine's observer and registration boundary. Normative sources:
4
+ * entity-model.md (identity axioms, the two continuity witnesses) and
5
+ * entity-implementation.md (the ratified seams).
6
+ *
7
+ * Everything here is rows and entries in, verdicts out. Walking disk,
8
+ * hashing bytes, opening watchers, and writing stores are the host's;
9
+ * the host injects its answers (a stat, a channel row, an enrollment
10
+ * policy) and this layer owns only the laws:
11
+ *
12
+ * - `adapter-contract` the seven rails, the ratified detect socket,
13
+ * descriptor conviction, the three-state truth
14
+ * judgment, the reference adapter
15
+ * - `classify` text/binary from detect's own read evidence
16
+ * - `refusal` declined-vs-broken, named where it is raised
17
+ * - `enrollment` the default manual enrollment policy
18
+ * - `diff` the compare functions: file/dir/link identity
19
+ * - `coverage` one OS watcher per outermost tree
20
+ * - `continuity` root rescue and the undecided address
21
+ */
22
+ export * from './adapter-contract.js';
23
+ export * from './classify.js';
24
+ export * from './continuity.js';
25
+ export * from './coverage.js';
26
+ export * from './diff.js';
27
+ export * from './enrollment.js';
28
+ export * from './refusal.js';
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detection/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Detection — the pure cores of the Watch/Detect rails, ported from the
3
+ * engine's observer and registration boundary. Normative sources:
4
+ * entity-model.md (identity axioms, the two continuity witnesses) and
5
+ * entity-implementation.md (the ratified seams).
6
+ *
7
+ * Everything here is rows and entries in, verdicts out. Walking disk,
8
+ * hashing bytes, opening watchers, and writing stores are the host's;
9
+ * the host injects its answers (a stat, a channel row, an enrollment
10
+ * policy) and this layer owns only the laws:
11
+ *
12
+ * - `adapter-contract` the seven rails, the ratified detect socket,
13
+ * descriptor conviction, the three-state truth
14
+ * judgment, the reference adapter
15
+ * - `classify` text/binary from detect's own read evidence
16
+ * - `refusal` declined-vs-broken, named where it is raised
17
+ * - `enrollment` the default manual enrollment policy
18
+ * - `diff` the compare functions: file/dir/link identity
19
+ * - `coverage` one OS watcher per outermost tree
20
+ * - `continuity` root rescue and the undecided address
21
+ */
22
+ export * from './adapter-contract.js';
23
+ export * from './classify.js';
24
+ export * from './continuity.js';
25
+ export * from './coverage.js';
26
+ export * from './diff.js';
27
+ export * from './enrollment.js';
28
+ export * from './refusal.js';
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detection/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * A REFUSAL: the boundary understood the request and declined it.
3
+ * Ratified by entity-implementation.md ("A refusal is named where it is
4
+ * raised").
5
+ *
6
+ * Two things can go wrong when a caller asks for something, and they
7
+ * mean opposite things:
8
+ *
9
+ * a refusal the request named ground amalgm will not take — excluded
10
+ * by enrollment policy, already owned by another tree, not
11
+ * there at all. Nothing is broken. The message IS the
12
+ * reason and is meant to be shown to whoever asked.
13
+ * a fault the boundary could not do its job — a torn identity
14
+ * store, an unusable database, a bug. The request was
15
+ * fine; the installation is not.
16
+ *
17
+ * A refusal is NAMED WHERE IT IS RAISED, by the code that decided to
18
+ * refuse. It is never guessed later from an error's wording: matching
19
+ * on message text would quietly reclassify every fault as the caller's
20
+ * mistake the moment a message changed, and "your path is bad" is the
21
+ * worst possible thing to say on the day the identity store tears.
22
+ *
23
+ * Callers that must answer differently — an HTTP status, an exit code —
24
+ * ask `isRefusal`. Everything else stays an ordinary Error and travels
25
+ * to whatever handles faults. The mark is a registry symbol
26
+ * (`Symbol.for`), so a refusal raised by one copy of this module is
27
+ * recognized by every other.
28
+ */
29
+ /** Decline a request, with the reason the caller should be shown. */
30
+ export declare function refusal(message: string): Error;
31
+ /** True only for an error this boundary deliberately raised as a refusal. */
32
+ export declare function isRefusal(error: unknown): boolean;
33
+ //# sourceMappingURL=refusal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refusal.d.ts","sourceRoot":"","sources":["../../src/detection/refusal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,qEAAqE;AACrE,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAI9C;AAED,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEjD"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * A REFUSAL: the boundary understood the request and declined it.
3
+ * Ratified by entity-implementation.md ("A refusal is named where it is
4
+ * raised").
5
+ *
6
+ * Two things can go wrong when a caller asks for something, and they
7
+ * mean opposite things:
8
+ *
9
+ * a refusal the request named ground amalgm will not take — excluded
10
+ * by enrollment policy, already owned by another tree, not
11
+ * there at all. Nothing is broken. The message IS the
12
+ * reason and is meant to be shown to whoever asked.
13
+ * a fault the boundary could not do its job — a torn identity
14
+ * store, an unusable database, a bug. The request was
15
+ * fine; the installation is not.
16
+ *
17
+ * A refusal is NAMED WHERE IT IS RAISED, by the code that decided to
18
+ * refuse. It is never guessed later from an error's wording: matching
19
+ * on message text would quietly reclassify every fault as the caller's
20
+ * mistake the moment a message changed, and "your path is bad" is the
21
+ * worst possible thing to say on the day the identity store tears.
22
+ *
23
+ * Callers that must answer differently — an HTTP status, an exit code —
24
+ * ask `isRefusal`. Everything else stays an ordinary Error and travels
25
+ * to whatever handles faults. The mark is a registry symbol
26
+ * (`Symbol.for`), so a refusal raised by one copy of this module is
27
+ * recognized by every other.
28
+ */
29
+ const REFUSAL = Symbol.for('amalgm.registration.refusal');
30
+ /** Decline a request, with the reason the caller should be shown. */
31
+ export function refusal(message) {
32
+ const error = new Error(message);
33
+ error[REFUSAL] = true;
34
+ return error;
35
+ }
36
+ /** True only for an error this boundary deliberately raised as a refusal. */
37
+ export function isRefusal(error) {
38
+ return Boolean(error && error[REFUSAL]);
39
+ }
40
+ //# sourceMappingURL=refusal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refusal.js","sourceRoot":"","sources":["../../src/detection/refusal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,MAAM,OAAO,GAAkB,MAAM,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;AAEzE,qEAAqE;AACrE,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAAgC,CAAC;IAChE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IACtB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,OAAO,CAAC,KAAK,IAAK,KAAiC,CAAC,OAAO,CAAC,CAAC,CAAC;AACvE,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Portable byte codecs shared by the entity layer — UTF-8, standard base64
3
+ * (padded, as Node's `Buffer#toString('base64')` emits it), base64url, and
4
+ * hex. They exist so cloud.ts and repo-states.ts can produce byte-for-byte
5
+ * the same wire text the engine produces with Buffer, without src/
6
+ * importing any Node module (PURPOSE.md axiom 2).
7
+ */
8
+ export declare const utf8Encode: (text: string) => Uint8Array;
9
+ export declare const utf8Decode: (bytes: Uint8Array) => string;
10
+ /** Bytes → standard base64 with padding (Buffer's 'base64' spelling). */
11
+ export declare const bytesToBase64: (bytes: Uint8Array) => string;
12
+ /** Bytes → unpadded base64url (Buffer's 'base64url' spelling). */
13
+ export declare const bytesToBase64Url: (bytes: Uint8Array) => string;
14
+ /** Standard base64 (padded or unpadded) → bytes. */
15
+ export declare function base64ToBytes(text: string): Uint8Array;
16
+ /** Lowercase/uppercase hex → bytes. */
17
+ export declare function hexToBytes(hex: string): Uint8Array;
18
+ //# sourceMappingURL=bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../../src/entities/bytes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,UAA4C,CAAC;AAEvF,eAAO,MAAM,UAAU,GAAI,OAAO,UAAU,KAAG,MAAyC,CAAC;AAgBzF,yEAAyE;AACzE,eAAO,MAAM,aAAa,GAAI,OAAO,UAAU,KAAG,MAAqC,CAAC;AAExF,kEAAkE;AAClE,eAAO,MAAM,gBAAgB,GAAI,OAAO,UAAU,KAAG,MAA0C,CAAC;AAEhG,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAkBtD;AAED,uCAAuC;AACvC,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CASlD"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Portable byte codecs shared by the entity layer — UTF-8, standard base64
3
+ * (padded, as Node's `Buffer#toString('base64')` emits it), base64url, and
4
+ * hex. They exist so cloud.ts and repo-states.ts can produce byte-for-byte
5
+ * the same wire text the engine produces with Buffer, without src/
6
+ * importing any Node module (PURPOSE.md axiom 2).
7
+ */
8
+ const BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
9
+ const BASE64_URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
10
+ export const utf8Encode = (text) => new TextEncoder().encode(text);
11
+ export const utf8Decode = (bytes) => new TextDecoder().decode(bytes);
12
+ function encode(bytes, alphabet, pad) {
13
+ let out = '';
14
+ for (let i = 0; i < bytes.length; i += 3) {
15
+ const a = bytes[i];
16
+ const b = bytes[i + 1];
17
+ const c = bytes[i + 2];
18
+ out += alphabet[a >> 2];
19
+ out += alphabet[((a & 0x03) << 4) | ((b ?? 0) >> 4)];
20
+ out += b === undefined ? (pad ? '=' : '') : alphabet[((b & 0x0f) << 2) | ((c ?? 0) >> 6)];
21
+ out += c === undefined ? (pad ? '=' : '') : alphabet[c & 0x3f];
22
+ }
23
+ return out;
24
+ }
25
+ /** Bytes → standard base64 with padding (Buffer's 'base64' spelling). */
26
+ export const bytesToBase64 = (bytes) => encode(bytes, BASE64, true);
27
+ /** Bytes → unpadded base64url (Buffer's 'base64url' spelling). */
28
+ export const bytesToBase64Url = (bytes) => encode(bytes, BASE64_URL, false);
29
+ /** Standard base64 (padded or unpadded) → bytes. */
30
+ export function base64ToBytes(text) {
31
+ const out = [];
32
+ let buffer = 0;
33
+ let bits = 0;
34
+ for (const char of text) {
35
+ if (char === '=')
36
+ break; // padding ends the payload
37
+ const value = BASE64.indexOf(char);
38
+ if (value === -1) {
39
+ throw new Error(`expected standard base64 like "aGVsbG8=" — found ${JSON.stringify(char)}`);
40
+ }
41
+ buffer = (buffer << 6) | value;
42
+ bits += 6;
43
+ if (bits >= 8) {
44
+ bits -= 8;
45
+ out.push((buffer >> bits) & 0xff);
46
+ }
47
+ }
48
+ return new Uint8Array(out);
49
+ }
50
+ /** Lowercase/uppercase hex → bytes. */
51
+ export function hexToBytes(hex) {
52
+ if (hex.length % 2 !== 0 || /[^0-9a-f]/i.test(hex)) {
53
+ throw new Error(`expected even-length hex like "a1b2" — got ${JSON.stringify(hex)}`);
54
+ }
55
+ const out = new Uint8Array(hex.length / 2);
56
+ for (let i = 0; i < out.length; i += 1) {
57
+ out[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
58
+ }
59
+ return out;
60
+ }
61
+ //# sourceMappingURL=bytes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes.js","sourceRoot":"","sources":["../../src/entities/bytes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The entity-cloud boundary's pure half (engine
3
+ * registration/entity-cloud.js): the snapshot codec, record assertions,
4
+ * equality, the private resource id, and the repo travel law — only
5
+ * logical graph facts, never a path, inode, watcher, or database row.
6
+ *
7
+ * Wire parity is the contract here: `stableJson`, record key order, and
8
+ * snapshot sorting reproduce the engine's bytes exactly, so a snapshot
9
+ * packed on either side hashes and compares identically.
10
+ */
11
+ import { type EntityStatus, type EntityType, type Sha256Hex } from './types.js';
12
+ /** `@1` could project arbitrary pre-cloud registrations. `@2` omitted the
13
+ * declared built-in tool entities, so its toolbox root could not prove the
14
+ * snapshot membership it named. A resource contract names immutable
15
+ * authority semantics: both remain quarantined rather than reinterpreted
16
+ * or overwritten. `@3` begins with the complete verified user home; later
17
+ * user ground enters exclusively through `amalgm register`. */
18
+ export declare const ENTITY_CLOUD_CONTRACT = "amalgm-entity-registry@3";
19
+ export declare const ENTITY_CLOUD_SCHEMA_VERSION = 1;
20
+ /** The record as it travels in a cloud snapshot: the six fields, the leaf
21
+ * head, and — for repositories only — the immutable transport head naming
22
+ * the Card + Checkpoint parcel. */
23
+ export interface CloudEntityRecord {
24
+ readonly uuid: string;
25
+ readonly type: EntityType;
26
+ readonly parentUUID: string | null;
27
+ readonly name: string;
28
+ readonly status: EntityStatus;
29
+ readonly version: string;
30
+ readonly payloadVersion: string | null;
31
+ readonly transportVersion: string | null;
32
+ }
33
+ export interface CloudSnapshot {
34
+ readonly schemaVersion: number;
35
+ readonly kind: 'amalgm-entity-registry';
36
+ readonly records: readonly CloudEntityRecord[];
37
+ }
38
+ /** The deterministic private entity-resource id for a user under the
39
+ * current contract: `pvr_` + the first 32 base64url characters of
40
+ * sha256("private-user:<userId>:<contract>"). */
41
+ export declare function privateEntityResourceId(userId: string, sha256Hex: Sha256Hex): string;
42
+ /** The one JSON spelling every snapshot comparison and checksum uses. */
43
+ export declare const stableJson: (value: unknown) => string;
44
+ export declare const sameRecord: (left: unknown, right: unknown) => boolean;
45
+ /** Two record lists describe the same graph (normalized, sorted, compared whole). */
46
+ export declare const sameRecords: (left: readonly unknown[], right: readonly unknown[]) => boolean;
47
+ /** Every record in `records` appears byte-identically in `expected`. */
48
+ export declare function recordsAreSubset(records: readonly unknown[], expected: readonly unknown[]): boolean;
49
+ /**
50
+ * Validate one snapshot record and normalize it (UUIDs lowercased,
51
+ * transportVersion defaulted to null). Refusals: an invalid shape; a
52
+ * parentless record whose type no tree root wears; a transport head on
53
+ * anything but a repository.
54
+ */
55
+ export declare function assertRecord(value: unknown): CloudEntityRecord;
56
+ /** How an enclosing lookup answers: the parent record's type and its own
57
+ * parent, or null/undefined for missing ancestry. */
58
+ export type CloudAncestorLookup = (uuid: string) => {
59
+ readonly type: string;
60
+ readonly parentUUID: string | null | undefined;
61
+ } | null | undefined;
62
+ /**
63
+ * The repo travel law: a record with a `repo.git` PROPER ancestor never
64
+ * travels to the cloud on its own. The repository is the sync boundary —
65
+ * its one Card + Checkpoint state carries the worktree's bytes AND its
66
+ * children's permanent UUIDs (the transport identity map), so a register
67
+ * or a rebase is one parcel, never one postcard per file. A nested
68
+ * repository inside another repo's worktree is enclosed too: it becomes
69
+ * cloud-visible only when registered explicitly as its own tree.
70
+ * Missing ancestry keeps the record traveling rather than risking a
71
+ * silently unsynced entity.
72
+ */
73
+ export declare function enclosedByRepositoryAncestor(record: {
74
+ readonly uuid: string;
75
+ readonly parentUUID: string | null | undefined;
76
+ }, lookup: CloudAncestorLookup): boolean;
77
+ /** Normalize records into the one canonical snapshot: asserted, sorted by
78
+ * uuid, duplicates refused. */
79
+ export declare function snapshotFromRecords(records: readonly unknown[]): CloudSnapshot;
80
+ /** Parse snapshot bytes (or their UTF-8 text) back into the canonical form. */
81
+ export declare function parseSnapshot(bytes: Uint8Array | string): CloudSnapshot;
82
+ //# sourceMappingURL=cloud.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/entities/cloud.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAmC,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAGjH;;;;;+DAK+D;AAC/D,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAEhE,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAK7C;;mCAEmC;AACnC,MAAM,WAAW,iBAAiB;IAChC,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,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAChD;AAED;;iDAEiD;AACjD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,MAAM,CAGpF;AAED,yEAAyE;AACzE,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,MAA+B,CAAC;AAE5E,eAAO,MAAM,UAAU,GAAI,MAAM,OAAO,EAAE,OAAO,OAAO,KAAG,OACnB,CAAC;AAEzC,qFAAqF;AACrF,eAAO,MAAM,WAAW,GAAI,MAAM,SAAS,OAAO,EAAE,EAAE,OAAO,SAAS,OAAO,EAAE,KAAG,OACf,CAAC;AAEpE,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAMnG;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAkC9D;AAED;qDACqD;AACrD,MAAM,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,MAAM,KAC7C;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,CAAC;AAE/F;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,EACjF,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAYT;AAED;+BAC+B;AAC/B,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,GAAG,aAAa,CAW9E;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,aAAa,CAavE"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * The entity-cloud boundary's pure half (engine
3
+ * registration/entity-cloud.js): the snapshot codec, record assertions,
4
+ * equality, the private resource id, and the repo travel law — only
5
+ * logical graph facts, never a path, inode, watcher, or database row.
6
+ *
7
+ * Wire parity is the contract here: `stableJson`, record key order, and
8
+ * snapshot sorting reproduce the engine's bytes exactly, so a snapshot
9
+ * packed on either side hashes and compares identically.
10
+ */
11
+ import { ROOT_TYPES, TYPES, UUID_PATTERN } from './types.js';
12
+ import { bytesToBase64Url, hexToBytes, utf8Decode } from './bytes.js';
13
+ /** `@1` could project arbitrary pre-cloud registrations. `@2` omitted the
14
+ * declared built-in tool entities, so its toolbox root could not prove the
15
+ * snapshot membership it named. A resource contract names immutable
16
+ * authority semantics: both remain quarantined rather than reinterpreted
17
+ * or overwritten. `@3` begins with the complete verified user home; later
18
+ * user ground enters exclusively through `amalgm register`. */
19
+ export const ENTITY_CLOUD_CONTRACT = 'amalgm-entity-registry@3';
20
+ export const ENTITY_CLOUD_SCHEMA_VERSION = 1;
21
+ /** A 64-hex content head (a SHA-256 naming immutable bytes). */
22
+ const CONTENT_HEAD = /^[0-9a-f]{64}$/;
23
+ /** The deterministic private entity-resource id for a user under the
24
+ * current contract: `pvr_` + the first 32 base64url characters of
25
+ * sha256("private-user:<userId>:<contract>"). */
26
+ export function privateEntityResourceId(userId, sha256Hex) {
27
+ return `pvr_${bytesToBase64Url(hexToBytes(sha256Hex(`private-user:${userId}:${ENTITY_CLOUD_CONTRACT}`)))
28
+ .slice(0, 32)}`;
29
+ }
30
+ /** The one JSON spelling every snapshot comparison and checksum uses. */
31
+ export const stableJson = (value) => JSON.stringify(value);
32
+ export const sameRecord = (left, right) => stableJson(left) === stableJson(right);
33
+ /** Two record lists describe the same graph (normalized, sorted, compared whole). */
34
+ export const sameRecords = (left, right) => sameRecord(snapshotFromRecords(left), snapshotFromRecords(right));
35
+ /** Every record in `records` appears byte-identically in `expected`. */
36
+ export function recordsAreSubset(records, expected) {
37
+ const expectedByUuid = new Map(snapshotFromRecords(expected).records.map((record) => [record.uuid, record]));
38
+ return snapshotFromRecords(records).records
39
+ .every((record) => sameRecord(record, expectedByUuid.get(record.uuid)));
40
+ }
41
+ /**
42
+ * Validate one snapshot record and normalize it (UUIDs lowercased,
43
+ * transportVersion defaulted to null). Refusals: an invalid shape; a
44
+ * parentless record whose type no tree root wears; a transport head on
45
+ * anything but a repository.
46
+ */
47
+ export function assertRecord(value) {
48
+ const record = value;
49
+ if (!record || typeof record !== 'object'
50
+ || typeof record.uuid !== 'string' || !UUID_PATTERN.test(record.uuid)
51
+ || typeof record.type !== 'string' || !TYPES.has(record.type)
52
+ || (record.parentUUID !== null && (typeof record.parentUUID !== 'string' || !UUID_PATTERN.test(record.parentUUID)))
53
+ || typeof record.name !== 'string' || !record.name || record.name.includes('/') || record.name.includes('\0')
54
+ || !['active', 'trashed', 'deleted'].includes(record.status)
55
+ || typeof record.version !== 'string' || !/^[0-9a-f]{64}$/.test(record.version)
56
+ || (record.payloadVersion !== null && typeof record.payloadVersion !== 'string')
57
+ || (record.transportVersion !== undefined && record.transportVersion !== null
58
+ && (typeof record.transportVersion !== 'string' || !CONTENT_HEAD.test(record.transportVersion)))) {
59
+ throw new Error('cloud entity snapshot has an invalid record');
60
+ }
61
+ if (record.parentUUID === null && !ROOT_TYPES.has(record.type)) {
62
+ throw new Error(`cloud entity ${record.uuid} is not a valid tree root`);
63
+ }
64
+ const transportVersion = (record.transportVersion ?? null);
65
+ if (record.type !== 'repo.git' && transportVersion !== null) {
66
+ throw new Error('only repository entities may declare a transport head');
67
+ }
68
+ return {
69
+ uuid: record.uuid.toLowerCase(),
70
+ type: record.type,
71
+ parentUUID: record.parentUUID === null ? null : record.parentUUID.toLowerCase(),
72
+ name: record.name,
73
+ status: record.status,
74
+ version: record.version,
75
+ payloadVersion: record.payloadVersion,
76
+ transportVersion,
77
+ };
78
+ }
79
+ /**
80
+ * The repo travel law: a record with a `repo.git` PROPER ancestor never
81
+ * travels to the cloud on its own. The repository is the sync boundary —
82
+ * its one Card + Checkpoint state carries the worktree's bytes AND its
83
+ * children's permanent UUIDs (the transport identity map), so a register
84
+ * or a rebase is one parcel, never one postcard per file. A nested
85
+ * repository inside another repo's worktree is enclosed too: it becomes
86
+ * cloud-visible only when registered explicitly as its own tree.
87
+ * Missing ancestry keeps the record traveling rather than risking a
88
+ * silently unsynced entity.
89
+ */
90
+ export function enclosedByRepositoryAncestor(record, lookup) {
91
+ const seen = new Set([record.uuid]);
92
+ let parentUUID = record.parentUUID;
93
+ while (parentUUID !== null && parentUUID !== undefined) {
94
+ if (seen.has(parentUUID))
95
+ throw new Error(`cloud entity ${record.uuid} has a cyclic parent chain`);
96
+ seen.add(parentUUID);
97
+ const parent = lookup(parentUUID);
98
+ if (!parent)
99
+ return false;
100
+ if (parent.type === 'repo.git')
101
+ return true;
102
+ parentUUID = parent.parentUUID;
103
+ }
104
+ return false;
105
+ }
106
+ /** Normalize records into the one canonical snapshot: asserted, sorted by
107
+ * uuid, duplicates refused. */
108
+ export function snapshotFromRecords(records) {
109
+ const normalized = records.map(assertRecord)
110
+ .sort((left, right) => (left.uuid < right.uuid ? -1 : left.uuid > right.uuid ? 1 : 0));
111
+ if (new Set(normalized.map((record) => record.uuid)).size !== normalized.length) {
112
+ throw new Error('cloud entity snapshot has duplicate UUIDs');
113
+ }
114
+ return {
115
+ schemaVersion: ENTITY_CLOUD_SCHEMA_VERSION,
116
+ kind: 'amalgm-entity-registry',
117
+ records: normalized,
118
+ };
119
+ }
120
+ /** Parse snapshot bytes (or their UTF-8 text) back into the canonical form. */
121
+ export function parseSnapshot(bytes) {
122
+ let snapshot;
123
+ try {
124
+ snapshot = JSON.parse(typeof bytes === 'string' ? bytes : utf8Decode(bytes));
125
+ }
126
+ catch {
127
+ throw new Error('cloud entity snapshot is not JSON');
128
+ }
129
+ if (snapshot?.schemaVersion !== ENTITY_CLOUD_SCHEMA_VERSION
130
+ || snapshot?.kind !== 'amalgm-entity-registry'
131
+ || !Array.isArray(snapshot.records)) {
132
+ throw new Error('cloud entity snapshot has an unsupported shape');
133
+ }
134
+ return snapshotFromRecords(snapshot.records);
135
+ }
136
+ //# sourceMappingURL=cloud.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud.js","sourceRoot":"","sources":["../../src/entities/cloud.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * entities/ — the Register/Record pure cores: the entity model's laws
3
+ * (engine docs/entity-model.md — two axioms, the six-field record) as
4
+ * portable functions. Store reads arrive through `EntityReadPort`, hashing
5
+ * through `Sha256Hex`; nothing here touches SQLite, node:crypto, or a
6
+ * filesystem. Hash formulas and id derivations are byte-for-byte the
7
+ * engine's, so records interoperate across the cloud boundary.
8
+ *
9
+ * - types.ts the alphabet, the six fields, UUID shape, injected ports
10
+ * - bytes.ts portable byte codecs (utf8, base64, base64url, hex)
11
+ * - rules.ts version formula, naming, lifecycle inheritance,
12
+ * slot/container laws, record builders
13
+ * - moves.ts batch move validation: permutations, acyclicity, adoption
14
+ * - cloud.ts entity-cloud snapshot codec + the repo travel law
15
+ * - repo-states.ts Card + Checkpoint state codec and id derivations
16
+ */
17
+ export * from './types.js';
18
+ export * from './bytes.js';
19
+ export * from './rules.js';
20
+ export * from './moves.js';
21
+ export * from './cloud.js';
22
+ export * from './repo-states.js';
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/entities/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * entities/ — the Register/Record pure cores: the entity model's laws
3
+ * (engine docs/entity-model.md — two axioms, the six-field record) as
4
+ * portable functions. Store reads arrive through `EntityReadPort`, hashing
5
+ * through `Sha256Hex`; nothing here touches SQLite, node:crypto, or a
6
+ * filesystem. Hash formulas and id derivations are byte-for-byte the
7
+ * engine's, so records interoperate across the cloud boundary.
8
+ *
9
+ * - types.ts the alphabet, the six fields, UUID shape, injected ports
10
+ * - bytes.ts portable byte codecs (utf8, base64, base64url, hex)
11
+ * - rules.ts version formula, naming, lifecycle inheritance,
12
+ * slot/container laws, record builders
13
+ * - moves.ts batch move validation: permutations, acyclicity, adoption
14
+ * - cloud.ts entity-cloud snapshot codec + the repo travel law
15
+ * - repo-states.ts Card + Checkpoint state codec and id derivations
16
+ */
17
+ export * from './types.js';
18
+ export * from './bytes.js';
19
+ export * from './rules.js';
20
+ export * from './moves.js';
21
+ export * from './cloud.js';
22
+ export * from './repo-states.js';
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/entities/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC"}