@bcts/gstp 1.0.0-alpha.22 → 1.0.0-beta.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.
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll as t };
package/dist/index.cjs CHANGED
@@ -1,26 +1,21 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region \0rolldown/runtime.js
3
3
  var __defProp = Object.defineProperty;
4
4
  var __exportAll = (all, no_symbols) => {
5
5
  let target = {};
6
- for (var name in all) {
7
- __defProp(target, name, {
8
- get: all[name],
9
- enumerable: true
10
- });
11
- }
12
- if (!no_symbols) {
13
- __defProp(target, Symbol.toStringTag, { value: "Module" });
14
- }
6
+ for (var name in all) __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
15
11
  return target;
16
12
  };
17
-
18
13
  //#endregion
19
14
  let _bcts_components = require("@bcts/components");
20
15
  let _bcts_envelope = require("@bcts/envelope");
16
+ let _bcts_dcbor = require("@bcts/dcbor");
21
17
  let _bcts_known_values = require("@bcts/known-values");
22
18
  let _bcts_xid = require("@bcts/xid");
23
-
24
19
  //#region src/error.ts
25
20
  /**
26
21
  * Copyright © 2023-2026 Blockchain Commons, LLC
@@ -75,58 +70,57 @@ var GstpError = class GstpError extends Error {
75
70
  * Returned when the sender is missing an encryption key.
76
71
  */
77
72
  static senderMissingEncryptionKey() {
78
- return new GstpError(GstpErrorCode.SENDER_MISSING_ENCRYPTION_KEY, "sender must have an encryption key");
73
+ return new GstpError("SENDER_MISSING_ENCRYPTION_KEY", "sender must have an encryption key");
79
74
  }
80
75
  /**
81
76
  * Returned when the recipient is missing an encryption key.
82
77
  */
83
78
  static recipientMissingEncryptionKey() {
84
- return new GstpError(GstpErrorCode.RECIPIENT_MISSING_ENCRYPTION_KEY, "recipient must have an encryption key");
79
+ return new GstpError("RECIPIENT_MISSING_ENCRYPTION_KEY", "recipient must have an encryption key");
85
80
  }
86
81
  /**
87
82
  * Returned when the sender is missing a verification key.
88
83
  */
89
84
  static senderMissingVerificationKey() {
90
- return new GstpError(GstpErrorCode.SENDER_MISSING_VERIFICATION_KEY, "sender must have a verification key");
85
+ return new GstpError("SENDER_MISSING_VERIFICATION_KEY", "sender must have a verification key");
91
86
  }
92
87
  /**
93
88
  * Returned when the continuation has expired.
94
89
  */
95
90
  static continuationExpired() {
96
- return new GstpError(GstpErrorCode.CONTINUATION_EXPIRED, "continuation expired");
91
+ return new GstpError("CONTINUATION_EXPIRED", "continuation expired");
97
92
  }
98
93
  /**
99
94
  * Returned when the continuation ID is invalid.
100
95
  */
101
96
  static continuationIdInvalid() {
102
- return new GstpError(GstpErrorCode.CONTINUATION_ID_INVALID, "continuation ID invalid");
97
+ return new GstpError("CONTINUATION_ID_INVALID", "continuation ID invalid");
103
98
  }
104
99
  /**
105
100
  * Returned when the peer continuation is not encrypted.
106
101
  */
107
102
  static peerContinuationNotEncrypted() {
108
- return new GstpError(GstpErrorCode.PEER_CONTINUATION_NOT_ENCRYPTED, "peer continuation must be encrypted");
103
+ return new GstpError("PEER_CONTINUATION_NOT_ENCRYPTED", "peer continuation must be encrypted");
109
104
  }
110
105
  /**
111
106
  * Returned when a request is missing the peer continuation.
112
107
  */
113
108
  static missingPeerContinuation() {
114
- return new GstpError(GstpErrorCode.MISSING_PEER_CONTINUATION, "requests must contain a peer continuation");
109
+ return new GstpError("MISSING_PEER_CONTINUATION", "requests must contain a peer continuation");
115
110
  }
116
111
  /**
117
112
  * Envelope error wrapper.
118
113
  */
119
114
  static envelope(cause) {
120
- return new GstpError(GstpErrorCode.ENVELOPE, "envelope error", cause);
115
+ return new GstpError("ENVELOPE", "envelope error", cause);
121
116
  }
122
117
  /**
123
118
  * XID error wrapper.
124
119
  */
125
120
  static xid(cause) {
126
- return new GstpError(GstpErrorCode.XID, "XID error", cause);
121
+ return new GstpError("XID", "XID error", cause);
127
122
  }
128
123
  };
129
-
130
124
  //#endregion
131
125
  //#region src/continuation.ts
132
126
  /**
@@ -140,7 +134,22 @@ var GstpError = class GstpError extends Error {
140
134
  * eliminating the need for local state storage and enhancing security
141
135
  * for devices with limited storage or requiring distributed state management.
142
136
  *
143
- * Ported from gstp-rust/src/continuation.rs
137
+ * Ported from gstp-rust/src/continuation.rs.
138
+ *
139
+ * Wire shape — mirrors Rust:
140
+ * ```
141
+ * {
142
+ * <state envelope>
143
+ * } [
144
+ * 'id': ARID(...)
145
+ * 'validUntil': Date(...) ← CBOR tag 1, not ISO 8601 text
146
+ * ]
147
+ * ```
148
+ *
149
+ * The `state` envelope is **wrapped** before assertions are attached,
150
+ * matching Rust `self.state.wrap().add_optional_assertion(...)`. The
151
+ * earlier port attached the assertions directly to the un-wrapped state,
152
+ * producing a different digest tree.
144
153
  */
145
154
  /**
146
155
  * Represents an encrypted state continuation.
@@ -247,8 +256,10 @@ var Continuation = class Continuation {
247
256
  /**
248
257
  * Checks if the continuation is valid at the given time.
249
258
  *
250
- * If no valid_until is set, always returns true.
251
- * If no time is provided, always returns true.
259
+ * Mirrors Rust `is_valid_date(now)`: at the exact `valid_until`
260
+ * instant, the continuation is **expired** (returns `false`). The
261
+ * earlier port used `<=` here, which differed from Rust by one
262
+ * millisecond at the boundary.
252
263
  *
253
264
  * @param now - The time to check against, or undefined to skip time validation
254
265
  * @returns true if the continuation is valid at the given time
@@ -256,7 +267,7 @@ var Continuation = class Continuation {
256
267
  isValidDate(now) {
257
268
  if (this._validUntil === void 0) return true;
258
269
  if (now === void 0) return true;
259
- return now.getTime() <= this._validUntil.getTime();
270
+ return now.getTime() < this._validUntil.getTime();
260
271
  }
261
272
  /**
262
273
  * Checks if the continuation has the expected ID.
@@ -285,21 +296,39 @@ var Continuation = class Continuation {
285
296
  /**
286
297
  * Converts the continuation to an envelope.
287
298
  *
288
- * If a recipient is provided, the envelope is encrypted to that recipient.
299
+ * Mirrors Rust `Continuation::to_envelope`:
300
+ *
301
+ * ```rust
302
+ * self.state.wrap()
303
+ * .add_optional_assertion(ID, self.valid_id)
304
+ * .add_optional_assertion(VALID_UNTIL, self.valid_until)
305
+ * ```
306
+ *
307
+ * The state is wrapped first; the optional assertions then live on
308
+ * the wrap node. `valid_until` is encoded as a CBOR-tagged Date
309
+ * (tag 1) — never as a plain ISO 8601 string.
289
310
  *
290
311
  * @param recipient - Optional recipient to encrypt the envelope to
291
312
  * @returns The continuation as an envelope
292
313
  */
293
314
  toEnvelope(recipient) {
294
- let envelope = this._state;
315
+ let envelope = this._state.wrap();
295
316
  if (this._validId !== void 0) envelope = envelope.addAssertion(_bcts_known_values.ID, this._validId);
296
- if (this._validUntil !== void 0) envelope = envelope.addAssertion(_bcts_known_values.VALID_UNTIL, this._validUntil.toISOString());
317
+ if (this._validUntil !== void 0) envelope = envelope.addAssertion(_bcts_known_values.VALID_UNTIL, _bcts_dcbor.CborDate.fromDatetime(this._validUntil));
297
318
  if (recipient !== void 0) envelope = envelope.encryptToRecipients([recipient]);
298
319
  return envelope;
299
320
  }
300
321
  /**
301
322
  * Parses a continuation from an envelope.
302
323
  *
324
+ * Mirrors Rust `Continuation::try_from_envelope`:
325
+ *
326
+ * ```rust
327
+ * state: envelope.try_unwrap()?, // unwrap
328
+ * valid_id: envelope.extract_optional_object_for_predicate(ID)?,
329
+ * valid_until: envelope.extract_optional_object_for_predicate(VALID_UNTIL)?,
330
+ * ```
331
+ *
303
332
  * @param encryptedEnvelope - The envelope to parse
304
333
  * @param expectedId - Optional ID to validate against
305
334
  * @param now - Optional time to validate against
@@ -314,23 +343,32 @@ var Continuation = class Continuation {
314
343
  } catch (e) {
315
344
  throw GstpError.envelope(e instanceof Error ? e : new Error(String(e)));
316
345
  }
317
- const state = envelope.subject();
318
- let validId;
346
+ let state;
319
347
  try {
320
- const idObj = envelope.objectForPredicate(_bcts_known_values.ID);
321
- if (idObj !== void 0) {
322
- const leafCbor = idObj.asLeaf();
323
- if (leafCbor !== void 0) validId = _bcts_components.ARID.fromTaggedCborData(leafCbor.toData());
348
+ state = envelope.tryUnwrap();
349
+ } catch (e) {
350
+ throw GstpError.envelope(e instanceof Error ? e : new Error(String(e)));
351
+ }
352
+ let validId;
353
+ const idObj = envelope.optionalObjectForPredicate(_bcts_known_values.ID);
354
+ if (idObj !== void 0) {
355
+ const leafCbor = idObj.asLeaf();
356
+ if (leafCbor !== void 0) try {
357
+ validId = _bcts_components.ARID.fromTaggedCbor(leafCbor);
358
+ } catch (e) {
359
+ throw GstpError.envelope(e instanceof Error ? e : new Error(String(e)));
324
360
  }
325
- } catch {}
361
+ }
326
362
  let validUntil;
327
- try {
328
- const validUntilObj = envelope.objectForPredicate(_bcts_known_values.VALID_UNTIL);
329
- if (validUntilObj !== void 0) {
330
- const dateStr = validUntilObj.asText();
331
- if (dateStr !== void 0) validUntil = new Date(dateStr);
363
+ const validUntilObj = envelope.optionalObjectForPredicate(_bcts_known_values.VALID_UNTIL);
364
+ if (validUntilObj !== void 0) {
365
+ const leafCbor = validUntilObj.asLeaf();
366
+ if (leafCbor !== void 0) try {
367
+ validUntil = _bcts_dcbor.CborDate.fromTaggedCbor(leafCbor).datetime();
368
+ } catch (e) {
369
+ throw GstpError.envelope(e instanceof Error ? e : new Error(String(e)));
332
370
  }
333
- } catch {}
371
+ }
334
372
  const continuation = new Continuation(state, validId, validUntil);
335
373
  if (!continuation.isValidDate(now)) throw GstpError.continuationExpired();
336
374
  if (!continuation.isValidId(expectedId)) throw GstpError.continuationIdInvalid();
@@ -364,10 +402,50 @@ var Continuation = class Continuation {
364
402
  return `${parts.join(", ")})`;
365
403
  }
366
404
  };
367
-
368
405
  //#endregion
369
406
  //#region src/sealed-request.ts
370
407
  /**
408
+ * Copyright © 2023-2026 Blockchain Commons, LLC
409
+ * Copyright © 2025-2026 Parity Technologies
410
+ *
411
+ *
412
+ * SealedRequest - Sealed request messages for GSTP
413
+ *
414
+ * A SealedRequest wraps a Request with sender information and state
415
+ * continuations for secure, authenticated request messages.
416
+ *
417
+ * Ported from gstp-rust/src/sealed_request.rs
418
+ */
419
+ /**
420
+ * Decode a CBOR value into a typed JS value.
421
+ *
422
+ * Mirrors the type-driven `T: TryFrom<CBOR>` dispatch Rust's
423
+ * `extract_object_for_parameter` relies on. TS lacks compile-time
424
+ * trait dispatch, so we hand-roll the most common cases:
425
+ * - tag 1 (`Date`) → JS `Date`,
426
+ * - tag 40012 (`ARID`) → `ARID`,
427
+ * - integer / text / bool / number / byte-string primitives,
428
+ * - everything else → the raw `Cbor` value.
429
+ *
430
+ * Callers needing other typed extraction should use
431
+ * `objectForParameter()` directly and decode the envelope themselves.
432
+ */
433
+ function extractCborAsT(cbor) {
434
+ const tagged = cbor.asTagged();
435
+ if (tagged !== void 0) {
436
+ const [tag] = tagged;
437
+ const tagNumber = Number(tag.value);
438
+ if (tagNumber === 1) return _bcts_dcbor.CborDate.fromTaggedCbor(cbor).datetime();
439
+ if (tagNumber === 40012) return _bcts_components.ARID.fromTaggedCbor(cbor);
440
+ }
441
+ if (cbor.isInteger()) return cbor.toInteger();
442
+ if (cbor.isText()) return cbor.toText();
443
+ if (cbor.isBool()) return cbor.toBool();
444
+ if (cbor.isNumber()) return cbor.toNumber();
445
+ if (cbor.isByteString()) return cbor.toByteString();
446
+ return cbor;
447
+ }
448
+ /**
371
449
  * A sealed request that combines a Request with sender information and
372
450
  * state continuations for secure communication.
373
451
  *
@@ -459,25 +537,32 @@ var SealedRequest = class SealedRequest {
459
537
  }
460
538
  /**
461
539
  * Returns all objects for a parameter.
540
+ *
541
+ * Mirrors Rust `SealedRequest::objects_for_parameter` which delegates
542
+ * to `Expression::objects_for_parameter`. GSTP requests can carry
543
+ * multiple parameters with the same ID — e.g. a DKG invite has
544
+ * one `participant` per group member — and a decoder must see
545
+ * every one of them.
462
546
  */
463
547
  objectsForParameter(param) {
464
- const obj = this._request.body().getParameter(param);
465
- return obj !== void 0 ? [obj] : [];
548
+ return this._request.body().objectsForParameter(param);
466
549
  }
467
550
  /**
468
551
  * Extracts an object for a parameter as a specific type.
552
+ *
553
+ * Mirrors Rust `SealedRequest::extract_object_for_parameter` — Rust
554
+ * uses a `T: TryFrom<CBOR>` constraint and dispatches to whatever
555
+ * `From<CBOR> for T` impl is in scope (e.g. tag-1 CBOR decodes to
556
+ * `chrono::DateTime`, tag-40012 to `ARID`, etc.). TS lacks that
557
+ * trait dispatch, so we recognise the most common tagged types
558
+ * (`Date` via tag 1, `ARID` via tag 40012) plus the primitive
559
+ * fall-through. Callers needing other typed extraction should use
560
+ * `objectForParameter()` directly and decode the envelope themselves.
469
561
  */
470
562
  extractObjectForParameter(param) {
471
563
  const envelope = this.objectForParameter(param);
472
564
  if (envelope === void 0) throw GstpError.envelope(/* @__PURE__ */ new Error(`Parameter not found: ${param}`));
473
- return envelope.extractSubject((cbor) => {
474
- if (cbor.isInteger()) return cbor.toInteger();
475
- if (cbor.isText()) return cbor.toText();
476
- if (cbor.isBool()) return cbor.toBool();
477
- if (cbor.isNumber()) return cbor.toNumber();
478
- if (cbor.isByteString()) return cbor.toByteString();
479
- return cbor;
480
- });
565
+ return envelope.extractSubject((cbor) => extractCborAsT(cbor));
481
566
  }
482
567
  /**
483
568
  * Extracts an optional object for a parameter.
@@ -485,14 +570,7 @@ var SealedRequest = class SealedRequest {
485
570
  extractOptionalObjectForParameter(param) {
486
571
  const envelope = this.objectForParameter(param);
487
572
  if (envelope === void 0) return;
488
- return envelope.extractSubject((cbor) => {
489
- if (cbor.isInteger()) return cbor.toInteger();
490
- if (cbor.isText()) return cbor.toText();
491
- if (cbor.isBool()) return cbor.toBool();
492
- if (cbor.isNumber()) return cbor.toNumber();
493
- if (cbor.isByteString()) return cbor.toByteString();
494
- return cbor;
495
- });
573
+ return envelope.extractSubject((cbor) => extractCborAsT(cbor));
496
574
  }
497
575
  /**
498
576
  * Extracts all objects for a parameter as a specific type.
@@ -624,7 +702,7 @@ var SealedRequest = class SealedRequest {
624
702
  */
625
703
  toEnvelopeForRecipients(validUntil, signer, recipients) {
626
704
  const continuation = new Continuation(this._state ?? _bcts_envelope.Envelope.new(null), this.id(), validUntil);
627
- const senderEncryptionKey = this._sender.inceptionKey()?.publicKeys()?.encapsulationPublicKey();
705
+ const senderEncryptionKey = this._sender.encryptionKey();
628
706
  if (senderEncryptionKey === void 0) throw GstpError.senderMissingEncryptionKey();
629
707
  const senderContinuation = continuation.toEnvelope(senderEncryptionKey);
630
708
  let result = this._request.toEnvelope();
@@ -666,7 +744,7 @@ var SealedRequest = class SealedRequest {
666
744
  } catch (e) {
667
745
  throw GstpError.xid(e instanceof Error ? e : new Error(String(e)));
668
746
  }
669
- const senderVerificationKey = sender.inceptionKey()?.publicKeys()?.signingPublicKey();
747
+ const senderVerificationKey = sender.verificationKey();
670
748
  if (senderVerificationKey === void 0) throw GstpError.senderMissingVerificationKey();
671
749
  let requestEnvelope;
672
750
  try {
@@ -712,7 +790,6 @@ var SealedRequest = class SealedRequest {
712
790
  return true;
713
791
  }
714
792
  };
715
-
716
793
  //#endregion
717
794
  //#region src/sealed-response.ts
718
795
  /**
@@ -929,7 +1006,7 @@ var SealedResponse = class SealedResponse {
929
1006
  let senderContinuation;
930
1007
  if (this._state !== void 0) {
931
1008
  const continuation = new Continuation(this._state, void 0, validUntil);
932
- const senderEncryptionKey = this._sender.inceptionKey()?.publicKeys()?.encapsulationPublicKey();
1009
+ const senderEncryptionKey = this._sender.encryptionKey();
933
1010
  if (senderEncryptionKey === void 0) throw GstpError.senderMissingEncryptionKey();
934
1011
  senderContinuation = continuation.toEnvelope(senderEncryptionKey);
935
1012
  }
@@ -972,7 +1049,7 @@ var SealedResponse = class SealedResponse {
972
1049
  } catch (e) {
973
1050
  throw GstpError.xid(e instanceof Error ? e : new Error(String(e)));
974
1051
  }
975
- const senderVerificationKey = sender.inceptionKey()?.publicKeys()?.signingPublicKey();
1052
+ const senderVerificationKey = sender.verificationKey();
976
1053
  if (senderVerificationKey === void 0) throw GstpError.senderMissingVerificationKey();
977
1054
  let responseEnvelope;
978
1055
  try {
@@ -1022,7 +1099,6 @@ var SealedResponse = class SealedResponse {
1022
1099
  return true;
1023
1100
  }
1024
1101
  };
1025
-
1026
1102
  //#endregion
1027
1103
  //#region src/sealed-event.ts
1028
1104
  /**
@@ -1192,7 +1268,7 @@ var SealedEvent = class SealedEvent {
1192
1268
  * @returns The sealed event as an envelope
1193
1269
  */
1194
1270
  toEnvelopeForRecipients(validUntil, signer, recipients) {
1195
- const senderEncryptionKey = this._sender.inceptionKey()?.publicKeys()?.encapsulationPublicKey();
1271
+ const senderEncryptionKey = this._sender.encryptionKey();
1196
1272
  if (senderEncryptionKey === void 0) throw GstpError.senderMissingEncryptionKey();
1197
1273
  let senderContinuation;
1198
1274
  if (this._state !== void 0) senderContinuation = new Continuation(this._state, void 0, validUntil).toEnvelope(senderEncryptionKey);
@@ -1237,7 +1313,7 @@ var SealedEvent = class SealedEvent {
1237
1313
  } catch (e) {
1238
1314
  throw GstpError.xid(e instanceof Error ? e : new Error(String(e)));
1239
1315
  }
1240
- const senderVerificationKey = sender.inceptionKey()?.publicKeys()?.signingPublicKey();
1316
+ const senderVerificationKey = sender.verificationKey();
1241
1317
  if (senderVerificationKey === void 0) throw GstpError.senderMissingVerificationKey();
1242
1318
  let eventEnvelope;
1243
1319
  try {
@@ -1284,7 +1360,6 @@ var SealedEvent = class SealedEvent {
1284
1360
  return true;
1285
1361
  }
1286
1362
  };
1287
-
1288
1363
  //#endregion
1289
1364
  //#region src/prelude.ts
1290
1365
  var prelude_exports = /* @__PURE__ */ __exportAll({
@@ -1295,11 +1370,9 @@ var prelude_exports = /* @__PURE__ */ __exportAll({
1295
1370
  SealedRequest: () => SealedRequest,
1296
1371
  SealedResponse: () => SealedResponse
1297
1372
  });
1298
-
1299
1373
  //#endregion
1300
1374
  //#region src/index.ts
1301
1375
  const VERSION = "0.13.0";
1302
-
1303
1376
  //#endregion
1304
1377
  exports.Continuation = Continuation;
1305
1378
  exports.GstpError = GstpError;
@@ -1308,10 +1381,11 @@ exports.SealedEvent = SealedEvent;
1308
1381
  exports.SealedRequest = SealedRequest;
1309
1382
  exports.SealedResponse = SealedResponse;
1310
1383
  exports.VERSION = VERSION;
1311
- Object.defineProperty(exports, 'prelude', {
1312
- enumerable: true,
1313
- get: function () {
1314
- return prelude_exports;
1315
- }
1384
+ Object.defineProperty(exports, "prelude", {
1385
+ enumerable: true,
1386
+ get: function() {
1387
+ return prelude_exports;
1388
+ }
1316
1389
  });
1390
+
1317
1391
  //# sourceMappingURL=index.cjs.map