@tinycloud/sdk-core 2.11.0 → 3.0.0-beta.0

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.js CHANGED
@@ -315,6 +315,7 @@ var CREDENTIAL_ERROR_CODES = [
315
315
  "REQUEST_SUBSTITUTED",
316
316
  "SIGNATURE_REJECTED",
317
317
  "UNSUPPORTED_PROFILE",
318
+ "UNSUPPORTED_VERSION",
318
319
  "VERIFICATION_FAILED",
319
320
  "VERIFIED_NOT_SAVED"
320
321
  ];
@@ -326,6 +327,7 @@ var RECOVERABLE = /* @__PURE__ */ new Set([
326
327
  "REQUEST_EXPIRED",
327
328
  "SIGNATURE_REJECTED",
328
329
  "UNSUPPORTED_PROFILE",
330
+ "UNSUPPORTED_VERSION",
329
331
  "VERIFIED_NOT_SAVED"
330
332
  ]);
331
333
  var CredentialError = class extends Error {
@@ -613,11 +615,11 @@ async function createStoredCredentialRecord(input) {
613
615
  const recordId = await canonicalDigest({ credentialDigest: input.verified.credentialDigest, holderDid: input.ownerDid });
614
616
  return Object.freeze({ type: "TinyCloudStoredCredential", version: 1, ownerDid: input.ownerDid, recordId, requirementDigest: input.requirementDigest, descriptorDigest: input.verified.descriptorDigest, profile: input.verified.profile, credentialType: input.verified.credentialType, issuerDid: input.verified.issuerDid, issuerKid: input.verified.issuerKid, holderDid: input.verified.holderDid, claims: input.verified.claims, claimsDigest: input.verified.claimsDigest, credentialDigest: input.verified.credentialDigest, credential: input.verified.credential, schema: input.verified.schema, credentialId: input.verified.credentialId, issuedAt: input.verified.issuedAt, notBefore: input.verified.notBefore, expiresAt: input.verified.expiresAt, status: input.verified.status, verifiedAt: input.verified.verifiedAt, storedAt });
615
617
  }
616
- async function createStorageReceipt(record, etag) {
617
- return Object.freeze({ type: "TinyCloudCredentialStorageReceipt", version: 1, ownerDid: record.ownerDid, recordId: record.recordId, recordDigest: await canonicalDigest(record), storedAt: record.storedAt, ...etag === void 0 ? {} : { etag } });
618
+ async function createStorageReceipt(record2, etag) {
619
+ return Object.freeze({ type: "TinyCloudCredentialStorageReceipt", version: 1, ownerDid: record2.ownerDid, recordId: record2.recordId, recordDigest: await canonicalDigest(record2), storedAt: record2.storedAt, ...etag === void 0 ? {} : { etag } });
618
620
  }
619
- async function verifyStorageReceipt(record, receipt, activeOwnerDid, activeHolderDid) {
620
- return receipt.type === "TinyCloudCredentialStorageReceipt" && receipt.version === 1 && receipt.ownerDid === activeOwnerDid && record.ownerDid === activeOwnerDid && record.holderDid === activeHolderDid && receipt.recordId === record.recordId && receipt.storedAt === record.storedAt && receipt.recordDigest === await canonicalDigest(record);
621
+ async function verifyStorageReceipt(record2, receipt, activeOwnerDid, activeHolderDid) {
622
+ return receipt.type === "TinyCloudCredentialStorageReceipt" && receipt.version === 1 && receipt.ownerDid === activeOwnerDid && record2.ownerDid === activeOwnerDid && record2.holderDid === activeHolderDid && receipt.recordId === record2.recordId && receipt.storedAt === record2.storedAt && receipt.recordDigest === await canonicalDigest(record2);
621
623
  }
622
624
 
623
625
  // src/credentials/verification.ts
@@ -806,7 +808,7 @@ function makePkhSpaceId(address, chainId, name2) {
806
808
  }
807
809
 
808
810
  // src/requester/index.ts
809
- import { bytesToHex as bytesToHex3, sha256 as sha2565 } from "viem";
811
+ import { bytesToHex as bytesToHex3, sha256 as sha2566 } from "viem";
810
812
  import { blake3 as blake32 } from "@noble/hashes/blake3";
811
813
 
812
814
  // ../../node_modules/multiformats/dist/src/bases/base32.js
@@ -3176,13 +3178,13 @@ function base64UrlDecode(value) {
3176
3178
  return decoded;
3177
3179
  }
3178
3180
  function hexToBytes(value) {
3179
- const hex2 = value.slice(2);
3180
- if (hex2.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex2)) {
3181
+ const hex3 = value.slice(2);
3182
+ if (hex3.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex3)) {
3181
3183
  throw new SignatureMaterialError("hex signature must have even length");
3182
3184
  }
3183
- const output = new Uint8Array(hex2.length / 2);
3185
+ const output = new Uint8Array(hex3.length / 2);
3184
3186
  for (let index = 0; index < output.length; index++) {
3185
- output[index] = Number.parseInt(hex2.slice(index * 2, index * 2 + 2), 16);
3187
+ output[index] = Number.parseInt(hex3.slice(index * 2, index * 2 + 2), 16);
3186
3188
  }
3187
3189
  return output;
3188
3190
  }
@@ -3422,6 +3424,34 @@ var ROOT_REVOCATION_V1_DOMAIN = "xyz.tinycloud.policy/RootRevocation/v1\0";
3422
3424
  var LAST_V2_CREATE_AT = "2026-09-30T00:00:00Z";
3423
3425
  var MAX_LEGACY_ENVELOPE_EXPIRES_AT = "2026-12-29T00:00:00Z";
3424
3426
  var LAST_V2_READ_AT = "2027-01-05T00:00:00Z";
3427
+ async function requestPolicyChallengeV3(input) {
3428
+ const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
3429
+ const response = await fetchFn(new URL("/share/v3/policy/challenges", input.nodeOrigin), {
3430
+ method: "POST",
3431
+ redirect: "error",
3432
+ headers: { accept: "application/json", "content-type": "application/json" },
3433
+ body: JSON.stringify({ policyCid: input.policyCid, recipientDid: input.recipientDid, requestedCapabilities: input.requestedCapabilities.map(normalizeUnifiedPolicyCapability) })
3434
+ });
3435
+ if (!response.ok) throw new Error(`policy challenge rejected (${response.status})`);
3436
+ const value = object2(await response.json(), "policy challenge");
3437
+ if (typeof value.challengeId !== "string" || typeof value.nonce !== "string" || value.policyCid !== input.policyCid || value.recipientDid !== input.recipientDid)
3438
+ throw new Error("policy challenge binding is invalid");
3439
+ return value;
3440
+ }
3441
+ function compactAttenuationForPolicyCapabilities(input) {
3442
+ const attenuation = {};
3443
+ for (const raw of input) {
3444
+ const capability = normalizeUnifiedPolicyCapability(raw);
3445
+ if (attenuation[capability.resource] !== void 0)
3446
+ throw new Error("policy capabilities contain a duplicate resource");
3447
+ attenuation[capability.resource] = capability.kind === "encryption" ? { [capability.action]: [{}] } : Object.fromEntries(capability.actions.map((action) => [action, [{
3448
+ type: "xyz.tinycloud.resource/selector",
3449
+ kind: capability.selector,
3450
+ value: capability.resource
3451
+ }]]));
3452
+ }
3453
+ return attenuation;
3454
+ }
3425
3455
  function verifyPolicyRootStatusCheckpointV3(input) {
3426
3456
  const checkpoint = input.checkpoint;
3427
3457
  const allowed = /* @__PURE__ */ new Set(["schema", "targetCid", "targetRole", "ownerDid", "nodeAudience", "state", "sequence", "checkedAt", "freshUntil", "revokedAt", "revocationCid", "previousCheckpointDigestHex", "issuerDid", "signature"]);
@@ -3591,11 +3621,15 @@ function nonEmptyString(value, label) {
3591
3621
  return value;
3592
3622
  }
3593
3623
  function parseKvResource(resource) {
3594
- const match = /^tinycloud:\/\/([^/]+)\/kv\/(.+)$/.exec(resource);
3595
- if (!match || match[1].includes(":") || match[1].includes("?") || match[1].includes("#") || match[1].includes("%") || match[2].startsWith("/") || match[2].endsWith("/") || match[2].includes("//") || match[2].split("/").some((part) => part === "." || part === ".." || part.length === 0)) {
3624
+ const marker = resource.indexOf("/kv/");
3625
+ const encodedSpace = marker < 1 ? "" : resource.slice(0, marker);
3626
+ const legacy = encodedSpace.startsWith("tinycloud://");
3627
+ const space = legacy ? encodedSpace.slice("tinycloud://".length) : encodedSpace;
3628
+ const path = marker < 1 ? "" : resource.slice(marker + 4);
3629
+ if (marker < 1 || (legacy ? /[:/?#%]/.test(space) : !encodedSpace.startsWith("tinycloud:") || /[/?#%]/.test(encodedSpace)) || path.startsWith("/") || path.endsWith("/") || path.includes("//") || path.split("/").some((part) => part === "." || part === ".." || part.length === 0)) {
3596
3630
  throw new Error("KV resource is not canonical");
3597
3631
  }
3598
- return { space: match[1], path: match[2] };
3632
+ return { space, path };
3599
3633
  }
3600
3634
  function parseEncryptionResource(resource) {
3601
3635
  if (!resource.startsWith("urn:tinycloud:encryption:")) throw new Error("encryption capability is invalid");
@@ -3740,7 +3774,7 @@ function unifiedPolicyCapabilityFromNative(input) {
3740
3774
  throw new Error("native capability is not supported");
3741
3775
  const caveat = object2(value.caveat, "native.caveat");
3742
3776
  exactKeys(caveat, ["type", "kind", "value"], "native selector caveat");
3743
- if (caveat.type !== "xyz.tinycloud.resource/selector" || caveat.kind !== "exact" && caveat.kind !== "prefix" || caveat.value !== `tinycloud://${value.space}/kv/${value.path}`)
3777
+ if (caveat.type !== "xyz.tinycloud.resource/selector" || caveat.kind !== "exact" && caveat.kind !== "prefix" || caveat.value !== `${value.space.startsWith("tinycloud:") ? value.space : `tinycloud://${value.space}`}/kv/${value.path}`)
3744
3778
  throw new Error("native selector caveat does not match capability");
3745
3779
  return normalizeUnifiedPolicyCapability({
3746
3780
  kind: "kv",
@@ -3799,9 +3833,7 @@ var CompactPayloadSchema = z2.object({
3799
3833
  nnc: z2.string().min(1),
3800
3834
  prf: z2.array(z2.string().min(1))
3801
3835
  }).strict();
3802
- async function signCompactUcanAuthorization(input) {
3803
- if (input.notBefore >= input.expiresAt || input.expiresAt - input.notBefore > 60)
3804
- throw new Error("compact invocation lifetime must be between one and 60 seconds");
3836
+ async function signCompactUcan(input) {
3805
3837
  const principal = input.issuerDid.split("#", 1)[0];
3806
3838
  const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
3807
3839
  if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
@@ -3823,6 +3855,16 @@ async function signCompactUcanAuthorization(input) {
3823
3855
  if (signature.length !== 64) throw new Error("compact Authorization signature must be Ed25519");
3824
3856
  return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url2(signature)}`);
3825
3857
  }
3858
+ async function signCompactUcanAuthorization(input) {
3859
+ if (input.notBefore >= input.expiresAt || input.expiresAt - input.notBefore > 60)
3860
+ throw new Error("compact invocation lifetime must be between one and 60 seconds");
3861
+ return signCompactUcan(input);
3862
+ }
3863
+ async function signCompactUcanRootAuthorization(input) {
3864
+ if (input.notBefore >= input.expiresAt || input.expiresAt - input.notBefore > 31 * 24 * 60 * 60)
3865
+ throw new Error("compact policy root lifetime must be between one second and 31 days");
3866
+ return signCompactUcan({ ...input, proofs: [] });
3867
+ }
3826
3868
  function createCompactPolicyInvocation(input) {
3827
3869
  const session = parsePolicySessionUcan(input.sessionAuthorization);
3828
3870
  if (session.cid !== input.sessionCid || session.aud !== input.recipientDid)
@@ -3969,14 +4011,14 @@ function decodeBase64Url2(value) {
3969
4011
  if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1)
3970
4012
  throw new Error("value is not canonical base64url");
3971
4013
  const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
3972
- const binary = typeof Buffer !== "undefined" ? Buffer.from(normalized, "base64").toString("binary") : atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "="));
4014
+ const binary = typeof atob === "function" ? atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "=")) : Buffer.from(normalized, "base64").toString("binary");
3973
4015
  const bytes2 = Uint8Array.from(binary, (character) => character.charCodeAt(0));
3974
- const encoded = typeof Buffer !== "undefined" ? Buffer.from(bytes2).toString("base64url") : btoa(String.fromCharCode(...bytes2)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
4016
+ const encoded = typeof btoa === "function" ? btoa(String.fromCharCode(...bytes2)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_") : Buffer.from(bytes2).toString("base64url");
3975
4017
  if (encoded !== value) throw new Error("value is not canonical base64url");
3976
4018
  return bytes2;
3977
4019
  }
3978
4020
  function encodeBase64Url2(value) {
3979
- return typeof Buffer !== "undefined" ? Buffer.from(value).toString("base64url") : btoa(String.fromCharCode(...value)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
4021
+ return typeof btoa === "function" ? btoa(String.fromCharCode(...value)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_") : Buffer.from(value).toString("base64url");
3980
4022
  }
3981
4023
  function equalBytes(left, right) {
3982
4024
  return left.length === right.length && left.every((byte, index) => byte === right[index]);
@@ -4001,6 +4043,320 @@ function base32Lower(bytes2) {
4001
4043
  return output;
4002
4044
  }
4003
4045
 
4046
+ // src/policy/credential-admission.ts
4047
+ import { ed25519 as ed255194 } from "@noble/curves/ed25519";
4048
+ import { sha256 as sha2565 } from "@noble/hashes/sha256";
4049
+ var POLICY_V2_SCHEMA = "xyz.tinycloud.policy/policy/v2";
4050
+ var POLICY_V2_DOMAIN = "xyz.tinycloud.policy/policy/v2\0";
4051
+ var POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE = "TinyCloudPolicyCredentialRequirement";
4052
+ var POLICY_PRESENTATION_V3_SCHEMA = "xyz.tinycloud.policy/presentation/v3";
4053
+ var POLICY_PRESENTATION_V3_DOMAIN = "xyz.tinycloud.policy/Presentation/v3\0";
4054
+ function record(value, label) {
4055
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
4056
+ throw new Error(`${label} must be an object`);
4057
+ }
4058
+ return value;
4059
+ }
4060
+ function exactKeys2(value, keys, label) {
4061
+ const expected = [...keys].sort();
4062
+ const actual = Object.keys(value).sort();
4063
+ if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
4064
+ throw new Error(`${label} contains an unknown or missing field`);
4065
+ }
4066
+ }
4067
+ function nonEmpty(value, label) {
4068
+ if (typeof value !== "string" || value.length === 0) {
4069
+ throw new Error(`${label} must be a non-empty string`);
4070
+ }
4071
+ return value;
4072
+ }
4073
+ function policyNodeOrigin(value) {
4074
+ let url;
4075
+ try {
4076
+ url = new URL(value);
4077
+ } catch {
4078
+ throw new Error("policy node origin is invalid");
4079
+ }
4080
+ if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.pathname !== "/" || url.search !== "" || url.hash !== "") {
4081
+ throw new Error("policy node origin is invalid");
4082
+ }
4083
+ return url.origin;
4084
+ }
4085
+ function versionPair(value, label) {
4086
+ const item = record(value, label);
4087
+ exactKeys2(item, ["id", "version"], label);
4088
+ if (item.version !== 1) throw new Error(`${label} version is unsupported`);
4089
+ return Object.freeze({ id: nonEmpty(item.id, `${label}.id`), version: 1 });
4090
+ }
4091
+ function validatePolicyCredentialRequirementV1(value) {
4092
+ const item = record(value, "policy credential requirement");
4093
+ exactKeys2(
4094
+ item,
4095
+ [
4096
+ "type",
4097
+ "version",
4098
+ "requirementDigest",
4099
+ "descriptorDigest",
4100
+ "issuerDid",
4101
+ "issuerKid",
4102
+ "profile",
4103
+ "credentialType"
4104
+ ],
4105
+ "policy credential requirement"
4106
+ );
4107
+ if (item.type !== POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE || item.version !== 1 || !isDigest(item.requirementDigest) || !isDigest(item.descriptorDigest)) {
4108
+ throw new Error("policy credential requirement is invalid");
4109
+ }
4110
+ return Object.freeze({
4111
+ type: POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE,
4112
+ version: 1,
4113
+ requirementDigest: item.requirementDigest,
4114
+ descriptorDigest: item.descriptorDigest,
4115
+ issuerDid: nonEmpty(item.issuerDid, "policy credential issuer"),
4116
+ issuerKid: nonEmpty(item.issuerKid, "policy credential issuer key"),
4117
+ profile: versionPair(item.profile, "policy credential profile"),
4118
+ credentialType: versionPair(
4119
+ item.credentialType,
4120
+ "policy credential type"
4121
+ )
4122
+ });
4123
+ }
4124
+ function hex2(bytes2) {
4125
+ return [...bytes2].map((byte) => byte.toString(16).padStart(2, "0")).join("");
4126
+ }
4127
+ function policyV2DigestHex(input) {
4128
+ const canonicalPolicy = {
4129
+ ...input,
4130
+ credentialRequirement: validatePolicyCredentialRequirementV1(
4131
+ input.credentialRequirement
4132
+ ),
4133
+ capabilityCeiling: input.capabilityCeiling.map(
4134
+ normalizeUnifiedPolicyCapability
4135
+ )
4136
+ };
4137
+ return hex2(
4138
+ sha2565(
4139
+ new TextEncoder().encode(
4140
+ POLICY_V2_DOMAIN + jcsCanonicalize(canonicalPolicy)
4141
+ )
4142
+ )
4143
+ );
4144
+ }
4145
+ function date(value, label) {
4146
+ const text2 = nonEmpty(value, label);
4147
+ if (!Number.isFinite(Date.parse(text2))) throw new Error(`${label} is invalid`);
4148
+ return text2;
4149
+ }
4150
+ function rfc3339Seconds(value) {
4151
+ return new Date(Math.floor(value.getTime() / 1e3) * 1e3).toISOString().replace(/\.000Z$/, "Z");
4152
+ }
4153
+ function validateUnifiedPolicyV2(value, expectedPolicyCid) {
4154
+ const item = record(value, "Policy/v2");
4155
+ const allowed = [
4156
+ "schema",
4157
+ "policyId",
4158
+ "ownerDid",
4159
+ "createdAt",
4160
+ "contentSource",
4161
+ "capabilityCeiling",
4162
+ "credentialRequirement",
4163
+ "signature",
4164
+ ...item.expiresAt === void 0 ? [] : ["expiresAt"]
4165
+ ];
4166
+ exactKeys2(item, allowed, "Policy/v2");
4167
+ if (item.schema !== POLICY_V2_SCHEMA || !Array.isArray(item.capabilityCeiling)) {
4168
+ throw new Error("Policy/v2 is invalid");
4169
+ }
4170
+ const ownerDid = nonEmpty(item.ownerDid, "Policy/v2 ownerDid");
4171
+ const signature = record(item.signature, "Policy/v2 signature");
4172
+ exactKeys2(signature, ["suite", "signerDid", "value"], "Policy/v2 signature");
4173
+ if (signature.suite !== "Ed25519" || signature.signerDid !== ownerDid || typeof signature.value !== "string" || signature.value.length === 0) {
4174
+ throw new Error("Policy/v2 signature binding is invalid");
4175
+ }
4176
+ const policy = Object.freeze({
4177
+ schema: POLICY_V2_SCHEMA,
4178
+ policyId: nonEmpty(item.policyId, "Policy/v2 policyId"),
4179
+ ownerDid,
4180
+ createdAt: date(item.createdAt, "Policy/v2 createdAt"),
4181
+ ...item.expiresAt === void 0 ? {} : { expiresAt: date(item.expiresAt, "Policy/v2 expiresAt") },
4182
+ contentSource: item.contentSource,
4183
+ capabilityCeiling: Object.freeze(
4184
+ item.capabilityCeiling.map(normalizeUnifiedPolicyCapability)
4185
+ ),
4186
+ credentialRequirement: validatePolicyCredentialRequirementV1(
4187
+ item.credentialRequirement
4188
+ ),
4189
+ signature: Object.freeze({
4190
+ suite: "Ed25519",
4191
+ signerDid: ownerDid,
4192
+ value: signature.value
4193
+ })
4194
+ });
4195
+ const unsigned = { ...policy };
4196
+ delete unsigned.policyId;
4197
+ delete unsigned.signature;
4198
+ const digestHex = policyV2DigestHex(unsigned);
4199
+ if (policy.policyId !== policyIdForDigestHex(digestHex)) {
4200
+ throw new Error("Policy/v2 policyId binding is invalid");
4201
+ }
4202
+ if (expectedPolicyCid !== void 0) {
4203
+ const cid2 = policyCidFromCanonicalBytes(
4204
+ new TextEncoder().encode(jcsCanonicalize(policy))
4205
+ );
4206
+ if (cid2 !== expectedPolicyCid) throw new Error("Policy/v2 CID binding is invalid");
4207
+ }
4208
+ return policy;
4209
+ }
4210
+ function didKeyBytes(did) {
4211
+ const principal = did.split("#", 1)[0];
4212
+ if (!principal.startsWith("did:key:")) throw new Error("holder DID must be did:key");
4213
+ const material = base58btc.decode(principal.slice("did:key:".length));
4214
+ if (material.length !== 34 || material[0] !== 237 || material[1] !== 1) {
4215
+ throw new Error("holder DID must contain an Ed25519 key");
4216
+ }
4217
+ return material.slice(2);
4218
+ }
4219
+ function envelopeFromVerified(verified) {
4220
+ const {
4221
+ verifiedAt: _verifiedAt,
4222
+ credentialDigest: _credentialDigest,
4223
+ statusCheckedAt: _statusCheckedAt,
4224
+ ...envelope
4225
+ } = verified;
4226
+ return envelope;
4227
+ }
4228
+ async function buildPolicyCredentialPresentationV3(input) {
4229
+ const policy = validateUnifiedPolicyV2(input.policy, input.policyCid);
4230
+ const requirement = validateCredentialRequirement(input.requirement);
4231
+ const commitment = policy.credentialRequirement;
4232
+ const requirementDigest = await credentialRequirementDigest(requirement);
4233
+ const credentialDigest = await sha256Base64Url(input.credential.credential);
4234
+ 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)) {
4235
+ throw new Error("credential does not match the signed Policy/v2 requirement");
4236
+ }
4237
+ const requestedCapabilities = input.requestedCapabilities.map(
4238
+ normalizeUnifiedPolicyCapability
4239
+ );
4240
+ if (requestedCapabilities.length === 0 || requestedCapabilities.some(
4241
+ (requested) => !policy.capabilityCeiling.some(
4242
+ (authority) => unifiedPolicyCapabilityContains(authority, requested)
4243
+ )
4244
+ )) {
4245
+ throw new Error("requested capabilities exceed the signed Policy/v2 ceiling");
4246
+ }
4247
+ const challenge = input.challenge;
4248
+ const holderDid = input.credential.holderDid;
4249
+ if (challenge.policyCid !== input.policyCid || challenge.recipientDid !== holderDid || input.credential.subjectDid !== holderDid || typeof challenge.nodeAudience !== "string" || challenge.nodeAudience.length === 0 || typeof challenge.expiresAt !== "string" || !Number.isFinite(Date.parse(challenge.expiresAt))) {
4250
+ throw new Error("policy challenge binding is invalid");
4251
+ }
4252
+ didKeyBytes(holderDid);
4253
+ const now = input.now ?? /* @__PURE__ */ new Date();
4254
+ const challengeExpiry = Date.parse(challenge.expiresAt);
4255
+ const credentialExpiry = Date.parse(input.credential.expiresAt);
4256
+ const expiresAtMs = Math.min(
4257
+ now.getTime() + 6e4,
4258
+ challengeExpiry,
4259
+ credentialExpiry
4260
+ );
4261
+ if (expiresAtMs <= now.getTime()) throw new Error("policy challenge is expired");
4262
+ const unsigned = Object.freeze({
4263
+ schema: POLICY_PRESENTATION_V3_SCHEMA,
4264
+ jti: input.jti ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
4265
+ challengeId: challenge.challengeId,
4266
+ nonce: challenge.nonce,
4267
+ policyCid: input.policyCid,
4268
+ nodeAudience: challenge.nodeAudience,
4269
+ holderDid,
4270
+ subjectDid: input.credential.subjectDid,
4271
+ credentialSpaceOwnerDid: nonEmpty(
4272
+ input.credentialSpaceOwnerDid,
4273
+ "credential space owner DID"
4274
+ ),
4275
+ credentialDigest,
4276
+ requirementDigest,
4277
+ descriptorDigest: input.credential.descriptorDigest,
4278
+ requestedCapabilities: Object.freeze(requestedCapabilities),
4279
+ issuedAt: rfc3339Seconds(now),
4280
+ expiresAt: rfc3339Seconds(new Date(expiresAtMs))
4281
+ });
4282
+ const digest4 = sha2565(
4283
+ new TextEncoder().encode(
4284
+ POLICY_PRESENTATION_V3_DOMAIN + jcsCanonicalize(unsigned)
4285
+ )
4286
+ );
4287
+ const signature = await input.sign(digest4);
4288
+ if (signature.length !== 64 || !ed255194.verify(signature, digest4, didKeyBytes(holderDid))) {
4289
+ throw new Error("policy presentation signature is invalid");
4290
+ }
4291
+ return Object.freeze({
4292
+ ...unsigned,
4293
+ signature: Object.freeze({
4294
+ suite: "Ed25519",
4295
+ signerDid: holderDid,
4296
+ value: encodeBase64Url(signature)
4297
+ })
4298
+ });
4299
+ }
4300
+ async function admitPolicyCredentialV3(input) {
4301
+ const policy = validateUnifiedPolicyV2(input.policy, input.policyCid);
4302
+ const nodeOrigin = policyNodeOrigin(input.nodeOrigin);
4303
+ const accountAuthorizationCid = nonEmpty(
4304
+ input.accountAuthorizationCid,
4305
+ "account authorization CID"
4306
+ );
4307
+ const credentialSpaceId = nonEmpty(
4308
+ input.credentialSpaceId,
4309
+ "credential space ID"
4310
+ );
4311
+ const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
4312
+ const challenge = await requestPolicyChallengeV3({
4313
+ nodeOrigin,
4314
+ policyCid: input.policyCid,
4315
+ recipientDid: input.credential.holderDid,
4316
+ requestedCapabilities: input.requestedCapabilities,
4317
+ fetch: fetchFn
4318
+ });
4319
+ const presentation = await buildPolicyCredentialPresentationV3({
4320
+ ...input,
4321
+ policy,
4322
+ challenge
4323
+ });
4324
+ const response = await fetchFn(
4325
+ new URL("/share/v3/policy/delegations", nodeOrigin),
4326
+ {
4327
+ method: "POST",
4328
+ redirect: "error",
4329
+ headers: { accept: "application/json", "content-type": "application/json" },
4330
+ body: JSON.stringify({
4331
+ policyCid: input.policyCid,
4332
+ challengeId: challenge.challengeId,
4333
+ nonce: challenge.nonce,
4334
+ requirement: validateCredentialRequirement(input.requirement),
4335
+ credential: envelopeFromVerified(input.credential),
4336
+ accountAuthorizationCid,
4337
+ credentialSpaceId,
4338
+ presentation
4339
+ })
4340
+ }
4341
+ );
4342
+ if (!response.ok) throw new Error(`policy delegation rejected (${response.status})`);
4343
+ const value = record(await response.json(), "policy delegation");
4344
+ if (value.admitted !== true || typeof value.sessionCid !== "string" || typeof value.authorization !== "string") {
4345
+ throw new Error("policy delegation response is invalid");
4346
+ }
4347
+ const session = parsePolicySessionUcan(value.authorization, [
4348
+ input.policyRootCid,
4349
+ input.enforcementRootCid
4350
+ ]);
4351
+ const expectedAttenuation = compactAttenuationForPolicyCapabilities(
4352
+ input.requestedCapabilities
4353
+ );
4354
+ 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)) {
4355
+ throw new Error("policy delegation signed binding is invalid");
4356
+ }
4357
+ return Object.freeze({ challenge, presentation, session });
4358
+ }
4359
+
4004
4360
  // src/requester/index.ts
4005
4361
  var REQUESTER_NEAR_EXPIRY_SECONDS = 30;
4006
4362
  var REQUESTER_ENGINE_RETRY_ATTEMPTS = 3;
@@ -4252,15 +4608,15 @@ var TranscriptRequester = class _TranscriptRequester {
4252
4608
  "bootstrap owner-node binding does not match trusted discovery/config"
4253
4609
  );
4254
4610
  }
4255
- const record = await verifyRecordBeforeEgress(bootstrap, options2);
4256
- if (record.endpoint !== bootstrap.policyEngine.endpoint) {
4611
+ const record2 = await verifyRecordBeforeEgress(bootstrap, options2);
4612
+ if (record2.endpoint !== bootstrap.policyEngine.endpoint) {
4257
4613
  throw new TranscriptRequesterError(
4258
4614
  "requester-engine-record-endpoint-mismatch",
4259
4615
  "policy engine record endpoint does not match bootstrap endpoint",
4260
4616
  "bootstrap-invalid"
4261
4617
  );
4262
4618
  }
4263
- if (record.audience !== bootstrap.policyEngine.audience) {
4619
+ if (record2.audience !== bootstrap.policyEngine.audience) {
4264
4620
  throw new TranscriptRequesterError(
4265
4621
  "requester-engine-record-audience-mismatch",
4266
4622
  "policy engine record audience does not match bootstrap audience",
@@ -4291,7 +4647,7 @@ var TranscriptRequester = class _TranscriptRequester {
4291
4647
  requestedCapabilities,
4292
4648
  nativeAuthorityCeiling,
4293
4649
  requestedCapabilitiesHash(requestedCapabilities),
4294
- parseStrictRfc33392(record.expiresAt),
4650
+ parseStrictRfc33392(record2.expiresAt),
4295
4651
  policyEngineAddresses,
4296
4652
  ownerNodeAddresses,
4297
4653
  options2
@@ -4914,7 +5270,7 @@ function requestedCapabilitiesHash(capabilities) {
4914
5270
  const bytes2 = new Uint8Array(domain.length + body.length);
4915
5271
  bytes2.set(domain, 0);
4916
5272
  bytes2.set(body, domain.length);
4917
- return bytesToHex3(sha2565(bytes2, "bytes")).slice(2);
5273
+ return bytesToHex3(sha2566(bytes2, "bytes")).slice(2);
4918
5274
  }
4919
5275
  function normalizeWireDelegation(delegation) {
4920
5276
  const signed = delegationAuthorityFromCompactJws(delegation.encoded);
@@ -5160,9 +5516,9 @@ function parseNodeDataResponse(response, schema, label) {
5160
5516
  function nodeErrorMessage(body) {
5161
5517
  if (typeof body === "string") return body;
5162
5518
  if (body !== null && typeof body === "object") {
5163
- const record = body;
5164
- const code3 = typeof record.code === "string" ? record.code : void 0;
5165
- const message = typeof record.message === "string" ? record.message : void 0;
5519
+ const record2 = body;
5520
+ const code3 = typeof record2.code === "string" ? record2.code : void 0;
5521
+ const message = typeof record2.message === "string" ? record2.message : void 0;
5166
5522
  if (code3 !== void 0)
5167
5523
  return message === void 0 ? code3 : `${code3}: ${message}`;
5168
5524
  }
@@ -7484,7 +7840,7 @@ function parseRecapCapabilities(parseWasm, siwe) {
7484
7840
  }
7485
7841
 
7486
7842
  // src/delegations/SharingService.ts
7487
- import { ed25519 as ed255196 } from "@noble/curves/ed25519";
7843
+ import { ed25519 as ed255197 } from "@noble/curves/ed25519";
7488
7844
 
7489
7845
  // src/delegations/ShareRecipientClient.ts
7490
7846
  import {
@@ -7492,13 +7848,13 @@ import {
7492
7848
  KVService,
7493
7849
  ServiceContext
7494
7850
  } from "@tinycloud/sdk-services";
7495
- import { ed25519 as ed255195 } from "@noble/curves/ed25519";
7496
- import { sha256 as sha2568 } from "@noble/hashes/sha256";
7851
+ import { ed25519 as ed255196 } from "@noble/curves/ed25519";
7852
+ import { sha256 as sha2569 } from "@noble/hashes/sha256";
7497
7853
 
7498
7854
  // src/delegations/share-envelope.ts
7499
- import { ed25519 as ed255194 } from "@noble/curves/ed25519";
7855
+ import { ed25519 as ed255195 } from "@noble/curves/ed25519";
7500
7856
  import { blake3 as blake33 } from "@noble/hashes/blake3";
7501
- import { sha256 as sha2566 } from "@noble/hashes/sha256";
7857
+ import { sha256 as sha2567 } from "@noble/hashes/sha256";
7502
7858
  var ENVELOPE_SCHEMA = "xyz.tinycloud.share/envelope";
7503
7859
  var INLINE_PREFIX = "tc2:";
7504
7860
  var RAW_CID_CODEC = 85;
@@ -7717,7 +8073,7 @@ function createSharePolicy(input) {
7717
8073
  };
7718
8074
  }
7719
8075
  function contentDigest(bytes2) {
7720
- return bytesToBase64Url(sha2566(bytes2));
8076
+ return bytesToBase64Url(sha2567(bytes2));
7721
8077
  }
7722
8078
  function computeShareCid(bytes2) {
7723
8079
  const digest4 = create(BLAKE3_256_CODE, blake33(bytes2));
@@ -7737,7 +8093,7 @@ function envelopeSigningBytes(envelope) {
7737
8093
  }
7738
8094
  function signShareEnvelope(input) {
7739
8095
  if (input.signerPrivateKey.length !== 32) throw new ShareEnvelopeError("invalid-envelope", "Ed25519 private key must be 32 bytes");
7740
- const publicKey = ed255194.getPublicKey(input.signerPrivateKey);
8096
+ const publicKey = ed255195.getPublicKey(input.signerPrivateKey);
7741
8097
  const unsigned = {
7742
8098
  schema: ENVELOPE_SCHEMA,
7743
8099
  version: 2,
@@ -7752,7 +8108,7 @@ function signShareEnvelope(input) {
7752
8108
  expiresAt: new Date(input.expiresAt).toISOString(),
7753
8109
  signer: { did: input.signerDid, publicKey: bytesToBase64Url(publicKey) }
7754
8110
  };
7755
- return { ...unsigned, signature: bytesToBase64Url(ed255194.sign(envelopeSigningBytes(unsigned), input.signerPrivateKey)) };
8111
+ return { ...unsigned, signature: bytesToBase64Url(ed255195.sign(envelopeSigningBytes(unsigned), input.signerPrivateKey)) };
7756
8112
  }
7757
8113
  function verifyShareEnvelope(envelope, options2 = {}) {
7758
8114
  try {
@@ -7784,7 +8140,7 @@ function verifyShareEnvelope(envelope, options2 = {}) {
7784
8140
  const signature = base64UrlToBytes(envelope.signature);
7785
8141
  const unsigned = { ...envelope };
7786
8142
  delete unsigned.signature;
7787
- if (publicKey.length !== 32 || signature.length !== 64 || !ed255194.verify(signature, envelopeSigningBytes(unsigned), publicKey)) throw new ShareEnvelopeError("signature-invalid", "share envelope signature is invalid");
8143
+ if (publicKey.length !== 32 || signature.length !== 64 || !ed255195.verify(signature, envelopeSigningBytes(unsigned), publicKey)) throw new ShareEnvelopeError("signature-invalid", "share envelope signature is invalid");
7788
8144
  if (options2.trustedSignerDids !== void 0 && envelope.recipientKind !== void 0 && !options2.trustedSignerDids.includes(envelope.signer.did)) throw new ShareEnvelopeError("signature-invalid", "share signer is not trusted");
7789
8145
  return envelope;
7790
8146
  } catch (error) {
@@ -7832,7 +8188,7 @@ function encodeInlineShareUrl(input) {
7832
8188
  }
7833
8189
  var PUBLISHED_AAD = new TextEncoder().encode("tinycloud-share-envelope-v1");
7834
8190
  function publishedCid(bytes2) {
7835
- return CID.create(1, code, create(sha2562.code, sha2566(bytes2))).toString();
8191
+ return CID.create(1, code, create(sha2562.code, sha2567(bytes2))).toString();
7836
8192
  }
7837
8193
  function isPublishedCid(value) {
7838
8194
  try {
@@ -7872,7 +8228,7 @@ function publishedArtifact(envelope, plaintext, policy) {
7872
8228
  content: {
7873
8229
  mimeType: "application/octet-stream",
7874
8230
  size: plaintext.byteLength,
7875
- digest: bytesToBase64Url(sha2566(plaintext))
8231
+ digest: bytesToBase64Url(sha2567(plaintext))
7876
8232
  },
7877
8233
  // Addressed policy metadata is confidential even though this function
7878
8234
  // is called after the outer envelope has been opened. Keep the
@@ -7976,9 +8332,9 @@ function parsePolicyMetadata(policyBytes, target, expectedExpiry) {
7976
8332
  assertKeys(source, ["kind", "space", "database", "path", "statement", "arguments", "argumentsDigest", "action"], "published SQL content source");
7977
8333
  if (typeof source.space !== "string" || typeof source.database !== "string" || typeof source.path !== "string" || typeof source.statement !== "string" || !source.arguments || typeof source.arguments !== "object" || Array.isArray(source.arguments) || typeof source.argumentsDigest !== "string" || source.action !== "tinycloud.sql/read") throw new ShareEnvelopeError("invalid-envelope", "published SQL content source is invalid");
7978
8334
  for (const argument of Object.values(source.arguments)) if (!Number.isSafeInteger(argument)) throw new ShareEnvelopeError("invalid-envelope", "published SQL arguments are invalid");
7979
- if (bytesToBase64Url(sha2566(new TextEncoder().encode(canonicalJson(source.arguments)))) !== source.argumentsDigest) throw new ShareEnvelopeError("invalid-envelope", "published SQL argument digest is invalid");
8335
+ if (bytesToBase64Url(sha2567(new TextEncoder().encode(canonicalJson(source.arguments)))) !== source.argumentsDigest) throw new ShareEnvelopeError("invalid-envelope", "published SQL argument digest is invalid");
7980
8336
  } else throw new ShareEnvelopeError("invalid-envelope", "policy content source kind is invalid");
7981
- if (typeof policy.contentSourceDigest !== "string" || bytesToBase64Url(sha2566(new TextEncoder().encode(canonicalJson(source)))) !== policy.contentSourceDigest) throw new ShareEnvelopeError("invalid-envelope", "policy content source digest is invalid");
8337
+ if (typeof policy.contentSourceDigest !== "string" || bytesToBase64Url(sha2567(new TextEncoder().encode(canonicalJson(source)))) !== policy.contentSourceDigest) throw new ShareEnvelopeError("invalid-envelope", "policy content source digest is invalid");
7982
8338
  return { recipientKind, actions, resource };
7983
8339
  }
7984
8340
  function parseCanonicalPublishedV2(value, options2) {
@@ -8026,7 +8382,7 @@ function parseCanonicalPublishedV2(value, options2) {
8026
8382
  const signingBytes = new Uint8Array(domain.length + body.length);
8027
8383
  signingBytes.set(domain);
8028
8384
  signingBytes.set(body, domain.length);
8029
- if (signatureBytes.length !== 64 || !ed255194.verify(signatureBytes, signingBytes, signerKey)) throw new ShareEnvelopeError("signature-invalid", "published v2 envelope signature is invalid");
8385
+ if (signatureBytes.length !== 64 || !ed255195.verify(signatureBytes, signingBytes, signerKey)) throw new ShareEnvelopeError("signature-invalid", "published v2 envelope signature is invalid");
8030
8386
  const content = options2.plaintext ?? new Uint8Array();
8031
8387
  const normalized = {
8032
8388
  schema: ENVELOPE_SCHEMA,
@@ -8036,7 +8392,7 @@ function parseCanonicalPublishedV2(value, options2) {
8036
8392
  recipientKind: normalizedMatcher.kind,
8037
8393
  resource,
8038
8394
  actions,
8039
- content: { mimeType: typeof contentSource.mimeType === "string" ? contentSource.mimeType : "application/octet-stream", size: content.byteLength, digest: bytesToBase64Url(sha2566(content)) },
8395
+ content: { mimeType: typeof contentSource.mimeType === "string" ? contentSource.mimeType : "application/octet-stream", size: content.byteLength, digest: bytesToBase64Url(sha2567(content)) },
8040
8396
  encrypted: true,
8041
8397
  expiresAt: value.expiry,
8042
8398
  signer: { did: signature.signerDid, publicKey: bytesToBase64Url(signerKey) },
@@ -8135,7 +8491,7 @@ function parsePublishedShareEnvelope(bytes2, options2 = {}) {
8135
8491
  if (envelope.authorizationTarget.kind !== "bearerKey" && (options2.trustedSignerDids === void 0 || !options2.trustedSignerDids.includes(envelope.signature.signerDid))) throw new ShareEnvelopeError("signature-invalid", "a trusted authority is required for addressed shares");
8136
8492
  const signature = base64UrlToBytes(envelope.signature.value);
8137
8493
  const publicKey = publishedPublicKey(envelope.signature.signerDid);
8138
- if (signature.length !== 64 || !ed255194.verify(signature, publishedEnvelopeSigningBytes(envelope), publicKey)) throw new ShareEnvelopeError("signature-invalid", "published envelope signature is invalid");
8494
+ if (signature.length !== 64 || !ed255195.verify(signature, publishedEnvelopeSigningBytes(envelope), publicKey)) throw new ShareEnvelopeError("signature-invalid", "published envelope signature is invalid");
8139
8495
  return { envelope, artifact: publishedArtifact(envelope, options2.plaintext ?? new Uint8Array(), policy) };
8140
8496
  }
8141
8497
  function parseLegacyPublishedShareEnvelope(bytes2, options2 = {}) {
@@ -8174,7 +8530,7 @@ function parseLegacyPublishedShareEnvelope(bytes2, options2 = {}) {
8174
8530
  const signingBytes = new Uint8Array(domain.length + body.length);
8175
8531
  signingBytes.set(domain);
8176
8532
  signingBytes.set(body, domain.length);
8177
- if (signatureBytes.length !== 64 || !ed255194.verify(signatureBytes, signingBytes, signerKey)) throw new ShareEnvelopeError("signature-invalid", "published v1 envelope signature is invalid");
8533
+ if (signatureBytes.length !== 64 || !ed255195.verify(signatureBytes, signingBytes, signerKey)) throw new ShareEnvelopeError("signature-invalid", "published v1 envelope signature is invalid");
8178
8534
  const content = options2.plaintext ?? new Uint8Array();
8179
8535
  const artifact = {
8180
8536
  envelope: {
@@ -8185,7 +8541,7 @@ function parseLegacyPublishedShareEnvelope(bytes2, options2 = {}) {
8185
8541
  resource: { kind: resource.kind, path: resource.path },
8186
8542
  recipientKind: authorizationTarget.kind === "bearer" ? "bearer" : authorizationTarget.kind === "exact-email" ? "exactEmail" : authorizationTarget.kind === "email-domain" ? "emailDomain" : void 0,
8187
8543
  actions: ["read"],
8188
- content: { mimeType: "application/octet-stream", size: content.byteLength, digest: bytesToBase64Url(sha2566(content)) },
8544
+ content: { mimeType: "application/octet-stream", size: content.byteLength, digest: bytesToBase64Url(sha2567(content)) },
8189
8545
  encrypted: true,
8190
8546
  expiresAt: envelope.expiry,
8191
8547
  signer: { did: signature.signerDid, publicKey: bytesToBase64Url(signerKey) },
@@ -8372,13 +8728,13 @@ function shareCapabilityAllows(capability, action, path) {
8372
8728
  }
8373
8729
 
8374
8730
  // src/delegations/ShareCache.ts
8375
- import { sha256 as sha2567 } from "@noble/hashes/sha256";
8731
+ import { sha256 as sha2568 } from "@noble/hashes/sha256";
8376
8732
  function cacheKey(key) {
8377
8733
  if (!key.cid || !key.expiresAt) throw new Error("share cache keys require CID and expiry");
8378
8734
  return `${key.cid}\0${key.expiresAt}`;
8379
8735
  }
8380
8736
  function digest2(bytes2) {
8381
- return sha2567(bytes2);
8737
+ return sha2568(bytes2);
8382
8738
  }
8383
8739
  function equalBytes2(left, right) {
8384
8740
  if (left.byteLength !== right.byteLength) return false;
@@ -8755,7 +9111,7 @@ function randomJti() {
8755
9111
  return bytesToBase64Url2(bytes2);
8756
9112
  }
8757
9113
  function digestCanonical(value) {
8758
- return bytesToBase64Url2(sha2568(new TextEncoder().encode(canonicalJsonForProof(value))));
9114
+ return bytesToBase64Url2(sha2569(new TextEncoder().encode(canonicalJsonForProof(value))));
8759
9115
  }
8760
9116
  function actionWire(action) {
8761
9117
  return action === "get" ? "tinycloud.kv/get" : action === "metadata" ? "tinycloud.kv/metadata" : action === "list" ? "tinycloud.kv/list" : "tinycloud.kv/put";
@@ -8991,9 +9347,9 @@ var ShareRecipientClient = class {
8991
9347
  const authority = Object.entries(session.att).find(([parentResource, abilities]) => {
8992
9348
  if (!(action in abilities)) return false;
8993
9349
  if (serviceName === "encryption") return parentResource.startsWith("urn:tinycloud:encryption:") && parentResource === cleanPath;
8994
- const match = /^tinycloud:\/\/[^/]+\/kv\/(.+)$/.exec(parentResource);
8995
- if (match === null) return false;
8996
- const parentPath = match[1];
9350
+ const marker = parentResource.indexOf("/kv/");
9351
+ if (marker < 1) return false;
9352
+ const parentPath = parentResource.slice(marker + 4);
8997
9353
  const caveats = abilities[action] ?? [];
8998
9354
  const prefix = caveats.some((value) => isRecord(value) && value.kind === "prefix");
8999
9355
  return cleanPath === parentPath || prefix && cleanPath.startsWith(`${parentPath}/`);
@@ -9019,10 +9375,10 @@ var ShareRecipientClient = class {
9019
9375
  policySessionProjection(delegation) {
9020
9376
  const session = parsePolicySessionUcan(delegation.delegationHeader.Authorization);
9021
9377
  if (session.cid !== delegation.cid || session.aud !== delegation.delegateDID) throw new ShareAccessError("SHARE_SESSION_INVALID");
9022
- const kvResource = Object.keys(session.att).find((resource) => /^tinycloud:\/\/[^/]+\/kv\/.+$/.test(resource));
9023
- const match = kvResource === void 0 ? void 0 : /^tinycloud:\/\/([^/]+)\/kv\/(.+)$/.exec(kvResource);
9024
- if (match === void 0 || match === null) throw new ShareAccessError("SHARE_SESSION_INVALID");
9025
- return { spaceId: match[1] };
9378
+ const kvResource = Object.keys(session.att).find((resource) => resource.indexOf("/kv/") > 0);
9379
+ const marker = kvResource?.indexOf("/kv/") ?? -1;
9380
+ if (kvResource === void 0 || marker < 1) throw new ShareAccessError("SHARE_SESSION_INVALID");
9381
+ return { spaceId: kvResource.slice(0, marker) };
9026
9382
  }
9027
9383
  createKV(origin2, session, invokeOverride) {
9028
9384
  const invoke = invokeOverride ?? this.options.invoke ?? nativeInvoke;
@@ -9072,7 +9428,7 @@ var ShareRecipientClient = class {
9072
9428
  if (bytes2.byteLength > (this.options.maxContentBytes ?? DEFAULT_MAX_CONTENT_BYTES)) throw new ShareAccessError("SHARE_TOO_LARGE");
9073
9429
  const contentType = input.contentType ?? envelope.content.mimeType;
9074
9430
  if (contentType !== envelope.content.mimeType && !/^text\/(?:plain|markdown)(?:;|$)/i.test(contentType)) throw new ShareAccessError("SHARE_CONTENT_TYPE_INVALID");
9075
- const result = await this.invokeNative({ envelope, session, action: "put", resource: path, body: bytes2, bodyDigest: bytesToBase64Url2(sha2568(bytes2)), contentType, ifMatch: input.etag, mediaType: "application/vnd.tinycloud.share+json" });
9431
+ const result = await this.invokeNative({ envelope, session, action: "put", resource: path, body: bytes2, bodyDigest: bytesToBase64Url2(sha2569(bytes2)), contentType, ifMatch: input.etag, mediaType: "application/vnd.tinycloud.share+json" });
9076
9432
  if (result.status === 412 || result.status === 409) throw new ShareConflict(path, result.headers?.etag);
9077
9433
  if (result.status === 401 || result.status === 403) throw new ShareAccessError("SHARE_DENIED");
9078
9434
  if (result.status < 200 || result.status >= 300) throw new ShareAccessError("SHARE_WRITE_FAILED");
@@ -9224,44 +9580,44 @@ var ShareRecipientClient = class {
9224
9580
  }
9225
9581
  const parsed = ShareNativeResponseSchema.safeParse(value);
9226
9582
  if (!parsed.success) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
9227
- const record = parsed.data;
9583
+ const record2 = parsed.data;
9228
9584
  const expectedAction = actionWire(input.action);
9229
- if (record.action !== expectedAction || record.version !== 2 || record.resource !== input.resource) {
9585
+ if (record2.action !== expectedAction || record2.version !== 2 || record2.resource !== input.resource) {
9230
9586
  throw new ShareAccessError("SHARE_RESPONSE_MISMATCH");
9231
9587
  }
9232
- if (record.etag !== void 0 && record.etag !== null && headers.etag !== void 0 && record.etag !== headers.etag) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
9233
- if (record.etag !== void 0 && record.etag !== null) headers.etag = record.etag;
9588
+ if (record2.etag !== void 0 && record2.etag !== null && headers.etag !== void 0 && record2.etag !== headers.etag) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
9589
+ if (record2.etag !== void 0 && record2.etag !== null) headers.etag = record2.etag;
9234
9590
  if (input.action === "list") {
9235
- if (record.entries === void 0) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
9236
- const rawEntries = record.entries;
9591
+ if (record2.entries === void 0) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
9592
+ const rawEntries = record2.entries;
9237
9593
  if (rawEntries.length > MAX_NATIVE_ENTRIES) throw new ShareAccessError("SHARE_TOO_LARGE");
9238
9594
  const entries = [...rawEntries];
9239
9595
  const headerCursor = response.headers.get("x-tinycloud-next-cursor");
9240
- if (record.nextCursor !== void 0 && record.nextCursor !== null && headerCursor !== null && record.nextCursor !== headerCursor) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
9241
- const nextCursor = record.nextCursor ?? headerCursor ?? void 0;
9596
+ if (record2.nextCursor !== void 0 && record2.nextCursor !== null && headerCursor !== null && record2.nextCursor !== headerCursor) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
9597
+ const nextCursor = record2.nextCursor ?? headerCursor ?? void 0;
9242
9598
  if (nextCursor !== void 0 && new TextEncoder().encode(nextCursor).byteLength > MAX_NATIVE_CURSOR_BYTES) throw new ShareAccessError("SHARE_TOO_LARGE");
9243
- return { status: response.status, headers, type: record.type, version: record.version, action: record.action, resource: record.resource, keys: entries.map((entry) => entry.path), entries, truncated: nextCursor !== void 0, nextCursor };
9599
+ return { status: response.status, headers, type: record2.type, version: record2.version, action: record2.action, resource: record2.resource, keys: entries.map((entry) => entry.path), entries, truncated: nextCursor !== void 0, nextCursor };
9244
9600
  }
9245
9601
  if (input.action === "get") {
9246
- if (record.content === void 0 || record.bodyDigest === void 0) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
9602
+ if (record2.content === void 0 || record2.bodyDigest === void 0) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
9247
9603
  let bytes2;
9248
9604
  try {
9249
- bytes2 = base64UrlToBytes2(record.content);
9605
+ bytes2 = base64UrlToBytes2(record2.content);
9250
9606
  } catch {
9251
9607
  throw new ShareAccessError("SHARE_RESPONSE_INVALID");
9252
9608
  }
9253
- if (bytes2.byteLength > (this.options.maxContentBytes ?? DEFAULT_MAX_CONTENT_BYTES) || !this.digestMatches(record.bodyDigest, bytes2)) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
9254
- return { status: response.status, headers, bytes: bytes2, bodyDigest: record.bodyDigest, type: record.type, version: record.version, action: record.action, resource: record.resource };
9609
+ if (bytes2.byteLength > (this.options.maxContentBytes ?? DEFAULT_MAX_CONTENT_BYTES) || !this.digestMatches(record2.bodyDigest, bytes2)) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
9610
+ return { status: response.status, headers, bytes: bytes2, bodyDigest: record2.bodyDigest, type: record2.type, version: record2.version, action: record2.action, resource: record2.resource };
9255
9611
  }
9256
9612
  if (input.action === "metadata") {
9257
- if (record.metadata === void 0) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
9258
- return { status: response.status, headers, metadata: record.metadata, etag: record.etag ?? void 0, type: record.type, version: record.version, action: record.action, resource: record.resource };
9613
+ if (record2.metadata === void 0) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
9614
+ return { status: response.status, headers, metadata: record2.metadata, etag: record2.etag ?? void 0, type: record2.type, version: record2.version, action: record2.action, resource: record2.resource };
9259
9615
  }
9260
- const responseEtag = record.etag;
9261
- const responseBodyDigest = record.bodyDigest;
9616
+ const responseEtag = record2.etag;
9617
+ const responseBodyDigest = record2.bodyDigest;
9262
9618
  if (responseEtag === void 0 || responseEtag === null || responseEtag.length === 0 || headers.etag !== void 0 && responseEtag !== headers.etag) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
9263
9619
  if (input.bodyDigest === void 0 || responseBodyDigest === void 0 || responseBodyDigest !== input.bodyDigest || !this.digestMatches(responseBodyDigest, input.body ?? new Uint8Array())) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
9264
- return { status: response.status, headers, bodyDigest: responseBodyDigest, type: record.type, version: record.version, action: record.action, resource: record.resource };
9620
+ return { status: response.status, headers, bodyDigest: responseBodyDigest, type: record2.type, version: record2.version, action: record2.action, resource: record2.resource };
9265
9621
  }
9266
9622
  validateNativeResult(input, result) {
9267
9623
  if (!isNativeSuccess(result)) throw new ShareAccessError("SHARE_RESPONSE_MISMATCH");
@@ -9318,7 +9674,7 @@ var ShareRecipientClient = class {
9318
9674
  }]);
9319
9675
  }
9320
9676
  digestMatches(value, bytes2) {
9321
- const digest4 = bytesToBase64Url2(sha2568(bytes2));
9677
+ const digest4 = bytesToBase64Url2(sha2569(bytes2));
9322
9678
  return value === digest4 || value === `sha-256=:${digest4}:`;
9323
9679
  }
9324
9680
  assertNativeRequestBounds(envelope, session, operation, path, limit, cursor) {
@@ -9536,7 +9892,7 @@ var ShareRecipientClient = class {
9536
9892
  nodeAudience: binding.nodeAudience,
9537
9893
  ...isV2 ? {
9538
9894
  enforcerDid: challenge.enforcerDid,
9539
- credentialDigest: typeof presentation.credentialDigest === "string" ? presentation.credentialDigest : bytesToBase64Url2(sha2568(new TextEncoder().encode(credential)))
9895
+ credentialDigest: typeof presentation.credentialDigest === "string" ? presentation.credentialDigest : bytesToBase64Url2(sha2569(new TextEncoder().encode(credential)))
9540
9896
  } : {},
9541
9897
  action,
9542
9898
  ...binding.actions === void 0 ? {} : { actions: [...binding.actions] },
@@ -9602,7 +9958,7 @@ var ShareRecipientClient = class {
9602
9958
  }
9603
9959
  if (isJwsProof && detached.kid !== `${signerDid}#${encoded}` || isEd25519Proof && detached.signerDid !== signerDid || signature.length !== 64) throw new ShareAccessError("SHARE_SESSION_INVALID", "Node proof binding is invalid");
9604
9960
  const bytes2 = new TextEncoder().encode(`${domain}${canonicalJsonForProof(message)}`);
9605
- if (!ed255195.verify(signature, bytes2, key)) throw new ShareAccessError("SHARE_SESSION_INVALID", "Node proof signature is invalid");
9961
+ if (!ed255196.verify(signature, bytes2, key)) throw new ShareAccessError("SHARE_SESSION_INVALID", "Node proof signature is invalid");
9606
9962
  }
9607
9963
  assertChallengeRequestBinding(request, challenge) {
9608
9964
  const source = isRecord(request.body) ? request.body : request;
@@ -10806,7 +11162,7 @@ function shareKeyMatchesDid(key, didUrl) {
10806
11162
  if (!publicKey) return false;
10807
11163
  const jwkBytes = decodeBase64UrlBytes(key.x);
10808
11164
  const privateKey = decodeBase64UrlBytes(key.d);
10809
- const derivedPublicKey = ed255196.getPublicKey(privateKey);
11165
+ const derivedPublicKey = ed255197.getPublicKey(privateKey);
10810
11166
  return privateKey.length === 32 && publicKey.length === jwkBytes.length && publicKey.every((byte, index) => byte === jwkBytes[index]) && derivedPublicKey.length === jwkBytes.length && derivedPublicKey.every((byte, index) => byte === jwkBytes[index]);
10811
11167
  } catch {
10812
11168
  return false;
@@ -10856,8 +11212,8 @@ function verifySignedChild(result, expected, computeCid) {
10856
11212
  }
10857
11213
 
10858
11214
  // src/delegations/owner-policy.ts
10859
- import { ed25519 as ed255197 } from "@noble/curves/ed25519";
10860
- import { sha256 as sha2569 } from "@noble/hashes/sha256";
11215
+ import { ed25519 as ed255198 } from "@noble/curves/ed25519";
11216
+ import { sha256 as sha25610 } from "@noble/hashes/sha256";
10861
11217
  var MAX_CONTENT_BYTES = 100 * 1024 * 1024;
10862
11218
  var ENFORCEMENT_DOMAIN = "xyz.tinycloud.share/policy-enforcement/v2\0";
10863
11219
  var POLICY_DOMAIN = "xyz.tinycloud.share/policy/v2\0";
@@ -10884,10 +11240,10 @@ function fromB64(value) {
10884
11240
  throw new Error("base64url decoding is unavailable");
10885
11241
  }
10886
11242
  function cid(bytesValue) {
10887
- return CID.createV1(code, create(sha2562.code, sha2569(bytesValue))).toString(base32.encoder);
11243
+ return CID.createV1(code, create(sha2562.code, sha25610(bytesValue))).toString(base32.encoder);
10888
11244
  }
10889
11245
  function digest3(bytesValue) {
10890
- return b64(sha2569(bytesValue));
11246
+ return b64(sha25610(bytesValue));
10891
11247
  }
10892
11248
  function didKeyFromEd25519PublicKey(publicKey) {
10893
11249
  if (publicKey.length !== 32) throw new Error("share key public key must be 32 bytes");
@@ -10959,9 +11315,9 @@ function dagCborEncode(value) {
10959
11315
  }
10960
11316
  function assertObject(value, keys, label) {
10961
11317
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
10962
- const record = value;
10963
- if (Object.keys(record).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record, key))) throw new Error(`${label} has unknown or missing fields`);
10964
- return record;
11318
+ const record2 = value;
11319
+ 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`);
11320
+ return record2;
10965
11321
  }
10966
11322
  async function createDelegatedShareKey(options2) {
10967
11323
  if (!globalThis.crypto?.subtle) throw new Error("WebCrypto Ed25519 is required for delegated share keys");
@@ -11072,7 +11428,7 @@ function validateOwnerSharePolicyRegistration(value, expected) {
11072
11428
  const publicKey = encodedKid.length === 34 ? encodedKid.slice(2) : encodedKid;
11073
11429
  const signatureBytes = fromB64(proof.signature);
11074
11430
  const signedBytes = new TextEncoder().encode(`${OWNER_SHARE_REGISTRATION_DOMAIN}${canonicalizeSignedObjectUnsigned(registrationCore)}`);
11075
- if (signatureBytes.length !== 64 || !ed255197.verify(signatureBytes, signedBytes, publicKey)) throw new Error("owner-share registration proof signature is invalid");
11431
+ if (signatureBytes.length !== 64 || !ed255198.verify(signatureBytes, signedBytes, publicKey)) throw new Error("owner-share registration proof signature is invalid");
11076
11432
  return { registration, proof };
11077
11433
  }
11078
11434
  function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
@@ -11086,7 +11442,7 @@ function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
11086
11442
  }
11087
11443
 
11088
11444
  // src/delegations/share-delivery.ts
11089
- import { ed25519 as ed255198 } from "@noble/curves/ed25519";
11445
+ import { ed25519 as ed255199 } from "@noble/curves/ed25519";
11090
11446
  var SHARE_DELIVERY_AUTHORIZATION_DOMAIN = "xyz.tinycloud.share/delivery-authorization/v2\0";
11091
11447
  function isCanonicalHttpsOrigin(value) {
11092
11448
  let url;
@@ -11135,9 +11491,9 @@ var AUTHORIZATION_KEYS = [
11135
11491
  ];
11136
11492
  function assertObject2(value, keys, label) {
11137
11493
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
11138
- const record = value;
11139
- if (Object.keys(record).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record, key))) throw new Error(`${label} has unknown or missing fields`);
11140
- return record;
11494
+ const record2 = value;
11495
+ 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`);
11496
+ return record2;
11141
11497
  }
11142
11498
  function fromB642(value) {
11143
11499
  if (!/^[A-Za-z0-9_-]+$/.test(value)) throw new Error("share delivery value is not canonical base64url");
@@ -11174,7 +11530,7 @@ function validateShareDeliveryAuthorizationBytes(bytesValue, expected) {
11174
11530
  if (publicKey.length !== 32) throw new Error("share delivery authorization proof key is invalid");
11175
11531
  const signatureBytes = fromB642(proof.signature);
11176
11532
  const signedBytes = new TextEncoder().encode(`${SHARE_DELIVERY_AUTHORIZATION_DOMAIN}${canonicalizeSignedObjectUnsigned(authorization)}`);
11177
- if (signatureBytes.length !== 64 || !ed255198.verify(signatureBytes, signedBytes, publicKey)) throw new Error("share delivery authorization proof signature is invalid");
11533
+ if (signatureBytes.length !== 64 || !ed255199.verify(signatureBytes, signedBytes, publicKey)) throw new Error("share delivery authorization proof signature is invalid");
11178
11534
  return { authorization, proof };
11179
11535
  }
11180
11536
  function shareDeliveryTrustedKid(publicKey) {
@@ -11191,8 +11547,8 @@ var MemorySenderShareRecordStorage = class {
11191
11547
  constructor() {
11192
11548
  this.records = /* @__PURE__ */ new Map();
11193
11549
  }
11194
- async put(record) {
11195
- this.records.set(record.shareId, record);
11550
+ async put(record2) {
11551
+ this.records.set(record2.shareId, record2);
11196
11552
  }
11197
11553
  async list() {
11198
11554
  return [...this.records.values()];
@@ -11228,7 +11584,7 @@ var SenderShareStore = class {
11228
11584
  async save(receipt, key) {
11229
11585
  const registration = receipt.registration;
11230
11586
  if (registration.shareKeyDid !== key.did) throw new Error("share key does not match the registered receipt");
11231
- const record = {
11587
+ const record2 = {
11232
11588
  shareId: registration.shareId,
11233
11589
  registrationCid: registration.registrationCid,
11234
11590
  policyCid: registration.policyCid,
@@ -11244,15 +11600,15 @@ var SenderShareStore = class {
11244
11600
  registeredAt: registration.registeredAt,
11245
11601
  expiresAt: registration.expiresAt
11246
11602
  };
11247
- await this.records.put(record);
11248
- await this.keys.put(record.shareId, { cryptoKey: key.cryptoKey, publicKey: key.publicKey, extractable: key.extractable });
11249
- return record;
11603
+ await this.records.put(record2);
11604
+ await this.keys.put(record2.shareId, { cryptoKey: key.cryptoKey, publicKey: key.publicKey, extractable: key.extractable });
11605
+ return record2;
11250
11606
  }
11251
11607
  /** List shares created in any session, most recent first. */
11252
11608
  async list(options2) {
11253
11609
  const now = this.now().getTime();
11254
11610
  const records = await this.records.list();
11255
- return records.filter((record) => (options2?.includeRevoked ?? false) || record.revokedAt === void 0).filter((record) => (options2?.includeExpired ?? false) || Date.parse(record.expiresAt) > now).sort((left, right) => Date.parse(right.registeredAt) - Date.parse(left.registeredAt));
11611
+ return records.filter((record2) => (options2?.includeRevoked ?? false) || record2.revokedAt === void 0).filter((record2) => (options2?.includeExpired ?? false) || Date.parse(record2.expiresAt) > now).sort((left, right) => Date.parse(right.registeredAt) - Date.parse(left.registeredAt));
11256
11612
  }
11257
11613
  async get(shareId) {
11258
11614
  return this.records.get(shareId);
@@ -11275,15 +11631,15 @@ var SenderShareStore = class {
11275
11631
  * returned CID, then call {@link markRevoked} once that succeeds.
11276
11632
  */
11277
11633
  async revocationTarget(shareId, scope) {
11278
- const record = await this.records.get(shareId);
11279
- if (record === void 0) throw new Error(`Unknown share: ${shareId}`);
11280
- return scope === "direct" ? record.enforcementDelegationCid : record.ownerDelegationCid;
11634
+ const record2 = await this.records.get(shareId);
11635
+ if (record2 === void 0) throw new Error(`Unknown share: ${shareId}`);
11636
+ return scope === "direct" ? record2.enforcementDelegationCid : record2.ownerDelegationCid;
11281
11637
  }
11282
11638
  /** Mark a share revoked locally after the caller's node-side revoke call succeeds. */
11283
11639
  async markRevoked(shareId, revokedAt = this.now().toISOString()) {
11284
- const record = await this.records.get(shareId);
11285
- if (record === void 0) throw new Error(`Unknown share: ${shareId}`);
11286
- const revoked = { ...record, revokedAt };
11640
+ const record2 = await this.records.get(shareId);
11641
+ if (record2 === void 0) throw new Error(`Unknown share: ${shareId}`);
11642
+ const revoked = { ...record2, revokedAt };
11287
11643
  await this.records.put(revoked);
11288
11644
  return revoked;
11289
11645
  }
@@ -13117,27 +13473,27 @@ var AccountService = class {
13117
13473
  const kvResult = this.accountKV();
13118
13474
  if (!kvResult.ok) return kvResult;
13119
13475
  let registered;
13120
- for (const record of request.registryRecords) {
13121
- const manifestHash = hashJson(record.manifests);
13122
- if (!options2.assumeUnregistered && await this.indexHasApplicationHash(record.app_id, manifestHash)) {
13476
+ for (const record2 of request.registryRecords) {
13477
+ const manifestHash = hashJson(record2.manifests);
13478
+ if (!options2.assumeUnregistered && await this.indexHasApplicationHash(record2.app_id, manifestHash)) {
13123
13479
  registered = {
13124
- appId: record.app_id,
13125
- manifests: record.manifests,
13480
+ appId: record2.app_id,
13481
+ manifests: record2.manifests,
13126
13482
  manifestHash,
13127
- name: record.manifests[0]?.name,
13128
- description: record.manifests[0]?.description
13483
+ name: record2.manifests[0]?.name,
13484
+ description: record2.manifests[0]?.description
13129
13485
  };
13130
13486
  continue;
13131
13487
  }
13132
13488
  const stored = {
13133
- app_id: record.app_id,
13134
- manifests: record.manifests,
13489
+ app_id: record2.app_id,
13490
+ manifests: record2.manifests,
13135
13491
  manifest_hash: manifestHash,
13136
13492
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
13137
13493
  };
13138
- const written = await kvResult.data.put(record.key, stored);
13494
+ const written = await kvResult.data.put(record2.key, stored);
13139
13495
  if (!written.ok) return accountErr(written.error);
13140
- registered = applicationFromRecord(record.key, stored);
13496
+ registered = applicationFromRecord(record2.key, stored);
13141
13497
  await this.upsertApplicationIndexQuietly(registered);
13142
13498
  }
13143
13499
  return ok3(registered);
@@ -13211,11 +13567,11 @@ var AccountService = class {
13211
13567
  if (!kvResult.ok) return kvResult;
13212
13568
  const stored = spaces.map((space) => spaceRecordFromInput(space));
13213
13569
  const registered = stored.map(
13214
- (record) => spaceFromRecord(spaceKey(record.space_id), record)
13570
+ (record2) => spaceFromRecord(spaceKey(record2.space_id), record2)
13215
13571
  );
13216
- const items = stored.map((record) => ({
13217
- key: spaceKey(record.space_id),
13218
- value: record
13572
+ const items = stored.map((record2) => ({
13573
+ key: spaceKey(record2.space_id),
13574
+ value: record2
13219
13575
  }));
13220
13576
  const batchResult = await kvResult.data.batchPut(items);
13221
13577
  if (batchResult.ok) {
@@ -13226,10 +13582,10 @@ var AccountService = class {
13226
13582
  return accountErr(batchResult.error);
13227
13583
  }
13228
13584
  const reconcileFailures = [];
13229
- for (const record of stored) {
13230
- const written = await kvResult.data.put(spaceKey(record.space_id), record);
13585
+ for (const record2 of stored) {
13586
+ const written = await kvResult.data.put(spaceKey(record2.space_id), record2);
13231
13587
  if (!written.ok) {
13232
- reconcileFailures.push(`${record.space_id}: ${written.error.message}`);
13588
+ reconcileFailures.push(`${record2.space_id}: ${written.error.message}`);
13233
13589
  }
13234
13590
  }
13235
13591
  if (reconcileFailures.length > 0) {
@@ -13849,16 +14205,16 @@ function applicationKey(appId) {
13849
14205
  function appIdFromKey(key) {
13850
14206
  return key.startsWith(ACCOUNT_REGISTRY_PATH) ? key.slice(ACCOUNT_REGISTRY_PATH.length) : key;
13851
14207
  }
13852
- function applicationFromRecord(key, record) {
13853
- const manifests = Array.isArray(record.manifests) ? record.manifests : [];
14208
+ function applicationFromRecord(key, record2) {
14209
+ const manifests = Array.isArray(record2.manifests) ? record2.manifests : [];
13854
14210
  const first = manifests[0];
13855
14211
  return {
13856
- appId: record.app_id ?? record.appId ?? first?.app_id ?? appIdFromKey(key),
14212
+ appId: record2.app_id ?? record2.appId ?? first?.app_id ?? appIdFromKey(key),
13857
14213
  manifests,
13858
- updatedAt: record.updated_at ?? record.updatedAt,
14214
+ updatedAt: record2.updated_at ?? record2.updatedAt,
13859
14215
  name: first?.name,
13860
14216
  description: first?.description,
13861
- manifestHash: record.manifest_hash ?? record.manifestHash ?? hashJson(manifests)
14217
+ manifestHash: record2.manifest_hash ?? record2.manifestHash ?? hashJson(manifests)
13862
14218
  };
13863
14219
  }
13864
14220
  function indexedApplicationFromRow(row) {
@@ -13901,17 +14257,17 @@ function spaceRecordFromInput(space) {
13901
14257
  expires_at: accountSpace.expiresAt instanceof Date ? accountSpace.expiresAt.toISOString() : accountSpace.expiresAt
13902
14258
  };
13903
14259
  }
13904
- function spaceFromRecord(key, record) {
13905
- const expiresAt = record.expires_at ?? record.expiresAt;
14260
+ function spaceFromRecord(key, record2) {
14261
+ const expiresAt = record2.expires_at ?? record2.expiresAt;
13906
14262
  return {
13907
- spaceId: record.space_id ?? record.spaceId ?? spaceIdFromKey(key),
13908
- name: record.name ?? spaceIdFromKey(key).split(":").pop() ?? spaceIdFromKey(key),
13909
- ownerDid: record.owner_did ?? record.ownerDid ?? record.owner ?? "",
13910
- type: record.type ?? "discovered",
13911
- permissions: Array.isArray(record.permissions) ? record.permissions : [],
13912
- status: record.status ?? "active",
13913
- registeredAt: record.registered_at ?? record.registeredAt,
13914
- updatedAt: record.updated_at ?? record.updatedAt,
14263
+ spaceId: record2.space_id ?? record2.spaceId ?? spaceIdFromKey(key),
14264
+ name: record2.name ?? spaceIdFromKey(key).split(":").pop() ?? spaceIdFromKey(key),
14265
+ ownerDid: record2.owner_did ?? record2.ownerDid ?? record2.owner ?? "",
14266
+ type: record2.type ?? "discovered",
14267
+ permissions: Array.isArray(record2.permissions) ? record2.permissions : [],
14268
+ status: record2.status ?? "active",
14269
+ registeredAt: record2.registered_at ?? record2.registeredAt,
14270
+ updatedAt: record2.updated_at ?? record2.updatedAt,
13915
14271
  expiresAt: expiresAt ? new Date(expiresAt) : void 0
13916
14272
  };
13917
14273
  }
@@ -16722,7 +17078,7 @@ function portForProtocol(protocol) {
16722
17078
  }
16723
17079
 
16724
17080
  // src/location.ts
16725
- import { ed25519 as ed255199 } from "@noble/curves/ed25519";
17081
+ import { ed25519 as ed2551910 } from "@noble/curves/ed25519";
16726
17082
  import { verifyMessage as verifyMessage2 } from "viem";
16727
17083
  var DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL = "https://registry.tinycloud.xyz";
16728
17084
  var DEFAULT_TINYCLOUD_FALLBACK_HOST = "https://node.tinycloud.xyz";
@@ -16787,13 +17143,13 @@ var CloudLocationResolutionError = class extends Error {
16787
17143
  this.attempts = attempts;
16788
17144
  }
16789
17145
  };
16790
- function locationPayloadForRecord(record) {
17146
+ function locationPayloadForRecord(record2) {
16791
17147
  return {
16792
- version: record.version,
16793
- subject: record.subject,
16794
- multiaddrs: [...record.multiaddrs],
16795
- updated_at: record.updated_at,
16796
- sequence: record.sequence
17148
+ version: record2.version,
17149
+ subject: record2.subject,
17150
+ multiaddrs: [...record2.multiaddrs],
17151
+ updated_at: record2.updated_at,
17152
+ sequence: record2.sequence
16797
17153
  };
16798
17154
  }
16799
17155
  function canonicalLocationPayload(payload) {
@@ -16852,13 +17208,13 @@ function validateLocationRecord(input) {
16852
17208
  return { ...payload, signature };
16853
17209
  }
16854
17210
  async function verifyLocationRecord(input) {
16855
- const record = validateLocationRecord(input);
16856
- const payload = canonicalLocationPayload(locationPayloadForRecord(record));
16857
- if (record.subject.startsWith("did:pkh:")) {
16858
- return verifyPkhSignature(record.subject, payload, record.signature);
17211
+ const record2 = validateLocationRecord(input);
17212
+ const payload = canonicalLocationPayload(locationPayloadForRecord(record2));
17213
+ if (record2.subject.startsWith("did:pkh:")) {
17214
+ return verifyPkhSignature(record2.subject, payload, record2.signature);
16859
17215
  }
16860
- if (record.subject.startsWith("did:key:")) {
16861
- return verifyDidKeySignature(record.subject, payload, record.signature);
17216
+ if (record2.subject.startsWith("did:key:")) {
17217
+ return verifyDidKeySignature(record2.subject, payload, record2.signature);
16862
17218
  }
16863
17219
  return false;
16864
17220
  }
@@ -17044,18 +17400,18 @@ async function fetchRegistryLocalLinkCandidates(options2, fetchFn, existingCandi
17044
17400
  }
17045
17401
  const registryUrl = options2.registryUrl ?? DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL;
17046
17402
  try {
17047
- const record = await fetchLocationRecord(registryUrl, options2.subject, fetchFn);
17048
- if (!record) {
17403
+ const record2 = await fetchLocationRecord(registryUrl, options2.subject, fetchFn);
17404
+ if (!record2) {
17049
17405
  return [];
17050
17406
  }
17051
17407
  const shouldVerify = options2.verifyRecords ?? true;
17052
- if (shouldVerify && !await verifyLocationRecord(record)) {
17408
+ if (shouldVerify && !await verifyLocationRecord(record2)) {
17053
17409
  debugLog(
17054
17410
  `registry record signature invalid for ${options2.subject}; skipping local-link lookup`
17055
17411
  );
17056
17412
  return [];
17057
17413
  }
17058
- return extractLocalLinkUrls(record).filter((url) => !existingCandidates.some((c) => c.url === url)).map((url) => ({
17414
+ return extractLocalLinkUrls(record2).filter((url) => !existingCandidates.some((c) => c.url === url)).map((url) => ({
17059
17415
  source: "local-link",
17060
17416
  url,
17061
17417
  timeoutMs: LOCAL_LINK_PROBE_TIMEOUT_MS
@@ -17064,12 +17420,12 @@ async function fetchRegistryLocalLinkCandidates(options2, fetchFn, existingCandi
17064
17420
  return [];
17065
17421
  }
17066
17422
  }
17067
- function extractLocalLinkUrls(record) {
17068
- if (!record) {
17423
+ function extractLocalLinkUrls(record2) {
17424
+ if (!record2) {
17069
17425
  return [];
17070
17426
  }
17071
17427
  const urls = [];
17072
- for (const addr of record.multiaddrs) {
17428
+ for (const addr of record2.multiaddrs) {
17073
17429
  let url;
17074
17430
  try {
17075
17431
  url = multiaddrToHttpUrl(addr);
@@ -17168,12 +17524,12 @@ async function resolveCentralized(subject, options2, verifyRecords) {
17168
17524
  if (!options2.centralizedRegistryUrl) {
17169
17525
  return null;
17170
17526
  }
17171
- const record = await fetchLocationRecord(
17527
+ const record2 = await fetchLocationRecord(
17172
17528
  options2.centralizedRegistryUrl,
17173
17529
  subject,
17174
17530
  options2.fetch
17175
17531
  );
17176
- return toCandidate(subject, "centralized", record, verifyRecords);
17532
+ return toCandidate(subject, "centralized", record2, verifyRecords);
17177
17533
  });
17178
17534
  }
17179
17535
  async function resolveFallback(subject, multiaddrs) {
@@ -17205,18 +17561,18 @@ async function toCandidate(subject, source, input, verifyRecord) {
17205
17561
  }
17206
17562
  const maybeRecord = input;
17207
17563
  if (maybeRecord.version === 1 && maybeRecord.signature !== void 0) {
17208
- const record = validateLocationRecord(input);
17209
- if (record.subject !== subject) {
17564
+ const record2 = validateLocationRecord(input);
17565
+ if (record2.subject !== subject) {
17210
17566
  throw new LocationRecordValidationError(
17211
17567
  "location record subject does not match requested subject"
17212
17568
  );
17213
17569
  }
17214
- if (verifyRecord && !await verifyLocationRecord(record)) {
17570
+ if (verifyRecord && !await verifyLocationRecord(record2)) {
17215
17571
  throw new LocationRecordValidationError(
17216
17572
  "location record signature is invalid"
17217
17573
  );
17218
17574
  }
17219
- return { source, multiaddrs: [...record.multiaddrs], record };
17575
+ return { source, multiaddrs: [...record2.multiaddrs], record: record2 };
17220
17576
  }
17221
17577
  const candidateInput = input;
17222
17578
  if (!Array.isArray(candidateInput.multiaddrs)) {
@@ -17226,18 +17582,18 @@ async function toCandidate(subject, source, input, verifyRecord) {
17226
17582
  }
17227
17583
  validateMultiaddrs(candidateInput.multiaddrs);
17228
17584
  if (candidateInput.record !== void 0) {
17229
- const record = validateLocationRecord(candidateInput.record);
17230
- if (record.subject !== subject) {
17585
+ const record2 = validateLocationRecord(candidateInput.record);
17586
+ if (record2.subject !== subject) {
17231
17587
  throw new LocationRecordValidationError(
17232
17588
  "location record subject does not match requested subject"
17233
17589
  );
17234
17590
  }
17235
- if (verifyRecord && !await verifyLocationRecord(record)) {
17591
+ if (verifyRecord && !await verifyLocationRecord(record2)) {
17236
17592
  throw new LocationRecordValidationError(
17237
17593
  "location record signature is invalid"
17238
17594
  );
17239
17595
  }
17240
- return { source, multiaddrs: [...candidateInput.multiaddrs], record };
17596
+ return { source, multiaddrs: [...candidateInput.multiaddrs], record: record2 };
17241
17597
  }
17242
17598
  return { source, multiaddrs: [...candidateInput.multiaddrs] };
17243
17599
  }
@@ -17294,7 +17650,7 @@ function verifyDidKeySignature(did, payload, signature) {
17294
17650
  "did:key signature must be a base64url Ed25519 signature"
17295
17651
  );
17296
17652
  }
17297
- return ed255199.verify(
17653
+ return ed2551910.verify(
17298
17654
  signatureBytes,
17299
17655
  new TextEncoder().encode(payload),
17300
17656
  publicKey
@@ -17302,7 +17658,7 @@ function verifyDidKeySignature(did, payload, signature) {
17302
17658
  }
17303
17659
  function verifyDidKeyEd25519Signature(did, payload, signature) {
17304
17660
  const publicKey = ed25519PublicKeyFromDidKey2(did);
17305
- return ed255199.verify(signature, payload, publicKey);
17661
+ return ed2551910.verify(signature, payload, publicKey);
17306
17662
  }
17307
17663
  function ed25519PublicKeyFromDidKey2(did) {
17308
17664
  const identifier = did.slice("did:key:".length);
@@ -17462,6 +17818,7 @@ export {
17462
17818
  OPENKEY_ACTION_ID_SEPARATOR,
17463
17819
  POLICY_CAPABILITY_V1_DOMAIN,
17464
17820
  POLICY_CAPABILITY_V1_SCHEMA,
17821
+ POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE,
17465
17822
  POLICY_ENFORCEMENT_DELEGATION_V2_SCHEMA,
17466
17823
  POLICY_ENGINE_CHALLENGE_REQUEST_SCHEMA,
17467
17824
  POLICY_ENGINE_CHALLENGE_RESPONSE_SCHEMA,
@@ -17469,11 +17826,15 @@ export {
17469
17826
  POLICY_ENGINE_GRANT_PRESENTATION_DENIAL_CODES,
17470
17827
  POLICY_ENGINE_RECORD_SCHEMA,
17471
17828
  POLICY_ENGINE_RESOLVE_REQUEST_SCHEMA,
17829
+ POLICY_PRESENTATION_V3_DOMAIN,
17830
+ POLICY_PRESENTATION_V3_SCHEMA,
17472
17831
  POLICY_SCHEMA,
17473
17832
  POLICY_SESSION_UCAN_V1_PROFILE,
17474
17833
  POLICY_STATUS_SCHEMA,
17475
17834
  POLICY_V1_DOMAIN,
17476
17835
  POLICY_V1_SCHEMA,
17836
+ POLICY_V2_DOMAIN,
17837
+ POLICY_V2_SCHEMA,
17477
17838
  PORTABLE_DELEGATION_SCHEMA,
17478
17839
  PermissionNotInManifestError,
17479
17840
  PrefixedKVService,
@@ -17541,6 +17902,7 @@ export {
17541
17902
  actionContains,
17542
17903
  activateSessionWithHost,
17543
17904
  addressStorageKey,
17905
+ admitPolicyCredentialV3,
17544
17906
  applyPrefix,
17545
17907
  bootstrapEncryptionNetworkId,
17546
17908
  bootstrapSpaceId,
@@ -17550,6 +17912,7 @@ export {
17550
17912
  buildDecryptFacts,
17551
17913
  buildDecryptInvocation,
17552
17914
  buildNetworkId2 as buildNetworkId,
17915
+ buildPolicyCredentialPresentationV3,
17553
17916
  buildSpaceUri,
17554
17917
  canonicalDigest,
17555
17918
  canonicalHashHex,
@@ -17689,6 +18052,7 @@ export {
17689
18052
  policyCidFromCanonicalBytes,
17690
18053
  policyDigestHex,
17691
18054
  policyIdForDigestHex,
18055
+ policyV2DigestHex,
17692
18056
  principalDid,
17693
18057
  principalDidEquals,
17694
18058
  projectUnifiedPolicyCapabilities,
@@ -17712,6 +18076,7 @@ export {
17712
18076
  shareCapabilityAllows,
17713
18077
  shareDeliveryTrustedKid,
17714
18078
  signCompactUcanAuthorization,
18079
+ signCompactUcanRootAuthorization,
17715
18080
  signLocationRecord,
17716
18081
  signShareEnvelope,
17717
18082
  signedObjectIdFor,
@@ -17735,6 +18100,7 @@ export {
17735
18100
  validateOwnerSharePolicyRegistration,
17736
18101
  validateOwnerSharePolicyRegistrationBytes,
17737
18102
  validatePersistedSessionData,
18103
+ validatePolicyCredentialRequirementV1,
17738
18104
  validatePolicyEngineRecordSigned,
17739
18105
  validatePolicyEngineRecordSignedShape,
17740
18106
  validatePolicyEngineRecordUnsigned,
@@ -17745,6 +18111,7 @@ export {
17745
18111
  validatePolicyStatusUnsigned,
17746
18112
  validatePolicyUnsigned,
17747
18113
  validateShareDeliveryAuthorizationBytes,
18114
+ validateUnifiedPolicyV2,
17748
18115
  verifyDecryptResponse,
17749
18116
  verifyDidKeyEd25519Signature,
17750
18117
  verifyEip191MessageSignature,