@tinycloud/cli 1.3.0-beta.19 → 1.3.0-beta.21
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 +177 -14
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +154 -13
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +7 -7
- package/skills/tc-cli/REFERENCE.md +3 -1
package/dist/legacy-entry.js
CHANGED
|
@@ -23736,6 +23736,20 @@ var v3TargetSchema = external_exports.object({
|
|
|
23736
23736
|
nodeAudience: external_exports.string().min(1),
|
|
23737
23737
|
spaceId: external_exports.string().refine(isCanonicalPathSegment, { message: "expected a canonical space id" })
|
|
23738
23738
|
}).strict();
|
|
23739
|
+
var ARTIFACT_ID_PATTERN = /^[a-z0-9][a-z0-9_-]{2,62}$/;
|
|
23740
|
+
var artifactPinSchema = external_exports.object({
|
|
23741
|
+
v: external_exports.literal(1),
|
|
23742
|
+
artifactId: external_exports.string().regex(ARTIFACT_ID_PATTERN),
|
|
23743
|
+
version: external_exports.number().int().min(1).max(Number.MAX_SAFE_INTEGER),
|
|
23744
|
+
/** SHA-256 (lowercase hex) of the exact `manifest.json` bytes. The manifest itself stays an owner-side record. */
|
|
23745
|
+
manifestSha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
23746
|
+
/** An addressed share reads one exact file, so exactly one entry: the stored bytes (ciphertext) it will fetch. */
|
|
23747
|
+
files: external_exports.array(external_exports.object({
|
|
23748
|
+
path: external_exports.string().min(1).max(255),
|
|
23749
|
+
sha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
23750
|
+
bytes: external_exports.number().int().nonnegative()
|
|
23751
|
+
}).strict()).length(1)
|
|
23752
|
+
}).strict();
|
|
23739
23753
|
var unsignedShareEnvelopeV3BaseSchema = external_exports.object({
|
|
23740
23754
|
version: external_exports.literal(3),
|
|
23741
23755
|
shareId: external_exports.string().min(1),
|
|
@@ -23755,7 +23769,13 @@ var unsignedShareEnvelopeV3BaseSchema = external_exports.object({
|
|
|
23755
23769
|
expiry: external_exports.string().datetime({ offset: true }),
|
|
23756
23770
|
display: displaySchema,
|
|
23757
23771
|
encrypted: external_exports.literal(true),
|
|
23758
|
-
metadata: contentMetadataSchema
|
|
23772
|
+
metadata: contentMetadataSchema,
|
|
23773
|
+
/**
|
|
23774
|
+
* TC-1428: an owner-signed statement that this share reads one write-once artifact version. Additive: absent on
|
|
23775
|
+
* every other share, and covered by the envelope signature because the signature spans the whole unsigned object.
|
|
23776
|
+
* The shape is checked here; its binding to the content source is `verifyArtifactShare` in share-sdk.
|
|
23777
|
+
*/
|
|
23778
|
+
artifactPin: artifactPinSchema.optional()
|
|
23759
23779
|
}).strict();
|
|
23760
23780
|
function validateV3Invariants(value, ctx) {
|
|
23761
23781
|
const actions = [...value.actions];
|
|
@@ -23791,6 +23811,12 @@ var shareEnvelopeV3Schema = unsignedShareEnvelopeV3BaseSchema.extend({ signature
|
|
|
23791
23811
|
var ENVELOPE_AAD_LABEL = "tinycloud-share-envelope-v1";
|
|
23792
23812
|
var AAD = utf8Bytes(ENVELOPE_AAD_LABEL);
|
|
23793
23813
|
var MAX_INLINE_BYTES = 256 * 1024;
|
|
23814
|
+
var ARTIFACT_ROOT = "artifacts";
|
|
23815
|
+
function parseArtifactVersionPath(path) {
|
|
23816
|
+
const match = /^artifacts\/([a-z0-9][a-z0-9_-]{2,62})\/versions\/([1-9][0-9]{0,14})\/([^/]+)$/.exec(path);
|
|
23817
|
+
if (match === null) return void 0;
|
|
23818
|
+
return { artifactId: match[1], version: Number(match[2]), file: match[3] };
|
|
23819
|
+
}
|
|
23794
23820
|
var UNSAFE_FILENAME_CODE_POINT = /[\p{Cc}\p{Cf}\p{Cs}\u2028\u2029]/u;
|
|
23795
23821
|
function hasUnsafeFilenameCodePoint(value) {
|
|
23796
23822
|
return UNSAFE_FILENAME_CODE_POINT.test(value);
|
|
@@ -23802,7 +23828,9 @@ function canonicalShareFilename(value) {
|
|
|
23802
23828
|
}
|
|
23803
23829
|
return canonical;
|
|
23804
23830
|
}
|
|
23805
|
-
|
|
23831
|
+
function sha256Hex(bytes) {
|
|
23832
|
+
return Array.from(sha2562(bytes), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
23833
|
+
}
|
|
23806
23834
|
var ARTIFACT_MANIFEST_NAME = "manifest.json";
|
|
23807
23835
|
var ARTIFACT_MANIFEST_VERSION = 1;
|
|
23808
23836
|
var ARTIFACT_ID = /^[a-z0-9][a-z0-9_-]{2,62}$/;
|
|
@@ -23815,9 +23843,6 @@ var ArtifactError = class extends Error {
|
|
|
23815
23843
|
this.code = code22;
|
|
23816
23844
|
}
|
|
23817
23845
|
};
|
|
23818
|
-
function sha256Hex(bytes) {
|
|
23819
|
-
return Array.from(sha2562(bytes), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
23820
|
-
}
|
|
23821
23846
|
function newArtifactId(random = (length23) => crypto.getRandomValues(new Uint8Array(length23))) {
|
|
23822
23847
|
return `art_${Array.from(random(8), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
23823
23848
|
}
|
|
@@ -23840,11 +23865,6 @@ function artifactVersionResource(artifactId, version) {
|
|
|
23840
23865
|
function artifactVersionFilePath(artifactId, version, filename) {
|
|
23841
23866
|
return `${artifactVersionResource(artifactId, version)}/${filename}`;
|
|
23842
23867
|
}
|
|
23843
|
-
function parseArtifactVersionPath(path) {
|
|
23844
|
-
const match = /^artifacts\/([a-z0-9][a-z0-9_-]{2,62})\/versions\/([1-9][0-9]{0,14})\/([^/]+)$/.exec(path);
|
|
23845
|
-
if (match === null) return void 0;
|
|
23846
|
-
return { artifactId: match[1], version: Number(match[2]), file: match[3] };
|
|
23847
|
-
}
|
|
23848
23868
|
function parseArtifactManifest(bytes) {
|
|
23849
23869
|
let value;
|
|
23850
23870
|
try {
|
|
@@ -29216,6 +29236,20 @@ var v3TargetSchema2 = external_exports2.object({
|
|
|
29216
29236
|
nodeAudience: external_exports2.string().min(1),
|
|
29217
29237
|
spaceId: external_exports2.string().refine(isCanonicalPathSegment2, { message: "expected a canonical space id" })
|
|
29218
29238
|
}).strict();
|
|
29239
|
+
var ARTIFACT_ID_PATTERN2 = /^[a-z0-9][a-z0-9_-]{2,62}$/;
|
|
29240
|
+
var artifactPinSchema2 = external_exports2.object({
|
|
29241
|
+
v: external_exports2.literal(1),
|
|
29242
|
+
artifactId: external_exports2.string().regex(ARTIFACT_ID_PATTERN2),
|
|
29243
|
+
version: external_exports2.number().int().min(1).max(Number.MAX_SAFE_INTEGER),
|
|
29244
|
+
/** SHA-256 (lowercase hex) of the exact `manifest.json` bytes. The manifest itself stays an owner-side record. */
|
|
29245
|
+
manifestSha256: external_exports2.string().regex(/^[0-9a-f]{64}$/),
|
|
29246
|
+
/** An addressed share reads one exact file, so exactly one entry: the stored bytes (ciphertext) it will fetch. */
|
|
29247
|
+
files: external_exports2.array(external_exports2.object({
|
|
29248
|
+
path: external_exports2.string().min(1).max(255),
|
|
29249
|
+
sha256: external_exports2.string().regex(/^[0-9a-f]{64}$/),
|
|
29250
|
+
bytes: external_exports2.number().int().nonnegative()
|
|
29251
|
+
}).strict()).length(1)
|
|
29252
|
+
}).strict();
|
|
29219
29253
|
var unsignedShareEnvelopeV3BaseSchema2 = external_exports2.object({
|
|
29220
29254
|
version: external_exports2.literal(3),
|
|
29221
29255
|
shareId: external_exports2.string().min(1),
|
|
@@ -29235,7 +29269,13 @@ var unsignedShareEnvelopeV3BaseSchema2 = external_exports2.object({
|
|
|
29235
29269
|
expiry: external_exports2.string().datetime({ offset: true }),
|
|
29236
29270
|
display: displaySchema2,
|
|
29237
29271
|
encrypted: external_exports2.literal(true),
|
|
29238
|
-
metadata: contentMetadataSchema2
|
|
29272
|
+
metadata: contentMetadataSchema2,
|
|
29273
|
+
/**
|
|
29274
|
+
* TC-1428: an owner-signed statement that this share reads one write-once artifact version. Additive: absent on
|
|
29275
|
+
* every other share, and covered by the envelope signature because the signature spans the whole unsigned object.
|
|
29276
|
+
* The shape is checked here; its binding to the content source is `verifyArtifactShare` in share-sdk.
|
|
29277
|
+
*/
|
|
29278
|
+
artifactPin: artifactPinSchema2.optional()
|
|
29239
29279
|
}).strict();
|
|
29240
29280
|
function validateV3Invariants2(value, ctx) {
|
|
29241
29281
|
const actions = [...value.actions];
|
|
@@ -29579,6 +29619,80 @@ async function parseSealedInlineShareUrl(url, options = {}) {
|
|
|
29579
29619
|
if (await computeCid(ciphertext) !== record2.cid) throw new TypeError("sealed inline ciphertext does not match its CID");
|
|
29580
29620
|
return { kind: "inline", ciphertextCid: record2.cid, ciphertext, key32 };
|
|
29581
29621
|
}
|
|
29622
|
+
var ARTIFACT_ROOT2 = "artifacts";
|
|
29623
|
+
function parseArtifactVersionPath2(path) {
|
|
29624
|
+
const match = /^artifacts\/([a-z0-9][a-z0-9_-]{2,62})\/versions\/([1-9][0-9]{0,14})\/([^/]+)$/.exec(path);
|
|
29625
|
+
if (match === null) return void 0;
|
|
29626
|
+
return { artifactId: match[1], version: Number(match[2]), file: match[3] };
|
|
29627
|
+
}
|
|
29628
|
+
var ArtifactPinError = class extends Error {
|
|
29629
|
+
code;
|
|
29630
|
+
/** The code is the message: stable, short, and what callers and tests match on. */
|
|
29631
|
+
constructor(code32) {
|
|
29632
|
+
super(code32);
|
|
29633
|
+
this.name = "ArtifactPinError";
|
|
29634
|
+
this.code = code32;
|
|
29635
|
+
}
|
|
29636
|
+
};
|
|
29637
|
+
function artifactBindingView(envelope) {
|
|
29638
|
+
return {
|
|
29639
|
+
...envelope.artifactPin === void 0 ? {} : { artifactPin: envelope.artifactPin },
|
|
29640
|
+
target: envelope.target,
|
|
29641
|
+
contentSource: envelope.contentSource,
|
|
29642
|
+
resource: envelope.resource,
|
|
29643
|
+
actions: envelope.actions,
|
|
29644
|
+
policyKvActions: envelope.policy.capabilityCeiling.flatMap((capability) => capability.kind === "kv" ? capability.actions : [])
|
|
29645
|
+
};
|
|
29646
|
+
}
|
|
29647
|
+
function sourcePath(view) {
|
|
29648
|
+
const resource = view.contentSource.kvResource;
|
|
29649
|
+
const marker = "/kv/";
|
|
29650
|
+
const at = resource.indexOf(marker);
|
|
29651
|
+
if (at <= 0 || resource.slice(0, at) !== view.target.spaceId) {
|
|
29652
|
+
throw new ArtifactPinError("pin-source-mismatch");
|
|
29653
|
+
}
|
|
29654
|
+
return resource.slice(at + marker.length);
|
|
29655
|
+
}
|
|
29656
|
+
function assertArtifactBinding(view, expected = {}) {
|
|
29657
|
+
const pin = view.artifactPin;
|
|
29658
|
+
const path = sourcePath(view);
|
|
29659
|
+
const inArtifacts = path === ARTIFACT_ROOT2 || path.startsWith(`${ARTIFACT_ROOT2}/`);
|
|
29660
|
+
if (!inArtifacts) {
|
|
29661
|
+
if (pin !== void 0) throw new ArtifactPinError("pin-source-mismatch");
|
|
29662
|
+
return void 0;
|
|
29663
|
+
}
|
|
29664
|
+
if (pin === void 0) throw new ArtifactPinError("missing-pin");
|
|
29665
|
+
const parsed = parseArtifactVersionPath2(path);
|
|
29666
|
+
if (parsed === void 0) throw new ArtifactPinError("unsupported-artifact-path");
|
|
29667
|
+
const file = pin.files[0];
|
|
29668
|
+
const source = view.contentSource;
|
|
29669
|
+
if (
|
|
29670
|
+
// The stored ciphertext of one file: bounded like content (100 MiB) plus the envelope's own framing.
|
|
29671
|
+
file.bytes > 128 * 1024 * 1024 || pin.artifactId !== parsed.artifactId || pin.version !== parsed.version || file.path !== parsed.file || view.resource.kind !== "exact" || view.resource.path !== path || source.selector !== "exact" || source.mode !== "immutable" || source.initialCiphertextDigestHex !== file.sha256
|
|
29672
|
+
) {
|
|
29673
|
+
throw new ArtifactPinError("pin-source-mismatch");
|
|
29674
|
+
}
|
|
29675
|
+
if (view.actions.includes("edit") || view.policyKvActions.includes("tinycloud.kv/put")) {
|
|
29676
|
+
throw new ArtifactPinError("pinned-share-writable");
|
|
29677
|
+
}
|
|
29678
|
+
if (expected.artifactId !== void 0 && expected.artifactId !== pin.artifactId || expected.version !== void 0 && expected.version !== pin.version) {
|
|
29679
|
+
throw new ArtifactPinError("expectation-mismatch");
|
|
29680
|
+
}
|
|
29681
|
+
return pin;
|
|
29682
|
+
}
|
|
29683
|
+
function verifyArtifactShare(envelope, options) {
|
|
29684
|
+
if (envelope.signature.signerDid !== options.expectedOwnerDid) {
|
|
29685
|
+
throw new ArtifactPinError("wrong-signer");
|
|
29686
|
+
}
|
|
29687
|
+
let valid;
|
|
29688
|
+
try {
|
|
29689
|
+
valid = verifyEnvelopeV3SignatureOnly(envelope) && envelope.policy.ownerDid === options.expectedOwnerDid;
|
|
29690
|
+
} catch {
|
|
29691
|
+
valid = false;
|
|
29692
|
+
}
|
|
29693
|
+
if (!valid) throw new ArtifactPinError("bad-signature");
|
|
29694
|
+
return assertArtifactBinding(artifactBindingView(envelope), options.expected);
|
|
29695
|
+
}
|
|
29582
29696
|
var SHARE_RESULT_VERSION = 1;
|
|
29583
29697
|
var DEFAULT_MAX_SEALED_BLOB_BYTES = 100 * 1024 * 1024 + 29;
|
|
29584
29698
|
var ShareReceiveError = class extends Error {
|
|
@@ -29609,7 +29723,8 @@ function metadataFor(envelope, origin) {
|
|
|
29609
29723
|
...envelope.display.senderName === void 0 ? {} : { senderName: envelope.display.senderName },
|
|
29610
29724
|
...envelope.display.filename === void 0 ? {} : { filename: envelope.display.filename },
|
|
29611
29725
|
...envelope.display.mode === void 0 ? {} : { mode: envelope.display.mode }
|
|
29612
|
-
}
|
|
29726
|
+
},
|
|
29727
|
+
...envelope.artifactPin === void 0 ? {} : { artifact: { id: envelope.artifactPin.artifactId, version: envelope.artifactPin.version } }
|
|
29613
29728
|
};
|
|
29614
29729
|
}
|
|
29615
29730
|
async function resolvePolicyShare(link3, options) {
|
|
@@ -29640,6 +29755,12 @@ async function resolvePolicyShare(link3, options) {
|
|
|
29640
29755
|
} catch {
|
|
29641
29756
|
throw new ShareReceiveError("signature-invalid", "share signature is invalid");
|
|
29642
29757
|
}
|
|
29758
|
+
try {
|
|
29759
|
+
verifyArtifactShare(envelope, { expectedOwnerDid: envelope.policy.ownerDid });
|
|
29760
|
+
} catch (error) {
|
|
29761
|
+
if (!(error instanceof ArtifactPinError)) throw error;
|
|
29762
|
+
throw new ShareReceiveError("envelope-invalid", `share artifact pin is invalid (${error.code})`);
|
|
29763
|
+
}
|
|
29643
29764
|
options.signal?.throwIfAborted();
|
|
29644
29765
|
const expiry = Date.parse(envelope.expiry);
|
|
29645
29766
|
if (!Number.isFinite(expiry)) throw new ShareReceiveError("envelope-invalid", "share expiry is invalid");
|
|
@@ -36148,6 +36269,20 @@ var v3TargetSchema3 = external_exports3.object({
|
|
|
36148
36269
|
nodeAudience: external_exports3.string().min(1),
|
|
36149
36270
|
spaceId: external_exports3.string().refine(isCanonicalPathSegment3, { message: "expected a canonical space id" })
|
|
36150
36271
|
}).strict();
|
|
36272
|
+
var ARTIFACT_ID_PATTERN3 = /^[a-z0-9][a-z0-9_-]{2,62}$/;
|
|
36273
|
+
var artifactPinSchema3 = external_exports3.object({
|
|
36274
|
+
v: external_exports3.literal(1),
|
|
36275
|
+
artifactId: external_exports3.string().regex(ARTIFACT_ID_PATTERN3),
|
|
36276
|
+
version: external_exports3.number().int().min(1).max(Number.MAX_SAFE_INTEGER),
|
|
36277
|
+
/** SHA-256 (lowercase hex) of the exact `manifest.json` bytes. The manifest itself stays an owner-side record. */
|
|
36278
|
+
manifestSha256: external_exports3.string().regex(/^[0-9a-f]{64}$/),
|
|
36279
|
+
/** An addressed share reads one exact file, so exactly one entry: the stored bytes (ciphertext) it will fetch. */
|
|
36280
|
+
files: external_exports3.array(external_exports3.object({
|
|
36281
|
+
path: external_exports3.string().min(1).max(255),
|
|
36282
|
+
sha256: external_exports3.string().regex(/^[0-9a-f]{64}$/),
|
|
36283
|
+
bytes: external_exports3.number().int().nonnegative()
|
|
36284
|
+
}).strict()).length(1)
|
|
36285
|
+
}).strict();
|
|
36151
36286
|
var unsignedShareEnvelopeV3BaseSchema3 = external_exports3.object({
|
|
36152
36287
|
version: external_exports3.literal(3),
|
|
36153
36288
|
shareId: external_exports3.string().min(1),
|
|
@@ -36167,7 +36302,13 @@ var unsignedShareEnvelopeV3BaseSchema3 = external_exports3.object({
|
|
|
36167
36302
|
expiry: external_exports3.string().datetime({ offset: true }),
|
|
36168
36303
|
display: displaySchema3,
|
|
36169
36304
|
encrypted: external_exports3.literal(true),
|
|
36170
|
-
metadata: contentMetadataSchema3
|
|
36305
|
+
metadata: contentMetadataSchema3,
|
|
36306
|
+
/**
|
|
36307
|
+
* TC-1428: an owner-signed statement that this share reads one write-once artifact version. Additive: absent on
|
|
36308
|
+
* every other share, and covered by the envelope signature because the signature spans the whole unsigned object.
|
|
36309
|
+
* The shape is checked here; its binding to the content source is `verifyArtifactShare` in share-sdk.
|
|
36310
|
+
*/
|
|
36311
|
+
artifactPin: artifactPinSchema3.optional()
|
|
36171
36312
|
}).strict();
|
|
36172
36313
|
function validateV3Invariants3(value, ctx) {
|
|
36173
36314
|
const actions = [...value.actions];
|