@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.
@@ -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 = [
@@ -57,8 +79,12 @@ var EMAIL_PROOF_ISSUER_KEYS = [
57
79
  }
58
80
  ];
59
81
  var PROFILE_PINS = {
60
- "tinycloud.email-proof/v1": { descriptorDigest: EMAIL_PROOF_PINS.descriptorDigest, requiredStep: "mailbox_otp", enabled: true }
82
+ "tinycloud.email-proof/v1": { descriptorDigest: EMAIL_PROOF_PINS.descriptorDigest, requiredStep: "mailbox_otp", enabled: true },
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 }
61
86
  };
87
+ var OPENER_ORIGIN = HELD_ACCOUNT_BINDING_PINS.openerOrigin;
62
88
  var INSPECT = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
63
89
  function restoreEmailProofPending(fields) {
64
90
  const shown = {
@@ -72,7 +98,8 @@ function restoreEmailProofPending(fields) {
72
98
  requirementDigest: fields.requirementDigest,
73
99
  openerOrigin: fields.openerOrigin,
74
100
  createdAt: fields.createdAt,
75
- expiresAt: fields.expiresAt
101
+ expiresAt: fields.expiresAt,
102
+ ...fields.serverExpiresAt === void 0 ? {} : { serverExpiresAt: fields.serverExpiresAt }
76
103
  };
77
104
  const pending = { ...shown };
78
105
  hide(pending, "verifier", fields.verifier);
@@ -115,6 +142,7 @@ var FILE_TEXT_FIELDS = [
115
142
  "createdAt",
116
143
  "expiresAt"
117
144
  ];
145
+ var HELD_PROFILE_ID = "tinycloud.email-held/v1";
118
146
  var secrets = /* @__PURE__ */ new WeakMap();
119
147
  function sha256Hex(text) {
120
148
  return createHash("sha256").update(text).digest("hex");
@@ -269,6 +297,11 @@ function isFileRecord(value) {
269
297
  if (record.type !== "TinyCloudEmailProofPending" || record.version !== 1) return false;
270
298
  if (!FILE_TEXT_FIELDS.every((field) => typeof record[field] === "string")) return false;
271
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
+ }
272
305
  return Number.isFinite(Date.parse(record.createdAt)) && Number.isFinite(Date.parse(record.expiresAt));
273
306
  }
274
307
  function restoreFromFile(record) {
@@ -284,7 +317,8 @@ function restoreFromFile(record) {
284
317
  requirementDigest: record.requirementDigest,
285
318
  openerOrigin: record.openerOrigin,
286
319
  createdAt: record.createdAt,
287
- expiresAt: record.expiresAt
320
+ expiresAt: record.expiresAt,
321
+ ...record.serverExpiresAt === void 0 ? {} : { serverExpiresAt: record.serverExpiresAt }
288
322
  });
289
323
  }
290
324
  function readEntry(home, file, now) {
@@ -330,6 +364,7 @@ function toFileRecord(pending, secret) {
330
364
  openerOrigin: pending.openerOrigin,
331
365
  createdAt: pending.createdAt,
332
366
  expiresAt: pending.expiresAt,
367
+ ...pending.serverExpiresAt === void 0 ? {} : { serverExpiresAt: pending.serverExpiresAt },
333
368
  ...secret === void 0 ? {} : { secret: Buffer.from(secret).toString("base64") }
334
369
  };
335
370
  }
@@ -360,7 +395,11 @@ function createFileEmailProofPendingStore(options) {
360
395
  if (exceedsWindow(pending)) {
361
396
  throw new PendingStoreError("credential-store-invalid", "Pending record expires beyond the 15-minute window and was rejected.");
362
397
  }
363
- 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);
364
403
  });
365
404
  },
366
405
  async delete(requestId) {