@tinycloud/cli 1.0.1-beta.5 → 1.1.0-beta.11
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 +2253 -1863
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +2443 -588
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +5 -5
- package/skills/tc-cli/AUTH.md +14 -1
- package/skills/tc-cli/REFERENCE.md +37 -7
- package/skills/tc-cli/SKILL.md +5 -1
package/dist/legacy-entry.js
CHANGED
|
@@ -14,11 +14,11 @@ var __export = (target, all) => {
|
|
|
14
14
|
for (var name in all)
|
|
15
15
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
16
|
};
|
|
17
|
-
var __copyProps = (to,
|
|
18
|
-
if (
|
|
19
|
-
for (let key of __getOwnPropNames(
|
|
17
|
+
var __copyProps = (to, from4, except, desc) => {
|
|
18
|
+
if (from4 && typeof from4 === "object" || typeof from4 === "function") {
|
|
19
|
+
for (let key of __getOwnPropNames(from4))
|
|
20
20
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
21
|
-
__defProp(to, key, { get: () =>
|
|
21
|
+
__defProp(to, key, { get: () => from4[key], enumerable: !(desc = __getOwnPropDesc(from4, key)) || desc.enumerable });
|
|
22
22
|
}
|
|
23
23
|
return to;
|
|
24
24
|
};
|
|
@@ -163,10 +163,10 @@ import ora from "ora";
|
|
|
163
163
|
function outputJson(data) {
|
|
164
164
|
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
165
165
|
}
|
|
166
|
-
function outputError(
|
|
166
|
+
function outputError(code3, message, hint, meta) {
|
|
167
167
|
if (isInteractive()) {
|
|
168
168
|
process.stderr.write(
|
|
169
|
-
`${theme.error("\u2717")} ${theme.label(
|
|
169
|
+
`${theme.error("\u2717")} ${theme.label(code3)}: ${message}
|
|
170
170
|
`
|
|
171
171
|
);
|
|
172
172
|
if (hint) {
|
|
@@ -177,9 +177,10 @@ function outputError(code2, message, hint) {
|
|
|
177
177
|
}
|
|
178
178
|
} else {
|
|
179
179
|
const payload = {
|
|
180
|
-
error: { code:
|
|
180
|
+
error: { code: code3, message }
|
|
181
181
|
};
|
|
182
182
|
if (hint) payload.error.hint = hint;
|
|
183
|
+
if (meta) payload.error.meta = meta;
|
|
183
184
|
process.stderr.write(JSON.stringify(payload, null, 2) + "\n");
|
|
184
185
|
}
|
|
185
186
|
}
|
|
@@ -260,24 +261,43 @@ var init_formatter = __esm({
|
|
|
260
261
|
// src/output/errors.ts
|
|
261
262
|
import { readFileSync, readdirSync } from "fs";
|
|
262
263
|
import { join as join2 } from "path";
|
|
263
|
-
import { ProfileLockTimeoutError } from "@tinycloud/operations/state";
|
|
264
|
+
import { ProfileDeletedError, ProfileLockTimeoutError } from "@tinycloud/operations/state";
|
|
265
|
+
import { authorizationVerdictOf, parseCapabilityResource, SERVICE_LONG_TO_SHORT, validatedCapabilityOf } from "@tinycloud/sdk-core";
|
|
264
266
|
function setActiveProfileName(name) {
|
|
265
267
|
activeProfileName = name;
|
|
266
268
|
}
|
|
269
|
+
function cliErrorFromService(error, message = error.message) {
|
|
270
|
+
if (error instanceof CLIError) return error;
|
|
271
|
+
const meta = { ...error.meta };
|
|
272
|
+
delete meta.hint;
|
|
273
|
+
const status = error.status ?? error.statusCode;
|
|
274
|
+
if (typeof status === "number" && Number.isInteger(status) && status >= 400 && status <= 599) meta.status = status;
|
|
275
|
+
const verdict = authorizationVerdictOf({ ...error, meta });
|
|
276
|
+
if (verdict === void 0 && message.includes("Missing private key parameter in JWK")) {
|
|
277
|
+
return missingPrivateKeyError();
|
|
278
|
+
}
|
|
279
|
+
const missingCapability = validatedCapabilityOf({ ...error, meta }) !== void 0;
|
|
280
|
+
const denied = verdict === "forbidden" || verdict === "unauthenticated" && missingCapability;
|
|
281
|
+
return new CLIError(
|
|
282
|
+
denied ? "PERMISSION_DENIED" : verdict === "unauthenticated" ? "AUTH_REQUIRED" : error.code,
|
|
283
|
+
message,
|
|
284
|
+
denied ? ExitCode.PERMISSION_DENIED : verdict === "unauthenticated" ? ExitCode.AUTH_REQUIRED : ExitCode.ERROR,
|
|
285
|
+
meta
|
|
286
|
+
);
|
|
287
|
+
}
|
|
267
288
|
function wrapError(error) {
|
|
289
|
+
if (error instanceof CLIError) return error;
|
|
268
290
|
const message = error instanceof Error ? error.message : String(error);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
return new CLIError(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
);
|
|
291
|
+
const verdict = authorizationVerdictOf(error);
|
|
292
|
+
if (verdict === "unauthenticated") {
|
|
293
|
+
return new CLIError("AUTH_REQUIRED", message, ExitCode.AUTH_REQUIRED);
|
|
294
|
+
}
|
|
295
|
+
if (verdict === "forbidden") {
|
|
296
|
+
return new CLIError("PERMISSION_DENIED", message, ExitCode.PERMISSION_DENIED);
|
|
297
|
+
}
|
|
298
|
+
if (verdict === void 0 && message.includes("Missing private key parameter in JWK")) {
|
|
299
|
+
return missingPrivateKeyError();
|
|
279
300
|
}
|
|
280
|
-
if (error instanceof CLIError) return error;
|
|
281
301
|
if (error instanceof ProfileLockTimeoutError) {
|
|
282
302
|
return new CLIError(
|
|
283
303
|
"PROFILE_LOCK_TIMEOUT",
|
|
@@ -286,13 +306,16 @@ function wrapError(error) {
|
|
|
286
306
|
{ hint: "Wait for the other command to finish and retry. A crashed process's lock is reclaimed automatically after 30 s." }
|
|
287
307
|
);
|
|
288
308
|
}
|
|
289
|
-
if (
|
|
309
|
+
if (error instanceof ProfileDeletedError) {
|
|
310
|
+
return new CLIError("PROFILE_NOT_FOUND", message);
|
|
311
|
+
}
|
|
312
|
+
if (verdict === void 0 && (message.includes("Not signed in") || message.includes("AUTH_EXPIRED") || message.includes("Session expired"))) {
|
|
290
313
|
return new CLIError("AUTH_REQUIRED", message, ExitCode.AUTH_REQUIRED);
|
|
291
314
|
}
|
|
292
315
|
if (message.includes("NOT_FOUND") || message.includes("KV_NOT_FOUND")) {
|
|
293
316
|
return new CLIError("NOT_FOUND", message, ExitCode.NOT_FOUND);
|
|
294
317
|
}
|
|
295
|
-
if (message.includes("PERMISSION_DENIED")) {
|
|
318
|
+
if (verdict === void 0 && message.includes("PERMISSION_DENIED")) {
|
|
296
319
|
return new CLIError("PERMISSION_DENIED", message, ExitCode.PERMISSION_DENIED);
|
|
297
320
|
}
|
|
298
321
|
if (message.includes("ECONNREFUSED") || message.includes("ETIMEDOUT") || message.includes("fetch failed")) {
|
|
@@ -300,39 +323,51 @@ function wrapError(error) {
|
|
|
300
323
|
}
|
|
301
324
|
return new CLIError("ERROR", message, ExitCode.ERROR);
|
|
302
325
|
}
|
|
326
|
+
function missingPrivateKeyError() {
|
|
327
|
+
const profileName = activeProfileName ?? process.env.TC_PROFILE ?? DEFAULT_PROFILE;
|
|
328
|
+
return new CLIError(
|
|
329
|
+
"AUTH_REQUIRED",
|
|
330
|
+
`Profile "${profileName}" cannot restore its session because its private key material is missing.`,
|
|
331
|
+
ExitCode.AUTH_REQUIRED,
|
|
332
|
+
{ hint: `Sign in again with: tc --profile ${profileName} auth login --method openkey` }
|
|
333
|
+
);
|
|
334
|
+
}
|
|
303
335
|
function handleError(error) {
|
|
304
336
|
const cliError = wrapError(error);
|
|
305
337
|
const prebuilt = typeof cliError.metadata?.hint === "string" ? cliError.metadata.hint : void 0;
|
|
306
338
|
const hint = prebuilt ?? buildAuthHint(cliError) ?? (cliError.code === "NETWORK_ERROR" ? buildNetworkHint() : void 0);
|
|
307
|
-
|
|
339
|
+
const authMeta = cliError.code === "AUTH_REQUIRED" || cliError.code === "PERMISSION_DENIED" ? cliError.metadata : void 0;
|
|
340
|
+
const meta = {};
|
|
341
|
+
if (cliError.status !== void 0 && authMeta !== void 0) meta.status = cliError.status;
|
|
342
|
+
const capability = validatedCapabilityOf({ meta: authMeta });
|
|
343
|
+
if (capability) {
|
|
344
|
+
meta.resource = capability.resource;
|
|
345
|
+
meta.requiredAction = capability.requiredAction;
|
|
346
|
+
}
|
|
347
|
+
outputError(cliError.code, cliError.message, hint, Object.keys(meta).length ? meta : void 0);
|
|
308
348
|
process.exit(cliError.exitCode);
|
|
309
349
|
}
|
|
310
350
|
function buildAuthHint(error) {
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return void 0;
|
|
315
|
-
}
|
|
316
|
-
const spec = capSpecFromAuthMeta(resource, requiredAction);
|
|
351
|
+
const capability = validatedCapabilityOf({ meta: error.metadata });
|
|
352
|
+
if (!capability) return void 0;
|
|
353
|
+
const spec = capSpecFromAuthMeta(capability.resource, capability.requiredAction);
|
|
317
354
|
if (!spec) return void 0;
|
|
318
355
|
return [
|
|
319
356
|
"The active session is missing a TinyCloud capability.",
|
|
320
|
-
`Request it with: tc auth request --cap
|
|
357
|
+
`Request it with: tc auth request --cap '${spec.replaceAll("'", "'\\''")}'`,
|
|
321
358
|
"Then retry the original command."
|
|
322
359
|
].join("\n");
|
|
323
360
|
}
|
|
324
361
|
function capSpecFromAuthMeta(resource, action) {
|
|
325
|
-
const slash =
|
|
326
|
-
if (slash
|
|
327
|
-
const
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
const spaceName = spaceUri.startsWith("tinycloud:") ? spaceUri.slice(spaceUri.lastIndexOf(":") + 1) : spaceUri;
|
|
335
|
-
return `tinycloud.${serviceShort}:${spaceName}:${path}:${actionName}`;
|
|
362
|
+
const slash = action.indexOf("/");
|
|
363
|
+
if (slash < 0) return void 0;
|
|
364
|
+
const longService = action.slice(0, slash);
|
|
365
|
+
const serviceShort = SERVICE_LONG_TO_SHORT[longService];
|
|
366
|
+
if (!serviceShort) return void 0;
|
|
367
|
+
const parsed = parseCapabilityResource(resource, serviceShort);
|
|
368
|
+
if (!parsed) return void 0;
|
|
369
|
+
const spaceName = parsed.space.slice(parsed.space.lastIndexOf(":") + 1);
|
|
370
|
+
return `${longService}:${spaceName}:${parsed.path}:${action.slice(slash + 1)}`;
|
|
336
371
|
}
|
|
337
372
|
function buildNetworkHint() {
|
|
338
373
|
const readHost = (name) => {
|
|
@@ -380,13 +415,15 @@ var init_errors = __esm({
|
|
|
380
415
|
init_constants();
|
|
381
416
|
init_formatter();
|
|
382
417
|
CLIError = class extends Error {
|
|
383
|
-
constructor(
|
|
418
|
+
constructor(code3, message, exitCode = ExitCode.ERROR, metadata) {
|
|
384
419
|
super(message);
|
|
385
|
-
this.code =
|
|
420
|
+
this.code = code3;
|
|
386
421
|
this.exitCode = exitCode;
|
|
387
422
|
this.metadata = metadata;
|
|
388
423
|
this.name = "CLIError";
|
|
424
|
+
if (typeof metadata?.status === "number" && Number.isInteger(metadata.status) && metadata.status >= 400 && metadata.status <= 599) this.status = metadata.status;
|
|
389
425
|
}
|
|
426
|
+
status;
|
|
390
427
|
};
|
|
391
428
|
}
|
|
392
429
|
});
|
|
@@ -644,6 +681,8 @@ import { join as join3 } from "path";
|
|
|
644
681
|
import {
|
|
645
682
|
profilePath,
|
|
646
683
|
readSession,
|
|
684
|
+
recordProfileDeletion,
|
|
685
|
+
refuseWriteToDeletedProfile,
|
|
647
686
|
removeSession,
|
|
648
687
|
withProfileLock,
|
|
649
688
|
writeSession
|
|
@@ -723,7 +762,7 @@ var init_profiles = __esm({
|
|
|
723
762
|
if (!profile) {
|
|
724
763
|
throw new CLIError(
|
|
725
764
|
"PROFILE_NOT_FOUND",
|
|
726
|
-
`Profile "${name}" does not exist.
|
|
765
|
+
`Profile "${name}" does not exist. Create it with \`tc init --name ${name}\`.`
|
|
727
766
|
);
|
|
728
767
|
}
|
|
729
768
|
return profile;
|
|
@@ -758,10 +797,12 @@ var init_profiles = __esm({
|
|
|
758
797
|
* removed while holding the profile lock, so another writer's critical
|
|
759
798
|
* section never sees them vanish midway: session and key first, settings
|
|
760
799
|
* last, so a crash midway never leaves a session or key without its
|
|
761
|
-
* profile.
|
|
762
|
-
*
|
|
763
|
-
*
|
|
764
|
-
*
|
|
800
|
+
* profile. The deletion is then recorded, so a store write that waited for
|
|
801
|
+
* the lock meanwhile refuses rather than recreating a profile with only a
|
|
802
|
+
* session in it. `.lock` itself is left to the lock's release; the
|
|
803
|
+
* then-empty directory is removed afterwards unless another writer took
|
|
804
|
+
* the lock (or wrote) meanwhile. A profile directory that is a symlink is
|
|
805
|
+
* unlinked, its target left alone.
|
|
765
806
|
* Throws if the name is not one path segment or names the default profile.
|
|
766
807
|
*/
|
|
767
808
|
static async deleteProfile(name) {
|
|
@@ -782,11 +823,12 @@ var init_profiles = __esm({
|
|
|
782
823
|
`Cannot delete the default profile "${name}". Change the default first with \`tc profile default <other>\`.`
|
|
783
824
|
);
|
|
784
825
|
}
|
|
785
|
-
const
|
|
786
|
-
if (error.code === "ENOENT") return
|
|
826
|
+
const kind = await lstat(profileDir).then((stats) => stats.isSymbolicLink() ? "link" : "present", (error) => {
|
|
827
|
+
if (error.code === "ENOENT") return "missing";
|
|
787
828
|
throw error;
|
|
788
829
|
});
|
|
789
|
-
if (
|
|
830
|
+
if (kind === "missing") return;
|
|
831
|
+
if (kind === "link") {
|
|
790
832
|
await rm2(profileDir, { force: true });
|
|
791
833
|
return;
|
|
792
834
|
}
|
|
@@ -796,6 +838,7 @@ var init_profiles = __esm({
|
|
|
796
838
|
if (entry !== ".lock" && entry !== "profile.json") await rm2(join3(profileDir, entry), { recursive: true, force: true });
|
|
797
839
|
}
|
|
798
840
|
await rm2(join3(profileDir, "profile.json"), { force: true });
|
|
841
|
+
await recordProfileDeletion(name);
|
|
799
842
|
});
|
|
800
843
|
await rmdir(profileDir).catch((error) => {
|
|
801
844
|
if (error.code !== "ENOENT" && error.code !== "ENOTEMPTY" && error.code !== "EEXIST") throw error;
|
|
@@ -808,9 +851,14 @@ var init_profiles = __esm({
|
|
|
808
851
|
static async getKey(name) {
|
|
809
852
|
return readJson(join3(PROFILES_DIR, name, "key.json"));
|
|
810
853
|
}
|
|
811
|
-
/**
|
|
854
|
+
/**
|
|
855
|
+
* Saves a JWK key under the profile lock (0600, in an owner-only profile
|
|
856
|
+
* directory). Refused (PROFILE_NOT_FOUND) if the profile was deleted while
|
|
857
|
+
* this waited for the lock, rather than leaving a key-only profile.
|
|
858
|
+
*/
|
|
812
859
|
static async setKey(name, jwk) {
|
|
813
860
|
await _ProfileManager.withLock(name, async () => {
|
|
861
|
+
await refuseWriteToDeletedProfile(name);
|
|
814
862
|
await writeJson(join3(await _ProfileManager.ensureProfileDir(name), "key.json"), jwk);
|
|
815
863
|
});
|
|
816
864
|
}
|
|
@@ -1325,12 +1373,12 @@ var init_md = __esm({
|
|
|
1325
1373
|
_cloneInto(to) {
|
|
1326
1374
|
to || (to = new this.constructor());
|
|
1327
1375
|
to.set(...this.get());
|
|
1328
|
-
const { blockLen, buffer, length:
|
|
1376
|
+
const { blockLen, buffer, length: length4, finished, destroyed, pos } = this;
|
|
1329
1377
|
to.destroyed = destroyed;
|
|
1330
1378
|
to.finished = finished;
|
|
1331
|
-
to.length =
|
|
1379
|
+
to.length = length4;
|
|
1332
1380
|
to.pos = pos;
|
|
1333
|
-
if (
|
|
1381
|
+
if (length4 % blockLen)
|
|
1334
1382
|
to.buffer.set(buffer);
|
|
1335
1383
|
return to;
|
|
1336
1384
|
}
|
|
@@ -1728,11 +1776,11 @@ var require_decrypt_transport_response_error = __commonJS({
|
|
|
1728
1776
|
for (var name in all)
|
|
1729
1777
|
__defProp3(target, name, { get: all[name], enumerable: true });
|
|
1730
1778
|
};
|
|
1731
|
-
var __copyProps2 = (to,
|
|
1732
|
-
if (
|
|
1733
|
-
for (let key of __getOwnPropNames2(
|
|
1779
|
+
var __copyProps2 = (to, from4, except, desc) => {
|
|
1780
|
+
if (from4 && typeof from4 === "object" || typeof from4 === "function") {
|
|
1781
|
+
for (let key of __getOwnPropNames2(from4))
|
|
1734
1782
|
if (!__hasOwnProp2.call(to, key) && key !== except)
|
|
1735
|
-
__defProp3(to, key, { get: () =>
|
|
1783
|
+
__defProp3(to, key, { get: () => from4[key], enumerable: !(desc = __getOwnPropDesc2(from4, key)) || desc.enumerable });
|
|
1736
1784
|
}
|
|
1737
1785
|
return to;
|
|
1738
1786
|
};
|
|
@@ -1779,7 +1827,8 @@ import {
|
|
|
1779
1827
|
profileStoreMetadataPath,
|
|
1780
1828
|
readAdditionalDelegations,
|
|
1781
1829
|
readAuthRequests,
|
|
1782
|
-
|
|
1830
|
+
refuseWriteToDeletedProfile as refuseWriteToDeletedProfile2,
|
|
1831
|
+
updateProfileStore,
|
|
1783
1832
|
withProfileLock as withProfileLock2,
|
|
1784
1833
|
writeJsonAtomic
|
|
1785
1834
|
} from "@tinycloud/operations/state";
|
|
@@ -1865,6 +1914,7 @@ var CAPABILITIES2 = deriveServiceConstants("capabilities");
|
|
|
1865
1914
|
var HOOKS = deriveServiceConstants("hooks");
|
|
1866
1915
|
var ENCRYPTION = deriveServiceConstants("encryption");
|
|
1867
1916
|
var SPACE = deriveServiceConstants("space");
|
|
1917
|
+
var CAPABILITY_REGISTRY = CAPABILITIES;
|
|
1868
1918
|
var DEFAULT_MANIFEST_SPACE = "applications";
|
|
1869
1919
|
var ACCOUNT_REGISTRY_SPACE = "account";
|
|
1870
1920
|
var ACCOUNT_REGISTRY_PATH = "applications/";
|
|
@@ -3322,8 +3372,8 @@ function isValidJWT(jwt, alg) {
|
|
|
3322
3372
|
const [header] = jwt.split(".");
|
|
3323
3373
|
if (!header)
|
|
3324
3374
|
return false;
|
|
3325
|
-
const
|
|
3326
|
-
const decoded = JSON.parse(atob(
|
|
3375
|
+
const base643 = header.replace(/-/g, "+").replace(/_/g, "/").padEnd(header.length + (4 - header.length % 4) % 4, "=");
|
|
3376
|
+
const decoded = JSON.parse(atob(base643));
|
|
3327
3377
|
if (typeof decoded !== "object" || decoded === null)
|
|
3328
3378
|
return false;
|
|
3329
3379
|
if ("typ" in decoded && decoded?.typ !== "JWT")
|
|
@@ -5977,23 +6027,23 @@ var ZodEffects = class extends ZodType {
|
|
|
5977
6027
|
}
|
|
5978
6028
|
if (effect.type === "transform") {
|
|
5979
6029
|
if (ctx.common.async === false) {
|
|
5980
|
-
const
|
|
6030
|
+
const base4 = this._def.schema._parseSync({
|
|
5981
6031
|
data: ctx.data,
|
|
5982
6032
|
path: ctx.path,
|
|
5983
6033
|
parent: ctx
|
|
5984
6034
|
});
|
|
5985
|
-
if (!isValid(
|
|
6035
|
+
if (!isValid(base4))
|
|
5986
6036
|
return INVALID;
|
|
5987
|
-
const result = effect.transform(
|
|
6037
|
+
const result = effect.transform(base4.value, checkCtx);
|
|
5988
6038
|
if (result instanceof Promise) {
|
|
5989
6039
|
throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`);
|
|
5990
6040
|
}
|
|
5991
6041
|
return { status: status.value, value: result };
|
|
5992
6042
|
} else {
|
|
5993
|
-
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((
|
|
5994
|
-
if (!isValid(
|
|
6043
|
+
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base4) => {
|
|
6044
|
+
if (!isValid(base4))
|
|
5995
6045
|
return INVALID;
|
|
5996
|
-
return Promise.resolve(effect.transform(
|
|
6046
|
+
return Promise.resolve(effect.transform(base4.value, checkCtx)).then((result) => ({
|
|
5997
6047
|
status: status.value,
|
|
5998
6048
|
value: result
|
|
5999
6049
|
}));
|
|
@@ -6432,9 +6482,9 @@ function ok(data) {
|
|
|
6432
6482
|
function err(error) {
|
|
6433
6483
|
return { ok: false, error };
|
|
6434
6484
|
}
|
|
6435
|
-
function serviceError(
|
|
6485
|
+
function serviceError(code3, message, service, options) {
|
|
6436
6486
|
return {
|
|
6437
|
-
code:
|
|
6487
|
+
code: code3,
|
|
6438
6488
|
message,
|
|
6439
6489
|
service,
|
|
6440
6490
|
cause: options?.cause,
|
|
@@ -6805,6 +6855,75 @@ var ServiceSessionSchema = external_exports.object({
|
|
|
6805
6855
|
/** The session key JWK (required for invoke) */
|
|
6806
6856
|
jwk: external_exports.object({}).passthrough()
|
|
6807
6857
|
});
|
|
6858
|
+
var URN_PREFIX = "urn:tinycloud:encryption:";
|
|
6859
|
+
var NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
6860
|
+
var PKH_EIP155_DID_RE = /^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/;
|
|
6861
|
+
var NetworkIdError = class extends Error {
|
|
6862
|
+
constructor(message) {
|
|
6863
|
+
super(message);
|
|
6864
|
+
this.name = "NetworkIdError";
|
|
6865
|
+
}
|
|
6866
|
+
};
|
|
6867
|
+
function parseNetworkId(networkId) {
|
|
6868
|
+
if (typeof networkId !== "string" || networkId.length === 0) {
|
|
6869
|
+
throw new NetworkIdError("networkId must be a non-empty string");
|
|
6870
|
+
}
|
|
6871
|
+
if (!networkId.startsWith(URN_PREFIX)) {
|
|
6872
|
+
throw new NetworkIdError(
|
|
6873
|
+
`networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`
|
|
6874
|
+
);
|
|
6875
|
+
}
|
|
6876
|
+
const body = networkId.slice(URN_PREFIX.length);
|
|
6877
|
+
const lastColon = body.lastIndexOf(":");
|
|
6878
|
+
if (lastColon <= 0 || lastColon === body.length - 1) {
|
|
6879
|
+
throw new NetworkIdError(
|
|
6880
|
+
`networkId missing ownerDid or name segment (got ${JSON.stringify(networkId)})`
|
|
6881
|
+
);
|
|
6882
|
+
}
|
|
6883
|
+
const ownerDid = body.slice(0, lastColon);
|
|
6884
|
+
const name = body.slice(lastColon + 1);
|
|
6885
|
+
if (!ownerDid.startsWith("did:")) {
|
|
6886
|
+
throw new NetworkIdError(
|
|
6887
|
+
`networkId ownerDid must be a DID (got ${JSON.stringify(ownerDid)})`
|
|
6888
|
+
);
|
|
6889
|
+
}
|
|
6890
|
+
const didParts = ownerDid.split(":");
|
|
6891
|
+
if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {
|
|
6892
|
+
throw new NetworkIdError(
|
|
6893
|
+
`networkId ownerDid is not a well-formed DID (got ${JSON.stringify(ownerDid)})`
|
|
6894
|
+
);
|
|
6895
|
+
}
|
|
6896
|
+
if (!NETWORK_NAME_RE.test(name)) {
|
|
6897
|
+
throw new NetworkIdError(
|
|
6898
|
+
`networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
6899
|
+
);
|
|
6900
|
+
}
|
|
6901
|
+
return { networkId, ownerDid, name };
|
|
6902
|
+
}
|
|
6903
|
+
function parsePkhOwnerDid(ownerDid) {
|
|
6904
|
+
const match = ownerDid.match(PKH_EIP155_DID_RE);
|
|
6905
|
+
if (!match) return null;
|
|
6906
|
+
return {
|
|
6907
|
+
chainId: match[1],
|
|
6908
|
+
address: match[2].toLowerCase()
|
|
6909
|
+
};
|
|
6910
|
+
}
|
|
6911
|
+
function ownerDidMatches(a, b) {
|
|
6912
|
+
const aPkh = parsePkhOwnerDid(a);
|
|
6913
|
+
const bPkh = parsePkhOwnerDid(b);
|
|
6914
|
+
if (aPkh && bPkh) {
|
|
6915
|
+
return aPkh.chainId === bPkh.chainId && aPkh.address === bPkh.address;
|
|
6916
|
+
}
|
|
6917
|
+
return a === b;
|
|
6918
|
+
}
|
|
6919
|
+
function networkDiscoveryKey(name) {
|
|
6920
|
+
if (!NETWORK_NAME_RE.test(name)) {
|
|
6921
|
+
throw new NetworkIdError(
|
|
6922
|
+
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
6923
|
+
);
|
|
6924
|
+
}
|
|
6925
|
+
return `.well-known/encryption/network/${name}`;
|
|
6926
|
+
}
|
|
6808
6927
|
function parsePermissionHint(value) {
|
|
6809
6928
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
6810
6929
|
const candidate = value;
|
|
@@ -6848,11 +6967,31 @@ function authRequiredError(service) {
|
|
|
6848
6967
|
service
|
|
6849
6968
|
};
|
|
6850
6969
|
}
|
|
6851
|
-
|
|
6970
|
+
var RequestTimeoutError = class extends Error {
|
|
6971
|
+
constructor(timeoutMs) {
|
|
6972
|
+
super(`Request timed out after ${timeoutMs}ms.`);
|
|
6973
|
+
this.name = "TimeoutError";
|
|
6974
|
+
this.timeoutMs = timeoutMs;
|
|
6975
|
+
}
|
|
6976
|
+
};
|
|
6977
|
+
function isRequestTimeoutError(error) {
|
|
6978
|
+
return error instanceof RequestTimeoutError || error instanceof Error && error.name === "TimeoutError" && typeof error.timeoutMs === "number";
|
|
6979
|
+
}
|
|
6980
|
+
function timeoutError(service, timeoutMs, cause) {
|
|
6981
|
+
if (timeoutMs === void 0) {
|
|
6982
|
+
return {
|
|
6983
|
+
code: ErrorCodes.TIMEOUT,
|
|
6984
|
+
message: "Request timed out.",
|
|
6985
|
+
service,
|
|
6986
|
+
...cause === void 0 ? {} : { cause }
|
|
6987
|
+
};
|
|
6988
|
+
}
|
|
6852
6989
|
return {
|
|
6853
6990
|
code: ErrorCodes.TIMEOUT,
|
|
6854
|
-
message:
|
|
6855
|
-
service
|
|
6991
|
+
message: `Request timed out after ${timeoutMs}ms.`,
|
|
6992
|
+
service,
|
|
6993
|
+
...cause === void 0 ? {} : { cause },
|
|
6994
|
+
meta: { timeoutMs }
|
|
6856
6995
|
};
|
|
6857
6996
|
}
|
|
6858
6997
|
function abortedError(service) {
|
|
@@ -6872,6 +7011,101 @@ function parseAuthError(responseText) {
|
|
|
6872
7011
|
function authUnauthorizedError(service, message, meta) {
|
|
6873
7012
|
return serviceError(ErrorCodes.AUTH_UNAUTHORIZED, message, service, { meta });
|
|
6874
7013
|
}
|
|
7014
|
+
var grantableActions = new Set(
|
|
7015
|
+
CAPABILITY_REGISTRY.map(({ urn }) => urn).filter((urn) => !urn.endsWith("/*"))
|
|
7016
|
+
);
|
|
7017
|
+
var capabilityServices = new Set(
|
|
7018
|
+
CAPABILITY_REGISTRY.map(({ service }) => service.slice("tinycloud.".length))
|
|
7019
|
+
);
|
|
7020
|
+
function parseCapabilityResource2(resource, service) {
|
|
7021
|
+
if (resource.length === 0 || resource.length > 1024 || !capabilityServices.has(service) || /[\s\p{C}*#]/u.test(resource) || resource.includes("://")) return void 0;
|
|
7022
|
+
const segments = resource.split("/");
|
|
7023
|
+
if (!/^tinycloud:[A-Za-z0-9][A-Za-z0-9:._-]*$/.test(segments[0])) return void 0;
|
|
7024
|
+
const serviceIndex = segments.findIndex(
|
|
7025
|
+
(segment, index) => index > 0 && capabilityServices.has(segment)
|
|
7026
|
+
);
|
|
7027
|
+
if (serviceIndex < 1 || segments[serviceIndex] !== service) return void 0;
|
|
7028
|
+
if (segments.slice(1, serviceIndex).some(
|
|
7029
|
+
(segment) => segment.length === 0 || segment === "." || segment === ".."
|
|
7030
|
+
)) return void 0;
|
|
7031
|
+
const pathSegments = segments.slice(serviceIndex + 1);
|
|
7032
|
+
if (pathSegments.some((segment) => segment === "." || segment === "..")) return void 0;
|
|
7033
|
+
if (service !== "kv" && (pathSegments.length === 0 || pathSegments[pathSegments.length - 1] === "")) return void 0;
|
|
7034
|
+
return {
|
|
7035
|
+
space: segments.slice(0, serviceIndex).join("/"),
|
|
7036
|
+
path: pathSegments.join("/")
|
|
7037
|
+
};
|
|
7038
|
+
}
|
|
7039
|
+
function safeCapabilityResource(value, service, action) {
|
|
7040
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 1024) return false;
|
|
7041
|
+
if (service === "encryption" && value.startsWith("urn:tinycloud:encryption:")) {
|
|
7042
|
+
if (!/^[A-Za-z0-9_][A-Za-z0-9_.:/-]*$/.test(value) || value.includes("//") || value.split("/").some((segment) => segment === "." || segment === "..")) return false;
|
|
7043
|
+
try {
|
|
7044
|
+
parseNetworkId(value);
|
|
7045
|
+
return true;
|
|
7046
|
+
} catch {
|
|
7047
|
+
return false;
|
|
7048
|
+
}
|
|
7049
|
+
}
|
|
7050
|
+
const parsed = parseCapabilityResource2(value, service);
|
|
7051
|
+
return parsed !== void 0 && (!parsed.path.endsWith("/") || service === "kv" && action === "tinycloud.kv/list") && (parsed.path !== "" || service === "kv" && action === "tinycloud.kv/list");
|
|
7052
|
+
}
|
|
7053
|
+
function validatedCapabilityOf2(error) {
|
|
7054
|
+
const verdict = authorizationVerdictOf2(error);
|
|
7055
|
+
if (verdict !== "unauthenticated" && verdict !== "forbidden") return void 0;
|
|
7056
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7057
|
+
let node = error;
|
|
7058
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
|
|
7059
|
+
seen.add(node);
|
|
7060
|
+
const record = node;
|
|
7061
|
+
const status = errorStatusOf(record);
|
|
7062
|
+
const meta = record.meta;
|
|
7063
|
+
if ((status === 401 || status === 403 || status === void 0 && record.code === ErrorCodes.AUTH_UNAUTHORIZED) && typeof meta === "object" && meta !== null && !Array.isArray(meta)) {
|
|
7064
|
+
const metadata = meta;
|
|
7065
|
+
const { resource, requiredAction } = metadata;
|
|
7066
|
+
if (typeof requiredAction === "string" && grantableActions.has(requiredAction)) {
|
|
7067
|
+
const actionService = requiredAction.slice("tinycloud.".length, requiredAction.indexOf("/"));
|
|
7068
|
+
const explicitService = record.service === void 0 ? metadata.service : record.service;
|
|
7069
|
+
if (safeCapabilityResource(resource, actionService, requiredAction) && (explicitService === void 0 || explicitService === actionService || explicitService === `tinycloud.${actionService}`)) {
|
|
7070
|
+
return { resource, requiredAction };
|
|
7071
|
+
}
|
|
7072
|
+
}
|
|
7073
|
+
}
|
|
7074
|
+
node = record.cause;
|
|
7075
|
+
}
|
|
7076
|
+
return void 0;
|
|
7077
|
+
}
|
|
7078
|
+
var MAX_CAUSE_DEPTH = 8;
|
|
7079
|
+
function errorStatusOf(node) {
|
|
7080
|
+
const meta = node.meta;
|
|
7081
|
+
const candidates = [
|
|
7082
|
+
node.status,
|
|
7083
|
+
node.statusCode,
|
|
7084
|
+
typeof meta === "object" && meta !== null ? meta.status : void 0
|
|
7085
|
+
];
|
|
7086
|
+
for (const candidate of candidates) {
|
|
7087
|
+
if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 400 && candidate <= 599) {
|
|
7088
|
+
return candidate;
|
|
7089
|
+
}
|
|
7090
|
+
}
|
|
7091
|
+
return void 0;
|
|
7092
|
+
}
|
|
7093
|
+
function authorizationVerdictOf2(error) {
|
|
7094
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7095
|
+
let sawUnauthorizedCode = false;
|
|
7096
|
+
let node = error;
|
|
7097
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
|
|
7098
|
+
seen.add(node);
|
|
7099
|
+
const record = node;
|
|
7100
|
+
const status = errorStatusOf(record);
|
|
7101
|
+
if (status === 401) return "unauthenticated";
|
|
7102
|
+
if (status === 403) return "forbidden";
|
|
7103
|
+
if (status !== void 0) return "other";
|
|
7104
|
+
if (record.code === ErrorCodes.AUTH_UNAUTHORIZED) sawUnauthorizedCode = true;
|
|
7105
|
+
node = record.cause;
|
|
7106
|
+
}
|
|
7107
|
+
return sawUnauthorizedCode ? "forbidden" : void 0;
|
|
7108
|
+
}
|
|
6875
7109
|
function storageQuotaExceededError(service, message, meta) {
|
|
6876
7110
|
return {
|
|
6877
7111
|
code: ErrorCodes.STORAGE_QUOTA_EXCEEDED,
|
|
@@ -6904,6 +7138,9 @@ function storageRejectionError(service, status, meta, responseText) {
|
|
|
6904
7138
|
}
|
|
6905
7139
|
function wrapError2(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
6906
7140
|
if (error instanceof Error) {
|
|
7141
|
+
if (isRequestTimeoutError(error)) {
|
|
7142
|
+
return timeoutError(service, error.timeoutMs, error);
|
|
7143
|
+
}
|
|
6907
7144
|
if (error.name === "AbortError") {
|
|
6908
7145
|
return abortedError(service);
|
|
6909
7146
|
}
|
|
@@ -6923,6 +7160,7 @@ function wrapError2(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
|
6923
7160
|
service
|
|
6924
7161
|
};
|
|
6925
7162
|
}
|
|
7163
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
6926
7164
|
var BaseService = class {
|
|
6927
7165
|
constructor() {
|
|
6928
7166
|
this.abortController = new AbortController();
|
|
@@ -7096,6 +7334,64 @@ var BaseService = class {
|
|
|
7096
7334
|
}
|
|
7097
7335
|
return controller.signal;
|
|
7098
7336
|
}
|
|
7337
|
+
/**
|
|
7338
|
+
* Create the abort signal for one request, bounded by the request timeout.
|
|
7339
|
+
*
|
|
7340
|
+
* The signal aborts when the service signs out, the context aborts, the
|
|
7341
|
+
* caller's `signal` aborts, or the timeout elapses, whichever comes first.
|
|
7342
|
+
* A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
|
|
7343
|
+
* `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
|
|
7344
|
+
* reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
|
|
7345
|
+
*
|
|
7346
|
+
* The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
|
|
7347
|
+
* positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
|
|
7348
|
+
* `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
|
|
7349
|
+
*
|
|
7350
|
+
* Callers must call `dispose()` once the response body has been consumed,
|
|
7351
|
+
* which clears the timer and removes the listeners this adds to the
|
|
7352
|
+
* long-lived service and context signals.
|
|
7353
|
+
*
|
|
7354
|
+
* @param signal - The caller's abort signal for this request
|
|
7355
|
+
* @param timeoutMs - Per-request timeout override in milliseconds
|
|
7356
|
+
*/
|
|
7357
|
+
createRequestSignal(signal, timeoutMs) {
|
|
7358
|
+
const controller = new AbortController();
|
|
7359
|
+
const detachers = [];
|
|
7360
|
+
let timer;
|
|
7361
|
+
const dispose = () => {
|
|
7362
|
+
if (timer !== void 0) {
|
|
7363
|
+
clearTimeout(timer);
|
|
7364
|
+
timer = void 0;
|
|
7365
|
+
}
|
|
7366
|
+
for (const detach of detachers.splice(0)) {
|
|
7367
|
+
detach();
|
|
7368
|
+
}
|
|
7369
|
+
};
|
|
7370
|
+
const abort = (reason) => {
|
|
7371
|
+
dispose();
|
|
7372
|
+
controller.abort(reason);
|
|
7373
|
+
};
|
|
7374
|
+
const requestSignal = { signal: controller.signal, dispose };
|
|
7375
|
+
const parents = [
|
|
7376
|
+
this.abortController.signal,
|
|
7377
|
+
this.context?.abortSignal,
|
|
7378
|
+
signal
|
|
7379
|
+
].filter((parent) => parent !== void 0);
|
|
7380
|
+
for (const parent of parents) {
|
|
7381
|
+
if (parent.aborted) {
|
|
7382
|
+
abort(parent.reason);
|
|
7383
|
+
return requestSignal;
|
|
7384
|
+
}
|
|
7385
|
+
const onAbort = () => abort(parent.reason);
|
|
7386
|
+
parent.addEventListener("abort", onAbort, { once: true });
|
|
7387
|
+
detachers.push(() => parent.removeEventListener("abort", onAbort));
|
|
7388
|
+
}
|
|
7389
|
+
const timeout = timeoutMs ?? this._config.timeout;
|
|
7390
|
+
if (typeof timeout === "number" && timeout > 0 && timeout <= MAX_TIMER_DELAY_MS) {
|
|
7391
|
+
timer = setTimeout(() => abort(new RequestTimeoutError(timeout)), timeout);
|
|
7392
|
+
}
|
|
7393
|
+
return requestSignal;
|
|
7394
|
+
}
|
|
7099
7395
|
/**
|
|
7100
7396
|
* Wrap an operation with error handling and telemetry.
|
|
7101
7397
|
*
|
|
@@ -7350,7 +7646,7 @@ var KVService = class extends BaseService {
|
|
|
7350
7646
|
* @param path - Resource path
|
|
7351
7647
|
* @param action - KV action
|
|
7352
7648
|
* @param body - Optional request body
|
|
7353
|
-
* @param signal -
|
|
7649
|
+
* @param signal - Request signal from createRequestSignal()
|
|
7354
7650
|
* @returns Fetch response
|
|
7355
7651
|
*/
|
|
7356
7652
|
async invokeOperation(path, action, body, signal, extraHeaders) {
|
|
@@ -7366,7 +7662,7 @@ var KVService = class extends BaseService {
|
|
|
7366
7662
|
method: "POST",
|
|
7367
7663
|
headers: requestHeaders,
|
|
7368
7664
|
body,
|
|
7369
|
-
signal
|
|
7665
|
+
signal
|
|
7370
7666
|
});
|
|
7371
7667
|
}
|
|
7372
7668
|
/**
|
|
@@ -7543,6 +7839,7 @@ var KVService = class extends BaseService {
|
|
|
7543
7839
|
"kv"
|
|
7544
7840
|
));
|
|
7545
7841
|
}
|
|
7842
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
7546
7843
|
try {
|
|
7547
7844
|
const session = this.context.session;
|
|
7548
7845
|
const invocationHeaders = this.context.invokeAny(
|
|
@@ -7564,15 +7861,17 @@ var KVService = class extends BaseService {
|
|
|
7564
7861
|
const response = await this.context.fetch(`${this.host}/invoke`, {
|
|
7565
7862
|
method: "POST",
|
|
7566
7863
|
headers,
|
|
7567
|
-
signal:
|
|
7864
|
+
signal: request.signal
|
|
7568
7865
|
});
|
|
7569
7866
|
if (!response.ok) {
|
|
7570
|
-
const errorText = await response.text();
|
|
7867
|
+
const errorText = response.status === 401 || response.status === 403 ? await this.readAuthorizationText(response) : await response.text();
|
|
7571
7868
|
if (response.status === 401 || response.status === 403) {
|
|
7572
7869
|
return this.authorizationFailure(
|
|
7573
7870
|
`Failed to batch read ${keys.length} key(s)`,
|
|
7574
7871
|
response,
|
|
7575
|
-
errorText
|
|
7872
|
+
errorText,
|
|
7873
|
+
paths,
|
|
7874
|
+
action
|
|
7576
7875
|
);
|
|
7577
7876
|
}
|
|
7578
7877
|
if (response.status === 413) {
|
|
@@ -7627,6 +7926,8 @@ var KVService = class extends BaseService {
|
|
|
7627
7926
|
return ok({ results, count: results.length });
|
|
7628
7927
|
} catch (error) {
|
|
7629
7928
|
return err(wrapError2("kv", error));
|
|
7929
|
+
} finally {
|
|
7930
|
+
request.dispose();
|
|
7630
7931
|
}
|
|
7631
7932
|
}
|
|
7632
7933
|
/**
|
|
@@ -7662,7 +7963,7 @@ var KVService = class extends BaseService {
|
|
|
7662
7963
|
return text;
|
|
7663
7964
|
}
|
|
7664
7965
|
}
|
|
7665
|
-
async createSignedReadUrlError(response, key) {
|
|
7966
|
+
async createSignedReadUrlError(response, key, path) {
|
|
7666
7967
|
let errorText = response.statusText;
|
|
7667
7968
|
try {
|
|
7668
7969
|
const text = await response.text();
|
|
@@ -7675,34 +7976,57 @@ var KVService = class extends BaseService {
|
|
|
7675
7976
|
return this.authorizationFailure(
|
|
7676
7977
|
`Failed to create signed read URL for key ${JSON.stringify(key)}`,
|
|
7677
7978
|
response,
|
|
7678
|
-
errorText
|
|
7979
|
+
errorText,
|
|
7980
|
+
[path],
|
|
7981
|
+
KVAction.GET
|
|
7679
7982
|
);
|
|
7680
7983
|
}
|
|
7681
|
-
const
|
|
7984
|
+
const code3 = response.status === 400 ? ErrorCodes.INVALID_INPUT : ErrorCodes.NETWORK_ERROR;
|
|
7682
7985
|
return err(
|
|
7683
7986
|
serviceError(
|
|
7684
|
-
|
|
7987
|
+
code3,
|
|
7685
7988
|
`Failed to create signed read URL for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
7686
7989
|
"kv",
|
|
7687
7990
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
7688
7991
|
)
|
|
7689
7992
|
);
|
|
7690
7993
|
}
|
|
7994
|
+
/** A known 401/403 keeps its typed status even if reading its body fails. */
|
|
7995
|
+
async readAuthorizationText(response) {
|
|
7996
|
+
try {
|
|
7997
|
+
return await response.text();
|
|
7998
|
+
} catch {
|
|
7999
|
+
return "";
|
|
8000
|
+
}
|
|
8001
|
+
}
|
|
7691
8002
|
/**
|
|
7692
8003
|
* AUTH_UNAUTHORIZED for a 401/403 response. The message keeps the HTTP
|
|
7693
8004
|
* status and the server text (`<context>: <status> - <text>`, the same
|
|
7694
8005
|
* shape as every other KV failure) so callers that rethrow only the message
|
|
7695
8006
|
* still see the status; `meta.status` carries it for typed callers.
|
|
7696
|
-
*
|
|
8007
|
+
* Server hints must match the requested path/action (whether the node sends
|
|
8008
|
+
* a relative path or full resource); metadata uses only the request-derived
|
|
8009
|
+
* canonical resource under the authenticated session's space.
|
|
7697
8010
|
*/
|
|
7698
|
-
authorizationFailure(context, response, errorText, extraMeta = {}) {
|
|
8011
|
+
authorizationFailure(context, response, errorText, paths, expectedAction, extraMeta = {}) {
|
|
7699
8012
|
const { resource, action } = parseAuthError(errorText);
|
|
8013
|
+
const requestedPath = paths.find(
|
|
8014
|
+
(path) => resource === path || resource === `${this.context.session.spaceId}/kv/${path}`
|
|
8015
|
+
);
|
|
8016
|
+
const capability = requestedPath !== void 0 && action === expectedAction ? validatedCapabilityOf2({
|
|
8017
|
+
service: "kv",
|
|
8018
|
+
code: ErrorCodes.AUTH_UNAUTHORIZED,
|
|
8019
|
+
meta: {
|
|
8020
|
+
status: response.status,
|
|
8021
|
+
resource: `${this.context.session.spaceId}/kv/${requestedPath}`,
|
|
8022
|
+
requiredAction: action
|
|
8023
|
+
}
|
|
8024
|
+
}) : void 0;
|
|
7700
8025
|
const detail = errorText.trim().length > 0 ? errorText : response.statusText || "authorization failed";
|
|
7701
8026
|
return err(authUnauthorizedError("kv", `${context}: ${response.status} - ${detail}`, {
|
|
7702
8027
|
status: response.status,
|
|
7703
|
-
...
|
|
7704
|
-
...
|
|
7705
|
-
...extraMeta
|
|
8028
|
+
...extraMeta,
|
|
8029
|
+
...capability
|
|
7706
8030
|
}));
|
|
7707
8031
|
}
|
|
7708
8032
|
normalizeSignedReadUrlResponse(data) {
|
|
@@ -7736,23 +8060,35 @@ var KVService = class extends BaseService {
|
|
|
7736
8060
|
));
|
|
7737
8061
|
}
|
|
7738
8062
|
const path = this.getFullPath(key, options?.prefix);
|
|
8063
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
7739
8064
|
try {
|
|
7740
8065
|
const response = await this.invokeOperation(
|
|
7741
8066
|
path,
|
|
7742
8067
|
KVAction.GET,
|
|
7743
8068
|
void 0,
|
|
7744
|
-
|
|
8069
|
+
request.signal,
|
|
7745
8070
|
options?.maxResponseBytes === void 0 ? void 0 : { "x-tinycloud-max-response-bytes": String(options.maxResponseBytes) }
|
|
7746
8071
|
);
|
|
7747
8072
|
if (!response.ok) {
|
|
7748
8073
|
if (response.status === 401 || response.status === 403) {
|
|
7749
|
-
const errorText2 = await
|
|
8074
|
+
const errorText2 = await this.readAuthorizationText(response);
|
|
7750
8075
|
const permissionHint = parsePermissionHintFromErrorText(errorText2);
|
|
8076
|
+
const structuredCapability = permissionHint?.service === "tinycloud.kv" && permissionHint.space === this.context.session.spaceId && permissionHint.path === path ? validatedCapabilityOf2({
|
|
8077
|
+
service: "kv",
|
|
8078
|
+
code: ErrorCodes.AUTH_UNAUTHORIZED,
|
|
8079
|
+
meta: {
|
|
8080
|
+
status: response.status,
|
|
8081
|
+
resource: `${this.context.session.spaceId}/kv/${path}`,
|
|
8082
|
+
requiredAction: KVAction.GET
|
|
8083
|
+
}
|
|
8084
|
+
}) : void 0;
|
|
7751
8085
|
return this.authorizationFailure(
|
|
7752
8086
|
`Failed to get key ${JSON.stringify(key)}`,
|
|
7753
8087
|
response,
|
|
7754
8088
|
errorText2,
|
|
7755
|
-
|
|
8089
|
+
[path],
|
|
8090
|
+
KVAction.GET,
|
|
8091
|
+
structuredCapability ? { permissionHint, ...structuredCapability } : {}
|
|
7756
8092
|
);
|
|
7757
8093
|
}
|
|
7758
8094
|
if (response.status === 404) {
|
|
@@ -7787,6 +8123,8 @@ var KVService = class extends BaseService {
|
|
|
7787
8123
|
});
|
|
7788
8124
|
} catch (error) {
|
|
7789
8125
|
return err(wrapError2("kv", error));
|
|
8126
|
+
} finally {
|
|
8127
|
+
request.dispose();
|
|
7790
8128
|
}
|
|
7791
8129
|
});
|
|
7792
8130
|
}
|
|
@@ -7814,12 +8152,13 @@ var KVService = class extends BaseService {
|
|
|
7814
8152
|
}
|
|
7815
8153
|
const path = this.getFullPath(key, options?.prefix);
|
|
7816
8154
|
const body = this.serializePutValue(value, options?.contentType);
|
|
8155
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
7817
8156
|
try {
|
|
7818
8157
|
const response = await this.invokeOperation(
|
|
7819
8158
|
path,
|
|
7820
8159
|
KVAction.PUT,
|
|
7821
8160
|
body,
|
|
7822
|
-
|
|
8161
|
+
request.signal,
|
|
7823
8162
|
{
|
|
7824
8163
|
...options?.ifMatch === void 0 ? {} : { "if-match": options.ifMatch },
|
|
7825
8164
|
...options?.ifNoneMatch === void 0 ? {} : { "if-none-match": options.ifNoneMatch }
|
|
@@ -7829,7 +8168,9 @@ var KVService = class extends BaseService {
|
|
|
7829
8168
|
return this.authorizationFailure(
|
|
7830
8169
|
`Failed to put key ${JSON.stringify(key)}`,
|
|
7831
8170
|
response,
|
|
7832
|
-
await
|
|
8171
|
+
await this.readAuthorizationText(response),
|
|
8172
|
+
[path],
|
|
8173
|
+
KVAction.PUT
|
|
7833
8174
|
);
|
|
7834
8175
|
}
|
|
7835
8176
|
if (!response.ok) {
|
|
@@ -7873,6 +8214,8 @@ var KVService = class extends BaseService {
|
|
|
7873
8214
|
});
|
|
7874
8215
|
} catch (error) {
|
|
7875
8216
|
return err(wrapError2("kv", error));
|
|
8217
|
+
} finally {
|
|
8218
|
+
request.dispose();
|
|
7876
8219
|
}
|
|
7877
8220
|
});
|
|
7878
8221
|
}
|
|
@@ -7912,6 +8255,7 @@ var KVService = class extends BaseService {
|
|
|
7912
8255
|
seen.add(path);
|
|
7913
8256
|
}
|
|
7914
8257
|
let requestMayHaveDispatched = false;
|
|
8258
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
7915
8259
|
try {
|
|
7916
8260
|
const body = new FormData();
|
|
7917
8261
|
for (let index = 0; index < items.length; index++) {
|
|
@@ -7934,7 +8278,7 @@ var KVService = class extends BaseService {
|
|
|
7934
8278
|
method: "POST",
|
|
7935
8279
|
headers,
|
|
7936
8280
|
body,
|
|
7937
|
-
signal:
|
|
8281
|
+
signal: request.signal
|
|
7938
8282
|
};
|
|
7939
8283
|
const fetchFn = this.context.fetch;
|
|
7940
8284
|
requestMayHaveDispatched = true;
|
|
@@ -7958,7 +8302,9 @@ var KVService = class extends BaseService {
|
|
|
7958
8302
|
return this.authorizationFailure(
|
|
7959
8303
|
`Failed to batch put ${items.length} key(s)`,
|
|
7960
8304
|
response,
|
|
7961
|
-
errorText
|
|
8305
|
+
errorText,
|
|
8306
|
+
paths,
|
|
8307
|
+
KVAction.PUT
|
|
7962
8308
|
);
|
|
7963
8309
|
}
|
|
7964
8310
|
const quotaError = this.handleQuotaErrorResponse(
|
|
@@ -7983,14 +8329,16 @@ var KVService = class extends BaseService {
|
|
|
7983
8329
|
rawBody = await response.json();
|
|
7984
8330
|
} catch (jsonError) {
|
|
7985
8331
|
const cause = jsonError instanceof Error ? jsonError : new Error(String(jsonError));
|
|
8332
|
+
const timedOut = isRequestTimeoutError(cause);
|
|
7986
8333
|
return err(
|
|
7987
8334
|
serviceError(
|
|
7988
|
-
ErrorCodes.NETWORK_ERROR,
|
|
7989
|
-
`KV batchPut response was not valid JSON: ${cause.message}`,
|
|
8335
|
+
timedOut ? ErrorCodes.TIMEOUT : ErrorCodes.NETWORK_ERROR,
|
|
8336
|
+
timedOut ? `KV batchPut response body did not arrive in time: ${cause.message}` : `KV batchPut response was not valid JSON: ${cause.message}`,
|
|
7990
8337
|
"kv",
|
|
7991
8338
|
{
|
|
7992
8339
|
cause,
|
|
7993
8340
|
meta: {
|
|
8341
|
+
...timedOut ? { timeoutMs: cause.timeoutMs } : {},
|
|
7994
8342
|
requestMayHaveDispatched: true,
|
|
7995
8343
|
responseReceived: true,
|
|
7996
8344
|
status: response.status,
|
|
@@ -8045,6 +8393,8 @@ var KVService = class extends BaseService {
|
|
|
8045
8393
|
...wrapped,
|
|
8046
8394
|
meta: { ...wrapped.meta, requestMayHaveDispatched }
|
|
8047
8395
|
});
|
|
8396
|
+
} finally {
|
|
8397
|
+
request.dispose();
|
|
8048
8398
|
}
|
|
8049
8399
|
});
|
|
8050
8400
|
}
|
|
@@ -8067,23 +8417,26 @@ var KVService = class extends BaseService {
|
|
|
8067
8417
|
if (options?.path) {
|
|
8068
8418
|
listPath = listPath ? `${listPath}/${options.path}` : options.path;
|
|
8069
8419
|
}
|
|
8420
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
8070
8421
|
try {
|
|
8071
8422
|
const response = await this.invokeOperation(
|
|
8072
8423
|
listPath,
|
|
8073
8424
|
KVAction.LIST,
|
|
8074
8425
|
void 0,
|
|
8075
|
-
|
|
8426
|
+
request.signal,
|
|
8076
8427
|
options?.limit === void 0 && options?.cursor === void 0 ? void 0 : {
|
|
8077
8428
|
...options?.limit === void 0 ? {} : { "x-tinycloud-limit": String(options.limit) },
|
|
8078
8429
|
...options?.cursor === void 0 ? {} : { "x-tinycloud-cursor": options.cursor }
|
|
8079
8430
|
}
|
|
8080
8431
|
);
|
|
8081
8432
|
if (!response.ok) {
|
|
8082
|
-
if (response.status === 401) {
|
|
8433
|
+
if (response.status === 401 || response.status === 403) {
|
|
8083
8434
|
return this.authorizationFailure(
|
|
8084
8435
|
"Failed to list keys",
|
|
8085
8436
|
response,
|
|
8086
|
-
await
|
|
8437
|
+
await this.readAuthorizationText(response),
|
|
8438
|
+
[listPath],
|
|
8439
|
+
KVAction.LIST
|
|
8087
8440
|
);
|
|
8088
8441
|
}
|
|
8089
8442
|
const errorText = await response.text();
|
|
@@ -8111,6 +8464,8 @@ var KVService = class extends BaseService {
|
|
|
8111
8464
|
});
|
|
8112
8465
|
} catch (error) {
|
|
8113
8466
|
return err(wrapError2("kv", error));
|
|
8467
|
+
} finally {
|
|
8468
|
+
request.dispose();
|
|
8114
8469
|
}
|
|
8115
8470
|
});
|
|
8116
8471
|
}
|
|
@@ -8123,20 +8478,23 @@ var KVService = class extends BaseService {
|
|
|
8123
8478
|
return err(authRequiredError("kv"));
|
|
8124
8479
|
}
|
|
8125
8480
|
const path = this.getFullPath(key, options?.prefix);
|
|
8481
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
8126
8482
|
try {
|
|
8127
8483
|
const response = await this.invokeOperation(
|
|
8128
8484
|
path,
|
|
8129
8485
|
KVAction.DELETE,
|
|
8130
8486
|
void 0,
|
|
8131
|
-
|
|
8487
|
+
request.signal,
|
|
8132
8488
|
options?.ifMatch === void 0 ? void 0 : { "if-match": options.ifMatch }
|
|
8133
8489
|
);
|
|
8134
8490
|
if (!response.ok) {
|
|
8135
|
-
if (response.status === 401) {
|
|
8491
|
+
if (response.status === 401 || response.status === 403) {
|
|
8136
8492
|
return this.authorizationFailure(
|
|
8137
8493
|
`Failed to delete key ${JSON.stringify(key)}`,
|
|
8138
8494
|
response,
|
|
8139
|
-
await
|
|
8495
|
+
await this.readAuthorizationText(response),
|
|
8496
|
+
[path],
|
|
8497
|
+
KVAction.DELETE
|
|
8140
8498
|
);
|
|
8141
8499
|
}
|
|
8142
8500
|
if (response.status === 404) {
|
|
@@ -8174,6 +8532,8 @@ var KVService = class extends BaseService {
|
|
|
8174
8532
|
});
|
|
8175
8533
|
} catch (error) {
|
|
8176
8534
|
return err(wrapError2("kv", error));
|
|
8535
|
+
} finally {
|
|
8536
|
+
request.dispose();
|
|
8177
8537
|
}
|
|
8178
8538
|
});
|
|
8179
8539
|
}
|
|
@@ -8186,19 +8546,22 @@ var KVService = class extends BaseService {
|
|
|
8186
8546
|
return err(authRequiredError("kv"));
|
|
8187
8547
|
}
|
|
8188
8548
|
const path = this.getFullPath(key, options?.prefix);
|
|
8549
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
8189
8550
|
try {
|
|
8190
8551
|
const response = await this.invokeOperation(
|
|
8191
8552
|
path,
|
|
8192
8553
|
KVAction.HEAD,
|
|
8193
8554
|
void 0,
|
|
8194
|
-
|
|
8555
|
+
request.signal
|
|
8195
8556
|
);
|
|
8196
8557
|
if (!response.ok) {
|
|
8197
|
-
if (response.status === 401) {
|
|
8558
|
+
if (response.status === 401 || response.status === 403) {
|
|
8198
8559
|
return this.authorizationFailure(
|
|
8199
8560
|
`Failed to get metadata for key ${JSON.stringify(key)}`,
|
|
8200
8561
|
response,
|
|
8201
|
-
await
|
|
8562
|
+
await this.readAuthorizationText(response),
|
|
8563
|
+
[path],
|
|
8564
|
+
KVAction.HEAD
|
|
8202
8565
|
);
|
|
8203
8566
|
}
|
|
8204
8567
|
if (response.status === 404) {
|
|
@@ -8220,6 +8583,8 @@ var KVService = class extends BaseService {
|
|
|
8220
8583
|
});
|
|
8221
8584
|
} catch (error) {
|
|
8222
8585
|
return err(wrapError2("kv", error));
|
|
8586
|
+
} finally {
|
|
8587
|
+
request.dispose();
|
|
8223
8588
|
}
|
|
8224
8589
|
});
|
|
8225
8590
|
}
|
|
@@ -8257,15 +8622,16 @@ var KVService = class extends BaseService {
|
|
|
8257
8622
|
if (options?.etag !== void 0) {
|
|
8258
8623
|
body.etag = options.etag;
|
|
8259
8624
|
}
|
|
8625
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
8260
8626
|
try {
|
|
8261
8627
|
const response = await this.context.fetch(`${this.host}/signed/kv`, {
|
|
8262
8628
|
method: "POST",
|
|
8263
8629
|
headers: this.withJsonContentType(headers),
|
|
8264
8630
|
body: JSON.stringify(body),
|
|
8265
|
-
signal:
|
|
8631
|
+
signal: request.signal
|
|
8266
8632
|
});
|
|
8267
8633
|
if (!response.ok) {
|
|
8268
|
-
return this.createSignedReadUrlError(response, key);
|
|
8634
|
+
return this.createSignedReadUrlError(response, key, path);
|
|
8269
8635
|
}
|
|
8270
8636
|
const signedUrl = this.normalizeSignedReadUrlResponse(
|
|
8271
8637
|
await response.json()
|
|
@@ -8282,6 +8648,8 @@ var KVService = class extends BaseService {
|
|
|
8282
8648
|
return ok(signedUrl);
|
|
8283
8649
|
} catch (error) {
|
|
8284
8650
|
return err(wrapError2("kv", error));
|
|
8651
|
+
} finally {
|
|
8652
|
+
request.dispose();
|
|
8285
8653
|
}
|
|
8286
8654
|
});
|
|
8287
8655
|
}
|
|
@@ -8481,6 +8849,7 @@ var SQLService = class extends BaseService {
|
|
|
8481
8849
|
if (!this.requireAuth()) {
|
|
8482
8850
|
return err(authRequiredError("sql"));
|
|
8483
8851
|
}
|
|
8852
|
+
const request = this.createRequestSignal(options?.signal);
|
|
8484
8853
|
try {
|
|
8485
8854
|
const body = {
|
|
8486
8855
|
action: "query",
|
|
@@ -8489,19 +8858,22 @@ var SQLService = class extends BaseService {
|
|
|
8489
8858
|
};
|
|
8490
8859
|
if (options?.maxRows !== void 0) body.maxRows = options.maxRows;
|
|
8491
8860
|
if (options?.maxBytes !== void 0) body.maxBytes = options.maxBytes;
|
|
8861
|
+
const action = this.actionForSql(sql, SQLAction.READ);
|
|
8492
8862
|
const response = await this.invokeSQL(
|
|
8493
8863
|
dbName,
|
|
8494
|
-
|
|
8864
|
+
action,
|
|
8495
8865
|
body,
|
|
8496
|
-
|
|
8866
|
+
request.signal
|
|
8497
8867
|
);
|
|
8498
8868
|
if (!response.ok) {
|
|
8499
|
-
return this.handleErrorResponse(response, "query");
|
|
8869
|
+
return this.handleErrorResponse(response, "query", dbName, [action]);
|
|
8500
8870
|
}
|
|
8501
8871
|
const data = await response.json();
|
|
8502
8872
|
return ok(data);
|
|
8503
8873
|
} catch (error) {
|
|
8504
8874
|
return err(wrapError2("sql", error));
|
|
8875
|
+
} finally {
|
|
8876
|
+
request.dispose();
|
|
8505
8877
|
}
|
|
8506
8878
|
});
|
|
8507
8879
|
}
|
|
@@ -8510,6 +8882,7 @@ var SQLService = class extends BaseService {
|
|
|
8510
8882
|
if (!this.requireAuth()) {
|
|
8511
8883
|
return err(authRequiredError("sql"));
|
|
8512
8884
|
}
|
|
8885
|
+
const request = this.createRequestSignal(options?.signal);
|
|
8513
8886
|
try {
|
|
8514
8887
|
const body = {
|
|
8515
8888
|
action: "execute",
|
|
@@ -8525,19 +8898,22 @@ var SQLService = class extends BaseService {
|
|
|
8525
8898
|
(statement) => this.actionForSql(statement, SQLAction.SCHEMA)
|
|
8526
8899
|
)
|
|
8527
8900
|
];
|
|
8901
|
+
const requestedActions2 = this.dedupeActions(actions);
|
|
8528
8902
|
const response = await this.invokeSQL(
|
|
8529
8903
|
dbName,
|
|
8530
|
-
|
|
8904
|
+
requestedActions2,
|
|
8531
8905
|
body,
|
|
8532
|
-
|
|
8906
|
+
request.signal
|
|
8533
8907
|
);
|
|
8534
8908
|
if (!response.ok) {
|
|
8535
|
-
return this.handleErrorResponse(response, "execute");
|
|
8909
|
+
return this.handleErrorResponse(response, "execute", dbName, requestedActions2);
|
|
8536
8910
|
}
|
|
8537
8911
|
const data = await response.json();
|
|
8538
8912
|
return ok(data);
|
|
8539
8913
|
} catch (error) {
|
|
8540
8914
|
return err(wrapError2("sql", error));
|
|
8915
|
+
} finally {
|
|
8916
|
+
request.dispose();
|
|
8541
8917
|
}
|
|
8542
8918
|
});
|
|
8543
8919
|
}
|
|
@@ -8546,20 +8922,24 @@ var SQLService = class extends BaseService {
|
|
|
8546
8922
|
if (!this.requireAuth()) {
|
|
8547
8923
|
return err(authRequiredError("sql"));
|
|
8548
8924
|
}
|
|
8925
|
+
const request = this.createRequestSignal(options?.signal);
|
|
8549
8926
|
try {
|
|
8927
|
+
const requestedActions2 = this.actionsForSqlBatch(statements);
|
|
8550
8928
|
const response = await this.invokeSQL(
|
|
8551
8929
|
dbName,
|
|
8552
|
-
|
|
8930
|
+
requestedActions2,
|
|
8553
8931
|
{ action: "batch", statements },
|
|
8554
|
-
|
|
8932
|
+
request.signal
|
|
8555
8933
|
);
|
|
8556
8934
|
if (!response.ok) {
|
|
8557
|
-
return this.handleErrorResponse(response, "batch");
|
|
8935
|
+
return this.handleErrorResponse(response, "batch", dbName, requestedActions2);
|
|
8558
8936
|
}
|
|
8559
8937
|
const data = await response.json();
|
|
8560
8938
|
return ok(data);
|
|
8561
8939
|
} catch (error) {
|
|
8562
8940
|
return err(wrapError2("sql", error));
|
|
8941
|
+
} finally {
|
|
8942
|
+
request.dispose();
|
|
8563
8943
|
}
|
|
8564
8944
|
});
|
|
8565
8945
|
}
|
|
@@ -8568,20 +8948,23 @@ var SQLService = class extends BaseService {
|
|
|
8568
8948
|
if (!this.requireAuth()) {
|
|
8569
8949
|
return err(authRequiredError("sql"));
|
|
8570
8950
|
}
|
|
8951
|
+
const request = this.createRequestSignal(options?.signal);
|
|
8571
8952
|
try {
|
|
8572
8953
|
const response = await this.invokeSQL(
|
|
8573
8954
|
dbName,
|
|
8574
8955
|
SQLAction.WRITE,
|
|
8575
8956
|
{ action: "execute_statement", name, params: params ?? [] },
|
|
8576
|
-
|
|
8957
|
+
request.signal
|
|
8577
8958
|
);
|
|
8578
8959
|
if (!response.ok) {
|
|
8579
|
-
return this.handleErrorResponse(response, "executeStatement");
|
|
8960
|
+
return this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
|
|
8580
8961
|
}
|
|
8581
8962
|
const data = await response.json();
|
|
8582
8963
|
return ok(data);
|
|
8583
8964
|
} catch (error) {
|
|
8584
8965
|
return err(wrapError2("sql", error));
|
|
8966
|
+
} finally {
|
|
8967
|
+
request.dispose();
|
|
8585
8968
|
}
|
|
8586
8969
|
});
|
|
8587
8970
|
}
|
|
@@ -8590,15 +8973,16 @@ var SQLService = class extends BaseService {
|
|
|
8590
8973
|
if (!this.requireAuth()) {
|
|
8591
8974
|
return err(authRequiredError("sql"));
|
|
8592
8975
|
}
|
|
8976
|
+
const request = this.createRequestSignal(options?.signal);
|
|
8593
8977
|
try {
|
|
8594
8978
|
const response = await this.invokeSQL(
|
|
8595
8979
|
dbName,
|
|
8596
8980
|
SQLAction.READ,
|
|
8597
8981
|
{ action: "export" },
|
|
8598
|
-
|
|
8982
|
+
request.signal
|
|
8599
8983
|
);
|
|
8600
8984
|
if (!response.ok) {
|
|
8601
|
-
return this.handleErrorResponse(response, "export");
|
|
8985
|
+
return this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
|
|
8602
8986
|
}
|
|
8603
8987
|
const resp = response;
|
|
8604
8988
|
if (typeof resp.blob === "function") {
|
|
@@ -8609,6 +8993,8 @@ var SQLService = class extends BaseService {
|
|
|
8609
8993
|
return ok(text);
|
|
8610
8994
|
} catch (error) {
|
|
8611
8995
|
return err(wrapError2("sql", error));
|
|
8996
|
+
} finally {
|
|
8997
|
+
request.dispose();
|
|
8612
8998
|
}
|
|
8613
8999
|
});
|
|
8614
9000
|
}
|
|
@@ -8699,7 +9085,7 @@ var SQLService = class extends BaseService {
|
|
|
8699
9085
|
"Content-Type": "application/json"
|
|
8700
9086
|
},
|
|
8701
9087
|
body: JSON.stringify(body),
|
|
8702
|
-
signal
|
|
9088
|
+
signal
|
|
8703
9089
|
});
|
|
8704
9090
|
}
|
|
8705
9091
|
actionForSql(sql, fallback) {
|
|
@@ -8732,7 +9118,7 @@ var SQLService = class extends BaseService {
|
|
|
8732
9118
|
}))
|
|
8733
9119
|
);
|
|
8734
9120
|
}
|
|
8735
|
-
async handleErrorResponse(response, operation) {
|
|
9121
|
+
async handleErrorResponse(response, operation, dbName, requestedActions2) {
|
|
8736
9122
|
const errorText = await response.text();
|
|
8737
9123
|
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
8738
9124
|
if (response.status === 402) {
|
|
@@ -8751,9 +9137,11 @@ var SQLService = class extends BaseService {
|
|
|
8751
9137
|
errorBody
|
|
8752
9138
|
);
|
|
8753
9139
|
if (response.status === 401) {
|
|
8754
|
-
const {
|
|
8755
|
-
if (action
|
|
8756
|
-
|
|
9140
|
+
const { action } = parseAuthError(errorText);
|
|
9141
|
+
if (action && requestedActions2.includes(action)) {
|
|
9142
|
+
meta.requiredAction = action;
|
|
9143
|
+
meta.resource = `${this.context.session.spaceId}/sql/${dbName}`;
|
|
9144
|
+
}
|
|
8757
9145
|
}
|
|
8758
9146
|
return err(
|
|
8759
9147
|
serviceError(errorCode2, message, "sql", { meta })
|
|
@@ -8954,12 +9342,13 @@ var DuckDbService = class extends BaseService {
|
|
|
8954
9342
|
if (!this.requireAuth()) {
|
|
8955
9343
|
return err(authRequiredError("duckdb"));
|
|
8956
9344
|
}
|
|
9345
|
+
const request = this.createRequestSignal(options?.signal);
|
|
8957
9346
|
try {
|
|
8958
9347
|
const response = await this.invokeDuckDb(
|
|
8959
9348
|
dbName,
|
|
8960
9349
|
DuckDbAction.READ,
|
|
8961
9350
|
{ action: "query", sql, params: params ?? [] },
|
|
8962
|
-
|
|
9351
|
+
request.signal
|
|
8963
9352
|
);
|
|
8964
9353
|
if (!response.ok) {
|
|
8965
9354
|
return this.handleErrorResponse(response, "query");
|
|
@@ -8968,6 +9357,8 @@ var DuckDbService = class extends BaseService {
|
|
|
8968
9357
|
return ok(data);
|
|
8969
9358
|
} catch (error) {
|
|
8970
9359
|
return err(wrapError2("duckdb", error));
|
|
9360
|
+
} finally {
|
|
9361
|
+
request.dispose();
|
|
8971
9362
|
}
|
|
8972
9363
|
});
|
|
8973
9364
|
}
|
|
@@ -8976,12 +9367,13 @@ var DuckDbService = class extends BaseService {
|
|
|
8976
9367
|
if (!this.requireAuth()) {
|
|
8977
9368
|
return err(authRequiredError("duckdb"));
|
|
8978
9369
|
}
|
|
9370
|
+
const request = this.createRequestSignal(options?.signal);
|
|
8979
9371
|
try {
|
|
8980
9372
|
const response = await this.invokeDuckDb(
|
|
8981
9373
|
dbName,
|
|
8982
9374
|
DuckDbAction.READ,
|
|
8983
9375
|
{ action: "query", sql, params: params ?? [] },
|
|
8984
|
-
|
|
9376
|
+
request.signal,
|
|
8985
9377
|
{ Accept: "application/vnd.apache.arrow.stream" }
|
|
8986
9378
|
);
|
|
8987
9379
|
if (!response.ok) {
|
|
@@ -8991,6 +9383,8 @@ var DuckDbService = class extends BaseService {
|
|
|
8991
9383
|
return ok(buffer);
|
|
8992
9384
|
} catch (error) {
|
|
8993
9385
|
return err(wrapError2("duckdb", error));
|
|
9386
|
+
} finally {
|
|
9387
|
+
request.dispose();
|
|
8994
9388
|
}
|
|
8995
9389
|
});
|
|
8996
9390
|
}
|
|
@@ -8999,6 +9393,7 @@ var DuckDbService = class extends BaseService {
|
|
|
8999
9393
|
if (!this.requireAuth()) {
|
|
9000
9394
|
return err(authRequiredError("duckdb"));
|
|
9001
9395
|
}
|
|
9396
|
+
const request = this.createRequestSignal(options?.signal);
|
|
9002
9397
|
try {
|
|
9003
9398
|
const body = {
|
|
9004
9399
|
action: "execute",
|
|
@@ -9012,7 +9407,7 @@ var DuckDbService = class extends BaseService {
|
|
|
9012
9407
|
dbName,
|
|
9013
9408
|
DuckDbAction.WRITE,
|
|
9014
9409
|
body,
|
|
9015
|
-
|
|
9410
|
+
request.signal
|
|
9016
9411
|
);
|
|
9017
9412
|
if (!response.ok) {
|
|
9018
9413
|
return this.handleErrorResponse(response, "execute");
|
|
@@ -9021,6 +9416,8 @@ var DuckDbService = class extends BaseService {
|
|
|
9021
9416
|
return ok(data);
|
|
9022
9417
|
} catch (error) {
|
|
9023
9418
|
return err(wrapError2("duckdb", error));
|
|
9419
|
+
} finally {
|
|
9420
|
+
request.dispose();
|
|
9024
9421
|
}
|
|
9025
9422
|
});
|
|
9026
9423
|
}
|
|
@@ -9029,6 +9426,7 @@ var DuckDbService = class extends BaseService {
|
|
|
9029
9426
|
if (!this.requireAuth()) {
|
|
9030
9427
|
return err(authRequiredError("duckdb"));
|
|
9031
9428
|
}
|
|
9429
|
+
const request = this.createRequestSignal(options?.signal);
|
|
9032
9430
|
try {
|
|
9033
9431
|
const body = {
|
|
9034
9432
|
action: "batch",
|
|
@@ -9041,7 +9439,7 @@ var DuckDbService = class extends BaseService {
|
|
|
9041
9439
|
dbName,
|
|
9042
9440
|
DuckDbAction.WRITE,
|
|
9043
9441
|
body,
|
|
9044
|
-
|
|
9442
|
+
request.signal
|
|
9045
9443
|
);
|
|
9046
9444
|
if (!response.ok) {
|
|
9047
9445
|
return this.handleErrorResponse(response, "batch");
|
|
@@ -9050,6 +9448,8 @@ var DuckDbService = class extends BaseService {
|
|
|
9050
9448
|
return ok(data);
|
|
9051
9449
|
} catch (error) {
|
|
9052
9450
|
return err(wrapError2("duckdb", error));
|
|
9451
|
+
} finally {
|
|
9452
|
+
request.dispose();
|
|
9053
9453
|
}
|
|
9054
9454
|
});
|
|
9055
9455
|
}
|
|
@@ -9058,12 +9458,13 @@ var DuckDbService = class extends BaseService {
|
|
|
9058
9458
|
if (!this.requireAuth()) {
|
|
9059
9459
|
return err(authRequiredError("duckdb"));
|
|
9060
9460
|
}
|
|
9461
|
+
const request = this.createRequestSignal(options?.signal);
|
|
9061
9462
|
try {
|
|
9062
9463
|
const response = await this.invokeDuckDb(
|
|
9063
9464
|
dbName,
|
|
9064
9465
|
DuckDbAction.WRITE,
|
|
9065
9466
|
{ action: "executeStatement", name, params: params ?? [] },
|
|
9066
|
-
|
|
9467
|
+
request.signal
|
|
9067
9468
|
);
|
|
9068
9469
|
if (!response.ok) {
|
|
9069
9470
|
return this.handleErrorResponse(response, "executeStatement");
|
|
@@ -9072,6 +9473,8 @@ var DuckDbService = class extends BaseService {
|
|
|
9072
9473
|
return ok(data);
|
|
9073
9474
|
} catch (error) {
|
|
9074
9475
|
return err(wrapError2("duckdb", error));
|
|
9476
|
+
} finally {
|
|
9477
|
+
request.dispose();
|
|
9075
9478
|
}
|
|
9076
9479
|
});
|
|
9077
9480
|
}
|
|
@@ -9080,12 +9483,13 @@ var DuckDbService = class extends BaseService {
|
|
|
9080
9483
|
if (!this.requireAuth()) {
|
|
9081
9484
|
return err(authRequiredError("duckdb"));
|
|
9082
9485
|
}
|
|
9486
|
+
const request = this.createRequestSignal(options?.signal);
|
|
9083
9487
|
try {
|
|
9084
9488
|
const response = await this.invokeDuckDb(
|
|
9085
9489
|
dbName,
|
|
9086
9490
|
DuckDbAction.READ,
|
|
9087
9491
|
{ action: "describe" },
|
|
9088
|
-
|
|
9492
|
+
request.signal
|
|
9089
9493
|
);
|
|
9090
9494
|
if (!response.ok) {
|
|
9091
9495
|
return this.handleErrorResponse(response, "describe");
|
|
@@ -9094,6 +9498,8 @@ var DuckDbService = class extends BaseService {
|
|
|
9094
9498
|
return ok(data);
|
|
9095
9499
|
} catch (error) {
|
|
9096
9500
|
return err(wrapError2("duckdb", error));
|
|
9501
|
+
} finally {
|
|
9502
|
+
request.dispose();
|
|
9097
9503
|
}
|
|
9098
9504
|
});
|
|
9099
9505
|
}
|
|
@@ -9102,12 +9508,13 @@ var DuckDbService = class extends BaseService {
|
|
|
9102
9508
|
if (!this.requireAuth()) {
|
|
9103
9509
|
return err(authRequiredError("duckdb"));
|
|
9104
9510
|
}
|
|
9511
|
+
const request = this.createRequestSignal(options?.signal);
|
|
9105
9512
|
try {
|
|
9106
9513
|
const response = await this.invokeDuckDb(
|
|
9107
9514
|
dbName,
|
|
9108
9515
|
DuckDbAction.EXPORT,
|
|
9109
9516
|
{ action: "export" },
|
|
9110
|
-
|
|
9517
|
+
request.signal
|
|
9111
9518
|
);
|
|
9112
9519
|
if (!response.ok) {
|
|
9113
9520
|
return this.handleErrorResponse(response, "export");
|
|
@@ -9116,6 +9523,8 @@ var DuckDbService = class extends BaseService {
|
|
|
9116
9523
|
return ok(blob);
|
|
9117
9524
|
} catch (error) {
|
|
9118
9525
|
return err(wrapError2("duckdb", error));
|
|
9526
|
+
} finally {
|
|
9527
|
+
request.dispose();
|
|
9119
9528
|
}
|
|
9120
9529
|
});
|
|
9121
9530
|
}
|
|
@@ -9124,6 +9533,7 @@ var DuckDbService = class extends BaseService {
|
|
|
9124
9533
|
if (!this.requireAuth()) {
|
|
9125
9534
|
return err(authRequiredError("duckdb"));
|
|
9126
9535
|
}
|
|
9536
|
+
const request = this.createRequestSignal(options?.signal);
|
|
9127
9537
|
try {
|
|
9128
9538
|
const session = this.context.session;
|
|
9129
9539
|
const headers = this.context.invoke(
|
|
@@ -9139,7 +9549,7 @@ var DuckDbService = class extends BaseService {
|
|
|
9139
9549
|
"Content-Type": "application/x-duckdb"
|
|
9140
9550
|
},
|
|
9141
9551
|
body: new Blob([data]),
|
|
9142
|
-
signal:
|
|
9552
|
+
signal: request.signal
|
|
9143
9553
|
});
|
|
9144
9554
|
if (!response.ok) {
|
|
9145
9555
|
return this.handleErrorResponse(response, "import");
|
|
@@ -9147,6 +9557,8 @@ var DuckDbService = class extends BaseService {
|
|
|
9147
9557
|
return ok(void 0);
|
|
9148
9558
|
} catch (error) {
|
|
9149
9559
|
return err(wrapError2("duckdb", error));
|
|
9560
|
+
} finally {
|
|
9561
|
+
request.dispose();
|
|
9150
9562
|
}
|
|
9151
9563
|
});
|
|
9152
9564
|
}
|
|
@@ -9162,7 +9574,7 @@ var DuckDbService = class extends BaseService {
|
|
|
9162
9574
|
...extraHeaders
|
|
9163
9575
|
},
|
|
9164
9576
|
body: JSON.stringify(body),
|
|
9165
|
-
signal
|
|
9577
|
+
signal
|
|
9166
9578
|
});
|
|
9167
9579
|
}
|
|
9168
9580
|
async handleErrorResponse(response, operation) {
|
|
@@ -11502,75 +11914,6 @@ function canonicalHashHex(sha2563, value) {
|
|
|
11502
11914
|
const canonical = canonicalize(value);
|
|
11503
11915
|
return hexEncode2(sha2563(utf8Encode(canonical)));
|
|
11504
11916
|
}
|
|
11505
|
-
var URN_PREFIX = "urn:tinycloud:encryption:";
|
|
11506
|
-
var NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
11507
|
-
var PKH_EIP155_DID_RE = /^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/;
|
|
11508
|
-
var NetworkIdError = class extends Error {
|
|
11509
|
-
constructor(message) {
|
|
11510
|
-
super(message);
|
|
11511
|
-
this.name = "NetworkIdError";
|
|
11512
|
-
}
|
|
11513
|
-
};
|
|
11514
|
-
function parseNetworkId(networkId) {
|
|
11515
|
-
if (typeof networkId !== "string" || networkId.length === 0) {
|
|
11516
|
-
throw new NetworkIdError("networkId must be a non-empty string");
|
|
11517
|
-
}
|
|
11518
|
-
if (!networkId.startsWith(URN_PREFIX)) {
|
|
11519
|
-
throw new NetworkIdError(
|
|
11520
|
-
`networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`
|
|
11521
|
-
);
|
|
11522
|
-
}
|
|
11523
|
-
const body = networkId.slice(URN_PREFIX.length);
|
|
11524
|
-
const lastColon = body.lastIndexOf(":");
|
|
11525
|
-
if (lastColon <= 0 || lastColon === body.length - 1) {
|
|
11526
|
-
throw new NetworkIdError(
|
|
11527
|
-
`networkId missing ownerDid or name segment (got ${JSON.stringify(networkId)})`
|
|
11528
|
-
);
|
|
11529
|
-
}
|
|
11530
|
-
const ownerDid = body.slice(0, lastColon);
|
|
11531
|
-
const name = body.slice(lastColon + 1);
|
|
11532
|
-
if (!ownerDid.startsWith("did:")) {
|
|
11533
|
-
throw new NetworkIdError(
|
|
11534
|
-
`networkId ownerDid must be a DID (got ${JSON.stringify(ownerDid)})`
|
|
11535
|
-
);
|
|
11536
|
-
}
|
|
11537
|
-
const didParts = ownerDid.split(":");
|
|
11538
|
-
if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {
|
|
11539
|
-
throw new NetworkIdError(
|
|
11540
|
-
`networkId ownerDid is not a well-formed DID (got ${JSON.stringify(ownerDid)})`
|
|
11541
|
-
);
|
|
11542
|
-
}
|
|
11543
|
-
if (!NETWORK_NAME_RE.test(name)) {
|
|
11544
|
-
throw new NetworkIdError(
|
|
11545
|
-
`networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
11546
|
-
);
|
|
11547
|
-
}
|
|
11548
|
-
return { networkId, ownerDid, name };
|
|
11549
|
-
}
|
|
11550
|
-
function parsePkhOwnerDid(ownerDid) {
|
|
11551
|
-
const match = ownerDid.match(PKH_EIP155_DID_RE);
|
|
11552
|
-
if (!match) return null;
|
|
11553
|
-
return {
|
|
11554
|
-
chainId: match[1],
|
|
11555
|
-
address: match[2].toLowerCase()
|
|
11556
|
-
};
|
|
11557
|
-
}
|
|
11558
|
-
function ownerDidMatches(a, b) {
|
|
11559
|
-
const aPkh = parsePkhOwnerDid(a);
|
|
11560
|
-
const bPkh = parsePkhOwnerDid(b);
|
|
11561
|
-
if (aPkh && bPkh) {
|
|
11562
|
-
return aPkh.chainId === bPkh.chainId && aPkh.address === bPkh.address;
|
|
11563
|
-
}
|
|
11564
|
-
return a === b;
|
|
11565
|
-
}
|
|
11566
|
-
function networkDiscoveryKey(name) {
|
|
11567
|
-
if (!NETWORK_NAME_RE.test(name)) {
|
|
11568
|
-
throw new NetworkIdError(
|
|
11569
|
-
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
11570
|
-
);
|
|
11571
|
-
}
|
|
11572
|
-
return `.well-known/encryption/network/${name}`;
|
|
11573
|
-
}
|
|
11574
11917
|
var DEFAULT_ENCRYPTION_ALG = "x25519-aes256gcm/v1";
|
|
11575
11918
|
var ENVELOPE_VERSION = 1;
|
|
11576
11919
|
var DEFAULT_KEY_VERSION = 1;
|
|
@@ -12406,7 +12749,7 @@ var SERVICE_SHORT_TO_LONG = Object.freeze({
|
|
|
12406
12749
|
});
|
|
12407
12750
|
var ENCRYPTION_PERMISSION_SERVICE2 = "tinycloud.encryption";
|
|
12408
12751
|
var ENCRYPTION_MANIFEST_SPACE2 = "encryption";
|
|
12409
|
-
var
|
|
12752
|
+
var SERVICE_LONG_TO_SHORT2 = Object.freeze(
|
|
12410
12753
|
Object.fromEntries(
|
|
12411
12754
|
Object.entries(SERVICE_SHORT_TO_LONG).map(([s, l]) => [l, s])
|
|
12412
12755
|
)
|
|
@@ -12896,18 +13239,18 @@ function expandVaultPermissionEntry(entry) {
|
|
|
12896
13239
|
const byBase = /* @__PURE__ */ new Map();
|
|
12897
13240
|
for (const action of entry.actions) {
|
|
12898
13241
|
const expansion = vaultActionExpansion(action);
|
|
12899
|
-
for (const
|
|
12900
|
-
const actions = byBase.get(
|
|
13242
|
+
for (const base4 of expansion.bases) {
|
|
13243
|
+
const actions = byBase.get(base4) ?? [];
|
|
12901
13244
|
if (!actions.includes(expansion.action)) {
|
|
12902
13245
|
actions.push(expansion.action);
|
|
12903
13246
|
}
|
|
12904
|
-
byBase.set(
|
|
13247
|
+
byBase.set(base4, actions);
|
|
12905
13248
|
}
|
|
12906
13249
|
}
|
|
12907
|
-
return [...byBase.entries()].map(([
|
|
13250
|
+
return [...byBase.entries()].map(([base4, actions]) => ({
|
|
12908
13251
|
...entry,
|
|
12909
13252
|
service: "tinycloud.kv",
|
|
12910
|
-
path: vaultKVPath(
|
|
13253
|
+
path: vaultKVPath(base4, entry.path),
|
|
12911
13254
|
actions,
|
|
12912
13255
|
skipPrefix: true
|
|
12913
13256
|
}));
|
|
@@ -12950,9 +13293,9 @@ function normalizeVaultAction(action) {
|
|
|
12950
13293
|
}
|
|
12951
13294
|
return action;
|
|
12952
13295
|
}
|
|
12953
|
-
function vaultKVPath(
|
|
13296
|
+
function vaultKVPath(base4, path) {
|
|
12954
13297
|
const normalized = path.startsWith("/") ? path.slice(1) : path;
|
|
12955
|
-
return `${
|
|
13298
|
+
return `${base4}/${normalized}`;
|
|
12956
13299
|
}
|
|
12957
13300
|
function cloneResourceCapability(entry) {
|
|
12958
13301
|
return {
|
|
@@ -13123,17 +13466,15 @@ function didWithoutFragment(did) {
|
|
|
13123
13466
|
async function loadAdditionalDelegations(profile) {
|
|
13124
13467
|
return readAdditionalDelegations(profile);
|
|
13125
13468
|
}
|
|
13126
|
-
async function
|
|
13127
|
-
await
|
|
13469
|
+
async function appendAdditionalDelegations(profile, entries) {
|
|
13470
|
+
const { mergeDelegationsWithoutRequest } = await import("@tinycloud/operations/delegation-binding");
|
|
13471
|
+
await updateProfileStore(profile, "additional-delegations", (stored) => ({
|
|
13472
|
+
records: mergeDelegationsWithoutRequest(stored, entries.map((entry) => ({ ...entry }))),
|
|
13473
|
+
result: void 0
|
|
13474
|
+
}));
|
|
13128
13475
|
}
|
|
13129
13476
|
async function appendAdditionalDelegation(profile, entry) {
|
|
13130
|
-
await
|
|
13131
|
-
profile,
|
|
13132
|
-
"additional-delegations",
|
|
13133
|
-
entry.delegation.cid,
|
|
13134
|
-
entry,
|
|
13135
|
-
(candidate) => candidate.delegation.cid
|
|
13136
|
-
);
|
|
13477
|
+
await appendAdditionalDelegations(profile, [entry]);
|
|
13137
13478
|
}
|
|
13138
13479
|
async function loadPermissionRequestArtifacts(profile) {
|
|
13139
13480
|
const raw = await readAuthRequests(profile);
|
|
@@ -13147,10 +13488,8 @@ async function appendPermissionRequestArtifact(profile, artifact) {
|
|
|
13147
13488
|
await writeSharedRecords(profile, "auth-requests", next);
|
|
13148
13489
|
});
|
|
13149
13490
|
}
|
|
13150
|
-
async function replaceSharedRecords(profile, store, entries) {
|
|
13151
|
-
await withProfileLock2(profile, () => writeSharedRecords(profile, store, entries));
|
|
13152
|
-
}
|
|
13153
13491
|
async function writeSharedRecords(profile, store, entries) {
|
|
13492
|
+
await refuseWriteToDeletedProfile2(profile);
|
|
13154
13493
|
const path = store === "additional-delegations" ? additionalDelegationsPath(profile) : permissionRequestsPath(profile);
|
|
13155
13494
|
await writeJsonAtomic(path, entries);
|
|
13156
13495
|
await writeJsonAtomic(profileStoreMetadataPath(profile, store), { formatVersion: 1 });
|
|
@@ -13163,13 +13502,48 @@ async function getLastPermissionRequestArtifact(profile) {
|
|
|
13163
13502
|
const existing = await loadPermissionRequestArtifacts(profile);
|
|
13164
13503
|
return existing.at(-1) ?? null;
|
|
13165
13504
|
}
|
|
13166
|
-
async function replayAdditionalDelegations(node, profile) {
|
|
13505
|
+
async function replayAdditionalDelegations(node, profile, options) {
|
|
13506
|
+
const {
|
|
13507
|
+
operationSpaceResolver,
|
|
13508
|
+
prepareStoredDelegationReplay,
|
|
13509
|
+
replayStoredDelegation,
|
|
13510
|
+
storedDelegationKind
|
|
13511
|
+
} = await import("@tinycloud/operations/delegation-binding");
|
|
13512
|
+
const activator = node;
|
|
13513
|
+
const migrated = await prepareStoredDelegationReplay(profile, activator, {
|
|
13514
|
+
host: options.host,
|
|
13515
|
+
migrate: options.migrate
|
|
13516
|
+
});
|
|
13517
|
+
const resolveSpace = operationSpaceResolver(node, options.ownerSpace);
|
|
13167
13518
|
const entries = await loadAdditionalDelegations(profile);
|
|
13168
|
-
for (const
|
|
13519
|
+
for (const stored of entries) {
|
|
13520
|
+
const kind = storedDelegationKind(stored);
|
|
13521
|
+
if (kind === "compact" || kind === "signed-login") {
|
|
13522
|
+
const installed = await replayStoredDelegation(activator, stored, {
|
|
13523
|
+
host: options.host,
|
|
13524
|
+
migrated,
|
|
13525
|
+
resolveSpace
|
|
13526
|
+
});
|
|
13527
|
+
if (installed === void 0 && process.env.TC_DEBUG_REPLAY === "1") {
|
|
13528
|
+
process.stderr.write("[replay] skipping a stored delegation refused by validation or its request binding\n");
|
|
13529
|
+
}
|
|
13530
|
+
continue;
|
|
13531
|
+
}
|
|
13532
|
+
if (kind === "refused") {
|
|
13533
|
+
if (process.env.TC_DEBUG_REPLAY === "1") {
|
|
13534
|
+
process.stderr.write("[replay] skipping a malformed stored record or one bound to a request it cannot be held to\n");
|
|
13535
|
+
}
|
|
13536
|
+
continue;
|
|
13537
|
+
}
|
|
13538
|
+
const entry = stored;
|
|
13169
13539
|
const expiry = entry.delegation.expiry instanceof Date ? entry.delegation.expiry : new Date(entry.delegation.expiry);
|
|
13170
13540
|
if (expiry.getTime() <= Date.now()) continue;
|
|
13171
13541
|
try {
|
|
13172
|
-
await node.useRuntimeDelegation({
|
|
13542
|
+
await node.useRuntimeDelegation({
|
|
13543
|
+
...entry.delegation,
|
|
13544
|
+
delegationHeader: { Authorization: entry.delegation.delegationHeader.Authorization },
|
|
13545
|
+
expiry
|
|
13546
|
+
});
|
|
13173
13547
|
} catch (err2) {
|
|
13174
13548
|
if (process.env.TC_DEBUG_REPLAY === "1") {
|
|
13175
13549
|
process.stderr.write(`[replay] skipping ${entry.delegation.cid}: ${err2.message}
|
|
@@ -13465,7 +13839,7 @@ async function createSDKInstance(ctx, options) {
|
|
|
13465
13839
|
if (!key && !effectivePrivateKey && !(profile?.authMethod === "openkey" && session !== null)) {
|
|
13466
13840
|
throw new CLIError(
|
|
13467
13841
|
"AUTH_REQUIRED",
|
|
13468
|
-
`No key found for profile "${ctx.profile}". Run \`tc
|
|
13842
|
+
`No key found for profile "${ctx.profile}". Run \`tc --profile ${ctx.profile} auth rotate\` to create a new key and sign in.`,
|
|
13469
13843
|
ExitCode.AUTH_REQUIRED
|
|
13470
13844
|
);
|
|
13471
13845
|
}
|
|
@@ -13474,6 +13848,7 @@ async function createSDKInstance(ctx, options) {
|
|
|
13474
13848
|
host: ctx.host,
|
|
13475
13849
|
privateKey: effectivePrivateKey
|
|
13476
13850
|
});
|
|
13851
|
+
let restoredOwnSession2 = false;
|
|
13477
13852
|
if (session && session.delegationHeader && session.delegationCid && session.spaceId) {
|
|
13478
13853
|
await node2.restoreSession({
|
|
13479
13854
|
delegationHeader: session.delegationHeader,
|
|
@@ -13486,16 +13861,22 @@ async function createSDKInstance(ctx, options) {
|
|
|
13486
13861
|
siwe: session.siwe,
|
|
13487
13862
|
signature: session.signature
|
|
13488
13863
|
});
|
|
13864
|
+
restoredOwnSession2 = true;
|
|
13489
13865
|
} else {
|
|
13490
13866
|
await node2.signIn();
|
|
13491
13867
|
}
|
|
13492
|
-
await replayAdditionalDelegations(node2, ctx.profile
|
|
13868
|
+
await replayAdditionalDelegations(node2, ctx.profile, {
|
|
13869
|
+
host: ctx.host,
|
|
13870
|
+
ownerSpace: profile.spaceId,
|
|
13871
|
+
migrate: restoredOwnSession2 && options?.privateKey === void 0
|
|
13872
|
+
});
|
|
13493
13873
|
return node2;
|
|
13494
13874
|
}
|
|
13495
13875
|
const node = new TinyCloudNode({
|
|
13496
13876
|
host: ctx.host,
|
|
13497
13877
|
privateKey: options?.privateKey
|
|
13498
13878
|
});
|
|
13879
|
+
let restoredOwnSession = false;
|
|
13499
13880
|
if (options?.privateKey) {
|
|
13500
13881
|
await node.signIn();
|
|
13501
13882
|
} else if (session && session.delegationHeader && session.delegationCid && session.spaceId) {
|
|
@@ -13510,10 +13891,16 @@ async function createSDKInstance(ctx, options) {
|
|
|
13510
13891
|
siwe: session.siwe,
|
|
13511
13892
|
signature: session.signature
|
|
13512
13893
|
});
|
|
13894
|
+
restoredOwnSession = true;
|
|
13513
13895
|
}
|
|
13514
|
-
await replayAdditionalDelegations(node, ctx.profile
|
|
13896
|
+
await replayAdditionalDelegations(node, ctx.profile, {
|
|
13897
|
+
host: ctx.host,
|
|
13898
|
+
ownerSpace: profile?.spaceId,
|
|
13899
|
+
migrate: restoredOwnSession
|
|
13900
|
+
});
|
|
13515
13901
|
return node;
|
|
13516
13902
|
}
|
|
13903
|
+
var BOOTSTRAP_PROFILE_FIELDS = ["sessionDid", "spaceId"];
|
|
13517
13904
|
async function bootstrapDelegatedSession(ctx, delegation) {
|
|
13518
13905
|
const written = await ProfileManager.withLock(ctx.profile, async () => {
|
|
13519
13906
|
const previousProfile = await ProfileManager.getProfile(ctx.profile);
|
|
@@ -13563,13 +13950,13 @@ async function bootstrapDelegatedSession(ctx, delegation) {
|
|
|
13563
13950
|
throw error;
|
|
13564
13951
|
});
|
|
13565
13952
|
const session = await ProfileManager.getSession(ctx.profile);
|
|
13566
|
-
if (
|
|
13953
|
+
if (profile === null || BOOTSTRAP_PROFILE_FIELDS.some((field) => profile[field] !== written.profile[field]) || JSON.stringify(session) !== JSON.stringify(written.session)) {
|
|
13567
13954
|
return `Profile "${ctx.profile}" changed while the import was pending (another login, logout or profile update), so its newer state was kept and the provisional session was not rolled back.`;
|
|
13568
13955
|
}
|
|
13569
13956
|
return restoreBeforeBootstrap(ctx.profile, written.previousProfile);
|
|
13570
13957
|
}, { timeoutMs: PROFILE_COMMIT_LOCK_TIMEOUT_MS }).catch((error) => (
|
|
13571
13958
|
// The lock or a read failed: the import's error stays the one reported.
|
|
13572
|
-
`Rolling back the provisional session of profile "${ctx.profile}" could not run (${
|
|
13959
|
+
`Rolling back the provisional session of profile "${ctx.profile}" could not run (${failureName(error)}); check \`tc --profile ${ctx.profile} context\`.`
|
|
13573
13960
|
));
|
|
13574
13961
|
throw annotate(cause, note);
|
|
13575
13962
|
};
|
|
@@ -13585,15 +13972,27 @@ async function restoreBeforeBootstrap(profileName, previousProfile) {
|
|
|
13585
13972
|
const failures = [];
|
|
13586
13973
|
for (const write of [
|
|
13587
13974
|
() => ProfileManager.clearSession(profileName),
|
|
13588
|
-
() => ProfileManager.
|
|
13975
|
+
() => ProfileManager.updateProfile(profileName, (current) => {
|
|
13976
|
+
const restored = { ...current };
|
|
13977
|
+
for (const field of BOOTSTRAP_PROFILE_FIELDS) {
|
|
13978
|
+
if (previousProfile[field] === void 0) delete restored[field];
|
|
13979
|
+
else restored[field] = previousProfile[field];
|
|
13980
|
+
}
|
|
13981
|
+
return restored;
|
|
13982
|
+
})
|
|
13589
13983
|
]) {
|
|
13590
13984
|
await write().catch((error) => {
|
|
13591
|
-
failures.push(
|
|
13985
|
+
failures.push(failureName(error));
|
|
13592
13986
|
});
|
|
13593
13987
|
}
|
|
13594
13988
|
if (failures.length === 0) return void 0;
|
|
13595
13989
|
return `Rolling back the provisional session of profile "${profileName}" failed too (${failures.join("; ")}); check \`tc --profile ${profileName} context\`.`;
|
|
13596
13990
|
}
|
|
13991
|
+
function failureName(error) {
|
|
13992
|
+
if (error instanceof SyntaxError) return "a profile file is not valid JSON";
|
|
13993
|
+
if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string") return error.code;
|
|
13994
|
+
return error instanceof Error ? error.name : "unknown error";
|
|
13995
|
+
}
|
|
13597
13996
|
function annotate(error, note) {
|
|
13598
13997
|
if (note === void 0) return error;
|
|
13599
13998
|
const cause = wrapError(error);
|
|
@@ -13605,7 +14004,7 @@ async function ensureAuthenticated(ctx, options) {
|
|
|
13605
14004
|
}
|
|
13606
14005
|
const profile = await ProfileManager.getProfile(ctx.profile).catch(() => null);
|
|
13607
14006
|
if (profile?.authMethod === "local" && profile.privateKey) {
|
|
13608
|
-
return createSDKInstance(ctx
|
|
14007
|
+
return createSDKInstance(ctx);
|
|
13609
14008
|
}
|
|
13610
14009
|
const session = await ProfileManager.getSession(ctx.profile);
|
|
13611
14010
|
if (!session) {
|
|
@@ -13884,7 +14283,7 @@ async function authenticatedNode(cmd) {
|
|
|
13884
14283
|
}
|
|
13885
14284
|
function assertOk(result) {
|
|
13886
14285
|
if (!result.ok) {
|
|
13887
|
-
throw
|
|
14286
|
+
throw cliErrorFromService(result.error);
|
|
13888
14287
|
}
|
|
13889
14288
|
}
|
|
13890
14289
|
async function loadManifestSource(source) {
|
|
@@ -14018,8 +14417,8 @@ function buildAuthUrl(did, options = {}) {
|
|
|
14018
14417
|
params.set("expiry", String(options.expiry));
|
|
14019
14418
|
}
|
|
14020
14419
|
params.set("protocolVersion", "1");
|
|
14021
|
-
const
|
|
14022
|
-
return `${
|
|
14420
|
+
const base4 = options.openkeyHost ?? DEFAULT_OPENKEY_HOST;
|
|
14421
|
+
return `${base4}/delegate?${params.toString()}`;
|
|
14023
14422
|
}
|
|
14024
14423
|
function validateDelegationCallbackPayload(value) {
|
|
14025
14424
|
if (!value || typeof value !== "object") return "expected an object";
|
|
@@ -14989,20 +15388,20 @@ async function acquireDeviceDelegation(input) {
|
|
|
14989
15388
|
}
|
|
14990
15389
|
const startValue = await responseJson(startResponse);
|
|
14991
15390
|
if (!startResponse.ok) {
|
|
14992
|
-
const
|
|
15391
|
+
const code3 = errorCode(startValue);
|
|
14993
15392
|
const description = errorDescription(startValue);
|
|
14994
|
-
if (startResponse.status === 429 &&
|
|
15393
|
+
if (startResponse.status === 429 && code3 === "rate_limited") {
|
|
14995
15394
|
throw deviceAuthRateLimit(startResponse);
|
|
14996
15395
|
}
|
|
14997
|
-
if (
|
|
15396
|
+
if (code3 === "invalid_scope") {
|
|
14998
15397
|
throw new CLIError(
|
|
14999
15398
|
"SCOPE_REJECTED",
|
|
15000
15399
|
`OpenKey rejected the requested scope${description ? `: ${description}` : "."} Remove that capability from the manifest or use another approval flow.`,
|
|
15001
15400
|
ExitCode.PERMISSION_DENIED,
|
|
15002
|
-
{ openkeyError:
|
|
15401
|
+
{ openkeyError: code3, ...description ? { capability: description } : {} }
|
|
15003
15402
|
);
|
|
15004
15403
|
}
|
|
15005
|
-
throw new CLIError("DEVICE_AUTH_FAILED", `OpenKey device authorization failed: ${
|
|
15404
|
+
throw new CLIError("DEVICE_AUTH_FAILED", `OpenKey device authorization failed: ${code3 ?? `HTTP ${startResponse.status}`}${description ? ` (${description})` : ""}`, ExitCode.ERROR);
|
|
15006
15405
|
}
|
|
15007
15406
|
const started = validateStart(startValue, openkeyHost);
|
|
15008
15407
|
const deadline = Date.now() + started.expiresIn * 1e3;
|
|
@@ -15030,20 +15429,20 @@ async function acquireDeviceDelegation(input) {
|
|
|
15030
15429
|
continue;
|
|
15031
15430
|
}
|
|
15032
15431
|
const value = await responseJson(response);
|
|
15033
|
-
const
|
|
15034
|
-
if (response.status >= 500 || response.status === 429 &&
|
|
15035
|
-
if (
|
|
15432
|
+
const code3 = errorCode(value);
|
|
15433
|
+
if (response.status >= 500 || response.status === 429 && code3 !== "slow_down") continue;
|
|
15434
|
+
if (code3 === "slow_down") {
|
|
15036
15435
|
interval += 5;
|
|
15037
15436
|
continue;
|
|
15038
15437
|
}
|
|
15039
|
-
if (
|
|
15040
|
-
if (
|
|
15438
|
+
if (code3 === "authorization_pending") continue;
|
|
15439
|
+
if (code3 === "access_denied") {
|
|
15041
15440
|
throw new CLIError("DEVICE_AUTH_DENIED", "The owner denied the OpenKey device authorization. No session was saved.", ExitCode.PERMISSION_DENIED);
|
|
15042
15441
|
}
|
|
15043
|
-
if (
|
|
15442
|
+
if (code3 === "expired_token") {
|
|
15044
15443
|
throw new CLIError("DEVICE_AUTH_EXPIRED", "OpenKey device authorization expired_token: the approval window closed. Run the command again.", ExitCode.AUTH_REQUIRED);
|
|
15045
15444
|
}
|
|
15046
|
-
if (!response.ok) throw new CLIError("DEVICE_AUTH_FAILED", `OpenKey device authorization failed: ${
|
|
15445
|
+
if (!response.ok) throw new CLIError("DEVICE_AUTH_FAILED", `OpenKey device authorization failed: ${code3 ?? `HTTP ${response.status}`}`, ExitCode.ERROR);
|
|
15047
15446
|
const result = value;
|
|
15048
15447
|
if (result?.status === "pending") {
|
|
15049
15448
|
interval = Math.max(interval, Number.isSafeInteger(result.interval) ? result.interval : interval);
|
|
@@ -15252,6 +15651,7 @@ function registerAuthCommand(program) {
|
|
|
15252
15651
|
try {
|
|
15253
15652
|
const globalOpts = cmd.optsWithGlobals();
|
|
15254
15653
|
const ctx = await ProfileManager.resolveContext(globalOpts);
|
|
15654
|
+
await ProfileManager.getProfile(ctx.profile);
|
|
15255
15655
|
await ProfileManager.clearSession(ctx.profile);
|
|
15256
15656
|
outputJson({ profile: ctx.profile, authenticated: false });
|
|
15257
15657
|
} catch (error) {
|
|
@@ -15364,7 +15764,7 @@ function registerAuthCommand(program) {
|
|
|
15364
15764
|
if (profile.authMethod === "openkey" || options.device) {
|
|
15365
15765
|
const key = await ProfileManager.getKey(ctx.profile);
|
|
15366
15766
|
if (!key) {
|
|
15367
|
-
throw new CLIError("NO_KEY", `No key found for profile "${ctx.profile}". Run \`tc
|
|
15767
|
+
throw new CLIError("NO_KEY", `No key found for profile "${ctx.profile}". Run \`tc --profile ${ctx.profile} auth rotate\` to create a new key and sign in.`, ExitCode.AUTH_REQUIRED);
|
|
15368
15768
|
}
|
|
15369
15769
|
const openkeyHost = resolveOpenKeyHost(profile);
|
|
15370
15770
|
const grants = [];
|
|
@@ -15496,6 +15896,15 @@ function registerAuthCommand(program) {
|
|
|
15496
15896
|
return;
|
|
15497
15897
|
}
|
|
15498
15898
|
const imported = normalizeDelegationImport(parsed);
|
|
15899
|
+
const { activateUnboundCompactImport, storedDelegationKind } = await import("@tinycloud/operations/delegation-binding");
|
|
15900
|
+
const kind = storedDelegationKind({ delegation: imported.delegation });
|
|
15901
|
+
if (kind === "refused") {
|
|
15902
|
+
throw new CLIError(
|
|
15903
|
+
"INVALID_AUTH_IMPORT",
|
|
15904
|
+
"Imported delegation must carry exactly one string Authorization header.",
|
|
15905
|
+
ExitCode.USAGE_ERROR
|
|
15906
|
+
);
|
|
15907
|
+
}
|
|
15499
15908
|
let node;
|
|
15500
15909
|
try {
|
|
15501
15910
|
node = await ensureAuthenticated(ctx);
|
|
@@ -15505,18 +15914,33 @@ function registerAuthCommand(program) {
|
|
|
15505
15914
|
if (session || resolveProfilePosture(profile) !== "delegate-session") throw error;
|
|
15506
15915
|
node = (await bootstrapDelegatedSession(ctx, imported.delegation)).node;
|
|
15507
15916
|
}
|
|
15508
|
-
await appendAdditionalDelegation(ctx.profile, storedAdditionalDelegation(
|
|
15509
|
-
imported.delegation,
|
|
15510
|
-
imported.permissions
|
|
15511
|
-
));
|
|
15512
15917
|
const targetsSessionKey = typeof imported.delegation.delegateDID === "string" && principalDidEquals(imported.delegation.delegateDID, node.sessionDid);
|
|
15513
15918
|
let activated = false;
|
|
15514
|
-
|
|
15515
|
-
|
|
15919
|
+
let permissions = imported.permissions;
|
|
15920
|
+
if (targetsSessionKey && kind === "compact") {
|
|
15921
|
+
const record = await activateUnboundCompactImport(
|
|
15922
|
+
node,
|
|
15923
|
+
imported.delegation,
|
|
15924
|
+
ctx.host
|
|
15925
|
+
);
|
|
15926
|
+
await appendAdditionalDelegation(ctx.profile, record);
|
|
15927
|
+
permissions = record.permissions;
|
|
15516
15928
|
activated = true;
|
|
15929
|
+
} else {
|
|
15930
|
+
await appendAdditionalDelegation(ctx.profile, storedAdditionalDelegation(
|
|
15931
|
+
imported.delegation,
|
|
15932
|
+
imported.permissions
|
|
15933
|
+
));
|
|
15934
|
+
if (targetsSessionKey) {
|
|
15935
|
+
await node.useRuntimeDelegation({
|
|
15936
|
+
...imported.delegation,
|
|
15937
|
+
delegationHeader: { Authorization: imported.delegation.delegationHeader.Authorization }
|
|
15938
|
+
});
|
|
15939
|
+
activated = true;
|
|
15940
|
+
}
|
|
15517
15941
|
}
|
|
15518
15942
|
await appendGrantHistory(ctx.profile, {
|
|
15519
|
-
addedCaps:
|
|
15943
|
+
addedCaps: permissions,
|
|
15520
15944
|
source: "cli",
|
|
15521
15945
|
delegationCid: imported.delegation.cid,
|
|
15522
15946
|
expiry: imported.delegation.expiry.toISOString()
|
|
@@ -15527,7 +15951,7 @@ function registerAuthCommand(program) {
|
|
|
15527
15951
|
kind: "tinycloud.auth.delegation",
|
|
15528
15952
|
requestId: imported.requestId ?? null,
|
|
15529
15953
|
delegationCid: imported.delegation.cid,
|
|
15530
|
-
permissions
|
|
15954
|
+
permissions,
|
|
15531
15955
|
expiry: imported.delegation.expiry.toISOString()
|
|
15532
15956
|
});
|
|
15533
15957
|
} catch (error) {
|
|
@@ -15872,7 +16296,7 @@ async function importRequestBoundDelegation(ctx, artifact) {
|
|
|
15872
16296
|
ExitCode.ERROR
|
|
15873
16297
|
);
|
|
15874
16298
|
case "error":
|
|
15875
|
-
throw
|
|
16299
|
+
throw cliErrorFromService(result.error);
|
|
15876
16300
|
}
|
|
15877
16301
|
}
|
|
15878
16302
|
function isStoredDelegationLike(value) {
|
|
@@ -15901,8 +16325,6 @@ async function activateAndStoreOpenKeyGrants(profileName, node, grants, source)
|
|
|
15901
16325
|
for (const { delegation } of grants) await node.useRuntimeDelegation(delegation);
|
|
15902
16326
|
if (grants.length === 0) return;
|
|
15903
16327
|
await ProfileManager.withLock(profileName, async () => {
|
|
15904
|
-
const existing = await loadAdditionalDelegations(profileName);
|
|
15905
|
-
const replacing = new Set(grants.map(({ delegation }) => delegation.cid));
|
|
15906
16328
|
for (const { delegation, effective } of grants) {
|
|
15907
16329
|
await appendGrantHistory(profileName, {
|
|
15908
16330
|
addedCaps: effective,
|
|
@@ -15911,10 +16333,10 @@ async function activateAndStoreOpenKeyGrants(profileName, node, grants, source)
|
|
|
15911
16333
|
expiry: delegation.expiry.toISOString()
|
|
15912
16334
|
});
|
|
15913
16335
|
}
|
|
15914
|
-
await
|
|
15915
|
-
|
|
15916
|
-
|
|
15917
|
-
|
|
16336
|
+
await appendAdditionalDelegations(
|
|
16337
|
+
profileName,
|
|
16338
|
+
grants.map(({ delegation, effective }) => storedAdditionalDelegation(delegation, effective))
|
|
16339
|
+
);
|
|
15918
16340
|
});
|
|
15919
16341
|
}
|
|
15920
16342
|
async function ensureDelegationAuthority(params) {
|
|
@@ -15924,7 +16346,7 @@ async function ensureDelegationAuthority(params) {
|
|
|
15924
16346
|
if (!key) {
|
|
15925
16347
|
throw new CLIError(
|
|
15926
16348
|
"NO_KEY",
|
|
15927
|
-
`No key found for profile "${params.ctx.profile}". Run \`tc
|
|
16349
|
+
`No key found for profile "${params.ctx.profile}". Run \`tc --profile ${params.ctx.profile} auth rotate\` to create a new key and sign in.`,
|
|
15928
16350
|
ExitCode.AUTH_REQUIRED
|
|
15929
16351
|
);
|
|
15930
16352
|
}
|
|
@@ -15996,7 +16418,7 @@ function execCapturedCommand(command) {
|
|
|
15996
16418
|
stdio: "inherit"
|
|
15997
16419
|
});
|
|
15998
16420
|
child.on("error", reject);
|
|
15999
|
-
child.on("exit", (
|
|
16421
|
+
child.on("exit", (code3, signal) => {
|
|
16000
16422
|
if (signal) {
|
|
16001
16423
|
reject(new CLIError(
|
|
16002
16424
|
"COMMAND_SIGNAL",
|
|
@@ -16005,8 +16427,8 @@ function execCapturedCommand(command) {
|
|
|
16005
16427
|
));
|
|
16006
16428
|
return;
|
|
16007
16429
|
}
|
|
16008
|
-
if (
|
|
16009
|
-
process.exitCode =
|
|
16430
|
+
if (code3 && code3 !== 0) {
|
|
16431
|
+
process.exitCode = code3;
|
|
16010
16432
|
}
|
|
16011
16433
|
resolve4();
|
|
16012
16434
|
});
|
|
@@ -16333,15 +16755,15 @@ ${declined.map((permission) => ` ${compactPermission(permission)}`).join("\n")}
|
|
|
16333
16755
|
}
|
|
16334
16756
|
async function refreshOpenKeySession(profileName, host, options = {}) {
|
|
16335
16757
|
const snapshot = await readProfileSnapshot(profileName);
|
|
16758
|
+
const profile = snapshot.profile ?? await ProfileManager.getProfile(profileName);
|
|
16336
16759
|
const key = snapshot.key;
|
|
16337
16760
|
if (!key) {
|
|
16338
16761
|
throw new CLIError(
|
|
16339
16762
|
"NO_KEY",
|
|
16340
|
-
`No key found for profile "${profileName}". Run \`tc
|
|
16763
|
+
`No key found for profile "${profileName}". Run \`tc --profile ${profileName} auth rotate\` to create a new key and sign in.`,
|
|
16341
16764
|
ExitCode.AUTH_REQUIRED
|
|
16342
16765
|
);
|
|
16343
16766
|
}
|
|
16344
|
-
const profile = snapshot.profile ?? await ProfileManager.getProfile(profileName);
|
|
16345
16767
|
if (options.permissions !== void 0) validateLoginPermissions(options.permissions);
|
|
16346
16768
|
const permissions = options.permissions === void 0 ? void 0 : scopedLoginPermissions(options.permissions);
|
|
16347
16769
|
if (permissions !== void 0) {
|
|
@@ -16609,7 +17031,7 @@ function registerDelegationCommand(program) {
|
|
|
16609
17031
|
expiry
|
|
16610
17032
|
});
|
|
16611
17033
|
if (!result.ok) {
|
|
16612
|
-
throw
|
|
17034
|
+
throw cliErrorFromService(result.error);
|
|
16613
17035
|
}
|
|
16614
17036
|
outputJson({
|
|
16615
17037
|
cid: result.data.cid,
|
|
@@ -16629,7 +17051,7 @@ function registerDelegationCommand(program) {
|
|
|
16629
17051
|
const node = await ensureAuthenticated(ctx);
|
|
16630
17052
|
const result = await node.delegationManager.list();
|
|
16631
17053
|
if (!result.ok) {
|
|
16632
|
-
throw
|
|
17054
|
+
throw cliErrorFromService(result.error);
|
|
16633
17055
|
}
|
|
16634
17056
|
let delegations = result.data;
|
|
16635
17057
|
if (options.granted) {
|
|
@@ -16675,7 +17097,7 @@ function registerDelegationCommand(program) {
|
|
|
16675
17097
|
const node = await ensureAuthenticated(ctx);
|
|
16676
17098
|
const result = await node.delegationManager.revoke(cid);
|
|
16677
17099
|
if (!result.ok) {
|
|
16678
|
-
throw
|
|
17100
|
+
throw cliErrorFromService(result.error);
|
|
16679
17101
|
}
|
|
16680
17102
|
outputJson({ cid, revoked: true });
|
|
16681
17103
|
} catch (error) {
|
|
@@ -16800,7 +17222,6 @@ function registerDoctorCommand(program) {
|
|
|
16800
17222
|
init_profiles();
|
|
16801
17223
|
init_formatter();
|
|
16802
17224
|
init_errors();
|
|
16803
|
-
init_constants();
|
|
16804
17225
|
import { readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
|
|
16805
17226
|
import { resolve } from "path";
|
|
16806
17227
|
init_theme();
|
|
@@ -16817,7 +17238,7 @@ function registerDuckdbCommand(program) {
|
|
|
16817
17238
|
() => node.duckdb.db(options.db).query(sqlStr, params)
|
|
16818
17239
|
);
|
|
16819
17240
|
if (!result.ok) {
|
|
16820
|
-
throw
|
|
17241
|
+
throw cliErrorFromService(result.error);
|
|
16821
17242
|
}
|
|
16822
17243
|
const { columns, rows, rowCount } = result.data;
|
|
16823
17244
|
if (shouldOutputJson()) {
|
|
@@ -16849,7 +17270,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
16849
17270
|
() => node.duckdb.db(options.db).execute(sqlStr, params)
|
|
16850
17271
|
);
|
|
16851
17272
|
if (!result.ok) {
|
|
16852
|
-
throw
|
|
17273
|
+
throw cliErrorFromService(result.error);
|
|
16853
17274
|
}
|
|
16854
17275
|
outputJson({ changes: result.data.changes });
|
|
16855
17276
|
} catch (error) {
|
|
@@ -16866,7 +17287,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
16866
17287
|
() => node.duckdb.db(options.db).describe()
|
|
16867
17288
|
);
|
|
16868
17289
|
if (!result.ok) {
|
|
16869
|
-
throw
|
|
17290
|
+
throw cliErrorFromService(result.error);
|
|
16870
17291
|
}
|
|
16871
17292
|
const schema = result.data;
|
|
16872
17293
|
if (shouldOutputJson()) {
|
|
@@ -16911,7 +17332,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
16911
17332
|
() => node.duckdb.db(options.db).export()
|
|
16912
17333
|
);
|
|
16913
17334
|
if (!result.ok) {
|
|
16914
|
-
throw
|
|
17335
|
+
throw cliErrorFromService(result.error);
|
|
16915
17336
|
}
|
|
16916
17337
|
const blob = result.data;
|
|
16917
17338
|
const buffer = Buffer.from(await blob.arrayBuffer());
|
|
@@ -16938,7 +17359,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
16938
17359
|
() => node.duckdb.db(options.db).import(bytes)
|
|
16939
17360
|
);
|
|
16940
17361
|
if (!result.ok) {
|
|
16941
|
-
throw
|
|
17362
|
+
throw cliErrorFromService(result.error);
|
|
16942
17363
|
}
|
|
16943
17364
|
outputJson({
|
|
16944
17365
|
file: filePath,
|
|
@@ -17075,7 +17496,7 @@ init_theme();
|
|
|
17075
17496
|
async function throwKvError(error, spaceUri, profileName) {
|
|
17076
17497
|
const hosted = await unhostedSpaceError(error, spaceUri, profileName);
|
|
17077
17498
|
if (hosted) throw hosted;
|
|
17078
|
-
throw
|
|
17499
|
+
throw cliErrorFromService(error);
|
|
17079
17500
|
}
|
|
17080
17501
|
function isByteCount(value) {
|
|
17081
17502
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
@@ -17088,8 +17509,8 @@ function storageQuotaError(error) {
|
|
|
17088
17509
|
}
|
|
17089
17510
|
function assertAddressableKey(key) {
|
|
17090
17511
|
for (let i = 0; i < key.length; i++) {
|
|
17091
|
-
const
|
|
17092
|
-
if (
|
|
17512
|
+
const code3 = key.charCodeAt(i);
|
|
17513
|
+
if (code3 <= 32 || code3 === 127) {
|
|
17093
17514
|
throw new CLIError("USAGE_ERROR", "KV keys cannot contain spaces or control characters; use a URL-safe key", ExitCode.USAGE_ERROR);
|
|
17094
17515
|
}
|
|
17095
17516
|
}
|
|
@@ -17919,8 +18340,8 @@ async function writeSecretFile(path, value) {
|
|
|
17919
18340
|
if (created) {
|
|
17920
18341
|
await rm3(temp, { force: true }).catch(() => void 0);
|
|
17921
18342
|
}
|
|
17922
|
-
const
|
|
17923
|
-
throw new CLIError("ERROR", `Could not write secret output "${path}"${
|
|
18343
|
+
const code3 = error instanceof Error && "code" in error && typeof error.code === "string" ? ` (${error.code})` : "";
|
|
18344
|
+
throw new CLIError("ERROR", `Could not write secret output "${path}"${code3}.`, ExitCode.ERROR);
|
|
17924
18345
|
}
|
|
17925
18346
|
try {
|
|
17926
18347
|
const parent = await open2(parentPath, "r");
|
|
@@ -18058,8 +18479,8 @@ function shouldRequestSecretPermissions(error) {
|
|
|
18058
18479
|
function thrownPermissionError(error) {
|
|
18059
18480
|
const record = error;
|
|
18060
18481
|
const message = typeof record?.message === "string" ? record.message : String(error);
|
|
18061
|
-
const
|
|
18062
|
-
if (
|
|
18482
|
+
const code3 = typeof record?.code === "string" ? record.code : "PERMISSION_DENIED";
|
|
18483
|
+
if (code3 !== "PERMISSION_DENIED" && !/permission|session expired|autosign|capabilit/i.test(message)) {
|
|
18063
18484
|
return null;
|
|
18064
18485
|
}
|
|
18065
18486
|
return {
|
|
@@ -18267,9 +18688,9 @@ async function resolveDelegatedSecretSource(source, secretPath, space = SECRETS_
|
|
|
18267
18688
|
return { ...selected, source };
|
|
18268
18689
|
}
|
|
18269
18690
|
function mapEncryptionResultError(error) {
|
|
18270
|
-
const
|
|
18271
|
-
const exitCode =
|
|
18272
|
-
return new CLIError(
|
|
18691
|
+
const code3 = error.code || "DECRYPTION_FAILED";
|
|
18692
|
+
const exitCode = code3 === "PERMISSION_DENIED" ? ExitCode.PERMISSION_DENIED : code3 === "NOT_FOUND" ? ExitCode.NOT_FOUND : code3 === "NETWORK_ERROR" || code3 === "TRANSPORT_ERROR" ? ExitCode.NETWORK_ERROR : ExitCode.ERROR;
|
|
18693
|
+
return new CLIError(code3, error.message, exitCode);
|
|
18273
18694
|
}
|
|
18274
18695
|
function parseDecryptedSecretPayload(data, secretPath) {
|
|
18275
18696
|
const text = new TextDecoder().decode(data);
|
|
@@ -18592,7 +19013,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
18592
19013
|
operation: () => secrets2.list(scopeOptions)
|
|
18593
19014
|
});
|
|
18594
19015
|
if (!result.ok) {
|
|
18595
|
-
throw
|
|
19016
|
+
throw cliErrorFromService(result.error);
|
|
18596
19017
|
}
|
|
18597
19018
|
const secretNames = Array.isArray(result.data) ? result.data : [];
|
|
18598
19019
|
outputJson({
|
|
@@ -18709,7 +19130,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
18709
19130
|
operation: () => secrets2.put(name, secretValue, scopeOptions)
|
|
18710
19131
|
});
|
|
18711
19132
|
if (!result.ok) {
|
|
18712
|
-
throw
|
|
19133
|
+
throw cliErrorFromService(result.error);
|
|
18713
19134
|
}
|
|
18714
19135
|
outputJson({ name, written: true });
|
|
18715
19136
|
} catch (error) {
|
|
@@ -18735,7 +19156,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
18735
19156
|
operation: () => secrets2.delete(name, scopeOptions)
|
|
18736
19157
|
});
|
|
18737
19158
|
if (!result.ok) {
|
|
18738
|
-
throw
|
|
19159
|
+
throw cliErrorFromService(result.error);
|
|
18739
19160
|
}
|
|
18740
19161
|
outputJson({ name, deleted: true });
|
|
18741
19162
|
} catch (error) {
|
|
@@ -18803,13 +19224,13 @@ function _abool2(value, title = "") {
|
|
|
18803
19224
|
}
|
|
18804
19225
|
return value;
|
|
18805
19226
|
}
|
|
18806
|
-
function _abytes2(value,
|
|
19227
|
+
function _abytes2(value, length4, title = "") {
|
|
18807
19228
|
const bytes = isBytes(value);
|
|
18808
19229
|
const len = value?.length;
|
|
18809
|
-
const needsLen =
|
|
18810
|
-
if (!bytes || needsLen && len !==
|
|
19230
|
+
const needsLen = length4 !== void 0;
|
|
19231
|
+
if (!bytes || needsLen && len !== length4) {
|
|
18811
19232
|
const prefix = title && `"${title}" `;
|
|
18812
|
-
const ofLen = needsLen ? ` of length ${
|
|
19233
|
+
const ofLen = needsLen ? ` of length ${length4}` : "";
|
|
18813
19234
|
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
18814
19235
|
throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
|
|
18815
19236
|
}
|
|
@@ -19332,15 +19753,15 @@ var wNAF = class {
|
|
|
19332
19753
|
const { windows, windowSize } = calcWOpts(W, this.bits);
|
|
19333
19754
|
const points = [];
|
|
19334
19755
|
let p = point;
|
|
19335
|
-
let
|
|
19756
|
+
let base4 = p;
|
|
19336
19757
|
for (let window = 0; window < windows; window++) {
|
|
19337
|
-
|
|
19338
|
-
points.push(
|
|
19758
|
+
base4 = p;
|
|
19759
|
+
points.push(base4);
|
|
19339
19760
|
for (let i = 1; i < windowSize; i++) {
|
|
19340
|
-
|
|
19341
|
-
points.push(
|
|
19761
|
+
base4 = base4.add(p);
|
|
19762
|
+
points.push(base4);
|
|
19342
19763
|
}
|
|
19343
|
-
p =
|
|
19764
|
+
p = base4.double();
|
|
19344
19765
|
}
|
|
19345
19766
|
return points;
|
|
19346
19767
|
}
|
|
@@ -20360,13 +20781,13 @@ var BLAKE2 = class extends Hash {
|
|
|
20360
20781
|
return res;
|
|
20361
20782
|
}
|
|
20362
20783
|
_cloneInto(to) {
|
|
20363
|
-
const { buffer, length:
|
|
20784
|
+
const { buffer, length: length4, finished, destroyed, outputLen, pos } = this;
|
|
20364
20785
|
to || (to = new this.constructor({ dkLen: outputLen }));
|
|
20365
20786
|
to.set(...this.get());
|
|
20366
20787
|
to.buffer.set(buffer);
|
|
20367
20788
|
to.destroyed = destroyed;
|
|
20368
20789
|
to.finished = finished;
|
|
20369
|
-
to.length =
|
|
20790
|
+
to.length = length4;
|
|
20370
20791
|
to.pos = pos;
|
|
20371
20792
|
to.outputLen = outputLen;
|
|
20372
20793
|
return to;
|
|
@@ -21600,8 +22021,8 @@ function isValidJWT2(jwt, alg) {
|
|
|
21600
22021
|
const [header] = jwt.split(".");
|
|
21601
22022
|
if (!header)
|
|
21602
22023
|
return false;
|
|
21603
|
-
const
|
|
21604
|
-
const decoded = JSON.parse(atob(
|
|
22024
|
+
const base6422 = header.replace(/-/g, "+").replace(/_/g, "/").padEnd(header.length + (4 - header.length % 4) % 4, "=");
|
|
22025
|
+
const decoded = JSON.parse(atob(base6422));
|
|
21605
22026
|
if (typeof decoded !== "object" || decoded === null)
|
|
21606
22027
|
return false;
|
|
21607
22028
|
if ("typ" in decoded && decoded?.typ !== "JWT")
|
|
@@ -24255,23 +24676,23 @@ var ZodEffects2 = class extends ZodType2 {
|
|
|
24255
24676
|
}
|
|
24256
24677
|
if (effect.type === "transform") {
|
|
24257
24678
|
if (ctx.common.async === false) {
|
|
24258
|
-
const
|
|
24679
|
+
const base33 = this._def.schema._parseSync({
|
|
24259
24680
|
data: ctx.data,
|
|
24260
24681
|
path: ctx.path,
|
|
24261
24682
|
parent: ctx
|
|
24262
24683
|
});
|
|
24263
|
-
if (!isValid2(
|
|
24684
|
+
if (!isValid2(base33))
|
|
24264
24685
|
return INVALID2;
|
|
24265
|
-
const result = effect.transform(
|
|
24686
|
+
const result = effect.transform(base33.value, checkCtx);
|
|
24266
24687
|
if (result instanceof Promise) {
|
|
24267
24688
|
throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`);
|
|
24268
24689
|
}
|
|
24269
24690
|
return { status: status.value, value: result };
|
|
24270
24691
|
} else {
|
|
24271
|
-
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((
|
|
24272
|
-
if (!isValid2(
|
|
24692
|
+
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base33) => {
|
|
24693
|
+
if (!isValid2(base33))
|
|
24273
24694
|
return INVALID2;
|
|
24274
|
-
return Promise.resolve(effect.transform(
|
|
24695
|
+
return Promise.resolve(effect.transform(base33.value, checkCtx)).then((result) => ({
|
|
24275
24696
|
status: status.value,
|
|
24276
24697
|
value: result
|
|
24277
24698
|
}));
|
|
@@ -25179,9 +25600,9 @@ var cache = /* @__PURE__ */ new WeakMap();
|
|
|
25179
25600
|
function baseCache(cid2) {
|
|
25180
25601
|
const baseCache22 = cache.get(cid2);
|
|
25181
25602
|
if (baseCache22 == null) {
|
|
25182
|
-
const
|
|
25183
|
-
cache.set(cid2,
|
|
25184
|
-
return
|
|
25603
|
+
const baseCache32 = /* @__PURE__ */ new Map();
|
|
25604
|
+
cache.set(cid2, baseCache32);
|
|
25605
|
+
return baseCache32;
|
|
25185
25606
|
}
|
|
25186
25607
|
return baseCache22;
|
|
25187
25608
|
}
|
|
@@ -26419,7 +26840,7 @@ function base2(ALPHABET, name) {
|
|
|
26419
26840
|
var LEADER = ALPHABET.charAt(0);
|
|
26420
26841
|
var FACTOR = Math.log(BASE) / Math.log(256);
|
|
26421
26842
|
var iFACTOR = Math.log(256) / Math.log(BASE);
|
|
26422
|
-
function
|
|
26843
|
+
function encode52(source) {
|
|
26423
26844
|
if (source instanceof Uint8Array)
|
|
26424
26845
|
;
|
|
26425
26846
|
else if (ArrayBuffer.isView(source)) {
|
|
@@ -26434,7 +26855,7 @@ function base2(ALPHABET, name) {
|
|
|
26434
26855
|
return "";
|
|
26435
26856
|
}
|
|
26436
26857
|
var zeroes = 0;
|
|
26437
|
-
var
|
|
26858
|
+
var length32 = 0;
|
|
26438
26859
|
var pbegin = 0;
|
|
26439
26860
|
var pend = source.length;
|
|
26440
26861
|
while (pbegin !== pend && source[pbegin] === 0) {
|
|
@@ -26446,7 +26867,7 @@ function base2(ALPHABET, name) {
|
|
|
26446
26867
|
while (pbegin !== pend) {
|
|
26447
26868
|
var carry = source[pbegin];
|
|
26448
26869
|
var i2 = 0;
|
|
26449
|
-
for (var it1 = size - 1; (carry !== 0 || i2 <
|
|
26870
|
+
for (var it1 = size - 1; (carry !== 0 || i2 < length32) && it1 !== -1; it1--, i2++) {
|
|
26450
26871
|
carry += 256 * b58[it1] >>> 0;
|
|
26451
26872
|
b58[it1] = carry % BASE >>> 0;
|
|
26452
26873
|
carry = carry / BASE >>> 0;
|
|
@@ -26454,10 +26875,10 @@ function base2(ALPHABET, name) {
|
|
|
26454
26875
|
if (carry !== 0) {
|
|
26455
26876
|
throw new Error("Non-zero carry");
|
|
26456
26877
|
}
|
|
26457
|
-
|
|
26878
|
+
length32 = i2;
|
|
26458
26879
|
pbegin++;
|
|
26459
26880
|
}
|
|
26460
|
-
var it2 = size -
|
|
26881
|
+
var it2 = size - length32;
|
|
26461
26882
|
while (it2 !== size && b58[it2] === 0) {
|
|
26462
26883
|
it2++;
|
|
26463
26884
|
}
|
|
@@ -26479,7 +26900,7 @@ function base2(ALPHABET, name) {
|
|
|
26479
26900
|
return;
|
|
26480
26901
|
}
|
|
26481
26902
|
var zeroes = 0;
|
|
26482
|
-
var
|
|
26903
|
+
var length32 = 0;
|
|
26483
26904
|
while (source[psz] === LEADER) {
|
|
26484
26905
|
zeroes++;
|
|
26485
26906
|
psz++;
|
|
@@ -26492,7 +26913,7 @@ function base2(ALPHABET, name) {
|
|
|
26492
26913
|
return;
|
|
26493
26914
|
}
|
|
26494
26915
|
var i2 = 0;
|
|
26495
|
-
for (var it3 = size - 1; (carry !== 0 || i2 <
|
|
26916
|
+
for (var it3 = size - 1; (carry !== 0 || i2 < length32) && it3 !== -1; it3--, i2++) {
|
|
26496
26917
|
carry += BASE * b256[it3] >>> 0;
|
|
26497
26918
|
b256[it3] = carry % 256 >>> 0;
|
|
26498
26919
|
carry = carry / 256 >>> 0;
|
|
@@ -26500,13 +26921,13 @@ function base2(ALPHABET, name) {
|
|
|
26500
26921
|
if (carry !== 0) {
|
|
26501
26922
|
throw new Error("Non-zero carry");
|
|
26502
26923
|
}
|
|
26503
|
-
|
|
26924
|
+
length32 = i2;
|
|
26504
26925
|
psz++;
|
|
26505
26926
|
}
|
|
26506
26927
|
if (source[psz] === " ") {
|
|
26507
26928
|
return;
|
|
26508
26929
|
}
|
|
26509
|
-
var it4 = size -
|
|
26930
|
+
var it4 = size - length32;
|
|
26510
26931
|
while (it4 !== size && b256[it4] === 0) {
|
|
26511
26932
|
it4++;
|
|
26512
26933
|
}
|
|
@@ -26517,7 +26938,7 @@ function base2(ALPHABET, name) {
|
|
|
26517
26938
|
}
|
|
26518
26939
|
return vch;
|
|
26519
26940
|
}
|
|
26520
|
-
function
|
|
26941
|
+
function decode92(string) {
|
|
26521
26942
|
var buffer = decodeUnsafe(string);
|
|
26522
26943
|
if (buffer) {
|
|
26523
26944
|
return buffer;
|
|
@@ -26525,9 +26946,9 @@ function base2(ALPHABET, name) {
|
|
|
26525
26946
|
throw new Error(`Non-${name} character`);
|
|
26526
26947
|
}
|
|
26527
26948
|
return {
|
|
26528
|
-
encode:
|
|
26949
|
+
encode: encode52,
|
|
26529
26950
|
decodeUnsafe,
|
|
26530
|
-
decode:
|
|
26951
|
+
decode: decode92
|
|
26531
26952
|
};
|
|
26532
26953
|
}
|
|
26533
26954
|
var src2 = base2;
|
|
@@ -26625,16 +27046,16 @@ var Codec2 = class {
|
|
|
26625
27046
|
return this.decoder.decode(input);
|
|
26626
27047
|
}
|
|
26627
27048
|
};
|
|
26628
|
-
function from2({ name, prefix, encode:
|
|
26629
|
-
return new Codec2(name, prefix,
|
|
27049
|
+
function from2({ name, prefix, encode: encode52, decode: decode92 }) {
|
|
27050
|
+
return new Codec2(name, prefix, encode52, decode92);
|
|
26630
27051
|
}
|
|
26631
27052
|
function baseX2({ name, prefix, alphabet }) {
|
|
26632
|
-
const { encode:
|
|
27053
|
+
const { encode: encode52, decode: decode92 } = base_x_default2(alphabet, name);
|
|
26633
27054
|
return from2({
|
|
26634
27055
|
prefix,
|
|
26635
27056
|
name,
|
|
26636
|
-
encode:
|
|
26637
|
-
decode: (text) => coerce3(
|
|
27057
|
+
encode: encode52,
|
|
27058
|
+
decode: (text) => coerce3(decode92(text))
|
|
26638
27059
|
});
|
|
26639
27060
|
}
|
|
26640
27061
|
function decode5(string, alphabetIdx, bitsPerChar, name) {
|
|
@@ -27004,24 +27425,24 @@ var Digest2 = class {
|
|
|
27004
27425
|
this.bytes = bytes3;
|
|
27005
27426
|
}
|
|
27006
27427
|
};
|
|
27007
|
-
function format2(link2,
|
|
27428
|
+
function format2(link2, base33) {
|
|
27008
27429
|
const { bytes: bytes3, version } = link2;
|
|
27009
27430
|
switch (version) {
|
|
27010
27431
|
case 0:
|
|
27011
|
-
return toStringV02(bytes3, baseCache2(link2),
|
|
27432
|
+
return toStringV02(bytes3, baseCache2(link2), base33 ?? base58btc2.encoder);
|
|
27012
27433
|
default:
|
|
27013
|
-
return toStringV12(bytes3, baseCache2(link2),
|
|
27434
|
+
return toStringV12(bytes3, baseCache2(link2), base33 ?? base322.encoder);
|
|
27014
27435
|
}
|
|
27015
27436
|
}
|
|
27016
27437
|
var cache2 = /* @__PURE__ */ new WeakMap();
|
|
27017
27438
|
function baseCache2(cid2) {
|
|
27018
|
-
const
|
|
27019
|
-
if (
|
|
27439
|
+
const baseCache32 = cache2.get(cid2);
|
|
27440
|
+
if (baseCache32 == null) {
|
|
27020
27441
|
const baseCache4 = /* @__PURE__ */ new Map();
|
|
27021
27442
|
cache2.set(cid2, baseCache4);
|
|
27022
27443
|
return baseCache4;
|
|
27023
27444
|
}
|
|
27024
|
-
return
|
|
27445
|
+
return baseCache32;
|
|
27025
27446
|
}
|
|
27026
27447
|
var CID2 = class _CID2 {
|
|
27027
27448
|
code;
|
|
@@ -27100,8 +27521,8 @@ var CID2 = class _CID2 {
|
|
|
27100
27521
|
const unknown = other;
|
|
27101
27522
|
return unknown != null && self.code === unknown.code && self.version === unknown.version && equals4(self.multihash, unknown.multihash);
|
|
27102
27523
|
}
|
|
27103
|
-
toString(
|
|
27104
|
-
return format2(this,
|
|
27524
|
+
toString(base33) {
|
|
27525
|
+
return format2(this, base33);
|
|
27105
27526
|
}
|
|
27106
27527
|
toJSON() {
|
|
27107
27528
|
return { "/": format2(this) };
|
|
@@ -27233,8 +27654,8 @@ var CID2 = class _CID2 {
|
|
|
27233
27654
|
static inspectBytes(initialBytes) {
|
|
27234
27655
|
let offset = 0;
|
|
27235
27656
|
const next = () => {
|
|
27236
|
-
const [i,
|
|
27237
|
-
offset +=
|
|
27657
|
+
const [i, length32] = decode7(initialBytes.subarray(offset));
|
|
27658
|
+
offset += length32;
|
|
27238
27659
|
return i;
|
|
27239
27660
|
};
|
|
27240
27661
|
let version = next();
|
|
@@ -27261,8 +27682,8 @@ var CID2 = class _CID2 {
|
|
|
27261
27682
|
* throw an error if encoding of the CID is not compatible with supplied (or
|
|
27262
27683
|
* a default decoder).
|
|
27263
27684
|
*/
|
|
27264
|
-
static parse(source,
|
|
27265
|
-
const [prefix, bytes3] = parseCIDtoBytes2(source,
|
|
27685
|
+
static parse(source, base33) {
|
|
27686
|
+
const [prefix, bytes3] = parseCIDtoBytes2(source, base33);
|
|
27266
27687
|
const cid2 = _CID2.decode(bytes3);
|
|
27267
27688
|
if (cid2.version === 0 && source[0] !== "Q") {
|
|
27268
27689
|
throw Error("Version 0 CID string must not include multibase prefix");
|
|
@@ -27271,56 +27692,56 @@ var CID2 = class _CID2 {
|
|
|
27271
27692
|
return cid2;
|
|
27272
27693
|
}
|
|
27273
27694
|
};
|
|
27274
|
-
function parseCIDtoBytes2(source,
|
|
27695
|
+
function parseCIDtoBytes2(source, base33) {
|
|
27275
27696
|
switch (source[0]) {
|
|
27276
27697
|
// CIDv0 is parsed differently
|
|
27277
27698
|
case "Q": {
|
|
27278
|
-
const decoder =
|
|
27699
|
+
const decoder = base33 ?? base58btc2;
|
|
27279
27700
|
return [
|
|
27280
27701
|
base58btc2.prefix,
|
|
27281
27702
|
decoder.decode(`${base58btc2.prefix}${source}`)
|
|
27282
27703
|
];
|
|
27283
27704
|
}
|
|
27284
27705
|
case base58btc2.prefix: {
|
|
27285
|
-
const decoder =
|
|
27706
|
+
const decoder = base33 ?? base58btc2;
|
|
27286
27707
|
return [base58btc2.prefix, decoder.decode(source)];
|
|
27287
27708
|
}
|
|
27288
27709
|
case base322.prefix: {
|
|
27289
|
-
const decoder =
|
|
27710
|
+
const decoder = base33 ?? base322;
|
|
27290
27711
|
return [base322.prefix, decoder.decode(source)];
|
|
27291
27712
|
}
|
|
27292
27713
|
case base362.prefix: {
|
|
27293
|
-
const decoder =
|
|
27714
|
+
const decoder = base33 ?? base362;
|
|
27294
27715
|
return [base362.prefix, decoder.decode(source)];
|
|
27295
27716
|
}
|
|
27296
27717
|
default: {
|
|
27297
|
-
if (
|
|
27718
|
+
if (base33 == null) {
|
|
27298
27719
|
throw Error("To parse non base32, base36 or base58btc encoded CID multibase decoder must be provided");
|
|
27299
27720
|
}
|
|
27300
|
-
return [source[0],
|
|
27721
|
+
return [source[0], base33.decode(source)];
|
|
27301
27722
|
}
|
|
27302
27723
|
}
|
|
27303
27724
|
}
|
|
27304
|
-
function toStringV02(bytes3,
|
|
27305
|
-
const { prefix } =
|
|
27725
|
+
function toStringV02(bytes3, cache32, base33) {
|
|
27726
|
+
const { prefix } = base33;
|
|
27306
27727
|
if (prefix !== base58btc2.prefix) {
|
|
27307
|
-
throw Error(`Cannot string encode V0 in ${
|
|
27728
|
+
throw Error(`Cannot string encode V0 in ${base33.name} encoding`);
|
|
27308
27729
|
}
|
|
27309
|
-
const cid2 =
|
|
27730
|
+
const cid2 = cache32.get(prefix);
|
|
27310
27731
|
if (cid2 == null) {
|
|
27311
|
-
const cid3 =
|
|
27312
|
-
|
|
27732
|
+
const cid3 = base33.encode(bytes3).slice(1);
|
|
27733
|
+
cache32.set(prefix, cid3);
|
|
27313
27734
|
return cid3;
|
|
27314
27735
|
} else {
|
|
27315
27736
|
return cid2;
|
|
27316
27737
|
}
|
|
27317
27738
|
}
|
|
27318
|
-
function toStringV12(bytes3,
|
|
27319
|
-
const { prefix } =
|
|
27320
|
-
const cid2 =
|
|
27739
|
+
function toStringV12(bytes3, cache32, base33) {
|
|
27740
|
+
const { prefix } = base33;
|
|
27741
|
+
const cid2 = cache32.get(prefix);
|
|
27321
27742
|
if (cid2 == null) {
|
|
27322
|
-
const cid3 =
|
|
27323
|
-
|
|
27743
|
+
const cid3 = base33.encode(bytes3);
|
|
27744
|
+
cache32.set(prefix, cid3);
|
|
27324
27745
|
return cid3;
|
|
27325
27746
|
} else {
|
|
27326
27747
|
return cid2;
|
|
@@ -27374,11 +27795,12 @@ function historyRecordForPublishedShare(result, now = /* @__PURE__ */ new Date()
|
|
|
27374
27795
|
};
|
|
27375
27796
|
}
|
|
27376
27797
|
var ShareNotifyError = class extends Error {
|
|
27377
|
-
|
|
27378
|
-
constructor(message = "share delivery did not complete") {
|
|
27798
|
+
constructor(message = "share delivery did not complete", reason) {
|
|
27379
27799
|
super(message);
|
|
27800
|
+
this.reason = reason;
|
|
27380
27801
|
this.name = "ShareNotifyError";
|
|
27381
27802
|
}
|
|
27803
|
+
code = "delivery-failed";
|
|
27382
27804
|
};
|
|
27383
27805
|
function recipientMatchesShareRecord(record, recipient) {
|
|
27384
27806
|
const matcher = record.recipientMatcher;
|
|
@@ -27388,6 +27810,11 @@ function recipientMatchesShareRecord(record, recipient) {
|
|
|
27388
27810
|
if (matcher.kind === "emailDomain") return mailbox.domain === matcher.value;
|
|
27389
27811
|
return false;
|
|
27390
27812
|
}
|
|
27813
|
+
function shareDeliveryWindowExpiresAt(record) {
|
|
27814
|
+
const expiresAt = Math.min(Date.parse(record.expiresAt), Date.parse(record.registeredAt) + 5 * 60 * 1e3);
|
|
27815
|
+
if (!Number.isFinite(expiresAt)) throw new ShareNotifyError("share delivery history has invalid timestamps");
|
|
27816
|
+
return expiresAt;
|
|
27817
|
+
}
|
|
27391
27818
|
async function notifyShare(input) {
|
|
27392
27819
|
const mailbox = canonicalMailbox(input.recipient);
|
|
27393
27820
|
if (!input.shareId || mailbox === void 0) throw new ShareNotifyError("recipient is invalid");
|
|
@@ -27398,19 +27825,59 @@ async function notifyShare(input) {
|
|
|
27398
27825
|
const idempotencyKey = input.idempotencyKey ?? await defaultIdempotencyKey(input.shareId, recipient);
|
|
27399
27826
|
const attemptsLimit = input.maxAttempts ?? 3;
|
|
27400
27827
|
if (!Number.isSafeInteger(attemptsLimit) || attemptsLimit < 1 || attemptsLimit > 8) throw new ShareNotifyError("maxAttempts is invalid");
|
|
27828
|
+
if (input.signal?.aborted) throw new ShareNotifyError("share delivery was cancelled");
|
|
27829
|
+
if (input.checkDeliveryWindow && input.record !== void 0 && shareDeliveryWindowExpiresAt(input.record) <= Date.now()) {
|
|
27830
|
+
return {
|
|
27831
|
+
protocol: "tinycloud-share",
|
|
27832
|
+
version: 1,
|
|
27833
|
+
shareId: input.shareId,
|
|
27834
|
+
state: "partial-failure",
|
|
27835
|
+
idempotencyKey,
|
|
27836
|
+
attempts: 1,
|
|
27837
|
+
retryable: false,
|
|
27838
|
+
reason: "delivery-window-expired"
|
|
27839
|
+
};
|
|
27840
|
+
}
|
|
27401
27841
|
let attempts = 0;
|
|
27402
|
-
let lastError;
|
|
27403
27842
|
while (attempts < attemptsLimit) {
|
|
27404
27843
|
if (input.signal?.aborted) throw new ShareNotifyError("share delivery was cancelled");
|
|
27405
27844
|
attempts += 1;
|
|
27406
27845
|
try {
|
|
27407
27846
|
const state = await input.adapter.deliver({ shareId: input.shareId, recipient, idempotencyKey, ...input.record === void 0 ? {} : { record: input.record }, ...input.signal === void 0 ? {} : { signal: input.signal } });
|
|
27408
|
-
return {
|
|
27847
|
+
return {
|
|
27848
|
+
protocol: "tinycloud-share",
|
|
27849
|
+
version: 1,
|
|
27850
|
+
shareId: input.shareId,
|
|
27851
|
+
state: state === "delivered" && input.record?.deliveredRecipients?.includes(recipient) ? "already-delivered" : state,
|
|
27852
|
+
idempotencyKey,
|
|
27853
|
+
attempts
|
|
27854
|
+
};
|
|
27409
27855
|
} catch (error) {
|
|
27410
|
-
|
|
27856
|
+
if (error instanceof ShareNotifyError && error.reason === "delivery-window-expired") {
|
|
27857
|
+
return {
|
|
27858
|
+
protocol: "tinycloud-share",
|
|
27859
|
+
version: 1,
|
|
27860
|
+
shareId: input.shareId,
|
|
27861
|
+
state: "partial-failure",
|
|
27862
|
+
idempotencyKey,
|
|
27863
|
+
attempts,
|
|
27864
|
+
retryable: false,
|
|
27865
|
+
reason: "delivery-window-expired"
|
|
27866
|
+
};
|
|
27867
|
+
}
|
|
27868
|
+
if (error !== null && typeof error === "object" && "status" in error && (error.status === 401 || error.status === 403)) {
|
|
27869
|
+
return {
|
|
27870
|
+
protocol: "tinycloud-share",
|
|
27871
|
+
version: 1,
|
|
27872
|
+
shareId: input.shareId,
|
|
27873
|
+
state: "partial-failure",
|
|
27874
|
+
idempotencyKey,
|
|
27875
|
+
attempts,
|
|
27876
|
+
retryable: false
|
|
27877
|
+
};
|
|
27878
|
+
}
|
|
27411
27879
|
}
|
|
27412
27880
|
}
|
|
27413
|
-
void lastError;
|
|
27414
27881
|
return { protocol: "tinycloud-share", version: 1, shareId: input.shareId, state: "partial-failure", idempotencyKey, attempts, retryable: true };
|
|
27415
27882
|
}
|
|
27416
27883
|
async function defaultIdempotencyKey(shareId, recipient) {
|
|
@@ -27454,7 +27921,11 @@ async function revokeShare(input) {
|
|
|
27454
27921
|
});
|
|
27455
27922
|
}
|
|
27456
27923
|
const revokedAt = (input.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
|
|
27457
|
-
if (input.records !== void 0)
|
|
27924
|
+
if (input.records?.update !== void 0) {
|
|
27925
|
+
await input.records.update(input.record.shareId, (record) => ({ ...record, revokedAt }));
|
|
27926
|
+
} else if (input.records !== void 0) {
|
|
27927
|
+
await input.records.put({ ...input.record, revokedAt });
|
|
27928
|
+
}
|
|
27458
27929
|
return { state: "revoked", target, delegationCid, revokedAt };
|
|
27459
27930
|
}
|
|
27460
27931
|
function redactRecord(record, revealLink, link2) {
|
|
@@ -27502,204 +27973,1527 @@ function parseNativeShareUrl(value) {
|
|
|
27502
27973
|
return token;
|
|
27503
27974
|
}
|
|
27504
27975
|
|
|
27505
|
-
//
|
|
27506
|
-
|
|
27507
|
-
|
|
27508
|
-
|
|
27509
|
-
|
|
27510
|
-
function writeJson2(value) {
|
|
27511
|
-
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
27512
|
-
`);
|
|
27513
|
-
}
|
|
27514
|
-
function authorizationRequiredJson(result) {
|
|
27515
|
-
return {
|
|
27516
|
-
state: "authorization-required",
|
|
27517
|
-
method: result.method,
|
|
27518
|
-
next: "complete authorization through the configured authority adapter, then retry with the required proof"
|
|
27519
|
-
};
|
|
27520
|
-
}
|
|
27521
|
-
function publishHuman(result) {
|
|
27522
|
-
process.stdout.write(`${result.url}
|
|
27523
|
-
`);
|
|
27524
|
-
}
|
|
27525
|
-
function inspectHuman(result) {
|
|
27526
|
-
const metadata = result.metadata;
|
|
27527
|
-
process.stdout.write([
|
|
27528
|
-
`Share ${metadata.shareId}`,
|
|
27529
|
-
`File: ${metadata.display.filename ?? "unnamed"}`,
|
|
27530
|
-
`Target: ${metadata.target.kind === "bearer" ? "bearer (anyone with the complete link can read)" : metadata.target.kind}`,
|
|
27531
|
-
`Expires: ${metadata.expiresAt}`,
|
|
27532
|
-
`Resource: ${metadata.resource.path}`,
|
|
27533
|
-
`Link format: ${result.link.kind}`
|
|
27534
|
-
].join("\n") + "\n");
|
|
27535
|
-
}
|
|
27536
|
-
function receiveHuman(path) {
|
|
27537
|
-
process.stdout.write(`${path}
|
|
27538
|
-
`);
|
|
27539
|
-
}
|
|
27540
|
-
function receiveJson(result, path) {
|
|
27541
|
-
writeJson2({ protocol: "tinycloud-share", version: 1, path, metadata: result.metadata });
|
|
27542
|
-
}
|
|
27543
|
-
|
|
27544
|
-
// src/share/io.ts
|
|
27545
|
-
import { constants } from "fs";
|
|
27546
|
-
import { lstat as lstat3, mkdir as mkdir3, mkdtemp, open as open4, readFile as readFile9, realpath, stat as stat2, link, rename as rename3, rm as rm4, unlink } from "fs/promises";
|
|
27547
|
-
import { randomBytes as randomBytes4 } from "crypto";
|
|
27548
|
-
import { basename as basename3, join as join6, resolve as resolve2, sep } from "path";
|
|
27549
|
-
init_errors();
|
|
27550
|
-
var MAX_SHARE_STDIN_BYTES = 100 * 1024 * 1024;
|
|
27551
|
-
var MAX_SHARE_URL_BYTES = 64 * 1024;
|
|
27552
|
-
async function readBoundedStdin(limit = MAX_SHARE_STDIN_BYTES) {
|
|
27553
|
-
if (!Number.isSafeInteger(limit) || limit <= 0) throw new Error("MAX_BYTES_EXCEEDED");
|
|
27554
|
-
const chunks = [];
|
|
27555
|
-
let total = 0;
|
|
27556
|
-
for await (const chunk of process.stdin) {
|
|
27557
|
-
const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
27558
|
-
total += bytes.byteLength;
|
|
27559
|
-
if (total > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
27560
|
-
chunks.push(bytes);
|
|
27976
|
+
// ../share-envelope/dist/index.js
|
|
27977
|
+
var empty3 = new Uint8Array(0);
|
|
27978
|
+
function equals5(aa, bb) {
|
|
27979
|
+
if (aa === bb) {
|
|
27980
|
+
return true;
|
|
27561
27981
|
}
|
|
27562
|
-
|
|
27563
|
-
|
|
27564
|
-
async function readBoundedUrlStdin() {
|
|
27565
|
-
const bytes = await readBoundedStdin(MAX_SHARE_URL_BYTES);
|
|
27566
|
-
const value = new TextDecoder("utf-8", { fatal: true }).decode(bytes).trim();
|
|
27567
|
-
if (value.length === 0 || /\s/.test(value)) throw new Error("INVALID_ARGUMENT");
|
|
27568
|
-
return value;
|
|
27569
|
-
}
|
|
27570
|
-
function safeFilename(value) {
|
|
27571
|
-
return shareFilename(value);
|
|
27572
|
-
}
|
|
27573
|
-
function shareFilename(value) {
|
|
27574
|
-
try {
|
|
27575
|
-
return canonicalShareFilename(value);
|
|
27576
|
-
} catch {
|
|
27577
|
-
throw new CLIError(
|
|
27578
|
-
"UNSAFE_FILENAME",
|
|
27579
|
-
hasUnsafeFilenameCodePoint(value) ? "filename contains control or invisible characters" : "filename must be one safe path segment",
|
|
27580
|
-
8
|
|
27581
|
-
);
|
|
27982
|
+
if (aa.byteLength !== bb.byteLength) {
|
|
27983
|
+
return false;
|
|
27582
27984
|
}
|
|
27583
|
-
|
|
27584
|
-
|
|
27585
|
-
|
|
27586
|
-
}
|
|
27587
|
-
async function readShareInput(input, name, limit = MAX_SHARE_STDIN_BYTES) {
|
|
27588
|
-
const filename = shareInputFilename(input, name);
|
|
27589
|
-
if (input === "-") return { bytes: await readBoundedStdin(limit), filename };
|
|
27590
|
-
const path = resolve2(input);
|
|
27591
|
-
const info = await stat2(path);
|
|
27592
|
-
if (!info.isFile() || info.size > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
27593
|
-
const bytes = new Uint8Array(await readFile9(path));
|
|
27594
|
-
if (bytes.byteLength > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
27595
|
-
return { bytes, filename };
|
|
27596
|
-
}
|
|
27597
|
-
async function assertDirectory(path) {
|
|
27598
|
-
const absolute = resolve2(path);
|
|
27599
|
-
const segments = absolute.split(sep).filter(Boolean);
|
|
27600
|
-
let current = absolute.startsWith(sep) ? sep : "";
|
|
27601
|
-
for (const segment of segments) {
|
|
27602
|
-
current = current === sep ? join6(current, segment) : join6(current, segment);
|
|
27603
|
-
try {
|
|
27604
|
-
const info = await lstat3(current);
|
|
27605
|
-
if (info.isSymbolicLink()) {
|
|
27606
|
-
const canonical = await realpath(current);
|
|
27607
|
-
if (current !== "/tmp" && current !== "/var") throw new Error("OUTPUT_EXISTS");
|
|
27608
|
-
if (canonical !== `/private${current}`) throw new Error("OUTPUT_EXISTS");
|
|
27609
|
-
} else if (!info.isDirectory()) throw new Error("OUTPUT_EXISTS");
|
|
27610
|
-
} catch (error) {
|
|
27611
|
-
if (error.code !== "ENOENT") throw error;
|
|
27612
|
-
await mkdir3(current, { mode: 448 });
|
|
27613
|
-
const created = await lstat3(current);
|
|
27614
|
-
if (created.isSymbolicLink() || !created.isDirectory()) throw new Error("OUTPUT_EXISTS");
|
|
27985
|
+
for (let ii = 0; ii < aa.byteLength; ii++) {
|
|
27986
|
+
if (aa[ii] !== bb[ii]) {
|
|
27987
|
+
return false;
|
|
27615
27988
|
}
|
|
27616
27989
|
}
|
|
27990
|
+
return true;
|
|
27617
27991
|
}
|
|
27618
|
-
|
|
27619
|
-
|
|
27620
|
-
|
|
27621
|
-
const safeName = safeFilename(filename);
|
|
27622
|
-
const directoryHandle = await open4(outputDirectory, constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0));
|
|
27623
|
-
const stableDirectory = await realpath(outputDirectory);
|
|
27624
|
-
const outputPath = join6(stableDirectory, safeName);
|
|
27625
|
-
const directoryIdentity = await directoryHandle.stat();
|
|
27626
|
-
const assertStableDirectory = async () => {
|
|
27627
|
-
const current = await stat2(stableDirectory);
|
|
27628
|
-
if (current.dev !== directoryIdentity.dev || current.ino !== directoryIdentity.ino) throw new Error("OUTPUT_EXISTS");
|
|
27629
|
-
};
|
|
27630
|
-
await assertStableDirectory();
|
|
27631
|
-
const stagingDirectory = await mkdtemp(join6(stableDirectory, ".tinycloud-share-stage-"));
|
|
27632
|
-
const stagingInfo = await lstat3(stagingDirectory);
|
|
27633
|
-
if (!stagingInfo.isDirectory() || (stagingInfo.mode & 511) !== 448) throw new Error("OUTPUT_EXISTS");
|
|
27634
|
-
const stagingPath = join6(stagingDirectory, `.tinycloud-share-${randomBytes4(16).toString("hex")}.tmp`);
|
|
27635
|
-
let temporaryPath;
|
|
27636
|
-
let handle;
|
|
27637
|
-
try {
|
|
27638
|
-
await assertStableDirectory();
|
|
27639
|
-
try {
|
|
27640
|
-
const existing = await lstat3(outputPath);
|
|
27641
|
-
if (existing.isSymbolicLink()) throw new Error("UNSAFE_FILENAME");
|
|
27642
|
-
} catch (error) {
|
|
27643
|
-
if (error.code !== "ENOENT") throw error;
|
|
27644
|
-
}
|
|
27645
|
-
temporaryPath = stagingPath;
|
|
27646
|
-
handle = await open4(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0), 384);
|
|
27647
|
-
await handle.writeFile(bytes);
|
|
27648
|
-
await handle.close();
|
|
27649
|
-
handle = void 0;
|
|
27650
|
-
await assertStableDirectory();
|
|
27651
|
-
if (force) {
|
|
27652
|
-
await rename3(temporaryPath, outputPath);
|
|
27653
|
-
} else {
|
|
27654
|
-
await link(temporaryPath, outputPath);
|
|
27655
|
-
await unlink(temporaryPath);
|
|
27656
|
-
}
|
|
27657
|
-
await assertStableDirectory();
|
|
27658
|
-
} catch (error) {
|
|
27659
|
-
if (error.code === "EEXIST") throw new Error("OUTPUT_EXISTS");
|
|
27660
|
-
if (error.code === "ELOOP") throw new Error("UNSAFE_FILENAME");
|
|
27661
|
-
throw error;
|
|
27662
|
-
} finally {
|
|
27663
|
-
await handle?.close();
|
|
27664
|
-
try {
|
|
27665
|
-
if (temporaryPath !== void 0) await unlink(temporaryPath);
|
|
27666
|
-
} catch {
|
|
27667
|
-
}
|
|
27668
|
-
await rm4(stagingDirectory, { recursive: true, force: true });
|
|
27669
|
-
await directoryHandle.close();
|
|
27992
|
+
function coerce4(o) {
|
|
27993
|
+
if (o instanceof Uint8Array && o.constructor.name === "Uint8Array") {
|
|
27994
|
+
return o;
|
|
27670
27995
|
}
|
|
27671
|
-
|
|
27672
|
-
|
|
27673
|
-
|
|
27674
|
-
// src/share/errors.ts
|
|
27675
|
-
var SharePublishAuthorityError = class extends Error {
|
|
27676
|
-
constructor(failure) {
|
|
27677
|
-
super(failure.kind);
|
|
27678
|
-
this.failure = failure;
|
|
27679
|
-
this.name = "SharePublishAuthorityError";
|
|
27996
|
+
if (o instanceof ArrayBuffer) {
|
|
27997
|
+
return new Uint8Array(o);
|
|
27680
27998
|
}
|
|
27681
|
-
|
|
27682
|
-
|
|
27683
|
-
// src/commands/share.ts
|
|
27684
|
-
var SHARE_ORIGIN = "https://share.tinycloud.xyz";
|
|
27685
|
-
var shareServices = {};
|
|
27686
|
-
function parseShareTarget(value) {
|
|
27687
|
-
if (value === "anyone" || value === "bearer") return { kind: "bearer" };
|
|
27688
|
-
if (value.startsWith("did:")) return { kind: "recipientDid", did: value };
|
|
27689
|
-
if (value.startsWith("domain:")) return canonicalMailboxTarget({ kind: "emailDomain", domain: value.slice("domain:".length) });
|
|
27690
|
-
if (value.startsWith("email:")) return canonicalMailboxTarget({ kind: "email", address: value.slice("email:".length) });
|
|
27691
|
-
if (value.includes("@")) return canonicalMailboxTarget({ kind: "email", address: value });
|
|
27692
|
-
throw new CLIError("INVALID_ARGUMENT", "--to must be anyone, a did:, an email address, or domain:example.com", 2);
|
|
27693
|
-
}
|
|
27694
|
-
function canonicalMailboxTarget(target) {
|
|
27695
|
-
try {
|
|
27696
|
-
return normalizeShareTarget(target);
|
|
27697
|
-
} catch (error) {
|
|
27698
|
-
throw new CLIError("INVALID_ARGUMENT", error instanceof TypeError ? error.message : "share recipient is invalid", 2);
|
|
27999
|
+
if (ArrayBuffer.isView(o)) {
|
|
28000
|
+
return new Uint8Array(o.buffer, o.byteOffset, o.byteLength);
|
|
27699
28001
|
}
|
|
28002
|
+
throw new Error("Unknown type, must be binary type");
|
|
27700
28003
|
}
|
|
27701
|
-
function
|
|
27702
|
-
if (
|
|
28004
|
+
function base3(ALPHABET, name) {
|
|
28005
|
+
if (ALPHABET.length >= 255) {
|
|
28006
|
+
throw new TypeError("Alphabet too long");
|
|
28007
|
+
}
|
|
28008
|
+
var BASE_MAP = new Uint8Array(256);
|
|
28009
|
+
for (var j = 0; j < BASE_MAP.length; j++) {
|
|
28010
|
+
BASE_MAP[j] = 255;
|
|
28011
|
+
}
|
|
28012
|
+
for (var i = 0; i < ALPHABET.length; i++) {
|
|
28013
|
+
var x = ALPHABET.charAt(i);
|
|
28014
|
+
var xc = x.charCodeAt(0);
|
|
28015
|
+
if (BASE_MAP[xc] !== 255) {
|
|
28016
|
+
throw new TypeError(x + " is ambiguous");
|
|
28017
|
+
}
|
|
28018
|
+
BASE_MAP[xc] = i;
|
|
28019
|
+
}
|
|
28020
|
+
var BASE = ALPHABET.length;
|
|
28021
|
+
var LEADER = ALPHABET.charAt(0);
|
|
28022
|
+
var FACTOR = Math.log(BASE) / Math.log(256);
|
|
28023
|
+
var iFACTOR = Math.log(256) / Math.log(BASE);
|
|
28024
|
+
function encode32(source) {
|
|
28025
|
+
if (source instanceof Uint8Array)
|
|
28026
|
+
;
|
|
28027
|
+
else if (ArrayBuffer.isView(source)) {
|
|
28028
|
+
source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
28029
|
+
} else if (Array.isArray(source)) {
|
|
28030
|
+
source = Uint8Array.from(source);
|
|
28031
|
+
}
|
|
28032
|
+
if (!(source instanceof Uint8Array)) {
|
|
28033
|
+
throw new TypeError("Expected Uint8Array");
|
|
28034
|
+
}
|
|
28035
|
+
if (source.length === 0) {
|
|
28036
|
+
return "";
|
|
28037
|
+
}
|
|
28038
|
+
var zeroes = 0;
|
|
28039
|
+
var length22 = 0;
|
|
28040
|
+
var pbegin = 0;
|
|
28041
|
+
var pend = source.length;
|
|
28042
|
+
while (pbegin !== pend && source[pbegin] === 0) {
|
|
28043
|
+
pbegin++;
|
|
28044
|
+
zeroes++;
|
|
28045
|
+
}
|
|
28046
|
+
var size = (pend - pbegin) * iFACTOR + 1 >>> 0;
|
|
28047
|
+
var b58 = new Uint8Array(size);
|
|
28048
|
+
while (pbegin !== pend) {
|
|
28049
|
+
var carry = source[pbegin];
|
|
28050
|
+
var i2 = 0;
|
|
28051
|
+
for (var it1 = size - 1; (carry !== 0 || i2 < length22) && it1 !== -1; it1--, i2++) {
|
|
28052
|
+
carry += 256 * b58[it1] >>> 0;
|
|
28053
|
+
b58[it1] = carry % BASE >>> 0;
|
|
28054
|
+
carry = carry / BASE >>> 0;
|
|
28055
|
+
}
|
|
28056
|
+
if (carry !== 0) {
|
|
28057
|
+
throw new Error("Non-zero carry");
|
|
28058
|
+
}
|
|
28059
|
+
length22 = i2;
|
|
28060
|
+
pbegin++;
|
|
28061
|
+
}
|
|
28062
|
+
var it2 = size - length22;
|
|
28063
|
+
while (it2 !== size && b58[it2] === 0) {
|
|
28064
|
+
it2++;
|
|
28065
|
+
}
|
|
28066
|
+
var str = LEADER.repeat(zeroes);
|
|
28067
|
+
for (; it2 < size; ++it2) {
|
|
28068
|
+
str += ALPHABET.charAt(b58[it2]);
|
|
28069
|
+
}
|
|
28070
|
+
return str;
|
|
28071
|
+
}
|
|
28072
|
+
function decodeUnsafe(source) {
|
|
28073
|
+
if (typeof source !== "string") {
|
|
28074
|
+
throw new TypeError("Expected String");
|
|
28075
|
+
}
|
|
28076
|
+
if (source.length === 0) {
|
|
28077
|
+
return new Uint8Array();
|
|
28078
|
+
}
|
|
28079
|
+
var psz = 0;
|
|
28080
|
+
if (source[psz] === " ") {
|
|
28081
|
+
return;
|
|
28082
|
+
}
|
|
28083
|
+
var zeroes = 0;
|
|
28084
|
+
var length22 = 0;
|
|
28085
|
+
while (source[psz] === LEADER) {
|
|
28086
|
+
zeroes++;
|
|
28087
|
+
psz++;
|
|
28088
|
+
}
|
|
28089
|
+
var size = (source.length - psz) * FACTOR + 1 >>> 0;
|
|
28090
|
+
var b256 = new Uint8Array(size);
|
|
28091
|
+
while (source[psz]) {
|
|
28092
|
+
var carry = BASE_MAP[source.charCodeAt(psz)];
|
|
28093
|
+
if (carry === 255) {
|
|
28094
|
+
return;
|
|
28095
|
+
}
|
|
28096
|
+
var i2 = 0;
|
|
28097
|
+
for (var it3 = size - 1; (carry !== 0 || i2 < length22) && it3 !== -1; it3--, i2++) {
|
|
28098
|
+
carry += BASE * b256[it3] >>> 0;
|
|
28099
|
+
b256[it3] = carry % 256 >>> 0;
|
|
28100
|
+
carry = carry / 256 >>> 0;
|
|
28101
|
+
}
|
|
28102
|
+
if (carry !== 0) {
|
|
28103
|
+
throw new Error("Non-zero carry");
|
|
28104
|
+
}
|
|
28105
|
+
length22 = i2;
|
|
28106
|
+
psz++;
|
|
28107
|
+
}
|
|
28108
|
+
if (source[psz] === " ") {
|
|
28109
|
+
return;
|
|
28110
|
+
}
|
|
28111
|
+
var it4 = size - length22;
|
|
28112
|
+
while (it4 !== size && b256[it4] === 0) {
|
|
28113
|
+
it4++;
|
|
28114
|
+
}
|
|
28115
|
+
var vch = new Uint8Array(zeroes + (size - it4));
|
|
28116
|
+
var j2 = zeroes;
|
|
28117
|
+
while (it4 !== size) {
|
|
28118
|
+
vch[j2++] = b256[it4++];
|
|
28119
|
+
}
|
|
28120
|
+
return vch;
|
|
28121
|
+
}
|
|
28122
|
+
function decode52(string) {
|
|
28123
|
+
var buffer = decodeUnsafe(string);
|
|
28124
|
+
if (buffer) {
|
|
28125
|
+
return buffer;
|
|
28126
|
+
}
|
|
28127
|
+
throw new Error(`Non-${name} character`);
|
|
28128
|
+
}
|
|
28129
|
+
return {
|
|
28130
|
+
encode: encode32,
|
|
28131
|
+
decodeUnsafe,
|
|
28132
|
+
decode: decode52
|
|
28133
|
+
};
|
|
28134
|
+
}
|
|
28135
|
+
var src3 = base3;
|
|
28136
|
+
var _brrp__multiformats_scope_baseX3 = src3;
|
|
28137
|
+
var base_x_default3 = _brrp__multiformats_scope_baseX3;
|
|
28138
|
+
var Encoder3 = class {
|
|
28139
|
+
name;
|
|
28140
|
+
prefix;
|
|
28141
|
+
baseEncode;
|
|
28142
|
+
constructor(name, prefix, baseEncode) {
|
|
28143
|
+
this.name = name;
|
|
28144
|
+
this.prefix = prefix;
|
|
28145
|
+
this.baseEncode = baseEncode;
|
|
28146
|
+
}
|
|
28147
|
+
encode(bytes) {
|
|
28148
|
+
if (bytes instanceof Uint8Array) {
|
|
28149
|
+
return `${this.prefix}${this.baseEncode(bytes)}`;
|
|
28150
|
+
} else {
|
|
28151
|
+
throw Error("Unknown type, must be binary type");
|
|
28152
|
+
}
|
|
28153
|
+
}
|
|
28154
|
+
};
|
|
28155
|
+
var Decoder3 = class {
|
|
28156
|
+
name;
|
|
28157
|
+
prefix;
|
|
28158
|
+
baseDecode;
|
|
28159
|
+
prefixCodePoint;
|
|
28160
|
+
constructor(name, prefix, baseDecode) {
|
|
28161
|
+
this.name = name;
|
|
28162
|
+
this.prefix = prefix;
|
|
28163
|
+
const prefixCodePoint = prefix.codePointAt(0);
|
|
28164
|
+
if (prefixCodePoint === void 0) {
|
|
28165
|
+
throw new Error("Invalid prefix character");
|
|
28166
|
+
}
|
|
28167
|
+
this.prefixCodePoint = prefixCodePoint;
|
|
28168
|
+
this.baseDecode = baseDecode;
|
|
28169
|
+
}
|
|
28170
|
+
decode(text) {
|
|
28171
|
+
if (typeof text === "string") {
|
|
28172
|
+
if (text.codePointAt(0) !== this.prefixCodePoint) {
|
|
28173
|
+
throw Error(`Unable to decode multibase string ${JSON.stringify(text)}, ${this.name} decoder only supports inputs prefixed with ${this.prefix}`);
|
|
28174
|
+
}
|
|
28175
|
+
return this.baseDecode(text.slice(this.prefix.length));
|
|
28176
|
+
} else {
|
|
28177
|
+
throw Error("Can only multibase decode strings");
|
|
28178
|
+
}
|
|
28179
|
+
}
|
|
28180
|
+
or(decoder) {
|
|
28181
|
+
return or3(this, decoder);
|
|
28182
|
+
}
|
|
28183
|
+
};
|
|
28184
|
+
var ComposedDecoder3 = class {
|
|
28185
|
+
decoders;
|
|
28186
|
+
constructor(decoders) {
|
|
28187
|
+
this.decoders = decoders;
|
|
28188
|
+
}
|
|
28189
|
+
or(decoder) {
|
|
28190
|
+
return or3(this, decoder);
|
|
28191
|
+
}
|
|
28192
|
+
decode(input) {
|
|
28193
|
+
const prefix = input[0];
|
|
28194
|
+
const decoder = this.decoders[prefix];
|
|
28195
|
+
if (decoder != null) {
|
|
28196
|
+
return decoder.decode(input);
|
|
28197
|
+
} else {
|
|
28198
|
+
throw RangeError(`Unable to decode multibase string ${JSON.stringify(input)}, only inputs prefixed with ${Object.keys(this.decoders)} are supported`);
|
|
28199
|
+
}
|
|
28200
|
+
}
|
|
28201
|
+
};
|
|
28202
|
+
function or3(left, right) {
|
|
28203
|
+
return new ComposedDecoder3({
|
|
28204
|
+
...left.decoders ?? { [left.prefix]: left },
|
|
28205
|
+
...right.decoders ?? { [right.prefix]: right }
|
|
28206
|
+
});
|
|
28207
|
+
}
|
|
28208
|
+
var Codec3 = class {
|
|
28209
|
+
name;
|
|
28210
|
+
prefix;
|
|
28211
|
+
baseEncode;
|
|
28212
|
+
baseDecode;
|
|
28213
|
+
encoder;
|
|
28214
|
+
decoder;
|
|
28215
|
+
constructor(name, prefix, baseEncode, baseDecode) {
|
|
28216
|
+
this.name = name;
|
|
28217
|
+
this.prefix = prefix;
|
|
28218
|
+
this.baseEncode = baseEncode;
|
|
28219
|
+
this.baseDecode = baseDecode;
|
|
28220
|
+
this.encoder = new Encoder3(name, prefix, baseEncode);
|
|
28221
|
+
this.decoder = new Decoder3(name, prefix, baseDecode);
|
|
28222
|
+
}
|
|
28223
|
+
encode(input) {
|
|
28224
|
+
return this.encoder.encode(input);
|
|
28225
|
+
}
|
|
28226
|
+
decode(input) {
|
|
28227
|
+
return this.decoder.decode(input);
|
|
28228
|
+
}
|
|
28229
|
+
};
|
|
28230
|
+
function from3({ name, prefix, encode: encode32, decode: decode52 }) {
|
|
28231
|
+
return new Codec3(name, prefix, encode32, decode52);
|
|
28232
|
+
}
|
|
28233
|
+
function baseX3({ name, prefix, alphabet }) {
|
|
28234
|
+
const { encode: encode32, decode: decode52 } = base_x_default3(alphabet, name);
|
|
28235
|
+
return from3({
|
|
28236
|
+
prefix,
|
|
28237
|
+
name,
|
|
28238
|
+
encode: encode32,
|
|
28239
|
+
decode: (text) => coerce4(decode52(text))
|
|
28240
|
+
});
|
|
28241
|
+
}
|
|
28242
|
+
function decode9(string, alphabetIdx, bitsPerChar, name) {
|
|
28243
|
+
let end = string.length;
|
|
28244
|
+
while (string[end - 1] === "=") {
|
|
28245
|
+
--end;
|
|
28246
|
+
}
|
|
28247
|
+
const out = new Uint8Array(end * bitsPerChar / 8 | 0);
|
|
28248
|
+
let bits = 0;
|
|
28249
|
+
let buffer = 0;
|
|
28250
|
+
let written = 0;
|
|
28251
|
+
for (let i = 0; i < end; ++i) {
|
|
28252
|
+
const value = alphabetIdx[string[i]];
|
|
28253
|
+
if (value === void 0) {
|
|
28254
|
+
throw new SyntaxError(`Non-${name} character`);
|
|
28255
|
+
}
|
|
28256
|
+
buffer = buffer << bitsPerChar | value;
|
|
28257
|
+
bits += bitsPerChar;
|
|
28258
|
+
if (bits >= 8) {
|
|
28259
|
+
bits -= 8;
|
|
28260
|
+
out[written++] = 255 & buffer >> bits;
|
|
28261
|
+
}
|
|
28262
|
+
}
|
|
28263
|
+
if (bits >= bitsPerChar || (255 & buffer << 8 - bits) !== 0) {
|
|
28264
|
+
throw new SyntaxError("Unexpected end of data");
|
|
28265
|
+
}
|
|
28266
|
+
return out;
|
|
28267
|
+
}
|
|
28268
|
+
function encode5(data, alphabet, bitsPerChar) {
|
|
28269
|
+
const pad = alphabet[alphabet.length - 1] === "=";
|
|
28270
|
+
const mask = (1 << bitsPerChar) - 1;
|
|
28271
|
+
let out = "";
|
|
28272
|
+
let bits = 0;
|
|
28273
|
+
let buffer = 0;
|
|
28274
|
+
for (let i = 0; i < data.length; ++i) {
|
|
28275
|
+
buffer = buffer << 8 | data[i];
|
|
28276
|
+
bits += 8;
|
|
28277
|
+
while (bits > bitsPerChar) {
|
|
28278
|
+
bits -= bitsPerChar;
|
|
28279
|
+
out += alphabet[mask & buffer >> bits];
|
|
28280
|
+
}
|
|
28281
|
+
}
|
|
28282
|
+
if (bits !== 0) {
|
|
28283
|
+
out += alphabet[mask & buffer << bitsPerChar - bits];
|
|
28284
|
+
}
|
|
28285
|
+
if (pad) {
|
|
28286
|
+
while ((out.length * bitsPerChar & 7) !== 0) {
|
|
28287
|
+
out += "=";
|
|
28288
|
+
}
|
|
28289
|
+
}
|
|
28290
|
+
return out;
|
|
28291
|
+
}
|
|
28292
|
+
function createAlphabetIdx3(alphabet) {
|
|
28293
|
+
const alphabetIdx = {};
|
|
28294
|
+
for (let i = 0; i < alphabet.length; ++i) {
|
|
28295
|
+
alphabetIdx[alphabet[i]] = i;
|
|
28296
|
+
}
|
|
28297
|
+
return alphabetIdx;
|
|
28298
|
+
}
|
|
28299
|
+
function rfc46483({ name, prefix, bitsPerChar, alphabet }) {
|
|
28300
|
+
const alphabetIdx = createAlphabetIdx3(alphabet);
|
|
28301
|
+
return from3({
|
|
28302
|
+
prefix,
|
|
28303
|
+
name,
|
|
28304
|
+
encode(input) {
|
|
28305
|
+
return encode5(input, alphabet, bitsPerChar);
|
|
28306
|
+
},
|
|
28307
|
+
decode(input) {
|
|
28308
|
+
return decode9(input, alphabetIdx, bitsPerChar, name);
|
|
28309
|
+
}
|
|
28310
|
+
});
|
|
28311
|
+
}
|
|
28312
|
+
var base323 = rfc46483({
|
|
28313
|
+
prefix: "b",
|
|
28314
|
+
name: "base32",
|
|
28315
|
+
alphabet: "abcdefghijklmnopqrstuvwxyz234567",
|
|
28316
|
+
bitsPerChar: 5
|
|
28317
|
+
});
|
|
28318
|
+
var base32upper3 = rfc46483({
|
|
28319
|
+
prefix: "B",
|
|
28320
|
+
name: "base32upper",
|
|
28321
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
|
|
28322
|
+
bitsPerChar: 5
|
|
28323
|
+
});
|
|
28324
|
+
var base32pad3 = rfc46483({
|
|
28325
|
+
prefix: "c",
|
|
28326
|
+
name: "base32pad",
|
|
28327
|
+
alphabet: "abcdefghijklmnopqrstuvwxyz234567=",
|
|
28328
|
+
bitsPerChar: 5
|
|
28329
|
+
});
|
|
28330
|
+
var base32padupper3 = rfc46483({
|
|
28331
|
+
prefix: "C",
|
|
28332
|
+
name: "base32padupper",
|
|
28333
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
|
|
28334
|
+
bitsPerChar: 5
|
|
28335
|
+
});
|
|
28336
|
+
var base32hex3 = rfc46483({
|
|
28337
|
+
prefix: "v",
|
|
28338
|
+
name: "base32hex",
|
|
28339
|
+
alphabet: "0123456789abcdefghijklmnopqrstuv",
|
|
28340
|
+
bitsPerChar: 5
|
|
28341
|
+
});
|
|
28342
|
+
var base32hexupper3 = rfc46483({
|
|
28343
|
+
prefix: "V",
|
|
28344
|
+
name: "base32hexupper",
|
|
28345
|
+
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
|
|
28346
|
+
bitsPerChar: 5
|
|
28347
|
+
});
|
|
28348
|
+
var base32hexpad3 = rfc46483({
|
|
28349
|
+
prefix: "t",
|
|
28350
|
+
name: "base32hexpad",
|
|
28351
|
+
alphabet: "0123456789abcdefghijklmnopqrstuv=",
|
|
28352
|
+
bitsPerChar: 5
|
|
28353
|
+
});
|
|
28354
|
+
var base32hexpadupper3 = rfc46483({
|
|
28355
|
+
prefix: "T",
|
|
28356
|
+
name: "base32hexpadupper",
|
|
28357
|
+
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV=",
|
|
28358
|
+
bitsPerChar: 5
|
|
28359
|
+
});
|
|
28360
|
+
var base32z3 = rfc46483({
|
|
28361
|
+
prefix: "h",
|
|
28362
|
+
name: "base32z",
|
|
28363
|
+
alphabet: "ybndrfg8ejkmcpqxot1uwisza345h769",
|
|
28364
|
+
bitsPerChar: 5
|
|
28365
|
+
});
|
|
28366
|
+
var base363 = baseX3({
|
|
28367
|
+
prefix: "k",
|
|
28368
|
+
name: "base36",
|
|
28369
|
+
alphabet: "0123456789abcdefghijklmnopqrstuvwxyz"
|
|
28370
|
+
});
|
|
28371
|
+
var base36upper3 = baseX3({
|
|
28372
|
+
prefix: "K",
|
|
28373
|
+
name: "base36upper",
|
|
28374
|
+
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
28375
|
+
});
|
|
28376
|
+
var base58btc3 = baseX3({
|
|
28377
|
+
name: "base58btc",
|
|
28378
|
+
prefix: "z",
|
|
28379
|
+
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
28380
|
+
});
|
|
28381
|
+
var base58flickr3 = baseX3({
|
|
28382
|
+
name: "base58flickr",
|
|
28383
|
+
prefix: "Z",
|
|
28384
|
+
alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
|
|
28385
|
+
});
|
|
28386
|
+
var encode_13 = encode22;
|
|
28387
|
+
var MSB3 = 128;
|
|
28388
|
+
var REST3 = 127;
|
|
28389
|
+
var MSBALL3 = ~REST3;
|
|
28390
|
+
var INT3 = Math.pow(2, 31);
|
|
28391
|
+
function encode22(num, out, offset) {
|
|
28392
|
+
out = out || [];
|
|
28393
|
+
offset = offset || 0;
|
|
28394
|
+
var oldOffset = offset;
|
|
28395
|
+
while (num >= INT3) {
|
|
28396
|
+
out[offset++] = num & 255 | MSB3;
|
|
28397
|
+
num /= 128;
|
|
28398
|
+
}
|
|
28399
|
+
while (num & MSBALL3) {
|
|
28400
|
+
out[offset++] = num & 255 | MSB3;
|
|
28401
|
+
num >>>= 7;
|
|
28402
|
+
}
|
|
28403
|
+
out[offset] = num | 0;
|
|
28404
|
+
encode22.bytes = offset - oldOffset + 1;
|
|
28405
|
+
return out;
|
|
28406
|
+
}
|
|
28407
|
+
var decode22 = read3;
|
|
28408
|
+
var MSB$13 = 128;
|
|
28409
|
+
var REST$13 = 127;
|
|
28410
|
+
function read3(buf, offset) {
|
|
28411
|
+
var res = 0, offset = offset || 0, shift = 0, counter = offset, b, l = buf.length;
|
|
28412
|
+
do {
|
|
28413
|
+
if (counter >= l) {
|
|
28414
|
+
read3.bytes = 0;
|
|
28415
|
+
throw new RangeError("Could not decode varint");
|
|
28416
|
+
}
|
|
28417
|
+
b = buf[counter++];
|
|
28418
|
+
res += shift < 28 ? (b & REST$13) << shift : (b & REST$13) * Math.pow(2, shift);
|
|
28419
|
+
shift += 7;
|
|
28420
|
+
} while (b >= MSB$13);
|
|
28421
|
+
read3.bytes = counter - offset;
|
|
28422
|
+
return res;
|
|
28423
|
+
}
|
|
28424
|
+
var N13 = Math.pow(2, 7);
|
|
28425
|
+
var N23 = Math.pow(2, 14);
|
|
28426
|
+
var N33 = Math.pow(2, 21);
|
|
28427
|
+
var N43 = Math.pow(2, 28);
|
|
28428
|
+
var N53 = Math.pow(2, 35);
|
|
28429
|
+
var N63 = Math.pow(2, 42);
|
|
28430
|
+
var N73 = Math.pow(2, 49);
|
|
28431
|
+
var N83 = Math.pow(2, 56);
|
|
28432
|
+
var N93 = Math.pow(2, 63);
|
|
28433
|
+
var length3 = function(value) {
|
|
28434
|
+
return value < N13 ? 1 : value < N23 ? 2 : value < N33 ? 3 : value < N43 ? 4 : value < N53 ? 5 : value < N63 ? 6 : value < N73 ? 7 : value < N83 ? 8 : value < N93 ? 9 : 10;
|
|
28435
|
+
};
|
|
28436
|
+
var varint3 = {
|
|
28437
|
+
encode: encode_13,
|
|
28438
|
+
decode: decode22,
|
|
28439
|
+
encodingLength: length3
|
|
28440
|
+
};
|
|
28441
|
+
var _brrp_varint3 = varint3;
|
|
28442
|
+
var varint_default3 = _brrp_varint3;
|
|
28443
|
+
function decode32(data, offset = 0) {
|
|
28444
|
+
const code22 = varint_default3.decode(data, offset);
|
|
28445
|
+
return [code22, varint_default3.decode.bytes];
|
|
28446
|
+
}
|
|
28447
|
+
function encodeTo3(int, target, offset = 0) {
|
|
28448
|
+
varint_default3.encode(int, target, offset);
|
|
28449
|
+
return target;
|
|
28450
|
+
}
|
|
28451
|
+
function encodingLength3(int) {
|
|
28452
|
+
return varint_default3.encodingLength(int);
|
|
28453
|
+
}
|
|
28454
|
+
function create3(code22, digest2) {
|
|
28455
|
+
const size = digest2.byteLength;
|
|
28456
|
+
const sizeOffset = encodingLength3(code22);
|
|
28457
|
+
const digestOffset = sizeOffset + encodingLength3(size);
|
|
28458
|
+
const bytes = new Uint8Array(digestOffset + size);
|
|
28459
|
+
encodeTo3(code22, bytes, 0);
|
|
28460
|
+
encodeTo3(size, bytes, sizeOffset);
|
|
28461
|
+
bytes.set(digest2, digestOffset);
|
|
28462
|
+
return new Digest3(code22, size, digest2, bytes);
|
|
28463
|
+
}
|
|
28464
|
+
function decode42(multihash) {
|
|
28465
|
+
const bytes = coerce4(multihash);
|
|
28466
|
+
const [code22, sizeOffset] = decode32(bytes);
|
|
28467
|
+
const [size, digestOffset] = decode32(bytes.subarray(sizeOffset));
|
|
28468
|
+
const digest2 = bytes.subarray(sizeOffset + digestOffset);
|
|
28469
|
+
if (digest2.byteLength !== size) {
|
|
28470
|
+
throw new Error("Incorrect length");
|
|
28471
|
+
}
|
|
28472
|
+
return new Digest3(code22, size, digest2, bytes);
|
|
28473
|
+
}
|
|
28474
|
+
function equals22(a, b) {
|
|
28475
|
+
if (a === b) {
|
|
28476
|
+
return true;
|
|
28477
|
+
} else {
|
|
28478
|
+
const data = b;
|
|
28479
|
+
return a.code === data.code && a.size === data.size && data.bytes instanceof Uint8Array && equals5(a.bytes, data.bytes);
|
|
28480
|
+
}
|
|
28481
|
+
}
|
|
28482
|
+
var Digest3 = class {
|
|
28483
|
+
code;
|
|
28484
|
+
size;
|
|
28485
|
+
digest;
|
|
28486
|
+
bytes;
|
|
28487
|
+
/**
|
|
28488
|
+
* Creates a multihash digest.
|
|
28489
|
+
*/
|
|
28490
|
+
constructor(code22, size, digest2, bytes) {
|
|
28491
|
+
this.code = code22;
|
|
28492
|
+
this.size = size;
|
|
28493
|
+
this.digest = digest2;
|
|
28494
|
+
this.bytes = bytes;
|
|
28495
|
+
}
|
|
28496
|
+
};
|
|
28497
|
+
function format3(link2, base22) {
|
|
28498
|
+
const { bytes, version } = link2;
|
|
28499
|
+
switch (version) {
|
|
28500
|
+
case 0:
|
|
28501
|
+
return toStringV03(bytes, baseCache3(link2), base22 ?? base58btc3.encoder);
|
|
28502
|
+
default:
|
|
28503
|
+
return toStringV13(bytes, baseCache3(link2), base22 ?? base323.encoder);
|
|
28504
|
+
}
|
|
28505
|
+
}
|
|
28506
|
+
var cache3 = /* @__PURE__ */ new WeakMap();
|
|
28507
|
+
function baseCache3(cid) {
|
|
28508
|
+
const baseCache22 = cache3.get(cid);
|
|
28509
|
+
if (baseCache22 == null) {
|
|
28510
|
+
const baseCache32 = /* @__PURE__ */ new Map();
|
|
28511
|
+
cache3.set(cid, baseCache32);
|
|
28512
|
+
return baseCache32;
|
|
28513
|
+
}
|
|
28514
|
+
return baseCache22;
|
|
28515
|
+
}
|
|
28516
|
+
var CID3 = class _CID3 {
|
|
28517
|
+
code;
|
|
28518
|
+
version;
|
|
28519
|
+
multihash;
|
|
28520
|
+
bytes;
|
|
28521
|
+
"/";
|
|
28522
|
+
/**
|
|
28523
|
+
* @param version - Version of the CID
|
|
28524
|
+
* @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
28525
|
+
* @param multihash - (Multi)hash of the of the content.
|
|
28526
|
+
*/
|
|
28527
|
+
constructor(version, code22, multihash, bytes) {
|
|
28528
|
+
this.code = code22;
|
|
28529
|
+
this.version = version;
|
|
28530
|
+
this.multihash = multihash;
|
|
28531
|
+
this.bytes = bytes;
|
|
28532
|
+
this["/"] = bytes;
|
|
28533
|
+
}
|
|
28534
|
+
/**
|
|
28535
|
+
* Signalling `cid.asCID === cid` has been replaced with `cid['/'] === cid.bytes`
|
|
28536
|
+
* please either use `CID.asCID(cid)` or switch to new signalling mechanism
|
|
28537
|
+
*
|
|
28538
|
+
* @deprecated
|
|
28539
|
+
*/
|
|
28540
|
+
get asCID() {
|
|
28541
|
+
return this;
|
|
28542
|
+
}
|
|
28543
|
+
// ArrayBufferView
|
|
28544
|
+
get byteOffset() {
|
|
28545
|
+
return this.bytes.byteOffset;
|
|
28546
|
+
}
|
|
28547
|
+
// ArrayBufferView
|
|
28548
|
+
get byteLength() {
|
|
28549
|
+
return this.bytes.byteLength;
|
|
28550
|
+
}
|
|
28551
|
+
toV0() {
|
|
28552
|
+
switch (this.version) {
|
|
28553
|
+
case 0: {
|
|
28554
|
+
return this;
|
|
28555
|
+
}
|
|
28556
|
+
case 1: {
|
|
28557
|
+
const { code: code22, multihash } = this;
|
|
28558
|
+
if (code22 !== DAG_PB_CODE3) {
|
|
28559
|
+
throw new Error("Cannot convert a non dag-pb CID to CIDv0");
|
|
28560
|
+
}
|
|
28561
|
+
if (multihash.code !== SHA_256_CODE3) {
|
|
28562
|
+
throw new Error("Cannot convert non sha2-256 multihash CID to CIDv0");
|
|
28563
|
+
}
|
|
28564
|
+
return _CID3.createV0(multihash);
|
|
28565
|
+
}
|
|
28566
|
+
default: {
|
|
28567
|
+
throw Error(`Can not convert CID version ${this.version} to version 0. This is a bug please report`);
|
|
28568
|
+
}
|
|
28569
|
+
}
|
|
28570
|
+
}
|
|
28571
|
+
toV1() {
|
|
28572
|
+
switch (this.version) {
|
|
28573
|
+
case 0: {
|
|
28574
|
+
const { code: code22, digest: digest2 } = this.multihash;
|
|
28575
|
+
const multihash = create3(code22, digest2);
|
|
28576
|
+
return _CID3.createV1(this.code, multihash);
|
|
28577
|
+
}
|
|
28578
|
+
case 1: {
|
|
28579
|
+
return this;
|
|
28580
|
+
}
|
|
28581
|
+
default: {
|
|
28582
|
+
throw Error(`Can not convert CID version ${this.version} to version 1. This is a bug please report`);
|
|
28583
|
+
}
|
|
28584
|
+
}
|
|
28585
|
+
}
|
|
28586
|
+
equals(other) {
|
|
28587
|
+
return _CID3.equals(this, other);
|
|
28588
|
+
}
|
|
28589
|
+
static equals(self, other) {
|
|
28590
|
+
const unknown = other;
|
|
28591
|
+
return unknown != null && self.code === unknown.code && self.version === unknown.version && equals22(self.multihash, unknown.multihash);
|
|
28592
|
+
}
|
|
28593
|
+
toString(base22) {
|
|
28594
|
+
return format3(this, base22);
|
|
28595
|
+
}
|
|
28596
|
+
toJSON() {
|
|
28597
|
+
return { "/": format3(this) };
|
|
28598
|
+
}
|
|
28599
|
+
link() {
|
|
28600
|
+
return this;
|
|
28601
|
+
}
|
|
28602
|
+
[Symbol.toStringTag] = "CID";
|
|
28603
|
+
// Legacy
|
|
28604
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
28605
|
+
return `CID(${this.toString()})`;
|
|
28606
|
+
}
|
|
28607
|
+
/**
|
|
28608
|
+
* Takes any input `value` and returns a `CID` instance if it was
|
|
28609
|
+
* a `CID` otherwise returns `null`. If `value` is instanceof `CID`
|
|
28610
|
+
* it will return value back. If `value` is not instance of this CID
|
|
28611
|
+
* class, but is compatible CID it will return new instance of this
|
|
28612
|
+
* `CID` class. Otherwise returns null.
|
|
28613
|
+
*
|
|
28614
|
+
* This allows two different incompatible versions of CID library to
|
|
28615
|
+
* co-exist and interop as long as binary interface is compatible.
|
|
28616
|
+
*/
|
|
28617
|
+
static asCID(input) {
|
|
28618
|
+
if (input == null) {
|
|
28619
|
+
return null;
|
|
28620
|
+
}
|
|
28621
|
+
const value = input;
|
|
28622
|
+
if (value instanceof _CID3) {
|
|
28623
|
+
return value;
|
|
28624
|
+
} else if (value["/"] != null && value["/"] === value.bytes || value.asCID === value) {
|
|
28625
|
+
const { version, code: code22, multihash, bytes } = value;
|
|
28626
|
+
return new _CID3(version, code22, multihash, bytes ?? encodeCID3(version, code22, multihash.bytes));
|
|
28627
|
+
} else if (value[cidSymbol3] === true) {
|
|
28628
|
+
const { version, multihash, code: code22 } = value;
|
|
28629
|
+
const digest2 = decode42(multihash);
|
|
28630
|
+
return _CID3.create(version, code22, digest2);
|
|
28631
|
+
} else {
|
|
28632
|
+
return null;
|
|
28633
|
+
}
|
|
28634
|
+
}
|
|
28635
|
+
/**
|
|
28636
|
+
* @param version - Version of the CID
|
|
28637
|
+
* @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
28638
|
+
* @param digest - (Multi)hash of the of the content.
|
|
28639
|
+
*/
|
|
28640
|
+
static create(version, code22, digest2) {
|
|
28641
|
+
if (typeof code22 !== "number") {
|
|
28642
|
+
throw new Error("String codecs are no longer supported");
|
|
28643
|
+
}
|
|
28644
|
+
if (!(digest2.bytes instanceof Uint8Array)) {
|
|
28645
|
+
throw new Error("Invalid digest");
|
|
28646
|
+
}
|
|
28647
|
+
switch (version) {
|
|
28648
|
+
case 0: {
|
|
28649
|
+
if (code22 !== DAG_PB_CODE3) {
|
|
28650
|
+
throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE3}) block encoding`);
|
|
28651
|
+
} else {
|
|
28652
|
+
return new _CID3(version, code22, digest2, digest2.bytes);
|
|
28653
|
+
}
|
|
28654
|
+
}
|
|
28655
|
+
case 1: {
|
|
28656
|
+
const bytes = encodeCID3(version, code22, digest2.bytes);
|
|
28657
|
+
return new _CID3(version, code22, digest2, bytes);
|
|
28658
|
+
}
|
|
28659
|
+
default: {
|
|
28660
|
+
throw new Error("Invalid version");
|
|
28661
|
+
}
|
|
28662
|
+
}
|
|
28663
|
+
}
|
|
28664
|
+
/**
|
|
28665
|
+
* Simplified version of `create` for CIDv0.
|
|
28666
|
+
*/
|
|
28667
|
+
static createV0(digest2) {
|
|
28668
|
+
return _CID3.create(0, DAG_PB_CODE3, digest2);
|
|
28669
|
+
}
|
|
28670
|
+
/**
|
|
28671
|
+
* Simplified version of `create` for CIDv1.
|
|
28672
|
+
*
|
|
28673
|
+
* @param code - Content encoding format code.
|
|
28674
|
+
* @param digest - Multihash of the content.
|
|
28675
|
+
*/
|
|
28676
|
+
static createV1(code22, digest2) {
|
|
28677
|
+
return _CID3.create(1, code22, digest2);
|
|
28678
|
+
}
|
|
28679
|
+
/**
|
|
28680
|
+
* Decoded a CID from its binary representation. The byte array must contain
|
|
28681
|
+
* only the CID with no additional bytes.
|
|
28682
|
+
*
|
|
28683
|
+
* An error will be thrown if the bytes provided do not contain a valid
|
|
28684
|
+
* binary representation of a CID.
|
|
28685
|
+
*/
|
|
28686
|
+
static decode(bytes) {
|
|
28687
|
+
const [cid, remainder] = _CID3.decodeFirst(bytes);
|
|
28688
|
+
if (remainder.length !== 0) {
|
|
28689
|
+
throw new Error("Incorrect length");
|
|
28690
|
+
}
|
|
28691
|
+
return cid;
|
|
28692
|
+
}
|
|
28693
|
+
/**
|
|
28694
|
+
* Decoded a CID from its binary representation at the beginning of a byte
|
|
28695
|
+
* array.
|
|
28696
|
+
*
|
|
28697
|
+
* Returns an array with the first element containing the CID and the second
|
|
28698
|
+
* element containing the remainder of the original byte array. The remainder
|
|
28699
|
+
* will be a zero-length byte array if the provided bytes only contained a
|
|
28700
|
+
* binary CID representation.
|
|
28701
|
+
*/
|
|
28702
|
+
static decodeFirst(bytes) {
|
|
28703
|
+
const specs = _CID3.inspectBytes(bytes);
|
|
28704
|
+
const prefixSize = specs.size - specs.multihashSize;
|
|
28705
|
+
const multihashBytes = coerce4(bytes.subarray(prefixSize, prefixSize + specs.multihashSize));
|
|
28706
|
+
if (multihashBytes.byteLength !== specs.multihashSize) {
|
|
28707
|
+
throw new Error("Incorrect length");
|
|
28708
|
+
}
|
|
28709
|
+
const digestBytes = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
|
|
28710
|
+
const digest2 = new Digest3(specs.multihashCode, specs.digestSize, digestBytes, multihashBytes);
|
|
28711
|
+
const cid = specs.version === 0 ? _CID3.createV0(digest2) : _CID3.createV1(specs.codec, digest2);
|
|
28712
|
+
return [cid, bytes.subarray(specs.size)];
|
|
28713
|
+
}
|
|
28714
|
+
/**
|
|
28715
|
+
* Inspect the initial bytes of a CID to determine its properties.
|
|
28716
|
+
*
|
|
28717
|
+
* Involves decoding up to 4 varints. Typically this will require only 4 to 6
|
|
28718
|
+
* bytes but for larger multicodec code values and larger multihash digest
|
|
28719
|
+
* lengths these varints can be quite large. It is recommended that at least
|
|
28720
|
+
* 10 bytes be made available in the `initialBytes` argument for a complete
|
|
28721
|
+
* inspection.
|
|
28722
|
+
*/
|
|
28723
|
+
static inspectBytes(initialBytes) {
|
|
28724
|
+
let offset = 0;
|
|
28725
|
+
const next = () => {
|
|
28726
|
+
const [i, length22] = decode32(initialBytes.subarray(offset));
|
|
28727
|
+
offset += length22;
|
|
28728
|
+
return i;
|
|
28729
|
+
};
|
|
28730
|
+
let version = next();
|
|
28731
|
+
let codec = DAG_PB_CODE3;
|
|
28732
|
+
if (version === 18) {
|
|
28733
|
+
version = 0;
|
|
28734
|
+
offset = 0;
|
|
28735
|
+
} else {
|
|
28736
|
+
codec = next();
|
|
28737
|
+
}
|
|
28738
|
+
if (version !== 0 && version !== 1) {
|
|
28739
|
+
throw new RangeError(`Invalid CID version ${version}`);
|
|
28740
|
+
}
|
|
28741
|
+
const prefixSize = offset;
|
|
28742
|
+
const multihashCode = next();
|
|
28743
|
+
const digestSize = next();
|
|
28744
|
+
const size = offset + digestSize;
|
|
28745
|
+
const multihashSize = size - prefixSize;
|
|
28746
|
+
return { version, codec, multihashCode, digestSize, multihashSize, size };
|
|
28747
|
+
}
|
|
28748
|
+
/**
|
|
28749
|
+
* Takes cid in a string representation and creates an instance. If `base`
|
|
28750
|
+
* decoder is not provided will use a default from the configuration. It will
|
|
28751
|
+
* throw an error if encoding of the CID is not compatible with supplied (or
|
|
28752
|
+
* a default decoder).
|
|
28753
|
+
*/
|
|
28754
|
+
static parse(source, base22) {
|
|
28755
|
+
const [prefix, bytes] = parseCIDtoBytes3(source, base22);
|
|
28756
|
+
const cid = _CID3.decode(bytes);
|
|
28757
|
+
if (cid.version === 0 && source[0] !== "Q") {
|
|
28758
|
+
throw Error("Version 0 CID string must not include multibase prefix");
|
|
28759
|
+
}
|
|
28760
|
+
baseCache3(cid).set(prefix, source);
|
|
28761
|
+
return cid;
|
|
28762
|
+
}
|
|
28763
|
+
};
|
|
28764
|
+
function parseCIDtoBytes3(source, base22) {
|
|
28765
|
+
switch (source[0]) {
|
|
28766
|
+
// CIDv0 is parsed differently
|
|
28767
|
+
case "Q": {
|
|
28768
|
+
const decoder = base22 ?? base58btc3;
|
|
28769
|
+
return [
|
|
28770
|
+
base58btc3.prefix,
|
|
28771
|
+
decoder.decode(`${base58btc3.prefix}${source}`)
|
|
28772
|
+
];
|
|
28773
|
+
}
|
|
28774
|
+
case base58btc3.prefix: {
|
|
28775
|
+
const decoder = base22 ?? base58btc3;
|
|
28776
|
+
return [base58btc3.prefix, decoder.decode(source)];
|
|
28777
|
+
}
|
|
28778
|
+
case base323.prefix: {
|
|
28779
|
+
const decoder = base22 ?? base323;
|
|
28780
|
+
return [base323.prefix, decoder.decode(source)];
|
|
28781
|
+
}
|
|
28782
|
+
case base363.prefix: {
|
|
28783
|
+
const decoder = base22 ?? base363;
|
|
28784
|
+
return [base363.prefix, decoder.decode(source)];
|
|
28785
|
+
}
|
|
28786
|
+
default: {
|
|
28787
|
+
if (base22 == null) {
|
|
28788
|
+
throw Error("To parse non base32, base36 or base58btc encoded CID multibase decoder must be provided");
|
|
28789
|
+
}
|
|
28790
|
+
return [source[0], base22.decode(source)];
|
|
28791
|
+
}
|
|
28792
|
+
}
|
|
28793
|
+
}
|
|
28794
|
+
function toStringV03(bytes, cache22, base22) {
|
|
28795
|
+
const { prefix } = base22;
|
|
28796
|
+
if (prefix !== base58btc3.prefix) {
|
|
28797
|
+
throw Error(`Cannot string encode V0 in ${base22.name} encoding`);
|
|
28798
|
+
}
|
|
28799
|
+
const cid = cache22.get(prefix);
|
|
28800
|
+
if (cid == null) {
|
|
28801
|
+
const cid2 = base22.encode(bytes).slice(1);
|
|
28802
|
+
cache22.set(prefix, cid2);
|
|
28803
|
+
return cid2;
|
|
28804
|
+
} else {
|
|
28805
|
+
return cid;
|
|
28806
|
+
}
|
|
28807
|
+
}
|
|
28808
|
+
function toStringV13(bytes, cache22, base22) {
|
|
28809
|
+
const { prefix } = base22;
|
|
28810
|
+
const cid = cache22.get(prefix);
|
|
28811
|
+
if (cid == null) {
|
|
28812
|
+
const cid2 = base22.encode(bytes);
|
|
28813
|
+
cache22.set(prefix, cid2);
|
|
28814
|
+
return cid2;
|
|
28815
|
+
} else {
|
|
28816
|
+
return cid;
|
|
28817
|
+
}
|
|
28818
|
+
}
|
|
28819
|
+
var DAG_PB_CODE3 = 112;
|
|
28820
|
+
var SHA_256_CODE3 = 18;
|
|
28821
|
+
function encodeCID3(version, code22, multihash) {
|
|
28822
|
+
const codeOffset = encodingLength3(version);
|
|
28823
|
+
const hashOffset = codeOffset + encodingLength3(code22);
|
|
28824
|
+
const bytes = new Uint8Array(hashOffset + multihash.byteLength);
|
|
28825
|
+
encodeTo3(version, bytes, 0);
|
|
28826
|
+
encodeTo3(code22, bytes, codeOffset);
|
|
28827
|
+
bytes.set(multihash, hashOffset);
|
|
28828
|
+
return bytes;
|
|
28829
|
+
}
|
|
28830
|
+
var cidSymbol3 = /* @__PURE__ */ Symbol.for("@ipld/js-cid/CID");
|
|
28831
|
+
var code2 = 85;
|
|
28832
|
+
var SHA256_CODE2 = 18;
|
|
28833
|
+
function isCanonicalRawCid2(cidString) {
|
|
28834
|
+
let cid;
|
|
28835
|
+
try {
|
|
28836
|
+
cid = CID3.parse(cidString);
|
|
28837
|
+
} catch {
|
|
28838
|
+
return false;
|
|
28839
|
+
}
|
|
28840
|
+
return cid.version === 1 && cid.code === code2 && cid.multihash.code === SHA256_CODE2 && cid.toString() === cidString;
|
|
28841
|
+
}
|
|
28842
|
+
var base642 = rfc46483({
|
|
28843
|
+
prefix: "m",
|
|
28844
|
+
name: "base64",
|
|
28845
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
|
28846
|
+
bitsPerChar: 6
|
|
28847
|
+
});
|
|
28848
|
+
var base64pad2 = rfc46483({
|
|
28849
|
+
prefix: "M",
|
|
28850
|
+
name: "base64pad",
|
|
28851
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
|
28852
|
+
bitsPerChar: 6
|
|
28853
|
+
});
|
|
28854
|
+
var base64url2 = rfc46483({
|
|
28855
|
+
prefix: "u",
|
|
28856
|
+
name: "base64url",
|
|
28857
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
|
|
28858
|
+
bitsPerChar: 6
|
|
28859
|
+
});
|
|
28860
|
+
var base64urlpad2 = rfc46483({
|
|
28861
|
+
prefix: "U",
|
|
28862
|
+
name: "base64urlpad",
|
|
28863
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",
|
|
28864
|
+
bitsPerChar: 6
|
|
28865
|
+
});
|
|
28866
|
+
function fromBase64Url2(text) {
|
|
28867
|
+
const bytes = base64url2.baseDecode(text);
|
|
28868
|
+
if (base64url2.baseEncode(bytes) !== text) {
|
|
28869
|
+
throw new TypeError("non-canonical base64url input");
|
|
28870
|
+
}
|
|
28871
|
+
return bytes;
|
|
28872
|
+
}
|
|
28873
|
+
function utf8Bytes2(text) {
|
|
28874
|
+
return new TextEncoder().encode(text);
|
|
28875
|
+
}
|
|
28876
|
+
var ED25519_MULTICODEC_PREFIX2 = Uint8Array.of(237, 1);
|
|
28877
|
+
function decodeBase64UrlOrNull2(value) {
|
|
28878
|
+
try {
|
|
28879
|
+
return fromBase64Url2(value);
|
|
28880
|
+
} catch {
|
|
28881
|
+
return null;
|
|
28882
|
+
}
|
|
28883
|
+
}
|
|
28884
|
+
var base64UrlString2 = () => external_exports.string().refine((value) => decodeBase64UrlOrNull2(value) !== null, {
|
|
28885
|
+
message: "expected strictly-decodable unpadded base64url"
|
|
28886
|
+
});
|
|
28887
|
+
function isCanonicalHttpsOrigin2(value) {
|
|
28888
|
+
let url;
|
|
28889
|
+
try {
|
|
28890
|
+
url = new URL(value);
|
|
28891
|
+
} catch {
|
|
28892
|
+
return false;
|
|
28893
|
+
}
|
|
28894
|
+
return url.protocol === "https:" && url.origin === value;
|
|
28895
|
+
}
|
|
28896
|
+
var sessionJwkCommonFields2 = {
|
|
28897
|
+
alg: external_exports.string().min(1).optional(),
|
|
28898
|
+
use: external_exports.string().min(1).optional(),
|
|
28899
|
+
key_ops: external_exports.array(external_exports.string().min(1)).optional(),
|
|
28900
|
+
kid: external_exports.string().min(1).optional(),
|
|
28901
|
+
ext: external_exports.boolean().optional()
|
|
28902
|
+
};
|
|
28903
|
+
var okpPrivateJwkSchema2 = external_exports.object({
|
|
28904
|
+
kty: external_exports.literal("OKP"),
|
|
28905
|
+
crv: external_exports.string().min(1),
|
|
28906
|
+
x: base64UrlString2(),
|
|
28907
|
+
d: base64UrlString2(),
|
|
28908
|
+
...sessionJwkCommonFields2
|
|
28909
|
+
}).strict();
|
|
28910
|
+
var ecPrivateJwkSchema2 = external_exports.object({
|
|
28911
|
+
kty: external_exports.literal("EC"),
|
|
28912
|
+
crv: external_exports.string().min(1),
|
|
28913
|
+
x: base64UrlString2(),
|
|
28914
|
+
y: base64UrlString2(),
|
|
28915
|
+
d: base64UrlString2(),
|
|
28916
|
+
...sessionJwkCommonFields2
|
|
28917
|
+
}).strict();
|
|
28918
|
+
var sessionJwkSchema2 = external_exports.discriminatedUnion("kty", [
|
|
28919
|
+
okpPrivateJwkSchema2,
|
|
28920
|
+
ecPrivateJwkSchema2
|
|
28921
|
+
]);
|
|
28922
|
+
var policyTargetSchema2 = external_exports.object({
|
|
28923
|
+
kind: external_exports.literal("policy"),
|
|
28924
|
+
policyCid: external_exports.string().min(1),
|
|
28925
|
+
/** Canonical policy bytes, base64url-encoded (bytes are not JSON). */
|
|
28926
|
+
policyBytes: base64UrlString2()
|
|
28927
|
+
}).strict();
|
|
28928
|
+
var bearerKeyTargetSchema2 = external_exports.object({
|
|
28929
|
+
kind: external_exports.literal("bearerKey"),
|
|
28930
|
+
sessionJwk: sessionJwkSchema2
|
|
28931
|
+
}).strict();
|
|
28932
|
+
var recipientDidTargetSchema2 = external_exports.object({
|
|
28933
|
+
kind: external_exports.literal("recipientDid"),
|
|
28934
|
+
did: external_exports.string().regex(/^did:[a-z0-9]+:.+$/, "expected a DID")
|
|
28935
|
+
}).strict();
|
|
28936
|
+
var authorizationTargetSchema2 = external_exports.discriminatedUnion("kind", [
|
|
28937
|
+
policyTargetSchema2,
|
|
28938
|
+
bearerKeyTargetSchema2,
|
|
28939
|
+
recipientDidTargetSchema2
|
|
28940
|
+
]);
|
|
28941
|
+
function isCanonicalResourcePath2(value) {
|
|
28942
|
+
if (value.length === 0) return false;
|
|
28943
|
+
if (/[\u0000-\u001f\u007f\\]/.test(value)) return false;
|
|
28944
|
+
if (/%2f|%5c|%2e/i.test(value)) return false;
|
|
28945
|
+
return value.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
28946
|
+
}
|
|
28947
|
+
function isCanonicalPathSegment2(value) {
|
|
28948
|
+
return isCanonicalResourcePath2(value) && !value.includes("/");
|
|
28949
|
+
}
|
|
28950
|
+
var resourceSelectorSchema2 = external_exports.object({
|
|
28951
|
+
kind: external_exports.union([external_exports.literal("exact"), external_exports.literal("prefix")]),
|
|
28952
|
+
path: external_exports.string().min(1)
|
|
28953
|
+
}).strict().superRefine((selector, ctx) => {
|
|
28954
|
+
const body = selector.kind === "prefix" && selector.path.endsWith("/") ? selector.path.slice(0, -1) : selector.path;
|
|
28955
|
+
if (!isCanonicalResourcePath2(body)) {
|
|
28956
|
+
ctx.addIssue({
|
|
28957
|
+
code: external_exports.ZodIssueCode.custom,
|
|
28958
|
+
path: ["path"],
|
|
28959
|
+
message: "expected a canonical resource path (non-empty segments, no . or .. segments, no //, no backslash, no %2f/%5c/%2e, no control chars)"
|
|
28960
|
+
});
|
|
28961
|
+
}
|
|
28962
|
+
});
|
|
28963
|
+
var targetSchema2 = external_exports.object({
|
|
28964
|
+
origin: external_exports.string().refine(isCanonicalHttpsOrigin2, {
|
|
28965
|
+
message: "expected a canonical https origin (https://host[:port], nothing else)"
|
|
28966
|
+
}),
|
|
28967
|
+
nodeAudience: external_exports.string().min(1),
|
|
28968
|
+
spaceId: external_exports.string().refine(isCanonicalPathSegment2, {
|
|
28969
|
+
message: "expected a single canonical path segment (spaceId joins the resource URI; separators/traversal would alias grants)"
|
|
28970
|
+
}),
|
|
28971
|
+
resource: resourceSelectorSchema2
|
|
28972
|
+
}).strict();
|
|
28973
|
+
var displaySchema2 = external_exports.object({
|
|
28974
|
+
senderName: external_exports.string().optional(),
|
|
28975
|
+
filename: external_exports.string().optional(),
|
|
28976
|
+
recipientHint: external_exports.string().optional(),
|
|
28977
|
+
/**
|
|
28978
|
+
* Presentation preference only (viewer spec §1): may narrow, never widen;
|
|
28979
|
+
* capabilities always win.
|
|
28980
|
+
*/
|
|
28981
|
+
mode: external_exports.union([external_exports.literal("document"), external_exports.literal("source"), external_exports.literal("folder")]).optional()
|
|
28982
|
+
}).strict();
|
|
28983
|
+
var contentPointerSchema2 = external_exports.object({
|
|
28984
|
+
cid: external_exports.string().refine(isCanonicalRawCid2, {
|
|
28985
|
+
message: "expected a canonical CIDv1 raw sha2-256 base32 CID"
|
|
28986
|
+
}),
|
|
28987
|
+
key: external_exports.string().refine((value) => decodeBase64UrlOrNull2(value)?.length === 32, {
|
|
28988
|
+
message: "expected base64url decoding to exactly 32 bytes"
|
|
28989
|
+
})
|
|
28990
|
+
}).strict();
|
|
28991
|
+
var signatureSchema2 = external_exports.object({
|
|
28992
|
+
/** did:key of the sender's ed25519 signing key. */
|
|
28993
|
+
signerDid: external_exports.string().regex(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/, "expected a did:key"),
|
|
28994
|
+
algorithm: external_exports.literal("Ed25519"),
|
|
28995
|
+
/** base64url-encoded ed25519 signature over the JCS bytes of all other fields. */
|
|
28996
|
+
value: external_exports.string().refine((value) => decodeBase64UrlOrNull2(value)?.length === 64, {
|
|
28997
|
+
message: "expected base64url decoding to exactly 64 bytes"
|
|
28998
|
+
})
|
|
28999
|
+
}).strict();
|
|
29000
|
+
var unsignedShareEnvelopeSchema2 = external_exports.object({
|
|
29001
|
+
version: external_exports.literal(1),
|
|
29002
|
+
shareId: external_exports.string().min(1),
|
|
29003
|
+
/** Full signed delegation chain, opaque serialized form. */
|
|
29004
|
+
delegation: external_exports.string().min(1),
|
|
29005
|
+
authorizationTarget: authorizationTargetSchema2,
|
|
29006
|
+
target: targetSchema2,
|
|
29007
|
+
display: displaySchema2,
|
|
29008
|
+
/** ISO 8601 UTC datetime. Advisory here; enforcement is the delegation's. */
|
|
29009
|
+
expiry: external_exports.string().datetime(),
|
|
29010
|
+
/** Bearer-slice sealed-content pointer (see contentPointerSchema). */
|
|
29011
|
+
content: contentPointerSchema2.optional()
|
|
29012
|
+
}).strict();
|
|
29013
|
+
var shareEnvelopeSchema2 = unsignedShareEnvelopeSchema2.extend({ signature: signatureSchema2 }).strict();
|
|
29014
|
+
var recipientMatcherSchema2 = external_exports.discriminatedUnion("kind", [
|
|
29015
|
+
external_exports.object({ kind: external_exports.literal("exactEmail"), value: external_exports.string().min(3).regex(/^[^@\s]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/) }).strict(),
|
|
29016
|
+
external_exports.object({ kind: external_exports.literal("emailDomain"), value: external_exports.string().regex(/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/) }).strict(),
|
|
29017
|
+
external_exports.object({ kind: external_exports.literal("recipientDid"), value: external_exports.string().regex(/^did:[a-z0-9]+:.+$/) }).strict(),
|
|
29018
|
+
external_exports.object({ kind: external_exports.literal("policyDigest"), value: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/) }).strict(),
|
|
29019
|
+
external_exports.object({ kind: external_exports.literal("bearer") }).strict()
|
|
29020
|
+
]);
|
|
29021
|
+
var shareActionSchema2 = external_exports.union([external_exports.literal("read"), external_exports.literal("list"), external_exports.literal("edit")]);
|
|
29022
|
+
var kvContentSourceSchema2 = external_exports.object({
|
|
29023
|
+
kind: external_exports.literal("kv"),
|
|
29024
|
+
space: external_exports.string().min(1),
|
|
29025
|
+
path: external_exports.string().min(1),
|
|
29026
|
+
action: external_exports.literal("tinycloud.kv/get")
|
|
29027
|
+
}).strict();
|
|
29028
|
+
var sqlContentSourceSchema2 = external_exports.object({
|
|
29029
|
+
kind: external_exports.literal("sql"),
|
|
29030
|
+
space: external_exports.string().min(1),
|
|
29031
|
+
database: external_exports.string().min(1),
|
|
29032
|
+
path: external_exports.string().min(1),
|
|
29033
|
+
statement: external_exports.string().min(1),
|
|
29034
|
+
arguments: external_exports.record(external_exports.string(), external_exports.number().int()),
|
|
29035
|
+
argumentsDigest: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
29036
|
+
action: external_exports.literal("tinycloud.sql/read")
|
|
29037
|
+
}).strict();
|
|
29038
|
+
var contentSourceSchema2 = external_exports.discriminatedUnion("kind", [kvContentSourceSchema2, sqlContentSourceSchema2]);
|
|
29039
|
+
var v2TargetSchema2 = external_exports.object({
|
|
29040
|
+
origin: external_exports.string().refine(isCanonicalHttpsOrigin2, { message: "expected a canonical https origin" }),
|
|
29041
|
+
nodeAudience: external_exports.string().min(1),
|
|
29042
|
+
spaceId: external_exports.string().refine(isCanonicalPathSegment2, { message: "expected a canonical space id" })
|
|
29043
|
+
}).strict();
|
|
29044
|
+
var shareDecryptionSchema2 = external_exports.object({
|
|
29045
|
+
networkId: external_exports.string().min(1),
|
|
29046
|
+
action: external_exports.literal("tinycloud.encryption/decrypt")
|
|
29047
|
+
}).strict();
|
|
29048
|
+
var ownerAuthoritySchema2 = external_exports.object({
|
|
29049
|
+
registrationCid: external_exports.string().min(1),
|
|
29050
|
+
shareCid: external_exports.string().min(1),
|
|
29051
|
+
envelopeCid: external_exports.string().min(1),
|
|
29052
|
+
enforcementDelegation: external_exports.record(external_exports.string(), external_exports.unknown()),
|
|
29053
|
+
outerEnvelope: external_exports.record(external_exports.string(), external_exports.unknown()),
|
|
29054
|
+
/** Node-signed registration evidence; required by trusted policy adapters. */
|
|
29055
|
+
registrationReceipt: external_exports.object({
|
|
29056
|
+
registration: external_exports.record(external_exports.string(), external_exports.unknown()),
|
|
29057
|
+
proof: external_exports.record(external_exports.string(), external_exports.unknown())
|
|
29058
|
+
}).strict().optional()
|
|
29059
|
+
}).strict();
|
|
29060
|
+
var contentMetadataSchema2 = external_exports.object({
|
|
29061
|
+
mediaType: external_exports.string().min(1).max(128).optional(),
|
|
29062
|
+
byteLength: external_exports.number().int().nonnegative().max(100 * 1024 * 1024).optional(),
|
|
29063
|
+
filename: external_exports.string().min(1).max(255).optional(),
|
|
29064
|
+
encoding: external_exports.literal("utf-8").optional(),
|
|
29065
|
+
/** Encrypted presentation discriminator. The fixed entry point is index.html. */
|
|
29066
|
+
artifact: external_exports.literal("html").optional()
|
|
29067
|
+
}).strict();
|
|
29068
|
+
var deliveryEmailSchema2 = external_exports.string().email();
|
|
29069
|
+
var unsignedShareEnvelopeV2BaseSchema2 = external_exports.object({
|
|
29070
|
+
version: external_exports.literal(2),
|
|
29071
|
+
shareId: external_exports.string().min(1),
|
|
29072
|
+
recipientMatcher: recipientMatcherSchema2,
|
|
29073
|
+
deliveryEmail: deliveryEmailSchema2.optional(),
|
|
29074
|
+
actions: external_exports.array(shareActionSchema2).min(1).max(3),
|
|
29075
|
+
resource: resourceSelectorSchema2,
|
|
29076
|
+
target: v2TargetSchema2,
|
|
29077
|
+
delegationCid: external_exports.string().min(1),
|
|
29078
|
+
authorityMaterialHandle: external_exports.string().min(1),
|
|
29079
|
+
authorityMaterialDigest: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
29080
|
+
decryption: shareDecryptionSchema2.optional(),
|
|
29081
|
+
contentSource: contentSourceSchema2,
|
|
29082
|
+
contentSourceDigest: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
29083
|
+
authorizationTarget: authorizationTargetSchema2,
|
|
29084
|
+
display: displaySchema2,
|
|
29085
|
+
expiry: external_exports.string().datetime(),
|
|
29086
|
+
encrypted: external_exports.boolean(),
|
|
29087
|
+
content: contentPointerSchema2.optional(),
|
|
29088
|
+
metadata: contentMetadataSchema2,
|
|
29089
|
+
ownerAuthority: ownerAuthoritySchema2.optional()
|
|
29090
|
+
}).strict();
|
|
29091
|
+
function validateV2Invariants2(value, ctx) {
|
|
29092
|
+
const actions = [...value.actions];
|
|
29093
|
+
if (new Set(actions).size !== actions.length) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["actions"], message: "actions must be unique" });
|
|
29094
|
+
if (actions.some((action, index) => action !== ["read", "list", "edit"].filter((candidate) => actions.includes(candidate))[index])) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["actions"], message: "actions must be canonically ordered" });
|
|
29095
|
+
if (!value.encrypted && value.recipientMatcher.kind !== "policyDigest") ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["recipientMatcher"], message: "safe plaintext must carry only a matcher digest" });
|
|
29096
|
+
if (!value.encrypted && value.authorizationTarget.kind !== "policy") ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["encrypted"], message: "unencrypted content requires a policy target" });
|
|
29097
|
+
if (!value.encrypted && value.content !== void 0) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["content"], message: "policy-only plaintext cannot carry content" });
|
|
29098
|
+
if (value.encrypted && (value.metadata.mediaType === void 0 || value.metadata.filename === void 0 || value.metadata.byteLength === void 0)) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["metadata"], message: "encrypted shares must describe their content" });
|
|
29099
|
+
if (!value.encrypted && Object.keys(value.metadata).length !== 0) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["metadata"], message: "policy-only plaintext cannot describe content" });
|
|
29100
|
+
if (!value.encrypted && value.metadata.encoding !== void 0) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["metadata", "encoding"], message: "policy-only plaintext cannot carry content encoding" });
|
|
29101
|
+
if (value.metadata.artifact === "html" && (!value.encrypted || value.resource.kind !== "prefix" || !value.actions.includes("read") || !value.actions.includes("list"))) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["metadata", "artifact"], message: "html artifacts require an encrypted readable prefix" });
|
|
29102
|
+
if (!value.encrypted && (value.display.senderName !== void 0 || value.display.filename !== void 0 || value.display.recipientHint !== void 0)) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["display"], message: "policy-only plaintext cannot carry display metadata" });
|
|
29103
|
+
if (!value.encrypted && value.deliveryEmail !== void 0) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["deliveryEmail"], message: "policy-only plaintext cannot carry delivery metadata" });
|
|
29104
|
+
if (value.recipientMatcher.kind === "exactEmail" && value.deliveryEmail !== void 0 && value.deliveryEmail !== value.recipientMatcher.value) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["deliveryEmail"], message: "delivery email must match the exact matcher" });
|
|
29105
|
+
if (value.recipientMatcher.kind === "emailDomain" && value.deliveryEmail !== void 0 && value.deliveryEmail.toLowerCase().endsWith(`@${value.recipientMatcher.value}`) === false) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["deliveryEmail"], message: "delivery email must belong to the matcher domain" });
|
|
29106
|
+
if (value.contentSource.kind === "kv" && value.contentSource.action !== "tinycloud.kv/get") ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource"], message: "source action mismatch" });
|
|
29107
|
+
if (value.contentSource.kind === "sql" && value.contentSource.action !== "tinycloud.sql/read") ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource"], message: "source action mismatch" });
|
|
29108
|
+
}
|
|
29109
|
+
var unsignedShareEnvelopeV2Schema2 = unsignedShareEnvelopeV2BaseSchema2.superRefine(validateV2Invariants2);
|
|
29110
|
+
var shareEnvelopeV2Schema2 = unsignedShareEnvelopeV2BaseSchema2.extend({ signature: signatureSchema2 }).strict().superRefine(validateV2Invariants2);
|
|
29111
|
+
var unifiedResourceSchema2 = external_exports.string().refine((value) => {
|
|
29112
|
+
const marker = value.indexOf("/kv/");
|
|
29113
|
+
if (marker < 1) return false;
|
|
29114
|
+
const space = value.slice(0, marker);
|
|
29115
|
+
const legacy = space.startsWith("tinycloud://");
|
|
29116
|
+
if (legacy ? /[:/?#%]/.test(space.slice("tinycloud://".length)) : !space.startsWith("tinycloud:") || /[/?#%]/.test(space)) return false;
|
|
29117
|
+
const path = value.slice(marker + 4);
|
|
29118
|
+
return !path.startsWith("/") && !path.endsWith("/") && !path.includes("//") && path.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
29119
|
+
}, { message: "expected canonical TinyCloud KV resource" });
|
|
29120
|
+
var unifiedEncryptionNetworkSchema2 = external_exports.string().refine((value) => {
|
|
29121
|
+
if (!value.startsWith("urn:tinycloud:encryption:")) return false;
|
|
29122
|
+
const rest = value.slice("urn:tinycloud:encryption:".length);
|
|
29123
|
+
const separator = rest.lastIndexOf(":");
|
|
29124
|
+
const owner = separator < 0 ? "" : rest.slice(0, separator);
|
|
29125
|
+
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
29126
|
+
return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
|
|
29127
|
+
}, { message: "expected canonical TinyCloud encryption network" });
|
|
29128
|
+
var unifiedKvCapabilitySchema2 = external_exports.object({
|
|
29129
|
+
kind: external_exports.literal("kv"),
|
|
29130
|
+
resource: unifiedResourceSchema2,
|
|
29131
|
+
selector: external_exports.union([external_exports.literal("exact"), external_exports.literal("prefix")]),
|
|
29132
|
+
actions: external_exports.array(external_exports.union([
|
|
29133
|
+
external_exports.literal("tinycloud.kv/get"),
|
|
29134
|
+
external_exports.literal("tinycloud.kv/list"),
|
|
29135
|
+
external_exports.literal("tinycloud.kv/metadata"),
|
|
29136
|
+
external_exports.literal("tinycloud.kv/put")
|
|
29137
|
+
])).min(1)
|
|
29138
|
+
}).strict();
|
|
29139
|
+
var unifiedEncryptionCapabilitySchema2 = external_exports.object({
|
|
29140
|
+
kind: external_exports.literal("encryption"),
|
|
29141
|
+
resource: unifiedEncryptionNetworkSchema2,
|
|
29142
|
+
action: external_exports.literal("tinycloud.encryption/decrypt")
|
|
29143
|
+
}).strict();
|
|
29144
|
+
var unifiedCapabilitySchema2 = external_exports.union([unifiedKvCapabilitySchema2, unifiedEncryptionCapabilitySchema2]);
|
|
29145
|
+
var unifiedContentSourceSchema2 = external_exports.object({
|
|
29146
|
+
shareId: external_exports.string().min(1),
|
|
29147
|
+
kvResource: unifiedResourceSchema2,
|
|
29148
|
+
selector: external_exports.union([external_exports.literal("exact"), external_exports.literal("prefix")]),
|
|
29149
|
+
encryptionNetwork: unifiedEncryptionNetworkSchema2,
|
|
29150
|
+
encryptedSymmetricKeyDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
29151
|
+
keyVersion: external_exports.number().int().positive(),
|
|
29152
|
+
mode: external_exports.union([external_exports.literal("mutable"), external_exports.literal("immutable")]),
|
|
29153
|
+
initialCiphertextDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/).optional()
|
|
29154
|
+
}).strict();
|
|
29155
|
+
var unifiedPolicyV1Schema2 = external_exports.object({
|
|
29156
|
+
schema: external_exports.literal("xyz.tinycloud.policy/policy/v1"),
|
|
29157
|
+
policyId: external_exports.string().regex(/^pol_[a-z2-7]+$/),
|
|
29158
|
+
ownerDid: external_exports.string().min(1),
|
|
29159
|
+
createdAt: external_exports.string().datetime({ offset: true }),
|
|
29160
|
+
expiresAt: external_exports.string().datetime({ offset: true }).optional(),
|
|
29161
|
+
contentSource: unifiedContentSourceSchema2,
|
|
29162
|
+
capabilityCeiling: external_exports.array(unifiedCapabilitySchema2).min(2),
|
|
29163
|
+
signature: external_exports.object({ suite: external_exports.string().min(1), signerDid: external_exports.string().min(1), value: external_exports.string().min(1) }).strict()
|
|
29164
|
+
}).strict();
|
|
29165
|
+
var policyCredentialRequirementV1Schema2 = external_exports.object({
|
|
29166
|
+
type: external_exports.literal("TinyCloudPolicyCredentialRequirement"),
|
|
29167
|
+
version: external_exports.literal(1),
|
|
29168
|
+
requirementDigest: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
29169
|
+
descriptorDigest: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
29170
|
+
issuerDid: external_exports.string().min(1),
|
|
29171
|
+
issuerKid: external_exports.string().min(1),
|
|
29172
|
+
profile: external_exports.object({ id: external_exports.string().min(1), version: external_exports.literal(1) }).strict(),
|
|
29173
|
+
credentialType: external_exports.object({ id: external_exports.string().min(1), version: external_exports.literal(1) }).strict()
|
|
29174
|
+
}).strict();
|
|
29175
|
+
var unifiedPolicyV2Schema2 = external_exports.object({
|
|
29176
|
+
schema: external_exports.literal("xyz.tinycloud.policy/policy/v2"),
|
|
29177
|
+
policyId: external_exports.string().regex(/^pol_[a-z2-7]+$/),
|
|
29178
|
+
ownerDid: external_exports.string().min(1),
|
|
29179
|
+
createdAt: external_exports.string().datetime({ offset: true }),
|
|
29180
|
+
expiresAt: external_exports.string().datetime({ offset: true }).optional(),
|
|
29181
|
+
contentSource: unifiedContentSourceSchema2,
|
|
29182
|
+
capabilityCeiling: external_exports.array(unifiedCapabilitySchema2).min(2),
|
|
29183
|
+
credentialRequirement: policyCredentialRequirementV1Schema2,
|
|
29184
|
+
signature: external_exports.object({ suite: external_exports.literal("Ed25519"), signerDid: external_exports.string().min(1), value: external_exports.string().min(1) }).strict()
|
|
29185
|
+
}).strict();
|
|
29186
|
+
var unifiedPolicySchema2 = external_exports.discriminatedUnion("schema", [
|
|
29187
|
+
unifiedPolicyV1Schema2,
|
|
29188
|
+
unifiedPolicyV2Schema2
|
|
29189
|
+
]);
|
|
29190
|
+
var unifiedRootSchema2 = external_exports.object({
|
|
29191
|
+
cid: external_exports.string().min(1),
|
|
29192
|
+
authorization: external_exports.string().regex(/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/),
|
|
29193
|
+
role: external_exports.union([external_exports.literal("policy-authority"), external_exports.literal("policy-enforcement")])
|
|
29194
|
+
}).strict();
|
|
29195
|
+
var attestedEnforcerBindingV2Schema2 = external_exports.object({
|
|
29196
|
+
schema: external_exports.literal("xyz.tinycloud.policy/attested-enforcer/v2"),
|
|
29197
|
+
enforcerDid: external_exports.string().regex(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/),
|
|
29198
|
+
nodeAudience: external_exports.string().min(1),
|
|
29199
|
+
attestationBindingDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
29200
|
+
issuedAt: external_exports.string().datetime({ offset: true }),
|
|
29201
|
+
expiresAt: external_exports.string().datetime({ offset: true }),
|
|
29202
|
+
signature: external_exports.object({ suite: external_exports.literal("Ed25519"), signerDid: external_exports.string().min(1), value: base64UrlString2() }).strict()
|
|
29203
|
+
}).strict();
|
|
29204
|
+
var v3TargetSchema2 = external_exports.object({
|
|
29205
|
+
origin: external_exports.string().refine(isCanonicalHttpsOrigin2, { message: "expected a canonical https origin" }),
|
|
29206
|
+
nodeAudience: external_exports.string().min(1),
|
|
29207
|
+
spaceId: external_exports.string().refine(isCanonicalPathSegment2, { message: "expected a canonical space id" })
|
|
29208
|
+
}).strict();
|
|
29209
|
+
var unsignedShareEnvelopeV3BaseSchema2 = external_exports.object({
|
|
29210
|
+
version: external_exports.literal(3),
|
|
29211
|
+
shareId: external_exports.string().min(1),
|
|
29212
|
+
recipientMatcher: recipientMatcherSchema2,
|
|
29213
|
+
deliveryEmail: deliveryEmailSchema2.optional(),
|
|
29214
|
+
actions: external_exports.array(shareActionSchema2).min(1).max(3),
|
|
29215
|
+
resource: resourceSelectorSchema2,
|
|
29216
|
+
target: v3TargetSchema2,
|
|
29217
|
+
policy: unifiedPolicySchema2,
|
|
29218
|
+
policyCid: external_exports.string().min(1),
|
|
29219
|
+
policyRoot: unifiedRootSchema2,
|
|
29220
|
+
enforcementRoot: unifiedRootSchema2,
|
|
29221
|
+
attestedEnforcerBinding: attestedEnforcerBindingV2Schema2,
|
|
29222
|
+
contentSource: unifiedContentSourceSchema2,
|
|
29223
|
+
contentSourceDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
29224
|
+
encryptionNetwork: unifiedEncryptionNetworkSchema2,
|
|
29225
|
+
expiry: external_exports.string().datetime({ offset: true }),
|
|
29226
|
+
display: displaySchema2,
|
|
29227
|
+
encrypted: external_exports.literal(true),
|
|
29228
|
+
metadata: contentMetadataSchema2
|
|
29229
|
+
}).strict();
|
|
29230
|
+
function validateV3Invariants2(value, ctx) {
|
|
29231
|
+
const actions = [...value.actions];
|
|
29232
|
+
if (new Set(actions).size !== actions.length || actions.some((action, index) => action !== ["read", "list", "edit"].filter((candidate) => actions.includes(candidate))[index])) {
|
|
29233
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["actions"], message: "actions must be unique and canonically ordered" });
|
|
29234
|
+
}
|
|
29235
|
+
if (value.policyRoot.role !== "policy-authority" || value.enforcementRoot.role !== "policy-enforcement") {
|
|
29236
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policyRoot", "role"], message: "root roles are fixed" });
|
|
29237
|
+
}
|
|
29238
|
+
if (value.policyCid.length === 0 || value.policyCid === value.policyRoot.cid || value.policyCid === value.enforcementRoot.cid) {
|
|
29239
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policyCid"], message: "policy CID must be distinct from both roots" });
|
|
29240
|
+
}
|
|
29241
|
+
if (value.contentSource.encryptionNetwork !== value.encryptionNetwork) {
|
|
29242
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["encryptionNetwork"], message: "encryption network is not bound to the source" });
|
|
29243
|
+
}
|
|
29244
|
+
if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
|
|
29245
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
|
|
29246
|
+
}
|
|
29247
|
+
if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
|
|
29248
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
|
|
29249
|
+
}
|
|
29250
|
+
if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
|
|
29251
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
|
|
29252
|
+
}
|
|
29253
|
+
const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
|
|
29254
|
+
const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === value.encryptionNetwork && capability.action === "tinycloud.encryption/decrypt");
|
|
29255
|
+
if (value.policy.capabilityCeiling.length !== 2 || kvCapabilities.length !== 1 || decryptCapabilities.length !== 1 || kvCapabilities[0]?.resource !== value.contentSource.kvResource || kvCapabilities[0]?.selector !== value.contentSource.selector) {
|
|
29256
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain exact decrypt network" });
|
|
29257
|
+
}
|
|
29258
|
+
}
|
|
29259
|
+
var unsignedShareEnvelopeV3Schema2 = unsignedShareEnvelopeV3BaseSchema2.superRefine(validateV3Invariants2);
|
|
29260
|
+
var shareEnvelopeV3Schema2 = unsignedShareEnvelopeV3BaseSchema2.extend({ signature: signatureSchema2 }).strict().superRefine(validateV3Invariants2);
|
|
29261
|
+
var ENVELOPE_AAD_LABEL2 = "tinycloud-share-envelope-v1";
|
|
29262
|
+
var AAD2 = utf8Bytes2(ENVELOPE_AAD_LABEL2);
|
|
29263
|
+
var LABEL2 = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
29264
|
+
function isCanonicalEmailDomain2(value) {
|
|
29265
|
+
if (value.length === 0 || value.length > 253) return false;
|
|
29266
|
+
const labels = value.split(".");
|
|
29267
|
+
return labels.length >= 2 && labels.every((label) => LABEL2.test(label)) && !/^[0-9]+$/.test(labels.at(-1));
|
|
29268
|
+
}
|
|
29269
|
+
function canonicalMailbox2(value) {
|
|
29270
|
+
const email = value.trim().toLowerCase();
|
|
29271
|
+
const at = email.indexOf("@");
|
|
29272
|
+
if (at <= 0 || at !== email.lastIndexOf("@")) return void 0;
|
|
29273
|
+
const local = email.slice(0, at);
|
|
29274
|
+
const domain = email.slice(at + 1);
|
|
29275
|
+
if (local.length > 64 || !/^[a-z0-9#$&'*+/=?^_`{|}~-]+(?:\.[a-z0-9#$&'*+/=?^_`{|}~-]+)*$/.test(local) || !isCanonicalEmailDomain2(domain)) return void 0;
|
|
29276
|
+
return Object.freeze({ email, domain });
|
|
29277
|
+
}
|
|
29278
|
+
var MAX_INLINE_BYTES2 = 256 * 1024;
|
|
29279
|
+
|
|
29280
|
+
// src/commands/share.ts
|
|
29281
|
+
import { ProfileLockTimeoutError as ProfileLockTimeoutError3 } from "@tinycloud/operations/state";
|
|
29282
|
+
init_formatter();
|
|
29283
|
+
init_errors();
|
|
29284
|
+
|
|
29285
|
+
// src/share/output.ts
|
|
29286
|
+
function writeJson2(value) {
|
|
29287
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
29288
|
+
`);
|
|
29289
|
+
}
|
|
29290
|
+
function authorizationRequiredJson(result) {
|
|
29291
|
+
return {
|
|
29292
|
+
state: "authorization-required",
|
|
29293
|
+
method: result.method,
|
|
29294
|
+
next: "complete authorization through the configured authority adapter, then retry with the required proof"
|
|
29295
|
+
};
|
|
29296
|
+
}
|
|
29297
|
+
function publishHuman(result) {
|
|
29298
|
+
process.stdout.write(`${result.url}
|
|
29299
|
+
`);
|
|
29300
|
+
}
|
|
29301
|
+
function inspectHuman(result) {
|
|
29302
|
+
const metadata = result.metadata;
|
|
29303
|
+
process.stdout.write([
|
|
29304
|
+
`Share ${metadata.shareId}`,
|
|
29305
|
+
`File: ${metadata.display.filename ?? "unnamed"}`,
|
|
29306
|
+
`Target: ${metadata.target.kind === "bearer" ? "bearer (anyone with the complete link can read)" : metadata.target.kind}`,
|
|
29307
|
+
`Expires: ${metadata.expiresAt}`,
|
|
29308
|
+
`Resource: ${metadata.resource.path}`,
|
|
29309
|
+
`Link format: ${result.link.kind}`
|
|
29310
|
+
].join("\n") + "\n");
|
|
29311
|
+
}
|
|
29312
|
+
function receiveHuman(path) {
|
|
29313
|
+
process.stdout.write(`${path}
|
|
29314
|
+
`);
|
|
29315
|
+
}
|
|
29316
|
+
function receiveJson(result, path) {
|
|
29317
|
+
writeJson2({ protocol: "tinycloud-share", version: 1, path, metadata: result.metadata });
|
|
29318
|
+
}
|
|
29319
|
+
|
|
29320
|
+
// src/share/io.ts
|
|
29321
|
+
import { constants } from "fs";
|
|
29322
|
+
import { lstat as lstat3, mkdir as mkdir3, mkdtemp, open as open4, readFile as readFile9, realpath, stat as stat2, link, rename as rename3, rm as rm4, unlink } from "fs/promises";
|
|
29323
|
+
import { randomBytes as randomBytes4 } from "crypto";
|
|
29324
|
+
import { basename as basename3, join as join6, resolve as resolve2, sep } from "path";
|
|
29325
|
+
init_errors();
|
|
29326
|
+
var MAX_SHARE_STDIN_BYTES = 100 * 1024 * 1024;
|
|
29327
|
+
var MAX_SHARE_URL_BYTES = 64 * 1024;
|
|
29328
|
+
async function readBoundedStdin(limit = MAX_SHARE_STDIN_BYTES) {
|
|
29329
|
+
if (!Number.isSafeInteger(limit) || limit <= 0) throw new Error("MAX_BYTES_EXCEEDED");
|
|
29330
|
+
const chunks = [];
|
|
29331
|
+
let total = 0;
|
|
29332
|
+
for await (const chunk of process.stdin) {
|
|
29333
|
+
const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
29334
|
+
total += bytes.byteLength;
|
|
29335
|
+
if (total > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
29336
|
+
chunks.push(bytes);
|
|
29337
|
+
}
|
|
29338
|
+
return new Uint8Array(Buffer.concat(chunks, total));
|
|
29339
|
+
}
|
|
29340
|
+
async function readBoundedUrlStdin() {
|
|
29341
|
+
const bytes = await readBoundedStdin(MAX_SHARE_URL_BYTES);
|
|
29342
|
+
const value = new TextDecoder("utf-8", { fatal: true }).decode(bytes).trim();
|
|
29343
|
+
if (value.length === 0 || /\s/.test(value)) throw new Error("INVALID_ARGUMENT");
|
|
29344
|
+
return value;
|
|
29345
|
+
}
|
|
29346
|
+
function safeFilename(value) {
|
|
29347
|
+
return shareFilename(value);
|
|
29348
|
+
}
|
|
29349
|
+
function shareFilename(value) {
|
|
29350
|
+
try {
|
|
29351
|
+
return canonicalShareFilename(value);
|
|
29352
|
+
} catch {
|
|
29353
|
+
throw new CLIError(
|
|
29354
|
+
"UNSAFE_FILENAME",
|
|
29355
|
+
hasUnsafeFilenameCodePoint(value) ? "filename contains control or invisible characters" : "filename must be one safe path segment",
|
|
29356
|
+
8
|
|
29357
|
+
);
|
|
29358
|
+
}
|
|
29359
|
+
}
|
|
29360
|
+
function shareInputFilename(input, name) {
|
|
29361
|
+
return shareFilename(name ?? (input === "-" ? "stdin.md" : basename3(resolve2(input))));
|
|
29362
|
+
}
|
|
29363
|
+
async function readShareInput(input, name, limit = MAX_SHARE_STDIN_BYTES) {
|
|
29364
|
+
const filename = shareInputFilename(input, name);
|
|
29365
|
+
if (input === "-") return { bytes: await readBoundedStdin(limit), filename };
|
|
29366
|
+
const path = resolve2(input);
|
|
29367
|
+
const info = await stat2(path);
|
|
29368
|
+
if (!info.isFile() || info.size > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
29369
|
+
const bytes = new Uint8Array(await readFile9(path));
|
|
29370
|
+
if (bytes.byteLength > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
29371
|
+
return { bytes, filename };
|
|
29372
|
+
}
|
|
29373
|
+
async function assertDirectory(path) {
|
|
29374
|
+
const absolute = resolve2(path);
|
|
29375
|
+
const segments = absolute.split(sep).filter(Boolean);
|
|
29376
|
+
let current = absolute.startsWith(sep) ? sep : "";
|
|
29377
|
+
for (const segment of segments) {
|
|
29378
|
+
current = current === sep ? join6(current, segment) : join6(current, segment);
|
|
29379
|
+
try {
|
|
29380
|
+
const info = await lstat3(current);
|
|
29381
|
+
if (info.isSymbolicLink()) {
|
|
29382
|
+
const canonical = await realpath(current);
|
|
29383
|
+
if (current !== "/tmp" && current !== "/var") throw new Error("OUTPUT_EXISTS");
|
|
29384
|
+
if (canonical !== `/private${current}`) throw new Error("OUTPUT_EXISTS");
|
|
29385
|
+
} else if (!info.isDirectory()) throw new Error("OUTPUT_EXISTS");
|
|
29386
|
+
} catch (error) {
|
|
29387
|
+
if (error.code !== "ENOENT") throw error;
|
|
29388
|
+
await mkdir3(current, { mode: 448 });
|
|
29389
|
+
const created = await lstat3(current);
|
|
29390
|
+
if (created.isSymbolicLink() || !created.isDirectory()) throw new Error("OUTPUT_EXISTS");
|
|
29391
|
+
}
|
|
29392
|
+
}
|
|
29393
|
+
}
|
|
29394
|
+
async function writeShareOutput(directory, filename, bytes, force) {
|
|
29395
|
+
const outputDirectory = resolve2(directory);
|
|
29396
|
+
await assertDirectory(outputDirectory);
|
|
29397
|
+
const safeName = safeFilename(filename);
|
|
29398
|
+
const directoryHandle = await open4(outputDirectory, constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0));
|
|
29399
|
+
const stableDirectory = await realpath(outputDirectory);
|
|
29400
|
+
const outputPath = join6(stableDirectory, safeName);
|
|
29401
|
+
const directoryIdentity = await directoryHandle.stat();
|
|
29402
|
+
const assertStableDirectory = async () => {
|
|
29403
|
+
const current = await stat2(stableDirectory);
|
|
29404
|
+
if (current.dev !== directoryIdentity.dev || current.ino !== directoryIdentity.ino) throw new Error("OUTPUT_EXISTS");
|
|
29405
|
+
};
|
|
29406
|
+
await assertStableDirectory();
|
|
29407
|
+
const stagingDirectory = await mkdtemp(join6(stableDirectory, ".tinycloud-share-stage-"));
|
|
29408
|
+
const stagingInfo = await lstat3(stagingDirectory);
|
|
29409
|
+
if (!stagingInfo.isDirectory() || (stagingInfo.mode & 511) !== 448) throw new Error("OUTPUT_EXISTS");
|
|
29410
|
+
const stagingPath = join6(stagingDirectory, `.tinycloud-share-${randomBytes4(16).toString("hex")}.tmp`);
|
|
29411
|
+
let temporaryPath;
|
|
29412
|
+
let handle;
|
|
29413
|
+
try {
|
|
29414
|
+
await assertStableDirectory();
|
|
29415
|
+
try {
|
|
29416
|
+
const existing = await lstat3(outputPath);
|
|
29417
|
+
if (existing.isSymbolicLink()) throw new Error("UNSAFE_FILENAME");
|
|
29418
|
+
} catch (error) {
|
|
29419
|
+
if (error.code !== "ENOENT") throw error;
|
|
29420
|
+
}
|
|
29421
|
+
temporaryPath = stagingPath;
|
|
29422
|
+
handle = await open4(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0), 384);
|
|
29423
|
+
await handle.writeFile(bytes);
|
|
29424
|
+
await handle.close();
|
|
29425
|
+
handle = void 0;
|
|
29426
|
+
await assertStableDirectory();
|
|
29427
|
+
if (force) {
|
|
29428
|
+
await rename3(temporaryPath, outputPath);
|
|
29429
|
+
} else {
|
|
29430
|
+
await link(temporaryPath, outputPath);
|
|
29431
|
+
await unlink(temporaryPath);
|
|
29432
|
+
}
|
|
29433
|
+
await assertStableDirectory();
|
|
29434
|
+
} catch (error) {
|
|
29435
|
+
if (error.code === "EEXIST") throw new Error("OUTPUT_EXISTS");
|
|
29436
|
+
if (error.code === "ELOOP") throw new Error("UNSAFE_FILENAME");
|
|
29437
|
+
throw error;
|
|
29438
|
+
} finally {
|
|
29439
|
+
await handle?.close();
|
|
29440
|
+
try {
|
|
29441
|
+
if (temporaryPath !== void 0) await unlink(temporaryPath);
|
|
29442
|
+
} catch {
|
|
29443
|
+
}
|
|
29444
|
+
await rm4(stagingDirectory, { recursive: true, force: true });
|
|
29445
|
+
await directoryHandle.close();
|
|
29446
|
+
}
|
|
29447
|
+
return join6(outputDirectory, safeName);
|
|
29448
|
+
}
|
|
29449
|
+
|
|
29450
|
+
// src/share/errors.ts
|
|
29451
|
+
var SharePublishAuthorityError = class extends Error {
|
|
29452
|
+
constructor(failure) {
|
|
29453
|
+
super(failure.kind);
|
|
29454
|
+
this.failure = failure;
|
|
29455
|
+
this.name = "SharePublishAuthorityError";
|
|
29456
|
+
}
|
|
29457
|
+
};
|
|
29458
|
+
var ShareHistoryRetryError = class extends Error {
|
|
29459
|
+
constructor(profile) {
|
|
29460
|
+
super("sender history changed during the operation");
|
|
29461
|
+
this.profile = profile;
|
|
29462
|
+
this.name = "ShareHistoryRetryError";
|
|
29463
|
+
}
|
|
29464
|
+
code = "SHARE_HISTORY_RETRY";
|
|
29465
|
+
};
|
|
29466
|
+
|
|
29467
|
+
// src/commands/share.ts
|
|
29468
|
+
var SHARE_ORIGIN = "https://share.tinycloud.xyz";
|
|
29469
|
+
var NOTIFY_WINDOW_MESSAGE = "Share notification authorization expired (at share expiry or 5 minutes after publication); publish a new share and invite the recipient then.\n";
|
|
29470
|
+
var shareServices = {};
|
|
29471
|
+
function parseShareTarget(value) {
|
|
29472
|
+
if (value === "anyone" || value === "bearer") return { kind: "bearer" };
|
|
29473
|
+
if (value.startsWith("did:")) return { kind: "recipientDid", did: value };
|
|
29474
|
+
if (value.startsWith("domain:")) return canonicalMailboxTarget({ kind: "emailDomain", domain: value.slice("domain:".length) });
|
|
29475
|
+
if (value.startsWith("email:")) return canonicalMailboxTarget({ kind: "email", address: value.slice("email:".length) });
|
|
29476
|
+
if (value.includes("@")) return canonicalMailboxTarget({ kind: "email", address: value });
|
|
29477
|
+
throw new CLIError("INVALID_ARGUMENT", "--to must be anyone, a did:, an email address, or domain:example.com", 2);
|
|
29478
|
+
}
|
|
29479
|
+
function canonicalMailboxTarget(target) {
|
|
29480
|
+
try {
|
|
29481
|
+
return normalizeShareTarget(target);
|
|
29482
|
+
} catch (error) {
|
|
29483
|
+
throw new CLIError("INVALID_ARGUMENT", error instanceof TypeError ? error.message : "share recipient is invalid", 2);
|
|
29484
|
+
}
|
|
29485
|
+
}
|
|
29486
|
+
function shareCliError(error, operation = "publish") {
|
|
29487
|
+
if (error instanceof CLIError) return error;
|
|
29488
|
+
if (error instanceof ProfileLockTimeoutError3) return wrapError(error);
|
|
29489
|
+
if (error instanceof ShareHistoryRetryError) {
|
|
29490
|
+
return new CLIError(
|
|
29491
|
+
"SHARE_HISTORY_RETRY",
|
|
29492
|
+
`sender history for profile ${JSON.stringify(error.profile)} changed or disappeared during this command`,
|
|
29493
|
+
1,
|
|
29494
|
+
{ hint: `Retry this command with --profile ${JSON.stringify(error.profile)}. If this was a revoke, check its node state first: revocation may already have succeeded.` }
|
|
29495
|
+
);
|
|
29496
|
+
}
|
|
27703
29497
|
if (error instanceof SharePublishAuthorityError) {
|
|
27704
29498
|
const failure = error.failure;
|
|
27705
29499
|
const profileName = "profileName" in failure ? failure.profileName : void 0;
|
|
@@ -27741,6 +29535,10 @@ function shareCliError(error) {
|
|
|
27741
29535
|
if (failure.kind === "registry-unavailable") {
|
|
27742
29536
|
return new CLIError("UNAVAILABLE", "the TinyCloud location registry could not be reached, so nothing was shared; try again shortly", 4);
|
|
27743
29537
|
}
|
|
29538
|
+
if (failure.kind === "node-info-unavailable") {
|
|
29539
|
+
const outcome = operation === "publish" ? "nothing was shared and no invitation was sent" : "no invitation was sent";
|
|
29540
|
+
return new CLIError("UNAVAILABLE", `could not verify TinyCloud node 1.17.3 domain delivery support; ${outcome}. Check the node and retry`, 4);
|
|
29541
|
+
}
|
|
27744
29542
|
if (failure.kind === "registry-rejected") {
|
|
27745
29543
|
return new CLIError("REGISTRY_REJECTED", "the TinyCloud location registry rejected this session's location record, so nothing was shared; retrying will not help. Log in again, and report the problem if it persists", 6);
|
|
27746
29544
|
}
|
|
@@ -27757,14 +29555,14 @@ function shareCliError(error) {
|
|
|
27757
29555
|
}
|
|
27758
29556
|
if (error instanceof SharePublishError) {
|
|
27759
29557
|
const exit = error.code === "authority-required" ? 3 : error.code === "max-bytes-exceeded" ? 7 : 2;
|
|
27760
|
-
const
|
|
27761
|
-
return new CLIError(
|
|
29558
|
+
const code3 = error.code === "authority-required" ? "AUTH_REQUIRED" : error.code === "max-bytes-exceeded" ? "MAX_BYTES_EXCEEDED" : "INVALID_ARGUMENT";
|
|
29559
|
+
return new CLIError(code3, error.message, exit);
|
|
27762
29560
|
}
|
|
27763
29561
|
if (error instanceof ShareReceiveError) {
|
|
27764
29562
|
const verification = /* @__PURE__ */ new Set(["cid-mismatch", "decrypt-failed", "envelope-invalid", "origin-mismatch", "signature-invalid", "capability-invalid", "content-integrity-failed"]);
|
|
27765
29563
|
const exit = error.code === "max-bytes-exceeded" ? 7 : verification.has(error.code) ? 5 : error.code === "expired" || error.code === "fetch-failed" ? 4 : error.code === "invalid-link" || error.code === "unsupported-target" ? 2 : 2;
|
|
27766
|
-
const
|
|
27767
|
-
return new CLIError(
|
|
29564
|
+
const code3 = error.code === "fetch-failed" ? "NOT_FOUND" : error.code.replaceAll("-", "_").toUpperCase();
|
|
29565
|
+
return new CLIError(code3, error.message, exit);
|
|
27768
29566
|
}
|
|
27769
29567
|
const message = error instanceof Error ? error.message : String(error);
|
|
27770
29568
|
const nodeCode = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
@@ -27809,8 +29607,33 @@ function expires(value) {
|
|
|
27809
29607
|
}
|
|
27810
29608
|
async function rememberPublishedShare(result) {
|
|
27811
29609
|
const record = historyRecordForPublishedShare(result);
|
|
27812
|
-
if (shareServices.records
|
|
27813
|
-
|
|
29610
|
+
if (shareServices.records === void 0) return { record, recorded: false };
|
|
29611
|
+
try {
|
|
29612
|
+
await shareServices.records.put(record);
|
|
29613
|
+
return { record, recorded: true };
|
|
29614
|
+
} catch {
|
|
29615
|
+
process.stderr.write("Warning: share was published but not recorded in sender history; future share list, share notify, and share revoke by ID will not find it.\n");
|
|
29616
|
+
return { record, recorded: false };
|
|
29617
|
+
}
|
|
29618
|
+
}
|
|
29619
|
+
async function notifyRecordedShare(record, recipient, adapter, storage) {
|
|
29620
|
+
const result = await notifyShare({ shareId: record.shareId, recipient, record, adapter, checkDeliveryWindow: true });
|
|
29621
|
+
if (result.state !== "partial-failure" && storage !== void 0) {
|
|
29622
|
+
const mailbox = canonicalMailbox2(recipient).email;
|
|
29623
|
+
if (!record.deliveredRecipients?.includes(mailbox)) {
|
|
29624
|
+
try {
|
|
29625
|
+
if (storage.update === void 0) throw new Error("atomic sender history update is unavailable");
|
|
29626
|
+
const updated = await storage.update(record.shareId, (current) => ({
|
|
29627
|
+
...current,
|
|
29628
|
+
deliveredRecipients: current.deliveredRecipients?.includes(mailbox) ? current.deliveredRecipients : [...current.deliveredRecipients ?? [], mailbox]
|
|
29629
|
+
}));
|
|
29630
|
+
if (updated === void 0) throw new Error("sender history record was removed");
|
|
29631
|
+
} catch {
|
|
29632
|
+
process.stderr.write("Warning: delivery succeeded, but could not record its confirmation in sender history.\n");
|
|
29633
|
+
}
|
|
29634
|
+
}
|
|
29635
|
+
}
|
|
29636
|
+
return result;
|
|
27814
29637
|
}
|
|
27815
29638
|
function byteLimit(value) {
|
|
27816
29639
|
if (value === void 0) return void 0;
|
|
@@ -27837,7 +29660,7 @@ function assertAggregateInputLimit(inputs, maxBytes) {
|
|
|
27837
29660
|
}
|
|
27838
29661
|
function registerShareCommand(program) {
|
|
27839
29662
|
const share = program.command("share").description("Publish and consume TinyCloud Share links");
|
|
27840
|
-
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", "
|
|
29663
|
+
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", "Email an exact-email recipient, or a domain mailbox on node 1.17.3+").option("--notify-to <address>", "Mailbox to invite for --to domain:<name> --notify (node 1.17.3+)").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) => {
|
|
27841
29664
|
try {
|
|
27842
29665
|
const json = jsonOutput(options, command);
|
|
27843
29666
|
const maxBytes = byteLimit(options.maxBytes);
|
|
@@ -27851,7 +29674,21 @@ function registerShareCommand(program) {
|
|
|
27851
29674
|
if (options.prefix && target.kind === "bearer") throw new CLIError("INVALID_ARGUMENT", "--prefix requires an addressed target", 2);
|
|
27852
29675
|
if (inputs.length > 1 && target.kind === "bearer") throw new CLIError("UNSUPPORTED_LINK", "multiple files require an addressed target", 2);
|
|
27853
29676
|
if (inputs.length > 1 && !options.prefix) throw new CLIError("INVALID_ARGUMENT", "multiple files require --prefix", 2);
|
|
27854
|
-
if (options.notify === true &&
|
|
29677
|
+
if (options.notify === true && !actions.includes("read")) throw new CLIError("INVALID_ARGUMENT", "--notify requires the read action; nothing was shared", 2);
|
|
29678
|
+
if (options.notifyTo !== void 0 && (options.notify !== true || target.kind !== "emailDomain")) {
|
|
29679
|
+
throw new CLIError("INVALID_ARGUMENT", "--notify-to requires --to domain:<name> --notify", 2);
|
|
29680
|
+
}
|
|
29681
|
+
let notifyRecipient;
|
|
29682
|
+
if (options.notify === true && target.kind === "email") notifyRecipient = target.address;
|
|
29683
|
+
else if (options.notify === true && target.kind === "emailDomain") {
|
|
29684
|
+
const mailbox = options.notifyTo === void 0 ? void 0 : canonicalMailbox2(options.notifyTo);
|
|
29685
|
+
if (mailbox === void 0 || mailbox.domain !== target.domain) {
|
|
29686
|
+
throw new CLIError("INVALID_ARGUMENT", "--to domain:<name> --notify requires --notify-to <email> at that exact domain (node 1.17.3+)", 2);
|
|
29687
|
+
}
|
|
29688
|
+
notifyRecipient = mailbox.email;
|
|
29689
|
+
} else if (options.notify === true) {
|
|
29690
|
+
throw new CLIError("INVALID_ARGUMENT", "--notify requires an email target, or a domain target with --notify-to on node 1.17.3+", 2);
|
|
29691
|
+
}
|
|
27855
29692
|
const result = await publishTargetShare({
|
|
27856
29693
|
source: inputs[0].bytes,
|
|
27857
29694
|
filename: inputs[0].filename,
|
|
@@ -27876,16 +29713,17 @@ function registerShareCommand(program) {
|
|
|
27876
29713
|
}
|
|
27877
29714
|
throw new CLIError(result.method === "openkey-device" ? "DEVICE_AUTH_REQUIRED" : "CLAIM_REQUIRED", "recipient authorization is required; continue through the configured authority adapter", 6);
|
|
27878
29715
|
}
|
|
27879
|
-
const record = await rememberPublishedShare(result);
|
|
27880
|
-
|
|
29716
|
+
const { record, recorded } = await rememberPublishedShare(result);
|
|
29717
|
+
let notification;
|
|
29718
|
+
if (notifyRecipient !== void 0) {
|
|
27881
29719
|
if (shareServices.delivery === void 0) throw new CLIError("AUTH_REQUIRED", "delivery authority is not configured", 3);
|
|
27882
|
-
|
|
27883
|
-
|
|
27884
|
-
if (
|
|
29720
|
+
notification = await notifyRecordedShare(record, notifyRecipient, shareServices.delivery, recorded ? shareServices.records : void 0);
|
|
29721
|
+
if (notification.state === "partial-failure") process.exitCode = 9;
|
|
29722
|
+
if (notification.reason === "delivery-window-expired") process.stderr.write(NOTIFY_WINDOW_MESSAGE);
|
|
27885
29723
|
}
|
|
27886
29724
|
if (result.metadata.expiryClamped === true) process.stderr.write(`Share expiry clamped to session expiry (${result.metadata.expiresAt}).
|
|
27887
29725
|
`);
|
|
27888
|
-
if (json) writeJson2({ ...redactPublishedShare(result), expiryClamped: result.metadata.expiryClamped === true });
|
|
29726
|
+
if (json) writeJson2({ ...redactPublishedShare(result), expiryClamped: result.metadata.expiryClamped === true, ...notification === void 0 ? {} : { notification } });
|
|
27889
29727
|
else publishHuman(result);
|
|
27890
29728
|
} catch (error) {
|
|
27891
29729
|
handleError(shareCliError(error));
|
|
@@ -27972,20 +29810,31 @@ function registerShareCommand(program) {
|
|
|
27972
29810
|
handleError(shareCliError(error));
|
|
27973
29811
|
}
|
|
27974
29812
|
});
|
|
27975
|
-
share.command("notify <id>").description("Retry idempotent delivery
|
|
29813
|
+
share.command("notify <id>").description("Retry idempotent delivery within 5 minutes of publication; after that publish a new share").requiredOption("--to <address>", "Recipient email").option("--json", "Print versioned JSON").action(async (id, options, command) => {
|
|
27976
29814
|
try {
|
|
27977
29815
|
const json = jsonOutput(options, command);
|
|
27978
29816
|
if (shareServices.delivery === void 0) throw new CLIError("AUTH_REQUIRED", "delivery authority is not configured", 3);
|
|
27979
29817
|
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
27980
29818
|
const record = await shareServices.records.get(id);
|
|
27981
29819
|
if (record === void 0) throw new CLIError("NOT_FOUND", "share not found", 4);
|
|
27982
|
-
|
|
29820
|
+
if (!record.actions.includes("tinycloud.kv/get")) {
|
|
29821
|
+
throw new CLIError("INVALID_ARGUMENT", "share notify requires a stored share with the read action; no invitation was sent", 2);
|
|
29822
|
+
}
|
|
29823
|
+
const mailbox = canonicalMailbox2(options.to);
|
|
29824
|
+
if (mailbox === void 0) throw new ShareNotifyError("recipient is invalid");
|
|
29825
|
+
if (!recipientMatchesShareRecord(record, mailbox.email)) throw new ShareNotifyError("recipient does not match the stored share target");
|
|
29826
|
+
if (record.recipientMatcher.kind === "emailDomain" && shareDeliveryWindowExpiresAt(record) > Date.now()) {
|
|
29827
|
+
if (shareServices.assertDomainDelivery === void 0) throw new CLIError("UNAVAILABLE", "could not verify TinyCloud node 1.17.3 domain delivery support; no invitation was sent", 4);
|
|
29828
|
+
await shareServices.assertDomainDelivery();
|
|
29829
|
+
}
|
|
29830
|
+
const result = await notifyRecordedShare(record, options.to, shareServices.delivery, shareServices.records);
|
|
27983
29831
|
if (json) writeJson2(result);
|
|
27984
29832
|
else process.stdout.write(`${result.state}
|
|
27985
29833
|
`);
|
|
29834
|
+
if (result.reason === "delivery-window-expired") process.stderr.write(NOTIFY_WINDOW_MESSAGE);
|
|
27986
29835
|
if (result.state === "partial-failure") process.exitCode = 9;
|
|
27987
29836
|
} catch (error) {
|
|
27988
|
-
handleError(shareCliError(error));
|
|
29837
|
+
handleError(shareCliError(error, "notify"));
|
|
27989
29838
|
}
|
|
27990
29839
|
});
|
|
27991
29840
|
share.command("revoke <id>").description("Revoke addressed shares; report bearer retention honestly").option("--ancestor", "Revoke the owner delegation ancestry").option("--json", "Print versioned JSON").action(async (id, options, command) => {
|
|
@@ -28030,7 +29879,7 @@ function registerSpaceCommand(program) {
|
|
|
28030
29879
|
const node = await ensureAuthenticated(ctx);
|
|
28031
29880
|
const result = await node.spaces.list();
|
|
28032
29881
|
if (!result.ok) {
|
|
28033
|
-
throw
|
|
29882
|
+
throw cliErrorFromService(result.error);
|
|
28034
29883
|
}
|
|
28035
29884
|
if (shouldOutputJson()) {
|
|
28036
29885
|
outputJson({ spaces: result.data, count: result.data.length });
|
|
@@ -28175,7 +30024,7 @@ async function throwSqlError(error, spaceUri, profileName, prefix) {
|
|
|
28175
30024
|
const hosted = await unhostedSpaceError(error, spaceUri, profileName);
|
|
28176
30025
|
if (hosted) throw hosted;
|
|
28177
30026
|
const message = prefix ? `${prefix}${error.message}` : error.message;
|
|
28178
|
-
throw
|
|
30027
|
+
throw cliErrorFromService(error, message);
|
|
28179
30028
|
}
|
|
28180
30029
|
function registerSqlCommand(program) {
|
|
28181
30030
|
const sql = program.command("sql").description("SQLite database operations for your TinyCloud space").addHelpText("after", `
|
|
@@ -28561,7 +30410,13 @@ async function readHasKey(name, issues) {
|
|
|
28561
30410
|
}
|
|
28562
30411
|
async function readDelegations(name, issues) {
|
|
28563
30412
|
try {
|
|
28564
|
-
|
|
30413
|
+
const entries = await loadAdditionalDelegations(name);
|
|
30414
|
+
const { storedDelegationKind } = await import("@tinycloud/operations/delegation-binding");
|
|
30415
|
+
const readable = entries.filter((entry) => storedDelegationKind(entry) !== "refused");
|
|
30416
|
+
if (readable.length < entries.length) {
|
|
30417
|
+
issues.push(`delegations: ${entries.length - readable.length} unreadable stored record(s) skipped`);
|
|
30418
|
+
}
|
|
30419
|
+
return readable;
|
|
28565
30420
|
} catch (error) {
|
|
28566
30421
|
issues.push(`delegations: ${messageFromError(error)}`);
|
|
28567
30422
|
return [];
|
|
@@ -28881,7 +30736,7 @@ async function unlockVault(node, privateKey) {
|
|
|
28881
30736
|
const signer = new PrivateKeySigner2(privateKey);
|
|
28882
30737
|
const result = await node.vault.unlock(signer);
|
|
28883
30738
|
if (result && !result.ok) {
|
|
28884
|
-
throw
|
|
30739
|
+
throw cliErrorFromService(result.error);
|
|
28885
30740
|
}
|
|
28886
30741
|
}
|
|
28887
30742
|
function registerVaultCommand(program) {
|
|
@@ -28922,7 +30777,7 @@ function registerVaultCommand(program) {
|
|
|
28922
30777
|
}
|
|
28923
30778
|
const result = await withSpinner(`Writing ${key}...`, () => node.vault.put(key, putValue));
|
|
28924
30779
|
if (!result.ok) {
|
|
28925
|
-
throw
|
|
30780
|
+
throw cliErrorFromService(result.error);
|
|
28926
30781
|
}
|
|
28927
30782
|
outputJson({ key, written: true });
|
|
28928
30783
|
} catch (error) {
|
|
@@ -28941,7 +30796,7 @@ function registerVaultCommand(program) {
|
|
|
28941
30796
|
if (result.error.code === "NOT_FOUND") {
|
|
28942
30797
|
throw new CLIError("NOT_FOUND", `Key "${key}" not found`, ExitCode.NOT_FOUND);
|
|
28943
30798
|
}
|
|
28944
|
-
throw
|
|
30799
|
+
throw cliErrorFromService(result.error);
|
|
28945
30800
|
}
|
|
28946
30801
|
const data = result.data.data ?? result.data;
|
|
28947
30802
|
if (options.output) {
|
|
@@ -28972,7 +30827,7 @@ function registerVaultCommand(program) {
|
|
|
28972
30827
|
await withSpinner("Unlocking vault...", () => unlockVault(node, privateKey));
|
|
28973
30828
|
const result = await withSpinner(`Deleting ${key}...`, () => node.vault.delete(key));
|
|
28974
30829
|
if (!result.ok) {
|
|
28975
|
-
throw
|
|
30830
|
+
throw cliErrorFromService(result.error);
|
|
28976
30831
|
}
|
|
28977
30832
|
outputJson({ key, deleted: true });
|
|
28978
30833
|
} catch (error) {
|
|
@@ -28989,7 +30844,7 @@ function registerVaultCommand(program) {
|
|
|
28989
30844
|
const listOptions = options.prefix ? { prefix: options.prefix } : void 0;
|
|
28990
30845
|
const result = await withSpinner("Listing vault keys...", () => node.vault.list(listOptions));
|
|
28991
30846
|
if (!result.ok) {
|
|
28992
|
-
throw
|
|
30847
|
+
throw cliErrorFromService(result.error);
|
|
28993
30848
|
}
|
|
28994
30849
|
const keys = result.data.data ?? result.data;
|
|
28995
30850
|
const keyList = Array.isArray(keys) ? keys : [];
|
|
@@ -29015,7 +30870,7 @@ function registerVaultCommand(program) {
|
|
|
29015
30870
|
outputJson({ key, exists: false, metadata: {} });
|
|
29016
30871
|
return;
|
|
29017
30872
|
}
|
|
29018
|
-
throw
|
|
30873
|
+
throw cliErrorFromService(result.error);
|
|
29019
30874
|
}
|
|
29020
30875
|
outputJson({
|
|
29021
30876
|
key,
|
|
@@ -29065,7 +30920,7 @@ function registerVarsCommand(program) {
|
|
|
29065
30920
|
const prefixedKv = node.kv.withPrefix(VARIABLES_PREFIX);
|
|
29066
30921
|
const result = await withSpinner("Listing variables...", () => prefixedKv.list());
|
|
29067
30922
|
if (!result.ok) {
|
|
29068
|
-
throw
|
|
30923
|
+
throw cliErrorFromService(result.error);
|
|
29069
30924
|
}
|
|
29070
30925
|
const rawData = result.data.data ?? result.data;
|
|
29071
30926
|
const keyList = Array.isArray(rawData) ? rawData : rawData?.keys ?? [];
|
|
@@ -29089,7 +30944,7 @@ function registerVarsCommand(program) {
|
|
|
29089
30944
|
if (result.error.code === "KV_NOT_FOUND" || result.error.code === "NOT_FOUND") {
|
|
29090
30945
|
throw new CLIError("NOT_FOUND", `Variable "${name}" not found`, ExitCode.NOT_FOUND);
|
|
29091
30946
|
}
|
|
29092
|
-
throw
|
|
30947
|
+
throw cliErrorFromService(result.error);
|
|
29093
30948
|
}
|
|
29094
30949
|
const data = result.data.data;
|
|
29095
30950
|
let value;
|
|
@@ -29147,7 +31002,7 @@ function registerVarsCommand(program) {
|
|
|
29147
31002
|
const prefixedKv = node.kv.withPrefix(VARIABLES_PREFIX);
|
|
29148
31003
|
const result = await withSpinner(`Setting variable ${name}...`, () => prefixedKv.put(name, payload));
|
|
29149
31004
|
if (!result.ok) {
|
|
29150
|
-
throw
|
|
31005
|
+
throw cliErrorFromService(result.error);
|
|
29151
31006
|
}
|
|
29152
31007
|
outputJson({ name, written: true });
|
|
29153
31008
|
} catch (error) {
|
|
@@ -29163,7 +31018,7 @@ function registerVarsCommand(program) {
|
|
|
29163
31018
|
const prefixedKv = node.kv.withPrefix(VARIABLES_PREFIX);
|
|
29164
31019
|
const result = await withSpinner(`Deleting variable ${name}...`, () => prefixedKv.delete(name));
|
|
29165
31020
|
if (!result.ok) {
|
|
29166
|
-
throw
|
|
31021
|
+
throw cliErrorFromService(result.error);
|
|
29167
31022
|
}
|
|
29168
31023
|
outputJson({ name, deleted: true });
|
|
29169
31024
|
} catch (error) {
|