@tinycloud/cli 1.0.0-beta.13 → 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.
- package/dist/index.js +186 -31
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +55 -13
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -13682,16 +13682,17 @@ var init_dist2 = __esm({
|
|
|
13682
13682
|
...options?.ifNoneMatch === void 0 ? {} : { "if-none-match": options.ifNoneMatch }
|
|
13683
13683
|
}
|
|
13684
13684
|
);
|
|
13685
|
+
if (response.status === 401 || response.status === 403) {
|
|
13686
|
+
const errorText = await response.text();
|
|
13687
|
+
const message = errorText.trim().length > 0 ? errorText : `Failed to put key "${key}": ${response.status} - ${response.statusText || "authorization failed"}`;
|
|
13688
|
+
const { resource, action: requiredAction } = parseAuthError(errorText);
|
|
13689
|
+
return err(authUnauthorizedError("kv", message, {
|
|
13690
|
+
status: response.status,
|
|
13691
|
+
...requiredAction && { requiredAction },
|
|
13692
|
+
...resource && { resource }
|
|
13693
|
+
}));
|
|
13694
|
+
}
|
|
13685
13695
|
if (!response.ok) {
|
|
13686
|
-
if (response.status === 401) {
|
|
13687
|
-
const errorText2 = await response.text();
|
|
13688
|
-
const { resource, action } = parseAuthError(errorText2);
|
|
13689
|
-
return err(authUnauthorizedError("kv", errorText2, {
|
|
13690
|
-
status: response.status,
|
|
13691
|
-
...action && { requiredAction: action },
|
|
13692
|
-
...resource && { resource }
|
|
13693
|
-
}));
|
|
13694
|
-
}
|
|
13695
13696
|
const errorText = await response.text();
|
|
13696
13697
|
if (response.status === 412) {
|
|
13697
13698
|
return err(serviceError(
|
|
@@ -17970,6 +17971,7 @@ function redactPublishedShare(result) {
|
|
|
17970
17971
|
target: { ...result.metadata.target },
|
|
17971
17972
|
resource: { ...result.metadata.resource },
|
|
17972
17973
|
actions: [...result.metadata.actions],
|
|
17974
|
+
...result.metadata.expiryClamped === void 0 ? {} : { expiryClamped: result.metadata.expiryClamped },
|
|
17973
17975
|
expiresAt: result.metadata.expiresAt,
|
|
17974
17976
|
display: { ...result.metadata.display }
|
|
17975
17977
|
}
|
|
@@ -18329,6 +18331,7 @@ async function publishTargetShare(input) {
|
|
|
18329
18331
|
...input.actions === void 0 ? {} : { actions: input.actions },
|
|
18330
18332
|
target,
|
|
18331
18333
|
expiresAt,
|
|
18334
|
+
expiryWasExplicit: input.expiryWasExplicit ?? input.expiresAt !== void 0,
|
|
18332
18335
|
origin: input.origin,
|
|
18333
18336
|
...input.notify === void 0 ? {} : { notify: input.notify }
|
|
18334
18337
|
});
|
|
@@ -18945,7 +18948,11 @@ function canonicalViewerUrl(viewerOrigin) {
|
|
|
18945
18948
|
async function createNativeShare(sharing, input) {
|
|
18946
18949
|
if (!input.path || input.path.startsWith("/") || input.path.endsWith("/") || input.path.includes("..") || input.path.includes("//")) throw new TypeError("native share path must be one canonical TinyCloud KV key");
|
|
18947
18950
|
const generated = await sharing.generate({ path: input.path, actions: ["tinycloud.kv/get"], expiry: input.expiresAt });
|
|
18948
|
-
if (generated.ok !== true)
|
|
18951
|
+
if (generated.ok !== true) {
|
|
18952
|
+
const error = new Error(typeof generated.error?.message === "string" ? generated.error.message : "TinyCloud sharing service rejected delegation generation");
|
|
18953
|
+
if (typeof generated.error?.code === "string") Object.assign(error, { code: generated.error.code });
|
|
18954
|
+
throw error;
|
|
18955
|
+
}
|
|
18949
18956
|
if (typeof generated.data?.token !== "string" || typeof generated.data.delegation?.cid !== "string" || !(generated.data.expiresAt instanceof Date)) throw new Error("TinyCloud sharing service returned incomplete delegation metadata");
|
|
18950
18957
|
const delegation = sharing.decodeLink(generated.data.token);
|
|
18951
18958
|
if (typeof delegation.spaceId !== "string" || delegation.spaceId.length === 0 || typeof delegation.path !== "string" || delegation.path.length === 0) throw new Error("TinyCloud sharing service returned a non-canonical delegation authority");
|
|
@@ -27126,7 +27133,7 @@ var init_dist4 = __esm({
|
|
|
27126
27133
|
});
|
|
27127
27134
|
EPHEMERAL_MS = 60 * 60 * 1e3;
|
|
27128
27135
|
SIGNED_READ_URL_MS = 5 * 60 * 1e3;
|
|
27129
|
-
SESSION_MS =
|
|
27136
|
+
SESSION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
27130
27137
|
SHARE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
27131
27138
|
APP_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
27132
27139
|
MAX_MS = 10 * 365 * 24 * 60 * 60 * 1e3;
|
|
@@ -29393,6 +29400,15 @@ async function writeShareOutput(directory, filename, bytes, force) {
|
|
|
29393
29400
|
return join4(outputDirectory, safeName);
|
|
29394
29401
|
}
|
|
29395
29402
|
|
|
29403
|
+
// src/share/errors.ts
|
|
29404
|
+
var SharePublishAuthorityError = class extends Error {
|
|
29405
|
+
constructor(failure) {
|
|
29406
|
+
super(failure.kind);
|
|
29407
|
+
this.failure = failure;
|
|
29408
|
+
this.name = "SharePublishAuthorityError";
|
|
29409
|
+
}
|
|
29410
|
+
};
|
|
29411
|
+
|
|
29396
29412
|
// src/commands/share.ts
|
|
29397
29413
|
var SHARE_ORIGIN = "https://share.tinycloud.xyz";
|
|
29398
29414
|
var shareServices = {};
|
|
@@ -29409,6 +29425,33 @@ function parseShareTarget(value) {
|
|
|
29409
29425
|
}
|
|
29410
29426
|
function shareCliError(error) {
|
|
29411
29427
|
if (error instanceof CLIError) return error;
|
|
29428
|
+
if (error instanceof SharePublishAuthorityError) {
|
|
29429
|
+
const failure = error.failure;
|
|
29430
|
+
const profileName = "profileName" in failure ? failure.profileName : void 0;
|
|
29431
|
+
const localKey = "localKey" in failure && failure.localKey === true;
|
|
29432
|
+
const profileHint = profileName === void 0 ? "" : `--profile ${profileName} `;
|
|
29433
|
+
const loginHint = `tc ${profileHint}auth login${localKey ? " --method local" : ""}`;
|
|
29434
|
+
if (failure.kind === "owner-space-unresolved") {
|
|
29435
|
+
return new CLIError("AUTH_REQUIRED", `a valid signed TinyCloud session is required; run \`${loginHint}\``, 3);
|
|
29436
|
+
}
|
|
29437
|
+
if (failure.kind === "scope-denied") {
|
|
29438
|
+
const requiredAction = failure.requiredAction === void 0 ? "" : ` (${failure.requiredAction})`;
|
|
29439
|
+
return new CLIError("PERMISSION_DENIED", `the session lacks ${failure.capability} authority${requiredAction}; renew it with \`${loginHint}\` using the required capability`, 5);
|
|
29440
|
+
}
|
|
29441
|
+
if (failure.kind === "lifetime-exceeds-session") {
|
|
29442
|
+
const expiresAt = failure.sessionExpiresAt.toISOString();
|
|
29443
|
+
if (failure.reason === "session-too-close") {
|
|
29444
|
+
return new CLIError("AUTH_REQUIRED", `the signed session expires too soon (${expiresAt}); log in again with \`${loginHint}\``, 3);
|
|
29445
|
+
}
|
|
29446
|
+
if (failure.reason === "below-minimum") {
|
|
29447
|
+
return new CLIError("SESSION_LIFETIME_EXCEEDED", "share expiry must be at least 60 seconds from now; use a longer --expires value", 2);
|
|
29448
|
+
}
|
|
29449
|
+
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);
|
|
29450
|
+
}
|
|
29451
|
+
if (failure.kind === "origin-mismatch") {
|
|
29452
|
+
return new CLIError("ORIGIN_MISMATCH", "share origin does not match the configured service", 2);
|
|
29453
|
+
}
|
|
29454
|
+
}
|
|
29412
29455
|
if (error instanceof SharePublishError) {
|
|
29413
29456
|
const exit = error.code === "authority-required" ? 3 : error.code === "max-bytes-exceeded" ? 7 : 2;
|
|
29414
29457
|
const code4 = error.code === "authority-required" ? "AUTH_REQUIRED" : error.code === "max-bytes-exceeded" ? "MAX_BYTES_EXCEEDED" : "INVALID_ARGUMENT";
|
|
@@ -29491,7 +29534,7 @@ function assertAggregateInputLimit(inputs, maxBytes) {
|
|
|
29491
29534
|
}
|
|
29492
29535
|
function registerShareCommand(program2) {
|
|
29493
29536
|
const share = program2.command("share").description("Publish and consume TinyCloud Share links");
|
|
29494
|
-
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"
|
|
29537
|
+
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) => {
|
|
29495
29538
|
try {
|
|
29496
29539
|
const json = jsonOutput(options, command);
|
|
29497
29540
|
const maxBytes = byteLimit(options.maxBytes);
|
|
@@ -29513,7 +29556,8 @@ function registerShareCommand(program2) {
|
|
|
29513
29556
|
target,
|
|
29514
29557
|
resourceKind: options.prefix || inputs.length > 1 ? "prefix" : "exact",
|
|
29515
29558
|
actions,
|
|
29516
|
-
expiresAt: expires(options.expires),
|
|
29559
|
+
expiresAt: expires(options.expires ?? "7d"),
|
|
29560
|
+
expiryWasExplicit: options.expires !== void 0,
|
|
29517
29561
|
origin: options.viewerOrigin,
|
|
29518
29562
|
...maxBytes === void 0 ? {} : { maxBytes },
|
|
29519
29563
|
notify: options.notify === true,
|
|
@@ -29533,7 +29577,9 @@ function registerShareCommand(program2) {
|
|
|
29533
29577
|
const delivery = await notifyShare({ shareId: record.shareId, recipient: target.address, record, adapter: shareServices.delivery });
|
|
29534
29578
|
if (delivery.state === "partial-failure") process.exitCode = 9;
|
|
29535
29579
|
}
|
|
29536
|
-
if (
|
|
29580
|
+
if (result.metadata.expiryClamped === true) process.stderr.write(`Share expiry clamped to session expiry (${result.metadata.expiresAt}).
|
|
29581
|
+
`);
|
|
29582
|
+
if (json) writeJson2({ ...redactPublishedShare(result), expiryClamped: result.metadata.expiryClamped === true });
|
|
29537
29583
|
else publishHuman(result);
|
|
29538
29584
|
} catch (error) {
|
|
29539
29585
|
handleError(shareCliError(error));
|
|
@@ -31015,6 +31061,12 @@ var MAX_INLINE_BYTES2 = 256 * 1024;
|
|
|
31015
31061
|
|
|
31016
31062
|
// src/share/adapters.ts
|
|
31017
31063
|
init_dist4();
|
|
31064
|
+
import { extractSiweExpiration, InvalidRestoredSessionError } from "@tinycloud/node-sdk";
|
|
31065
|
+
function requiredKvAction(meta) {
|
|
31066
|
+
if (meta === null || typeof meta !== "object" || !("requiredAction" in meta)) return void 0;
|
|
31067
|
+
const action = meta.requiredAction;
|
|
31068
|
+
return action === "tinycloud.kv/put" || action === "tinycloud.kv/get" ? action : void 0;
|
|
31069
|
+
}
|
|
31018
31070
|
var DEFAULT_SHARE_ORIGIN = "https://share.tinycloud.xyz";
|
|
31019
31071
|
function createEncryptedSessionHistory() {
|
|
31020
31072
|
const records = /* @__PURE__ */ new Map();
|
|
@@ -31170,16 +31222,76 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
31170
31222
|
};
|
|
31171
31223
|
})();
|
|
31172
31224
|
let nodePromise;
|
|
31225
|
+
let activeProfileName2;
|
|
31173
31226
|
const authenticatedNode = async () => nodePromise ??= (async () => {
|
|
31174
31227
|
const profile = await (input.profileName?.() ?? selectedProfileName());
|
|
31228
|
+
activeProfileName2 = profile;
|
|
31175
31229
|
const context = await ProfileManager.resolveContext({ profile, ...input.nodeOrigin === void 0 ? {} : { host: input.nodeOrigin } });
|
|
31176
31230
|
const { ensureAuthenticated: ensureAuthenticated2 } = await Promise.resolve().then(() => (init_sdk(), sdk_exports));
|
|
31177
|
-
|
|
31231
|
+
try {
|
|
31232
|
+
return await ensureAuthenticated2(context);
|
|
31233
|
+
} catch (error) {
|
|
31234
|
+
const profileConfig = await ProfileManager.getProfile(profile).catch(() => void 0);
|
|
31235
|
+
const code4 = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
31236
|
+
if (error instanceof InvalidRestoredSessionError || code4 === "AUTH_EXPIRED") {
|
|
31237
|
+
throw new SharePublishAuthorityError({
|
|
31238
|
+
kind: "owner-space-unresolved",
|
|
31239
|
+
localKey: profileConfig?.authMethod === "local",
|
|
31240
|
+
profileName: profile
|
|
31241
|
+
});
|
|
31242
|
+
}
|
|
31243
|
+
throw error;
|
|
31244
|
+
}
|
|
31178
31245
|
})();
|
|
31179
31246
|
const targetAdapter = { async publish(targetInput) {
|
|
31180
31247
|
if (input.publishTarget !== void 0) return input.publishTarget(targetInput);
|
|
31181
31248
|
const [config, node] = await Promise.all([publicConfig(), authenticatedNode()]);
|
|
31182
|
-
|
|
31249
|
+
const session = node.restorableSession;
|
|
31250
|
+
const ownerSpaceId = session?.spaceId;
|
|
31251
|
+
const localKey = !node.isSessionOnly;
|
|
31252
|
+
let sessionExpiresAt;
|
|
31253
|
+
try {
|
|
31254
|
+
sessionExpiresAt = node.isSessionOnly && session?.siwe ? extractSiweExpiration(session.siwe) : void 0;
|
|
31255
|
+
} catch {
|
|
31256
|
+
throw new SharePublishAuthorityError({ kind: "owner-space-unresolved", localKey, profileName: activeProfileName2 });
|
|
31257
|
+
}
|
|
31258
|
+
if (ownerSpaceId === void 0 || node.isSessionOnly && (!session?.siwe || !session.signature || sessionExpiresAt === void 0)) {
|
|
31259
|
+
throw new SharePublishAuthorityError({ kind: "owner-space-unresolved", localKey, profileName: activeProfileName2 });
|
|
31260
|
+
}
|
|
31261
|
+
if (targetInput.origin !== config.shareOrigin) throw new SharePublishAuthorityError({ kind: "origin-mismatch" });
|
|
31262
|
+
if (node.isSessionOnly && sessionExpiresAt !== void 0) {
|
|
31263
|
+
const roundedSessionExpiry = new Date(Math.floor(sessionExpiresAt.getTime() / 1e3) * 1e3);
|
|
31264
|
+
if (roundedSessionExpiry.getTime() <= Date.now() + 6e4) {
|
|
31265
|
+
throw new SharePublishAuthorityError({
|
|
31266
|
+
kind: "lifetime-exceeds-session",
|
|
31267
|
+
sessionExpiresAt,
|
|
31268
|
+
reason: "session-too-close",
|
|
31269
|
+
localKey,
|
|
31270
|
+
profileName: activeProfileName2
|
|
31271
|
+
});
|
|
31272
|
+
}
|
|
31273
|
+
}
|
|
31274
|
+
const expiryClamped = node.isSessionOnly && sessionExpiresAt !== void 0 && targetInput.expiresAt > sessionExpiresAt;
|
|
31275
|
+
if (expiryClamped && targetInput.expiryWasExplicit) {
|
|
31276
|
+
throw new SharePublishAuthorityError({
|
|
31277
|
+
kind: "lifetime-exceeds-session",
|
|
31278
|
+
sessionExpiresAt,
|
|
31279
|
+
reason: "beyond-session",
|
|
31280
|
+
localKey,
|
|
31281
|
+
profileName: activeProfileName2
|
|
31282
|
+
});
|
|
31283
|
+
}
|
|
31284
|
+
const effectiveExpiry = expiryClamped ? sessionExpiresAt : targetInput.expiresAt;
|
|
31285
|
+
const expiresAt = new Date(Math.floor(effectiveExpiry.getTime() / 1e3) * 1e3);
|
|
31286
|
+
if (expiresAt.getTime() <= Date.now() + 6e4) {
|
|
31287
|
+
throw new SharePublishAuthorityError({
|
|
31288
|
+
kind: "lifetime-exceeds-session",
|
|
31289
|
+
sessionExpiresAt: sessionExpiresAt ?? expiresAt,
|
|
31290
|
+
reason: node.isSessionOnly && expiryClamped && !targetInput.expiryWasExplicit ? "session-too-close" : "below-minimum",
|
|
31291
|
+
localKey,
|
|
31292
|
+
profileName: activeProfileName2
|
|
31293
|
+
});
|
|
31294
|
+
}
|
|
31183
31295
|
const activeNode = await node.activeNodeIdentity();
|
|
31184
31296
|
const shareId = crypto.randomUUID().replaceAll("-", "");
|
|
31185
31297
|
const files = targetInput.files === void 0 || targetInput.files.length === 0 ? [{ bytes: targetInput.source, filename: targetInput.filename, mediaType: targetInput.mediaType }] : targetInput.files;
|
|
@@ -31188,16 +31300,43 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
31188
31300
|
if (resourceKind !== "exact" || files.length !== 1) throw new Error("native bearer publication requires one exact source file");
|
|
31189
31301
|
const file2 = files[0];
|
|
31190
31302
|
const resourcePath2 = `xyz.tinycloud.share/shares/${shareId}/${targetInput.filename}`;
|
|
31191
|
-
const written = await node.kvForSpace(
|
|
31303
|
+
const written = await node.kvForSpace(ownerSpaceId).put(resourcePath2, file2.bytes.slice(), {
|
|
31192
31304
|
contentType: targetInput.mediaType ?? file2.mediaType ?? "application/octet-stream"
|
|
31193
31305
|
});
|
|
31194
|
-
if (!written.ok)
|
|
31195
|
-
|
|
31196
|
-
|
|
31197
|
-
|
|
31198
|
-
|
|
31199
|
-
|
|
31200
|
-
|
|
31306
|
+
if (!written.ok) {
|
|
31307
|
+
const code4 = typeof written.error === "object" && written.error !== null && "code" in written.error ? written.error.code : void 0;
|
|
31308
|
+
if (code4 === "AUTH_UNAUTHORIZED" || code4 === "PERMISSION_DENIED") {
|
|
31309
|
+
const requiredAction = requiredKvAction(written.error.meta);
|
|
31310
|
+
throw new SharePublishAuthorityError({
|
|
31311
|
+
kind: "scope-denied",
|
|
31312
|
+
capability: "KV upload",
|
|
31313
|
+
...requiredAction === void 0 ? {} : { requiredAction },
|
|
31314
|
+
localKey,
|
|
31315
|
+
profileName: activeProfileName2
|
|
31316
|
+
});
|
|
31317
|
+
}
|
|
31318
|
+
throw new Error("native bearer source upload failed");
|
|
31319
|
+
}
|
|
31320
|
+
let native;
|
|
31321
|
+
try {
|
|
31322
|
+
native = await createNativeShare(node.sharing, {
|
|
31323
|
+
path: resourcePath2,
|
|
31324
|
+
expiresAt,
|
|
31325
|
+
viewerOrigin: config.shareOrigin
|
|
31326
|
+
});
|
|
31327
|
+
} catch (error) {
|
|
31328
|
+
const code4 = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
31329
|
+
if (code4 === "AUTH_UNAUTHORIZED" || code4 === "PERMISSION_DENIED") {
|
|
31330
|
+
throw new SharePublishAuthorityError({
|
|
31331
|
+
kind: "scope-denied",
|
|
31332
|
+
capability: "sharing delegation",
|
|
31333
|
+
localKey,
|
|
31334
|
+
profileName: activeProfileName2
|
|
31335
|
+
});
|
|
31336
|
+
}
|
|
31337
|
+
throw error;
|
|
31338
|
+
}
|
|
31339
|
+
if (native.spaceId !== ownerSpaceId) throw new Error("native bearer delegation authority does not match the authenticated owner space");
|
|
31201
31340
|
const result = {
|
|
31202
31341
|
protocol: "tinycloud-share",
|
|
31203
31342
|
version: SHARE_PUBLISH_RESULT_VERSION,
|
|
@@ -31211,6 +31350,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
31211
31350
|
target: { kind: "bearer", origin: activeNode.origin, nodeAudience: activeNode.nodeDid, spaceId: native.spaceId },
|
|
31212
31351
|
resource: { kind: "exact", path: resourcePath2 },
|
|
31213
31352
|
actions: ["read"],
|
|
31353
|
+
...expiryClamped ? { expiryClamped: true } : {},
|
|
31214
31354
|
expiresAt: native.expiresAt.toISOString(),
|
|
31215
31355
|
display: { filename: targetInput.filename },
|
|
31216
31356
|
recipientMatcher: { kind: "bearer" },
|
|
@@ -31227,15 +31367,28 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
31227
31367
|
const byteLength = file.bytes.byteLength;
|
|
31228
31368
|
if (!Number.isSafeInteger(byteLength) || byteLength > 100 * 1024 * 1024) throw new Error("addressed publication exceeds the combined byte limit");
|
|
31229
31369
|
const mediaType = targetInput.mediaType ?? file.mediaType ?? "application/octet-stream";
|
|
31230
|
-
const encryptionNetwork = node.getEncryptionNetworkIdForSpace(
|
|
31370
|
+
const encryptionNetwork = node.getEncryptionNetworkIdForSpace(ownerSpaceId);
|
|
31231
31371
|
const encrypted = await node.encryption.encryptToNetwork(encryptionNetwork, file.bytes, { metadata: { contentType: mediaType } });
|
|
31232
31372
|
if (!encrypted.ok) throw new Error("addressed source encryption was rejected");
|
|
31233
31373
|
const storedBytes = new TextEncoder().encode(canonicalize3(encrypted.data));
|
|
31234
|
-
const stored = await node.kvForSpace(
|
|
31235
|
-
if (!stored.ok)
|
|
31374
|
+
const stored = await node.kvForSpace(ownerSpaceId).put(resourcePath, storedBytes, { contentType: "application/vnd.tinycloud.encrypted-envelope+json" });
|
|
31375
|
+
if (!stored.ok) {
|
|
31376
|
+
const code4 = typeof stored.error === "object" && stored.error !== null && "code" in stored.error ? stored.error.code : void 0;
|
|
31377
|
+
if (code4 === "AUTH_UNAUTHORIZED" || code4 === "PERMISSION_DENIED") {
|
|
31378
|
+
const requiredAction = requiredKvAction(stored.error.meta);
|
|
31379
|
+
throw new SharePublishAuthorityError({
|
|
31380
|
+
kind: "scope-denied",
|
|
31381
|
+
capability: "KV upload",
|
|
31382
|
+
...requiredAction === void 0 ? {} : { requiredAction },
|
|
31383
|
+
localKey,
|
|
31384
|
+
profileName: activeProfileName2
|
|
31385
|
+
});
|
|
31386
|
+
}
|
|
31387
|
+
throw new Error("addressed source upload failed");
|
|
31388
|
+
}
|
|
31236
31389
|
const contentSource = {
|
|
31237
31390
|
shareId,
|
|
31238
|
-
kvResource: `${
|
|
31391
|
+
kvResource: `${ownerSpaceId}/kv/${resourcePath}`,
|
|
31239
31392
|
selector: resourceKind,
|
|
31240
31393
|
encryptionNetwork: encrypted.data.networkId,
|
|
31241
31394
|
encryptedSymmetricKeyDigestHex: encrypted.data.encryptedSymmetricKeyHash,
|
|
@@ -31245,13 +31398,13 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
31245
31398
|
};
|
|
31246
31399
|
const actions = targetInput.actions === void 0 || targetInput.actions.length === 0 ? ["read"] : targetInput.actions;
|
|
31247
31400
|
const policyActions = [...new Set(actions.flatMap((action) => action === "read" ? ["tinycloud.kv/get", "tinycloud.kv/metadata"] : action === "list" ? ["tinycloud.kv/list"] : ["tinycloud.kv/put"]))];
|
|
31248
|
-
|
|
31401
|
+
const published = await publishAddressedShare({
|
|
31249
31402
|
shareId,
|
|
31250
31403
|
shareOrigin: config.shareOrigin,
|
|
31251
31404
|
nodeOrigin: activeNode.origin,
|
|
31252
31405
|
nodeAudience: activeNode.nodeDid,
|
|
31253
31406
|
enforcerDid: activeNode.nodeDid,
|
|
31254
|
-
spaceId:
|
|
31407
|
+
spaceId: ownerSpaceId,
|
|
31255
31408
|
target: targetInput.target,
|
|
31256
31409
|
resource: { kind: resourceKind, path: resourcePath },
|
|
31257
31410
|
actions,
|
|
@@ -31260,7 +31413,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
31260
31413
|
filename: targetInput.filename,
|
|
31261
31414
|
mediaType,
|
|
31262
31415
|
byteLength,
|
|
31263
|
-
expiresAt
|
|
31416
|
+
expiresAt,
|
|
31264
31417
|
// App-neutral owner authority: the Node SDK owns every Policy/v3
|
|
31265
31418
|
// transport hop, so the CLI supplies only owner signing material.
|
|
31266
31419
|
authority: {
|
|
@@ -31270,6 +31423,8 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
31270
31423
|
registerPolicy: (request) => node.registerPolicy(request)
|
|
31271
31424
|
}
|
|
31272
31425
|
});
|
|
31426
|
+
if (expiryClamped) Object.defineProperty(published.metadata, "expiryClamped", { value: true, enumerable: true });
|
|
31427
|
+
return published;
|
|
31273
31428
|
} };
|
|
31274
31429
|
const delivery = { deliver: input.deliver ?? (async (request) => {
|
|
31275
31430
|
const record = request.record;
|