@tinycloud/cli 1.0.0-beta.14 → 1.0.0-beta.15

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.
@@ -13791,16 +13791,17 @@ var init_dist2 = __esm({
13791
13791
  ...options?.ifNoneMatch === void 0 ? {} : { "if-none-match": options.ifNoneMatch }
13792
13792
  }
13793
13793
  );
13794
+ if (response.status === 401 || response.status === 403) {
13795
+ const errorText = await response.text();
13796
+ const message = errorText.trim().length > 0 ? errorText : `Failed to put key "${key}": ${response.status} - ${response.statusText || "authorization failed"}`;
13797
+ const { resource, action: requiredAction } = parseAuthError(errorText);
13798
+ return err(authUnauthorizedError("kv", message, {
13799
+ status: response.status,
13800
+ ...requiredAction && { requiredAction },
13801
+ ...resource && { resource }
13802
+ }));
13803
+ }
13794
13804
  if (!response.ok) {
13795
- if (response.status === 401) {
13796
- const errorText2 = await response.text();
13797
- const { resource, action } = parseAuthError(errorText2);
13798
- return err(authUnauthorizedError("kv", errorText2, {
13799
- status: response.status,
13800
- ...action && { requiredAction: action },
13801
- ...resource && { resource }
13802
- }));
13803
- }
13804
13805
  const errorText = await response.text();
13805
13806
  if (response.status === 412) {
13806
13807
  return err(serviceError(
@@ -18045,6 +18046,7 @@ function redactPublishedShare(result) {
18045
18046
  target: { ...result.metadata.target },
18046
18047
  resource: { ...result.metadata.resource },
18047
18048
  actions: [...result.metadata.actions],
18049
+ ...result.metadata.expiryClamped === void 0 ? {} : { expiryClamped: result.metadata.expiryClamped },
18048
18050
  expiresAt: result.metadata.expiresAt,
18049
18051
  display: { ...result.metadata.display }
18050
18052
  }
@@ -18404,6 +18406,7 @@ async function publishTargetShare(input) {
18404
18406
  ...input.actions === void 0 ? {} : { actions: input.actions },
18405
18407
  target,
18406
18408
  expiresAt,
18409
+ expiryWasExplicit: input.expiryWasExplicit ?? input.expiresAt !== void 0,
18407
18410
  origin: input.origin,
18408
18411
  ...input.notify === void 0 ? {} : { notify: input.notify }
18409
18412
  });
@@ -34129,6 +34132,15 @@ async function writeShareOutput(directory, filename, bytes, force) {
34129
34132
  return join6(outputDirectory, safeName);
34130
34133
  }
34131
34134
 
34135
+ // src/share/errors.ts
34136
+ var SharePublishAuthorityError = class extends Error {
34137
+ constructor(failure) {
34138
+ super(failure.kind);
34139
+ this.failure = failure;
34140
+ this.name = "SharePublishAuthorityError";
34141
+ }
34142
+ };
34143
+
34132
34144
  // src/commands/share.ts
34133
34145
  var SHARE_ORIGIN = "https://share.tinycloud.xyz";
34134
34146
  var shareServices = {};
@@ -34142,6 +34154,33 @@ function parseShareTarget(value) {
34142
34154
  }
34143
34155
  function shareCliError(error) {
34144
34156
  if (error instanceof CLIError) return error;
34157
+ if (error instanceof SharePublishAuthorityError) {
34158
+ const failure = error.failure;
34159
+ const profileName = "profileName" in failure ? failure.profileName : void 0;
34160
+ const localKey = "localKey" in failure && failure.localKey === true;
34161
+ const profileHint = profileName === void 0 ? "" : `--profile ${profileName} `;
34162
+ const loginHint = `tc ${profileHint}auth login${localKey ? " --method local" : ""}`;
34163
+ if (failure.kind === "owner-space-unresolved") {
34164
+ return new CLIError("AUTH_REQUIRED", `a valid signed TinyCloud session is required; run \`${loginHint}\``, 3);
34165
+ }
34166
+ if (failure.kind === "scope-denied") {
34167
+ const requiredAction = failure.requiredAction === void 0 ? "" : ` (${failure.requiredAction})`;
34168
+ return new CLIError("PERMISSION_DENIED", `the session lacks ${failure.capability} authority${requiredAction}; renew it with \`${loginHint}\` using the required capability`, 5);
34169
+ }
34170
+ if (failure.kind === "lifetime-exceeds-session") {
34171
+ const expiresAt = failure.sessionExpiresAt.toISOString();
34172
+ if (failure.reason === "session-too-close") {
34173
+ return new CLIError("AUTH_REQUIRED", `the signed session expires too soon (${expiresAt}); log in again with \`${loginHint}\``, 3);
34174
+ }
34175
+ if (failure.reason === "below-minimum") {
34176
+ return new CLIError("SESSION_LIFETIME_EXCEEDED", "share expiry must be at least 60 seconds from now; use a longer --expires value", 2);
34177
+ }
34178
+ return new CLIError("SESSION_LIFETIME_EXCEEDED", `requested share lifetime exceeds session expiry ${expiresAt}; use a shorter --expires value or renew the session with \`${loginHint}\``, 2);
34179
+ }
34180
+ if (failure.kind === "origin-mismatch") {
34181
+ return new CLIError("ORIGIN_MISMATCH", "share origin does not match the configured service", 2);
34182
+ }
34183
+ }
34145
34184
  if (error instanceof SharePublishError) {
34146
34185
  const exit = error.code === "authority-required" ? 3 : error.code === "max-bytes-exceeded" ? 7 : 2;
34147
34186
  const code3 = error.code === "authority-required" ? "AUTH_REQUIRED" : error.code === "max-bytes-exceeded" ? "MAX_BYTES_EXCEEDED" : "INVALID_ARGUMENT";
@@ -34224,7 +34263,7 @@ function assertAggregateInputLimit(inputs, maxBytes) {
34224
34263
  }
34225
34264
  function registerShareCommand(program) {
34226
34265
  const share = program.command("share").description("Publish and consume TinyCloud Share links");
34227
- share.command("publish <files...>").description("Publish one or more bounded files as a Share").option("--name <filename>", "Filename for stdin input").option("--to <target>", "Share target", "anyone").option("--notify", "Request idempotent email delivery for addressed targets").option("--expires <duration>", "Share lifetime", "7d").option("--max-bytes <bytes>", "Bound input bytes").option("--media-type <type>", "Media type for a single input").option("--action <actions...>", "Addressed permission: read, list, or edit").option("--prefix", "Publish multiple inputs beneath one addressed prefix").option("--binary", "Allow non-UTF-8 bearer content").option("--json", "Print versioned redacted JSON").option("--viewer-origin <origin>", "Canonical HTTPS viewer origin", SHARE_ORIGIN).action(async (files, options, command) => {
34266
+ share.command("publish <files...>").description("Publish one or more bounded files as a Share").option("--name <filename>", "Filename for stdin input").option("--to <target>", "Share target", "anyone").option("--notify", "Request idempotent email delivery for addressed targets").option("--expires <duration>", "Share lifetime").option("--max-bytes <bytes>", "Bound input bytes").option("--media-type <type>", "Media type for a single input").option("--action <actions...>", "Addressed permission: read, list, or edit").option("--prefix", "Publish multiple inputs beneath one addressed prefix").option("--binary", "Allow non-UTF-8 bearer content").option("--json", "Print versioned redacted JSON").option("--viewer-origin <origin>", "Canonical HTTPS viewer origin", SHARE_ORIGIN).action(async (files, options, command) => {
34228
34267
  try {
34229
34268
  const json = jsonOutput(options, command);
34230
34269
  const maxBytes = byteLimit(options.maxBytes);
@@ -34246,7 +34285,8 @@ function registerShareCommand(program) {
34246
34285
  target,
34247
34286
  resourceKind: options.prefix || inputs.length > 1 ? "prefix" : "exact",
34248
34287
  actions,
34249
- expiresAt: expires(options.expires),
34288
+ expiresAt: expires(options.expires ?? "7d"),
34289
+ expiryWasExplicit: options.expires !== void 0,
34250
34290
  origin: options.viewerOrigin,
34251
34291
  ...maxBytes === void 0 ? {} : { maxBytes },
34252
34292
  notify: options.notify === true,
@@ -34266,7 +34306,9 @@ function registerShareCommand(program) {
34266
34306
  const delivery = await notifyShare({ shareId: record.shareId, recipient: target.address, record, adapter: shareServices.delivery });
34267
34307
  if (delivery.state === "partial-failure") process.exitCode = 9;
34268
34308
  }
34269
- if (json) writeJson2(redactPublishedShare(result));
34309
+ if (result.metadata.expiryClamped === true) process.stderr.write(`Share expiry clamped to session expiry (${result.metadata.expiresAt}).
34310
+ `);
34311
+ if (json) writeJson2({ ...redactPublishedShare(result), expiryClamped: result.metadata.expiryClamped === true });
34270
34312
  else publishHuman(result);
34271
34313
  } catch (error) {
34272
34314
  handleError(shareCliError(error));