@tinycloud/sdk-core 3.0.0-beta.1 → 3.0.0-beta.10

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.
package/dist/index.cjs CHANGED
@@ -64,6 +64,7 @@ __export(index_exports, {
64
64
  CREDENTIAL_CONTRACT_VERSION: () => CREDENTIAL_CONTRACT_VERSION,
65
65
  CREDENTIAL_ERROR_CODES: () => CREDENTIAL_ERROR_CODES,
66
66
  CREDENTIAL_FORMAT: () => CREDENTIAL_FORMAT,
67
+ CREDENTIAL_INVITATION_REQUEST_DOMAIN: () => CREDENTIAL_INVITATION_REQUEST_DOMAIN,
67
68
  CREDENTIAL_PROTOCOL: () => CREDENTIAL_ACQUISITION_PROTOCOL,
68
69
  CREDENTIAL_STEP_REGISTRY_VERSION: () => CREDENTIAL_STEP_REGISTRY_VERSION,
69
70
  CapabilityKeyRegistry: () => CapabilityKeyRegistry,
@@ -87,6 +88,7 @@ __export(index_exports, {
87
88
  DEFAULT_SIGNED_READ_URL_EXPIRY_MS: () => DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
88
89
  DEFAULT_TINYCLOUD_FALLBACK_HOST: () => DEFAULT_TINYCLOUD_FALLBACK_HOST,
89
90
  DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL: () => DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL,
91
+ DELIVERY_ADMISSION_DOMAIN: () => DELIVERY_ADMISSION_DOMAIN,
90
92
  DUCKDB: () => import_bootstrap4.DUCKDB,
91
93
  DataVaultService: () => import_sdk_services8.DataVaultService,
92
94
  DatabaseHandle: () => import_sdk_services8.DatabaseHandle,
@@ -98,6 +100,7 @@ __export(index_exports, {
98
100
  DuckDbService: () => import_sdk_services8.DuckDbService,
99
101
  ED25519_JCS_SIGNATURE_SUITE: () => ED25519_JCS_SIGNATURE_SUITE,
100
102
  EIP191_JCS_SIGNATURE_SUITE: () => EIP191_JCS_SIGNATURE_SUITE,
103
+ EMAIL_CREDENTIAL_MAX_AGE_SECONDS: () => EMAIL_CREDENTIAL_MAX_AGE_SECONDS,
101
104
  ENCRYPTION: () => import_bootstrap4.ENCRYPTION,
102
105
  ENCRYPTION_MANIFEST_SPACE: () => ENCRYPTION_MANIFEST_SPACE,
103
106
  ENCRYPTION_NETWORK_URN_PREFIX: () => import_sdk_services8.ENCRYPTION_NETWORK_URN_PREFIX,
@@ -136,6 +139,7 @@ __export(index_exports, {
136
139
  NETWORK_NAME_PATTERN: () => import_sdk_services8.NETWORK_NAME_PATTERN,
137
140
  NetworkIdError: () => import_sdk_services8.NetworkIdError,
138
141
  OPENKEY_ACTION_ID_SEPARATOR: () => OPENKEY_ACTION_ID_SEPARATOR,
142
+ OWNER_NODE_BINDING_TIMEOUT_MS: () => OWNER_NODE_BINDING_TIMEOUT_MS,
139
143
  OpenKeyManageKeyError: () => OpenKeyManageKeyError,
140
144
  POLICY_CAPABILITY_V1_DOMAIN: () => POLICY_CAPABILITY_V1_DOMAIN,
141
145
  POLICY_CAPABILITY_V1_SCHEMA: () => POLICY_CAPABILITY_V1_SCHEMA,
@@ -149,6 +153,8 @@ __export(index_exports, {
149
153
  POLICY_ENGINE_RESOLVE_REQUEST_SCHEMA: () => POLICY_ENGINE_RESOLVE_REQUEST_SCHEMA,
150
154
  POLICY_PRESENTATION_V3_DOMAIN: () => POLICY_PRESENTATION_V3_DOMAIN,
151
155
  POLICY_PRESENTATION_V3_SCHEMA: () => POLICY_PRESENTATION_V3_SCHEMA,
156
+ POLICY_PRESENTATION_V4_DOMAIN: () => POLICY_PRESENTATION_V4_DOMAIN,
157
+ POLICY_PRESENTATION_V4_SCHEMA: () => POLICY_PRESENTATION_V4_SCHEMA,
152
158
  POLICY_SCHEMA: () => POLICY_SCHEMA,
153
159
  POLICY_SESSION_UCAN_V1_PROFILE: () => POLICY_SESSION_UCAN_V1_PROFILE,
154
160
  POLICY_STATUS_SCHEMA: () => POLICY_STATUS_SCHEMA,
@@ -173,7 +179,6 @@ __export(index_exports, {
173
179
  SECRET_RECORDS_SCHEMA: () => import_bootstrap4.SECRET_RECORDS_SCHEMA,
174
180
  SERVICE_LONG_TO_SHORT: () => SERVICE_LONG_TO_SHORT,
175
181
  SERVICE_SHORT_TO_LONG: () => SERVICE_SHORT_TO_LONG,
176
- SHARE_DELIVERY_AUTHORIZATION_DOMAIN: () => SHARE_DELIVERY_AUTHORIZATION_DOMAIN,
177
182
  SPACE: () => import_bootstrap4.SPACE,
178
183
  SQL: () => import_bootstrap4.SQL,
179
184
  SQLAction: () => import_sdk_services8.SQLAction,
@@ -226,6 +231,7 @@ __export(index_exports, {
226
231
  activateSessionWithHost: () => activateSessionWithHost,
227
232
  addressStorageKey: () => addressStorageKey,
228
233
  admitPolicyCredentialV3: () => admitPolicyCredentialV3,
234
+ admitPolicyCredentialV4: () => admitPolicyCredentialV4,
229
235
  applyPrefix: () => applyPrefix,
230
236
  bootstrapEncryptionNetworkId: () => import_bootstrap4.bootstrapEncryptionNetworkId,
231
237
  bootstrapSpaceId: () => import_bootstrap4.bootstrapSpaceId,
@@ -236,6 +242,7 @@ __export(index_exports, {
236
242
  buildDecryptInvocation: () => import_sdk_services8.buildDecryptInvocation,
237
243
  buildNetworkId: () => import_sdk_services8.buildNetworkId,
238
244
  buildPolicyCredentialPresentationV3: () => buildPolicyCredentialPresentationV3,
245
+ buildPolicyCredentialPresentationV4: () => buildPolicyCredentialPresentationV4,
239
246
  buildSpaceUri: () => buildSpaceUri,
240
247
  canonicalDigest: () => canonicalDigest,
241
248
  canonicalHashHex: () => import_sdk_services8.canonicalHashHex,
@@ -266,6 +273,7 @@ __export(index_exports, {
266
273
  createAndSignSignedObject: () => createAndSignSignedObject,
267
274
  createCapabilityKeyRegistry: () => createCapabilityKeyRegistry,
268
275
  createDelegatedShareKey: () => createDelegatedShareKey,
276
+ createEmailCredentialRequirement: () => createEmailCredentialRequirement,
269
277
  createHolderBinding: () => createHolderBinding,
270
278
  createInMemoryLocalNodeIdentityStore: () => createInMemoryLocalNodeIdentityStore,
271
279
  createLocalStorageLocalNodeIdentityStore: () => createLocalStorageLocalNodeIdentityStore,
@@ -344,6 +352,7 @@ __export(index_exports, {
344
352
  isNetworkId: () => import_sdk_services8.isNetworkId,
345
353
  isPlausibleOpenKeyActionId: () => isPlausibleOpenKeyActionId,
346
354
  isV2ShareLink: () => isV2ShareLink,
355
+ issuedCredentialEnvelopeFromVerified: () => issuedCredentialEnvelopeFromVerified,
347
356
  jcsCanonicalize: () => jcsCanonicalize,
348
357
  loadManifest: () => loadManifest,
349
358
  locationPayloadForRecord: () => locationPayloadForRecord,
@@ -372,6 +381,7 @@ __export(index_exports, {
372
381
  parsePolicySessionUcan: () => parsePolicySessionUcan,
373
382
  parsePortableDelegation: () => parsePortableDelegation,
374
383
  parseRecapCapabilities: () => parseRecapCapabilities,
384
+ parseSecretCatalogKey: () => import_sdk_services8.parseSecretCatalogKey,
375
385
  parseShareArtifact: () => parseShareArtifact,
376
386
  parseShareUrl: () => parseShareUrl,
377
387
  parseSpaceUri: () => parseSpaceUri,
@@ -384,7 +394,9 @@ __export(index_exports, {
384
394
  principalDidEquals: () => principalDidEquals,
385
395
  projectUnifiedPolicyCapabilities: () => projectUnifiedPolicyCapabilities,
386
396
  projectUnifiedPolicyCapability: () => projectUnifiedPolicyCapability,
397
+ publishLocationRecord: () => publishLocationRecord,
387
398
  recapCaveatsEqual: () => recapCaveatsEqual,
399
+ registerPolicyV3: () => registerPolicyV3,
388
400
  renewPolicyRootStatusV3: () => renewPolicyRootStatusV3,
389
401
  requestTinyCloudManageKeyScope: () => requestTinyCloudManageKeyScope,
390
402
  resolveCloudLocation: () => resolveCloudLocation,
@@ -402,10 +414,10 @@ __export(index_exports, {
402
414
  serviceError: () => import_sdk_services8.serviceError,
403
415
  sha256Base64Url: () => sha256Base64Url,
404
416
  shareCapabilityAllows: () => shareCapabilityAllows,
405
- shareDeliveryTrustedKid: () => shareDeliveryTrustedKid,
406
417
  signCompactUcanAuthorization: () => signCompactUcanAuthorization,
407
418
  signCompactUcanRootAuthorization: () => signCompactUcanRootAuthorization,
408
419
  signLocationRecord: () => signLocationRecord,
420
+ signPolicyCredentialPresentationV4: () => signPolicyCredentialPresentationV4,
409
421
  signShareEnvelope: () => signShareEnvelope,
410
422
  signedObjectIdFor: () => signedObjectIdFor,
411
423
  submitHostDelegation: () => submitHostDelegation,
@@ -438,13 +450,14 @@ __export(index_exports, {
438
450
  validatePolicyStatusSignedShape: () => validatePolicyStatusSignedShape,
439
451
  validatePolicyStatusUnsigned: () => validatePolicyStatusUnsigned,
440
452
  validatePolicyUnsigned: () => validatePolicyUnsigned,
441
- validateShareDeliveryAuthorizationBytes: () => validateShareDeliveryAuthorizationBytes,
453
+ validateShareDeliveryAuthorizationV3Bytes: () => validateShareDeliveryAuthorizationV3Bytes,
442
454
  validateUnifiedPolicyV2: () => validateUnifiedPolicyV2,
443
455
  verifyDecryptResponse: () => import_sdk_services8.verifyDecryptResponse,
444
456
  verifyDidKeyEd25519Signature: () => verifyDidKeyEd25519Signature,
445
457
  verifyEip191MessageSignature: () => verifyEip191MessageSignature,
446
458
  verifyIssuedCredential: () => verifyIssuedCredential,
447
459
  verifyLocationRecord: () => verifyLocationRecord,
460
+ verifyOwnerNodeBinding: () => verifyOwnerNodeBinding,
448
461
  verifyPolicy: () => verifyPolicy,
449
462
  verifyPolicyEngineRecord: () => verifyPolicyEngineRecord,
450
463
  verifyPolicyRootRevocationV3: () => verifyPolicyRootRevocationV3,
@@ -1009,6 +1022,17 @@ function isDigest(value) {
1009
1022
 
1010
1023
  // src/credentials/requirement.ts
1011
1024
  var ID2 = /^[a-z0-9][a-z0-9._-]{0,127}(?:\/v1)?$/;
1025
+ var EMAIL_CREDENTIAL_MAX_AGE_SECONDS = 3600;
1026
+ function createEmailCredentialRequirement(input) {
1027
+ return validateCredentialRequirement({
1028
+ type: "TinyCloudCredentialRequirement",
1029
+ version: 1,
1030
+ profile: input.profile,
1031
+ credentialType: input.credentialType,
1032
+ claims: { email: input.email },
1033
+ maxAgeSeconds: EMAIL_CREDENTIAL_MAX_AGE_SECONDS
1034
+ });
1035
+ }
1012
1036
  function validateCredentialRequirement(value) {
1013
1037
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new CredentialError("UNSUPPORTED_PROFILE", "Credential requirement is invalid");
1014
1038
  const raw = value;
@@ -2223,16 +2247,16 @@ function policyCapabilityContains(authority, request) {
2223
2247
  return caveatsContain(auth.caveats, req.caveats);
2224
2248
  }
2225
2249
  function normalizePolicyCapabilityWithOptions(input, options2) {
2226
- const object3 = expectObject(input, "$");
2227
- assertExactKeys(object3, ["service", "space", "path", "actions", "caveats"], "$");
2228
- const service = requiredString(object3, "service", "$", "policy-capability-malformed-service");
2250
+ const object4 = expectObject(input, "$");
2251
+ assertExactKeys(object4, ["service", "space", "path", "actions", "caveats"], "$");
2252
+ const service = requiredString(object4, "service", "$", "policy-capability-malformed-service");
2229
2253
  if (!CEILING_SERVICES.has(service)) {
2230
2254
  throw new PolicyCapabilityError(
2231
2255
  "policy-capability-malformed-service",
2232
2256
  "$.service is outside the frozen permissionsCeiling vocabulary"
2233
2257
  );
2234
2258
  }
2235
- const space = requiredString(object3, "space", "$", "policy-capability-malformed-space");
2259
+ const space = requiredString(object4, "space", "$", "policy-capability-malformed-space");
2236
2260
  validateConcreteSpace(space);
2237
2261
  const canonicalSpace = space.normalize("NFC");
2238
2262
  if (options2.requireCanonical && canonicalSpace !== space) {
@@ -2241,7 +2265,7 @@ function normalizePolicyCapabilityWithOptions(input, options2) {
2241
2265
  "$.space must already be canonical NFC"
2242
2266
  );
2243
2267
  }
2244
- const rawPath = requiredString(object3, "path", "$", "policy-capability-malformed-path");
2268
+ const rawPath = requiredString(object4, "path", "$", "policy-capability-malformed-path");
2245
2269
  validateRawPath(rawPath, options2);
2246
2270
  const path = normalizePath(rawPath);
2247
2271
  if (options2.requireCanonical && path !== rawPath) {
@@ -2252,7 +2276,7 @@ function normalizePolicyCapabilityWithOptions(input, options2) {
2252
2276
  }
2253
2277
  validateRawPath(path, options2);
2254
2278
  const actions = normalizeActions(
2255
- requiredArray(object3, "actions", "$", "policy-capability-malformed-action"),
2279
+ requiredArray(object4, "actions", "$", "policy-capability-malformed-action"),
2256
2280
  service,
2257
2281
  options2
2258
2282
  );
@@ -2261,9 +2285,9 @@ function normalizePolicyCapabilityWithOptions(input, options2) {
2261
2285
  output.space = canonicalSpace;
2262
2286
  output.path = path;
2263
2287
  output.actions = actions;
2264
- if (hasOwn(object3, "caveats")) {
2288
+ if (hasOwn(object4, "caveats")) {
2265
2289
  output.caveats = validateCaveats(
2266
- requiredValue(object3, "caveats", "$", "policy-capability-malformed-caveats"),
2290
+ requiredValue(object4, "caveats", "$", "policy-capability-malformed-caveats"),
2267
2291
  output.service
2268
2292
  );
2269
2293
  }
@@ -2286,9 +2310,9 @@ function expectObject(input, path) {
2286
2310
  );
2287
2311
  }
2288
2312
  }
2289
- function assertExactKeys(object3, allowed, path) {
2313
+ function assertExactKeys(object4, allowed, path) {
2290
2314
  const allowedSet = new Set(allowed);
2291
- for (const key of Object.keys(object3)) {
2315
+ for (const key of Object.keys(object4)) {
2292
2316
  if (!allowedSet.has(key)) {
2293
2317
  throw new PolicyCapabilityError(
2294
2318
  key === "id" || key === "scope" ? "policy-capability-malformed" : "policy-capability-unknown-key",
@@ -2297,21 +2321,21 @@ function assertExactKeys(object3, allowed, path) {
2297
2321
  }
2298
2322
  }
2299
2323
  }
2300
- function requiredValue(object3, key, path, code3) {
2301
- if (!hasOwn(object3, key)) {
2324
+ function requiredValue(object4, key, path, code3) {
2325
+ if (!hasOwn(object4, key)) {
2302
2326
  throw new PolicyCapabilityError(code3, `${path}.${key} is required`);
2303
2327
  }
2304
- return object3[key];
2328
+ return object4[key];
2305
2329
  }
2306
- function requiredString(object3, key, path, code3) {
2307
- const value = requiredValue(object3, key, path, code3);
2330
+ function requiredString(object4, key, path, code3) {
2331
+ const value = requiredValue(object4, key, path, code3);
2308
2332
  if (typeof value !== "string" || value.length === 0) {
2309
2333
  throw new PolicyCapabilityError(code3, `${path}.${key} must be a non-empty string`);
2310
2334
  }
2311
2335
  return value;
2312
2336
  }
2313
- function requiredArray(object3, key, path, code3) {
2314
- const value = requiredValue(object3, key, path, code3);
2337
+ function requiredArray(object4, key, path, code3) {
2338
+ const value = requiredValue(object4, key, path, code3);
2315
2339
  if (!Array.isArray(value)) {
2316
2340
  throw new PolicyCapabilityError(code3, `${path}.${key} must be an array`);
2317
2341
  }
@@ -2456,11 +2480,11 @@ function validateSqlStatement(input, path) {
2456
2480
  if (input === null || typeof input !== "object" || Array.isArray(input)) {
2457
2481
  throw new PolicyCapabilityError("policy-capability-malformed-caveats", `${path} must be an object`);
2458
2482
  }
2459
- const object3 = input;
2460
- assertCaveatKeys(object3, ["name", "sql", "fixedParams"], path);
2461
- caveatString(object3, "name", path);
2462
- caveatString(object3, "sql", path);
2463
- const fixedParams = requiredCaveat(object3, "fixedParams", path);
2483
+ const object4 = input;
2484
+ assertCaveatKeys(object4, ["name", "sql", "fixedParams"], path);
2485
+ caveatString(object4, "name", path);
2486
+ caveatString(object4, "sql", path);
2487
+ const fixedParams = requiredCaveat(object4, "fixedParams", path);
2464
2488
  if (!Array.isArray(fixedParams)) {
2465
2489
  throw new PolicyCapabilityError(
2466
2490
  "policy-capability-malformed-caveats",
@@ -2475,20 +2499,20 @@ function validateFixedParam(input, path) {
2475
2499
  if (input === null || typeof input !== "object" || Array.isArray(input)) {
2476
2500
  throw new PolicyCapabilityError("policy-capability-malformed-caveats", `${path} must be an object`);
2477
2501
  }
2478
- const object3 = input;
2479
- assertCaveatKeys(object3, ["index", "value"], path);
2480
- const index = requiredCaveat(object3, "index", path);
2502
+ const object4 = input;
2503
+ assertCaveatKeys(object4, ["index", "value"], path);
2504
+ const index = requiredCaveat(object4, "index", path);
2481
2505
  if (typeof index !== "number" || !Number.isSafeInteger(index) || index < 0) {
2482
2506
  throw new PolicyCapabilityError(
2483
2507
  "policy-capability-malformed-caveats",
2484
2508
  `${path}.index must be a non-negative integer`
2485
2509
  );
2486
2510
  }
2487
- requiredCaveat(object3, "value", path);
2511
+ requiredCaveat(object4, "value", path);
2488
2512
  }
2489
- function assertCaveatKeys(object3, allowed, path) {
2513
+ function assertCaveatKeys(object4, allowed, path) {
2490
2514
  const allowedSet = new Set(allowed);
2491
- for (const key of Object.keys(object3)) {
2515
+ for (const key of Object.keys(object4)) {
2492
2516
  if (!allowedSet.has(key)) {
2493
2517
  throw new PolicyCapabilityError(
2494
2518
  "policy-capability-malformed-caveats",
@@ -2497,17 +2521,17 @@ function assertCaveatKeys(object3, allowed, path) {
2497
2521
  }
2498
2522
  }
2499
2523
  }
2500
- function requiredCaveat(object3, key, path) {
2501
- if (!hasOwn(object3, key)) {
2524
+ function requiredCaveat(object4, key, path) {
2525
+ if (!hasOwn(object4, key)) {
2502
2526
  throw new PolicyCapabilityError(
2503
2527
  "policy-capability-malformed-caveats",
2504
2528
  `${path}.${key} is required`
2505
2529
  );
2506
2530
  }
2507
- return object3[key];
2531
+ return object4[key];
2508
2532
  }
2509
- function caveatString(object3, key, path) {
2510
- const value = requiredCaveat(object3, key, path);
2533
+ function caveatString(object4, key, path) {
2534
+ const value = requiredCaveat(object4, key, path);
2511
2535
  if (typeof value !== "string" || value.length === 0) {
2512
2536
  throw new PolicyCapabilityError(
2513
2537
  "policy-capability-malformed-caveats",
@@ -2538,8 +2562,8 @@ function caveatsContain(authority, request) {
2538
2562
  (statement) => authorityStatements.some((candidate) => jcsCanonicalize(candidate) === jcsCanonicalize(statement))
2539
2563
  );
2540
2564
  }
2541
- function hasOwn(object3, key) {
2542
- return objectHasOwn2(object3, key);
2565
+ function hasOwn(object4, key) {
2566
+ return objectHasOwn2(object4, key);
2543
2567
  }
2544
2568
 
2545
2569
  // src/policy/signed-object.ts
@@ -2867,17 +2891,17 @@ async function createAndSignSignedObject(input, signer) {
2867
2891
  }
2868
2892
  function createAndSignPolicy(input, signer) {
2869
2893
  return createAndSignSignedObject(input, signer).then(
2870
- (object3) => validatePolicySignedShape(object3)
2894
+ (object4) => validatePolicySignedShape(object4)
2871
2895
  );
2872
2896
  }
2873
2897
  function createAndSignPolicyStatus(input, signer) {
2874
2898
  return createAndSignSignedObject(input, signer).then(
2875
- (object3) => validatePolicyStatusSignedShape(object3)
2899
+ (object4) => validatePolicyStatusSignedShape(object4)
2876
2900
  );
2877
2901
  }
2878
2902
  function createAndSignPolicyEngineRecord(input, signer) {
2879
2903
  return createAndSignSignedObject(input, signer).then(
2880
- (object3) => validatePolicyEngineRecordSignedShape(object3)
2904
+ (object4) => validatePolicyEngineRecordSignedShape(object4)
2881
2905
  );
2882
2906
  }
2883
2907
  async function verifySignedObject(input) {
@@ -2981,9 +3005,9 @@ function validateUnsignedForDescriptor(input, descriptor) {
2981
3005
  }
2982
3006
  }
2983
3007
  function validatePolicyShape(input, signed) {
2984
- const object3 = expectJsonObject(normalizeJson(input), "$");
3008
+ const object4 = expectJsonObject(normalizeJson(input), "$");
2985
3009
  assertExactKeys2(
2986
- object3,
3010
+ object4,
2987
3011
  signed ? [
2988
3012
  "schema",
2989
3013
  "policyId",
@@ -3011,30 +3035,30 @@ function validatePolicyShape(input, signed) {
3011
3035
  ],
3012
3036
  "$"
3013
3037
  );
3014
- expectConst(requiredString2(object3, "schema", "$"), POLICY_SCHEMA, "$.schema");
3038
+ expectConst(requiredString2(object4, "schema", "$"), POLICY_SCHEMA, "$.schema");
3015
3039
  if (signed) {
3016
- requiredString2(object3, "policyId", "$");
3017
- validateSignature(requiredValue2(object3, "signature", "$"));
3040
+ requiredString2(object4, "policyId", "$");
3041
+ validateSignature(requiredValue2(object4, "signature", "$"));
3018
3042
  }
3019
- requiredString2(object3, "ownerDid", "$");
3020
- requiredString2(object3, "signingKeyDid", "$");
3021
- requiredDateString(object3, "createdAt", "$");
3022
- optionalDateString(object3, "expiresAt", "$");
3023
- validatePolicyResource(requiredValue2(object3, "resource", "$"), "$.resource");
3024
- validateExpression(requiredValue2(object3, "when", "$"), "$.when");
3025
- validateGrant(requiredValue2(object3, "grant", "$"), "$.grant");
3026
- if (hasOwn2(object3, "disclosure")) {
3027
- validateDisclosure(requiredValue2(object3, "disclosure", "$"), "$.disclosure");
3043
+ requiredString2(object4, "ownerDid", "$");
3044
+ requiredString2(object4, "signingKeyDid", "$");
3045
+ requiredDateString(object4, "createdAt", "$");
3046
+ optionalDateString(object4, "expiresAt", "$");
3047
+ validatePolicyResource(requiredValue2(object4, "resource", "$"), "$.resource");
3048
+ validateExpression(requiredValue2(object4, "when", "$"), "$.when");
3049
+ validateGrant(requiredValue2(object4, "grant", "$"), "$.grant");
3050
+ if (hasOwn2(object4, "disclosure")) {
3051
+ validateDisclosure(requiredValue2(object4, "disclosure", "$"), "$.disclosure");
3028
3052
  }
3029
- if (hasOwn2(object3, "audit")) {
3030
- validateAudit(requiredValue2(object3, "audit", "$"), "$.audit");
3053
+ if (hasOwn2(object4, "audit")) {
3054
+ validateAudit(requiredValue2(object4, "audit", "$"), "$.audit");
3031
3055
  }
3032
- return object3;
3056
+ return object4;
3033
3057
  }
3034
3058
  function validatePolicyStatusShape(input, signed) {
3035
- const object3 = expectJsonObject(normalizeJson(input), "$");
3059
+ const object4 = expectJsonObject(normalizeJson(input), "$");
3036
3060
  assertExactKeys2(
3037
- object3,
3061
+ object4,
3038
3062
  signed ? [
3039
3063
  "schema",
3040
3064
  "statusId",
@@ -3058,28 +3082,28 @@ function validatePolicyStatusShape(input, signed) {
3058
3082
  ],
3059
3083
  "$"
3060
3084
  );
3061
- expectConst(requiredString2(object3, "schema", "$"), POLICY_STATUS_SCHEMA, "$.schema");
3085
+ expectConst(requiredString2(object4, "schema", "$"), POLICY_STATUS_SCHEMA, "$.schema");
3062
3086
  if (signed) {
3063
- requiredString2(object3, "statusId", "$");
3064
- validateSignature(requiredValue2(object3, "signature", "$"));
3087
+ requiredString2(object4, "statusId", "$");
3088
+ validateSignature(requiredValue2(object4, "signature", "$"));
3065
3089
  }
3066
- requiredString2(object3, "policyId", "$");
3067
- requiredString2(object3, "ownerDid", "$");
3068
- requiredInteger(object3, "sequence", "$", 0);
3069
- expectOneOf(requiredString2(object3, "disposition", "$"), [
3090
+ requiredString2(object4, "policyId", "$");
3091
+ requiredString2(object4, "ownerDid", "$");
3092
+ requiredInteger(object4, "sequence", "$", 0);
3093
+ expectOneOf(requiredString2(object4, "disposition", "$"), [
3070
3094
  "active",
3071
3095
  "suspended",
3072
3096
  "revoked"
3073
3097
  ], "$.disposition");
3074
- requiredDateString(object3, "effectiveAt", "$");
3075
- optionalString(object3, "reasonCode", "$");
3076
- requiredString2(object3, "signingKeyDid", "$");
3077
- return object3;
3098
+ requiredDateString(object4, "effectiveAt", "$");
3099
+ optionalString(object4, "reasonCode", "$");
3100
+ requiredString2(object4, "signingKeyDid", "$");
3101
+ return object4;
3078
3102
  }
3079
3103
  function validatePolicyEngineRecordShape(input, signed) {
3080
- const object3 = expectJsonObject(normalizeJson(input), "$");
3104
+ const object4 = expectJsonObject(normalizeJson(input), "$");
3081
3105
  assertExactKeys2(
3082
- object3,
3106
+ object4,
3083
3107
  signed ? [
3084
3108
  "schema",
3085
3109
  "engineRecordId",
@@ -3104,44 +3128,44 @@ function validatePolicyEngineRecordShape(input, signed) {
3104
3128
  "$"
3105
3129
  );
3106
3130
  expectConst(
3107
- requiredString2(object3, "schema", "$"),
3131
+ requiredString2(object4, "schema", "$"),
3108
3132
  POLICY_ENGINE_RECORD_SCHEMA,
3109
3133
  "$.schema"
3110
3134
  );
3111
3135
  if (signed) {
3112
- requiredString2(object3, "engineRecordId", "$");
3113
- validateSignature(requiredValue2(object3, "signature", "$"));
3136
+ requiredString2(object4, "engineRecordId", "$");
3137
+ validateSignature(requiredValue2(object4, "signature", "$"));
3114
3138
  }
3115
- requiredString2(object3, "ownerDid", "$");
3116
- requiredString2(object3, "endpoint", "$");
3117
- requiredString2(object3, "audience", "$");
3139
+ requiredString2(object4, "ownerDid", "$");
3140
+ requiredString2(object4, "endpoint", "$");
3141
+ requiredString2(object4, "audience", "$");
3118
3142
  requiredStringArray(
3119
- object3,
3143
+ object4,
3120
3144
  "supportedPolicyVersions",
3121
3145
  "$",
3122
3146
  (value, path) => expectConst(value, "v0", path)
3123
3147
  );
3124
- requiredStringArray(object3, "supportedEvidenceVerifiers", "$");
3125
- requiredString2(object3, "grantIssuerDid", "$");
3126
- requiredDateString(object3, "expiresAt", "$");
3127
- return object3;
3148
+ requiredStringArray(object4, "supportedEvidenceVerifiers", "$");
3149
+ requiredString2(object4, "grantIssuerDid", "$");
3150
+ requiredDateString(object4, "expiresAt", "$");
3151
+ return object4;
3128
3152
  }
3129
3153
  function validateSignature(input) {
3130
- const object3 = expectJsonObject(input, "$.signature");
3131
- assertExactKeys2(object3, ["suite", "signerDid", "value"], "$.signature");
3132
- const suite = requiredString2(object3, "suite", "$.signature");
3154
+ const object4 = expectJsonObject(input, "$.signature");
3155
+ assertExactKeys2(object4, ["suite", "signerDid", "value"], "$.signature");
3156
+ const suite = requiredString2(object4, "suite", "$.signature");
3133
3157
  assertSupportedSignatureSuite(suite);
3134
- const signerDid = requiredString2(object3, "signerDid", "$.signature");
3135
- const value = requiredString2(object3, "value", "$.signature");
3158
+ const signerDid = requiredString2(object4, "signerDid", "$.signature");
3159
+ const value = requiredString2(object4, "value", "$.signature");
3136
3160
  decodeSignatureValue(value, suite);
3137
3161
  return { suite, signerDid, value };
3138
3162
  }
3139
3163
  function validatePolicyResource(input, path) {
3140
- const object3 = expectJsonObject(input, path);
3141
- assertExactKeys2(object3, ["resourceType", "resourceId", "permissionsCeiling"], path);
3142
- requiredString2(object3, "resourceType", path);
3143
- requiredString2(object3, "resourceId", path);
3144
- const ceiling = requiredArray2(object3, "permissionsCeiling", path, 1);
3164
+ const object4 = expectJsonObject(input, path);
3165
+ assertExactKeys2(object4, ["resourceType", "resourceId", "permissionsCeiling"], path);
3166
+ requiredString2(object4, "resourceType", path);
3167
+ requiredString2(object4, "resourceId", path);
3168
+ const ceiling = requiredArray2(object4, "permissionsCeiling", path, 1);
3145
3169
  for (let index = 0; index < ceiling.length; index++) {
3146
3170
  validatePolicyCapability(ceiling[index], `${path}.permissionsCeiling[${index}]`);
3147
3171
  }
@@ -3157,10 +3181,10 @@ function validatePolicyPermissionsCeilingForSigning(input) {
3157
3181
  }
3158
3182
  }
3159
3183
  function validatePolicyCapability(input, path) {
3160
- const object3 = expectJsonObject(input, path);
3184
+ const object4 = expectJsonObject(input, path);
3161
3185
  try {
3162
- const canonical = canonicalizePolicyCapability(object3);
3163
- if (jcsCanonicalize(object3) !== jcsCanonicalize(canonical)) {
3186
+ const canonical = canonicalizePolicyCapability(object4);
3187
+ if (jcsCanonicalize(object4) !== jcsCanonicalize(canonical)) {
3164
3188
  throw new SignedObjectSchemaError(`${path} must be canonical PolicyCapability JSON`);
3165
3189
  }
3166
3190
  } catch (error) {
@@ -3173,10 +3197,10 @@ function validatePolicyCapability(input, path) {
3173
3197
  }
3174
3198
  }
3175
3199
  function validatePolicyCapabilityForSigning(input, path) {
3176
- const object3 = expectJsonObject(input, path);
3200
+ const object4 = expectJsonObject(input, path);
3177
3201
  try {
3178
- const canonical = normalizePolicyCapability(object3);
3179
- if (jcsCanonicalize(object3) !== jcsCanonicalize(canonical)) {
3202
+ const canonical = normalizePolicyCapability(object4);
3203
+ if (jcsCanonicalize(object4) !== jcsCanonicalize(canonical)) {
3180
3204
  throw new SignedObjectSchemaError(`${path} must be strict canonical PolicyCapability JSON`);
3181
3205
  }
3182
3206
  } catch (error) {
@@ -3189,43 +3213,43 @@ function validatePolicyCapabilityForSigning(input, path) {
3189
3213
  }
3190
3214
  }
3191
3215
  function validateExpression(input, path) {
3192
- const object3 = expectJsonObject(input, path);
3193
- const keys = Object.keys(object3);
3216
+ const object4 = expectJsonObject(input, path);
3217
+ const keys = Object.keys(object4);
3194
3218
  if (keys.length !== 1) {
3195
3219
  throw new SignedObjectSchemaError(`${path} must have exactly one expression key`);
3196
3220
  }
3197
3221
  const key = keys[0];
3198
3222
  if (key === "allOf" || key === "anyOf") {
3199
- const values = requiredArray2(object3, key, path, 1);
3223
+ const values = requiredArray2(object4, key, path, 1);
3200
3224
  for (let index = 0; index < values.length; index++) {
3201
3225
  validateExpression(values[index], `${path}.${key}[${index}]`);
3202
3226
  }
3203
3227
  return;
3204
3228
  }
3205
3229
  if (key === "subject") {
3206
- const subject = expectJsonObject(requiredValue2(object3, "subject", path), `${path}.subject`);
3230
+ const subject = expectJsonObject(requiredValue2(object4, "subject", path), `${path}.subject`);
3207
3231
  assertExactKeys2(subject, ["did"], `${path}.subject`);
3208
3232
  requiredString2(subject, "did", `${path}.subject`);
3209
3233
  return;
3210
3234
  }
3211
3235
  if (key === "evidence") {
3212
- validateEvidenceRequirement(requiredValue2(object3, "evidence", path), `${path}.evidence`);
3236
+ validateEvidenceRequirement(requiredValue2(object4, "evidence", path), `${path}.evidence`);
3213
3237
  return;
3214
3238
  }
3215
3239
  throw new SignedObjectSchemaError(`${path} has unknown expression key ${key}`);
3216
3240
  }
3217
3241
  function validateEvidenceRequirement(input, path) {
3218
- const object3 = expectJsonObject(input, path);
3242
+ const object4 = expectJsonObject(input, path);
3219
3243
  assertExactKeys2(
3220
- object3,
3244
+ object4,
3221
3245
  ["requirementId", "verifier", "requirements", "authority", "freshness"],
3222
3246
  path
3223
3247
  );
3224
- requiredString2(object3, "requirementId", path);
3225
- requiredString2(object3, "verifier", path);
3226
- requiredValue2(object3, "requirements", path);
3227
- if (hasOwn2(object3, "authority")) {
3228
- const authority = expectJsonObject(requiredValue2(object3, "authority", path), `${path}.authority`);
3248
+ requiredString2(object4, "requirementId", path);
3249
+ requiredString2(object4, "verifier", path);
3250
+ requiredValue2(object4, "requirements", path);
3251
+ if (hasOwn2(object4, "authority")) {
3252
+ const authority = expectJsonObject(requiredValue2(object4, "authority", path), `${path}.authority`);
3229
3253
  assertExactKeys2(
3230
3254
  authority,
3231
3255
  ["profile", "acceptedIssuers", "allowOwnerAuthorizedIssuer"],
@@ -3237,35 +3261,35 @@ function validateEvidenceRequirement(input, path) {
3237
3261
  }
3238
3262
  optionalBoolean(authority, "allowOwnerAuthorizedIssuer", `${path}.authority`);
3239
3263
  }
3240
- if (hasOwn2(object3, "freshness")) {
3241
- const freshness = expectJsonObject(requiredValue2(object3, "freshness", path), `${path}.freshness`);
3264
+ if (hasOwn2(object4, "freshness")) {
3265
+ const freshness = expectJsonObject(requiredValue2(object4, "freshness", path), `${path}.freshness`);
3242
3266
  assertExactKeys2(freshness, ["maxStatusAgeSeconds"], `${path}.freshness`);
3243
3267
  requiredInteger(freshness, "maxStatusAgeSeconds", `${path}.freshness`, 0);
3244
3268
  }
3245
3269
  }
3246
3270
  function validateGrant(input, path) {
3247
- const object3 = expectJsonObject(input, path);
3248
- assertExactKeys2(object3, ["output", "maxTtlSeconds", "delegationMode", "revocation"], path);
3249
- expectConst(requiredString2(object3, "output", path), "portable-delegation", `${path}.output`);
3250
- requiredInteger(object3, "maxTtlSeconds", path, 1);
3251
- expectOneOf(requiredString2(object3, "delegationMode", path), [
3271
+ const object4 = expectJsonObject(input, path);
3272
+ assertExactKeys2(object4, ["output", "maxTtlSeconds", "delegationMode", "revocation"], path);
3273
+ expectConst(requiredString2(object4, "output", path), "portable-delegation", `${path}.output`);
3274
+ requiredInteger(object4, "maxTtlSeconds", path, 1);
3275
+ expectOneOf(requiredString2(object4, "delegationMode", path), [
3252
3276
  "terminal",
3253
3277
  "attenuable"
3254
3278
  ], `${path}.delegationMode`);
3255
- expectOneOf(requiredString2(object3, "revocation", path), [
3279
+ expectOneOf(requiredString2(object4, "revocation", path), [
3256
3280
  "refresh_only",
3257
3281
  "active_cutoff"
3258
3282
  ], `${path}.revocation`);
3259
3283
  }
3260
3284
  function validateDisclosure(input, path) {
3261
- const object3 = expectJsonObject(input, path);
3262
- assertExactKeys2(object3, ["denial"], path);
3263
- expectOneOf(requiredString2(object3, "denial", path), ["none", "code", "debug"], `${path}.denial`);
3285
+ const object4 = expectJsonObject(input, path);
3286
+ assertExactKeys2(object4, ["denial"], path);
3287
+ expectOneOf(requiredString2(object4, "denial", path), ["none", "code", "debug"], `${path}.denial`);
3264
3288
  }
3265
3289
  function validateAudit(input, path) {
3266
- const object3 = expectJsonObject(input, path);
3267
- assertExactKeys2(object3, ["issuance"], path);
3268
- expectOneOf(requiredString2(object3, "issuance", path), ["off", "security", "full"], `${path}.issuance`);
3290
+ const object4 = expectJsonObject(input, path);
3291
+ assertExactKeys2(object4, ["issuance"], path);
3292
+ expectOneOf(requiredString2(object4, "issuance", path), ["off", "security", "full"], `${path}.issuance`);
3269
3293
  }
3270
3294
  function materialForUnsigned(unsigned, descriptor) {
3271
3295
  const jcs = jcsCanonicalize(unsigned);
@@ -3414,9 +3438,9 @@ function encodeSignatureValue(value, suite) {
3414
3438
  decodeSignatureValue(encoded, suite);
3415
3439
  return encoded;
3416
3440
  }
3417
- function stripOwnIdAndSignature(object3, descriptor) {
3441
+ function stripOwnIdAndSignature(object4, descriptor) {
3418
3442
  const output = /* @__PURE__ */ Object.create(null);
3419
- for (const [key, value] of Object.entries(object3)) {
3443
+ for (const [key, value] of Object.entries(object4)) {
3420
3444
  if (key === descriptor.idField || key === "signature") {
3421
3445
  continue;
3422
3446
  }
@@ -3425,8 +3449,8 @@ function stripOwnIdAndSignature(object3, descriptor) {
3425
3449
  return output;
3426
3450
  }
3427
3451
  function descriptorForUnsigned(input) {
3428
- const object3 = expectJsonObject(normalizeJson(input), "$");
3429
- return descriptorForSchema(requiredString2(object3, "schema", "$"));
3452
+ const object4 = expectJsonObject(normalizeJson(input), "$");
3453
+ return descriptorForSchema(requiredString2(object4, "schema", "$"));
3430
3454
  }
3431
3455
  function descriptorForSchema(schema) {
3432
3456
  if (schema === POLICY_SCHEMA) return DESCRIPTORS.Policy;
@@ -3440,28 +3464,28 @@ function expectJsonObject(input, path) {
3440
3464
  }
3441
3465
  return input;
3442
3466
  }
3443
- function assertExactKeys2(object3, allowed, path) {
3467
+ function assertExactKeys2(object4, allowed, path) {
3444
3468
  const allowedSet = new Set(allowed);
3445
- for (const key of Object.keys(object3)) {
3469
+ for (const key of Object.keys(object4)) {
3446
3470
  if (!allowedSet.has(key)) {
3447
3471
  throw new SignedObjectSchemaError(`${path} has unknown field ${key}`);
3448
3472
  }
3449
3473
  }
3450
3474
  }
3451
- function requiredValue2(object3, key, path) {
3452
- if (!hasOwn2(object3, key)) {
3475
+ function requiredValue2(object4, key, path) {
3476
+ if (!hasOwn2(object4, key)) {
3453
3477
  throw new SignedObjectSchemaError(`${path}.${key} is required`);
3454
3478
  }
3455
- return object3[key];
3479
+ return object4[key];
3456
3480
  }
3457
- function requiredString2(object3, key, path) {
3458
- return requireStringType(requiredValue2(object3, key, path), `${path}.${key}`);
3481
+ function requiredString2(object4, key, path) {
3482
+ return requireStringType(requiredValue2(object4, key, path), `${path}.${key}`);
3459
3483
  }
3460
- function optionalString(object3, key, path) {
3461
- if (!hasOwn2(object3, key)) {
3484
+ function optionalString(object4, key, path) {
3485
+ if (!hasOwn2(object4, key)) {
3462
3486
  return;
3463
3487
  }
3464
- requireStringType(requiredValue2(object3, key, path), `${path}.${key}`);
3488
+ requireStringType(requiredValue2(object4, key, path), `${path}.${key}`);
3465
3489
  }
3466
3490
  function requireStringType(value, path) {
3467
3491
  if (typeof value !== "string" || value.length === 0) {
@@ -3469,16 +3493,16 @@ function requireStringType(value, path) {
3469
3493
  }
3470
3494
  return value;
3471
3495
  }
3472
- function optionalBoolean(object3, key, path) {
3473
- if (!hasOwn2(object3, key)) {
3496
+ function optionalBoolean(object4, key, path) {
3497
+ if (!hasOwn2(object4, key)) {
3474
3498
  return;
3475
3499
  }
3476
- if (typeof requiredValue2(object3, key, path) !== "boolean") {
3500
+ if (typeof requiredValue2(object4, key, path) !== "boolean") {
3477
3501
  throw new SignedObjectSchemaError(`${path}.${key} must be a boolean`);
3478
3502
  }
3479
3503
  }
3480
- function requiredInteger(object3, key, path, minimum) {
3481
- const value = requiredValue2(object3, key, path);
3504
+ function requiredInteger(object4, key, path, minimum) {
3505
+ const value = requiredValue2(object4, key, path);
3482
3506
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < minimum) {
3483
3507
  throw new SignedObjectSchemaError(
3484
3508
  `${path}.${key} must be an integer >= ${minimum}`
@@ -3486,8 +3510,8 @@ function requiredInteger(object3, key, path, minimum) {
3486
3510
  }
3487
3511
  return value;
3488
3512
  }
3489
- function requiredArray2(object3, key, path, minimum) {
3490
- const value = requiredValue2(object3, key, path);
3513
+ function requiredArray2(object4, key, path, minimum) {
3514
+ const value = requiredValue2(object4, key, path);
3491
3515
  if (!Array.isArray(value) || value.length < minimum) {
3492
3516
  throw new SignedObjectSchemaError(
3493
3517
  `${path}.${key} must be an array with at least ${minimum} item(s)`
@@ -3495,22 +3519,22 @@ function requiredArray2(object3, key, path, minimum) {
3495
3519
  }
3496
3520
  return value;
3497
3521
  }
3498
- function requiredStringArray(object3, key, path, check) {
3499
- const values = requiredArray2(object3, key, path, 0);
3522
+ function requiredStringArray(object4, key, path, check) {
3523
+ const values = requiredArray2(object4, key, path, 0);
3500
3524
  for (let index = 0; index < values.length; index++) {
3501
3525
  const itemPath = `${path}.${key}[${index}]`;
3502
3526
  const value = requireStringType(values[index], itemPath);
3503
3527
  check?.(value, itemPath);
3504
3528
  }
3505
3529
  }
3506
- function requiredDateString(object3, key, path) {
3507
- assertRfc3339(requiredString2(object3, key, path), `${path}.${key}`);
3530
+ function requiredDateString(object4, key, path) {
3531
+ assertRfc3339(requiredString2(object4, key, path), `${path}.${key}`);
3508
3532
  }
3509
- function optionalDateString(object3, key, path) {
3510
- if (!hasOwn2(object3, key)) {
3533
+ function optionalDateString(object4, key, path) {
3534
+ if (!hasOwn2(object4, key)) {
3511
3535
  return;
3512
3536
  }
3513
- assertRfc3339(requiredString2(object3, key, path), `${path}.${key}`);
3537
+ assertRfc3339(requiredString2(object4, key, path), `${path}.${key}`);
3514
3538
  }
3515
3539
  function assertRfc3339(value, path) {
3516
3540
  const match = value.match(
@@ -3542,8 +3566,8 @@ function expectOneOf(actual, allowed, path) {
3542
3566
  }
3543
3567
  throw new SignedObjectSchemaError(`${path} has unsupported value ${actual}`);
3544
3568
  }
3545
- function hasOwn2(object3, key) {
3546
- return objectHasOwn3(object3, key);
3569
+ function hasOwn2(object4, key) {
3570
+ return objectHasOwn3(object4, key);
3547
3571
  }
3548
3572
  function assertSupportedSignatureSuite(suite) {
3549
3573
  if (suite !== ED25519_JCS_SIGNATURE_SUITE && suite !== EIP191_JCS_SIGNATURE_SUITE) {
@@ -3770,9 +3794,9 @@ function expectObject2(input, path, code3) {
3770
3794
  );
3771
3795
  }
3772
3796
  }
3773
- function assertExactKeys3(object3, allowed, path) {
3797
+ function assertExactKeys3(object4, allowed, path) {
3774
3798
  const allowedSet = new Set(allowed);
3775
- for (const key of Object.keys(object3)) {
3799
+ for (const key of Object.keys(object4)) {
3776
3800
  if (!allowedSet.has(key)) {
3777
3801
  throw new PolicyAuthoringError(
3778
3802
  "policy-authoring-unknown-key",
@@ -3781,17 +3805,17 @@ function assertExactKeys3(object3, allowed, path) {
3781
3805
  }
3782
3806
  }
3783
3807
  }
3784
- function requiredValue3(object3, key, path) {
3785
- if (!hasOwn3(object3, key)) {
3808
+ function requiredValue3(object4, key, path) {
3809
+ if (!hasOwn3(object4, key)) {
3786
3810
  throw new PolicyAuthoringError(
3787
3811
  "policy-authoring-malformed",
3788
3812
  `${path}.${key} is required`
3789
3813
  );
3790
3814
  }
3791
- return object3[key];
3815
+ return object4[key];
3792
3816
  }
3793
- function requiredString3(object3, key, path) {
3794
- const value = requiredValue3(object3, key, path);
3817
+ function requiredString3(object4, key, path) {
3818
+ const value = requiredValue3(object4, key, path);
3795
3819
  if (typeof value !== "string" || value.length === 0) {
3796
3820
  throw new PolicyAuthoringError(
3797
3821
  "policy-authoring-malformed",
@@ -3800,11 +3824,11 @@ function requiredString3(object3, key, path) {
3800
3824
  }
3801
3825
  return value;
3802
3826
  }
3803
- function fieldString(object3, key, path, code3) {
3804
- if (!hasOwn3(object3, key)) {
3827
+ function fieldString(object4, key, path, code3) {
3828
+ if (!hasOwn3(object4, key)) {
3805
3829
  throw new PolicyAuthoringError(code3, `${path}.${key} is required`);
3806
3830
  }
3807
- const value = object3[key];
3831
+ const value = object4[key];
3808
3832
  if (typeof value !== "string" || value.length === 0) {
3809
3833
  throw new PolicyAuthoringError(
3810
3834
  code3,
@@ -3842,8 +3866,8 @@ function parseStrictRfc3339(value, path) {
3842
3866
  var objectHasOwn4 = Object.hasOwn ?? Object.prototype.hasOwnProperty.call.bind(
3843
3867
  Object.prototype.hasOwnProperty
3844
3868
  );
3845
- function hasOwn3(object3, key) {
3846
- return objectHasOwn4(object3, key);
3869
+ function hasOwn3(object4, key) {
3870
+ return objectHasOwn4(object4, key);
3847
3871
  }
3848
3872
 
3849
3873
  // src/policy/unified.ts
@@ -3870,9 +3894,11 @@ var MAX_LEGACY_ENVELOPE_EXPIRES_AT = "2026-12-29T00:00:00Z";
3870
3894
  var LAST_V2_READ_AT = "2027-01-05T00:00:00Z";
3871
3895
  async function requestPolicyChallengeV3(input) {
3872
3896
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
3873
- const response = await fetchFn(new URL("/share/v3/policy/challenges", input.nodeOrigin), {
3897
+ const policyRuntimePath = policyRuntimeBasePath(input.policyRuntimePath);
3898
+ const response = await fetchFn(new URL(`${policyRuntimePath}/challenges`, input.nodeOrigin), {
3874
3899
  method: "POST",
3875
3900
  redirect: "error",
3901
+ signal: input.signal,
3876
3902
  headers: { accept: "application/json", "content-type": "application/json" },
3877
3903
  body: JSON.stringify({ policyCid: input.policyCid, recipientDid: input.recipientDid, requestedCapabilities: input.requestedCapabilities.map(normalizeUnifiedPolicyCapability) })
3878
3904
  });
@@ -3882,6 +3908,13 @@ async function requestPolicyChallengeV3(input) {
3882
3908
  throw new Error("policy challenge binding is invalid");
3883
3909
  return value;
3884
3910
  }
3911
+ function policyRuntimeBasePath(value) {
3912
+ const path = value ?? "/policy/v3";
3913
+ if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
3914
+ throw new Error("policy runtime path is invalid");
3915
+ }
3916
+ return path;
3917
+ }
3885
3918
  function compactAttenuationForPolicyCapabilities(input) {
3886
3919
  const attenuation = {};
3887
3920
  for (const raw of input) {
@@ -3927,7 +3960,7 @@ function verifyPolicyRootStatusCheckpointV3(input) {
3927
3960
  }
3928
3961
  async function getPolicyRootStatusV3(input) {
3929
3962
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
3930
- const response = await fetchFn(new URL(`/share/v3/policy/status/${encodeURIComponent(input.rootCid)}`, input.nodeOrigin), {
3963
+ const response = await fetchFn(new URL(`/policy/v3/status/${encodeURIComponent(input.rootCid)}`, input.nodeOrigin), {
3931
3964
  method: "GET",
3932
3965
  redirect: "error",
3933
3966
  headers: { accept: "application/json" }
@@ -3986,7 +4019,7 @@ async function renewPolicyRootStatusV3(input) {
3986
4019
  };
3987
4020
  const signature = await input.sign((0, import_sha256.sha256)(new TextEncoder().encode(ROOT_STATUS_RENEWAL_V1_DOMAIN + jcsCanonicalize(unsigned))));
3988
4021
  if (signature.length !== 64) throw new Error("policy root renewal signature must be Ed25519");
3989
- const response = await fetchFn(new URL("/share/v3/policy/status", input.nodeOrigin), {
4022
+ const response = await fetchFn(new URL("/policy/v3/status", input.nodeOrigin), {
3990
4023
  method: "POST",
3991
4024
  redirect: "error",
3992
4025
  headers: { accept: "application/json", "content-type": "application/json" },
@@ -4042,6 +4075,11 @@ var POLICY_SESSION_FACT_KEYS = [
4042
4075
  "issuanceAuditDigestHex",
4043
4076
  "remainingRedelegationDepth"
4044
4077
  ];
4078
+ var POLICY_SESSION_V4_AUDIT_FACT_KEYS = [
4079
+ "credentialIdAuditDigestHex",
4080
+ "presentationJtiAuditDigestHex"
4081
+ ];
4082
+ var LOWER_SHA256_HEX = /^[0-9a-f]{64}$/;
4045
4083
  var KV_ACTIONS = /* @__PURE__ */ new Set([
4046
4084
  "tinycloud.kv/get",
4047
4085
  "tinycloud.kv/list",
@@ -4236,6 +4274,133 @@ function contentSourceDigestHex(input) {
4236
4274
  )
4237
4275
  );
4238
4276
  }
4277
+ function exactObject(value, keys, label) {
4278
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
4279
+ throw new Error(`${label} is invalid`);
4280
+ }
4281
+ const record2 = value;
4282
+ if (Object.keys(record2).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record2, key))) {
4283
+ throw new Error(`${label} is invalid`);
4284
+ }
4285
+ return record2;
4286
+ }
4287
+ function didKeyEd25519PublicKey(value) {
4288
+ const principal = value.split("#", 1)[0];
4289
+ if (!principal.startsWith("did:key:")) {
4290
+ throw new Error("policy enforcer binding signer is invalid");
4291
+ }
4292
+ const material = base58btc.decode(principal.slice("did:key:".length));
4293
+ if (material.length !== 34 || material[0] !== 237 || material[1] !== 1) {
4294
+ throw new Error("policy enforcer binding signer is invalid");
4295
+ }
4296
+ return material.slice(2);
4297
+ }
4298
+ async function registerPolicyV3(input) {
4299
+ const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
4300
+ const rootExpiresAt = new Date(input.rootExpiresAt);
4301
+ const canonicalRootExpiresAt = new Date(
4302
+ Math.floor(rootExpiresAt.getTime() / 1e3) * 1e3
4303
+ ).toISOString().replace(/\.000Z$/, "Z");
4304
+ if (!Number.isFinite(rootExpiresAt.getTime()) || canonicalRootExpiresAt !== input.rootExpiresAt || rootExpiresAt.getTime() <= Date.now()) {
4305
+ throw new Error("policy root expiry is invalid");
4306
+ }
4307
+ const bindingResponse = await fetchFn(
4308
+ new URL("/policy/v3/enforcer-bindings", input.nodeOrigin),
4309
+ {
4310
+ method: "POST",
4311
+ redirect: "error",
4312
+ signal: input.signal,
4313
+ headers: { accept: "application/json", "content-type": "application/json" },
4314
+ body: JSON.stringify({
4315
+ rootExpiresAt: input.rootExpiresAt,
4316
+ enforcerDid: input.enforcerDid
4317
+ })
4318
+ }
4319
+ );
4320
+ if (!bindingResponse.ok) {
4321
+ throw new Error(`policy enforcer binding rejected (${bindingResponse.status})`);
4322
+ }
4323
+ const binding = exactObject(
4324
+ await bindingResponse.json(),
4325
+ [
4326
+ "schema",
4327
+ "enforcerDid",
4328
+ "nodeAudience",
4329
+ "attestationBindingDigestHex",
4330
+ "issuedAt",
4331
+ "expiresAt",
4332
+ "signature"
4333
+ ],
4334
+ "policy enforcer binding"
4335
+ );
4336
+ const signature = exactObject(
4337
+ binding.signature,
4338
+ ["suite", "signerDid", "value"],
4339
+ "policy enforcer binding signature"
4340
+ );
4341
+ const expectedBindingDigestHex = hex(
4342
+ (0, import_sha256.sha256)(
4343
+ new TextEncoder().encode(
4344
+ jcsCanonicalize({
4345
+ enforcerDid: input.enforcerDid,
4346
+ nodeAudience: input.expectedNodeAudience
4347
+ })
4348
+ )
4349
+ )
4350
+ );
4351
+ if (binding.schema !== ATTESTED_ENFORCER_BINDING_V2_SCHEMA || binding.enforcerDid !== input.enforcerDid || binding.nodeAudience !== input.expectedNodeAudience || binding.attestationBindingDigestHex !== expectedBindingDigestHex || binding.expiresAt !== input.rootExpiresAt || typeof binding.issuedAt !== "string" || Date.parse(binding.issuedAt) > Date.now() || signature.suite !== "Ed25519" || signature.signerDid !== input.expectedNodeAudience || typeof signature.value !== "string") {
4352
+ throw new Error("policy enforcer binding is invalid");
4353
+ }
4354
+ const { signature: _signature, ...unsignedBinding } = binding;
4355
+ const signedBinding = (0, import_sha256.sha256)(
4356
+ new TextEncoder().encode(
4357
+ `xyz.tinycloud.policy/AttestedEnforcerBinding/v2\0${jcsCanonicalize(unsignedBinding)}`
4358
+ )
4359
+ );
4360
+ if (!import_ed255193.ed25519.verify(
4361
+ decodeBase64Url2(signature.value),
4362
+ signedBinding,
4363
+ didKeyEd25519PublicKey(input.expectedNodeAudience),
4364
+ { zip215: false }
4365
+ )) {
4366
+ throw new Error("policy enforcer binding signature is invalid");
4367
+ }
4368
+ const response = await fetchFn(
4369
+ new URL("/policy/v3/policies", input.nodeOrigin),
4370
+ {
4371
+ method: "POST",
4372
+ redirect: "error",
4373
+ signal: input.signal,
4374
+ headers: { accept: "application/json", "content-type": "application/json" },
4375
+ body: JSON.stringify({
4376
+ policyCid: input.policyCid,
4377
+ policy: input.policy,
4378
+ policyRoot: input.policyRoot.authorization.replace(/^Bearer\s+/i, ""),
4379
+ enforcementRoot: input.enforcementRoot.authorization.replace(/^Bearer\s+/i, ""),
4380
+ contentSourceDigestHex: input.contentSourceDigestHex,
4381
+ nativeProjectionHashHex: input.nativeProjectionHashHex,
4382
+ attestedEnforcerBinding: binding
4383
+ })
4384
+ }
4385
+ );
4386
+ if (!response.ok) {
4387
+ throw new Error(`policy registration rejected (${response.status})`);
4388
+ }
4389
+ const receipt = exactObject(
4390
+ await response.json(),
4391
+ ["policyCid", "policyRootCid", "enforcementRootCid"],
4392
+ "policy registration response"
4393
+ );
4394
+ if (receipt.policyCid !== input.policyCid || receipt.policyRootCid !== input.policyRoot.cid || receipt.enforcementRootCid !== input.enforcementRoot.cid) {
4395
+ throw new Error("policy registration response binding is invalid");
4396
+ }
4397
+ return {
4398
+ policyCid: input.policyCid,
4399
+ policyRootCid: input.policyRoot.cid,
4400
+ enforcementRootCid: input.enforcementRoot.cid,
4401
+ attestedEnforcerBinding: binding
4402
+ };
4403
+ }
4239
4404
  function policyDigestHex(policy) {
4240
4405
  const canonicalPolicy = {
4241
4406
  ...policy,
@@ -4434,9 +4599,13 @@ function parsePolicySessionUcan(authorization, expectedProofs) {
4434
4599
  if (expectedProofs !== void 0 && (parsed.payload.prf[0] !== expectedProofs[0] || parsed.payload.prf[1] !== expectedProofs[1]))
4435
4600
  throw new Error("policy session UCAN ordered proofs do not match");
4436
4601
  const factKeys = Object.keys(fact);
4437
- if (factKeys.length !== POLICY_SESSION_FACT_KEYS.length || factKeys.some((key) => !POLICY_SESSION_FACT_KEYS.includes(key)) || POLICY_SESSION_FACT_KEYS.some((key) => !(key in fact)))
4602
+ const hasLegacyFactShape = factKeys.length === POLICY_SESSION_FACT_KEYS.length && factKeys.every((key) => POLICY_SESSION_FACT_KEYS.includes(key)) && POLICY_SESSION_FACT_KEYS.every((key) => key in fact);
4603
+ const hasV4AuditFactShape = factKeys.length === POLICY_SESSION_FACT_KEYS.length + POLICY_SESSION_V4_AUDIT_FACT_KEYS.length && factKeys.every((key) => POLICY_SESSION_FACT_KEYS.includes(key) || POLICY_SESSION_V4_AUDIT_FACT_KEYS.includes(key)) && POLICY_SESSION_FACT_KEYS.every((key) => key in fact) && POLICY_SESSION_V4_AUDIT_FACT_KEYS.every((key) => key in fact);
4604
+ if (!hasLegacyFactShape && !hasV4AuditFactShape)
4438
4605
  throw new Error("policy session UCAN fact is incomplete");
4439
- if (fact.profile !== POLICY_SESSION_UCAN_V1_PROFILE || typeof fact.remainingRedelegationDepth !== "number" || !Number.isInteger(fact.remainingRedelegationDepth) || fact.remainingRedelegationDepth < 0 || fact.remainingRedelegationDepth > 8 || parsed.payload.exp - parsed.payload.nbf > 60 || parsed.payload.iss.split("#", 1)[0] !== fact.enforcerDid || parsed.payload.aud !== fact.recipientDid)
4606
+ if (hasV4AuditFactShape && (!LOWER_SHA256_HEX.test(fact.credentialIdAuditDigestHex) || !LOWER_SHA256_HEX.test(fact.presentationJtiAuditDigestHex)))
4607
+ throw new Error("policy session UCAN v4 audit facts are invalid");
4608
+ if (fact.profile !== POLICY_SESSION_UCAN_V1_PROFILE || typeof fact.remainingRedelegationDepth !== "number" || !Number.isInteger(fact.remainingRedelegationDepth) || fact.remainingRedelegationDepth < 0 || fact.remainingRedelegationDepth > 8 || parsed.payload.exp - parsed.payload.nbf > 60 || parsed.payload.iss.split("#", 1)[0] !== fact.nodeAudience || parsed.payload.aud !== fact.recipientDid)
4440
4609
  throw new Error("policy session UCAN fact is invalid");
4441
4610
  return {
4442
4611
  authorization,
@@ -4495,6 +4664,8 @@ var POLICY_V2_DOMAIN = "xyz.tinycloud.policy/policy/v2\0";
4495
4664
  var POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE = "TinyCloudPolicyCredentialRequirement";
4496
4665
  var POLICY_PRESENTATION_V3_SCHEMA = "xyz.tinycloud.policy/presentation/v3";
4497
4666
  var POLICY_PRESENTATION_V3_DOMAIN = "xyz.tinycloud.policy/Presentation/v3\0";
4667
+ var POLICY_PRESENTATION_V4_SCHEMA = "xyz.tinycloud.policy/presentation/v4";
4668
+ var POLICY_PRESENTATION_V4_DOMAIN = "xyz.tinycloud.policy/Presentation/v4\0";
4498
4669
  function record(value, label) {
4499
4670
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
4500
4671
  throw new Error(`${label} must be an object`);
@@ -4669,6 +4840,97 @@ function envelopeFromVerified(verified) {
4669
4840
  } = verified;
4670
4841
  return envelope;
4671
4842
  }
4843
+ function issuedCredentialEnvelopeFromVerified(verified) {
4844
+ return envelopeFromVerified(verified);
4845
+ }
4846
+ async function signPolicyCredentialPresentationV4(value, sign) {
4847
+ const item = record(value, "Policy presentation v4");
4848
+ exactKeys2(item, [
4849
+ "schema",
4850
+ "jti",
4851
+ "challengeId",
4852
+ "nonce",
4853
+ "policyCid",
4854
+ "nodeAudience",
4855
+ "holderDid",
4856
+ "subjectDid",
4857
+ "credentialDigest",
4858
+ "requirementDigest",
4859
+ "descriptorDigest",
4860
+ "requestedCapabilities",
4861
+ "issuedAt",
4862
+ "expiresAt"
4863
+ ], "Policy presentation v4");
4864
+ if (item.schema !== POLICY_PRESENTATION_V4_SCHEMA || item.holderDid !== item.subjectDid || !Array.isArray(item.requestedCapabilities)) throw new Error("Policy presentation v4 is invalid");
4865
+ const holderDid = nonEmpty(item.holderDid, "Policy presentation v4 holder DID");
4866
+ didKeyBytes(holderDid);
4867
+ const unsigned = Object.freeze({
4868
+ schema: POLICY_PRESENTATION_V4_SCHEMA,
4869
+ jti: nonEmpty(item.jti, "Policy presentation v4 jti"),
4870
+ challengeId: nonEmpty(item.challengeId, "Policy presentation v4 challenge"),
4871
+ nonce: nonEmpty(item.nonce, "Policy presentation v4 nonce"),
4872
+ policyCid: nonEmpty(item.policyCid, "Policy presentation v4 policy CID"),
4873
+ nodeAudience: nonEmpty(item.nodeAudience, "Policy presentation v4 audience"),
4874
+ holderDid,
4875
+ subjectDid: holderDid,
4876
+ credentialDigest: nonEmpty(item.credentialDigest, "Policy presentation v4 credential digest"),
4877
+ requirementDigest: nonEmpty(item.requirementDigest, "Policy presentation v4 requirement digest"),
4878
+ descriptorDigest: nonEmpty(item.descriptorDigest, "Policy presentation v4 descriptor digest"),
4879
+ // The low-level signer preserves the frozen wire bytes exactly. The
4880
+ // policy-aware builder performs capability normalization and containment.
4881
+ requestedCapabilities: Object.freeze(item.requestedCapabilities),
4882
+ issuedAt: date(item.issuedAt, "Policy presentation v4 issuedAt"),
4883
+ expiresAt: date(item.expiresAt, "Policy presentation v4 expiresAt")
4884
+ });
4885
+ const digest4 = (0, import_sha2562.sha256)(new TextEncoder().encode(
4886
+ POLICY_PRESENTATION_V4_DOMAIN + jcsCanonicalize(unsigned)
4887
+ ));
4888
+ const signature = await sign(digest4);
4889
+ if (signature.length !== 64 || !import_ed255194.ed25519.verify(signature, digest4, didKeyBytes(holderDid))) throw new Error("policy presentation signature is invalid");
4890
+ return Object.freeze({
4891
+ ...unsigned,
4892
+ signature: Object.freeze({
4893
+ suite: "Ed25519",
4894
+ signerDid: holderDid,
4895
+ value: encodeBase64Url(signature)
4896
+ })
4897
+ });
4898
+ }
4899
+ async function buildPolicyCredentialPresentationV4(input) {
4900
+ const policy = validateUnifiedPolicyV2(input.policy, input.policyCid);
4901
+ const requirement = validateCredentialRequirement(input.requirement);
4902
+ const commitment = policy.credentialRequirement;
4903
+ const requirementDigest = await credentialRequirementDigest(requirement);
4904
+ const credentialDigest = await sha256Base64Url(input.credential.credential);
4905
+ if (requirementDigest !== commitment.requirementDigest || input.credential.descriptorDigest !== commitment.descriptorDigest || input.credential.credentialDigest !== credentialDigest || input.credential.issuerDid !== commitment.issuerDid || input.credential.issuerKid !== commitment.issuerKid || jcsCanonicalize(input.credential.profile) !== jcsCanonicalize(commitment.profile) || jcsCanonicalize(input.credential.credentialType) !== jcsCanonicalize(commitment.credentialType)) throw new Error("credential does not match the signed Policy/v2 requirement");
4906
+ const requestedCapabilities = input.requestedCapabilities.map(normalizeUnifiedPolicyCapability);
4907
+ if (requestedCapabilities.length === 0 || requestedCapabilities.some((requested) => !policy.capabilityCeiling.some((authority) => unifiedPolicyCapabilityContains(authority, requested)))) throw new Error("requested capabilities exceed the signed Policy/v2 ceiling");
4908
+ const holderDid = input.credential.holderDid;
4909
+ if (input.challenge.policyCid !== input.policyCid || input.challenge.recipientDid !== holderDid || input.credential.subjectDid !== holderDid || typeof input.challenge.nodeAudience !== "string" || input.challenge.nodeAudience.length === 0 || typeof input.challenge.expiresAt !== "string" || !Number.isFinite(Date.parse(input.challenge.expiresAt))) throw new Error("policy challenge binding is invalid");
4910
+ const now = input.now ?? /* @__PURE__ */ new Date();
4911
+ const expiresAtMs = Math.min(
4912
+ now.getTime() + 6e4,
4913
+ Date.parse(input.challenge.expiresAt),
4914
+ Date.parse(input.credential.expiresAt)
4915
+ );
4916
+ if (expiresAtMs <= now.getTime()) throw new Error("policy challenge is expired");
4917
+ return signPolicyCredentialPresentationV4(Object.freeze({
4918
+ schema: POLICY_PRESENTATION_V4_SCHEMA,
4919
+ jti: input.jti ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
4920
+ challengeId: input.challenge.challengeId,
4921
+ nonce: input.challenge.nonce,
4922
+ policyCid: input.policyCid,
4923
+ nodeAudience: input.challenge.nodeAudience,
4924
+ holderDid,
4925
+ subjectDid: holderDid,
4926
+ credentialDigest,
4927
+ requirementDigest,
4928
+ descriptorDigest: input.credential.descriptorDigest,
4929
+ requestedCapabilities: Object.freeze(requestedCapabilities),
4930
+ issuedAt: rfc3339Seconds(now),
4931
+ expiresAt: rfc3339Seconds(new Date(expiresAtMs))
4932
+ }), input.sign);
4933
+ }
4672
4934
  async function buildPolicyCredentialPresentationV3(input) {
4673
4935
  const policy = validateUnifiedPolicyV2(input.policy, input.policyCid);
4674
4936
  const requirement = validateCredentialRequirement(input.requirement);
@@ -4755,10 +5017,12 @@ async function admitPolicyCredentialV3(input) {
4755
5017
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
4756
5018
  const challenge = await requestPolicyChallengeV3({
4757
5019
  nodeOrigin,
5020
+ policyRuntimePath: input.policyRuntimePath,
4758
5021
  policyCid: input.policyCid,
4759
5022
  recipientDid: input.credential.holderDid,
4760
5023
  requestedCapabilities: input.requestedCapabilities,
4761
- fetch: fetchFn
5024
+ fetch: fetchFn,
5025
+ signal: input.signal
4762
5026
  });
4763
5027
  const presentation = await buildPolicyCredentialPresentationV3({
4764
5028
  ...input,
@@ -4766,10 +5030,11 @@ async function admitPolicyCredentialV3(input) {
4766
5030
  challenge
4767
5031
  });
4768
5032
  const response = await fetchFn(
4769
- new URL("/share/v3/policy/delegations", nodeOrigin),
5033
+ new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin),
4770
5034
  {
4771
5035
  method: "POST",
4772
5036
  redirect: "error",
5037
+ signal: input.signal,
4773
5038
  headers: { accept: "application/json", "content-type": "application/json" },
4774
5039
  body: JSON.stringify({
4775
5040
  policyCid: input.policyCid,
@@ -4798,8 +5063,74 @@ async function admitPolicyCredentialV3(input) {
4798
5063
  if (session.cid !== value.sessionCid || session.aud !== input.credential.holderDid || session.fact.policyCid !== input.policyCid || session.fact.recipientDid !== input.credential.holderDid || session.fact.policyDelegationCid !== input.policyRootCid || session.fact.enforcementDelegationCid !== input.enforcementRootCid || jcsCanonicalize(session.att) !== jcsCanonicalize(expectedAttenuation)) {
4799
5064
  throw new Error("policy delegation signed binding is invalid");
4800
5065
  }
5066
+ input.signal?.throwIfAborted();
4801
5067
  return Object.freeze({ challenge, presentation, session });
4802
5068
  }
5069
+ function validatePolicyCredentialAdmissionV4Authority(session, expected) {
5070
+ if (session.iss.split("#", 1)[0] !== expected.nodeAudience || session.fact.nodeAudience !== expected.nodeAudience || session.fact.enforcerDid !== expected.enforcerDid) throw new Error("policy delegation authority binding is invalid");
5071
+ }
5072
+ async function admitPolicyCredentialV4(input) {
5073
+ const policy = validateUnifiedPolicyV2(input.policy, input.policyCid);
5074
+ const nodeOrigin = policyNodeOrigin(input.nodeOrigin);
5075
+ const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
5076
+ const challenge = await requestPolicyChallengeV3({
5077
+ nodeOrigin,
5078
+ policyRuntimePath: input.policyRuntimePath,
5079
+ policyCid: input.policyCid,
5080
+ recipientDid: input.credential.holderDid,
5081
+ requestedCapabilities: input.requestedCapabilities,
5082
+ fetch: fetchFn,
5083
+ signal: input.signal
5084
+ });
5085
+ const presentation = await buildPolicyCredentialPresentationV4({
5086
+ ...input,
5087
+ policy,
5088
+ challenge
5089
+ });
5090
+ const response = await fetchFn(new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin), {
5091
+ method: "POST",
5092
+ redirect: "error",
5093
+ signal: input.signal,
5094
+ headers: { accept: "application/json", "content-type": "application/json" },
5095
+ body: JSON.stringify({
5096
+ policyCid: input.policyCid,
5097
+ challengeId: challenge.challengeId,
5098
+ nonce: challenge.nonce,
5099
+ requirement: validateCredentialRequirement(input.requirement),
5100
+ credential: envelopeFromVerified(input.credential),
5101
+ presentation
5102
+ })
5103
+ });
5104
+ if (!response.ok) throw new Error(`policy delegation rejected (${response.status})`);
5105
+ const value = record(await response.json(), "policy delegation");
5106
+ if (value.admitted !== true || typeof value.sessionCid !== "string" || typeof value.authorization !== "string") throw new Error("policy delegation response is invalid");
5107
+ const session = parsePolicySessionUcan(value.authorization, [
5108
+ input.policyRootCid,
5109
+ input.enforcementRootCid
5110
+ ]);
5111
+ const expectedAttenuation = compactAttenuationForPolicyCapabilities(input.requestedCapabilities);
5112
+ validatePolicyCredentialAdmissionV4Authority(session, {
5113
+ nodeAudience: input.expectedNodeAudience,
5114
+ enforcerDid: input.expectedEnforcerDid
5115
+ });
5116
+ if (session.cid !== value.sessionCid || session.aud !== input.credential.holderDid || session.fact.policyCid !== input.policyCid || session.fact.recipientDid !== input.credential.holderDid || session.fact.policyDelegationCid !== input.policyRootCid || session.fact.enforcementDelegationCid !== input.enforcementRootCid || jcsCanonicalize(session.att) !== jcsCanonicalize(expectedAttenuation)) throw new Error("policy delegation signed binding is invalid");
5117
+ const importResponse = await fetchFn(new URL("/delegate", nodeOrigin), {
5118
+ method: "POST",
5119
+ redirect: "error",
5120
+ signal: input.signal,
5121
+ headers: { Authorization: session.authorization }
5122
+ });
5123
+ if (!importResponse.ok) throw new Error(`delegation import rejected (${importResponse.status})`);
5124
+ input.signal?.throwIfAborted();
5125
+ return Object.freeze({ challenge, presentation, session, delegationImported: true });
5126
+ }
5127
+ function policyRuntimeBasePath2(value) {
5128
+ const path = value ?? "/policy/v3";
5129
+ if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
5130
+ throw new Error("policy runtime path is invalid");
5131
+ }
5132
+ return path;
5133
+ }
4803
5134
 
4804
5135
  // src/requester/index.ts
4805
5136
  var REQUESTER_NEAR_EXPIRY_SECONDS = 30;
@@ -8206,13 +8537,13 @@ function canonicalizeRecapCaveats(caveats) {
8206
8537
  }
8207
8538
  if (Array.isArray(value)) return `[${value.map(canonicalize).join(",")}]`;
8208
8539
  if (typeof value === "object") {
8209
- const object3 = value;
8210
- const prototype = Object.getPrototypeOf(object3);
8540
+ const object4 = value;
8541
+ const prototype = Object.getPrototypeOf(object4);
8211
8542
  if (prototype !== Object.prototype && prototype !== null) {
8212
8543
  throw new Error("ReCap caveats must contain only JSON values.");
8213
8544
  }
8214
- return `{${Object.keys(object3).sort().map(
8215
- (key) => `${JSON.stringify(key)}:${canonicalize(object3[key])}`
8545
+ return `{${Object.keys(object4).sort().map(
8546
+ (key) => `${JSON.stringify(key)}:${canonicalize(object4[key])}`
8216
8547
  ).join(",")}}`;
8217
8548
  }
8218
8549
  throw new Error("ReCap caveats must contain only JSON values.");
@@ -8296,7 +8627,6 @@ var import_ed255195 = require("@noble/curves/ed25519");
8296
8627
  var import_blake33 = require("@noble/hashes/blake3");
8297
8628
  var import_sha2563 = require("@noble/hashes/sha256");
8298
8629
  var ENVELOPE_SCHEMA = "xyz.tinycloud.share/envelope";
8299
- var INLINE_PREFIX = "tc2:";
8300
8630
  var RAW_CID_CODEC = 85;
8301
8631
  var BLAKE3_256_CODE = 30;
8302
8632
  var DEFAULT_MAX_INLINE_BYTES = 256 * 1024;
@@ -8343,8 +8673,8 @@ function canonicalJson(value) {
8343
8673
  }
8344
8674
  if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
8345
8675
  if (typeof value === "object") {
8346
- const object3 = value;
8347
- return `{${Object.keys(object3).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(object3[key])}`).join(",")}}`;
8676
+ const object4 = value;
8677
+ return `{${Object.keys(object4).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(object4[key])}`).join(",")}}`;
8348
8678
  }
8349
8679
  throw new ShareEnvelopeError("invalid-envelope", "unsupported JSON value");
8350
8680
  }
@@ -9001,25 +9331,8 @@ function parsePublishedShareLink(link, options2 = {}) {
9001
9331
  }
9002
9332
  const origin2 = normalizeOrigin(url.origin);
9003
9333
  if (options2.trustedOrigins !== void 0 && !options2.trustedOrigins.map(normalizeOrigin).includes(origin2)) throw new ShareEnvelopeError("origin-mismatch", "share link origin is not trusted");
9004
- if (url.search !== "" || url.username !== "" || url.password !== "") throw new ShareEnvelopeError("invalid-link", "share link is not canonical");
9005
- if (url.pathname === "/s/inline" && url.hash.startsWith("#v=2&p=")) {
9006
- let payload;
9007
- try {
9008
- const bytes2 = base64UrlToBytes(url.hash.slice("#v=2&p=".length));
9009
- if (bytes2.length > (options2.maxInlineBytes ?? DEFAULT_MAX_INLINE_BYTES) * 2) throw new Error("inline payload too large");
9010
- const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes2));
9011
- if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("inline payload shape");
9012
- payload = value;
9013
- } catch (error) {
9014
- throw new ShareEnvelopeError("invalid-link", error instanceof Error ? error.message : "invalid inline payload");
9015
- }
9016
- if (payload.v !== 2 || typeof payload.c !== "string" || typeof payload.cid !== "string" || payload.k !== void 0 && typeof payload.k !== "string" || Object.keys(payload).some((key3) => !["v", "c", "cid", "k"].includes(key3))) throw new ShareEnvelopeError("invalid-link", "inline payload fields are invalid");
9017
- const sealed = base64UrlToBytes(payload.c);
9018
- if (!verifyPublishedShareCid(payload.cid, sealed)) throw new ShareEnvelopeError("cid-mismatch", "inline payload CID does not match");
9019
- const key2 = payload.k === void 0 ? void 0 : base64UrlToBytes(payload.k);
9020
- if (key2 !== void 0 && key2.length !== 32) throw new ShareEnvelopeError("invalid-link", "inline payload key is invalid");
9021
- return { origin: origin2, cid: payload.cid, ...key2 === void 0 ? {} : { key: key2 }, sealed };
9022
- }
9334
+ if (url.username !== "" || url.password !== "") throw new ShareEnvelopeError("invalid-link", "share link is not canonical");
9335
+ if (url.search !== "") throw new ShareEnvelopeError("invalid-link", "share link is not canonical");
9023
9336
  const match = /^\/s\/([a-z2-7]+)$/.exec(url.pathname);
9024
9337
  if (match === null || !url.hash.startsWith("#k=")) throw new ShareEnvelopeError("invalid-link", "published share link is invalid");
9025
9338
  const key = base64UrlToBytes(url.hash.slice(3));
@@ -9039,13 +9352,10 @@ function parseShareUrl(link, options2 = {}) {
9039
9352
  } catch {
9040
9353
  throw new ShareEnvelopeError("invalid-link", "share link must be an absolute URL");
9041
9354
  }
9042
- if (url.search !== "") throw new ShareEnvelopeError("invalid-link", "share links must not contain query parameters");
9043
9355
  const origin2 = normalizeOrigin(url.origin);
9044
9356
  if (options2.trustedOrigins !== void 0 && !options2.trustedOrigins.map(normalizeOrigin).includes(origin2)) throw new ShareEnvelopeError("origin-mismatch", "share link origin is not trusted");
9045
- if (url.pathname === "/s/inline" && url.hash.startsWith("#v=2&p=")) {
9046
- const published = parsePublishedShareLink(link, options2);
9047
- return { kind: "inline", origin: origin2, cid: published.cid, key: published.key, url: `${url.origin}${url.pathname}`, protocol: "share-envelope-v2" };
9048
- }
9357
+ if (url.pathname === "/viewer") throw new ShareEnvelopeError("invalid-link", "retired viewer links are not accepted");
9358
+ if (url.search !== "") throw new ShareEnvelopeError("invalid-link", "share links must not contain query parameters");
9049
9359
  const match = url.pathname.match(/^\/s\/(i\/)?([^/]+)$/);
9050
9360
  if (!match) throw new ShareEnvelopeError("invalid-link", "share link path is invalid");
9051
9361
  const fragmentParams = url.hash === "" ? void 0 : new URLSearchParams(url.hash.slice(1));
@@ -9068,9 +9378,10 @@ function parseShareUrl(link, options2 = {}) {
9068
9378
  }
9069
9379
  function isV2ShareLink(link) {
9070
9380
  try {
9071
- return new URL(link).pathname.startsWith("/s/");
9381
+ const url = new URL(link);
9382
+ return url.search === "" && url.pathname.startsWith("/s/");
9072
9383
  } catch {
9073
- return link.startsWith(INLINE_PREFIX);
9384
+ return false;
9074
9385
  }
9075
9386
  }
9076
9387
  async function encryptShareBytes(bytes2, key) {
@@ -9526,8 +9837,8 @@ function canonicalJsonForProof(value) {
9526
9837
  }
9527
9838
  if (Array.isArray(value)) return `[${value.map(canonicalJsonForProof).join(",")}]`;
9528
9839
  if (typeof value === "object") {
9529
- const object3 = value;
9530
- return `{${Object.keys(object3).sort().map((key) => `${JSON.stringify(key)}:${canonicalJsonForProof(object3[key])}`).join(",")}}`;
9840
+ const object4 = value;
9841
+ return `{${Object.keys(object4).sort().map((key) => `${JSON.stringify(key)}:${canonicalJsonForProof(object4[key])}`).join(",")}}`;
9531
9842
  }
9532
9843
  throw new ShareAccessError("SHARE_SESSION_INVALID");
9533
9844
  }
@@ -10236,12 +10547,12 @@ var ShareRecipientClient = class {
10236
10547
  this.assertDetachedProof(request.proof);
10237
10548
  }
10238
10549
  parseSessionCapability(value) {
10239
- const object3 = this.requireObject(value, "session capability");
10240
- if (typeof object3.spaceId !== "string") throw new ShareAccessError("SHARE_SESSION_INVALID", "session capability space is invalid");
10241
- if (!Array.isArray(object3.actions) || object3.actions.some((action) => !["read", "list", "edit"].includes(action))) throw new ShareAccessError("SHARE_SESSION_INVALID", "session capability actions are invalid");
10242
- const resource = this.requireObject(object3.resource, "session capability resource");
10550
+ const object4 = this.requireObject(value, "session capability");
10551
+ if (typeof object4.spaceId !== "string") throw new ShareAccessError("SHARE_SESSION_INVALID", "session capability space is invalid");
10552
+ if (!Array.isArray(object4.actions) || object4.actions.some((action) => !["read", "list", "edit"].includes(action))) throw new ShareAccessError("SHARE_SESSION_INVALID", "session capability actions are invalid");
10553
+ const resource = this.requireObject(object4.resource, "session capability resource");
10243
10554
  if (resource.kind !== "exact" && resource.kind !== "prefix" || typeof resource.path !== "string") throw new ShareAccessError("SHARE_SESSION_INVALID", "session capability resource is invalid");
10244
- return { spaceId: object3.spaceId, actions: [...new Set(object3.actions)], resource: { kind: resource.kind, path: resource.path } };
10555
+ return { spaceId: object4.spaceId, actions: [...new Set(object4.actions)], resource: { kind: resource.kind, path: resource.path } };
10245
10556
  }
10246
10557
  assertProvidedPolicySession(session, envelope) {
10247
10558
  const sessionExpiry = dateValue(session.expiresAt);
@@ -11881,62 +12192,21 @@ function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
11881
12192
  return validateOwnerSharePolicyRegistration(value, expected);
11882
12193
  }
11883
12194
 
11884
- // src/delegations/share-delivery.ts
12195
+ // src/delegations/share-delivery-v3.ts
11885
12196
  var import_ed255199 = require("@noble/curves/ed25519");
11886
- var SHARE_DELIVERY_AUTHORIZATION_DOMAIN = "xyz.tinycloud.share/delivery-authorization/v2\0";
11887
- function isCanonicalHttpsOrigin(value) {
11888
- let url;
11889
- try {
11890
- url = new URL(value);
11891
- } catch {
11892
- return false;
11893
- }
11894
- return url.protocol === "https:" && url.origin === value && url.pathname === "/" && url.search === "" && url.hash === "" && url.username === "" && url.password === "";
11895
- }
11896
- var AUTHORIZATION_KEYS = [
11897
- "type",
11898
- "version",
11899
- "jti",
11900
- "shareCid",
11901
- "shareId",
11902
- "registrationCid",
11903
- "delegationCid",
11904
- "enforcementDelegationCid",
11905
- "envelopeCid",
11906
- "policyCid",
11907
- "nodeAudience",
11908
- "targetOrigin",
11909
- "openCredentialsAudience",
11910
- "holder",
11911
- "recipientMatcher",
11912
- "deliveryEmail",
11913
- "shareUrl",
11914
- "returnOrigin",
11915
- "documentName",
11916
- "senderDid",
11917
- "senderTrust",
11918
- "contentSource",
11919
- "contentSourceDigest",
11920
- "shareExpiresAt",
11921
- "issuedAt",
11922
- "reportAbuseToken",
11923
- "actions",
11924
- "resource",
11925
- "authorityMaterialHandle",
11926
- "authorityMaterialDigest",
11927
- "requestBodyDigest",
11928
- "idempotencyKey",
11929
- "expiresAt",
11930
- "dataAuthority"
11931
- ];
11932
- function assertObject2(value, keys, label) {
12197
+ var import_sha2567 = require("@noble/hashes/sha256");
12198
+ var CREDENTIAL_INVITATION_REQUEST_DOMAIN = "xyz.tinycloud.credentials/invitation-request/v1\0";
12199
+ var DELIVERY_ADMISSION_DOMAIN = "xyz.tinycloud.policy/delivery-admission/v0\0";
12200
+ var REQUEST_KEYS = ["schema", "policyId", "recipient", "resource", "credentialType", "returnLink", "envelopeRef", "label", "shareExpiresAt", "audience", "issuedAt", "expiresAt", "nonce"];
12201
+ var ADMISSION_KEYS = ["schema", "policyId", "ownerDid", "recipient", "resource", "actions", "credentialType", "returnLink", "envelopeRef", "label", "shareExpiresAt", "senderKeyDid", "audience", "issuedAt", "expiresAt", "nonce", "signature"];
12202
+ function exactObject2(value, keys, label) {
11933
12203
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
11934
12204
  const record2 = value;
11935
12205
  if (Object.keys(record2).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record2, key))) throw new Error(`${label} has unknown or missing fields`);
11936
12206
  return record2;
11937
12207
  }
11938
- function fromB642(value) {
11939
- if (!/^[A-Za-z0-9_-]+$/.test(value)) throw new Error("share delivery value is not canonical base64url");
12208
+ function decodeBase64Url3(value) {
12209
+ if (typeof value !== "string" || !/^[A-Za-z0-9_-]+$/.test(value)) throw new Error("share delivery value is not canonical base64url");
11940
12210
  if (typeof atob === "function") {
11941
12211
  const padded = value.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - value.length % 4) % 4);
11942
12212
  return Uint8Array.from(atob(padded), (character) => character.charCodeAt(0));
@@ -11944,42 +12214,45 @@ function fromB642(value) {
11944
12214
  if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(value, "base64url"));
11945
12215
  throw new Error("base64url decoding is unavailable");
11946
12216
  }
11947
- function validateShareDeliveryAuthorizationBytes(bytesValue, expected) {
11948
- let value;
12217
+ function object3(value, label) {
12218
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
12219
+ return value;
12220
+ }
12221
+ function didKeyBytes2(did) {
12222
+ if (!did.startsWith("did:key:z") || /[#/?]/.test(did.slice("did:key:".length))) throw new Error("v3 delivery admission signer is invalid");
12223
+ const decoded = base58btc.decode(did.slice("did:key:".length));
12224
+ if (decoded.length !== 34 || decoded[0] !== 237 || decoded[1] !== 1) throw new Error("v3 delivery admission signer is invalid");
12225
+ return decoded.slice(2);
12226
+ }
12227
+ function validateShareDeliveryAuthorizationV3Bytes(bytes2, expected) {
12228
+ let parsed;
11949
12229
  try {
11950
- value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytesValue));
12230
+ parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes2));
11951
12231
  } catch {
11952
- throw new Error("share delivery authorization response is not valid UTF-8 JSON");
11953
- }
11954
- const root = assertObject2(value, ["authorization", "proof"], "share delivery authorization response");
11955
- const authorization = assertObject2(root.authorization, AUTHORIZATION_KEYS, "share delivery authorization");
11956
- const proof = assertObject2(root.proof, ["alg", "kid", "signature"], "share delivery authorization proof");
11957
- const request = expected.request;
11958
- if (authorization.type !== "TinyCloudShareDeliveryAuthorization" || authorization.version !== 2 || authorization.dataAuthority !== false || authorization.jti !== request.jti || authorization.shareCid !== request.shareCid || authorization.shareId !== request.shareId || authorization.registrationCid !== request.registrationCid || authorization.delegationCid !== request.delegationCid || authorization.enforcementDelegationCid !== request.enforcementDelegationCid || authorization.envelopeCid !== request.envelopeCid || authorization.policyCid !== request.policyCid || authorization.deliveryEmail !== request.recipientEmail || authorization.shareUrl !== request.shareUrl || authorization.documentName !== request.documentName || authorization.requestBodyDigest !== request.requestBodyDigest || authorization.expiresAt !== request.expiresAt || authorization.idempotencyKey !== request.idempotencyKey || authorization.reportAbuseToken !== request.jti || authorization.authorityMaterialHandle !== request.registrationCid) {
11959
- throw new Error("share delivery authorization is not bound to the submitted request");
11960
- }
11961
- if (typeof authorization.issuedAt !== "string" || Date.parse(authorization.issuedAt) > Date.now() + 6e4) throw new Error("share delivery authorization issuedAt is invalid");
11962
- if (new Date(authorization.expiresAt).toISOString() !== authorization.expiresAt) throw new Error("share delivery authorization expiresAt is non-canonical");
11963
- if (typeof authorization.openCredentialsAudience !== "string" || !isCanonicalHttpsOrigin(authorization.openCredentialsAudience) || authorization.openCredentialsAudience !== expected.credentialsAudience || authorization.openCredentialsAudience === authorization.nodeAudience || authorization.openCredentialsAudience === authorization.returnOrigin) {
11964
- throw new Error("share delivery authorization openCredentialsAudience is missing or untrusted");
11965
- }
11966
- if (proof.alg !== "EdDSA" || typeof proof.kid !== "string" || typeof proof.signature !== "string") throw new Error("share delivery authorization proof is invalid");
11967
- if (proof.kid !== expected.nodeProof.kid) throw new Error("share delivery authorization proof key is not trusted");
11968
- const encodedKid = expected.nodeProof.publicKey;
11969
- const publicKey = encodedKid.length === 34 && encodedKid[0] === 237 && encodedKid[1] === 1 ? encodedKid.slice(2) : encodedKid;
11970
- if (publicKey.length !== 32) throw new Error("share delivery authorization proof key is invalid");
11971
- const signatureBytes = fromB642(proof.signature);
11972
- const signedBytes = new TextEncoder().encode(`${SHARE_DELIVERY_AUTHORIZATION_DOMAIN}${canonicalizeSignedObjectUnsigned(authorization)}`);
11973
- if (signatureBytes.length !== 64 || !import_ed255199.ed25519.verify(signatureBytes, signedBytes, publicKey)) throw new Error("share delivery authorization proof signature is invalid");
11974
- return { authorization, proof };
11975
- }
11976
- function shareDeliveryTrustedKid(publicKey) {
11977
- if (publicKey.length !== 32) throw new Error("share delivery node key must be a raw 32-byte Ed25519 public key");
11978
- const prefixed = new Uint8Array(34);
11979
- prefixed.set([237, 1]);
11980
- prefixed.set(publicKey, 2);
11981
- const did = `did:key:${base58btc.encode(prefixed)}`;
11982
- return `${did}#${did.slice("did:key:".length)}`;
12232
+ throw new Error("v3 share delivery response is not valid UTF-8 JSON");
12233
+ }
12234
+ const root = exactObject2(parsed, ["request", "admission"], "v3 share delivery response");
12235
+ const request = exactObject2(root.request, REQUEST_KEYS, "credential invitation request");
12236
+ const admission = exactObject2(root.admission, ADMISSION_KEYS, "delivery admission");
12237
+ const signature = exactObject2(admission.signature, ["suite", "signerDid", "value"], "delivery admission signature");
12238
+ const envelope = object3(expected.request.envelope, "v3 share envelope");
12239
+ const policy = object3(envelope.policy, "v3 share policy");
12240
+ const requirement = object3(policy.credentialRequirement, "v3 credential requirement");
12241
+ const credentialType = object3(requirement.credentialType, "v3 credential type");
12242
+ const contentSource = object3(envelope.contentSource, "v3 content source");
12243
+ const envelopeSignature = object3(envelope.signature, "v3 envelope signature");
12244
+ const target = object3(envelope.target, "v3 target");
12245
+ const binding = object3(envelope.attestedEnforcerBinding, "v3 attested enforcer binding");
12246
+ const fields = ["policyId", "recipient", "resource", "credentialType", "returnLink", "envelopeRef", "label", "shareExpiresAt", "audience", "issuedAt", "expiresAt", "nonce"];
12247
+ if (request.schema !== "xyz.tinycloud.credentials/invitation-request/v1" || admission.schema !== "xyz.tinycloud.policy/delivery-admission/v0" || fields.some((field) => request[field] !== admission[field]) || request.policyId !== envelope.policyCid || request.recipient !== expected.request.recipientEmail || request.resource !== contentSource.kvResource || request.credentialType !== credentialType.id || request.credentialType !== "opencredentials.email/v1" || request.returnLink !== expected.request.shareUrl || request.envelopeRef !== expected.request.shareCid || request.label !== expected.request.documentName || request.shareExpiresAt !== envelope.expiry || request.audience !== expected.deliveryAudience || request.expiresAt !== expected.request.expiresAt || request.nonce !== expected.request.jti || admission.ownerDid !== envelopeSignature.signerDid || admission.senderKeyDid !== expected.senderKeyDid || canonicalizeSignedObjectUnsigned(admission.actions) !== canonicalizeSignedObjectUnsigned(["tinycloud.kv/get"]) || signature.suite !== "eddsa-ed25519-sha256-jcs-v1" || target.nodeAudience !== binding.nodeAudience || signature.signerDid !== binding.nodeAudience) throw new Error("v3 share delivery authorization is not bound to the submitted request");
12248
+ const issuedAt = Date.parse(String(request.issuedAt));
12249
+ const expiresAt = Date.parse(String(request.expiresAt));
12250
+ if (!Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) || expiresAt <= issuedAt || expiresAt - issuedAt > 15 * 6e4) throw new Error("v3 share delivery authorization time is invalid");
12251
+ const admissionSignature = decodeBase64Url3(signature.value);
12252
+ const { signature: _signature, ...unsignedAdmission } = admission;
12253
+ const digest4 = (0, import_sha2567.sha256)(new TextEncoder().encode(`${DELIVERY_ADMISSION_DOMAIN}${canonicalizeSignedObjectUnsigned(unsignedAdmission)}`));
12254
+ if (admissionSignature.length !== 64 || !import_ed255199.ed25519.verify(admissionSignature, digest4, didKeyBytes2(String(signature.signerDid)))) throw new Error("v3 share delivery admission signature is invalid");
12255
+ return { request, admission };
11983
12256
  }
11984
12257
 
11985
12258
  // src/delegations/sender-share-store.ts
@@ -14702,8 +14975,8 @@ function stableJson(value) {
14702
14975
  if (Array.isArray(value)) {
14703
14976
  return `[${value.map(stableJson).join(",")}]`;
14704
14977
  }
14705
- const object3 = value;
14706
- return `{${Object.keys(object3).sort().map((key) => `${JSON.stringify(key)}:${stableJson(object3[key])}`).join(",")}}`;
14978
+ const object4 = value;
14979
+ return `{${Object.keys(object4).sort().map((key) => `${JSON.stringify(key)}:${stableJson(object4[key])}`).join(",")}}`;
14707
14980
  }
14708
14981
  function indexedDelegationFromRow(row) {
14709
14982
  const [
@@ -17611,6 +17884,7 @@ var DEFAULT_LOCAL_NODE_URL = "http://127.0.0.1:8000";
17611
17884
  var LOCAL_LOOPBACK_PROBE_TIMEOUT_MS = 250;
17612
17885
  var LOCAL_LINK_PROBE_TIMEOUT_MS = 750;
17613
17886
  var LOCAL_LINK_HOST_SUFFIX = ".local.tinycloud.link";
17887
+ var OWNER_NODE_BINDING_TIMEOUT_MS = 5e3;
17614
17888
  function createInMemoryLocalNodeIdentityStore() {
17615
17889
  const pins = /* @__PURE__ */ new Map();
17616
17890
  return {
@@ -17743,21 +18017,80 @@ async function verifyLocationRecord(input) {
17743
18017
  }
17744
18018
  return false;
17745
18019
  }
17746
- async function fetchLocationRecord(registryUrl, subject, fetchFn = globalThis.fetch) {
18020
+ async function fetchLocationRecord(registryUrl, subject, fetchFn = globalThis.fetch, signal) {
17747
18021
  const url = `${registryUrl.replace(/\/$/, "")}/v1/locations/${encodeURIComponent(subject)}`;
17748
- const response = await fetchFn(url);
18022
+ const response = await fetchFn(url, {
18023
+ redirect: "error",
18024
+ headers: { accept: "application/json" },
18025
+ ...signal === void 0 ? {} : { signal }
18026
+ });
17749
18027
  if (response.status === 404) {
17750
18028
  return null;
17751
18029
  }
17752
18030
  if (!response.ok) {
17753
18031
  throw new Error(`location registry returned HTTP ${response.status}`);
17754
18032
  }
17755
- const body = await response.json();
18033
+ const text2 = await boundedResponseText(response, "location registry", 64 * 1024);
18034
+ let body;
18035
+ try {
18036
+ body = JSON.parse(text2);
18037
+ } catch {
18038
+ throw new LocationRecordValidationError("registry response is not JSON");
18039
+ }
17756
18040
  if (body.record === void 0) {
17757
18041
  throw new LocationRecordValidationError("registry response missing record");
17758
18042
  }
17759
18043
  return validateLocationRecord(body.record);
17760
18044
  }
18045
+ async function publishLocationRecord(options2) {
18046
+ validateSubject(options2.subject);
18047
+ const registryUrl = exactHttpOrigin(options2.registryUrl, "registry URL");
18048
+ const nodeOrigin = exactHttpOrigin(options2.nodeOrigin, "node origin");
18049
+ const fetchFn = options2.fetch ?? globalThis.fetch.bind(globalThis);
18050
+ const current = await fetchLocationRecord(registryUrl, options2.subject, fetchFn);
18051
+ if (current !== null) {
18052
+ if (current.subject !== options2.subject || !await verifyLocationRecord(current)) {
18053
+ throw new LocationRecordValidationError("existing location record signature is invalid");
18054
+ }
18055
+ if (publishedHttpOrigins(current).includes(nodeOrigin)) {
18056
+ return current;
18057
+ }
18058
+ }
18059
+ const record2 = await signLocationRecord({
18060
+ version: 1,
18061
+ subject: options2.subject,
18062
+ multiaddrs: [...current?.multiaddrs ?? [], httpUrlToMultiaddr(nodeOrigin)],
18063
+ updated_at: (options2.now?.() ?? /* @__PURE__ */ new Date()).toISOString(),
18064
+ sequence: (current?.sequence ?? -1) + 1
18065
+ }, options2.signer);
18066
+ const response = await fetchFn(
18067
+ `${registryUrl}/v1/locations/${encodeURIComponent(options2.subject)}`,
18068
+ {
18069
+ method: "PUT",
18070
+ redirect: "error",
18071
+ headers: { accept: "application/json", "content-type": "application/json" },
18072
+ body: JSON.stringify(record2)
18073
+ }
18074
+ );
18075
+ if (!response.ok) {
18076
+ throw new Error(`location registry publish returned HTTP ${response.status}`);
18077
+ }
18078
+ const text2 = await boundedResponseText(response, "location registry", 64 * 1024);
18079
+ let body;
18080
+ try {
18081
+ body = JSON.parse(text2);
18082
+ } catch {
18083
+ throw new LocationRecordValidationError("registry publish response is not JSON");
18084
+ }
18085
+ if (body.record === void 0) {
18086
+ throw new LocationRecordValidationError("registry publish response missing record");
18087
+ }
18088
+ const published = validateLocationRecord(body.record);
18089
+ if (canonicalLocationPayload(locationPayloadForRecord(published)) !== canonicalLocationPayload(locationPayloadForRecord(record2)) || published.signature !== record2.signature || !await verifyLocationRecord(published)) {
18090
+ throw new LocationRecordValidationError("registry publish response does not match the signed record");
18091
+ }
18092
+ return published;
18093
+ }
17761
18094
  async function resolveCloudLocation(subject, options2 = {}) {
17762
18095
  validateSubject(subject);
17763
18096
  const verifyRecords = options2.verifyRecords ?? true;
@@ -18008,6 +18341,123 @@ function multiaddrToHttpUrl(input) {
18008
18341
  }
18009
18342
  return uri;
18010
18343
  }
18344
+ function exactHttpOrigin(value, label) {
18345
+ let url;
18346
+ try {
18347
+ url = new URL(value);
18348
+ } catch {
18349
+ throw new LocationRecordValidationError(`${label} must be an absolute URL origin`);
18350
+ }
18351
+ const loopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]";
18352
+ if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
18353
+ throw new LocationRecordValidationError(`${label} must use HTTPS (or loopback HTTP)`);
18354
+ }
18355
+ if (url.username !== "" || url.password !== "" || url.pathname !== "/" || url.search !== "" || url.hash !== "") {
18356
+ throw new LocationRecordValidationError(`${label} must be an origin without credentials, path, query, or fragment`);
18357
+ }
18358
+ return url.origin;
18359
+ }
18360
+ function publishedHttpOrigins(record2) {
18361
+ const origins = [];
18362
+ for (const address of record2.multiaddrs) {
18363
+ try {
18364
+ origins.push(exactHttpOrigin(multiaddrToHttpUrl(address), "published node URL"));
18365
+ } catch {
18366
+ }
18367
+ }
18368
+ return origins;
18369
+ }
18370
+ async function boundedResponseText(response, label, maxBytes) {
18371
+ const declaredLength = response.headers.get("content-length");
18372
+ if (declaredLength !== null && (!/^\d+$/.test(declaredLength) || Number(declaredLength) > maxBytes)) {
18373
+ throw new LocationRecordValidationError(`${label} response is too large`);
18374
+ }
18375
+ if (response.body === null) return "";
18376
+ const reader = response.body.getReader();
18377
+ const chunks = [];
18378
+ let total = 0;
18379
+ try {
18380
+ while (true) {
18381
+ const { done, value } = await reader.read();
18382
+ if (done) break;
18383
+ if (value === void 0) continue;
18384
+ total += value.byteLength;
18385
+ if (total > maxBytes) {
18386
+ await reader.cancel().catch(() => void 0);
18387
+ throw new LocationRecordValidationError(`${label} response is too large`);
18388
+ }
18389
+ chunks.push(value);
18390
+ }
18391
+ } finally {
18392
+ reader.releaseLock();
18393
+ }
18394
+ const bytes2 = new Uint8Array(total);
18395
+ let offset = 0;
18396
+ for (const chunk of chunks) {
18397
+ bytes2.set(chunk, offset);
18398
+ offset += chunk.byteLength;
18399
+ }
18400
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes2);
18401
+ }
18402
+ function boundedSignal(parent, timeoutMs) {
18403
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
18404
+ throw new LocationRecordValidationError("owner-node binding timeout must be positive");
18405
+ }
18406
+ const controller = new AbortController();
18407
+ const abortFromParent = () => controller.abort(parent?.reason);
18408
+ if (parent?.aborted) abortFromParent();
18409
+ else parent?.addEventListener("abort", abortFromParent, { once: true });
18410
+ const timer = setTimeout(() => controller.abort(new DOMException("owner-node binding timed out", "TimeoutError")), timeoutMs);
18411
+ return {
18412
+ signal: controller.signal,
18413
+ dispose() {
18414
+ clearTimeout(timer);
18415
+ parent?.removeEventListener("abort", abortFromParent);
18416
+ }
18417
+ };
18418
+ }
18419
+ async function verifyOwnerNodeBinding(options2) {
18420
+ validateSubject(options2.ownerDid);
18421
+ validateSubject(options2.nodeDid);
18422
+ const registryUrl = exactHttpOrigin(options2.registryUrl, "registry URL");
18423
+ const nodeOrigin = exactHttpOrigin(options2.nodeOrigin, "node origin");
18424
+ const fetchFn = options2.fetch ?? globalThis.fetch.bind(globalThis);
18425
+ const lookup = boundedSignal(options2.signal, options2.timeoutMs ?? OWNER_NODE_BINDING_TIMEOUT_MS);
18426
+ try {
18427
+ const record2 = await fetchLocationRecord(registryUrl, options2.ownerDid, fetchFn, lookup.signal);
18428
+ if (record2 === null) {
18429
+ throw new LocationRecordValidationError("owner has no published location record");
18430
+ }
18431
+ if (record2.subject !== options2.ownerDid || !await verifyLocationRecord(record2)) {
18432
+ throw new LocationRecordValidationError("owner location record signature is invalid");
18433
+ }
18434
+ const publishedOrigins = publishedHttpOrigins(record2);
18435
+ if (!publishedOrigins.includes(nodeOrigin)) {
18436
+ throw new LocationRecordValidationError("share target is not in the owner's signed location record");
18437
+ }
18438
+ const response = await fetchFn(new URL("/info", nodeOrigin), {
18439
+ redirect: "error",
18440
+ headers: { accept: "application/json" },
18441
+ signal: lookup.signal
18442
+ });
18443
+ if (!response.ok) {
18444
+ throw new LocationRecordValidationError(`target node /info returned HTTP ${response.status}`);
18445
+ }
18446
+ const text2 = await boundedResponseText(response, "target node /info", 16 * 1024);
18447
+ let body;
18448
+ try {
18449
+ body = JSON.parse(text2);
18450
+ } catch {
18451
+ throw new LocationRecordValidationError("target node /info response is not JSON");
18452
+ }
18453
+ if (body === null || typeof body !== "object" || Array.isArray(body) || body.nodeId !== options2.nodeDid) {
18454
+ throw new LocationRecordValidationError("target node identity does not match the share attestation");
18455
+ }
18456
+ return Object.freeze({ record: record2, nodeOrigin, nodeDid: options2.nodeDid });
18457
+ } finally {
18458
+ lookup.dispose();
18459
+ }
18460
+ }
18011
18461
  function httpUrlToMultiaddr(input) {
18012
18462
  const url = new URL(input);
18013
18463
  if (url.protocol !== "http:" && url.protocol !== "https:") {
@@ -18169,7 +18619,7 @@ async function verifyPkhSignature(did, payload, signature) {
18169
18619
  }
18170
18620
  function verifyDidKeySignature(did, payload, signature) {
18171
18621
  const publicKey = ed25519PublicKeyFromDidKey2(did);
18172
- const signatureBytes = decodeBase64Url3(signature);
18622
+ const signatureBytes = decodeBase64Url4(signature);
18173
18623
  if (signatureBytes.length !== 64) {
18174
18624
  throw new LocationRecordValidationError(
18175
18625
  "did:key signature must be a base64url Ed25519 signature"
@@ -18222,7 +18672,7 @@ function base64UrlEncode3(bytes2) {
18222
18672
  }
18223
18673
  return output;
18224
18674
  }
18225
- function decodeBase64Url3(value) {
18675
+ function decodeBase64Url4(value) {
18226
18676
  const alphabet2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
18227
18677
  const bytes2 = [];
18228
18678
  let buffer = 0;