@tinycloud/cli 0.9.1-beta.1 → 0.9.1-beta.3

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
@@ -17725,7 +17725,7 @@ function validateV3Invariants(value, ctx) {
17725
17725
  if (value.contentSource.encryptionNetwork !== value.encryptionNetwork) {
17726
17726
  ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["encryptionNetwork"], message: "encryption network is not bound to the source" });
17727
17727
  }
17728
- if (value.attestedEnforcerBinding.enforcerDid !== value.target.nodeAudience || value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.target.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
17728
+ if (value.attestedEnforcerBinding.enforcerDid !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
17729
17729
  ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
17730
17730
  }
17731
17731
  if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
@@ -18077,7 +18077,7 @@ async function signCompactUcanAuthorization(input) {
18077
18077
  const publicKey = ed25519PublicKeyFromDidKey(principal);
18078
18078
  const header = {
18079
18079
  alg: "EdDSA",
18080
- jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(publicKey) },
18080
+ jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: toBase64Url(publicKey) },
18081
18081
  typ: "JWT",
18082
18082
  ucv: "0.10.0"
18083
18083
  };
@@ -18091,13 +18091,13 @@ async function signCompactUcanAuthorization(input) {
18091
18091
  nnc: input.nonce,
18092
18092
  prf: input.proofs
18093
18093
  };
18094
- const protectedSegment = encodeBase64Url(new TextEncoder().encode(canonicalize2(header)));
18095
- const payloadSegment = encodeBase64Url(new TextEncoder().encode(canonicalize2(payload)));
18094
+ const protectedSegment = toBase64Url(new TextEncoder().encode(canonicalize2(header)));
18095
+ const payloadSegment = toBase64Url(new TextEncoder().encode(canonicalize2(payload)));
18096
18096
  const signingInput = new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`);
18097
18097
  const signature = await input.sign(signingInput);
18098
18098
  if (signature.length !== 64) throw new TypeError("compact Authorization signature must be Ed25519");
18099
18099
  return verifyCompactUcanAuthorization(
18100
- `${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`
18100
+ `${protectedSegment}.${payloadSegment}.${toBase64Url(signature)}`
18101
18101
  );
18102
18102
  }
18103
18103
  function verifyCompactUcanAuthorization(authorization, expectedCid) {
@@ -18105,9 +18105,9 @@ function verifyCompactUcanAuthorization(authorization, expectedCid) {
18105
18105
  const segments = authorization.split(".");
18106
18106
  if (segments.length !== 3 || segments.some((segment) => segment.length === 0)) throw new TypeError("compact Authorization must contain three segments");
18107
18107
  const [headerSegment, payloadSegment, signatureSegment] = segments;
18108
- const headerBytes = decodeBase64Url(headerSegment);
18109
- const payloadBytes = decodeBase64Url(payloadSegment);
18110
- const signature = decodeBase64Url(signatureSegment);
18108
+ const headerBytes = fromBase64Url(headerSegment);
18109
+ const payloadBytes = fromBase64Url(payloadSegment);
18110
+ const signature = fromBase64Url(signatureSegment);
18111
18111
  const decoder = new TextDecoder("utf-8", { fatal: true });
18112
18112
  const header = JSON.parse(decoder.decode(headerBytes));
18113
18113
  const payload = JSON.parse(decoder.decode(payloadBytes));
@@ -18120,7 +18120,7 @@ function verifyCompactUcanAuthorization(authorization, expectedCid) {
18120
18120
  if (typeof payload.iss !== "string" || typeof payload.aud !== "string" || typeof payload.nnc !== "string" || !Number.isInteger(payload.nbf) || !Number.isInteger(payload.exp) || payload.nbf >= payload.exp || !Array.isArray(payload.prf) || payload.prf.some((proof) => typeof proof !== "string") || !Array.isArray(payload.fct) || payload.fct.length !== 1) throw new TypeError("compact Authorization payload is invalid");
18121
18121
  const principal = payload.iss.split("#", 1)[0];
18122
18122
  const publicKey = ed25519PublicKeyFromDidKey(principal);
18123
- if (!equal(publicKey, decodeBase64Url(jwk.x))) throw new TypeError("compact Authorization JWK does not bind issuer");
18123
+ if (!equal(publicKey, fromBase64Url(jwk.x))) throw new TypeError("compact Authorization JWK does not bind issuer");
18124
18124
  if (!ed25519.verify(signature, new TextEncoder().encode(`${headerSegment}.${payloadSegment}`), publicKey, { zip215: false })) throw new TypeError("compact Authorization signature is invalid");
18125
18125
  const cid2 = CID.createV1(85, create(30, blake3(new TextEncoder().encode(authorization)))).toString();
18126
18126
  if (expectedCid !== void 0 && cid2 !== expectedCid) throw new TypeError("compact Authorization CID mismatch");
@@ -18133,16 +18133,6 @@ function object(value, label) {
18133
18133
  function assertExactKeys(value, keys, label) {
18134
18134
  if (Object.keys(value).length !== keys.length || Object.keys(value).some((key) => !keys.includes(key))) throw new TypeError(`${label} has unknown or missing fields`);
18135
18135
  }
18136
- function decodeBase64Url(value) {
18137
- if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1) throw new TypeError("compact Authorization segment is not base64url");
18138
- const bytes3 = typeof Buffer !== "undefined" ? new Uint8Array(Buffer.from(value, "base64url")) : Uint8Array.from(atob(value.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(value.length / 4) * 4, "=")), (character) => character.charCodeAt(0));
18139
- const encoded = typeof Buffer !== "undefined" ? Buffer.from(bytes3).toString("base64url") : btoa(String.fromCharCode(...bytes3)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
18140
- if (encoded !== value) throw new TypeError("compact Authorization segment is not canonical");
18141
- return bytes3;
18142
- }
18143
- function encodeBase64Url(value) {
18144
- return typeof Buffer !== "undefined" ? Buffer.from(value).toString("base64url") : btoa(String.fromCharCode(...value)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
18145
- }
18146
18136
  function equal(left, right) {
18147
18137
  return left.length === right.length && left.every((byte, index) => byte === right[index]);
18148
18138
  }
@@ -18262,10 +18252,10 @@ async function verifyEnvelopeV3(envelope, options) {
18262
18252
  const binding = parsed.attestedEnforcerBinding;
18263
18253
  const { signature: bindingSignature, ...unsignedBinding } = binding;
18264
18254
  const expectedBindingDigestHex = hex(sha2562(new TextEncoder().encode(canonicalize2({ enforcerDid: binding.enforcerDid, nodeAudience: binding.nodeAudience }))));
18265
- if (binding.enforcerDid !== parsed.target.nodeAudience || binding.nodeAudience !== parsed.target.nodeAudience || binding.attestationBindingDigestHex !== expectedBindingDigestHex || bindingSignature.signerDid !== binding.enforcerDid || bindingSignature.suite !== "Ed25519" || Date.parse(binding.issuedAt) > Date.now() || Date.parse(binding.expiresAt) <= Date.now() || Date.parse(binding.expiresAt) < Date.parse(parsed.expiry)) return false;
18255
+ if (binding.enforcerDid !== parsed.target.nodeAudience || binding.attestationBindingDigestHex !== expectedBindingDigestHex || bindingSignature.signerDid !== binding.nodeAudience || bindingSignature.suite !== "Ed25519" || Date.parse(binding.issuedAt) > Date.now() || Date.parse(binding.expiresAt) <= Date.now() || Date.parse(binding.expiresAt) < Date.parse(parsed.expiry)) return false;
18266
18256
  try {
18267
18257
  const digest4 = sha2562(new TextEncoder().encode(`${ATTESTED_ENFORCER_V2_DOMAIN}${canonicalize2(unsignedBinding)}`));
18268
- if (!ed25519.verify(fromBase64Url(bindingSignature.value), digest4, ed25519PublicKeyFromDidKey(binding.enforcerDid), ED25519_VERIFY_OPTS2)) return false;
18258
+ if (!ed25519.verify(fromBase64Url(bindingSignature.value), digest4, ed25519PublicKeyFromDidKey(binding.nodeAudience), ED25519_VERIFY_OPTS2)) return false;
18269
18259
  } catch {
18270
18260
  return false;
18271
18261
  }
@@ -18278,7 +18268,7 @@ async function verifyEnvelopeV3(envelope, options) {
18278
18268
  const common = ["ownerDid", "policyId", "policyDigestHex", "policyCid", "contentSourceDigestHex", "capabilityCeilingHashHex", "nativeProjectionHashHex", "nodeAudience"];
18279
18269
  const policyKeys = [...common, "role", "mode"];
18280
18270
  const enforcementKeys = [...policyKeys, "enforcerDid"];
18281
- if (Object.keys(policyFact).length !== policyKeys.length || policyKeys.some((key) => !(key in policyFact)) || Object.keys(enforcementFact).length !== enforcementKeys.length || enforcementKeys.some((key) => !(key in enforcementFact)) || policyRoot.payload.prf.length !== 0 || enforcementRoot.payload.prf.length !== 0 || policyRoot.payload.iss.split("#", 1)[0] !== policy.ownerDid || enforcementRoot.payload.iss.split("#", 1)[0] !== policy.ownerDid || policyRoot.payload.nbf !== enforcementRoot.payload.nbf || policyRoot.payload.exp !== enforcementRoot.payload.exp || canonicalize2(policyRoot.payload.att) !== canonicalize2(expectedAttenuation) || canonicalize2(enforcementRoot.payload.att) !== canonicalize2(expectedAttenuation) || policyFact.role !== "policy-authority" || policyFact.mode !== "policy-source" || "enforcerDid" in policyFact || enforcementFact.role !== "policy-enforcement" || enforcementFact.mode !== "conditional-mint" || policyRoot.payload.aud !== `did:tinycloud:policy:${hex(policyIdDigest)}` || enforcementRoot.payload.aud !== parsed.target.nodeAudience || enforcementFact.enforcerDid !== parsed.target.nodeAudience || common.some((key) => policyFact[key] !== enforcementFact[key]) || policyFact.ownerDid !== policy.ownerDid || policyFact.policyId !== policy.policyId || policyFact.policyDigestHex !== hex(policyIdDigest) || policyFact.policyCid !== parsed.policyCid || policyFact.contentSourceDigestHex !== parsed.contentSourceDigestHex || policyFact.capabilityCeilingHashHex !== capabilityCeilingHashHex || policyFact.nativeProjectionHashHex !== nativeProjectionHashHex || policyFact.nodeAudience !== parsed.target.nodeAudience || policyRoot.payload.exp * 1e3 < Date.parse(parsed.expiry)) return false;
18271
+ if (Object.keys(policyFact).length !== policyKeys.length || policyKeys.some((key) => !(key in policyFact)) || Object.keys(enforcementFact).length !== enforcementKeys.length || enforcementKeys.some((key) => !(key in enforcementFact)) || policyRoot.payload.prf.length !== 0 || enforcementRoot.payload.prf.length !== 0 || policyRoot.payload.iss.split("#", 1)[0] !== policy.ownerDid || enforcementRoot.payload.iss.split("#", 1)[0] !== policy.ownerDid || policyRoot.payload.nbf !== enforcementRoot.payload.nbf || policyRoot.payload.exp !== enforcementRoot.payload.exp || canonicalize2(policyRoot.payload.att) !== canonicalize2(expectedAttenuation) || canonicalize2(enforcementRoot.payload.att) !== canonicalize2(expectedAttenuation) || policyFact.role !== "policy-authority" || policyFact.mode !== "policy-source" || "enforcerDid" in policyFact || enforcementFact.role !== "policy-enforcement" || enforcementFact.mode !== "conditional-mint" || policyRoot.payload.aud !== `did:tinycloud:policy:${hex(policyIdDigest)}` || enforcementRoot.payload.aud !== binding.enforcerDid || enforcementFact.enforcerDid !== binding.enforcerDid || common.some((key) => policyFact[key] !== enforcementFact[key]) || policyFact.ownerDid !== policy.ownerDid || policyFact.policyId !== policy.policyId || policyFact.policyDigestHex !== hex(policyIdDigest) || policyFact.policyCid !== parsed.policyCid || policyFact.contentSourceDigestHex !== parsed.contentSourceDigestHex || policyFact.capabilityCeilingHashHex !== capabilityCeilingHashHex || policyFact.nativeProjectionHashHex !== nativeProjectionHashHex || policyFact.nodeAudience !== binding.nodeAudience || policyRoot.payload.exp * 1e3 < Date.parse(parsed.expiry)) return false;
18282
18272
  } catch {
18283
18273
  return false;
18284
18274
  }
@@ -18460,8 +18450,12 @@ async function readResponseBytes(response, limit, tooLargeCode) {
18460
18450
  function registryFetcher(options, limit, tooLargeCode = "max-bytes-exceeded", stage = "envelope") {
18461
18451
  if (options.fetchBlob !== void 0) return async (input) => {
18462
18452
  try {
18463
- return boundedBytes(await options.fetchBlob(input), limit, tooLargeCode);
18453
+ options.signal?.throwIfAborted();
18454
+ const bytes3 = await options.fetchBlob({ ...input, ...options.signal === void 0 ? {} : { signal: options.signal } });
18455
+ options.signal?.throwIfAborted();
18456
+ return boundedBytes(bytes3, limit, tooLargeCode);
18464
18457
  } catch (error) {
18458
+ if (options.signal?.aborted) throw options.signal.reason ?? error;
18465
18459
  if (error instanceof ShareReceiveError) throw error;
18466
18460
  throw new ShareReceiveError("fetch-failed", "registry unavailable", { stage });
18467
18461
  }
@@ -18471,10 +18465,19 @@ function registryFetcher(options, limit, tooLargeCode = "max-bytes-exceeded", st
18471
18465
  const base33 = options.registryBaseUrl.replace(/\/+$/, "");
18472
18466
  return async ({ cid: cid2 }) => {
18473
18467
  try {
18474
- const response = await fetchFn(`${base33}/ipfs/${cid2}?format=raw`, { headers: { accept: "application/vnd.ipld.raw" }, redirect: "error" });
18468
+ options.signal?.throwIfAborted();
18469
+ const response = await fetchFn(`${base33}/ipfs/${cid2}?format=raw`, {
18470
+ headers: { accept: "application/vnd.ipld.raw" },
18471
+ redirect: "error",
18472
+ ...options.signal === void 0 ? {} : { signal: options.signal }
18473
+ });
18474
+ options.signal?.throwIfAborted();
18475
18475
  if (!response.ok) throw new ShareReceiveError("fetch-failed", `registry returned ${response.status}`, { stage });
18476
- return await readResponseBytes(response, limit, tooLargeCode);
18476
+ const bytes3 = await readResponseBytes(response, limit, tooLargeCode);
18477
+ options.signal?.throwIfAborted();
18478
+ return bytes3;
18477
18479
  } catch (error) {
18480
+ if (options.signal?.aborted) throw options.signal.reason ?? error;
18478
18481
  if (error instanceof ShareReceiveError) throw error;
18479
18482
  throw new ShareReceiveError("fetch-failed", "registry unavailable", { stage });
18480
18483
  }
@@ -20265,6 +20268,39 @@ function uiAction(action) {
20265
20268
  function selectedAction(envelope) {
20266
20269
  return envelope.actions.includes("list") ? "tinycloud.kv/list" : envelope.actions.includes("edit") ? "tinycloud.kv/put" : "tinycloud.kv/get";
20267
20270
  }
20271
+ function policyAttenuationForV3(envelope) {
20272
+ const policy = object2(envelope.policy, "v3 policy");
20273
+ if (!Array.isArray(policy.capabilityCeiling)) throw new Error("v3 policy capability ceiling is invalid");
20274
+ const attenuation = {};
20275
+ for (const raw of policy.capabilityCeiling) {
20276
+ const capability = object2(raw, "v3 policy capability");
20277
+ if (typeof capability.resource !== "string" || attenuation[capability.resource] !== void 0) throw new Error("v3 policy capability is invalid");
20278
+ if (capability.kind === "encryption") {
20279
+ if (capability.action !== "tinycloud.encryption/decrypt") throw new Error("v3 policy capability is invalid");
20280
+ attenuation[capability.resource] = { [capability.action]: [{}] };
20281
+ continue;
20282
+ }
20283
+ if (capability.kind !== "kv" || capability.selector !== "exact" && capability.selector !== "prefix" || !Array.isArray(capability.actions) || capability.actions.length === 0 || capability.actions.some((action) => typeof action !== "string")) throw new Error("v3 policy capability is invalid");
20284
+ attenuation[capability.resource] = Object.fromEntries(capability.actions.map((action) => [action, [{
20285
+ type: "xyz.tinycloud.resource/selector",
20286
+ kind: capability.selector,
20287
+ value: capability.resource
20288
+ }]]));
20289
+ }
20290
+ return attenuation;
20291
+ }
20292
+ function verifyV3PolicyAuthorization(input) {
20293
+ const compact = verifyCompactUcanAuthorization(input.authorization, input.cid);
20294
+ const fact = compact.payload.fct[0];
20295
+ const factKeys = Object.keys(fact);
20296
+ const legacyShape = 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);
20297
+ const v4Shape = 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);
20298
+ const binding = object2(input.envelope.attestedEnforcerBinding, "v3 attested enforcer binding");
20299
+ const policy = object2(input.envelope.policy, "v3 policy");
20300
+ const now = Math.floor(Date.now() / 1e3);
20301
+ if (!legacyShape && !v4Shape || POLICY_SESSION_DIGEST_FACT_KEYS.some((key) => !LOWER_SHA256_HEX.test(fact[key])) || v4Shape && (!LOWER_SHA256_HEX.test(fact.credentialIdAuditDigestHex) || !LOWER_SHA256_HEX.test(fact.presentationJtiAuditDigestHex)) || compact.payload.aud !== input.holderDid || compact.payload.iss.split("#", 1)[0] !== fact.nodeAudience || fact.profile !== "policy-session-ucan/v1" || fact.ownerDid !== policy.ownerDid || fact.policyId !== policy.policyId || fact.policyCid !== input.envelope.policyCid || fact.contentSourceDigestHex !== input.envelope.contentSourceDigestHex || fact.enforcerDid !== binding.enforcerDid || fact.nodeAudience !== binding.nodeAudience || fact.recipientDid !== input.holderDid || fact.policyDelegationCid !== input.envelope.policyRoot.cid || fact.enforcementDelegationCid !== input.envelope.enforcementRoot.cid || typeof fact.remainingRedelegationDepth !== "number" || !Number.isInteger(fact.remainingRedelegationDepth) || fact.remainingRedelegationDepth < 0 || fact.remainingRedelegationDepth > 8 || compact.payload.prf.length !== 2 || compact.payload.prf[0] !== input.envelope.policyRoot.cid || compact.payload.prf[1] !== input.envelope.enforcementRoot.cid || compact.payload.nbf > now || compact.payload.exp <= now || compact.payload.exp - compact.payload.nbf > 60 || canonicalize2(compact.payload.att) !== canonicalize2(policyAttenuationForV3(input.envelope))) throw new Error("v3 policy delegation signed binding mismatch");
20302
+ return compact;
20303
+ }
20268
20304
  function hex2(value) {
20269
20305
  return [...value].map((byte) => byte.toString(16).padStart(2, "0")).join("");
20270
20306
  }
@@ -20355,7 +20391,7 @@ function createAddressedAuthorization(input) {
20355
20391
  }
20356
20392
  };
20357
20393
  }
20358
- var __defProp2, __export2, external_exports2, util2, objectUtil2, ZodParsedType2, getParsedType2, ZodIssueCode2, quotelessJson2, ZodError2, errorMap2, en_default2, overrideErrorMap2, makeIssue2, EMPTY_PATH2, ParseStatus2, INVALID2, DIRTY2, OK2, isAborted2, isDirty2, isValid2, isAsync2, errorUtil2, ParseInputLazyPath2, handleResult2, ZodType2, cuidRegex2, cuid2Regex2, ulidRegex2, uuidRegex2, nanoidRegex2, jwtRegex2, durationRegex2, emailRegex2, _emojiRegex2, emojiRegex2, ipv4Regex2, ipv4CidrRegex2, ipv6Regex2, ipv6CidrRegex2, base64Regex2, base64urlRegex2, dateRegexSource2, dateRegex2, ZodString2, ZodNumber2, ZodBigInt2, ZodBoolean2, ZodDate2, ZodSymbol2, ZodUndefined2, ZodNull2, ZodAny2, ZodUnknown2, ZodNever2, ZodVoid2, ZodArray2, ZodObject2, ZodUnion2, getDiscriminator2, ZodDiscriminatedUnion2, ZodIntersection2, ZodTuple2, ZodRecord2, ZodMap2, ZodSet2, ZodFunction2, ZodLazy2, ZodLiteral2, ZodEnum2, ZodNativeEnum2, ZodPromise2, ZodEffects2, ZodOptional2, ZodNullable2, ZodDefault2, ZodCatch2, ZodNaN2, BRAND2, ZodBranded2, ZodPipeline2, ZodReadonly2, late2, ZodFirstPartyTypeKind2, instanceOfType2, stringType2, numberType2, nanType2, bigIntType2, booleanType2, dateType2, symbolType2, undefinedType2, nullType2, anyType2, unknownType2, neverType2, voidType2, arrayType2, objectType2, strictObjectType2, unionType2, discriminatedUnionType2, intersectionType2, tupleType2, recordType2, mapType2, setType2, functionType2, lazyType2, literalType2, enumType2, nativeEnumType2, promiseType2, effectsType2, optionalType2, nullableType2, preprocessType2, pipelineType2, ostring2, onumber2, oboolean2, coerce2, NEVER2, empty, src, _brrp__multiformats_scope_baseX, base_x_default, Encoder, Decoder, ComposedDecoder, Codec, base32, base32upper, base32pad, base32padupper, base32hex, base32hexupper, base32hexpad, base32hexpadupper, base32z, base36, base36upper, base58btc, base58flickr, encode_1, MSB, REST, MSBALL, INT, decode2, MSB$1, REST$1, N1, N2, N3, N4, N5, N6, N7, N8, N9, length, varint, _brrp_varint, varint_default, Digest, cache, CID, DAG_PB_CODE, SHA_256_CODE, cidSymbol, code, SHA256_CODE, base64, base64pad, base64url, base64urlpad, ED25519_MULTICODEC_PREFIX, PUBLIC_KEY_LENGTH, base64UrlString, sessionJwkCommonFields, okpPrivateJwkSchema, ecPrivateJwkSchema, sessionJwkSchema, policyTargetSchema, bearerKeyTargetSchema, recipientDidTargetSchema, authorizationTargetSchema, resourceSelectorSchema, targetSchema, displaySchema, contentPointerSchema, signatureSchema, unsignedShareEnvelopeSchema, shareEnvelopeSchema, recipientMatcherSchema, shareActionSchema, kvContentSourceSchema, sqlContentSourceSchema, contentSourceSchema, v2TargetSchema, shareDecryptionSchema, ownerAuthoritySchema, contentMetadataSchema, unsignedShareEnvelopeV2BaseSchema, unsignedShareEnvelopeV2Schema, shareEnvelopeV2Schema, unifiedResourceSchema, unifiedEncryptionNetworkSchema, unifiedKvCapabilitySchema, unifiedEncryptionCapabilitySchema, unifiedCapabilitySchema, unifiedContentSourceSchema, unifiedPolicyV1Schema, policyCredentialRequirementV1Schema, unifiedPolicyV2Schema, unifiedPolicySchema, unifiedRootSchema, attestedEnforcerBindingV2Schema, v3TargetSchema, unsignedShareEnvelopeV3BaseSchema, unsignedShareEnvelopeV3Schema, shareEnvelopeV3Schema, BEARER_READ_ABILITY, READ_ABILITIES, ED25519_VERIFY_OPTS, ENVELOPE_AAD_LABEL, SEALED_BLOB_VERSION, AAD, KEY_LENGTH, NONCE_LENGTH, TAG_LENGTH, HEADER_LENGTH, ED25519_VERIFY_OPTS2, ENVELOPE_SIGNATURE_DOMAIN, ENVELOPE_V2_SIGNATURE_DOMAIN, ENVELOPE_V3_SIGNATURE_DOMAIN, POLICY_V1_SIGNATURE_DOMAIN, POLICY_V2_SIGNATURE_DOMAIN, CONTENT_SOURCE_V1_DOMAIN, POLICY_CAPABILITY_V1_DOMAIN, NATIVE_PROJECTION_V1_DOMAIN, ATTESTED_ENFORCER_V2_DOMAIN, KEY_LENGTH2, INLINE_PREFIX, MAX_INLINE_BYTES, SHARE_RESULT_VERSION, DEFAULT_MAX_SEALED_BLOB_BYTES, DEFAULT_MAX_CONTENT_BLOB_BYTES, CONTENT_SEALED_OVERHEAD, ShareReceiveError, SHARE_CONTENT_LIMIT, SHARE_SEALED_OVERHEAD, SHARE_PUBLISH_RESULT_VERSION, DEFAULT_SHARE_LIFETIME_MS, SharePublishError, empty2, src2, _brrp__multiformats_scope_baseX2, base_x_default2, Encoder2, Decoder2, ComposedDecoder2, Codec2, base322, base32upper2, base32pad2, base32padupper2, base32hex2, base32hexupper2, base32hexpad2, base32hexpadupper2, base32z2, base362, base36upper2, base58btc2, base58flickr2, encode_12, MSB2, REST2, MSBALL2, INT2, decode6, MSB$12, REST$12, N12, N22, N32, N42, N52, N62, N72, N82, N92, length2, varint2, _brrp_varint2, varint_default2, Digest2, cache2, CID2, DAG_PB_CODE2, SHA_256_CODE2, cidSymbol2, code2, SHA256_CODE2, MAX_CONTENT_BYTES, POLICY_ENFORCEMENT_DOMAIN, POLICY_DOMAIN, OWNER_SHARE_REGISTRATION_DOMAIN, ENVELOPE_DOMAIN, ENVELOPE_DOMAIN2, ShareNotifyError, SHARE_V2_PROTOCOL, DOMAIN, PRESENTATION_DOMAIN, SESSION_DOMAIN, INVOCATION_DOMAIN, BASE64_ALPHABET, ShareRecipientClient;
20394
+ var __defProp2, __export2, external_exports2, util2, objectUtil2, ZodParsedType2, getParsedType2, ZodIssueCode2, quotelessJson2, ZodError2, errorMap2, en_default2, overrideErrorMap2, makeIssue2, EMPTY_PATH2, ParseStatus2, INVALID2, DIRTY2, OK2, isAborted2, isDirty2, isValid2, isAsync2, errorUtil2, ParseInputLazyPath2, handleResult2, ZodType2, cuidRegex2, cuid2Regex2, ulidRegex2, uuidRegex2, nanoidRegex2, jwtRegex2, durationRegex2, emailRegex2, _emojiRegex2, emojiRegex2, ipv4Regex2, ipv4CidrRegex2, ipv6Regex2, ipv6CidrRegex2, base64Regex2, base64urlRegex2, dateRegexSource2, dateRegex2, ZodString2, ZodNumber2, ZodBigInt2, ZodBoolean2, ZodDate2, ZodSymbol2, ZodUndefined2, ZodNull2, ZodAny2, ZodUnknown2, ZodNever2, ZodVoid2, ZodArray2, ZodObject2, ZodUnion2, getDiscriminator2, ZodDiscriminatedUnion2, ZodIntersection2, ZodTuple2, ZodRecord2, ZodMap2, ZodSet2, ZodFunction2, ZodLazy2, ZodLiteral2, ZodEnum2, ZodNativeEnum2, ZodPromise2, ZodEffects2, ZodOptional2, ZodNullable2, ZodDefault2, ZodCatch2, ZodNaN2, BRAND2, ZodBranded2, ZodPipeline2, ZodReadonly2, late2, ZodFirstPartyTypeKind2, instanceOfType2, stringType2, numberType2, nanType2, bigIntType2, booleanType2, dateType2, symbolType2, undefinedType2, nullType2, anyType2, unknownType2, neverType2, voidType2, arrayType2, objectType2, strictObjectType2, unionType2, discriminatedUnionType2, intersectionType2, tupleType2, recordType2, mapType2, setType2, functionType2, lazyType2, literalType2, enumType2, nativeEnumType2, promiseType2, effectsType2, optionalType2, nullableType2, preprocessType2, pipelineType2, ostring2, onumber2, oboolean2, coerce2, NEVER2, empty, src, _brrp__multiformats_scope_baseX, base_x_default, Encoder, Decoder, ComposedDecoder, Codec, base32, base32upper, base32pad, base32padupper, base32hex, base32hexupper, base32hexpad, base32hexpadupper, base32z, base36, base36upper, base58btc, base58flickr, encode_1, MSB, REST, MSBALL, INT, decode2, MSB$1, REST$1, N1, N2, N3, N4, N5, N6, N7, N8, N9, length, varint, _brrp_varint, varint_default, Digest, cache, CID, DAG_PB_CODE, SHA_256_CODE, cidSymbol, code, SHA256_CODE, base64, base64pad, base64url, base64urlpad, ED25519_MULTICODEC_PREFIX, PUBLIC_KEY_LENGTH, base64UrlString, sessionJwkCommonFields, okpPrivateJwkSchema, ecPrivateJwkSchema, sessionJwkSchema, policyTargetSchema, bearerKeyTargetSchema, recipientDidTargetSchema, authorizationTargetSchema, resourceSelectorSchema, targetSchema, displaySchema, contentPointerSchema, signatureSchema, unsignedShareEnvelopeSchema, shareEnvelopeSchema, recipientMatcherSchema, shareActionSchema, kvContentSourceSchema, sqlContentSourceSchema, contentSourceSchema, v2TargetSchema, shareDecryptionSchema, ownerAuthoritySchema, contentMetadataSchema, unsignedShareEnvelopeV2BaseSchema, unsignedShareEnvelopeV2Schema, shareEnvelopeV2Schema, unifiedResourceSchema, unifiedEncryptionNetworkSchema, unifiedKvCapabilitySchema, unifiedEncryptionCapabilitySchema, unifiedCapabilitySchema, unifiedContentSourceSchema, unifiedPolicyV1Schema, policyCredentialRequirementV1Schema, unifiedPolicyV2Schema, unifiedPolicySchema, unifiedRootSchema, attestedEnforcerBindingV2Schema, v3TargetSchema, unsignedShareEnvelopeV3BaseSchema, unsignedShareEnvelopeV3Schema, shareEnvelopeV3Schema, BEARER_READ_ABILITY, READ_ABILITIES, ED25519_VERIFY_OPTS, ENVELOPE_AAD_LABEL, SEALED_BLOB_VERSION, AAD, KEY_LENGTH, NONCE_LENGTH, TAG_LENGTH, HEADER_LENGTH, ED25519_VERIFY_OPTS2, ENVELOPE_SIGNATURE_DOMAIN, ENVELOPE_V2_SIGNATURE_DOMAIN, ENVELOPE_V3_SIGNATURE_DOMAIN, POLICY_V1_SIGNATURE_DOMAIN, POLICY_V2_SIGNATURE_DOMAIN, CONTENT_SOURCE_V1_DOMAIN, POLICY_CAPABILITY_V1_DOMAIN, NATIVE_PROJECTION_V1_DOMAIN, ATTESTED_ENFORCER_V2_DOMAIN, KEY_LENGTH2, INLINE_PREFIX, MAX_INLINE_BYTES, SHARE_RESULT_VERSION, DEFAULT_MAX_SEALED_BLOB_BYTES, DEFAULT_MAX_CONTENT_BLOB_BYTES, CONTENT_SEALED_OVERHEAD, ShareReceiveError, SHARE_CONTENT_LIMIT, SHARE_SEALED_OVERHEAD, SHARE_PUBLISH_RESULT_VERSION, DEFAULT_SHARE_LIFETIME_MS, SharePublishError, empty2, src2, _brrp__multiformats_scope_baseX2, base_x_default2, Encoder2, Decoder2, ComposedDecoder2, Codec2, base322, base32upper2, base32pad2, base32padupper2, base32hex2, base32hexupper2, base32hexpad2, base32hexpadupper2, base32z2, base362, base36upper2, base58btc2, base58flickr2, encode_12, MSB2, REST2, MSBALL2, INT2, decode6, MSB$12, REST$12, N12, N22, N32, N42, N52, N62, N72, N82, N92, length2, varint2, _brrp_varint2, varint_default2, Digest2, cache2, CID2, DAG_PB_CODE2, SHA_256_CODE2, cidSymbol2, code2, SHA256_CODE2, MAX_CONTENT_BYTES, POLICY_ENFORCEMENT_DOMAIN, POLICY_DOMAIN, OWNER_SHARE_REGISTRATION_DOMAIN, ENVELOPE_DOMAIN, ENVELOPE_DOMAIN2, ShareNotifyError, SHARE_V2_PROTOCOL, DOMAIN, PRESENTATION_DOMAIN, SESSION_DOMAIN, INVOCATION_DOMAIN, BASE64_ALPHABET, POLICY_SESSION_FACT_KEYS, POLICY_SESSION_V4_AUDIT_FACT_KEYS, POLICY_SESSION_DIGEST_FACT_KEYS, LOWER_SHA256_HEX, ShareRecipientClient;
20359
20395
  var init_dist3 = __esm({
20360
20396
  "../share-sdk/dist/index.js"() {
20361
20397
  "use strict";
@@ -25518,11 +25554,61 @@ var init_dist3 = __esm({
25518
25554
  SESSION_DOMAIN = SHARE_V2_PROTOCOL.sessionDomain;
25519
25555
  INVOCATION_DOMAIN = SHARE_V2_PROTOCOL.invocationDomain;
25520
25556
  BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
25557
+ POLICY_SESSION_FACT_KEYS = [
25558
+ "profile",
25559
+ "ownerDid",
25560
+ "policyId",
25561
+ "policyDigestHex",
25562
+ "policyCid",
25563
+ "policyDelegationCid",
25564
+ "enforcementDelegationCid",
25565
+ "contentSourceDigestHex",
25566
+ "capabilityCeilingHashHex",
25567
+ "nativeProjectionHashHex",
25568
+ "enforcerDid",
25569
+ "nodeAudience",
25570
+ "recipientDid",
25571
+ "challengeId",
25572
+ "claimDigestHex",
25573
+ "claimJti",
25574
+ "vpDigestHex",
25575
+ "credentialEvidenceDigestHex",
25576
+ "decisionContextDigestHex",
25577
+ "issuanceAuditDigestHex",
25578
+ "remainingRedelegationDepth"
25579
+ ];
25580
+ POLICY_SESSION_V4_AUDIT_FACT_KEYS = ["credentialIdAuditDigestHex", "presentationJtiAuditDigestHex"];
25581
+ POLICY_SESSION_DIGEST_FACT_KEYS = [
25582
+ "policyDigestHex",
25583
+ "contentSourceDigestHex",
25584
+ "capabilityCeilingHashHex",
25585
+ "nativeProjectionHashHex",
25586
+ "claimDigestHex",
25587
+ "vpDigestHex",
25588
+ "credentialEvidenceDigestHex",
25589
+ "decisionContextDigestHex",
25590
+ "issuanceAuditDigestHex"
25591
+ ];
25592
+ LOWER_SHA256_HEX = /^[0-9a-f]{64}$/;
25521
25593
  ShareRecipientClient = class {
25522
25594
  constructor(options) {
25523
25595
  this.options = options;
25524
25596
  this.fetchFn = options.fetchFn ?? globalThis.fetch.bind(globalThis);
25525
25597
  this.signer = options.sign;
25598
+ if (options.policyAuthorization !== void 0) {
25599
+ if (options.envelope.version !== 3) throw new Error("policy delegation fast path requires a v3 envelope");
25600
+ const compact = verifyV3PolicyAuthorization({ ...options.policyAuthorization, envelope: options.envelope, holderDid: options.holderDid });
25601
+ const nodeAudience = compact.payload.fct[0].nodeAudience;
25602
+ this.v3Authorization = options.policyAuthorization.authorization;
25603
+ this.v3NodeAudience = nodeAudience;
25604
+ this.nativeSigner = options.sign;
25605
+ this.session = {
25606
+ sessionId: options.policyAuthorization.cid,
25607
+ expiresAt: new Date(compact.payload.exp * 1e3).toISOString(),
25608
+ actions: options.envelope.actions,
25609
+ resource: options.envelope.resource
25610
+ };
25611
+ }
25526
25612
  }
25527
25613
  fetchFn;
25528
25614
  session;
@@ -25530,6 +25616,7 @@ var init_dist3 = __esm({
25530
25616
  nativeSigner;
25531
25617
  holderProof;
25532
25618
  v3Authorization;
25619
+ v3NodeAudience;
25533
25620
  v3ContentKey;
25534
25621
  v3ContentEnvelope;
25535
25622
  async beginChallenge(envelope) {
@@ -25619,37 +25706,52 @@ var init_dist3 = __esm({
25619
25706
  }
25620
25707
  async establishV3(envelope) {
25621
25708
  if (this.options.buildPresentation === void 0) throw new Error("share presentation builder is required");
25709
+ const attestedEnforcer = object2(envelope.attestedEnforcerBinding, "v3 attested enforcer binding");
25710
+ if (attestedEnforcer.enforcerDid !== envelope.target.nodeAudience || typeof attestedEnforcer.nodeAudience !== "string") throw new Error("v3 attested enforcer binding mismatch");
25711
+ try {
25712
+ ed25519PublicKeyFromDidKey(attestedEnforcer.nodeAudience);
25713
+ } catch {
25714
+ throw new Error("v3 attested Node audience is invalid");
25715
+ }
25622
25716
  const challengeResponse = await this.fetchFn(new URL("/share/v3/policy/challenges", this.options.nodeOrigin), {
25623
25717
  method: "POST",
25624
25718
  redirect: "error",
25625
25719
  headers: { accept: "application/json", "content-type": "application/json" },
25626
- body: JSON.stringify({ policyCid: envelope.policyCid, recipientDid: this.options.holderDid, requestedCapabilities: envelope.policy.capabilityCeiling })
25720
+ body: JSON.stringify({ policyCid: envelope.policyCid, recipientDid: this.options.holderDid, requestedCapabilities: envelope.policy.capabilityCeiling }),
25721
+ ...this.options.signal === void 0 ? {} : { signal: this.options.signal }
25627
25722
  });
25628
25723
  if (!challengeResponse.ok) throw new Error(`v3 policy challenge rejected (${challengeResponse.status})`);
25629
25724
  const challenge2 = object2(await challengeResponse.json(), "v3 policy challenge");
25630
- if (typeof challenge2.challengeId !== "string" || typeof challenge2.nonce !== "string" || challenge2.policyCid !== envelope.policyCid || challenge2.recipientDid !== this.options.holderDid) throw new Error("v3 policy challenge binding mismatch");
25725
+ if (typeof challenge2.challengeId !== "string" || typeof challenge2.nonce !== "string" || challenge2.policyCid !== envelope.policyCid || challenge2.recipientDid !== this.options.holderDid || challenge2.nodeAudience !== attestedEnforcer.nodeAudience || challenge2.enforcerDid !== void 0 && challenge2.enforcerDid !== attestedEnforcer.enforcerDid || typeof challenge2.expiresAt !== "string" || !Number.isFinite(Date.parse(challenge2.expiresAt)) || Date.parse(challenge2.expiresAt) <= Date.now()) throw new Error("v3 policy challenge binding mismatch");
25631
25726
  const material = await this.options.buildPresentation({
25632
25727
  challenge: challenge2,
25633
25728
  envelope,
25634
25729
  policy: envelope.policy
25635
25730
  });
25636
- if (material.sign === void 0 || material.claim === void 0 || material.presentation === void 0) throw new Error("v3 ceremony requires a recipient signer, claim, and presentation");
25731
+ if (material.sign === void 0 || material.presentation === void 0) throw new Error("v3 ceremony requires a recipient signer and presentation");
25732
+ const accountless = material.presentation.schema === "xyz.tinycloud.policy/presentation/v4";
25733
+ if (accountless ? material.credentialEnvelope === void 0 || material.requirement === void 0 : material.claim === void 0) {
25734
+ throw new Error(accountless ? "v4 ceremony requires a verified credential and requirement" : "v3 ceremony requires a claim");
25735
+ }
25736
+ this.options.onStage?.("policy-admission");
25637
25737
  const delegationResponse = await this.fetchFn(new URL("/share/v3/policy/delegations", this.options.nodeOrigin), {
25638
25738
  method: "POST",
25639
25739
  redirect: "error",
25640
25740
  headers: { accept: "application/json", "content-type": "application/json" },
25641
- body: JSON.stringify({ policyCid: envelope.policyCid, challengeId: challenge2.challengeId, nonce: challenge2.nonce, claim: material.claim, presentation: material.presentation })
25741
+ body: JSON.stringify(accountless ? { policyCid: envelope.policyCid, challengeId: challenge2.challengeId, nonce: challenge2.nonce, requirement: material.requirement, credential: material.credentialEnvelope, presentation: material.presentation } : { policyCid: envelope.policyCid, challengeId: challenge2.challengeId, nonce: challenge2.nonce, claim: material.claim, presentation: material.presentation }),
25742
+ ...this.options.signal === void 0 ? {} : { signal: this.options.signal }
25642
25743
  });
25643
25744
  if (!delegationResponse.ok) throw new Error(`v3 policy delegation rejected (${delegationResponse.status})`);
25644
25745
  const delegation = object2(await delegationResponse.json(), "v3 policy delegation");
25645
25746
  if (delegation.admitted !== true || typeof delegation.sessionCid !== "string" || typeof delegation.authorization !== "string") throw new Error("v3 policy delegation response is not admitted");
25646
- const compact = verifyCompactUcanAuthorization(delegation.authorization, delegation.sessionCid);
25747
+ const compact = verifyV3PolicyAuthorization({ authorization: delegation.authorization, cid: delegation.sessionCid, envelope, holderDid: this.options.holderDid });
25647
25748
  const fact = compact.payload.fct[0];
25648
- if (compact.payload.aud !== this.options.holderDid || fact.profile !== "policy-session-ucan/v1" || fact.policyCid !== envelope.policyCid || fact.recipientDid !== this.options.holderDid || fact.policyDelegationCid !== envelope.policyRoot.cid || fact.enforcementDelegationCid !== envelope.enforcementRoot.cid || compact.payload.prf.length !== 2 || compact.payload.prf[0] !== envelope.policyRoot.cid || compact.payload.prf[1] !== envelope.enforcementRoot.cid || compact.payload.exp - compact.payload.nbf > 60) throw new Error("v3 policy delegation signed binding mismatch");
25649
- const imported = await this.fetchFn(new URL("/delegate", this.options.nodeOrigin), { method: "POST", redirect: "error", headers: { Authorization: delegation.authorization } });
25749
+ this.options.onStage?.("delegation-import");
25750
+ const imported = await this.fetchFn(new URL("/delegate", this.options.nodeOrigin), { method: "POST", redirect: "error", headers: { Authorization: delegation.authorization }, ...this.options.signal === void 0 ? {} : { signal: this.options.signal } });
25650
25751
  if (!imported.ok) throw new Error(`ordinary delegation import rejected (${imported.status})`);
25651
25752
  this.signer = material.sign;
25652
25753
  this.v3Authorization = delegation.authorization;
25754
+ this.v3NodeAudience = fact.nodeAudience;
25653
25755
  this.session = { sessionId: delegation.sessionCid, expiresAt: new Date(compact.payload.exp * 1e3).toISOString(), actions: envelope.actions, resource: envelope.resource };
25654
25756
  return this.session;
25655
25757
  }
@@ -25657,18 +25759,18 @@ var init_dist3 = __esm({
25657
25759
  async decryptV3Content(bytes3) {
25658
25760
  const envelope = this.options.envelope;
25659
25761
  const signer = this.nativeSigner ?? this.signer;
25660
- if (envelope.version !== 3 || this.session === void 0 || this.v3Authorization === void 0 || signer === void 0) throw new Error("v3 policy session signer is required");
25762
+ if (envelope.version !== 3 || this.session === void 0 || this.v3Authorization === void 0 || this.v3NodeAudience === void 0 || signer === void 0) throw new Error("v3 policy session signer is required");
25661
25763
  const encrypted = parseV3InlineEncryptedEnvelope(bytes3, envelope);
25662
25764
  const receiverPrivateKey = crypto.getRandomValues(new Uint8Array(32));
25663
- const receiverPublicKey = toBase64Url(x25519.getPublicKey(receiverPrivateKey));
25765
+ const receiverPublicKey = toBase64(x25519.getPublicKey(receiverPrivateKey));
25664
25766
  const receiverPublicKeyHash = canonicalHashHex2(receiverPublicKey);
25665
- const body = { type: "tinycloud.encryption.decrypt/v1", targetNode: envelope.target.nodeAudience, networkId: encrypted.networkId, alg: encrypted.alg, keyVersion: encrypted.keyVersion, encryptedSymmetricKey: encrypted.encryptedSymmetricKey, encryptedSymmetricKeyHash: encrypted.encryptedSymmetricKeyHash, receiverPublicKey, receiverPublicKeyHash };
25767
+ const body = { type: "tinycloud.encryption.decrypt/v1", targetNode: this.v3NodeAudience, networkId: encrypted.networkId, alg: encrypted.alg, keyVersion: encrypted.keyVersion, encryptedSymmetricKey: encrypted.encryptedSymmetricKey, encryptedSymmetricKeyHash: encrypted.encryptedSymmetricKeyHash, receiverPublicKey, receiverPublicKeyHash };
25666
25768
  const bodyHash = hex2(sha2562(new TextEncoder().encode(canonicalize2(body))));
25667
25769
  const session = verifyCompactUcanAuthorization(this.v3Authorization, this.session.sessionId);
25668
25770
  const now = Math.floor(Date.now() / 1e3);
25669
25771
  const invocation = await signCompactUcanAuthorization({
25670
25772
  issuerDid: this.options.holderDid,
25671
- audienceDid: envelope.target.nodeAudience,
25773
+ audienceDid: this.v3NodeAudience,
25672
25774
  attenuation: { [encrypted.networkId]: { "tinycloud.encryption/decrypt": [{}] } },
25673
25775
  facts: [{ type: body.type, targetNode: body.targetNode, networkId: body.networkId, bodyHash, encryptedSymmetricKeyHash: body.encryptedSymmetricKeyHash, receiverPublicKeyHash, alg: body.alg, keyVersion: body.keyVersion }],
25674
25776
  proofs: [session.cid],
@@ -25678,7 +25780,8 @@ var init_dist3 = __esm({
25678
25780
  sign: signer
25679
25781
  });
25680
25782
  try {
25681
- const response = await this.fetchFn(new URL("/invoke", this.options.nodeOrigin), { method: "POST", redirect: "error", headers: { accept: "application/json", "content-type": "application/json", Authorization: invocation.authorization }, body: JSON.stringify(body) });
25783
+ this.options.onStage?.("decryption");
25784
+ const response = await this.fetchFn(new URL("/invoke", this.options.nodeOrigin), { method: "POST", redirect: "error", headers: { accept: "application/json", "content-type": "application/json", Authorization: invocation.authorization }, body: JSON.stringify(body), ...this.options.signal === void 0 ? {} : { signal: this.options.signal } });
25682
25785
  if (!response.ok) throw new Error(`v3 decrypt invocation rejected (${response.status})`);
25683
25786
  const value = object2(await response.json(), "v3 decrypt response");
25684
25787
  const allowed = ["type", "targetNode", "networkId", "invocationCid", "encryptedSymmetricKeyHash", "receiverPublicKeyHash", "wrappedKey", "alg", "keyVersion", "requestHash", "nodeId", "nodeSignature"];
@@ -25688,12 +25791,12 @@ var init_dist3 = __esm({
25688
25791
  const signature = fromBase64(value.nodeSignature, "v3 decrypt response signature");
25689
25792
  if (signature.length !== 64 || !ed25519.verify(signature, new TextEncoder().encode(canonicalize2(unsigned)), ed25519PublicKeyFromDidKey(body.targetNode), { zip215: false })) throw new Error("v3 decrypt response signature is invalid");
25690
25793
  const wrapped = fromBase64(value.wrappedKey, "v3 wrapped content key");
25691
- if (wrapped.length < 60) throw new Error("v3 wrapped content key is malformed");
25794
+ if (wrapped.length < 61 || wrapped[32] !== 1) throw new Error("v3 wrapped content key is malformed");
25692
25795
  const shared = x25519.getSharedSecret(receiverPrivateKey, wrapped.slice(0, 32));
25693
- const symmetricKey = await aesGcmDecrypt(shared, wrapped.slice(32));
25796
+ const symmetricKey = await aesGcmDecrypt(shared, wrapped.slice(33));
25694
25797
  shared.fill(0);
25695
25798
  if (symmetricKey.length !== 32) throw new Error("v3 content key is malformed");
25696
- const plaintext = await aesGcmDecrypt(symmetricKey, fromBase64Url(encrypted.ciphertext));
25799
+ const plaintext = await aesGcmDecrypt(symmetricKey, fromBase64(encrypted.ciphertext, "v3 encrypted content"));
25697
25800
  this.v3ContentKey?.fill(0);
25698
25801
  this.v3ContentKey = symmetricKey;
25699
25802
  this.v3ContentEnvelope = encrypted;
@@ -25752,7 +25855,7 @@ var init_dist3 = __esm({
25752
25855
  }
25753
25856
  async nativeInvokeV3(request, envelope) {
25754
25857
  const signer = this.nativeSigner ?? this.signer;
25755
- if (this.session === void 0 || this.v3Authorization === void 0 || signer === void 0) throw new Error("v3 policy session signer is required");
25858
+ if (this.session === void 0 || this.v3Authorization === void 0 || this.v3NodeAudience === void 0 || signer === void 0) throw new Error("v3 policy session signer is required");
25756
25859
  const session = verifyCompactUcanAuthorization(this.v3Authorization, this.session.sessionId);
25757
25860
  if (session.payload.aud !== this.options.holderDid) throw new Error("v3 session recipient mismatch");
25758
25861
  const action = request.action === "list" ? "tinycloud.kv/list" : request.action === "put" ? "tinycloud.kv/put" : request.action === "metadata" ? "tinycloud.kv/metadata" : "tinycloud.kv/get";
@@ -25766,7 +25869,7 @@ var init_dist3 = __esm({
25766
25869
  if (path !== root && !(capability.selector === "prefix" && path.startsWith(`${root}/`))) throw new Error("v3 KV request is outside the signed selector");
25767
25870
  const resource = `${capability.resource.slice(0, split2 + marker.length)}${path}`;
25768
25871
  const now = Math.floor(Date.now() / 1e3);
25769
- const invocation = await signCompactUcanAuthorization({ issuerDid: this.options.holderDid, audienceDid: envelope.target.nodeAudience, attenuation: { [resource]: { [action]: [{ type: "xyz.tinycloud.resource/selector", kind: capability.selector, value: resource }] } }, facts: [{ type: "tinycloud.policy.invocation/v1", policyCid: envelope.policyCid, sessionCid: session.cid }], proofs: [session.cid], notBefore: now, expiresAt: Math.min(now + 60, session.payload.exp), nonce: toBase64Url(crypto.getRandomValues(new Uint8Array(16))), sign: signer });
25872
+ const invocation = await signCompactUcanAuthorization({ issuerDid: this.options.holderDid, audienceDid: this.v3NodeAudience, attenuation: { [resource]: { [action]: [{ type: "xyz.tinycloud.resource/selector", kind: capability.selector, value: resource }] } }, facts: [{ type: "tinycloud.policy.invocation/v1", policyCid: envelope.policyCid, sessionCid: session.cid }], proofs: [session.cid], notBefore: now, expiresAt: Math.min(now + 60, session.payload.exp), nonce: toBase64Url(crypto.getRandomValues(new Uint8Array(16))), sign: signer });
25770
25873
  const headers = new Headers({ accept: "application/json", Authorization: invocation.authorization });
25771
25874
  let body;
25772
25875
  if (action === "tinycloud.kv/put") {
@@ -25775,7 +25878,8 @@ var init_dist3 = __esm({
25775
25878
  headers.set("content-type", request.contentType ?? "application/octet-stream");
25776
25879
  if (request.ifMatch !== void 0) headers.set("if-match", request.ifMatch);
25777
25880
  }
25778
- return this.fetchFn(new URL("/invoke", this.options.nodeOrigin), { method: "POST", redirect: "error", headers, ...body === void 0 ? {} : { body } });
25881
+ this.options.onStage?.("invocation");
25882
+ return this.fetchFn(new URL("/invoke", this.options.nodeOrigin), { method: "POST", redirect: "error", headers, ...body === void 0 ? {} : { body }, ...this.options.signal === void 0 ? {} : { signal: this.options.signal } });
25779
25883
  }
25780
25884
  };
25781
25885
  }
@@ -32445,7 +32549,7 @@ function validateV3Invariants2(value, ctx) {
32445
32549
  if (value.contentSource.encryptionNetwork !== value.encryptionNetwork) {
32446
32550
  ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["encryptionNetwork"], message: "encryption network is not bound to the source" });
32447
32551
  }
32448
- if (value.attestedEnforcerBinding.enforcerDid !== value.target.nodeAudience || value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.target.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
32552
+ if (value.attestedEnforcerBinding.enforcerDid !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
32449
32553
  ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
32450
32554
  }
32451
32555
  if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {