@degenerate/sharedata 0.2.7 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +31 -0
  2. package/dist/index.d.ts +16 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +20 -0
  5. package/dist/manager/share-data-manager-events.d.ts +27 -0
  6. package/dist/manager/share-data-manager-events.d.ts.map +1 -0
  7. package/dist/manager/share-data-manager-events.js +2 -0
  8. package/dist/manager/share-data-manager.d.ts +84 -0
  9. package/dist/manager/share-data-manager.d.ts.map +1 -0
  10. package/dist/manager/share-data-manager.js +210 -0
  11. package/dist/persistence/block-factory-registry.d.ts +51 -0
  12. package/dist/persistence/block-factory-registry.d.ts.map +1 -0
  13. package/dist/persistence/block-factory-registry.js +36 -0
  14. package/dist/persistence/deserialize-share-data.d.ts +18 -0
  15. package/dist/persistence/deserialize-share-data.d.ts.map +1 -0
  16. package/dist/persistence/deserialize-share-data.js +144 -0
  17. package/dist/persistence/file-share-data-repository.d.ts +30 -0
  18. package/dist/persistence/file-share-data-repository.d.ts.map +1 -0
  19. package/dist/persistence/file-share-data-repository.js +147 -0
  20. package/dist/persistence/firestore-share-data-repository.d.ts +38 -0
  21. package/dist/persistence/firestore-share-data-repository.d.ts.map +1 -0
  22. package/dist/persistence/firestore-share-data-repository.js +78 -0
  23. package/dist/persistence/in-memory-share-data-repository.d.ts +19 -0
  24. package/dist/persistence/in-memory-share-data-repository.d.ts.map +1 -0
  25. package/dist/persistence/in-memory-share-data-repository.js +48 -0
  26. package/dist/persistence/serialize-share-data.d.ts +22 -0
  27. package/dist/persistence/serialize-share-data.d.ts.map +1 -0
  28. package/dist/persistence/serialize-share-data.js +62 -0
  29. package/dist/persistence/share-data-repository.d.ts +49 -0
  30. package/dist/persistence/share-data-repository.d.ts.map +1 -0
  31. package/dist/persistence/share-data-repository.js +2 -0
  32. package/dist/share-data/creation/create-share-data-initial-crypto.d.ts +11 -0
  33. package/dist/share-data/creation/create-share-data-initial-crypto.d.ts.map +1 -0
  34. package/dist/share-data/creation/create-share-data-initial-crypto.js +26 -0
  35. package/dist/share-data/helpers/calculate-share-data-string.d.ts +21 -0
  36. package/dist/share-data/helpers/calculate-share-data-string.d.ts.map +1 -0
  37. package/dist/share-data/helpers/calculate-share-data-string.js +71 -0
  38. package/dist/share-data/helpers/config/default-share-data-string.config.d.ts +7 -0
  39. package/dist/share-data/helpers/config/default-share-data-string.config.d.ts.map +1 -0
  40. package/dist/share-data/helpers/config/default-share-data-string.config.js +25 -0
  41. package/dist/share-data/helpers/config/stringify.d.ts +5 -0
  42. package/dist/share-data/helpers/config/stringify.d.ts.map +1 -0
  43. package/dist/share-data/helpers/config/stringify.js +10 -0
  44. package/dist/share-data/helpers/get-array-string.d.ts +6 -0
  45. package/dist/share-data/helpers/get-array-string.d.ts.map +1 -0
  46. package/dist/share-data/helpers/get-array-string.js +17 -0
  47. package/dist/share-data/proofs/creation/build-transaction-proposal-signer.d.ts +57 -0
  48. package/dist/share-data/proofs/creation/build-transaction-proposal-signer.d.ts.map +1 -0
  49. package/dist/share-data/proofs/creation/build-transaction-proposal-signer.js +36 -0
  50. package/dist/share-data/proofs/creation/create-share-data-proposal-proof.d.ts +12 -0
  51. package/dist/share-data/proofs/creation/create-share-data-proposal-proof.d.ts.map +1 -0
  52. package/dist/share-data/proofs/creation/create-share-data-proposal-proof.js +41 -0
  53. package/dist/share-data/proofs/creation/create-transaction-proposal-proof.d.ts +27 -0
  54. package/dist/share-data/proofs/creation/create-transaction-proposal-proof.d.ts.map +1 -0
  55. package/dist/share-data/proofs/creation/create-transaction-proposal-proof.js +58 -0
  56. package/dist/share-data/proofs/helpers/create-share-data-string-to-sign.d.ts +12 -0
  57. package/dist/share-data/proofs/helpers/create-share-data-string-to-sign.d.ts.map +1 -0
  58. package/dist/share-data/proofs/helpers/create-share-data-string-to-sign.js +17 -0
  59. package/dist/share-data/proofs/helpers/create-transaction-proposal-string-to-sign.d.ts +24 -0
  60. package/dist/share-data/proofs/helpers/create-transaction-proposal-string-to-sign.d.ts.map +1 -0
  61. package/dist/share-data/proofs/helpers/create-transaction-proposal-string-to-sign.js +29 -0
  62. package/dist/share-data/proofs/helpers/get-previous-hash-from-share-data.d.ts +9 -0
  63. package/dist/share-data/proofs/helpers/get-previous-hash-from-share-data.d.ts.map +1 -0
  64. package/dist/share-data/proofs/helpers/get-previous-hash-from-share-data.js +28 -0
  65. package/dist/share-data/proofs/helpers/hash-proposed-state.d.ts +12 -0
  66. package/dist/share-data/proofs/helpers/hash-proposed-state.d.ts.map +1 -0
  67. package/dist/share-data/proofs/helpers/hash-proposed-state.js +18 -0
  68. package/dist/share-data/proofs/testing/test-proof-signer.d.ts +53 -0
  69. package/dist/share-data/proofs/testing/test-proof-signer.d.ts.map +1 -0
  70. package/dist/share-data/proofs/testing/test-proof-signer.js +113 -0
  71. package/dist/share-data/proofs/verification/verify-share-data-proposal-proof.d.ts +40 -0
  72. package/dist/share-data/proofs/verification/verify-share-data-proposal-proof.d.ts.map +1 -0
  73. package/dist/share-data/proofs/verification/verify-share-data-proposal-proof.js +126 -0
  74. package/dist/share-data/proofs/verification/verify-transaction-proposal-proof.d.ts +37 -0
  75. package/dist/share-data/proofs/verification/verify-transaction-proposal-proof.d.ts.map +1 -0
  76. package/dist/share-data/proofs/verification/verify-transaction-proposal-proof.js +125 -0
  77. package/dist/share-data/share-data.d.ts +180 -27
  78. package/dist/share-data/share-data.d.ts.map +1 -1
  79. package/dist/share-data/share-data.js +303 -60
  80. package/package.json +31 -13
package/README.md CHANGED
@@ -8,6 +8,7 @@ The `@degenerate/sharedata` package is a core component of the SAFE system, resp
8
8
  ## Contents
9
9
 
10
10
  1. [Installation](#installation)
11
+ 2. [Persistence](#persistence)
11
12
 
12
13
 
13
14
  ## Installation
@@ -17,3 +18,33 @@ To install the `@degenerate/sharedata` package, use the following command:
17
18
  ```bash
18
19
  npm install @degenerate/sharedata
19
20
  ```
21
+
22
+ ## Persistence
23
+
24
+ `ShareData` state is **durable** — it survives a process restart. A
25
+ `ShareDataManager` constructed with a `ShareDataRepository` hydrates its blocks
26
+ on `await manager.hydrate()` and write-through-persists every `addShareData` /
27
+ `applyTransaction` / `removeShareDataById`. Constructed with no repository it
28
+ behaves exactly as before (in-memory only), so existing callers are untouched.
29
+
30
+ Loads are a **trust gate**, never a passthrough: each snapshot is replayed
31
+ through `deserializeShareData`, which re-verifies the creation signature, the
32
+ full structural-proof chain, and an integrity cross-check against the stored
33
+ `expected*` values. A snapshot edited out-of-band fails loudly instead of
34
+ loading silently. Reconstruction needs the block-type builders registered
35
+ first — call `registerShareBlockFactories()` from `@degenerate/shareblock`
36
+ during start-up.
37
+
38
+ Three interchangeable implementations of the `ShareDataRepository` interface
39
+ ship here:
40
+
41
+ | Repository | Backing store | Typical use |
42
+ |---|---|---|
43
+ | `FileShareDataRepository` | one JSON file per block (atomic temp-file + rename writes) | single-node durability with no external service |
44
+ | `FirestoreShareDataRepository` | one Firestore document per block | hosted/multi-node deployments |
45
+ | `InMemoryShareDataRepository` | an in-process `Map` | tests and parity (still round-trips the trust gate) |
46
+
47
+ `firebase-admin` is an **optional peer dependency** — only install it if you
48
+ use `FirestoreShareDataRepository`. The repository takes an injected
49
+ `firestore.Firestore` instance (the host initializes its own app); the package
50
+ never references `firebase-admin` at runtime.
package/dist/index.d.ts CHANGED
@@ -1,2 +1,18 @@
1
+ export * from './manager/share-data-manager';
2
+ export * from './manager/share-data-manager-events';
3
+ export * from './persistence/block-factory-registry';
4
+ export * from './persistence/serialize-share-data';
5
+ export * from './persistence/deserialize-share-data';
6
+ export * from './persistence/share-data-repository';
7
+ export * from './persistence/file-share-data-repository';
8
+ export * from './persistence/firestore-share-data-repository';
9
+ export * from './persistence/in-memory-share-data-repository';
1
10
  export * from './share-data/share-data';
11
+ export * from './share-data/creation/create-share-data-initial-crypto';
12
+ export * from './share-data/proofs/creation/create-share-data-proposal-proof';
13
+ export * from './share-data/proofs/creation/create-transaction-proposal-proof';
14
+ export * from './share-data/proofs/creation/build-transaction-proposal-signer';
15
+ export * from './share-data/proofs/verification/verify-share-data-proposal-proof';
16
+ export * from './share-data/proofs/verification/verify-transaction-proposal-proof';
17
+ export * from './share-data/proofs/testing/test-proof-signer';
2
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,oCAAoC,CAAC;AACnD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,+CAA+C,CAAC;AAC9D,cAAc,yBAAyB,CAAC;AACxC,cAAc,wDAAwD,CAAC;AACvE,cAAc,+DAA+D,CAAC;AAC9E,cAAc,gEAAgE,CAAC;AAC/E,cAAc,gEAAgE,CAAC;AAC/E,cAAc,mEAAmE,CAAC;AAClF,cAAc,oEAAoE,CAAC;AAKnF,cAAc,+CAA+C,CAAC"}
package/dist/index.js CHANGED
@@ -14,4 +14,24 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./manager/share-data-manager"), exports);
18
+ __exportStar(require("./manager/share-data-manager-events"), exports);
19
+ __exportStar(require("./persistence/block-factory-registry"), exports);
20
+ __exportStar(require("./persistence/serialize-share-data"), exports);
21
+ __exportStar(require("./persistence/deserialize-share-data"), exports);
22
+ __exportStar(require("./persistence/share-data-repository"), exports);
23
+ __exportStar(require("./persistence/file-share-data-repository"), exports);
24
+ __exportStar(require("./persistence/firestore-share-data-repository"), exports);
25
+ __exportStar(require("./persistence/in-memory-share-data-repository"), exports);
17
26
  __exportStar(require("./share-data/share-data"), exports);
27
+ __exportStar(require("./share-data/creation/create-share-data-initial-crypto"), exports);
28
+ __exportStar(require("./share-data/proofs/creation/create-share-data-proposal-proof"), exports);
29
+ __exportStar(require("./share-data/proofs/creation/create-transaction-proposal-proof"), exports);
30
+ __exportStar(require("./share-data/proofs/creation/build-transaction-proposal-signer"), exports);
31
+ __exportStar(require("./share-data/proofs/verification/verify-share-data-proposal-proof"), exports);
32
+ __exportStar(require("./share-data/proofs/verification/verify-transaction-proposal-proof"), exports);
33
+ // Test-only signing helpers. Naming convention (`generateTest*`,
34
+ // `createTestProofFor`) is the documentation — these are not for
35
+ // production use. Production wiring lives in
36
+ // `buildEllipticalCurvesProofFor` from `@degenerate/shareblock`.
37
+ __exportStar(require("./share-data/proofs/testing/test-proof-signer"), exports);
@@ -0,0 +1,27 @@
1
+ import { IShareData, IShareFunction } from '@degenerate/generic';
2
+ export type ShareDataManagerEventType = 'share-data:added' | 'share-data:updated' | 'share-data:removed' | 'share-data:transaction';
3
+ export interface ShareDataAddedEvent {
4
+ type: 'share-data:added';
5
+ shareDataId: string;
6
+ currentState: IShareData;
7
+ }
8
+ export interface ShareDataUpdatedEvent {
9
+ type: 'share-data:updated';
10
+ shareDataId: string;
11
+ currentState: IShareData;
12
+ }
13
+ export interface ShareDataRemovedEvent {
14
+ type: 'share-data:removed';
15
+ shareDataId: string;
16
+ }
17
+ export interface ShareDataTransactionEvent {
18
+ type: 'share-data:transaction';
19
+ shareDataId: string;
20
+ transactionId: string;
21
+ accepted: boolean;
22
+ currentState: IShareData;
23
+ transactionFunction: IShareFunction<any, (...args: any[]) => any, any>;
24
+ }
25
+ export type ShareDataManagerEvent = ShareDataAddedEvent | ShareDataUpdatedEvent | ShareDataRemovedEvent | ShareDataTransactionEvent;
26
+ export type ShareDataManagerListener<E extends ShareDataManagerEvent = ShareDataManagerEvent> = (event: E) => void;
27
+ //# sourceMappingURL=share-data-manager-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"share-data-manager-events.d.ts","sourceRoot":"","sources":["../../src/manager/share-data-manager-events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEjE,MAAM,MAAM,yBAAyB,GAC/B,kBAAkB,GAClB,oBAAoB,GACpB,oBAAoB,GACpB,wBAAwB,CAAC;AAE/B,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,kBAAkB,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,UAAU,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,UAAU,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,yBAAyB;IACtC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,UAAU,CAAC;IACzB,mBAAmB,EAAE,cAAc,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,GAAG,CAAC,CAAC;CAC1E;AAED,MAAM,MAAM,qBAAqB,GAC3B,mBAAmB,GACnB,qBAAqB,GACrB,qBAAqB,GACrB,yBAAyB,CAAC;AAEhC,MAAM,MAAM,wBAAwB,CAAC,CAAC,SAAS,qBAAqB,GAAG,qBAAqB,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,84 @@
1
+ import { IShareData, IShareDataCryptoProof, IShareFunction, ShareDataCreationRecord } from '@degenerate/generic';
2
+ import { ShareData } from '../share-data/share-data';
3
+ import { ShareDataRepository } from '../persistence/share-data-repository';
4
+ import { ShareDataManagerEventType, ShareDataManagerListener } from './share-data-manager-events';
5
+ export declare class ShareDataManager {
6
+ private _shareDataObjects;
7
+ private _emitter;
8
+ private readonly _repository?;
9
+ private _persistence;
10
+ /**
11
+ * @param repository optional durable store. When supplied, blocks added
12
+ * with a creation record are persisted and every subsequent mutation
13
+ * writes through; call {@link hydrate} once at startup to reload them.
14
+ * The no-arg form stays purely in-memory, so existing callers/tests are
15
+ * untouched.
16
+ */
17
+ constructor(repository?: ShareDataRepository);
18
+ /**
19
+ * Loads every durably-stored block into memory, re-verifying each through
20
+ * the trust gate, and recovers its per-block persistence state so later
21
+ * transactions keep writing through. A no-op when no repository was
22
+ * supplied. Call once at startup, before serving traffic. Throws if a
23
+ * stored snapshot fails verification or collides with an already-registered
24
+ * id.
25
+ */
26
+ hydrate(): Promise<void>;
27
+ /**
28
+ * Registers a block and, when a {@link ShareDataCreationRecord} is supplied
29
+ * and a repository is configured, durably persists it. The record carries
30
+ * the two things a live block cannot reproduce on its own — the block type
31
+ * and the factory creation config — which the manager needs to keep
32
+ * re-serializing the block as transactions accrue. Without a record (or
33
+ * without a repository) the block is in-memory only.
34
+ *
35
+ * Persists before registering: a durable-write failure rejects and the
36
+ * block never enters the in-memory set, so memory and store cannot diverge.
37
+ */
38
+ addShareData(shareData: ShareData, creationRecord?: ShareDataCreationRecord): Promise<void>;
39
+ getShareDataById(id: string): ShareData | undefined;
40
+ updateShareData(shareData: ShareData): void;
41
+ /**
42
+ * Removes a block and, when it was persisted, deletes its durable snapshot
43
+ * first so a delete that cannot be recorded rejects before memory changes.
44
+ */
45
+ removeShareDataById(id: string): Promise<void>;
46
+ getShareData(): ShareData[];
47
+ getShareDataData(): IShareData[];
48
+ /**
49
+ * Returns the current state of the ShareData with the given id. Throws
50
+ * {@link ShareDataNotFoundError} when no ShareData is registered under
51
+ * that id — i.e., the return is never `undefined`. Callers that need a
52
+ * "lookup or null" shape should use {@link getShareDataById} instead.
53
+ */
54
+ getCurrentShareDataState(id: string): IShareData;
55
+ /**
56
+ * Proposes a transaction against the ShareData identified by `id`. The
57
+ * `proof` must cryptographically authorize moving the block to exactly
58
+ * `proposedData` via `transactionFunction` — it is verified by
59
+ * `ShareData.addTransaction` before the rule engine runs, so an unsigned or
60
+ * mis-signed proposal never reaches the rules or mutates state. `proof`
61
+ * is required precisely so nothing gets in without a signature: this is the
62
+ * canonical mutation entry point (the realtime propose handler routes
63
+ * here), and there is deliberately no unsigned variant on it.
64
+ *
65
+ * Once authorized, the proposal is judged by `startRuleEvaluation`;
66
+ * `_currentState` is replaced only if accepted. When the block is
67
+ * persisted, the appended transaction is written through before the event
68
+ * is emitted — a durable-write failure rejects rather than silently
69
+ * advancing only memory. Either way a transaction event is emitted with the
70
+ * outcome so observers can react.
71
+ *
72
+ * Library-internal callers that operate before the signing boundary (replay,
73
+ * seeding) use `ShareData.addTransactionNotValidated` directly; that path
74
+ * bypasses both the proof check and the emitter.
75
+ */
76
+ applyTransaction(id: string, proposedData: IShareData, transactionFunction: IShareFunction<any, (...args: any[]) => any, any>, proof: IShareDataCryptoProof): Promise<{
77
+ accepted: boolean;
78
+ transactionId: string;
79
+ }>;
80
+ on(type: ShareDataManagerEventType, listener: ShareDataManagerListener): void;
81
+ off(type: ShareDataManagerEventType, listener: ShareDataManagerListener): void;
82
+ private _emit;
83
+ }
84
+ //# sourceMappingURL=share-data-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"share-data-manager.d.ts","sourceRoot":"","sources":["../../src/manager/share-data-manager.ts"],"names":[],"mappings":"AACA,OAAO,EACH,UAAU,EACV,qBAAqB,EACrB,cAAc,EAGd,uBAAuB,EAG1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAGrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAEH,yBAAyB,EACzB,wBAAwB,EAC3B,MAAM,6BAA6B,CAAC;AAmBrC,qBAAa,gBAAgB;IACzB,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAsB;IACnD,OAAO,CAAC,YAAY,CAAgC;IAEpD;;;;;;OAMG;gBACS,UAAU,CAAC,EAAE,mBAAmB;IAO5C;;;;;;;OAOG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB9B;;;;;;;;;;OAUG;IACG,YAAY,CACd,SAAS,EAAE,SAAS,EACpB,cAAc,CAAC,EAAE,uBAAuB,GACzC,OAAO,CAAC,IAAI,CAAC;IA+BhB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAInD,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAkB3C;;;OAGG;IACG,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpD,YAAY,IAAI,SAAS,EAAE;IAI3B,gBAAgB,IAAI,UAAU,EAAE;IAIhC;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU;IAQhD;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,gBAAgB,CAClB,EAAE,EAAE,MAAM,EACV,YAAY,EAAE,UAAU,EACxB,mBAAmB,EAAE,cAAc,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,GAAG,CAAC,EACtE,KAAK,EAAE,qBAAqB,GAC7B,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAmDxD,EAAE,CAAC,IAAI,EAAE,yBAAyB,EAAE,QAAQ,EAAE,wBAAwB,GAAG,IAAI;IAI7E,GAAG,CAAC,IAAI,EAAE,yBAAyB,EAAE,QAAQ,EAAE,wBAAwB,GAAG,IAAI;IAI9E,OAAO,CAAC,KAAK;CAGhB"}
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ShareDataManager = void 0;
4
+ const events_1 = require("events");
5
+ const generic_1 = require("@degenerate/generic");
6
+ const deserialize_share_data_1 = require("../persistence/deserialize-share-data");
7
+ const serialize_share_data_1 = require("../persistence/serialize-share-data");
8
+ class ShareDataManager {
9
+ /**
10
+ * @param repository optional durable store. When supplied, blocks added
11
+ * with a creation record are persisted and every subsequent mutation
12
+ * writes through; call {@link hydrate} once at startup to reload them.
13
+ * The no-arg form stays purely in-memory, so existing callers/tests are
14
+ * untouched.
15
+ */
16
+ constructor(repository) {
17
+ this._shareDataObjects = [];
18
+ this._emitter = new events_1.EventEmitter();
19
+ this._repository = repository;
20
+ this._persistence = new Map();
21
+ }
22
+ /**
23
+ * Loads every durably-stored block into memory, re-verifying each through
24
+ * the trust gate, and recovers its per-block persistence state so later
25
+ * transactions keep writing through. A no-op when no repository was
26
+ * supplied. Call once at startup, before serving traffic. Throws if a
27
+ * stored snapshot fails verification or collides with an already-registered
28
+ * id.
29
+ */
30
+ async hydrate() {
31
+ if (!this._repository) {
32
+ return;
33
+ }
34
+ const snapshots = await this._repository.loadAllSnapshots();
35
+ for (const snapshot of snapshots) {
36
+ // The trust gate: a tampered snapshot throws here rather than being
37
+ // loaded. The executable block and the recovered persistence state
38
+ // are rebuilt from the same bytes.
39
+ const block = (0, deserialize_share_data_1.deserializeShareData)(snapshot);
40
+ if (this.getShareDataById(block.id)) {
41
+ throw new generic_1.ShareDataAlreadyExistsError(block.id);
42
+ }
43
+ this._shareDataObjects.push(block);
44
+ this._persistence.set(block.id, {
45
+ blockType: snapshot.blockType,
46
+ creationConfig: snapshot.creationConfig,
47
+ transactionLog: [...snapshot.transactionLog],
48
+ });
49
+ }
50
+ }
51
+ /**
52
+ * Registers a block and, when a {@link ShareDataCreationRecord} is supplied
53
+ * and a repository is configured, durably persists it. The record carries
54
+ * the two things a live block cannot reproduce on its own — the block type
55
+ * and the factory creation config — which the manager needs to keep
56
+ * re-serializing the block as transactions accrue. Without a record (or
57
+ * without a repository) the block is in-memory only.
58
+ *
59
+ * Persists before registering: a durable-write failure rejects and the
60
+ * block never enters the in-memory set, so memory and store cannot diverge.
61
+ */
62
+ async addShareData(shareData, creationRecord) {
63
+ const existingShareData = this.getShareDataById(shareData.id);
64
+ if (existingShareData) {
65
+ throw new generic_1.ShareDataAlreadyExistsError(shareData.id);
66
+ }
67
+ if (this._repository && creationRecord) {
68
+ const persistence = {
69
+ blockType: creationRecord.blockType,
70
+ creationConfig: creationRecord.creationConfig,
71
+ transactionLog: [],
72
+ };
73
+ await this._repository.save((0, serialize_share_data_1.serializeShareData)(persistence.blockType, persistence.creationConfig, shareData, persistence.transactionLog));
74
+ this._persistence.set(shareData.id, persistence);
75
+ }
76
+ this._shareDataObjects.push(shareData);
77
+ this._emit({
78
+ type: 'share-data:added',
79
+ shareDataId: shareData.id,
80
+ currentState: shareData.currentState,
81
+ });
82
+ }
83
+ getShareDataById(id) {
84
+ return this._shareDataObjects.find((shareData) => shareData.id === id);
85
+ }
86
+ updateShareData(shareData) {
87
+ const existingShareData = this.getShareDataById(shareData.id);
88
+ if (!existingShareData) {
89
+ throw new generic_1.ShareDataNotFoundError(shareData.id);
90
+ }
91
+ this._shareDataObjects = this._shareDataObjects.map((sd) => {
92
+ if (sd.id === shareData.id) {
93
+ return shareData;
94
+ }
95
+ return sd;
96
+ });
97
+ this._emit({
98
+ type: 'share-data:updated',
99
+ shareDataId: shareData.id,
100
+ currentState: shareData.currentState,
101
+ });
102
+ }
103
+ /**
104
+ * Removes a block and, when it was persisted, deletes its durable snapshot
105
+ * first so a delete that cannot be recorded rejects before memory changes.
106
+ */
107
+ async removeShareDataById(id) {
108
+ const existingShareData = this.getShareDataById(id);
109
+ if (!existingShareData) {
110
+ throw new generic_1.ShareDataNotFoundError(id);
111
+ }
112
+ if (this._repository && this._persistence.has(id)) {
113
+ await this._repository.remove(id);
114
+ }
115
+ this._persistence.delete(id);
116
+ this._shareDataObjects = this._shareDataObjects.filter((shareData) => shareData.id !== id);
117
+ this._emit({
118
+ type: 'share-data:removed',
119
+ shareDataId: id,
120
+ });
121
+ }
122
+ getShareData() {
123
+ return this._shareDataObjects;
124
+ }
125
+ getShareDataData() {
126
+ return this._shareDataObjects.map((shareData) => shareData.currentState);
127
+ }
128
+ /**
129
+ * Returns the current state of the ShareData with the given id. Throws
130
+ * {@link ShareDataNotFoundError} when no ShareData is registered under
131
+ * that id — i.e., the return is never `undefined`. Callers that need a
132
+ * "lookup or null" shape should use {@link getShareDataById} instead.
133
+ */
134
+ getCurrentShareDataState(id) {
135
+ const shareData = this.getShareDataById(id);
136
+ if (!shareData) {
137
+ throw new generic_1.ShareDataNotFoundError(id);
138
+ }
139
+ return shareData.currentState;
140
+ }
141
+ /**
142
+ * Proposes a transaction against the ShareData identified by `id`. The
143
+ * `proof` must cryptographically authorize moving the block to exactly
144
+ * `proposedData` via `transactionFunction` — it is verified by
145
+ * `ShareData.addTransaction` before the rule engine runs, so an unsigned or
146
+ * mis-signed proposal never reaches the rules or mutates state. `proof`
147
+ * is required precisely so nothing gets in without a signature: this is the
148
+ * canonical mutation entry point (the realtime propose handler routes
149
+ * here), and there is deliberately no unsigned variant on it.
150
+ *
151
+ * Once authorized, the proposal is judged by `startRuleEvaluation`;
152
+ * `_currentState` is replaced only if accepted. When the block is
153
+ * persisted, the appended transaction is written through before the event
154
+ * is emitted — a durable-write failure rejects rather than silently
155
+ * advancing only memory. Either way a transaction event is emitted with the
156
+ * outcome so observers can react.
157
+ *
158
+ * Library-internal callers that operate before the signing boundary (replay,
159
+ * seeding) use `ShareData.addTransactionNotValidated` directly; that path
160
+ * bypasses both the proof check and the emitter.
161
+ */
162
+ async applyTransaction(id, proposedData, transactionFunction, proof) {
163
+ const shareData = this.getShareDataById(id);
164
+ if (!shareData) {
165
+ throw new generic_1.ShareDataNotFoundError(id);
166
+ }
167
+ const outcome = shareData.addTransaction(proposedData, transactionFunction, proof);
168
+ const persistence = this._persistence.get(id);
169
+ if (this._repository && persistence) {
170
+ if (transactionFunction.id === undefined) {
171
+ throw new generic_1.ShareDataPersistenceError(id, 'cannot persist a transaction for a function without an id');
172
+ }
173
+ // Read the just-appended history entry for the deterministic time
174
+ // and recorded outcome so a reload replays an identical hash chain.
175
+ const latest = shareData.transactionHistory[shareData.transactionHistory.length - 1];
176
+ const appended = {
177
+ functionId: transactionFunction.id,
178
+ proposedState: proposedData,
179
+ proof,
180
+ transactionTime: latest.transactionTime,
181
+ ruleOutcome: latest.ruleOutcome,
182
+ };
183
+ // Build the next log locally and only commit it after the durable
184
+ // write succeeds, so the manager's record never claims a
185
+ // transaction the store rejected.
186
+ const nextLog = [...persistence.transactionLog, appended];
187
+ await this._repository.save((0, serialize_share_data_1.serializeShareData)(persistence.blockType, persistence.creationConfig, shareData, nextLog));
188
+ persistence.transactionLog = nextLog;
189
+ }
190
+ this._emit({
191
+ type: 'share-data:transaction',
192
+ shareDataId: id,
193
+ transactionId: outcome.transactionId,
194
+ accepted: outcome.accepted,
195
+ currentState: shareData.currentState,
196
+ transactionFunction,
197
+ });
198
+ return outcome;
199
+ }
200
+ on(type, listener) {
201
+ this._emitter.on(type, listener);
202
+ }
203
+ off(type, listener) {
204
+ this._emitter.off(type, listener);
205
+ }
206
+ _emit(event) {
207
+ this._emitter.emit(event.type, event);
208
+ }
209
+ }
210
+ exports.ShareDataManager = ShareDataManager;
@@ -0,0 +1,51 @@
1
+ import { IShareDataInitialCryptoData, PersistedCreationConfig, ShareBlockType, ShareDataProofs } from '@degenerate/generic';
2
+ import { ShareData } from '../share-data/share-data';
3
+ /**
4
+ * The inputs a block builder needs to replay construction of a persisted
5
+ * ShareData. These are exactly the fields a factory consumes once the
6
+ * `proofFor` callback is reconstructed from the stored proofs:
7
+ *
8
+ * - `creationConfig` — the factory options minus `proofFor`
9
+ * (`metadata`, `creationPublicKey`, `initialState`).
10
+ * - `initialCrypto` — the client-computed creation crypto, applied to the
11
+ * in-construction block on the first proof lookup.
12
+ * - `structuralProofs` — the per-purpose proof bundle, replayed in place of
13
+ * a live signer so the rebuilt block carries byte-identical proofs.
14
+ */
15
+ export interface ShareBlockBuilderInput {
16
+ creationConfig: PersistedCreationConfig;
17
+ initialCrypto: IShareDataInitialCryptoData;
18
+ structuralProofs: ShareDataProofs;
19
+ }
20
+ /**
21
+ * Rebuilds a ShareData of a single block type from its persisted recipe.
22
+ * Implementations live in `@degenerate/shareblock` (one per
23
+ * {@link ShareBlockType}) and are wired in via
24
+ * {@link registerShareBlockBuilder}. A builder must replay the *same* factory
25
+ * the block was created with so the structural-proof chain re-verifies; it
26
+ * must not mutate or trust any `expected*` integrity values (those are
27
+ * cross-checked separately after replay).
28
+ */
29
+ export type ShareBlockBuilder = (input: ShareBlockBuilderInput) => ShareData;
30
+ /**
31
+ * Registers the builder used to rehydrate snapshots of a given block type.
32
+ * Idempotent-by-overwrite: re-registering replaces the prior builder, which
33
+ * keeps test setup and repeated module loads stable.
34
+ */
35
+ export declare const registerShareBlockBuilder: (blockType: ShareBlockType, builder: ShareBlockBuilder) => void;
36
+ /**
37
+ * Returns the registered builder for a block type, or `undefined` if none has
38
+ * been registered. The deserialize engine treats `undefined` as an
39
+ * unreconstructable snapshot and throws `ShareDataPersistenceError` with the
40
+ * offending id — resolution stays decoupled from error-with-id semantics.
41
+ */
42
+ export declare const getShareBlockBuilder: (blockType: ShareBlockType) => ShareBlockBuilder | undefined;
43
+ /** Whether a builder is registered for the given block type. */
44
+ export declare const hasShareBlockBuilder: (blockType: ShareBlockType) => boolean;
45
+ /**
46
+ * Clears all registered builders. Intended for test isolation so one suite's
47
+ * registrations do not leak into another; production code registers once at
48
+ * import time and never clears.
49
+ */
50
+ export declare const clearShareBlockBuilders: () => void;
51
+ //# sourceMappingURL=block-factory-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-factory-registry.d.ts","sourceRoot":"","sources":["../../src/persistence/block-factory-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,2BAA2B,EAC3B,uBAAuB,EACvB,cAAc,EACd,eAAe,EAClB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAgBrD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,sBAAsB;IACnC,cAAc,EAAE,uBAAuB,CAAC;IACxC,aAAa,EAAE,2BAA2B,CAAC;IAC3C,gBAAgB,EAAE,eAAe,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,SAAS,CAAC;AAQ7E;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GAClC,WAAW,cAAc,EACzB,SAAS,iBAAiB,KAC3B,IAEF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC7B,WAAW,cAAc,KAC1B,iBAAiB,GAAG,SAAoC,CAAC;AAE5D,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,GAAI,WAAW,cAAc,KAAG,OACtC,CAAC;AAE5B;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QAAO,IAE1C,CAAC"}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clearShareBlockBuilders = exports.hasShareBlockBuilder = exports.getShareBlockBuilder = exports.registerShareBlockBuilder = void 0;
4
+ //#endregion Builder contract
5
+ //#region Registry
6
+ const builders = new Map();
7
+ /**
8
+ * Registers the builder used to rehydrate snapshots of a given block type.
9
+ * Idempotent-by-overwrite: re-registering replaces the prior builder, which
10
+ * keeps test setup and repeated module loads stable.
11
+ */
12
+ const registerShareBlockBuilder = (blockType, builder) => {
13
+ builders.set(blockType, builder);
14
+ };
15
+ exports.registerShareBlockBuilder = registerShareBlockBuilder;
16
+ /**
17
+ * Returns the registered builder for a block type, or `undefined` if none has
18
+ * been registered. The deserialize engine treats `undefined` as an
19
+ * unreconstructable snapshot and throws `ShareDataPersistenceError` with the
20
+ * offending id — resolution stays decoupled from error-with-id semantics.
21
+ */
22
+ const getShareBlockBuilder = (blockType) => builders.get(blockType);
23
+ exports.getShareBlockBuilder = getShareBlockBuilder;
24
+ /** Whether a builder is registered for the given block type. */
25
+ const hasShareBlockBuilder = (blockType) => builders.has(blockType);
26
+ exports.hasShareBlockBuilder = hasShareBlockBuilder;
27
+ /**
28
+ * Clears all registered builders. Intended for test isolation so one suite's
29
+ * registrations do not leak into another; production code registers once at
30
+ * import time and never clears.
31
+ */
32
+ const clearShareBlockBuilders = () => {
33
+ builders.clear();
34
+ };
35
+ exports.clearShareBlockBuilders = clearShareBlockBuilders;
36
+ //#endregion Registry
@@ -0,0 +1,18 @@
1
+ import { ShareData } from '../share-data/share-data';
2
+ /**
3
+ * Replays a {@link PersistedShareData} snapshot back into a live, executable
4
+ * ShareData. The rebuilt block re-binds real function closures (via the
5
+ * registered builder for its block type), so it accepts new proposals just
6
+ * like a freshly-created block.
7
+ *
8
+ * Throws:
9
+ * - {@link ShareDataPersistenceError} for an unsupported schema version, an
10
+ * unregistered block type, or a transaction referencing an unknown
11
+ * `functionId`.
12
+ * - {@link ShareDataStructuralProofFailedError} (from the replayed factory)
13
+ * if the structural-proof chain does not verify.
14
+ * - {@link ShareDataIntegrityError} if the replayed block diverges from the
15
+ * snapshot's `expected*` cross-checks.
16
+ */
17
+ export declare const deserializeShareData: (snapshot: unknown) => ShareData;
18
+ //# sourceMappingURL=deserialize-share-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deserialize-share-data.d.ts","sourceRoot":"","sources":["../../src/persistence/deserialize-share-data.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAYrD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,OAAO,KAAG,SAgHxD,CAAC"}