@tinycloud/node-sdk 3.9.0-beta.3 → 3.9.0-beta.4

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.
@@ -42,15 +42,17 @@ var fs = __toESM(require("fs"), 1);
42
42
  var path = __toESM(require("path"), 1);
43
43
 
44
44
  // src/credentials/email-proof.ts
45
- var import_sdk_core3 = require("@tinycloud/sdk-core");
45
+ var import_sdk_core5 = require("@tinycloud/sdk-core");
46
+ var import_held_credentials = require("@tinycloud/sdk-core/held-credentials");
46
47
 
47
48
  // src/credentials/interpreter.ts
48
- var import_sdk_core = require("@tinycloud/sdk-core");
49
+ var import_sdk_core3 = require("@tinycloud/sdk-core");
49
50
 
50
- // src/credentials/transport.ts
51
+ // src/credentials/held-binding.ts
51
52
  var import_sdk_core2 = require("@tinycloud/sdk-core");
52
53
 
53
- // src/credentials/email-proof.ts
54
+ // src/credentials/pins.ts
55
+ var import_sdk_core = require("@tinycloud/sdk-core");
54
56
  var EMAIL_PROOF_PINS = Object.freeze({
55
57
  witnessOrigin: "https://witness.credentials.org",
56
58
  issuerDid: "did:web:issuer.credentials.org",
@@ -58,6 +60,25 @@ var EMAIL_PROOF_PINS = Object.freeze({
58
60
  issuerX: "eEJI4xEobto4HtQ7Pg9R1vBOwcpfGRTlXDG5QfqLnGQ",
59
61
  descriptorDigest: "1tg-qphmKBVtNwzVg9xyz-xxqt_xtMXAsQyXw46m8S0"
60
62
  });
63
+ var HELD_ACCOUNT_BINDING_PINS = Object.freeze({
64
+ type: import_sdk_core.ACCOUNT_HOLDER_BINDING_DOMAIN,
65
+ protocol: "tinycloud.credentials/acquisition/v1",
66
+ profile: "tinycloud.email-held/v1",
67
+ profileVersion: 1,
68
+ descriptorDigest: "dc3_DuvzipXwYkTfjKqTaK1c3VS0YSPnaBsYSQriC0w",
69
+ issuer: EMAIL_PROOF_PINS.issuerDid,
70
+ issuerKid: EMAIL_PROOF_PINS.issuerKid,
71
+ audience: "tinycloud://credentials",
72
+ openerOrigin: "https://localhost",
73
+ completionOrigin: "https://localhost",
74
+ completionContext: "sdk-acquisition",
75
+ credentialLifetimeSeconds: 31536e3
76
+ });
77
+
78
+ // src/credentials/transport.ts
79
+ var import_sdk_core4 = require("@tinycloud/sdk-core");
80
+
81
+ // src/credentials/email-proof.ts
61
82
  var EMAIL_PROOF_PENDING_MAX_MS = 15 * 6e4;
62
83
  var DISCOVERY_URL = `${EMAIL_PROOF_PINS.witnessOrigin}/.well-known/opencredentials`;
63
84
  var EMAIL_PROOF_ISSUER_KEYS = [
@@ -71,9 +92,11 @@ var EMAIL_PROOF_ISSUER_KEYS = [
71
92
  ];
72
93
  var PROFILE_PINS = {
73
94
  "tinycloud.email-proof/v1": { descriptorDigest: EMAIL_PROOF_PINS.descriptorDigest, requiredStep: "mailbox_otp", enabled: true },
74
- // Held profile: disabled until the held wire path ships. Requests refuse with PROFILE_UNAVAILABLE before any network call.
75
- "tinycloud.email-held/v1": { descriptorDigest: "dc3_DuvzipXwYkTfjKqTaK1c3VS0YSPnaBsYSQriC0w", requiredStep: "mailbox_otp", enabled: false }
95
+ // Held profile: disabled by default. A call enables it only with the per-call opt-in `allowHeldProfile: true` (see `profilePin`).
96
+ // Without it, requests refuse with PROFILE_UNAVAILABLE before any network call.
97
+ "tinycloud.email-held/v1": { descriptorDigest: HELD_ACCOUNT_BINDING_PINS.descriptorDigest, requiredStep: "mailbox_otp", enabled: false }
76
98
  };
99
+ var OPENER_ORIGIN = HELD_ACCOUNT_BINDING_PINS.openerOrigin;
77
100
  var INSPECT = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
78
101
  function restoreEmailProofPending(fields) {
79
102
  const shown = {
@@ -87,7 +110,8 @@ function restoreEmailProofPending(fields) {
87
110
  requirementDigest: fields.requirementDigest,
88
111
  openerOrigin: fields.openerOrigin,
89
112
  createdAt: fields.createdAt,
90
- expiresAt: fields.expiresAt
113
+ expiresAt: fields.expiresAt,
114
+ ...fields.serverExpiresAt === void 0 ? {} : { serverExpiresAt: fields.serverExpiresAt }
91
115
  };
92
116
  const pending = { ...shown };
93
117
  hide(pending, "verifier", fields.verifier);
@@ -130,6 +154,7 @@ var FILE_TEXT_FIELDS = [
130
154
  "createdAt",
131
155
  "expiresAt"
132
156
  ];
157
+ var HELD_PROFILE_ID = "tinycloud.email-held/v1";
133
158
  var secrets = /* @__PURE__ */ new WeakMap();
134
159
  function sha256Hex(text) {
135
160
  return (0, import_node_crypto.createHash)("sha256").update(text).digest("hex");
@@ -284,6 +309,11 @@ function isFileRecord(value) {
284
309
  if (record.type !== "TinyCloudEmailProofPending" || record.version !== 1) return false;
285
310
  if (!FILE_TEXT_FIELDS.every((field) => typeof record[field] === "string")) return false;
286
311
  if (record.secret !== void 0 && (typeof record.secret !== "string" || !BASE64.test(record.secret))) return false;
312
+ if (record.profile === HELD_PROFILE_ID) {
313
+ if (typeof record.serverExpiresAt !== "string" || !Number.isFinite(Date.parse(record.serverExpiresAt))) return false;
314
+ } else if (record.serverExpiresAt !== void 0) {
315
+ return false;
316
+ }
287
317
  return Number.isFinite(Date.parse(record.createdAt)) && Number.isFinite(Date.parse(record.expiresAt));
288
318
  }
289
319
  function restoreFromFile(record) {
@@ -299,7 +329,8 @@ function restoreFromFile(record) {
299
329
  requirementDigest: record.requirementDigest,
300
330
  openerOrigin: record.openerOrigin,
301
331
  createdAt: record.createdAt,
302
- expiresAt: record.expiresAt
332
+ expiresAt: record.expiresAt,
333
+ ...record.serverExpiresAt === void 0 ? {} : { serverExpiresAt: record.serverExpiresAt }
303
334
  });
304
335
  }
305
336
  function readEntry(home, file, now) {
@@ -345,6 +376,7 @@ function toFileRecord(pending, secret) {
345
376
  openerOrigin: pending.openerOrigin,
346
377
  createdAt: pending.createdAt,
347
378
  expiresAt: pending.expiresAt,
379
+ ...pending.serverExpiresAt === void 0 ? {} : { serverExpiresAt: pending.serverExpiresAt },
348
380
  ...secret === void 0 ? {} : { secret: Buffer.from(secret).toString("base64") }
349
381
  };
350
382
  }
@@ -375,7 +407,11 @@ function createFileEmailProofPendingStore(options) {
375
407
  if (exceedsWindow(pending)) {
376
408
  throw new PendingStoreError("credential-store-invalid", "Pending record expires beyond the 15-minute window and was rejected.");
377
409
  }
378
- writeOwnerOnly(home, pendingFile(home, pending.requestId), toFileRecord(pending, putOptions?.secret));
410
+ const record = toFileRecord(pending, putOptions?.secret);
411
+ if (!isFileRecord(record)) {
412
+ throw new PendingStoreError("credential-store-invalid", "Pending record is not a valid held or ticket record and was rejected.");
413
+ }
414
+ writeOwnerOnly(home, pendingFile(home, pending.requestId), record);
379
415
  });
380
416
  },
381
417
  async delete(requestId) {