@tinycloud/cli 1.0.1-beta.4 → 1.1.0-beta.10
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 +2287 -579
- 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;
|
|
@@ -6872,6 +6991,101 @@ function parseAuthError(responseText) {
|
|
|
6872
6991
|
function authUnauthorizedError(service, message, meta) {
|
|
6873
6992
|
return serviceError(ErrorCodes.AUTH_UNAUTHORIZED, message, service, { meta });
|
|
6874
6993
|
}
|
|
6994
|
+
var grantableActions = new Set(
|
|
6995
|
+
CAPABILITY_REGISTRY.map(({ urn }) => urn).filter((urn) => !urn.endsWith("/*"))
|
|
6996
|
+
);
|
|
6997
|
+
var capabilityServices = new Set(
|
|
6998
|
+
CAPABILITY_REGISTRY.map(({ service }) => service.slice("tinycloud.".length))
|
|
6999
|
+
);
|
|
7000
|
+
function parseCapabilityResource2(resource, service) {
|
|
7001
|
+
if (resource.length === 0 || resource.length > 1024 || !capabilityServices.has(service) || /[\s\p{C}*#]/u.test(resource) || resource.includes("://")) return void 0;
|
|
7002
|
+
const segments = resource.split("/");
|
|
7003
|
+
if (!/^tinycloud:[A-Za-z0-9][A-Za-z0-9:._-]*$/.test(segments[0])) return void 0;
|
|
7004
|
+
const serviceIndex = segments.findIndex(
|
|
7005
|
+
(segment, index) => index > 0 && capabilityServices.has(segment)
|
|
7006
|
+
);
|
|
7007
|
+
if (serviceIndex < 1 || segments[serviceIndex] !== service) return void 0;
|
|
7008
|
+
if (segments.slice(1, serviceIndex).some(
|
|
7009
|
+
(segment) => segment.length === 0 || segment === "." || segment === ".."
|
|
7010
|
+
)) return void 0;
|
|
7011
|
+
const pathSegments = segments.slice(serviceIndex + 1);
|
|
7012
|
+
if (pathSegments.some((segment) => segment === "." || segment === "..")) return void 0;
|
|
7013
|
+
if (service !== "kv" && (pathSegments.length === 0 || pathSegments[pathSegments.length - 1] === "")) return void 0;
|
|
7014
|
+
return {
|
|
7015
|
+
space: segments.slice(0, serviceIndex).join("/"),
|
|
7016
|
+
path: pathSegments.join("/")
|
|
7017
|
+
};
|
|
7018
|
+
}
|
|
7019
|
+
function safeCapabilityResource(value, service, action) {
|
|
7020
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 1024) return false;
|
|
7021
|
+
if (service === "encryption" && value.startsWith("urn:tinycloud:encryption:")) {
|
|
7022
|
+
if (!/^[A-Za-z0-9_][A-Za-z0-9_.:/-]*$/.test(value) || value.includes("//") || value.split("/").some((segment) => segment === "." || segment === "..")) return false;
|
|
7023
|
+
try {
|
|
7024
|
+
parseNetworkId(value);
|
|
7025
|
+
return true;
|
|
7026
|
+
} catch {
|
|
7027
|
+
return false;
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
const parsed = parseCapabilityResource2(value, service);
|
|
7031
|
+
return parsed !== void 0 && (!parsed.path.endsWith("/") || service === "kv" && action === "tinycloud.kv/list") && (parsed.path !== "" || service === "kv" && action === "tinycloud.kv/list");
|
|
7032
|
+
}
|
|
7033
|
+
function validatedCapabilityOf2(error) {
|
|
7034
|
+
const verdict = authorizationVerdictOf2(error);
|
|
7035
|
+
if (verdict !== "unauthenticated" && verdict !== "forbidden") return void 0;
|
|
7036
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7037
|
+
let node = error;
|
|
7038
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
|
|
7039
|
+
seen.add(node);
|
|
7040
|
+
const record = node;
|
|
7041
|
+
const status = errorStatusOf(record);
|
|
7042
|
+
const meta = record.meta;
|
|
7043
|
+
if ((status === 401 || status === 403 || status === void 0 && record.code === ErrorCodes.AUTH_UNAUTHORIZED) && typeof meta === "object" && meta !== null && !Array.isArray(meta)) {
|
|
7044
|
+
const metadata = meta;
|
|
7045
|
+
const { resource, requiredAction } = metadata;
|
|
7046
|
+
if (typeof requiredAction === "string" && grantableActions.has(requiredAction)) {
|
|
7047
|
+
const actionService = requiredAction.slice("tinycloud.".length, requiredAction.indexOf("/"));
|
|
7048
|
+
const explicitService = record.service === void 0 ? metadata.service : record.service;
|
|
7049
|
+
if (safeCapabilityResource(resource, actionService, requiredAction) && (explicitService === void 0 || explicitService === actionService || explicitService === `tinycloud.${actionService}`)) {
|
|
7050
|
+
return { resource, requiredAction };
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
}
|
|
7054
|
+
node = record.cause;
|
|
7055
|
+
}
|
|
7056
|
+
return void 0;
|
|
7057
|
+
}
|
|
7058
|
+
var MAX_CAUSE_DEPTH = 8;
|
|
7059
|
+
function errorStatusOf(node) {
|
|
7060
|
+
const meta = node.meta;
|
|
7061
|
+
const candidates = [
|
|
7062
|
+
node.status,
|
|
7063
|
+
node.statusCode,
|
|
7064
|
+
typeof meta === "object" && meta !== null ? meta.status : void 0
|
|
7065
|
+
];
|
|
7066
|
+
for (const candidate of candidates) {
|
|
7067
|
+
if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 400 && candidate <= 599) {
|
|
7068
|
+
return candidate;
|
|
7069
|
+
}
|
|
7070
|
+
}
|
|
7071
|
+
return void 0;
|
|
7072
|
+
}
|
|
7073
|
+
function authorizationVerdictOf2(error) {
|
|
7074
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7075
|
+
let sawUnauthorizedCode = false;
|
|
7076
|
+
let node = error;
|
|
7077
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
|
|
7078
|
+
seen.add(node);
|
|
7079
|
+
const record = node;
|
|
7080
|
+
const status = errorStatusOf(record);
|
|
7081
|
+
if (status === 401) return "unauthenticated";
|
|
7082
|
+
if (status === 403) return "forbidden";
|
|
7083
|
+
if (status !== void 0) return "other";
|
|
7084
|
+
if (record.code === ErrorCodes.AUTH_UNAUTHORIZED) sawUnauthorizedCode = true;
|
|
7085
|
+
node = record.cause;
|
|
7086
|
+
}
|
|
7087
|
+
return sawUnauthorizedCode ? "forbidden" : void 0;
|
|
7088
|
+
}
|
|
6875
7089
|
function storageQuotaExceededError(service, message, meta) {
|
|
6876
7090
|
return {
|
|
6877
7091
|
code: ErrorCodes.STORAGE_QUOTA_EXCEEDED,
|
|
@@ -7567,12 +7781,14 @@ var KVService = class extends BaseService {
|
|
|
7567
7781
|
signal: this.combineSignals(options?.signal)
|
|
7568
7782
|
});
|
|
7569
7783
|
if (!response.ok) {
|
|
7570
|
-
const errorText = await response.text();
|
|
7784
|
+
const errorText = response.status === 401 || response.status === 403 ? await this.readAuthorizationText(response) : await response.text();
|
|
7571
7785
|
if (response.status === 401 || response.status === 403) {
|
|
7572
7786
|
return this.authorizationFailure(
|
|
7573
7787
|
`Failed to batch read ${keys.length} key(s)`,
|
|
7574
7788
|
response,
|
|
7575
|
-
errorText
|
|
7789
|
+
errorText,
|
|
7790
|
+
paths,
|
|
7791
|
+
action
|
|
7576
7792
|
);
|
|
7577
7793
|
}
|
|
7578
7794
|
if (response.status === 413) {
|
|
@@ -7662,7 +7878,7 @@ var KVService = class extends BaseService {
|
|
|
7662
7878
|
return text;
|
|
7663
7879
|
}
|
|
7664
7880
|
}
|
|
7665
|
-
async createSignedReadUrlError(response, key) {
|
|
7881
|
+
async createSignedReadUrlError(response, key, path) {
|
|
7666
7882
|
let errorText = response.statusText;
|
|
7667
7883
|
try {
|
|
7668
7884
|
const text = await response.text();
|
|
@@ -7675,34 +7891,57 @@ var KVService = class extends BaseService {
|
|
|
7675
7891
|
return this.authorizationFailure(
|
|
7676
7892
|
`Failed to create signed read URL for key ${JSON.stringify(key)}`,
|
|
7677
7893
|
response,
|
|
7678
|
-
errorText
|
|
7894
|
+
errorText,
|
|
7895
|
+
[path],
|
|
7896
|
+
KVAction.GET
|
|
7679
7897
|
);
|
|
7680
7898
|
}
|
|
7681
|
-
const
|
|
7899
|
+
const code3 = response.status === 400 ? ErrorCodes.INVALID_INPUT : ErrorCodes.NETWORK_ERROR;
|
|
7682
7900
|
return err(
|
|
7683
7901
|
serviceError(
|
|
7684
|
-
|
|
7902
|
+
code3,
|
|
7685
7903
|
`Failed to create signed read URL for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
7686
7904
|
"kv",
|
|
7687
7905
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
7688
7906
|
)
|
|
7689
7907
|
);
|
|
7690
7908
|
}
|
|
7909
|
+
/** A known 401/403 keeps its typed status even if reading its body fails. */
|
|
7910
|
+
async readAuthorizationText(response) {
|
|
7911
|
+
try {
|
|
7912
|
+
return await response.text();
|
|
7913
|
+
} catch {
|
|
7914
|
+
return "";
|
|
7915
|
+
}
|
|
7916
|
+
}
|
|
7691
7917
|
/**
|
|
7692
7918
|
* AUTH_UNAUTHORIZED for a 401/403 response. The message keeps the HTTP
|
|
7693
7919
|
* status and the server text (`<context>: <status> - <text>`, the same
|
|
7694
7920
|
* shape as every other KV failure) so callers that rethrow only the message
|
|
7695
7921
|
* still see the status; `meta.status` carries it for typed callers.
|
|
7696
|
-
*
|
|
7922
|
+
* Server hints must match the requested path/action (whether the node sends
|
|
7923
|
+
* a relative path or full resource); metadata uses only the request-derived
|
|
7924
|
+
* canonical resource under the authenticated session's space.
|
|
7697
7925
|
*/
|
|
7698
|
-
authorizationFailure(context, response, errorText, extraMeta = {}) {
|
|
7926
|
+
authorizationFailure(context, response, errorText, paths, expectedAction, extraMeta = {}) {
|
|
7699
7927
|
const { resource, action } = parseAuthError(errorText);
|
|
7928
|
+
const requestedPath = paths.find(
|
|
7929
|
+
(path) => resource === path || resource === `${this.context.session.spaceId}/kv/${path}`
|
|
7930
|
+
);
|
|
7931
|
+
const capability = requestedPath !== void 0 && action === expectedAction ? validatedCapabilityOf2({
|
|
7932
|
+
service: "kv",
|
|
7933
|
+
code: ErrorCodes.AUTH_UNAUTHORIZED,
|
|
7934
|
+
meta: {
|
|
7935
|
+
status: response.status,
|
|
7936
|
+
resource: `${this.context.session.spaceId}/kv/${requestedPath}`,
|
|
7937
|
+
requiredAction: action
|
|
7938
|
+
}
|
|
7939
|
+
}) : void 0;
|
|
7700
7940
|
const detail = errorText.trim().length > 0 ? errorText : response.statusText || "authorization failed";
|
|
7701
7941
|
return err(authUnauthorizedError("kv", `${context}: ${response.status} - ${detail}`, {
|
|
7702
7942
|
status: response.status,
|
|
7703
|
-
...
|
|
7704
|
-
...
|
|
7705
|
-
...extraMeta
|
|
7943
|
+
...extraMeta,
|
|
7944
|
+
...capability
|
|
7706
7945
|
}));
|
|
7707
7946
|
}
|
|
7708
7947
|
normalizeSignedReadUrlResponse(data) {
|
|
@@ -7746,13 +7985,24 @@ var KVService = class extends BaseService {
|
|
|
7746
7985
|
);
|
|
7747
7986
|
if (!response.ok) {
|
|
7748
7987
|
if (response.status === 401 || response.status === 403) {
|
|
7749
|
-
const errorText2 = await
|
|
7988
|
+
const errorText2 = await this.readAuthorizationText(response);
|
|
7750
7989
|
const permissionHint = parsePermissionHintFromErrorText(errorText2);
|
|
7990
|
+
const structuredCapability = permissionHint?.service === "tinycloud.kv" && permissionHint.space === this.context.session.spaceId && permissionHint.path === path ? validatedCapabilityOf2({
|
|
7991
|
+
service: "kv",
|
|
7992
|
+
code: ErrorCodes.AUTH_UNAUTHORIZED,
|
|
7993
|
+
meta: {
|
|
7994
|
+
status: response.status,
|
|
7995
|
+
resource: `${this.context.session.spaceId}/kv/${path}`,
|
|
7996
|
+
requiredAction: KVAction.GET
|
|
7997
|
+
}
|
|
7998
|
+
}) : void 0;
|
|
7751
7999
|
return this.authorizationFailure(
|
|
7752
8000
|
`Failed to get key ${JSON.stringify(key)}`,
|
|
7753
8001
|
response,
|
|
7754
8002
|
errorText2,
|
|
7755
|
-
|
|
8003
|
+
[path],
|
|
8004
|
+
KVAction.GET,
|
|
8005
|
+
structuredCapability ? { permissionHint, ...structuredCapability } : {}
|
|
7756
8006
|
);
|
|
7757
8007
|
}
|
|
7758
8008
|
if (response.status === 404) {
|
|
@@ -7829,7 +8079,9 @@ var KVService = class extends BaseService {
|
|
|
7829
8079
|
return this.authorizationFailure(
|
|
7830
8080
|
`Failed to put key ${JSON.stringify(key)}`,
|
|
7831
8081
|
response,
|
|
7832
|
-
await
|
|
8082
|
+
await this.readAuthorizationText(response),
|
|
8083
|
+
[path],
|
|
8084
|
+
KVAction.PUT
|
|
7833
8085
|
);
|
|
7834
8086
|
}
|
|
7835
8087
|
if (!response.ok) {
|
|
@@ -7958,7 +8210,9 @@ var KVService = class extends BaseService {
|
|
|
7958
8210
|
return this.authorizationFailure(
|
|
7959
8211
|
`Failed to batch put ${items.length} key(s)`,
|
|
7960
8212
|
response,
|
|
7961
|
-
errorText
|
|
8213
|
+
errorText,
|
|
8214
|
+
paths,
|
|
8215
|
+
KVAction.PUT
|
|
7962
8216
|
);
|
|
7963
8217
|
}
|
|
7964
8218
|
const quotaError = this.handleQuotaErrorResponse(
|
|
@@ -8079,11 +8333,13 @@ var KVService = class extends BaseService {
|
|
|
8079
8333
|
}
|
|
8080
8334
|
);
|
|
8081
8335
|
if (!response.ok) {
|
|
8082
|
-
if (response.status === 401) {
|
|
8336
|
+
if (response.status === 401 || response.status === 403) {
|
|
8083
8337
|
return this.authorizationFailure(
|
|
8084
8338
|
"Failed to list keys",
|
|
8085
8339
|
response,
|
|
8086
|
-
await
|
|
8340
|
+
await this.readAuthorizationText(response),
|
|
8341
|
+
[listPath],
|
|
8342
|
+
KVAction.LIST
|
|
8087
8343
|
);
|
|
8088
8344
|
}
|
|
8089
8345
|
const errorText = await response.text();
|
|
@@ -8132,11 +8388,13 @@ var KVService = class extends BaseService {
|
|
|
8132
8388
|
options?.ifMatch === void 0 ? void 0 : { "if-match": options.ifMatch }
|
|
8133
8389
|
);
|
|
8134
8390
|
if (!response.ok) {
|
|
8135
|
-
if (response.status === 401) {
|
|
8391
|
+
if (response.status === 401 || response.status === 403) {
|
|
8136
8392
|
return this.authorizationFailure(
|
|
8137
8393
|
`Failed to delete key ${JSON.stringify(key)}`,
|
|
8138
8394
|
response,
|
|
8139
|
-
await
|
|
8395
|
+
await this.readAuthorizationText(response),
|
|
8396
|
+
[path],
|
|
8397
|
+
KVAction.DELETE
|
|
8140
8398
|
);
|
|
8141
8399
|
}
|
|
8142
8400
|
if (response.status === 404) {
|
|
@@ -8194,11 +8452,13 @@ var KVService = class extends BaseService {
|
|
|
8194
8452
|
options?.signal
|
|
8195
8453
|
);
|
|
8196
8454
|
if (!response.ok) {
|
|
8197
|
-
if (response.status === 401) {
|
|
8455
|
+
if (response.status === 401 || response.status === 403) {
|
|
8198
8456
|
return this.authorizationFailure(
|
|
8199
8457
|
`Failed to get metadata for key ${JSON.stringify(key)}`,
|
|
8200
8458
|
response,
|
|
8201
|
-
await
|
|
8459
|
+
await this.readAuthorizationText(response),
|
|
8460
|
+
[path],
|
|
8461
|
+
KVAction.HEAD
|
|
8202
8462
|
);
|
|
8203
8463
|
}
|
|
8204
8464
|
if (response.status === 404) {
|
|
@@ -8265,7 +8525,7 @@ var KVService = class extends BaseService {
|
|
|
8265
8525
|
signal: this.combineSignals(options?.signal)
|
|
8266
8526
|
});
|
|
8267
8527
|
if (!response.ok) {
|
|
8268
|
-
return this.createSignedReadUrlError(response, key);
|
|
8528
|
+
return this.createSignedReadUrlError(response, key, path);
|
|
8269
8529
|
}
|
|
8270
8530
|
const signedUrl = this.normalizeSignedReadUrlResponse(
|
|
8271
8531
|
await response.json()
|
|
@@ -8489,14 +8749,15 @@ var SQLService = class extends BaseService {
|
|
|
8489
8749
|
};
|
|
8490
8750
|
if (options?.maxRows !== void 0) body.maxRows = options.maxRows;
|
|
8491
8751
|
if (options?.maxBytes !== void 0) body.maxBytes = options.maxBytes;
|
|
8752
|
+
const action = this.actionForSql(sql, SQLAction.READ);
|
|
8492
8753
|
const response = await this.invokeSQL(
|
|
8493
8754
|
dbName,
|
|
8494
|
-
|
|
8755
|
+
action,
|
|
8495
8756
|
body,
|
|
8496
8757
|
options?.signal
|
|
8497
8758
|
);
|
|
8498
8759
|
if (!response.ok) {
|
|
8499
|
-
return this.handleErrorResponse(response, "query");
|
|
8760
|
+
return this.handleErrorResponse(response, "query", dbName, [action]);
|
|
8500
8761
|
}
|
|
8501
8762
|
const data = await response.json();
|
|
8502
8763
|
return ok(data);
|
|
@@ -8525,14 +8786,15 @@ var SQLService = class extends BaseService {
|
|
|
8525
8786
|
(statement) => this.actionForSql(statement, SQLAction.SCHEMA)
|
|
8526
8787
|
)
|
|
8527
8788
|
];
|
|
8789
|
+
const requestedActions2 = this.dedupeActions(actions);
|
|
8528
8790
|
const response = await this.invokeSQL(
|
|
8529
8791
|
dbName,
|
|
8530
|
-
|
|
8792
|
+
requestedActions2,
|
|
8531
8793
|
body,
|
|
8532
8794
|
options?.signal
|
|
8533
8795
|
);
|
|
8534
8796
|
if (!response.ok) {
|
|
8535
|
-
return this.handleErrorResponse(response, "execute");
|
|
8797
|
+
return this.handleErrorResponse(response, "execute", dbName, requestedActions2);
|
|
8536
8798
|
}
|
|
8537
8799
|
const data = await response.json();
|
|
8538
8800
|
return ok(data);
|
|
@@ -8547,14 +8809,15 @@ var SQLService = class extends BaseService {
|
|
|
8547
8809
|
return err(authRequiredError("sql"));
|
|
8548
8810
|
}
|
|
8549
8811
|
try {
|
|
8812
|
+
const requestedActions2 = this.actionsForSqlBatch(statements);
|
|
8550
8813
|
const response = await this.invokeSQL(
|
|
8551
8814
|
dbName,
|
|
8552
|
-
|
|
8815
|
+
requestedActions2,
|
|
8553
8816
|
{ action: "batch", statements },
|
|
8554
8817
|
options?.signal
|
|
8555
8818
|
);
|
|
8556
8819
|
if (!response.ok) {
|
|
8557
|
-
return this.handleErrorResponse(response, "batch");
|
|
8820
|
+
return this.handleErrorResponse(response, "batch", dbName, requestedActions2);
|
|
8558
8821
|
}
|
|
8559
8822
|
const data = await response.json();
|
|
8560
8823
|
return ok(data);
|
|
@@ -8576,7 +8839,7 @@ var SQLService = class extends BaseService {
|
|
|
8576
8839
|
options?.signal
|
|
8577
8840
|
);
|
|
8578
8841
|
if (!response.ok) {
|
|
8579
|
-
return this.handleErrorResponse(response, "executeStatement");
|
|
8842
|
+
return this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
|
|
8580
8843
|
}
|
|
8581
8844
|
const data = await response.json();
|
|
8582
8845
|
return ok(data);
|
|
@@ -8598,7 +8861,7 @@ var SQLService = class extends BaseService {
|
|
|
8598
8861
|
options?.signal
|
|
8599
8862
|
);
|
|
8600
8863
|
if (!response.ok) {
|
|
8601
|
-
return this.handleErrorResponse(response, "export");
|
|
8864
|
+
return this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
|
|
8602
8865
|
}
|
|
8603
8866
|
const resp = response;
|
|
8604
8867
|
if (typeof resp.blob === "function") {
|
|
@@ -8732,7 +8995,7 @@ var SQLService = class extends BaseService {
|
|
|
8732
8995
|
}))
|
|
8733
8996
|
);
|
|
8734
8997
|
}
|
|
8735
|
-
async handleErrorResponse(response, operation) {
|
|
8998
|
+
async handleErrorResponse(response, operation, dbName, requestedActions2) {
|
|
8736
8999
|
const errorText = await response.text();
|
|
8737
9000
|
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
8738
9001
|
if (response.status === 402) {
|
|
@@ -8751,9 +9014,11 @@ var SQLService = class extends BaseService {
|
|
|
8751
9014
|
errorBody
|
|
8752
9015
|
);
|
|
8753
9016
|
if (response.status === 401) {
|
|
8754
|
-
const {
|
|
8755
|
-
if (action
|
|
8756
|
-
|
|
9017
|
+
const { action } = parseAuthError(errorText);
|
|
9018
|
+
if (action && requestedActions2.includes(action)) {
|
|
9019
|
+
meta.requiredAction = action;
|
|
9020
|
+
meta.resource = `${this.context.session.spaceId}/sql/${dbName}`;
|
|
9021
|
+
}
|
|
8757
9022
|
}
|
|
8758
9023
|
return err(
|
|
8759
9024
|
serviceError(errorCode2, message, "sql", { meta })
|
|
@@ -11502,75 +11767,6 @@ function canonicalHashHex(sha2563, value) {
|
|
|
11502
11767
|
const canonical = canonicalize(value);
|
|
11503
11768
|
return hexEncode2(sha2563(utf8Encode(canonical)));
|
|
11504
11769
|
}
|
|
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
11770
|
var DEFAULT_ENCRYPTION_ALG = "x25519-aes256gcm/v1";
|
|
11575
11771
|
var ENVELOPE_VERSION = 1;
|
|
11576
11772
|
var DEFAULT_KEY_VERSION = 1;
|
|
@@ -12406,7 +12602,7 @@ var SERVICE_SHORT_TO_LONG = Object.freeze({
|
|
|
12406
12602
|
});
|
|
12407
12603
|
var ENCRYPTION_PERMISSION_SERVICE2 = "tinycloud.encryption";
|
|
12408
12604
|
var ENCRYPTION_MANIFEST_SPACE2 = "encryption";
|
|
12409
|
-
var
|
|
12605
|
+
var SERVICE_LONG_TO_SHORT2 = Object.freeze(
|
|
12410
12606
|
Object.fromEntries(
|
|
12411
12607
|
Object.entries(SERVICE_SHORT_TO_LONG).map(([s, l]) => [l, s])
|
|
12412
12608
|
)
|
|
@@ -12896,18 +13092,18 @@ function expandVaultPermissionEntry(entry) {
|
|
|
12896
13092
|
const byBase = /* @__PURE__ */ new Map();
|
|
12897
13093
|
for (const action of entry.actions) {
|
|
12898
13094
|
const expansion = vaultActionExpansion(action);
|
|
12899
|
-
for (const
|
|
12900
|
-
const actions = byBase.get(
|
|
13095
|
+
for (const base4 of expansion.bases) {
|
|
13096
|
+
const actions = byBase.get(base4) ?? [];
|
|
12901
13097
|
if (!actions.includes(expansion.action)) {
|
|
12902
13098
|
actions.push(expansion.action);
|
|
12903
13099
|
}
|
|
12904
|
-
byBase.set(
|
|
13100
|
+
byBase.set(base4, actions);
|
|
12905
13101
|
}
|
|
12906
13102
|
}
|
|
12907
|
-
return [...byBase.entries()].map(([
|
|
13103
|
+
return [...byBase.entries()].map(([base4, actions]) => ({
|
|
12908
13104
|
...entry,
|
|
12909
13105
|
service: "tinycloud.kv",
|
|
12910
|
-
path: vaultKVPath(
|
|
13106
|
+
path: vaultKVPath(base4, entry.path),
|
|
12911
13107
|
actions,
|
|
12912
13108
|
skipPrefix: true
|
|
12913
13109
|
}));
|
|
@@ -12950,9 +13146,9 @@ function normalizeVaultAction(action) {
|
|
|
12950
13146
|
}
|
|
12951
13147
|
return action;
|
|
12952
13148
|
}
|
|
12953
|
-
function vaultKVPath(
|
|
13149
|
+
function vaultKVPath(base4, path) {
|
|
12954
13150
|
const normalized = path.startsWith("/") ? path.slice(1) : path;
|
|
12955
|
-
return `${
|
|
13151
|
+
return `${base4}/${normalized}`;
|
|
12956
13152
|
}
|
|
12957
13153
|
function cloneResourceCapability(entry) {
|
|
12958
13154
|
return {
|
|
@@ -13123,17 +13319,15 @@ function didWithoutFragment(did) {
|
|
|
13123
13319
|
async function loadAdditionalDelegations(profile) {
|
|
13124
13320
|
return readAdditionalDelegations(profile);
|
|
13125
13321
|
}
|
|
13126
|
-
async function
|
|
13127
|
-
await
|
|
13322
|
+
async function appendAdditionalDelegations(profile, entries) {
|
|
13323
|
+
const { mergeDelegationsWithoutRequest } = await import("@tinycloud/operations/delegation-binding");
|
|
13324
|
+
await updateProfileStore(profile, "additional-delegations", (stored) => ({
|
|
13325
|
+
records: mergeDelegationsWithoutRequest(stored, entries.map((entry) => ({ ...entry }))),
|
|
13326
|
+
result: void 0
|
|
13327
|
+
}));
|
|
13128
13328
|
}
|
|
13129
13329
|
async function appendAdditionalDelegation(profile, entry) {
|
|
13130
|
-
await
|
|
13131
|
-
profile,
|
|
13132
|
-
"additional-delegations",
|
|
13133
|
-
entry.delegation.cid,
|
|
13134
|
-
entry,
|
|
13135
|
-
(candidate) => candidate.delegation.cid
|
|
13136
|
-
);
|
|
13330
|
+
await appendAdditionalDelegations(profile, [entry]);
|
|
13137
13331
|
}
|
|
13138
13332
|
async function loadPermissionRequestArtifacts(profile) {
|
|
13139
13333
|
const raw = await readAuthRequests(profile);
|
|
@@ -13147,10 +13341,8 @@ async function appendPermissionRequestArtifact(profile, artifact) {
|
|
|
13147
13341
|
await writeSharedRecords(profile, "auth-requests", next);
|
|
13148
13342
|
});
|
|
13149
13343
|
}
|
|
13150
|
-
async function replaceSharedRecords(profile, store, entries) {
|
|
13151
|
-
await withProfileLock2(profile, () => writeSharedRecords(profile, store, entries));
|
|
13152
|
-
}
|
|
13153
13344
|
async function writeSharedRecords(profile, store, entries) {
|
|
13345
|
+
await refuseWriteToDeletedProfile2(profile);
|
|
13154
13346
|
const path = store === "additional-delegations" ? additionalDelegationsPath(profile) : permissionRequestsPath(profile);
|
|
13155
13347
|
await writeJsonAtomic(path, entries);
|
|
13156
13348
|
await writeJsonAtomic(profileStoreMetadataPath(profile, store), { formatVersion: 1 });
|
|
@@ -13163,13 +13355,48 @@ async function getLastPermissionRequestArtifact(profile) {
|
|
|
13163
13355
|
const existing = await loadPermissionRequestArtifacts(profile);
|
|
13164
13356
|
return existing.at(-1) ?? null;
|
|
13165
13357
|
}
|
|
13166
|
-
async function replayAdditionalDelegations(node, profile) {
|
|
13358
|
+
async function replayAdditionalDelegations(node, profile, options) {
|
|
13359
|
+
const {
|
|
13360
|
+
operationSpaceResolver,
|
|
13361
|
+
prepareStoredDelegationReplay,
|
|
13362
|
+
replayStoredDelegation,
|
|
13363
|
+
storedDelegationKind
|
|
13364
|
+
} = await import("@tinycloud/operations/delegation-binding");
|
|
13365
|
+
const activator = node;
|
|
13366
|
+
const migrated = await prepareStoredDelegationReplay(profile, activator, {
|
|
13367
|
+
host: options.host,
|
|
13368
|
+
migrate: options.migrate
|
|
13369
|
+
});
|
|
13370
|
+
const resolveSpace = operationSpaceResolver(node, options.ownerSpace);
|
|
13167
13371
|
const entries = await loadAdditionalDelegations(profile);
|
|
13168
|
-
for (const
|
|
13372
|
+
for (const stored of entries) {
|
|
13373
|
+
const kind = storedDelegationKind(stored);
|
|
13374
|
+
if (kind === "compact" || kind === "signed-login") {
|
|
13375
|
+
const installed = await replayStoredDelegation(activator, stored, {
|
|
13376
|
+
host: options.host,
|
|
13377
|
+
migrated,
|
|
13378
|
+
resolveSpace
|
|
13379
|
+
});
|
|
13380
|
+
if (installed === void 0 && process.env.TC_DEBUG_REPLAY === "1") {
|
|
13381
|
+
process.stderr.write("[replay] skipping a stored delegation refused by validation or its request binding\n");
|
|
13382
|
+
}
|
|
13383
|
+
continue;
|
|
13384
|
+
}
|
|
13385
|
+
if (kind === "refused") {
|
|
13386
|
+
if (process.env.TC_DEBUG_REPLAY === "1") {
|
|
13387
|
+
process.stderr.write("[replay] skipping a malformed stored record or one bound to a request it cannot be held to\n");
|
|
13388
|
+
}
|
|
13389
|
+
continue;
|
|
13390
|
+
}
|
|
13391
|
+
const entry = stored;
|
|
13169
13392
|
const expiry = entry.delegation.expiry instanceof Date ? entry.delegation.expiry : new Date(entry.delegation.expiry);
|
|
13170
13393
|
if (expiry.getTime() <= Date.now()) continue;
|
|
13171
13394
|
try {
|
|
13172
|
-
await node.useRuntimeDelegation({
|
|
13395
|
+
await node.useRuntimeDelegation({
|
|
13396
|
+
...entry.delegation,
|
|
13397
|
+
delegationHeader: { Authorization: entry.delegation.delegationHeader.Authorization },
|
|
13398
|
+
expiry
|
|
13399
|
+
});
|
|
13173
13400
|
} catch (err2) {
|
|
13174
13401
|
if (process.env.TC_DEBUG_REPLAY === "1") {
|
|
13175
13402
|
process.stderr.write(`[replay] skipping ${entry.delegation.cid}: ${err2.message}
|
|
@@ -13465,7 +13692,7 @@ async function createSDKInstance(ctx, options) {
|
|
|
13465
13692
|
if (!key && !effectivePrivateKey && !(profile?.authMethod === "openkey" && session !== null)) {
|
|
13466
13693
|
throw new CLIError(
|
|
13467
13694
|
"AUTH_REQUIRED",
|
|
13468
|
-
`No key found for profile "${ctx.profile}". Run \`tc
|
|
13695
|
+
`No key found for profile "${ctx.profile}". Run \`tc --profile ${ctx.profile} auth rotate\` to create a new key and sign in.`,
|
|
13469
13696
|
ExitCode.AUTH_REQUIRED
|
|
13470
13697
|
);
|
|
13471
13698
|
}
|
|
@@ -13474,6 +13701,7 @@ async function createSDKInstance(ctx, options) {
|
|
|
13474
13701
|
host: ctx.host,
|
|
13475
13702
|
privateKey: effectivePrivateKey
|
|
13476
13703
|
});
|
|
13704
|
+
let restoredOwnSession2 = false;
|
|
13477
13705
|
if (session && session.delegationHeader && session.delegationCid && session.spaceId) {
|
|
13478
13706
|
await node2.restoreSession({
|
|
13479
13707
|
delegationHeader: session.delegationHeader,
|
|
@@ -13486,16 +13714,22 @@ async function createSDKInstance(ctx, options) {
|
|
|
13486
13714
|
siwe: session.siwe,
|
|
13487
13715
|
signature: session.signature
|
|
13488
13716
|
});
|
|
13717
|
+
restoredOwnSession2 = true;
|
|
13489
13718
|
} else {
|
|
13490
13719
|
await node2.signIn();
|
|
13491
13720
|
}
|
|
13492
|
-
await replayAdditionalDelegations(node2, ctx.profile
|
|
13721
|
+
await replayAdditionalDelegations(node2, ctx.profile, {
|
|
13722
|
+
host: ctx.host,
|
|
13723
|
+
ownerSpace: profile.spaceId,
|
|
13724
|
+
migrate: restoredOwnSession2 && options?.privateKey === void 0
|
|
13725
|
+
});
|
|
13493
13726
|
return node2;
|
|
13494
13727
|
}
|
|
13495
13728
|
const node = new TinyCloudNode({
|
|
13496
13729
|
host: ctx.host,
|
|
13497
13730
|
privateKey: options?.privateKey
|
|
13498
13731
|
});
|
|
13732
|
+
let restoredOwnSession = false;
|
|
13499
13733
|
if (options?.privateKey) {
|
|
13500
13734
|
await node.signIn();
|
|
13501
13735
|
} else if (session && session.delegationHeader && session.delegationCid && session.spaceId) {
|
|
@@ -13510,10 +13744,16 @@ async function createSDKInstance(ctx, options) {
|
|
|
13510
13744
|
siwe: session.siwe,
|
|
13511
13745
|
signature: session.signature
|
|
13512
13746
|
});
|
|
13747
|
+
restoredOwnSession = true;
|
|
13513
13748
|
}
|
|
13514
|
-
await replayAdditionalDelegations(node, ctx.profile
|
|
13749
|
+
await replayAdditionalDelegations(node, ctx.profile, {
|
|
13750
|
+
host: ctx.host,
|
|
13751
|
+
ownerSpace: profile?.spaceId,
|
|
13752
|
+
migrate: restoredOwnSession
|
|
13753
|
+
});
|
|
13515
13754
|
return node;
|
|
13516
13755
|
}
|
|
13756
|
+
var BOOTSTRAP_PROFILE_FIELDS = ["sessionDid", "spaceId"];
|
|
13517
13757
|
async function bootstrapDelegatedSession(ctx, delegation) {
|
|
13518
13758
|
const written = await ProfileManager.withLock(ctx.profile, async () => {
|
|
13519
13759
|
const previousProfile = await ProfileManager.getProfile(ctx.profile);
|
|
@@ -13563,13 +13803,13 @@ async function bootstrapDelegatedSession(ctx, delegation) {
|
|
|
13563
13803
|
throw error;
|
|
13564
13804
|
});
|
|
13565
13805
|
const session = await ProfileManager.getSession(ctx.profile);
|
|
13566
|
-
if (
|
|
13806
|
+
if (profile === null || BOOTSTRAP_PROFILE_FIELDS.some((field) => profile[field] !== written.profile[field]) || JSON.stringify(session) !== JSON.stringify(written.session)) {
|
|
13567
13807
|
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
13808
|
}
|
|
13569
13809
|
return restoreBeforeBootstrap(ctx.profile, written.previousProfile);
|
|
13570
13810
|
}, { timeoutMs: PROFILE_COMMIT_LOCK_TIMEOUT_MS }).catch((error) => (
|
|
13571
13811
|
// 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 (${
|
|
13812
|
+
`Rolling back the provisional session of profile "${ctx.profile}" could not run (${failureName(error)}); check \`tc --profile ${ctx.profile} context\`.`
|
|
13573
13813
|
));
|
|
13574
13814
|
throw annotate(cause, note);
|
|
13575
13815
|
};
|
|
@@ -13585,15 +13825,27 @@ async function restoreBeforeBootstrap(profileName, previousProfile) {
|
|
|
13585
13825
|
const failures = [];
|
|
13586
13826
|
for (const write of [
|
|
13587
13827
|
() => ProfileManager.clearSession(profileName),
|
|
13588
|
-
() => ProfileManager.
|
|
13828
|
+
() => ProfileManager.updateProfile(profileName, (current) => {
|
|
13829
|
+
const restored = { ...current };
|
|
13830
|
+
for (const field of BOOTSTRAP_PROFILE_FIELDS) {
|
|
13831
|
+
if (previousProfile[field] === void 0) delete restored[field];
|
|
13832
|
+
else restored[field] = previousProfile[field];
|
|
13833
|
+
}
|
|
13834
|
+
return restored;
|
|
13835
|
+
})
|
|
13589
13836
|
]) {
|
|
13590
13837
|
await write().catch((error) => {
|
|
13591
|
-
failures.push(
|
|
13838
|
+
failures.push(failureName(error));
|
|
13592
13839
|
});
|
|
13593
13840
|
}
|
|
13594
13841
|
if (failures.length === 0) return void 0;
|
|
13595
13842
|
return `Rolling back the provisional session of profile "${profileName}" failed too (${failures.join("; ")}); check \`tc --profile ${profileName} context\`.`;
|
|
13596
13843
|
}
|
|
13844
|
+
function failureName(error) {
|
|
13845
|
+
if (error instanceof SyntaxError) return "a profile file is not valid JSON";
|
|
13846
|
+
if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string") return error.code;
|
|
13847
|
+
return error instanceof Error ? error.name : "unknown error";
|
|
13848
|
+
}
|
|
13597
13849
|
function annotate(error, note) {
|
|
13598
13850
|
if (note === void 0) return error;
|
|
13599
13851
|
const cause = wrapError(error);
|
|
@@ -13605,7 +13857,7 @@ async function ensureAuthenticated(ctx, options) {
|
|
|
13605
13857
|
}
|
|
13606
13858
|
const profile = await ProfileManager.getProfile(ctx.profile).catch(() => null);
|
|
13607
13859
|
if (profile?.authMethod === "local" && profile.privateKey) {
|
|
13608
|
-
return createSDKInstance(ctx
|
|
13860
|
+
return createSDKInstance(ctx);
|
|
13609
13861
|
}
|
|
13610
13862
|
const session = await ProfileManager.getSession(ctx.profile);
|
|
13611
13863
|
if (!session) {
|
|
@@ -13884,7 +14136,7 @@ async function authenticatedNode(cmd) {
|
|
|
13884
14136
|
}
|
|
13885
14137
|
function assertOk(result) {
|
|
13886
14138
|
if (!result.ok) {
|
|
13887
|
-
throw
|
|
14139
|
+
throw cliErrorFromService(result.error);
|
|
13888
14140
|
}
|
|
13889
14141
|
}
|
|
13890
14142
|
async function loadManifestSource(source) {
|
|
@@ -14018,8 +14270,8 @@ function buildAuthUrl(did, options = {}) {
|
|
|
14018
14270
|
params.set("expiry", String(options.expiry));
|
|
14019
14271
|
}
|
|
14020
14272
|
params.set("protocolVersion", "1");
|
|
14021
|
-
const
|
|
14022
|
-
return `${
|
|
14273
|
+
const base4 = options.openkeyHost ?? DEFAULT_OPENKEY_HOST;
|
|
14274
|
+
return `${base4}/delegate?${params.toString()}`;
|
|
14023
14275
|
}
|
|
14024
14276
|
function validateDelegationCallbackPayload(value) {
|
|
14025
14277
|
if (!value || typeof value !== "object") return "expected an object";
|
|
@@ -14989,20 +15241,20 @@ async function acquireDeviceDelegation(input) {
|
|
|
14989
15241
|
}
|
|
14990
15242
|
const startValue = await responseJson(startResponse);
|
|
14991
15243
|
if (!startResponse.ok) {
|
|
14992
|
-
const
|
|
15244
|
+
const code3 = errorCode(startValue);
|
|
14993
15245
|
const description = errorDescription(startValue);
|
|
14994
|
-
if (startResponse.status === 429 &&
|
|
15246
|
+
if (startResponse.status === 429 && code3 === "rate_limited") {
|
|
14995
15247
|
throw deviceAuthRateLimit(startResponse);
|
|
14996
15248
|
}
|
|
14997
|
-
if (
|
|
15249
|
+
if (code3 === "invalid_scope") {
|
|
14998
15250
|
throw new CLIError(
|
|
14999
15251
|
"SCOPE_REJECTED",
|
|
15000
15252
|
`OpenKey rejected the requested scope${description ? `: ${description}` : "."} Remove that capability from the manifest or use another approval flow.`,
|
|
15001
15253
|
ExitCode.PERMISSION_DENIED,
|
|
15002
|
-
{ openkeyError:
|
|
15254
|
+
{ openkeyError: code3, ...description ? { capability: description } : {} }
|
|
15003
15255
|
);
|
|
15004
15256
|
}
|
|
15005
|
-
throw new CLIError("DEVICE_AUTH_FAILED", `OpenKey device authorization failed: ${
|
|
15257
|
+
throw new CLIError("DEVICE_AUTH_FAILED", `OpenKey device authorization failed: ${code3 ?? `HTTP ${startResponse.status}`}${description ? ` (${description})` : ""}`, ExitCode.ERROR);
|
|
15006
15258
|
}
|
|
15007
15259
|
const started = validateStart(startValue, openkeyHost);
|
|
15008
15260
|
const deadline = Date.now() + started.expiresIn * 1e3;
|
|
@@ -15030,20 +15282,20 @@ async function acquireDeviceDelegation(input) {
|
|
|
15030
15282
|
continue;
|
|
15031
15283
|
}
|
|
15032
15284
|
const value = await responseJson(response);
|
|
15033
|
-
const
|
|
15034
|
-
if (response.status >= 500 || response.status === 429 &&
|
|
15035
|
-
if (
|
|
15285
|
+
const code3 = errorCode(value);
|
|
15286
|
+
if (response.status >= 500 || response.status === 429 && code3 !== "slow_down") continue;
|
|
15287
|
+
if (code3 === "slow_down") {
|
|
15036
15288
|
interval += 5;
|
|
15037
15289
|
continue;
|
|
15038
15290
|
}
|
|
15039
|
-
if (
|
|
15040
|
-
if (
|
|
15291
|
+
if (code3 === "authorization_pending") continue;
|
|
15292
|
+
if (code3 === "access_denied") {
|
|
15041
15293
|
throw new CLIError("DEVICE_AUTH_DENIED", "The owner denied the OpenKey device authorization. No session was saved.", ExitCode.PERMISSION_DENIED);
|
|
15042
15294
|
}
|
|
15043
|
-
if (
|
|
15295
|
+
if (code3 === "expired_token") {
|
|
15044
15296
|
throw new CLIError("DEVICE_AUTH_EXPIRED", "OpenKey device authorization expired_token: the approval window closed. Run the command again.", ExitCode.AUTH_REQUIRED);
|
|
15045
15297
|
}
|
|
15046
|
-
if (!response.ok) throw new CLIError("DEVICE_AUTH_FAILED", `OpenKey device authorization failed: ${
|
|
15298
|
+
if (!response.ok) throw new CLIError("DEVICE_AUTH_FAILED", `OpenKey device authorization failed: ${code3 ?? `HTTP ${response.status}`}`, ExitCode.ERROR);
|
|
15047
15299
|
const result = value;
|
|
15048
15300
|
if (result?.status === "pending") {
|
|
15049
15301
|
interval = Math.max(interval, Number.isSafeInteger(result.interval) ? result.interval : interval);
|
|
@@ -15252,6 +15504,7 @@ function registerAuthCommand(program) {
|
|
|
15252
15504
|
try {
|
|
15253
15505
|
const globalOpts = cmd.optsWithGlobals();
|
|
15254
15506
|
const ctx = await ProfileManager.resolveContext(globalOpts);
|
|
15507
|
+
await ProfileManager.getProfile(ctx.profile);
|
|
15255
15508
|
await ProfileManager.clearSession(ctx.profile);
|
|
15256
15509
|
outputJson({ profile: ctx.profile, authenticated: false });
|
|
15257
15510
|
} catch (error) {
|
|
@@ -15364,7 +15617,7 @@ function registerAuthCommand(program) {
|
|
|
15364
15617
|
if (profile.authMethod === "openkey" || options.device) {
|
|
15365
15618
|
const key = await ProfileManager.getKey(ctx.profile);
|
|
15366
15619
|
if (!key) {
|
|
15367
|
-
throw new CLIError("NO_KEY", `No key found for profile "${ctx.profile}". Run \`tc
|
|
15620
|
+
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
15621
|
}
|
|
15369
15622
|
const openkeyHost = resolveOpenKeyHost(profile);
|
|
15370
15623
|
const grants = [];
|
|
@@ -15496,6 +15749,15 @@ function registerAuthCommand(program) {
|
|
|
15496
15749
|
return;
|
|
15497
15750
|
}
|
|
15498
15751
|
const imported = normalizeDelegationImport(parsed);
|
|
15752
|
+
const { activateUnboundCompactImport, storedDelegationKind } = await import("@tinycloud/operations/delegation-binding");
|
|
15753
|
+
const kind = storedDelegationKind({ delegation: imported.delegation });
|
|
15754
|
+
if (kind === "refused") {
|
|
15755
|
+
throw new CLIError(
|
|
15756
|
+
"INVALID_AUTH_IMPORT",
|
|
15757
|
+
"Imported delegation must carry exactly one string Authorization header.",
|
|
15758
|
+
ExitCode.USAGE_ERROR
|
|
15759
|
+
);
|
|
15760
|
+
}
|
|
15499
15761
|
let node;
|
|
15500
15762
|
try {
|
|
15501
15763
|
node = await ensureAuthenticated(ctx);
|
|
@@ -15505,18 +15767,33 @@ function registerAuthCommand(program) {
|
|
|
15505
15767
|
if (session || resolveProfilePosture(profile) !== "delegate-session") throw error;
|
|
15506
15768
|
node = (await bootstrapDelegatedSession(ctx, imported.delegation)).node;
|
|
15507
15769
|
}
|
|
15508
|
-
await appendAdditionalDelegation(ctx.profile, storedAdditionalDelegation(
|
|
15509
|
-
imported.delegation,
|
|
15510
|
-
imported.permissions
|
|
15511
|
-
));
|
|
15512
15770
|
const targetsSessionKey = typeof imported.delegation.delegateDID === "string" && principalDidEquals(imported.delegation.delegateDID, node.sessionDid);
|
|
15513
15771
|
let activated = false;
|
|
15514
|
-
|
|
15515
|
-
|
|
15772
|
+
let permissions = imported.permissions;
|
|
15773
|
+
if (targetsSessionKey && kind === "compact") {
|
|
15774
|
+
const record = await activateUnboundCompactImport(
|
|
15775
|
+
node,
|
|
15776
|
+
imported.delegation,
|
|
15777
|
+
ctx.host
|
|
15778
|
+
);
|
|
15779
|
+
await appendAdditionalDelegation(ctx.profile, record);
|
|
15780
|
+
permissions = record.permissions;
|
|
15516
15781
|
activated = true;
|
|
15782
|
+
} else {
|
|
15783
|
+
await appendAdditionalDelegation(ctx.profile, storedAdditionalDelegation(
|
|
15784
|
+
imported.delegation,
|
|
15785
|
+
imported.permissions
|
|
15786
|
+
));
|
|
15787
|
+
if (targetsSessionKey) {
|
|
15788
|
+
await node.useRuntimeDelegation({
|
|
15789
|
+
...imported.delegation,
|
|
15790
|
+
delegationHeader: { Authorization: imported.delegation.delegationHeader.Authorization }
|
|
15791
|
+
});
|
|
15792
|
+
activated = true;
|
|
15793
|
+
}
|
|
15517
15794
|
}
|
|
15518
15795
|
await appendGrantHistory(ctx.profile, {
|
|
15519
|
-
addedCaps:
|
|
15796
|
+
addedCaps: permissions,
|
|
15520
15797
|
source: "cli",
|
|
15521
15798
|
delegationCid: imported.delegation.cid,
|
|
15522
15799
|
expiry: imported.delegation.expiry.toISOString()
|
|
@@ -15527,7 +15804,7 @@ function registerAuthCommand(program) {
|
|
|
15527
15804
|
kind: "tinycloud.auth.delegation",
|
|
15528
15805
|
requestId: imported.requestId ?? null,
|
|
15529
15806
|
delegationCid: imported.delegation.cid,
|
|
15530
|
-
permissions
|
|
15807
|
+
permissions,
|
|
15531
15808
|
expiry: imported.delegation.expiry.toISOString()
|
|
15532
15809
|
});
|
|
15533
15810
|
} catch (error) {
|
|
@@ -15872,7 +16149,7 @@ async function importRequestBoundDelegation(ctx, artifact) {
|
|
|
15872
16149
|
ExitCode.ERROR
|
|
15873
16150
|
);
|
|
15874
16151
|
case "error":
|
|
15875
|
-
throw
|
|
16152
|
+
throw cliErrorFromService(result.error);
|
|
15876
16153
|
}
|
|
15877
16154
|
}
|
|
15878
16155
|
function isStoredDelegationLike(value) {
|
|
@@ -15901,8 +16178,6 @@ async function activateAndStoreOpenKeyGrants(profileName, node, grants, source)
|
|
|
15901
16178
|
for (const { delegation } of grants) await node.useRuntimeDelegation(delegation);
|
|
15902
16179
|
if (grants.length === 0) return;
|
|
15903
16180
|
await ProfileManager.withLock(profileName, async () => {
|
|
15904
|
-
const existing = await loadAdditionalDelegations(profileName);
|
|
15905
|
-
const replacing = new Set(grants.map(({ delegation }) => delegation.cid));
|
|
15906
16181
|
for (const { delegation, effective } of grants) {
|
|
15907
16182
|
await appendGrantHistory(profileName, {
|
|
15908
16183
|
addedCaps: effective,
|
|
@@ -15911,10 +16186,10 @@ async function activateAndStoreOpenKeyGrants(profileName, node, grants, source)
|
|
|
15911
16186
|
expiry: delegation.expiry.toISOString()
|
|
15912
16187
|
});
|
|
15913
16188
|
}
|
|
15914
|
-
await
|
|
15915
|
-
|
|
15916
|
-
|
|
15917
|
-
|
|
16189
|
+
await appendAdditionalDelegations(
|
|
16190
|
+
profileName,
|
|
16191
|
+
grants.map(({ delegation, effective }) => storedAdditionalDelegation(delegation, effective))
|
|
16192
|
+
);
|
|
15918
16193
|
});
|
|
15919
16194
|
}
|
|
15920
16195
|
async function ensureDelegationAuthority(params) {
|
|
@@ -15924,7 +16199,7 @@ async function ensureDelegationAuthority(params) {
|
|
|
15924
16199
|
if (!key) {
|
|
15925
16200
|
throw new CLIError(
|
|
15926
16201
|
"NO_KEY",
|
|
15927
|
-
`No key found for profile "${params.ctx.profile}". Run \`tc
|
|
16202
|
+
`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
16203
|
ExitCode.AUTH_REQUIRED
|
|
15929
16204
|
);
|
|
15930
16205
|
}
|
|
@@ -15996,7 +16271,7 @@ function execCapturedCommand(command) {
|
|
|
15996
16271
|
stdio: "inherit"
|
|
15997
16272
|
});
|
|
15998
16273
|
child.on("error", reject);
|
|
15999
|
-
child.on("exit", (
|
|
16274
|
+
child.on("exit", (code3, signal) => {
|
|
16000
16275
|
if (signal) {
|
|
16001
16276
|
reject(new CLIError(
|
|
16002
16277
|
"COMMAND_SIGNAL",
|
|
@@ -16005,8 +16280,8 @@ function execCapturedCommand(command) {
|
|
|
16005
16280
|
));
|
|
16006
16281
|
return;
|
|
16007
16282
|
}
|
|
16008
|
-
if (
|
|
16009
|
-
process.exitCode =
|
|
16283
|
+
if (code3 && code3 !== 0) {
|
|
16284
|
+
process.exitCode = code3;
|
|
16010
16285
|
}
|
|
16011
16286
|
resolve4();
|
|
16012
16287
|
});
|
|
@@ -16333,15 +16608,15 @@ ${declined.map((permission) => ` ${compactPermission(permission)}`).join("\n")}
|
|
|
16333
16608
|
}
|
|
16334
16609
|
async function refreshOpenKeySession(profileName, host, options = {}) {
|
|
16335
16610
|
const snapshot = await readProfileSnapshot(profileName);
|
|
16611
|
+
const profile = snapshot.profile ?? await ProfileManager.getProfile(profileName);
|
|
16336
16612
|
const key = snapshot.key;
|
|
16337
16613
|
if (!key) {
|
|
16338
16614
|
throw new CLIError(
|
|
16339
16615
|
"NO_KEY",
|
|
16340
|
-
`No key found for profile "${profileName}". Run \`tc
|
|
16616
|
+
`No key found for profile "${profileName}". Run \`tc --profile ${profileName} auth rotate\` to create a new key and sign in.`,
|
|
16341
16617
|
ExitCode.AUTH_REQUIRED
|
|
16342
16618
|
);
|
|
16343
16619
|
}
|
|
16344
|
-
const profile = snapshot.profile ?? await ProfileManager.getProfile(profileName);
|
|
16345
16620
|
if (options.permissions !== void 0) validateLoginPermissions(options.permissions);
|
|
16346
16621
|
const permissions = options.permissions === void 0 ? void 0 : scopedLoginPermissions(options.permissions);
|
|
16347
16622
|
if (permissions !== void 0) {
|
|
@@ -16609,7 +16884,7 @@ function registerDelegationCommand(program) {
|
|
|
16609
16884
|
expiry
|
|
16610
16885
|
});
|
|
16611
16886
|
if (!result.ok) {
|
|
16612
|
-
throw
|
|
16887
|
+
throw cliErrorFromService(result.error);
|
|
16613
16888
|
}
|
|
16614
16889
|
outputJson({
|
|
16615
16890
|
cid: result.data.cid,
|
|
@@ -16629,7 +16904,7 @@ function registerDelegationCommand(program) {
|
|
|
16629
16904
|
const node = await ensureAuthenticated(ctx);
|
|
16630
16905
|
const result = await node.delegationManager.list();
|
|
16631
16906
|
if (!result.ok) {
|
|
16632
|
-
throw
|
|
16907
|
+
throw cliErrorFromService(result.error);
|
|
16633
16908
|
}
|
|
16634
16909
|
let delegations = result.data;
|
|
16635
16910
|
if (options.granted) {
|
|
@@ -16675,7 +16950,7 @@ function registerDelegationCommand(program) {
|
|
|
16675
16950
|
const node = await ensureAuthenticated(ctx);
|
|
16676
16951
|
const result = await node.delegationManager.revoke(cid);
|
|
16677
16952
|
if (!result.ok) {
|
|
16678
|
-
throw
|
|
16953
|
+
throw cliErrorFromService(result.error);
|
|
16679
16954
|
}
|
|
16680
16955
|
outputJson({ cid, revoked: true });
|
|
16681
16956
|
} catch (error) {
|
|
@@ -16800,7 +17075,6 @@ function registerDoctorCommand(program) {
|
|
|
16800
17075
|
init_profiles();
|
|
16801
17076
|
init_formatter();
|
|
16802
17077
|
init_errors();
|
|
16803
|
-
init_constants();
|
|
16804
17078
|
import { readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
|
|
16805
17079
|
import { resolve } from "path";
|
|
16806
17080
|
init_theme();
|
|
@@ -16817,7 +17091,7 @@ function registerDuckdbCommand(program) {
|
|
|
16817
17091
|
() => node.duckdb.db(options.db).query(sqlStr, params)
|
|
16818
17092
|
);
|
|
16819
17093
|
if (!result.ok) {
|
|
16820
|
-
throw
|
|
17094
|
+
throw cliErrorFromService(result.error);
|
|
16821
17095
|
}
|
|
16822
17096
|
const { columns, rows, rowCount } = result.data;
|
|
16823
17097
|
if (shouldOutputJson()) {
|
|
@@ -16849,7 +17123,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
16849
17123
|
() => node.duckdb.db(options.db).execute(sqlStr, params)
|
|
16850
17124
|
);
|
|
16851
17125
|
if (!result.ok) {
|
|
16852
|
-
throw
|
|
17126
|
+
throw cliErrorFromService(result.error);
|
|
16853
17127
|
}
|
|
16854
17128
|
outputJson({ changes: result.data.changes });
|
|
16855
17129
|
} catch (error) {
|
|
@@ -16866,7 +17140,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
16866
17140
|
() => node.duckdb.db(options.db).describe()
|
|
16867
17141
|
);
|
|
16868
17142
|
if (!result.ok) {
|
|
16869
|
-
throw
|
|
17143
|
+
throw cliErrorFromService(result.error);
|
|
16870
17144
|
}
|
|
16871
17145
|
const schema = result.data;
|
|
16872
17146
|
if (shouldOutputJson()) {
|
|
@@ -16911,7 +17185,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
16911
17185
|
() => node.duckdb.db(options.db).export()
|
|
16912
17186
|
);
|
|
16913
17187
|
if (!result.ok) {
|
|
16914
|
-
throw
|
|
17188
|
+
throw cliErrorFromService(result.error);
|
|
16915
17189
|
}
|
|
16916
17190
|
const blob = result.data;
|
|
16917
17191
|
const buffer = Buffer.from(await blob.arrayBuffer());
|
|
@@ -16938,7 +17212,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
16938
17212
|
() => node.duckdb.db(options.db).import(bytes)
|
|
16939
17213
|
);
|
|
16940
17214
|
if (!result.ok) {
|
|
16941
|
-
throw
|
|
17215
|
+
throw cliErrorFromService(result.error);
|
|
16942
17216
|
}
|
|
16943
17217
|
outputJson({
|
|
16944
17218
|
file: filePath,
|
|
@@ -17075,7 +17349,7 @@ init_theme();
|
|
|
17075
17349
|
async function throwKvError(error, spaceUri, profileName) {
|
|
17076
17350
|
const hosted = await unhostedSpaceError(error, spaceUri, profileName);
|
|
17077
17351
|
if (hosted) throw hosted;
|
|
17078
|
-
throw
|
|
17352
|
+
throw cliErrorFromService(error);
|
|
17079
17353
|
}
|
|
17080
17354
|
function isByteCount(value) {
|
|
17081
17355
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
@@ -17088,8 +17362,8 @@ function storageQuotaError(error) {
|
|
|
17088
17362
|
}
|
|
17089
17363
|
function assertAddressableKey(key) {
|
|
17090
17364
|
for (let i = 0; i < key.length; i++) {
|
|
17091
|
-
const
|
|
17092
|
-
if (
|
|
17365
|
+
const code3 = key.charCodeAt(i);
|
|
17366
|
+
if (code3 <= 32 || code3 === 127) {
|
|
17093
17367
|
throw new CLIError("USAGE_ERROR", "KV keys cannot contain spaces or control characters; use a URL-safe key", ExitCode.USAGE_ERROR);
|
|
17094
17368
|
}
|
|
17095
17369
|
}
|
|
@@ -17919,8 +18193,8 @@ async function writeSecretFile(path, value) {
|
|
|
17919
18193
|
if (created) {
|
|
17920
18194
|
await rm3(temp, { force: true }).catch(() => void 0);
|
|
17921
18195
|
}
|
|
17922
|
-
const
|
|
17923
|
-
throw new CLIError("ERROR", `Could not write secret output "${path}"${
|
|
18196
|
+
const code3 = error instanceof Error && "code" in error && typeof error.code === "string" ? ` (${error.code})` : "";
|
|
18197
|
+
throw new CLIError("ERROR", `Could not write secret output "${path}"${code3}.`, ExitCode.ERROR);
|
|
17924
18198
|
}
|
|
17925
18199
|
try {
|
|
17926
18200
|
const parent = await open2(parentPath, "r");
|
|
@@ -18058,8 +18332,8 @@ function shouldRequestSecretPermissions(error) {
|
|
|
18058
18332
|
function thrownPermissionError(error) {
|
|
18059
18333
|
const record = error;
|
|
18060
18334
|
const message = typeof record?.message === "string" ? record.message : String(error);
|
|
18061
|
-
const
|
|
18062
|
-
if (
|
|
18335
|
+
const code3 = typeof record?.code === "string" ? record.code : "PERMISSION_DENIED";
|
|
18336
|
+
if (code3 !== "PERMISSION_DENIED" && !/permission|session expired|autosign|capabilit/i.test(message)) {
|
|
18063
18337
|
return null;
|
|
18064
18338
|
}
|
|
18065
18339
|
return {
|
|
@@ -18267,9 +18541,9 @@ async function resolveDelegatedSecretSource(source, secretPath, space = SECRETS_
|
|
|
18267
18541
|
return { ...selected, source };
|
|
18268
18542
|
}
|
|
18269
18543
|
function mapEncryptionResultError(error) {
|
|
18270
|
-
const
|
|
18271
|
-
const exitCode =
|
|
18272
|
-
return new CLIError(
|
|
18544
|
+
const code3 = error.code || "DECRYPTION_FAILED";
|
|
18545
|
+
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;
|
|
18546
|
+
return new CLIError(code3, error.message, exitCode);
|
|
18273
18547
|
}
|
|
18274
18548
|
function parseDecryptedSecretPayload(data, secretPath) {
|
|
18275
18549
|
const text = new TextDecoder().decode(data);
|
|
@@ -18592,7 +18866,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
18592
18866
|
operation: () => secrets2.list(scopeOptions)
|
|
18593
18867
|
});
|
|
18594
18868
|
if (!result.ok) {
|
|
18595
|
-
throw
|
|
18869
|
+
throw cliErrorFromService(result.error);
|
|
18596
18870
|
}
|
|
18597
18871
|
const secretNames = Array.isArray(result.data) ? result.data : [];
|
|
18598
18872
|
outputJson({
|
|
@@ -18709,7 +18983,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
18709
18983
|
operation: () => secrets2.put(name, secretValue, scopeOptions)
|
|
18710
18984
|
});
|
|
18711
18985
|
if (!result.ok) {
|
|
18712
|
-
throw
|
|
18986
|
+
throw cliErrorFromService(result.error);
|
|
18713
18987
|
}
|
|
18714
18988
|
outputJson({ name, written: true });
|
|
18715
18989
|
} catch (error) {
|
|
@@ -18735,7 +19009,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
18735
19009
|
operation: () => secrets2.delete(name, scopeOptions)
|
|
18736
19010
|
});
|
|
18737
19011
|
if (!result.ok) {
|
|
18738
|
-
throw
|
|
19012
|
+
throw cliErrorFromService(result.error);
|
|
18739
19013
|
}
|
|
18740
19014
|
outputJson({ name, deleted: true });
|
|
18741
19015
|
} catch (error) {
|
|
@@ -18803,13 +19077,13 @@ function _abool2(value, title = "") {
|
|
|
18803
19077
|
}
|
|
18804
19078
|
return value;
|
|
18805
19079
|
}
|
|
18806
|
-
function _abytes2(value,
|
|
19080
|
+
function _abytes2(value, length4, title = "") {
|
|
18807
19081
|
const bytes = isBytes(value);
|
|
18808
19082
|
const len = value?.length;
|
|
18809
|
-
const needsLen =
|
|
18810
|
-
if (!bytes || needsLen && len !==
|
|
19083
|
+
const needsLen = length4 !== void 0;
|
|
19084
|
+
if (!bytes || needsLen && len !== length4) {
|
|
18811
19085
|
const prefix = title && `"${title}" `;
|
|
18812
|
-
const ofLen = needsLen ? ` of length ${
|
|
19086
|
+
const ofLen = needsLen ? ` of length ${length4}` : "";
|
|
18813
19087
|
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
18814
19088
|
throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
|
|
18815
19089
|
}
|
|
@@ -19332,15 +19606,15 @@ var wNAF = class {
|
|
|
19332
19606
|
const { windows, windowSize } = calcWOpts(W, this.bits);
|
|
19333
19607
|
const points = [];
|
|
19334
19608
|
let p = point;
|
|
19335
|
-
let
|
|
19609
|
+
let base4 = p;
|
|
19336
19610
|
for (let window = 0; window < windows; window++) {
|
|
19337
|
-
|
|
19338
|
-
points.push(
|
|
19611
|
+
base4 = p;
|
|
19612
|
+
points.push(base4);
|
|
19339
19613
|
for (let i = 1; i < windowSize; i++) {
|
|
19340
|
-
|
|
19341
|
-
points.push(
|
|
19614
|
+
base4 = base4.add(p);
|
|
19615
|
+
points.push(base4);
|
|
19342
19616
|
}
|
|
19343
|
-
p =
|
|
19617
|
+
p = base4.double();
|
|
19344
19618
|
}
|
|
19345
19619
|
return points;
|
|
19346
19620
|
}
|
|
@@ -20360,13 +20634,13 @@ var BLAKE2 = class extends Hash {
|
|
|
20360
20634
|
return res;
|
|
20361
20635
|
}
|
|
20362
20636
|
_cloneInto(to) {
|
|
20363
|
-
const { buffer, length:
|
|
20637
|
+
const { buffer, length: length4, finished, destroyed, outputLen, pos } = this;
|
|
20364
20638
|
to || (to = new this.constructor({ dkLen: outputLen }));
|
|
20365
20639
|
to.set(...this.get());
|
|
20366
20640
|
to.buffer.set(buffer);
|
|
20367
20641
|
to.destroyed = destroyed;
|
|
20368
20642
|
to.finished = finished;
|
|
20369
|
-
to.length =
|
|
20643
|
+
to.length = length4;
|
|
20370
20644
|
to.pos = pos;
|
|
20371
20645
|
to.outputLen = outputLen;
|
|
20372
20646
|
return to;
|
|
@@ -21600,8 +21874,8 @@ function isValidJWT2(jwt, alg) {
|
|
|
21600
21874
|
const [header] = jwt.split(".");
|
|
21601
21875
|
if (!header)
|
|
21602
21876
|
return false;
|
|
21603
|
-
const
|
|
21604
|
-
const decoded = JSON.parse(atob(
|
|
21877
|
+
const base6422 = header.replace(/-/g, "+").replace(/_/g, "/").padEnd(header.length + (4 - header.length % 4) % 4, "=");
|
|
21878
|
+
const decoded = JSON.parse(atob(base6422));
|
|
21605
21879
|
if (typeof decoded !== "object" || decoded === null)
|
|
21606
21880
|
return false;
|
|
21607
21881
|
if ("typ" in decoded && decoded?.typ !== "JWT")
|
|
@@ -24255,23 +24529,23 @@ var ZodEffects2 = class extends ZodType2 {
|
|
|
24255
24529
|
}
|
|
24256
24530
|
if (effect.type === "transform") {
|
|
24257
24531
|
if (ctx.common.async === false) {
|
|
24258
|
-
const
|
|
24532
|
+
const base33 = this._def.schema._parseSync({
|
|
24259
24533
|
data: ctx.data,
|
|
24260
24534
|
path: ctx.path,
|
|
24261
24535
|
parent: ctx
|
|
24262
24536
|
});
|
|
24263
|
-
if (!isValid2(
|
|
24537
|
+
if (!isValid2(base33))
|
|
24264
24538
|
return INVALID2;
|
|
24265
|
-
const result = effect.transform(
|
|
24539
|
+
const result = effect.transform(base33.value, checkCtx);
|
|
24266
24540
|
if (result instanceof Promise) {
|
|
24267
24541
|
throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`);
|
|
24268
24542
|
}
|
|
24269
24543
|
return { status: status.value, value: result };
|
|
24270
24544
|
} else {
|
|
24271
|
-
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((
|
|
24272
|
-
if (!isValid2(
|
|
24545
|
+
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base33) => {
|
|
24546
|
+
if (!isValid2(base33))
|
|
24273
24547
|
return INVALID2;
|
|
24274
|
-
return Promise.resolve(effect.transform(
|
|
24548
|
+
return Promise.resolve(effect.transform(base33.value, checkCtx)).then((result) => ({
|
|
24275
24549
|
status: status.value,
|
|
24276
24550
|
value: result
|
|
24277
24551
|
}));
|
|
@@ -25179,9 +25453,9 @@ var cache = /* @__PURE__ */ new WeakMap();
|
|
|
25179
25453
|
function baseCache(cid2) {
|
|
25180
25454
|
const baseCache22 = cache.get(cid2);
|
|
25181
25455
|
if (baseCache22 == null) {
|
|
25182
|
-
const
|
|
25183
|
-
cache.set(cid2,
|
|
25184
|
-
return
|
|
25456
|
+
const baseCache32 = /* @__PURE__ */ new Map();
|
|
25457
|
+
cache.set(cid2, baseCache32);
|
|
25458
|
+
return baseCache32;
|
|
25185
25459
|
}
|
|
25186
25460
|
return baseCache22;
|
|
25187
25461
|
}
|
|
@@ -26419,7 +26693,7 @@ function base2(ALPHABET, name) {
|
|
|
26419
26693
|
var LEADER = ALPHABET.charAt(0);
|
|
26420
26694
|
var FACTOR = Math.log(BASE) / Math.log(256);
|
|
26421
26695
|
var iFACTOR = Math.log(256) / Math.log(BASE);
|
|
26422
|
-
function
|
|
26696
|
+
function encode52(source) {
|
|
26423
26697
|
if (source instanceof Uint8Array)
|
|
26424
26698
|
;
|
|
26425
26699
|
else if (ArrayBuffer.isView(source)) {
|
|
@@ -26434,7 +26708,7 @@ function base2(ALPHABET, name) {
|
|
|
26434
26708
|
return "";
|
|
26435
26709
|
}
|
|
26436
26710
|
var zeroes = 0;
|
|
26437
|
-
var
|
|
26711
|
+
var length32 = 0;
|
|
26438
26712
|
var pbegin = 0;
|
|
26439
26713
|
var pend = source.length;
|
|
26440
26714
|
while (pbegin !== pend && source[pbegin] === 0) {
|
|
@@ -26446,7 +26720,7 @@ function base2(ALPHABET, name) {
|
|
|
26446
26720
|
while (pbegin !== pend) {
|
|
26447
26721
|
var carry = source[pbegin];
|
|
26448
26722
|
var i2 = 0;
|
|
26449
|
-
for (var it1 = size - 1; (carry !== 0 || i2 <
|
|
26723
|
+
for (var it1 = size - 1; (carry !== 0 || i2 < length32) && it1 !== -1; it1--, i2++) {
|
|
26450
26724
|
carry += 256 * b58[it1] >>> 0;
|
|
26451
26725
|
b58[it1] = carry % BASE >>> 0;
|
|
26452
26726
|
carry = carry / BASE >>> 0;
|
|
@@ -26454,10 +26728,10 @@ function base2(ALPHABET, name) {
|
|
|
26454
26728
|
if (carry !== 0) {
|
|
26455
26729
|
throw new Error("Non-zero carry");
|
|
26456
26730
|
}
|
|
26457
|
-
|
|
26731
|
+
length32 = i2;
|
|
26458
26732
|
pbegin++;
|
|
26459
26733
|
}
|
|
26460
|
-
var it2 = size -
|
|
26734
|
+
var it2 = size - length32;
|
|
26461
26735
|
while (it2 !== size && b58[it2] === 0) {
|
|
26462
26736
|
it2++;
|
|
26463
26737
|
}
|
|
@@ -26479,7 +26753,7 @@ function base2(ALPHABET, name) {
|
|
|
26479
26753
|
return;
|
|
26480
26754
|
}
|
|
26481
26755
|
var zeroes = 0;
|
|
26482
|
-
var
|
|
26756
|
+
var length32 = 0;
|
|
26483
26757
|
while (source[psz] === LEADER) {
|
|
26484
26758
|
zeroes++;
|
|
26485
26759
|
psz++;
|
|
@@ -26492,7 +26766,7 @@ function base2(ALPHABET, name) {
|
|
|
26492
26766
|
return;
|
|
26493
26767
|
}
|
|
26494
26768
|
var i2 = 0;
|
|
26495
|
-
for (var it3 = size - 1; (carry !== 0 || i2 <
|
|
26769
|
+
for (var it3 = size - 1; (carry !== 0 || i2 < length32) && it3 !== -1; it3--, i2++) {
|
|
26496
26770
|
carry += BASE * b256[it3] >>> 0;
|
|
26497
26771
|
b256[it3] = carry % 256 >>> 0;
|
|
26498
26772
|
carry = carry / 256 >>> 0;
|
|
@@ -26500,13 +26774,13 @@ function base2(ALPHABET, name) {
|
|
|
26500
26774
|
if (carry !== 0) {
|
|
26501
26775
|
throw new Error("Non-zero carry");
|
|
26502
26776
|
}
|
|
26503
|
-
|
|
26777
|
+
length32 = i2;
|
|
26504
26778
|
psz++;
|
|
26505
26779
|
}
|
|
26506
26780
|
if (source[psz] === " ") {
|
|
26507
26781
|
return;
|
|
26508
26782
|
}
|
|
26509
|
-
var it4 = size -
|
|
26783
|
+
var it4 = size - length32;
|
|
26510
26784
|
while (it4 !== size && b256[it4] === 0) {
|
|
26511
26785
|
it4++;
|
|
26512
26786
|
}
|
|
@@ -26517,7 +26791,7 @@ function base2(ALPHABET, name) {
|
|
|
26517
26791
|
}
|
|
26518
26792
|
return vch;
|
|
26519
26793
|
}
|
|
26520
|
-
function
|
|
26794
|
+
function decode92(string) {
|
|
26521
26795
|
var buffer = decodeUnsafe(string);
|
|
26522
26796
|
if (buffer) {
|
|
26523
26797
|
return buffer;
|
|
@@ -26525,9 +26799,9 @@ function base2(ALPHABET, name) {
|
|
|
26525
26799
|
throw new Error(`Non-${name} character`);
|
|
26526
26800
|
}
|
|
26527
26801
|
return {
|
|
26528
|
-
encode:
|
|
26802
|
+
encode: encode52,
|
|
26529
26803
|
decodeUnsafe,
|
|
26530
|
-
decode:
|
|
26804
|
+
decode: decode92
|
|
26531
26805
|
};
|
|
26532
26806
|
}
|
|
26533
26807
|
var src2 = base2;
|
|
@@ -26625,16 +26899,16 @@ var Codec2 = class {
|
|
|
26625
26899
|
return this.decoder.decode(input);
|
|
26626
26900
|
}
|
|
26627
26901
|
};
|
|
26628
|
-
function from2({ name, prefix, encode:
|
|
26629
|
-
return new Codec2(name, prefix,
|
|
26902
|
+
function from2({ name, prefix, encode: encode52, decode: decode92 }) {
|
|
26903
|
+
return new Codec2(name, prefix, encode52, decode92);
|
|
26630
26904
|
}
|
|
26631
26905
|
function baseX2({ name, prefix, alphabet }) {
|
|
26632
|
-
const { encode:
|
|
26906
|
+
const { encode: encode52, decode: decode92 } = base_x_default2(alphabet, name);
|
|
26633
26907
|
return from2({
|
|
26634
26908
|
prefix,
|
|
26635
26909
|
name,
|
|
26636
|
-
encode:
|
|
26637
|
-
decode: (text) => coerce3(
|
|
26910
|
+
encode: encode52,
|
|
26911
|
+
decode: (text) => coerce3(decode92(text))
|
|
26638
26912
|
});
|
|
26639
26913
|
}
|
|
26640
26914
|
function decode5(string, alphabetIdx, bitsPerChar, name) {
|
|
@@ -27004,24 +27278,24 @@ var Digest2 = class {
|
|
|
27004
27278
|
this.bytes = bytes3;
|
|
27005
27279
|
}
|
|
27006
27280
|
};
|
|
27007
|
-
function format2(link2,
|
|
27281
|
+
function format2(link2, base33) {
|
|
27008
27282
|
const { bytes: bytes3, version } = link2;
|
|
27009
27283
|
switch (version) {
|
|
27010
27284
|
case 0:
|
|
27011
|
-
return toStringV02(bytes3, baseCache2(link2),
|
|
27285
|
+
return toStringV02(bytes3, baseCache2(link2), base33 ?? base58btc2.encoder);
|
|
27012
27286
|
default:
|
|
27013
|
-
return toStringV12(bytes3, baseCache2(link2),
|
|
27287
|
+
return toStringV12(bytes3, baseCache2(link2), base33 ?? base322.encoder);
|
|
27014
27288
|
}
|
|
27015
27289
|
}
|
|
27016
27290
|
var cache2 = /* @__PURE__ */ new WeakMap();
|
|
27017
27291
|
function baseCache2(cid2) {
|
|
27018
|
-
const
|
|
27019
|
-
if (
|
|
27292
|
+
const baseCache32 = cache2.get(cid2);
|
|
27293
|
+
if (baseCache32 == null) {
|
|
27020
27294
|
const baseCache4 = /* @__PURE__ */ new Map();
|
|
27021
27295
|
cache2.set(cid2, baseCache4);
|
|
27022
27296
|
return baseCache4;
|
|
27023
27297
|
}
|
|
27024
|
-
return
|
|
27298
|
+
return baseCache32;
|
|
27025
27299
|
}
|
|
27026
27300
|
var CID2 = class _CID2 {
|
|
27027
27301
|
code;
|
|
@@ -27100,8 +27374,8 @@ var CID2 = class _CID2 {
|
|
|
27100
27374
|
const unknown = other;
|
|
27101
27375
|
return unknown != null && self.code === unknown.code && self.version === unknown.version && equals4(self.multihash, unknown.multihash);
|
|
27102
27376
|
}
|
|
27103
|
-
toString(
|
|
27104
|
-
return format2(this,
|
|
27377
|
+
toString(base33) {
|
|
27378
|
+
return format2(this, base33);
|
|
27105
27379
|
}
|
|
27106
27380
|
toJSON() {
|
|
27107
27381
|
return { "/": format2(this) };
|
|
@@ -27233,8 +27507,8 @@ var CID2 = class _CID2 {
|
|
|
27233
27507
|
static inspectBytes(initialBytes) {
|
|
27234
27508
|
let offset = 0;
|
|
27235
27509
|
const next = () => {
|
|
27236
|
-
const [i,
|
|
27237
|
-
offset +=
|
|
27510
|
+
const [i, length32] = decode7(initialBytes.subarray(offset));
|
|
27511
|
+
offset += length32;
|
|
27238
27512
|
return i;
|
|
27239
27513
|
};
|
|
27240
27514
|
let version = next();
|
|
@@ -27261,8 +27535,8 @@ var CID2 = class _CID2 {
|
|
|
27261
27535
|
* throw an error if encoding of the CID is not compatible with supplied (or
|
|
27262
27536
|
* a default decoder).
|
|
27263
27537
|
*/
|
|
27264
|
-
static parse(source,
|
|
27265
|
-
const [prefix, bytes3] = parseCIDtoBytes2(source,
|
|
27538
|
+
static parse(source, base33) {
|
|
27539
|
+
const [prefix, bytes3] = parseCIDtoBytes2(source, base33);
|
|
27266
27540
|
const cid2 = _CID2.decode(bytes3);
|
|
27267
27541
|
if (cid2.version === 0 && source[0] !== "Q") {
|
|
27268
27542
|
throw Error("Version 0 CID string must not include multibase prefix");
|
|
@@ -27271,56 +27545,56 @@ var CID2 = class _CID2 {
|
|
|
27271
27545
|
return cid2;
|
|
27272
27546
|
}
|
|
27273
27547
|
};
|
|
27274
|
-
function parseCIDtoBytes2(source,
|
|
27548
|
+
function parseCIDtoBytes2(source, base33) {
|
|
27275
27549
|
switch (source[0]) {
|
|
27276
27550
|
// CIDv0 is parsed differently
|
|
27277
27551
|
case "Q": {
|
|
27278
|
-
const decoder =
|
|
27552
|
+
const decoder = base33 ?? base58btc2;
|
|
27279
27553
|
return [
|
|
27280
27554
|
base58btc2.prefix,
|
|
27281
27555
|
decoder.decode(`${base58btc2.prefix}${source}`)
|
|
27282
27556
|
];
|
|
27283
27557
|
}
|
|
27284
27558
|
case base58btc2.prefix: {
|
|
27285
|
-
const decoder =
|
|
27559
|
+
const decoder = base33 ?? base58btc2;
|
|
27286
27560
|
return [base58btc2.prefix, decoder.decode(source)];
|
|
27287
27561
|
}
|
|
27288
27562
|
case base322.prefix: {
|
|
27289
|
-
const decoder =
|
|
27563
|
+
const decoder = base33 ?? base322;
|
|
27290
27564
|
return [base322.prefix, decoder.decode(source)];
|
|
27291
27565
|
}
|
|
27292
27566
|
case base362.prefix: {
|
|
27293
|
-
const decoder =
|
|
27567
|
+
const decoder = base33 ?? base362;
|
|
27294
27568
|
return [base362.prefix, decoder.decode(source)];
|
|
27295
27569
|
}
|
|
27296
27570
|
default: {
|
|
27297
|
-
if (
|
|
27571
|
+
if (base33 == null) {
|
|
27298
27572
|
throw Error("To parse non base32, base36 or base58btc encoded CID multibase decoder must be provided");
|
|
27299
27573
|
}
|
|
27300
|
-
return [source[0],
|
|
27574
|
+
return [source[0], base33.decode(source)];
|
|
27301
27575
|
}
|
|
27302
27576
|
}
|
|
27303
27577
|
}
|
|
27304
|
-
function toStringV02(bytes3,
|
|
27305
|
-
const { prefix } =
|
|
27578
|
+
function toStringV02(bytes3, cache32, base33) {
|
|
27579
|
+
const { prefix } = base33;
|
|
27306
27580
|
if (prefix !== base58btc2.prefix) {
|
|
27307
|
-
throw Error(`Cannot string encode V0 in ${
|
|
27581
|
+
throw Error(`Cannot string encode V0 in ${base33.name} encoding`);
|
|
27308
27582
|
}
|
|
27309
|
-
const cid2 =
|
|
27583
|
+
const cid2 = cache32.get(prefix);
|
|
27310
27584
|
if (cid2 == null) {
|
|
27311
|
-
const cid3 =
|
|
27312
|
-
|
|
27585
|
+
const cid3 = base33.encode(bytes3).slice(1);
|
|
27586
|
+
cache32.set(prefix, cid3);
|
|
27313
27587
|
return cid3;
|
|
27314
27588
|
} else {
|
|
27315
27589
|
return cid2;
|
|
27316
27590
|
}
|
|
27317
27591
|
}
|
|
27318
|
-
function toStringV12(bytes3,
|
|
27319
|
-
const { prefix } =
|
|
27320
|
-
const cid2 =
|
|
27592
|
+
function toStringV12(bytes3, cache32, base33) {
|
|
27593
|
+
const { prefix } = base33;
|
|
27594
|
+
const cid2 = cache32.get(prefix);
|
|
27321
27595
|
if (cid2 == null) {
|
|
27322
|
-
const cid3 =
|
|
27323
|
-
|
|
27596
|
+
const cid3 = base33.encode(bytes3);
|
|
27597
|
+
cache32.set(prefix, cid3);
|
|
27324
27598
|
return cid3;
|
|
27325
27599
|
} else {
|
|
27326
27600
|
return cid2;
|
|
@@ -27374,11 +27648,12 @@ function historyRecordForPublishedShare(result, now = /* @__PURE__ */ new Date()
|
|
|
27374
27648
|
};
|
|
27375
27649
|
}
|
|
27376
27650
|
var ShareNotifyError = class extends Error {
|
|
27377
|
-
|
|
27378
|
-
constructor(message = "share delivery did not complete") {
|
|
27651
|
+
constructor(message = "share delivery did not complete", reason) {
|
|
27379
27652
|
super(message);
|
|
27653
|
+
this.reason = reason;
|
|
27380
27654
|
this.name = "ShareNotifyError";
|
|
27381
27655
|
}
|
|
27656
|
+
code = "delivery-failed";
|
|
27382
27657
|
};
|
|
27383
27658
|
function recipientMatchesShareRecord(record, recipient) {
|
|
27384
27659
|
const matcher = record.recipientMatcher;
|
|
@@ -27388,6 +27663,11 @@ function recipientMatchesShareRecord(record, recipient) {
|
|
|
27388
27663
|
if (matcher.kind === "emailDomain") return mailbox.domain === matcher.value;
|
|
27389
27664
|
return false;
|
|
27390
27665
|
}
|
|
27666
|
+
function shareDeliveryWindowExpiresAt(record) {
|
|
27667
|
+
const expiresAt = Math.min(Date.parse(record.expiresAt), Date.parse(record.registeredAt) + 5 * 60 * 1e3);
|
|
27668
|
+
if (!Number.isFinite(expiresAt)) throw new ShareNotifyError("share delivery history has invalid timestamps");
|
|
27669
|
+
return expiresAt;
|
|
27670
|
+
}
|
|
27391
27671
|
async function notifyShare(input) {
|
|
27392
27672
|
const mailbox = canonicalMailbox(input.recipient);
|
|
27393
27673
|
if (!input.shareId || mailbox === void 0) throw new ShareNotifyError("recipient is invalid");
|
|
@@ -27398,19 +27678,59 @@ async function notifyShare(input) {
|
|
|
27398
27678
|
const idempotencyKey = input.idempotencyKey ?? await defaultIdempotencyKey(input.shareId, recipient);
|
|
27399
27679
|
const attemptsLimit = input.maxAttempts ?? 3;
|
|
27400
27680
|
if (!Number.isSafeInteger(attemptsLimit) || attemptsLimit < 1 || attemptsLimit > 8) throw new ShareNotifyError("maxAttempts is invalid");
|
|
27681
|
+
if (input.signal?.aborted) throw new ShareNotifyError("share delivery was cancelled");
|
|
27682
|
+
if (input.checkDeliveryWindow && input.record !== void 0 && shareDeliveryWindowExpiresAt(input.record) <= Date.now()) {
|
|
27683
|
+
return {
|
|
27684
|
+
protocol: "tinycloud-share",
|
|
27685
|
+
version: 1,
|
|
27686
|
+
shareId: input.shareId,
|
|
27687
|
+
state: "partial-failure",
|
|
27688
|
+
idempotencyKey,
|
|
27689
|
+
attempts: 1,
|
|
27690
|
+
retryable: false,
|
|
27691
|
+
reason: "delivery-window-expired"
|
|
27692
|
+
};
|
|
27693
|
+
}
|
|
27401
27694
|
let attempts = 0;
|
|
27402
|
-
let lastError;
|
|
27403
27695
|
while (attempts < attemptsLimit) {
|
|
27404
27696
|
if (input.signal?.aborted) throw new ShareNotifyError("share delivery was cancelled");
|
|
27405
27697
|
attempts += 1;
|
|
27406
27698
|
try {
|
|
27407
27699
|
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 {
|
|
27700
|
+
return {
|
|
27701
|
+
protocol: "tinycloud-share",
|
|
27702
|
+
version: 1,
|
|
27703
|
+
shareId: input.shareId,
|
|
27704
|
+
state: state === "delivered" && input.record?.deliveredRecipients?.includes(recipient) ? "already-delivered" : state,
|
|
27705
|
+
idempotencyKey,
|
|
27706
|
+
attempts
|
|
27707
|
+
};
|
|
27409
27708
|
} catch (error) {
|
|
27410
|
-
|
|
27709
|
+
if (error instanceof ShareNotifyError && error.reason === "delivery-window-expired") {
|
|
27710
|
+
return {
|
|
27711
|
+
protocol: "tinycloud-share",
|
|
27712
|
+
version: 1,
|
|
27713
|
+
shareId: input.shareId,
|
|
27714
|
+
state: "partial-failure",
|
|
27715
|
+
idempotencyKey,
|
|
27716
|
+
attempts,
|
|
27717
|
+
retryable: false,
|
|
27718
|
+
reason: "delivery-window-expired"
|
|
27719
|
+
};
|
|
27720
|
+
}
|
|
27721
|
+
if (error !== null && typeof error === "object" && "status" in error && (error.status === 401 || error.status === 403)) {
|
|
27722
|
+
return {
|
|
27723
|
+
protocol: "tinycloud-share",
|
|
27724
|
+
version: 1,
|
|
27725
|
+
shareId: input.shareId,
|
|
27726
|
+
state: "partial-failure",
|
|
27727
|
+
idempotencyKey,
|
|
27728
|
+
attempts,
|
|
27729
|
+
retryable: false
|
|
27730
|
+
};
|
|
27731
|
+
}
|
|
27411
27732
|
}
|
|
27412
27733
|
}
|
|
27413
|
-
void lastError;
|
|
27414
27734
|
return { protocol: "tinycloud-share", version: 1, shareId: input.shareId, state: "partial-failure", idempotencyKey, attempts, retryable: true };
|
|
27415
27735
|
}
|
|
27416
27736
|
async function defaultIdempotencyKey(shareId, recipient) {
|
|
@@ -27454,7 +27774,11 @@ async function revokeShare(input) {
|
|
|
27454
27774
|
});
|
|
27455
27775
|
}
|
|
27456
27776
|
const revokedAt = (input.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
|
|
27457
|
-
if (input.records !== void 0)
|
|
27777
|
+
if (input.records?.update !== void 0) {
|
|
27778
|
+
await input.records.update(input.record.shareId, (record) => ({ ...record, revokedAt }));
|
|
27779
|
+
} else if (input.records !== void 0) {
|
|
27780
|
+
await input.records.put({ ...input.record, revokedAt });
|
|
27781
|
+
}
|
|
27458
27782
|
return { state: "revoked", target, delegationCid, revokedAt };
|
|
27459
27783
|
}
|
|
27460
27784
|
function redactRecord(record, revealLink, link2) {
|
|
@@ -27502,225 +27826,1548 @@ function parseNativeShareUrl(value) {
|
|
|
27502
27826
|
return token;
|
|
27503
27827
|
}
|
|
27504
27828
|
|
|
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);
|
|
27829
|
+
// ../share-envelope/dist/index.js
|
|
27830
|
+
var empty3 = new Uint8Array(0);
|
|
27831
|
+
function equals5(aa, bb) {
|
|
27832
|
+
if (aa === bb) {
|
|
27833
|
+
return true;
|
|
27561
27834
|
}
|
|
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
|
-
);
|
|
27835
|
+
if (aa.byteLength !== bb.byteLength) {
|
|
27836
|
+
return false;
|
|
27582
27837
|
}
|
|
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");
|
|
27838
|
+
for (let ii = 0; ii < aa.byteLength; ii++) {
|
|
27839
|
+
if (aa[ii] !== bb[ii]) {
|
|
27840
|
+
return false;
|
|
27615
27841
|
}
|
|
27616
27842
|
}
|
|
27843
|
+
return true;
|
|
27617
27844
|
}
|
|
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();
|
|
27845
|
+
function coerce4(o) {
|
|
27846
|
+
if (o instanceof Uint8Array && o.constructor.name === "Uint8Array") {
|
|
27847
|
+
return o;
|
|
27670
27848
|
}
|
|
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";
|
|
27849
|
+
if (o instanceof ArrayBuffer) {
|
|
27850
|
+
return new Uint8Array(o);
|
|
27680
27851
|
}
|
|
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);
|
|
27852
|
+
if (ArrayBuffer.isView(o)) {
|
|
27853
|
+
return new Uint8Array(o.buffer, o.byteOffset, o.byteLength);
|
|
27699
27854
|
}
|
|
27855
|
+
throw new Error("Unknown type, must be binary type");
|
|
27700
27856
|
}
|
|
27701
|
-
function
|
|
27702
|
-
if (
|
|
27703
|
-
|
|
27704
|
-
|
|
27705
|
-
|
|
27706
|
-
|
|
27707
|
-
|
|
27708
|
-
|
|
27709
|
-
|
|
27710
|
-
|
|
27711
|
-
|
|
27712
|
-
|
|
27713
|
-
|
|
27714
|
-
|
|
27715
|
-
|
|
27716
|
-
|
|
27717
|
-
|
|
27718
|
-
|
|
27719
|
-
|
|
27720
|
-
|
|
27721
|
-
|
|
27722
|
-
|
|
27723
|
-
|
|
27857
|
+
function base3(ALPHABET, name) {
|
|
27858
|
+
if (ALPHABET.length >= 255) {
|
|
27859
|
+
throw new TypeError("Alphabet too long");
|
|
27860
|
+
}
|
|
27861
|
+
var BASE_MAP = new Uint8Array(256);
|
|
27862
|
+
for (var j = 0; j < BASE_MAP.length; j++) {
|
|
27863
|
+
BASE_MAP[j] = 255;
|
|
27864
|
+
}
|
|
27865
|
+
for (var i = 0; i < ALPHABET.length; i++) {
|
|
27866
|
+
var x = ALPHABET.charAt(i);
|
|
27867
|
+
var xc = x.charCodeAt(0);
|
|
27868
|
+
if (BASE_MAP[xc] !== 255) {
|
|
27869
|
+
throw new TypeError(x + " is ambiguous");
|
|
27870
|
+
}
|
|
27871
|
+
BASE_MAP[xc] = i;
|
|
27872
|
+
}
|
|
27873
|
+
var BASE = ALPHABET.length;
|
|
27874
|
+
var LEADER = ALPHABET.charAt(0);
|
|
27875
|
+
var FACTOR = Math.log(BASE) / Math.log(256);
|
|
27876
|
+
var iFACTOR = Math.log(256) / Math.log(BASE);
|
|
27877
|
+
function encode32(source) {
|
|
27878
|
+
if (source instanceof Uint8Array)
|
|
27879
|
+
;
|
|
27880
|
+
else if (ArrayBuffer.isView(source)) {
|
|
27881
|
+
source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
27882
|
+
} else if (Array.isArray(source)) {
|
|
27883
|
+
source = Uint8Array.from(source);
|
|
27884
|
+
}
|
|
27885
|
+
if (!(source instanceof Uint8Array)) {
|
|
27886
|
+
throw new TypeError("Expected Uint8Array");
|
|
27887
|
+
}
|
|
27888
|
+
if (source.length === 0) {
|
|
27889
|
+
return "";
|
|
27890
|
+
}
|
|
27891
|
+
var zeroes = 0;
|
|
27892
|
+
var length22 = 0;
|
|
27893
|
+
var pbegin = 0;
|
|
27894
|
+
var pend = source.length;
|
|
27895
|
+
while (pbegin !== pend && source[pbegin] === 0) {
|
|
27896
|
+
pbegin++;
|
|
27897
|
+
zeroes++;
|
|
27898
|
+
}
|
|
27899
|
+
var size = (pend - pbegin) * iFACTOR + 1 >>> 0;
|
|
27900
|
+
var b58 = new Uint8Array(size);
|
|
27901
|
+
while (pbegin !== pend) {
|
|
27902
|
+
var carry = source[pbegin];
|
|
27903
|
+
var i2 = 0;
|
|
27904
|
+
for (var it1 = size - 1; (carry !== 0 || i2 < length22) && it1 !== -1; it1--, i2++) {
|
|
27905
|
+
carry += 256 * b58[it1] >>> 0;
|
|
27906
|
+
b58[it1] = carry % BASE >>> 0;
|
|
27907
|
+
carry = carry / BASE >>> 0;
|
|
27908
|
+
}
|
|
27909
|
+
if (carry !== 0) {
|
|
27910
|
+
throw new Error("Non-zero carry");
|
|
27911
|
+
}
|
|
27912
|
+
length22 = i2;
|
|
27913
|
+
pbegin++;
|
|
27914
|
+
}
|
|
27915
|
+
var it2 = size - length22;
|
|
27916
|
+
while (it2 !== size && b58[it2] === 0) {
|
|
27917
|
+
it2++;
|
|
27918
|
+
}
|
|
27919
|
+
var str = LEADER.repeat(zeroes);
|
|
27920
|
+
for (; it2 < size; ++it2) {
|
|
27921
|
+
str += ALPHABET.charAt(b58[it2]);
|
|
27922
|
+
}
|
|
27923
|
+
return str;
|
|
27924
|
+
}
|
|
27925
|
+
function decodeUnsafe(source) {
|
|
27926
|
+
if (typeof source !== "string") {
|
|
27927
|
+
throw new TypeError("Expected String");
|
|
27928
|
+
}
|
|
27929
|
+
if (source.length === 0) {
|
|
27930
|
+
return new Uint8Array();
|
|
27931
|
+
}
|
|
27932
|
+
var psz = 0;
|
|
27933
|
+
if (source[psz] === " ") {
|
|
27934
|
+
return;
|
|
27935
|
+
}
|
|
27936
|
+
var zeroes = 0;
|
|
27937
|
+
var length22 = 0;
|
|
27938
|
+
while (source[psz] === LEADER) {
|
|
27939
|
+
zeroes++;
|
|
27940
|
+
psz++;
|
|
27941
|
+
}
|
|
27942
|
+
var size = (source.length - psz) * FACTOR + 1 >>> 0;
|
|
27943
|
+
var b256 = new Uint8Array(size);
|
|
27944
|
+
while (source[psz]) {
|
|
27945
|
+
var carry = BASE_MAP[source.charCodeAt(psz)];
|
|
27946
|
+
if (carry === 255) {
|
|
27947
|
+
return;
|
|
27948
|
+
}
|
|
27949
|
+
var i2 = 0;
|
|
27950
|
+
for (var it3 = size - 1; (carry !== 0 || i2 < length22) && it3 !== -1; it3--, i2++) {
|
|
27951
|
+
carry += BASE * b256[it3] >>> 0;
|
|
27952
|
+
b256[it3] = carry % 256 >>> 0;
|
|
27953
|
+
carry = carry / 256 >>> 0;
|
|
27954
|
+
}
|
|
27955
|
+
if (carry !== 0) {
|
|
27956
|
+
throw new Error("Non-zero carry");
|
|
27957
|
+
}
|
|
27958
|
+
length22 = i2;
|
|
27959
|
+
psz++;
|
|
27960
|
+
}
|
|
27961
|
+
if (source[psz] === " ") {
|
|
27962
|
+
return;
|
|
27963
|
+
}
|
|
27964
|
+
var it4 = size - length22;
|
|
27965
|
+
while (it4 !== size && b256[it4] === 0) {
|
|
27966
|
+
it4++;
|
|
27967
|
+
}
|
|
27968
|
+
var vch = new Uint8Array(zeroes + (size - it4));
|
|
27969
|
+
var j2 = zeroes;
|
|
27970
|
+
while (it4 !== size) {
|
|
27971
|
+
vch[j2++] = b256[it4++];
|
|
27972
|
+
}
|
|
27973
|
+
return vch;
|
|
27974
|
+
}
|
|
27975
|
+
function decode52(string) {
|
|
27976
|
+
var buffer = decodeUnsafe(string);
|
|
27977
|
+
if (buffer) {
|
|
27978
|
+
return buffer;
|
|
27979
|
+
}
|
|
27980
|
+
throw new Error(`Non-${name} character`);
|
|
27981
|
+
}
|
|
27982
|
+
return {
|
|
27983
|
+
encode: encode32,
|
|
27984
|
+
decodeUnsafe,
|
|
27985
|
+
decode: decode52
|
|
27986
|
+
};
|
|
27987
|
+
}
|
|
27988
|
+
var src3 = base3;
|
|
27989
|
+
var _brrp__multiformats_scope_baseX3 = src3;
|
|
27990
|
+
var base_x_default3 = _brrp__multiformats_scope_baseX3;
|
|
27991
|
+
var Encoder3 = class {
|
|
27992
|
+
name;
|
|
27993
|
+
prefix;
|
|
27994
|
+
baseEncode;
|
|
27995
|
+
constructor(name, prefix, baseEncode) {
|
|
27996
|
+
this.name = name;
|
|
27997
|
+
this.prefix = prefix;
|
|
27998
|
+
this.baseEncode = baseEncode;
|
|
27999
|
+
}
|
|
28000
|
+
encode(bytes) {
|
|
28001
|
+
if (bytes instanceof Uint8Array) {
|
|
28002
|
+
return `${this.prefix}${this.baseEncode(bytes)}`;
|
|
28003
|
+
} else {
|
|
28004
|
+
throw Error("Unknown type, must be binary type");
|
|
28005
|
+
}
|
|
28006
|
+
}
|
|
28007
|
+
};
|
|
28008
|
+
var Decoder3 = class {
|
|
28009
|
+
name;
|
|
28010
|
+
prefix;
|
|
28011
|
+
baseDecode;
|
|
28012
|
+
prefixCodePoint;
|
|
28013
|
+
constructor(name, prefix, baseDecode) {
|
|
28014
|
+
this.name = name;
|
|
28015
|
+
this.prefix = prefix;
|
|
28016
|
+
const prefixCodePoint = prefix.codePointAt(0);
|
|
28017
|
+
if (prefixCodePoint === void 0) {
|
|
28018
|
+
throw new Error("Invalid prefix character");
|
|
28019
|
+
}
|
|
28020
|
+
this.prefixCodePoint = prefixCodePoint;
|
|
28021
|
+
this.baseDecode = baseDecode;
|
|
28022
|
+
}
|
|
28023
|
+
decode(text) {
|
|
28024
|
+
if (typeof text === "string") {
|
|
28025
|
+
if (text.codePointAt(0) !== this.prefixCodePoint) {
|
|
28026
|
+
throw Error(`Unable to decode multibase string ${JSON.stringify(text)}, ${this.name} decoder only supports inputs prefixed with ${this.prefix}`);
|
|
28027
|
+
}
|
|
28028
|
+
return this.baseDecode(text.slice(this.prefix.length));
|
|
28029
|
+
} else {
|
|
28030
|
+
throw Error("Can only multibase decode strings");
|
|
28031
|
+
}
|
|
28032
|
+
}
|
|
28033
|
+
or(decoder) {
|
|
28034
|
+
return or3(this, decoder);
|
|
28035
|
+
}
|
|
28036
|
+
};
|
|
28037
|
+
var ComposedDecoder3 = class {
|
|
28038
|
+
decoders;
|
|
28039
|
+
constructor(decoders) {
|
|
28040
|
+
this.decoders = decoders;
|
|
28041
|
+
}
|
|
28042
|
+
or(decoder) {
|
|
28043
|
+
return or3(this, decoder);
|
|
28044
|
+
}
|
|
28045
|
+
decode(input) {
|
|
28046
|
+
const prefix = input[0];
|
|
28047
|
+
const decoder = this.decoders[prefix];
|
|
28048
|
+
if (decoder != null) {
|
|
28049
|
+
return decoder.decode(input);
|
|
28050
|
+
} else {
|
|
28051
|
+
throw RangeError(`Unable to decode multibase string ${JSON.stringify(input)}, only inputs prefixed with ${Object.keys(this.decoders)} are supported`);
|
|
28052
|
+
}
|
|
28053
|
+
}
|
|
28054
|
+
};
|
|
28055
|
+
function or3(left, right) {
|
|
28056
|
+
return new ComposedDecoder3({
|
|
28057
|
+
...left.decoders ?? { [left.prefix]: left },
|
|
28058
|
+
...right.decoders ?? { [right.prefix]: right }
|
|
28059
|
+
});
|
|
28060
|
+
}
|
|
28061
|
+
var Codec3 = class {
|
|
28062
|
+
name;
|
|
28063
|
+
prefix;
|
|
28064
|
+
baseEncode;
|
|
28065
|
+
baseDecode;
|
|
28066
|
+
encoder;
|
|
28067
|
+
decoder;
|
|
28068
|
+
constructor(name, prefix, baseEncode, baseDecode) {
|
|
28069
|
+
this.name = name;
|
|
28070
|
+
this.prefix = prefix;
|
|
28071
|
+
this.baseEncode = baseEncode;
|
|
28072
|
+
this.baseDecode = baseDecode;
|
|
28073
|
+
this.encoder = new Encoder3(name, prefix, baseEncode);
|
|
28074
|
+
this.decoder = new Decoder3(name, prefix, baseDecode);
|
|
28075
|
+
}
|
|
28076
|
+
encode(input) {
|
|
28077
|
+
return this.encoder.encode(input);
|
|
28078
|
+
}
|
|
28079
|
+
decode(input) {
|
|
28080
|
+
return this.decoder.decode(input);
|
|
28081
|
+
}
|
|
28082
|
+
};
|
|
28083
|
+
function from3({ name, prefix, encode: encode32, decode: decode52 }) {
|
|
28084
|
+
return new Codec3(name, prefix, encode32, decode52);
|
|
28085
|
+
}
|
|
28086
|
+
function baseX3({ name, prefix, alphabet }) {
|
|
28087
|
+
const { encode: encode32, decode: decode52 } = base_x_default3(alphabet, name);
|
|
28088
|
+
return from3({
|
|
28089
|
+
prefix,
|
|
28090
|
+
name,
|
|
28091
|
+
encode: encode32,
|
|
28092
|
+
decode: (text) => coerce4(decode52(text))
|
|
28093
|
+
});
|
|
28094
|
+
}
|
|
28095
|
+
function decode9(string, alphabetIdx, bitsPerChar, name) {
|
|
28096
|
+
let end = string.length;
|
|
28097
|
+
while (string[end - 1] === "=") {
|
|
28098
|
+
--end;
|
|
28099
|
+
}
|
|
28100
|
+
const out = new Uint8Array(end * bitsPerChar / 8 | 0);
|
|
28101
|
+
let bits = 0;
|
|
28102
|
+
let buffer = 0;
|
|
28103
|
+
let written = 0;
|
|
28104
|
+
for (let i = 0; i < end; ++i) {
|
|
28105
|
+
const value = alphabetIdx[string[i]];
|
|
28106
|
+
if (value === void 0) {
|
|
28107
|
+
throw new SyntaxError(`Non-${name} character`);
|
|
28108
|
+
}
|
|
28109
|
+
buffer = buffer << bitsPerChar | value;
|
|
28110
|
+
bits += bitsPerChar;
|
|
28111
|
+
if (bits >= 8) {
|
|
28112
|
+
bits -= 8;
|
|
28113
|
+
out[written++] = 255 & buffer >> bits;
|
|
28114
|
+
}
|
|
28115
|
+
}
|
|
28116
|
+
if (bits >= bitsPerChar || (255 & buffer << 8 - bits) !== 0) {
|
|
28117
|
+
throw new SyntaxError("Unexpected end of data");
|
|
28118
|
+
}
|
|
28119
|
+
return out;
|
|
28120
|
+
}
|
|
28121
|
+
function encode5(data, alphabet, bitsPerChar) {
|
|
28122
|
+
const pad = alphabet[alphabet.length - 1] === "=";
|
|
28123
|
+
const mask = (1 << bitsPerChar) - 1;
|
|
28124
|
+
let out = "";
|
|
28125
|
+
let bits = 0;
|
|
28126
|
+
let buffer = 0;
|
|
28127
|
+
for (let i = 0; i < data.length; ++i) {
|
|
28128
|
+
buffer = buffer << 8 | data[i];
|
|
28129
|
+
bits += 8;
|
|
28130
|
+
while (bits > bitsPerChar) {
|
|
28131
|
+
bits -= bitsPerChar;
|
|
28132
|
+
out += alphabet[mask & buffer >> bits];
|
|
28133
|
+
}
|
|
28134
|
+
}
|
|
28135
|
+
if (bits !== 0) {
|
|
28136
|
+
out += alphabet[mask & buffer << bitsPerChar - bits];
|
|
28137
|
+
}
|
|
28138
|
+
if (pad) {
|
|
28139
|
+
while ((out.length * bitsPerChar & 7) !== 0) {
|
|
28140
|
+
out += "=";
|
|
28141
|
+
}
|
|
28142
|
+
}
|
|
28143
|
+
return out;
|
|
28144
|
+
}
|
|
28145
|
+
function createAlphabetIdx3(alphabet) {
|
|
28146
|
+
const alphabetIdx = {};
|
|
28147
|
+
for (let i = 0; i < alphabet.length; ++i) {
|
|
28148
|
+
alphabetIdx[alphabet[i]] = i;
|
|
28149
|
+
}
|
|
28150
|
+
return alphabetIdx;
|
|
28151
|
+
}
|
|
28152
|
+
function rfc46483({ name, prefix, bitsPerChar, alphabet }) {
|
|
28153
|
+
const alphabetIdx = createAlphabetIdx3(alphabet);
|
|
28154
|
+
return from3({
|
|
28155
|
+
prefix,
|
|
28156
|
+
name,
|
|
28157
|
+
encode(input) {
|
|
28158
|
+
return encode5(input, alphabet, bitsPerChar);
|
|
28159
|
+
},
|
|
28160
|
+
decode(input) {
|
|
28161
|
+
return decode9(input, alphabetIdx, bitsPerChar, name);
|
|
28162
|
+
}
|
|
28163
|
+
});
|
|
28164
|
+
}
|
|
28165
|
+
var base323 = rfc46483({
|
|
28166
|
+
prefix: "b",
|
|
28167
|
+
name: "base32",
|
|
28168
|
+
alphabet: "abcdefghijklmnopqrstuvwxyz234567",
|
|
28169
|
+
bitsPerChar: 5
|
|
28170
|
+
});
|
|
28171
|
+
var base32upper3 = rfc46483({
|
|
28172
|
+
prefix: "B",
|
|
28173
|
+
name: "base32upper",
|
|
28174
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
|
|
28175
|
+
bitsPerChar: 5
|
|
28176
|
+
});
|
|
28177
|
+
var base32pad3 = rfc46483({
|
|
28178
|
+
prefix: "c",
|
|
28179
|
+
name: "base32pad",
|
|
28180
|
+
alphabet: "abcdefghijklmnopqrstuvwxyz234567=",
|
|
28181
|
+
bitsPerChar: 5
|
|
28182
|
+
});
|
|
28183
|
+
var base32padupper3 = rfc46483({
|
|
28184
|
+
prefix: "C",
|
|
28185
|
+
name: "base32padupper",
|
|
28186
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
|
|
28187
|
+
bitsPerChar: 5
|
|
28188
|
+
});
|
|
28189
|
+
var base32hex3 = rfc46483({
|
|
28190
|
+
prefix: "v",
|
|
28191
|
+
name: "base32hex",
|
|
28192
|
+
alphabet: "0123456789abcdefghijklmnopqrstuv",
|
|
28193
|
+
bitsPerChar: 5
|
|
28194
|
+
});
|
|
28195
|
+
var base32hexupper3 = rfc46483({
|
|
28196
|
+
prefix: "V",
|
|
28197
|
+
name: "base32hexupper",
|
|
28198
|
+
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
|
|
28199
|
+
bitsPerChar: 5
|
|
28200
|
+
});
|
|
28201
|
+
var base32hexpad3 = rfc46483({
|
|
28202
|
+
prefix: "t",
|
|
28203
|
+
name: "base32hexpad",
|
|
28204
|
+
alphabet: "0123456789abcdefghijklmnopqrstuv=",
|
|
28205
|
+
bitsPerChar: 5
|
|
28206
|
+
});
|
|
28207
|
+
var base32hexpadupper3 = rfc46483({
|
|
28208
|
+
prefix: "T",
|
|
28209
|
+
name: "base32hexpadupper",
|
|
28210
|
+
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV=",
|
|
28211
|
+
bitsPerChar: 5
|
|
28212
|
+
});
|
|
28213
|
+
var base32z3 = rfc46483({
|
|
28214
|
+
prefix: "h",
|
|
28215
|
+
name: "base32z",
|
|
28216
|
+
alphabet: "ybndrfg8ejkmcpqxot1uwisza345h769",
|
|
28217
|
+
bitsPerChar: 5
|
|
28218
|
+
});
|
|
28219
|
+
var base363 = baseX3({
|
|
28220
|
+
prefix: "k",
|
|
28221
|
+
name: "base36",
|
|
28222
|
+
alphabet: "0123456789abcdefghijklmnopqrstuvwxyz"
|
|
28223
|
+
});
|
|
28224
|
+
var base36upper3 = baseX3({
|
|
28225
|
+
prefix: "K",
|
|
28226
|
+
name: "base36upper",
|
|
28227
|
+
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
28228
|
+
});
|
|
28229
|
+
var base58btc3 = baseX3({
|
|
28230
|
+
name: "base58btc",
|
|
28231
|
+
prefix: "z",
|
|
28232
|
+
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
28233
|
+
});
|
|
28234
|
+
var base58flickr3 = baseX3({
|
|
28235
|
+
name: "base58flickr",
|
|
28236
|
+
prefix: "Z",
|
|
28237
|
+
alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
|
|
28238
|
+
});
|
|
28239
|
+
var encode_13 = encode22;
|
|
28240
|
+
var MSB3 = 128;
|
|
28241
|
+
var REST3 = 127;
|
|
28242
|
+
var MSBALL3 = ~REST3;
|
|
28243
|
+
var INT3 = Math.pow(2, 31);
|
|
28244
|
+
function encode22(num, out, offset) {
|
|
28245
|
+
out = out || [];
|
|
28246
|
+
offset = offset || 0;
|
|
28247
|
+
var oldOffset = offset;
|
|
28248
|
+
while (num >= INT3) {
|
|
28249
|
+
out[offset++] = num & 255 | MSB3;
|
|
28250
|
+
num /= 128;
|
|
28251
|
+
}
|
|
28252
|
+
while (num & MSBALL3) {
|
|
28253
|
+
out[offset++] = num & 255 | MSB3;
|
|
28254
|
+
num >>>= 7;
|
|
28255
|
+
}
|
|
28256
|
+
out[offset] = num | 0;
|
|
28257
|
+
encode22.bytes = offset - oldOffset + 1;
|
|
28258
|
+
return out;
|
|
28259
|
+
}
|
|
28260
|
+
var decode22 = read3;
|
|
28261
|
+
var MSB$13 = 128;
|
|
28262
|
+
var REST$13 = 127;
|
|
28263
|
+
function read3(buf, offset) {
|
|
28264
|
+
var res = 0, offset = offset || 0, shift = 0, counter = offset, b, l = buf.length;
|
|
28265
|
+
do {
|
|
28266
|
+
if (counter >= l) {
|
|
28267
|
+
read3.bytes = 0;
|
|
28268
|
+
throw new RangeError("Could not decode varint");
|
|
28269
|
+
}
|
|
28270
|
+
b = buf[counter++];
|
|
28271
|
+
res += shift < 28 ? (b & REST$13) << shift : (b & REST$13) * Math.pow(2, shift);
|
|
28272
|
+
shift += 7;
|
|
28273
|
+
} while (b >= MSB$13);
|
|
28274
|
+
read3.bytes = counter - offset;
|
|
28275
|
+
return res;
|
|
28276
|
+
}
|
|
28277
|
+
var N13 = Math.pow(2, 7);
|
|
28278
|
+
var N23 = Math.pow(2, 14);
|
|
28279
|
+
var N33 = Math.pow(2, 21);
|
|
28280
|
+
var N43 = Math.pow(2, 28);
|
|
28281
|
+
var N53 = Math.pow(2, 35);
|
|
28282
|
+
var N63 = Math.pow(2, 42);
|
|
28283
|
+
var N73 = Math.pow(2, 49);
|
|
28284
|
+
var N83 = Math.pow(2, 56);
|
|
28285
|
+
var N93 = Math.pow(2, 63);
|
|
28286
|
+
var length3 = function(value) {
|
|
28287
|
+
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;
|
|
28288
|
+
};
|
|
28289
|
+
var varint3 = {
|
|
28290
|
+
encode: encode_13,
|
|
28291
|
+
decode: decode22,
|
|
28292
|
+
encodingLength: length3
|
|
28293
|
+
};
|
|
28294
|
+
var _brrp_varint3 = varint3;
|
|
28295
|
+
var varint_default3 = _brrp_varint3;
|
|
28296
|
+
function decode32(data, offset = 0) {
|
|
28297
|
+
const code22 = varint_default3.decode(data, offset);
|
|
28298
|
+
return [code22, varint_default3.decode.bytes];
|
|
28299
|
+
}
|
|
28300
|
+
function encodeTo3(int, target, offset = 0) {
|
|
28301
|
+
varint_default3.encode(int, target, offset);
|
|
28302
|
+
return target;
|
|
28303
|
+
}
|
|
28304
|
+
function encodingLength3(int) {
|
|
28305
|
+
return varint_default3.encodingLength(int);
|
|
28306
|
+
}
|
|
28307
|
+
function create3(code22, digest2) {
|
|
28308
|
+
const size = digest2.byteLength;
|
|
28309
|
+
const sizeOffset = encodingLength3(code22);
|
|
28310
|
+
const digestOffset = sizeOffset + encodingLength3(size);
|
|
28311
|
+
const bytes = new Uint8Array(digestOffset + size);
|
|
28312
|
+
encodeTo3(code22, bytes, 0);
|
|
28313
|
+
encodeTo3(size, bytes, sizeOffset);
|
|
28314
|
+
bytes.set(digest2, digestOffset);
|
|
28315
|
+
return new Digest3(code22, size, digest2, bytes);
|
|
28316
|
+
}
|
|
28317
|
+
function decode42(multihash) {
|
|
28318
|
+
const bytes = coerce4(multihash);
|
|
28319
|
+
const [code22, sizeOffset] = decode32(bytes);
|
|
28320
|
+
const [size, digestOffset] = decode32(bytes.subarray(sizeOffset));
|
|
28321
|
+
const digest2 = bytes.subarray(sizeOffset + digestOffset);
|
|
28322
|
+
if (digest2.byteLength !== size) {
|
|
28323
|
+
throw new Error("Incorrect length");
|
|
28324
|
+
}
|
|
28325
|
+
return new Digest3(code22, size, digest2, bytes);
|
|
28326
|
+
}
|
|
28327
|
+
function equals22(a, b) {
|
|
28328
|
+
if (a === b) {
|
|
28329
|
+
return true;
|
|
28330
|
+
} else {
|
|
28331
|
+
const data = b;
|
|
28332
|
+
return a.code === data.code && a.size === data.size && data.bytes instanceof Uint8Array && equals5(a.bytes, data.bytes);
|
|
28333
|
+
}
|
|
28334
|
+
}
|
|
28335
|
+
var Digest3 = class {
|
|
28336
|
+
code;
|
|
28337
|
+
size;
|
|
28338
|
+
digest;
|
|
28339
|
+
bytes;
|
|
28340
|
+
/**
|
|
28341
|
+
* Creates a multihash digest.
|
|
28342
|
+
*/
|
|
28343
|
+
constructor(code22, size, digest2, bytes) {
|
|
28344
|
+
this.code = code22;
|
|
28345
|
+
this.size = size;
|
|
28346
|
+
this.digest = digest2;
|
|
28347
|
+
this.bytes = bytes;
|
|
28348
|
+
}
|
|
28349
|
+
};
|
|
28350
|
+
function format3(link2, base22) {
|
|
28351
|
+
const { bytes, version } = link2;
|
|
28352
|
+
switch (version) {
|
|
28353
|
+
case 0:
|
|
28354
|
+
return toStringV03(bytes, baseCache3(link2), base22 ?? base58btc3.encoder);
|
|
28355
|
+
default:
|
|
28356
|
+
return toStringV13(bytes, baseCache3(link2), base22 ?? base323.encoder);
|
|
28357
|
+
}
|
|
28358
|
+
}
|
|
28359
|
+
var cache3 = /* @__PURE__ */ new WeakMap();
|
|
28360
|
+
function baseCache3(cid) {
|
|
28361
|
+
const baseCache22 = cache3.get(cid);
|
|
28362
|
+
if (baseCache22 == null) {
|
|
28363
|
+
const baseCache32 = /* @__PURE__ */ new Map();
|
|
28364
|
+
cache3.set(cid, baseCache32);
|
|
28365
|
+
return baseCache32;
|
|
28366
|
+
}
|
|
28367
|
+
return baseCache22;
|
|
28368
|
+
}
|
|
28369
|
+
var CID3 = class _CID3 {
|
|
28370
|
+
code;
|
|
28371
|
+
version;
|
|
28372
|
+
multihash;
|
|
28373
|
+
bytes;
|
|
28374
|
+
"/";
|
|
28375
|
+
/**
|
|
28376
|
+
* @param version - Version of the CID
|
|
28377
|
+
* @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
28378
|
+
* @param multihash - (Multi)hash of the of the content.
|
|
28379
|
+
*/
|
|
28380
|
+
constructor(version, code22, multihash, bytes) {
|
|
28381
|
+
this.code = code22;
|
|
28382
|
+
this.version = version;
|
|
28383
|
+
this.multihash = multihash;
|
|
28384
|
+
this.bytes = bytes;
|
|
28385
|
+
this["/"] = bytes;
|
|
28386
|
+
}
|
|
28387
|
+
/**
|
|
28388
|
+
* Signalling `cid.asCID === cid` has been replaced with `cid['/'] === cid.bytes`
|
|
28389
|
+
* please either use `CID.asCID(cid)` or switch to new signalling mechanism
|
|
28390
|
+
*
|
|
28391
|
+
* @deprecated
|
|
28392
|
+
*/
|
|
28393
|
+
get asCID() {
|
|
28394
|
+
return this;
|
|
28395
|
+
}
|
|
28396
|
+
// ArrayBufferView
|
|
28397
|
+
get byteOffset() {
|
|
28398
|
+
return this.bytes.byteOffset;
|
|
28399
|
+
}
|
|
28400
|
+
// ArrayBufferView
|
|
28401
|
+
get byteLength() {
|
|
28402
|
+
return this.bytes.byteLength;
|
|
28403
|
+
}
|
|
28404
|
+
toV0() {
|
|
28405
|
+
switch (this.version) {
|
|
28406
|
+
case 0: {
|
|
28407
|
+
return this;
|
|
28408
|
+
}
|
|
28409
|
+
case 1: {
|
|
28410
|
+
const { code: code22, multihash } = this;
|
|
28411
|
+
if (code22 !== DAG_PB_CODE3) {
|
|
28412
|
+
throw new Error("Cannot convert a non dag-pb CID to CIDv0");
|
|
28413
|
+
}
|
|
28414
|
+
if (multihash.code !== SHA_256_CODE3) {
|
|
28415
|
+
throw new Error("Cannot convert non sha2-256 multihash CID to CIDv0");
|
|
28416
|
+
}
|
|
28417
|
+
return _CID3.createV0(multihash);
|
|
28418
|
+
}
|
|
28419
|
+
default: {
|
|
28420
|
+
throw Error(`Can not convert CID version ${this.version} to version 0. This is a bug please report`);
|
|
28421
|
+
}
|
|
28422
|
+
}
|
|
28423
|
+
}
|
|
28424
|
+
toV1() {
|
|
28425
|
+
switch (this.version) {
|
|
28426
|
+
case 0: {
|
|
28427
|
+
const { code: code22, digest: digest2 } = this.multihash;
|
|
28428
|
+
const multihash = create3(code22, digest2);
|
|
28429
|
+
return _CID3.createV1(this.code, multihash);
|
|
28430
|
+
}
|
|
28431
|
+
case 1: {
|
|
28432
|
+
return this;
|
|
28433
|
+
}
|
|
28434
|
+
default: {
|
|
28435
|
+
throw Error(`Can not convert CID version ${this.version} to version 1. This is a bug please report`);
|
|
28436
|
+
}
|
|
28437
|
+
}
|
|
28438
|
+
}
|
|
28439
|
+
equals(other) {
|
|
28440
|
+
return _CID3.equals(this, other);
|
|
28441
|
+
}
|
|
28442
|
+
static equals(self, other) {
|
|
28443
|
+
const unknown = other;
|
|
28444
|
+
return unknown != null && self.code === unknown.code && self.version === unknown.version && equals22(self.multihash, unknown.multihash);
|
|
28445
|
+
}
|
|
28446
|
+
toString(base22) {
|
|
28447
|
+
return format3(this, base22);
|
|
28448
|
+
}
|
|
28449
|
+
toJSON() {
|
|
28450
|
+
return { "/": format3(this) };
|
|
28451
|
+
}
|
|
28452
|
+
link() {
|
|
28453
|
+
return this;
|
|
28454
|
+
}
|
|
28455
|
+
[Symbol.toStringTag] = "CID";
|
|
28456
|
+
// Legacy
|
|
28457
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
28458
|
+
return `CID(${this.toString()})`;
|
|
28459
|
+
}
|
|
28460
|
+
/**
|
|
28461
|
+
* Takes any input `value` and returns a `CID` instance if it was
|
|
28462
|
+
* a `CID` otherwise returns `null`. If `value` is instanceof `CID`
|
|
28463
|
+
* it will return value back. If `value` is not instance of this CID
|
|
28464
|
+
* class, but is compatible CID it will return new instance of this
|
|
28465
|
+
* `CID` class. Otherwise returns null.
|
|
28466
|
+
*
|
|
28467
|
+
* This allows two different incompatible versions of CID library to
|
|
28468
|
+
* co-exist and interop as long as binary interface is compatible.
|
|
28469
|
+
*/
|
|
28470
|
+
static asCID(input) {
|
|
28471
|
+
if (input == null) {
|
|
28472
|
+
return null;
|
|
28473
|
+
}
|
|
28474
|
+
const value = input;
|
|
28475
|
+
if (value instanceof _CID3) {
|
|
28476
|
+
return value;
|
|
28477
|
+
} else if (value["/"] != null && value["/"] === value.bytes || value.asCID === value) {
|
|
28478
|
+
const { version, code: code22, multihash, bytes } = value;
|
|
28479
|
+
return new _CID3(version, code22, multihash, bytes ?? encodeCID3(version, code22, multihash.bytes));
|
|
28480
|
+
} else if (value[cidSymbol3] === true) {
|
|
28481
|
+
const { version, multihash, code: code22 } = value;
|
|
28482
|
+
const digest2 = decode42(multihash);
|
|
28483
|
+
return _CID3.create(version, code22, digest2);
|
|
28484
|
+
} else {
|
|
28485
|
+
return null;
|
|
28486
|
+
}
|
|
28487
|
+
}
|
|
28488
|
+
/**
|
|
28489
|
+
* @param version - Version of the CID
|
|
28490
|
+
* @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
28491
|
+
* @param digest - (Multi)hash of the of the content.
|
|
28492
|
+
*/
|
|
28493
|
+
static create(version, code22, digest2) {
|
|
28494
|
+
if (typeof code22 !== "number") {
|
|
28495
|
+
throw new Error("String codecs are no longer supported");
|
|
28496
|
+
}
|
|
28497
|
+
if (!(digest2.bytes instanceof Uint8Array)) {
|
|
28498
|
+
throw new Error("Invalid digest");
|
|
28499
|
+
}
|
|
28500
|
+
switch (version) {
|
|
28501
|
+
case 0: {
|
|
28502
|
+
if (code22 !== DAG_PB_CODE3) {
|
|
28503
|
+
throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE3}) block encoding`);
|
|
28504
|
+
} else {
|
|
28505
|
+
return new _CID3(version, code22, digest2, digest2.bytes);
|
|
28506
|
+
}
|
|
28507
|
+
}
|
|
28508
|
+
case 1: {
|
|
28509
|
+
const bytes = encodeCID3(version, code22, digest2.bytes);
|
|
28510
|
+
return new _CID3(version, code22, digest2, bytes);
|
|
28511
|
+
}
|
|
28512
|
+
default: {
|
|
28513
|
+
throw new Error("Invalid version");
|
|
28514
|
+
}
|
|
28515
|
+
}
|
|
28516
|
+
}
|
|
28517
|
+
/**
|
|
28518
|
+
* Simplified version of `create` for CIDv0.
|
|
28519
|
+
*/
|
|
28520
|
+
static createV0(digest2) {
|
|
28521
|
+
return _CID3.create(0, DAG_PB_CODE3, digest2);
|
|
28522
|
+
}
|
|
28523
|
+
/**
|
|
28524
|
+
* Simplified version of `create` for CIDv1.
|
|
28525
|
+
*
|
|
28526
|
+
* @param code - Content encoding format code.
|
|
28527
|
+
* @param digest - Multihash of the content.
|
|
28528
|
+
*/
|
|
28529
|
+
static createV1(code22, digest2) {
|
|
28530
|
+
return _CID3.create(1, code22, digest2);
|
|
28531
|
+
}
|
|
28532
|
+
/**
|
|
28533
|
+
* Decoded a CID from its binary representation. The byte array must contain
|
|
28534
|
+
* only the CID with no additional bytes.
|
|
28535
|
+
*
|
|
28536
|
+
* An error will be thrown if the bytes provided do not contain a valid
|
|
28537
|
+
* binary representation of a CID.
|
|
28538
|
+
*/
|
|
28539
|
+
static decode(bytes) {
|
|
28540
|
+
const [cid, remainder] = _CID3.decodeFirst(bytes);
|
|
28541
|
+
if (remainder.length !== 0) {
|
|
28542
|
+
throw new Error("Incorrect length");
|
|
28543
|
+
}
|
|
28544
|
+
return cid;
|
|
28545
|
+
}
|
|
28546
|
+
/**
|
|
28547
|
+
* Decoded a CID from its binary representation at the beginning of a byte
|
|
28548
|
+
* array.
|
|
28549
|
+
*
|
|
28550
|
+
* Returns an array with the first element containing the CID and the second
|
|
28551
|
+
* element containing the remainder of the original byte array. The remainder
|
|
28552
|
+
* will be a zero-length byte array if the provided bytes only contained a
|
|
28553
|
+
* binary CID representation.
|
|
28554
|
+
*/
|
|
28555
|
+
static decodeFirst(bytes) {
|
|
28556
|
+
const specs = _CID3.inspectBytes(bytes);
|
|
28557
|
+
const prefixSize = specs.size - specs.multihashSize;
|
|
28558
|
+
const multihashBytes = coerce4(bytes.subarray(prefixSize, prefixSize + specs.multihashSize));
|
|
28559
|
+
if (multihashBytes.byteLength !== specs.multihashSize) {
|
|
28560
|
+
throw new Error("Incorrect length");
|
|
28561
|
+
}
|
|
28562
|
+
const digestBytes = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
|
|
28563
|
+
const digest2 = new Digest3(specs.multihashCode, specs.digestSize, digestBytes, multihashBytes);
|
|
28564
|
+
const cid = specs.version === 0 ? _CID3.createV0(digest2) : _CID3.createV1(specs.codec, digest2);
|
|
28565
|
+
return [cid, bytes.subarray(specs.size)];
|
|
28566
|
+
}
|
|
28567
|
+
/**
|
|
28568
|
+
* Inspect the initial bytes of a CID to determine its properties.
|
|
28569
|
+
*
|
|
28570
|
+
* Involves decoding up to 4 varints. Typically this will require only 4 to 6
|
|
28571
|
+
* bytes but for larger multicodec code values and larger multihash digest
|
|
28572
|
+
* lengths these varints can be quite large. It is recommended that at least
|
|
28573
|
+
* 10 bytes be made available in the `initialBytes` argument for a complete
|
|
28574
|
+
* inspection.
|
|
28575
|
+
*/
|
|
28576
|
+
static inspectBytes(initialBytes) {
|
|
28577
|
+
let offset = 0;
|
|
28578
|
+
const next = () => {
|
|
28579
|
+
const [i, length22] = decode32(initialBytes.subarray(offset));
|
|
28580
|
+
offset += length22;
|
|
28581
|
+
return i;
|
|
28582
|
+
};
|
|
28583
|
+
let version = next();
|
|
28584
|
+
let codec = DAG_PB_CODE3;
|
|
28585
|
+
if (version === 18) {
|
|
28586
|
+
version = 0;
|
|
28587
|
+
offset = 0;
|
|
28588
|
+
} else {
|
|
28589
|
+
codec = next();
|
|
28590
|
+
}
|
|
28591
|
+
if (version !== 0 && version !== 1) {
|
|
28592
|
+
throw new RangeError(`Invalid CID version ${version}`);
|
|
28593
|
+
}
|
|
28594
|
+
const prefixSize = offset;
|
|
28595
|
+
const multihashCode = next();
|
|
28596
|
+
const digestSize = next();
|
|
28597
|
+
const size = offset + digestSize;
|
|
28598
|
+
const multihashSize = size - prefixSize;
|
|
28599
|
+
return { version, codec, multihashCode, digestSize, multihashSize, size };
|
|
28600
|
+
}
|
|
28601
|
+
/**
|
|
28602
|
+
* Takes cid in a string representation and creates an instance. If `base`
|
|
28603
|
+
* decoder is not provided will use a default from the configuration. It will
|
|
28604
|
+
* throw an error if encoding of the CID is not compatible with supplied (or
|
|
28605
|
+
* a default decoder).
|
|
28606
|
+
*/
|
|
28607
|
+
static parse(source, base22) {
|
|
28608
|
+
const [prefix, bytes] = parseCIDtoBytes3(source, base22);
|
|
28609
|
+
const cid = _CID3.decode(bytes);
|
|
28610
|
+
if (cid.version === 0 && source[0] !== "Q") {
|
|
28611
|
+
throw Error("Version 0 CID string must not include multibase prefix");
|
|
28612
|
+
}
|
|
28613
|
+
baseCache3(cid).set(prefix, source);
|
|
28614
|
+
return cid;
|
|
28615
|
+
}
|
|
28616
|
+
};
|
|
28617
|
+
function parseCIDtoBytes3(source, base22) {
|
|
28618
|
+
switch (source[0]) {
|
|
28619
|
+
// CIDv0 is parsed differently
|
|
28620
|
+
case "Q": {
|
|
28621
|
+
const decoder = base22 ?? base58btc3;
|
|
28622
|
+
return [
|
|
28623
|
+
base58btc3.prefix,
|
|
28624
|
+
decoder.decode(`${base58btc3.prefix}${source}`)
|
|
28625
|
+
];
|
|
28626
|
+
}
|
|
28627
|
+
case base58btc3.prefix: {
|
|
28628
|
+
const decoder = base22 ?? base58btc3;
|
|
28629
|
+
return [base58btc3.prefix, decoder.decode(source)];
|
|
28630
|
+
}
|
|
28631
|
+
case base323.prefix: {
|
|
28632
|
+
const decoder = base22 ?? base323;
|
|
28633
|
+
return [base323.prefix, decoder.decode(source)];
|
|
28634
|
+
}
|
|
28635
|
+
case base363.prefix: {
|
|
28636
|
+
const decoder = base22 ?? base363;
|
|
28637
|
+
return [base363.prefix, decoder.decode(source)];
|
|
28638
|
+
}
|
|
28639
|
+
default: {
|
|
28640
|
+
if (base22 == null) {
|
|
28641
|
+
throw Error("To parse non base32, base36 or base58btc encoded CID multibase decoder must be provided");
|
|
28642
|
+
}
|
|
28643
|
+
return [source[0], base22.decode(source)];
|
|
28644
|
+
}
|
|
28645
|
+
}
|
|
28646
|
+
}
|
|
28647
|
+
function toStringV03(bytes, cache22, base22) {
|
|
28648
|
+
const { prefix } = base22;
|
|
28649
|
+
if (prefix !== base58btc3.prefix) {
|
|
28650
|
+
throw Error(`Cannot string encode V0 in ${base22.name} encoding`);
|
|
28651
|
+
}
|
|
28652
|
+
const cid = cache22.get(prefix);
|
|
28653
|
+
if (cid == null) {
|
|
28654
|
+
const cid2 = base22.encode(bytes).slice(1);
|
|
28655
|
+
cache22.set(prefix, cid2);
|
|
28656
|
+
return cid2;
|
|
28657
|
+
} else {
|
|
28658
|
+
return cid;
|
|
28659
|
+
}
|
|
28660
|
+
}
|
|
28661
|
+
function toStringV13(bytes, cache22, base22) {
|
|
28662
|
+
const { prefix } = base22;
|
|
28663
|
+
const cid = cache22.get(prefix);
|
|
28664
|
+
if (cid == null) {
|
|
28665
|
+
const cid2 = base22.encode(bytes);
|
|
28666
|
+
cache22.set(prefix, cid2);
|
|
28667
|
+
return cid2;
|
|
28668
|
+
} else {
|
|
28669
|
+
return cid;
|
|
28670
|
+
}
|
|
28671
|
+
}
|
|
28672
|
+
var DAG_PB_CODE3 = 112;
|
|
28673
|
+
var SHA_256_CODE3 = 18;
|
|
28674
|
+
function encodeCID3(version, code22, multihash) {
|
|
28675
|
+
const codeOffset = encodingLength3(version);
|
|
28676
|
+
const hashOffset = codeOffset + encodingLength3(code22);
|
|
28677
|
+
const bytes = new Uint8Array(hashOffset + multihash.byteLength);
|
|
28678
|
+
encodeTo3(version, bytes, 0);
|
|
28679
|
+
encodeTo3(code22, bytes, codeOffset);
|
|
28680
|
+
bytes.set(multihash, hashOffset);
|
|
28681
|
+
return bytes;
|
|
28682
|
+
}
|
|
28683
|
+
var cidSymbol3 = /* @__PURE__ */ Symbol.for("@ipld/js-cid/CID");
|
|
28684
|
+
var code2 = 85;
|
|
28685
|
+
var SHA256_CODE2 = 18;
|
|
28686
|
+
function isCanonicalRawCid2(cidString) {
|
|
28687
|
+
let cid;
|
|
28688
|
+
try {
|
|
28689
|
+
cid = CID3.parse(cidString);
|
|
28690
|
+
} catch {
|
|
28691
|
+
return false;
|
|
28692
|
+
}
|
|
28693
|
+
return cid.version === 1 && cid.code === code2 && cid.multihash.code === SHA256_CODE2 && cid.toString() === cidString;
|
|
28694
|
+
}
|
|
28695
|
+
var base642 = rfc46483({
|
|
28696
|
+
prefix: "m",
|
|
28697
|
+
name: "base64",
|
|
28698
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
|
28699
|
+
bitsPerChar: 6
|
|
28700
|
+
});
|
|
28701
|
+
var base64pad2 = rfc46483({
|
|
28702
|
+
prefix: "M",
|
|
28703
|
+
name: "base64pad",
|
|
28704
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
|
28705
|
+
bitsPerChar: 6
|
|
28706
|
+
});
|
|
28707
|
+
var base64url2 = rfc46483({
|
|
28708
|
+
prefix: "u",
|
|
28709
|
+
name: "base64url",
|
|
28710
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
|
|
28711
|
+
bitsPerChar: 6
|
|
28712
|
+
});
|
|
28713
|
+
var base64urlpad2 = rfc46483({
|
|
28714
|
+
prefix: "U",
|
|
28715
|
+
name: "base64urlpad",
|
|
28716
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",
|
|
28717
|
+
bitsPerChar: 6
|
|
28718
|
+
});
|
|
28719
|
+
function fromBase64Url2(text) {
|
|
28720
|
+
const bytes = base64url2.baseDecode(text);
|
|
28721
|
+
if (base64url2.baseEncode(bytes) !== text) {
|
|
28722
|
+
throw new TypeError("non-canonical base64url input");
|
|
28723
|
+
}
|
|
28724
|
+
return bytes;
|
|
28725
|
+
}
|
|
28726
|
+
function utf8Bytes2(text) {
|
|
28727
|
+
return new TextEncoder().encode(text);
|
|
28728
|
+
}
|
|
28729
|
+
var ED25519_MULTICODEC_PREFIX2 = Uint8Array.of(237, 1);
|
|
28730
|
+
function decodeBase64UrlOrNull2(value) {
|
|
28731
|
+
try {
|
|
28732
|
+
return fromBase64Url2(value);
|
|
28733
|
+
} catch {
|
|
28734
|
+
return null;
|
|
28735
|
+
}
|
|
28736
|
+
}
|
|
28737
|
+
var base64UrlString2 = () => external_exports.string().refine((value) => decodeBase64UrlOrNull2(value) !== null, {
|
|
28738
|
+
message: "expected strictly-decodable unpadded base64url"
|
|
28739
|
+
});
|
|
28740
|
+
function isCanonicalHttpsOrigin2(value) {
|
|
28741
|
+
let url;
|
|
28742
|
+
try {
|
|
28743
|
+
url = new URL(value);
|
|
28744
|
+
} catch {
|
|
28745
|
+
return false;
|
|
28746
|
+
}
|
|
28747
|
+
return url.protocol === "https:" && url.origin === value;
|
|
28748
|
+
}
|
|
28749
|
+
var sessionJwkCommonFields2 = {
|
|
28750
|
+
alg: external_exports.string().min(1).optional(),
|
|
28751
|
+
use: external_exports.string().min(1).optional(),
|
|
28752
|
+
key_ops: external_exports.array(external_exports.string().min(1)).optional(),
|
|
28753
|
+
kid: external_exports.string().min(1).optional(),
|
|
28754
|
+
ext: external_exports.boolean().optional()
|
|
28755
|
+
};
|
|
28756
|
+
var okpPrivateJwkSchema2 = external_exports.object({
|
|
28757
|
+
kty: external_exports.literal("OKP"),
|
|
28758
|
+
crv: external_exports.string().min(1),
|
|
28759
|
+
x: base64UrlString2(),
|
|
28760
|
+
d: base64UrlString2(),
|
|
28761
|
+
...sessionJwkCommonFields2
|
|
28762
|
+
}).strict();
|
|
28763
|
+
var ecPrivateJwkSchema2 = external_exports.object({
|
|
28764
|
+
kty: external_exports.literal("EC"),
|
|
28765
|
+
crv: external_exports.string().min(1),
|
|
28766
|
+
x: base64UrlString2(),
|
|
28767
|
+
y: base64UrlString2(),
|
|
28768
|
+
d: base64UrlString2(),
|
|
28769
|
+
...sessionJwkCommonFields2
|
|
28770
|
+
}).strict();
|
|
28771
|
+
var sessionJwkSchema2 = external_exports.discriminatedUnion("kty", [
|
|
28772
|
+
okpPrivateJwkSchema2,
|
|
28773
|
+
ecPrivateJwkSchema2
|
|
28774
|
+
]);
|
|
28775
|
+
var policyTargetSchema2 = external_exports.object({
|
|
28776
|
+
kind: external_exports.literal("policy"),
|
|
28777
|
+
policyCid: external_exports.string().min(1),
|
|
28778
|
+
/** Canonical policy bytes, base64url-encoded (bytes are not JSON). */
|
|
28779
|
+
policyBytes: base64UrlString2()
|
|
28780
|
+
}).strict();
|
|
28781
|
+
var bearerKeyTargetSchema2 = external_exports.object({
|
|
28782
|
+
kind: external_exports.literal("bearerKey"),
|
|
28783
|
+
sessionJwk: sessionJwkSchema2
|
|
28784
|
+
}).strict();
|
|
28785
|
+
var recipientDidTargetSchema2 = external_exports.object({
|
|
28786
|
+
kind: external_exports.literal("recipientDid"),
|
|
28787
|
+
did: external_exports.string().regex(/^did:[a-z0-9]+:.+$/, "expected a DID")
|
|
28788
|
+
}).strict();
|
|
28789
|
+
var authorizationTargetSchema2 = external_exports.discriminatedUnion("kind", [
|
|
28790
|
+
policyTargetSchema2,
|
|
28791
|
+
bearerKeyTargetSchema2,
|
|
28792
|
+
recipientDidTargetSchema2
|
|
28793
|
+
]);
|
|
28794
|
+
function isCanonicalResourcePath2(value) {
|
|
28795
|
+
if (value.length === 0) return false;
|
|
28796
|
+
if (/[\u0000-\u001f\u007f\\]/.test(value)) return false;
|
|
28797
|
+
if (/%2f|%5c|%2e/i.test(value)) return false;
|
|
28798
|
+
return value.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
28799
|
+
}
|
|
28800
|
+
function isCanonicalPathSegment2(value) {
|
|
28801
|
+
return isCanonicalResourcePath2(value) && !value.includes("/");
|
|
28802
|
+
}
|
|
28803
|
+
var resourceSelectorSchema2 = external_exports.object({
|
|
28804
|
+
kind: external_exports.union([external_exports.literal("exact"), external_exports.literal("prefix")]),
|
|
28805
|
+
path: external_exports.string().min(1)
|
|
28806
|
+
}).strict().superRefine((selector, ctx) => {
|
|
28807
|
+
const body = selector.kind === "prefix" && selector.path.endsWith("/") ? selector.path.slice(0, -1) : selector.path;
|
|
28808
|
+
if (!isCanonicalResourcePath2(body)) {
|
|
28809
|
+
ctx.addIssue({
|
|
28810
|
+
code: external_exports.ZodIssueCode.custom,
|
|
28811
|
+
path: ["path"],
|
|
28812
|
+
message: "expected a canonical resource path (non-empty segments, no . or .. segments, no //, no backslash, no %2f/%5c/%2e, no control chars)"
|
|
28813
|
+
});
|
|
28814
|
+
}
|
|
28815
|
+
});
|
|
28816
|
+
var targetSchema2 = external_exports.object({
|
|
28817
|
+
origin: external_exports.string().refine(isCanonicalHttpsOrigin2, {
|
|
28818
|
+
message: "expected a canonical https origin (https://host[:port], nothing else)"
|
|
28819
|
+
}),
|
|
28820
|
+
nodeAudience: external_exports.string().min(1),
|
|
28821
|
+
spaceId: external_exports.string().refine(isCanonicalPathSegment2, {
|
|
28822
|
+
message: "expected a single canonical path segment (spaceId joins the resource URI; separators/traversal would alias grants)"
|
|
28823
|
+
}),
|
|
28824
|
+
resource: resourceSelectorSchema2
|
|
28825
|
+
}).strict();
|
|
28826
|
+
var displaySchema2 = external_exports.object({
|
|
28827
|
+
senderName: external_exports.string().optional(),
|
|
28828
|
+
filename: external_exports.string().optional(),
|
|
28829
|
+
recipientHint: external_exports.string().optional(),
|
|
28830
|
+
/**
|
|
28831
|
+
* Presentation preference only (viewer spec §1): may narrow, never widen;
|
|
28832
|
+
* capabilities always win.
|
|
28833
|
+
*/
|
|
28834
|
+
mode: external_exports.union([external_exports.literal("document"), external_exports.literal("source"), external_exports.literal("folder")]).optional()
|
|
28835
|
+
}).strict();
|
|
28836
|
+
var contentPointerSchema2 = external_exports.object({
|
|
28837
|
+
cid: external_exports.string().refine(isCanonicalRawCid2, {
|
|
28838
|
+
message: "expected a canonical CIDv1 raw sha2-256 base32 CID"
|
|
28839
|
+
}),
|
|
28840
|
+
key: external_exports.string().refine((value) => decodeBase64UrlOrNull2(value)?.length === 32, {
|
|
28841
|
+
message: "expected base64url decoding to exactly 32 bytes"
|
|
28842
|
+
})
|
|
28843
|
+
}).strict();
|
|
28844
|
+
var signatureSchema2 = external_exports.object({
|
|
28845
|
+
/** did:key of the sender's ed25519 signing key. */
|
|
28846
|
+
signerDid: external_exports.string().regex(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/, "expected a did:key"),
|
|
28847
|
+
algorithm: external_exports.literal("Ed25519"),
|
|
28848
|
+
/** base64url-encoded ed25519 signature over the JCS bytes of all other fields. */
|
|
28849
|
+
value: external_exports.string().refine((value) => decodeBase64UrlOrNull2(value)?.length === 64, {
|
|
28850
|
+
message: "expected base64url decoding to exactly 64 bytes"
|
|
28851
|
+
})
|
|
28852
|
+
}).strict();
|
|
28853
|
+
var unsignedShareEnvelopeSchema2 = external_exports.object({
|
|
28854
|
+
version: external_exports.literal(1),
|
|
28855
|
+
shareId: external_exports.string().min(1),
|
|
28856
|
+
/** Full signed delegation chain, opaque serialized form. */
|
|
28857
|
+
delegation: external_exports.string().min(1),
|
|
28858
|
+
authorizationTarget: authorizationTargetSchema2,
|
|
28859
|
+
target: targetSchema2,
|
|
28860
|
+
display: displaySchema2,
|
|
28861
|
+
/** ISO 8601 UTC datetime. Advisory here; enforcement is the delegation's. */
|
|
28862
|
+
expiry: external_exports.string().datetime(),
|
|
28863
|
+
/** Bearer-slice sealed-content pointer (see contentPointerSchema). */
|
|
28864
|
+
content: contentPointerSchema2.optional()
|
|
28865
|
+
}).strict();
|
|
28866
|
+
var shareEnvelopeSchema2 = unsignedShareEnvelopeSchema2.extend({ signature: signatureSchema2 }).strict();
|
|
28867
|
+
var recipientMatcherSchema2 = external_exports.discriminatedUnion("kind", [
|
|
28868
|
+
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(),
|
|
28869
|
+
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(),
|
|
28870
|
+
external_exports.object({ kind: external_exports.literal("recipientDid"), value: external_exports.string().regex(/^did:[a-z0-9]+:.+$/) }).strict(),
|
|
28871
|
+
external_exports.object({ kind: external_exports.literal("policyDigest"), value: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/) }).strict(),
|
|
28872
|
+
external_exports.object({ kind: external_exports.literal("bearer") }).strict()
|
|
28873
|
+
]);
|
|
28874
|
+
var shareActionSchema2 = external_exports.union([external_exports.literal("read"), external_exports.literal("list"), external_exports.literal("edit")]);
|
|
28875
|
+
var kvContentSourceSchema2 = external_exports.object({
|
|
28876
|
+
kind: external_exports.literal("kv"),
|
|
28877
|
+
space: external_exports.string().min(1),
|
|
28878
|
+
path: external_exports.string().min(1),
|
|
28879
|
+
action: external_exports.literal("tinycloud.kv/get")
|
|
28880
|
+
}).strict();
|
|
28881
|
+
var sqlContentSourceSchema2 = external_exports.object({
|
|
28882
|
+
kind: external_exports.literal("sql"),
|
|
28883
|
+
space: external_exports.string().min(1),
|
|
28884
|
+
database: external_exports.string().min(1),
|
|
28885
|
+
path: external_exports.string().min(1),
|
|
28886
|
+
statement: external_exports.string().min(1),
|
|
28887
|
+
arguments: external_exports.record(external_exports.string(), external_exports.number().int()),
|
|
28888
|
+
argumentsDigest: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
28889
|
+
action: external_exports.literal("tinycloud.sql/read")
|
|
28890
|
+
}).strict();
|
|
28891
|
+
var contentSourceSchema2 = external_exports.discriminatedUnion("kind", [kvContentSourceSchema2, sqlContentSourceSchema2]);
|
|
28892
|
+
var v2TargetSchema2 = external_exports.object({
|
|
28893
|
+
origin: external_exports.string().refine(isCanonicalHttpsOrigin2, { message: "expected a canonical https origin" }),
|
|
28894
|
+
nodeAudience: external_exports.string().min(1),
|
|
28895
|
+
spaceId: external_exports.string().refine(isCanonicalPathSegment2, { message: "expected a canonical space id" })
|
|
28896
|
+
}).strict();
|
|
28897
|
+
var shareDecryptionSchema2 = external_exports.object({
|
|
28898
|
+
networkId: external_exports.string().min(1),
|
|
28899
|
+
action: external_exports.literal("tinycloud.encryption/decrypt")
|
|
28900
|
+
}).strict();
|
|
28901
|
+
var ownerAuthoritySchema2 = external_exports.object({
|
|
28902
|
+
registrationCid: external_exports.string().min(1),
|
|
28903
|
+
shareCid: external_exports.string().min(1),
|
|
28904
|
+
envelopeCid: external_exports.string().min(1),
|
|
28905
|
+
enforcementDelegation: external_exports.record(external_exports.string(), external_exports.unknown()),
|
|
28906
|
+
outerEnvelope: external_exports.record(external_exports.string(), external_exports.unknown()),
|
|
28907
|
+
/** Node-signed registration evidence; required by trusted policy adapters. */
|
|
28908
|
+
registrationReceipt: external_exports.object({
|
|
28909
|
+
registration: external_exports.record(external_exports.string(), external_exports.unknown()),
|
|
28910
|
+
proof: external_exports.record(external_exports.string(), external_exports.unknown())
|
|
28911
|
+
}).strict().optional()
|
|
28912
|
+
}).strict();
|
|
28913
|
+
var contentMetadataSchema2 = external_exports.object({
|
|
28914
|
+
mediaType: external_exports.string().min(1).max(128).optional(),
|
|
28915
|
+
byteLength: external_exports.number().int().nonnegative().max(100 * 1024 * 1024).optional(),
|
|
28916
|
+
filename: external_exports.string().min(1).max(255).optional(),
|
|
28917
|
+
encoding: external_exports.literal("utf-8").optional(),
|
|
28918
|
+
/** Encrypted presentation discriminator. The fixed entry point is index.html. */
|
|
28919
|
+
artifact: external_exports.literal("html").optional()
|
|
28920
|
+
}).strict();
|
|
28921
|
+
var deliveryEmailSchema2 = external_exports.string().email();
|
|
28922
|
+
var unsignedShareEnvelopeV2BaseSchema2 = external_exports.object({
|
|
28923
|
+
version: external_exports.literal(2),
|
|
28924
|
+
shareId: external_exports.string().min(1),
|
|
28925
|
+
recipientMatcher: recipientMatcherSchema2,
|
|
28926
|
+
deliveryEmail: deliveryEmailSchema2.optional(),
|
|
28927
|
+
actions: external_exports.array(shareActionSchema2).min(1).max(3),
|
|
28928
|
+
resource: resourceSelectorSchema2,
|
|
28929
|
+
target: v2TargetSchema2,
|
|
28930
|
+
delegationCid: external_exports.string().min(1),
|
|
28931
|
+
authorityMaterialHandle: external_exports.string().min(1),
|
|
28932
|
+
authorityMaterialDigest: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
28933
|
+
decryption: shareDecryptionSchema2.optional(),
|
|
28934
|
+
contentSource: contentSourceSchema2,
|
|
28935
|
+
contentSourceDigest: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
28936
|
+
authorizationTarget: authorizationTargetSchema2,
|
|
28937
|
+
display: displaySchema2,
|
|
28938
|
+
expiry: external_exports.string().datetime(),
|
|
28939
|
+
encrypted: external_exports.boolean(),
|
|
28940
|
+
content: contentPointerSchema2.optional(),
|
|
28941
|
+
metadata: contentMetadataSchema2,
|
|
28942
|
+
ownerAuthority: ownerAuthoritySchema2.optional()
|
|
28943
|
+
}).strict();
|
|
28944
|
+
function validateV2Invariants2(value, ctx) {
|
|
28945
|
+
const actions = [...value.actions];
|
|
28946
|
+
if (new Set(actions).size !== actions.length) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["actions"], message: "actions must be unique" });
|
|
28947
|
+
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" });
|
|
28948
|
+
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" });
|
|
28949
|
+
if (!value.encrypted && value.authorizationTarget.kind !== "policy") ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["encrypted"], message: "unencrypted content requires a policy target" });
|
|
28950
|
+
if (!value.encrypted && value.content !== void 0) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["content"], message: "policy-only plaintext cannot carry content" });
|
|
28951
|
+
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" });
|
|
28952
|
+
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" });
|
|
28953
|
+
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" });
|
|
28954
|
+
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" });
|
|
28955
|
+
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" });
|
|
28956
|
+
if (!value.encrypted && value.deliveryEmail !== void 0) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["deliveryEmail"], message: "policy-only plaintext cannot carry delivery metadata" });
|
|
28957
|
+
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" });
|
|
28958
|
+
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" });
|
|
28959
|
+
if (value.contentSource.kind === "kv" && value.contentSource.action !== "tinycloud.kv/get") ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource"], message: "source action mismatch" });
|
|
28960
|
+
if (value.contentSource.kind === "sql" && value.contentSource.action !== "tinycloud.sql/read") ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource"], message: "source action mismatch" });
|
|
28961
|
+
}
|
|
28962
|
+
var unsignedShareEnvelopeV2Schema2 = unsignedShareEnvelopeV2BaseSchema2.superRefine(validateV2Invariants2);
|
|
28963
|
+
var shareEnvelopeV2Schema2 = unsignedShareEnvelopeV2BaseSchema2.extend({ signature: signatureSchema2 }).strict().superRefine(validateV2Invariants2);
|
|
28964
|
+
var unifiedResourceSchema2 = external_exports.string().refine((value) => {
|
|
28965
|
+
const marker = value.indexOf("/kv/");
|
|
28966
|
+
if (marker < 1) return false;
|
|
28967
|
+
const space = value.slice(0, marker);
|
|
28968
|
+
const legacy = space.startsWith("tinycloud://");
|
|
28969
|
+
if (legacy ? /[:/?#%]/.test(space.slice("tinycloud://".length)) : !space.startsWith("tinycloud:") || /[/?#%]/.test(space)) return false;
|
|
28970
|
+
const path = value.slice(marker + 4);
|
|
28971
|
+
return !path.startsWith("/") && !path.endsWith("/") && !path.includes("//") && path.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
28972
|
+
}, { message: "expected canonical TinyCloud KV resource" });
|
|
28973
|
+
var unifiedEncryptionNetworkSchema2 = external_exports.string().refine((value) => {
|
|
28974
|
+
if (!value.startsWith("urn:tinycloud:encryption:")) return false;
|
|
28975
|
+
const rest = value.slice("urn:tinycloud:encryption:".length);
|
|
28976
|
+
const separator = rest.lastIndexOf(":");
|
|
28977
|
+
const owner = separator < 0 ? "" : rest.slice(0, separator);
|
|
28978
|
+
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
28979
|
+
return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
|
|
28980
|
+
}, { message: "expected canonical TinyCloud encryption network" });
|
|
28981
|
+
var unifiedKvCapabilitySchema2 = external_exports.object({
|
|
28982
|
+
kind: external_exports.literal("kv"),
|
|
28983
|
+
resource: unifiedResourceSchema2,
|
|
28984
|
+
selector: external_exports.union([external_exports.literal("exact"), external_exports.literal("prefix")]),
|
|
28985
|
+
actions: external_exports.array(external_exports.union([
|
|
28986
|
+
external_exports.literal("tinycloud.kv/get"),
|
|
28987
|
+
external_exports.literal("tinycloud.kv/list"),
|
|
28988
|
+
external_exports.literal("tinycloud.kv/metadata"),
|
|
28989
|
+
external_exports.literal("tinycloud.kv/put")
|
|
28990
|
+
])).min(1)
|
|
28991
|
+
}).strict();
|
|
28992
|
+
var unifiedEncryptionCapabilitySchema2 = external_exports.object({
|
|
28993
|
+
kind: external_exports.literal("encryption"),
|
|
28994
|
+
resource: unifiedEncryptionNetworkSchema2,
|
|
28995
|
+
action: external_exports.literal("tinycloud.encryption/decrypt")
|
|
28996
|
+
}).strict();
|
|
28997
|
+
var unifiedCapabilitySchema2 = external_exports.union([unifiedKvCapabilitySchema2, unifiedEncryptionCapabilitySchema2]);
|
|
28998
|
+
var unifiedContentSourceSchema2 = external_exports.object({
|
|
28999
|
+
shareId: external_exports.string().min(1),
|
|
29000
|
+
kvResource: unifiedResourceSchema2,
|
|
29001
|
+
selector: external_exports.union([external_exports.literal("exact"), external_exports.literal("prefix")]),
|
|
29002
|
+
encryptionNetwork: unifiedEncryptionNetworkSchema2,
|
|
29003
|
+
encryptedSymmetricKeyDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
29004
|
+
keyVersion: external_exports.number().int().positive(),
|
|
29005
|
+
mode: external_exports.union([external_exports.literal("mutable"), external_exports.literal("immutable")]),
|
|
29006
|
+
initialCiphertextDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/).optional()
|
|
29007
|
+
}).strict();
|
|
29008
|
+
var unifiedPolicyV1Schema2 = external_exports.object({
|
|
29009
|
+
schema: external_exports.literal("xyz.tinycloud.policy/policy/v1"),
|
|
29010
|
+
policyId: external_exports.string().regex(/^pol_[a-z2-7]+$/),
|
|
29011
|
+
ownerDid: external_exports.string().min(1),
|
|
29012
|
+
createdAt: external_exports.string().datetime({ offset: true }),
|
|
29013
|
+
expiresAt: external_exports.string().datetime({ offset: true }).optional(),
|
|
29014
|
+
contentSource: unifiedContentSourceSchema2,
|
|
29015
|
+
capabilityCeiling: external_exports.array(unifiedCapabilitySchema2).min(2),
|
|
29016
|
+
signature: external_exports.object({ suite: external_exports.string().min(1), signerDid: external_exports.string().min(1), value: external_exports.string().min(1) }).strict()
|
|
29017
|
+
}).strict();
|
|
29018
|
+
var policyCredentialRequirementV1Schema2 = external_exports.object({
|
|
29019
|
+
type: external_exports.literal("TinyCloudPolicyCredentialRequirement"),
|
|
29020
|
+
version: external_exports.literal(1),
|
|
29021
|
+
requirementDigest: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
29022
|
+
descriptorDigest: external_exports.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
29023
|
+
issuerDid: external_exports.string().min(1),
|
|
29024
|
+
issuerKid: external_exports.string().min(1),
|
|
29025
|
+
profile: external_exports.object({ id: external_exports.string().min(1), version: external_exports.literal(1) }).strict(),
|
|
29026
|
+
credentialType: external_exports.object({ id: external_exports.string().min(1), version: external_exports.literal(1) }).strict()
|
|
29027
|
+
}).strict();
|
|
29028
|
+
var unifiedPolicyV2Schema2 = external_exports.object({
|
|
29029
|
+
schema: external_exports.literal("xyz.tinycloud.policy/policy/v2"),
|
|
29030
|
+
policyId: external_exports.string().regex(/^pol_[a-z2-7]+$/),
|
|
29031
|
+
ownerDid: external_exports.string().min(1),
|
|
29032
|
+
createdAt: external_exports.string().datetime({ offset: true }),
|
|
29033
|
+
expiresAt: external_exports.string().datetime({ offset: true }).optional(),
|
|
29034
|
+
contentSource: unifiedContentSourceSchema2,
|
|
29035
|
+
capabilityCeiling: external_exports.array(unifiedCapabilitySchema2).min(2),
|
|
29036
|
+
credentialRequirement: policyCredentialRequirementV1Schema2,
|
|
29037
|
+
signature: external_exports.object({ suite: external_exports.literal("Ed25519"), signerDid: external_exports.string().min(1), value: external_exports.string().min(1) }).strict()
|
|
29038
|
+
}).strict();
|
|
29039
|
+
var unifiedPolicySchema2 = external_exports.discriminatedUnion("schema", [
|
|
29040
|
+
unifiedPolicyV1Schema2,
|
|
29041
|
+
unifiedPolicyV2Schema2
|
|
29042
|
+
]);
|
|
29043
|
+
var unifiedRootSchema2 = external_exports.object({
|
|
29044
|
+
cid: external_exports.string().min(1),
|
|
29045
|
+
authorization: external_exports.string().regex(/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/),
|
|
29046
|
+
role: external_exports.union([external_exports.literal("policy-authority"), external_exports.literal("policy-enforcement")])
|
|
29047
|
+
}).strict();
|
|
29048
|
+
var attestedEnforcerBindingV2Schema2 = external_exports.object({
|
|
29049
|
+
schema: external_exports.literal("xyz.tinycloud.policy/attested-enforcer/v2"),
|
|
29050
|
+
enforcerDid: external_exports.string().regex(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/),
|
|
29051
|
+
nodeAudience: external_exports.string().min(1),
|
|
29052
|
+
attestationBindingDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
29053
|
+
issuedAt: external_exports.string().datetime({ offset: true }),
|
|
29054
|
+
expiresAt: external_exports.string().datetime({ offset: true }),
|
|
29055
|
+
signature: external_exports.object({ suite: external_exports.literal("Ed25519"), signerDid: external_exports.string().min(1), value: base64UrlString2() }).strict()
|
|
29056
|
+
}).strict();
|
|
29057
|
+
var v3TargetSchema2 = external_exports.object({
|
|
29058
|
+
origin: external_exports.string().refine(isCanonicalHttpsOrigin2, { message: "expected a canonical https origin" }),
|
|
29059
|
+
nodeAudience: external_exports.string().min(1),
|
|
29060
|
+
spaceId: external_exports.string().refine(isCanonicalPathSegment2, { message: "expected a canonical space id" })
|
|
29061
|
+
}).strict();
|
|
29062
|
+
var unsignedShareEnvelopeV3BaseSchema2 = external_exports.object({
|
|
29063
|
+
version: external_exports.literal(3),
|
|
29064
|
+
shareId: external_exports.string().min(1),
|
|
29065
|
+
recipientMatcher: recipientMatcherSchema2,
|
|
29066
|
+
deliveryEmail: deliveryEmailSchema2.optional(),
|
|
29067
|
+
actions: external_exports.array(shareActionSchema2).min(1).max(3),
|
|
29068
|
+
resource: resourceSelectorSchema2,
|
|
29069
|
+
target: v3TargetSchema2,
|
|
29070
|
+
policy: unifiedPolicySchema2,
|
|
29071
|
+
policyCid: external_exports.string().min(1),
|
|
29072
|
+
policyRoot: unifiedRootSchema2,
|
|
29073
|
+
enforcementRoot: unifiedRootSchema2,
|
|
29074
|
+
attestedEnforcerBinding: attestedEnforcerBindingV2Schema2,
|
|
29075
|
+
contentSource: unifiedContentSourceSchema2,
|
|
29076
|
+
contentSourceDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
29077
|
+
encryptionNetwork: unifiedEncryptionNetworkSchema2,
|
|
29078
|
+
expiry: external_exports.string().datetime({ offset: true }),
|
|
29079
|
+
display: displaySchema2,
|
|
29080
|
+
encrypted: external_exports.literal(true),
|
|
29081
|
+
metadata: contentMetadataSchema2
|
|
29082
|
+
}).strict();
|
|
29083
|
+
function validateV3Invariants2(value, ctx) {
|
|
29084
|
+
const actions = [...value.actions];
|
|
29085
|
+
if (new Set(actions).size !== actions.length || actions.some((action, index) => action !== ["read", "list", "edit"].filter((candidate) => actions.includes(candidate))[index])) {
|
|
29086
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["actions"], message: "actions must be unique and canonically ordered" });
|
|
29087
|
+
}
|
|
29088
|
+
if (value.policyRoot.role !== "policy-authority" || value.enforcementRoot.role !== "policy-enforcement") {
|
|
29089
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policyRoot", "role"], message: "root roles are fixed" });
|
|
29090
|
+
}
|
|
29091
|
+
if (value.policyCid.length === 0 || value.policyCid === value.policyRoot.cid || value.policyCid === value.enforcementRoot.cid) {
|
|
29092
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policyCid"], message: "policy CID must be distinct from both roots" });
|
|
29093
|
+
}
|
|
29094
|
+
if (value.contentSource.encryptionNetwork !== value.encryptionNetwork) {
|
|
29095
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["encryptionNetwork"], message: "encryption network is not bound to the source" });
|
|
29096
|
+
}
|
|
29097
|
+
if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
|
|
29098
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
|
|
29099
|
+
}
|
|
29100
|
+
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) {
|
|
29101
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
|
|
29102
|
+
}
|
|
29103
|
+
if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
|
|
29104
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
|
|
29105
|
+
}
|
|
29106
|
+
const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
|
|
29107
|
+
const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === value.encryptionNetwork && capability.action === "tinycloud.encryption/decrypt");
|
|
29108
|
+
if (value.policy.capabilityCeiling.length !== 2 || kvCapabilities.length !== 1 || decryptCapabilities.length !== 1 || kvCapabilities[0]?.resource !== value.contentSource.kvResource || kvCapabilities[0]?.selector !== value.contentSource.selector) {
|
|
29109
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain exact decrypt network" });
|
|
29110
|
+
}
|
|
29111
|
+
}
|
|
29112
|
+
var unsignedShareEnvelopeV3Schema2 = unsignedShareEnvelopeV3BaseSchema2.superRefine(validateV3Invariants2);
|
|
29113
|
+
var shareEnvelopeV3Schema2 = unsignedShareEnvelopeV3BaseSchema2.extend({ signature: signatureSchema2 }).strict().superRefine(validateV3Invariants2);
|
|
29114
|
+
var ENVELOPE_AAD_LABEL2 = "tinycloud-share-envelope-v1";
|
|
29115
|
+
var AAD2 = utf8Bytes2(ENVELOPE_AAD_LABEL2);
|
|
29116
|
+
var LABEL2 = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
29117
|
+
function isCanonicalEmailDomain2(value) {
|
|
29118
|
+
if (value.length === 0 || value.length > 253) return false;
|
|
29119
|
+
const labels = value.split(".");
|
|
29120
|
+
return labels.length >= 2 && labels.every((label) => LABEL2.test(label)) && !/^[0-9]+$/.test(labels.at(-1));
|
|
29121
|
+
}
|
|
29122
|
+
function canonicalMailbox2(value) {
|
|
29123
|
+
const email = value.trim().toLowerCase();
|
|
29124
|
+
const at = email.indexOf("@");
|
|
29125
|
+
if (at <= 0 || at !== email.lastIndexOf("@")) return void 0;
|
|
29126
|
+
const local = email.slice(0, at);
|
|
29127
|
+
const domain = email.slice(at + 1);
|
|
29128
|
+
if (local.length > 64 || !/^[a-z0-9#$&'*+/=?^_`{|}~-]+(?:\.[a-z0-9#$&'*+/=?^_`{|}~-]+)*$/.test(local) || !isCanonicalEmailDomain2(domain)) return void 0;
|
|
29129
|
+
return Object.freeze({ email, domain });
|
|
29130
|
+
}
|
|
29131
|
+
var MAX_INLINE_BYTES2 = 256 * 1024;
|
|
29132
|
+
|
|
29133
|
+
// src/commands/share.ts
|
|
29134
|
+
import { ProfileLockTimeoutError as ProfileLockTimeoutError3 } from "@tinycloud/operations/state";
|
|
29135
|
+
init_formatter();
|
|
29136
|
+
init_errors();
|
|
29137
|
+
|
|
29138
|
+
// src/share/output.ts
|
|
29139
|
+
function writeJson2(value) {
|
|
29140
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
29141
|
+
`);
|
|
29142
|
+
}
|
|
29143
|
+
function authorizationRequiredJson(result) {
|
|
29144
|
+
return {
|
|
29145
|
+
state: "authorization-required",
|
|
29146
|
+
method: result.method,
|
|
29147
|
+
next: "complete authorization through the configured authority adapter, then retry with the required proof"
|
|
29148
|
+
};
|
|
29149
|
+
}
|
|
29150
|
+
function publishHuman(result) {
|
|
29151
|
+
process.stdout.write(`${result.url}
|
|
29152
|
+
`);
|
|
29153
|
+
}
|
|
29154
|
+
function inspectHuman(result) {
|
|
29155
|
+
const metadata = result.metadata;
|
|
29156
|
+
process.stdout.write([
|
|
29157
|
+
`Share ${metadata.shareId}`,
|
|
29158
|
+
`File: ${metadata.display.filename ?? "unnamed"}`,
|
|
29159
|
+
`Target: ${metadata.target.kind === "bearer" ? "bearer (anyone with the complete link can read)" : metadata.target.kind}`,
|
|
29160
|
+
`Expires: ${metadata.expiresAt}`,
|
|
29161
|
+
`Resource: ${metadata.resource.path}`,
|
|
29162
|
+
`Link format: ${result.link.kind}`
|
|
29163
|
+
].join("\n") + "\n");
|
|
29164
|
+
}
|
|
29165
|
+
function receiveHuman(path) {
|
|
29166
|
+
process.stdout.write(`${path}
|
|
29167
|
+
`);
|
|
29168
|
+
}
|
|
29169
|
+
function receiveJson(result, path) {
|
|
29170
|
+
writeJson2({ protocol: "tinycloud-share", version: 1, path, metadata: result.metadata });
|
|
29171
|
+
}
|
|
29172
|
+
|
|
29173
|
+
// src/share/io.ts
|
|
29174
|
+
import { constants } from "fs";
|
|
29175
|
+
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";
|
|
29176
|
+
import { randomBytes as randomBytes4 } from "crypto";
|
|
29177
|
+
import { basename as basename3, join as join6, resolve as resolve2, sep } from "path";
|
|
29178
|
+
init_errors();
|
|
29179
|
+
var MAX_SHARE_STDIN_BYTES = 100 * 1024 * 1024;
|
|
29180
|
+
var MAX_SHARE_URL_BYTES = 64 * 1024;
|
|
29181
|
+
async function readBoundedStdin(limit = MAX_SHARE_STDIN_BYTES) {
|
|
29182
|
+
if (!Number.isSafeInteger(limit) || limit <= 0) throw new Error("MAX_BYTES_EXCEEDED");
|
|
29183
|
+
const chunks = [];
|
|
29184
|
+
let total = 0;
|
|
29185
|
+
for await (const chunk of process.stdin) {
|
|
29186
|
+
const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
29187
|
+
total += bytes.byteLength;
|
|
29188
|
+
if (total > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
29189
|
+
chunks.push(bytes);
|
|
29190
|
+
}
|
|
29191
|
+
return new Uint8Array(Buffer.concat(chunks, total));
|
|
29192
|
+
}
|
|
29193
|
+
async function readBoundedUrlStdin() {
|
|
29194
|
+
const bytes = await readBoundedStdin(MAX_SHARE_URL_BYTES);
|
|
29195
|
+
const value = new TextDecoder("utf-8", { fatal: true }).decode(bytes).trim();
|
|
29196
|
+
if (value.length === 0 || /\s/.test(value)) throw new Error("INVALID_ARGUMENT");
|
|
29197
|
+
return value;
|
|
29198
|
+
}
|
|
29199
|
+
function safeFilename(value) {
|
|
29200
|
+
return shareFilename(value);
|
|
29201
|
+
}
|
|
29202
|
+
function shareFilename(value) {
|
|
29203
|
+
try {
|
|
29204
|
+
return canonicalShareFilename(value);
|
|
29205
|
+
} catch {
|
|
29206
|
+
throw new CLIError(
|
|
29207
|
+
"UNSAFE_FILENAME",
|
|
29208
|
+
hasUnsafeFilenameCodePoint(value) ? "filename contains control or invisible characters" : "filename must be one safe path segment",
|
|
29209
|
+
8
|
|
29210
|
+
);
|
|
29211
|
+
}
|
|
29212
|
+
}
|
|
29213
|
+
function shareInputFilename(input, name) {
|
|
29214
|
+
return shareFilename(name ?? (input === "-" ? "stdin.md" : basename3(resolve2(input))));
|
|
29215
|
+
}
|
|
29216
|
+
async function readShareInput(input, name, limit = MAX_SHARE_STDIN_BYTES) {
|
|
29217
|
+
const filename = shareInputFilename(input, name);
|
|
29218
|
+
if (input === "-") return { bytes: await readBoundedStdin(limit), filename };
|
|
29219
|
+
const path = resolve2(input);
|
|
29220
|
+
const info = await stat2(path);
|
|
29221
|
+
if (!info.isFile() || info.size > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
29222
|
+
const bytes = new Uint8Array(await readFile9(path));
|
|
29223
|
+
if (bytes.byteLength > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
29224
|
+
return { bytes, filename };
|
|
29225
|
+
}
|
|
29226
|
+
async function assertDirectory(path) {
|
|
29227
|
+
const absolute = resolve2(path);
|
|
29228
|
+
const segments = absolute.split(sep).filter(Boolean);
|
|
29229
|
+
let current = absolute.startsWith(sep) ? sep : "";
|
|
29230
|
+
for (const segment of segments) {
|
|
29231
|
+
current = current === sep ? join6(current, segment) : join6(current, segment);
|
|
29232
|
+
try {
|
|
29233
|
+
const info = await lstat3(current);
|
|
29234
|
+
if (info.isSymbolicLink()) {
|
|
29235
|
+
const canonical = await realpath(current);
|
|
29236
|
+
if (current !== "/tmp" && current !== "/var") throw new Error("OUTPUT_EXISTS");
|
|
29237
|
+
if (canonical !== `/private${current}`) throw new Error("OUTPUT_EXISTS");
|
|
29238
|
+
} else if (!info.isDirectory()) throw new Error("OUTPUT_EXISTS");
|
|
29239
|
+
} catch (error) {
|
|
29240
|
+
if (error.code !== "ENOENT") throw error;
|
|
29241
|
+
await mkdir3(current, { mode: 448 });
|
|
29242
|
+
const created = await lstat3(current);
|
|
29243
|
+
if (created.isSymbolicLink() || !created.isDirectory()) throw new Error("OUTPUT_EXISTS");
|
|
29244
|
+
}
|
|
29245
|
+
}
|
|
29246
|
+
}
|
|
29247
|
+
async function writeShareOutput(directory, filename, bytes, force) {
|
|
29248
|
+
const outputDirectory = resolve2(directory);
|
|
29249
|
+
await assertDirectory(outputDirectory);
|
|
29250
|
+
const safeName = safeFilename(filename);
|
|
29251
|
+
const directoryHandle = await open4(outputDirectory, constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0));
|
|
29252
|
+
const stableDirectory = await realpath(outputDirectory);
|
|
29253
|
+
const outputPath = join6(stableDirectory, safeName);
|
|
29254
|
+
const directoryIdentity = await directoryHandle.stat();
|
|
29255
|
+
const assertStableDirectory = async () => {
|
|
29256
|
+
const current = await stat2(stableDirectory);
|
|
29257
|
+
if (current.dev !== directoryIdentity.dev || current.ino !== directoryIdentity.ino) throw new Error("OUTPUT_EXISTS");
|
|
29258
|
+
};
|
|
29259
|
+
await assertStableDirectory();
|
|
29260
|
+
const stagingDirectory = await mkdtemp(join6(stableDirectory, ".tinycloud-share-stage-"));
|
|
29261
|
+
const stagingInfo = await lstat3(stagingDirectory);
|
|
29262
|
+
if (!stagingInfo.isDirectory() || (stagingInfo.mode & 511) !== 448) throw new Error("OUTPUT_EXISTS");
|
|
29263
|
+
const stagingPath = join6(stagingDirectory, `.tinycloud-share-${randomBytes4(16).toString("hex")}.tmp`);
|
|
29264
|
+
let temporaryPath;
|
|
29265
|
+
let handle;
|
|
29266
|
+
try {
|
|
29267
|
+
await assertStableDirectory();
|
|
29268
|
+
try {
|
|
29269
|
+
const existing = await lstat3(outputPath);
|
|
29270
|
+
if (existing.isSymbolicLink()) throw new Error("UNSAFE_FILENAME");
|
|
29271
|
+
} catch (error) {
|
|
29272
|
+
if (error.code !== "ENOENT") throw error;
|
|
29273
|
+
}
|
|
29274
|
+
temporaryPath = stagingPath;
|
|
29275
|
+
handle = await open4(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0), 384);
|
|
29276
|
+
await handle.writeFile(bytes);
|
|
29277
|
+
await handle.close();
|
|
29278
|
+
handle = void 0;
|
|
29279
|
+
await assertStableDirectory();
|
|
29280
|
+
if (force) {
|
|
29281
|
+
await rename3(temporaryPath, outputPath);
|
|
29282
|
+
} else {
|
|
29283
|
+
await link(temporaryPath, outputPath);
|
|
29284
|
+
await unlink(temporaryPath);
|
|
29285
|
+
}
|
|
29286
|
+
await assertStableDirectory();
|
|
29287
|
+
} catch (error) {
|
|
29288
|
+
if (error.code === "EEXIST") throw new Error("OUTPUT_EXISTS");
|
|
29289
|
+
if (error.code === "ELOOP") throw new Error("UNSAFE_FILENAME");
|
|
29290
|
+
throw error;
|
|
29291
|
+
} finally {
|
|
29292
|
+
await handle?.close();
|
|
29293
|
+
try {
|
|
29294
|
+
if (temporaryPath !== void 0) await unlink(temporaryPath);
|
|
29295
|
+
} catch {
|
|
29296
|
+
}
|
|
29297
|
+
await rm4(stagingDirectory, { recursive: true, force: true });
|
|
29298
|
+
await directoryHandle.close();
|
|
29299
|
+
}
|
|
29300
|
+
return join6(outputDirectory, safeName);
|
|
29301
|
+
}
|
|
29302
|
+
|
|
29303
|
+
// src/share/errors.ts
|
|
29304
|
+
var SharePublishAuthorityError = class extends Error {
|
|
29305
|
+
constructor(failure) {
|
|
29306
|
+
super(failure.kind);
|
|
29307
|
+
this.failure = failure;
|
|
29308
|
+
this.name = "SharePublishAuthorityError";
|
|
29309
|
+
}
|
|
29310
|
+
};
|
|
29311
|
+
var ShareHistoryRetryError = class extends Error {
|
|
29312
|
+
constructor(profile) {
|
|
29313
|
+
super("sender history changed during the operation");
|
|
29314
|
+
this.profile = profile;
|
|
29315
|
+
this.name = "ShareHistoryRetryError";
|
|
29316
|
+
}
|
|
29317
|
+
code = "SHARE_HISTORY_RETRY";
|
|
29318
|
+
};
|
|
29319
|
+
|
|
29320
|
+
// src/commands/share.ts
|
|
29321
|
+
var SHARE_ORIGIN = "https://share.tinycloud.xyz";
|
|
29322
|
+
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";
|
|
29323
|
+
var shareServices = {};
|
|
29324
|
+
function parseShareTarget(value) {
|
|
29325
|
+
if (value === "anyone" || value === "bearer") return { kind: "bearer" };
|
|
29326
|
+
if (value.startsWith("did:")) return { kind: "recipientDid", did: value };
|
|
29327
|
+
if (value.startsWith("domain:")) return canonicalMailboxTarget({ kind: "emailDomain", domain: value.slice("domain:".length) });
|
|
29328
|
+
if (value.startsWith("email:")) return canonicalMailboxTarget({ kind: "email", address: value.slice("email:".length) });
|
|
29329
|
+
if (value.includes("@")) return canonicalMailboxTarget({ kind: "email", address: value });
|
|
29330
|
+
throw new CLIError("INVALID_ARGUMENT", "--to must be anyone, a did:, an email address, or domain:example.com", 2);
|
|
29331
|
+
}
|
|
29332
|
+
function canonicalMailboxTarget(target) {
|
|
29333
|
+
try {
|
|
29334
|
+
return normalizeShareTarget(target);
|
|
29335
|
+
} catch (error) {
|
|
29336
|
+
throw new CLIError("INVALID_ARGUMENT", error instanceof TypeError ? error.message : "share recipient is invalid", 2);
|
|
29337
|
+
}
|
|
29338
|
+
}
|
|
29339
|
+
function shareCliError(error, operation = "publish") {
|
|
29340
|
+
if (error instanceof CLIError) return error;
|
|
29341
|
+
if (error instanceof ProfileLockTimeoutError3) return wrapError(error);
|
|
29342
|
+
if (error instanceof ShareHistoryRetryError) {
|
|
29343
|
+
return new CLIError(
|
|
29344
|
+
"SHARE_HISTORY_RETRY",
|
|
29345
|
+
`sender history for profile ${JSON.stringify(error.profile)} changed or disappeared during this command`,
|
|
29346
|
+
1,
|
|
29347
|
+
{ 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.` }
|
|
29348
|
+
);
|
|
29349
|
+
}
|
|
29350
|
+
if (error instanceof SharePublishAuthorityError) {
|
|
29351
|
+
const failure = error.failure;
|
|
29352
|
+
const profileName = "profileName" in failure ? failure.profileName : void 0;
|
|
29353
|
+
const localKey = "localKey" in failure && failure.localKey === true;
|
|
29354
|
+
const profileHint = profileName === void 0 ? "" : `--profile ${profileName} `;
|
|
29355
|
+
const loginHint = localKey ? `\`tc ${profileHint}auth login --method local\`` : `\`tc ${profileHint}auth login --device --manifest builtin:share-publishing\` (or \`tc ${profileHint}enable share\`)`;
|
|
29356
|
+
if (failure.kind === "caveated-session") {
|
|
29357
|
+
const holder = profileName === void 0 ? "this session" : `profile ${profileName}'s session`;
|
|
29358
|
+
return new CLIError(
|
|
29359
|
+
"PERMISSION_DENIED",
|
|
29360
|
+
`${holder} carries signed restrictions (caveats) on the authority an anyone-with-link share needs, so it cannot create the share link; nothing was shared. Approve Share publishing without restrictions on a new, dedicated profile (any unused name): \`tc init --name publisher --key-only && tc --profile publisher enable share\``,
|
|
29361
|
+
5
|
|
29362
|
+
);
|
|
29363
|
+
}
|
|
29364
|
+
if (failure.kind === "owner-space-unresolved") {
|
|
29365
|
+
return new CLIError("AUTH_REQUIRED", `a valid signed TinyCloud session is required; run ${loginHint}`, 3);
|
|
29366
|
+
}
|
|
29367
|
+
if (failure.kind === "scope-denied") {
|
|
29368
|
+
const requiredAction = failure.requiredAction === void 0 ? "" : ` (${failure.requiredAction})`;
|
|
29369
|
+
const renew = localKey ? `renew it with ${loginHint} using the required capability` : `verify the session includes the builtin:share-publishing scope; if it does not, request it with ${loginHint}`;
|
|
29370
|
+
return new CLIError("PERMISSION_DENIED", `the session lacks ${failure.capability} authority${requiredAction}; ${renew}`, 5);
|
|
27724
29371
|
}
|
|
27725
29372
|
if (failure.kind === "lifetime-exceeds-session") {
|
|
27726
29373
|
const expiresAt = failure.sessionExpiresAt.toISOString();
|
|
@@ -27741,6 +29388,10 @@ function shareCliError(error) {
|
|
|
27741
29388
|
if (failure.kind === "registry-unavailable") {
|
|
27742
29389
|
return new CLIError("UNAVAILABLE", "the TinyCloud location registry could not be reached, so nothing was shared; try again shortly", 4);
|
|
27743
29390
|
}
|
|
29391
|
+
if (failure.kind === "node-info-unavailable") {
|
|
29392
|
+
const outcome = operation === "publish" ? "nothing was shared and no invitation was sent" : "no invitation was sent";
|
|
29393
|
+
return new CLIError("UNAVAILABLE", `could not verify TinyCloud node 1.17.3 domain delivery support; ${outcome}. Check the node and retry`, 4);
|
|
29394
|
+
}
|
|
27744
29395
|
if (failure.kind === "registry-rejected") {
|
|
27745
29396
|
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
29397
|
}
|
|
@@ -27757,14 +29408,14 @@ function shareCliError(error) {
|
|
|
27757
29408
|
}
|
|
27758
29409
|
if (error instanceof SharePublishError) {
|
|
27759
29410
|
const exit = error.code === "authority-required" ? 3 : error.code === "max-bytes-exceeded" ? 7 : 2;
|
|
27760
|
-
const
|
|
27761
|
-
return new CLIError(
|
|
29411
|
+
const code3 = error.code === "authority-required" ? "AUTH_REQUIRED" : error.code === "max-bytes-exceeded" ? "MAX_BYTES_EXCEEDED" : "INVALID_ARGUMENT";
|
|
29412
|
+
return new CLIError(code3, error.message, exit);
|
|
27762
29413
|
}
|
|
27763
29414
|
if (error instanceof ShareReceiveError) {
|
|
27764
29415
|
const verification = /* @__PURE__ */ new Set(["cid-mismatch", "decrypt-failed", "envelope-invalid", "origin-mismatch", "signature-invalid", "capability-invalid", "content-integrity-failed"]);
|
|
27765
29416
|
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(
|
|
29417
|
+
const code3 = error.code === "fetch-failed" ? "NOT_FOUND" : error.code.replaceAll("-", "_").toUpperCase();
|
|
29418
|
+
return new CLIError(code3, error.message, exit);
|
|
27768
29419
|
}
|
|
27769
29420
|
const message = error instanceof Error ? error.message : String(error);
|
|
27770
29421
|
const nodeCode = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
@@ -27809,8 +29460,33 @@ function expires(value) {
|
|
|
27809
29460
|
}
|
|
27810
29461
|
async function rememberPublishedShare(result) {
|
|
27811
29462
|
const record = historyRecordForPublishedShare(result);
|
|
27812
|
-
if (shareServices.records
|
|
27813
|
-
|
|
29463
|
+
if (shareServices.records === void 0) return { record, recorded: false };
|
|
29464
|
+
try {
|
|
29465
|
+
await shareServices.records.put(record);
|
|
29466
|
+
return { record, recorded: true };
|
|
29467
|
+
} catch {
|
|
29468
|
+
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");
|
|
29469
|
+
return { record, recorded: false };
|
|
29470
|
+
}
|
|
29471
|
+
}
|
|
29472
|
+
async function notifyRecordedShare(record, recipient, adapter, storage) {
|
|
29473
|
+
const result = await notifyShare({ shareId: record.shareId, recipient, record, adapter, checkDeliveryWindow: true });
|
|
29474
|
+
if (result.state !== "partial-failure" && storage !== void 0) {
|
|
29475
|
+
const mailbox = canonicalMailbox2(recipient).email;
|
|
29476
|
+
if (!record.deliveredRecipients?.includes(mailbox)) {
|
|
29477
|
+
try {
|
|
29478
|
+
if (storage.update === void 0) throw new Error("atomic sender history update is unavailable");
|
|
29479
|
+
const updated = await storage.update(record.shareId, (current) => ({
|
|
29480
|
+
...current,
|
|
29481
|
+
deliveredRecipients: current.deliveredRecipients?.includes(mailbox) ? current.deliveredRecipients : [...current.deliveredRecipients ?? [], mailbox]
|
|
29482
|
+
}));
|
|
29483
|
+
if (updated === void 0) throw new Error("sender history record was removed");
|
|
29484
|
+
} catch {
|
|
29485
|
+
process.stderr.write("Warning: delivery succeeded, but could not record its confirmation in sender history.\n");
|
|
29486
|
+
}
|
|
29487
|
+
}
|
|
29488
|
+
}
|
|
29489
|
+
return result;
|
|
27814
29490
|
}
|
|
27815
29491
|
function byteLimit(value) {
|
|
27816
29492
|
if (value === void 0) return void 0;
|
|
@@ -27837,7 +29513,7 @@ function assertAggregateInputLimit(inputs, maxBytes) {
|
|
|
27837
29513
|
}
|
|
27838
29514
|
function registerShareCommand(program) {
|
|
27839
29515
|
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", "
|
|
29516
|
+
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
29517
|
try {
|
|
27842
29518
|
const json = jsonOutput(options, command);
|
|
27843
29519
|
const maxBytes = byteLimit(options.maxBytes);
|
|
@@ -27851,7 +29527,21 @@ function registerShareCommand(program) {
|
|
|
27851
29527
|
if (options.prefix && target.kind === "bearer") throw new CLIError("INVALID_ARGUMENT", "--prefix requires an addressed target", 2);
|
|
27852
29528
|
if (inputs.length > 1 && target.kind === "bearer") throw new CLIError("UNSUPPORTED_LINK", "multiple files require an addressed target", 2);
|
|
27853
29529
|
if (inputs.length > 1 && !options.prefix) throw new CLIError("INVALID_ARGUMENT", "multiple files require --prefix", 2);
|
|
27854
|
-
if (options.notify === true &&
|
|
29530
|
+
if (options.notify === true && !actions.includes("read")) throw new CLIError("INVALID_ARGUMENT", "--notify requires the read action; nothing was shared", 2);
|
|
29531
|
+
if (options.notifyTo !== void 0 && (options.notify !== true || target.kind !== "emailDomain")) {
|
|
29532
|
+
throw new CLIError("INVALID_ARGUMENT", "--notify-to requires --to domain:<name> --notify", 2);
|
|
29533
|
+
}
|
|
29534
|
+
let notifyRecipient;
|
|
29535
|
+
if (options.notify === true && target.kind === "email") notifyRecipient = target.address;
|
|
29536
|
+
else if (options.notify === true && target.kind === "emailDomain") {
|
|
29537
|
+
const mailbox = options.notifyTo === void 0 ? void 0 : canonicalMailbox2(options.notifyTo);
|
|
29538
|
+
if (mailbox === void 0 || mailbox.domain !== target.domain) {
|
|
29539
|
+
throw new CLIError("INVALID_ARGUMENT", "--to domain:<name> --notify requires --notify-to <email> at that exact domain (node 1.17.3+)", 2);
|
|
29540
|
+
}
|
|
29541
|
+
notifyRecipient = mailbox.email;
|
|
29542
|
+
} else if (options.notify === true) {
|
|
29543
|
+
throw new CLIError("INVALID_ARGUMENT", "--notify requires an email target, or a domain target with --notify-to on node 1.17.3+", 2);
|
|
29544
|
+
}
|
|
27855
29545
|
const result = await publishTargetShare({
|
|
27856
29546
|
source: inputs[0].bytes,
|
|
27857
29547
|
filename: inputs[0].filename,
|
|
@@ -27876,16 +29566,17 @@ function registerShareCommand(program) {
|
|
|
27876
29566
|
}
|
|
27877
29567
|
throw new CLIError(result.method === "openkey-device" ? "DEVICE_AUTH_REQUIRED" : "CLAIM_REQUIRED", "recipient authorization is required; continue through the configured authority adapter", 6);
|
|
27878
29568
|
}
|
|
27879
|
-
const record = await rememberPublishedShare(result);
|
|
27880
|
-
|
|
29569
|
+
const { record, recorded } = await rememberPublishedShare(result);
|
|
29570
|
+
let notification;
|
|
29571
|
+
if (notifyRecipient !== void 0) {
|
|
27881
29572
|
if (shareServices.delivery === void 0) throw new CLIError("AUTH_REQUIRED", "delivery authority is not configured", 3);
|
|
27882
|
-
|
|
27883
|
-
|
|
27884
|
-
if (
|
|
29573
|
+
notification = await notifyRecordedShare(record, notifyRecipient, shareServices.delivery, recorded ? shareServices.records : void 0);
|
|
29574
|
+
if (notification.state === "partial-failure") process.exitCode = 9;
|
|
29575
|
+
if (notification.reason === "delivery-window-expired") process.stderr.write(NOTIFY_WINDOW_MESSAGE);
|
|
27885
29576
|
}
|
|
27886
29577
|
if (result.metadata.expiryClamped === true) process.stderr.write(`Share expiry clamped to session expiry (${result.metadata.expiresAt}).
|
|
27887
29578
|
`);
|
|
27888
|
-
if (json) writeJson2({ ...redactPublishedShare(result), expiryClamped: result.metadata.expiryClamped === true });
|
|
29579
|
+
if (json) writeJson2({ ...redactPublishedShare(result), expiryClamped: result.metadata.expiryClamped === true, ...notification === void 0 ? {} : { notification } });
|
|
27889
29580
|
else publishHuman(result);
|
|
27890
29581
|
} catch (error) {
|
|
27891
29582
|
handleError(shareCliError(error));
|
|
@@ -27972,20 +29663,31 @@ function registerShareCommand(program) {
|
|
|
27972
29663
|
handleError(shareCliError(error));
|
|
27973
29664
|
}
|
|
27974
29665
|
});
|
|
27975
|
-
share.command("notify <id>").description("Retry idempotent delivery
|
|
29666
|
+
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
29667
|
try {
|
|
27977
29668
|
const json = jsonOutput(options, command);
|
|
27978
29669
|
if (shareServices.delivery === void 0) throw new CLIError("AUTH_REQUIRED", "delivery authority is not configured", 3);
|
|
27979
29670
|
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
27980
29671
|
const record = await shareServices.records.get(id);
|
|
27981
29672
|
if (record === void 0) throw new CLIError("NOT_FOUND", "share not found", 4);
|
|
27982
|
-
|
|
29673
|
+
if (!record.actions.includes("tinycloud.kv/get")) {
|
|
29674
|
+
throw new CLIError("INVALID_ARGUMENT", "share notify requires a stored share with the read action; no invitation was sent", 2);
|
|
29675
|
+
}
|
|
29676
|
+
const mailbox = canonicalMailbox2(options.to);
|
|
29677
|
+
if (mailbox === void 0) throw new ShareNotifyError("recipient is invalid");
|
|
29678
|
+
if (!recipientMatchesShareRecord(record, mailbox.email)) throw new ShareNotifyError("recipient does not match the stored share target");
|
|
29679
|
+
if (record.recipientMatcher.kind === "emailDomain" && shareDeliveryWindowExpiresAt(record) > Date.now()) {
|
|
29680
|
+
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);
|
|
29681
|
+
await shareServices.assertDomainDelivery();
|
|
29682
|
+
}
|
|
29683
|
+
const result = await notifyRecordedShare(record, options.to, shareServices.delivery, shareServices.records);
|
|
27983
29684
|
if (json) writeJson2(result);
|
|
27984
29685
|
else process.stdout.write(`${result.state}
|
|
27985
29686
|
`);
|
|
29687
|
+
if (result.reason === "delivery-window-expired") process.stderr.write(NOTIFY_WINDOW_MESSAGE);
|
|
27986
29688
|
if (result.state === "partial-failure") process.exitCode = 9;
|
|
27987
29689
|
} catch (error) {
|
|
27988
|
-
handleError(shareCliError(error));
|
|
29690
|
+
handleError(shareCliError(error, "notify"));
|
|
27989
29691
|
}
|
|
27990
29692
|
});
|
|
27991
29693
|
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 +29732,7 @@ function registerSpaceCommand(program) {
|
|
|
28030
29732
|
const node = await ensureAuthenticated(ctx);
|
|
28031
29733
|
const result = await node.spaces.list();
|
|
28032
29734
|
if (!result.ok) {
|
|
28033
|
-
throw
|
|
29735
|
+
throw cliErrorFromService(result.error);
|
|
28034
29736
|
}
|
|
28035
29737
|
if (shouldOutputJson()) {
|
|
28036
29738
|
outputJson({ spaces: result.data, count: result.data.length });
|
|
@@ -28175,7 +29877,7 @@ async function throwSqlError(error, spaceUri, profileName, prefix) {
|
|
|
28175
29877
|
const hosted = await unhostedSpaceError(error, spaceUri, profileName);
|
|
28176
29878
|
if (hosted) throw hosted;
|
|
28177
29879
|
const message = prefix ? `${prefix}${error.message}` : error.message;
|
|
28178
|
-
throw
|
|
29880
|
+
throw cliErrorFromService(error, message);
|
|
28179
29881
|
}
|
|
28180
29882
|
function registerSqlCommand(program) {
|
|
28181
29883
|
const sql = program.command("sql").description("SQLite database operations for your TinyCloud space").addHelpText("after", `
|
|
@@ -28561,7 +30263,13 @@ async function readHasKey(name, issues) {
|
|
|
28561
30263
|
}
|
|
28562
30264
|
async function readDelegations(name, issues) {
|
|
28563
30265
|
try {
|
|
28564
|
-
|
|
30266
|
+
const entries = await loadAdditionalDelegations(name);
|
|
30267
|
+
const { storedDelegationKind } = await import("@tinycloud/operations/delegation-binding");
|
|
30268
|
+
const readable = entries.filter((entry) => storedDelegationKind(entry) !== "refused");
|
|
30269
|
+
if (readable.length < entries.length) {
|
|
30270
|
+
issues.push(`delegations: ${entries.length - readable.length} unreadable stored record(s) skipped`);
|
|
30271
|
+
}
|
|
30272
|
+
return readable;
|
|
28565
30273
|
} catch (error) {
|
|
28566
30274
|
issues.push(`delegations: ${messageFromError(error)}`);
|
|
28567
30275
|
return [];
|
|
@@ -28881,7 +30589,7 @@ async function unlockVault(node, privateKey) {
|
|
|
28881
30589
|
const signer = new PrivateKeySigner2(privateKey);
|
|
28882
30590
|
const result = await node.vault.unlock(signer);
|
|
28883
30591
|
if (result && !result.ok) {
|
|
28884
|
-
throw
|
|
30592
|
+
throw cliErrorFromService(result.error);
|
|
28885
30593
|
}
|
|
28886
30594
|
}
|
|
28887
30595
|
function registerVaultCommand(program) {
|
|
@@ -28922,7 +30630,7 @@ function registerVaultCommand(program) {
|
|
|
28922
30630
|
}
|
|
28923
30631
|
const result = await withSpinner(`Writing ${key}...`, () => node.vault.put(key, putValue));
|
|
28924
30632
|
if (!result.ok) {
|
|
28925
|
-
throw
|
|
30633
|
+
throw cliErrorFromService(result.error);
|
|
28926
30634
|
}
|
|
28927
30635
|
outputJson({ key, written: true });
|
|
28928
30636
|
} catch (error) {
|
|
@@ -28941,7 +30649,7 @@ function registerVaultCommand(program) {
|
|
|
28941
30649
|
if (result.error.code === "NOT_FOUND") {
|
|
28942
30650
|
throw new CLIError("NOT_FOUND", `Key "${key}" not found`, ExitCode.NOT_FOUND);
|
|
28943
30651
|
}
|
|
28944
|
-
throw
|
|
30652
|
+
throw cliErrorFromService(result.error);
|
|
28945
30653
|
}
|
|
28946
30654
|
const data = result.data.data ?? result.data;
|
|
28947
30655
|
if (options.output) {
|
|
@@ -28972,7 +30680,7 @@ function registerVaultCommand(program) {
|
|
|
28972
30680
|
await withSpinner("Unlocking vault...", () => unlockVault(node, privateKey));
|
|
28973
30681
|
const result = await withSpinner(`Deleting ${key}...`, () => node.vault.delete(key));
|
|
28974
30682
|
if (!result.ok) {
|
|
28975
|
-
throw
|
|
30683
|
+
throw cliErrorFromService(result.error);
|
|
28976
30684
|
}
|
|
28977
30685
|
outputJson({ key, deleted: true });
|
|
28978
30686
|
} catch (error) {
|
|
@@ -28989,7 +30697,7 @@ function registerVaultCommand(program) {
|
|
|
28989
30697
|
const listOptions = options.prefix ? { prefix: options.prefix } : void 0;
|
|
28990
30698
|
const result = await withSpinner("Listing vault keys...", () => node.vault.list(listOptions));
|
|
28991
30699
|
if (!result.ok) {
|
|
28992
|
-
throw
|
|
30700
|
+
throw cliErrorFromService(result.error);
|
|
28993
30701
|
}
|
|
28994
30702
|
const keys = result.data.data ?? result.data;
|
|
28995
30703
|
const keyList = Array.isArray(keys) ? keys : [];
|
|
@@ -29015,7 +30723,7 @@ function registerVaultCommand(program) {
|
|
|
29015
30723
|
outputJson({ key, exists: false, metadata: {} });
|
|
29016
30724
|
return;
|
|
29017
30725
|
}
|
|
29018
|
-
throw
|
|
30726
|
+
throw cliErrorFromService(result.error);
|
|
29019
30727
|
}
|
|
29020
30728
|
outputJson({
|
|
29021
30729
|
key,
|
|
@@ -29065,7 +30773,7 @@ function registerVarsCommand(program) {
|
|
|
29065
30773
|
const prefixedKv = node.kv.withPrefix(VARIABLES_PREFIX);
|
|
29066
30774
|
const result = await withSpinner("Listing variables...", () => prefixedKv.list());
|
|
29067
30775
|
if (!result.ok) {
|
|
29068
|
-
throw
|
|
30776
|
+
throw cliErrorFromService(result.error);
|
|
29069
30777
|
}
|
|
29070
30778
|
const rawData = result.data.data ?? result.data;
|
|
29071
30779
|
const keyList = Array.isArray(rawData) ? rawData : rawData?.keys ?? [];
|
|
@@ -29089,7 +30797,7 @@ function registerVarsCommand(program) {
|
|
|
29089
30797
|
if (result.error.code === "KV_NOT_FOUND" || result.error.code === "NOT_FOUND") {
|
|
29090
30798
|
throw new CLIError("NOT_FOUND", `Variable "${name}" not found`, ExitCode.NOT_FOUND);
|
|
29091
30799
|
}
|
|
29092
|
-
throw
|
|
30800
|
+
throw cliErrorFromService(result.error);
|
|
29093
30801
|
}
|
|
29094
30802
|
const data = result.data.data;
|
|
29095
30803
|
let value;
|
|
@@ -29147,7 +30855,7 @@ function registerVarsCommand(program) {
|
|
|
29147
30855
|
const prefixedKv = node.kv.withPrefix(VARIABLES_PREFIX);
|
|
29148
30856
|
const result = await withSpinner(`Setting variable ${name}...`, () => prefixedKv.put(name, payload));
|
|
29149
30857
|
if (!result.ok) {
|
|
29150
|
-
throw
|
|
30858
|
+
throw cliErrorFromService(result.error);
|
|
29151
30859
|
}
|
|
29152
30860
|
outputJson({ name, written: true });
|
|
29153
30861
|
} catch (error) {
|
|
@@ -29163,7 +30871,7 @@ function registerVarsCommand(program) {
|
|
|
29163
30871
|
const prefixedKv = node.kv.withPrefix(VARIABLES_PREFIX);
|
|
29164
30872
|
const result = await withSpinner(`Deleting variable ${name}...`, () => prefixedKv.delete(name));
|
|
29165
30873
|
if (!result.ok) {
|
|
29166
|
-
throw
|
|
30874
|
+
throw cliErrorFromService(result.error);
|
|
29167
30875
|
}
|
|
29168
30876
|
outputJson({ name, deleted: true });
|
|
29169
30877
|
} catch (error) {
|