@tinycloud/node-sdk 3.8.1-beta.2 → 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 = [
@@ -70,8 +91,12 @@ var EMAIL_PROOF_ISSUER_KEYS = [
70
91
  }
71
92
  ];
72
93
  var PROFILE_PINS = {
73
- "tinycloud.email-proof/v1": { descriptorDigest: EMAIL_PROOF_PINS.descriptorDigest, requiredStep: "mailbox_otp", enabled: true }
94
+ "tinycloud.email-proof/v1": { descriptorDigest: EMAIL_PROOF_PINS.descriptorDigest, requiredStep: "mailbox_otp", enabled: true },
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 }
74
98
  };
99
+ var OPENER_ORIGIN = HELD_ACCOUNT_BINDING_PINS.openerOrigin;
75
100
  var INSPECT = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
76
101
  function restoreEmailProofPending(fields) {
77
102
  const shown = {
@@ -85,7 +110,8 @@ function restoreEmailProofPending(fields) {
85
110
  requirementDigest: fields.requirementDigest,
86
111
  openerOrigin: fields.openerOrigin,
87
112
  createdAt: fields.createdAt,
88
- expiresAt: fields.expiresAt
113
+ expiresAt: fields.expiresAt,
114
+ ...fields.serverExpiresAt === void 0 ? {} : { serverExpiresAt: fields.serverExpiresAt }
89
115
  };
90
116
  const pending = { ...shown };
91
117
  hide(pending, "verifier", fields.verifier);
@@ -128,6 +154,7 @@ var FILE_TEXT_FIELDS = [
128
154
  "createdAt",
129
155
  "expiresAt"
130
156
  ];
157
+ var HELD_PROFILE_ID = "tinycloud.email-held/v1";
131
158
  var secrets = /* @__PURE__ */ new WeakMap();
132
159
  function sha256Hex(text) {
133
160
  return (0, import_node_crypto.createHash)("sha256").update(text).digest("hex");
@@ -282,6 +309,11 @@ function isFileRecord(value) {
282
309
  if (record.type !== "TinyCloudEmailProofPending" || record.version !== 1) return false;
283
310
  if (!FILE_TEXT_FIELDS.every((field) => typeof record[field] === "string")) return false;
284
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
+ }
285
317
  return Number.isFinite(Date.parse(record.createdAt)) && Number.isFinite(Date.parse(record.expiresAt));
286
318
  }
287
319
  function restoreFromFile(record) {
@@ -297,7 +329,8 @@ function restoreFromFile(record) {
297
329
  requirementDigest: record.requirementDigest,
298
330
  openerOrigin: record.openerOrigin,
299
331
  createdAt: record.createdAt,
300
- expiresAt: record.expiresAt
332
+ expiresAt: record.expiresAt,
333
+ ...record.serverExpiresAt === void 0 ? {} : { serverExpiresAt: record.serverExpiresAt }
301
334
  });
302
335
  }
303
336
  function readEntry(home, file, now) {
@@ -343,6 +376,7 @@ function toFileRecord(pending, secret) {
343
376
  openerOrigin: pending.openerOrigin,
344
377
  createdAt: pending.createdAt,
345
378
  expiresAt: pending.expiresAt,
379
+ ...pending.serverExpiresAt === void 0 ? {} : { serverExpiresAt: pending.serverExpiresAt },
346
380
  ...secret === void 0 ? {} : { secret: Buffer.from(secret).toString("base64") }
347
381
  };
348
382
  }
@@ -373,7 +407,11 @@ function createFileEmailProofPendingStore(options) {
373
407
  if (exceedsWindow(pending)) {
374
408
  throw new PendingStoreError("credential-store-invalid", "Pending record expires beyond the 15-minute window and was rejected.");
375
409
  }
376
- 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);
377
415
  });
378
416
  },
379
417
  async delete(requestId) {