@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.cjs CHANGED
@@ -4614,25 +4614,25 @@ function encodeTo(int, target, offset = 0) {
4614
4614
  function encodingLength(int) {
4615
4615
  return varint_default.encodingLength(int);
4616
4616
  }
4617
- function create(code22, digest4) {
4618
- const size = digest4.byteLength;
4617
+ function create(code22, digest3) {
4618
+ const size = digest3.byteLength;
4619
4619
  const sizeOffset = encodingLength(code22);
4620
4620
  const digestOffset = sizeOffset + encodingLength(size);
4621
4621
  const bytes3 = new Uint8Array(digestOffset + size);
4622
4622
  encodeTo(code22, bytes3, 0);
4623
4623
  encodeTo(size, bytes3, sizeOffset);
4624
- bytes3.set(digest4, digestOffset);
4625
- return new Digest(code22, size, digest4, bytes3);
4624
+ bytes3.set(digest3, digestOffset);
4625
+ return new Digest(code22, size, digest3, bytes3);
4626
4626
  }
4627
4627
  function decode4(multihash) {
4628
4628
  const bytes3 = coerce2(multihash);
4629
4629
  const [code22, sizeOffset] = decode3(bytes3);
4630
4630
  const [size, digestOffset] = decode3(bytes3.subarray(sizeOffset));
4631
- const digest4 = bytes3.subarray(sizeOffset + digestOffset);
4632
- if (digest4.byteLength !== size) {
4631
+ const digest3 = bytes3.subarray(sizeOffset + digestOffset);
4632
+ if (digest3.byteLength !== size) {
4633
4633
  throw new Error("Incorrect length");
4634
4634
  }
4635
- return new Digest(code22, size, digest4, bytes3);
4635
+ return new Digest(code22, size, digest3, bytes3);
4636
4636
  }
4637
4637
  function equals2(a, b) {
4638
4638
  if (a === b) {
@@ -4650,10 +4650,10 @@ var Digest = class {
4650
4650
  /**
4651
4651
  * Creates a multihash digest.
4652
4652
  */
4653
- constructor(code22, size, digest4, bytes3) {
4653
+ constructor(code22, size, digest3, bytes3) {
4654
4654
  this.code = code22;
4655
4655
  this.size = size;
4656
- this.digest = digest4;
4656
+ this.digest = digest3;
4657
4657
  this.bytes = bytes3;
4658
4658
  }
4659
4659
  };
@@ -4734,8 +4734,8 @@ var CID = class _CID {
4734
4734
  toV1() {
4735
4735
  switch (this.version) {
4736
4736
  case 0: {
4737
- const { code: code22, digest: digest4 } = this.multihash;
4738
- const multihash = create(code22, digest4);
4737
+ const { code: code22, digest: digest3 } = this.multihash;
4738
+ const multihash = create(code22, digest3);
4739
4739
  return _CID.createV1(this.code, multihash);
4740
4740
  }
4741
4741
  case 1: {
@@ -4789,8 +4789,8 @@ var CID = class _CID {
4789
4789
  return new _CID(version, code22, multihash, bytes3 ?? encodeCID(version, code22, multihash.bytes));
4790
4790
  } else if (value[cidSymbol] === true) {
4791
4791
  const { version, multihash, code: code22 } = value;
4792
- const digest4 = decode4(multihash);
4793
- return _CID.create(version, code22, digest4);
4792
+ const digest3 = decode4(multihash);
4793
+ return _CID.create(version, code22, digest3);
4794
4794
  } else {
4795
4795
  return null;
4796
4796
  }
@@ -4800,11 +4800,11 @@ var CID = class _CID {
4800
4800
  * @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
4801
4801
  * @param digest - (Multi)hash of the of the content.
4802
4802
  */
4803
- static create(version, code22, digest4) {
4803
+ static create(version, code22, digest3) {
4804
4804
  if (typeof code22 !== "number") {
4805
4805
  throw new Error("String codecs are no longer supported");
4806
4806
  }
4807
- if (!(digest4.bytes instanceof Uint8Array)) {
4807
+ if (!(digest3.bytes instanceof Uint8Array)) {
4808
4808
  throw new Error("Invalid digest");
4809
4809
  }
4810
4810
  switch (version) {
@@ -4812,12 +4812,12 @@ var CID = class _CID {
4812
4812
  if (code22 !== DAG_PB_CODE) {
4813
4813
  throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE}) block encoding`);
4814
4814
  } else {
4815
- return new _CID(version, code22, digest4, digest4.bytes);
4815
+ return new _CID(version, code22, digest3, digest3.bytes);
4816
4816
  }
4817
4817
  }
4818
4818
  case 1: {
4819
- const bytes3 = encodeCID(version, code22, digest4.bytes);
4820
- return new _CID(version, code22, digest4, bytes3);
4819
+ const bytes3 = encodeCID(version, code22, digest3.bytes);
4820
+ return new _CID(version, code22, digest3, bytes3);
4821
4821
  }
4822
4822
  default: {
4823
4823
  throw new Error("Invalid version");
@@ -4827,8 +4827,8 @@ var CID = class _CID {
4827
4827
  /**
4828
4828
  * Simplified version of `create` for CIDv0.
4829
4829
  */
4830
- static createV0(digest4) {
4831
- return _CID.create(0, DAG_PB_CODE, digest4);
4830
+ static createV0(digest3) {
4831
+ return _CID.create(0, DAG_PB_CODE, digest3);
4832
4832
  }
4833
4833
  /**
4834
4834
  * Simplified version of `create` for CIDv1.
@@ -4836,8 +4836,8 @@ var CID = class _CID {
4836
4836
  * @param code - Content encoding format code.
4837
4837
  * @param digest - Multihash of the content.
4838
4838
  */
4839
- static createV1(code22, digest4) {
4840
- return _CID.create(1, code22, digest4);
4839
+ static createV1(code22, digest3) {
4840
+ return _CID.create(1, code22, digest3);
4841
4841
  }
4842
4842
  /**
4843
4843
  * Decoded a CID from its binary representation. The byte array must contain
@@ -4870,8 +4870,8 @@ var CID = class _CID {
4870
4870
  throw new Error("Incorrect length");
4871
4871
  }
4872
4872
  const digestBytes3 = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
4873
- const digest4 = new Digest(specs.multihashCode, specs.digestSize, digestBytes3, multihashBytes);
4874
- const cid2 = specs.version === 0 ? _CID.createV0(digest4) : _CID.createV1(specs.codec, digest4);
4873
+ const digest3 = new Digest(specs.multihashCode, specs.digestSize, digestBytes3, multihashBytes);
4874
+ const cid2 = specs.version === 0 ? _CID.createV0(digest3) : _CID.createV1(specs.codec, digest3);
4875
4875
  return [cid2, bytes3.subarray(specs.size)];
4876
4876
  }
4877
4877
  /**
@@ -4994,8 +4994,8 @@ var cidSymbol = /* @__PURE__ */ Symbol.for("@ipld/js-cid/CID");
4994
4994
  var code = 85;
4995
4995
  var SHA256_CODE = 18;
4996
4996
  async function computeCid(bytes3) {
4997
- const digest4 = create(SHA256_CODE, (0, import_sha2.sha256)(new Uint8Array(bytes3)));
4998
- return CID.create(1, code, digest4).toString();
4997
+ const digest3 = create(SHA256_CODE, (0, import_sha2.sha256)(new Uint8Array(bytes3)));
4998
+ return CID.create(1, code, digest3).toString();
4999
4999
  }
5000
5000
  function isCanonicalRawCid(cidString) {
5001
5001
  let cid2;
@@ -5979,8 +5979,8 @@ async function verifyEnvelopeV3(envelope, options) {
5979
5979
  if (hex(sourceDigest) !== parsed.contentSourceDigestHex) return false;
5980
5980
  const sortedCapabilities = [...policy.capabilityCeiling].sort((left, right) => canonicalize(left).localeCompare(canonicalize(right)));
5981
5981
  const capabilityCeilingHashHex = hex((0, import_sha256.sha256)(new TextEncoder().encode(`${POLICY_CAPABILITY_V1_DOMAIN}${canonicalize(sortedCapabilities)}`)));
5982
- 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)));
5983
- const nativeProjectionHashHex = hex((0, import_sha256.sha256)(new TextEncoder().encode(`${NATIVE_PROJECTION_V1_DOMAIN}${canonicalize(nativeProjection)}`)));
5982
+ 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)));
5983
+ const nativeProjectionHashHex = hex((0, import_sha256.sha256)(new TextEncoder().encode(`${NATIVE_PROJECTION_V1_DOMAIN}${canonicalize(nativeProjection2)}`)));
5984
5984
  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 }]]))]));
5985
5985
  const kv = policy.capabilityCeiling.find((capability) => capability.kind === "kv");
5986
5986
  const expectedKvActions = parsed.actions.flatMap((action) => action === "read" ? ["tinycloud.kv/get", "tinycloud.kv/metadata"] : action === "list" ? ["tinycloud.kv/list"] : ["tinycloud.kv/put"]);
@@ -5993,8 +5993,8 @@ async function verifyEnvelopeV3(envelope, options) {
5993
5993
  const expectedBindingDigestHex = hex((0, import_sha256.sha256)(new TextEncoder().encode(canonicalize({ enforcerDid: binding.enforcerDid, nodeAudience: binding.nodeAudience }))));
5994
5994
  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;
5995
5995
  try {
5996
- const digest4 = (0, import_sha256.sha256)(new TextEncoder().encode(`${ATTESTED_ENFORCER_V2_DOMAIN}${canonicalize(unsignedBinding)}`));
5997
- if (!import_ed255193.ed25519.verify(fromBase64Url(bindingSignature.value), digest4, ed25519PublicKeyFromDidKey(binding.nodeAudience), ED25519_VERIFY_OPTS2)) return false;
5996
+ const digest3 = (0, import_sha256.sha256)(new TextEncoder().encode(`${ATTESTED_ENFORCER_V2_DOMAIN}${canonicalize(unsignedBinding)}`));
5997
+ if (!import_ed255193.ed25519.verify(fromBase64Url(bindingSignature.value), digest3, ed25519PublicKeyFromDidKey(binding.nodeAudience), ED25519_VERIFY_OPTS2)) return false;
5998
5998
  } catch {
5999
5999
  return false;
6000
6000
  }
@@ -6777,10 +6777,31 @@ async function parseAddressedEnvelope(value) {
6777
6777
  return { envelope, policy: decoded, policyCid: envelope.authorizationTarget.policyCid };
6778
6778
  }
6779
6779
 
6780
- // src/owner-policy.ts
6781
- var import_ed255195 = require("@noble/curves/ed25519");
6780
+ // src/addressed-publish.ts
6782
6781
  var import_sha2562 = require("@noble/hashes/sha256");
6783
6782
 
6783
+ // src/authorization.ts
6784
+ async function authorizeShare(input) {
6785
+ if (input.resumeToken !== void 0) {
6786
+ if (input.resumeToken.length < 16 || input.resumeToken.length > 512) {
6787
+ return { state: "denied", reason: "rejected" };
6788
+ }
6789
+ return input.adapter.resume({
6790
+ envelope: input.envelope,
6791
+ method: input.method,
6792
+ resumeToken: input.resumeToken,
6793
+ ...input.proof === void 0 ? {} : { proof: input.proof }
6794
+ });
6795
+ }
6796
+ return input.adapter.begin({ envelope: input.envelope, method: input.method });
6797
+ }
6798
+ function authorizationMethodForTarget(target) {
6799
+ if (target.kind === "recipientDid") return "openkey-device";
6800
+ if (target.kind === "email") return "email-claim";
6801
+ if (target.kind === "emailDomain") return "email-claim";
6802
+ return void 0;
6803
+ }
6804
+
6784
6805
  // ../../node_modules/multiformats/dist/src/bytes.js
6785
6806
  var empty2 = new Uint8Array(0);
6786
6807
  function equals3(aa, bb) {
@@ -7122,6 +7143,347 @@ function rfc46482({ name, prefix, bitsPerChar, alphabet }) {
7122
7143
  });
7123
7144
  }
7124
7145
 
7146
+ // ../../node_modules/multiformats/dist/src/bases/base58.js
7147
+ var base58btc2 = baseX2({
7148
+ name: "base58btc",
7149
+ prefix: "z",
7150
+ alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
7151
+ });
7152
+ var base58flickr2 = baseX2({
7153
+ name: "base58flickr",
7154
+ prefix: "Z",
7155
+ alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
7156
+ });
7157
+
7158
+ // src/targets.ts
7159
+ function validEmail(value) {
7160
+ 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);
7161
+ }
7162
+ function validDomain(value) {
7163
+ 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);
7164
+ }
7165
+ function validRecipientDid(value) {
7166
+ if (value.length === 0 || value.length > 2048 || /[\u0000-\u0020\u007f]/.test(value)) return false;
7167
+ const parts = value.split(":");
7168
+ if (parts.length < 3 || parts[0] !== "did" || !/^[a-z0-9]+$/.test(parts[1] ?? "")) return false;
7169
+ const identifier = parts.slice(2);
7170
+ if (identifier.some((part) => part.length === 0)) return false;
7171
+ if (parts[1] === "web") {
7172
+ const host = identifier[0] ?? "";
7173
+ if (host.length > 253 || host.split(".").some((label) => !label || label.length > 63 || !/^[A-Za-z0-9-]+$/.test(label) || label.startsWith("-") || label.endsWith("-"))) return false;
7174
+ return identifier.slice(1).every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
7175
+ }
7176
+ if (parts[1] === "pkh") return identifier.length >= 3 && identifier.every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
7177
+ if (parts[1] === "key") {
7178
+ try {
7179
+ const bytes3 = base58btc2.decode(identifier.join(":"));
7180
+ return bytes3.length === 34 && bytes3[0] === 237 && bytes3[1] === 1;
7181
+ } catch {
7182
+ return false;
7183
+ }
7184
+ }
7185
+ return false;
7186
+ }
7187
+ function normalizeShareTarget(target) {
7188
+ if (target.kind === "bearer") return target;
7189
+ if (target.kind === "recipientDid") {
7190
+ if (!validRecipientDid(target.did)) throw new TypeError("recipient DID is invalid");
7191
+ return { kind: target.kind, did: target.did };
7192
+ }
7193
+ if (target.kind === "email") {
7194
+ if (!validEmail(target.address)) throw new TypeError("recipient email is invalid");
7195
+ const at = target.address.lastIndexOf("@");
7196
+ return { kind: target.kind, address: `${target.address.slice(0, at)}@${target.address.slice(at + 1).toLowerCase()}` };
7197
+ }
7198
+ if (!validDomain(target.domain)) throw new TypeError("recipient email domain is invalid");
7199
+ return { kind: target.kind, domain: target.domain.toLowerCase() };
7200
+ }
7201
+ function targetAuthorizationMethod(target) {
7202
+ return authorizationMethodForTarget(target);
7203
+ }
7204
+ async function publishTargetShare(input) {
7205
+ const target = normalizeShareTarget(input.target);
7206
+ if (target.kind === "bearer") return publishShare(input);
7207
+ if (input.targetAdapter === void 0) {
7208
+ return {
7209
+ state: "authorization-required",
7210
+ method: targetAuthorizationMethod(target)
7211
+ };
7212
+ }
7213
+ const source = input.source instanceof Uint8Array ? input.source.slice() : await (async () => {
7214
+ const chunks = [];
7215
+ let size = 0;
7216
+ for await (const chunk of input.source) {
7217
+ if (!(chunk instanceof Uint8Array)) throw new TypeError("addressed publication source yielded invalid bytes");
7218
+ size += chunk.byteLength;
7219
+ if (size > (input.maxBytes ?? 100 * 1024 * 1024)) throw new TypeError("addressed publication exceeds maxBytes");
7220
+ chunks.push(chunk.slice());
7221
+ }
7222
+ const bytes3 = new Uint8Array(size);
7223
+ let offset = 0;
7224
+ for (const chunk of chunks) {
7225
+ bytes3.set(chunk, offset);
7226
+ offset += chunk.byteLength;
7227
+ }
7228
+ return bytes3;
7229
+ })();
7230
+ const files = input.files === void 0 || input.files.length === 0 ? [{ bytes: source }] : input.files;
7231
+ const limit = input.maxBytes ?? SHARE_CONTENT_LIMIT;
7232
+ let totalBytes = 0;
7233
+ for (const file of files) {
7234
+ totalBytes += file.bytes.byteLength;
7235
+ if (!Number.isSafeInteger(totalBytes) || totalBytes > limit) {
7236
+ throw new SharePublishError("max-bytes-exceeded", "addressed publication exceeds the combined byte limit");
7237
+ }
7238
+ }
7239
+ return input.targetAdapter.publish({
7240
+ source,
7241
+ filename: input.filename,
7242
+ ...input.files === void 0 ? {} : { files: input.files },
7243
+ ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
7244
+ ...input.resourceKind === void 0 ? {} : { resourceKind: input.resourceKind },
7245
+ ...input.actions === void 0 ? {} : { actions: input.actions },
7246
+ target,
7247
+ expiresAt: input.expiresAt ?? new Date((input.now?.() ?? Date.now()) + 7 * 24 * 60 * 60 * 1e3),
7248
+ origin: input.origin,
7249
+ ...input.inline === void 0 ? {} : { inline: input.inline },
7250
+ upload: {
7251
+ ...input.registryBaseUrl === void 0 ? {} : { registryBaseUrl: input.registryBaseUrl },
7252
+ ...input.fetchFn === void 0 ? {} : { fetchFn: input.fetchFn },
7253
+ ...input.authorizeUpload === void 0 ? {} : { authorizeUpload: input.authorizeUpload },
7254
+ ...input.authorizationOrigin === void 0 ? {} : { authorizationOrigin: input.authorizationOrigin },
7255
+ ...input.credentials === void 0 ? {} : { credentials: input.credentials },
7256
+ ...input.allowInsecureRegistry === void 0 ? {} : { allowInsecureRegistry: input.allowInsecureRegistry },
7257
+ ...input.uploadBlob === void 0 ? {} : { uploadBlob: input.uploadBlob }
7258
+ },
7259
+ ...input.notify === void 0 ? {} : { notify: input.notify }
7260
+ });
7261
+ }
7262
+
7263
+ // src/addressed-publish.ts
7264
+ var POLICY_V1_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
7265
+ var POLICY_V2_DOMAIN = "xyz.tinycloud.policy/policy/v2\0";
7266
+ var POLICY_CAPABILITY_V1_DOMAIN2 = "xyz.tinycloud.policy/PolicyCapability/v1\0";
7267
+ var CONTENT_SOURCE_V1_DOMAIN2 = "xyz.tinycloud.policy/ContentSource/v1\0";
7268
+ var NATIVE_PROJECTION_V1_DOMAIN2 = "xyz.tinycloud.policy/NativeProjection/v1\0";
7269
+ var ENVELOPE_V3_DOMAIN = "xyz.tinycloud.share/envelope/v3\0";
7270
+ var textEncoder = new TextEncoder();
7271
+ function targetMatcher(target) {
7272
+ if (target.kind === "recipientDid") return { kind: "recipientDid", value: target.did };
7273
+ if (target.kind === "email") return { kind: "exactEmail", value: target.address };
7274
+ return { kind: "emailDomain", value: target.domain };
7275
+ }
7276
+ function targetKind(target) {
7277
+ return target.kind;
7278
+ }
7279
+ function assertSafeInput(input) {
7280
+ if (!/^[A-Za-z0-9_-]{16,128}$/.test(input.shareId)) throw new TypeError("addressed share id is invalid");
7281
+ if (input.filename.length === 0 || input.filename === "." || input.filename === ".." || /[/\\\u0000-\u001f\u007f]/.test(input.filename)) throw new TypeError("addressed filename is invalid");
7282
+ if (!Number.isSafeInteger(input.byteLength) || input.byteLength < 0 || input.byteLength > SHARE_CONTENT_LIMIT) throw new TypeError("addressed content length is invalid");
7283
+ if (input.actions.length === 0 || input.policyActions.length === 0) throw new TypeError("addressed share actions are empty");
7284
+ if (!Number.isFinite(input.expiresAt.getTime()) || input.expiresAt.getTime() <= Date.now()) throw new TypeError("addressed share expiry must be in the future");
7285
+ 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");
7286
+ if (input.contentSource.shareId !== input.shareId || input.contentSource.selector !== input.resource.kind) throw new TypeError("addressed content source is not bound to the share");
7287
+ }
7288
+ function hex2(bytes3) {
7289
+ return [...bytes3].map((byte) => byte.toString(16).padStart(2, "0")).join("");
7290
+ }
7291
+ function digestHex(value, domain) {
7292
+ return hex2((0, import_sha2562.sha256)(textEncoder.encode(`${domain}${canonicalize(value)}`)));
7293
+ }
7294
+ function sortCanonical(values) {
7295
+ return [...values].sort((left, right) => canonicalize(left).localeCompare(canonicalize(right)));
7296
+ }
7297
+ function base32Lower2(bytes3) {
7298
+ const alphabet = "abcdefghijklmnopqrstuvwxyz234567";
7299
+ let output = "";
7300
+ let buffer = 0;
7301
+ let bits = 0;
7302
+ for (const byte of bytes3) {
7303
+ buffer = buffer << 8 | byte;
7304
+ bits += 8;
7305
+ while (bits >= 5) {
7306
+ output += alphabet[buffer >>> bits - 5 & 31];
7307
+ bits -= 5;
7308
+ }
7309
+ }
7310
+ if (bits > 0) output += alphabet[buffer << 5 - bits & 31];
7311
+ return output;
7312
+ }
7313
+ function rfc3339Seconds(value) {
7314
+ return new Date(Math.floor(value.getTime() / 1e3) * 1e3).toISOString().replace(".000Z", "Z");
7315
+ }
7316
+ function nativeProjection(capabilities) {
7317
+ return sortCanonical(capabilities.map((capability) => capability.kind === "encryption" ? { service: "tinycloud.encryption", space: capability.resource, path: capability.resource, actions: [capability.action] } : {
7318
+ service: "tinycloud.kv",
7319
+ space: capability.resource.slice(0, capability.resource.indexOf("/kv/")),
7320
+ path: capability.resource.slice(capability.resource.indexOf("/kv/") + 4),
7321
+ actions: [...capability.actions],
7322
+ caveat: { type: "xyz.tinycloud.resource/selector", kind: capability.selector, value: capability.resource }
7323
+ }));
7324
+ }
7325
+ async function createPolicy(options, capabilities) {
7326
+ const fields = {
7327
+ ownerDid: options.authority.ownerDid,
7328
+ createdAt: rfc3339Seconds(/* @__PURE__ */ new Date()),
7329
+ expiresAt: rfc3339Seconds(options.expiresAt),
7330
+ contentSource: options.contentSource,
7331
+ capabilityCeiling: [...capabilities]
7332
+ };
7333
+ const unsigned = options.credentialRequirement === void 0 ? { schema: "xyz.tinycloud.policy/policy/v1", ...fields } : { schema: "xyz.tinycloud.policy/policy/v2", ...fields, credentialRequirement: options.credentialRequirement };
7334
+ const domain = options.credentialRequirement === void 0 ? POLICY_V1_DOMAIN : POLICY_V2_DOMAIN;
7335
+ const policyDigestHex = digestHex(unsigned, domain);
7336
+ const signature = await options.authority.sign((0, import_sha2562.sha256)(textEncoder.encode(`${domain}${canonicalize(unsigned)}`)));
7337
+ if (signature.byteLength !== 64) throw new TypeError("policy signature must be Ed25519");
7338
+ const policy = {
7339
+ ...unsigned,
7340
+ policyId: `pol_${base32Lower2(Uint8Array.from(policyDigestHex.match(/../g), (byte) => Number.parseInt(byte, 16)))}`,
7341
+ signature: { suite: "Ed25519", signerDid: options.authority.ownerDid, value: toBase64Url(signature) }
7342
+ };
7343
+ return { policy, policyCid: await computeCid(textEncoder.encode(canonicalize(policy))), policyDigestHex };
7344
+ }
7345
+ function publicationResult(input) {
7346
+ const result = {
7347
+ protocol: "tinycloud-share",
7348
+ version: SHARE_PUBLISH_RESULT_VERSION,
7349
+ url: input.url,
7350
+ link: { kind: input.options.inline === true ? "inline" : "compact", cid: input.envelopeCid },
7351
+ metadata: {
7352
+ protocol: "tinycloud-share",
7353
+ version: 1,
7354
+ shareId: input.options.shareId,
7355
+ origin: input.options.shareOrigin,
7356
+ target: { kind: targetKind(input.options.target), origin: input.options.nodeOrigin, nodeAudience: input.enforcerDid, spaceId: input.options.spaceId },
7357
+ resource: { ...input.options.resource },
7358
+ actions: [...input.options.actions],
7359
+ expiresAt: input.expiry,
7360
+ display: { filename: input.options.filename },
7361
+ recipientMatcher: { ...input.matcher },
7362
+ policyCid: input.policyCid,
7363
+ ownerDelegationCid: input.policyRootCid,
7364
+ enforcementDelegationCid: input.enforcementRootCid,
7365
+ ownerDid: input.options.authority.ownerDid,
7366
+ enforcerDid: input.enforcerDid,
7367
+ envelopeCid: input.envelopeCid,
7368
+ shareCid: input.envelopeCid
7369
+ },
7370
+ registryDeleteAfter: input.retention
7371
+ };
7372
+ Object.defineProperty(result, "toJSON", { enumerable: false, value: () => redactPublishedShare(result) });
7373
+ Object.defineProperty(result, "url", { enumerable: false, value: input.url });
7374
+ Object.defineProperty(result, "deliveryMaterial", { enumerable: false, value: input.deliveryMaterial });
7375
+ return result;
7376
+ }
7377
+ async function publishAddressedShare(options) {
7378
+ assertSafeInput(options);
7379
+ const target = normalizeShareTarget(options.target);
7380
+ if (target.kind === "bearer") throw new TypeError("addressed target is required");
7381
+ const expiry = rfc3339Seconds(options.expiresAt);
7382
+ const matcher = targetMatcher(target);
7383
+ const capabilities = sortCanonical([
7384
+ { kind: "kv", resource: options.contentSource.kvResource, selector: options.resource.kind, actions: [...options.policyActions] },
7385
+ { kind: "encryption", resource: options.contentSource.encryptionNetwork, action: "tinycloud.encryption/decrypt" }
7386
+ ]);
7387
+ const created = await createPolicy(options, capabilities);
7388
+ const contentSourceDigestHex = digestHex(options.contentSource, CONTENT_SOURCE_V1_DOMAIN2);
7389
+ const capabilityCeilingHashHex = digestHex(capabilities, POLICY_CAPABILITY_V1_DOMAIN2);
7390
+ const nativeProjectionHashHex = digestHex(nativeProjection(capabilities), NATIVE_PROJECTION_V1_DOMAIN2);
7391
+ const commonRoot = {
7392
+ ownerDid: options.authority.ownerDid,
7393
+ policyId: created.policy.policyId,
7394
+ policyDigestHex: created.policyDigestHex,
7395
+ policyCid: created.policyCid,
7396
+ contentSourceDigestHex,
7397
+ capabilityCeilingHashHex,
7398
+ nativeProjectionHashHex,
7399
+ notBefore: new Date(created.policy.createdAt),
7400
+ expiresAt: new Date(expiry),
7401
+ nodeAudience: options.nodeAudience,
7402
+ capabilities
7403
+ };
7404
+ const policyRootReceipt = await options.authority.createOwnerRoot({ ...commonRoot, role: "policy-authority", audienceDid: `did:tinycloud:policy:${created.policyDigestHex}` });
7405
+ const enforcementRootReceipt = await options.authority.createOwnerRoot({ ...commonRoot, role: "policy-enforcement", audienceDid: options.enforcerDid });
7406
+ const policyRoot = { cid: policyRootReceipt.cid, authorization: policyRootReceipt.delegationHeader.Authorization.replace(/^Bearer\s+/i, ""), role: "policy-authority" };
7407
+ const enforcementRoot = { cid: enforcementRootReceipt.cid, authorization: enforcementRootReceipt.delegationHeader.Authorization.replace(/^Bearer\s+/i, ""), role: "policy-enforcement" };
7408
+ const registration = await options.authority.registerPolicy({
7409
+ policyCid: created.policyCid,
7410
+ policy: created.policy,
7411
+ policyRoot,
7412
+ enforcementRoot,
7413
+ contentSourceDigestHex,
7414
+ nativeProjectionHashHex,
7415
+ rootExpiresAt: expiry,
7416
+ enforcerDid: options.enforcerDid,
7417
+ expectedNodeAudience: options.nodeAudience
7418
+ });
7419
+ 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");
7420
+ const unsigned = {
7421
+ version: 3,
7422
+ shareId: options.shareId,
7423
+ recipientMatcher: matcher,
7424
+ ...options.deliveryEmail === void 0 ? {} : { deliveryEmail: options.deliveryEmail },
7425
+ actions: [...options.actions],
7426
+ resource: { ...options.resource },
7427
+ target: { origin: options.nodeOrigin, nodeAudience: registration.attestedEnforcerBinding.enforcerDid, spaceId: options.spaceId },
7428
+ policy: created.policy,
7429
+ policyCid: created.policyCid,
7430
+ policyRoot,
7431
+ enforcementRoot,
7432
+ attestedEnforcerBinding: registration.attestedEnforcerBinding,
7433
+ contentSource: options.contentSource,
7434
+ contentSourceDigestHex,
7435
+ encryptionNetwork: options.contentSource.encryptionNetwork,
7436
+ expiry,
7437
+ display: { filename: options.filename },
7438
+ encrypted: true,
7439
+ metadata: {
7440
+ mediaType: options.mediaType,
7441
+ byteLength: options.byteLength,
7442
+ filename: options.filename,
7443
+ ...options.mediaType.startsWith("text/") ? { encoding: "utf-8" } : {},
7444
+ ...options.artifact === void 0 ? {} : { artifact: options.artifact }
7445
+ }
7446
+ };
7447
+ unsignedShareEnvelopeV3Schema.parse(unsigned);
7448
+ const envelopeSignature = await options.authority.sign((0, import_sha2562.sha256)(textEncoder.encode(`${ENVELOPE_V3_DOMAIN}${canonicalize(unsigned)}`)));
7449
+ if (envelopeSignature.byteLength !== 64) throw new TypeError("v3 envelope signature must be Ed25519");
7450
+ const envelope = { ...unsigned, signature: { signerDid: options.authority.ownerDid, algorithm: "Ed25519", value: toBase64Url(envelopeSignature) } };
7451
+ shareEnvelopeV3Schema.parse(envelope);
7452
+ const envelopeKey = generateKey();
7453
+ try {
7454
+ const sealed = await seal(textEncoder.encode(canonicalize(envelope)), envelopeKey);
7455
+ let url;
7456
+ let retention = options.expiresAt.toISOString();
7457
+ if (options.inline === true) url = await encodeInlineShareUrl({ origin: options.shareOrigin, ciphertext: sealed.blob, key32: envelopeKey });
7458
+ else {
7459
+ 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 });
7460
+ retention = uploaded.deleteAfter;
7461
+ url = encodeShareUrl({ origin: options.shareOrigin, ciphertextCid: uploaded.cid, key32: envelopeKey });
7462
+ }
7463
+ await options.publishBinding?.({
7464
+ version: 3,
7465
+ shareCid: sealed.cid,
7466
+ shareId: options.shareId,
7467
+ policyCid: created.policyCid,
7468
+ policyRootCid: policyRoot.cid,
7469
+ enforcementRootCid: enforcementRoot.cid,
7470
+ contentSourceDigestHex
7471
+ });
7472
+ const deliveryMaterial = { envelope, sealedEnvelope: toBase64Url(sealed.blob), envelopeKey: toBase64Url(envelopeKey), shareCid: sealed.cid };
7473
+ options.onDeliveryMaterial?.(deliveryMaterial);
7474
+ return publicationResult({ options, url, envelopeCid: sealed.cid, matcher, policyCid: created.policyCid, policyRootCid: policyRoot.cid, enforcementRootCid: enforcementRoot.cid, enforcerDid: registration.attestedEnforcerBinding.enforcerDid, expiry, retention, deliveryMaterial });
7475
+ } finally {
7476
+ envelopeKey.fill(0);
7477
+ }
7478
+ }
7479
+
7480
+ // src/policy-authority.ts
7481
+ var import_ed255196 = require("@noble/curves/ed25519");
7482
+
7483
+ // src/owner-policy.ts
7484
+ var import_ed255195 = require("@noble/curves/ed25519");
7485
+ var import_sha2563 = require("@noble/hashes/sha256");
7486
+
7125
7487
  // ../../node_modules/multiformats/dist/src/bases/base32.js
7126
7488
  var base322 = rfc46482({
7127
7489
  prefix: "b",
@@ -7190,18 +7552,6 @@ var base36upper2 = baseX2({
7190
7552
  alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
7191
7553
  });
7192
7554
 
7193
- // ../../node_modules/multiformats/dist/src/bases/base58.js
7194
- var base58btc2 = baseX2({
7195
- name: "base58btc",
7196
- prefix: "z",
7197
- alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
7198
- });
7199
- var base58flickr2 = baseX2({
7200
- name: "base58flickr",
7201
- prefix: "Z",
7202
- alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
7203
- });
7204
-
7205
7555
  // ../../node_modules/multiformats/dist/src/vendor/varint.js
7206
7556
  var encode_12 = encode4;
7207
7557
  var MSB2 = 128;
@@ -7275,25 +7625,25 @@ function encodingLength2(int) {
7275
7625
  }
7276
7626
 
7277
7627
  // ../../node_modules/multiformats/dist/src/hashes/digest.js
7278
- function create2(code3, digest4) {
7279
- const size = digest4.byteLength;
7628
+ function create2(code3, digest3) {
7629
+ const size = digest3.byteLength;
7280
7630
  const sizeOffset = encodingLength2(code3);
7281
7631
  const digestOffset = sizeOffset + encodingLength2(size);
7282
7632
  const bytes3 = new Uint8Array(digestOffset + size);
7283
7633
  encodeTo2(code3, bytes3, 0);
7284
7634
  encodeTo2(size, bytes3, sizeOffset);
7285
- bytes3.set(digest4, digestOffset);
7286
- return new Digest2(code3, size, digest4, bytes3);
7635
+ bytes3.set(digest3, digestOffset);
7636
+ return new Digest2(code3, size, digest3, bytes3);
7287
7637
  }
7288
7638
  function decode8(multihash) {
7289
7639
  const bytes3 = coerce3(multihash);
7290
7640
  const [code3, sizeOffset] = decode7(bytes3);
7291
7641
  const [size, digestOffset] = decode7(bytes3.subarray(sizeOffset));
7292
- const digest4 = bytes3.subarray(sizeOffset + digestOffset);
7293
- if (digest4.byteLength !== size) {
7642
+ const digest3 = bytes3.subarray(sizeOffset + digestOffset);
7643
+ if (digest3.byteLength !== size) {
7294
7644
  throw new Error("Incorrect length");
7295
7645
  }
7296
- return new Digest2(code3, size, digest4, bytes3);
7646
+ return new Digest2(code3, size, digest3, bytes3);
7297
7647
  }
7298
7648
  function equals4(a, b) {
7299
7649
  if (a === b) {
@@ -7311,10 +7661,10 @@ var Digest2 = class {
7311
7661
  /**
7312
7662
  * Creates a multihash digest.
7313
7663
  */
7314
- constructor(code3, size, digest4, bytes3) {
7664
+ constructor(code3, size, digest3, bytes3) {
7315
7665
  this.code = code3;
7316
7666
  this.size = size;
7317
- this.digest = digest4;
7667
+ this.digest = digest3;
7318
7668
  this.bytes = bytes3;
7319
7669
  }
7320
7670
  };
@@ -7397,8 +7747,8 @@ var CID2 = class _CID2 {
7397
7747
  toV1() {
7398
7748
  switch (this.version) {
7399
7749
  case 0: {
7400
- const { code: code3, digest: digest4 } = this.multihash;
7401
- const multihash = create2(code3, digest4);
7750
+ const { code: code3, digest: digest3 } = this.multihash;
7751
+ const multihash = create2(code3, digest3);
7402
7752
  return _CID2.createV1(this.code, multihash);
7403
7753
  }
7404
7754
  case 1: {
@@ -7452,8 +7802,8 @@ var CID2 = class _CID2 {
7452
7802
  return new _CID2(version, code3, multihash, bytes3 ?? encodeCID2(version, code3, multihash.bytes));
7453
7803
  } else if (value[cidSymbol2] === true) {
7454
7804
  const { version, multihash, code: code3 } = value;
7455
- const digest4 = decode8(multihash);
7456
- return _CID2.create(version, code3, digest4);
7805
+ const digest3 = decode8(multihash);
7806
+ return _CID2.create(version, code3, digest3);
7457
7807
  } else {
7458
7808
  return null;
7459
7809
  }
@@ -7463,11 +7813,11 @@ var CID2 = class _CID2 {
7463
7813
  * @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
7464
7814
  * @param digest - (Multi)hash of the of the content.
7465
7815
  */
7466
- static create(version, code3, digest4) {
7816
+ static create(version, code3, digest3) {
7467
7817
  if (typeof code3 !== "number") {
7468
7818
  throw new Error("String codecs are no longer supported");
7469
7819
  }
7470
- if (!(digest4.bytes instanceof Uint8Array)) {
7820
+ if (!(digest3.bytes instanceof Uint8Array)) {
7471
7821
  throw new Error("Invalid digest");
7472
7822
  }
7473
7823
  switch (version) {
@@ -7475,12 +7825,12 @@ var CID2 = class _CID2 {
7475
7825
  if (code3 !== DAG_PB_CODE2) {
7476
7826
  throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE2}) block encoding`);
7477
7827
  } else {
7478
- return new _CID2(version, code3, digest4, digest4.bytes);
7828
+ return new _CID2(version, code3, digest3, digest3.bytes);
7479
7829
  }
7480
7830
  }
7481
7831
  case 1: {
7482
- const bytes3 = encodeCID2(version, code3, digest4.bytes);
7483
- return new _CID2(version, code3, digest4, bytes3);
7832
+ const bytes3 = encodeCID2(version, code3, digest3.bytes);
7833
+ return new _CID2(version, code3, digest3, bytes3);
7484
7834
  }
7485
7835
  default: {
7486
7836
  throw new Error("Invalid version");
@@ -7490,8 +7840,8 @@ var CID2 = class _CID2 {
7490
7840
  /**
7491
7841
  * Simplified version of `create` for CIDv0.
7492
7842
  */
7493
- static createV0(digest4) {
7494
- return _CID2.create(0, DAG_PB_CODE2, digest4);
7843
+ static createV0(digest3) {
7844
+ return _CID2.create(0, DAG_PB_CODE2, digest3);
7495
7845
  }
7496
7846
  /**
7497
7847
  * Simplified version of `create` for CIDv1.
@@ -7499,8 +7849,8 @@ var CID2 = class _CID2 {
7499
7849
  * @param code - Content encoding format code.
7500
7850
  * @param digest - Multihash of the content.
7501
7851
  */
7502
- static createV1(code3, digest4) {
7503
- return _CID2.create(1, code3, digest4);
7852
+ static createV1(code3, digest3) {
7853
+ return _CID2.create(1, code3, digest3);
7504
7854
  }
7505
7855
  /**
7506
7856
  * Decoded a CID from its binary representation. The byte array must contain
@@ -7533,8 +7883,8 @@ var CID2 = class _CID2 {
7533
7883
  throw new Error("Incorrect length");
7534
7884
  }
7535
7885
  const digestBytes3 = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
7536
- const digest4 = new Digest2(specs.multihashCode, specs.digestSize, digestBytes3, multihashBytes);
7537
- const cid2 = specs.version === 0 ? _CID2.createV0(digest4) : _CID2.createV1(specs.codec, digest4);
7886
+ const digest3 = new Digest2(specs.multihashCode, specs.digestSize, digestBytes3, multihashBytes);
7887
+ const cid2 = specs.version === 0 ? _CID2.createV0(digest3) : _CID2.createV1(specs.codec, digest3);
7538
7888
  return [cid2, bytes3.subarray(specs.size)];
7539
7889
  }
7540
7890
  /**
@@ -7686,10 +8036,10 @@ function fromB64(value) {
7686
8036
  throw new Error("base64url decoding is unavailable");
7687
8037
  }
7688
8038
  function cid(bytesValue) {
7689
- return CID2.createV1(code2, create2(SHA256_CODE2, (0, import_sha2562.sha256)(bytesValue))).toString(base322.encoder);
8039
+ return CID2.createV1(code2, create2(SHA256_CODE2, (0, import_sha2563.sha256)(bytesValue))).toString(base322.encoder);
7690
8040
  }
7691
8041
  function digest(bytesValue) {
7692
- return b64((0, import_sha2562.sha256)(bytesValue));
8042
+ return b64((0, import_sha2563.sha256)(bytesValue));
7693
8043
  }
7694
8044
  function didKeyFromEd25519PublicKey2(publicKey) {
7695
8045
  if (publicKey.length !== 32) throw new Error("share key public key must be 32 bytes");
@@ -7880,368 +8230,8 @@ function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
7880
8230
  return validateOwnerSharePolicyRegistration(value, expected);
7881
8231
  }
7882
8232
 
7883
- // src/authorization.ts
7884
- async function authorizeShare(input) {
7885
- if (input.resumeToken !== void 0) {
7886
- if (input.resumeToken.length < 16 || input.resumeToken.length > 512) {
7887
- return { state: "denied", reason: "rejected" };
7888
- }
7889
- return input.adapter.resume({
7890
- envelope: input.envelope,
7891
- method: input.method,
7892
- resumeToken: input.resumeToken,
7893
- ...input.proof === void 0 ? {} : { proof: input.proof }
7894
- });
7895
- }
7896
- return input.adapter.begin({ envelope: input.envelope, method: input.method });
7897
- }
7898
- function authorizationMethodForTarget(target) {
7899
- if (target.kind === "recipientDid") return "openkey-device";
7900
- if (target.kind === "email") return "email-claim";
7901
- if (target.kind === "emailDomain") return "email-claim";
7902
- return void 0;
7903
- }
7904
-
7905
- // src/targets.ts
7906
- function validEmail(value) {
7907
- 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);
7908
- }
7909
- function validDomain(value) {
7910
- 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);
7911
- }
7912
- function validRecipientDid(value) {
7913
- if (value.length === 0 || value.length > 2048 || /[\u0000-\u0020\u007f]/.test(value)) return false;
7914
- const parts = value.split(":");
7915
- if (parts.length < 3 || parts[0] !== "did" || !/^[a-z0-9]+$/.test(parts[1] ?? "")) return false;
7916
- const identifier = parts.slice(2);
7917
- if (identifier.some((part) => part.length === 0)) return false;
7918
- if (parts[1] === "web") {
7919
- const host = identifier[0] ?? "";
7920
- if (host.length > 253 || host.split(".").some((label) => !label || label.length > 63 || !/^[A-Za-z0-9-]+$/.test(label) || label.startsWith("-") || label.endsWith("-"))) return false;
7921
- return identifier.slice(1).every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
7922
- }
7923
- if (parts[1] === "pkh") return identifier.length >= 3 && identifier.every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
7924
- if (parts[1] === "key") {
7925
- try {
7926
- const bytes3 = base58btc2.decode(identifier.join(":"));
7927
- return bytes3.length === 34 && bytes3[0] === 237 && bytes3[1] === 1;
7928
- } catch {
7929
- return false;
7930
- }
7931
- }
7932
- return false;
7933
- }
7934
- function normalizeShareTarget(target) {
7935
- if (target.kind === "bearer") return target;
7936
- if (target.kind === "recipientDid") {
7937
- if (!validRecipientDid(target.did)) throw new TypeError("recipient DID is invalid");
7938
- return { kind: target.kind, did: target.did };
7939
- }
7940
- if (target.kind === "email") {
7941
- if (!validEmail(target.address)) throw new TypeError("recipient email is invalid");
7942
- const at = target.address.lastIndexOf("@");
7943
- return { kind: target.kind, address: `${target.address.slice(0, at)}@${target.address.slice(at + 1).toLowerCase()}` };
7944
- }
7945
- if (!validDomain(target.domain)) throw new TypeError("recipient email domain is invalid");
7946
- return { kind: target.kind, domain: target.domain.toLowerCase() };
7947
- }
7948
- function targetAuthorizationMethod(target) {
7949
- return authorizationMethodForTarget(target);
7950
- }
7951
- async function publishTargetShare(input) {
7952
- const target = normalizeShareTarget(input.target);
7953
- if (target.kind === "bearer") return publishShare(input);
7954
- if (input.targetAdapter === void 0) {
7955
- return {
7956
- state: "authorization-required",
7957
- method: targetAuthorizationMethod(target)
7958
- };
7959
- }
7960
- const source = input.source instanceof Uint8Array ? input.source.slice() : await (async () => {
7961
- const chunks = [];
7962
- let size = 0;
7963
- for await (const chunk of input.source) {
7964
- if (!(chunk instanceof Uint8Array)) throw new TypeError("addressed publication source yielded invalid bytes");
7965
- size += chunk.byteLength;
7966
- if (size > (input.maxBytes ?? 100 * 1024 * 1024)) throw new TypeError("addressed publication exceeds maxBytes");
7967
- chunks.push(chunk.slice());
7968
- }
7969
- const bytes3 = new Uint8Array(size);
7970
- let offset = 0;
7971
- for (const chunk of chunks) {
7972
- bytes3.set(chunk, offset);
7973
- offset += chunk.byteLength;
7974
- }
7975
- return bytes3;
7976
- })();
7977
- const files = input.files === void 0 || input.files.length === 0 ? [{ bytes: source }] : input.files;
7978
- const limit = input.maxBytes ?? SHARE_CONTENT_LIMIT;
7979
- let totalBytes = 0;
7980
- for (const file of files) {
7981
- totalBytes += file.bytes.byteLength;
7982
- if (!Number.isSafeInteger(totalBytes) || totalBytes > limit) {
7983
- throw new SharePublishError("max-bytes-exceeded", "addressed publication exceeds the combined byte limit");
7984
- }
7985
- }
7986
- return input.targetAdapter.publish({
7987
- source,
7988
- filename: input.filename,
7989
- ...input.files === void 0 ? {} : { files: input.files },
7990
- ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
7991
- ...input.resourceKind === void 0 ? {} : { resourceKind: input.resourceKind },
7992
- ...input.actions === void 0 ? {} : { actions: input.actions },
7993
- target,
7994
- expiresAt: input.expiresAt ?? new Date((input.now?.() ?? Date.now()) + 7 * 24 * 60 * 60 * 1e3),
7995
- origin: input.origin,
7996
- ...input.inline === void 0 ? {} : { inline: input.inline },
7997
- upload: {
7998
- ...input.registryBaseUrl === void 0 ? {} : { registryBaseUrl: input.registryBaseUrl },
7999
- ...input.fetchFn === void 0 ? {} : { fetchFn: input.fetchFn },
8000
- ...input.authorizeUpload === void 0 ? {} : { authorizeUpload: input.authorizeUpload },
8001
- ...input.authorizationOrigin === void 0 ? {} : { authorizationOrigin: input.authorizationOrigin },
8002
- ...input.credentials === void 0 ? {} : { credentials: input.credentials },
8003
- ...input.allowInsecureRegistry === void 0 ? {} : { allowInsecureRegistry: input.allowInsecureRegistry },
8004
- ...input.uploadBlob === void 0 ? {} : { uploadBlob: input.uploadBlob }
8005
- },
8006
- ...input.notify === void 0 ? {} : { notify: input.notify }
8007
- });
8008
- }
8009
-
8010
- // src/addressed-publish.ts
8011
- var ENVELOPE_DOMAIN = "xyz.tinycloud.share/envelope/v2\0";
8012
- function targetMatcher(target) {
8013
- if (target.kind === "recipientDid") return { kind: "recipientDid", value: target.did };
8014
- if (target.kind === "email") return { kind: "exactEmail", value: target.address };
8015
- return { kind: "emailDomain", value: target.domain };
8016
- }
8017
- function targetKind(target) {
8018
- return target.kind;
8019
- }
8020
- function assertSafeInput(input) {
8021
- if (!/^[A-Za-z0-9_-]{16,128}$/.test(input.shareId)) throw new TypeError("addressed share id is invalid");
8022
- if (input.filename.length === 0 || input.filename === "." || input.filename === ".." || /[/\\\u0000-\u001f\u007f]/.test(input.filename)) throw new TypeError("addressed filename is invalid");
8023
- if (!Number.isSafeInteger(input.byteLength) || input.byteLength < 0 || input.byteLength > SHARE_CONTENT_LIMIT) throw new TypeError("addressed content length is invalid");
8024
- if (input.actions.length === 0 || input.policyActions.length === 0) throw new TypeError("addressed share actions are empty");
8025
- const expiry = input.expiresAt.getTime();
8026
- if (!Number.isFinite(expiry) || expiry <= Date.now()) throw new TypeError("addressed share expiry must be in the future");
8027
- 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");
8028
- if (input.contentSource.kind !== "kv") throw new TypeError("addressed policy publication requires a KV content source");
8029
- }
8030
- async function sha2564(value) {
8031
- return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", value)));
8032
- }
8033
- function publicationResult(input) {
8034
- const result = {
8035
- protocol: "tinycloud-share",
8036
- version: SHARE_PUBLISH_RESULT_VERSION,
8037
- url: input.url,
8038
- link: { kind: input.options.inline === true ? "inline" : "compact", cid: input.envelopeCid },
8039
- metadata: {
8040
- protocol: "tinycloud-share",
8041
- version: 1,
8042
- shareId: input.options.shareId,
8043
- origin: input.options.shareOrigin,
8044
- target: {
8045
- kind: targetKind(input.options.target),
8046
- origin: input.options.nodeOrigin,
8047
- nodeAudience: input.options.nodeAudience,
8048
- spaceId: input.options.spaceId
8049
- },
8050
- resource: { ...input.options.resource },
8051
- actions: [...input.options.actions],
8052
- expiresAt: input.options.expiresAt.toISOString(),
8053
- display: { filename: input.options.filename },
8054
- recipientMatcher: { ...input.matcher },
8055
- registrationCid: input.registration.registrationCid,
8056
- policyCid: input.policyCid,
8057
- ownerDelegationCid: input.registration.ownerDelegationCid,
8058
- enforcementDelegationCid: input.enforcementDelegationCid,
8059
- ownerDid: input.registration.ownerDid,
8060
- shareKeyDid: input.shareKeyDid,
8061
- enforcerDid: input.registration.enforcerDid,
8062
- envelopeCid: input.envelopeCid,
8063
- shareCid: input.shareCid
8064
- },
8065
- registryDeleteAfter: input.retention
8066
- };
8067
- Object.defineProperty(result, "toJSON", { enumerable: false, value: () => redactPublishedShare(result) });
8068
- Object.defineProperty(result, "url", { enumerable: false, value: input.url });
8069
- return result;
8070
- }
8071
- async function publishAddressedShare(options) {
8072
- assertSafeInput(options);
8073
- const target = normalizeShareTarget(options.target);
8074
- if (target.kind === "bearer") throw new TypeError("addressed target is required");
8075
- if (options.contentSource.kind !== "kv") throw new TypeError("addressed policy publication requires a KV content source");
8076
- const contentSource = options.contentSource;
8077
- const matcher = targetMatcher(target);
8078
- const expiresAt = options.expiresAt.toISOString();
8079
- const contentSourceDigest = options.contentSourceDigest ?? await sha2564(new TextEncoder().encode(canonicalize(contentSource)));
8080
- const shareKey = await createDelegatedShareKey({ extractable: false });
8081
- let envelopeKey;
8082
- try {
8083
- const permissions = [
8084
- {
8085
- service: "tinycloud.kv",
8086
- path: options.resource.kind === "prefix" ? `${options.resource.path.replace(/\/+$/, "")}/` : options.resource.path,
8087
- actions: [...options.policyActions]
8088
- },
8089
- ...options.decryption === void 0 ? [] : [{
8090
- service: "tinycloud.encryption",
8091
- path: options.decryption.networkId,
8092
- actions: [options.decryption.action]
8093
- }]
8094
- ];
8095
- const ownerDelegation = await options.authority.createOwnerDelegation({
8096
- delegateDid: shareKey.did,
8097
- spaceId: options.spaceId,
8098
- permissions,
8099
- expiresAt: options.expiresAt
8100
- });
8101
- const policy = {
8102
- type: "TinyCloudSharePolicy",
8103
- version: 2,
8104
- shareId: options.shareId,
8105
- ownerDid: options.authority.ownerDid,
8106
- shareKeyDid: shareKey.did,
8107
- recipientMatcher: matcher,
8108
- target: {
8109
- origin: options.nodeOrigin,
8110
- nodeAudience: options.nodeAudience,
8111
- enforcerDid: options.enforcerDid,
8112
- spaceId: options.spaceId
8113
- },
8114
- resource: { ...options.resource },
8115
- actions: [...options.policyActions],
8116
- ...options.decryption === void 0 ? {} : { decryption: options.decryption },
8117
- contentSource,
8118
- contentSourceDigest,
8119
- ownerDelegationCid: ownerDelegation.delegationCid,
8120
- expiresAt
8121
- };
8122
- const canonicalPolicy = await canonicalOwnerSharePolicy(policy);
8123
- const policyProof = toBase64Url(await shareKey.sign(canonicalPolicy.bytes));
8124
- const enforcementDelegation = await createPolicyEnforcementDelegation({
8125
- ownerDelegation,
8126
- shareKey,
8127
- enforcerDid: options.enforcerDid,
8128
- policyCid: canonicalPolicy.cid,
8129
- shareId: options.shareId,
8130
- spaceId: options.spaceId,
8131
- nodeAudience: options.nodeAudience,
8132
- path: options.resource.path,
8133
- actions: options.policyActions,
8134
- contentSourceDigest,
8135
- expiresAt
8136
- });
8137
- const registration = await options.authority.registerOwnerSharePolicy({
8138
- policy: { bytes: canonicalPolicy.bytes, cid: canonicalPolicy.cid, proof: policyProof },
8139
- ownerDelegation,
8140
- enforcementDelegation,
8141
- contentSourceDigest
8142
- });
8143
- const authorityMaterialDigest = await sha2564(fromBase64Url(enforcementDelegation.dagCbor));
8144
- const authorityTarget = {
8145
- origin: options.nodeOrigin,
8146
- nodeAudience: options.nodeAudience,
8147
- enforcerDid: options.enforcerDid,
8148
- spaceId: options.spaceId
8149
- };
8150
- const envelopeIdentity = {
8151
- schema: "xyz.tinycloud.share/envelope/v2",
8152
- version: 2,
8153
- shareId: options.shareId,
8154
- delegationCid: ownerDelegation.delegationCid,
8155
- policyCid: canonicalPolicy.cid,
8156
- target: authorityTarget,
8157
- resource: options.resource,
8158
- actions: options.policyActions,
8159
- ...options.decryption === void 0 ? {} : { decryption: options.decryption },
8160
- contentSource,
8161
- contentSourceDigest,
8162
- expiresAt
8163
- };
8164
- const envelopeCid = await computeCid(new TextEncoder().encode(canonicalize(envelopeIdentity)));
8165
- const shareCid = await computeCid(new TextEncoder().encode(canonicalize({ version: 2, shareId: options.shareId, policyCid: canonicalPolicy.cid, envelopeCid })));
8166
- const outerUnsigned = { ...envelopeIdentity, envelopeCid, shareCid };
8167
- const outerSignature = toBase64Url(await shareKey.sign(new TextEncoder().encode(`${ENVELOPE_DOMAIN}${canonicalize(outerUnsigned)}`)));
8168
- const unsigned = {
8169
- version: 2,
8170
- shareId: options.shareId,
8171
- recipientMatcher: matcher,
8172
- ...options.deliveryEmail === void 0 ? {} : { deliveryEmail: options.deliveryEmail },
8173
- actions: [...options.actions],
8174
- resource: { ...options.resource },
8175
- target: { origin: options.nodeOrigin, nodeAudience: options.nodeAudience, spaceId: options.spaceId },
8176
- delegationCid: ownerDelegation.delegationCid,
8177
- authorityMaterialHandle: registration.registration.registrationCid,
8178
- authorityMaterialDigest,
8179
- contentSource,
8180
- contentSourceDigest,
8181
- authorizationTarget: { kind: "policy", policyCid: canonicalPolicy.cid, policyBytes: toBase64Url(canonicalPolicy.bytes) },
8182
- display: { filename: options.filename },
8183
- expiry: expiresAt,
8184
- encrypted: true,
8185
- metadata: {
8186
- mediaType: options.mediaType,
8187
- byteLength: options.byteLength,
8188
- filename: options.filename,
8189
- ...options.mediaType.startsWith("text/") ? { encoding: "utf-8" } : {},
8190
- ...options.artifact === void 0 ? {} : { artifact: options.artifact }
8191
- },
8192
- ownerAuthority: {
8193
- registrationCid: registration.registration.registrationCid,
8194
- shareCid,
8195
- envelopeCid,
8196
- enforcementDelegation,
8197
- registrationReceipt: registration,
8198
- outerEnvelope: {
8199
- ...outerUnsigned,
8200
- signature: { signerDid: shareKey.did, algorithm: "Ed25519", value: outerSignature }
8201
- }
8202
- }
8203
- };
8204
- unsignedShareEnvelopeV2Schema.parse(unsigned);
8205
- const envelopeSignature = toBase64Url(await shareKey.sign(new TextEncoder().encode(`${ENVELOPE_DOMAIN}${canonicalize(unsigned)}`)));
8206
- const envelope = { ...unsigned, signature: { signerDid: shareKey.did, algorithm: "Ed25519", value: envelopeSignature } };
8207
- shareEnvelopeV2Schema.parse(envelope);
8208
- envelopeKey = generateKey();
8209
- const sealed = await seal(new TextEncoder().encode(canonicalize(envelope)), envelopeKey);
8210
- let url;
8211
- let retention = expiresAt;
8212
- if (options.inline === true) {
8213
- url = await encodeInlineShareUrl({ origin: options.shareOrigin, ciphertext: sealed.blob, key32: envelopeKey });
8214
- } else {
8215
- const uploaded = await uploadShareBlob({
8216
- source: new Uint8Array([1]),
8217
- filename: options.filename,
8218
- origin: options.shareOrigin,
8219
- ...options.upload
8220
- }, { blob: sealed.blob, cid: sealed.cid, deleteAfter: expiresAt, contentLength: sealed.blob.byteLength });
8221
- retention = uploaded.deleteAfter;
8222
- url = encodeShareUrl({ origin: options.shareOrigin, ciphertextCid: uploaded.cid, key32: envelopeKey });
8223
- }
8224
- return publicationResult({
8225
- options,
8226
- url,
8227
- envelopeCid: sealed.cid,
8228
- shareCid,
8229
- matcher,
8230
- registration: registration.registration,
8231
- policyCid: canonicalPolicy.cid,
8232
- enforcementDelegationCid: enforcementDelegation.cid,
8233
- shareKeyDid: shareKey.did,
8234
- retention
8235
- });
8236
- } finally {
8237
- shareKey.clear();
8238
- envelopeKey?.fill(0);
8239
- }
8240
- }
8241
-
8242
8233
  // src/policy-authority.ts
8243
- var import_ed255196 = require("@noble/curves/ed25519");
8244
- var ENVELOPE_DOMAIN2 = "xyz.tinycloud.share/envelope/v2\0";
8234
+ var ENVELOPE_DOMAIN = "xyz.tinycloud.share/envelope/v2\0";
8245
8235
  function record(value, keys, label) {
8246
8236
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
8247
8237
  const output = value;
@@ -8322,7 +8312,7 @@ async function verifyOuterEnvelope(value, envelope, policyCid, expectedEnforcerD
8322
8312
  const signatureBytes = fromBase64Url(requiredString(signature.value, "outer signature"));
8323
8313
  if (signatureBytes.length !== 64 || !import_ed255196.ed25519.verify(
8324
8314
  signatureBytes,
8325
- new TextEncoder().encode(`${ENVELOPE_DOMAIN2}${canonicalize(unsigned)}`),
8315
+ new TextEncoder().encode(`${ENVELOPE_DOMAIN}${canonicalize(unsigned)}`),
8326
8316
  ed25519PublicKeyFromDidKey(envelope.signature.signerDid),
8327
8317
  { zip215: false }
8328
8318
  )) return void 0;
@@ -8387,13 +8377,13 @@ function createRegisteredPolicyAuthority(options) {
8387
8377
  }
8388
8378
 
8389
8379
  // src/cache.ts
8390
- var import_sha2563 = require("@noble/hashes/sha256");
8380
+ var import_sha2564 = require("@noble/hashes/sha256");
8391
8381
  function cacheKey(key) {
8392
8382
  if (!key.cid || !key.expiresAt) throw new Error("share cache keys require CID and expiry");
8393
8383
  return `${key.cid}\0${key.expiresAt}`;
8394
8384
  }
8395
8385
  function digest2(bytes3) {
8396
- return (0, import_sha2563.sha256)(bytes3);
8386
+ return (0, import_sha2564.sha256)(bytes3);
8397
8387
  }
8398
8388
  function equalBytes(left, right) {
8399
8389
  if (left.byteLength !== right.byteLength) return false;
@@ -8595,6 +8585,7 @@ function historyRecordForPublishedShare(result, now = /* @__PURE__ */ new Date()
8595
8585
  registeredAt: now.toISOString(),
8596
8586
  expiresAt: result.metadata.expiresAt,
8597
8587
  link: result.url,
8588
+ ...result.deliveryMaterial === void 0 ? {} : { deliveryMaterial: result.deliveryMaterial },
8598
8589
  ...result.metadata.display.filename === void 0 ? {} : { filename: result.metadata.display.filename }
8599
8590
  };
8600
8591
  }
@@ -8779,11 +8770,11 @@ async function notifyShare(input) {
8779
8770
  }
8780
8771
  async function defaultIdempotencyKey(shareId, recipient) {
8781
8772
  const canonicalRecipient = canonicalize(recipient.trim().toLowerCase());
8782
- const digest4 = new Uint8Array(await crypto.subtle.digest(
8773
+ const digest3 = new Uint8Array(await crypto.subtle.digest(
8783
8774
  "SHA-256",
8784
8775
  new TextEncoder().encode(canonicalRecipient)
8785
8776
  ));
8786
- return `tinycloud-share:${shareId}:${toBase64Url(digest4)}`;
8777
+ return `tinycloud-share:${shareId}:${toBase64Url(digest3)}`;
8787
8778
  }
8788
8779
 
8789
8780
  // src/lifecycle.ts
@@ -8840,7 +8831,7 @@ async function migrateShare(input) {
8840
8831
 
8841
8832
  // src/recipient.ts
8842
8833
  var import_ed255198 = require("@noble/curves/ed25519");
8843
- var import_sha2564 = require("@noble/hashes/sha256");
8834
+ var import_sha2565 = require("@noble/hashes/sha256");
8844
8835
 
8845
8836
  // src/protocol.ts
8846
8837
  var SHARE_V2_PROTOCOL = Object.freeze({
@@ -8931,12 +8922,6 @@ function fromBase64(value, label) {
8931
8922
  if (toBase64(out) !== value) throw new Error(`${label} is invalid`);
8932
8923
  return out;
8933
8924
  }
8934
- async function digest3(value) {
8935
- return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonicalize(value)))));
8936
- }
8937
- async function digestText2(value) {
8938
- return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value))));
8939
- }
8940
8925
  async function digestBytes2(value) {
8941
8926
  return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", value)));
8942
8927
  }
@@ -8946,24 +8931,9 @@ function trustedPublicKey(value) {
8946
8931
  }
8947
8932
  return value.invitationPublicKey;
8948
8933
  }
8949
- async function verifyWrapped(value, key, domain, trust) {
8950
- const wrapper = object2(value, `${key} response`);
8951
- if (Object.keys(wrapper).length !== 2 || !Object.hasOwn(wrapper, key) || !Object.hasOwn(wrapper, "proof")) throw new Error(`${key} response is invalid`);
8952
- const artifact = object2(wrapper[key], `${key} artifact`);
8953
- const proof = object2(wrapper.proof, `${key} proof`);
8954
- if (proof.alg !== "EdDSA" || proof.kid !== trust.invitationKid) throw new Error(`${key} proof is invalid`);
8955
- if (!import_ed255198.ed25519.verify(bytes2(proof.signature, `${key} signature`), new TextEncoder().encode(`${domain}${canonicalize(artifact)}`), trustedPublicKey(trust))) throw new Error(`${key} proof is invalid`);
8956
- return artifact;
8957
- }
8958
8934
  function nativeAction(action) {
8959
8935
  return action === "list" ? "tinycloud.kv/list" : action === "edit" ? "tinycloud.kv/put" : "tinycloud.kv/get";
8960
8936
  }
8961
- function uiAction(action) {
8962
- return action === "tinycloud.kv/list" ? "list" : action === "tinycloud.kv/put" ? "edit" : "read";
8963
- }
8964
- function selectedAction(envelope) {
8965
- return envelope.actions.includes("list") ? "tinycloud.kv/list" : envelope.actions.includes("edit") ? "tinycloud.kv/put" : "tinycloud.kv/get";
8966
- }
8967
8937
  function policyAttenuationForV3(envelope) {
8968
8938
  const policy = object2(envelope.policy, "v3 policy");
8969
8939
  if (!Array.isArray(policy.capabilityCeiling)) throw new Error("v3 policy capability ceiling is invalid");
@@ -9033,11 +9003,11 @@ function verifyV3PolicyAuthorization(input) {
9033
9003
  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");
9034
9004
  return compact;
9035
9005
  }
9036
- function hex2(value) {
9006
+ function hex3(value) {
9037
9007
  return [...value].map((byte) => byte.toString(16).padStart(2, "0")).join("");
9038
9008
  }
9039
9009
  function canonicalHashHex(value) {
9040
- return hex2((0, import_sha2564.sha256)(new TextEncoder().encode(canonicalize(value))));
9010
+ return hex3((0, import_sha2565.sha256)(new TextEncoder().encode(canonicalize(value))));
9041
9011
  }
9042
9012
  async function aesGcmDecrypt(key, blob) {
9043
9013
  if (key.length !== 32 || blob.length < 28) throw new Error("encrypted content is malformed");
@@ -9069,25 +9039,6 @@ function parseV3InlineEncryptedEnvelope(bytes3, expected) {
9069
9039
  }
9070
9040
  return record2;
9071
9041
  }
9072
- async function verifyDetachedResponse(response, trust) {
9073
- let value;
9074
- try {
9075
- value = await response.clone().json();
9076
- } catch {
9077
- throw new Error("share read response is invalid");
9078
- }
9079
- const record2 = object2(value, "share read response");
9080
- const proof = object2(record2.proof, "share read detached proof");
9081
- if (proof.alg !== "EdDSA" || proof.kid !== trust.invitationKid) throw new Error("share read detached proof is invalid");
9082
- const unsigned = { ...record2 };
9083
- delete unsigned.proof;
9084
- if (!import_ed255198.ed25519.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");
9085
- }
9086
- async function post(fetchFn, origin, path, body) {
9087
- const response = await fetchFn(new URL(path, origin), { method: "POST", redirect: "error", headers: { accept: "application/json", "content-type": "application/json" }, body: JSON.stringify(body) });
9088
- if (!response.ok) throw new Error("share authority rejected the request");
9089
- return response.json();
9090
- }
9091
9042
  var ShareRecipientClient = class {
9092
9043
  constructor(options) {
9093
9044
  this.options = options;
@@ -9118,72 +9069,12 @@ var ShareRecipientClient = class {
9118
9069
  v3ContentKey;
9119
9070
  v3ContentEnvelope;
9120
9071
  async beginChallenge(envelope) {
9121
- const authority = envelope.ownerAuthority;
9122
- if (authority === void 0) throw new Error("addressed owner authority is required");
9123
- const outer = object2(authority.outerEnvelope, "owner authority outer envelope");
9124
- const enforcement = object2(authority.enforcementDelegation, "owner authority enforcement delegation");
9125
- const target = object2(outer.target, "owner authority target");
9126
- const outerResource = object2(outer.resource, "owner authority resource");
9127
- const source = object2(outer.contentSource, "owner authority content source");
9128
- 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");
9129
- const actions = [...outer.actions];
9130
- const action = selectedAction(envelope);
9131
- 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) };
9132
- const requestBodyDigest = await digest3(challengeBody);
9133
- const challenge = await verifyWrapped(await post(this.fetchFn, this.options.nodeOrigin, "/share/v2/policy/challenges", { ...challengeBody, requestBodyDigest }), "challenge", DOMAIN, this.options.trustedNode);
9134
- 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");
9135
- return challenge;
9072
+ void envelope;
9073
+ throw new Error("v2 Share recipient transport has been removed; use the embedded policy v3 envelope");
9136
9074
  }
9137
9075
  async establish(envelope) {
9138
- const authority = envelope.ownerAuthority;
9139
- if (authority === void 0) throw new Error("addressed owner authority is required");
9140
- const outer = object2(authority.outerEnvelope, "owner authority outer envelope");
9141
- const enforcement = object2(authority.enforcementDelegation, "owner authority enforcement delegation");
9142
- const target = object2(outer.target, "owner authority target");
9143
- const outerResource = object2(outer.resource, "owner authority resource");
9144
- const source = object2(outer.contentSource, "owner authority content source");
9145
- 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");
9146
- const actions = [...outer.actions];
9147
- const action = selectedAction(envelope);
9148
- 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) };
9149
- const requestBodyDigest = await digest3(challengeBody);
9150
- const challenge = await verifyWrapped(await post(this.fetchFn, this.options.nodeOrigin, "/share/v2/policy/challenges", { ...challengeBody, requestBodyDigest }), "challenge", DOMAIN, this.options.trustedNode);
9151
- 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");
9152
- if (this.options.buildPresentation === void 0) throw new Error("share presentation builder is required");
9153
- const material = await this.options.buildPresentation({ challenge, envelope, policy: {} });
9154
- this.holderProof = material.proof;
9155
- this.signer = material.sign;
9156
- this.nativeSigner = material.sign;
9157
- if (this.signer === void 0) throw new Error("share holder signer is required");
9158
- const presentation = {
9159
- type: "TinyCloudSharePolicyPresentation",
9160
- version: 2,
9161
- challengeId: challenge.challengeId,
9162
- nonce: challenge.nonce,
9163
- shareCid: authority.shareCid,
9164
- shareId: envelope.shareId,
9165
- delegationCid: envelope.delegationCid,
9166
- policyCid: challengeBody.policyCid,
9167
- contentSource: source,
9168
- contentSourceDigest: challengeBody.contentSourceDigest,
9169
- holderDid: material.holderDid,
9170
- targetOrigin: challengeBody.targetOrigin,
9171
- nodeAudience: challengeBody.nodeAudience,
9172
- ...challenge.enforcerDid === void 0 ? {} : { enforcerDid: challenge.enforcerDid },
9173
- credentialDigest: material.credentialDigest ?? await digestText2(material.credential),
9174
- action,
9175
- actions,
9176
- resource: challengeBody.resource,
9177
- requestBodyDigest,
9178
- issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
9179
- expiresAt: challenge.expiresAt,
9180
- jti: toBase64Url(crypto.getRandomValues(new Uint8Array(16)))
9181
- };
9182
- 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)}`))) };
9183
- 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);
9184
- 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");
9185
- this.session = { sessionId: session.sessionId, expiresAt: session.expiresAt, actions: actions.map(uiAction), resource: { kind: envelope.resource.kind, path: String(session.resource) } };
9186
- return this.session;
9076
+ void envelope;
9077
+ throw new Error("v2 Share recipient transport has been removed; use the embedded policy v3 envelope");
9187
9078
  }
9188
9079
  async authorize(envelope) {
9189
9080
  if (this.session === void 0) await this.establish(envelope);
@@ -9211,7 +9102,7 @@ var ShareRecipientClient = class {
9211
9102
  } catch {
9212
9103
  throw new Error("v3 attested Node audience is invalid");
9213
9104
  }
9214
- const challengeResponse = await this.fetchFn(new URL("/share/v3/policy/challenges", this.options.nodeOrigin), {
9105
+ const challengeResponse = await this.fetchFn(new URL("/policy/v3/challenges", this.options.nodeOrigin), {
9215
9106
  method: "POST",
9216
9107
  redirect: "error",
9217
9108
  headers: { accept: "application/json", "content-type": "application/json" },
@@ -9232,7 +9123,7 @@ var ShareRecipientClient = class {
9232
9123
  throw new Error(accountless ? "v4 ceremony requires a verified credential and requirement" : "v3 ceremony requires a claim");
9233
9124
  }
9234
9125
  this.options.onStage?.("policy-admission");
9235
- const delegationResponse = await this.fetchFn(new URL("/share/v3/policy/delegations", this.options.nodeOrigin), {
9126
+ const delegationResponse = await this.fetchFn(new URL("/policy/v3/delegations", this.options.nodeOrigin), {
9236
9127
  method: "POST",
9237
9128
  redirect: "error",
9238
9129
  headers: { accept: "application/json", "content-type": "application/json" },
@@ -9263,7 +9154,7 @@ var ShareRecipientClient = class {
9263
9154
  const receiverPublicKey = toBase64(import_ed255198.x25519.getPublicKey(receiverPrivateKey));
9264
9155
  const receiverPublicKeyHash = canonicalHashHex(receiverPublicKey);
9265
9156
  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 };
9266
- const bodyHash = hex2((0, import_sha2564.sha256)(new TextEncoder().encode(canonicalize(body))));
9157
+ const bodyHash = hex3((0, import_sha2565.sha256)(new TextEncoder().encode(canonicalize(body))));
9267
9158
  const session = verifyCompactUcanAuthorization(this.v3Authorization, this.session.sessionId);
9268
9159
  const now = Math.floor(Date.now() / 1e3);
9269
9160
  const invocation = await signCompactUcanAuthorization({
@@ -9283,7 +9174,7 @@ var ShareRecipientClient = class {
9283
9174
  if (!response.ok) throw new Error(`v3 decrypt invocation rejected (${response.status})`);
9284
9175
  const value = object2(await response.json(), "v3 decrypt response");
9285
9176
  const allowed = ["type", "targetNode", "networkId", "invocationCid", "encryptedSymmetricKeyHash", "receiverPublicKeyHash", "wrappedKey", "alg", "keyVersion", "requestHash", "nodeId", "nodeSignature"];
9286
- 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((0, import_sha2564.sha256)(new TextEncoder().encode(`${invocation.cid}${bodyHash}`))) || typeof value.wrappedKey !== "string" || typeof value.nodeSignature !== "string") throw new Error("v3 decrypt response binding is invalid");
9177
+ 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((0, import_sha2565.sha256)(new TextEncoder().encode(`${invocation.cid}${bodyHash}`))) || typeof value.wrappedKey !== "string" || typeof value.nodeSignature !== "string") throw new Error("v3 decrypt response binding is invalid");
9287
9178
  const unsigned = { ...value };
9288
9179
  delete unsigned.nodeSignature;
9289
9180
  const signature = fromBase64(value.nodeSignature, "v3 decrypt response signature");
@@ -9309,47 +9200,16 @@ var ShareRecipientClient = class {
9309
9200
  return new TextEncoder().encode(canonicalize({ ...this.v3ContentEnvelope, ciphertext: toBase64Url(await aesGcmEncrypt(this.v3ContentKey, bytes3)), metadata: { ...this.v3ContentEnvelope.metadata ?? {}, contentType: mediaType } }));
9310
9201
  }
9311
9202
  async resumeWithProof(envelope, resumeToken, proof) {
9312
- const material = object2(proof, "share authorization proof");
9313
- const presentation = object2(material.presentation, "share presentation");
9314
- const presentationProof = object2(material.presentationProof, "share presentation proof");
9315
- const nonce = material.nonce;
9316
- const credential = material.credential;
9317
- const holderDid = material.holderDid;
9318
- const holderBinding = material.holderBinding;
9319
- 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");
9320
- 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");
9321
- const session = await verifyWrapped(value, "session", SESSION_DOMAIN, this.options.trustedNode);
9322
- const authority = envelope.ownerAuthority;
9323
- 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");
9324
- const policyCid = envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "";
9325
- const actions = [...new Set(envelope.actions.map(nativeAction))].sort();
9326
- 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");
9327
- this.session = { sessionId: session.sessionId, expiresAt: session.expiresAt, actions: actions.map(uiAction), resource: { kind: envelope.resource.kind, path: String(session.resource) } };
9328
- this.holderProof = presentationProof;
9329
- this.signer ??= this.options.sign;
9330
- return this.authorize(envelope);
9203
+ void envelope;
9204
+ void resumeToken;
9205
+ void proof;
9206
+ throw new Error("v2 Share recipient transport has been removed; use the embedded policy v3 envelope");
9331
9207
  }
9332
9208
  async nativeInvoke(request) {
9333
9209
  if (this.session === void 0) throw new Error("share policy session is required");
9334
9210
  const envelope = this.options.envelope;
9335
9211
  if (envelope.version === 3) return this.nativeInvokeV3(request, envelope);
9336
- if (envelope.ownerAuthority === void 0 || this.signer === void 0 || this.holderProof === void 0) throw new Error("share holder signer is required");
9337
- const authority = envelope.ownerAuthority;
9338
- const action = request.action === "list" ? "tinycloud.kv/list" : request.action === "put" ? "tinycloud.kv/put" : request.action === "metadata" ? "tinycloud.kv/metadata" : "tinycloud.kv/get";
9339
- const resource = typeof request.resource?.path === "string" ? request.resource.path : this.session.resource.path;
9340
- const actions = [...new Set(this.session.actions.map(nativeAction).concat(action === "tinycloud.kv/metadata" ? [action] : []))].sort();
9341
- const bodyBytes = request.body === void 0 ? void 0 : Uint8Array.from(request.body);
9342
- const bodyDigest = bodyBytes === void 0 ? void 0 : toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", bodyBytes)));
9343
- const outer = object2(authority.outerEnvelope, "owner authority outer envelope");
9344
- const enforcement = object2(authority.enforcementDelegation, "owner authority enforcement delegation");
9345
- 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))) };
9346
- const requestBodyDigest = await digest3(invocationBase);
9347
- const invocation = { ...invocationBase, requestBodyDigest };
9348
- const proof = { ...this.holderProof, signature: toBase64Url(await this.signer(new TextEncoder().encode(`${INVOCATION_DOMAIN}${canonicalize(invocation)}`))) };
9349
- 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 };
9350
- 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 } }) });
9351
- if (response.ok) await verifyDetachedResponse(response, this.options.trustedNode);
9352
- return response;
9212
+ throw new Error("v2 Share invocation transport has been removed; use the embedded policy v3 envelope");
9353
9213
  }
9354
9214
  async nativeInvokeV3(request, envelope) {
9355
9215
  const signer = this.nativeSigner ?? this.signer;