@tinycloud/cli 1.3.0-beta.32 → 1.3.0-beta.34
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 +222 -133
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +214 -146
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +1 -1
- package/skills/tc-cli/REFERENCE.md +41 -2
- package/skills/tc-cli/SKILL.md +2 -0
package/dist/index.js
CHANGED
|
@@ -303,20 +303,20 @@ var init_formatter = __esm({
|
|
|
303
303
|
function storageRejection(error) {
|
|
304
304
|
let node = error;
|
|
305
305
|
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null; depth += 1) {
|
|
306
|
-
const
|
|
306
|
+
const record2 = node;
|
|
307
307
|
let code4;
|
|
308
|
-
if (
|
|
309
|
-
code4 =
|
|
310
|
-
} else if (
|
|
308
|
+
if (record2.code === "STORAGE_QUOTA_EXCEEDED" || record2.code === "STORAGE_LIMIT_REACHED") {
|
|
309
|
+
code4 = record2.code;
|
|
310
|
+
} else if (record2.code !== void 0) {
|
|
311
311
|
return void 0;
|
|
312
|
-
} else if (isStorageStatus(
|
|
313
|
-
code4 = storageCodeFromText(
|
|
312
|
+
} else if (isStorageStatus(record2)) {
|
|
313
|
+
code4 = storageCodeFromText(record2.message);
|
|
314
314
|
}
|
|
315
315
|
if (code4) {
|
|
316
|
-
const account = accountTotals(
|
|
316
|
+
const account = accountTotals(record2) ?? accountTotals(record2.meta) ?? accountTotals(record2.metadata);
|
|
317
317
|
return account ? { code: code4, account } : { code: code4 };
|
|
318
318
|
}
|
|
319
|
-
node =
|
|
319
|
+
node = record2.cause;
|
|
320
320
|
}
|
|
321
321
|
return void 0;
|
|
322
322
|
}
|
|
@@ -350,11 +350,11 @@ function storageCodeFromText(message) {
|
|
|
350
350
|
}
|
|
351
351
|
return void 0;
|
|
352
352
|
}
|
|
353
|
-
function isStorageStatus(
|
|
354
|
-
const meta = "meta" in
|
|
353
|
+
function isStorageStatus(record2) {
|
|
354
|
+
const meta = "meta" in record2 && typeof record2.meta === "object" && record2.meta !== null ? record2.meta : {};
|
|
355
355
|
const statuses = [
|
|
356
|
-
"status" in
|
|
357
|
-
"statusCode" in
|
|
356
|
+
"status" in record2 ? record2.status : void 0,
|
|
357
|
+
"statusCode" in record2 ? record2.statusCode : void 0,
|
|
358
358
|
"status" in meta ? meta.status : void 0
|
|
359
359
|
];
|
|
360
360
|
return statuses.some((value) => value === 402 || value === 413);
|
|
@@ -3834,30 +3834,30 @@ function parseState(text) {
|
|
|
3834
3834
|
throw gateRefusal("gate_unavailable", "The replica gate file is not valid JSON.");
|
|
3835
3835
|
}
|
|
3836
3836
|
if (typeof raw !== "object" || raw === null) throw gateRefusal("gate_unavailable", "The replica gate file is malformed.");
|
|
3837
|
-
const
|
|
3838
|
-
if (
|
|
3839
|
-
if (typeof
|
|
3837
|
+
const record2 = raw;
|
|
3838
|
+
if (record2.v !== GATE_FILE_VERSION) throw gateRefusal("gate_unavailable", "The replica gate file has an unknown version.");
|
|
3839
|
+
if (typeof record2.incarnation !== "string" || record2.incarnation.length === 0) {
|
|
3840
3840
|
throw gateRefusal("gate_unavailable", "The replica gate file has no incarnation.");
|
|
3841
3841
|
}
|
|
3842
|
-
if (typeof
|
|
3842
|
+
if (typeof record2.salt !== "string" || Buffer.from(record2.salt, "base64url").toString("base64url") !== record2.salt || Buffer.from(record2.salt, "base64url").length < 32) {
|
|
3843
3843
|
throw gateRefusal("gate_unavailable", "The replica gate file has an invalid salt.");
|
|
3844
3844
|
}
|
|
3845
|
-
if (
|
|
3845
|
+
if (record2.principalHash !== null && (typeof record2.principalHash !== "string" || !/^[0-9a-f]{64}$/.test(record2.principalHash))) {
|
|
3846
3846
|
throw gateRefusal("gate_unavailable", "The replica gate file has an invalid principal hash.");
|
|
3847
3847
|
}
|
|
3848
|
-
if (typeof
|
|
3848
|
+
if (typeof record2.lifecycleEpoch !== "number" || !Number.isSafeInteger(record2.lifecycleEpoch) || record2.lifecycleEpoch < 0) {
|
|
3849
3849
|
throw gateRefusal("gate_unavailable", "The replica gate file has an invalid lifecycle epoch.");
|
|
3850
3850
|
}
|
|
3851
|
-
if (
|
|
3851
|
+
if (record2.deniedAt !== null && (typeof record2.deniedAt !== "number" || !Number.isSafeInteger(record2.deniedAt) || record2.deniedAt < 0)) {
|
|
3852
3852
|
throw gateRefusal("gate_unavailable", "The replica gate file has an invalid deniedAt.");
|
|
3853
3853
|
}
|
|
3854
|
-
if (!Array.isArray(
|
|
3855
|
-
for (const intent of
|
|
3854
|
+
if (!Array.isArray(record2.intents)) throw gateRefusal("gate_unavailable", "The replica gate file has no intents list.");
|
|
3855
|
+
for (const intent of record2.intents) {
|
|
3856
3856
|
if (typeof intent !== "object" || intent === null || typeof intent.id !== "string" || !/^[0-9a-f]{64}$/.test(intent.principalHash) || !Number.isSafeInteger(intent.recordedAt) || intent.recordedAt < 0 || (intent.kind === "pending" ? !/^[0-9a-f]{64}$/.test(intent.identityKeyHash) || intent.id !== `pending:${intent.identityKeyHash}` : intent.kind !== "partition" || typeof intent.partitionId !== "string" || intent.partitionId.length === 0 || intent.id !== intent.partitionId)) {
|
|
3857
3857
|
throw gateRefusal("gate_unavailable", "The replica gate file has an invalid purge intent.");
|
|
3858
3858
|
}
|
|
3859
3859
|
}
|
|
3860
|
-
const firstInstall =
|
|
3860
|
+
const firstInstall = record2.firstInstall;
|
|
3861
3861
|
if (typeof firstInstall !== "object" || firstInstall === null || Array.isArray(firstInstall)) {
|
|
3862
3862
|
throw gateRefusal("gate_unavailable", "The replica gate file has no valid firstInstall map.");
|
|
3863
3863
|
}
|
|
@@ -3866,7 +3866,7 @@ function parseState(text) {
|
|
|
3866
3866
|
throw gateRefusal("gate_unavailable", "The replica gate file has an invalid firstInstall entry.");
|
|
3867
3867
|
}
|
|
3868
3868
|
}
|
|
3869
|
-
const grantInstall = Object.prototype.hasOwnProperty.call(
|
|
3869
|
+
const grantInstall = Object.prototype.hasOwnProperty.call(record2, "grantInstall") ? record2.grantInstall : {};
|
|
3870
3870
|
if (typeof grantInstall !== "object" || grantInstall === null || Array.isArray(grantInstall)) {
|
|
3871
3871
|
throw gateRefusal("gate_unavailable", "The replica gate has an invalid grantInstall map.");
|
|
3872
3872
|
}
|
|
@@ -3875,7 +3875,7 @@ function parseState(text) {
|
|
|
3875
3875
|
throw gateRefusal("gate_unavailable", "The replica gate has an invalid grant install time.");
|
|
3876
3876
|
}
|
|
3877
3877
|
}
|
|
3878
|
-
const pendingGenerations =
|
|
3878
|
+
const pendingGenerations = record2.pendingGenerations;
|
|
3879
3879
|
if (typeof pendingGenerations !== "object" || pendingGenerations === null || Array.isArray(pendingGenerations)) {
|
|
3880
3880
|
throw gateRefusal("gate_unavailable", "The replica gate file has an invalid pending generation map.");
|
|
3881
3881
|
}
|
|
@@ -3884,18 +3884,18 @@ function parseState(text) {
|
|
|
3884
3884
|
throw gateRefusal("gate_unavailable", "The replica gate file has an invalid pending generation.");
|
|
3885
3885
|
}
|
|
3886
3886
|
}
|
|
3887
|
-
const eraseDeferred = Object.prototype.hasOwnProperty.call(
|
|
3888
|
-
const deferredPrincipalHash = Object.prototype.hasOwnProperty.call(
|
|
3889
|
-
if (typeof eraseDeferred !== "boolean" || deferredPrincipalHash !== null && (typeof deferredPrincipalHash !== "string" || !/^[0-9a-f]{64}$/.test(deferredPrincipalHash)) || eraseDeferred && (
|
|
3887
|
+
const eraseDeferred = Object.prototype.hasOwnProperty.call(record2, "eraseDeferred") ? record2.eraseDeferred : false;
|
|
3888
|
+
const deferredPrincipalHash = Object.prototype.hasOwnProperty.call(record2, "deferredPrincipalHash") ? record2.deferredPrincipalHash : null;
|
|
3889
|
+
if (typeof eraseDeferred !== "boolean" || deferredPrincipalHash !== null && (typeof deferredPrincipalHash !== "string" || !/^[0-9a-f]{64}$/.test(deferredPrincipalHash)) || eraseDeferred && (record2.principalHash !== null || deferredPrincipalHash === null)) {
|
|
3890
3890
|
throw gateRefusal("gate_unavailable", "The replica gate has an invalid deferred erase state.");
|
|
3891
3891
|
}
|
|
3892
3892
|
return {
|
|
3893
|
-
incarnation:
|
|
3894
|
-
salt:
|
|
3895
|
-
principalHash:
|
|
3896
|
-
lifecycleEpoch:
|
|
3897
|
-
deniedAt:
|
|
3898
|
-
intents:
|
|
3893
|
+
incarnation: record2.incarnation,
|
|
3894
|
+
salt: record2.salt,
|
|
3895
|
+
principalHash: record2.principalHash,
|
|
3896
|
+
lifecycleEpoch: record2.lifecycleEpoch,
|
|
3897
|
+
deniedAt: record2.deniedAt,
|
|
3898
|
+
intents: record2.intents,
|
|
3899
3899
|
firstInstall,
|
|
3900
3900
|
grantInstall,
|
|
3901
3901
|
pendingGenerations,
|
|
@@ -3917,17 +3917,17 @@ async function readStoredState(profileDir) {
|
|
|
3917
3917
|
return parseState(text);
|
|
3918
3918
|
}
|
|
3919
3919
|
async function readDenyFloor(profileDir) {
|
|
3920
|
-
let
|
|
3920
|
+
let record2;
|
|
3921
3921
|
try {
|
|
3922
|
-
|
|
3922
|
+
record2 = JSON.parse(await readFile3(join6(profileDir, DENY_FLOOR_FILE), "utf8"));
|
|
3923
3923
|
} catch (error) {
|
|
3924
3924
|
if (isNotFound(error)) return void 0;
|
|
3925
3925
|
throw gateRefusal("gate_unavailable", "The replica deny floor cannot be read.");
|
|
3926
3926
|
}
|
|
3927
|
-
if (typeof
|
|
3927
|
+
if (typeof record2 !== "object" || record2 === null || Array.isArray(record2) || Object.keys(record2).length !== 2 || !("epoch" in record2) || !("deniedAt" in record2) || !Number.isSafeInteger(record2.epoch) || record2.epoch < 1 || !Number.isSafeInteger(record2.deniedAt) || record2.deniedAt < 0) {
|
|
3928
3928
|
throw gateRefusal("gate_unavailable", "The replica deny floor is malformed.");
|
|
3929
3929
|
}
|
|
3930
|
-
return { epoch:
|
|
3930
|
+
return { epoch: record2.epoch, deniedAt: record2.deniedAt };
|
|
3931
3931
|
}
|
|
3932
3932
|
function behindFloor(state2, floor) {
|
|
3933
3933
|
return state2.lifecycleEpoch < floor.epoch || state2.deniedAt === null || state2.deniedAt < floor.deniedAt;
|
|
@@ -13204,15 +13204,15 @@ function parseArtifactManifest(bytes) {
|
|
|
13204
13204
|
throw new ArtifactError("corrupt", "artifact manifest is malformed");
|
|
13205
13205
|
};
|
|
13206
13206
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return fail();
|
|
13207
|
-
const
|
|
13207
|
+
const record2 = value;
|
|
13208
13208
|
const allowed = ["v", "files", "createdAt", "parent", "note"];
|
|
13209
|
-
if (Object.keys(
|
|
13210
|
-
if (!Array.isArray(
|
|
13211
|
-
if (typeof
|
|
13212
|
-
if (
|
|
13213
|
-
if (
|
|
13209
|
+
if (Object.keys(record2).some((key) => !allowed.includes(key)) || record2.v !== ARTIFACT_MANIFEST_VERSION) return fail();
|
|
13210
|
+
if (!Array.isArray(record2.files) || record2.files.length === 0) return fail();
|
|
13211
|
+
if (typeof record2.createdAt !== "string" || Number.isNaN(Date.parse(record2.createdAt))) return fail();
|
|
13212
|
+
if (record2.parent !== null && (typeof record2.parent !== "number" || !Number.isSafeInteger(record2.parent) || record2.parent < 1)) return fail();
|
|
13213
|
+
if (record2.note !== void 0 && (typeof record2.note !== "string" || record2.note.length > 1024)) return fail();
|
|
13214
13214
|
const seen = /* @__PURE__ */ new Set();
|
|
13215
|
-
const files =
|
|
13215
|
+
const files = record2.files.map((entry) => {
|
|
13216
13216
|
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return fail();
|
|
13217
13217
|
const file = entry;
|
|
13218
13218
|
if (Object.keys(file).some((key) => !["path", "sha256", "bytes"].includes(key))) return fail();
|
|
@@ -13230,9 +13230,9 @@ function parseArtifactManifest(bytes) {
|
|
|
13230
13230
|
return {
|
|
13231
13231
|
v: ARTIFACT_MANIFEST_VERSION,
|
|
13232
13232
|
files,
|
|
13233
|
-
createdAt:
|
|
13234
|
-
parent:
|
|
13235
|
-
...
|
|
13233
|
+
createdAt: record2.createdAt,
|
|
13234
|
+
parent: record2.parent,
|
|
13235
|
+
...record2.note === void 0 ? {} : { note: record2.note }
|
|
13236
13236
|
};
|
|
13237
13237
|
}
|
|
13238
13238
|
async function listArtifactVersions(store, artifactId) {
|
|
@@ -19054,21 +19054,21 @@ async function parseSealedInlineShareUrl(url, options = {}) {
|
|
|
19054
19054
|
throw new TypeError("sealed inline payload is not valid JSON");
|
|
19055
19055
|
}
|
|
19056
19056
|
if (typeof value !== "object" || value === null || Array.isArray(value) || canonicalize2(value) !== payloadText) throw new TypeError("sealed inline payload is not canonical JSON");
|
|
19057
|
-
const
|
|
19058
|
-
if (Object.keys(
|
|
19057
|
+
const record2 = value;
|
|
19058
|
+
if (Object.keys(record2).length !== 4 || record2.v !== 2 || typeof record2.c !== "string" || typeof record2.cid !== "string" || typeof record2.k !== "string") throw new TypeError("sealed inline payload has invalid fields");
|
|
19059
19059
|
let ciphertext;
|
|
19060
19060
|
let key32;
|
|
19061
19061
|
try {
|
|
19062
|
-
ciphertext = fromBase64Url2(
|
|
19063
|
-
key32 = fromBase64Url2(
|
|
19062
|
+
ciphertext = fromBase64Url2(record2.c);
|
|
19063
|
+
key32 = fromBase64Url2(record2.k);
|
|
19064
19064
|
} catch {
|
|
19065
19065
|
throw new TypeError("sealed inline payload has invalid base64url material");
|
|
19066
19066
|
}
|
|
19067
19067
|
if (ciphertext.byteLength === 0 || ciphertext.byteLength > MAX_INLINE_BYTES2) throw new TypeError("sealed inline ciphertext is outside the allowed size");
|
|
19068
19068
|
if (key32.byteLength !== KEY_LENGTH2) throw new TypeError("sealed inline key must be 32 bytes");
|
|
19069
|
-
assertCanonicalCid(
|
|
19070
|
-
if (await computeCid(ciphertext) !==
|
|
19071
|
-
return { kind: "inline", ciphertextCid:
|
|
19069
|
+
assertCanonicalCid(record2.cid);
|
|
19070
|
+
if (await computeCid(ciphertext) !== record2.cid) throw new TypeError("sealed inline ciphertext does not match its CID");
|
|
19071
|
+
return { kind: "inline", ciphertextCid: record2.cid, ciphertext, key32 };
|
|
19072
19072
|
}
|
|
19073
19073
|
var ARTIFACT_ROOT2 = "artifacts";
|
|
19074
19074
|
function parseArtifactVersionPath2(path) {
|
|
@@ -20539,16 +20539,16 @@ var ShareNotifyError = class extends Error {
|
|
|
20539
20539
|
}
|
|
20540
20540
|
code = "delivery-failed";
|
|
20541
20541
|
};
|
|
20542
|
-
function recipientMatchesShareRecord(
|
|
20543
|
-
const matcher =
|
|
20542
|
+
function recipientMatchesShareRecord(record2, recipient) {
|
|
20543
|
+
const matcher = record2.recipientMatcher;
|
|
20544
20544
|
const mailbox = canonicalMailbox(recipient);
|
|
20545
20545
|
if (mailbox === void 0) return false;
|
|
20546
20546
|
if (matcher.kind === "exactEmail") return canonicalMailbox(matcher.value)?.email === mailbox.email;
|
|
20547
20547
|
if (matcher.kind === "emailDomain") return mailbox.domain === matcher.value;
|
|
20548
20548
|
return false;
|
|
20549
20549
|
}
|
|
20550
|
-
function shareDeliveryWindowExpiresAt(
|
|
20551
|
-
const expiresAt = Math.min(Date.parse(
|
|
20550
|
+
function shareDeliveryWindowExpiresAt(record2) {
|
|
20551
|
+
const expiresAt = Math.min(Date.parse(record2.expiresAt), Date.parse(record2.registeredAt) + 5 * 60 * 1e3);
|
|
20552
20552
|
if (!Number.isFinite(expiresAt)) throw new ShareNotifyError("share delivery history has invalid timestamps");
|
|
20553
20553
|
return expiresAt;
|
|
20554
20554
|
}
|
|
@@ -20736,17 +20736,17 @@ async function deliverCredentialInvitation(input) {
|
|
|
20736
20736
|
}
|
|
20737
20737
|
return { status: "accepted" };
|
|
20738
20738
|
}
|
|
20739
|
-
function targetKind2(
|
|
20740
|
-
if (
|
|
20741
|
-
return
|
|
20739
|
+
function targetKind2(record2) {
|
|
20740
|
+
if (record2.targetKind !== void 0) return record2.targetKind;
|
|
20741
|
+
return record2.recipientMatcher.kind === "exactEmail" ? "email" : record2.recipientMatcher.kind === "emailDomain" ? "emailDomain" : record2.recipientMatcher.kind === "recipientDid" ? "recipientDid" : "bearer";
|
|
20742
20742
|
}
|
|
20743
|
-
function policyNodeAudience(
|
|
20744
|
-
const envelope =
|
|
20745
|
-
if (typeof envelope !== "object" || envelope === null || Array.isArray(envelope)) return
|
|
20743
|
+
function policyNodeAudience(record2) {
|
|
20744
|
+
const envelope = record2.deliveryMaterial?.envelope;
|
|
20745
|
+
if (typeof envelope !== "object" || envelope === null || Array.isArray(envelope)) return record2.target.nodeAudience;
|
|
20746
20746
|
const binding = envelope.attestedEnforcerBinding;
|
|
20747
|
-
if (typeof binding !== "object" || binding === null || Array.isArray(binding)) return
|
|
20747
|
+
if (typeof binding !== "object" || binding === null || Array.isArray(binding)) return record2.target.nodeAudience;
|
|
20748
20748
|
const nodeAudience = binding.nodeAudience;
|
|
20749
|
-
return typeof nodeAudience === "string" ? nodeAudience :
|
|
20749
|
+
return typeof nodeAudience === "string" ? nodeAudience : record2.target.nodeAudience;
|
|
20750
20750
|
}
|
|
20751
20751
|
async function revokeShare(input) {
|
|
20752
20752
|
const target = targetKind2(input.record);
|
|
@@ -20770,7 +20770,7 @@ async function revokeShare(input) {
|
|
|
20770
20770
|
}
|
|
20771
20771
|
let revokedAt = input.record.revokedAt ?? (input.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
|
|
20772
20772
|
if (input.records?.update !== void 0) {
|
|
20773
|
-
const updated = await input.records.update(input.record.shareId, (
|
|
20773
|
+
const updated = await input.records.update(input.record.shareId, (record2) => ({ ...record2, revokedAt: record2.revokedAt ?? revokedAt }));
|
|
20774
20774
|
revokedAt = updated?.revokedAt ?? revokedAt;
|
|
20775
20775
|
} else if (input.records !== void 0) {
|
|
20776
20776
|
const latest = await input.records.get(input.record.shareId);
|
|
@@ -20779,26 +20779,26 @@ async function revokeShare(input) {
|
|
|
20779
20779
|
}
|
|
20780
20780
|
return { state: "revoked", target, delegationCid, revokedAt };
|
|
20781
20781
|
}
|
|
20782
|
-
function redactRecord(
|
|
20783
|
-
const matcher =
|
|
20784
|
-
const revealedLink = revealLink ? link3 ??
|
|
20782
|
+
function redactRecord(record2, revealLink, link3) {
|
|
20783
|
+
const matcher = record2.recipientMatcher;
|
|
20784
|
+
const revealedLink = revealLink ? link3 ?? record2.link : void 0;
|
|
20785
20785
|
return {
|
|
20786
|
-
shareId:
|
|
20786
|
+
shareId: record2.shareId,
|
|
20787
20787
|
target: matcher.kind === "exactEmail" ? "email" : matcher.kind === "emailDomain" ? "email-domain" : matcher.kind === "recipientDid" ? "recipient-did" : "bearer",
|
|
20788
20788
|
...matcher.kind === "exactEmail" ? { recipient: matcher.value } : matcher.kind === "emailDomain" ? { recipient: `*@${matcher.value}` } : matcher.kind === "recipientDid" ? { recipient: matcher.value } : {},
|
|
20789
|
-
expiresAt:
|
|
20790
|
-
revoked:
|
|
20789
|
+
expiresAt: record2.expiresAt,
|
|
20790
|
+
revoked: record2.revokedAt !== void 0,
|
|
20791
20791
|
...revealedLink === void 0 ? {} : { link: revealedLink }
|
|
20792
20792
|
};
|
|
20793
20793
|
}
|
|
20794
20794
|
async function listShares(storage) {
|
|
20795
20795
|
const records = await storage.list();
|
|
20796
|
-
return records.map((
|
|
20796
|
+
return records.map((record2) => redactRecord(record2, false));
|
|
20797
20797
|
}
|
|
20798
20798
|
async function showShare(input) {
|
|
20799
|
-
const
|
|
20800
|
-
if (
|
|
20801
|
-
return redactRecord(
|
|
20799
|
+
const record2 = await input.storage.get(input.shareId);
|
|
20800
|
+
if (record2 === void 0) throw new Error("share not found");
|
|
20801
|
+
return redactRecord(record2, input.revealLink === true, input.link);
|
|
20802
20802
|
}
|
|
20803
20803
|
var SHARE_V2_PROTOCOL = Object.freeze({
|
|
20804
20804
|
challengeDomain: "xyz.tinycloud.share/policy-challenge/v2\0",
|
|
@@ -26306,6 +26306,60 @@ function parseDuration(input) {
|
|
|
26306
26306
|
// src/commands/share.ts
|
|
26307
26307
|
init_errors();
|
|
26308
26308
|
|
|
26309
|
+
// src/share/failure-class.ts
|
|
26310
|
+
init_constants();
|
|
26311
|
+
import { authorizationVerdictOf as authorizationVerdictOf2 } from "@tinycloud/sdk-core";
|
|
26312
|
+
var NETWORK_FAILURE = /\b(?:fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|UND_ERR_[A-Z_]+)\b|network ?error|failed to fetch/i;
|
|
26313
|
+
function record(value) {
|
|
26314
|
+
return typeof value === "object" && value !== null ? value : void 0;
|
|
26315
|
+
}
|
|
26316
|
+
function httpStatus(value) {
|
|
26317
|
+
const status = typeof value === "number" && Number.isInteger(value) && value >= 400 && value <= 599 ? value : void 0;
|
|
26318
|
+
return status;
|
|
26319
|
+
}
|
|
26320
|
+
function statusOf(error, depth = 0) {
|
|
26321
|
+
const fields = record(error);
|
|
26322
|
+
if (fields === void 0) return void 0;
|
|
26323
|
+
const direct = httpStatus(fields.status) ?? httpStatus(fields.statusCode) ?? httpStatus(record(fields.meta)?.status);
|
|
26324
|
+
return direct ?? (depth === 0 ? statusOf(fields.cause, 1) : void 0);
|
|
26325
|
+
}
|
|
26326
|
+
function codeOf(error) {
|
|
26327
|
+
const code4 = record(error)?.code;
|
|
26328
|
+
return typeof code4 === "string" && /^[A-Z][A-Z0-9_]{2,63}$/.test(code4) ? code4 : void 0;
|
|
26329
|
+
}
|
|
26330
|
+
function classifyShareFailure(error, loginHint) {
|
|
26331
|
+
const status = statusOf(error);
|
|
26332
|
+
const verdict = authorizationVerdictOf2(error);
|
|
26333
|
+
const message = error instanceof Error ? error.message : "";
|
|
26334
|
+
const code4 = codeOf(error);
|
|
26335
|
+
const detail = (text) => {
|
|
26336
|
+
const parts = [status === void 0 ? void 0 : `HTTP ${status}`, code4].filter((part) => part !== void 0);
|
|
26337
|
+
return parts.length === 0 ? text : `${text} (${parts.join(", ")})`;
|
|
26338
|
+
};
|
|
26339
|
+
if (verdict === "unauthenticated" || status === 401) {
|
|
26340
|
+
return { code: "AUTH_REQUIRED", exitCode: ExitCode.AUTH_REQUIRED, reason: detail(`the node did not accept this session; sign in again with ${loginHint}`) };
|
|
26341
|
+
}
|
|
26342
|
+
if (verdict === "forbidden" || status === 403) {
|
|
26343
|
+
return { code: "PERMISSION_DENIED", exitCode: ExitCode.PERMISSION_DENIED, reason: detail("the node refused this session's authority for the request") };
|
|
26344
|
+
}
|
|
26345
|
+
if (status === 404) {
|
|
26346
|
+
return { code: "NOT_FOUND", exitCode: ExitCode.NOT_FOUND, reason: detail("the node could not find what the request names") };
|
|
26347
|
+
}
|
|
26348
|
+
if (status !== void 0 && (status >= 500 || status === 408 || status === 429)) {
|
|
26349
|
+
return { code: "NODE_UNAVAILABLE", exitCode: ExitCode.NODE_ERROR, reason: detail("the node could not complete the request; try again shortly") };
|
|
26350
|
+
}
|
|
26351
|
+
if (status === 400 || status === 422) {
|
|
26352
|
+
return { code: "INVALID_ARGUMENT", exitCode: ExitCode.USAGE_ERROR, reason: detail("the node rejected the request as invalid") };
|
|
26353
|
+
}
|
|
26354
|
+
if (status !== void 0) {
|
|
26355
|
+
return { code: "NODE_REJECTED", exitCode: ExitCode.ERROR, reason: detail("the node rejected the request") };
|
|
26356
|
+
}
|
|
26357
|
+
if (NETWORK_FAILURE.test(message) || typeof record(error)?.code === "string" && NETWORK_FAILURE.test(String(record(error)?.code))) {
|
|
26358
|
+
return { code: "NETWORK_ERROR", exitCode: ExitCode.NETWORK_ERROR, reason: "the TinyCloud node could not be reached; check the connection and retry" };
|
|
26359
|
+
}
|
|
26360
|
+
return void 0;
|
|
26361
|
+
}
|
|
26362
|
+
|
|
26309
26363
|
// src/share/output.ts
|
|
26310
26364
|
function writeJson2(value) {
|
|
26311
26365
|
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
@@ -26473,8 +26527,8 @@ async function writeShareOutput(directory, filename, bytes, force) {
|
|
|
26473
26527
|
|
|
26474
26528
|
// src/share/errors.ts
|
|
26475
26529
|
var SharePublishAuthorityError = class extends Error {
|
|
26476
|
-
constructor(failure) {
|
|
26477
|
-
super(failure.kind);
|
|
26530
|
+
constructor(failure, options) {
|
|
26531
|
+
super(failure.kind, options);
|
|
26478
26532
|
this.failure = failure;
|
|
26479
26533
|
this.name = "SharePublishAuthorityError";
|
|
26480
26534
|
}
|
|
@@ -26592,6 +26646,17 @@ function shareCliError(error, operation = "publish") {
|
|
|
26592
26646
|
if (failure.kind === "storage-full") {
|
|
26593
26647
|
return storageFullError(failure);
|
|
26594
26648
|
}
|
|
26649
|
+
if (failure.kind === "space-not-ready") {
|
|
26650
|
+
return Object.assign(
|
|
26651
|
+
new CLIError(
|
|
26652
|
+
"SPACE_NOT_READY",
|
|
26653
|
+
"Your TinyCloud space isn't ready for this yet (SPACE_NOT_READY). This is a known node problem being fixed: retry after the node update; contact support with this code if it persists.",
|
|
26654
|
+
4,
|
|
26655
|
+
{ hint: "Nothing was shared, and repeating the command is safe. Retries keep failing until the node is updated." }
|
|
26656
|
+
),
|
|
26657
|
+
{ cause: error.cause }
|
|
26658
|
+
);
|
|
26659
|
+
}
|
|
26595
26660
|
if (failure.kind === "upload-failed") {
|
|
26596
26661
|
return new CLIError("UPLOAD_FAILED", "share source upload failed; nothing was shared", 4);
|
|
26597
26662
|
}
|
|
@@ -26625,8 +26690,10 @@ function shareCliError(error, operation = "publish") {
|
|
|
26625
26690
|
};
|
|
26626
26691
|
if (nodeCode === "ENOENT") return new CLIError("INVALID_ARGUMENT", "share input was not found", 2);
|
|
26627
26692
|
if (nodeCode === "EISDIR") return new CLIError("INVALID_ARGUMENT", "share input must be a Markdown file", 2);
|
|
26628
|
-
if (error instanceof TypeError) return new CLIError("INVALID_ARGUMENT", "share input is invalid", 2);
|
|
26629
26693
|
const mapped = typeof nodeCode === "string" && known[nodeCode] !== void 0 ? known[nodeCode] : known[message];
|
|
26694
|
+
const classified = mapped === void 0 ? classifyShareFailure(error, `\`${CLI_NAME12} auth login\``) : void 0;
|
|
26695
|
+
if (classified !== void 0) return Object.assign(new CLIError(classified.code, classified.reason, classified.exitCode), { cause: error });
|
|
26696
|
+
if (error instanceof TypeError) return new CLIError("INVALID_ARGUMENT", "share input is invalid", 2);
|
|
26630
26697
|
return new CLIError(mapped?.code ?? "INVALID_ARGUMENT", mapped ? mapped.code : "share operation failed", mapped?.exit ?? 2);
|
|
26631
26698
|
}
|
|
26632
26699
|
function inputUrl(value, stdin) {
|
|
@@ -26654,24 +26721,24 @@ function expires(value) {
|
|
|
26654
26721
|
}
|
|
26655
26722
|
}
|
|
26656
26723
|
async function rememberPublishedShare(result) {
|
|
26657
|
-
const
|
|
26658
|
-
if (shareServices.records === void 0) return { record, recorded: false };
|
|
26724
|
+
const record2 = historyRecordForPublishedShare(result);
|
|
26725
|
+
if (shareServices.records === void 0) return { record: record2, recorded: false };
|
|
26659
26726
|
try {
|
|
26660
|
-
await shareServices.records.put(
|
|
26661
|
-
return { record, recorded: true };
|
|
26727
|
+
await shareServices.records.put(record2);
|
|
26728
|
+
return { record: record2, recorded: true };
|
|
26662
26729
|
} catch {
|
|
26663
26730
|
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");
|
|
26664
|
-
return { record, recorded: false };
|
|
26731
|
+
return { record: record2, recorded: false };
|
|
26665
26732
|
}
|
|
26666
26733
|
}
|
|
26667
|
-
async function notifyRecordedShare(
|
|
26668
|
-
const result = await notifyShare({ shareId:
|
|
26734
|
+
async function notifyRecordedShare(record2, recipient, adapter, storage) {
|
|
26735
|
+
const result = await notifyShare({ shareId: record2.shareId, recipient, record: record2, adapter, checkDeliveryWindow: true });
|
|
26669
26736
|
if (result.state !== "partial-failure" && storage !== void 0) {
|
|
26670
26737
|
const mailbox = canonicalMailbox2(recipient).email;
|
|
26671
|
-
if (!
|
|
26738
|
+
if (!record2.deliveredRecipients?.includes(mailbox)) {
|
|
26672
26739
|
try {
|
|
26673
26740
|
if (storage.update === void 0) throw new Error("atomic sender history update is unavailable");
|
|
26674
|
-
const updated = await storage.update(
|
|
26741
|
+
const updated = await storage.update(record2.shareId, (current) => ({
|
|
26675
26742
|
...current,
|
|
26676
26743
|
deliveredRecipients: current.deliveredRecipients?.includes(mailbox) ? current.deliveredRecipients : [...current.deliveredRecipients ?? [], mailbox]
|
|
26677
26744
|
}));
|
|
@@ -26691,7 +26758,7 @@ function byteLimit(value) {
|
|
|
26691
26758
|
}
|
|
26692
26759
|
function mediaTypeFor(filename) {
|
|
26693
26760
|
const extension = filename.toLowerCase().split(".").at(-1);
|
|
26694
|
-
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";
|
|
26761
|
+
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" : extension === "jsx" ? "text/jsx" : extension === "tsx" ? "text/tsx" : "application/octet-stream";
|
|
26695
26762
|
}
|
|
26696
26763
|
function requestedActions(values) {
|
|
26697
26764
|
const actions = values === void 0 || values.length === 0 ? ["read"] : values;
|
|
@@ -26721,6 +26788,7 @@ function registerShareCommand(program2) {
|
|
|
26721
26788
|
const target = parseShareTarget(options.to);
|
|
26722
26789
|
const actions = requestedActions(options.action);
|
|
26723
26790
|
if (options.prefix && target.kind === "bearer") throw new CLIError("INVALID_ARGUMENT", "--prefix requires an addressed target", 2);
|
|
26791
|
+
if (target.kind === "bearer" && actions.includes("edit")) throw new CLIError("INVALID_ARGUMENT", `--action edit is not available with --to ${options.to}: a link can only be read; address a recipient to allow edits`, 2);
|
|
26724
26792
|
if (inputs.length > 1 && target.kind === "bearer") throw new CLIError("UNSUPPORTED_LINK", "multiple files require an addressed target", 2);
|
|
26725
26793
|
const artifact = artifactRequest(options, actions, inputs.length);
|
|
26726
26794
|
if (inputs.length > 1 && !options.prefix) throw new CLIError("INVALID_ARGUMENT", "multiple files require --prefix", 2);
|
|
@@ -26765,11 +26833,11 @@ function registerShareCommand(program2) {
|
|
|
26765
26833
|
}
|
|
26766
26834
|
throw new CLIError(result.method === "openkey-device" ? "DEVICE_AUTH_REQUIRED" : "CLAIM_REQUIRED", "recipient authorization is required; continue through the configured authority adapter", 6);
|
|
26767
26835
|
}
|
|
26768
|
-
const { record, recorded } = await rememberPublishedShare(result);
|
|
26836
|
+
const { record: record2, recorded } = await rememberPublishedShare(result);
|
|
26769
26837
|
let notification;
|
|
26770
26838
|
if (notifyRecipient !== void 0) {
|
|
26771
26839
|
if (shareServices.delivery === void 0) throw new CLIError("AUTH_REQUIRED", "delivery authority is not configured", 3);
|
|
26772
|
-
notification = await notifyRecordedShare(
|
|
26840
|
+
notification = await notifyRecordedShare(record2, notifyRecipient, shareServices.delivery, recorded ? shareServices.records : void 0);
|
|
26773
26841
|
if (notification.state === "partial-failure") process.exitCode = 9;
|
|
26774
26842
|
if (notification.reason === "delivery-window-expired") process.stderr.write(NOTIFY_WINDOW_MESSAGE);
|
|
26775
26843
|
}
|
|
@@ -26802,11 +26870,11 @@ function registerShareCommand(program2) {
|
|
|
26802
26870
|
if (shareServices.artifactStore === void 0) throw new CLIError("AUTH_REQUIRED", "artifact storage is not configured", 3);
|
|
26803
26871
|
const versions = await listArtifactVersions(await shareServices.artifactStore(), id);
|
|
26804
26872
|
const pinned = /* @__PURE__ */ new Map();
|
|
26805
|
-
for (const
|
|
26806
|
-
const path = parseArtifactVersionPath(
|
|
26873
|
+
for (const record2 of await shareServices.records?.list() ?? []) {
|
|
26874
|
+
const path = parseArtifactVersionPath(record2.resource.path);
|
|
26807
26875
|
if (path === void 0 || path.artifactId !== id) continue;
|
|
26808
26876
|
const shares = pinned.get(path.version) ?? [];
|
|
26809
|
-
shares.push({ shareId:
|
|
26877
|
+
shares.push({ shareId: record2.shareId, target: record2.targetKind ?? record2.recipientMatcher.kind, expiresAt: record2.expiresAt, ...record2.revokedAt === void 0 ? {} : { revokedAt: record2.revokedAt } });
|
|
26810
26878
|
pinned.set(path.version, shares);
|
|
26811
26879
|
}
|
|
26812
26880
|
const view = versions.map((version2) => ({
|
|
@@ -26906,19 +26974,19 @@ function registerShareCommand(program2) {
|
|
|
26906
26974
|
const json = jsonOutput(options, command);
|
|
26907
26975
|
if (shareServices.delivery === void 0) throw new CLIError("AUTH_REQUIRED", "delivery authority is not configured", 3);
|
|
26908
26976
|
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
26909
|
-
const
|
|
26910
|
-
if (
|
|
26911
|
-
if (!
|
|
26977
|
+
const record2 = await shareServices.records.get(id);
|
|
26978
|
+
if (record2 === void 0) throw new CLIError("NOT_FOUND", "share not found", 4);
|
|
26979
|
+
if (!record2.actions.includes("tinycloud.kv/get")) {
|
|
26912
26980
|
throw new CLIError("INVALID_ARGUMENT", "share notify requires a stored share with the read action; no invitation was sent", 2);
|
|
26913
26981
|
}
|
|
26914
26982
|
const mailbox = canonicalMailbox2(options.to);
|
|
26915
26983
|
if (mailbox === void 0) throw new ShareNotifyError("recipient is invalid");
|
|
26916
|
-
if (!recipientMatchesShareRecord(
|
|
26917
|
-
if (
|
|
26984
|
+
if (!recipientMatchesShareRecord(record2, mailbox.email)) throw new ShareNotifyError("recipient does not match the stored share target");
|
|
26985
|
+
if (record2.recipientMatcher.kind === "emailDomain" && shareDeliveryWindowExpiresAt(record2) > Date.now()) {
|
|
26918
26986
|
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);
|
|
26919
26987
|
await shareServices.assertDomainDelivery();
|
|
26920
26988
|
}
|
|
26921
|
-
const result = await notifyRecordedShare(
|
|
26989
|
+
const result = await notifyRecordedShare(record2, options.to, shareServices.delivery, shareServices.records);
|
|
26922
26990
|
if (json) writeJson2(result);
|
|
26923
26991
|
else process.stdout.write(`${result.state}
|
|
26924
26992
|
`);
|
|
@@ -26932,9 +27000,9 @@ function registerShareCommand(program2) {
|
|
|
26932
27000
|
try {
|
|
26933
27001
|
const json = jsonOutput(options, command);
|
|
26934
27002
|
if (shareServices.records === void 0) throw new CLIError("AUTH_REQUIRED", "sender history storage is not configured", 3);
|
|
26935
|
-
const
|
|
26936
|
-
if (
|
|
26937
|
-
const result = await revokeShare({ record, records: shareServices.records, adapter: shareServices.revocation, scope: options.ancestor ? "ancestor" : "direct" });
|
|
27003
|
+
const record2 = shareServices.getRecord ? await shareServices.getRecord(id) : await shareServices.records.get(id);
|
|
27004
|
+
if (record2 === void 0) throw new CLIError("NOT_FOUND", "share not found", 4);
|
|
27005
|
+
const result = await revokeShare({ record: record2, records: shareServices.records, adapter: shareServices.revocation, scope: options.ancestor ? "ancestor" : "direct" });
|
|
26938
27006
|
if (result.state === "unsupported") {
|
|
26939
27007
|
throw new CLIError("UNSUPPORTED_TARGET", result.reason, 2);
|
|
26940
27008
|
}
|
|
@@ -26985,6 +27053,25 @@ function kvArtifactStore(kv) {
|
|
|
26985
27053
|
};
|
|
26986
27054
|
}
|
|
26987
27055
|
|
|
27056
|
+
// src/share/space-not-ready.ts
|
|
27057
|
+
function isSpaceNotFound(error) {
|
|
27058
|
+
if (typeof error !== "object" || error === null) return false;
|
|
27059
|
+
const message = "message" in error && typeof error.message === "string" ? error.message : "";
|
|
27060
|
+
if (!/space not found/i.test(message)) return false;
|
|
27061
|
+
const meta = "meta" in error && typeof error.meta === "object" && error.meta !== null ? error.meta : void 0;
|
|
27062
|
+
const status = meta !== void 0 && "status" in meta ? meta.status : void 0;
|
|
27063
|
+
return status === 404 || /\b404\b/.test(message);
|
|
27064
|
+
}
|
|
27065
|
+
function spaceNotReadyFailure(cause) {
|
|
27066
|
+
return new SharePublishAuthorityError({ kind: "space-not-ready" }, { cause });
|
|
27067
|
+
}
|
|
27068
|
+
function failIfSpaceNotReady(result) {
|
|
27069
|
+
if (!result.ok && isSpaceNotFound(result.error)) throw spaceNotReadyFailure(result.error);
|
|
27070
|
+
}
|
|
27071
|
+
function artifactSpaceNotReady(error) {
|
|
27072
|
+
return error instanceof ArtifactError && isSpaceNotFound(error.cause) ? spaceNotReadyFailure(error.cause) : error;
|
|
27073
|
+
}
|
|
27074
|
+
|
|
26988
27075
|
// src/share/adapters.ts
|
|
26989
27076
|
init_storage();
|
|
26990
27077
|
init_profiles();
|
|
@@ -27064,7 +27151,7 @@ async function storeArtifactVersion(kv, version2, authority) {
|
|
|
27064
27151
|
try {
|
|
27065
27152
|
return await publishArtifactVersion(kvArtifactStore(kv), version2);
|
|
27066
27153
|
} catch (error) {
|
|
27067
|
-
throw scopeDeniedFromArtifactError(error, "KV upload", authority) ?? error;
|
|
27154
|
+
throw scopeDeniedFromArtifactError(error, "KV upload", authority) ?? artifactSpaceNotReady(error);
|
|
27068
27155
|
}
|
|
27069
27156
|
}
|
|
27070
27157
|
function createEncryptedSessionHistory() {
|
|
@@ -27077,8 +27164,8 @@ function createEncryptedSessionHistory() {
|
|
|
27077
27164
|
};
|
|
27078
27165
|
let keyPromise;
|
|
27079
27166
|
const key = async () => keyPromise ??= crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
|
|
27080
|
-
const encode6 = async (
|
|
27081
|
-
const secret = new TextEncoder().encode(JSON.stringify(
|
|
27167
|
+
const encode6 = async (record2) => {
|
|
27168
|
+
const secret = new TextEncoder().encode(JSON.stringify(record2));
|
|
27082
27169
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
27083
27170
|
const encrypted = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv }, await key(), secret));
|
|
27084
27171
|
const value = new Uint8Array(iv.length + encrypted.length);
|
|
@@ -27088,9 +27175,9 @@ function createEncryptedSessionHistory() {
|
|
|
27088
27175
|
};
|
|
27089
27176
|
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))));
|
|
27090
27177
|
return {
|
|
27091
|
-
async put(
|
|
27178
|
+
async put(record2) {
|
|
27092
27179
|
return serial(async () => {
|
|
27093
|
-
records.set(
|
|
27180
|
+
records.set(record2.shareId, await encode6(record2));
|
|
27094
27181
|
});
|
|
27095
27182
|
},
|
|
27096
27183
|
async update(shareId, change) {
|
|
@@ -27256,19 +27343,19 @@ function createEncryptedProfileHistory(profileName, sessionSigner) {
|
|
|
27256
27343
|
throw new ShareHistoryRetryError(profile);
|
|
27257
27344
|
});
|
|
27258
27345
|
return {
|
|
27259
|
-
async put(
|
|
27346
|
+
async put(record2) {
|
|
27260
27347
|
return locked(async (profile, ready) => {
|
|
27261
27348
|
const values = await read4(profile, ready);
|
|
27262
|
-
const index = values.findIndex((value) => value.shareId ===
|
|
27263
|
-
if (index >= 0) values[index] =
|
|
27264
|
-
else values.push(
|
|
27349
|
+
const index = values.findIndex((value) => value.shareId === record2.shareId);
|
|
27350
|
+
if (index >= 0) values[index] = record2;
|
|
27351
|
+
else values.push(record2);
|
|
27265
27352
|
await write(profile, values, ready);
|
|
27266
27353
|
}, true);
|
|
27267
27354
|
},
|
|
27268
27355
|
async update(shareId, change) {
|
|
27269
27356
|
return locked(async (profile, ready) => {
|
|
27270
27357
|
const values = await read4(profile, ready);
|
|
27271
|
-
const index = values.findIndex((
|
|
27358
|
+
const index = values.findIndex((record2) => record2.shareId === shareId);
|
|
27272
27359
|
if (index < 0) return void 0;
|
|
27273
27360
|
const updated = await change(values[index]);
|
|
27274
27361
|
values[index] = updated;
|
|
@@ -27280,11 +27367,11 @@ function createEncryptedProfileHistory(profileName, sessionSigner) {
|
|
|
27280
27367
|
return locked((profile, ready) => read4(profile, ready));
|
|
27281
27368
|
},
|
|
27282
27369
|
async get(shareId) {
|
|
27283
|
-
return locked(async (profile, ready) => (await read4(profile, ready)).find((
|
|
27370
|
+
return locked(async (profile, ready) => (await read4(profile, ready)).find((record2) => record2.shareId === shareId));
|
|
27284
27371
|
},
|
|
27285
27372
|
async delete(shareId) {
|
|
27286
27373
|
return locked(async (profile, ready) => {
|
|
27287
|
-
await write(profile, (await read4(profile, ready)).filter((
|
|
27374
|
+
await write(profile, (await read4(profile, ready)).filter((record2) => record2.shareId !== shareId), ready);
|
|
27288
27375
|
}, true);
|
|
27289
27376
|
}
|
|
27290
27377
|
};
|
|
@@ -27457,6 +27544,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
27457
27544
|
const written = await node.kvForSpace(ownerSpaceId).put(resourcePath2, file2.bytes.slice(), {
|
|
27458
27545
|
contentType: targetInput.mediaType ?? file2.mediaType ?? "application/octet-stream"
|
|
27459
27546
|
});
|
|
27547
|
+
failIfSpaceNotReady(written);
|
|
27460
27548
|
if (!written.ok) {
|
|
27461
27549
|
const code4 = typeof written.error === "object" && written.error !== null && "code" in written.error ? written.error.code : void 0;
|
|
27462
27550
|
if (code4 === "AUTH_UNAUTHORIZED" || code4 === "PERMISSION_DENIED") {
|
|
@@ -27556,6 +27644,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
27556
27644
|
resourcePath = artifactVersionFilePath(artifact.id, artifactVersion.version, storageName);
|
|
27557
27645
|
} else {
|
|
27558
27646
|
const stored = await node.kvForSpace(ownerSpaceId).put(resourcePath, storedBytes, { contentType: "application/vnd.tinycloud.encrypted-envelope+json" });
|
|
27647
|
+
failIfSpaceNotReady(stored);
|
|
27559
27648
|
if (!stored.ok) {
|
|
27560
27649
|
const code4 = typeof stored.error === "object" && stored.error !== null && "code" in stored.error ? stored.error.code : void 0;
|
|
27561
27650
|
if (code4 === "AUTH_UNAUTHORIZED" || code4 === "PERMISSION_DENIED") {
|
|
@@ -27622,21 +27711,21 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
27622
27711
|
return published;
|
|
27623
27712
|
} };
|
|
27624
27713
|
const delivery = { deliver: input.deliver ?? (async (request) => {
|
|
27625
|
-
const
|
|
27626
|
-
if (
|
|
27627
|
-
const expiry = shareDeliveryWindowExpiresAt(
|
|
27714
|
+
const record2 = request.record;
|
|
27715
|
+
if (record2 === void 0 || record2.link === void 0 || record2.deliveryMaterial === void 0 || request.idempotencyKey === void 0) throw new Error("share delivery history is incomplete");
|
|
27716
|
+
const expiry = shareDeliveryWindowExpiresAt(record2);
|
|
27628
27717
|
if (expiry <= Date.now()) throw new ShareNotifyError("share delivery authorization window has expired", "delivery-window-expired");
|
|
27629
27718
|
const authorizationExpiresAt = new Date(expiry).toISOString();
|
|
27630
27719
|
const [config, node] = await Promise.all([publicConfig(), authenticatedNode()]);
|
|
27631
27720
|
const receipt = await node.authorizeShareDeliveryV3({
|
|
27632
|
-
envelope:
|
|
27633
|
-
sealedEnvelope:
|
|
27634
|
-
envelopeKey:
|
|
27635
|
-
shareCid:
|
|
27636
|
-
resourcePath:
|
|
27721
|
+
envelope: record2.deliveryMaterial.envelope,
|
|
27722
|
+
sealedEnvelope: record2.deliveryMaterial.sealedEnvelope,
|
|
27723
|
+
envelopeKey: record2.deliveryMaterial.envelopeKey,
|
|
27724
|
+
shareCid: record2.deliveryMaterial.shareCid,
|
|
27725
|
+
resourcePath: record2.resource.path,
|
|
27637
27726
|
recipientEmail: request.recipient,
|
|
27638
|
-
shareUrl:
|
|
27639
|
-
documentName:
|
|
27727
|
+
shareUrl: record2.link,
|
|
27728
|
+
documentName: record2.filename ?? "share.md",
|
|
27640
27729
|
expiresAt: authorizationExpiresAt,
|
|
27641
27730
|
deliveryAudience: config.credentialsOrigin,
|
|
27642
27731
|
idempotencyKey: request.idempotencyKey
|
|
@@ -27644,7 +27733,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
27644
27733
|
await deliverCredentialInvitation({
|
|
27645
27734
|
credentialsOrigin: config.credentialsOrigin,
|
|
27646
27735
|
receipt,
|
|
27647
|
-
shareUrl:
|
|
27736
|
+
shareUrl: record2.link,
|
|
27648
27737
|
fetchFn,
|
|
27649
27738
|
signal: request.signal
|
|
27650
27739
|
});
|
|
@@ -27657,15 +27746,15 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
27657
27746
|
// proofless session-key revocation covers the first, and a local owner
|
|
27658
27747
|
// key covers both. Without either key (a session-only profile that signed
|
|
27659
27748
|
// in again since, for example) the link cannot be revoked here.
|
|
27660
|
-
revokeDelegation: input.revokeDelegation ?? (async ({ delegationCid, record }) => {
|
|
27749
|
+
revokeDelegation: input.revokeDelegation ?? (async ({ delegationCid, record: record2 }) => {
|
|
27661
27750
|
const node = await authenticatedNode();
|
|
27662
27751
|
const activeNode = await node.activeNodeIdentity();
|
|
27663
|
-
if (
|
|
27752
|
+
if (record2.target.origin !== activeNode.origin) throw new Error("share delegation revocation is not bound to the active owner node");
|
|
27664
27753
|
const linkUnavailable = new CLIError("SHARE_LINK_UNAVAILABLE", "this share's stored link could not be verified; nothing was revoked", ExitCode.NOT_FOUND);
|
|
27665
|
-
const resource = `${
|
|
27754
|
+
const resource = `${record2.target.spaceId}/kv/${record2.resource.path}`;
|
|
27666
27755
|
let sessionIssued;
|
|
27667
27756
|
try {
|
|
27668
|
-
const decoded = node.sharing.decodeLink(parseNativeShareUrl(
|
|
27757
|
+
const decoded = node.sharing.decodeLink(parseNativeShareUrl(record2.link ?? ""));
|
|
27669
27758
|
const linkKey = decoded.keyDid.split("#", 1)[0];
|
|
27670
27759
|
const authorization2 = withoutBearer(decoded.delegation.authHeader ?? "");
|
|
27671
27760
|
if (authorization2.split(".").length === 3) {
|
|
@@ -27674,7 +27763,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
27674
27763
|
sessionIssued = signed.payload.iss.split("#", 1)[0] === node.credentialHolderDid;
|
|
27675
27764
|
} else {
|
|
27676
27765
|
const signed = await parseSignedSiweCacao(authorization2, delegationCid);
|
|
27677
|
-
const owner = /^tinycloud:pkh:(eip155:[1-9]\d*:0x[0-9a-fA-F]{40}):/.exec(
|
|
27766
|
+
const owner = /^tinycloud:pkh:(eip155:[1-9]\d*:0x[0-9a-fA-F]{40}):/.exec(record2.target.spaceId)?.[1];
|
|
27678
27767
|
if (owner === void 0 || signed.issuer.toLowerCase() !== `did:pkh:${owner}`.toLowerCase() || signed.audience !== linkKey || signed.attenuation[resource] === void 0) throw linkUnavailable;
|
|
27679
27768
|
sessionIssued = false;
|
|
27680
27769
|
}
|
|
@@ -27770,7 +27859,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
27770
27859
|
try {
|
|
27771
27860
|
return await operation();
|
|
27772
27861
|
} catch (error) {
|
|
27773
|
-
throw scopeDeniedFromArtifactError(error, "artifact storage", authority) ?? error;
|
|
27862
|
+
throw scopeDeniedFromArtifactError(error, "artifact storage", authority) ?? artifactSpaceNotReady(error);
|
|
27774
27863
|
}
|
|
27775
27864
|
};
|
|
27776
27865
|
return {
|