@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.
@@ -5,30 +5,59 @@ import * as path from "path";
5
5
 
6
6
  // src/credentials/email-proof.ts
7
7
  import {
8
- canonicalDigest as canonicalDigest2,
8
+ canonicalDigest as canonicalDigest3,
9
9
  createEmailCredentialRequirement,
10
10
  credentialError,
11
11
  credentialRequirementDigest,
12
- CredentialError as CredentialError3,
12
+ CredentialError as CredentialError4,
13
13
  descriptorSatisfiesRequirement,
14
14
  encodeBase64Url as encodeBase64Url3,
15
15
  sha256Base64Url as sha256Base64Url2,
16
16
  validateCredentialFlowDescriptor,
17
+ validateCredentialRequirement,
17
18
  verifyIssuedCredential
18
19
  } from "@tinycloud/sdk-core";
20
+ import { parseIssuerSet, parsePkhDid, toChecksumAddress, verifyHeldEmailCredential } from "@tinycloud/sdk-core/held-credentials";
19
21
 
20
22
  // src/credentials/interpreter.ts
21
23
  import {
22
- CredentialError,
24
+ CredentialError as CredentialError2,
23
25
  encodeBase64Url,
24
26
  holderBindingSigningBytes,
25
27
  validateCredentialHolderBinding
26
28
  } from "@tinycloud/sdk-core";
27
29
 
30
+ // src/credentials/held-binding.ts
31
+ import { canonicalDigest, CredentialError } from "@tinycloud/sdk-core";
32
+
33
+ // src/credentials/pins.ts
34
+ import { ACCOUNT_HOLDER_BINDING_DOMAIN } from "@tinycloud/sdk-core";
35
+ var EMAIL_PROOF_PINS = Object.freeze({
36
+ witnessOrigin: "https://witness.credentials.org",
37
+ issuerDid: "did:web:issuer.credentials.org",
38
+ issuerKid: "did:web:issuer.credentials.org#controller",
39
+ issuerX: "eEJI4xEobto4HtQ7Pg9R1vBOwcpfGRTlXDG5QfqLnGQ",
40
+ descriptorDigest: "1tg-qphmKBVtNwzVg9xyz-xxqt_xtMXAsQyXw46m8S0"
41
+ });
42
+ var HELD_ACCOUNT_BINDING_PINS = Object.freeze({
43
+ type: ACCOUNT_HOLDER_BINDING_DOMAIN,
44
+ protocol: "tinycloud.credentials/acquisition/v1",
45
+ profile: "tinycloud.email-held/v1",
46
+ profileVersion: 1,
47
+ descriptorDigest: "dc3_DuvzipXwYkTfjKqTaK1c3VS0YSPnaBsYSQriC0w",
48
+ issuer: EMAIL_PROOF_PINS.issuerDid,
49
+ issuerKid: EMAIL_PROOF_PINS.issuerKid,
50
+ audience: "tinycloud://credentials",
51
+ openerOrigin: "https://localhost",
52
+ completionOrigin: "https://localhost",
53
+ completionContext: "sdk-acquisition",
54
+ credentialLifetimeSeconds: 31536e3
55
+ });
56
+
28
57
  // src/credentials/transport.ts
29
58
  import {
30
- CredentialError as CredentialError2,
31
- canonicalDigest,
59
+ CredentialError as CredentialError3,
60
+ canonicalDigest as canonicalDigest2,
32
61
  credentialEndpointPath,
33
62
  decodeBase64Url,
34
63
  encodeBase64Url as encodeBase64Url2,
@@ -38,13 +67,6 @@ import {
38
67
  } from "@tinycloud/sdk-core";
39
68
 
40
69
  // src/credentials/email-proof.ts
41
- var EMAIL_PROOF_PINS = Object.freeze({
42
- witnessOrigin: "https://witness.credentials.org",
43
- issuerDid: "did:web:issuer.credentials.org",
44
- issuerKid: "did:web:issuer.credentials.org#controller",
45
- issuerX: "eEJI4xEobto4HtQ7Pg9R1vBOwcpfGRTlXDG5QfqLnGQ",
46
- descriptorDigest: "1tg-qphmKBVtNwzVg9xyz-xxqt_xtMXAsQyXw46m8S0"
47
- });
48
70
  var EMAIL_PROOF_PENDING_MAX_MS = 15 * 6e4;
49
71
  var DISCOVERY_URL = `${EMAIL_PROOF_PINS.witnessOrigin}/.well-known/opencredentials`;
50
72
  var EMAIL_PROOF_ISSUER_KEYS = [
@@ -58,9 +80,11 @@ var EMAIL_PROOF_ISSUER_KEYS = [
58
80
  ];
59
81
  var PROFILE_PINS = {
60
82
  "tinycloud.email-proof/v1": { descriptorDigest: EMAIL_PROOF_PINS.descriptorDigest, requiredStep: "mailbox_otp", enabled: true },
61
- // Held profile: disabled until the held wire path ships. Requests refuse with PROFILE_UNAVAILABLE before any network call.
62
- "tinycloud.email-held/v1": { descriptorDigest: "dc3_DuvzipXwYkTfjKqTaK1c3VS0YSPnaBsYSQriC0w", requiredStep: "mailbox_otp", enabled: false }
83
+ // Held profile: disabled by default. A call enables it only with the per-call opt-in `allowHeldProfile: true` (see `profilePin`).
84
+ // Without it, requests refuse with PROFILE_UNAVAILABLE before any network call.
85
+ "tinycloud.email-held/v1": { descriptorDigest: HELD_ACCOUNT_BINDING_PINS.descriptorDigest, requiredStep: "mailbox_otp", enabled: false }
63
86
  };
87
+ var OPENER_ORIGIN = HELD_ACCOUNT_BINDING_PINS.openerOrigin;
64
88
  var INSPECT = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
65
89
  function restoreEmailProofPending(fields) {
66
90
  const shown = {
@@ -74,7 +98,8 @@ function restoreEmailProofPending(fields) {
74
98
  requirementDigest: fields.requirementDigest,
75
99
  openerOrigin: fields.openerOrigin,
76
100
  createdAt: fields.createdAt,
77
- expiresAt: fields.expiresAt
101
+ expiresAt: fields.expiresAt,
102
+ ...fields.serverExpiresAt === void 0 ? {} : { serverExpiresAt: fields.serverExpiresAt }
78
103
  };
79
104
  const pending = { ...shown };
80
105
  hide(pending, "verifier", fields.verifier);
@@ -117,6 +142,7 @@ var FILE_TEXT_FIELDS = [
117
142
  "createdAt",
118
143
  "expiresAt"
119
144
  ];
145
+ var HELD_PROFILE_ID = "tinycloud.email-held/v1";
120
146
  var secrets = /* @__PURE__ */ new WeakMap();
121
147
  function sha256Hex(text) {
122
148
  return createHash("sha256").update(text).digest("hex");
@@ -271,6 +297,11 @@ function isFileRecord(value) {
271
297
  if (record.type !== "TinyCloudEmailProofPending" || record.version !== 1) return false;
272
298
  if (!FILE_TEXT_FIELDS.every((field) => typeof record[field] === "string")) return false;
273
299
  if (record.secret !== void 0 && (typeof record.secret !== "string" || !BASE64.test(record.secret))) return false;
300
+ if (record.profile === HELD_PROFILE_ID) {
301
+ if (typeof record.serverExpiresAt !== "string" || !Number.isFinite(Date.parse(record.serverExpiresAt))) return false;
302
+ } else if (record.serverExpiresAt !== void 0) {
303
+ return false;
304
+ }
274
305
  return Number.isFinite(Date.parse(record.createdAt)) && Number.isFinite(Date.parse(record.expiresAt));
275
306
  }
276
307
  function restoreFromFile(record) {
@@ -286,7 +317,8 @@ function restoreFromFile(record) {
286
317
  requirementDigest: record.requirementDigest,
287
318
  openerOrigin: record.openerOrigin,
288
319
  createdAt: record.createdAt,
289
- expiresAt: record.expiresAt
320
+ expiresAt: record.expiresAt,
321
+ ...record.serverExpiresAt === void 0 ? {} : { serverExpiresAt: record.serverExpiresAt }
290
322
  });
291
323
  }
292
324
  function readEntry(home, file, now) {
@@ -332,6 +364,7 @@ function toFileRecord(pending, secret) {
332
364
  openerOrigin: pending.openerOrigin,
333
365
  createdAt: pending.createdAt,
334
366
  expiresAt: pending.expiresAt,
367
+ ...pending.serverExpiresAt === void 0 ? {} : { serverExpiresAt: pending.serverExpiresAt },
335
368
  ...secret === void 0 ? {} : { secret: Buffer.from(secret).toString("base64") }
336
369
  };
337
370
  }
@@ -362,7 +395,11 @@ function createFileEmailProofPendingStore(options) {
362
395
  if (exceedsWindow(pending)) {
363
396
  throw new PendingStoreError("credential-store-invalid", "Pending record expires beyond the 15-minute window and was rejected.");
364
397
  }
365
- writeOwnerOnly(home, pendingFile(home, pending.requestId), toFileRecord(pending, putOptions?.secret));
398
+ const record = toFileRecord(pending, putOptions?.secret);
399
+ if (!isFileRecord(record)) {
400
+ throw new PendingStoreError("credential-store-invalid", "Pending record is not a valid held or ticket record and was rejected.");
401
+ }
402
+ writeOwnerOnly(home, pendingFile(home, pending.requestId), record);
366
403
  });
367
404
  },
368
405
  async delete(requestId) {