@tinycloud/cli 1.0.1-beta.5 → 1.1.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2253 -1863
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +2443 -588
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +5 -5
- package/skills/tc-cli/AUTH.md +14 -1
- package/skills/tc-cli/REFERENCE.md +37 -7
- package/skills/tc-cli/SKILL.md +5 -1
package/dist/index.js
CHANGED
|
@@ -72,7 +72,7 @@ var init_theme = __esm({
|
|
|
72
72
|
|
|
73
73
|
// src/output/formatter.ts
|
|
74
74
|
import ora from "ora";
|
|
75
|
-
function outputError(code3, message, hint) {
|
|
75
|
+
function outputError(code3, message, hint, meta) {
|
|
76
76
|
if (isInteractive()) {
|
|
77
77
|
process.stderr.write(
|
|
78
78
|
`${theme.error("\u2717")} ${theme.label(code3)}: ${message}
|
|
@@ -89,6 +89,7 @@ function outputError(code3, message, hint) {
|
|
|
89
89
|
error: { code: code3, message }
|
|
90
90
|
};
|
|
91
91
|
if (hint) payload.error.hint = hint;
|
|
92
|
+
if (meta) payload.error.meta = meta;
|
|
92
93
|
process.stderr.write(JSON.stringify(payload, null, 2) + "\n");
|
|
93
94
|
}
|
|
94
95
|
}
|
|
@@ -110,24 +111,24 @@ var init_formatter = __esm({
|
|
|
110
111
|
// src/output/errors.ts
|
|
111
112
|
import { readFileSync, readdirSync } from "fs";
|
|
112
113
|
import { join } from "path";
|
|
113
|
-
import { ProfileLockTimeoutError } from "@tinycloud/operations/state";
|
|
114
|
+
import { ProfileDeletedError, ProfileLockTimeoutError } from "@tinycloud/operations/state";
|
|
115
|
+
import { authorizationVerdictOf, parseCapabilityResource, SERVICE_LONG_TO_SHORT, validatedCapabilityOf } from "@tinycloud/sdk-core";
|
|
114
116
|
function setActiveProfileName(name) {
|
|
115
117
|
activeProfileName = name;
|
|
116
118
|
}
|
|
117
119
|
function wrapError(error) {
|
|
120
|
+
if (error instanceof CLIError) return error;
|
|
118
121
|
const message = error instanceof Error ? error.message : String(error);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return new CLIError(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
);
|
|
122
|
+
const verdict = authorizationVerdictOf(error);
|
|
123
|
+
if (verdict === "unauthenticated") {
|
|
124
|
+
return new CLIError("AUTH_REQUIRED", message, ExitCode.AUTH_REQUIRED);
|
|
125
|
+
}
|
|
126
|
+
if (verdict === "forbidden") {
|
|
127
|
+
return new CLIError("PERMISSION_DENIED", message, ExitCode.PERMISSION_DENIED);
|
|
128
|
+
}
|
|
129
|
+
if (verdict === void 0 && message.includes("Missing private key parameter in JWK")) {
|
|
130
|
+
return missingPrivateKeyError();
|
|
129
131
|
}
|
|
130
|
-
if (error instanceof CLIError) return error;
|
|
131
132
|
if (error instanceof ProfileLockTimeoutError) {
|
|
132
133
|
return new CLIError(
|
|
133
134
|
"PROFILE_LOCK_TIMEOUT",
|
|
@@ -136,13 +137,16 @@ function wrapError(error) {
|
|
|
136
137
|
{ hint: "Wait for the other command to finish and retry. A crashed process's lock is reclaimed automatically after 30 s." }
|
|
137
138
|
);
|
|
138
139
|
}
|
|
139
|
-
if (
|
|
140
|
+
if (error instanceof ProfileDeletedError) {
|
|
141
|
+
return new CLIError("PROFILE_NOT_FOUND", message);
|
|
142
|
+
}
|
|
143
|
+
if (verdict === void 0 && (message.includes("Not signed in") || message.includes("AUTH_EXPIRED") || message.includes("Session expired"))) {
|
|
140
144
|
return new CLIError("AUTH_REQUIRED", message, ExitCode.AUTH_REQUIRED);
|
|
141
145
|
}
|
|
142
146
|
if (message.includes("NOT_FOUND") || message.includes("KV_NOT_FOUND")) {
|
|
143
147
|
return new CLIError("NOT_FOUND", message, ExitCode.NOT_FOUND);
|
|
144
148
|
}
|
|
145
|
-
if (message.includes("PERMISSION_DENIED")) {
|
|
149
|
+
if (verdict === void 0 && message.includes("PERMISSION_DENIED")) {
|
|
146
150
|
return new CLIError("PERMISSION_DENIED", message, ExitCode.PERMISSION_DENIED);
|
|
147
151
|
}
|
|
148
152
|
if (message.includes("ECONNREFUSED") || message.includes("ETIMEDOUT") || message.includes("fetch failed")) {
|
|
@@ -150,39 +154,51 @@ function wrapError(error) {
|
|
|
150
154
|
}
|
|
151
155
|
return new CLIError("ERROR", message, ExitCode.ERROR);
|
|
152
156
|
}
|
|
157
|
+
function missingPrivateKeyError() {
|
|
158
|
+
const profileName = activeProfileName ?? process.env.TC_PROFILE ?? DEFAULT_PROFILE;
|
|
159
|
+
return new CLIError(
|
|
160
|
+
"AUTH_REQUIRED",
|
|
161
|
+
`Profile "${profileName}" cannot restore its session because its private key material is missing.`,
|
|
162
|
+
ExitCode.AUTH_REQUIRED,
|
|
163
|
+
{ hint: `Sign in again with: tc --profile ${profileName} auth login --method openkey` }
|
|
164
|
+
);
|
|
165
|
+
}
|
|
153
166
|
function handleError(error) {
|
|
154
167
|
const cliError = wrapError(error);
|
|
155
168
|
const prebuilt = typeof cliError.metadata?.hint === "string" ? cliError.metadata.hint : void 0;
|
|
156
169
|
const hint = prebuilt ?? buildAuthHint(cliError) ?? (cliError.code === "NETWORK_ERROR" ? buildNetworkHint() : void 0);
|
|
157
|
-
|
|
170
|
+
const authMeta = cliError.code === "AUTH_REQUIRED" || cliError.code === "PERMISSION_DENIED" ? cliError.metadata : void 0;
|
|
171
|
+
const meta = {};
|
|
172
|
+
if (cliError.status !== void 0 && authMeta !== void 0) meta.status = cliError.status;
|
|
173
|
+
const capability = validatedCapabilityOf({ meta: authMeta });
|
|
174
|
+
if (capability) {
|
|
175
|
+
meta.resource = capability.resource;
|
|
176
|
+
meta.requiredAction = capability.requiredAction;
|
|
177
|
+
}
|
|
178
|
+
outputError(cliError.code, cliError.message, hint, Object.keys(meta).length ? meta : void 0);
|
|
158
179
|
process.exit(cliError.exitCode);
|
|
159
180
|
}
|
|
160
181
|
function buildAuthHint(error) {
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return void 0;
|
|
165
|
-
}
|
|
166
|
-
const spec = capSpecFromAuthMeta(resource, requiredAction);
|
|
182
|
+
const capability = validatedCapabilityOf({ meta: error.metadata });
|
|
183
|
+
if (!capability) return void 0;
|
|
184
|
+
const spec = capSpecFromAuthMeta(capability.resource, capability.requiredAction);
|
|
167
185
|
if (!spec) return void 0;
|
|
168
186
|
return [
|
|
169
187
|
"The active session is missing a TinyCloud capability.",
|
|
170
|
-
`Request it with: tc auth request --cap
|
|
188
|
+
`Request it with: tc auth request --cap '${spec.replaceAll("'", "'\\''")}'`,
|
|
171
189
|
"Then retry the original command."
|
|
172
190
|
].join("\n");
|
|
173
191
|
}
|
|
174
192
|
function capSpecFromAuthMeta(resource, action) {
|
|
175
|
-
const slash =
|
|
176
|
-
if (slash
|
|
177
|
-
const
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
const spaceName = spaceUri.startsWith("tinycloud:") ? spaceUri.slice(spaceUri.lastIndexOf(":") + 1) : spaceUri;
|
|
185
|
-
return `tinycloud.${serviceShort}:${spaceName}:${path}:${actionName}`;
|
|
193
|
+
const slash = action.indexOf("/");
|
|
194
|
+
if (slash < 0) return void 0;
|
|
195
|
+
const longService = action.slice(0, slash);
|
|
196
|
+
const serviceShort = SERVICE_LONG_TO_SHORT[longService];
|
|
197
|
+
if (!serviceShort) return void 0;
|
|
198
|
+
const parsed = parseCapabilityResource(resource, serviceShort);
|
|
199
|
+
if (!parsed) return void 0;
|
|
200
|
+
const spaceName = parsed.space.slice(parsed.space.lastIndexOf(":") + 1);
|
|
201
|
+
return `${longService}:${spaceName}:${parsed.path}:${action.slice(slash + 1)}`;
|
|
186
202
|
}
|
|
187
203
|
function buildNetworkHint() {
|
|
188
204
|
const readHost = (name) => {
|
|
@@ -236,7 +252,9 @@ var init_errors = __esm({
|
|
|
236
252
|
this.exitCode = exitCode;
|
|
237
253
|
this.metadata = metadata;
|
|
238
254
|
this.name = "CLIError";
|
|
255
|
+
if (typeof metadata?.status === "number" && Number.isInteger(metadata.status) && metadata.status >= 400 && metadata.status <= 599) this.status = metadata.status;
|
|
239
256
|
}
|
|
257
|
+
status;
|
|
240
258
|
};
|
|
241
259
|
}
|
|
242
260
|
});
|
|
@@ -541,6 +559,8 @@ import { join as join3 } from "path";
|
|
|
541
559
|
import {
|
|
542
560
|
profilePath,
|
|
543
561
|
readSession,
|
|
562
|
+
recordProfileDeletion,
|
|
563
|
+
refuseWriteToDeletedProfile,
|
|
544
564
|
removeSession,
|
|
545
565
|
withProfileLock,
|
|
546
566
|
writeSession
|
|
@@ -620,7 +640,7 @@ var init_profiles = __esm({
|
|
|
620
640
|
if (!profile) {
|
|
621
641
|
throw new CLIError(
|
|
622
642
|
"PROFILE_NOT_FOUND",
|
|
623
|
-
`Profile "${name}" does not exist.
|
|
643
|
+
`Profile "${name}" does not exist. Create it with \`tc init --name ${name}\`.`
|
|
624
644
|
);
|
|
625
645
|
}
|
|
626
646
|
return profile;
|
|
@@ -655,10 +675,12 @@ var init_profiles = __esm({
|
|
|
655
675
|
* removed while holding the profile lock, so another writer's critical
|
|
656
676
|
* section never sees them vanish midway: session and key first, settings
|
|
657
677
|
* last, so a crash midway never leaves a session or key without its
|
|
658
|
-
* profile.
|
|
659
|
-
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
678
|
+
* profile. The deletion is then recorded, so a store write that waited for
|
|
679
|
+
* the lock meanwhile refuses rather than recreating a profile with only a
|
|
680
|
+
* session in it. `.lock` itself is left to the lock's release; the
|
|
681
|
+
* then-empty directory is removed afterwards unless another writer took
|
|
682
|
+
* the lock (or wrote) meanwhile. A profile directory that is a symlink is
|
|
683
|
+
* unlinked, its target left alone.
|
|
662
684
|
* Throws if the name is not one path segment or names the default profile.
|
|
663
685
|
*/
|
|
664
686
|
static async deleteProfile(name) {
|
|
@@ -679,11 +701,12 @@ var init_profiles = __esm({
|
|
|
679
701
|
`Cannot delete the default profile "${name}". Change the default first with \`tc profile default <other>\`.`
|
|
680
702
|
);
|
|
681
703
|
}
|
|
682
|
-
const
|
|
683
|
-
if (error.code === "ENOENT") return
|
|
704
|
+
const kind = await lstat(profileDir).then((stats) => stats.isSymbolicLink() ? "link" : "present", (error) => {
|
|
705
|
+
if (error.code === "ENOENT") return "missing";
|
|
684
706
|
throw error;
|
|
685
707
|
});
|
|
686
|
-
if (
|
|
708
|
+
if (kind === "missing") return;
|
|
709
|
+
if (kind === "link") {
|
|
687
710
|
await rm2(profileDir, { force: true });
|
|
688
711
|
return;
|
|
689
712
|
}
|
|
@@ -693,6 +716,7 @@ var init_profiles = __esm({
|
|
|
693
716
|
if (entry !== ".lock" && entry !== "profile.json") await rm2(join3(profileDir, entry), { recursive: true, force: true });
|
|
694
717
|
}
|
|
695
718
|
await rm2(join3(profileDir, "profile.json"), { force: true });
|
|
719
|
+
await recordProfileDeletion(name);
|
|
696
720
|
});
|
|
697
721
|
await rmdir(profileDir).catch((error) => {
|
|
698
722
|
if (error.code !== "ENOENT" && error.code !== "ENOTEMPTY" && error.code !== "EEXIST") throw error;
|
|
@@ -705,9 +729,14 @@ var init_profiles = __esm({
|
|
|
705
729
|
static async getKey(name) {
|
|
706
730
|
return readJson(join3(PROFILES_DIR, name, "key.json"));
|
|
707
731
|
}
|
|
708
|
-
/**
|
|
732
|
+
/**
|
|
733
|
+
* Saves a JWK key under the profile lock (0600, in an owner-only profile
|
|
734
|
+
* directory). Refused (PROFILE_NOT_FOUND) if the profile was deleted while
|
|
735
|
+
* this waited for the lock, rather than leaving a key-only profile.
|
|
736
|
+
*/
|
|
709
737
|
static async setKey(name, jwk) {
|
|
710
738
|
await _ProfileManager.withLock(name, async () => {
|
|
739
|
+
await refuseWriteToDeletedProfile(name);
|
|
711
740
|
await writeJson(join3(await _ProfileManager.ensureProfileDir(name), "key.json"), jwk);
|
|
712
741
|
});
|
|
713
742
|
}
|
|
@@ -5659,20 +5688,56 @@ import {
|
|
|
5659
5688
|
profileStoreMetadataPath,
|
|
5660
5689
|
readAdditionalDelegations,
|
|
5661
5690
|
readAuthRequests,
|
|
5662
|
-
|
|
5691
|
+
refuseWriteToDeletedProfile as refuseWriteToDeletedProfile2,
|
|
5692
|
+
updateProfileStore,
|
|
5663
5693
|
withProfileLock as withProfileLock2,
|
|
5664
5694
|
writeJsonAtomic
|
|
5665
5695
|
} from "@tinycloud/operations/state";
|
|
5666
5696
|
async function loadAdditionalDelegations(profile) {
|
|
5667
5697
|
return readAdditionalDelegations(profile);
|
|
5668
5698
|
}
|
|
5669
|
-
async function replayAdditionalDelegations(node, profile) {
|
|
5699
|
+
async function replayAdditionalDelegations(node, profile, options) {
|
|
5700
|
+
const {
|
|
5701
|
+
operationSpaceResolver,
|
|
5702
|
+
prepareStoredDelegationReplay,
|
|
5703
|
+
replayStoredDelegation,
|
|
5704
|
+
storedDelegationKind
|
|
5705
|
+
} = await import("@tinycloud/operations/delegation-binding");
|
|
5706
|
+
const activator = node;
|
|
5707
|
+
const migrated = await prepareStoredDelegationReplay(profile, activator, {
|
|
5708
|
+
host: options.host,
|
|
5709
|
+
migrate: options.migrate
|
|
5710
|
+
});
|
|
5711
|
+
const resolveSpace = operationSpaceResolver(node, options.ownerSpace);
|
|
5670
5712
|
const entries = await loadAdditionalDelegations(profile);
|
|
5671
|
-
for (const
|
|
5713
|
+
for (const stored of entries) {
|
|
5714
|
+
const kind = storedDelegationKind(stored);
|
|
5715
|
+
if (kind === "compact" || kind === "signed-login") {
|
|
5716
|
+
const installed = await replayStoredDelegation(activator, stored, {
|
|
5717
|
+
host: options.host,
|
|
5718
|
+
migrated,
|
|
5719
|
+
resolveSpace
|
|
5720
|
+
});
|
|
5721
|
+
if (installed === void 0 && process.env.TC_DEBUG_REPLAY === "1") {
|
|
5722
|
+
process.stderr.write("[replay] skipping a stored delegation refused by validation or its request binding\n");
|
|
5723
|
+
}
|
|
5724
|
+
continue;
|
|
5725
|
+
}
|
|
5726
|
+
if (kind === "refused") {
|
|
5727
|
+
if (process.env.TC_DEBUG_REPLAY === "1") {
|
|
5728
|
+
process.stderr.write("[replay] skipping a malformed stored record or one bound to a request it cannot be held to\n");
|
|
5729
|
+
}
|
|
5730
|
+
continue;
|
|
5731
|
+
}
|
|
5732
|
+
const entry = stored;
|
|
5672
5733
|
const expiry = entry.delegation.expiry instanceof Date ? entry.delegation.expiry : new Date(entry.delegation.expiry);
|
|
5673
5734
|
if (expiry.getTime() <= Date.now()) continue;
|
|
5674
5735
|
try {
|
|
5675
|
-
await node.useRuntimeDelegation({
|
|
5736
|
+
await node.useRuntimeDelegation({
|
|
5737
|
+
...entry.delegation,
|
|
5738
|
+
delegationHeader: { Authorization: entry.delegation.delegationHeader.Authorization },
|
|
5739
|
+
expiry
|
|
5740
|
+
});
|
|
5676
5741
|
} catch (err) {
|
|
5677
5742
|
if (process.env.TC_DEBUG_REPLAY === "1") {
|
|
5678
5743
|
process.stderr.write(`[replay] skipping ${entry.delegation.cid}: ${err.message}
|
|
@@ -5740,7 +5805,7 @@ async function createSDKInstance(ctx, options) {
|
|
|
5740
5805
|
if (!key && !effectivePrivateKey && !(profile?.authMethod === "openkey" && session !== null)) {
|
|
5741
5806
|
throw new CLIError(
|
|
5742
5807
|
"AUTH_REQUIRED",
|
|
5743
|
-
`No key found for profile "${ctx.profile}". Run \`tc
|
|
5808
|
+
`No key found for profile "${ctx.profile}". Run \`tc --profile ${ctx.profile} auth rotate\` to create a new key and sign in.`,
|
|
5744
5809
|
ExitCode.AUTH_REQUIRED
|
|
5745
5810
|
);
|
|
5746
5811
|
}
|
|
@@ -5749,6 +5814,7 @@ async function createSDKInstance(ctx, options) {
|
|
|
5749
5814
|
host: ctx.host,
|
|
5750
5815
|
privateKey: effectivePrivateKey
|
|
5751
5816
|
});
|
|
5817
|
+
let restoredOwnSession2 = false;
|
|
5752
5818
|
if (session && session.delegationHeader && session.delegationCid && session.spaceId) {
|
|
5753
5819
|
await node2.restoreSession({
|
|
5754
5820
|
delegationHeader: session.delegationHeader,
|
|
@@ -5761,16 +5827,22 @@ async function createSDKInstance(ctx, options) {
|
|
|
5761
5827
|
siwe: session.siwe,
|
|
5762
5828
|
signature: session.signature
|
|
5763
5829
|
});
|
|
5830
|
+
restoredOwnSession2 = true;
|
|
5764
5831
|
} else {
|
|
5765
5832
|
await node2.signIn();
|
|
5766
5833
|
}
|
|
5767
|
-
await replayAdditionalDelegations(node2, ctx.profile
|
|
5834
|
+
await replayAdditionalDelegations(node2, ctx.profile, {
|
|
5835
|
+
host: ctx.host,
|
|
5836
|
+
ownerSpace: profile.spaceId,
|
|
5837
|
+
migrate: restoredOwnSession2 && options?.privateKey === void 0
|
|
5838
|
+
});
|
|
5768
5839
|
return node2;
|
|
5769
5840
|
}
|
|
5770
5841
|
const node = new TinyCloudNode({
|
|
5771
5842
|
host: ctx.host,
|
|
5772
5843
|
privateKey: options?.privateKey
|
|
5773
5844
|
});
|
|
5845
|
+
let restoredOwnSession = false;
|
|
5774
5846
|
if (options?.privateKey) {
|
|
5775
5847
|
await node.signIn();
|
|
5776
5848
|
} else if (session && session.delegationHeader && session.delegationCid && session.spaceId) {
|
|
@@ -5785,8 +5857,13 @@ async function createSDKInstance(ctx, options) {
|
|
|
5785
5857
|
siwe: session.siwe,
|
|
5786
5858
|
signature: session.signature
|
|
5787
5859
|
});
|
|
5860
|
+
restoredOwnSession = true;
|
|
5788
5861
|
}
|
|
5789
|
-
await replayAdditionalDelegations(node, ctx.profile
|
|
5862
|
+
await replayAdditionalDelegations(node, ctx.profile, {
|
|
5863
|
+
host: ctx.host,
|
|
5864
|
+
ownerSpace: profile?.spaceId,
|
|
5865
|
+
migrate: restoredOwnSession
|
|
5866
|
+
});
|
|
5790
5867
|
return node;
|
|
5791
5868
|
}
|
|
5792
5869
|
async function bootstrapDelegatedSession(ctx, delegation) {
|
|
@@ -5838,13 +5915,13 @@ async function bootstrapDelegatedSession(ctx, delegation) {
|
|
|
5838
5915
|
throw error;
|
|
5839
5916
|
});
|
|
5840
5917
|
const session = await ProfileManager.getSession(ctx.profile);
|
|
5841
|
-
if (
|
|
5918
|
+
if (profile === null || BOOTSTRAP_PROFILE_FIELDS.some((field) => profile[field] !== written.profile[field]) || JSON.stringify(session) !== JSON.stringify(written.session)) {
|
|
5842
5919
|
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.`;
|
|
5843
5920
|
}
|
|
5844
5921
|
return restoreBeforeBootstrap(ctx.profile, written.previousProfile);
|
|
5845
5922
|
}, { timeoutMs: PROFILE_COMMIT_LOCK_TIMEOUT_MS }).catch((error) => (
|
|
5846
5923
|
// The lock or a read failed: the import's error stays the one reported.
|
|
5847
|
-
`Rolling back the provisional session of profile "${ctx.profile}" could not run (${
|
|
5924
|
+
`Rolling back the provisional session of profile "${ctx.profile}" could not run (${failureName(error)}); check \`tc --profile ${ctx.profile} context\`.`
|
|
5848
5925
|
));
|
|
5849
5926
|
throw annotate(cause, note);
|
|
5850
5927
|
};
|
|
@@ -5860,15 +5937,27 @@ async function restoreBeforeBootstrap(profileName, previousProfile) {
|
|
|
5860
5937
|
const failures = [];
|
|
5861
5938
|
for (const write of [
|
|
5862
5939
|
() => ProfileManager.clearSession(profileName),
|
|
5863
|
-
() => ProfileManager.
|
|
5940
|
+
() => ProfileManager.updateProfile(profileName, (current) => {
|
|
5941
|
+
const restored = { ...current };
|
|
5942
|
+
for (const field of BOOTSTRAP_PROFILE_FIELDS) {
|
|
5943
|
+
if (previousProfile[field] === void 0) delete restored[field];
|
|
5944
|
+
else restored[field] = previousProfile[field];
|
|
5945
|
+
}
|
|
5946
|
+
return restored;
|
|
5947
|
+
})
|
|
5864
5948
|
]) {
|
|
5865
5949
|
await write().catch((error) => {
|
|
5866
|
-
failures.push(
|
|
5950
|
+
failures.push(failureName(error));
|
|
5867
5951
|
});
|
|
5868
5952
|
}
|
|
5869
5953
|
if (failures.length === 0) return void 0;
|
|
5870
5954
|
return `Rolling back the provisional session of profile "${profileName}" failed too (${failures.join("; ")}); check \`tc --profile ${profileName} context\`.`;
|
|
5871
5955
|
}
|
|
5956
|
+
function failureName(error) {
|
|
5957
|
+
if (error instanceof SyntaxError) return "a profile file is not valid JSON";
|
|
5958
|
+
if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string") return error.code;
|
|
5959
|
+
return error instanceof Error ? error.name : "unknown error";
|
|
5960
|
+
}
|
|
5872
5961
|
function annotate(error, note) {
|
|
5873
5962
|
if (note === void 0) return error;
|
|
5874
5963
|
const cause = wrapError(error);
|
|
@@ -5880,7 +5969,7 @@ async function ensureAuthenticated(ctx, options) {
|
|
|
5880
5969
|
}
|
|
5881
5970
|
const profile = await ProfileManager.getProfile(ctx.profile).catch(() => null);
|
|
5882
5971
|
if (profile?.authMethod === "local" && profile.privateKey) {
|
|
5883
|
-
return createSDKInstance(ctx
|
|
5972
|
+
return createSDKInstance(ctx);
|
|
5884
5973
|
}
|
|
5885
5974
|
const session = await ProfileManager.getSession(ctx.profile);
|
|
5886
5975
|
if (!session) {
|
|
@@ -5892,6 +5981,7 @@ async function ensureAuthenticated(ctx, options) {
|
|
|
5892
5981
|
}
|
|
5893
5982
|
return createSDKInstance(ctx, options);
|
|
5894
5983
|
}
|
|
5984
|
+
var BOOTSTRAP_PROFILE_FIELDS;
|
|
5895
5985
|
var init_sdk = __esm({
|
|
5896
5986
|
"src/lib/sdk.ts"() {
|
|
5897
5987
|
"use strict";
|
|
@@ -5900,6 +5990,7 @@ var init_sdk = __esm({
|
|
|
5900
5990
|
init_errors();
|
|
5901
5991
|
init_constants();
|
|
5902
5992
|
init_permissions();
|
|
5993
|
+
BOOTSTRAP_PROFILE_FIELDS = ["sessionDid", "spaceId"];
|
|
5903
5994
|
}
|
|
5904
5995
|
});
|
|
5905
5996
|
|
|
@@ -14899,11 +14990,12 @@ function historyRecordForPublishedShare(result, now = /* @__PURE__ */ new Date()
|
|
|
14899
14990
|
};
|
|
14900
14991
|
}
|
|
14901
14992
|
var ShareNotifyError = class extends Error {
|
|
14902
|
-
|
|
14903
|
-
constructor(message = "share delivery did not complete") {
|
|
14993
|
+
constructor(message = "share delivery did not complete", reason) {
|
|
14904
14994
|
super(message);
|
|
14995
|
+
this.reason = reason;
|
|
14905
14996
|
this.name = "ShareNotifyError";
|
|
14906
14997
|
}
|
|
14998
|
+
code = "delivery-failed";
|
|
14907
14999
|
};
|
|
14908
15000
|
function recipientMatchesShareRecord(record, recipient) {
|
|
14909
15001
|
const matcher = record.recipientMatcher;
|
|
@@ -14913,6 +15005,11 @@ function recipientMatchesShareRecord(record, recipient) {
|
|
|
14913
15005
|
if (matcher.kind === "emailDomain") return mailbox.domain === matcher.value;
|
|
14914
15006
|
return false;
|
|
14915
15007
|
}
|
|
15008
|
+
function shareDeliveryWindowExpiresAt(record) {
|
|
15009
|
+
const expiresAt = Math.min(Date.parse(record.expiresAt), Date.parse(record.registeredAt) + 5 * 60 * 1e3);
|
|
15010
|
+
if (!Number.isFinite(expiresAt)) throw new ShareNotifyError("share delivery history has invalid timestamps");
|
|
15011
|
+
return expiresAt;
|
|
15012
|
+
}
|
|
14916
15013
|
async function notifyShare(input) {
|
|
14917
15014
|
const mailbox = canonicalMailbox(input.recipient);
|
|
14918
15015
|
if (!input.shareId || mailbox === void 0) throw new ShareNotifyError("recipient is invalid");
|
|
@@ -14923,19 +15020,59 @@ async function notifyShare(input) {
|
|
|
14923
15020
|
const idempotencyKey = input.idempotencyKey ?? await defaultIdempotencyKey(input.shareId, recipient);
|
|
14924
15021
|
const attemptsLimit = input.maxAttempts ?? 3;
|
|
14925
15022
|
if (!Number.isSafeInteger(attemptsLimit) || attemptsLimit < 1 || attemptsLimit > 8) throw new ShareNotifyError("maxAttempts is invalid");
|
|
15023
|
+
if (input.signal?.aborted) throw new ShareNotifyError("share delivery was cancelled");
|
|
15024
|
+
if (input.checkDeliveryWindow && input.record !== void 0 && shareDeliveryWindowExpiresAt(input.record) <= Date.now()) {
|
|
15025
|
+
return {
|
|
15026
|
+
protocol: "tinycloud-share",
|
|
15027
|
+
version: 1,
|
|
15028
|
+
shareId: input.shareId,
|
|
15029
|
+
state: "partial-failure",
|
|
15030
|
+
idempotencyKey,
|
|
15031
|
+
attempts: 1,
|
|
15032
|
+
retryable: false,
|
|
15033
|
+
reason: "delivery-window-expired"
|
|
15034
|
+
};
|
|
15035
|
+
}
|
|
14926
15036
|
let attempts = 0;
|
|
14927
|
-
let lastError;
|
|
14928
15037
|
while (attempts < attemptsLimit) {
|
|
14929
15038
|
if (input.signal?.aborted) throw new ShareNotifyError("share delivery was cancelled");
|
|
14930
15039
|
attempts += 1;
|
|
14931
15040
|
try {
|
|
14932
15041
|
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 } });
|
|
14933
|
-
return {
|
|
15042
|
+
return {
|
|
15043
|
+
protocol: "tinycloud-share",
|
|
15044
|
+
version: 1,
|
|
15045
|
+
shareId: input.shareId,
|
|
15046
|
+
state: state === "delivered" && input.record?.deliveredRecipients?.includes(recipient) ? "already-delivered" : state,
|
|
15047
|
+
idempotencyKey,
|
|
15048
|
+
attempts
|
|
15049
|
+
};
|
|
14934
15050
|
} catch (error) {
|
|
14935
|
-
|
|
15051
|
+
if (error instanceof ShareNotifyError && error.reason === "delivery-window-expired") {
|
|
15052
|
+
return {
|
|
15053
|
+
protocol: "tinycloud-share",
|
|
15054
|
+
version: 1,
|
|
15055
|
+
shareId: input.shareId,
|
|
15056
|
+
state: "partial-failure",
|
|
15057
|
+
idempotencyKey,
|
|
15058
|
+
attempts,
|
|
15059
|
+
retryable: false,
|
|
15060
|
+
reason: "delivery-window-expired"
|
|
15061
|
+
};
|
|
15062
|
+
}
|
|
15063
|
+
if (error !== null && typeof error === "object" && "status" in error && (error.status === 401 || error.status === 403)) {
|
|
15064
|
+
return {
|
|
15065
|
+
protocol: "tinycloud-share",
|
|
15066
|
+
version: 1,
|
|
15067
|
+
shareId: input.shareId,
|
|
15068
|
+
state: "partial-failure",
|
|
15069
|
+
idempotencyKey,
|
|
15070
|
+
attempts,
|
|
15071
|
+
retryable: false
|
|
15072
|
+
};
|
|
15073
|
+
}
|
|
14936
15074
|
}
|
|
14937
15075
|
}
|
|
14938
|
-
void lastError;
|
|
14939
15076
|
return { protocol: "tinycloud-share", version: 1, shareId: input.shareId, state: "partial-failure", idempotencyKey, attempts, retryable: true };
|
|
14940
15077
|
}
|
|
14941
15078
|
async function defaultIdempotencyKey(shareId, recipient) {
|
|
@@ -15090,7 +15227,11 @@ async function revokeShare(input) {
|
|
|
15090
15227
|
});
|
|
15091
15228
|
}
|
|
15092
15229
|
const revokedAt = (input.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
|
|
15093
|
-
if (input.records !== void 0)
|
|
15230
|
+
if (input.records?.update !== void 0) {
|
|
15231
|
+
await input.records.update(input.record.shareId, (record) => ({ ...record, revokedAt }));
|
|
15232
|
+
} else if (input.records !== void 0) {
|
|
15233
|
+
await input.records.put({ ...input.record, revokedAt });
|
|
15234
|
+
}
|
|
15094
15235
|
return { state: "revoked", target, delegationCid, revokedAt };
|
|
15095
15236
|
}
|
|
15096
15237
|
function redactRecord(record, revealLink, link2) {
|
|
@@ -15159,1550 +15300,1011 @@ function parseNativeShareUrl(value) {
|
|
|
15159
15300
|
return token;
|
|
15160
15301
|
}
|
|
15161
15302
|
|
|
15162
|
-
//
|
|
15163
|
-
|
|
15164
|
-
|
|
15165
|
-
|
|
15166
|
-
|
|
15167
|
-
|
|
15168
|
-
const multipliers = {
|
|
15169
|
-
m: 60 * 1e3,
|
|
15170
|
-
h: 60 * 60 * 1e3,
|
|
15171
|
-
d: 24 * 60 * 60 * 1e3,
|
|
15172
|
-
w: 7 * 24 * 60 * 60 * 1e3
|
|
15173
|
-
};
|
|
15174
|
-
return value * multipliers[unit];
|
|
15303
|
+
// ../share-envelope/dist/index.js
|
|
15304
|
+
init_zod();
|
|
15305
|
+
var empty3 = new Uint8Array(0);
|
|
15306
|
+
function equals5(aa, bb) {
|
|
15307
|
+
if (aa === bb) {
|
|
15308
|
+
return true;
|
|
15175
15309
|
}
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
|
|
15310
|
+
if (aa.byteLength !== bb.byteLength) {
|
|
15311
|
+
return false;
|
|
15312
|
+
}
|
|
15313
|
+
for (let ii = 0; ii < aa.byteLength; ii++) {
|
|
15314
|
+
if (aa[ii] !== bb[ii]) {
|
|
15315
|
+
return false;
|
|
15181
15316
|
}
|
|
15182
|
-
return ms;
|
|
15183
15317
|
}
|
|
15184
|
-
|
|
15185
|
-
}
|
|
15186
|
-
|
|
15187
|
-
// src/commands/share.ts
|
|
15188
|
-
init_formatter();
|
|
15189
|
-
init_errors();
|
|
15190
|
-
|
|
15191
|
-
// src/share/output.ts
|
|
15192
|
-
function writeJson2(value) {
|
|
15193
|
-
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
15194
|
-
`);
|
|
15195
|
-
}
|
|
15196
|
-
function authorizationRequiredJson(result) {
|
|
15197
|
-
return {
|
|
15198
|
-
state: "authorization-required",
|
|
15199
|
-
method: result.method,
|
|
15200
|
-
next: "complete authorization through the configured authority adapter, then retry with the required proof"
|
|
15201
|
-
};
|
|
15202
|
-
}
|
|
15203
|
-
function publishHuman(result) {
|
|
15204
|
-
process.stdout.write(`${result.url}
|
|
15205
|
-
`);
|
|
15206
|
-
}
|
|
15207
|
-
function inspectHuman(result) {
|
|
15208
|
-
const metadata = result.metadata;
|
|
15209
|
-
process.stdout.write([
|
|
15210
|
-
`Share ${metadata.shareId}`,
|
|
15211
|
-
`File: ${metadata.display.filename ?? "unnamed"}`,
|
|
15212
|
-
`Target: ${metadata.target.kind === "bearer" ? "bearer (anyone with the complete link can read)" : metadata.target.kind}`,
|
|
15213
|
-
`Expires: ${metadata.expiresAt}`,
|
|
15214
|
-
`Resource: ${metadata.resource.path}`,
|
|
15215
|
-
`Link format: ${result.link.kind}`
|
|
15216
|
-
].join("\n") + "\n");
|
|
15217
|
-
}
|
|
15218
|
-
function receiveHuman(path) {
|
|
15219
|
-
process.stdout.write(`${path}
|
|
15220
|
-
`);
|
|
15221
|
-
}
|
|
15222
|
-
function receiveJson(result, path) {
|
|
15223
|
-
writeJson2({ protocol: "tinycloud-share", version: 1, path, metadata: result.metadata });
|
|
15318
|
+
return true;
|
|
15224
15319
|
}
|
|
15225
|
-
|
|
15226
|
-
|
|
15227
|
-
|
|
15228
|
-
import { lstat as lstat2, mkdir as mkdir2, mkdtemp, open as open2, readFile as readFile2, realpath, stat as stat2, link, rename as rename2, rm as rm3, unlink } from "fs/promises";
|
|
15229
|
-
import { randomBytes as randomBytes2 } from "crypto";
|
|
15230
|
-
import { basename as basename2, join as join4, resolve, sep } from "path";
|
|
15231
|
-
init_errors();
|
|
15232
|
-
var MAX_SHARE_STDIN_BYTES = 100 * 1024 * 1024;
|
|
15233
|
-
var MAX_SHARE_URL_BYTES = 64 * 1024;
|
|
15234
|
-
async function readBoundedStdin(limit = MAX_SHARE_STDIN_BYTES) {
|
|
15235
|
-
if (!Number.isSafeInteger(limit) || limit <= 0) throw new Error("MAX_BYTES_EXCEEDED");
|
|
15236
|
-
const chunks = [];
|
|
15237
|
-
let total = 0;
|
|
15238
|
-
for await (const chunk of process.stdin) {
|
|
15239
|
-
const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
15240
|
-
total += bytes.byteLength;
|
|
15241
|
-
if (total > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
15242
|
-
chunks.push(bytes);
|
|
15320
|
+
function coerce5(o) {
|
|
15321
|
+
if (o instanceof Uint8Array && o.constructor.name === "Uint8Array") {
|
|
15322
|
+
return o;
|
|
15243
15323
|
}
|
|
15244
|
-
|
|
15245
|
-
|
|
15246
|
-
async function readBoundedUrlStdin() {
|
|
15247
|
-
const bytes = await readBoundedStdin(MAX_SHARE_URL_BYTES);
|
|
15248
|
-
const value = new TextDecoder("utf-8", { fatal: true }).decode(bytes).trim();
|
|
15249
|
-
if (value.length === 0 || /\s/.test(value)) throw new Error("INVALID_ARGUMENT");
|
|
15250
|
-
return value;
|
|
15251
|
-
}
|
|
15252
|
-
function safeFilename(value) {
|
|
15253
|
-
return shareFilename(value);
|
|
15254
|
-
}
|
|
15255
|
-
function shareFilename(value) {
|
|
15256
|
-
try {
|
|
15257
|
-
return canonicalShareFilename(value);
|
|
15258
|
-
} catch {
|
|
15259
|
-
throw new CLIError(
|
|
15260
|
-
"UNSAFE_FILENAME",
|
|
15261
|
-
hasUnsafeFilenameCodePoint(value) ? "filename contains control or invisible characters" : "filename must be one safe path segment",
|
|
15262
|
-
8
|
|
15263
|
-
);
|
|
15324
|
+
if (o instanceof ArrayBuffer) {
|
|
15325
|
+
return new Uint8Array(o);
|
|
15264
15326
|
}
|
|
15265
|
-
|
|
15266
|
-
|
|
15267
|
-
return shareFilename(name ?? (input === "-" ? "stdin.md" : basename2(resolve(input))));
|
|
15268
|
-
}
|
|
15269
|
-
async function readShareInput(input, name, limit = MAX_SHARE_STDIN_BYTES) {
|
|
15270
|
-
const filename = shareInputFilename(input, name);
|
|
15271
|
-
if (input === "-") return { bytes: await readBoundedStdin(limit), filename };
|
|
15272
|
-
const path = resolve(input);
|
|
15273
|
-
const info = await stat2(path);
|
|
15274
|
-
if (!info.isFile() || info.size > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
15275
|
-
const bytes = new Uint8Array(await readFile2(path));
|
|
15276
|
-
if (bytes.byteLength > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
15277
|
-
return { bytes, filename };
|
|
15278
|
-
}
|
|
15279
|
-
async function assertDirectory(path) {
|
|
15280
|
-
const absolute = resolve(path);
|
|
15281
|
-
const segments = absolute.split(sep).filter(Boolean);
|
|
15282
|
-
let current = absolute.startsWith(sep) ? sep : "";
|
|
15283
|
-
for (const segment of segments) {
|
|
15284
|
-
current = current === sep ? join4(current, segment) : join4(current, segment);
|
|
15285
|
-
try {
|
|
15286
|
-
const info = await lstat2(current);
|
|
15287
|
-
if (info.isSymbolicLink()) {
|
|
15288
|
-
const canonical = await realpath(current);
|
|
15289
|
-
if (current !== "/tmp" && current !== "/var") throw new Error("OUTPUT_EXISTS");
|
|
15290
|
-
if (canonical !== `/private${current}`) throw new Error("OUTPUT_EXISTS");
|
|
15291
|
-
} else if (!info.isDirectory()) throw new Error("OUTPUT_EXISTS");
|
|
15292
|
-
} catch (error) {
|
|
15293
|
-
if (error.code !== "ENOENT") throw error;
|
|
15294
|
-
await mkdir2(current, { mode: 448 });
|
|
15295
|
-
const created = await lstat2(current);
|
|
15296
|
-
if (created.isSymbolicLink() || !created.isDirectory()) throw new Error("OUTPUT_EXISTS");
|
|
15297
|
-
}
|
|
15327
|
+
if (ArrayBuffer.isView(o)) {
|
|
15328
|
+
return new Uint8Array(o.buffer, o.byteOffset, o.byteLength);
|
|
15298
15329
|
}
|
|
15330
|
+
throw new Error("Unknown type, must be binary type");
|
|
15299
15331
|
}
|
|
15300
|
-
|
|
15301
|
-
|
|
15302
|
-
|
|
15303
|
-
|
|
15304
|
-
|
|
15305
|
-
|
|
15306
|
-
|
|
15307
|
-
|
|
15308
|
-
|
|
15309
|
-
|
|
15310
|
-
|
|
15311
|
-
|
|
15312
|
-
|
|
15313
|
-
const stagingDirectory = await mkdtemp(join4(stableDirectory, ".tinycloud-share-stage-"));
|
|
15314
|
-
const stagingInfo = await lstat2(stagingDirectory);
|
|
15315
|
-
if (!stagingInfo.isDirectory() || (stagingInfo.mode & 511) !== 448) throw new Error("OUTPUT_EXISTS");
|
|
15316
|
-
const stagingPath = join4(stagingDirectory, `.tinycloud-share-${randomBytes2(16).toString("hex")}.tmp`);
|
|
15317
|
-
let temporaryPath;
|
|
15318
|
-
let handle;
|
|
15319
|
-
try {
|
|
15320
|
-
await assertStableDirectory();
|
|
15321
|
-
try {
|
|
15322
|
-
const existing = await lstat2(outputPath);
|
|
15323
|
-
if (existing.isSymbolicLink()) throw new Error("UNSAFE_FILENAME");
|
|
15324
|
-
} catch (error) {
|
|
15325
|
-
if (error.code !== "ENOENT") throw error;
|
|
15332
|
+
function base3(ALPHABET, name) {
|
|
15333
|
+
if (ALPHABET.length >= 255) {
|
|
15334
|
+
throw new TypeError("Alphabet too long");
|
|
15335
|
+
}
|
|
15336
|
+
var BASE_MAP = new Uint8Array(256);
|
|
15337
|
+
for (var j = 0; j < BASE_MAP.length; j++) {
|
|
15338
|
+
BASE_MAP[j] = 255;
|
|
15339
|
+
}
|
|
15340
|
+
for (var i = 0; i < ALPHABET.length; i++) {
|
|
15341
|
+
var x = ALPHABET.charAt(i);
|
|
15342
|
+
var xc = x.charCodeAt(0);
|
|
15343
|
+
if (BASE_MAP[xc] !== 255) {
|
|
15344
|
+
throw new TypeError(x + " is ambiguous");
|
|
15326
15345
|
}
|
|
15327
|
-
|
|
15328
|
-
|
|
15329
|
-
|
|
15330
|
-
|
|
15331
|
-
|
|
15332
|
-
|
|
15333
|
-
|
|
15334
|
-
|
|
15335
|
-
|
|
15336
|
-
|
|
15337
|
-
|
|
15346
|
+
BASE_MAP[xc] = i;
|
|
15347
|
+
}
|
|
15348
|
+
var BASE = ALPHABET.length;
|
|
15349
|
+
var LEADER = ALPHABET.charAt(0);
|
|
15350
|
+
var FACTOR = Math.log(BASE) / Math.log(256);
|
|
15351
|
+
var iFACTOR = Math.log(256) / Math.log(BASE);
|
|
15352
|
+
function encode32(source) {
|
|
15353
|
+
if (source instanceof Uint8Array)
|
|
15354
|
+
;
|
|
15355
|
+
else if (ArrayBuffer.isView(source)) {
|
|
15356
|
+
source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
15357
|
+
} else if (Array.isArray(source)) {
|
|
15358
|
+
source = Uint8Array.from(source);
|
|
15338
15359
|
}
|
|
15339
|
-
|
|
15340
|
-
|
|
15341
|
-
if (error.code === "EEXIST") throw new Error("OUTPUT_EXISTS");
|
|
15342
|
-
if (error.code === "ELOOP") throw new Error("UNSAFE_FILENAME");
|
|
15343
|
-
throw error;
|
|
15344
|
-
} finally {
|
|
15345
|
-
await handle?.close();
|
|
15346
|
-
try {
|
|
15347
|
-
if (temporaryPath !== void 0) await unlink(temporaryPath);
|
|
15348
|
-
} catch {
|
|
15360
|
+
if (!(source instanceof Uint8Array)) {
|
|
15361
|
+
throw new TypeError("Expected Uint8Array");
|
|
15349
15362
|
}
|
|
15350
|
-
|
|
15351
|
-
|
|
15352
|
-
|
|
15353
|
-
|
|
15354
|
-
|
|
15355
|
-
|
|
15356
|
-
|
|
15357
|
-
|
|
15358
|
-
|
|
15359
|
-
|
|
15360
|
-
|
|
15361
|
-
|
|
15362
|
-
|
|
15363
|
-
|
|
15364
|
-
|
|
15365
|
-
|
|
15366
|
-
var
|
|
15367
|
-
|
|
15368
|
-
|
|
15369
|
-
|
|
15370
|
-
}
|
|
15371
|
-
|
|
15372
|
-
|
|
15373
|
-
|
|
15374
|
-
|
|
15375
|
-
|
|
15376
|
-
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
|
|
15382
|
-
|
|
15383
|
-
|
|
15363
|
+
if (source.length === 0) {
|
|
15364
|
+
return "";
|
|
15365
|
+
}
|
|
15366
|
+
var zeroes = 0;
|
|
15367
|
+
var length22 = 0;
|
|
15368
|
+
var pbegin = 0;
|
|
15369
|
+
var pend = source.length;
|
|
15370
|
+
while (pbegin !== pend && source[pbegin] === 0) {
|
|
15371
|
+
pbegin++;
|
|
15372
|
+
zeroes++;
|
|
15373
|
+
}
|
|
15374
|
+
var size = (pend - pbegin) * iFACTOR + 1 >>> 0;
|
|
15375
|
+
var b58 = new Uint8Array(size);
|
|
15376
|
+
while (pbegin !== pend) {
|
|
15377
|
+
var carry = source[pbegin];
|
|
15378
|
+
var i2 = 0;
|
|
15379
|
+
for (var it1 = size - 1; (carry !== 0 || i2 < length22) && it1 !== -1; it1--, i2++) {
|
|
15380
|
+
carry += 256 * b58[it1] >>> 0;
|
|
15381
|
+
b58[it1] = carry % BASE >>> 0;
|
|
15382
|
+
carry = carry / BASE >>> 0;
|
|
15383
|
+
}
|
|
15384
|
+
if (carry !== 0) {
|
|
15385
|
+
throw new Error("Non-zero carry");
|
|
15386
|
+
}
|
|
15387
|
+
length22 = i2;
|
|
15388
|
+
pbegin++;
|
|
15389
|
+
}
|
|
15390
|
+
var it2 = size - length22;
|
|
15391
|
+
while (it2 !== size && b58[it2] === 0) {
|
|
15392
|
+
it2++;
|
|
15393
|
+
}
|
|
15394
|
+
var str = LEADER.repeat(zeroes);
|
|
15395
|
+
for (; it2 < size; ++it2) {
|
|
15396
|
+
str += ALPHABET.charAt(b58[it2]);
|
|
15397
|
+
}
|
|
15398
|
+
return str;
|
|
15384
15399
|
}
|
|
15385
|
-
|
|
15386
|
-
|
|
15387
|
-
|
|
15388
|
-
if (error instanceof SharePublishAuthorityError) {
|
|
15389
|
-
const failure = error.failure;
|
|
15390
|
-
const profileName = "profileName" in failure ? failure.profileName : void 0;
|
|
15391
|
-
const localKey = "localKey" in failure && failure.localKey === true;
|
|
15392
|
-
const profileHint = profileName === void 0 ? "" : `--profile ${profileName} `;
|
|
15393
|
-
const loginHint = localKey ? `\`tc ${profileHint}auth login --method local\`` : `\`tc ${profileHint}auth login --device --manifest builtin:share-publishing\` (or \`tc ${profileHint}enable share\`)`;
|
|
15394
|
-
if (failure.kind === "caveated-session") {
|
|
15395
|
-
const holder = profileName === void 0 ? "this session" : `profile ${profileName}'s session`;
|
|
15396
|
-
return new CLIError(
|
|
15397
|
-
"PERMISSION_DENIED",
|
|
15398
|
-
`${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\``,
|
|
15399
|
-
5
|
|
15400
|
-
);
|
|
15400
|
+
function decodeUnsafe(source) {
|
|
15401
|
+
if (typeof source !== "string") {
|
|
15402
|
+
throw new TypeError("Expected String");
|
|
15401
15403
|
}
|
|
15402
|
-
if (
|
|
15403
|
-
return new
|
|
15404
|
+
if (source.length === 0) {
|
|
15405
|
+
return new Uint8Array();
|
|
15404
15406
|
}
|
|
15405
|
-
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
return new CLIError("PERMISSION_DENIED", `the session lacks ${failure.capability} authority${requiredAction}; ${renew}`, 5);
|
|
15407
|
+
var psz = 0;
|
|
15408
|
+
if (source[psz] === " ") {
|
|
15409
|
+
return;
|
|
15409
15410
|
}
|
|
15410
|
-
|
|
15411
|
-
|
|
15412
|
-
|
|
15413
|
-
|
|
15411
|
+
var zeroes = 0;
|
|
15412
|
+
var length22 = 0;
|
|
15413
|
+
while (source[psz] === LEADER) {
|
|
15414
|
+
zeroes++;
|
|
15415
|
+
psz++;
|
|
15416
|
+
}
|
|
15417
|
+
var size = (source.length - psz) * FACTOR + 1 >>> 0;
|
|
15418
|
+
var b256 = new Uint8Array(size);
|
|
15419
|
+
while (source[psz]) {
|
|
15420
|
+
var carry = BASE_MAP[source.charCodeAt(psz)];
|
|
15421
|
+
if (carry === 255) {
|
|
15422
|
+
return;
|
|
15414
15423
|
}
|
|
15415
|
-
|
|
15416
|
-
|
|
15424
|
+
var i2 = 0;
|
|
15425
|
+
for (var it3 = size - 1; (carry !== 0 || i2 < length22) && it3 !== -1; it3--, i2++) {
|
|
15426
|
+
carry += BASE * b256[it3] >>> 0;
|
|
15427
|
+
b256[it3] = carry % 256 >>> 0;
|
|
15428
|
+
carry = carry / 256 >>> 0;
|
|
15417
15429
|
}
|
|
15418
|
-
|
|
15430
|
+
if (carry !== 0) {
|
|
15431
|
+
throw new Error("Non-zero carry");
|
|
15432
|
+
}
|
|
15433
|
+
length22 = i2;
|
|
15434
|
+
psz++;
|
|
15419
15435
|
}
|
|
15420
|
-
if (
|
|
15421
|
-
return
|
|
15436
|
+
if (source[psz] === " ") {
|
|
15437
|
+
return;
|
|
15422
15438
|
}
|
|
15423
|
-
|
|
15424
|
-
|
|
15439
|
+
var it4 = size - length22;
|
|
15440
|
+
while (it4 !== size && b256[it4] === 0) {
|
|
15441
|
+
it4++;
|
|
15425
15442
|
}
|
|
15426
|
-
|
|
15427
|
-
|
|
15443
|
+
var vch = new Uint8Array(zeroes + (size - it4));
|
|
15444
|
+
var j2 = zeroes;
|
|
15445
|
+
while (it4 !== size) {
|
|
15446
|
+
vch[j2++] = b256[it4++];
|
|
15428
15447
|
}
|
|
15429
|
-
|
|
15430
|
-
|
|
15448
|
+
return vch;
|
|
15449
|
+
}
|
|
15450
|
+
function decode52(string) {
|
|
15451
|
+
var buffer = decodeUnsafe(string);
|
|
15452
|
+
if (buffer) {
|
|
15453
|
+
return buffer;
|
|
15431
15454
|
}
|
|
15432
|
-
|
|
15433
|
-
|
|
15434
|
-
|
|
15455
|
+
throw new Error(`Non-${name} character`);
|
|
15456
|
+
}
|
|
15457
|
+
return {
|
|
15458
|
+
encode: encode32,
|
|
15459
|
+
decodeUnsafe,
|
|
15460
|
+
decode: decode52
|
|
15461
|
+
};
|
|
15462
|
+
}
|
|
15463
|
+
var src3 = base3;
|
|
15464
|
+
var _brrp__multiformats_scope_baseX3 = src3;
|
|
15465
|
+
var base_x_default3 = _brrp__multiformats_scope_baseX3;
|
|
15466
|
+
var Encoder3 = class {
|
|
15467
|
+
name;
|
|
15468
|
+
prefix;
|
|
15469
|
+
baseEncode;
|
|
15470
|
+
constructor(name, prefix, baseEncode) {
|
|
15471
|
+
this.name = name;
|
|
15472
|
+
this.prefix = prefix;
|
|
15473
|
+
this.baseEncode = baseEncode;
|
|
15474
|
+
}
|
|
15475
|
+
encode(bytes) {
|
|
15476
|
+
if (bytes instanceof Uint8Array) {
|
|
15477
|
+
return `${this.prefix}${this.baseEncode(bytes)}`;
|
|
15478
|
+
} else {
|
|
15479
|
+
throw Error("Unknown type, must be binary type");
|
|
15435
15480
|
}
|
|
15436
|
-
|
|
15437
|
-
|
|
15481
|
+
}
|
|
15482
|
+
};
|
|
15483
|
+
var Decoder3 = class {
|
|
15484
|
+
name;
|
|
15485
|
+
prefix;
|
|
15486
|
+
baseDecode;
|
|
15487
|
+
prefixCodePoint;
|
|
15488
|
+
constructor(name, prefix, baseDecode) {
|
|
15489
|
+
this.name = name;
|
|
15490
|
+
this.prefix = prefix;
|
|
15491
|
+
const prefixCodePoint = prefix.codePointAt(0);
|
|
15492
|
+
if (prefixCodePoint === void 0) {
|
|
15493
|
+
throw new Error("Invalid prefix character");
|
|
15438
15494
|
}
|
|
15495
|
+
this.prefixCodePoint = prefixCodePoint;
|
|
15496
|
+
this.baseDecode = baseDecode;
|
|
15439
15497
|
}
|
|
15440
|
-
|
|
15441
|
-
|
|
15498
|
+
decode(text) {
|
|
15499
|
+
if (typeof text === "string") {
|
|
15500
|
+
if (text.codePointAt(0) !== this.prefixCodePoint) {
|
|
15501
|
+
throw Error(`Unable to decode multibase string ${JSON.stringify(text)}, ${this.name} decoder only supports inputs prefixed with ${this.prefix}`);
|
|
15502
|
+
}
|
|
15503
|
+
return this.baseDecode(text.slice(this.prefix.length));
|
|
15504
|
+
} else {
|
|
15505
|
+
throw Error("Can only multibase decode strings");
|
|
15506
|
+
}
|
|
15442
15507
|
}
|
|
15443
|
-
|
|
15444
|
-
|
|
15445
|
-
const code3 = error.code === "authority-required" ? "AUTH_REQUIRED" : error.code === "max-bytes-exceeded" ? "MAX_BYTES_EXCEEDED" : "INVALID_ARGUMENT";
|
|
15446
|
-
return new CLIError(code3, error.message, exit);
|
|
15508
|
+
or(decoder) {
|
|
15509
|
+
return or3(this, decoder);
|
|
15447
15510
|
}
|
|
15448
|
-
|
|
15449
|
-
|
|
15450
|
-
|
|
15451
|
-
|
|
15452
|
-
|
|
15511
|
+
};
|
|
15512
|
+
var ComposedDecoder3 = class {
|
|
15513
|
+
decoders;
|
|
15514
|
+
constructor(decoders) {
|
|
15515
|
+
this.decoders = decoders;
|
|
15453
15516
|
}
|
|
15454
|
-
|
|
15455
|
-
|
|
15456
|
-
const known = {
|
|
15457
|
-
MAX_BYTES_EXCEEDED: { code: "MAX_BYTES_EXCEEDED", exit: 7 },
|
|
15458
|
-
UNSAFE_FILENAME: { code: "UNSAFE_FILENAME", exit: 8 },
|
|
15459
|
-
OUTPUT_EXISTS: { code: "OUTPUT_EXISTS", exit: 8 },
|
|
15460
|
-
INVALID_ARGUMENT: { code: "INVALID_ARGUMENT", exit: 2 },
|
|
15461
|
-
"share not found": { code: "NOT_FOUND", exit: 4 },
|
|
15462
|
-
AUTH_REQUIRED: { code: "AUTH_REQUIRED", exit: 3 },
|
|
15463
|
-
UNAVAILABLE: { code: "UNAVAILABLE", exit: 4 }
|
|
15464
|
-
};
|
|
15465
|
-
if (nodeCode === "ENOENT") return new CLIError("INVALID_ARGUMENT", "share input was not found", 2);
|
|
15466
|
-
if (nodeCode === "EISDIR") return new CLIError("INVALID_ARGUMENT", "share input must be a Markdown file", 2);
|
|
15467
|
-
if (error instanceof TypeError) return new CLIError("INVALID_ARGUMENT", "share input is invalid", 2);
|
|
15468
|
-
const mapped = typeof nodeCode === "string" && known[nodeCode] !== void 0 ? known[nodeCode] : known[message];
|
|
15469
|
-
return new CLIError(mapped?.code ?? "INVALID_ARGUMENT", mapped ? mapped.code : "share operation failed", mapped?.exit ?? 2);
|
|
15470
|
-
}
|
|
15471
|
-
function inputUrl(value, stdin) {
|
|
15472
|
-
if (stdin || value === "-") return readBoundedUrlStdin();
|
|
15473
|
-
if (value === void 0 || value.length === 0) throw new CLIError("INVALID_ARGUMENT", "a share URL or - is required", 2);
|
|
15474
|
-
return Promise.resolve(value);
|
|
15475
|
-
}
|
|
15476
|
-
async function inspectShareInputOnce(value, stdin, expectedOrigin, dependencies = {}) {
|
|
15477
|
-
const link2 = stdin || value === "-" ? await (dependencies.read ?? readBoundedUrlStdin)() : await inputUrl(value, false);
|
|
15478
|
-
try {
|
|
15479
|
-
parseNativeShareUrl(link2);
|
|
15480
|
-
} catch {
|
|
15481
|
-
return (dependencies.inspect ?? inspectShare)(link2, { expectedOrigin });
|
|
15517
|
+
or(decoder) {
|
|
15518
|
+
return or3(this, decoder);
|
|
15482
15519
|
}
|
|
15483
|
-
|
|
15484
|
-
|
|
15485
|
-
|
|
15486
|
-
|
|
15487
|
-
|
|
15488
|
-
|
|
15489
|
-
|
|
15490
|
-
|
|
15491
|
-
} catch {
|
|
15492
|
-
throw new CLIError("INVALID_ARGUMENT", "invalid expiry duration", 2);
|
|
15520
|
+
decode(input) {
|
|
15521
|
+
const prefix = input[0];
|
|
15522
|
+
const decoder = this.decoders[prefix];
|
|
15523
|
+
if (decoder != null) {
|
|
15524
|
+
return decoder.decode(input);
|
|
15525
|
+
} else {
|
|
15526
|
+
throw RangeError(`Unable to decode multibase string ${JSON.stringify(input)}, only inputs prefixed with ${Object.keys(this.decoders)} are supported`);
|
|
15527
|
+
}
|
|
15493
15528
|
}
|
|
15529
|
+
};
|
|
15530
|
+
function or3(left, right) {
|
|
15531
|
+
return new ComposedDecoder3({
|
|
15532
|
+
...left.decoders ?? { [left.prefix]: left },
|
|
15533
|
+
...right.decoders ?? { [right.prefix]: right }
|
|
15534
|
+
});
|
|
15494
15535
|
}
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
|
|
15536
|
+
var Codec3 = class {
|
|
15537
|
+
name;
|
|
15538
|
+
prefix;
|
|
15539
|
+
baseEncode;
|
|
15540
|
+
baseDecode;
|
|
15541
|
+
encoder;
|
|
15542
|
+
decoder;
|
|
15543
|
+
constructor(name, prefix, baseEncode, baseDecode) {
|
|
15544
|
+
this.name = name;
|
|
15545
|
+
this.prefix = prefix;
|
|
15546
|
+
this.baseEncode = baseEncode;
|
|
15547
|
+
this.baseDecode = baseDecode;
|
|
15548
|
+
this.encoder = new Encoder3(name, prefix, baseEncode);
|
|
15549
|
+
this.decoder = new Decoder3(name, prefix, baseDecode);
|
|
15550
|
+
}
|
|
15551
|
+
encode(input) {
|
|
15552
|
+
return this.encoder.encode(input);
|
|
15553
|
+
}
|
|
15554
|
+
decode(input) {
|
|
15555
|
+
return this.decoder.decode(input);
|
|
15556
|
+
}
|
|
15557
|
+
};
|
|
15558
|
+
function from3({ name, prefix, encode: encode32, decode: decode52 }) {
|
|
15559
|
+
return new Codec3(name, prefix, encode32, decode52);
|
|
15499
15560
|
}
|
|
15500
|
-
function
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
|
|
15561
|
+
function baseX3({ name, prefix, alphabet }) {
|
|
15562
|
+
const { encode: encode32, decode: decode52 } = base_x_default3(alphabet, name);
|
|
15563
|
+
return from3({
|
|
15564
|
+
prefix,
|
|
15565
|
+
name,
|
|
15566
|
+
encode: encode32,
|
|
15567
|
+
decode: (text) => coerce5(decode52(text))
|
|
15568
|
+
});
|
|
15505
15569
|
}
|
|
15506
|
-
function
|
|
15507
|
-
|
|
15508
|
-
|
|
15570
|
+
function decode9(string, alphabetIdx, bitsPerChar, name) {
|
|
15571
|
+
let end = string.length;
|
|
15572
|
+
while (string[end - 1] === "=") {
|
|
15573
|
+
--end;
|
|
15574
|
+
}
|
|
15575
|
+
const out = new Uint8Array(end * bitsPerChar / 8 | 0);
|
|
15576
|
+
let bits = 0;
|
|
15577
|
+
let buffer = 0;
|
|
15578
|
+
let written = 0;
|
|
15579
|
+
for (let i = 0; i < end; ++i) {
|
|
15580
|
+
const value = alphabetIdx[string[i]];
|
|
15581
|
+
if (value === void 0) {
|
|
15582
|
+
throw new SyntaxError(`Non-${name} character`);
|
|
15583
|
+
}
|
|
15584
|
+
buffer = buffer << bitsPerChar | value;
|
|
15585
|
+
bits += bitsPerChar;
|
|
15586
|
+
if (bits >= 8) {
|
|
15587
|
+
bits -= 8;
|
|
15588
|
+
out[written++] = 255 & buffer >> bits;
|
|
15589
|
+
}
|
|
15590
|
+
}
|
|
15591
|
+
if (bits >= bitsPerChar || (255 & buffer << 8 - bits) !== 0) {
|
|
15592
|
+
throw new SyntaxError("Unexpected end of data");
|
|
15593
|
+
}
|
|
15594
|
+
return out;
|
|
15509
15595
|
}
|
|
15510
|
-
function
|
|
15511
|
-
const
|
|
15512
|
-
|
|
15513
|
-
|
|
15596
|
+
function encode5(data, alphabet, bitsPerChar) {
|
|
15597
|
+
const pad = alphabet[alphabet.length - 1] === "=";
|
|
15598
|
+
const mask = (1 << bitsPerChar) - 1;
|
|
15599
|
+
let out = "";
|
|
15600
|
+
let bits = 0;
|
|
15601
|
+
let buffer = 0;
|
|
15602
|
+
for (let i = 0; i < data.length; ++i) {
|
|
15603
|
+
buffer = buffer << 8 | data[i];
|
|
15604
|
+
bits += 8;
|
|
15605
|
+
while (bits > bitsPerChar) {
|
|
15606
|
+
bits -= bitsPerChar;
|
|
15607
|
+
out += alphabet[mask & buffer >> bits];
|
|
15608
|
+
}
|
|
15609
|
+
}
|
|
15610
|
+
if (bits !== 0) {
|
|
15611
|
+
out += alphabet[mask & buffer << bitsPerChar - bits];
|
|
15612
|
+
}
|
|
15613
|
+
if (pad) {
|
|
15614
|
+
while ((out.length * bitsPerChar & 7) !== 0) {
|
|
15615
|
+
out += "=";
|
|
15616
|
+
}
|
|
15617
|
+
}
|
|
15618
|
+
return out;
|
|
15514
15619
|
}
|
|
15515
|
-
function
|
|
15516
|
-
const
|
|
15517
|
-
let
|
|
15518
|
-
|
|
15519
|
-
total += input.bytes.byteLength;
|
|
15520
|
-
if (!Number.isSafeInteger(total) || total > limit) throw new CLIError("MAX_BYTES_EXCEEDED", "combined share input exceeds the configured byte limit", 7);
|
|
15620
|
+
function createAlphabetIdx3(alphabet) {
|
|
15621
|
+
const alphabetIdx = {};
|
|
15622
|
+
for (let i = 0; i < alphabet.length; ++i) {
|
|
15623
|
+
alphabetIdx[alphabet[i]] = i;
|
|
15521
15624
|
}
|
|
15625
|
+
return alphabetIdx;
|
|
15522
15626
|
}
|
|
15523
|
-
function
|
|
15524
|
-
const
|
|
15525
|
-
|
|
15526
|
-
|
|
15527
|
-
|
|
15528
|
-
|
|
15529
|
-
|
|
15530
|
-
|
|
15531
|
-
|
|
15532
|
-
|
|
15533
|
-
assertAggregateInputLimit(inputs, maxBytes);
|
|
15534
|
-
const target = parseShareTarget(options.to);
|
|
15535
|
-
const actions = requestedActions(options.action);
|
|
15536
|
-
if (options.prefix && target.kind === "bearer") throw new CLIError("INVALID_ARGUMENT", "--prefix requires an addressed target", 2);
|
|
15537
|
-
if (inputs.length > 1 && target.kind === "bearer") throw new CLIError("UNSUPPORTED_LINK", "multiple files require an addressed target", 2);
|
|
15538
|
-
if (inputs.length > 1 && !options.prefix) throw new CLIError("INVALID_ARGUMENT", "multiple files require --prefix", 2);
|
|
15539
|
-
if (options.notify === true && target.kind !== "email") throw new CLIError("INVALID_ARGUMENT", "--notify requires an exact email target", 2);
|
|
15540
|
-
const result = await publishTargetShare({
|
|
15541
|
-
source: inputs[0].bytes,
|
|
15542
|
-
filename: inputs[0].filename,
|
|
15543
|
-
files: inputs.map((input) => ({ bytes: input.bytes, filename: input.filename, mediaType: mediaTypeFor(input.filename) })),
|
|
15544
|
-
mediaType: options.mediaType ?? mediaTypeFor(inputs[0].filename),
|
|
15545
|
-
allowBinary: options.binary === true,
|
|
15546
|
-
target,
|
|
15547
|
-
resourceKind: options.prefix || inputs.length > 1 ? "prefix" : "exact",
|
|
15548
|
-
actions,
|
|
15549
|
-
expiresAt: expires(options.expires ?? "7d"),
|
|
15550
|
-
expiryWasExplicit: options.expires !== void 0,
|
|
15551
|
-
origin: options.viewerOrigin,
|
|
15552
|
-
...maxBytes === void 0 ? {} : { maxBytes },
|
|
15553
|
-
notify: options.notify === true,
|
|
15554
|
-
targetAdapter: shareServices.targetAdapter
|
|
15555
|
-
});
|
|
15556
|
-
if ("state" in result) {
|
|
15557
|
-
if (json) {
|
|
15558
|
-
writeJson2({ protocol: "tinycloud-share", version: 1, authorization: authorizationRequiredJson(result) });
|
|
15559
|
-
process.exitCode = 6;
|
|
15560
|
-
return;
|
|
15561
|
-
}
|
|
15562
|
-
throw new CLIError(result.method === "openkey-device" ? "DEVICE_AUTH_REQUIRED" : "CLAIM_REQUIRED", "recipient authorization is required; continue through the configured authority adapter", 6);
|
|
15563
|
-
}
|
|
15564
|
-
const record = await rememberPublishedShare(result);
|
|
15565
|
-
if (options.notify === true && target.kind === "email") {
|
|
15566
|
-
if (shareServices.delivery === void 0) throw new CLIError("AUTH_REQUIRED", "delivery authority is not configured", 3);
|
|
15567
|
-
const recipient = record.recipientMatcher.kind === "exactEmail" ? record.recipientMatcher.value : target.address;
|
|
15568
|
-
const delivery = await notifyShare({ shareId: record.shareId, recipient, record, adapter: shareServices.delivery });
|
|
15569
|
-
if (delivery.state === "partial-failure") process.exitCode = 9;
|
|
15570
|
-
}
|
|
15571
|
-
if (result.metadata.expiryClamped === true) process.stderr.write(`Share expiry clamped to session expiry (${result.metadata.expiresAt}).
|
|
15572
|
-
`);
|
|
15573
|
-
if (json) writeJson2({ ...redactPublishedShare(result), expiryClamped: result.metadata.expiryClamped === true });
|
|
15574
|
-
else publishHuman(result);
|
|
15575
|
-
} catch (error) {
|
|
15576
|
-
handleError(shareCliError(error));
|
|
15577
|
-
}
|
|
15578
|
-
});
|
|
15579
|
-
share.command("inspect [url]").description("Verify a share link and print safe metadata").option("--stdin", "Read the complete URL from stdin").option("--json", "Print versioned redacted JSON").option("--viewer-origin <origin>", "Require this canonical Share origin", SHARE_ORIGIN).action(async (url, options, command) => {
|
|
15580
|
-
try {
|
|
15581
|
-
const json = jsonOutput(options, command);
|
|
15582
|
-
const result = await inspectShareInputOnce(url, options.stdin === true, options.viewerOrigin);
|
|
15583
|
-
if (json) writeJson2(result);
|
|
15584
|
-
else inspectHuman(result);
|
|
15585
|
-
} catch (error) {
|
|
15586
|
-
handleError(shareCliError(error));
|
|
15587
|
-
}
|
|
15588
|
-
});
|
|
15589
|
-
share.command("receive [url]").description("Verify and receive a share link").option("--stdin", "Read the complete URL from stdin").option("--output <directory>", "Create the file in this directory").option("--stdout", "Write verified plaintext bytes to stdout").option("--force", "Allow replacing an existing non-symlink output").option("--max-bytes <bytes>", "Bound received content bytes").option("--json", "Print versioned redacted JSON").option("--viewer-origin <origin>", "Require this canonical Share origin", SHARE_ORIGIN).action(async (url, options, command) => {
|
|
15590
|
-
try {
|
|
15591
|
-
const json = jsonOutput(options, command);
|
|
15592
|
-
if (options.stdout && json) throw new CLIError("INVALID_ARGUMENT", "--stdout and --json are mutually exclusive", 2);
|
|
15593
|
-
const maxBytes = byteLimit(options.maxBytes);
|
|
15594
|
-
const link2 = await inputUrl(url, options.stdin === true);
|
|
15595
|
-
let nativeLink = false;
|
|
15596
|
-
try {
|
|
15597
|
-
parseNativeShareUrl(link2);
|
|
15598
|
-
nativeLink = true;
|
|
15599
|
-
} catch {
|
|
15600
|
-
}
|
|
15601
|
-
if (nativeLink) {
|
|
15602
|
-
if (shareServices.nativeReader === void 0) throw new CLIError("AUTH_REQUIRED", "native TinyCloud receive is not configured", 3);
|
|
15603
|
-
const native = await shareServices.nativeReader(link2);
|
|
15604
|
-
if (maxBytes !== void 0 && native.bytes.byteLength > maxBytes) throw new CLIError("MAX_BYTES_EXCEEDED", "shared content exceeds max-bytes", 7);
|
|
15605
|
-
if (options.stdout) {
|
|
15606
|
-
process.stdout.write(Buffer.from(native.bytes));
|
|
15607
|
-
return;
|
|
15608
|
-
}
|
|
15609
|
-
const output2 = await writeShareOutput(options.output ?? ".", native.filename, native.bytes, options.force === true);
|
|
15610
|
-
if (json) writeJson2({ protocol: "tinycloud-share", version: 1, path: output2, transport: "native" });
|
|
15611
|
-
else receiveHuman(output2);
|
|
15612
|
-
return;
|
|
15613
|
-
}
|
|
15614
|
-
const result = await receiveShare(link2, {
|
|
15615
|
-
expectedOrigin: options.viewerOrigin,
|
|
15616
|
-
...maxBytes === void 0 ? {} : { maxContentBlobBytes: maxBytes }
|
|
15617
|
-
});
|
|
15618
|
-
if ("state" in result) {
|
|
15619
|
-
if (json) {
|
|
15620
|
-
writeJson2({ protocol: "tinycloud-share", version: 1, authorization: authorizationRequiredJson(result) });
|
|
15621
|
-
process.exitCode = 6;
|
|
15622
|
-
return;
|
|
15623
|
-
}
|
|
15624
|
-
throw new CLIError(result.method === "openkey-device" ? "DEVICE_AUTH_REQUIRED" : "CLAIM_REQUIRED", "recipient authorization is required; resume through the configured authority adapter", 6);
|
|
15625
|
-
}
|
|
15626
|
-
if (options.stdout) {
|
|
15627
|
-
process.stdout.write(Buffer.from(result.bytes));
|
|
15628
|
-
return;
|
|
15629
|
-
}
|
|
15630
|
-
const output = await writeShareOutput(options.output ?? ".", result.metadata.display.filename ?? "share.md", result.bytes, options.force === true);
|
|
15631
|
-
if (json) receiveJson(result, output);
|
|
15632
|
-
else receiveHuman(output);
|
|
15633
|
-
} catch (error) {
|
|
15634
|
-
handleError(shareCliError(error));
|
|
15635
|
-
}
|
|
15636
|
-
});
|
|
15637
|
-
share.command("list").description("List encrypted sender history without complete bearer URLs").option("--json", "Print versioned redacted JSON").action(async (options, command) => {
|
|
15638
|
-
try {
|
|
15639
|
-
const json = jsonOutput(options, command);
|
|
15640
|
-
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
15641
|
-
const result = await listShares(shareServices.records);
|
|
15642
|
-
if (json) writeJson2({ protocol: "tinycloud-share", version: 1, shares: result });
|
|
15643
|
-
else process.stdout.write(result.map((item) => `${item.shareId} ${item.target} ${item.expiresAt}`).join("\n") + (result.length ? "\n" : ""));
|
|
15644
|
-
} catch (error) {
|
|
15645
|
-
handleError(shareCliError(error));
|
|
15646
|
-
}
|
|
15647
|
-
});
|
|
15648
|
-
share.command("show <id>").description("Show one redacted sender-history record").option("--reveal-link", "Explicitly include the complete link").option("--json", "Print versioned redacted JSON").action(async (id, options, command) => {
|
|
15649
|
-
try {
|
|
15650
|
-
const json = jsonOutput(options, command);
|
|
15651
|
-
if (options.revealLink && json) throw new CLIError("INVALID_ARGUMENT", "--reveal-link cannot be combined with --json", 2);
|
|
15652
|
-
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
15653
|
-
const result = await showShare({ storage: shareServices.records, shareId: id, revealLink: options.revealLink === true, link: options.revealLink ? await shareServices.linkFor?.(id) : void 0 });
|
|
15654
|
-
if (json) writeJson2({ protocol: "tinycloud-share", version: 1, share: result });
|
|
15655
|
-
else writeJson2(result);
|
|
15656
|
-
} catch (error) {
|
|
15657
|
-
handleError(shareCliError(error));
|
|
15658
|
-
}
|
|
15659
|
-
});
|
|
15660
|
-
share.command("notify <id>").description("Retry idempotent delivery without recreating the share").requiredOption("--to <address>", "Recipient email").option("--json", "Print versioned JSON").action(async (id, options, command) => {
|
|
15661
|
-
try {
|
|
15662
|
-
const json = jsonOutput(options, command);
|
|
15663
|
-
if (shareServices.delivery === void 0) throw new CLIError("AUTH_REQUIRED", "delivery authority is not configured", 3);
|
|
15664
|
-
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
15665
|
-
const record = await shareServices.records.get(id);
|
|
15666
|
-
if (record === void 0) throw new CLIError("NOT_FOUND", "share not found", 4);
|
|
15667
|
-
const result = await notifyShare({ shareId: id, recipient: options.to, record, adapter: shareServices.delivery });
|
|
15668
|
-
if (json) writeJson2(result);
|
|
15669
|
-
else process.stdout.write(`${result.state}
|
|
15670
|
-
`);
|
|
15671
|
-
if (result.state === "partial-failure") process.exitCode = 9;
|
|
15672
|
-
} catch (error) {
|
|
15673
|
-
handleError(shareCliError(error));
|
|
15674
|
-
}
|
|
15675
|
-
});
|
|
15676
|
-
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) => {
|
|
15677
|
-
try {
|
|
15678
|
-
const json = jsonOutput(options, command);
|
|
15679
|
-
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
15680
|
-
const record = shareServices.getRecord ? await shareServices.getRecord(id) : await shareServices.records.get(id);
|
|
15681
|
-
if (record === void 0) throw new CLIError("NOT_FOUND", "share not found", 4);
|
|
15682
|
-
const result = await revokeShare({ record, records: shareServices.records, adapter: shareServices.revocation, scope: options.ancestor ? "ancestor" : "direct" });
|
|
15683
|
-
if (result.state === "unsupported") {
|
|
15684
|
-
throw new CLIError("UNSUPPORTED_TARGET", result.reason, 2);
|
|
15685
|
-
}
|
|
15686
|
-
if (json) writeJson2({ protocol: "tinycloud-share", version: 1, result });
|
|
15687
|
-
else process.stdout.write(`${result.state}
|
|
15688
|
-
`);
|
|
15689
|
-
} catch (error) {
|
|
15690
|
-
handleError(shareCliError(error));
|
|
15627
|
+
function rfc46483({ name, prefix, bitsPerChar, alphabet }) {
|
|
15628
|
+
const alphabetIdx = createAlphabetIdx3(alphabet);
|
|
15629
|
+
return from3({
|
|
15630
|
+
prefix,
|
|
15631
|
+
name,
|
|
15632
|
+
encode(input) {
|
|
15633
|
+
return encode5(input, alphabet, bitsPerChar);
|
|
15634
|
+
},
|
|
15635
|
+
decode(input) {
|
|
15636
|
+
return decode9(input, alphabetIdx, bitsPerChar, name);
|
|
15691
15637
|
}
|
|
15692
15638
|
});
|
|
15693
15639
|
}
|
|
15694
|
-
|
|
15695
|
-
|
|
15696
|
-
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15702
|
-
|
|
15703
|
-
|
|
15704
|
-
|
|
15705
|
-
|
|
15706
|
-
|
|
15640
|
+
var base323 = rfc46483({
|
|
15641
|
+
prefix: "b",
|
|
15642
|
+
name: "base32",
|
|
15643
|
+
alphabet: "abcdefghijklmnopqrstuvwxyz234567",
|
|
15644
|
+
bitsPerChar: 5
|
|
15645
|
+
});
|
|
15646
|
+
var base32upper3 = rfc46483({
|
|
15647
|
+
prefix: "B",
|
|
15648
|
+
name: "base32upper",
|
|
15649
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
|
|
15650
|
+
bitsPerChar: 5
|
|
15651
|
+
});
|
|
15652
|
+
var base32pad3 = rfc46483({
|
|
15653
|
+
prefix: "c",
|
|
15654
|
+
name: "base32pad",
|
|
15655
|
+
alphabet: "abcdefghijklmnopqrstuvwxyz234567=",
|
|
15656
|
+
bitsPerChar: 5
|
|
15657
|
+
});
|
|
15658
|
+
var base32padupper3 = rfc46483({
|
|
15659
|
+
prefix: "C",
|
|
15660
|
+
name: "base32padupper",
|
|
15661
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
|
|
15662
|
+
bitsPerChar: 5
|
|
15663
|
+
});
|
|
15664
|
+
var base32hex3 = rfc46483({
|
|
15665
|
+
prefix: "v",
|
|
15666
|
+
name: "base32hex",
|
|
15667
|
+
alphabet: "0123456789abcdefghijklmnopqrstuv",
|
|
15668
|
+
bitsPerChar: 5
|
|
15669
|
+
});
|
|
15670
|
+
var base32hexupper3 = rfc46483({
|
|
15671
|
+
prefix: "V",
|
|
15672
|
+
name: "base32hexupper",
|
|
15673
|
+
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
|
|
15674
|
+
bitsPerChar: 5
|
|
15675
|
+
});
|
|
15676
|
+
var base32hexpad3 = rfc46483({
|
|
15677
|
+
prefix: "t",
|
|
15678
|
+
name: "base32hexpad",
|
|
15679
|
+
alphabet: "0123456789abcdefghijklmnopqrstuv=",
|
|
15680
|
+
bitsPerChar: 5
|
|
15681
|
+
});
|
|
15682
|
+
var base32hexpadupper3 = rfc46483({
|
|
15683
|
+
prefix: "T",
|
|
15684
|
+
name: "base32hexpadupper",
|
|
15685
|
+
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV=",
|
|
15686
|
+
bitsPerChar: 5
|
|
15687
|
+
});
|
|
15688
|
+
var base32z3 = rfc46483({
|
|
15689
|
+
prefix: "h",
|
|
15690
|
+
name: "base32z",
|
|
15691
|
+
alphabet: "ybndrfg8ejkmcpqxot1uwisza345h769",
|
|
15692
|
+
bitsPerChar: 5
|
|
15693
|
+
});
|
|
15694
|
+
var base363 = baseX3({
|
|
15695
|
+
prefix: "k",
|
|
15696
|
+
name: "base36",
|
|
15697
|
+
alphabet: "0123456789abcdefghijklmnopqrstuvwxyz"
|
|
15698
|
+
});
|
|
15699
|
+
var base36upper3 = baseX3({
|
|
15700
|
+
prefix: "K",
|
|
15701
|
+
name: "base36upper",
|
|
15702
|
+
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
15703
|
+
});
|
|
15704
|
+
var base58btc3 = baseX3({
|
|
15705
|
+
name: "base58btc",
|
|
15706
|
+
prefix: "z",
|
|
15707
|
+
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
15708
|
+
});
|
|
15709
|
+
var base58flickr3 = baseX3({
|
|
15710
|
+
name: "base58flickr",
|
|
15711
|
+
prefix: "Z",
|
|
15712
|
+
alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
|
|
15713
|
+
});
|
|
15714
|
+
var encode_13 = encode22;
|
|
15715
|
+
var MSB3 = 128;
|
|
15716
|
+
var REST3 = 127;
|
|
15717
|
+
var MSBALL3 = ~REST3;
|
|
15718
|
+
var INT3 = Math.pow(2, 31);
|
|
15719
|
+
function encode22(num, out, offset) {
|
|
15720
|
+
out = out || [];
|
|
15721
|
+
offset = offset || 0;
|
|
15722
|
+
var oldOffset = offset;
|
|
15723
|
+
while (num >= INT3) {
|
|
15724
|
+
out[offset++] = num & 255 | MSB3;
|
|
15725
|
+
num /= 128;
|
|
15707
15726
|
}
|
|
15708
|
-
|
|
15709
|
-
|
|
15727
|
+
while (num & MSBALL3) {
|
|
15728
|
+
out[offset++] = num & 255 | MSB3;
|
|
15729
|
+
num >>>= 7;
|
|
15710
15730
|
}
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15731
|
+
out[offset] = num | 0;
|
|
15732
|
+
encode22.bytes = offset - oldOffset + 1;
|
|
15733
|
+
return out;
|
|
15734
|
+
}
|
|
15735
|
+
var decode22 = read3;
|
|
15736
|
+
var MSB$13 = 128;
|
|
15737
|
+
var REST$13 = 127;
|
|
15738
|
+
function read3(buf, offset) {
|
|
15739
|
+
var res = 0, offset = offset || 0, shift = 0, counter = offset, b, l = buf.length;
|
|
15740
|
+
do {
|
|
15741
|
+
if (counter >= l) {
|
|
15742
|
+
read3.bytes = 0;
|
|
15743
|
+
throw new RangeError("Could not decode varint");
|
|
15714
15744
|
}
|
|
15715
|
-
|
|
15716
|
-
|
|
15745
|
+
b = buf[counter++];
|
|
15746
|
+
res += shift < 28 ? (b & REST$13) << shift : (b & REST$13) * Math.pow(2, shift);
|
|
15747
|
+
shift += 7;
|
|
15748
|
+
} while (b >= MSB$13);
|
|
15749
|
+
read3.bytes = counter - offset;
|
|
15750
|
+
return res;
|
|
15717
15751
|
}
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
|
|
15721
|
-
|
|
15722
|
-
|
|
15723
|
-
|
|
15724
|
-
|
|
15725
|
-
|
|
15726
|
-
|
|
15727
|
-
|
|
15728
|
-
|
|
15752
|
+
var N13 = Math.pow(2, 7);
|
|
15753
|
+
var N23 = Math.pow(2, 14);
|
|
15754
|
+
var N33 = Math.pow(2, 21);
|
|
15755
|
+
var N43 = Math.pow(2, 28);
|
|
15756
|
+
var N53 = Math.pow(2, 35);
|
|
15757
|
+
var N63 = Math.pow(2, 42);
|
|
15758
|
+
var N73 = Math.pow(2, 49);
|
|
15759
|
+
var N83 = Math.pow(2, 56);
|
|
15760
|
+
var N93 = Math.pow(2, 63);
|
|
15761
|
+
var length3 = function(value) {
|
|
15762
|
+
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;
|
|
15763
|
+
};
|
|
15764
|
+
var varint3 = {
|
|
15765
|
+
encode: encode_13,
|
|
15766
|
+
decode: decode22,
|
|
15767
|
+
encodingLength: length3
|
|
15768
|
+
};
|
|
15769
|
+
var _brrp_varint3 = varint3;
|
|
15770
|
+
var varint_default3 = _brrp_varint3;
|
|
15771
|
+
function decode32(data, offset = 0) {
|
|
15772
|
+
const code22 = varint_default3.decode(data, offset);
|
|
15773
|
+
return [code22, varint_default3.decode.bytes];
|
|
15729
15774
|
}
|
|
15730
|
-
function
|
|
15731
|
-
|
|
15732
|
-
|
|
15775
|
+
function encodeTo3(int, target, offset = 0) {
|
|
15776
|
+
varint_default3.encode(int, target, offset);
|
|
15777
|
+
return target;
|
|
15778
|
+
}
|
|
15779
|
+
function encodingLength3(int) {
|
|
15780
|
+
return varint_default3.encodingLength(int);
|
|
15781
|
+
}
|
|
15782
|
+
function create3(code22, digest) {
|
|
15783
|
+
const size = digest.byteLength;
|
|
15784
|
+
const sizeOffset = encodingLength3(code22);
|
|
15785
|
+
const digestOffset = sizeOffset + encodingLength3(size);
|
|
15786
|
+
const bytes = new Uint8Array(digestOffset + size);
|
|
15787
|
+
encodeTo3(code22, bytes, 0);
|
|
15788
|
+
encodeTo3(size, bytes, sizeOffset);
|
|
15789
|
+
bytes.set(digest, digestOffset);
|
|
15790
|
+
return new Digest3(code22, size, digest, bytes);
|
|
15791
|
+
}
|
|
15792
|
+
function decode42(multihash) {
|
|
15793
|
+
const bytes = coerce5(multihash);
|
|
15794
|
+
const [code22, sizeOffset] = decode32(bytes);
|
|
15795
|
+
const [size, digestOffset] = decode32(bytes.subarray(sizeOffset));
|
|
15796
|
+
const digest = bytes.subarray(sizeOffset + digestOffset);
|
|
15797
|
+
if (digest.byteLength !== size) {
|
|
15798
|
+
throw new Error("Incorrect length");
|
|
15733
15799
|
}
|
|
15734
|
-
|
|
15735
|
-
|
|
15736
|
-
|
|
15800
|
+
return new Digest3(code22, size, digest, bytes);
|
|
15801
|
+
}
|
|
15802
|
+
function equals22(a, b) {
|
|
15803
|
+
if (a === b) {
|
|
15804
|
+
return true;
|
|
15805
|
+
} else {
|
|
15806
|
+
const data = b;
|
|
15807
|
+
return a.code === data.code && a.size === data.size && data.bytes instanceof Uint8Array && equals5(a.bytes, data.bytes);
|
|
15737
15808
|
}
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15809
|
+
}
|
|
15810
|
+
var Digest3 = class {
|
|
15811
|
+
code;
|
|
15812
|
+
size;
|
|
15813
|
+
digest;
|
|
15814
|
+
bytes;
|
|
15815
|
+
/**
|
|
15816
|
+
* Creates a multihash digest.
|
|
15817
|
+
*/
|
|
15818
|
+
constructor(code22, size, digest, bytes) {
|
|
15819
|
+
this.code = code22;
|
|
15820
|
+
this.size = size;
|
|
15821
|
+
this.digest = digest;
|
|
15822
|
+
this.bytes = bytes;
|
|
15745
15823
|
}
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
|
|
15752
|
-
|
|
15753
|
-
|
|
15754
|
-
|
|
15755
|
-
|
|
15756
|
-
|
|
15757
|
-
|
|
15758
|
-
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
|
|
15775
|
-
|
|
15776
|
-
|
|
15777
|
-
|
|
15778
|
-
|
|
15779
|
-
|
|
15780
|
-
|
|
15824
|
+
};
|
|
15825
|
+
function format3(link2, base22) {
|
|
15826
|
+
const { bytes, version: version2 } = link2;
|
|
15827
|
+
switch (version2) {
|
|
15828
|
+
case 0:
|
|
15829
|
+
return toStringV03(bytes, baseCache3(link2), base22 ?? base58btc3.encoder);
|
|
15830
|
+
default:
|
|
15831
|
+
return toStringV13(bytes, baseCache3(link2), base22 ?? base323.encoder);
|
|
15832
|
+
}
|
|
15833
|
+
}
|
|
15834
|
+
var cache3 = /* @__PURE__ */ new WeakMap();
|
|
15835
|
+
function baseCache3(cid) {
|
|
15836
|
+
const baseCache22 = cache3.get(cid);
|
|
15837
|
+
if (baseCache22 == null) {
|
|
15838
|
+
const baseCache32 = /* @__PURE__ */ new Map();
|
|
15839
|
+
cache3.set(cid, baseCache32);
|
|
15840
|
+
return baseCache32;
|
|
15841
|
+
}
|
|
15842
|
+
return baseCache22;
|
|
15843
|
+
}
|
|
15844
|
+
var CID3 = class _CID3 {
|
|
15845
|
+
code;
|
|
15846
|
+
version;
|
|
15847
|
+
multihash;
|
|
15848
|
+
bytes;
|
|
15849
|
+
"/";
|
|
15850
|
+
/**
|
|
15851
|
+
* @param version - Version of the CID
|
|
15852
|
+
* @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
15853
|
+
* @param multihash - (Multi)hash of the of the content.
|
|
15854
|
+
*/
|
|
15855
|
+
constructor(version2, code22, multihash, bytes) {
|
|
15856
|
+
this.code = code22;
|
|
15857
|
+
this.version = version2;
|
|
15858
|
+
this.multihash = multihash;
|
|
15859
|
+
this.bytes = bytes;
|
|
15860
|
+
this["/"] = bytes;
|
|
15861
|
+
}
|
|
15862
|
+
/**
|
|
15863
|
+
* Signalling `cid.asCID === cid` has been replaced with `cid['/'] === cid.bytes`
|
|
15864
|
+
* please either use `CID.asCID(cid)` or switch to new signalling mechanism
|
|
15865
|
+
*
|
|
15866
|
+
* @deprecated
|
|
15867
|
+
*/
|
|
15868
|
+
get asCID() {
|
|
15869
|
+
return this;
|
|
15870
|
+
}
|
|
15871
|
+
// ArrayBufferView
|
|
15872
|
+
get byteOffset() {
|
|
15873
|
+
return this.bytes.byteOffset;
|
|
15874
|
+
}
|
|
15875
|
+
// ArrayBufferView
|
|
15876
|
+
get byteLength() {
|
|
15877
|
+
return this.bytes.byteLength;
|
|
15878
|
+
}
|
|
15879
|
+
toV0() {
|
|
15880
|
+
switch (this.version) {
|
|
15881
|
+
case 0: {
|
|
15882
|
+
return this;
|
|
15781
15883
|
}
|
|
15782
|
-
|
|
15783
|
-
|
|
15884
|
+
case 1: {
|
|
15885
|
+
const { code: code22, multihash } = this;
|
|
15886
|
+
if (code22 !== DAG_PB_CODE3) {
|
|
15887
|
+
throw new Error("Cannot convert a non dag-pb CID to CIDv0");
|
|
15888
|
+
}
|
|
15889
|
+
if (multihash.code !== SHA_256_CODE3) {
|
|
15890
|
+
throw new Error("Cannot convert non sha2-256 multihash CID to CIDv0");
|
|
15891
|
+
}
|
|
15892
|
+
return _CID3.createV0(multihash);
|
|
15893
|
+
}
|
|
15894
|
+
default: {
|
|
15895
|
+
throw Error(`Can not convert CID version ${this.version} to version 0. This is a bug please report`);
|
|
15784
15896
|
}
|
|
15785
|
-
length22 = i2;
|
|
15786
|
-
pbegin++;
|
|
15787
|
-
}
|
|
15788
|
-
var it2 = size - length22;
|
|
15789
|
-
while (it2 !== size && b58[it2] === 0) {
|
|
15790
|
-
it2++;
|
|
15791
|
-
}
|
|
15792
|
-
var str = LEADER.repeat(zeroes);
|
|
15793
|
-
for (; it2 < size; ++it2) {
|
|
15794
|
-
str += ALPHABET.charAt(b58[it2]);
|
|
15795
15897
|
}
|
|
15796
|
-
return str;
|
|
15797
15898
|
}
|
|
15798
|
-
|
|
15799
|
-
|
|
15800
|
-
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
}
|
|
15805
|
-
var psz = 0;
|
|
15806
|
-
if (source[psz] === " ") {
|
|
15807
|
-
return;
|
|
15808
|
-
}
|
|
15809
|
-
var zeroes = 0;
|
|
15810
|
-
var length22 = 0;
|
|
15811
|
-
while (source[psz] === LEADER) {
|
|
15812
|
-
zeroes++;
|
|
15813
|
-
psz++;
|
|
15814
|
-
}
|
|
15815
|
-
var size = (source.length - psz) * FACTOR + 1 >>> 0;
|
|
15816
|
-
var b256 = new Uint8Array(size);
|
|
15817
|
-
while (source[psz]) {
|
|
15818
|
-
var carry = BASE_MAP[source.charCodeAt(psz)];
|
|
15819
|
-
if (carry === 255) {
|
|
15820
|
-
return;
|
|
15899
|
+
toV1() {
|
|
15900
|
+
switch (this.version) {
|
|
15901
|
+
case 0: {
|
|
15902
|
+
const { code: code22, digest } = this.multihash;
|
|
15903
|
+
const multihash = create3(code22, digest);
|
|
15904
|
+
return _CID3.createV1(this.code, multihash);
|
|
15821
15905
|
}
|
|
15822
|
-
|
|
15823
|
-
|
|
15824
|
-
carry += BASE * b256[it3] >>> 0;
|
|
15825
|
-
b256[it3] = carry % 256 >>> 0;
|
|
15826
|
-
carry = carry / 256 >>> 0;
|
|
15906
|
+
case 1: {
|
|
15907
|
+
return this;
|
|
15827
15908
|
}
|
|
15828
|
-
|
|
15829
|
-
throw
|
|
15909
|
+
default: {
|
|
15910
|
+
throw Error(`Can not convert CID version ${this.version} to version 1. This is a bug please report`);
|
|
15830
15911
|
}
|
|
15831
|
-
length22 = i2;
|
|
15832
|
-
psz++;
|
|
15833
|
-
}
|
|
15834
|
-
if (source[psz] === " ") {
|
|
15835
|
-
return;
|
|
15836
|
-
}
|
|
15837
|
-
var it4 = size - length22;
|
|
15838
|
-
while (it4 !== size && b256[it4] === 0) {
|
|
15839
|
-
it4++;
|
|
15840
|
-
}
|
|
15841
|
-
var vch = new Uint8Array(zeroes + (size - it4));
|
|
15842
|
-
var j2 = zeroes;
|
|
15843
|
-
while (it4 !== size) {
|
|
15844
|
-
vch[j2++] = b256[it4++];
|
|
15845
|
-
}
|
|
15846
|
-
return vch;
|
|
15847
|
-
}
|
|
15848
|
-
function decode52(string) {
|
|
15849
|
-
var buffer = decodeUnsafe(string);
|
|
15850
|
-
if (buffer) {
|
|
15851
|
-
return buffer;
|
|
15852
15912
|
}
|
|
15853
|
-
throw new Error(`Non-${name} character`);
|
|
15854
15913
|
}
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
decodeUnsafe,
|
|
15858
|
-
decode: decode52
|
|
15859
|
-
};
|
|
15860
|
-
}
|
|
15861
|
-
var src3 = base3;
|
|
15862
|
-
var _brrp__multiformats_scope_baseX3 = src3;
|
|
15863
|
-
var base_x_default3 = _brrp__multiformats_scope_baseX3;
|
|
15864
|
-
var Encoder3 = class {
|
|
15865
|
-
name;
|
|
15866
|
-
prefix;
|
|
15867
|
-
baseEncode;
|
|
15868
|
-
constructor(name, prefix, baseEncode) {
|
|
15869
|
-
this.name = name;
|
|
15870
|
-
this.prefix = prefix;
|
|
15871
|
-
this.baseEncode = baseEncode;
|
|
15914
|
+
equals(other) {
|
|
15915
|
+
return _CID3.equals(this, other);
|
|
15872
15916
|
}
|
|
15873
|
-
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
} else {
|
|
15877
|
-
throw Error("Unknown type, must be binary type");
|
|
15878
|
-
}
|
|
15917
|
+
static equals(self, other) {
|
|
15918
|
+
const unknown = other;
|
|
15919
|
+
return unknown != null && self.code === unknown.code && self.version === unknown.version && equals22(self.multihash, unknown.multihash);
|
|
15879
15920
|
}
|
|
15880
|
-
|
|
15881
|
-
|
|
15882
|
-
name;
|
|
15883
|
-
prefix;
|
|
15884
|
-
baseDecode;
|
|
15885
|
-
prefixCodePoint;
|
|
15886
|
-
constructor(name, prefix, baseDecode) {
|
|
15887
|
-
this.name = name;
|
|
15888
|
-
this.prefix = prefix;
|
|
15889
|
-
const prefixCodePoint = prefix.codePointAt(0);
|
|
15890
|
-
if (prefixCodePoint === void 0) {
|
|
15891
|
-
throw new Error("Invalid prefix character");
|
|
15892
|
-
}
|
|
15893
|
-
this.prefixCodePoint = prefixCodePoint;
|
|
15894
|
-
this.baseDecode = baseDecode;
|
|
15921
|
+
toString(base22) {
|
|
15922
|
+
return format3(this, base22);
|
|
15895
15923
|
}
|
|
15896
|
-
|
|
15897
|
-
|
|
15898
|
-
if (text.codePointAt(0) !== this.prefixCodePoint) {
|
|
15899
|
-
throw Error(`Unable to decode multibase string ${JSON.stringify(text)}, ${this.name} decoder only supports inputs prefixed with ${this.prefix}`);
|
|
15900
|
-
}
|
|
15901
|
-
return this.baseDecode(text.slice(this.prefix.length));
|
|
15902
|
-
} else {
|
|
15903
|
-
throw Error("Can only multibase decode strings");
|
|
15904
|
-
}
|
|
15905
|
-
}
|
|
15906
|
-
or(decoder) {
|
|
15907
|
-
return or3(this, decoder);
|
|
15924
|
+
toJSON() {
|
|
15925
|
+
return { "/": format3(this) };
|
|
15908
15926
|
}
|
|
15909
|
-
|
|
15910
|
-
|
|
15911
|
-
decoders;
|
|
15912
|
-
constructor(decoders) {
|
|
15913
|
-
this.decoders = decoders;
|
|
15927
|
+
link() {
|
|
15928
|
+
return this;
|
|
15914
15929
|
}
|
|
15915
|
-
|
|
15916
|
-
|
|
15930
|
+
[Symbol.toStringTag] = "CID";
|
|
15931
|
+
// Legacy
|
|
15932
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
15933
|
+
return `CID(${this.toString()})`;
|
|
15917
15934
|
}
|
|
15918
|
-
|
|
15919
|
-
|
|
15920
|
-
|
|
15921
|
-
|
|
15922
|
-
|
|
15935
|
+
/**
|
|
15936
|
+
* Takes any input `value` and returns a `CID` instance if it was
|
|
15937
|
+
* a `CID` otherwise returns `null`. If `value` is instanceof `CID`
|
|
15938
|
+
* it will return value back. If `value` is not instance of this CID
|
|
15939
|
+
* class, but is compatible CID it will return new instance of this
|
|
15940
|
+
* `CID` class. Otherwise returns null.
|
|
15941
|
+
*
|
|
15942
|
+
* This allows two different incompatible versions of CID library to
|
|
15943
|
+
* co-exist and interop as long as binary interface is compatible.
|
|
15944
|
+
*/
|
|
15945
|
+
static asCID(input) {
|
|
15946
|
+
if (input == null) {
|
|
15947
|
+
return null;
|
|
15948
|
+
}
|
|
15949
|
+
const value = input;
|
|
15950
|
+
if (value instanceof _CID3) {
|
|
15951
|
+
return value;
|
|
15952
|
+
} else if (value["/"] != null && value["/"] === value.bytes || value.asCID === value) {
|
|
15953
|
+
const { version: version2, code: code22, multihash, bytes } = value;
|
|
15954
|
+
return new _CID3(version2, code22, multihash, bytes ?? encodeCID3(version2, code22, multihash.bytes));
|
|
15955
|
+
} else if (value[cidSymbol3] === true) {
|
|
15956
|
+
const { version: version2, multihash, code: code22 } = value;
|
|
15957
|
+
const digest = decode42(multihash);
|
|
15958
|
+
return _CID3.create(version2, code22, digest);
|
|
15923
15959
|
} else {
|
|
15924
|
-
|
|
15960
|
+
return null;
|
|
15925
15961
|
}
|
|
15926
15962
|
}
|
|
15927
|
-
|
|
15928
|
-
|
|
15929
|
-
|
|
15930
|
-
|
|
15931
|
-
|
|
15932
|
-
|
|
15933
|
-
|
|
15934
|
-
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
|
|
15942
|
-
|
|
15943
|
-
|
|
15944
|
-
|
|
15945
|
-
|
|
15946
|
-
|
|
15947
|
-
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
15963
|
+
/**
|
|
15964
|
+
* @param version - Version of the CID
|
|
15965
|
+
* @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
15966
|
+
* @param digest - (Multi)hash of the of the content.
|
|
15967
|
+
*/
|
|
15968
|
+
static create(version2, code22, digest) {
|
|
15969
|
+
if (typeof code22 !== "number") {
|
|
15970
|
+
throw new Error("String codecs are no longer supported");
|
|
15971
|
+
}
|
|
15972
|
+
if (!(digest.bytes instanceof Uint8Array)) {
|
|
15973
|
+
throw new Error("Invalid digest");
|
|
15974
|
+
}
|
|
15975
|
+
switch (version2) {
|
|
15976
|
+
case 0: {
|
|
15977
|
+
if (code22 !== DAG_PB_CODE3) {
|
|
15978
|
+
throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE3}) block encoding`);
|
|
15979
|
+
} else {
|
|
15980
|
+
return new _CID3(version2, code22, digest, digest.bytes);
|
|
15981
|
+
}
|
|
15982
|
+
}
|
|
15983
|
+
case 1: {
|
|
15984
|
+
const bytes = encodeCID3(version2, code22, digest.bytes);
|
|
15985
|
+
return new _CID3(version2, code22, digest, bytes);
|
|
15986
|
+
}
|
|
15987
|
+
default: {
|
|
15988
|
+
throw new Error("Invalid version");
|
|
15989
|
+
}
|
|
15990
|
+
}
|
|
15951
15991
|
}
|
|
15952
|
-
|
|
15953
|
-
|
|
15992
|
+
/**
|
|
15993
|
+
* Simplified version of `create` for CIDv0.
|
|
15994
|
+
*/
|
|
15995
|
+
static createV0(digest) {
|
|
15996
|
+
return _CID3.create(0, DAG_PB_CODE3, digest);
|
|
15954
15997
|
}
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
name,
|
|
15964
|
-
encode: encode32,
|
|
15965
|
-
decode: (text) => coerce5(decode52(text))
|
|
15966
|
-
});
|
|
15967
|
-
}
|
|
15968
|
-
function decode9(string, alphabetIdx, bitsPerChar, name) {
|
|
15969
|
-
let end = string.length;
|
|
15970
|
-
while (string[end - 1] === "=") {
|
|
15971
|
-
--end;
|
|
15998
|
+
/**
|
|
15999
|
+
* Simplified version of `create` for CIDv1.
|
|
16000
|
+
*
|
|
16001
|
+
* @param code - Content encoding format code.
|
|
16002
|
+
* @param digest - Multihash of the content.
|
|
16003
|
+
*/
|
|
16004
|
+
static createV1(code22, digest) {
|
|
16005
|
+
return _CID3.create(1, code22, digest);
|
|
15972
16006
|
}
|
|
15973
|
-
|
|
15974
|
-
|
|
15975
|
-
|
|
15976
|
-
|
|
15977
|
-
|
|
15978
|
-
|
|
15979
|
-
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
|
|
15984
|
-
if (bits >= 8) {
|
|
15985
|
-
bits -= 8;
|
|
15986
|
-
out[written++] = 255 & buffer >> bits;
|
|
16007
|
+
/**
|
|
16008
|
+
* Decoded a CID from its binary representation. The byte array must contain
|
|
16009
|
+
* only the CID with no additional bytes.
|
|
16010
|
+
*
|
|
16011
|
+
* An error will be thrown if the bytes provided do not contain a valid
|
|
16012
|
+
* binary representation of a CID.
|
|
16013
|
+
*/
|
|
16014
|
+
static decode(bytes) {
|
|
16015
|
+
const [cid, remainder] = _CID3.decodeFirst(bytes);
|
|
16016
|
+
if (remainder.length !== 0) {
|
|
16017
|
+
throw new Error("Incorrect length");
|
|
15987
16018
|
}
|
|
16019
|
+
return cid;
|
|
15988
16020
|
}
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
|
|
15994
|
-
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
|
|
16004
|
-
bits -= bitsPerChar;
|
|
16005
|
-
out += alphabet[mask & buffer >> bits];
|
|
16021
|
+
/**
|
|
16022
|
+
* Decoded a CID from its binary representation at the beginning of a byte
|
|
16023
|
+
* array.
|
|
16024
|
+
*
|
|
16025
|
+
* Returns an array with the first element containing the CID and the second
|
|
16026
|
+
* element containing the remainder of the original byte array. The remainder
|
|
16027
|
+
* will be a zero-length byte array if the provided bytes only contained a
|
|
16028
|
+
* binary CID representation.
|
|
16029
|
+
*/
|
|
16030
|
+
static decodeFirst(bytes) {
|
|
16031
|
+
const specs = _CID3.inspectBytes(bytes);
|
|
16032
|
+
const prefixSize = specs.size - specs.multihashSize;
|
|
16033
|
+
const multihashBytes = coerce5(bytes.subarray(prefixSize, prefixSize + specs.multihashSize));
|
|
16034
|
+
if (multihashBytes.byteLength !== specs.multihashSize) {
|
|
16035
|
+
throw new Error("Incorrect length");
|
|
16006
16036
|
}
|
|
16037
|
+
const digestBytes = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
|
|
16038
|
+
const digest = new Digest3(specs.multihashCode, specs.digestSize, digestBytes, multihashBytes);
|
|
16039
|
+
const cid = specs.version === 0 ? _CID3.createV0(digest) : _CID3.createV1(specs.codec, digest);
|
|
16040
|
+
return [cid, bytes.subarray(specs.size)];
|
|
16007
16041
|
}
|
|
16008
|
-
|
|
16009
|
-
|
|
16042
|
+
/**
|
|
16043
|
+
* Inspect the initial bytes of a CID to determine its properties.
|
|
16044
|
+
*
|
|
16045
|
+
* Involves decoding up to 4 varints. Typically this will require only 4 to 6
|
|
16046
|
+
* bytes but for larger multicodec code values and larger multihash digest
|
|
16047
|
+
* lengths these varints can be quite large. It is recommended that at least
|
|
16048
|
+
* 10 bytes be made available in the `initialBytes` argument for a complete
|
|
16049
|
+
* inspection.
|
|
16050
|
+
*/
|
|
16051
|
+
static inspectBytes(initialBytes) {
|
|
16052
|
+
let offset = 0;
|
|
16053
|
+
const next = () => {
|
|
16054
|
+
const [i, length22] = decode32(initialBytes.subarray(offset));
|
|
16055
|
+
offset += length22;
|
|
16056
|
+
return i;
|
|
16057
|
+
};
|
|
16058
|
+
let version2 = next();
|
|
16059
|
+
let codec = DAG_PB_CODE3;
|
|
16060
|
+
if (version2 === 18) {
|
|
16061
|
+
version2 = 0;
|
|
16062
|
+
offset = 0;
|
|
16063
|
+
} else {
|
|
16064
|
+
codec = next();
|
|
16065
|
+
}
|
|
16066
|
+
if (version2 !== 0 && version2 !== 1) {
|
|
16067
|
+
throw new RangeError(`Invalid CID version ${version2}`);
|
|
16068
|
+
}
|
|
16069
|
+
const prefixSize = offset;
|
|
16070
|
+
const multihashCode = next();
|
|
16071
|
+
const digestSize = next();
|
|
16072
|
+
const size = offset + digestSize;
|
|
16073
|
+
const multihashSize = size - prefixSize;
|
|
16074
|
+
return { version: version2, codec, multihashCode, digestSize, multihashSize, size };
|
|
16010
16075
|
}
|
|
16011
|
-
|
|
16012
|
-
|
|
16013
|
-
|
|
16076
|
+
/**
|
|
16077
|
+
* Takes cid in a string representation and creates an instance. If `base`
|
|
16078
|
+
* decoder is not provided will use a default from the configuration. It will
|
|
16079
|
+
* throw an error if encoding of the CID is not compatible with supplied (or
|
|
16080
|
+
* a default decoder).
|
|
16081
|
+
*/
|
|
16082
|
+
static parse(source, base22) {
|
|
16083
|
+
const [prefix, bytes] = parseCIDtoBytes3(source, base22);
|
|
16084
|
+
const cid = _CID3.decode(bytes);
|
|
16085
|
+
if (cid.version === 0 && source[0] !== "Q") {
|
|
16086
|
+
throw Error("Version 0 CID string must not include multibase prefix");
|
|
16087
|
+
}
|
|
16088
|
+
baseCache3(cid).set(prefix, source);
|
|
16089
|
+
return cid;
|
|
16090
|
+
}
|
|
16091
|
+
};
|
|
16092
|
+
function parseCIDtoBytes3(source, base22) {
|
|
16093
|
+
switch (source[0]) {
|
|
16094
|
+
// CIDv0 is parsed differently
|
|
16095
|
+
case "Q": {
|
|
16096
|
+
const decoder = base22 ?? base58btc3;
|
|
16097
|
+
return [
|
|
16098
|
+
base58btc3.prefix,
|
|
16099
|
+
decoder.decode(`${base58btc3.prefix}${source}`)
|
|
16100
|
+
];
|
|
16101
|
+
}
|
|
16102
|
+
case base58btc3.prefix: {
|
|
16103
|
+
const decoder = base22 ?? base58btc3;
|
|
16104
|
+
return [base58btc3.prefix, decoder.decode(source)];
|
|
16105
|
+
}
|
|
16106
|
+
case base323.prefix: {
|
|
16107
|
+
const decoder = base22 ?? base323;
|
|
16108
|
+
return [base323.prefix, decoder.decode(source)];
|
|
16109
|
+
}
|
|
16110
|
+
case base363.prefix: {
|
|
16111
|
+
const decoder = base22 ?? base363;
|
|
16112
|
+
return [base363.prefix, decoder.decode(source)];
|
|
16113
|
+
}
|
|
16114
|
+
default: {
|
|
16115
|
+
if (base22 == null) {
|
|
16116
|
+
throw Error("To parse non base32, base36 or base58btc encoded CID multibase decoder must be provided");
|
|
16117
|
+
}
|
|
16118
|
+
return [source[0], base22.decode(source)];
|
|
16014
16119
|
}
|
|
16015
16120
|
}
|
|
16016
|
-
return out;
|
|
16017
16121
|
}
|
|
16018
|
-
function
|
|
16019
|
-
const
|
|
16020
|
-
|
|
16021
|
-
|
|
16122
|
+
function toStringV03(bytes, cache22, base22) {
|
|
16123
|
+
const { prefix } = base22;
|
|
16124
|
+
if (prefix !== base58btc3.prefix) {
|
|
16125
|
+
throw Error(`Cannot string encode V0 in ${base22.name} encoding`);
|
|
16126
|
+
}
|
|
16127
|
+
const cid = cache22.get(prefix);
|
|
16128
|
+
if (cid == null) {
|
|
16129
|
+
const cid2 = base22.encode(bytes).slice(1);
|
|
16130
|
+
cache22.set(prefix, cid2);
|
|
16131
|
+
return cid2;
|
|
16132
|
+
} else {
|
|
16133
|
+
return cid;
|
|
16022
16134
|
}
|
|
16023
|
-
return alphabetIdx;
|
|
16024
16135
|
}
|
|
16025
|
-
function
|
|
16026
|
-
const
|
|
16027
|
-
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16032
|
-
|
|
16033
|
-
|
|
16034
|
-
|
|
16035
|
-
}
|
|
16036
|
-
});
|
|
16136
|
+
function toStringV13(bytes, cache22, base22) {
|
|
16137
|
+
const { prefix } = base22;
|
|
16138
|
+
const cid = cache22.get(prefix);
|
|
16139
|
+
if (cid == null) {
|
|
16140
|
+
const cid2 = base22.encode(bytes);
|
|
16141
|
+
cache22.set(prefix, cid2);
|
|
16142
|
+
return cid2;
|
|
16143
|
+
} else {
|
|
16144
|
+
return cid;
|
|
16145
|
+
}
|
|
16037
16146
|
}
|
|
16038
|
-
var
|
|
16039
|
-
|
|
16040
|
-
|
|
16041
|
-
|
|
16042
|
-
|
|
16043
|
-
|
|
16044
|
-
|
|
16045
|
-
|
|
16046
|
-
|
|
16047
|
-
|
|
16048
|
-
|
|
16049
|
-
|
|
16050
|
-
var
|
|
16051
|
-
|
|
16052
|
-
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
|
|
16058
|
-
|
|
16059
|
-
|
|
16060
|
-
|
|
16061
|
-
|
|
16062
|
-
|
|
16063
|
-
|
|
16064
|
-
|
|
16065
|
-
|
|
16066
|
-
bitsPerChar: 5
|
|
16067
|
-
});
|
|
16068
|
-
var base32hexupper3 = rfc46483({
|
|
16069
|
-
prefix: "V",
|
|
16070
|
-
name: "base32hexupper",
|
|
16071
|
-
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
|
|
16072
|
-
bitsPerChar: 5
|
|
16073
|
-
});
|
|
16074
|
-
var base32hexpad3 = rfc46483({
|
|
16075
|
-
prefix: "t",
|
|
16076
|
-
name: "base32hexpad",
|
|
16077
|
-
alphabet: "0123456789abcdefghijklmnopqrstuv=",
|
|
16078
|
-
bitsPerChar: 5
|
|
16079
|
-
});
|
|
16080
|
-
var base32hexpadupper3 = rfc46483({
|
|
16081
|
-
prefix: "T",
|
|
16082
|
-
name: "base32hexpadupper",
|
|
16083
|
-
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV=",
|
|
16084
|
-
bitsPerChar: 5
|
|
16085
|
-
});
|
|
16086
|
-
var base32z3 = rfc46483({
|
|
16087
|
-
prefix: "h",
|
|
16088
|
-
name: "base32z",
|
|
16089
|
-
alphabet: "ybndrfg8ejkmcpqxot1uwisza345h769",
|
|
16090
|
-
bitsPerChar: 5
|
|
16091
|
-
});
|
|
16092
|
-
var base363 = baseX3({
|
|
16093
|
-
prefix: "k",
|
|
16094
|
-
name: "base36",
|
|
16095
|
-
alphabet: "0123456789abcdefghijklmnopqrstuvwxyz"
|
|
16147
|
+
var DAG_PB_CODE3 = 112;
|
|
16148
|
+
var SHA_256_CODE3 = 18;
|
|
16149
|
+
function encodeCID3(version2, code22, multihash) {
|
|
16150
|
+
const codeOffset = encodingLength3(version2);
|
|
16151
|
+
const hashOffset = codeOffset + encodingLength3(code22);
|
|
16152
|
+
const bytes = new Uint8Array(hashOffset + multihash.byteLength);
|
|
16153
|
+
encodeTo3(version2, bytes, 0);
|
|
16154
|
+
encodeTo3(code22, bytes, codeOffset);
|
|
16155
|
+
bytes.set(multihash, hashOffset);
|
|
16156
|
+
return bytes;
|
|
16157
|
+
}
|
|
16158
|
+
var cidSymbol3 = /* @__PURE__ */ Symbol.for("@ipld/js-cid/CID");
|
|
16159
|
+
var code2 = 85;
|
|
16160
|
+
var SHA256_CODE2 = 18;
|
|
16161
|
+
function isCanonicalRawCid2(cidString) {
|
|
16162
|
+
let cid;
|
|
16163
|
+
try {
|
|
16164
|
+
cid = CID3.parse(cidString);
|
|
16165
|
+
} catch {
|
|
16166
|
+
return false;
|
|
16167
|
+
}
|
|
16168
|
+
return cid.version === 1 && cid.code === code2 && cid.multihash.code === SHA256_CODE2 && cid.toString() === cidString;
|
|
16169
|
+
}
|
|
16170
|
+
var base642 = rfc46483({
|
|
16171
|
+
prefix: "m",
|
|
16172
|
+
name: "base64",
|
|
16173
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
|
16174
|
+
bitsPerChar: 6
|
|
16096
16175
|
});
|
|
16097
|
-
var
|
|
16098
|
-
prefix: "
|
|
16099
|
-
name: "
|
|
16100
|
-
alphabet: "
|
|
16176
|
+
var base64pad2 = rfc46483({
|
|
16177
|
+
prefix: "M",
|
|
16178
|
+
name: "base64pad",
|
|
16179
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
|
16180
|
+
bitsPerChar: 6
|
|
16101
16181
|
});
|
|
16102
|
-
var
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
alphabet: "
|
|
16182
|
+
var base64url2 = rfc46483({
|
|
16183
|
+
prefix: "u",
|
|
16184
|
+
name: "base64url",
|
|
16185
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
|
|
16186
|
+
bitsPerChar: 6
|
|
16106
16187
|
});
|
|
16107
|
-
var
|
|
16108
|
-
|
|
16109
|
-
|
|
16110
|
-
alphabet: "
|
|
16188
|
+
var base64urlpad2 = rfc46483({
|
|
16189
|
+
prefix: "U",
|
|
16190
|
+
name: "base64urlpad",
|
|
16191
|
+
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",
|
|
16192
|
+
bitsPerChar: 6
|
|
16111
16193
|
});
|
|
16112
|
-
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
|
|
16116
|
-
var INT3 = Math.pow(2, 31);
|
|
16117
|
-
function encode22(num, out, offset) {
|
|
16118
|
-
out = out || [];
|
|
16119
|
-
offset = offset || 0;
|
|
16120
|
-
var oldOffset = offset;
|
|
16121
|
-
while (num >= INT3) {
|
|
16122
|
-
out[offset++] = num & 255 | MSB3;
|
|
16123
|
-
num /= 128;
|
|
16124
|
-
}
|
|
16125
|
-
while (num & MSBALL3) {
|
|
16126
|
-
out[offset++] = num & 255 | MSB3;
|
|
16127
|
-
num >>>= 7;
|
|
16194
|
+
function fromBase64Url2(text) {
|
|
16195
|
+
const bytes = base64url2.baseDecode(text);
|
|
16196
|
+
if (base64url2.baseEncode(bytes) !== text) {
|
|
16197
|
+
throw new TypeError("non-canonical base64url input");
|
|
16128
16198
|
}
|
|
16129
|
-
|
|
16130
|
-
encode22.bytes = offset - oldOffset + 1;
|
|
16131
|
-
return out;
|
|
16199
|
+
return bytes;
|
|
16132
16200
|
}
|
|
16133
|
-
|
|
16134
|
-
|
|
16135
|
-
var REST$13 = 127;
|
|
16136
|
-
function read3(buf, offset) {
|
|
16137
|
-
var res = 0, offset = offset || 0, shift = 0, counter = offset, b, l = buf.length;
|
|
16138
|
-
do {
|
|
16139
|
-
if (counter >= l) {
|
|
16140
|
-
read3.bytes = 0;
|
|
16141
|
-
throw new RangeError("Could not decode varint");
|
|
16142
|
-
}
|
|
16143
|
-
b = buf[counter++];
|
|
16144
|
-
res += shift < 28 ? (b & REST$13) << shift : (b & REST$13) * Math.pow(2, shift);
|
|
16145
|
-
shift += 7;
|
|
16146
|
-
} while (b >= MSB$13);
|
|
16147
|
-
read3.bytes = counter - offset;
|
|
16148
|
-
return res;
|
|
16201
|
+
function utf8Bytes2(text) {
|
|
16202
|
+
return new TextEncoder().encode(text);
|
|
16149
16203
|
}
|
|
16150
|
-
var
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
var N83 = Math.pow(2, 56);
|
|
16158
|
-
var N93 = Math.pow(2, 63);
|
|
16159
|
-
var length3 = function(value) {
|
|
16160
|
-
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;
|
|
16161
|
-
};
|
|
16162
|
-
var varint3 = {
|
|
16163
|
-
encode: encode_13,
|
|
16164
|
-
decode: decode22,
|
|
16165
|
-
encodingLength: length3
|
|
16166
|
-
};
|
|
16167
|
-
var _brrp_varint3 = varint3;
|
|
16168
|
-
var varint_default3 = _brrp_varint3;
|
|
16169
|
-
function decode32(data, offset = 0) {
|
|
16170
|
-
const code22 = varint_default3.decode(data, offset);
|
|
16171
|
-
return [code22, varint_default3.decode.bytes];
|
|
16204
|
+
var ED25519_MULTICODEC_PREFIX2 = Uint8Array.of(237, 1);
|
|
16205
|
+
function decodeBase64UrlOrNull2(value) {
|
|
16206
|
+
try {
|
|
16207
|
+
return fromBase64Url2(value);
|
|
16208
|
+
} catch {
|
|
16209
|
+
return null;
|
|
16210
|
+
}
|
|
16172
16211
|
}
|
|
16173
|
-
|
|
16174
|
-
|
|
16175
|
-
|
|
16176
|
-
|
|
16177
|
-
|
|
16178
|
-
|
|
16179
|
-
|
|
16180
|
-
|
|
16181
|
-
|
|
16182
|
-
const sizeOffset = encodingLength3(code22);
|
|
16183
|
-
const digestOffset = sizeOffset + encodingLength3(size);
|
|
16184
|
-
const bytes = new Uint8Array(digestOffset + size);
|
|
16185
|
-
encodeTo3(code22, bytes, 0);
|
|
16186
|
-
encodeTo3(size, bytes, sizeOffset);
|
|
16187
|
-
bytes.set(digest, digestOffset);
|
|
16188
|
-
return new Digest3(code22, size, digest, bytes);
|
|
16189
|
-
}
|
|
16190
|
-
function decode42(multihash) {
|
|
16191
|
-
const bytes = coerce5(multihash);
|
|
16192
|
-
const [code22, sizeOffset] = decode32(bytes);
|
|
16193
|
-
const [size, digestOffset] = decode32(bytes.subarray(sizeOffset));
|
|
16194
|
-
const digest = bytes.subarray(sizeOffset + digestOffset);
|
|
16195
|
-
if (digest.byteLength !== size) {
|
|
16196
|
-
throw new Error("Incorrect length");
|
|
16197
|
-
}
|
|
16198
|
-
return new Digest3(code22, size, digest, bytes);
|
|
16199
|
-
}
|
|
16200
|
-
function equals22(a, b) {
|
|
16201
|
-
if (a === b) {
|
|
16202
|
-
return true;
|
|
16203
|
-
} else {
|
|
16204
|
-
const data = b;
|
|
16205
|
-
return a.code === data.code && a.size === data.size && data.bytes instanceof Uint8Array && equals5(a.bytes, data.bytes);
|
|
16212
|
+
var base64UrlString2 = () => external_exports2.string().refine((value) => decodeBase64UrlOrNull2(value) !== null, {
|
|
16213
|
+
message: "expected strictly-decodable unpadded base64url"
|
|
16214
|
+
});
|
|
16215
|
+
function isCanonicalHttpsOrigin2(value) {
|
|
16216
|
+
let url;
|
|
16217
|
+
try {
|
|
16218
|
+
url = new URL(value);
|
|
16219
|
+
} catch {
|
|
16220
|
+
return false;
|
|
16206
16221
|
}
|
|
16222
|
+
return url.protocol === "https:" && url.origin === value;
|
|
16207
16223
|
}
|
|
16208
|
-
var
|
|
16209
|
-
|
|
16210
|
-
|
|
16211
|
-
|
|
16212
|
-
|
|
16213
|
-
|
|
16214
|
-
* Creates a multihash digest.
|
|
16215
|
-
*/
|
|
16216
|
-
constructor(code22, size, digest, bytes) {
|
|
16217
|
-
this.code = code22;
|
|
16218
|
-
this.size = size;
|
|
16219
|
-
this.digest = digest;
|
|
16220
|
-
this.bytes = bytes;
|
|
16221
|
-
}
|
|
16224
|
+
var sessionJwkCommonFields2 = {
|
|
16225
|
+
alg: external_exports2.string().min(1).optional(),
|
|
16226
|
+
use: external_exports2.string().min(1).optional(),
|
|
16227
|
+
key_ops: external_exports2.array(external_exports2.string().min(1)).optional(),
|
|
16228
|
+
kid: external_exports2.string().min(1).optional(),
|
|
16229
|
+
ext: external_exports2.boolean().optional()
|
|
16222
16230
|
};
|
|
16223
|
-
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16227
|
-
|
|
16228
|
-
|
|
16229
|
-
|
|
16230
|
-
|
|
16231
|
+
var okpPrivateJwkSchema2 = external_exports2.object({
|
|
16232
|
+
kty: external_exports2.literal("OKP"),
|
|
16233
|
+
crv: external_exports2.string().min(1),
|
|
16234
|
+
x: base64UrlString2(),
|
|
16235
|
+
d: base64UrlString2(),
|
|
16236
|
+
...sessionJwkCommonFields2
|
|
16237
|
+
}).strict();
|
|
16238
|
+
var ecPrivateJwkSchema2 = external_exports2.object({
|
|
16239
|
+
kty: external_exports2.literal("EC"),
|
|
16240
|
+
crv: external_exports2.string().min(1),
|
|
16241
|
+
x: base64UrlString2(),
|
|
16242
|
+
y: base64UrlString2(),
|
|
16243
|
+
d: base64UrlString2(),
|
|
16244
|
+
...sessionJwkCommonFields2
|
|
16245
|
+
}).strict();
|
|
16246
|
+
var sessionJwkSchema2 = external_exports2.discriminatedUnion("kty", [
|
|
16247
|
+
okpPrivateJwkSchema2,
|
|
16248
|
+
ecPrivateJwkSchema2
|
|
16249
|
+
]);
|
|
16250
|
+
var policyTargetSchema2 = external_exports2.object({
|
|
16251
|
+
kind: external_exports2.literal("policy"),
|
|
16252
|
+
policyCid: external_exports2.string().min(1),
|
|
16253
|
+
/** Canonical policy bytes, base64url-encoded (bytes are not JSON). */
|
|
16254
|
+
policyBytes: base64UrlString2()
|
|
16255
|
+
}).strict();
|
|
16256
|
+
var bearerKeyTargetSchema2 = external_exports2.object({
|
|
16257
|
+
kind: external_exports2.literal("bearerKey"),
|
|
16258
|
+
sessionJwk: sessionJwkSchema2
|
|
16259
|
+
}).strict();
|
|
16260
|
+
var recipientDidTargetSchema2 = external_exports2.object({
|
|
16261
|
+
kind: external_exports2.literal("recipientDid"),
|
|
16262
|
+
did: external_exports2.string().regex(/^did:[a-z0-9]+:.+$/, "expected a DID")
|
|
16263
|
+
}).strict();
|
|
16264
|
+
var authorizationTargetSchema2 = external_exports2.discriminatedUnion("kind", [
|
|
16265
|
+
policyTargetSchema2,
|
|
16266
|
+
bearerKeyTargetSchema2,
|
|
16267
|
+
recipientDidTargetSchema2
|
|
16268
|
+
]);
|
|
16269
|
+
function isCanonicalResourcePath2(value) {
|
|
16270
|
+
if (value.length === 0) return false;
|
|
16271
|
+
if (/[\u0000-\u001f\u007f\\]/.test(value)) return false;
|
|
16272
|
+
if (/%2f|%5c|%2e/i.test(value)) return false;
|
|
16273
|
+
return value.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
16231
16274
|
}
|
|
16232
|
-
|
|
16233
|
-
|
|
16234
|
-
const baseCache22 = cache3.get(cid);
|
|
16235
|
-
if (baseCache22 == null) {
|
|
16236
|
-
const baseCache32 = /* @__PURE__ */ new Map();
|
|
16237
|
-
cache3.set(cid, baseCache32);
|
|
16238
|
-
return baseCache32;
|
|
16239
|
-
}
|
|
16240
|
-
return baseCache22;
|
|
16275
|
+
function isCanonicalPathSegment2(value) {
|
|
16276
|
+
return isCanonicalResourcePath2(value) && !value.includes("/");
|
|
16241
16277
|
}
|
|
16242
|
-
var
|
|
16243
|
-
|
|
16244
|
-
|
|
16245
|
-
|
|
16246
|
-
|
|
16247
|
-
|
|
16248
|
-
|
|
16249
|
-
|
|
16250
|
-
|
|
16251
|
-
|
|
16252
|
-
|
|
16253
|
-
constructor(version2, code22, multihash, bytes) {
|
|
16254
|
-
this.code = code22;
|
|
16255
|
-
this.version = version2;
|
|
16256
|
-
this.multihash = multihash;
|
|
16257
|
-
this.bytes = bytes;
|
|
16258
|
-
this["/"] = bytes;
|
|
16259
|
-
}
|
|
16260
|
-
/**
|
|
16261
|
-
* Signalling `cid.asCID === cid` has been replaced with `cid['/'] === cid.bytes`
|
|
16262
|
-
* please either use `CID.asCID(cid)` or switch to new signalling mechanism
|
|
16263
|
-
*
|
|
16264
|
-
* @deprecated
|
|
16265
|
-
*/
|
|
16266
|
-
get asCID() {
|
|
16267
|
-
return this;
|
|
16268
|
-
}
|
|
16269
|
-
// ArrayBufferView
|
|
16270
|
-
get byteOffset() {
|
|
16271
|
-
return this.bytes.byteOffset;
|
|
16272
|
-
}
|
|
16273
|
-
// ArrayBufferView
|
|
16274
|
-
get byteLength() {
|
|
16275
|
-
return this.bytes.byteLength;
|
|
16276
|
-
}
|
|
16277
|
-
toV0() {
|
|
16278
|
-
switch (this.version) {
|
|
16279
|
-
case 0: {
|
|
16280
|
-
return this;
|
|
16281
|
-
}
|
|
16282
|
-
case 1: {
|
|
16283
|
-
const { code: code22, multihash } = this;
|
|
16284
|
-
if (code22 !== DAG_PB_CODE3) {
|
|
16285
|
-
throw new Error("Cannot convert a non dag-pb CID to CIDv0");
|
|
16286
|
-
}
|
|
16287
|
-
if (multihash.code !== SHA_256_CODE3) {
|
|
16288
|
-
throw new Error("Cannot convert non sha2-256 multihash CID to CIDv0");
|
|
16289
|
-
}
|
|
16290
|
-
return _CID3.createV0(multihash);
|
|
16291
|
-
}
|
|
16292
|
-
default: {
|
|
16293
|
-
throw Error(`Can not convert CID version ${this.version} to version 0. This is a bug please report`);
|
|
16294
|
-
}
|
|
16295
|
-
}
|
|
16296
|
-
}
|
|
16297
|
-
toV1() {
|
|
16298
|
-
switch (this.version) {
|
|
16299
|
-
case 0: {
|
|
16300
|
-
const { code: code22, digest } = this.multihash;
|
|
16301
|
-
const multihash = create3(code22, digest);
|
|
16302
|
-
return _CID3.createV1(this.code, multihash);
|
|
16303
|
-
}
|
|
16304
|
-
case 1: {
|
|
16305
|
-
return this;
|
|
16306
|
-
}
|
|
16307
|
-
default: {
|
|
16308
|
-
throw Error(`Can not convert CID version ${this.version} to version 1. This is a bug please report`);
|
|
16309
|
-
}
|
|
16310
|
-
}
|
|
16311
|
-
}
|
|
16312
|
-
equals(other) {
|
|
16313
|
-
return _CID3.equals(this, other);
|
|
16314
|
-
}
|
|
16315
|
-
static equals(self, other) {
|
|
16316
|
-
const unknown = other;
|
|
16317
|
-
return unknown != null && self.code === unknown.code && self.version === unknown.version && equals22(self.multihash, unknown.multihash);
|
|
16318
|
-
}
|
|
16319
|
-
toString(base22) {
|
|
16320
|
-
return format3(this, base22);
|
|
16321
|
-
}
|
|
16322
|
-
toJSON() {
|
|
16323
|
-
return { "/": format3(this) };
|
|
16324
|
-
}
|
|
16325
|
-
link() {
|
|
16326
|
-
return this;
|
|
16327
|
-
}
|
|
16328
|
-
[Symbol.toStringTag] = "CID";
|
|
16329
|
-
// Legacy
|
|
16330
|
-
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
16331
|
-
return `CID(${this.toString()})`;
|
|
16278
|
+
var resourceSelectorSchema2 = external_exports2.object({
|
|
16279
|
+
kind: external_exports2.union([external_exports2.literal("exact"), external_exports2.literal("prefix")]),
|
|
16280
|
+
path: external_exports2.string().min(1)
|
|
16281
|
+
}).strict().superRefine((selector, ctx) => {
|
|
16282
|
+
const body = selector.kind === "prefix" && selector.path.endsWith("/") ? selector.path.slice(0, -1) : selector.path;
|
|
16283
|
+
if (!isCanonicalResourcePath2(body)) {
|
|
16284
|
+
ctx.addIssue({
|
|
16285
|
+
code: external_exports2.ZodIssueCode.custom,
|
|
16286
|
+
path: ["path"],
|
|
16287
|
+
message: "expected a canonical resource path (non-empty segments, no . or .. segments, no //, no backslash, no %2f/%5c/%2e, no control chars)"
|
|
16288
|
+
});
|
|
16332
16289
|
}
|
|
16290
|
+
});
|
|
16291
|
+
var targetSchema2 = external_exports2.object({
|
|
16292
|
+
origin: external_exports2.string().refine(isCanonicalHttpsOrigin2, {
|
|
16293
|
+
message: "expected a canonical https origin (https://host[:port], nothing else)"
|
|
16294
|
+
}),
|
|
16295
|
+
nodeAudience: external_exports2.string().min(1),
|
|
16296
|
+
spaceId: external_exports2.string().refine(isCanonicalPathSegment2, {
|
|
16297
|
+
message: "expected a single canonical path segment (spaceId joins the resource URI; separators/traversal would alias grants)"
|
|
16298
|
+
}),
|
|
16299
|
+
resource: resourceSelectorSchema2
|
|
16300
|
+
}).strict();
|
|
16301
|
+
var displaySchema2 = external_exports2.object({
|
|
16302
|
+
senderName: external_exports2.string().optional(),
|
|
16303
|
+
filename: external_exports2.string().optional(),
|
|
16304
|
+
recipientHint: external_exports2.string().optional(),
|
|
16333
16305
|
/**
|
|
16334
|
-
*
|
|
16335
|
-
*
|
|
16336
|
-
* it will return value back. If `value` is not instance of this CID
|
|
16337
|
-
* class, but is compatible CID it will return new instance of this
|
|
16338
|
-
* `CID` class. Otherwise returns null.
|
|
16339
|
-
*
|
|
16340
|
-
* This allows two different incompatible versions of CID library to
|
|
16341
|
-
* co-exist and interop as long as binary interface is compatible.
|
|
16342
|
-
*/
|
|
16343
|
-
static asCID(input) {
|
|
16344
|
-
if (input == null) {
|
|
16345
|
-
return null;
|
|
16346
|
-
}
|
|
16347
|
-
const value = input;
|
|
16348
|
-
if (value instanceof _CID3) {
|
|
16349
|
-
return value;
|
|
16350
|
-
} else if (value["/"] != null && value["/"] === value.bytes || value.asCID === value) {
|
|
16351
|
-
const { version: version2, code: code22, multihash, bytes } = value;
|
|
16352
|
-
return new _CID3(version2, code22, multihash, bytes ?? encodeCID3(version2, code22, multihash.bytes));
|
|
16353
|
-
} else if (value[cidSymbol3] === true) {
|
|
16354
|
-
const { version: version2, multihash, code: code22 } = value;
|
|
16355
|
-
const digest = decode42(multihash);
|
|
16356
|
-
return _CID3.create(version2, code22, digest);
|
|
16357
|
-
} else {
|
|
16358
|
-
return null;
|
|
16359
|
-
}
|
|
16360
|
-
}
|
|
16361
|
-
/**
|
|
16362
|
-
* @param version - Version of the CID
|
|
16363
|
-
* @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
16364
|
-
* @param digest - (Multi)hash of the of the content.
|
|
16365
|
-
*/
|
|
16366
|
-
static create(version2, code22, digest) {
|
|
16367
|
-
if (typeof code22 !== "number") {
|
|
16368
|
-
throw new Error("String codecs are no longer supported");
|
|
16369
|
-
}
|
|
16370
|
-
if (!(digest.bytes instanceof Uint8Array)) {
|
|
16371
|
-
throw new Error("Invalid digest");
|
|
16372
|
-
}
|
|
16373
|
-
switch (version2) {
|
|
16374
|
-
case 0: {
|
|
16375
|
-
if (code22 !== DAG_PB_CODE3) {
|
|
16376
|
-
throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE3}) block encoding`);
|
|
16377
|
-
} else {
|
|
16378
|
-
return new _CID3(version2, code22, digest, digest.bytes);
|
|
16379
|
-
}
|
|
16380
|
-
}
|
|
16381
|
-
case 1: {
|
|
16382
|
-
const bytes = encodeCID3(version2, code22, digest.bytes);
|
|
16383
|
-
return new _CID3(version2, code22, digest, bytes);
|
|
16384
|
-
}
|
|
16385
|
-
default: {
|
|
16386
|
-
throw new Error("Invalid version");
|
|
16387
|
-
}
|
|
16388
|
-
}
|
|
16389
|
-
}
|
|
16390
|
-
/**
|
|
16391
|
-
* Simplified version of `create` for CIDv0.
|
|
16392
|
-
*/
|
|
16393
|
-
static createV0(digest) {
|
|
16394
|
-
return _CID3.create(0, DAG_PB_CODE3, digest);
|
|
16395
|
-
}
|
|
16396
|
-
/**
|
|
16397
|
-
* Simplified version of `create` for CIDv1.
|
|
16398
|
-
*
|
|
16399
|
-
* @param code - Content encoding format code.
|
|
16400
|
-
* @param digest - Multihash of the content.
|
|
16401
|
-
*/
|
|
16402
|
-
static createV1(code22, digest) {
|
|
16403
|
-
return _CID3.create(1, code22, digest);
|
|
16404
|
-
}
|
|
16405
|
-
/**
|
|
16406
|
-
* Decoded a CID from its binary representation. The byte array must contain
|
|
16407
|
-
* only the CID with no additional bytes.
|
|
16408
|
-
*
|
|
16409
|
-
* An error will be thrown if the bytes provided do not contain a valid
|
|
16410
|
-
* binary representation of a CID.
|
|
16411
|
-
*/
|
|
16412
|
-
static decode(bytes) {
|
|
16413
|
-
const [cid, remainder] = _CID3.decodeFirst(bytes);
|
|
16414
|
-
if (remainder.length !== 0) {
|
|
16415
|
-
throw new Error("Incorrect length");
|
|
16416
|
-
}
|
|
16417
|
-
return cid;
|
|
16418
|
-
}
|
|
16419
|
-
/**
|
|
16420
|
-
* Decoded a CID from its binary representation at the beginning of a byte
|
|
16421
|
-
* array.
|
|
16422
|
-
*
|
|
16423
|
-
* Returns an array with the first element containing the CID and the second
|
|
16424
|
-
* element containing the remainder of the original byte array. The remainder
|
|
16425
|
-
* will be a zero-length byte array if the provided bytes only contained a
|
|
16426
|
-
* binary CID representation.
|
|
16427
|
-
*/
|
|
16428
|
-
static decodeFirst(bytes) {
|
|
16429
|
-
const specs = _CID3.inspectBytes(bytes);
|
|
16430
|
-
const prefixSize = specs.size - specs.multihashSize;
|
|
16431
|
-
const multihashBytes = coerce5(bytes.subarray(prefixSize, prefixSize + specs.multihashSize));
|
|
16432
|
-
if (multihashBytes.byteLength !== specs.multihashSize) {
|
|
16433
|
-
throw new Error("Incorrect length");
|
|
16434
|
-
}
|
|
16435
|
-
const digestBytes = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
|
|
16436
|
-
const digest = new Digest3(specs.multihashCode, specs.digestSize, digestBytes, multihashBytes);
|
|
16437
|
-
const cid = specs.version === 0 ? _CID3.createV0(digest) : _CID3.createV1(specs.codec, digest);
|
|
16438
|
-
return [cid, bytes.subarray(specs.size)];
|
|
16439
|
-
}
|
|
16440
|
-
/**
|
|
16441
|
-
* Inspect the initial bytes of a CID to determine its properties.
|
|
16442
|
-
*
|
|
16443
|
-
* Involves decoding up to 4 varints. Typically this will require only 4 to 6
|
|
16444
|
-
* bytes but for larger multicodec code values and larger multihash digest
|
|
16445
|
-
* lengths these varints can be quite large. It is recommended that at least
|
|
16446
|
-
* 10 bytes be made available in the `initialBytes` argument for a complete
|
|
16447
|
-
* inspection.
|
|
16448
|
-
*/
|
|
16449
|
-
static inspectBytes(initialBytes) {
|
|
16450
|
-
let offset = 0;
|
|
16451
|
-
const next = () => {
|
|
16452
|
-
const [i, length22] = decode32(initialBytes.subarray(offset));
|
|
16453
|
-
offset += length22;
|
|
16454
|
-
return i;
|
|
16455
|
-
};
|
|
16456
|
-
let version2 = next();
|
|
16457
|
-
let codec = DAG_PB_CODE3;
|
|
16458
|
-
if (version2 === 18) {
|
|
16459
|
-
version2 = 0;
|
|
16460
|
-
offset = 0;
|
|
16461
|
-
} else {
|
|
16462
|
-
codec = next();
|
|
16463
|
-
}
|
|
16464
|
-
if (version2 !== 0 && version2 !== 1) {
|
|
16465
|
-
throw new RangeError(`Invalid CID version ${version2}`);
|
|
16466
|
-
}
|
|
16467
|
-
const prefixSize = offset;
|
|
16468
|
-
const multihashCode = next();
|
|
16469
|
-
const digestSize = next();
|
|
16470
|
-
const size = offset + digestSize;
|
|
16471
|
-
const multihashSize = size - prefixSize;
|
|
16472
|
-
return { version: version2, codec, multihashCode, digestSize, multihashSize, size };
|
|
16473
|
-
}
|
|
16474
|
-
/**
|
|
16475
|
-
* Takes cid in a string representation and creates an instance. If `base`
|
|
16476
|
-
* decoder is not provided will use a default from the configuration. It will
|
|
16477
|
-
* throw an error if encoding of the CID is not compatible with supplied (or
|
|
16478
|
-
* a default decoder).
|
|
16479
|
-
*/
|
|
16480
|
-
static parse(source, base22) {
|
|
16481
|
-
const [prefix, bytes] = parseCIDtoBytes3(source, base22);
|
|
16482
|
-
const cid = _CID3.decode(bytes);
|
|
16483
|
-
if (cid.version === 0 && source[0] !== "Q") {
|
|
16484
|
-
throw Error("Version 0 CID string must not include multibase prefix");
|
|
16485
|
-
}
|
|
16486
|
-
baseCache3(cid).set(prefix, source);
|
|
16487
|
-
return cid;
|
|
16488
|
-
}
|
|
16489
|
-
};
|
|
16490
|
-
function parseCIDtoBytes3(source, base22) {
|
|
16491
|
-
switch (source[0]) {
|
|
16492
|
-
// CIDv0 is parsed differently
|
|
16493
|
-
case "Q": {
|
|
16494
|
-
const decoder = base22 ?? base58btc3;
|
|
16495
|
-
return [
|
|
16496
|
-
base58btc3.prefix,
|
|
16497
|
-
decoder.decode(`${base58btc3.prefix}${source}`)
|
|
16498
|
-
];
|
|
16499
|
-
}
|
|
16500
|
-
case base58btc3.prefix: {
|
|
16501
|
-
const decoder = base22 ?? base58btc3;
|
|
16502
|
-
return [base58btc3.prefix, decoder.decode(source)];
|
|
16503
|
-
}
|
|
16504
|
-
case base323.prefix: {
|
|
16505
|
-
const decoder = base22 ?? base323;
|
|
16506
|
-
return [base323.prefix, decoder.decode(source)];
|
|
16507
|
-
}
|
|
16508
|
-
case base363.prefix: {
|
|
16509
|
-
const decoder = base22 ?? base363;
|
|
16510
|
-
return [base363.prefix, decoder.decode(source)];
|
|
16511
|
-
}
|
|
16512
|
-
default: {
|
|
16513
|
-
if (base22 == null) {
|
|
16514
|
-
throw Error("To parse non base32, base36 or base58btc encoded CID multibase decoder must be provided");
|
|
16515
|
-
}
|
|
16516
|
-
return [source[0], base22.decode(source)];
|
|
16517
|
-
}
|
|
16518
|
-
}
|
|
16519
|
-
}
|
|
16520
|
-
function toStringV03(bytes, cache22, base22) {
|
|
16521
|
-
const { prefix } = base22;
|
|
16522
|
-
if (prefix !== base58btc3.prefix) {
|
|
16523
|
-
throw Error(`Cannot string encode V0 in ${base22.name} encoding`);
|
|
16524
|
-
}
|
|
16525
|
-
const cid = cache22.get(prefix);
|
|
16526
|
-
if (cid == null) {
|
|
16527
|
-
const cid2 = base22.encode(bytes).slice(1);
|
|
16528
|
-
cache22.set(prefix, cid2);
|
|
16529
|
-
return cid2;
|
|
16530
|
-
} else {
|
|
16531
|
-
return cid;
|
|
16532
|
-
}
|
|
16533
|
-
}
|
|
16534
|
-
function toStringV13(bytes, cache22, base22) {
|
|
16535
|
-
const { prefix } = base22;
|
|
16536
|
-
const cid = cache22.get(prefix);
|
|
16537
|
-
if (cid == null) {
|
|
16538
|
-
const cid2 = base22.encode(bytes);
|
|
16539
|
-
cache22.set(prefix, cid2);
|
|
16540
|
-
return cid2;
|
|
16541
|
-
} else {
|
|
16542
|
-
return cid;
|
|
16543
|
-
}
|
|
16544
|
-
}
|
|
16545
|
-
var DAG_PB_CODE3 = 112;
|
|
16546
|
-
var SHA_256_CODE3 = 18;
|
|
16547
|
-
function encodeCID3(version2, code22, multihash) {
|
|
16548
|
-
const codeOffset = encodingLength3(version2);
|
|
16549
|
-
const hashOffset = codeOffset + encodingLength3(code22);
|
|
16550
|
-
const bytes = new Uint8Array(hashOffset + multihash.byteLength);
|
|
16551
|
-
encodeTo3(version2, bytes, 0);
|
|
16552
|
-
encodeTo3(code22, bytes, codeOffset);
|
|
16553
|
-
bytes.set(multihash, hashOffset);
|
|
16554
|
-
return bytes;
|
|
16555
|
-
}
|
|
16556
|
-
var cidSymbol3 = /* @__PURE__ */ Symbol.for("@ipld/js-cid/CID");
|
|
16557
|
-
var code2 = 85;
|
|
16558
|
-
var SHA256_CODE2 = 18;
|
|
16559
|
-
function isCanonicalRawCid2(cidString) {
|
|
16560
|
-
let cid;
|
|
16561
|
-
try {
|
|
16562
|
-
cid = CID3.parse(cidString);
|
|
16563
|
-
} catch {
|
|
16564
|
-
return false;
|
|
16565
|
-
}
|
|
16566
|
-
return cid.version === 1 && cid.code === code2 && cid.multihash.code === SHA256_CODE2 && cid.toString() === cidString;
|
|
16567
|
-
}
|
|
16568
|
-
var base642 = rfc46483({
|
|
16569
|
-
prefix: "m",
|
|
16570
|
-
name: "base64",
|
|
16571
|
-
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
|
16572
|
-
bitsPerChar: 6
|
|
16573
|
-
});
|
|
16574
|
-
var base64pad2 = rfc46483({
|
|
16575
|
-
prefix: "M",
|
|
16576
|
-
name: "base64pad",
|
|
16577
|
-
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
|
16578
|
-
bitsPerChar: 6
|
|
16579
|
-
});
|
|
16580
|
-
var base64url2 = rfc46483({
|
|
16581
|
-
prefix: "u",
|
|
16582
|
-
name: "base64url",
|
|
16583
|
-
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
|
|
16584
|
-
bitsPerChar: 6
|
|
16585
|
-
});
|
|
16586
|
-
var base64urlpad2 = rfc46483({
|
|
16587
|
-
prefix: "U",
|
|
16588
|
-
name: "base64urlpad",
|
|
16589
|
-
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",
|
|
16590
|
-
bitsPerChar: 6
|
|
16591
|
-
});
|
|
16592
|
-
function fromBase64Url2(text) {
|
|
16593
|
-
const bytes = base64url2.baseDecode(text);
|
|
16594
|
-
if (base64url2.baseEncode(bytes) !== text) {
|
|
16595
|
-
throw new TypeError("non-canonical base64url input");
|
|
16596
|
-
}
|
|
16597
|
-
return bytes;
|
|
16598
|
-
}
|
|
16599
|
-
function utf8Bytes2(text) {
|
|
16600
|
-
return new TextEncoder().encode(text);
|
|
16601
|
-
}
|
|
16602
|
-
var ED25519_MULTICODEC_PREFIX2 = Uint8Array.of(237, 1);
|
|
16603
|
-
function decodeBase64UrlOrNull2(value) {
|
|
16604
|
-
try {
|
|
16605
|
-
return fromBase64Url2(value);
|
|
16606
|
-
} catch {
|
|
16607
|
-
return null;
|
|
16608
|
-
}
|
|
16609
|
-
}
|
|
16610
|
-
var base64UrlString2 = () => external_exports2.string().refine((value) => decodeBase64UrlOrNull2(value) !== null, {
|
|
16611
|
-
message: "expected strictly-decodable unpadded base64url"
|
|
16612
|
-
});
|
|
16613
|
-
function isCanonicalHttpsOrigin2(value) {
|
|
16614
|
-
let url;
|
|
16615
|
-
try {
|
|
16616
|
-
url = new URL(value);
|
|
16617
|
-
} catch {
|
|
16618
|
-
return false;
|
|
16619
|
-
}
|
|
16620
|
-
return url.protocol === "https:" && url.origin === value;
|
|
16621
|
-
}
|
|
16622
|
-
var sessionJwkCommonFields2 = {
|
|
16623
|
-
alg: external_exports2.string().min(1).optional(),
|
|
16624
|
-
use: external_exports2.string().min(1).optional(),
|
|
16625
|
-
key_ops: external_exports2.array(external_exports2.string().min(1)).optional(),
|
|
16626
|
-
kid: external_exports2.string().min(1).optional(),
|
|
16627
|
-
ext: external_exports2.boolean().optional()
|
|
16628
|
-
};
|
|
16629
|
-
var okpPrivateJwkSchema2 = external_exports2.object({
|
|
16630
|
-
kty: external_exports2.literal("OKP"),
|
|
16631
|
-
crv: external_exports2.string().min(1),
|
|
16632
|
-
x: base64UrlString2(),
|
|
16633
|
-
d: base64UrlString2(),
|
|
16634
|
-
...sessionJwkCommonFields2
|
|
16635
|
-
}).strict();
|
|
16636
|
-
var ecPrivateJwkSchema2 = external_exports2.object({
|
|
16637
|
-
kty: external_exports2.literal("EC"),
|
|
16638
|
-
crv: external_exports2.string().min(1),
|
|
16639
|
-
x: base64UrlString2(),
|
|
16640
|
-
y: base64UrlString2(),
|
|
16641
|
-
d: base64UrlString2(),
|
|
16642
|
-
...sessionJwkCommonFields2
|
|
16643
|
-
}).strict();
|
|
16644
|
-
var sessionJwkSchema2 = external_exports2.discriminatedUnion("kty", [
|
|
16645
|
-
okpPrivateJwkSchema2,
|
|
16646
|
-
ecPrivateJwkSchema2
|
|
16647
|
-
]);
|
|
16648
|
-
var policyTargetSchema2 = external_exports2.object({
|
|
16649
|
-
kind: external_exports2.literal("policy"),
|
|
16650
|
-
policyCid: external_exports2.string().min(1),
|
|
16651
|
-
/** Canonical policy bytes, base64url-encoded (bytes are not JSON). */
|
|
16652
|
-
policyBytes: base64UrlString2()
|
|
16653
|
-
}).strict();
|
|
16654
|
-
var bearerKeyTargetSchema2 = external_exports2.object({
|
|
16655
|
-
kind: external_exports2.literal("bearerKey"),
|
|
16656
|
-
sessionJwk: sessionJwkSchema2
|
|
16657
|
-
}).strict();
|
|
16658
|
-
var recipientDidTargetSchema2 = external_exports2.object({
|
|
16659
|
-
kind: external_exports2.literal("recipientDid"),
|
|
16660
|
-
did: external_exports2.string().regex(/^did:[a-z0-9]+:.+$/, "expected a DID")
|
|
16661
|
-
}).strict();
|
|
16662
|
-
var authorizationTargetSchema2 = external_exports2.discriminatedUnion("kind", [
|
|
16663
|
-
policyTargetSchema2,
|
|
16664
|
-
bearerKeyTargetSchema2,
|
|
16665
|
-
recipientDidTargetSchema2
|
|
16666
|
-
]);
|
|
16667
|
-
function isCanonicalResourcePath2(value) {
|
|
16668
|
-
if (value.length === 0) return false;
|
|
16669
|
-
if (/[\u0000-\u001f\u007f\\]/.test(value)) return false;
|
|
16670
|
-
if (/%2f|%5c|%2e/i.test(value)) return false;
|
|
16671
|
-
return value.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
16672
|
-
}
|
|
16673
|
-
function isCanonicalPathSegment2(value) {
|
|
16674
|
-
return isCanonicalResourcePath2(value) && !value.includes("/");
|
|
16675
|
-
}
|
|
16676
|
-
var resourceSelectorSchema2 = external_exports2.object({
|
|
16677
|
-
kind: external_exports2.union([external_exports2.literal("exact"), external_exports2.literal("prefix")]),
|
|
16678
|
-
path: external_exports2.string().min(1)
|
|
16679
|
-
}).strict().superRefine((selector, ctx) => {
|
|
16680
|
-
const body = selector.kind === "prefix" && selector.path.endsWith("/") ? selector.path.slice(0, -1) : selector.path;
|
|
16681
|
-
if (!isCanonicalResourcePath2(body)) {
|
|
16682
|
-
ctx.addIssue({
|
|
16683
|
-
code: external_exports2.ZodIssueCode.custom,
|
|
16684
|
-
path: ["path"],
|
|
16685
|
-
message: "expected a canonical resource path (non-empty segments, no . or .. segments, no //, no backslash, no %2f/%5c/%2e, no control chars)"
|
|
16686
|
-
});
|
|
16687
|
-
}
|
|
16688
|
-
});
|
|
16689
|
-
var targetSchema2 = external_exports2.object({
|
|
16690
|
-
origin: external_exports2.string().refine(isCanonicalHttpsOrigin2, {
|
|
16691
|
-
message: "expected a canonical https origin (https://host[:port], nothing else)"
|
|
16692
|
-
}),
|
|
16693
|
-
nodeAudience: external_exports2.string().min(1),
|
|
16694
|
-
spaceId: external_exports2.string().refine(isCanonicalPathSegment2, {
|
|
16695
|
-
message: "expected a single canonical path segment (spaceId joins the resource URI; separators/traversal would alias grants)"
|
|
16696
|
-
}),
|
|
16697
|
-
resource: resourceSelectorSchema2
|
|
16698
|
-
}).strict();
|
|
16699
|
-
var displaySchema2 = external_exports2.object({
|
|
16700
|
-
senderName: external_exports2.string().optional(),
|
|
16701
|
-
filename: external_exports2.string().optional(),
|
|
16702
|
-
recipientHint: external_exports2.string().optional(),
|
|
16703
|
-
/**
|
|
16704
|
-
* Presentation preference only (viewer spec §1): may narrow, never widen;
|
|
16705
|
-
* capabilities always win.
|
|
16306
|
+
* Presentation preference only (viewer spec §1): may narrow, never widen;
|
|
16307
|
+
* capabilities always win.
|
|
16706
16308
|
*/
|
|
16707
16309
|
mode: external_exports2.union([external_exports2.literal("document"), external_exports2.literal("source"), external_exports2.literal("folder")]).optional()
|
|
16708
16310
|
}).strict();
|
|
@@ -16736,324 +16338,954 @@ var unsignedShareEnvelopeSchema2 = external_exports2.object({
|
|
|
16736
16338
|
/** Bearer-slice sealed-content pointer (see contentPointerSchema). */
|
|
16737
16339
|
content: contentPointerSchema2.optional()
|
|
16738
16340
|
}).strict();
|
|
16739
|
-
var shareEnvelopeSchema2 = unsignedShareEnvelopeSchema2.extend({ signature: signatureSchema2 }).strict();
|
|
16740
|
-
var recipientMatcherSchema2 = external_exports2.discriminatedUnion("kind", [
|
|
16741
|
-
external_exports2.object({ kind: external_exports2.literal("exactEmail"), value: external_exports2.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(),
|
|
16742
|
-
external_exports2.object({ kind: external_exports2.literal("emailDomain"), value: external_exports2.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(),
|
|
16743
|
-
external_exports2.object({ kind: external_exports2.literal("recipientDid"), value: external_exports2.string().regex(/^did:[a-z0-9]+:.+$/) }).strict(),
|
|
16744
|
-
external_exports2.object({ kind: external_exports2.literal("policyDigest"), value: external_exports2.string().regex(/^[A-Za-z0-9_-]{43}$/) }).strict(),
|
|
16745
|
-
external_exports2.object({ kind: external_exports2.literal("bearer") }).strict()
|
|
16341
|
+
var shareEnvelopeSchema2 = unsignedShareEnvelopeSchema2.extend({ signature: signatureSchema2 }).strict();
|
|
16342
|
+
var recipientMatcherSchema2 = external_exports2.discriminatedUnion("kind", [
|
|
16343
|
+
external_exports2.object({ kind: external_exports2.literal("exactEmail"), value: external_exports2.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(),
|
|
16344
|
+
external_exports2.object({ kind: external_exports2.literal("emailDomain"), value: external_exports2.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(),
|
|
16345
|
+
external_exports2.object({ kind: external_exports2.literal("recipientDid"), value: external_exports2.string().regex(/^did:[a-z0-9]+:.+$/) }).strict(),
|
|
16346
|
+
external_exports2.object({ kind: external_exports2.literal("policyDigest"), value: external_exports2.string().regex(/^[A-Za-z0-9_-]{43}$/) }).strict(),
|
|
16347
|
+
external_exports2.object({ kind: external_exports2.literal("bearer") }).strict()
|
|
16348
|
+
]);
|
|
16349
|
+
var shareActionSchema2 = external_exports2.union([external_exports2.literal("read"), external_exports2.literal("list"), external_exports2.literal("edit")]);
|
|
16350
|
+
var kvContentSourceSchema2 = external_exports2.object({
|
|
16351
|
+
kind: external_exports2.literal("kv"),
|
|
16352
|
+
space: external_exports2.string().min(1),
|
|
16353
|
+
path: external_exports2.string().min(1),
|
|
16354
|
+
action: external_exports2.literal("tinycloud.kv/get")
|
|
16355
|
+
}).strict();
|
|
16356
|
+
var sqlContentSourceSchema2 = external_exports2.object({
|
|
16357
|
+
kind: external_exports2.literal("sql"),
|
|
16358
|
+
space: external_exports2.string().min(1),
|
|
16359
|
+
database: external_exports2.string().min(1),
|
|
16360
|
+
path: external_exports2.string().min(1),
|
|
16361
|
+
statement: external_exports2.string().min(1),
|
|
16362
|
+
arguments: external_exports2.record(external_exports2.string(), external_exports2.number().int()),
|
|
16363
|
+
argumentsDigest: external_exports2.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
16364
|
+
action: external_exports2.literal("tinycloud.sql/read")
|
|
16365
|
+
}).strict();
|
|
16366
|
+
var contentSourceSchema2 = external_exports2.discriminatedUnion("kind", [kvContentSourceSchema2, sqlContentSourceSchema2]);
|
|
16367
|
+
var v2TargetSchema2 = external_exports2.object({
|
|
16368
|
+
origin: external_exports2.string().refine(isCanonicalHttpsOrigin2, { message: "expected a canonical https origin" }),
|
|
16369
|
+
nodeAudience: external_exports2.string().min(1),
|
|
16370
|
+
spaceId: external_exports2.string().refine(isCanonicalPathSegment2, { message: "expected a canonical space id" })
|
|
16371
|
+
}).strict();
|
|
16372
|
+
var shareDecryptionSchema2 = external_exports2.object({
|
|
16373
|
+
networkId: external_exports2.string().min(1),
|
|
16374
|
+
action: external_exports2.literal("tinycloud.encryption/decrypt")
|
|
16375
|
+
}).strict();
|
|
16376
|
+
var ownerAuthoritySchema2 = external_exports2.object({
|
|
16377
|
+
registrationCid: external_exports2.string().min(1),
|
|
16378
|
+
shareCid: external_exports2.string().min(1),
|
|
16379
|
+
envelopeCid: external_exports2.string().min(1),
|
|
16380
|
+
enforcementDelegation: external_exports2.record(external_exports2.string(), external_exports2.unknown()),
|
|
16381
|
+
outerEnvelope: external_exports2.record(external_exports2.string(), external_exports2.unknown()),
|
|
16382
|
+
/** Node-signed registration evidence; required by trusted policy adapters. */
|
|
16383
|
+
registrationReceipt: external_exports2.object({
|
|
16384
|
+
registration: external_exports2.record(external_exports2.string(), external_exports2.unknown()),
|
|
16385
|
+
proof: external_exports2.record(external_exports2.string(), external_exports2.unknown())
|
|
16386
|
+
}).strict().optional()
|
|
16387
|
+
}).strict();
|
|
16388
|
+
var contentMetadataSchema2 = external_exports2.object({
|
|
16389
|
+
mediaType: external_exports2.string().min(1).max(128).optional(),
|
|
16390
|
+
byteLength: external_exports2.number().int().nonnegative().max(100 * 1024 * 1024).optional(),
|
|
16391
|
+
filename: external_exports2.string().min(1).max(255).optional(),
|
|
16392
|
+
encoding: external_exports2.literal("utf-8").optional(),
|
|
16393
|
+
/** Encrypted presentation discriminator. The fixed entry point is index.html. */
|
|
16394
|
+
artifact: external_exports2.literal("html").optional()
|
|
16395
|
+
}).strict();
|
|
16396
|
+
var deliveryEmailSchema2 = external_exports2.string().email();
|
|
16397
|
+
function isEnvelopeDeliveryEmail2(value) {
|
|
16398
|
+
return deliveryEmailSchema2.safeParse(value).success;
|
|
16399
|
+
}
|
|
16400
|
+
var unsignedShareEnvelopeV2BaseSchema2 = external_exports2.object({
|
|
16401
|
+
version: external_exports2.literal(2),
|
|
16402
|
+
shareId: external_exports2.string().min(1),
|
|
16403
|
+
recipientMatcher: recipientMatcherSchema2,
|
|
16404
|
+
deliveryEmail: deliveryEmailSchema2.optional(),
|
|
16405
|
+
actions: external_exports2.array(shareActionSchema2).min(1).max(3),
|
|
16406
|
+
resource: resourceSelectorSchema2,
|
|
16407
|
+
target: v2TargetSchema2,
|
|
16408
|
+
delegationCid: external_exports2.string().min(1),
|
|
16409
|
+
authorityMaterialHandle: external_exports2.string().min(1),
|
|
16410
|
+
authorityMaterialDigest: external_exports2.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
16411
|
+
decryption: shareDecryptionSchema2.optional(),
|
|
16412
|
+
contentSource: contentSourceSchema2,
|
|
16413
|
+
contentSourceDigest: external_exports2.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
16414
|
+
authorizationTarget: authorizationTargetSchema2,
|
|
16415
|
+
display: displaySchema2,
|
|
16416
|
+
expiry: external_exports2.string().datetime(),
|
|
16417
|
+
encrypted: external_exports2.boolean(),
|
|
16418
|
+
content: contentPointerSchema2.optional(),
|
|
16419
|
+
metadata: contentMetadataSchema2,
|
|
16420
|
+
ownerAuthority: ownerAuthoritySchema2.optional()
|
|
16421
|
+
}).strict();
|
|
16422
|
+
function validateV2Invariants2(value, ctx) {
|
|
16423
|
+
const actions = [...value.actions];
|
|
16424
|
+
if (new Set(actions).size !== actions.length) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["actions"], message: "actions must be unique" });
|
|
16425
|
+
if (actions.some((action, index) => action !== ["read", "list", "edit"].filter((candidate) => actions.includes(candidate))[index])) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["actions"], message: "actions must be canonically ordered" });
|
|
16426
|
+
if (!value.encrypted && value.recipientMatcher.kind !== "policyDigest") ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["recipientMatcher"], message: "safe plaintext must carry only a matcher digest" });
|
|
16427
|
+
if (!value.encrypted && value.authorizationTarget.kind !== "policy") ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["encrypted"], message: "unencrypted content requires a policy target" });
|
|
16428
|
+
if (!value.encrypted && value.content !== void 0) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["content"], message: "policy-only plaintext cannot carry content" });
|
|
16429
|
+
if (value.encrypted && (value.metadata.mediaType === void 0 || value.metadata.filename === void 0 || value.metadata.byteLength === void 0)) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["metadata"], message: "encrypted shares must describe their content" });
|
|
16430
|
+
if (!value.encrypted && Object.keys(value.metadata).length !== 0) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["metadata"], message: "policy-only plaintext cannot describe content" });
|
|
16431
|
+
if (!value.encrypted && value.metadata.encoding !== void 0) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["metadata", "encoding"], message: "policy-only plaintext cannot carry content encoding" });
|
|
16432
|
+
if (value.metadata.artifact === "html" && (!value.encrypted || value.resource.kind !== "prefix" || !value.actions.includes("read") || !value.actions.includes("list"))) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["metadata", "artifact"], message: "html artifacts require an encrypted readable prefix" });
|
|
16433
|
+
if (!value.encrypted && (value.display.senderName !== void 0 || value.display.filename !== void 0 || value.display.recipientHint !== void 0)) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["display"], message: "policy-only plaintext cannot carry display metadata" });
|
|
16434
|
+
if (!value.encrypted && value.deliveryEmail !== void 0) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["deliveryEmail"], message: "policy-only plaintext cannot carry delivery metadata" });
|
|
16435
|
+
if (value.recipientMatcher.kind === "exactEmail" && value.deliveryEmail !== void 0 && value.deliveryEmail !== value.recipientMatcher.value) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["deliveryEmail"], message: "delivery email must match the exact matcher" });
|
|
16436
|
+
if (value.recipientMatcher.kind === "emailDomain" && value.deliveryEmail !== void 0 && value.deliveryEmail.toLowerCase().endsWith(`@${value.recipientMatcher.value}`) === false) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["deliveryEmail"], message: "delivery email must belong to the matcher domain" });
|
|
16437
|
+
if (value.contentSource.kind === "kv" && value.contentSource.action !== "tinycloud.kv/get") ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource"], message: "source action mismatch" });
|
|
16438
|
+
if (value.contentSource.kind === "sql" && value.contentSource.action !== "tinycloud.sql/read") ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource"], message: "source action mismatch" });
|
|
16439
|
+
}
|
|
16440
|
+
var unsignedShareEnvelopeV2Schema2 = unsignedShareEnvelopeV2BaseSchema2.superRefine(validateV2Invariants2);
|
|
16441
|
+
var shareEnvelopeV2Schema2 = unsignedShareEnvelopeV2BaseSchema2.extend({ signature: signatureSchema2 }).strict().superRefine(validateV2Invariants2);
|
|
16442
|
+
var unifiedResourceSchema2 = external_exports2.string().refine((value) => {
|
|
16443
|
+
const marker = value.indexOf("/kv/");
|
|
16444
|
+
if (marker < 1) return false;
|
|
16445
|
+
const space = value.slice(0, marker);
|
|
16446
|
+
const legacy = space.startsWith("tinycloud://");
|
|
16447
|
+
if (legacy ? /[:/?#%]/.test(space.slice("tinycloud://".length)) : !space.startsWith("tinycloud:") || /[/?#%]/.test(space)) return false;
|
|
16448
|
+
const path = value.slice(marker + 4);
|
|
16449
|
+
return !path.startsWith("/") && !path.endsWith("/") && !path.includes("//") && path.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
16450
|
+
}, { message: "expected canonical TinyCloud KV resource" });
|
|
16451
|
+
var unifiedEncryptionNetworkSchema2 = external_exports2.string().refine((value) => {
|
|
16452
|
+
if (!value.startsWith("urn:tinycloud:encryption:")) return false;
|
|
16453
|
+
const rest = value.slice("urn:tinycloud:encryption:".length);
|
|
16454
|
+
const separator = rest.lastIndexOf(":");
|
|
16455
|
+
const owner = separator < 0 ? "" : rest.slice(0, separator);
|
|
16456
|
+
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
16457
|
+
return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
|
|
16458
|
+
}, { message: "expected canonical TinyCloud encryption network" });
|
|
16459
|
+
var unifiedKvCapabilitySchema2 = external_exports2.object({
|
|
16460
|
+
kind: external_exports2.literal("kv"),
|
|
16461
|
+
resource: unifiedResourceSchema2,
|
|
16462
|
+
selector: external_exports2.union([external_exports2.literal("exact"), external_exports2.literal("prefix")]),
|
|
16463
|
+
actions: external_exports2.array(external_exports2.union([
|
|
16464
|
+
external_exports2.literal("tinycloud.kv/get"),
|
|
16465
|
+
external_exports2.literal("tinycloud.kv/list"),
|
|
16466
|
+
external_exports2.literal("tinycloud.kv/metadata"),
|
|
16467
|
+
external_exports2.literal("tinycloud.kv/put")
|
|
16468
|
+
])).min(1)
|
|
16469
|
+
}).strict();
|
|
16470
|
+
var unifiedEncryptionCapabilitySchema2 = external_exports2.object({
|
|
16471
|
+
kind: external_exports2.literal("encryption"),
|
|
16472
|
+
resource: unifiedEncryptionNetworkSchema2,
|
|
16473
|
+
action: external_exports2.literal("tinycloud.encryption/decrypt")
|
|
16474
|
+
}).strict();
|
|
16475
|
+
var unifiedCapabilitySchema2 = external_exports2.union([unifiedKvCapabilitySchema2, unifiedEncryptionCapabilitySchema2]);
|
|
16476
|
+
var unifiedContentSourceSchema2 = external_exports2.object({
|
|
16477
|
+
shareId: external_exports2.string().min(1),
|
|
16478
|
+
kvResource: unifiedResourceSchema2,
|
|
16479
|
+
selector: external_exports2.union([external_exports2.literal("exact"), external_exports2.literal("prefix")]),
|
|
16480
|
+
encryptionNetwork: unifiedEncryptionNetworkSchema2,
|
|
16481
|
+
encryptedSymmetricKeyDigestHex: external_exports2.string().regex(/^[0-9a-f]{64}$/),
|
|
16482
|
+
keyVersion: external_exports2.number().int().positive(),
|
|
16483
|
+
mode: external_exports2.union([external_exports2.literal("mutable"), external_exports2.literal("immutable")]),
|
|
16484
|
+
initialCiphertextDigestHex: external_exports2.string().regex(/^[0-9a-f]{64}$/).optional()
|
|
16485
|
+
}).strict();
|
|
16486
|
+
var unifiedPolicyV1Schema2 = external_exports2.object({
|
|
16487
|
+
schema: external_exports2.literal("xyz.tinycloud.policy/policy/v1"),
|
|
16488
|
+
policyId: external_exports2.string().regex(/^pol_[a-z2-7]+$/),
|
|
16489
|
+
ownerDid: external_exports2.string().min(1),
|
|
16490
|
+
createdAt: external_exports2.string().datetime({ offset: true }),
|
|
16491
|
+
expiresAt: external_exports2.string().datetime({ offset: true }).optional(),
|
|
16492
|
+
contentSource: unifiedContentSourceSchema2,
|
|
16493
|
+
capabilityCeiling: external_exports2.array(unifiedCapabilitySchema2).min(2),
|
|
16494
|
+
signature: external_exports2.object({ suite: external_exports2.string().min(1), signerDid: external_exports2.string().min(1), value: external_exports2.string().min(1) }).strict()
|
|
16495
|
+
}).strict();
|
|
16496
|
+
var policyCredentialRequirementV1Schema2 = external_exports2.object({
|
|
16497
|
+
type: external_exports2.literal("TinyCloudPolicyCredentialRequirement"),
|
|
16498
|
+
version: external_exports2.literal(1),
|
|
16499
|
+
requirementDigest: external_exports2.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
16500
|
+
descriptorDigest: external_exports2.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
16501
|
+
issuerDid: external_exports2.string().min(1),
|
|
16502
|
+
issuerKid: external_exports2.string().min(1),
|
|
16503
|
+
profile: external_exports2.object({ id: external_exports2.string().min(1), version: external_exports2.literal(1) }).strict(),
|
|
16504
|
+
credentialType: external_exports2.object({ id: external_exports2.string().min(1), version: external_exports2.literal(1) }).strict()
|
|
16505
|
+
}).strict();
|
|
16506
|
+
var unifiedPolicyV2Schema2 = external_exports2.object({
|
|
16507
|
+
schema: external_exports2.literal("xyz.tinycloud.policy/policy/v2"),
|
|
16508
|
+
policyId: external_exports2.string().regex(/^pol_[a-z2-7]+$/),
|
|
16509
|
+
ownerDid: external_exports2.string().min(1),
|
|
16510
|
+
createdAt: external_exports2.string().datetime({ offset: true }),
|
|
16511
|
+
expiresAt: external_exports2.string().datetime({ offset: true }).optional(),
|
|
16512
|
+
contentSource: unifiedContentSourceSchema2,
|
|
16513
|
+
capabilityCeiling: external_exports2.array(unifiedCapabilitySchema2).min(2),
|
|
16514
|
+
credentialRequirement: policyCredentialRequirementV1Schema2,
|
|
16515
|
+
signature: external_exports2.object({ suite: external_exports2.literal("Ed25519"), signerDid: external_exports2.string().min(1), value: external_exports2.string().min(1) }).strict()
|
|
16516
|
+
}).strict();
|
|
16517
|
+
var unifiedPolicySchema2 = external_exports2.discriminatedUnion("schema", [
|
|
16518
|
+
unifiedPolicyV1Schema2,
|
|
16519
|
+
unifiedPolicyV2Schema2
|
|
16746
16520
|
]);
|
|
16747
|
-
var
|
|
16748
|
-
|
|
16749
|
-
|
|
16750
|
-
|
|
16751
|
-
path: external_exports2.string().min(1),
|
|
16752
|
-
action: external_exports2.literal("tinycloud.kv/get")
|
|
16521
|
+
var unifiedRootSchema2 = external_exports2.object({
|
|
16522
|
+
cid: external_exports2.string().min(1),
|
|
16523
|
+
authorization: external_exports2.string().regex(/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/),
|
|
16524
|
+
role: external_exports2.union([external_exports2.literal("policy-authority"), external_exports2.literal("policy-enforcement")])
|
|
16753
16525
|
}).strict();
|
|
16754
|
-
var
|
|
16755
|
-
|
|
16756
|
-
|
|
16757
|
-
|
|
16758
|
-
|
|
16759
|
-
|
|
16760
|
-
|
|
16761
|
-
|
|
16762
|
-
action: external_exports2.literal("tinycloud.sql/read")
|
|
16526
|
+
var attestedEnforcerBindingV2Schema2 = external_exports2.object({
|
|
16527
|
+
schema: external_exports2.literal("xyz.tinycloud.policy/attested-enforcer/v2"),
|
|
16528
|
+
enforcerDid: external_exports2.string().regex(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/),
|
|
16529
|
+
nodeAudience: external_exports2.string().min(1),
|
|
16530
|
+
attestationBindingDigestHex: external_exports2.string().regex(/^[0-9a-f]{64}$/),
|
|
16531
|
+
issuedAt: external_exports2.string().datetime({ offset: true }),
|
|
16532
|
+
expiresAt: external_exports2.string().datetime({ offset: true }),
|
|
16533
|
+
signature: external_exports2.object({ suite: external_exports2.literal("Ed25519"), signerDid: external_exports2.string().min(1), value: base64UrlString2() }).strict()
|
|
16763
16534
|
}).strict();
|
|
16764
|
-
var
|
|
16765
|
-
var v2TargetSchema2 = external_exports2.object({
|
|
16535
|
+
var v3TargetSchema2 = external_exports2.object({
|
|
16766
16536
|
origin: external_exports2.string().refine(isCanonicalHttpsOrigin2, { message: "expected a canonical https origin" }),
|
|
16767
16537
|
nodeAudience: external_exports2.string().min(1),
|
|
16768
16538
|
spaceId: external_exports2.string().refine(isCanonicalPathSegment2, { message: "expected a canonical space id" })
|
|
16769
16539
|
}).strict();
|
|
16770
|
-
var
|
|
16771
|
-
|
|
16772
|
-
|
|
16773
|
-
|
|
16774
|
-
|
|
16775
|
-
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
16779
|
-
|
|
16780
|
-
|
|
16781
|
-
|
|
16782
|
-
|
|
16783
|
-
|
|
16784
|
-
|
|
16785
|
-
|
|
16786
|
-
|
|
16787
|
-
|
|
16788
|
-
|
|
16789
|
-
|
|
16790
|
-
encoding: external_exports2.literal("utf-8").optional(),
|
|
16791
|
-
/** Encrypted presentation discriminator. The fixed entry point is index.html. */
|
|
16792
|
-
artifact: external_exports2.literal("html").optional()
|
|
16540
|
+
var unsignedShareEnvelopeV3BaseSchema2 = external_exports2.object({
|
|
16541
|
+
version: external_exports2.literal(3),
|
|
16542
|
+
shareId: external_exports2.string().min(1),
|
|
16543
|
+
recipientMatcher: recipientMatcherSchema2,
|
|
16544
|
+
deliveryEmail: deliveryEmailSchema2.optional(),
|
|
16545
|
+
actions: external_exports2.array(shareActionSchema2).min(1).max(3),
|
|
16546
|
+
resource: resourceSelectorSchema2,
|
|
16547
|
+
target: v3TargetSchema2,
|
|
16548
|
+
policy: unifiedPolicySchema2,
|
|
16549
|
+
policyCid: external_exports2.string().min(1),
|
|
16550
|
+
policyRoot: unifiedRootSchema2,
|
|
16551
|
+
enforcementRoot: unifiedRootSchema2,
|
|
16552
|
+
attestedEnforcerBinding: attestedEnforcerBindingV2Schema2,
|
|
16553
|
+
contentSource: unifiedContentSourceSchema2,
|
|
16554
|
+
contentSourceDigestHex: external_exports2.string().regex(/^[0-9a-f]{64}$/),
|
|
16555
|
+
encryptionNetwork: unifiedEncryptionNetworkSchema2,
|
|
16556
|
+
expiry: external_exports2.string().datetime({ offset: true }),
|
|
16557
|
+
display: displaySchema2,
|
|
16558
|
+
encrypted: external_exports2.literal(true),
|
|
16559
|
+
metadata: contentMetadataSchema2
|
|
16793
16560
|
}).strict();
|
|
16794
|
-
|
|
16795
|
-
|
|
16796
|
-
|
|
16561
|
+
function validateV3Invariants2(value, ctx) {
|
|
16562
|
+
const actions = [...value.actions];
|
|
16563
|
+
if (new Set(actions).size !== actions.length || actions.some((action, index) => action !== ["read", "list", "edit"].filter((candidate) => actions.includes(candidate))[index])) {
|
|
16564
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["actions"], message: "actions must be unique and canonically ordered" });
|
|
16565
|
+
}
|
|
16566
|
+
if (value.policyRoot.role !== "policy-authority" || value.enforcementRoot.role !== "policy-enforcement") {
|
|
16567
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policyRoot", "role"], message: "root roles are fixed" });
|
|
16568
|
+
}
|
|
16569
|
+
if (value.policyCid.length === 0 || value.policyCid === value.policyRoot.cid || value.policyCid === value.enforcementRoot.cid) {
|
|
16570
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policyCid"], message: "policy CID must be distinct from both roots" });
|
|
16571
|
+
}
|
|
16572
|
+
if (value.contentSource.encryptionNetwork !== value.encryptionNetwork) {
|
|
16573
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["encryptionNetwork"], message: "encryption network is not bound to the source" });
|
|
16574
|
+
}
|
|
16575
|
+
if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
|
|
16576
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
|
|
16577
|
+
}
|
|
16578
|
+
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) {
|
|
16579
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
|
|
16580
|
+
}
|
|
16581
|
+
if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
|
|
16582
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
|
|
16583
|
+
}
|
|
16584
|
+
const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
|
|
16585
|
+
const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === value.encryptionNetwork && capability.action === "tinycloud.encryption/decrypt");
|
|
16586
|
+
if (value.policy.capabilityCeiling.length !== 2 || kvCapabilities.length !== 1 || decryptCapabilities.length !== 1 || kvCapabilities[0]?.resource !== value.contentSource.kvResource || kvCapabilities[0]?.selector !== value.contentSource.selector) {
|
|
16587
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain exact decrypt network" });
|
|
16588
|
+
}
|
|
16589
|
+
}
|
|
16590
|
+
var unsignedShareEnvelopeV3Schema2 = unsignedShareEnvelopeV3BaseSchema2.superRefine(validateV3Invariants2);
|
|
16591
|
+
var shareEnvelopeV3Schema2 = unsignedShareEnvelopeV3BaseSchema2.extend({ signature: signatureSchema2 }).strict().superRefine(validateV3Invariants2);
|
|
16592
|
+
var ENVELOPE_AAD_LABEL2 = "tinycloud-share-envelope-v1";
|
|
16593
|
+
var AAD2 = utf8Bytes2(ENVELOPE_AAD_LABEL2);
|
|
16594
|
+
function isPlainRecord2(value) {
|
|
16595
|
+
const proto = Object.getPrototypeOf(value);
|
|
16596
|
+
return proto === Object.prototype || proto === null;
|
|
16597
|
+
}
|
|
16598
|
+
function assertNoLoneSurrogates2(text) {
|
|
16599
|
+
for (let i = 0; i < text.length; i++) {
|
|
16600
|
+
const unit = text.charCodeAt(i);
|
|
16601
|
+
if (unit >= 56320 && unit <= 57343) {
|
|
16602
|
+
throw new TypeError(
|
|
16603
|
+
`cannot canonicalize string with unpaired low surrogate at index ${i}`
|
|
16604
|
+
);
|
|
16605
|
+
}
|
|
16606
|
+
if (unit >= 55296 && unit <= 56319) {
|
|
16607
|
+
const next = text.charCodeAt(i + 1);
|
|
16608
|
+
if (!(next >= 56320 && next <= 57343)) {
|
|
16609
|
+
throw new TypeError(
|
|
16610
|
+
`cannot canonicalize string with unpaired high surrogate at index ${i}`
|
|
16611
|
+
);
|
|
16612
|
+
}
|
|
16613
|
+
i++;
|
|
16614
|
+
}
|
|
16615
|
+
}
|
|
16616
|
+
}
|
|
16617
|
+
function serializeString2(text) {
|
|
16618
|
+
assertNoLoneSurrogates2(text);
|
|
16619
|
+
return JSON.stringify(text);
|
|
16620
|
+
}
|
|
16621
|
+
function serialize2(value) {
|
|
16622
|
+
if (value === null) return "null";
|
|
16623
|
+
switch (typeof value) {
|
|
16624
|
+
case "boolean":
|
|
16625
|
+
return JSON.stringify(value);
|
|
16626
|
+
case "string":
|
|
16627
|
+
return serializeString2(value);
|
|
16628
|
+
case "number":
|
|
16629
|
+
if (!Number.isFinite(value)) {
|
|
16630
|
+
throw new TypeError(`cannot canonicalize non-finite number: ${value}`);
|
|
16631
|
+
}
|
|
16632
|
+
return JSON.stringify(value);
|
|
16633
|
+
case "object":
|
|
16634
|
+
break;
|
|
16635
|
+
default:
|
|
16636
|
+
throw new TypeError(`cannot canonicalize value of type ${typeof value}`);
|
|
16637
|
+
}
|
|
16638
|
+
if (Array.isArray(value)) {
|
|
16639
|
+
return `[${value.map((item) => serialize2(item)).join(",")}]`;
|
|
16640
|
+
}
|
|
16641
|
+
if (!isPlainRecord2(value)) {
|
|
16642
|
+
throw new TypeError("cannot canonicalize non-plain object");
|
|
16643
|
+
}
|
|
16644
|
+
const keys = Object.keys(value).sort();
|
|
16645
|
+
const members = [];
|
|
16646
|
+
for (const key of keys) {
|
|
16647
|
+
const member = value[key];
|
|
16648
|
+
if (member === void 0) continue;
|
|
16649
|
+
members.push(`${serializeString2(key)}:${serialize2(member)}`);
|
|
16650
|
+
}
|
|
16651
|
+
return `{${members.join(",")}}`;
|
|
16652
|
+
}
|
|
16653
|
+
function canonicalize2(value) {
|
|
16654
|
+
return serialize2(value);
|
|
16655
|
+
}
|
|
16656
|
+
var LABEL2 = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
16657
|
+
function isCanonicalEmailDomain2(value) {
|
|
16658
|
+
if (value.length === 0 || value.length > 253) return false;
|
|
16659
|
+
const labels = value.split(".");
|
|
16660
|
+
return labels.length >= 2 && labels.every((label) => LABEL2.test(label)) && !/^[0-9]+$/.test(labels.at(-1));
|
|
16661
|
+
}
|
|
16662
|
+
function canonicalMailbox2(value) {
|
|
16663
|
+
const email = value.trim().toLowerCase();
|
|
16664
|
+
const at = email.indexOf("@");
|
|
16665
|
+
if (at <= 0 || at !== email.lastIndexOf("@")) return void 0;
|
|
16666
|
+
const local = email.slice(0, at);
|
|
16667
|
+
const domain = email.slice(at + 1);
|
|
16668
|
+
if (local.length > 64 || !/^[a-z0-9#$&'*+/=?^_`{|}~-]+(?:\.[a-z0-9#$&'*+/=?^_`{|}~-]+)*$/.test(local) || !isCanonicalEmailDomain2(domain)) return void 0;
|
|
16669
|
+
return Object.freeze({ email, domain });
|
|
16670
|
+
}
|
|
16671
|
+
var MAX_INLINE_BYTES2 = 256 * 1024;
|
|
16672
|
+
|
|
16673
|
+
// src/commands/share.ts
|
|
16674
|
+
import { ProfileLockTimeoutError as ProfileLockTimeoutError2 } from "@tinycloud/operations/state";
|
|
16675
|
+
|
|
16676
|
+
// src/lib/duration.ts
|
|
16677
|
+
function parseDuration(input) {
|
|
16678
|
+
const match = input.match(/^(\d+)(m|h|d|w)$/);
|
|
16679
|
+
if (match) {
|
|
16680
|
+
const value = parseInt(match[1], 10);
|
|
16681
|
+
const unit = match[2];
|
|
16682
|
+
const multipliers = {
|
|
16683
|
+
m: 60 * 1e3,
|
|
16684
|
+
h: 60 * 60 * 1e3,
|
|
16685
|
+
d: 24 * 60 * 60 * 1e3,
|
|
16686
|
+
w: 7 * 24 * 60 * 60 * 1e3
|
|
16687
|
+
};
|
|
16688
|
+
return value * multipliers[unit];
|
|
16689
|
+
}
|
|
16690
|
+
const date = new Date(input);
|
|
16691
|
+
if (!isNaN(date.getTime())) {
|
|
16692
|
+
const ms = date.getTime() - Date.now();
|
|
16693
|
+
if (ms <= 0) {
|
|
16694
|
+
throw new Error(`Expiry date "${input}" is in the past`);
|
|
16695
|
+
}
|
|
16696
|
+
return ms;
|
|
16697
|
+
}
|
|
16698
|
+
throw new Error(`Invalid duration: "${input}". Use format like "1h", "7d", or an ISO date.`);
|
|
16699
|
+
}
|
|
16700
|
+
|
|
16701
|
+
// src/commands/share.ts
|
|
16702
|
+
init_formatter();
|
|
16703
|
+
init_errors();
|
|
16704
|
+
|
|
16705
|
+
// src/share/output.ts
|
|
16706
|
+
function writeJson2(value) {
|
|
16707
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
16708
|
+
`);
|
|
16709
|
+
}
|
|
16710
|
+
function authorizationRequiredJson(result) {
|
|
16711
|
+
return {
|
|
16712
|
+
state: "authorization-required",
|
|
16713
|
+
method: result.method,
|
|
16714
|
+
next: "complete authorization through the configured authority adapter, then retry with the required proof"
|
|
16715
|
+
};
|
|
16716
|
+
}
|
|
16717
|
+
function publishHuman(result) {
|
|
16718
|
+
process.stdout.write(`${result.url}
|
|
16719
|
+
`);
|
|
16720
|
+
}
|
|
16721
|
+
function inspectHuman(result) {
|
|
16722
|
+
const metadata = result.metadata;
|
|
16723
|
+
process.stdout.write([
|
|
16724
|
+
`Share ${metadata.shareId}`,
|
|
16725
|
+
`File: ${metadata.display.filename ?? "unnamed"}`,
|
|
16726
|
+
`Target: ${metadata.target.kind === "bearer" ? "bearer (anyone with the complete link can read)" : metadata.target.kind}`,
|
|
16727
|
+
`Expires: ${metadata.expiresAt}`,
|
|
16728
|
+
`Resource: ${metadata.resource.path}`,
|
|
16729
|
+
`Link format: ${result.link.kind}`
|
|
16730
|
+
].join("\n") + "\n");
|
|
16731
|
+
}
|
|
16732
|
+
function receiveHuman(path) {
|
|
16733
|
+
process.stdout.write(`${path}
|
|
16734
|
+
`);
|
|
16797
16735
|
}
|
|
16798
|
-
|
|
16799
|
-
version:
|
|
16800
|
-
shareId: external_exports2.string().min(1),
|
|
16801
|
-
recipientMatcher: recipientMatcherSchema2,
|
|
16802
|
-
deliveryEmail: deliveryEmailSchema2.optional(),
|
|
16803
|
-
actions: external_exports2.array(shareActionSchema2).min(1).max(3),
|
|
16804
|
-
resource: resourceSelectorSchema2,
|
|
16805
|
-
target: v2TargetSchema2,
|
|
16806
|
-
delegationCid: external_exports2.string().min(1),
|
|
16807
|
-
authorityMaterialHandle: external_exports2.string().min(1),
|
|
16808
|
-
authorityMaterialDigest: external_exports2.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
16809
|
-
decryption: shareDecryptionSchema2.optional(),
|
|
16810
|
-
contentSource: contentSourceSchema2,
|
|
16811
|
-
contentSourceDigest: external_exports2.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
16812
|
-
authorizationTarget: authorizationTargetSchema2,
|
|
16813
|
-
display: displaySchema2,
|
|
16814
|
-
expiry: external_exports2.string().datetime(),
|
|
16815
|
-
encrypted: external_exports2.boolean(),
|
|
16816
|
-
content: contentPointerSchema2.optional(),
|
|
16817
|
-
metadata: contentMetadataSchema2,
|
|
16818
|
-
ownerAuthority: ownerAuthoritySchema2.optional()
|
|
16819
|
-
}).strict();
|
|
16820
|
-
function validateV2Invariants2(value, ctx) {
|
|
16821
|
-
const actions = [...value.actions];
|
|
16822
|
-
if (new Set(actions).size !== actions.length) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["actions"], message: "actions must be unique" });
|
|
16823
|
-
if (actions.some((action, index) => action !== ["read", "list", "edit"].filter((candidate) => actions.includes(candidate))[index])) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["actions"], message: "actions must be canonically ordered" });
|
|
16824
|
-
if (!value.encrypted && value.recipientMatcher.kind !== "policyDigest") ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["recipientMatcher"], message: "safe plaintext must carry only a matcher digest" });
|
|
16825
|
-
if (!value.encrypted && value.authorizationTarget.kind !== "policy") ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["encrypted"], message: "unencrypted content requires a policy target" });
|
|
16826
|
-
if (!value.encrypted && value.content !== void 0) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["content"], message: "policy-only plaintext cannot carry content" });
|
|
16827
|
-
if (value.encrypted && (value.metadata.mediaType === void 0 || value.metadata.filename === void 0 || value.metadata.byteLength === void 0)) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["metadata"], message: "encrypted shares must describe their content" });
|
|
16828
|
-
if (!value.encrypted && Object.keys(value.metadata).length !== 0) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["metadata"], message: "policy-only plaintext cannot describe content" });
|
|
16829
|
-
if (!value.encrypted && value.metadata.encoding !== void 0) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["metadata", "encoding"], message: "policy-only plaintext cannot carry content encoding" });
|
|
16830
|
-
if (value.metadata.artifact === "html" && (!value.encrypted || value.resource.kind !== "prefix" || !value.actions.includes("read") || !value.actions.includes("list"))) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["metadata", "artifact"], message: "html artifacts require an encrypted readable prefix" });
|
|
16831
|
-
if (!value.encrypted && (value.display.senderName !== void 0 || value.display.filename !== void 0 || value.display.recipientHint !== void 0)) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["display"], message: "policy-only plaintext cannot carry display metadata" });
|
|
16832
|
-
if (!value.encrypted && value.deliveryEmail !== void 0) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["deliveryEmail"], message: "policy-only plaintext cannot carry delivery metadata" });
|
|
16833
|
-
if (value.recipientMatcher.kind === "exactEmail" && value.deliveryEmail !== void 0 && value.deliveryEmail !== value.recipientMatcher.value) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["deliveryEmail"], message: "delivery email must match the exact matcher" });
|
|
16834
|
-
if (value.recipientMatcher.kind === "emailDomain" && value.deliveryEmail !== void 0 && value.deliveryEmail.toLowerCase().endsWith(`@${value.recipientMatcher.value}`) === false) ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["deliveryEmail"], message: "delivery email must belong to the matcher domain" });
|
|
16835
|
-
if (value.contentSource.kind === "kv" && value.contentSource.action !== "tinycloud.kv/get") ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource"], message: "source action mismatch" });
|
|
16836
|
-
if (value.contentSource.kind === "sql" && value.contentSource.action !== "tinycloud.sql/read") ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource"], message: "source action mismatch" });
|
|
16736
|
+
function receiveJson(result, path) {
|
|
16737
|
+
writeJson2({ protocol: "tinycloud-share", version: 1, path, metadata: result.metadata });
|
|
16837
16738
|
}
|
|
16838
|
-
|
|
16839
|
-
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
-
|
|
16843
|
-
|
|
16844
|
-
|
|
16845
|
-
|
|
16846
|
-
|
|
16847
|
-
|
|
16848
|
-
|
|
16849
|
-
|
|
16850
|
-
|
|
16851
|
-
const
|
|
16852
|
-
|
|
16853
|
-
|
|
16854
|
-
|
|
16855
|
-
|
|
16856
|
-
}
|
|
16857
|
-
|
|
16858
|
-
|
|
16859
|
-
|
|
16860
|
-
|
|
16861
|
-
|
|
16862
|
-
|
|
16863
|
-
|
|
16864
|
-
|
|
16865
|
-
|
|
16866
|
-
|
|
16867
|
-
}
|
|
16868
|
-
|
|
16869
|
-
|
|
16870
|
-
|
|
16871
|
-
|
|
16872
|
-
|
|
16873
|
-
|
|
16874
|
-
|
|
16875
|
-
|
|
16876
|
-
|
|
16877
|
-
|
|
16878
|
-
|
|
16879
|
-
|
|
16880
|
-
|
|
16881
|
-
|
|
16882
|
-
|
|
16883
|
-
|
|
16884
|
-
|
|
16885
|
-
|
|
16886
|
-
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
|
|
16890
|
-
|
|
16891
|
-
|
|
16892
|
-
|
|
16893
|
-
|
|
16894
|
-
|
|
16895
|
-
|
|
16896
|
-
|
|
16897
|
-
|
|
16898
|
-
|
|
16899
|
-
|
|
16900
|
-
|
|
16901
|
-
|
|
16902
|
-
|
|
16903
|
-
})
|
|
16904
|
-
|
|
16905
|
-
|
|
16906
|
-
|
|
16907
|
-
|
|
16908
|
-
|
|
16909
|
-
|
|
16910
|
-
|
|
16911
|
-
|
|
16912
|
-
|
|
16913
|
-
|
|
16914
|
-
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
16920
|
-
|
|
16921
|
-
|
|
16922
|
-
|
|
16923
|
-
|
|
16924
|
-
|
|
16925
|
-
|
|
16926
|
-
|
|
16927
|
-
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
|
|
16931
|
-
|
|
16932
|
-
|
|
16933
|
-
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
|
|
16937
|
-
}
|
|
16938
|
-
|
|
16939
|
-
|
|
16940
|
-
|
|
16941
|
-
|
|
16942
|
-
|
|
16943
|
-
|
|
16944
|
-
|
|
16945
|
-
|
|
16946
|
-
|
|
16947
|
-
|
|
16948
|
-
|
|
16949
|
-
|
|
16950
|
-
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
16955
|
-
|
|
16956
|
-
|
|
16957
|
-
|
|
16958
|
-
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
|
|
16739
|
+
|
|
16740
|
+
// src/share/io.ts
|
|
16741
|
+
import { constants } from "fs";
|
|
16742
|
+
import { lstat as lstat2, mkdir as mkdir2, mkdtemp, open as open2, readFile as readFile2, realpath, stat as stat2, link, rename as rename2, rm as rm3, unlink } from "fs/promises";
|
|
16743
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
16744
|
+
import { basename as basename2, join as join4, resolve, sep } from "path";
|
|
16745
|
+
init_errors();
|
|
16746
|
+
var MAX_SHARE_STDIN_BYTES = 100 * 1024 * 1024;
|
|
16747
|
+
var MAX_SHARE_URL_BYTES = 64 * 1024;
|
|
16748
|
+
async function readBoundedStdin(limit = MAX_SHARE_STDIN_BYTES) {
|
|
16749
|
+
if (!Number.isSafeInteger(limit) || limit <= 0) throw new Error("MAX_BYTES_EXCEEDED");
|
|
16750
|
+
const chunks = [];
|
|
16751
|
+
let total = 0;
|
|
16752
|
+
for await (const chunk of process.stdin) {
|
|
16753
|
+
const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
16754
|
+
total += bytes.byteLength;
|
|
16755
|
+
if (total > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
16756
|
+
chunks.push(bytes);
|
|
16757
|
+
}
|
|
16758
|
+
return new Uint8Array(Buffer.concat(chunks, total));
|
|
16759
|
+
}
|
|
16760
|
+
async function readBoundedUrlStdin() {
|
|
16761
|
+
const bytes = await readBoundedStdin(MAX_SHARE_URL_BYTES);
|
|
16762
|
+
const value = new TextDecoder("utf-8", { fatal: true }).decode(bytes).trim();
|
|
16763
|
+
if (value.length === 0 || /\s/.test(value)) throw new Error("INVALID_ARGUMENT");
|
|
16764
|
+
return value;
|
|
16765
|
+
}
|
|
16766
|
+
function safeFilename(value) {
|
|
16767
|
+
return shareFilename(value);
|
|
16768
|
+
}
|
|
16769
|
+
function shareFilename(value) {
|
|
16770
|
+
try {
|
|
16771
|
+
return canonicalShareFilename(value);
|
|
16772
|
+
} catch {
|
|
16773
|
+
throw new CLIError(
|
|
16774
|
+
"UNSAFE_FILENAME",
|
|
16775
|
+
hasUnsafeFilenameCodePoint(value) ? "filename contains control or invisible characters" : "filename must be one safe path segment",
|
|
16776
|
+
8
|
|
16777
|
+
);
|
|
16778
|
+
}
|
|
16779
|
+
}
|
|
16780
|
+
function shareInputFilename(input, name) {
|
|
16781
|
+
return shareFilename(name ?? (input === "-" ? "stdin.md" : basename2(resolve(input))));
|
|
16782
|
+
}
|
|
16783
|
+
async function readShareInput(input, name, limit = MAX_SHARE_STDIN_BYTES) {
|
|
16784
|
+
const filename = shareInputFilename(input, name);
|
|
16785
|
+
if (input === "-") return { bytes: await readBoundedStdin(limit), filename };
|
|
16786
|
+
const path = resolve(input);
|
|
16787
|
+
const info = await stat2(path);
|
|
16788
|
+
if (!info.isFile() || info.size > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
16789
|
+
const bytes = new Uint8Array(await readFile2(path));
|
|
16790
|
+
if (bytes.byteLength > limit) throw new Error("MAX_BYTES_EXCEEDED");
|
|
16791
|
+
return { bytes, filename };
|
|
16792
|
+
}
|
|
16793
|
+
async function assertDirectory(path) {
|
|
16794
|
+
const absolute = resolve(path);
|
|
16795
|
+
const segments = absolute.split(sep).filter(Boolean);
|
|
16796
|
+
let current = absolute.startsWith(sep) ? sep : "";
|
|
16797
|
+
for (const segment of segments) {
|
|
16798
|
+
current = current === sep ? join4(current, segment) : join4(current, segment);
|
|
16799
|
+
try {
|
|
16800
|
+
const info = await lstat2(current);
|
|
16801
|
+
if (info.isSymbolicLink()) {
|
|
16802
|
+
const canonical = await realpath(current);
|
|
16803
|
+
if (current !== "/tmp" && current !== "/var") throw new Error("OUTPUT_EXISTS");
|
|
16804
|
+
if (canonical !== `/private${current}`) throw new Error("OUTPUT_EXISTS");
|
|
16805
|
+
} else if (!info.isDirectory()) throw new Error("OUTPUT_EXISTS");
|
|
16806
|
+
} catch (error) {
|
|
16807
|
+
if (error.code !== "ENOENT") throw error;
|
|
16808
|
+
await mkdir2(current, { mode: 448 });
|
|
16809
|
+
const created = await lstat2(current);
|
|
16810
|
+
if (created.isSymbolicLink() || !created.isDirectory()) throw new Error("OUTPUT_EXISTS");
|
|
16811
|
+
}
|
|
16812
|
+
}
|
|
16813
|
+
}
|
|
16814
|
+
async function writeShareOutput(directory, filename, bytes, force) {
|
|
16815
|
+
const outputDirectory = resolve(directory);
|
|
16816
|
+
await assertDirectory(outputDirectory);
|
|
16817
|
+
const safeName = safeFilename(filename);
|
|
16818
|
+
const directoryHandle = await open2(outputDirectory, constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0));
|
|
16819
|
+
const stableDirectory = await realpath(outputDirectory);
|
|
16820
|
+
const outputPath = join4(stableDirectory, safeName);
|
|
16821
|
+
const directoryIdentity = await directoryHandle.stat();
|
|
16822
|
+
const assertStableDirectory = async () => {
|
|
16823
|
+
const current = await stat2(stableDirectory);
|
|
16824
|
+
if (current.dev !== directoryIdentity.dev || current.ino !== directoryIdentity.ino) throw new Error("OUTPUT_EXISTS");
|
|
16825
|
+
};
|
|
16826
|
+
await assertStableDirectory();
|
|
16827
|
+
const stagingDirectory = await mkdtemp(join4(stableDirectory, ".tinycloud-share-stage-"));
|
|
16828
|
+
const stagingInfo = await lstat2(stagingDirectory);
|
|
16829
|
+
if (!stagingInfo.isDirectory() || (stagingInfo.mode & 511) !== 448) throw new Error("OUTPUT_EXISTS");
|
|
16830
|
+
const stagingPath = join4(stagingDirectory, `.tinycloud-share-${randomBytes2(16).toString("hex")}.tmp`);
|
|
16831
|
+
let temporaryPath;
|
|
16832
|
+
let handle;
|
|
16833
|
+
try {
|
|
16834
|
+
await assertStableDirectory();
|
|
16835
|
+
try {
|
|
16836
|
+
const existing = await lstat2(outputPath);
|
|
16837
|
+
if (existing.isSymbolicLink()) throw new Error("UNSAFE_FILENAME");
|
|
16838
|
+
} catch (error) {
|
|
16839
|
+
if (error.code !== "ENOENT") throw error;
|
|
16840
|
+
}
|
|
16841
|
+
temporaryPath = stagingPath;
|
|
16842
|
+
handle = await open2(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0), 384);
|
|
16843
|
+
await handle.writeFile(bytes);
|
|
16844
|
+
await handle.close();
|
|
16845
|
+
handle = void 0;
|
|
16846
|
+
await assertStableDirectory();
|
|
16847
|
+
if (force) {
|
|
16848
|
+
await rename2(temporaryPath, outputPath);
|
|
16849
|
+
} else {
|
|
16850
|
+
await link(temporaryPath, outputPath);
|
|
16851
|
+
await unlink(temporaryPath);
|
|
16852
|
+
}
|
|
16853
|
+
await assertStableDirectory();
|
|
16854
|
+
} catch (error) {
|
|
16855
|
+
if (error.code === "EEXIST") throw new Error("OUTPUT_EXISTS");
|
|
16856
|
+
if (error.code === "ELOOP") throw new Error("UNSAFE_FILENAME");
|
|
16857
|
+
throw error;
|
|
16858
|
+
} finally {
|
|
16859
|
+
await handle?.close();
|
|
16860
|
+
try {
|
|
16861
|
+
if (temporaryPath !== void 0) await unlink(temporaryPath);
|
|
16862
|
+
} catch {
|
|
16863
|
+
}
|
|
16864
|
+
await rm3(stagingDirectory, { recursive: true, force: true });
|
|
16865
|
+
await directoryHandle.close();
|
|
16963
16866
|
}
|
|
16964
|
-
|
|
16965
|
-
|
|
16867
|
+
return join4(outputDirectory, safeName);
|
|
16868
|
+
}
|
|
16869
|
+
|
|
16870
|
+
// src/share/errors.ts
|
|
16871
|
+
var SharePublishAuthorityError = class extends Error {
|
|
16872
|
+
constructor(failure) {
|
|
16873
|
+
super(failure.kind);
|
|
16874
|
+
this.failure = failure;
|
|
16875
|
+
this.name = "SharePublishAuthorityError";
|
|
16966
16876
|
}
|
|
16967
|
-
|
|
16968
|
-
|
|
16877
|
+
};
|
|
16878
|
+
var ShareHistoryRetryError = class extends Error {
|
|
16879
|
+
constructor(profile) {
|
|
16880
|
+
super("sender history changed during the operation");
|
|
16881
|
+
this.profile = profile;
|
|
16882
|
+
this.name = "ShareHistoryRetryError";
|
|
16969
16883
|
}
|
|
16970
|
-
|
|
16971
|
-
|
|
16884
|
+
code = "SHARE_HISTORY_RETRY";
|
|
16885
|
+
};
|
|
16886
|
+
|
|
16887
|
+
// src/commands/share.ts
|
|
16888
|
+
var SHARE_ORIGIN = "https://share.tinycloud.xyz";
|
|
16889
|
+
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";
|
|
16890
|
+
var shareServices = {};
|
|
16891
|
+
function configureShareCommandServices(services) {
|
|
16892
|
+
shareServices = services;
|
|
16893
|
+
}
|
|
16894
|
+
function parseShareTarget(value) {
|
|
16895
|
+
if (value === "anyone" || value === "bearer") return { kind: "bearer" };
|
|
16896
|
+
if (value.startsWith("did:")) return { kind: "recipientDid", did: value };
|
|
16897
|
+
if (value.startsWith("domain:")) return canonicalMailboxTarget({ kind: "emailDomain", domain: value.slice("domain:".length) });
|
|
16898
|
+
if (value.startsWith("email:")) return canonicalMailboxTarget({ kind: "email", address: value.slice("email:".length) });
|
|
16899
|
+
if (value.includes("@")) return canonicalMailboxTarget({ kind: "email", address: value });
|
|
16900
|
+
throw new CLIError("INVALID_ARGUMENT", "--to must be anyone, a did:, an email address, or domain:example.com", 2);
|
|
16901
|
+
}
|
|
16902
|
+
function canonicalMailboxTarget(target) {
|
|
16903
|
+
try {
|
|
16904
|
+
return normalizeShareTarget(target);
|
|
16905
|
+
} catch (error) {
|
|
16906
|
+
throw new CLIError("INVALID_ARGUMENT", error instanceof TypeError ? error.message : "share recipient is invalid", 2);
|
|
16972
16907
|
}
|
|
16973
|
-
|
|
16974
|
-
|
|
16908
|
+
}
|
|
16909
|
+
function shareCliError(error, operation = "publish") {
|
|
16910
|
+
if (error instanceof CLIError) return error;
|
|
16911
|
+
if (error instanceof ProfileLockTimeoutError2) return wrapError(error);
|
|
16912
|
+
if (error instanceof ShareHistoryRetryError) {
|
|
16913
|
+
return new CLIError(
|
|
16914
|
+
"SHARE_HISTORY_RETRY",
|
|
16915
|
+
`sender history for profile ${JSON.stringify(error.profile)} changed or disappeared during this command`,
|
|
16916
|
+
1,
|
|
16917
|
+
{ 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.` }
|
|
16918
|
+
);
|
|
16975
16919
|
}
|
|
16976
|
-
if (
|
|
16977
|
-
|
|
16920
|
+
if (error instanceof SharePublishAuthorityError) {
|
|
16921
|
+
const failure = error.failure;
|
|
16922
|
+
const profileName = "profileName" in failure ? failure.profileName : void 0;
|
|
16923
|
+
const localKey = "localKey" in failure && failure.localKey === true;
|
|
16924
|
+
const profileHint = profileName === void 0 ? "" : `--profile ${profileName} `;
|
|
16925
|
+
const loginHint = localKey ? `\`tc ${profileHint}auth login --method local\`` : `\`tc ${profileHint}auth login --device --manifest builtin:share-publishing\` (or \`tc ${profileHint}enable share\`)`;
|
|
16926
|
+
if (failure.kind === "caveated-session") {
|
|
16927
|
+
const holder = profileName === void 0 ? "this session" : `profile ${profileName}'s session`;
|
|
16928
|
+
return new CLIError(
|
|
16929
|
+
"PERMISSION_DENIED",
|
|
16930
|
+
`${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\``,
|
|
16931
|
+
5
|
|
16932
|
+
);
|
|
16933
|
+
}
|
|
16934
|
+
if (failure.kind === "owner-space-unresolved") {
|
|
16935
|
+
return new CLIError("AUTH_REQUIRED", `a valid signed TinyCloud session is required; run ${loginHint}`, 3);
|
|
16936
|
+
}
|
|
16937
|
+
if (failure.kind === "scope-denied") {
|
|
16938
|
+
const requiredAction = failure.requiredAction === void 0 ? "" : ` (${failure.requiredAction})`;
|
|
16939
|
+
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}`;
|
|
16940
|
+
return new CLIError("PERMISSION_DENIED", `the session lacks ${failure.capability} authority${requiredAction}; ${renew}`, 5);
|
|
16941
|
+
}
|
|
16942
|
+
if (failure.kind === "lifetime-exceeds-session") {
|
|
16943
|
+
const expiresAt = failure.sessionExpiresAt.toISOString();
|
|
16944
|
+
if (failure.reason === "session-too-close") {
|
|
16945
|
+
return new CLIError("AUTH_REQUIRED", `the signed session expires too soon (${expiresAt}); log in again with ${loginHint}`, 3);
|
|
16946
|
+
}
|
|
16947
|
+
if (failure.reason === "below-minimum") {
|
|
16948
|
+
return new CLIError("SESSION_LIFETIME_EXCEEDED", "share expiry must be at least 60 seconds from now; use a longer --expires value", 2);
|
|
16949
|
+
}
|
|
16950
|
+
return new CLIError("SESSION_LIFETIME_EXCEEDED", `requested share lifetime exceeds session expiry ${expiresAt}; use a shorter --expires value or renew the session with ${loginHint}`, 2);
|
|
16951
|
+
}
|
|
16952
|
+
if (failure.kind === "origin-mismatch") {
|
|
16953
|
+
return new CLIError("ORIGIN_MISMATCH", "share origin does not match the configured service", 2);
|
|
16954
|
+
}
|
|
16955
|
+
if (failure.kind === "invalid-request") {
|
|
16956
|
+
return new CLIError("INVALID_ARGUMENT", failure.reason, 2);
|
|
16957
|
+
}
|
|
16958
|
+
if (failure.kind === "registry-unavailable") {
|
|
16959
|
+
return new CLIError("UNAVAILABLE", "the TinyCloud location registry could not be reached, so nothing was shared; try again shortly", 4);
|
|
16960
|
+
}
|
|
16961
|
+
if (failure.kind === "node-info-unavailable") {
|
|
16962
|
+
const outcome = operation === "publish" ? "nothing was shared and no invitation was sent" : "no invitation was sent";
|
|
16963
|
+
return new CLIError("UNAVAILABLE", `could not verify TinyCloud node 1.17.3 domain delivery support; ${outcome}. Check the node and retry`, 4);
|
|
16964
|
+
}
|
|
16965
|
+
if (failure.kind === "registry-rejected") {
|
|
16966
|
+
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);
|
|
16967
|
+
}
|
|
16968
|
+
if (failure.kind === "storage-quota-exceeded") {
|
|
16969
|
+
const sizes = failure.usedBytes === void 0 || failure.limitBytes === void 0 ? "" : ` (${formatBytes(failure.usedBytes)} used of ${formatBytes(failure.limitBytes)} limit)`;
|
|
16970
|
+
return new CLIError("STORAGE_QUOTA_EXCEEDED", `storage quota exceeded${sizes}; nothing was shared`, 4);
|
|
16971
|
+
}
|
|
16972
|
+
if (failure.kind === "upload-failed") {
|
|
16973
|
+
return new CLIError("UPLOAD_FAILED", "share source upload failed; nothing was shared", 4);
|
|
16974
|
+
}
|
|
16978
16975
|
}
|
|
16979
|
-
if (
|
|
16980
|
-
|
|
16976
|
+
if (error instanceof ShareNotifyError) {
|
|
16977
|
+
return new CLIError("INVALID_ARGUMENT", error.message, 2);
|
|
16981
16978
|
}
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
16979
|
+
if (error instanceof SharePublishError) {
|
|
16980
|
+
const exit = error.code === "authority-required" ? 3 : error.code === "max-bytes-exceeded" ? 7 : 2;
|
|
16981
|
+
const code3 = error.code === "authority-required" ? "AUTH_REQUIRED" : error.code === "max-bytes-exceeded" ? "MAX_BYTES_EXCEEDED" : "INVALID_ARGUMENT";
|
|
16982
|
+
return new CLIError(code3, error.message, exit);
|
|
16983
|
+
}
|
|
16984
|
+
if (error instanceof ShareReceiveError) {
|
|
16985
|
+
const verification = /* @__PURE__ */ new Set(["cid-mismatch", "decrypt-failed", "envelope-invalid", "origin-mismatch", "signature-invalid", "capability-invalid", "content-integrity-failed"]);
|
|
16986
|
+
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;
|
|
16987
|
+
const code3 = error.code === "fetch-failed" ? "NOT_FOUND" : error.code.replaceAll("-", "_").toUpperCase();
|
|
16988
|
+
return new CLIError(code3, error.message, exit);
|
|
16986
16989
|
}
|
|
16990
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16991
|
+
const nodeCode = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
16992
|
+
const known = {
|
|
16993
|
+
MAX_BYTES_EXCEEDED: { code: "MAX_BYTES_EXCEEDED", exit: 7 },
|
|
16994
|
+
UNSAFE_FILENAME: { code: "UNSAFE_FILENAME", exit: 8 },
|
|
16995
|
+
OUTPUT_EXISTS: { code: "OUTPUT_EXISTS", exit: 8 },
|
|
16996
|
+
INVALID_ARGUMENT: { code: "INVALID_ARGUMENT", exit: 2 },
|
|
16997
|
+
"share not found": { code: "NOT_FOUND", exit: 4 },
|
|
16998
|
+
AUTH_REQUIRED: { code: "AUTH_REQUIRED", exit: 3 },
|
|
16999
|
+
UNAVAILABLE: { code: "UNAVAILABLE", exit: 4 }
|
|
17000
|
+
};
|
|
17001
|
+
if (nodeCode === "ENOENT") return new CLIError("INVALID_ARGUMENT", "share input was not found", 2);
|
|
17002
|
+
if (nodeCode === "EISDIR") return new CLIError("INVALID_ARGUMENT", "share input must be a Markdown file", 2);
|
|
17003
|
+
if (error instanceof TypeError) return new CLIError("INVALID_ARGUMENT", "share input is invalid", 2);
|
|
17004
|
+
const mapped = typeof nodeCode === "string" && known[nodeCode] !== void 0 ? known[nodeCode] : known[message];
|
|
17005
|
+
return new CLIError(mapped?.code ?? "INVALID_ARGUMENT", mapped ? mapped.code : "share operation failed", mapped?.exit ?? 2);
|
|
16987
17006
|
}
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
function isPlainRecord2(value) {
|
|
16993
|
-
const proto = Object.getPrototypeOf(value);
|
|
16994
|
-
return proto === Object.prototype || proto === null;
|
|
17007
|
+
function inputUrl(value, stdin) {
|
|
17008
|
+
if (stdin || value === "-") return readBoundedUrlStdin();
|
|
17009
|
+
if (value === void 0 || value.length === 0) throw new CLIError("INVALID_ARGUMENT", "a share URL or - is required", 2);
|
|
17010
|
+
return Promise.resolve(value);
|
|
16995
17011
|
}
|
|
16996
|
-
function
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17012
|
+
async function inspectShareInputOnce(value, stdin, expectedOrigin, dependencies = {}) {
|
|
17013
|
+
const link2 = stdin || value === "-" ? await (dependencies.read ?? readBoundedUrlStdin)() : await inputUrl(value, false);
|
|
17014
|
+
try {
|
|
17015
|
+
parseNativeShareUrl(link2);
|
|
17016
|
+
} catch {
|
|
17017
|
+
return (dependencies.inspect ?? inspectShare)(link2, { expectedOrigin });
|
|
17018
|
+
}
|
|
17019
|
+
throw new CLIError("UNSUPPORTED_LINK", "native bearer links are opaque; receive the link to verify access", 2);
|
|
17020
|
+
}
|
|
17021
|
+
function jsonOutput(options, command) {
|
|
17022
|
+
return options.json === true || command.optsWithGlobals().json === true;
|
|
17023
|
+
}
|
|
17024
|
+
function expires(value) {
|
|
17025
|
+
try {
|
|
17026
|
+
return new Date(Date.now() + parseDuration(value));
|
|
17027
|
+
} catch {
|
|
17028
|
+
throw new CLIError("INVALID_ARGUMENT", "invalid expiry duration", 2);
|
|
17029
|
+
}
|
|
17030
|
+
}
|
|
17031
|
+
async function rememberPublishedShare(result) {
|
|
17032
|
+
const record = historyRecordForPublishedShare(result);
|
|
17033
|
+
if (shareServices.records === void 0) return { record, recorded: false };
|
|
17034
|
+
try {
|
|
17035
|
+
await shareServices.records.put(record);
|
|
17036
|
+
return { record, recorded: true };
|
|
17037
|
+
} catch {
|
|
17038
|
+
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");
|
|
17039
|
+
return { record, recorded: false };
|
|
17040
|
+
}
|
|
17041
|
+
}
|
|
17042
|
+
async function notifyRecordedShare(record, recipient, adapter, storage) {
|
|
17043
|
+
const result = await notifyShare({ shareId: record.shareId, recipient, record, adapter, checkDeliveryWindow: true });
|
|
17044
|
+
if (result.state !== "partial-failure" && storage !== void 0) {
|
|
17045
|
+
const mailbox = canonicalMailbox2(recipient).email;
|
|
17046
|
+
if (!record.deliveredRecipients?.includes(mailbox)) {
|
|
17047
|
+
try {
|
|
17048
|
+
if (storage.update === void 0) throw new Error("atomic sender history update is unavailable");
|
|
17049
|
+
const updated = await storage.update(record.shareId, (current) => ({
|
|
17050
|
+
...current,
|
|
17051
|
+
deliveredRecipients: current.deliveredRecipients?.includes(mailbox) ? current.deliveredRecipients : [...current.deliveredRecipients ?? [], mailbox]
|
|
17052
|
+
}));
|
|
17053
|
+
if (updated === void 0) throw new Error("sender history record was removed");
|
|
17054
|
+
} catch {
|
|
17055
|
+
process.stderr.write("Warning: delivery succeeded, but could not record its confirmation in sender history.\n");
|
|
17056
|
+
}
|
|
17057
|
+
}
|
|
17058
|
+
}
|
|
17059
|
+
return result;
|
|
17060
|
+
}
|
|
17061
|
+
function byteLimit(value) {
|
|
17062
|
+
if (value === void 0) return void 0;
|
|
17063
|
+
const parsed = Number(value);
|
|
17064
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0 || parsed > MAX_SHARE_STDIN_BYTES) throw new CLIError("MAX_BYTES_EXCEEDED", "max-bytes must be between 1 and 100 MiB", 7);
|
|
17065
|
+
return parsed;
|
|
17066
|
+
}
|
|
17067
|
+
function mediaTypeFor(filename) {
|
|
17068
|
+
const extension = filename.toLowerCase().split(".").at(-1);
|
|
17069
|
+
return extension === "md" || extension === "markdown" ? "text/markdown" : extension === "txt" ? "text/plain" : extension === "html" || extension === "htm" ? "text/html" : extension === "json" ? "application/json" : extension === "css" ? "text/css" : extension === "js" ? "text/javascript" : "application/octet-stream";
|
|
17070
|
+
}
|
|
17071
|
+
function requestedActions(values) {
|
|
17072
|
+
const actions = values === void 0 || values.length === 0 ? ["read"] : values;
|
|
17073
|
+
if (actions.some((value) => value !== "read" && value !== "list" && value !== "edit")) throw new CLIError("INVALID_ARGUMENT", "--action must be read, list, or edit", 2);
|
|
17074
|
+
return [...new Set(actions)];
|
|
17075
|
+
}
|
|
17076
|
+
function assertAggregateInputLimit(inputs, maxBytes) {
|
|
17077
|
+
const limit = maxBytes ?? MAX_SHARE_STDIN_BYTES;
|
|
17078
|
+
let total = 0;
|
|
17079
|
+
for (const input of inputs) {
|
|
17080
|
+
total += input.bytes.byteLength;
|
|
17081
|
+
if (!Number.isSafeInteger(total) || total > limit) throw new CLIError("MAX_BYTES_EXCEEDED", "combined share input exceeds the configured byte limit", 7);
|
|
17082
|
+
}
|
|
17083
|
+
}
|
|
17084
|
+
function registerShareCommand(program2) {
|
|
17085
|
+
const share = program2.command("share").description("Publish and consume TinyCloud Share links");
|
|
17086
|
+
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) => {
|
|
17087
|
+
try {
|
|
17088
|
+
const json = jsonOutput(options, command);
|
|
17089
|
+
const maxBytes = byteLimit(options.maxBytes);
|
|
17090
|
+
if (files.length === 0 || files.includes("-") && files.length > 1) throw new CLIError("INVALID_ARGUMENT", "stdin must be the only publish input", 2);
|
|
17091
|
+
const name = files.length === 1 ? options.name : void 0;
|
|
17092
|
+
for (const file of files) shareInputFilename(file, name);
|
|
17093
|
+
const inputs = await Promise.all(files.map((file) => readShareInput(file, name, maxBytes)));
|
|
17094
|
+
assertAggregateInputLimit(inputs, maxBytes);
|
|
17095
|
+
const target = parseShareTarget(options.to);
|
|
17096
|
+
const actions = requestedActions(options.action);
|
|
17097
|
+
if (options.prefix && target.kind === "bearer") throw new CLIError("INVALID_ARGUMENT", "--prefix requires an addressed target", 2);
|
|
17098
|
+
if (inputs.length > 1 && target.kind === "bearer") throw new CLIError("UNSUPPORTED_LINK", "multiple files require an addressed target", 2);
|
|
17099
|
+
if (inputs.length > 1 && !options.prefix) throw new CLIError("INVALID_ARGUMENT", "multiple files require --prefix", 2);
|
|
17100
|
+
if (options.notify === true && !actions.includes("read")) throw new CLIError("INVALID_ARGUMENT", "--notify requires the read action; nothing was shared", 2);
|
|
17101
|
+
if (options.notifyTo !== void 0 && (options.notify !== true || target.kind !== "emailDomain")) {
|
|
17102
|
+
throw new CLIError("INVALID_ARGUMENT", "--notify-to requires --to domain:<name> --notify", 2);
|
|
17103
|
+
}
|
|
17104
|
+
let notifyRecipient;
|
|
17105
|
+
if (options.notify === true && target.kind === "email") notifyRecipient = target.address;
|
|
17106
|
+
else if (options.notify === true && target.kind === "emailDomain") {
|
|
17107
|
+
const mailbox = options.notifyTo === void 0 ? void 0 : canonicalMailbox2(options.notifyTo);
|
|
17108
|
+
if (mailbox === void 0 || mailbox.domain !== target.domain) {
|
|
17109
|
+
throw new CLIError("INVALID_ARGUMENT", "--to domain:<name> --notify requires --notify-to <email> at that exact domain (node 1.17.3+)", 2);
|
|
17110
|
+
}
|
|
17111
|
+
notifyRecipient = mailbox.email;
|
|
17112
|
+
} else if (options.notify === true) {
|
|
17113
|
+
throw new CLIError("INVALID_ARGUMENT", "--notify requires an email target, or a domain target with --notify-to on node 1.17.3+", 2);
|
|
17114
|
+
}
|
|
17115
|
+
const result = await publishTargetShare({
|
|
17116
|
+
source: inputs[0].bytes,
|
|
17117
|
+
filename: inputs[0].filename,
|
|
17118
|
+
files: inputs.map((input) => ({ bytes: input.bytes, filename: input.filename, mediaType: mediaTypeFor(input.filename) })),
|
|
17119
|
+
mediaType: options.mediaType ?? mediaTypeFor(inputs[0].filename),
|
|
17120
|
+
allowBinary: options.binary === true,
|
|
17121
|
+
target,
|
|
17122
|
+
resourceKind: options.prefix || inputs.length > 1 ? "prefix" : "exact",
|
|
17123
|
+
actions,
|
|
17124
|
+
expiresAt: expires(options.expires ?? "7d"),
|
|
17125
|
+
expiryWasExplicit: options.expires !== void 0,
|
|
17126
|
+
origin: options.viewerOrigin,
|
|
17127
|
+
...maxBytes === void 0 ? {} : { maxBytes },
|
|
17128
|
+
notify: options.notify === true,
|
|
17129
|
+
targetAdapter: shareServices.targetAdapter
|
|
17130
|
+
});
|
|
17131
|
+
if ("state" in result) {
|
|
17132
|
+
if (json) {
|
|
17133
|
+
writeJson2({ protocol: "tinycloud-share", version: 1, authorization: authorizationRequiredJson(result) });
|
|
17134
|
+
process.exitCode = 6;
|
|
17135
|
+
return;
|
|
17136
|
+
}
|
|
17137
|
+
throw new CLIError(result.method === "openkey-device" ? "DEVICE_AUTH_REQUIRED" : "CLAIM_REQUIRED", "recipient authorization is required; continue through the configured authority adapter", 6);
|
|
17138
|
+
}
|
|
17139
|
+
const { record, recorded } = await rememberPublishedShare(result);
|
|
17140
|
+
let notification;
|
|
17141
|
+
if (notifyRecipient !== void 0) {
|
|
17142
|
+
if (shareServices.delivery === void 0) throw new CLIError("AUTH_REQUIRED", "delivery authority is not configured", 3);
|
|
17143
|
+
notification = await notifyRecordedShare(record, notifyRecipient, shareServices.delivery, recorded ? shareServices.records : void 0);
|
|
17144
|
+
if (notification.state === "partial-failure") process.exitCode = 9;
|
|
17145
|
+
if (notification.reason === "delivery-window-expired") process.stderr.write(NOTIFY_WINDOW_MESSAGE);
|
|
17146
|
+
}
|
|
17147
|
+
if (result.metadata.expiryClamped === true) process.stderr.write(`Share expiry clamped to session expiry (${result.metadata.expiresAt}).
|
|
17148
|
+
`);
|
|
17149
|
+
if (json) writeJson2({ ...redactPublishedShare(result), expiryClamped: result.metadata.expiryClamped === true, ...notification === void 0 ? {} : { notification } });
|
|
17150
|
+
else publishHuman(result);
|
|
17151
|
+
} catch (error) {
|
|
17152
|
+
handleError(shareCliError(error));
|
|
17003
17153
|
}
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
|
|
17009
|
-
|
|
17154
|
+
});
|
|
17155
|
+
share.command("inspect [url]").description("Verify a share link and print safe metadata").option("--stdin", "Read the complete URL from stdin").option("--json", "Print versioned redacted JSON").option("--viewer-origin <origin>", "Require this canonical Share origin", SHARE_ORIGIN).action(async (url, options, command) => {
|
|
17156
|
+
try {
|
|
17157
|
+
const json = jsonOutput(options, command);
|
|
17158
|
+
const result = await inspectShareInputOnce(url, options.stdin === true, options.viewerOrigin);
|
|
17159
|
+
if (json) writeJson2(result);
|
|
17160
|
+
else inspectHuman(result);
|
|
17161
|
+
} catch (error) {
|
|
17162
|
+
handleError(shareCliError(error));
|
|
17163
|
+
}
|
|
17164
|
+
});
|
|
17165
|
+
share.command("receive [url]").description("Verify and receive a share link").option("--stdin", "Read the complete URL from stdin").option("--output <directory>", "Create the file in this directory").option("--stdout", "Write verified plaintext bytes to stdout").option("--force", "Allow replacing an existing non-symlink output").option("--max-bytes <bytes>", "Bound received content bytes").option("--json", "Print versioned redacted JSON").option("--viewer-origin <origin>", "Require this canonical Share origin", SHARE_ORIGIN).action(async (url, options, command) => {
|
|
17166
|
+
try {
|
|
17167
|
+
const json = jsonOutput(options, command);
|
|
17168
|
+
if (options.stdout && json) throw new CLIError("INVALID_ARGUMENT", "--stdout and --json are mutually exclusive", 2);
|
|
17169
|
+
const maxBytes = byteLimit(options.maxBytes);
|
|
17170
|
+
const link2 = await inputUrl(url, options.stdin === true);
|
|
17171
|
+
let nativeLink = false;
|
|
17172
|
+
try {
|
|
17173
|
+
parseNativeShareUrl(link2);
|
|
17174
|
+
nativeLink = true;
|
|
17175
|
+
} catch {
|
|
17010
17176
|
}
|
|
17011
|
-
|
|
17177
|
+
if (nativeLink) {
|
|
17178
|
+
if (shareServices.nativeReader === void 0) throw new CLIError("AUTH_REQUIRED", "native TinyCloud receive is not configured", 3);
|
|
17179
|
+
const native = await shareServices.nativeReader(link2);
|
|
17180
|
+
if (maxBytes !== void 0 && native.bytes.byteLength > maxBytes) throw new CLIError("MAX_BYTES_EXCEEDED", "shared content exceeds max-bytes", 7);
|
|
17181
|
+
if (options.stdout) {
|
|
17182
|
+
process.stdout.write(Buffer.from(native.bytes));
|
|
17183
|
+
return;
|
|
17184
|
+
}
|
|
17185
|
+
const output2 = await writeShareOutput(options.output ?? ".", native.filename, native.bytes, options.force === true);
|
|
17186
|
+
if (json) writeJson2({ protocol: "tinycloud-share", version: 1, path: output2, transport: "native" });
|
|
17187
|
+
else receiveHuman(output2);
|
|
17188
|
+
return;
|
|
17189
|
+
}
|
|
17190
|
+
const result = await receiveShare(link2, {
|
|
17191
|
+
expectedOrigin: options.viewerOrigin,
|
|
17192
|
+
...maxBytes === void 0 ? {} : { maxContentBlobBytes: maxBytes }
|
|
17193
|
+
});
|
|
17194
|
+
if ("state" in result) {
|
|
17195
|
+
if (json) {
|
|
17196
|
+
writeJson2({ protocol: "tinycloud-share", version: 1, authorization: authorizationRequiredJson(result) });
|
|
17197
|
+
process.exitCode = 6;
|
|
17198
|
+
return;
|
|
17199
|
+
}
|
|
17200
|
+
throw new CLIError(result.method === "openkey-device" ? "DEVICE_AUTH_REQUIRED" : "CLAIM_REQUIRED", "recipient authorization is required; resume through the configured authority adapter", 6);
|
|
17201
|
+
}
|
|
17202
|
+
if (options.stdout) {
|
|
17203
|
+
process.stdout.write(Buffer.from(result.bytes));
|
|
17204
|
+
return;
|
|
17205
|
+
}
|
|
17206
|
+
const output = await writeShareOutput(options.output ?? ".", result.metadata.display.filename ?? "share.md", result.bytes, options.force === true);
|
|
17207
|
+
if (json) receiveJson(result, output);
|
|
17208
|
+
else receiveHuman(output);
|
|
17209
|
+
} catch (error) {
|
|
17210
|
+
handleError(shareCliError(error));
|
|
17012
17211
|
}
|
|
17013
|
-
}
|
|
17014
|
-
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
17025
|
-
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17212
|
+
});
|
|
17213
|
+
share.command("list").description("List encrypted sender history without complete bearer URLs").option("--json", "Print versioned redacted JSON").action(async (options, command) => {
|
|
17214
|
+
try {
|
|
17215
|
+
const json = jsonOutput(options, command);
|
|
17216
|
+
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
17217
|
+
const result = await listShares(shareServices.records);
|
|
17218
|
+
if (json) writeJson2({ protocol: "tinycloud-share", version: 1, shares: result });
|
|
17219
|
+
else process.stdout.write(result.map((item) => `${item.shareId} ${item.target} ${item.expiresAt}`).join("\n") + (result.length ? "\n" : ""));
|
|
17220
|
+
} catch (error) {
|
|
17221
|
+
handleError(shareCliError(error));
|
|
17222
|
+
}
|
|
17223
|
+
});
|
|
17224
|
+
share.command("show <id>").description("Show one redacted sender-history record").option("--reveal-link", "Explicitly include the complete link").option("--json", "Print versioned redacted JSON").action(async (id, options, command) => {
|
|
17225
|
+
try {
|
|
17226
|
+
const json = jsonOutput(options, command);
|
|
17227
|
+
if (options.revealLink && json) throw new CLIError("INVALID_ARGUMENT", "--reveal-link cannot be combined with --json", 2);
|
|
17228
|
+
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
17229
|
+
const result = await showShare({ storage: shareServices.records, shareId: id, revealLink: options.revealLink === true, link: options.revealLink ? await shareServices.linkFor?.(id) : void 0 });
|
|
17230
|
+
if (json) writeJson2({ protocol: "tinycloud-share", version: 1, share: result });
|
|
17231
|
+
else writeJson2(result);
|
|
17232
|
+
} catch (error) {
|
|
17233
|
+
handleError(shareCliError(error));
|
|
17234
|
+
}
|
|
17235
|
+
});
|
|
17236
|
+
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) => {
|
|
17237
|
+
try {
|
|
17238
|
+
const json = jsonOutput(options, command);
|
|
17239
|
+
if (shareServices.delivery === void 0) throw new CLIError("AUTH_REQUIRED", "delivery authority is not configured", 3);
|
|
17240
|
+
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
17241
|
+
const record = await shareServices.records.get(id);
|
|
17242
|
+
if (record === void 0) throw new CLIError("NOT_FOUND", "share not found", 4);
|
|
17243
|
+
if (!record.actions.includes("tinycloud.kv/get")) {
|
|
17244
|
+
throw new CLIError("INVALID_ARGUMENT", "share notify requires a stored share with the read action; no invitation was sent", 2);
|
|
17029
17245
|
}
|
|
17030
|
-
|
|
17031
|
-
|
|
17032
|
-
|
|
17033
|
-
|
|
17034
|
-
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17246
|
+
const mailbox = canonicalMailbox2(options.to);
|
|
17247
|
+
if (mailbox === void 0) throw new ShareNotifyError("recipient is invalid");
|
|
17248
|
+
if (!recipientMatchesShareRecord(record, mailbox.email)) throw new ShareNotifyError("recipient does not match the stored share target");
|
|
17249
|
+
if (record.recipientMatcher.kind === "emailDomain" && shareDeliveryWindowExpiresAt(record) > Date.now()) {
|
|
17250
|
+
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);
|
|
17251
|
+
await shareServices.assertDomainDelivery();
|
|
17252
|
+
}
|
|
17253
|
+
const result = await notifyRecordedShare(record, options.to, shareServices.delivery, shareServices.records);
|
|
17254
|
+
if (json) writeJson2(result);
|
|
17255
|
+
else process.stdout.write(`${result.state}
|
|
17256
|
+
`);
|
|
17257
|
+
if (result.reason === "delivery-window-expired") process.stderr.write(NOTIFY_WINDOW_MESSAGE);
|
|
17258
|
+
if (result.state === "partial-failure") process.exitCode = 9;
|
|
17259
|
+
} catch (error) {
|
|
17260
|
+
handleError(shareCliError(error, "notify"));
|
|
17261
|
+
}
|
|
17262
|
+
});
|
|
17263
|
+
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) => {
|
|
17264
|
+
try {
|
|
17265
|
+
const json = jsonOutput(options, command);
|
|
17266
|
+
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
17267
|
+
const record = shareServices.getRecord ? await shareServices.getRecord(id) : await shareServices.records.get(id);
|
|
17268
|
+
if (record === void 0) throw new CLIError("NOT_FOUND", "share not found", 4);
|
|
17269
|
+
const result = await revokeShare({ record, records: shareServices.records, adapter: shareServices.revocation, scope: options.ancestor ? "ancestor" : "direct" });
|
|
17270
|
+
if (result.state === "unsupported") {
|
|
17271
|
+
throw new CLIError("UNSUPPORTED_TARGET", result.reason, 2);
|
|
17272
|
+
}
|
|
17273
|
+
if (json) writeJson2({ protocol: "tinycloud-share", version: 1, result });
|
|
17274
|
+
else process.stdout.write(`${result.state}
|
|
17275
|
+
`);
|
|
17276
|
+
} catch (error) {
|
|
17277
|
+
handleError(shareCliError(error));
|
|
17278
|
+
}
|
|
17279
|
+
});
|
|
17053
17280
|
}
|
|
17054
|
-
var MAX_INLINE_BYTES2 = 256 * 1024;
|
|
17055
17281
|
|
|
17056
17282
|
// src/share/adapters.ts
|
|
17283
|
+
init_profiles();
|
|
17284
|
+
init_constants();
|
|
17285
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
17286
|
+
import { join as join6 } from "path";
|
|
17287
|
+
import { createHash } from "crypto";
|
|
17288
|
+
import { writeJsonAtomic as writeJsonAtomic2 } from "@tinycloud/operations/state";
|
|
17057
17289
|
import { LocationRecordValidationError, LocationRegistryHttpError, revokePolicyRootV3 } from "@tinycloud/sdk-core";
|
|
17058
17290
|
import { extractSiweExpiration, InvalidRestoredSessionError } from "@tinycloud/node-sdk";
|
|
17059
17291
|
function requiredKvAction(meta) {
|
|
@@ -17073,6 +17305,28 @@ function throwKvUploadFailure(error) {
|
|
|
17073
17305
|
throw new SharePublishAuthorityError({ kind: "upload-failed" });
|
|
17074
17306
|
}
|
|
17075
17307
|
var DEFAULT_SHARE_ORIGIN = "https://share.tinycloud.xyz";
|
|
17308
|
+
var MIN_DOMAIN_DELIVERY_VERSION = "1.17.3";
|
|
17309
|
+
function supportsDomainDelivery(version2) {
|
|
17310
|
+
if (typeof version2 !== "string") return false;
|
|
17311
|
+
const normalized = version2.trim();
|
|
17312
|
+
if (normalized.length > 128) return false;
|
|
17313
|
+
const match = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(normalized);
|
|
17314
|
+
if (match === null) return false;
|
|
17315
|
+
if (match[4] !== void 0 && /(?:^|\.)0[0-9]+(?:\.|$)/.test(match[4])) return false;
|
|
17316
|
+
const major = Number(match[1]);
|
|
17317
|
+
const minor = Number(match[2]);
|
|
17318
|
+
const patch = Number(match[3]);
|
|
17319
|
+
if (!Number.isSafeInteger(major) || !Number.isSafeInteger(minor) || !Number.isSafeInteger(patch)) return false;
|
|
17320
|
+
if (major !== 1) return major > 1;
|
|
17321
|
+
if (minor !== 17) return minor > 17;
|
|
17322
|
+
if (patch !== 3) return patch > 3;
|
|
17323
|
+
return match[4] === void 0;
|
|
17324
|
+
}
|
|
17325
|
+
function displayedNodeVersion(version2) {
|
|
17326
|
+
if (typeof version2 !== "string") return "(unrecognized)";
|
|
17327
|
+
const trimmed = version2.trim();
|
|
17328
|
+
return /^[A-Za-z0-9.+_-]{1,64}$/.test(trimmed) ? trimmed : "(unrecognized)";
|
|
17329
|
+
}
|
|
17076
17330
|
var URI_SAFE_FILENAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
17077
17331
|
function safeStorageFilename(filename) {
|
|
17078
17332
|
if (URI_SAFE_FILENAME.test(filename) && !filename.includes("..")) return filename;
|
|
@@ -17083,6 +17337,12 @@ function safeStorageFilename(filename) {
|
|
|
17083
17337
|
}
|
|
17084
17338
|
function createEncryptedSessionHistory() {
|
|
17085
17339
|
const records = /* @__PURE__ */ new Map();
|
|
17340
|
+
let operation = Promise.resolve();
|
|
17341
|
+
const serial = (action) => {
|
|
17342
|
+
const next = operation.then(action, action);
|
|
17343
|
+
operation = next.then(() => void 0, () => void 0);
|
|
17344
|
+
return next;
|
|
17345
|
+
};
|
|
17086
17346
|
let keyPromise;
|
|
17087
17347
|
const key = async () => keyPromise ??= crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
|
|
17088
17348
|
const encode6 = async (record) => {
|
|
@@ -17097,35 +17357,45 @@ function createEncryptedSessionHistory() {
|
|
|
17097
17357
|
const decode10 = async (value) => JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await crypto.subtle.decrypt({ name: "AES-GCM", iv: value.slice(0, 12) }, await key(), value.slice(12))));
|
|
17098
17358
|
return {
|
|
17099
17359
|
async put(record) {
|
|
17100
|
-
|
|
17360
|
+
return serial(async () => {
|
|
17361
|
+
records.set(record.shareId, await encode6(record));
|
|
17362
|
+
});
|
|
17363
|
+
},
|
|
17364
|
+
async update(shareId, change) {
|
|
17365
|
+
return serial(async () => {
|
|
17366
|
+
const value = records.get(shareId);
|
|
17367
|
+
if (value === void 0) return void 0;
|
|
17368
|
+
const updated = await change(await decode10(value));
|
|
17369
|
+
records.set(shareId, await encode6(updated));
|
|
17370
|
+
return updated;
|
|
17371
|
+
});
|
|
17101
17372
|
},
|
|
17102
17373
|
async list() {
|
|
17103
|
-
return Promise.all([...records.values()].map(decode10));
|
|
17374
|
+
return serial(() => Promise.all([...records.values()].map(decode10)));
|
|
17104
17375
|
},
|
|
17105
17376
|
async get(shareId) {
|
|
17106
|
-
|
|
17107
|
-
|
|
17377
|
+
return serial(async () => {
|
|
17378
|
+
const value = records.get(shareId);
|
|
17379
|
+
return value === void 0 ? void 0 : decode10(value);
|
|
17380
|
+
});
|
|
17108
17381
|
},
|
|
17109
17382
|
async delete(shareId) {
|
|
17110
|
-
|
|
17383
|
+
return serial(async () => {
|
|
17384
|
+
records.delete(shareId);
|
|
17385
|
+
});
|
|
17111
17386
|
}
|
|
17112
17387
|
};
|
|
17113
17388
|
}
|
|
17114
17389
|
function createEncryptedProfileHistory(profileName, sessionSigner) {
|
|
17115
17390
|
const HISTORY_VERSION = 2;
|
|
17116
|
-
|
|
17391
|
+
const identityChanged = new Error("share history profile or key changed");
|
|
17392
|
+
const saltChanged = new Error("share history salt changed");
|
|
17117
17393
|
let operation = Promise.resolve();
|
|
17118
|
-
const
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
throw new Error("share history requires an initialized profile");
|
|
17124
|
-
}
|
|
17125
|
-
return sessionSigner(new TextEncoder().encode("xyz.tinycloud.share/history-key/v1"));
|
|
17126
|
-
})();
|
|
17127
|
-
const path = async () => join6(await ProfileManager.getCacheDir(await profileName()), "share-history-v2.json");
|
|
17128
|
-
const legacyPath = async () => join6(await ProfileManager.getCacheDir(await profileName()), "share-history-v1.bin");
|
|
17394
|
+
const observedProfiles = /* @__PURE__ */ new Set();
|
|
17395
|
+
let preparedKeys;
|
|
17396
|
+
let preparedKey;
|
|
17397
|
+
const path = async (profile) => join6(await ProfileManager.getCacheDir(profile), "share-history-v2.json");
|
|
17398
|
+
const legacyPath = async (profile) => join6(await ProfileManager.getCacheDir(profile), "share-history-v1.bin");
|
|
17129
17399
|
const b64 = (value) => Buffer.from(value).toString("base64url");
|
|
17130
17400
|
const unb64 = (value) => {
|
|
17131
17401
|
if (typeof value !== "string" || !/^[A-Za-z0-9_-]+$/.test(value)) throw new Error("share history is unavailable");
|
|
@@ -17133,81 +17403,165 @@ function createEncryptedProfileHistory(profileName, sessionSigner) {
|
|
|
17133
17403
|
if (b64(bytes) !== value) throw new Error("share history is unavailable");
|
|
17134
17404
|
return bytes;
|
|
17135
17405
|
};
|
|
17136
|
-
const
|
|
17137
|
-
|
|
17138
|
-
|
|
17139
|
-
|
|
17140
|
-
|
|
17406
|
+
const isStoredRecord = (value) => typeof value === "object" && value !== null && "shareId" in value && typeof value.shareId === "string";
|
|
17407
|
+
const identity = async (profile) => {
|
|
17408
|
+
const config = await ProfileManager.getProfile(profile);
|
|
17409
|
+
const localKey = typeof config.privateKey === "string" && config.privateKey.length > 0;
|
|
17410
|
+
const [key, session] = localKey ? [null, null] : await Promise.all([ProfileManager.getKey(profile), ProfileManager.getSession(profile)]);
|
|
17411
|
+
const sessionJwk = session !== null && "jwk" in session ? session.jwk : void 0;
|
|
17412
|
+
const signerJwk = sessionJwk !== null && typeof sessionJwk === "object" && "d" in sessionJwk && typeof sessionJwk.d === "string" && sessionJwk.d.length > 0 ? sessionJwk : key;
|
|
17413
|
+
const method = session !== null && "verificationMethod" in session ? session.verificationMethod ?? config.did : config.did;
|
|
17414
|
+
const fingerprint = createHash("sha256").update(JSON.stringify(localKey ? ["local", config.privateKey] : ["openkey", sessionJwk, signerJwk, method])).digest("hex");
|
|
17415
|
+
return { config, fingerprint };
|
|
17416
|
+
};
|
|
17417
|
+
const prepareKeys = async (profile, snapshot) => {
|
|
17418
|
+
if (preparedKeys?.profile === profile && preparedKeys.identity === snapshot.fingerprint) return preparedKeys;
|
|
17419
|
+
let secret;
|
|
17420
|
+
if (typeof snapshot.config.privateKey === "string" && snapshot.config.privateKey.length > 0) {
|
|
17421
|
+
secret = new TextEncoder().encode(snapshot.config.privateKey);
|
|
17422
|
+
} else {
|
|
17423
|
+
if (sessionSigner === void 0) throw new Error("share history requires an initialized profile");
|
|
17424
|
+
secret = await sessionSigner(new TextEncoder().encode("xyz.tinycloud.share/history-key/v1"), profile);
|
|
17141
17425
|
}
|
|
17426
|
+
if ((await identity(profile)).fingerprint !== snapshot.fingerprint) throw identityChanged;
|
|
17142
17427
|
const material = await crypto.subtle.importKey("raw", secret, "PBKDF2", false, ["deriveKey"]);
|
|
17143
|
-
|
|
17428
|
+
const digest = await crypto.subtle.digest("SHA-256", secret);
|
|
17429
|
+
const legacyKey = await crypto.subtle.importKey("raw", digest, { name: "AES-GCM" }, false, ["decrypt"]);
|
|
17430
|
+
return preparedKeys = { profile, identity: snapshot.fingerprint, material, legacyKey };
|
|
17144
17431
|
};
|
|
17145
|
-
const
|
|
17432
|
+
const preparedSalt = async (profile) => {
|
|
17146
17433
|
try {
|
|
17147
|
-
const
|
|
17148
|
-
const envelope = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(encoded));
|
|
17434
|
+
const envelope = JSON.parse(await readFile4(await path(profile), "utf8"));
|
|
17149
17435
|
if (envelope.version !== HISTORY_VERSION) throw new Error("share history is unavailable");
|
|
17150
17436
|
const salt = unb64(envelope.kdfSalt);
|
|
17437
|
+
if (salt.length < 16) throw new Error("share history is unavailable");
|
|
17438
|
+
return salt;
|
|
17439
|
+
} catch (error) {
|
|
17440
|
+
if (error.code === "ENOENT") return crypto.getRandomValues(new Uint8Array(16));
|
|
17441
|
+
throw new Error("share history is unavailable");
|
|
17442
|
+
}
|
|
17443
|
+
};
|
|
17444
|
+
const read4 = async (profile, ready) => {
|
|
17445
|
+
try {
|
|
17446
|
+
const envelope = JSON.parse(await readFile4(await path(profile), "utf8"));
|
|
17447
|
+
if (envelope.version !== HISTORY_VERSION) throw new Error("share history is unavailable");
|
|
17448
|
+
if (envelope.kdfSalt !== b64(ready.salt)) throw saltChanged;
|
|
17151
17449
|
const iv = unb64(envelope.iv);
|
|
17152
17450
|
const ciphertext = unb64(envelope.ciphertext);
|
|
17153
|
-
if (
|
|
17154
|
-
const bytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv },
|
|
17451
|
+
if (iv.length !== 12 || ciphertext.length <= 16) throw new Error("share history is unavailable");
|
|
17452
|
+
const bytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, ready.key, ciphertext);
|
|
17155
17453
|
const values = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
17156
|
-
return
|
|
17454
|
+
return Array.isArray(values) ? values.filter(isStoredRecord) : [];
|
|
17157
17455
|
} catch (error) {
|
|
17456
|
+
if (error === saltChanged) throw error;
|
|
17158
17457
|
if (error.code !== "ENOENT") throw new Error("share history is unavailable");
|
|
17159
17458
|
try {
|
|
17160
|
-
const legacy = new Uint8Array(await readFile4(await legacyPath()));
|
|
17161
|
-
if (legacy.length <= 12) return
|
|
17162
|
-
const bytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv: legacy.slice(0, 12) },
|
|
17459
|
+
const legacy = new Uint8Array(await readFile4(await legacyPath(profile)));
|
|
17460
|
+
if (legacy.length <= 12) return [];
|
|
17461
|
+
const bytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv: legacy.slice(0, 12) }, ready.legacyKey, legacy.slice(12));
|
|
17163
17462
|
const values = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
17164
|
-
return
|
|
17463
|
+
return Array.isArray(values) ? values.filter(isStoredRecord) : [];
|
|
17165
17464
|
} catch (legacyError) {
|
|
17166
|
-
if (legacyError.code === "ENOENT") return
|
|
17465
|
+
if (legacyError.code === "ENOENT") return [];
|
|
17167
17466
|
throw new Error("share history is unavailable");
|
|
17168
17467
|
}
|
|
17169
17468
|
}
|
|
17170
17469
|
};
|
|
17171
|
-
const write = async (values,
|
|
17470
|
+
const write = async (profile, values, ready) => {
|
|
17172
17471
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
17173
17472
|
const bytes = new TextEncoder().encode(JSON.stringify(values));
|
|
17174
|
-
const encrypted = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv },
|
|
17175
|
-
|
|
17176
|
-
await writeFile2(await path(), output, { mode: 384 });
|
|
17473
|
+
const encrypted = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv }, ready.key, bytes));
|
|
17474
|
+
await writeJsonAtomic2(await path(profile), { version: HISTORY_VERSION, kdfSalt: b64(ready.salt), iv: b64(iv), ciphertext: b64(encrypted) });
|
|
17177
17475
|
};
|
|
17178
|
-
const serial = (
|
|
17179
|
-
const next = operation.then(
|
|
17476
|
+
const serial = (action) => {
|
|
17477
|
+
const next = operation.then(action, action);
|
|
17180
17478
|
operation = next.then(() => void 0, () => void 0);
|
|
17181
17479
|
return next;
|
|
17182
17480
|
};
|
|
17481
|
+
const locked = (action, writing = false) => serial(async () => {
|
|
17482
|
+
const profile = await profileName();
|
|
17483
|
+
let warned = false;
|
|
17484
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
17485
|
+
try {
|
|
17486
|
+
const snapshot = await identity(profile);
|
|
17487
|
+
observedProfiles.add(profile);
|
|
17488
|
+
const keys = await prepareKeys(profile, snapshot);
|
|
17489
|
+
const salt = await preparedSalt(profile);
|
|
17490
|
+
const saltId = b64(salt);
|
|
17491
|
+
const key = preparedKey?.profile === profile && preparedKey.identity === snapshot.fingerprint && preparedKey.salt === saltId ? preparedKey.key : await crypto.subtle.deriveKey(
|
|
17492
|
+
{ name: "PBKDF2", salt, iterations: 1e5, hash: "SHA-256" },
|
|
17493
|
+
keys.material,
|
|
17494
|
+
{ name: "AES-GCM", length: 256 },
|
|
17495
|
+
false,
|
|
17496
|
+
["encrypt", "decrypt"]
|
|
17497
|
+
);
|
|
17498
|
+
preparedKey = { profile, identity: snapshot.fingerprint, salt: saltId, key };
|
|
17499
|
+
const warning = writing ? setTimeout(() => {
|
|
17500
|
+
if (!warned) {
|
|
17501
|
+
warned = true;
|
|
17502
|
+
process.stderr.write(`Waiting for profile lock for ${JSON.stringify(profile)} before updating sender history.
|
|
17503
|
+
`);
|
|
17504
|
+
}
|
|
17505
|
+
}, 2e3) : void 0;
|
|
17506
|
+
warning?.unref();
|
|
17507
|
+
try {
|
|
17508
|
+
return await ProfileManager.withLock(profile, async () => {
|
|
17509
|
+
clearTimeout(warning);
|
|
17510
|
+
if ((await identity(profile)).fingerprint !== snapshot.fingerprint) throw identityChanged;
|
|
17511
|
+
return action(profile, { salt, key, legacyKey: keys.legacyKey });
|
|
17512
|
+
}, writing ? { timeoutMs: PROFILE_COMMIT_LOCK_TIMEOUT_MS } : void 0);
|
|
17513
|
+
} finally {
|
|
17514
|
+
clearTimeout(warning);
|
|
17515
|
+
}
|
|
17516
|
+
} catch (error) {
|
|
17517
|
+
if (error === saltChanged || error === identityChanged) continue;
|
|
17518
|
+
if (observedProfiles.has(profile) && typeof error === "object" && error !== null && "code" in error && error.code === "PROFILE_NOT_FOUND") {
|
|
17519
|
+
throw new ShareHistoryRetryError(profile);
|
|
17520
|
+
}
|
|
17521
|
+
throw error;
|
|
17522
|
+
}
|
|
17523
|
+
}
|
|
17524
|
+
throw new ShareHistoryRetryError(profile);
|
|
17525
|
+
});
|
|
17183
17526
|
return {
|
|
17184
17527
|
async put(record) {
|
|
17185
|
-
return
|
|
17186
|
-
const
|
|
17187
|
-
const values = [...state.values];
|
|
17528
|
+
return locked(async (profile, ready) => {
|
|
17529
|
+
const values = await read4(profile, ready);
|
|
17188
17530
|
const index = values.findIndex((value) => value.shareId === record.shareId);
|
|
17189
17531
|
if (index >= 0) values[index] = record;
|
|
17190
17532
|
else values.push(record);
|
|
17191
|
-
await write(values,
|
|
17192
|
-
});
|
|
17533
|
+
await write(profile, values, ready);
|
|
17534
|
+
}, true);
|
|
17535
|
+
},
|
|
17536
|
+
async update(shareId, change) {
|
|
17537
|
+
return locked(async (profile, ready) => {
|
|
17538
|
+
const values = await read4(profile, ready);
|
|
17539
|
+
const index = values.findIndex((record) => record.shareId === shareId);
|
|
17540
|
+
if (index < 0) return void 0;
|
|
17541
|
+
const updated = await change(values[index]);
|
|
17542
|
+
values[index] = updated;
|
|
17543
|
+
await write(profile, values, ready);
|
|
17544
|
+
return updated;
|
|
17545
|
+
}, true);
|
|
17193
17546
|
},
|
|
17194
17547
|
async list() {
|
|
17195
|
-
return
|
|
17548
|
+
return locked((profile, ready) => read4(profile, ready));
|
|
17196
17549
|
},
|
|
17197
17550
|
async get(shareId) {
|
|
17198
|
-
return
|
|
17551
|
+
return locked(async (profile, ready) => (await read4(profile, ready)).find((record) => record.shareId === shareId));
|
|
17199
17552
|
},
|
|
17200
17553
|
async delete(shareId) {
|
|
17201
|
-
return
|
|
17202
|
-
|
|
17203
|
-
|
|
17204
|
-
});
|
|
17554
|
+
return locked(async (profile, ready) => {
|
|
17555
|
+
await write(profile, (await read4(profile, ready)).filter((record) => record.shareId !== shareId), ready);
|
|
17556
|
+
}, true);
|
|
17205
17557
|
}
|
|
17206
17558
|
};
|
|
17207
17559
|
}
|
|
17208
17560
|
function createShareAuthorityAdapters(input = {}) {
|
|
17209
17561
|
const origin = input.origin ?? DEFAULT_SHARE_ORIGIN;
|
|
17210
17562
|
const fetchFn = input.fetchFn ?? globalThis.fetch;
|
|
17563
|
+
let selectedProfile;
|
|
17564
|
+
const profileName = () => selectedProfile ??= input.profileName?.() ?? selectedProfileName();
|
|
17211
17565
|
const canonicalOrigin2 = (value, label) => {
|
|
17212
17566
|
if (typeof value !== "string") throw new Error(`share ${label} is unavailable`);
|
|
17213
17567
|
const parsed = new URL(value);
|
|
@@ -17237,7 +17591,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
17237
17591
|
let nodePromise;
|
|
17238
17592
|
let activeProfileName2;
|
|
17239
17593
|
const authenticatedNode = async () => nodePromise ??= (async () => {
|
|
17240
|
-
const profile = await
|
|
17594
|
+
const profile = await profileName();
|
|
17241
17595
|
activeProfileName2 = profile;
|
|
17242
17596
|
const context = await ProfileManager.resolveContext({ profile, ...input.nodeOrigin === void 0 ? {} : { host: input.nodeOrigin } });
|
|
17243
17597
|
const { ensureAuthenticated: ensureAuthenticated2 } = await Promise.resolve().then(() => (init_sdk(), sdk_exports));
|
|
@@ -17256,6 +17610,38 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
17256
17610
|
throw error;
|
|
17257
17611
|
}
|
|
17258
17612
|
})();
|
|
17613
|
+
const assertDomainDeliveryForOrigin = async (nodeOrigin, operation) => {
|
|
17614
|
+
let response;
|
|
17615
|
+
try {
|
|
17616
|
+
response = await fetchFn(`${nodeOrigin}/info`, { signal: AbortSignal.timeout(5e3) });
|
|
17617
|
+
} catch {
|
|
17618
|
+
throw new SharePublishAuthorityError({ kind: "node-info-unavailable" });
|
|
17619
|
+
}
|
|
17620
|
+
if (!response.ok) throw new SharePublishAuthorityError({ kind: "node-info-unavailable" });
|
|
17621
|
+
let body;
|
|
17622
|
+
try {
|
|
17623
|
+
body = await response.text();
|
|
17624
|
+
} catch {
|
|
17625
|
+
throw new SharePublishAuthorityError({ kind: "node-info-unavailable" });
|
|
17626
|
+
}
|
|
17627
|
+
let info;
|
|
17628
|
+
try {
|
|
17629
|
+
info = JSON.parse(body);
|
|
17630
|
+
} catch {
|
|
17631
|
+
info = void 0;
|
|
17632
|
+
}
|
|
17633
|
+
const version2 = typeof info === "object" && info !== null && "version" in info ? info.version : void 0;
|
|
17634
|
+
if (!supportsDomainDelivery(version2)) {
|
|
17635
|
+
throw new SharePublishAuthorityError({
|
|
17636
|
+
kind: "invalid-request",
|
|
17637
|
+
reason: `domain notifications require tinycloud-node ${MIN_DOMAIN_DELIVERY_VERSION} or later; node reports version ${displayedNodeVersion(version2)}. Upgrade the node before inviting; ${operation === "publish" ? "nothing was shared and no invitation was sent" : "no invitation was sent"}`
|
|
17638
|
+
});
|
|
17639
|
+
}
|
|
17640
|
+
};
|
|
17641
|
+
const assertDomainDelivery = async () => {
|
|
17642
|
+
const node = await authenticatedNode();
|
|
17643
|
+
await assertDomainDeliveryForOrigin((await node.activeNodeIdentity()).origin, "notify");
|
|
17644
|
+
};
|
|
17259
17645
|
const targetAdapter = { async publish(targetInput) {
|
|
17260
17646
|
if (input.publishTarget !== void 0) return input.publishTarget(targetInput);
|
|
17261
17647
|
const [config, node] = await Promise.all([publicConfig(), authenticatedNode()]);
|
|
@@ -17306,6 +17692,9 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
17306
17692
|
});
|
|
17307
17693
|
}
|
|
17308
17694
|
const activeNode = await node.activeNodeIdentity();
|
|
17695
|
+
if (targetInput.notify === true && targetInput.target.kind === "emailDomain") {
|
|
17696
|
+
await assertDomainDeliveryForOrigin(activeNode.origin, "publish");
|
|
17697
|
+
}
|
|
17309
17698
|
const shareId = crypto.randomUUID().replaceAll("-", "");
|
|
17310
17699
|
const files = targetInput.files === void 0 || targetInput.files.length === 0 ? [{ bytes: targetInput.source, filename: targetInput.filename, mediaType: targetInput.mediaType }] : targetInput.files;
|
|
17311
17700
|
const resourceKind = targetInput.resourceKind ?? "exact";
|
|
@@ -17470,12 +17859,10 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
17470
17859
|
const delivery = { deliver: input.deliver ?? (async (request) => {
|
|
17471
17860
|
const record = request.record;
|
|
17472
17861
|
if (record === void 0 || record.link === void 0 || record.deliveryMaterial === void 0 || request.idempotencyKey === void 0) throw new Error("share delivery history is incomplete");
|
|
17862
|
+
const expiry = shareDeliveryWindowExpiresAt(record);
|
|
17863
|
+
if (expiry <= Date.now()) throw new ShareNotifyError("share delivery authorization window has expired", "delivery-window-expired");
|
|
17864
|
+
const authorizationExpiresAt = new Date(expiry).toISOString();
|
|
17473
17865
|
const [config, node] = await Promise.all([publicConfig(), authenticatedNode()]);
|
|
17474
|
-
const authorizationExpiresAt = new Date(Math.min(
|
|
17475
|
-
Date.parse(record.expiresAt),
|
|
17476
|
-
Date.parse(record.registeredAt) + 5 * 60 * 1e3
|
|
17477
|
-
)).toISOString();
|
|
17478
|
-
if (Date.parse(authorizationExpiresAt) <= Date.now()) throw new Error("share delivery authorization retry window has expired");
|
|
17479
17866
|
const receipt = await node.authorizeShareDeliveryV3({
|
|
17480
17867
|
envelope: record.deliveryMaterial.envelope,
|
|
17481
17868
|
sealedEnvelope: record.deliveryMaterial.sealedEnvelope,
|
|
@@ -17536,14 +17923,16 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
17536
17923
|
};
|
|
17537
17924
|
return {
|
|
17538
17925
|
targetAdapter,
|
|
17539
|
-
records: input.profileName === void 0 ? createEncryptedSessionHistory() : createEncryptedProfileHistory(
|
|
17540
|
-
const
|
|
17541
|
-
|
|
17926
|
+
records: input.profileName === void 0 ? createEncryptedSessionHistory() : createEncryptedProfileHistory(profileName, async (bytes, profile) => {
|
|
17927
|
+
const context = await ProfileManager.resolveContext({ profile });
|
|
17928
|
+
if (context.profile !== profile) throw new ShareHistoryRetryError(profile);
|
|
17542
17929
|
const { ensureAuthenticated: ensureAuthenticated2 } = await Promise.resolve().then(() => (init_sdk(), sdk_exports));
|
|
17543
|
-
|
|
17930
|
+
const signer = await ensureAuthenticated2(context);
|
|
17931
|
+
return signer.signSessionBytes(bytes);
|
|
17544
17932
|
}),
|
|
17545
17933
|
delivery,
|
|
17546
17934
|
revocation,
|
|
17935
|
+
assertDomainDelivery,
|
|
17547
17936
|
nativeReader
|
|
17548
17937
|
};
|
|
17549
17938
|
}
|
|
@@ -17602,6 +17991,7 @@ configureShareCommandServices({
|
|
|
17602
17991
|
targetAdapter: shareAuthority.targetAdapter,
|
|
17603
17992
|
records: shareAuthority.records,
|
|
17604
17993
|
delivery: shareAuthority.delivery,
|
|
17994
|
+
assertDomainDelivery: shareAuthority.assertDomainDelivery,
|
|
17605
17995
|
revocation: shareAuthority.revocation,
|
|
17606
17996
|
nativeReader: shareAuthority.nativeReader
|
|
17607
17997
|
});
|