@tinycloud/share-sdk 0.3.0-beta.1 → 0.3.0-beta.2

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
@@ -4531,25 +4531,25 @@ function encodeTo(int, target, offset = 0) {
4531
4531
  function encodingLength(int) {
4532
4532
  return varint_default.encodingLength(int);
4533
4533
  }
4534
- function create(code22, digest4) {
4535
- const size = digest4.byteLength;
4534
+ function create(code22, digest3) {
4535
+ const size = digest3.byteLength;
4536
4536
  const sizeOffset = encodingLength(code22);
4537
4537
  const digestOffset = sizeOffset + encodingLength(size);
4538
4538
  const bytes3 = new Uint8Array(digestOffset + size);
4539
4539
  encodeTo(code22, bytes3, 0);
4540
4540
  encodeTo(size, bytes3, sizeOffset);
4541
- bytes3.set(digest4, digestOffset);
4542
- return new Digest(code22, size, digest4, bytes3);
4541
+ bytes3.set(digest3, digestOffset);
4542
+ return new Digest(code22, size, digest3, bytes3);
4543
4543
  }
4544
4544
  function decode4(multihash) {
4545
4545
  const bytes3 = coerce2(multihash);
4546
4546
  const [code22, sizeOffset] = decode3(bytes3);
4547
4547
  const [size, digestOffset] = decode3(bytes3.subarray(sizeOffset));
4548
- const digest4 = bytes3.subarray(sizeOffset + digestOffset);
4549
- if (digest4.byteLength !== size) {
4548
+ const digest3 = bytes3.subarray(sizeOffset + digestOffset);
4549
+ if (digest3.byteLength !== size) {
4550
4550
  throw new Error("Incorrect length");
4551
4551
  }
4552
- return new Digest(code22, size, digest4, bytes3);
4552
+ return new Digest(code22, size, digest3, bytes3);
4553
4553
  }
4554
4554
  function equals2(a, b) {
4555
4555
  if (a === b) {
@@ -4567,10 +4567,10 @@ var Digest = class {
4567
4567
  /**
4568
4568
  * Creates a multihash digest.
4569
4569
  */
4570
- constructor(code22, size, digest4, bytes3) {
4570
+ constructor(code22, size, digest3, bytes3) {
4571
4571
  this.code = code22;
4572
4572
  this.size = size;
4573
- this.digest = digest4;
4573
+ this.digest = digest3;
4574
4574
  this.bytes = bytes3;
4575
4575
  }
4576
4576
  };
@@ -4651,8 +4651,8 @@ var CID = class _CID {
4651
4651
  toV1() {
4652
4652
  switch (this.version) {
4653
4653
  case 0: {
4654
- const { code: code22, digest: digest4 } = this.multihash;
4655
- const multihash = create(code22, digest4);
4654
+ const { code: code22, digest: digest3 } = this.multihash;
4655
+ const multihash = create(code22, digest3);
4656
4656
  return _CID.createV1(this.code, multihash);
4657
4657
  }
4658
4658
  case 1: {
@@ -4706,8 +4706,8 @@ var CID = class _CID {
4706
4706
  return new _CID(version, code22, multihash, bytes3 ?? encodeCID(version, code22, multihash.bytes));
4707
4707
  } else if (value[cidSymbol] === true) {
4708
4708
  const { version, multihash, code: code22 } = value;
4709
- const digest4 = decode4(multihash);
4710
- return _CID.create(version, code22, digest4);
4709
+ const digest3 = decode4(multihash);
4710
+ return _CID.create(version, code22, digest3);
4711
4711
  } else {
4712
4712
  return null;
4713
4713
  }
@@ -4717,11 +4717,11 @@ var CID = class _CID {
4717
4717
  * @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
4718
4718
  * @param digest - (Multi)hash of the of the content.
4719
4719
  */
4720
- static create(version, code22, digest4) {
4720
+ static create(version, code22, digest3) {
4721
4721
  if (typeof code22 !== "number") {
4722
4722
  throw new Error("String codecs are no longer supported");
4723
4723
  }
4724
- if (!(digest4.bytes instanceof Uint8Array)) {
4724
+ if (!(digest3.bytes instanceof Uint8Array)) {
4725
4725
  throw new Error("Invalid digest");
4726
4726
  }
4727
4727
  switch (version) {
@@ -4729,12 +4729,12 @@ var CID = class _CID {
4729
4729
  if (code22 !== DAG_PB_CODE) {
4730
4730
  throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE}) block encoding`);
4731
4731
  } else {
4732
- return new _CID(version, code22, digest4, digest4.bytes);
4732
+ return new _CID(version, code22, digest3, digest3.bytes);
4733
4733
  }
4734
4734
  }
4735
4735
  case 1: {
4736
- const bytes3 = encodeCID(version, code22, digest4.bytes);
4737
- return new _CID(version, code22, digest4, bytes3);
4736
+ const bytes3 = encodeCID(version, code22, digest3.bytes);
4737
+ return new _CID(version, code22, digest3, bytes3);
4738
4738
  }
4739
4739
  default: {
4740
4740
  throw new Error("Invalid version");
@@ -4744,8 +4744,8 @@ var CID = class _CID {
4744
4744
  /**
4745
4745
  * Simplified version of `create` for CIDv0.
4746
4746
  */
4747
- static createV0(digest4) {
4748
- return _CID.create(0, DAG_PB_CODE, digest4);
4747
+ static createV0(digest3) {
4748
+ return _CID.create(0, DAG_PB_CODE, digest3);
4749
4749
  }
4750
4750
  /**
4751
4751
  * Simplified version of `create` for CIDv1.
@@ -4753,8 +4753,8 @@ var CID = class _CID {
4753
4753
  * @param code - Content encoding format code.
4754
4754
  * @param digest - Multihash of the content.
4755
4755
  */
4756
- static createV1(code22, digest4) {
4757
- return _CID.create(1, code22, digest4);
4756
+ static createV1(code22, digest3) {
4757
+ return _CID.create(1, code22, digest3);
4758
4758
  }
4759
4759
  /**
4760
4760
  * Decoded a CID from its binary representation. The byte array must contain
@@ -4787,8 +4787,8 @@ var CID = class _CID {
4787
4787
  throw new Error("Incorrect length");
4788
4788
  }
4789
4789
  const digestBytes3 = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
4790
- const digest4 = new Digest(specs.multihashCode, specs.digestSize, digestBytes3, multihashBytes);
4791
- const cid2 = specs.version === 0 ? _CID.createV0(digest4) : _CID.createV1(specs.codec, digest4);
4790
+ const digest3 = new Digest(specs.multihashCode, specs.digestSize, digestBytes3, multihashBytes);
4791
+ const cid2 = specs.version === 0 ? _CID.createV0(digest3) : _CID.createV1(specs.codec, digest3);
4792
4792
  return [cid2, bytes3.subarray(specs.size)];
4793
4793
  }
4794
4794
  /**
@@ -4911,8 +4911,8 @@ var cidSymbol = /* @__PURE__ */ Symbol.for("@ipld/js-cid/CID");
4911
4911
  var code = 85;
4912
4912
  var SHA256_CODE = 18;
4913
4913
  async function computeCid(bytes3) {
4914
- const digest4 = create(SHA256_CODE, sha256(new Uint8Array(bytes3)));
4915
- return CID.create(1, code, digest4).toString();
4914
+ const digest3 = create(SHA256_CODE, sha256(new Uint8Array(bytes3)));
4915
+ return CID.create(1, code, digest3).toString();
4916
4916
  }
4917
4917
  function isCanonicalRawCid(cidString) {
4918
4918
  let cid2;
@@ -5896,8 +5896,8 @@ async function verifyEnvelopeV3(envelope, options) {
5896
5896
  if (hex(sourceDigest) !== parsed.contentSourceDigestHex) return false;
5897
5897
  const sortedCapabilities = [...policy.capabilityCeiling].sort((left, right) => canonicalize(left).localeCompare(canonicalize(right)));
5898
5898
  const capabilityCeilingHashHex = hex(sha2562(new TextEncoder().encode(`${POLICY_CAPABILITY_V1_DOMAIN}${canonicalize(sortedCapabilities)}`)));
5899
- const nativeProjection = sortedCapabilities.map((capability) => capability.kind === "encryption" ? { service: "tinycloud.encryption", space: capability.resource, path: capability.resource, actions: [capability.action] } : { service: "tinycloud.kv", space: capability.resource.slice(0, capability.resource.indexOf("/kv/")), path: capability.resource.split("/kv/")[1], actions: [...capability.actions], caveat: { type: "xyz.tinycloud.resource/selector", kind: capability.selector, value: capability.resource } }).sort((left, right) => canonicalize(left).localeCompare(canonicalize(right)));
5900
- const nativeProjectionHashHex = hex(sha2562(new TextEncoder().encode(`${NATIVE_PROJECTION_V1_DOMAIN}${canonicalize(nativeProjection)}`)));
5899
+ const nativeProjection2 = sortedCapabilities.map((capability) => capability.kind === "encryption" ? { service: "tinycloud.encryption", space: capability.resource, path: capability.resource, actions: [capability.action] } : { service: "tinycloud.kv", space: capability.resource.slice(0, capability.resource.indexOf("/kv/")), path: capability.resource.split("/kv/")[1], actions: [...capability.actions], caveat: { type: "xyz.tinycloud.resource/selector", kind: capability.selector, value: capability.resource } }).sort((left, right) => canonicalize(left).localeCompare(canonicalize(right)));
5900
+ const nativeProjectionHashHex = hex(sha2562(new TextEncoder().encode(`${NATIVE_PROJECTION_V1_DOMAIN}${canonicalize(nativeProjection2)}`)));
5901
5901
  const expectedAttenuation = Object.fromEntries(sortedCapabilities.map((capability) => capability.kind === "encryption" ? [capability.resource, { [capability.action]: [{}] }] : [capability.resource, Object.fromEntries(capability.actions.map((action) => [action, [{ kind: capability.selector, type: "xyz.tinycloud.resource/selector", value: capability.resource }]]))]));
5902
5902
  const kv = policy.capabilityCeiling.find((capability) => capability.kind === "kv");
5903
5903
  const expectedKvActions = parsed.actions.flatMap((action) => action === "read" ? ["tinycloud.kv/get", "tinycloud.kv/metadata"] : action === "list" ? ["tinycloud.kv/list"] : ["tinycloud.kv/put"]);
@@ -5910,8 +5910,8 @@ async function verifyEnvelopeV3(envelope, options) {
5910
5910
  const expectedBindingDigestHex = hex(sha2562(new TextEncoder().encode(canonicalize({ enforcerDid: binding.enforcerDid, nodeAudience: binding.nodeAudience }))));
5911
5911
  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;
5912
5912
  try {
5913
- const digest4 = sha2562(new TextEncoder().encode(`${ATTESTED_ENFORCER_V2_DOMAIN}${canonicalize(unsignedBinding)}`));
5914
- if (!ed255193.verify(fromBase64Url(bindingSignature.value), digest4, ed25519PublicKeyFromDidKey(binding.nodeAudience), ED25519_VERIFY_OPTS2)) return false;
5913
+ const digest3 = sha2562(new TextEncoder().encode(`${ATTESTED_ENFORCER_V2_DOMAIN}${canonicalize(unsignedBinding)}`));
5914
+ if (!ed255193.verify(fromBase64Url(bindingSignature.value), digest3, ed25519PublicKeyFromDidKey(binding.nodeAudience), ED25519_VERIFY_OPTS2)) return false;
5915
5915
  } catch {
5916
5916
  return false;
5917
5917
  }
@@ -6694,10 +6694,31 @@ async function parseAddressedEnvelope(value) {
6694
6694
  return { envelope, policy: decoded, policyCid: envelope.authorizationTarget.policyCid };
6695
6695
  }
6696
6696
 
6697
- // src/owner-policy.ts
6698
- import { ed25519 as ed255195 } from "@noble/curves/ed25519";
6697
+ // src/addressed-publish.ts
6699
6698
  import { sha256 as sha2563 } from "@noble/hashes/sha256";
6700
6699
 
6700
+ // src/authorization.ts
6701
+ async function authorizeShare(input) {
6702
+ if (input.resumeToken !== void 0) {
6703
+ if (input.resumeToken.length < 16 || input.resumeToken.length > 512) {
6704
+ return { state: "denied", reason: "rejected" };
6705
+ }
6706
+ return input.adapter.resume({
6707
+ envelope: input.envelope,
6708
+ method: input.method,
6709
+ resumeToken: input.resumeToken,
6710
+ ...input.proof === void 0 ? {} : { proof: input.proof }
6711
+ });
6712
+ }
6713
+ return input.adapter.begin({ envelope: input.envelope, method: input.method });
6714
+ }
6715
+ function authorizationMethodForTarget(target) {
6716
+ if (target.kind === "recipientDid") return "openkey-device";
6717
+ if (target.kind === "email") return "email-claim";
6718
+ if (target.kind === "emailDomain") return "email-claim";
6719
+ return void 0;
6720
+ }
6721
+
6701
6722
  // ../../node_modules/multiformats/dist/src/bytes.js
6702
6723
  var empty2 = new Uint8Array(0);
6703
6724
  function equals3(aa, bb) {
@@ -7039,6 +7060,347 @@ function rfc46482({ name, prefix, bitsPerChar, alphabet }) {
7039
7060
  });
7040
7061
  }
7041
7062
 
7063
+ // ../../node_modules/multiformats/dist/src/bases/base58.js
7064
+ var base58btc2 = baseX2({
7065
+ name: "base58btc",
7066
+ prefix: "z",
7067
+ alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
7068
+ });
7069
+ var base58flickr2 = baseX2({
7070
+ name: "base58flickr",
7071
+ prefix: "Z",
7072
+ alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
7073
+ });
7074
+
7075
+ // src/targets.ts
7076
+ function validEmail(value) {
7077
+ return /^[^@\s]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i.test(value);
7078
+ }
7079
+ function validDomain(value) {
7080
+ return /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))+$/i.test(value);
7081
+ }
7082
+ function validRecipientDid(value) {
7083
+ if (value.length === 0 || value.length > 2048 || /[\u0000-\u0020\u007f]/.test(value)) return false;
7084
+ const parts = value.split(":");
7085
+ if (parts.length < 3 || parts[0] !== "did" || !/^[a-z0-9]+$/.test(parts[1] ?? "")) return false;
7086
+ const identifier = parts.slice(2);
7087
+ if (identifier.some((part) => part.length === 0)) return false;
7088
+ if (parts[1] === "web") {
7089
+ const host = identifier[0] ?? "";
7090
+ if (host.length > 253 || host.split(".").some((label) => !label || label.length > 63 || !/^[A-Za-z0-9-]+$/.test(label) || label.startsWith("-") || label.endsWith("-"))) return false;
7091
+ return identifier.slice(1).every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
7092
+ }
7093
+ if (parts[1] === "pkh") return identifier.length >= 3 && identifier.every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
7094
+ if (parts[1] === "key") {
7095
+ try {
7096
+ const bytes3 = base58btc2.decode(identifier.join(":"));
7097
+ return bytes3.length === 34 && bytes3[0] === 237 && bytes3[1] === 1;
7098
+ } catch {
7099
+ return false;
7100
+ }
7101
+ }
7102
+ return false;
7103
+ }
7104
+ function normalizeShareTarget(target) {
7105
+ if (target.kind === "bearer") return target;
7106
+ if (target.kind === "recipientDid") {
7107
+ if (!validRecipientDid(target.did)) throw new TypeError("recipient DID is invalid");
7108
+ return { kind: target.kind, did: target.did };
7109
+ }
7110
+ if (target.kind === "email") {
7111
+ if (!validEmail(target.address)) throw new TypeError("recipient email is invalid");
7112
+ const at = target.address.lastIndexOf("@");
7113
+ return { kind: target.kind, address: `${target.address.slice(0, at)}@${target.address.slice(at + 1).toLowerCase()}` };
7114
+ }
7115
+ if (!validDomain(target.domain)) throw new TypeError("recipient email domain is invalid");
7116
+ return { kind: target.kind, domain: target.domain.toLowerCase() };
7117
+ }
7118
+ function targetAuthorizationMethod(target) {
7119
+ return authorizationMethodForTarget(target);
7120
+ }
7121
+ async function publishTargetShare(input) {
7122
+ const target = normalizeShareTarget(input.target);
7123
+ if (target.kind === "bearer") return publishShare(input);
7124
+ if (input.targetAdapter === void 0) {
7125
+ return {
7126
+ state: "authorization-required",
7127
+ method: targetAuthorizationMethod(target)
7128
+ };
7129
+ }
7130
+ const source = input.source instanceof Uint8Array ? input.source.slice() : await (async () => {
7131
+ const chunks = [];
7132
+ let size = 0;
7133
+ for await (const chunk of input.source) {
7134
+ if (!(chunk instanceof Uint8Array)) throw new TypeError("addressed publication source yielded invalid bytes");
7135
+ size += chunk.byteLength;
7136
+ if (size > (input.maxBytes ?? 100 * 1024 * 1024)) throw new TypeError("addressed publication exceeds maxBytes");
7137
+ chunks.push(chunk.slice());
7138
+ }
7139
+ const bytes3 = new Uint8Array(size);
7140
+ let offset = 0;
7141
+ for (const chunk of chunks) {
7142
+ bytes3.set(chunk, offset);
7143
+ offset += chunk.byteLength;
7144
+ }
7145
+ return bytes3;
7146
+ })();
7147
+ const files = input.files === void 0 || input.files.length === 0 ? [{ bytes: source }] : input.files;
7148
+ const limit = input.maxBytes ?? SHARE_CONTENT_LIMIT;
7149
+ let totalBytes = 0;
7150
+ for (const file of files) {
7151
+ totalBytes += file.bytes.byteLength;
7152
+ if (!Number.isSafeInteger(totalBytes) || totalBytes > limit) {
7153
+ throw new SharePublishError("max-bytes-exceeded", "addressed publication exceeds the combined byte limit");
7154
+ }
7155
+ }
7156
+ return input.targetAdapter.publish({
7157
+ source,
7158
+ filename: input.filename,
7159
+ ...input.files === void 0 ? {} : { files: input.files },
7160
+ ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
7161
+ ...input.resourceKind === void 0 ? {} : { resourceKind: input.resourceKind },
7162
+ ...input.actions === void 0 ? {} : { actions: input.actions },
7163
+ target,
7164
+ expiresAt: input.expiresAt ?? new Date((input.now?.() ?? Date.now()) + 7 * 24 * 60 * 60 * 1e3),
7165
+ origin: input.origin,
7166
+ ...input.inline === void 0 ? {} : { inline: input.inline },
7167
+ upload: {
7168
+ ...input.registryBaseUrl === void 0 ? {} : { registryBaseUrl: input.registryBaseUrl },
7169
+ ...input.fetchFn === void 0 ? {} : { fetchFn: input.fetchFn },
7170
+ ...input.authorizeUpload === void 0 ? {} : { authorizeUpload: input.authorizeUpload },
7171
+ ...input.authorizationOrigin === void 0 ? {} : { authorizationOrigin: input.authorizationOrigin },
7172
+ ...input.credentials === void 0 ? {} : { credentials: input.credentials },
7173
+ ...input.allowInsecureRegistry === void 0 ? {} : { allowInsecureRegistry: input.allowInsecureRegistry },
7174
+ ...input.uploadBlob === void 0 ? {} : { uploadBlob: input.uploadBlob }
7175
+ },
7176
+ ...input.notify === void 0 ? {} : { notify: input.notify }
7177
+ });
7178
+ }
7179
+
7180
+ // src/addressed-publish.ts
7181
+ var POLICY_V1_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
7182
+ var POLICY_V2_DOMAIN = "xyz.tinycloud.policy/policy/v2\0";
7183
+ var POLICY_CAPABILITY_V1_DOMAIN2 = "xyz.tinycloud.policy/PolicyCapability/v1\0";
7184
+ var CONTENT_SOURCE_V1_DOMAIN2 = "xyz.tinycloud.policy/ContentSource/v1\0";
7185
+ var NATIVE_PROJECTION_V1_DOMAIN2 = "xyz.tinycloud.policy/NativeProjection/v1\0";
7186
+ var ENVELOPE_V3_DOMAIN = "xyz.tinycloud.share/envelope/v3\0";
7187
+ var textEncoder = new TextEncoder();
7188
+ function targetMatcher(target) {
7189
+ if (target.kind === "recipientDid") return { kind: "recipientDid", value: target.did };
7190
+ if (target.kind === "email") return { kind: "exactEmail", value: target.address };
7191
+ return { kind: "emailDomain", value: target.domain };
7192
+ }
7193
+ function targetKind(target) {
7194
+ return target.kind;
7195
+ }
7196
+ function assertSafeInput(input) {
7197
+ if (!/^[A-Za-z0-9_-]{16,128}$/.test(input.shareId)) throw new TypeError("addressed share id is invalid");
7198
+ if (input.filename.length === 0 || input.filename === "." || input.filename === ".." || /[/\\\u0000-\u001f\u007f]/.test(input.filename)) throw new TypeError("addressed filename is invalid");
7199
+ if (!Number.isSafeInteger(input.byteLength) || input.byteLength < 0 || input.byteLength > SHARE_CONTENT_LIMIT) throw new TypeError("addressed content length is invalid");
7200
+ if (input.actions.length === 0 || input.policyActions.length === 0) throw new TypeError("addressed share actions are empty");
7201
+ if (!Number.isFinite(input.expiresAt.getTime()) || input.expiresAt.getTime() <= Date.now()) throw new TypeError("addressed share expiry must be in the future");
7202
+ if (input.artifact === "html" && (input.resource.kind !== "prefix" || !input.actions.includes("read") || !input.actions.includes("list"))) throw new TypeError("html artifacts require a readable prefix");
7203
+ if (input.contentSource.shareId !== input.shareId || input.contentSource.selector !== input.resource.kind) throw new TypeError("addressed content source is not bound to the share");
7204
+ }
7205
+ function hex2(bytes3) {
7206
+ return [...bytes3].map((byte) => byte.toString(16).padStart(2, "0")).join("");
7207
+ }
7208
+ function digestHex(value, domain) {
7209
+ return hex2(sha2563(textEncoder.encode(`${domain}${canonicalize(value)}`)));
7210
+ }
7211
+ function sortCanonical(values) {
7212
+ return [...values].sort((left, right) => canonicalize(left).localeCompare(canonicalize(right)));
7213
+ }
7214
+ function base32Lower2(bytes3) {
7215
+ const alphabet = "abcdefghijklmnopqrstuvwxyz234567";
7216
+ let output = "";
7217
+ let buffer = 0;
7218
+ let bits = 0;
7219
+ for (const byte of bytes3) {
7220
+ buffer = buffer << 8 | byte;
7221
+ bits += 8;
7222
+ while (bits >= 5) {
7223
+ output += alphabet[buffer >>> bits - 5 & 31];
7224
+ bits -= 5;
7225
+ }
7226
+ }
7227
+ if (bits > 0) output += alphabet[buffer << 5 - bits & 31];
7228
+ return output;
7229
+ }
7230
+ function rfc3339Seconds(value) {
7231
+ return new Date(Math.floor(value.getTime() / 1e3) * 1e3).toISOString().replace(".000Z", "Z");
7232
+ }
7233
+ function nativeProjection(capabilities) {
7234
+ return sortCanonical(capabilities.map((capability) => capability.kind === "encryption" ? { service: "tinycloud.encryption", space: capability.resource, path: capability.resource, actions: [capability.action] } : {
7235
+ service: "tinycloud.kv",
7236
+ space: capability.resource.slice(0, capability.resource.indexOf("/kv/")),
7237
+ path: capability.resource.slice(capability.resource.indexOf("/kv/") + 4),
7238
+ actions: [...capability.actions],
7239
+ caveat: { type: "xyz.tinycloud.resource/selector", kind: capability.selector, value: capability.resource }
7240
+ }));
7241
+ }
7242
+ async function createPolicy(options, capabilities) {
7243
+ const fields = {
7244
+ ownerDid: options.authority.ownerDid,
7245
+ createdAt: rfc3339Seconds(/* @__PURE__ */ new Date()),
7246
+ expiresAt: rfc3339Seconds(options.expiresAt),
7247
+ contentSource: options.contentSource,
7248
+ capabilityCeiling: [...capabilities]
7249
+ };
7250
+ const unsigned = options.credentialRequirement === void 0 ? { schema: "xyz.tinycloud.policy/policy/v1", ...fields } : { schema: "xyz.tinycloud.policy/policy/v2", ...fields, credentialRequirement: options.credentialRequirement };
7251
+ const domain = options.credentialRequirement === void 0 ? POLICY_V1_DOMAIN : POLICY_V2_DOMAIN;
7252
+ const policyDigestHex = digestHex(unsigned, domain);
7253
+ const signature = await options.authority.sign(sha2563(textEncoder.encode(`${domain}${canonicalize(unsigned)}`)));
7254
+ if (signature.byteLength !== 64) throw new TypeError("policy signature must be Ed25519");
7255
+ const policy = {
7256
+ ...unsigned,
7257
+ policyId: `pol_${base32Lower2(Uint8Array.from(policyDigestHex.match(/../g), (byte) => Number.parseInt(byte, 16)))}`,
7258
+ signature: { suite: "Ed25519", signerDid: options.authority.ownerDid, value: toBase64Url(signature) }
7259
+ };
7260
+ return { policy, policyCid: await computeCid(textEncoder.encode(canonicalize(policy))), policyDigestHex };
7261
+ }
7262
+ function publicationResult(input) {
7263
+ const result = {
7264
+ protocol: "tinycloud-share",
7265
+ version: SHARE_PUBLISH_RESULT_VERSION,
7266
+ url: input.url,
7267
+ link: { kind: input.options.inline === true ? "inline" : "compact", cid: input.envelopeCid },
7268
+ metadata: {
7269
+ protocol: "tinycloud-share",
7270
+ version: 1,
7271
+ shareId: input.options.shareId,
7272
+ origin: input.options.shareOrigin,
7273
+ target: { kind: targetKind(input.options.target), origin: input.options.nodeOrigin, nodeAudience: input.enforcerDid, spaceId: input.options.spaceId },
7274
+ resource: { ...input.options.resource },
7275
+ actions: [...input.options.actions],
7276
+ expiresAt: input.expiry,
7277
+ display: { filename: input.options.filename },
7278
+ recipientMatcher: { ...input.matcher },
7279
+ policyCid: input.policyCid,
7280
+ ownerDelegationCid: input.policyRootCid,
7281
+ enforcementDelegationCid: input.enforcementRootCid,
7282
+ ownerDid: input.options.authority.ownerDid,
7283
+ enforcerDid: input.enforcerDid,
7284
+ envelopeCid: input.envelopeCid,
7285
+ shareCid: input.envelopeCid
7286
+ },
7287
+ registryDeleteAfter: input.retention
7288
+ };
7289
+ Object.defineProperty(result, "toJSON", { enumerable: false, value: () => redactPublishedShare(result) });
7290
+ Object.defineProperty(result, "url", { enumerable: false, value: input.url });
7291
+ Object.defineProperty(result, "deliveryMaterial", { enumerable: false, value: input.deliveryMaterial });
7292
+ return result;
7293
+ }
7294
+ async function publishAddressedShare(options) {
7295
+ assertSafeInput(options);
7296
+ const target = normalizeShareTarget(options.target);
7297
+ if (target.kind === "bearer") throw new TypeError("addressed target is required");
7298
+ const expiry = rfc3339Seconds(options.expiresAt);
7299
+ const matcher = targetMatcher(target);
7300
+ const capabilities = sortCanonical([
7301
+ { kind: "kv", resource: options.contentSource.kvResource, selector: options.resource.kind, actions: [...options.policyActions] },
7302
+ { kind: "encryption", resource: options.contentSource.encryptionNetwork, action: "tinycloud.encryption/decrypt" }
7303
+ ]);
7304
+ const created = await createPolicy(options, capabilities);
7305
+ const contentSourceDigestHex = digestHex(options.contentSource, CONTENT_SOURCE_V1_DOMAIN2);
7306
+ const capabilityCeilingHashHex = digestHex(capabilities, POLICY_CAPABILITY_V1_DOMAIN2);
7307
+ const nativeProjectionHashHex = digestHex(nativeProjection(capabilities), NATIVE_PROJECTION_V1_DOMAIN2);
7308
+ const commonRoot = {
7309
+ ownerDid: options.authority.ownerDid,
7310
+ policyId: created.policy.policyId,
7311
+ policyDigestHex: created.policyDigestHex,
7312
+ policyCid: created.policyCid,
7313
+ contentSourceDigestHex,
7314
+ capabilityCeilingHashHex,
7315
+ nativeProjectionHashHex,
7316
+ notBefore: new Date(created.policy.createdAt),
7317
+ expiresAt: new Date(expiry),
7318
+ nodeAudience: options.nodeAudience,
7319
+ capabilities
7320
+ };
7321
+ const policyRootReceipt = await options.authority.createOwnerRoot({ ...commonRoot, role: "policy-authority", audienceDid: `did:tinycloud:policy:${created.policyDigestHex}` });
7322
+ const enforcementRootReceipt = await options.authority.createOwnerRoot({ ...commonRoot, role: "policy-enforcement", audienceDid: options.enforcerDid });
7323
+ const policyRoot = { cid: policyRootReceipt.cid, authorization: policyRootReceipt.delegationHeader.Authorization.replace(/^Bearer\s+/i, ""), role: "policy-authority" };
7324
+ const enforcementRoot = { cid: enforcementRootReceipt.cid, authorization: enforcementRootReceipt.delegationHeader.Authorization.replace(/^Bearer\s+/i, ""), role: "policy-enforcement" };
7325
+ const registration = await options.authority.registerPolicy({
7326
+ policyCid: created.policyCid,
7327
+ policy: created.policy,
7328
+ policyRoot,
7329
+ enforcementRoot,
7330
+ contentSourceDigestHex,
7331
+ nativeProjectionHashHex,
7332
+ rootExpiresAt: expiry,
7333
+ enforcerDid: options.enforcerDid,
7334
+ expectedNodeAudience: options.nodeAudience
7335
+ });
7336
+ if (registration.policyCid !== created.policyCid || registration.policyRootCid !== policyRoot.cid || registration.enforcementRootCid !== enforcementRoot.cid) throw new Error("Policy/v3 registration receipt is not bound to the published roots");
7337
+ const unsigned = {
7338
+ version: 3,
7339
+ shareId: options.shareId,
7340
+ recipientMatcher: matcher,
7341
+ ...options.deliveryEmail === void 0 ? {} : { deliveryEmail: options.deliveryEmail },
7342
+ actions: [...options.actions],
7343
+ resource: { ...options.resource },
7344
+ target: { origin: options.nodeOrigin, nodeAudience: registration.attestedEnforcerBinding.enforcerDid, spaceId: options.spaceId },
7345
+ policy: created.policy,
7346
+ policyCid: created.policyCid,
7347
+ policyRoot,
7348
+ enforcementRoot,
7349
+ attestedEnforcerBinding: registration.attestedEnforcerBinding,
7350
+ contentSource: options.contentSource,
7351
+ contentSourceDigestHex,
7352
+ encryptionNetwork: options.contentSource.encryptionNetwork,
7353
+ expiry,
7354
+ display: { filename: options.filename },
7355
+ encrypted: true,
7356
+ metadata: {
7357
+ mediaType: options.mediaType,
7358
+ byteLength: options.byteLength,
7359
+ filename: options.filename,
7360
+ ...options.mediaType.startsWith("text/") ? { encoding: "utf-8" } : {},
7361
+ ...options.artifact === void 0 ? {} : { artifact: options.artifact }
7362
+ }
7363
+ };
7364
+ unsignedShareEnvelopeV3Schema.parse(unsigned);
7365
+ const envelopeSignature = await options.authority.sign(sha2563(textEncoder.encode(`${ENVELOPE_V3_DOMAIN}${canonicalize(unsigned)}`)));
7366
+ if (envelopeSignature.byteLength !== 64) throw new TypeError("v3 envelope signature must be Ed25519");
7367
+ const envelope = { ...unsigned, signature: { signerDid: options.authority.ownerDid, algorithm: "Ed25519", value: toBase64Url(envelopeSignature) } };
7368
+ shareEnvelopeV3Schema.parse(envelope);
7369
+ const envelopeKey = generateKey();
7370
+ try {
7371
+ const sealed = await seal(textEncoder.encode(canonicalize(envelope)), envelopeKey);
7372
+ let url;
7373
+ let retention = options.expiresAt.toISOString();
7374
+ if (options.inline === true) url = await encodeInlineShareUrl({ origin: options.shareOrigin, ciphertext: sealed.blob, key32: envelopeKey });
7375
+ else {
7376
+ const uploaded = await uploadShareBlob({ source: new Uint8Array([1]), filename: options.filename, origin: options.shareOrigin, ...options.upload }, { blob: sealed.blob, cid: sealed.cid, deleteAfter: retention, contentLength: sealed.blob.byteLength });
7377
+ retention = uploaded.deleteAfter;
7378
+ url = encodeShareUrl({ origin: options.shareOrigin, ciphertextCid: uploaded.cid, key32: envelopeKey });
7379
+ }
7380
+ await options.publishBinding?.({
7381
+ version: 3,
7382
+ shareCid: sealed.cid,
7383
+ shareId: options.shareId,
7384
+ policyCid: created.policyCid,
7385
+ policyRootCid: policyRoot.cid,
7386
+ enforcementRootCid: enforcementRoot.cid,
7387
+ contentSourceDigestHex
7388
+ });
7389
+ const deliveryMaterial = { envelope, sealedEnvelope: toBase64Url(sealed.blob), envelopeKey: toBase64Url(envelopeKey), shareCid: sealed.cid };
7390
+ options.onDeliveryMaterial?.(deliveryMaterial);
7391
+ return publicationResult({ options, url, envelopeCid: sealed.cid, matcher, policyCid: created.policyCid, policyRootCid: policyRoot.cid, enforcementRootCid: enforcementRoot.cid, enforcerDid: registration.attestedEnforcerBinding.enforcerDid, expiry, retention, deliveryMaterial });
7392
+ } finally {
7393
+ envelopeKey.fill(0);
7394
+ }
7395
+ }
7396
+
7397
+ // src/policy-authority.ts
7398
+ import { ed25519 as ed255196 } from "@noble/curves/ed25519";
7399
+
7400
+ // src/owner-policy.ts
7401
+ import { ed25519 as ed255195 } from "@noble/curves/ed25519";
7402
+ import { sha256 as sha2564 } from "@noble/hashes/sha256";
7403
+
7042
7404
  // ../../node_modules/multiformats/dist/src/bases/base32.js
7043
7405
  var base322 = rfc46482({
7044
7406
  prefix: "b",
@@ -7107,18 +7469,6 @@ var base36upper2 = baseX2({
7107
7469
  alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
7108
7470
  });
7109
7471
 
7110
- // ../../node_modules/multiformats/dist/src/bases/base58.js
7111
- var base58btc2 = baseX2({
7112
- name: "base58btc",
7113
- prefix: "z",
7114
- alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
7115
- });
7116
- var base58flickr2 = baseX2({
7117
- name: "base58flickr",
7118
- prefix: "Z",
7119
- alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
7120
- });
7121
-
7122
7472
  // ../../node_modules/multiformats/dist/src/vendor/varint.js
7123
7473
  var encode_12 = encode4;
7124
7474
  var MSB2 = 128;
@@ -7192,25 +7542,25 @@ function encodingLength2(int) {
7192
7542
  }
7193
7543
 
7194
7544
  // ../../node_modules/multiformats/dist/src/hashes/digest.js
7195
- function create2(code3, digest4) {
7196
- const size = digest4.byteLength;
7545
+ function create2(code3, digest3) {
7546
+ const size = digest3.byteLength;
7197
7547
  const sizeOffset = encodingLength2(code3);
7198
7548
  const digestOffset = sizeOffset + encodingLength2(size);
7199
7549
  const bytes3 = new Uint8Array(digestOffset + size);
7200
7550
  encodeTo2(code3, bytes3, 0);
7201
7551
  encodeTo2(size, bytes3, sizeOffset);
7202
- bytes3.set(digest4, digestOffset);
7203
- return new Digest2(code3, size, digest4, bytes3);
7552
+ bytes3.set(digest3, digestOffset);
7553
+ return new Digest2(code3, size, digest3, bytes3);
7204
7554
  }
7205
7555
  function decode8(multihash) {
7206
7556
  const bytes3 = coerce3(multihash);
7207
7557
  const [code3, sizeOffset] = decode7(bytes3);
7208
7558
  const [size, digestOffset] = decode7(bytes3.subarray(sizeOffset));
7209
- const digest4 = bytes3.subarray(sizeOffset + digestOffset);
7210
- if (digest4.byteLength !== size) {
7559
+ const digest3 = bytes3.subarray(sizeOffset + digestOffset);
7560
+ if (digest3.byteLength !== size) {
7211
7561
  throw new Error("Incorrect length");
7212
7562
  }
7213
- return new Digest2(code3, size, digest4, bytes3);
7563
+ return new Digest2(code3, size, digest3, bytes3);
7214
7564
  }
7215
7565
  function equals4(a, b) {
7216
7566
  if (a === b) {
@@ -7228,10 +7578,10 @@ var Digest2 = class {
7228
7578
  /**
7229
7579
  * Creates a multihash digest.
7230
7580
  */
7231
- constructor(code3, size, digest4, bytes3) {
7581
+ constructor(code3, size, digest3, bytes3) {
7232
7582
  this.code = code3;
7233
7583
  this.size = size;
7234
- this.digest = digest4;
7584
+ this.digest = digest3;
7235
7585
  this.bytes = bytes3;
7236
7586
  }
7237
7587
  };
@@ -7314,8 +7664,8 @@ var CID2 = class _CID2 {
7314
7664
  toV1() {
7315
7665
  switch (this.version) {
7316
7666
  case 0: {
7317
- const { code: code3, digest: digest4 } = this.multihash;
7318
- const multihash = create2(code3, digest4);
7667
+ const { code: code3, digest: digest3 } = this.multihash;
7668
+ const multihash = create2(code3, digest3);
7319
7669
  return _CID2.createV1(this.code, multihash);
7320
7670
  }
7321
7671
  case 1: {
@@ -7369,8 +7719,8 @@ var CID2 = class _CID2 {
7369
7719
  return new _CID2(version, code3, multihash, bytes3 ?? encodeCID2(version, code3, multihash.bytes));
7370
7720
  } else if (value[cidSymbol2] === true) {
7371
7721
  const { version, multihash, code: code3 } = value;
7372
- const digest4 = decode8(multihash);
7373
- return _CID2.create(version, code3, digest4);
7722
+ const digest3 = decode8(multihash);
7723
+ return _CID2.create(version, code3, digest3);
7374
7724
  } else {
7375
7725
  return null;
7376
7726
  }
@@ -7380,11 +7730,11 @@ var CID2 = class _CID2 {
7380
7730
  * @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
7381
7731
  * @param digest - (Multi)hash of the of the content.
7382
7732
  */
7383
- static create(version, code3, digest4) {
7733
+ static create(version, code3, digest3) {
7384
7734
  if (typeof code3 !== "number") {
7385
7735
  throw new Error("String codecs are no longer supported");
7386
7736
  }
7387
- if (!(digest4.bytes instanceof Uint8Array)) {
7737
+ if (!(digest3.bytes instanceof Uint8Array)) {
7388
7738
  throw new Error("Invalid digest");
7389
7739
  }
7390
7740
  switch (version) {
@@ -7392,12 +7742,12 @@ var CID2 = class _CID2 {
7392
7742
  if (code3 !== DAG_PB_CODE2) {
7393
7743
  throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE2}) block encoding`);
7394
7744
  } else {
7395
- return new _CID2(version, code3, digest4, digest4.bytes);
7745
+ return new _CID2(version, code3, digest3, digest3.bytes);
7396
7746
  }
7397
7747
  }
7398
7748
  case 1: {
7399
- const bytes3 = encodeCID2(version, code3, digest4.bytes);
7400
- return new _CID2(version, code3, digest4, bytes3);
7749
+ const bytes3 = encodeCID2(version, code3, digest3.bytes);
7750
+ return new _CID2(version, code3, digest3, bytes3);
7401
7751
  }
7402
7752
  default: {
7403
7753
  throw new Error("Invalid version");
@@ -7407,8 +7757,8 @@ var CID2 = class _CID2 {
7407
7757
  /**
7408
7758
  * Simplified version of `create` for CIDv0.
7409
7759
  */
7410
- static createV0(digest4) {
7411
- return _CID2.create(0, DAG_PB_CODE2, digest4);
7760
+ static createV0(digest3) {
7761
+ return _CID2.create(0, DAG_PB_CODE2, digest3);
7412
7762
  }
7413
7763
  /**
7414
7764
  * Simplified version of `create` for CIDv1.
@@ -7416,8 +7766,8 @@ var CID2 = class _CID2 {
7416
7766
  * @param code - Content encoding format code.
7417
7767
  * @param digest - Multihash of the content.
7418
7768
  */
7419
- static createV1(code3, digest4) {
7420
- return _CID2.create(1, code3, digest4);
7769
+ static createV1(code3, digest3) {
7770
+ return _CID2.create(1, code3, digest3);
7421
7771
  }
7422
7772
  /**
7423
7773
  * Decoded a CID from its binary representation. The byte array must contain
@@ -7450,8 +7800,8 @@ var CID2 = class _CID2 {
7450
7800
  throw new Error("Incorrect length");
7451
7801
  }
7452
7802
  const digestBytes3 = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
7453
- const digest4 = new Digest2(specs.multihashCode, specs.digestSize, digestBytes3, multihashBytes);
7454
- const cid2 = specs.version === 0 ? _CID2.createV0(digest4) : _CID2.createV1(specs.codec, digest4);
7803
+ const digest3 = new Digest2(specs.multihashCode, specs.digestSize, digestBytes3, multihashBytes);
7804
+ const cid2 = specs.version === 0 ? _CID2.createV0(digest3) : _CID2.createV1(specs.codec, digest3);
7455
7805
  return [cid2, bytes3.subarray(specs.size)];
7456
7806
  }
7457
7807
  /**
@@ -7603,10 +7953,10 @@ function fromB64(value) {
7603
7953
  throw new Error("base64url decoding is unavailable");
7604
7954
  }
7605
7955
  function cid(bytesValue) {
7606
- return CID2.createV1(code2, create2(SHA256_CODE2, sha2563(bytesValue))).toString(base322.encoder);
7956
+ return CID2.createV1(code2, create2(SHA256_CODE2, sha2564(bytesValue))).toString(base322.encoder);
7607
7957
  }
7608
7958
  function digest(bytesValue) {
7609
- return b64(sha2563(bytesValue));
7959
+ return b64(sha2564(bytesValue));
7610
7960
  }
7611
7961
  function didKeyFromEd25519PublicKey2(publicKey) {
7612
7962
  if (publicKey.length !== 32) throw new Error("share key public key must be 32 bytes");
@@ -7797,368 +8147,8 @@ function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
7797
8147
  return validateOwnerSharePolicyRegistration(value, expected);
7798
8148
  }
7799
8149
 
7800
- // src/authorization.ts
7801
- async function authorizeShare(input) {
7802
- if (input.resumeToken !== void 0) {
7803
- if (input.resumeToken.length < 16 || input.resumeToken.length > 512) {
7804
- return { state: "denied", reason: "rejected" };
7805
- }
7806
- return input.adapter.resume({
7807
- envelope: input.envelope,
7808
- method: input.method,
7809
- resumeToken: input.resumeToken,
7810
- ...input.proof === void 0 ? {} : { proof: input.proof }
7811
- });
7812
- }
7813
- return input.adapter.begin({ envelope: input.envelope, method: input.method });
7814
- }
7815
- function authorizationMethodForTarget(target) {
7816
- if (target.kind === "recipientDid") return "openkey-device";
7817
- if (target.kind === "email") return "email-claim";
7818
- if (target.kind === "emailDomain") return "email-claim";
7819
- return void 0;
7820
- }
7821
-
7822
- // src/targets.ts
7823
- function validEmail(value) {
7824
- return /^[^@\s]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i.test(value);
7825
- }
7826
- function validDomain(value) {
7827
- return /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))+$/i.test(value);
7828
- }
7829
- function validRecipientDid(value) {
7830
- if (value.length === 0 || value.length > 2048 || /[\u0000-\u0020\u007f]/.test(value)) return false;
7831
- const parts = value.split(":");
7832
- if (parts.length < 3 || parts[0] !== "did" || !/^[a-z0-9]+$/.test(parts[1] ?? "")) return false;
7833
- const identifier = parts.slice(2);
7834
- if (identifier.some((part) => part.length === 0)) return false;
7835
- if (parts[1] === "web") {
7836
- const host = identifier[0] ?? "";
7837
- if (host.length > 253 || host.split(".").some((label) => !label || label.length > 63 || !/^[A-Za-z0-9-]+$/.test(label) || label.startsWith("-") || label.endsWith("-"))) return false;
7838
- return identifier.slice(1).every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
7839
- }
7840
- if (parts[1] === "pkh") return identifier.length >= 3 && identifier.every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
7841
- if (parts[1] === "key") {
7842
- try {
7843
- const bytes3 = base58btc2.decode(identifier.join(":"));
7844
- return bytes3.length === 34 && bytes3[0] === 237 && bytes3[1] === 1;
7845
- } catch {
7846
- return false;
7847
- }
7848
- }
7849
- return false;
7850
- }
7851
- function normalizeShareTarget(target) {
7852
- if (target.kind === "bearer") return target;
7853
- if (target.kind === "recipientDid") {
7854
- if (!validRecipientDid(target.did)) throw new TypeError("recipient DID is invalid");
7855
- return { kind: target.kind, did: target.did };
7856
- }
7857
- if (target.kind === "email") {
7858
- if (!validEmail(target.address)) throw new TypeError("recipient email is invalid");
7859
- const at = target.address.lastIndexOf("@");
7860
- return { kind: target.kind, address: `${target.address.slice(0, at)}@${target.address.slice(at + 1).toLowerCase()}` };
7861
- }
7862
- if (!validDomain(target.domain)) throw new TypeError("recipient email domain is invalid");
7863
- return { kind: target.kind, domain: target.domain.toLowerCase() };
7864
- }
7865
- function targetAuthorizationMethod(target) {
7866
- return authorizationMethodForTarget(target);
7867
- }
7868
- async function publishTargetShare(input) {
7869
- const target = normalizeShareTarget(input.target);
7870
- if (target.kind === "bearer") return publishShare(input);
7871
- if (input.targetAdapter === void 0) {
7872
- return {
7873
- state: "authorization-required",
7874
- method: targetAuthorizationMethod(target)
7875
- };
7876
- }
7877
- const source = input.source instanceof Uint8Array ? input.source.slice() : await (async () => {
7878
- const chunks = [];
7879
- let size = 0;
7880
- for await (const chunk of input.source) {
7881
- if (!(chunk instanceof Uint8Array)) throw new TypeError("addressed publication source yielded invalid bytes");
7882
- size += chunk.byteLength;
7883
- if (size > (input.maxBytes ?? 100 * 1024 * 1024)) throw new TypeError("addressed publication exceeds maxBytes");
7884
- chunks.push(chunk.slice());
7885
- }
7886
- const bytes3 = new Uint8Array(size);
7887
- let offset = 0;
7888
- for (const chunk of chunks) {
7889
- bytes3.set(chunk, offset);
7890
- offset += chunk.byteLength;
7891
- }
7892
- return bytes3;
7893
- })();
7894
- const files = input.files === void 0 || input.files.length === 0 ? [{ bytes: source }] : input.files;
7895
- const limit = input.maxBytes ?? SHARE_CONTENT_LIMIT;
7896
- let totalBytes = 0;
7897
- for (const file of files) {
7898
- totalBytes += file.bytes.byteLength;
7899
- if (!Number.isSafeInteger(totalBytes) || totalBytes > limit) {
7900
- throw new SharePublishError("max-bytes-exceeded", "addressed publication exceeds the combined byte limit");
7901
- }
7902
- }
7903
- return input.targetAdapter.publish({
7904
- source,
7905
- filename: input.filename,
7906
- ...input.files === void 0 ? {} : { files: input.files },
7907
- ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
7908
- ...input.resourceKind === void 0 ? {} : { resourceKind: input.resourceKind },
7909
- ...input.actions === void 0 ? {} : { actions: input.actions },
7910
- target,
7911
- expiresAt: input.expiresAt ?? new Date((input.now?.() ?? Date.now()) + 7 * 24 * 60 * 60 * 1e3),
7912
- origin: input.origin,
7913
- ...input.inline === void 0 ? {} : { inline: input.inline },
7914
- upload: {
7915
- ...input.registryBaseUrl === void 0 ? {} : { registryBaseUrl: input.registryBaseUrl },
7916
- ...input.fetchFn === void 0 ? {} : { fetchFn: input.fetchFn },
7917
- ...input.authorizeUpload === void 0 ? {} : { authorizeUpload: input.authorizeUpload },
7918
- ...input.authorizationOrigin === void 0 ? {} : { authorizationOrigin: input.authorizationOrigin },
7919
- ...input.credentials === void 0 ? {} : { credentials: input.credentials },
7920
- ...input.allowInsecureRegistry === void 0 ? {} : { allowInsecureRegistry: input.allowInsecureRegistry },
7921
- ...input.uploadBlob === void 0 ? {} : { uploadBlob: input.uploadBlob }
7922
- },
7923
- ...input.notify === void 0 ? {} : { notify: input.notify }
7924
- });
7925
- }
7926
-
7927
- // src/addressed-publish.ts
7928
- var ENVELOPE_DOMAIN = "xyz.tinycloud.share/envelope/v2\0";
7929
- function targetMatcher(target) {
7930
- if (target.kind === "recipientDid") return { kind: "recipientDid", value: target.did };
7931
- if (target.kind === "email") return { kind: "exactEmail", value: target.address };
7932
- return { kind: "emailDomain", value: target.domain };
7933
- }
7934
- function targetKind(target) {
7935
- return target.kind;
7936
- }
7937
- function assertSafeInput(input) {
7938
- if (!/^[A-Za-z0-9_-]{16,128}$/.test(input.shareId)) throw new TypeError("addressed share id is invalid");
7939
- if (input.filename.length === 0 || input.filename === "." || input.filename === ".." || /[/\\\u0000-\u001f\u007f]/.test(input.filename)) throw new TypeError("addressed filename is invalid");
7940
- if (!Number.isSafeInteger(input.byteLength) || input.byteLength < 0 || input.byteLength > SHARE_CONTENT_LIMIT) throw new TypeError("addressed content length is invalid");
7941
- if (input.actions.length === 0 || input.policyActions.length === 0) throw new TypeError("addressed share actions are empty");
7942
- const expiry = input.expiresAt.getTime();
7943
- if (!Number.isFinite(expiry) || expiry <= Date.now()) throw new TypeError("addressed share expiry must be in the future");
7944
- if (input.artifact === "html" && (input.resource.kind !== "prefix" || !input.actions.includes("read") || !input.actions.includes("list"))) throw new TypeError("html artifacts require a readable prefix");
7945
- if (input.contentSource.kind !== "kv") throw new TypeError("addressed policy publication requires a KV content source");
7946
- }
7947
- async function sha2564(value) {
7948
- return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", value)));
7949
- }
7950
- function publicationResult(input) {
7951
- const result = {
7952
- protocol: "tinycloud-share",
7953
- version: SHARE_PUBLISH_RESULT_VERSION,
7954
- url: input.url,
7955
- link: { kind: input.options.inline === true ? "inline" : "compact", cid: input.envelopeCid },
7956
- metadata: {
7957
- protocol: "tinycloud-share",
7958
- version: 1,
7959
- shareId: input.options.shareId,
7960
- origin: input.options.shareOrigin,
7961
- target: {
7962
- kind: targetKind(input.options.target),
7963
- origin: input.options.nodeOrigin,
7964
- nodeAudience: input.options.nodeAudience,
7965
- spaceId: input.options.spaceId
7966
- },
7967
- resource: { ...input.options.resource },
7968
- actions: [...input.options.actions],
7969
- expiresAt: input.options.expiresAt.toISOString(),
7970
- display: { filename: input.options.filename },
7971
- recipientMatcher: { ...input.matcher },
7972
- registrationCid: input.registration.registrationCid,
7973
- policyCid: input.policyCid,
7974
- ownerDelegationCid: input.registration.ownerDelegationCid,
7975
- enforcementDelegationCid: input.enforcementDelegationCid,
7976
- ownerDid: input.registration.ownerDid,
7977
- shareKeyDid: input.shareKeyDid,
7978
- enforcerDid: input.registration.enforcerDid,
7979
- envelopeCid: input.envelopeCid,
7980
- shareCid: input.shareCid
7981
- },
7982
- registryDeleteAfter: input.retention
7983
- };
7984
- Object.defineProperty(result, "toJSON", { enumerable: false, value: () => redactPublishedShare(result) });
7985
- Object.defineProperty(result, "url", { enumerable: false, value: input.url });
7986
- return result;
7987
- }
7988
- async function publishAddressedShare(options) {
7989
- assertSafeInput(options);
7990
- const target = normalizeShareTarget(options.target);
7991
- if (target.kind === "bearer") throw new TypeError("addressed target is required");
7992
- if (options.contentSource.kind !== "kv") throw new TypeError("addressed policy publication requires a KV content source");
7993
- const contentSource = options.contentSource;
7994
- const matcher = targetMatcher(target);
7995
- const expiresAt = options.expiresAt.toISOString();
7996
- const contentSourceDigest = options.contentSourceDigest ?? await sha2564(new TextEncoder().encode(canonicalize(contentSource)));
7997
- const shareKey = await createDelegatedShareKey({ extractable: false });
7998
- let envelopeKey;
7999
- try {
8000
- const permissions = [
8001
- {
8002
- service: "tinycloud.kv",
8003
- path: options.resource.kind === "prefix" ? `${options.resource.path.replace(/\/+$/, "")}/` : options.resource.path,
8004
- actions: [...options.policyActions]
8005
- },
8006
- ...options.decryption === void 0 ? [] : [{
8007
- service: "tinycloud.encryption",
8008
- path: options.decryption.networkId,
8009
- actions: [options.decryption.action]
8010
- }]
8011
- ];
8012
- const ownerDelegation = await options.authority.createOwnerDelegation({
8013
- delegateDid: shareKey.did,
8014
- spaceId: options.spaceId,
8015
- permissions,
8016
- expiresAt: options.expiresAt
8017
- });
8018
- const policy = {
8019
- type: "TinyCloudSharePolicy",
8020
- version: 2,
8021
- shareId: options.shareId,
8022
- ownerDid: options.authority.ownerDid,
8023
- shareKeyDid: shareKey.did,
8024
- recipientMatcher: matcher,
8025
- target: {
8026
- origin: options.nodeOrigin,
8027
- nodeAudience: options.nodeAudience,
8028
- enforcerDid: options.enforcerDid,
8029
- spaceId: options.spaceId
8030
- },
8031
- resource: { ...options.resource },
8032
- actions: [...options.policyActions],
8033
- ...options.decryption === void 0 ? {} : { decryption: options.decryption },
8034
- contentSource,
8035
- contentSourceDigest,
8036
- ownerDelegationCid: ownerDelegation.delegationCid,
8037
- expiresAt
8038
- };
8039
- const canonicalPolicy = await canonicalOwnerSharePolicy(policy);
8040
- const policyProof = toBase64Url(await shareKey.sign(canonicalPolicy.bytes));
8041
- const enforcementDelegation = await createPolicyEnforcementDelegation({
8042
- ownerDelegation,
8043
- shareKey,
8044
- enforcerDid: options.enforcerDid,
8045
- policyCid: canonicalPolicy.cid,
8046
- shareId: options.shareId,
8047
- spaceId: options.spaceId,
8048
- nodeAudience: options.nodeAudience,
8049
- path: options.resource.path,
8050
- actions: options.policyActions,
8051
- contentSourceDigest,
8052
- expiresAt
8053
- });
8054
- const registration = await options.authority.registerOwnerSharePolicy({
8055
- policy: { bytes: canonicalPolicy.bytes, cid: canonicalPolicy.cid, proof: policyProof },
8056
- ownerDelegation,
8057
- enforcementDelegation,
8058
- contentSourceDigest
8059
- });
8060
- const authorityMaterialDigest = await sha2564(fromBase64Url(enforcementDelegation.dagCbor));
8061
- const authorityTarget = {
8062
- origin: options.nodeOrigin,
8063
- nodeAudience: options.nodeAudience,
8064
- enforcerDid: options.enforcerDid,
8065
- spaceId: options.spaceId
8066
- };
8067
- const envelopeIdentity = {
8068
- schema: "xyz.tinycloud.share/envelope/v2",
8069
- version: 2,
8070
- shareId: options.shareId,
8071
- delegationCid: ownerDelegation.delegationCid,
8072
- policyCid: canonicalPolicy.cid,
8073
- target: authorityTarget,
8074
- resource: options.resource,
8075
- actions: options.policyActions,
8076
- ...options.decryption === void 0 ? {} : { decryption: options.decryption },
8077
- contentSource,
8078
- contentSourceDigest,
8079
- expiresAt
8080
- };
8081
- const envelopeCid = await computeCid(new TextEncoder().encode(canonicalize(envelopeIdentity)));
8082
- const shareCid = await computeCid(new TextEncoder().encode(canonicalize({ version: 2, shareId: options.shareId, policyCid: canonicalPolicy.cid, envelopeCid })));
8083
- const outerUnsigned = { ...envelopeIdentity, envelopeCid, shareCid };
8084
- const outerSignature = toBase64Url(await shareKey.sign(new TextEncoder().encode(`${ENVELOPE_DOMAIN}${canonicalize(outerUnsigned)}`)));
8085
- const unsigned = {
8086
- version: 2,
8087
- shareId: options.shareId,
8088
- recipientMatcher: matcher,
8089
- ...options.deliveryEmail === void 0 ? {} : { deliveryEmail: options.deliveryEmail },
8090
- actions: [...options.actions],
8091
- resource: { ...options.resource },
8092
- target: { origin: options.nodeOrigin, nodeAudience: options.nodeAudience, spaceId: options.spaceId },
8093
- delegationCid: ownerDelegation.delegationCid,
8094
- authorityMaterialHandle: registration.registration.registrationCid,
8095
- authorityMaterialDigest,
8096
- contentSource,
8097
- contentSourceDigest,
8098
- authorizationTarget: { kind: "policy", policyCid: canonicalPolicy.cid, policyBytes: toBase64Url(canonicalPolicy.bytes) },
8099
- display: { filename: options.filename },
8100
- expiry: expiresAt,
8101
- encrypted: true,
8102
- metadata: {
8103
- mediaType: options.mediaType,
8104
- byteLength: options.byteLength,
8105
- filename: options.filename,
8106
- ...options.mediaType.startsWith("text/") ? { encoding: "utf-8" } : {},
8107
- ...options.artifact === void 0 ? {} : { artifact: options.artifact }
8108
- },
8109
- ownerAuthority: {
8110
- registrationCid: registration.registration.registrationCid,
8111
- shareCid,
8112
- envelopeCid,
8113
- enforcementDelegation,
8114
- registrationReceipt: registration,
8115
- outerEnvelope: {
8116
- ...outerUnsigned,
8117
- signature: { signerDid: shareKey.did, algorithm: "Ed25519", value: outerSignature }
8118
- }
8119
- }
8120
- };
8121
- unsignedShareEnvelopeV2Schema.parse(unsigned);
8122
- const envelopeSignature = toBase64Url(await shareKey.sign(new TextEncoder().encode(`${ENVELOPE_DOMAIN}${canonicalize(unsigned)}`)));
8123
- const envelope = { ...unsigned, signature: { signerDid: shareKey.did, algorithm: "Ed25519", value: envelopeSignature } };
8124
- shareEnvelopeV2Schema.parse(envelope);
8125
- envelopeKey = generateKey();
8126
- const sealed = await seal(new TextEncoder().encode(canonicalize(envelope)), envelopeKey);
8127
- let url;
8128
- let retention = expiresAt;
8129
- if (options.inline === true) {
8130
- url = await encodeInlineShareUrl({ origin: options.shareOrigin, ciphertext: sealed.blob, key32: envelopeKey });
8131
- } else {
8132
- const uploaded = await uploadShareBlob({
8133
- source: new Uint8Array([1]),
8134
- filename: options.filename,
8135
- origin: options.shareOrigin,
8136
- ...options.upload
8137
- }, { blob: sealed.blob, cid: sealed.cid, deleteAfter: expiresAt, contentLength: sealed.blob.byteLength });
8138
- retention = uploaded.deleteAfter;
8139
- url = encodeShareUrl({ origin: options.shareOrigin, ciphertextCid: uploaded.cid, key32: envelopeKey });
8140
- }
8141
- return publicationResult({
8142
- options,
8143
- url,
8144
- envelopeCid: sealed.cid,
8145
- shareCid,
8146
- matcher,
8147
- registration: registration.registration,
8148
- policyCid: canonicalPolicy.cid,
8149
- enforcementDelegationCid: enforcementDelegation.cid,
8150
- shareKeyDid: shareKey.did,
8151
- retention
8152
- });
8153
- } finally {
8154
- shareKey.clear();
8155
- envelopeKey?.fill(0);
8156
- }
8157
- }
8158
-
8159
8150
  // src/policy-authority.ts
8160
- import { ed25519 as ed255196 } from "@noble/curves/ed25519";
8161
- var ENVELOPE_DOMAIN2 = "xyz.tinycloud.share/envelope/v2\0";
8151
+ var ENVELOPE_DOMAIN = "xyz.tinycloud.share/envelope/v2\0";
8162
8152
  function record(value, keys, label) {
8163
8153
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
8164
8154
  const output = value;
@@ -8239,7 +8229,7 @@ async function verifyOuterEnvelope(value, envelope, policyCid, expectedEnforcerD
8239
8229
  const signatureBytes = fromBase64Url(requiredString(signature.value, "outer signature"));
8240
8230
  if (signatureBytes.length !== 64 || !ed255196.verify(
8241
8231
  signatureBytes,
8242
- new TextEncoder().encode(`${ENVELOPE_DOMAIN2}${canonicalize(unsigned)}`),
8232
+ new TextEncoder().encode(`${ENVELOPE_DOMAIN}${canonicalize(unsigned)}`),
8243
8233
  ed25519PublicKeyFromDidKey(envelope.signature.signerDid),
8244
8234
  { zip215: false }
8245
8235
  )) return void 0;
@@ -8512,6 +8502,7 @@ function historyRecordForPublishedShare(result, now = /* @__PURE__ */ new Date()
8512
8502
  registeredAt: now.toISOString(),
8513
8503
  expiresAt: result.metadata.expiresAt,
8514
8504
  link: result.url,
8505
+ ...result.deliveryMaterial === void 0 ? {} : { deliveryMaterial: result.deliveryMaterial },
8515
8506
  ...result.metadata.display.filename === void 0 ? {} : { filename: result.metadata.display.filename }
8516
8507
  };
8517
8508
  }
@@ -8696,11 +8687,11 @@ async function notifyShare(input) {
8696
8687
  }
8697
8688
  async function defaultIdempotencyKey(shareId, recipient) {
8698
8689
  const canonicalRecipient = canonicalize(recipient.trim().toLowerCase());
8699
- const digest4 = new Uint8Array(await crypto.subtle.digest(
8690
+ const digest3 = new Uint8Array(await crypto.subtle.digest(
8700
8691
  "SHA-256",
8701
8692
  new TextEncoder().encode(canonicalRecipient)
8702
8693
  ));
8703
- return `tinycloud-share:${shareId}:${toBase64Url(digest4)}`;
8694
+ return `tinycloud-share:${shareId}:${toBase64Url(digest3)}`;
8704
8695
  }
8705
8696
 
8706
8697
  // src/lifecycle.ts
@@ -8848,12 +8839,6 @@ function fromBase64(value, label) {
8848
8839
  if (toBase64(out) !== value) throw new Error(`${label} is invalid`);
8849
8840
  return out;
8850
8841
  }
8851
- async function digest3(value) {
8852
- return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonicalize(value)))));
8853
- }
8854
- async function digestText2(value) {
8855
- return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value))));
8856
- }
8857
8842
  async function digestBytes2(value) {
8858
8843
  return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", value)));
8859
8844
  }
@@ -8863,24 +8848,9 @@ function trustedPublicKey(value) {
8863
8848
  }
8864
8849
  return value.invitationPublicKey;
8865
8850
  }
8866
- async function verifyWrapped(value, key, domain, trust) {
8867
- const wrapper = object2(value, `${key} response`);
8868
- if (Object.keys(wrapper).length !== 2 || !Object.hasOwn(wrapper, key) || !Object.hasOwn(wrapper, "proof")) throw new Error(`${key} response is invalid`);
8869
- const artifact = object2(wrapper[key], `${key} artifact`);
8870
- const proof = object2(wrapper.proof, `${key} proof`);
8871
- if (proof.alg !== "EdDSA" || proof.kid !== trust.invitationKid) throw new Error(`${key} proof is invalid`);
8872
- if (!ed255198.verify(bytes2(proof.signature, `${key} signature`), new TextEncoder().encode(`${domain}${canonicalize(artifact)}`), trustedPublicKey(trust))) throw new Error(`${key} proof is invalid`);
8873
- return artifact;
8874
- }
8875
8851
  function nativeAction(action) {
8876
8852
  return action === "list" ? "tinycloud.kv/list" : action === "edit" ? "tinycloud.kv/put" : "tinycloud.kv/get";
8877
8853
  }
8878
- function uiAction(action) {
8879
- return action === "tinycloud.kv/list" ? "list" : action === "tinycloud.kv/put" ? "edit" : "read";
8880
- }
8881
- function selectedAction(envelope) {
8882
- return envelope.actions.includes("list") ? "tinycloud.kv/list" : envelope.actions.includes("edit") ? "tinycloud.kv/put" : "tinycloud.kv/get";
8883
- }
8884
8854
  function policyAttenuationForV3(envelope) {
8885
8855
  const policy = object2(envelope.policy, "v3 policy");
8886
8856
  if (!Array.isArray(policy.capabilityCeiling)) throw new Error("v3 policy capability ceiling is invalid");
@@ -8950,11 +8920,11 @@ function verifyV3PolicyAuthorization(input) {
8950
8920
  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 || canonicalize(compact.payload.att) !== canonicalize(policyAttenuationForV3(input.envelope))) throw new Error("v3 policy delegation signed binding mismatch");
8951
8921
  return compact;
8952
8922
  }
8953
- function hex2(value) {
8923
+ function hex3(value) {
8954
8924
  return [...value].map((byte) => byte.toString(16).padStart(2, "0")).join("");
8955
8925
  }
8956
8926
  function canonicalHashHex(value) {
8957
- return hex2(sha2566(new TextEncoder().encode(canonicalize(value))));
8927
+ return hex3(sha2566(new TextEncoder().encode(canonicalize(value))));
8958
8928
  }
8959
8929
  async function aesGcmDecrypt(key, blob) {
8960
8930
  if (key.length !== 32 || blob.length < 28) throw new Error("encrypted content is malformed");
@@ -8986,25 +8956,6 @@ function parseV3InlineEncryptedEnvelope(bytes3, expected) {
8986
8956
  }
8987
8957
  return record2;
8988
8958
  }
8989
- async function verifyDetachedResponse(response, trust) {
8990
- let value;
8991
- try {
8992
- value = await response.clone().json();
8993
- } catch {
8994
- throw new Error("share read response is invalid");
8995
- }
8996
- const record2 = object2(value, "share read response");
8997
- const proof = object2(record2.proof, "share read detached proof");
8998
- if (proof.alg !== "EdDSA" || proof.kid !== trust.invitationKid) throw new Error("share read detached proof is invalid");
8999
- const unsigned = { ...record2 };
9000
- delete unsigned.proof;
9001
- if (!ed255198.verify(bytes2(proof.signature, "share read signature"), new TextEncoder().encode(`${SHARE_V2_PROTOCOL.readResponseDomain}${canonicalize(unsigned)}`), trustedPublicKey(trust))) throw new Error("share read detached proof is invalid");
9002
- }
9003
- async function post(fetchFn, origin, path, body) {
9004
- const response = await fetchFn(new URL(path, origin), { method: "POST", redirect: "error", headers: { accept: "application/json", "content-type": "application/json" }, body: JSON.stringify(body) });
9005
- if (!response.ok) throw new Error("share authority rejected the request");
9006
- return response.json();
9007
- }
9008
8959
  var ShareRecipientClient = class {
9009
8960
  constructor(options) {
9010
8961
  this.options = options;
@@ -9035,72 +8986,12 @@ var ShareRecipientClient = class {
9035
8986
  v3ContentKey;
9036
8987
  v3ContentEnvelope;
9037
8988
  async beginChallenge(envelope) {
9038
- const authority = envelope.ownerAuthority;
9039
- if (authority === void 0) throw new Error("addressed owner authority is required");
9040
- const outer = object2(authority.outerEnvelope, "owner authority outer envelope");
9041
- const enforcement = object2(authority.enforcementDelegation, "owner authority enforcement delegation");
9042
- const target = object2(outer.target, "owner authority target");
9043
- const outerResource = object2(outer.resource, "owner authority resource");
9044
- const source = object2(outer.contentSource, "owner authority content source");
9045
- if (!Array.isArray(outer.actions) || outer.actions.length === 0 || outer.actions.some((value) => typeof value !== "string")) throw new Error("owner authority outer envelope actions are invalid");
9046
- const actions = [...outer.actions];
9047
- const action = selectedAction(envelope);
9048
- const challengeBody = { envelopeCid: authority.envelopeCid, shareCid: authority.shareCid, shareId: envelope.shareId, registrationCid: authority.registrationCid, delegationCid: envelope.delegationCid, policyCid: envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "", enforcementDelegationCid: String(enforcement.cid), enforcementDelegation: enforcement, outerEnvelope: outer, contentSource: source, contentSourceDigest: String(outer.contentSourceDigest), holderDid: this.options.holderDid, targetOrigin: String(target.origin), nodeAudience: String(target.nodeAudience), action, actions, resource: String(outerResource.path) };
9049
- const requestBodyDigest = await digest3(challengeBody);
9050
- const challenge = await verifyWrapped(await post(this.fetchFn, this.options.nodeOrigin, "/share/v2/policy/challenges", { ...challengeBody, requestBodyDigest }), "challenge", DOMAIN, this.options.trustedNode);
9051
- if (challenge.type !== "TinyCloudSharePolicyChallenge" || challenge.version !== 2 || challenge.challengeId.length < 16 || challenge.nonce.length < 16 || challenge.shareCid !== authority.shareCid || challenge.shareId !== envelope.shareId || challenge.registrationCid !== authority.registrationCid || challenge.envelopeCid !== authority.envelopeCid || challenge.policyCid !== challengeBody.policyCid || challenge.delegationCid !== envelope.delegationCid || challenge.enforcementDelegationCid !== enforcement.cid || canonicalize(challenge.contentSource) !== canonicalize(source) || challenge.contentSourceDigest !== challengeBody.contentSourceDigest || challenge.requestBodyDigest !== requestBodyDigest || challenge.holderDid !== this.options.holderDid || challenge.targetOrigin !== challengeBody.targetOrigin || challenge.nodeAudience !== challengeBody.nodeAudience || challenge.action !== action || canonicalize(challenge.actions) !== canonicalize(actions) || challenge.resource !== challengeBody.resource || !Number.isFinite(Date.parse(challenge.expiresAt)) || Date.parse(challenge.expiresAt) <= Date.now()) throw new Error("share authority returned an unbound challenge");
9052
- return challenge;
8989
+ void envelope;
8990
+ throw new Error("v2 Share recipient transport has been removed; use the embedded policy v3 envelope");
9053
8991
  }
9054
8992
  async establish(envelope) {
9055
- const authority = envelope.ownerAuthority;
9056
- if (authority === void 0) throw new Error("addressed owner authority is required");
9057
- const outer = object2(authority.outerEnvelope, "owner authority outer envelope");
9058
- const enforcement = object2(authority.enforcementDelegation, "owner authority enforcement delegation");
9059
- const target = object2(outer.target, "owner authority target");
9060
- const outerResource = object2(outer.resource, "owner authority resource");
9061
- const source = object2(outer.contentSource, "owner authority content source");
9062
- if (!Array.isArray(outer.actions) || outer.actions.length === 0 || outer.actions.some((value) => typeof value !== "string")) throw new Error("owner authority outer envelope actions are invalid");
9063
- const actions = [...outer.actions];
9064
- const action = selectedAction(envelope);
9065
- const challengeBody = { envelopeCid: authority.envelopeCid, shareCid: authority.shareCid, shareId: envelope.shareId, registrationCid: authority.registrationCid, delegationCid: envelope.delegationCid, policyCid: envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "", enforcementDelegationCid: String(enforcement.cid), enforcementDelegation: enforcement, outerEnvelope: outer, contentSource: source, contentSourceDigest: String(outer.contentSourceDigest), holderDid: this.options.holderDid, targetOrigin: String(target.origin), nodeAudience: String(target.nodeAudience), action, actions, resource: String(outerResource.path) };
9066
- const requestBodyDigest = await digest3(challengeBody);
9067
- const challenge = await verifyWrapped(await post(this.fetchFn, this.options.nodeOrigin, "/share/v2/policy/challenges", { ...challengeBody, requestBodyDigest }), "challenge", DOMAIN, this.options.trustedNode);
9068
- if (challenge.type !== "TinyCloudSharePolicyChallenge" || challenge.version !== 2 || challenge.challengeId === void 0 || challenge.nonce === void 0 || challenge.shareCid !== authority.shareCid || challenge.shareId !== envelope.shareId || challenge.registrationCid !== authority.registrationCid || challenge.envelopeCid !== authority.envelopeCid || challenge.policyCid !== challengeBody.policyCid || challenge.delegationCid !== envelope.delegationCid || challenge.enforcementDelegationCid !== enforcement.cid || challenge.requestBodyDigest !== requestBodyDigest || canonicalize(challenge.contentSource) !== canonicalize(source) || challenge.contentSourceDigest !== challengeBody.contentSourceDigest || challenge.holderDid !== this.options.holderDid || challenge.targetOrigin !== challengeBody.targetOrigin || challenge.nodeAudience !== challengeBody.nodeAudience || challenge.action !== action || canonicalize(challenge.actions) !== canonicalize(actions) || challenge.resource !== challengeBody.resource || !Number.isFinite(Date.parse(challenge.expiresAt)) || Date.parse(challenge.expiresAt) <= Date.now()) throw new Error("share authority returned an unbound challenge");
9069
- if (this.options.buildPresentation === void 0) throw new Error("share presentation builder is required");
9070
- const material = await this.options.buildPresentation({ challenge, envelope, policy: {} });
9071
- this.holderProof = material.proof;
9072
- this.signer = material.sign;
9073
- this.nativeSigner = material.sign;
9074
- if (this.signer === void 0) throw new Error("share holder signer is required");
9075
- const presentation = {
9076
- type: "TinyCloudSharePolicyPresentation",
9077
- version: 2,
9078
- challengeId: challenge.challengeId,
9079
- nonce: challenge.nonce,
9080
- shareCid: authority.shareCid,
9081
- shareId: envelope.shareId,
9082
- delegationCid: envelope.delegationCid,
9083
- policyCid: challengeBody.policyCid,
9084
- contentSource: source,
9085
- contentSourceDigest: challengeBody.contentSourceDigest,
9086
- holderDid: material.holderDid,
9087
- targetOrigin: challengeBody.targetOrigin,
9088
- nodeAudience: challengeBody.nodeAudience,
9089
- ...challenge.enforcerDid === void 0 ? {} : { enforcerDid: challenge.enforcerDid },
9090
- credentialDigest: material.credentialDigest ?? await digestText2(material.credential),
9091
- action,
9092
- actions,
9093
- resource: challengeBody.resource,
9094
- requestBodyDigest,
9095
- issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
9096
- expiresAt: challenge.expiresAt,
9097
- jti: toBase64Url(crypto.getRandomValues(new Uint8Array(16)))
9098
- };
9099
- const presentationProof = { alg: "EdDSA", kid: `${material.holderDid}#${material.holderDid.slice("did:key:".length)}`, signature: toBase64Url(await this.signer(new TextEncoder().encode(`${PRESENTATION_DOMAIN}${canonicalize(presentation)}`))) };
9100
- const session = await verifyWrapped(await post(this.fetchFn, this.options.nodeOrigin, "/share/v2/policy/session", { challengeId: challenge.challengeId, nonce: challenge.nonce, presentation, credential: material.credential, proof: presentationProof, holderBinding: material.holderBinding, readSignerDid: material.holderDid }), "session", SESSION_DOMAIN, this.options.trustedNode);
9101
- if (session.type !== "TinyCloudSharePolicySession" || session.version !== 2 || typeof session.sessionId !== "string" || session.shareCid !== authority.shareCid || session.shareId !== envelope.shareId || session.registrationCid !== authority.registrationCid || session.envelopeCid !== authority.envelopeCid || session.policyCid !== challengeBody.policyCid || session.delegationCid !== envelope.delegationCid || session.holderDid !== this.options.holderDid || session.targetOrigin !== challengeBody.targetOrigin || session.nodeAudience !== challengeBody.nodeAudience || session.action !== action || canonicalize(session.actions) !== canonicalize(actions) || canonicalize(session.contentSource) !== canonicalize(source) || session.contentSourceDigest !== challengeBody.contentSourceDigest || session.resource !== challengeBody.resource || typeof session.expiresAt !== "string" || !Number.isFinite(Date.parse(session.expiresAt)) || Date.parse(session.expiresAt) <= Date.now()) throw new Error("share authority returned an unbound session");
9102
- this.session = { sessionId: session.sessionId, expiresAt: session.expiresAt, actions: actions.map(uiAction), resource: { kind: envelope.resource.kind, path: String(session.resource) } };
9103
- return this.session;
8993
+ void envelope;
8994
+ throw new Error("v2 Share recipient transport has been removed; use the embedded policy v3 envelope");
9104
8995
  }
9105
8996
  async authorize(envelope) {
9106
8997
  if (this.session === void 0) await this.establish(envelope);
@@ -9128,7 +9019,7 @@ var ShareRecipientClient = class {
9128
9019
  } catch {
9129
9020
  throw new Error("v3 attested Node audience is invalid");
9130
9021
  }
9131
- const challengeResponse = await this.fetchFn(new URL("/share/v3/policy/challenges", this.options.nodeOrigin), {
9022
+ const challengeResponse = await this.fetchFn(new URL("/policy/v3/challenges", this.options.nodeOrigin), {
9132
9023
  method: "POST",
9133
9024
  redirect: "error",
9134
9025
  headers: { accept: "application/json", "content-type": "application/json" },
@@ -9149,7 +9040,7 @@ var ShareRecipientClient = class {
9149
9040
  throw new Error(accountless ? "v4 ceremony requires a verified credential and requirement" : "v3 ceremony requires a claim");
9150
9041
  }
9151
9042
  this.options.onStage?.("policy-admission");
9152
- const delegationResponse = await this.fetchFn(new URL("/share/v3/policy/delegations", this.options.nodeOrigin), {
9043
+ const delegationResponse = await this.fetchFn(new URL("/policy/v3/delegations", this.options.nodeOrigin), {
9153
9044
  method: "POST",
9154
9045
  redirect: "error",
9155
9046
  headers: { accept: "application/json", "content-type": "application/json" },
@@ -9180,7 +9071,7 @@ var ShareRecipientClient = class {
9180
9071
  const receiverPublicKey = toBase64(x25519.getPublicKey(receiverPrivateKey));
9181
9072
  const receiverPublicKeyHash = canonicalHashHex(receiverPublicKey);
9182
9073
  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 };
9183
- const bodyHash = hex2(sha2566(new TextEncoder().encode(canonicalize(body))));
9074
+ const bodyHash = hex3(sha2566(new TextEncoder().encode(canonicalize(body))));
9184
9075
  const session = verifyCompactUcanAuthorization(this.v3Authorization, this.session.sessionId);
9185
9076
  const now = Math.floor(Date.now() / 1e3);
9186
9077
  const invocation = await signCompactUcanAuthorization({
@@ -9200,7 +9091,7 @@ var ShareRecipientClient = class {
9200
9091
  if (!response.ok) throw new Error(`v3 decrypt invocation rejected (${response.status})`);
9201
9092
  const value = object2(await response.json(), "v3 decrypt response");
9202
9093
  const allowed = ["type", "targetNode", "networkId", "invocationCid", "encryptedSymmetricKeyHash", "receiverPublicKeyHash", "wrappedKey", "alg", "keyVersion", "requestHash", "nodeId", "nodeSignature"];
9203
- if (Object.keys(value).length !== allowed.length || Object.keys(value).some((key) => !allowed.includes(key)) || value.type !== "tinycloud.encryption.decrypt-result/v1" || value.targetNode !== body.targetNode || value.nodeId !== body.targetNode || value.networkId !== body.networkId || value.invocationCid !== invocation.cid || value.encryptedSymmetricKeyHash !== body.encryptedSymmetricKeyHash || value.receiverPublicKeyHash !== receiverPublicKeyHash || value.alg !== body.alg || value.keyVersion !== body.keyVersion || value.requestHash !== hex2(sha2566(new TextEncoder().encode(`${invocation.cid}${bodyHash}`))) || typeof value.wrappedKey !== "string" || typeof value.nodeSignature !== "string") throw new Error("v3 decrypt response binding is invalid");
9094
+ if (Object.keys(value).length !== allowed.length || Object.keys(value).some((key) => !allowed.includes(key)) || value.type !== "tinycloud.encryption.decrypt-result/v1" || value.targetNode !== body.targetNode || value.nodeId !== body.targetNode || value.networkId !== body.networkId || value.invocationCid !== invocation.cid || value.encryptedSymmetricKeyHash !== body.encryptedSymmetricKeyHash || value.receiverPublicKeyHash !== receiverPublicKeyHash || value.alg !== body.alg || value.keyVersion !== body.keyVersion || value.requestHash !== hex3(sha2566(new TextEncoder().encode(`${invocation.cid}${bodyHash}`))) || typeof value.wrappedKey !== "string" || typeof value.nodeSignature !== "string") throw new Error("v3 decrypt response binding is invalid");
9204
9095
  const unsigned = { ...value };
9205
9096
  delete unsigned.nodeSignature;
9206
9097
  const signature = fromBase64(value.nodeSignature, "v3 decrypt response signature");
@@ -9226,47 +9117,16 @@ var ShareRecipientClient = class {
9226
9117
  return new TextEncoder().encode(canonicalize({ ...this.v3ContentEnvelope, ciphertext: toBase64Url(await aesGcmEncrypt(this.v3ContentKey, bytes3)), metadata: { ...this.v3ContentEnvelope.metadata ?? {}, contentType: mediaType } }));
9227
9118
  }
9228
9119
  async resumeWithProof(envelope, resumeToken, proof) {
9229
- const material = object2(proof, "share authorization proof");
9230
- const presentation = object2(material.presentation, "share presentation");
9231
- const presentationProof = object2(material.presentationProof, "share presentation proof");
9232
- const nonce = material.nonce;
9233
- const credential = material.credential;
9234
- const holderDid = material.holderDid;
9235
- const holderBinding = material.holderBinding;
9236
- if (typeof nonce !== "string" || typeof credential !== "string" || typeof holderDid !== "string" || holderDid !== this.options.holderDid || typeof holderBinding !== "object" || holderBinding === null || presentationProof.alg !== "EdDSA" || typeof presentationProof.signature !== "string") throw new Error("share authorization proof is incomplete");
9237
- const value = object2(await post(this.fetchFn, this.options.nodeOrigin, "/share/v2/policy/session", { challengeId: resumeToken, nonce, presentation, credential, proof: presentationProof, holderBinding, readSignerDid: holderDid }), "share policy session");
9238
- const session = await verifyWrapped(value, "session", SESSION_DOMAIN, this.options.trustedNode);
9239
- const authority = envelope.ownerAuthority;
9240
- if (authority === void 0 || session.type !== "TinyCloudSharePolicySession" || session.version !== 2 || typeof session.sessionId !== "string" || session.shareCid !== authority.shareCid || session.shareId !== envelope.shareId || session.registrationCid !== authority.registrationCid || session.envelopeCid !== authority.envelopeCid || session.delegationCid !== envelope.delegationCid || typeof session.resource !== "string" || typeof session.expiresAt !== "string") throw new Error("share authority returned an unbound session");
9241
- const policyCid = envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "";
9242
- const actions = [...new Set(envelope.actions.map(nativeAction))].sort();
9243
- if (session.policyCid !== policyCid || session.holderDid !== this.options.holderDid || session.targetOrigin !== envelope.target.origin || session.nodeAudience !== envelope.target.nodeAudience || session.action !== selectedAction(envelope) || canonicalize(session.actions) !== canonicalize(actions) || canonicalize(session.contentSource) !== canonicalize(envelope.contentSource) || session.contentSourceDigest !== envelope.contentSourceDigest || !Number.isFinite(Date.parse(session.expiresAt)) || Date.parse(session.expiresAt) <= Date.now()) throw new Error("share authority returned an unbound session");
9244
- this.session = { sessionId: session.sessionId, expiresAt: session.expiresAt, actions: actions.map(uiAction), resource: { kind: envelope.resource.kind, path: String(session.resource) } };
9245
- this.holderProof = presentationProof;
9246
- this.signer ??= this.options.sign;
9247
- return this.authorize(envelope);
9120
+ void envelope;
9121
+ void resumeToken;
9122
+ void proof;
9123
+ throw new Error("v2 Share recipient transport has been removed; use the embedded policy v3 envelope");
9248
9124
  }
9249
9125
  async nativeInvoke(request) {
9250
9126
  if (this.session === void 0) throw new Error("share policy session is required");
9251
9127
  const envelope = this.options.envelope;
9252
9128
  if (envelope.version === 3) return this.nativeInvokeV3(request, envelope);
9253
- if (envelope.ownerAuthority === void 0 || this.signer === void 0 || this.holderProof === void 0) throw new Error("share holder signer is required");
9254
- const authority = envelope.ownerAuthority;
9255
- const action = request.action === "list" ? "tinycloud.kv/list" : request.action === "put" ? "tinycloud.kv/put" : request.action === "metadata" ? "tinycloud.kv/metadata" : "tinycloud.kv/get";
9256
- const resource = typeof request.resource?.path === "string" ? request.resource.path : this.session.resource.path;
9257
- const actions = [...new Set(this.session.actions.map(nativeAction).concat(action === "tinycloud.kv/metadata" ? [action] : []))].sort();
9258
- const bodyBytes = request.body === void 0 ? void 0 : Uint8Array.from(request.body);
9259
- const bodyDigest = bodyBytes === void 0 ? void 0 : toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", bodyBytes)));
9260
- const outer = object2(authority.outerEnvelope, "owner authority outer envelope");
9261
- const enforcement = object2(authority.enforcementDelegation, "owner authority enforcement delegation");
9262
- const invocationBase = { type: "TinyCloudShareReadInvocation", version: 2, sessionId: this.session.sessionId, envelopeCid: authority.envelopeCid, shareCid: authority.shareCid, shareId: envelope.shareId, registrationCid: authority.registrationCid, delegationCid: envelope.delegationCid, policyCid: envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "", enforcementDelegationCid: String(enforcement.cid), contentSource: outer.contentSource, contentSourceDigest: String(outer.contentSourceDigest), holderDid: this.options.holderDid, targetOrigin: String(object2(outer.target, "owner authority target").origin), nodeAudience: String(object2(outer.target, "owner authority target").nodeAudience), action, actions, resource, ...action === "tinycloud.kv/list" ? { limit: 100 } : {}, ...bodyDigest === void 0 ? {} : { bodyDigest, ifMatch: request.ifMatch, contentType: request.contentType }, issuedAt: (/* @__PURE__ */ new Date()).toISOString(), expiresAt: new Date(Math.min(Date.now() + 6e4, Date.parse(this.session.expiresAt))).toISOString(), jti: toBase64Url(crypto.getRandomValues(new Uint8Array(16))) };
9263
- const requestBodyDigest = await digest3(invocationBase);
9264
- const invocation = { ...invocationBase, requestBodyDigest };
9265
- const proof = { ...this.holderProof, signature: toBase64Url(await this.signer(new TextEncoder().encode(`${INVOCATION_DOMAIN}${canonicalize(invocation)}`))) };
9266
- const signedRequest = { sessionId: this.session.sessionId, envelopeCid: authority.envelopeCid, shareCid: authority.shareCid, shareId: envelope.shareId, registrationCid: authority.registrationCid, delegationCid: envelope.delegationCid, policyCid: envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "", enforcementDelegationCid: String(enforcement.cid), contentSource: outer.contentSource, contentSourceDigest: String(outer.contentSourceDigest), holderDid: this.options.holderDid, nodeAudience: String(object2(outer.target, "owner authority target").nodeAudience), action, actions, resource, requestBodyDigest, invocation, proof };
9267
- const response = await this.fetchFn(new URL("/share/v2/invoke", this.options.nodeOrigin), { method: "POST", redirect: "error", headers: { accept: "application/vnd.tinycloud.share+json", "content-type": "application/vnd.tinycloud.share+json" }, body: JSON.stringify({ request: signedRequest, ...action === "tinycloud.kv/list" ? { limit: 100 } : {}, ...bodyBytes === void 0 ? {} : { body: toBase64Url(bodyBytes), bodyDigest, ifMatch: request.ifMatch, contentType: request.contentType } }) });
9268
- if (response.ok) await verifyDetachedResponse(response, this.options.trustedNode);
9269
- return response;
9129
+ throw new Error("v2 Share invocation transport has been removed; use the embedded policy v3 envelope");
9270
9130
  }
9271
9131
  async nativeInvokeV3(request, envelope) {
9272
9132
  const signer = this.nativeSigner ?? this.signer;