@degenerate/sharedata 0.2.7 → 0.4.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 (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 +57 -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 +149 -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 +66 -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 +30 -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 +232 -27
  78. package/dist/share-data/share-data.d.ts.map +1 -1
  79. package/dist/share-data/share-data.js +390 -60
  80. package/package.json +31 -13
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ShareData = void 0;
4
4
  const rules_1 = require("@degenerate/rules");
5
5
  const generic_1 = require("@degenerate/generic");
6
+ const verify_share_data_proposal_proof_1 = require("./proofs/verification/verify-share-data-proposal-proof");
7
+ const verify_transaction_proposal_proof_1 = require("./proofs/verification/verify-transaction-proposal-proof");
6
8
  /**
7
9
  * This contains the interface for the share data object
8
10
  */
@@ -10,48 +12,85 @@ class ShareData {
10
12
  /**
11
13
  * This is the constructor for the share data object
12
14
  * @param id the id of the share data
15
+ * @param creationPublicKey the public key of the creator of the share data
13
16
  */
14
- constructor(id) {
15
- this.isLocked = false;
16
- this._version = 1,
17
- this._id = id;
17
+ constructor(id, creationPublicKey, signingCurve = generic_1.EllipticalCurvesSigning.Curve25519) {
18
+ this._id = id;
19
+ this._creationHash = '';
20
+ this._creationSignature = '';
21
+ this._creationPublicKey = creationPublicKey,
22
+ this._version = 1,
23
+ this._isLocked = false;
24
+ this._lastUpdated = 0;
18
25
  this._rules = [];
19
26
  this._functions = [];
20
27
  this._transactionHistory = [];
21
28
  this._events = [];
22
- this._data = {};
29
+ this._currentState = {};
30
+ this._cryptoProofs = [];
31
+ this._signingCurve = signingCurve;
32
+ this._structuralProofs = [];
33
+ this._authorizedSigners = [];
23
34
  }
24
- //#region Getters and Setters
25
35
  /**
26
- * This adds a rule to the share block.
27
- * @param rule the rule to add to the share block
36
+ * This initializes the cryptographic properties of the share data
37
+ * @param creationPublicKey the public key of the creator of the share data (in hex format)
38
+ * @param creationHash the hash of the share data
39
+ * @param creationSignature the cryptographic signature of the share data
28
40
  */
29
- addRule(rule) {
30
- if (this.isLocked) {
31
- throw new generic_1.ShareDataIsLockedError(this._id, generic_1.ShareDataTypes.RULE);
41
+ initializeCrypto(initialCryptoData) {
42
+ // Implement the logic to initialize the cryptographic properties
43
+ if (this._creationSignature || this._creationHash || this._lastUpdated != 0) {
44
+ throw new generic_1.ShareDataCryptoAlreadyExistsError(this._id);
32
45
  }
33
- this._rules.push(rule);
46
+ if (initialCryptoData.publicKey !== this._creationPublicKey) {
47
+ throw new generic_1.CryptoInitializationPublicKeyIsDifferentError(this._id);
48
+ }
49
+ // check that the share data proof is valid.
50
+ this._lastUpdated = initialCryptoData.timestamp;
51
+ this._creationHash = initialCryptoData.shareDataHash;
52
+ this._creationSignature = initialCryptoData.shareDataSignature;
34
53
  }
54
+ //#region Validation
35
55
  /**
36
- * This gets the rules for the share block
56
+ * This validates the cryptographic properties of the share data
37
57
  */
38
- get rules() {
39
- return this._rules;
58
+ // validateRuleUpdate = (ruleToAdd )
59
+ //#endregion Validation
60
+ /**
61
+ * This validates the cryptographic properties of the share data
62
+ * @param creationPublicKey the public key of the creator of the share data (in hex format)
63
+ */
64
+ //#region Getters and Setters
65
+ /**
66
+ * get the creation hash
67
+ */
68
+ get creationHash() {
69
+ return this._creationHash;
40
70
  }
41
71
  /**
42
- * This gets the transaction history for the share block
72
+ * get the creation public key
43
73
  */
44
- addFunction(func) {
45
- if (this.isLocked) {
46
- throw new generic_1.ShareDataIsLockedError(this._id, generic_1.ShareDataTypes.FUNCTION);
47
- }
48
- this._functions.push(func);
74
+ get creationPublicKey() {
75
+ return this._creationPublicKey;
49
76
  }
50
77
  /**
51
- * This gets the functions for the share block
78
+ * get the creation signature
52
79
  */
53
- get functions() {
54
- return this._functions;
80
+ get creationSignature() {
81
+ return this._creationSignature;
82
+ }
83
+ /**
84
+ * This gets all cryptographic proofs for the share data
85
+ */
86
+ get cryptoProofs() {
87
+ return this._cryptoProofs;
88
+ }
89
+ /**
90
+ * This returns the current state of data for the share block
91
+ */
92
+ get currentState() {
93
+ return this._currentState;
55
94
  }
56
95
  /**
57
96
  * This gets the events for the sharedata
@@ -59,6 +98,72 @@ class ShareData {
59
98
  get events() {
60
99
  return this._events;
61
100
  }
101
+ /**
102
+ * This gets the functions for the share block
103
+ */
104
+ get functions() {
105
+ return this._functions;
106
+ }
107
+ /**
108
+ * This gets the id for the share data
109
+ */
110
+ get id() {
111
+ return this._id;
112
+ }
113
+ /**
114
+ * This get whether the share data is locked
115
+ */
116
+ get isLocked() {
117
+ return this._isLocked;
118
+ }
119
+ /**
120
+ * This gets the last timestamp (in milliseconds) that the share data was updated
121
+ */
122
+ get lastUpdated() {
123
+ return this._lastUpdated;
124
+ }
125
+ /**
126
+ * This gets the rules for the share block
127
+ */
128
+ get rules() {
129
+ return this._rules;
130
+ }
131
+ /**
132
+ * This gets the elliptical curve used for signing
133
+ */
134
+ get signingCurve() {
135
+ return this._signingCurve;
136
+ }
137
+ /**
138
+ * This gets the structure proofs for the share data
139
+ */
140
+ get structuralProofs() {
141
+ return this._structuralProofs;
142
+ }
143
+ /**
144
+ * This gets the delegated authorized-signer grants for the share data.
145
+ * Each grant is a `{ publicKey, functionIds }` pair: a key the owner has
146
+ * delegated the right to propose transactions for, scoped to those function
147
+ * ids. The block owner (`creationPublicKey`) is always authorized and is
148
+ * NOT listed here.
149
+ */
150
+ get authorizedSigners() {
151
+ return this._authorizedSigners;
152
+ }
153
+ /**
154
+ * This gets the transaction history for the share block
155
+ */
156
+ get transactionHistory() {
157
+ return this._transactionHistory;
158
+ }
159
+ /**
160
+ * This gets the version of the share data
161
+ */
162
+ get version() {
163
+ return this._version;
164
+ }
165
+ //#endregion Getters and Setters
166
+ //#region Adders
62
167
  /**
63
168
  * This adds an event to the share data
64
169
  * @param event the event to add
@@ -67,16 +172,125 @@ class ShareData {
67
172
  this._events.push(event);
68
173
  }
69
174
  /**
70
- * This adds a transaction to the share block
71
- * @param rulesEvaluation the evaluation of the rules (result)
72
- * @param transactionFunction the function that was run
175
+ * This adds a function to the share block.
176
+ * @param func the function to add to the share block
177
+ */
178
+ addFunction(func, cryptoProof) {
179
+ if (this._isLocked) {
180
+ throw new generic_1.ShareDataIsLockedError(this._id, generic_1.ShareDataTypes.FUNCTION);
181
+ }
182
+ // Verify against the share-data state as it stands BEFORE this
183
+ // function is appended. The signer signed over that pre-append
184
+ // snapshot, so verifying after the push would always fail.
185
+ this.verifyStructuralProof(cryptoProof);
186
+ this._structuralProofs.push(cryptoProof);
187
+ this._functions.push(func);
188
+ }
189
+ /**
190
+ * This adds a rule to the share block.
191
+ * @param rule the rule to add to the share block
192
+ */
193
+ addRule(rule, cryptoProof) {
194
+ if (this._isLocked) {
195
+ throw new generic_1.ShareDataIsLockedError(this._id, generic_1.ShareDataTypes.RULE);
196
+ }
197
+ // Same pre-append verification as addFunction — the signer signed
198
+ // over the state before this rule was added.
199
+ this.verifyStructuralProof(cryptoProof);
200
+ this._structuralProofs.push(cryptoProof);
201
+ this._rules.push(rule);
202
+ }
203
+ /**
204
+ * Delegates `signerPublicKey` the right to propose runtime transactions for
205
+ * the given `functionIds` (and ONLY those — least privilege). Creation-time
206
+ * only: rejected once the block is locked. The registration is part of the
207
+ * signed structure, so a delegate cannot be injected into a tampered
208
+ * snapshot without invalidating the chain.
209
+ *
210
+ * Three gates, in order:
211
+ * 1. Owner-identity: `registrationProof.publicKey === creationPublicKey`.
212
+ * ONLY the block owner may delegate — this is the check `addFunction` /
213
+ * `addRule` deliberately omit (the HTTP layer supplies it there). It
214
+ * must live here because the security of the widened transaction gate
215
+ * (see {@link isAuthorizedSigner}) rests on "the allow-list was
216
+ * authorized by the owner." It also blocks transitive delegation: a
217
+ * delegate's key is never the creation key, so a delegate can never
218
+ * register further delegates.
219
+ * 2. Grant binding: the proof's `purpose` must equal
220
+ * `buildDelegatePurpose(signerPublicKey, functionIds)`. The proof signs
221
+ * over the PRE-append state (the grant is not yet folded into
222
+ * `_authorizedSigners`), so the purpose is the only thing that attests
223
+ * to the exact `(key, functionIds)` grant — without this a tampered
224
+ * snapshot could widen a delegate's scope without breaking the
225
+ * signature.
226
+ * 3. Structural verification against the current (pre-append) state,
227
+ * reusing the same machinery `addFunction` / `addRule` use; folds the
228
+ * proof into the hash chain and verifies the owner's signature.
229
+ *
230
+ * Throws {@link ShareDataIsLockedError} if locked,
231
+ * {@link ShareDataDelegationNotAuthorizedError} for a non-owner registrant /
232
+ * empty grant / mismatched purpose, and
233
+ * {@link ShareDataStructuralProofFailedError} if the proof does not verify.
234
+ */
235
+ addAuthorizedSigner(signerPublicKey, functionIds, registrationProof) {
236
+ if (this._isLocked) {
237
+ throw new generic_1.ShareDataIsLockedError(this._id, generic_1.ShareDataTypes.AUTHORIZATION);
238
+ }
239
+ // Gate 1: owner-identity. Only the creation key may delegate.
240
+ if (registrationProof.publicKey !== this._creationPublicKey) {
241
+ throw new generic_1.ShareDataDelegationNotAuthorizedError(this._id, registrationProof.publicKey);
242
+ }
243
+ // Normalize so the purpose, the stored grant, and the canonical hash all
244
+ // agree byte-for-byte on live-create and on replay.
245
+ const normalizedFunctionIds = Array.from(new Set(functionIds.map((id) => id.trim()).filter((id) => id.length > 0))).sort();
246
+ if (normalizedFunctionIds.length === 0) {
247
+ throw new generic_1.ShareDataDelegationNotAuthorizedError(this._id, registrationProof.publicKey);
248
+ }
249
+ // Gate 2: the proof must bind this exact (key, functionIds) grant.
250
+ const expectedPurpose = (0, generic_1.buildDelegatePurpose)(signerPublicKey, normalizedFunctionIds);
251
+ if (registrationProof.purpose !== expectedPurpose) {
252
+ throw new generic_1.ShareDataDelegationNotAuthorizedError(this._id, registrationProof.publicKey);
253
+ }
254
+ // Gate 3: structural verification (pre-append, mirroring addFunction).
255
+ this.verifyStructuralProof(registrationProof);
256
+ this._structuralProofs.push(registrationProof);
257
+ this._authorizedSigners.push({ publicKey: signerPublicKey, functionIds: normalizedFunctionIds });
258
+ }
259
+ /**
260
+ * Whether `publicKey` is authorized to propose a transaction for
261
+ * `functionId` on this block. The block owner (`creationPublicKey`) is
262
+ * always authorized for every function; a delegated key is authorized only
263
+ * for the function ids its registration granted. This is the single
264
+ * predicate behind the proposer-identity gate, called from both the live
265
+ * mutation path ({@link addTransaction}) and the persistence replay path so
266
+ * the two cannot drift.
73
267
  */
74
- addTransactionAlreadyValidated(proposedData, rulesEvaluation, transactionFunction) {
268
+ isAuthorizedSigner(publicKey, functionId) {
269
+ if (publicKey === this._creationPublicKey) {
270
+ return true;
271
+ }
272
+ const grant = this._authorizedSigners.find((s) => s.publicKey === publicKey);
273
+ return grant !== undefined && grant.functionIds.includes(functionId);
274
+ }
275
+ /**
276
+ * Append a pre-validated transaction to the history. Pass `transactionTime`
277
+ * when the caller needs the recorded timestamp to be deterministic — for
278
+ * example, when a wire-format payload is being reconstructed and the
279
+ * resulting share-data state must hash identically to the one the
280
+ * remote signer produced. Omit it for ordinary live calls; defaults to
281
+ * `Date.now()`.
282
+ *
283
+ * Pass `proof` when replaying a persisted transaction so the rebuilt
284
+ * history entry carries the same proposal proof the live entry did. The
285
+ * canonical share-data hash folds `transactionHistory` in, so omitting the
286
+ * proof here would make a replayed block hash differently from the original
287
+ * and break verification of any later transaction's proof.
288
+ */
289
+ addTransactionAlreadyValidated(proposedData, rulesEvaluation, transactionFunction, transactionTime = Date.now(), proof) {
75
290
  // make sure the function is known.
76
291
  if (!this._functions.includes(transactionFunction)) {
77
292
  throw new Error('The function is not known');
78
293
  }
79
- const transactionTime = Date.now(); // get the current time
80
294
  const transactionId = this._transactionHistory.length + 1; // get the transaction id
81
295
  const ruleOutcome = (rulesEvaluation.proposedResult && rulesEvaluation.currentResult);
82
296
  const transaction = {
@@ -85,76 +299,192 @@ class ShareData {
85
299
  transactionFunction,
86
300
  transactionId: transactionId.toString(),
87
301
  transactionTime,
302
+ ...(proof ? { proof } : {}),
88
303
  };
89
304
  // the outcome of the rules is valid write the data to be the new current data.
90
305
  if (ruleOutcome) {
91
- this._data = proposedData;
306
+ this._currentState = proposedData;
92
307
  }
93
308
  this._transactionHistory.push(transaction);
94
309
  }
95
310
  /**
96
311
  * This adds a transaction to the share block but the transaction has not yet been validated
97
312
  *
313
+ * The unsigned/internal apply path: it runs the rule engine and records the
314
+ * outcome but carries no proposal proof, so it does NOT attest that any key
315
+ * holder authorized the change. New runtime mutations should go through
316
+ * {@link addTransaction}, which verifies a transaction proposal proof first.
317
+ * Retained for internal replay/seed callers that operate before the signed
318
+ * boundary is in play.
319
+ *
98
320
  * @param proposedData the proposed data
99
321
  * @param transactionFunction the function that was attempted
100
322
  */
101
323
  addTransactionNotValidated(proposedData, transactionFunction) {
324
+ return this.evaluateAndApply(proposedData, transactionFunction);
325
+ }
326
+ /**
327
+ * Signed runtime mutation path. Verifies that `proof` cryptographically
328
+ * authorizes applying `transactionFunction` to move this share-data to
329
+ * exactly `proposedData`, then runs the rule engine and records the
330
+ * outcome. The recorded history entry carries `proof`, so the audit log
331
+ * itself holds the signature — not merely "which function ran."
332
+ *
333
+ * Four gates, in order:
334
+ * 1. The function must be registered on this block.
335
+ * 2. The function must be addressable (`id` set) and the proof must be
336
+ * minted for that same id (`proof.purpose === transactionFunction.id`).
337
+ * This binds the proof to *this* function so a proof minted for one
338
+ * function can't be replayed to drive another even if the proposed
339
+ * state would satisfy both functions' rules.
340
+ * 3. The proof's signer must be authorized for this block AND this
341
+ * function — the creation key for any function, or a delegated key for
342
+ * the function ids its registration granted (`isAuthorizedSigner`).
343
+ * Signature validity alone only proves *someone* signed the transition;
344
+ * this binds the *authorized* someone. Without it any valid keypair
345
+ * could sign a legal transition.
346
+ * 4. The proof must verify against the current state AND `proposedData`
347
+ * (closes the amount-replay hole — see
348
+ * `verifyTransactionProposalProof`).
349
+ *
350
+ * Throws {@link ShareDataTransactionNotAuthorizedError} when the signer is
351
+ * not authorized (gate 3), {@link ShareDataTransactionProofFailedError} on
352
+ * any other auth failure — both before the rule engine runs and before any
353
+ * state is touched.
354
+ *
355
+ * @param proposedData the proposed next state
356
+ * @param transactionFunction the function producing `proposedData`
357
+ * @param proof the transaction proposal proof authorizing the change
358
+ */
359
+ addTransaction(proposedData, transactionFunction, proof) {
360
+ // Gate 1: function registered on this block.
361
+ if (!this._functions.includes(transactionFunction)) {
362
+ throw new Error('The function is not known');
363
+ }
364
+ // Gate 2: bind the proof to this specific function. The signed runtime
365
+ // path requires addressable functions — an id-less function cannot be
366
+ // the subject of a proof, so reject rather than silently skip the
367
+ // binding.
368
+ const functionId = transactionFunction.id;
369
+ if (typeof functionId !== 'string' || functionId.length < 1) {
370
+ throw new generic_1.ShareDataTransactionProofFailedError(this._id);
371
+ }
372
+ if (proof.purpose !== functionId) {
373
+ throw new generic_1.ShareDataTransactionProofFailedError(this._id);
374
+ }
375
+ // Gate 3: bind the proposer identity. The block's creation key may
376
+ // authorize any function; a delegated key may authorize only the
377
+ // function ids it was granted (see addAuthorizedSigner / isAuthorizedSigner).
378
+ // `functionId` equals `proof.purpose` here (enforced by Gate 2), so the
379
+ // scope check is against the function the proof is bound to. Checked
380
+ // before the (more expensive) signature verification so an unauthorized
381
+ // signer fails fast.
382
+ if (!this.isAuthorizedSigner(proof.publicKey, functionId)) {
383
+ throw new generic_1.ShareDataTransactionNotAuthorizedError(this._id, proof.publicKey);
384
+ }
385
+ // Gate 4: proof binds current state + proposed state + chain position.
386
+ this.verifyTransactionProof(proof, proposedData);
387
+ return this.evaluateAndApply(proposedData, transactionFunction, proof);
388
+ }
389
+ /**
390
+ * Shared rule-evaluate → apply-if-valid → record path used by both
391
+ * {@link addTransactionNotValidated} (no proof) and {@link addTransaction}
392
+ * (proof already verified by the caller). When `proof` is supplied it is
393
+ * recorded on the history entry so the audit log carries the signature.
394
+ */
395
+ evaluateAndApply(proposedData, transactionFunction, proof) {
102
396
  // make sure the function is known.
103
397
  if (!this._functions.includes(transactionFunction)) {
104
398
  // throw ShareDataFunctionBeingAppliedDoesNotExistOnShareDataError
105
399
  throw new Error('The function is not known');
106
400
  }
107
- // // evaluate the rules.
108
- // const rulesEvalOutcome = evaluateRules('transaction', this._data, proposedData, this._rules);
109
- const rulesOutcome = (0, rules_1.startRuleEvaluation)(this._id, transactionFunction, this.functions, this._rules, this._data, proposedData);
110
- const transactionTime = Date.now(); // get the current time
111
- const transactionId = this._transactionHistory.length + 1; // get the transaction id
401
+ const rulesOutcome = (0, rules_1.startRuleEvaluation)(this._id, transactionFunction, this.functions, this._rules, this._currentState, proposedData);
402
+ const transactionTime = Date.now();
403
+ const transactionId = (this._transactionHistory.length + 1).toString();
112
404
  const transaction = {
113
405
  ruleOutcome: rulesOutcome.isValidProposal,
114
406
  ruleFailures: [],
115
407
  transactionFunction,
116
- transactionId: transactionId.toString(),
408
+ transactionId,
117
409
  transactionTime,
410
+ ...(proof ? { proof } : {}),
118
411
  };
119
- // update the data if the rules are valid
120
412
  if (rulesOutcome.isValidProposal) {
121
- this._data = proposedData;
413
+ this._currentState = proposedData;
122
414
  }
123
- // add the transaction to the history
124
415
  this._transactionHistory.push(transaction);
416
+ return { accepted: rulesOutcome.isValidProposal, transactionId };
125
417
  }
126
- /**
127
- * This gets the transaction history for the share block
128
- */
129
- get transactionHistory() {
130
- return this._transactionHistory;
131
- }
132
- /**
133
- * This returns the current state of data for the share block
134
- */
135
- get data() {
136
- return this._data;
137
- }
138
- /**
139
- * This gets the version of the share data
140
- */
141
- get version() {
142
- return this._version;
143
- }
418
+ //#region Adders
419
+ //#region Copy
144
420
  /**
145
421
  * This copies a share data object to a new transaction number
146
422
  * @param transactionNumber the number of the transaction to run until.
423
+ * @param publicKey the public key of the application that will be the new owner of the share data
147
424
  */
148
- copyTo(transactionNumber) {
425
+ copyTo(transactionNumber, publicKey) {
149
426
  // return share data with a new ID
150
- const newShareData = new ShareData(`${this._id}-${transactionNumber}`);
427
+ const newShareData = new ShareData(`${this._id}-${transactionNumber}`, publicKey);
151
428
  newShareData._rules = [...this._rules];
152
429
  newShareData._functions = [...this._functions];
153
430
  newShareData._transactionHistory = [...this._transactionHistory];
154
431
  newShareData._events = [...this._events];
155
- newShareData._data = { ...this._data };
432
+ newShareData._currentState = { ...this._currentState };
156
433
  newShareData._version = this._version;
157
434
  return newShareData;
158
435
  }
436
+ //#endregion Copy
437
+ //#region Crypto Proofs
438
+ /**
439
+ * This adds a cryptographic proof to the share data
440
+ * @param proof the cryptographic proof to add
441
+ */
442
+ addCryptoProof(proof) {
443
+ this._cryptoProofs.push(proof);
444
+ }
445
+ /**
446
+ * Verifies that `proof` is a faithful attestation of this share-data's
447
+ * current structural state under `proof.purpose`. Returns `true` on
448
+ * success; throws `ShareDataStructuralProofFailedError` on any mismatch
449
+ * (hash, previousHash, signature, or purpose).
450
+ */
451
+ verifyStructuralProof(proof, curve = this._signingCurve) {
452
+ return (0, verify_share_data_proposal_proof_1.verifyShareDataProposalProof)(proof, this, curve);
453
+ }
454
+ /**
455
+ * Verifies that `proof` authorizes applying a transaction that moves this
456
+ * share-data to exactly `proposedData`. Unlike {@link verifyStructuralProof}
457
+ * (which binds only the current state under a purpose), this additionally
458
+ * binds the proposed state — a proof minted for one proposed state will not
459
+ * verify against any other. Returns `true`; throws
460
+ * `ShareDataTransactionProofFailedError` on any mismatch.
461
+ */
462
+ verifyTransactionProof(proof, proposedData, curve = this._signingCurve) {
463
+ return (0, verify_transaction_proposal_proof_1.verifyTransactionProposalProof)(proof, this, proposedData, curve);
464
+ }
465
+ //#endregion Crypto Proofs
466
+ //#region Structure Proofs
467
+ /**
468
+ * This adds a structure proof to the share data
469
+ * @param proof the structure proof to add
470
+ */
471
+ addStructuralProof(proof) {
472
+ if (this._structuralProofs.includes(proof)) {
473
+ throw new generic_1.ShareDataStructuralProofFailedError(this._id);
474
+ }
475
+ this._structuralProofs.push(proof);
476
+ }
477
+ //#region Initialization
478
+ /**
479
+ * This initializes the share data object and locks it
480
+ */
481
+ initialize() {
482
+ // Perform any necessary initialization steps here
483
+ // Lock the share data object
484
+ this._isLocked = true;
485
+ }
159
486
  }
160
487
  exports.ShareData = ShareData;
488
+ const itiem2 = new ShareData('1', '1234');
489
+ const item = new ShareData('1', '1234');
490
+ item.initialize();
package/package.json CHANGED
@@ -1,22 +1,40 @@
1
1
  {
2
2
  "name": "@degenerate/sharedata",
3
- "version": "0.2.7",
3
+ "version": "0.4.0",
4
4
  "description": "This contains the ShareData Adaptive Framework Ecosystem (SAFE) network core code",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
7
16
  "scripts": {
8
17
  "build": "rm -rf dist/* && tsc -p tsconfig.pkg.json",
9
18
  "compile": "rm -rf dist/* && tsc -p tsconfig.pkg.json",
10
- "test": "jest --forceExit --detectOpenHandles --verbose --silent=false --env node --config tsconfig.pkg.json",
11
- "test:coverage": "jest --forceExit --coverage --detectOpenHandles --verbose --silent=false --env node --config tsconfig.pkg.json",
19
+ "test": "jest --forceExit --detectOpenHandles --verbose --silent=false --env node",
20
+ "test:coverage": "jest --forceExit --coverage --detectOpenHandles --verbose --silent=false --env node ",
12
21
  "test:clearCache": "jest --clearCache"
13
22
  },
14
23
  "devDependencies": {
15
- "@types/jest": "^29.5.14",
16
- "@types/node": "^22.8.0",
17
- "jest": "^29.7.0",
18
- "ts-jest": "^29.2.5",
19
- "typescript": "^5.6.3"
24
+ "@types/jest": "^30.0.0",
25
+ "@types/node": "^22.19.18",
26
+ "firebase-admin": "^13.10.0",
27
+ "jest": "^30.4.2",
28
+ "ts-jest": "^29.4.9",
29
+ "typescript": "^6.0.3"
30
+ },
31
+ "peerDependencies": {
32
+ "firebase-admin": "^13.10.0"
33
+ },
34
+ "peerDependenciesMeta": {
35
+ "firebase-admin": {
36
+ "optional": true
37
+ }
20
38
  },
21
39
  "keywords": [
22
40
  "ShareData Adaptive Framework Ecosystem",
@@ -31,13 +49,13 @@
31
49
  "url": "https://github.com/syncrude/safe/issues"
32
50
  },
33
51
  "homepage": "https://github.com/syncrude/safe#readme",
34
- "gitHead": "29034ad37b42e7ec71a842e679b6c8a257d7cb6a",
52
+ "gitHead": "9453d9ab785e03fd01eb5b408ed0e3ca22baefd5",
35
53
  "dependencies": {
36
- "@degenerate/generic": "^0.2.7",
37
- "@degenerate/rules": "^0.2.7",
38
- "zod": "^3.24.1"
54
+ "@degenerate/generic": "^0.4.0",
55
+ "@degenerate/rules": "^0.4.0",
56
+ "zod": "^4.4.3"
39
57
  },
40
58
  "engines": {
41
- "node": "22.x"
59
+ "node": ">=22"
42
60
  }
43
61
  }