@tinycloud/share-sdk 1.0.0-beta.7 → 1.0.0-beta.9

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.d.cts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { ShareEnvelopeV2, ShareEnvelopeV3, UnifiedPolicyCapability, ShareAction, UnifiedContentSource, PolicyCredentialRequirementV1 } from '@tinycloud/share-envelope';
2
2
  export { CheckBearerDelegationOptions, DelegationCheckResult, canonicalize, checkBearerDelegation, fromBase64Url, requiredResourceUri, resourceUriCovers, toBase64Url } from '@tinycloud/share-envelope';
3
3
 
4
+ declare function hasUnsafeFilenameCodePoint(value: string): boolean;
5
+ /** A single display/download filename, never a path. Returns the NFC form. */
6
+ declare function canonicalShareFilename(value: string): string;
7
+
4
8
  /** The only interactive boundary exposed by the headless SDK. */
5
9
  type ShareAuthorizationMethod = "openkey-device" | "email-claim" | "email-otp";
6
10
  interface ShareAuthorizationRequired {
@@ -613,7 +617,7 @@ interface PreparedAddressedShare {
613
617
  */
614
618
  declare function prepareAddressedShare(request: AddressedShareRequest): PreparedAddressedShare;
615
619
  /** Canonical application-neutral Policy/v3 addressed publisher shared by browser and CLI. */
616
- declare function publishAddressedShare(options: AddressedSharePublishOptions): Promise<PublishedShare>;
620
+ declare function publishAddressedShare(input: AddressedSharePublishOptions): Promise<PublishedShare>;
617
621
 
618
622
  interface ShareCacheKey {
619
623
  readonly cid: string;
@@ -972,12 +976,21 @@ interface ShareRecipientClientOptions {
972
976
  readonly sign?: (bytes: Uint8Array) => Promise<Uint8Array>;
973
977
  readonly signal?: AbortSignal;
974
978
  readonly onStage?: (stage: "policy-admission" | "delegation-import" | "invocation" | "decryption") => void;
975
- /** Previously admitted and imported ordinary policy delegation (account v3 fast path). */
979
+ /**
980
+ * A previously admitted and imported policy session (S0), optionally with
981
+ * the descendants that re-delegate it, in order, down to this holder.
982
+ */
976
983
  readonly policyAuthorization?: {
977
984
  readonly authorization: string;
978
985
  readonly cid: string;
986
+ readonly descendants?: readonly SharePolicyDelegationLink[];
979
987
  };
980
988
  }
989
+ /** One signed link of a policy delegation chain, as imported into the Node. */
990
+ interface SharePolicyDelegationLink {
991
+ readonly authorization: string;
992
+ readonly cid: string;
993
+ }
981
994
  interface SharePolicySession {
982
995
  readonly sessionId: string;
983
996
  readonly expiresAt: string;
@@ -1120,4 +1133,4 @@ declare function parseNativeShareUrl(value: string): string;
1120
1133
  /** Receive through the public SDK without creating another transport protocol. */
1121
1134
  declare function openNativeShare(sharing: NativeSharingService, link: string): Promise<unknown>;
1122
1135
 
1123
- export { type AddressedOwnerRootInput, type AddressedOwnerRootReceipt, type AddressedPolicyRegistrationInput, type AddressedPolicyRegistrationReceipt, type AddressedPublishAuthority, type AddressedSharePublishOptions, type AddressedShareRequest, type CreateOwnerDelegationParams, CredentialInvitationError, type CredentialInvitationErrorCode, type CredentialInvitationReceipt, type CredentialInvitationResult, DEFAULT_MAX_CONTENT_BLOB_BYTES, DEFAULT_MAX_SEALED_BLOB_BYTES, DEFAULT_SHARE_LIFETIME_MS, type DelegatedShareKey, EncryptedSenderShareHistory, type EncryptedShareHistoryStorage, MAX_CONTENT_BYTES, MemoryEncryptedShareHistoryStorage, MemorySenderShareKeyStorage, MemorySenderShareRecordStorage, MemoryShareCache, NATIVE_SHARE_FRAGMENT_PARAMETER, type NativeShareResult, type NativeSharingService, OWNER_SHARE_REGISTRATION_DOMAIN, type OwnerDelegationPermission, type OwnerDelegationReceipt, type OwnerShareAction, type OwnerShareDecryption, type OwnerShareMatcher, type OwnerSharePolicyRegistration, type OwnerSharePolicyRegistrationReceipt, type OwnerSharePolicyV2, type ParsedAddressedEnvelope, type PreparedAddressedShare, type PublishedShare, type PublishedShareDeliveryMaterial, type PublishedShareMetadata, type RegisterOwnerSharePolicyParams, SHARE_CONTENT_LIMIT, SHARE_PUBLISH_RESULT_VERSION, SHARE_RESULT_VERSION, SHARE_V2_PROTOCOL, type SenderShareKeyStorage, type SenderShareRecord, type SenderShareRecordStorage, type SenderShareRevocationScope, SenderShareStore, type ShareAuthorizationAdapter, type ShareAuthorizationDenied, type ShareAuthorizationMethod, type ShareAuthorizationReady, type ShareAuthorizationRequired, type ShareAuthorizationResult, type ShareAuthorizedContent, type ShareCache, type ShareCacheEntry, type ShareCacheKey, type ShareCacheMetadata, type ShareDeliveryAdapter, type ShareErrorCode, type ShareErrorInfo, type ShareFetchOptions, type ShareHistoryView, type ShareInspection, type ShareMetadata, type ShareNodeTrust, ShareNotifyError, type ShareNotifyInput, type ShareNotifyResult, type ShareNotifyState, type SharePolicyChallenge, type SharePolicyPublishAdapter, type SharePolicyRootRevocation, type SharePolicySession, type SharePresentationMaterial, SharePublishError, type SharePublishErrorCode, type SharePublishOptions, type SharePublishTarget, type ShareReceiveAuthorizationRequired, ShareReceiveError, type ShareReceiveOutcome, type ShareReceiveResult, ShareRecipientClient, type ShareRecipientClientOptions, type ShareRevocationAdapter, type ShareRevocationResult, type ShareTarget, type SignedDelegation, type TargetPublishAdapter, type TargetPublishInput, type TargetPublishOutcome, addressedCredentialRequirement, authorizationMethodForTarget, authorizeShare, canonicalOwnerSharePolicy, claimShare, computeOwnerShareRegistrationCid, createAddressedAuthorization, createDelegatedShareKey, createNativeShare, createPolicyEnforcementDelegation, createShareV2HolderBindingArtifact, deliverCredentialInvitation, historyRecordForPublishedShare, inspectShare, listShares, normalizeShareTarget, notifyShare, openNativeShare, parseAddressedEnvelope, parseNativeShareUrl, prepareAddressedShare, publishAddressedShare, publishPolicyShare, publishTargetShare, receiveShare, recipientMatchesShareRecord, redactPublishedShare, restoreDelegatedShareKey, resumeShareAuthorization, revokeShare, showShare, targetAuthorizationMethod, toShareErrorInfo, validateOwnerSharePolicyRegistration, validateOwnerSharePolicyRegistrationBytes };
1136
+ export { type AddressedOwnerRootInput, type AddressedOwnerRootReceipt, type AddressedPolicyRegistrationInput, type AddressedPolicyRegistrationReceipt, type AddressedPublishAuthority, type AddressedSharePublishOptions, type AddressedShareRequest, type CreateOwnerDelegationParams, CredentialInvitationError, type CredentialInvitationErrorCode, type CredentialInvitationReceipt, type CredentialInvitationResult, DEFAULT_MAX_CONTENT_BLOB_BYTES, DEFAULT_MAX_SEALED_BLOB_BYTES, DEFAULT_SHARE_LIFETIME_MS, type DelegatedShareKey, EncryptedSenderShareHistory, type EncryptedShareHistoryStorage, MAX_CONTENT_BYTES, MemoryEncryptedShareHistoryStorage, MemorySenderShareKeyStorage, MemorySenderShareRecordStorage, MemoryShareCache, NATIVE_SHARE_FRAGMENT_PARAMETER, type NativeShareResult, type NativeSharingService, OWNER_SHARE_REGISTRATION_DOMAIN, type OwnerDelegationPermission, type OwnerDelegationReceipt, type OwnerShareAction, type OwnerShareDecryption, type OwnerShareMatcher, type OwnerSharePolicyRegistration, type OwnerSharePolicyRegistrationReceipt, type OwnerSharePolicyV2, type ParsedAddressedEnvelope, type PreparedAddressedShare, type PublishedShare, type PublishedShareDeliveryMaterial, type PublishedShareMetadata, type RegisterOwnerSharePolicyParams, SHARE_CONTENT_LIMIT, SHARE_PUBLISH_RESULT_VERSION, SHARE_RESULT_VERSION, SHARE_V2_PROTOCOL, type SenderShareKeyStorage, type SenderShareRecord, type SenderShareRecordStorage, type SenderShareRevocationScope, SenderShareStore, type ShareAuthorizationAdapter, type ShareAuthorizationDenied, type ShareAuthorizationMethod, type ShareAuthorizationReady, type ShareAuthorizationRequired, type ShareAuthorizationResult, type ShareAuthorizedContent, type ShareCache, type ShareCacheEntry, type ShareCacheKey, type ShareCacheMetadata, type ShareDeliveryAdapter, type ShareErrorCode, type ShareErrorInfo, type ShareFetchOptions, type ShareHistoryView, type ShareInspection, type ShareMetadata, type ShareNodeTrust, ShareNotifyError, type ShareNotifyInput, type ShareNotifyResult, type ShareNotifyState, type SharePolicyChallenge, type SharePolicyDelegationLink, type SharePolicyPublishAdapter, type SharePolicyRootRevocation, type SharePolicySession, type SharePresentationMaterial, SharePublishError, type SharePublishErrorCode, type SharePublishOptions, type SharePublishTarget, type ShareReceiveAuthorizationRequired, ShareReceiveError, type ShareReceiveOutcome, type ShareReceiveResult, ShareRecipientClient, type ShareRecipientClientOptions, type ShareRevocationAdapter, type ShareRevocationResult, type ShareTarget, type SignedDelegation, type TargetPublishAdapter, type TargetPublishInput, type TargetPublishOutcome, addressedCredentialRequirement, authorizationMethodForTarget, authorizeShare, canonicalOwnerSharePolicy, canonicalShareFilename, claimShare, computeOwnerShareRegistrationCid, createAddressedAuthorization, createDelegatedShareKey, createNativeShare, createPolicyEnforcementDelegation, createShareV2HolderBindingArtifact, deliverCredentialInvitation, hasUnsafeFilenameCodePoint, historyRecordForPublishedShare, inspectShare, listShares, normalizeShareTarget, notifyShare, openNativeShare, parseAddressedEnvelope, parseNativeShareUrl, prepareAddressedShare, publishAddressedShare, publishPolicyShare, publishTargetShare, receiveShare, recipientMatchesShareRecord, redactPublishedShare, restoreDelegatedShareKey, resumeShareAuthorization, revokeShare, showShare, targetAuthorizationMethod, toShareErrorInfo, validateOwnerSharePolicyRegistration, validateOwnerSharePolicyRegistrationBytes };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { ShareEnvelopeV2, ShareEnvelopeV3, UnifiedPolicyCapability, ShareAction, UnifiedContentSource, PolicyCredentialRequirementV1 } from '@tinycloud/share-envelope';
2
2
  export { CheckBearerDelegationOptions, DelegationCheckResult, canonicalize, checkBearerDelegation, fromBase64Url, requiredResourceUri, resourceUriCovers, toBase64Url } from '@tinycloud/share-envelope';
3
3
 
4
+ declare function hasUnsafeFilenameCodePoint(value: string): boolean;
5
+ /** A single display/download filename, never a path. Returns the NFC form. */
6
+ declare function canonicalShareFilename(value: string): string;
7
+
4
8
  /** The only interactive boundary exposed by the headless SDK. */
5
9
  type ShareAuthorizationMethod = "openkey-device" | "email-claim" | "email-otp";
6
10
  interface ShareAuthorizationRequired {
@@ -613,7 +617,7 @@ interface PreparedAddressedShare {
613
617
  */
614
618
  declare function prepareAddressedShare(request: AddressedShareRequest): PreparedAddressedShare;
615
619
  /** Canonical application-neutral Policy/v3 addressed publisher shared by browser and CLI. */
616
- declare function publishAddressedShare(options: AddressedSharePublishOptions): Promise<PublishedShare>;
620
+ declare function publishAddressedShare(input: AddressedSharePublishOptions): Promise<PublishedShare>;
617
621
 
618
622
  interface ShareCacheKey {
619
623
  readonly cid: string;
@@ -972,12 +976,21 @@ interface ShareRecipientClientOptions {
972
976
  readonly sign?: (bytes: Uint8Array) => Promise<Uint8Array>;
973
977
  readonly signal?: AbortSignal;
974
978
  readonly onStage?: (stage: "policy-admission" | "delegation-import" | "invocation" | "decryption") => void;
975
- /** Previously admitted and imported ordinary policy delegation (account v3 fast path). */
979
+ /**
980
+ * A previously admitted and imported policy session (S0), optionally with
981
+ * the descendants that re-delegate it, in order, down to this holder.
982
+ */
976
983
  readonly policyAuthorization?: {
977
984
  readonly authorization: string;
978
985
  readonly cid: string;
986
+ readonly descendants?: readonly SharePolicyDelegationLink[];
979
987
  };
980
988
  }
989
+ /** One signed link of a policy delegation chain, as imported into the Node. */
990
+ interface SharePolicyDelegationLink {
991
+ readonly authorization: string;
992
+ readonly cid: string;
993
+ }
981
994
  interface SharePolicySession {
982
995
  readonly sessionId: string;
983
996
  readonly expiresAt: string;
@@ -1120,4 +1133,4 @@ declare function parseNativeShareUrl(value: string): string;
1120
1133
  /** Receive through the public SDK without creating another transport protocol. */
1121
1134
  declare function openNativeShare(sharing: NativeSharingService, link: string): Promise<unknown>;
1122
1135
 
1123
- export { type AddressedOwnerRootInput, type AddressedOwnerRootReceipt, type AddressedPolicyRegistrationInput, type AddressedPolicyRegistrationReceipt, type AddressedPublishAuthority, type AddressedSharePublishOptions, type AddressedShareRequest, type CreateOwnerDelegationParams, CredentialInvitationError, type CredentialInvitationErrorCode, type CredentialInvitationReceipt, type CredentialInvitationResult, DEFAULT_MAX_CONTENT_BLOB_BYTES, DEFAULT_MAX_SEALED_BLOB_BYTES, DEFAULT_SHARE_LIFETIME_MS, type DelegatedShareKey, EncryptedSenderShareHistory, type EncryptedShareHistoryStorage, MAX_CONTENT_BYTES, MemoryEncryptedShareHistoryStorage, MemorySenderShareKeyStorage, MemorySenderShareRecordStorage, MemoryShareCache, NATIVE_SHARE_FRAGMENT_PARAMETER, type NativeShareResult, type NativeSharingService, OWNER_SHARE_REGISTRATION_DOMAIN, type OwnerDelegationPermission, type OwnerDelegationReceipt, type OwnerShareAction, type OwnerShareDecryption, type OwnerShareMatcher, type OwnerSharePolicyRegistration, type OwnerSharePolicyRegistrationReceipt, type OwnerSharePolicyV2, type ParsedAddressedEnvelope, type PreparedAddressedShare, type PublishedShare, type PublishedShareDeliveryMaterial, type PublishedShareMetadata, type RegisterOwnerSharePolicyParams, SHARE_CONTENT_LIMIT, SHARE_PUBLISH_RESULT_VERSION, SHARE_RESULT_VERSION, SHARE_V2_PROTOCOL, type SenderShareKeyStorage, type SenderShareRecord, type SenderShareRecordStorage, type SenderShareRevocationScope, SenderShareStore, type ShareAuthorizationAdapter, type ShareAuthorizationDenied, type ShareAuthorizationMethod, type ShareAuthorizationReady, type ShareAuthorizationRequired, type ShareAuthorizationResult, type ShareAuthorizedContent, type ShareCache, type ShareCacheEntry, type ShareCacheKey, type ShareCacheMetadata, type ShareDeliveryAdapter, type ShareErrorCode, type ShareErrorInfo, type ShareFetchOptions, type ShareHistoryView, type ShareInspection, type ShareMetadata, type ShareNodeTrust, ShareNotifyError, type ShareNotifyInput, type ShareNotifyResult, type ShareNotifyState, type SharePolicyChallenge, type SharePolicyPublishAdapter, type SharePolicyRootRevocation, type SharePolicySession, type SharePresentationMaterial, SharePublishError, type SharePublishErrorCode, type SharePublishOptions, type SharePublishTarget, type ShareReceiveAuthorizationRequired, ShareReceiveError, type ShareReceiveOutcome, type ShareReceiveResult, ShareRecipientClient, type ShareRecipientClientOptions, type ShareRevocationAdapter, type ShareRevocationResult, type ShareTarget, type SignedDelegation, type TargetPublishAdapter, type TargetPublishInput, type TargetPublishOutcome, addressedCredentialRequirement, authorizationMethodForTarget, authorizeShare, canonicalOwnerSharePolicy, claimShare, computeOwnerShareRegistrationCid, createAddressedAuthorization, createDelegatedShareKey, createNativeShare, createPolicyEnforcementDelegation, createShareV2HolderBindingArtifact, deliverCredentialInvitation, historyRecordForPublishedShare, inspectShare, listShares, normalizeShareTarget, notifyShare, openNativeShare, parseAddressedEnvelope, parseNativeShareUrl, prepareAddressedShare, publishAddressedShare, publishPolicyShare, publishTargetShare, receiveShare, recipientMatchesShareRecord, redactPublishedShare, restoreDelegatedShareKey, resumeShareAuthorization, revokeShare, showShare, targetAuthorizationMethod, toShareErrorInfo, validateOwnerSharePolicyRegistration, validateOwnerSharePolicyRegistrationBytes };
1136
+ export { type AddressedOwnerRootInput, type AddressedOwnerRootReceipt, type AddressedPolicyRegistrationInput, type AddressedPolicyRegistrationReceipt, type AddressedPublishAuthority, type AddressedSharePublishOptions, type AddressedShareRequest, type CreateOwnerDelegationParams, CredentialInvitationError, type CredentialInvitationErrorCode, type CredentialInvitationReceipt, type CredentialInvitationResult, DEFAULT_MAX_CONTENT_BLOB_BYTES, DEFAULT_MAX_SEALED_BLOB_BYTES, DEFAULT_SHARE_LIFETIME_MS, type DelegatedShareKey, EncryptedSenderShareHistory, type EncryptedShareHistoryStorage, MAX_CONTENT_BYTES, MemoryEncryptedShareHistoryStorage, MemorySenderShareKeyStorage, MemorySenderShareRecordStorage, MemoryShareCache, NATIVE_SHARE_FRAGMENT_PARAMETER, type NativeShareResult, type NativeSharingService, OWNER_SHARE_REGISTRATION_DOMAIN, type OwnerDelegationPermission, type OwnerDelegationReceipt, type OwnerShareAction, type OwnerShareDecryption, type OwnerShareMatcher, type OwnerSharePolicyRegistration, type OwnerSharePolicyRegistrationReceipt, type OwnerSharePolicyV2, type ParsedAddressedEnvelope, type PreparedAddressedShare, type PublishedShare, type PublishedShareDeliveryMaterial, type PublishedShareMetadata, type RegisterOwnerSharePolicyParams, SHARE_CONTENT_LIMIT, SHARE_PUBLISH_RESULT_VERSION, SHARE_RESULT_VERSION, SHARE_V2_PROTOCOL, type SenderShareKeyStorage, type SenderShareRecord, type SenderShareRecordStorage, type SenderShareRevocationScope, SenderShareStore, type ShareAuthorizationAdapter, type ShareAuthorizationDenied, type ShareAuthorizationMethod, type ShareAuthorizationReady, type ShareAuthorizationRequired, type ShareAuthorizationResult, type ShareAuthorizedContent, type ShareCache, type ShareCacheEntry, type ShareCacheKey, type ShareCacheMetadata, type ShareDeliveryAdapter, type ShareErrorCode, type ShareErrorInfo, type ShareFetchOptions, type ShareHistoryView, type ShareInspection, type ShareMetadata, type ShareNodeTrust, ShareNotifyError, type ShareNotifyInput, type ShareNotifyResult, type ShareNotifyState, type SharePolicyChallenge, type SharePolicyDelegationLink, type SharePolicyPublishAdapter, type SharePolicyRootRevocation, type SharePolicySession, type SharePresentationMaterial, SharePublishError, type SharePublishErrorCode, type SharePublishOptions, type SharePublishTarget, type ShareReceiveAuthorizationRequired, ShareReceiveError, type ShareReceiveOutcome, type ShareReceiveResult, ShareRecipientClient, type ShareRecipientClientOptions, type ShareRevocationAdapter, type ShareRevocationResult, type ShareTarget, type SignedDelegation, type TargetPublishAdapter, type TargetPublishInput, type TargetPublishOutcome, addressedCredentialRequirement, authorizationMethodForTarget, authorizeShare, canonicalOwnerSharePolicy, canonicalShareFilename, claimShare, computeOwnerShareRegistrationCid, createAddressedAuthorization, createDelegatedShareKey, createNativeShare, createPolicyEnforcementDelegation, createShareV2HolderBindingArtifact, deliverCredentialInvitation, hasUnsafeFilenameCodePoint, historyRecordForPublishedShare, inspectShare, listShares, normalizeShareTarget, notifyShare, openNativeShare, parseAddressedEnvelope, parseNativeShareUrl, prepareAddressedShare, publishAddressedShare, publishPolicyShare, publishTargetShare, receiveShare, recipientMatchesShareRecord, redactPublishedShare, restoreDelegatedShareKey, resumeShareAuthorization, revokeShare, showShare, targetAuthorizationMethod, toShareErrorInfo, validateOwnerSharePolicyRegistration, validateOwnerSharePolicyRegistrationBytes };
package/dist/index.js CHANGED
@@ -4,6 +4,19 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
+ // src/filename-policy.ts
8
+ var UNSAFE_FILENAME_CODE_POINT = /[\p{Cc}\p{Cf}\p{Cs}\u2028\u2029]/u;
9
+ function hasUnsafeFilenameCodePoint(value) {
10
+ return UNSAFE_FILENAME_CODE_POINT.test(value);
11
+ }
12
+ function canonicalShareFilename(value) {
13
+ const canonical = value.normalize("NFC");
14
+ if (canonical.length === 0 || canonical === "." || canonical === ".." || canonical.includes("/") || canonical.includes("\\") || hasUnsafeFilenameCodePoint(canonical)) {
15
+ throw new TypeError("share filename is unsafe");
16
+ }
17
+ return canonical;
18
+ }
19
+
7
20
  // ../share-envelope/dist/index.js
8
21
  import { sha256 } from "@noble/hashes/sha2";
9
22
  import { ed25519 } from "@noble/curves/ed25519";
@@ -6485,8 +6498,17 @@ function normalizeShareTarget(target) {
6485
6498
  function targetAuthorizationMethod(target) {
6486
6499
  return authorizationMethodForTarget(target);
6487
6500
  }
6501
+ function publishFilename(value) {
6502
+ try {
6503
+ return canonicalShareFilename(value);
6504
+ } catch {
6505
+ throw new SharePublishError("invalid-argument", hasUnsafeFilenameCodePoint(value) ? "filename contains control or invisible characters" : "filename must be one safe path segment");
6506
+ }
6507
+ }
6488
6508
  async function publishTargetShare(input) {
6489
6509
  const target = normalizeShareTarget(input.target);
6510
+ const filename = publishFilename(input.filename);
6511
+ const files = input.files?.map((file) => ({ ...file, filename: publishFilename(file.filename) }));
6490
6512
  if (input.targetAdapter === void 0) {
6491
6513
  if (target.kind === "bearer") throw new SharePublishError("authority-required", "native bearer publication requires an authenticated TinyCloud node");
6492
6514
  return {
@@ -6512,9 +6534,6 @@ async function publishTargetShare(input) {
6512
6534
  return bytes3;
6513
6535
  })();
6514
6536
  if (source.byteLength === 0) throw new SharePublishError("invalid-argument", "share content is empty");
6515
- if (!input.filename || input.filename === "." || input.filename === ".." || /[/\\\u0000-\u001f\u007f]/.test(input.filename)) {
6516
- throw new SharePublishError("invalid-argument", "filename must be one safe path segment");
6517
- }
6518
6537
  if (target.kind === "bearer" && input.allowBinary !== true) {
6519
6538
  try {
6520
6539
  new TextDecoder("utf-8", { fatal: true }).decode(source);
@@ -6522,10 +6541,10 @@ async function publishTargetShare(input) {
6522
6541
  throw new SharePublishError("invalid-argument", "Markdown input must be valid UTF-8");
6523
6542
  }
6524
6543
  }
6525
- const files = input.files === void 0 || input.files.length === 0 ? [{ bytes: source }] : input.files;
6544
+ const publishFiles = files === void 0 || files.length === 0 ? [{ bytes: source }] : files;
6526
6545
  const limit = input.maxBytes ?? SHARE_CONTENT_LIMIT;
6527
6546
  let totalBytes = 0;
6528
- for (const file of files) {
6547
+ for (const file of publishFiles) {
6529
6548
  totalBytes += file.bytes.byteLength;
6530
6549
  if (!Number.isSafeInteger(totalBytes) || totalBytes > limit) {
6531
6550
  throw new SharePublishError("max-bytes-exceeded", "share publication exceeds the combined byte limit");
@@ -6536,8 +6555,8 @@ async function publishTargetShare(input) {
6536
6555
  if (!Number.isFinite(expiresAt.getTime()) || expiresAt.getTime() <= nowMs) throw new SharePublishError("invalid-argument", "expiresAt must be a valid future time");
6537
6556
  return input.targetAdapter.publish({
6538
6557
  source,
6539
- filename: input.filename,
6540
- ...input.files === void 0 ? {} : { files: input.files },
6558
+ filename,
6559
+ ...files === void 0 ? {} : { files },
6541
6560
  ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
6542
6561
  ...input.resourceKind === void 0 ? {} : { resourceKind: input.resourceKind },
6543
6562
  ...input.actions === void 0 ? {} : { actions: input.actions },
@@ -6565,6 +6584,7 @@ function targetMatcher(target) {
6565
6584
  function targetKind(target) {
6566
6585
  return target.kind;
6567
6586
  }
6587
+ var OWNER_SHARE_ACTIONS = /* @__PURE__ */ new Set(["tinycloud.kv/get", "tinycloud.kv/list", "tinycloud.kv/metadata", "tinycloud.kv/put"]);
6568
6588
  function assertSafeInput(input) {
6569
6589
  if (!/^[A-Za-z0-9_-]{16,128}$/.test(input.shareId)) throw new TypeError("addressed share id is invalid");
6570
6590
  if (!Number.isSafeInteger(input.byteLength) || input.byteLength < 0 || input.byteLength > SHARE_CONTENT_LIMIT) throw new TypeError("addressed content length is invalid");
@@ -6687,14 +6707,18 @@ function addressedCredentialRequirement(target) {
6687
6707
  return mailboxCredentialCommitment(normalized);
6688
6708
  }
6689
6709
  function prepareAddressedShare(request) {
6690
- if (request.filename.length === 0 || request.filename === "." || request.filename === ".." || /[/\\\u0000-\u001f\u007f]/.test(request.filename)) throw new TypeError("addressed filename is invalid");
6710
+ try {
6711
+ canonicalShareFilename(request.filename);
6712
+ } catch {
6713
+ throw new TypeError("addressed filename is invalid");
6714
+ }
6691
6715
  if (request.actions.length === 0 || request.policyActions.length === 0) throw new TypeError("addressed share actions are empty");
6716
+ if (request.policyActions.some((action) => !OWNER_SHARE_ACTIONS.has(action))) throw new TypeError("addressed share action is not supported");
6692
6717
  const target = normalizeShareTarget(request.target);
6693
6718
  if (target.kind === "bearer") throw new TypeError("addressed target is required");
6694
6719
  if (target.kind === "recipientDid") return { target };
6695
- if (target.kind === "emailDomain") {
6696
- if (!request.actions.every((action) => action === "read" || action === "list") || !request.policyActions.every((action) => action === "tinycloud.kv/get" || action === "tinycloud.kv/list" || action === "tinycloud.kv/metadata")) throw new TypeError("email-domain shares are view-only");
6697
- if (request.deliveryEmail !== void 0) throw new TypeError("email-domain shares are not emailed");
6720
+ if (target.kind === "emailDomain" && request.deliveryEmail !== void 0 && (request.deliveryEmail !== request.deliveryEmail.toLowerCase() || !request.deliveryEmail.endsWith(`@${target.domain}`))) {
6721
+ throw new TypeError("email-domain delivery address must be a lowercase mailbox at the domain");
6698
6722
  }
6699
6723
  return { target, credentialRequirement: mailboxCredentialCommitment(target) };
6700
6724
  }
@@ -6705,9 +6729,10 @@ function assertMailboxCommitment(commitment, target) {
6705
6729
  if (canonicalize(commitment.profile) !== canonicalize(expected.profile) || canonicalize(commitment.credentialType) !== canonicalize(expected.credentialType) || commitment.descriptorDigest !== expected.descriptorDigest || commitment.issuerDid !== expected.issuerDid || commitment.issuerKid !== expected.issuerKid) throw new TypeError(`${label} shares require the ${label} credential profile`);
6706
6730
  if (commitment.requirementDigest !== expected.requirementDigest) throw new TypeError(`credential requirement is not bound to the email ${target.kind === "email" ? "address" : "domain"}`);
6707
6731
  }
6708
- async function publishAddressedShare(options) {
6709
- assertSafeInput(options);
6710
- const { target } = prepareAddressedShare(options);
6732
+ async function publishAddressedShare(input) {
6733
+ assertSafeInput(input);
6734
+ const { target } = prepareAddressedShare(input);
6735
+ const options = { ...input, filename: canonicalShareFilename(input.filename) };
6711
6736
  if (target.kind !== "recipientDid") assertMailboxCommitment(options.credentialRequirement, target);
6712
6737
  const expiry = rfc3339Seconds(options.expiresAt);
6713
6738
  const matcher = targetMatcher(target);
@@ -8202,9 +8227,28 @@ function verifyV3PolicyAuthorization(input) {
8202
8227
  const binding = object3(input.envelope.attestedEnforcerBinding, "v3 attested enforcer binding");
8203
8228
  const policy = object3(input.envelope.policy, "v3 policy");
8204
8229
  const now = Math.floor(Date.now() / 1e3);
8205
- 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");
8230
+ 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 * 1e3 <= Date.parse(input.envelope.expiry)) || canonicalize(compact.payload.att) !== canonicalize(policyAttenuationForV3(input.envelope))) throw new Error("v3 policy delegation signed binding mismatch");
8206
8231
  return compact;
8207
8232
  }
8233
+ function verifyV3PolicyDescendants(session, descendants, holderDid) {
8234
+ let parent = session;
8235
+ for (const link of descendants) {
8236
+ const child = verifyCompactUcanAuthorization(link.authorization, link.cid);
8237
+ const { remainingRedelegationDepth: parentDepth, ...parentFacts } = parent.payload.fct[0];
8238
+ const { remainingRedelegationDepth: depth, ...facts } = child.payload.fct[0];
8239
+ if (child.payload.iss.split("#", 1)[0] !== parent.payload.aud || child.payload.prf.length !== 1 || child.payload.prf[0] !== parent.cid || child.payload.nbf <= parent.payload.nbf || child.payload.exp >= parent.payload.exp || typeof parentDepth !== "number" || parentDepth <= 0 || depth !== parentDepth - 1 || canonicalize(facts) !== canonicalize(parentFacts) || canonicalize(child.payload.att) !== canonicalize(parent.payload.att)) throw new Error("v3 policy descendant does not extend its parent");
8240
+ parent = child;
8241
+ }
8242
+ const now = Math.floor(Date.now() / 1e3);
8243
+ if (parent.payload.aud !== holderDid) throw new Error("v3 policy delegation chain does not end at this holder");
8244
+ if (parent.payload.nbf > now || parent.payload.exp <= now) throw new Error("v3 policy delegation chain is not currently valid");
8245
+ return parent;
8246
+ }
8247
+ function requestedSessionExpiry(expiry) {
8248
+ const seconds = Math.floor(Date.parse(expiry) / 1e3);
8249
+ if (!Number.isFinite(seconds) || seconds <= Math.floor(Date.now() / 1e3) + 60) return void 0;
8250
+ return new Date(seconds * 1e3).toISOString().replace(/\.\d{3}Z$/, "Z");
8251
+ }
8208
8252
  function hex3(value) {
8209
8253
  return [...value].map((byte) => byte.toString(16).padStart(2, "0")).join("");
8210
8254
  }
@@ -8257,14 +8301,17 @@ var ShareRecipientClient = class {
8257
8301
  this.signer = options.sign;
8258
8302
  if (options.policyAuthorization !== void 0) {
8259
8303
  if (options.envelope.version !== 3) throw new Error("policy delegation fast path requires a v3 envelope");
8260
- const compact = verifyV3PolicyAuthorization({ ...options.policyAuthorization, envelope: options.envelope, holderDid: options.holderDid });
8304
+ const { authorization, cid: cid2, descendants = [] } = options.policyAuthorization;
8305
+ const sessionHolder = descendants.length === 0 ? options.holderDid : verifyCompactUcanAuthorization(authorization, cid2).payload.aud;
8306
+ const compact = verifyV3PolicyAuthorization({ authorization, cid: cid2, envelope: options.envelope, holderDid: sessionHolder });
8307
+ const leaf = verifyV3PolicyDescendants(compact, descendants, options.holderDid);
8261
8308
  const nodeAudience = compact.payload.fct[0].nodeAudience;
8262
- this.v3Authorization = options.policyAuthorization.authorization;
8309
+ this.v3Authorization = leaf.authorization;
8263
8310
  this.v3NodeAudience = nodeAudience;
8264
8311
  this.nativeSigner = options.sign;
8265
8312
  this.session = {
8266
- sessionId: options.policyAuthorization.cid,
8267
- expiresAt: new Date(compact.payload.exp * 1e3).toISOString(),
8313
+ sessionId: leaf.cid,
8314
+ expiresAt: new Date(leaf.payload.exp * 1e3).toISOString(),
8268
8315
  actions: options.envelope.actions,
8269
8316
  resource: options.envelope.resource
8270
8317
  };
@@ -8334,13 +8381,17 @@ var ShareRecipientClient = class {
8334
8381
  throw new Error(accountless ? "v4 ceremony requires a verified credential and requirement" : "v3 ceremony requires a claim");
8335
8382
  }
8336
8383
  this.options.onStage?.("policy-admission");
8337
- const delegationResponse = await this.fetchFn(new URL("/policy/v3/delegations", this.options.nodeOrigin), {
8384
+ const mintBody = accountless ? { policyCid: envelope.policyCid, challengeId: challenge.challengeId, nonce: challenge.nonce, requirement: material.requirement, credential: material.credentialEnvelope, presentation: material.presentation } : { policyCid: envelope.policyCid, challengeId: challenge.challengeId, nonce: challenge.nonce, claim: material.claim, presentation: material.presentation };
8385
+ const mint = (body) => this.fetchFn(new URL("/policy/v3/delegations", this.options.nodeOrigin), {
8338
8386
  method: "POST",
8339
8387
  redirect: "error",
8340
8388
  headers: { accept: "application/json", "content-type": "application/json" },
8341
- body: JSON.stringify(accountless ? { policyCid: envelope.policyCid, challengeId: challenge.challengeId, nonce: challenge.nonce, requirement: material.requirement, credential: material.credentialEnvelope, presentation: material.presentation } : { policyCid: envelope.policyCid, challengeId: challenge.challengeId, nonce: challenge.nonce, claim: material.claim, presentation: material.presentation }),
8389
+ body: JSON.stringify(body),
8342
8390
  ...this.options.signal === void 0 ? {} : { signal: this.options.signal }
8343
8391
  });
8392
+ const requestedExpiresAt = requestedSessionExpiry(envelope.expiry);
8393
+ let delegationResponse = await mint(requestedExpiresAt === void 0 ? mintBody : { ...mintBody, requestedExpiresAt });
8394
+ if (requestedExpiresAt !== void 0 && delegationResponse.status === 422) delegationResponse = await mint(mintBody);
8344
8395
  if (!delegationResponse.ok) throw new Error(`v3 policy delegation rejected (${delegationResponse.status})`);
8345
8396
  const delegation = object3(await delegationResponse.json(), "v3 policy delegation");
8346
8397
  if (delegation.admitted !== true || typeof delegation.sessionCid !== "string" || typeof delegation.authorization !== "string") throw new Error("v3 policy delegation response is not admitted");
@@ -8573,6 +8624,7 @@ export {
8573
8624
  authorizationMethodForTarget,
8574
8625
  authorizeShare,
8575
8626
  canonicalOwnerSharePolicy,
8627
+ canonicalShareFilename,
8576
8628
  canonicalize,
8577
8629
  checkBearerDelegation,
8578
8630
  claimShare,
@@ -8584,6 +8636,7 @@ export {
8584
8636
  createShareV2HolderBindingArtifact,
8585
8637
  deliverCredentialInvitation,
8586
8638
  fromBase64Url,
8639
+ hasUnsafeFilenameCodePoint,
8587
8640
  historyRecordForPublishedShare,
8588
8641
  inspectShare,
8589
8642
  listShares,