@popcraft/cli 0.32.0 → 0.33.0
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/popcraft.mjs +136 -21
- package/package.json +2 -2
package/dist/popcraft.mjs
CHANGED
|
@@ -594,7 +594,7 @@ var init_openapi = __esm({
|
|
|
594
594
|
init_api_limits();
|
|
595
595
|
init_listing();
|
|
596
596
|
init_groups();
|
|
597
|
-
API_VERSION = "1.
|
|
597
|
+
API_VERSION = "1.4.0";
|
|
598
598
|
ref = (name2) => ({ $ref: `#/components/schemas/${name2}` });
|
|
599
599
|
str = { type: "string" };
|
|
600
600
|
nstr = { type: ["string", "null"] };
|
|
@@ -897,7 +897,7 @@ Lists are paged: follow \`nextCursor\` (passing it as \`?cursor=\`) until it is
|
|
|
897
897
|
"/files/{key}": {
|
|
898
898
|
get: op("Files", "File metadata, your role and document JSON", "files:read", ok(ref("FileDetail")), { parameters: [key, query("depth", { type: "string", enum: ["metadata"] }, "Omit the document")] }),
|
|
899
899
|
put: op("Files", "Replace the document", "files:write", ok(ref("WriteResult")), {
|
|
900
|
-
description: "Body: a `Document`, `{ document }` or a .popcraft export. A live file takes the difference as one edit in its collaborative log, so people editing it see the change merge in; private (PopCorn) layers are never written. Send `If-Match: <revision>` to write only if the file has not changed since you read it. Needs edit access.",
|
|
900
|
+
description: "Body: a `Document`, `{ document }` or a .popcraft export, and may be gzipped (`Content-Encoding: gzip`). Requests are capped at about 4.5 MB on the wire, so upload pictures, video and fonts first (`POST /files/{key}/media`) and send a document that names them as `media://<hash>`. A live file takes the difference as one edit in its collaborative log, so people editing it see the change merge in; private (PopCorn) layers are never written. Send `If-Match: <revision>` to write only if the file has not changed since you read it. Needs edit access.",
|
|
901
901
|
parameters: [key, { name: "If-Match", in: "header", required: false, schema: str, description: "The `revision` you read" }],
|
|
902
902
|
requestBody: { required: true, content: { "application/json": { schema: ref("Document") } } },
|
|
903
903
|
responses: {
|
|
@@ -922,6 +922,14 @@ Lists are paged: follow \`nextCursor\` (passing it as \`?cursor=\`) until it is
|
|
|
922
922
|
"/files/{key}/nodes": { get: op("Files", "Nodes with their subtrees", "files:read", ok(ref("NodeResult")), { parameters: [key, query("ids", str, "Comma-separated node ids (\u2264 200)", true), query("depth", { type: "string", enum: ["1"] }, "Only the nodes themselves, no descendants")], responses: { "400": { description: "`ids` missing", content: errBody } } }) },
|
|
923
923
|
"/files/{key}/images": { get: op("Files", "Thumbnail and media assets the file references", "files:read", ok(ref("Images")), { parameters: [key] }) },
|
|
924
924
|
"/files/{key}/thumbnail": { get: op("Files", "Preview image bytes", "files:read", ok({ type: "string", format: "binary" }, "PNG or WebP bytes", "image/*"), { parameters: [key] }) },
|
|
925
|
+
"/files/{key}/media": {
|
|
926
|
+
post: op("Files", "Upload media the file uses", "files:write", null, {
|
|
927
|
+
description: 'The raw bytes of a picture, video, audio or font file, with `x-media-hash` set to their hash (SHA-256, the first 32 hex characters). The document, or a command such as `font.add` (`src: "media://<hash>"`), can then name them. A workspace stores the same bytes once. Needs edit access.',
|
|
928
|
+
parameters: [key, { name: "x-media-hash", in: "header", required: true, schema: str, description: "The bytes' hash: the first 32 hex characters of their SHA-256" }],
|
|
929
|
+
requestBody: { required: true, content: { "*/*": { schema: { type: "string", format: "binary" } } } },
|
|
930
|
+
responses: { "200": ok(obj({ hash: str, uploaded: bool }, ["hash", "uploaded"]), "Already stored"), "201": ok(obj({ hash: str, uploaded: bool }, ["hash", "uploaded"]), "Stored"), "400": { description: "Missing hash, or the hash does not match the bytes", content: errBody }, "413": { description: "Over the plan's upload size", content: errBody } }
|
|
931
|
+
})
|
|
932
|
+
},
|
|
925
933
|
"/files/{key}/media/{hash}": { get: op("Files", "Media asset bytes", "files:read", ok({ type: "string", format: "binary" }, "The asset, with its own content type", "*/*"), { parameters: [key, id("hash", "From `/files/{key}/images`")] }) },
|
|
926
934
|
"/files/{key}/comments": {
|
|
927
935
|
get: op("Comments", "Comments (threads and replies), oldest first", "comments:read", ok(ref("CommentList")), { parameters: [key, query("limit", { ...int, minimum: 1, maximum: 500, default: 500 }, "Page size"), cursor] }),
|
|
@@ -1188,7 +1196,7 @@ function operations(spec = openapi) {
|
|
|
1188
1196
|
}
|
|
1189
1197
|
async function call(target2, method, path, opts = {}) {
|
|
1190
1198
|
const qs = new URLSearchParams(opts.query ?? {}).toString();
|
|
1191
|
-
const headers = { "user-agent": `popcraft-cli/${"0.
|
|
1199
|
+
const headers = { "user-agent": `popcraft-cli/${"0.33.0"}`, ...opts.headers };
|
|
1192
1200
|
if (target2.token) headers.authorization = `Bearer ${target2.token}`;
|
|
1193
1201
|
if (opts.contentType) headers["content-type"] = opts.contentType;
|
|
1194
1202
|
try {
|
|
@@ -3872,7 +3880,6 @@ function paramLabel(name2) {
|
|
|
3872
3880
|
var AUDIO_SIGNAL_NAMES, XY, XYZ, RGB, RGBA, LAYOUT, TYPE_NAMES, roundUp, IDENT2, WHITE, numbers, MAX_SHADER_CHARS, reflections, isNum, EMPTY, packed, defaults;
|
|
3873
3881
|
var init_shader_params = __esm({
|
|
3874
3882
|
"lib/document/shader-params.ts"() {
|
|
3875
|
-
"use strict";
|
|
3876
3883
|
AUDIO_SIGNAL_NAMES = ["level", "bass", "mid", "treble", "beat", "onset", "spectrum"];
|
|
3877
3884
|
XY = ["x", "y"];
|
|
3878
3885
|
XYZ = ["x", "y", "z"];
|
|
@@ -6737,6 +6744,7 @@ __export(print_pages_exports, {
|
|
|
6737
6744
|
listMasterPages: () => listMasterPages,
|
|
6738
6745
|
listPrintPages: () => listPrintPages,
|
|
6739
6746
|
pagePosition: () => pagePosition,
|
|
6747
|
+
pagePositions: () => pagePositions,
|
|
6740
6748
|
placePrintPages: () => placePrintPages,
|
|
6741
6749
|
printPageOf: () => printPageOf,
|
|
6742
6750
|
reorderPrintPages: () => reorderPrintPages,
|
|
@@ -6814,6 +6822,36 @@ function pagePosition(index2, size6, facing) {
|
|
|
6814
6822
|
const right = index2 % 2 === 0;
|
|
6815
6823
|
return { x: right ? size6.width : 0, y: spread2 * (size6.height + gutter(size6.width)) };
|
|
6816
6824
|
}
|
|
6825
|
+
function pagePositions(sizes, page, facing) {
|
|
6826
|
+
if (!facing) {
|
|
6827
|
+
let x2 = 0;
|
|
6828
|
+
return sizes.map((s) => {
|
|
6829
|
+
const at4 = { x: x2, y: 0 };
|
|
6830
|
+
x2 += s.width + gutter(page.width);
|
|
6831
|
+
return at4;
|
|
6832
|
+
});
|
|
6833
|
+
}
|
|
6834
|
+
const row2 = page.height + gutter(page.width);
|
|
6835
|
+
let slot2 = 0;
|
|
6836
|
+
return sizes.map((s) => {
|
|
6837
|
+
if (isSpreadSheet(s.width, page)) {
|
|
6838
|
+
if (slot2 % 2 === 0) slot2++;
|
|
6839
|
+
const at5 = { x: 0, y: Math.ceil(slot2 / 2) * row2 };
|
|
6840
|
+
slot2 += 2;
|
|
6841
|
+
return at5;
|
|
6842
|
+
}
|
|
6843
|
+
const at4 = { x: slot2 % 2 === 0 ? page.width : 0, y: Math.ceil(slot2 / 2) * row2 };
|
|
6844
|
+
slot2++;
|
|
6845
|
+
return at4;
|
|
6846
|
+
});
|
|
6847
|
+
}
|
|
6848
|
+
function basePageSize(doc2, frames) {
|
|
6849
|
+
const preset = presetById(doc2.settings?.pageSize?.presetId);
|
|
6850
|
+
if (preset) return presetPx(preset);
|
|
6851
|
+
if (doc2.settings?.pageSize?.width && doc2.settings.pageSize.height) return { width: doc2.settings.pageSize.width, height: doc2.settings.pageSize.height };
|
|
6852
|
+
const first2 = frames[0];
|
|
6853
|
+
return first2 ? { width: first2.width, height: first2.height } : { width: 816, height: 1056 };
|
|
6854
|
+
}
|
|
6817
6855
|
function placePrintPages(doc2, pageId2) {
|
|
6818
6856
|
const patches = {};
|
|
6819
6857
|
const facing = doc2.settings?.facingPages;
|
|
@@ -6821,7 +6859,9 @@ function placePrintPages(doc2, pageId2) {
|
|
|
6821
6859
|
const p2 = at4(i2, f2);
|
|
6822
6860
|
if (f2.x !== p2.x || f2.y !== p2.y) patches[f2.id] = { ...patches[f2.id] ?? {}, ...p2 };
|
|
6823
6861
|
});
|
|
6824
|
-
|
|
6862
|
+
const pages2 = listPrintPages(doc2, pageId2);
|
|
6863
|
+
const positions = pagePositions(pages2, basePageSize(doc2, pages2), facing);
|
|
6864
|
+
place4(pages2, (i2) => positions[i2]);
|
|
6825
6865
|
place4(listMasterPages(doc2, pageId2), (i2, f2) => masterPosition(i2, f2));
|
|
6826
6866
|
return patches;
|
|
6827
6867
|
}
|
|
@@ -6842,7 +6882,7 @@ function createPrintPage(doc2, pageId2, opts = {}) {
|
|
|
6842
6882
|
const last3 = existing[existing.length - 1];
|
|
6843
6883
|
const frame2 = createFrame({
|
|
6844
6884
|
name: opts.name ?? `Page ${index2 + 1}`,
|
|
6845
|
-
...
|
|
6885
|
+
...pagePositions([...existing, size6], basePageSize(doc2, existing.length ? existing : [size6]), doc2.settings?.facingPages)[index2],
|
|
6846
6886
|
width: size6.width,
|
|
6847
6887
|
height: size6.height,
|
|
6848
6888
|
fills: [{ type: "SOLID", color: createColor(1, 1, 1), opacity: 1, visible: true }],
|
|
@@ -6950,7 +6990,7 @@ function documentFromPreset(name2, preset) {
|
|
|
6950
6990
|
if (guides.length) doc2.nodes[pageId2].guides = guides;
|
|
6951
6991
|
return doc2;
|
|
6952
6992
|
}
|
|
6953
|
-
var isFixedPageKind, isPrintPage, isMasterPage, ordered, edges, gutter, masterPosition, foldsOn, MASTER_NAMES;
|
|
6993
|
+
var isFixedPageKind, isPrintPage, isMasterPage, ordered, edges, gutter, isSpreadSheet, masterPosition, foldsOn, MASTER_NAMES;
|
|
6954
6994
|
var init_print_pages = __esm({
|
|
6955
6995
|
"lib/document/print-pages.ts"() {
|
|
6956
6996
|
"use strict";
|
|
@@ -6964,6 +7004,7 @@ var init_print_pages = __esm({
|
|
|
6964
7004
|
ordered = (frames) => frames.map((f2, i2) => ({ f: f2, i: i2 })).sort((a, b) => (a.f.print.index ?? Infinity) - (b.f.print.index ?? Infinity) || a.f.y - b.f.y || a.f.x - b.f.x || a.i - b.i).map((x2) => x2.f);
|
|
6965
7005
|
edges = (v) => ({ top: v, right: v, bottom: v, left: v });
|
|
6966
7006
|
gutter = (w) => Math.round(w * 0.15);
|
|
7007
|
+
isSpreadSheet = (w, page) => w > page.width * 1.5;
|
|
6967
7008
|
masterPosition = (index2, size6) => ({
|
|
6968
7009
|
x: index2 * (size6.width + gutter(size6.width)),
|
|
6969
7010
|
y: -(size6.height + 2 * gutter(size6.width))
|
|
@@ -95191,6 +95232,11 @@ var init_idb = __esm({
|
|
|
95191
95232
|
});
|
|
95192
95233
|
|
|
95193
95234
|
// lib/storage/media-hash.ts
|
|
95235
|
+
var media_hash_exports = {};
|
|
95236
|
+
__export(media_hash_exports, {
|
|
95237
|
+
hashBytesSync: () => hashBytesSync,
|
|
95238
|
+
sha256Prefix: () => sha256Prefix
|
|
95239
|
+
});
|
|
95194
95240
|
function hashBytesSync(bytes2) {
|
|
95195
95241
|
const run4 = (seed2) => {
|
|
95196
95242
|
let h1 = 3735928559 ^ seed2, h22 = 1103547991 ^ seed2;
|
|
@@ -95205,6 +95251,10 @@ function hashBytesSync(bytes2) {
|
|
|
95205
95251
|
};
|
|
95206
95252
|
return run4(2654435769) + run4(2246822507 ^ bytes2.length);
|
|
95207
95253
|
}
|
|
95254
|
+
async function sha256Prefix(bytes2) {
|
|
95255
|
+
const digest = await crypto.subtle.digest("SHA-256", bytes2);
|
|
95256
|
+
return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("").slice(0, 32);
|
|
95257
|
+
}
|
|
95208
95258
|
var init_media_hash = __esm({
|
|
95209
95259
|
"lib/storage/media-hash.ts"() {
|
|
95210
95260
|
"use strict";
|
|
@@ -310109,6 +310159,7 @@ async function dispatchShaped(key5, options) {
|
|
|
310109
310159
|
var onViolation;
|
|
310110
310160
|
var init_dispatch = __esm({
|
|
310111
310161
|
"lib/commands/dispatch.ts"() {
|
|
310162
|
+
"use strict";
|
|
310112
310163
|
init_errors();
|
|
310113
310164
|
init_registry();
|
|
310114
310165
|
init_confirm();
|
|
@@ -310279,6 +310330,7 @@ function downloadBlob(blob, filename) {
|
|
|
310279
310330
|
}
|
|
310280
310331
|
var init_download = __esm({
|
|
310281
310332
|
"lib/io/download.ts"() {
|
|
310333
|
+
"use strict";
|
|
310282
310334
|
}
|
|
310283
310335
|
});
|
|
310284
310336
|
|
|
@@ -310498,6 +310550,7 @@ function creditLine(c2) {
|
|
|
310498
310550
|
var MAX_PHOTO_PAGE, MAX_PHOTO_QUERY, UUID, isPhotoId, photoImagePath;
|
|
310499
310551
|
var init_stock = __esm({
|
|
310500
310552
|
"lib/photos/stock.ts"() {
|
|
310553
|
+
"use strict";
|
|
310501
310554
|
MAX_PHOTO_PAGE = 12;
|
|
310502
310555
|
MAX_PHOTO_QUERY = 200;
|
|
310503
310556
|
UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -326409,7 +326462,7 @@ var init_package = __esm({
|
|
|
326409
326462
|
"packages/runtime/package.json"() {
|
|
326410
326463
|
package_default = {
|
|
326411
326464
|
name: "@popcraft/runtime",
|
|
326412
|
-
version: "0.
|
|
326465
|
+
version: "0.33.0",
|
|
326413
326466
|
description: "What code exported from PopCraft shares: the meaning of expressions (operators and functions) and, as it grows, the parts of a design's behaviour that are common code rather than generated React.",
|
|
326414
326467
|
license: "MIT",
|
|
326415
326468
|
homepage: "https://popcraft.app/docs/exporting/nextjs",
|
|
@@ -351075,6 +351128,7 @@ function exportsOf(source3) {
|
|
|
351075
351128
|
var CODE_LIMITS, packageOf;
|
|
351076
351129
|
var init_source2 = __esm({
|
|
351077
351130
|
"lib/code/source.ts"() {
|
|
351131
|
+
"use strict";
|
|
351078
351132
|
CODE_LIMITS = { modules: 100, sourceLength: 2e5, packages: 12 };
|
|
351079
351133
|
packageOf = (spec) => spec.split("/").slice(0, spec.startsWith("@") ? 2 : 1).join("/");
|
|
351080
351134
|
}
|
|
@@ -351117,6 +351171,7 @@ function compileModule(module2) {
|
|
|
351117
351171
|
var import_sucrase, BUILT_IN, memo4;
|
|
351118
351172
|
var init_compile2 = __esm({
|
|
351119
351173
|
"lib/code/compile.ts"() {
|
|
351174
|
+
"use strict";
|
|
351120
351175
|
import_sucrase = __toESM(require_dist2());
|
|
351121
351176
|
init_source2();
|
|
351122
351177
|
init_source2();
|
|
@@ -360091,6 +360146,7 @@ var init_publish = __esm({
|
|
|
360091
360146
|
var storeOpsSeam;
|
|
360092
360147
|
var init_seams = __esm({
|
|
360093
360148
|
"lib/commands/seams.ts"() {
|
|
360149
|
+
"use strict";
|
|
360094
360150
|
storeOpsSeam = (st) => ({
|
|
360095
360151
|
booleanOperation: (op4) => st().booleanOperation(op4),
|
|
360096
360152
|
flatten: () => st().flattenSelection(),
|
|
@@ -396045,7 +396101,11 @@ async function fontBytes(args2, ctx2) {
|
|
|
396045
396101
|
}
|
|
396046
396102
|
} else if (args2.src) {
|
|
396047
396103
|
const { isMediaUrl: isMediaUrl2, loadMediaBlob: loadMediaBlob2 } = await Promise.resolve().then(() => (init_media_store(), media_store_exports));
|
|
396048
|
-
if (isMediaUrl2(args2.src)) {
|
|
396104
|
+
if (isMediaUrl2(args2.src) && ctx2.can("media")) {
|
|
396105
|
+
const bytes2 = await ctx2.use("media").read(args2.src);
|
|
396106
|
+
if (!bytes2) throw new CommandError(`${args2.src} is not in this file's media: upload it first (POST /files/{key}/media).`, "not_found");
|
|
396107
|
+
got = { bytes: bytes2 };
|
|
396108
|
+
} else if (isMediaUrl2(args2.src)) {
|
|
396049
396109
|
const blob = await loadMediaBlob2(args2.src);
|
|
396050
396110
|
if (!blob) throw new CommandError(`${args2.src} is not on this device.`, "not_found");
|
|
396051
396111
|
got = { bytes: new Uint8Array(await blob.arrayBuffer()) };
|
|
@@ -396122,7 +396182,7 @@ var init_font = __esm({
|
|
|
396122
396182
|
params: external_exports.object({
|
|
396123
396183
|
family: external_exports.string().trim().min(1).max(200).optional().describe("The family name texts will use (default: the name in the file). Texts set in it draw in this file."),
|
|
396124
396184
|
file: external_exports.string().min(1).max(4096).optional().describe("A font file on this machine, read by the CLI: .ttf, .otf, .ttc, .woff or .woff2."),
|
|
396125
|
-
src: external_exports.string().max(MAX_SRC).optional().describe("The font file as a base64 data URL, or a media:// ref already on this device."),
|
|
396185
|
+
src: external_exports.string().max(MAX_SRC).optional().describe("The font file as a base64 data URL, or a media:// ref already on this device (through the API: already uploaded to the file's media)."),
|
|
396126
396186
|
weight: external_exports.number().int().min(1).max(1e3).optional().describe("The weight this face stands for (default: the file's)."),
|
|
396127
396187
|
style: external_exports.enum(["normal", "italic"]).optional().describe("normal or italic (default: the file's)."),
|
|
396128
396188
|
face: faceParam.optional()
|
|
@@ -396137,10 +396197,9 @@ var init_font = __esm({
|
|
|
396137
396197
|
run: async (args2, ctx2) => {
|
|
396138
396198
|
const { bytes: bytes2, fileName: fileName2 } = await fontBytes(args2, ctx2);
|
|
396139
396199
|
const { face, family, weight, style, info: info2 } = await resolveFace(bytes2, args2);
|
|
396140
|
-
const { internBytes: internBytes2 } = await Promise.resolve().then(() => (init_media_store(), media_store_exports));
|
|
396141
396200
|
const { fontMime: fontMime2 } = await Promise.resolve().then(() => (init_sfnt(), sfnt_exports));
|
|
396142
396201
|
const { addDocumentFont: addDocumentFont2 } = await Promise.resolve().then(() => (init_document_fonts(), document_fonts_exports));
|
|
396143
|
-
const src =
|
|
396202
|
+
const src = ctx2.can("media") ? await ctx2.use("media").store(bytes2, fontMime2(bytes2)) : (await Promise.resolve().then(() => (init_media_store(), media_store_exports))).internBytes(bytes2, fontMime2(bytes2));
|
|
396144
396203
|
const font = {
|
|
396145
396204
|
id: `font-${src.slice(8, 20)}-${face.index}-${weight}-${style === "italic" ? "i" : "n"}`,
|
|
396146
396205
|
family,
|
|
@@ -397057,6 +397116,7 @@ function record(source, namespaces, globals, limits) {
|
|
|
397057
397116
|
var HELPER_NAMES;
|
|
397058
397117
|
var init_helper_names = __esm({
|
|
397059
397118
|
"lib/agent/design-script/helper-names.ts"() {
|
|
397119
|
+
"use strict";
|
|
397060
397120
|
HELPER_NAMES = ["draw", "marks", "fit", "motion", "captions", "overlays", "texture", "pointer", "windows", "devices", "type", "beat", "web", "social", "video", "site", "effects"];
|
|
397061
397121
|
}
|
|
397062
397122
|
});
|
|
@@ -407805,6 +407865,7 @@ var init_headless2 = __esm({
|
|
|
407805
407865
|
|
|
407806
407866
|
// packages/cli/src/cloud.ts
|
|
407807
407867
|
import { existsSync as existsSync4 } from "node:fs";
|
|
407868
|
+
import { gzipSync } from "node:zlib";
|
|
407808
407869
|
function signedIn2(target2) {
|
|
407809
407870
|
if (!target2.token) throw new CliError(`Not signed in to ${target2.url}: run \`popcraft login\` (with a files:write token).`);
|
|
407810
407871
|
return target2;
|
|
@@ -407819,25 +407880,79 @@ async function runPush(args2, flags, target2, out) {
|
|
|
407819
407880
|
const name2 = flagString(flags, "name");
|
|
407820
407881
|
if (key5) {
|
|
407821
407882
|
const ifMatch = flagString(flags, "ifMatch");
|
|
407822
|
-
const
|
|
407883
|
+
const { doc: doc3, media: media3 } = await separateMedia(document2);
|
|
407884
|
+
await uploadMedia2(t3, key5, media3);
|
|
407885
|
+
const body = gzipJson({ document: name2 ? { ...doc3, name: name2 } : doc3 });
|
|
407823
407886
|
const res2 = await callJson(t3, "PUT", `/files/${encodeURIComponent(key5)}`, {
|
|
407824
|
-
body
|
|
407825
|
-
|
|
407826
|
-
headers: ifMatch ? { "if-match": ifMatch } : void 0
|
|
407887
|
+
...body,
|
|
407888
|
+
headers: { ...body.headers, ...ifMatch ? { "if-match": ifMatch } : {} }
|
|
407827
407889
|
});
|
|
407828
407890
|
out.result(res2.changed ? `Updated ${key5} (revision ${res2.revision})${res2.live ? "; open sessions merged it" : ""}.` : `${key5} already matched ${file2}.`, out.json ? { key: key5, ...res2 } : void 0);
|
|
407829
407891
|
return;
|
|
407830
407892
|
}
|
|
407831
|
-
const
|
|
407832
|
-
|
|
407893
|
+
const { doc: doc2, media: media2 } = await separateMedia(document2);
|
|
407894
|
+
const res = await callJson(t3, "POST", "/files", gzipJson({
|
|
407895
|
+
document: doc2,
|
|
407833
407896
|
...name2 ? { name: name2 } : {},
|
|
407834
407897
|
...flagString(flags, "workspace") ? { workspaceId: flagString(flags, "workspace") } : {},
|
|
407835
407898
|
...flagString(flags, "project") ? { projectId: flagString(flags, "project") } : {},
|
|
407836
407899
|
...flagString(flags, "folder") ? { folderId: flagString(flags, "folder") } : {}
|
|
407837
|
-
});
|
|
407838
|
-
|
|
407900
|
+
}));
|
|
407901
|
+
await uploadMedia2(t3, res.key, media2);
|
|
407839
407902
|
out.result(`Created ${res.key}: ${t3.url}/pop/${res.key}`, out.json ? { ...res, url: `${t3.url}/pop/${res.key}` } : void 0);
|
|
407840
407903
|
}
|
|
407904
|
+
async function separateMedia(document2) {
|
|
407905
|
+
const { MEDIA_SCHEME: MEDIA_SCHEME2, isMediaUrl: isMediaUrl2, loadMediaBlob: loadMediaBlob2 } = await Promise.resolve().then(() => (init_media_store(), media_store_exports));
|
|
407906
|
+
const { hashBytesSync: hashBytesSync2 } = await Promise.resolve().then(() => (init_media_hash(), media_hash_exports));
|
|
407907
|
+
const media2 = /* @__PURE__ */ new Map();
|
|
407908
|
+
const pending8 = [];
|
|
407909
|
+
const walk4 = (v) => {
|
|
407910
|
+
if (typeof v === "string") {
|
|
407911
|
+
if (isMediaUrl2(v)) {
|
|
407912
|
+
const hash3 = v.slice(MEDIA_SCHEME2.length);
|
|
407913
|
+
if (!media2.has(hash3)) {
|
|
407914
|
+
media2.set(hash3, { bytes: new Uint8Array(0), type: "" });
|
|
407915
|
+
pending8.push(loadMediaBlob2(v).then(async (blob) => {
|
|
407916
|
+
if (blob) media2.set(hash3, { bytes: new Uint8Array(await blob.arrayBuffer()), type: blob.type });
|
|
407917
|
+
else media2.delete(hash3);
|
|
407918
|
+
}));
|
|
407919
|
+
}
|
|
407920
|
+
return v;
|
|
407921
|
+
}
|
|
407922
|
+
const m = /^data:([^;,]*)(?:;[^,]*)?;base64,/.exec(v);
|
|
407923
|
+
if (m && v.length > 1024) {
|
|
407924
|
+
const bytes2 = Uint8Array.from(Buffer.from(v.slice(m[0].length), "base64"));
|
|
407925
|
+
const hash3 = hashBytesSync2(bytes2);
|
|
407926
|
+
media2.set(hash3, { bytes: bytes2, type: m[1] || "application/octet-stream" });
|
|
407927
|
+
return MEDIA_SCHEME2 + hash3;
|
|
407928
|
+
}
|
|
407929
|
+
return v;
|
|
407930
|
+
}
|
|
407931
|
+
if (Array.isArray(v)) return v.map(walk4);
|
|
407932
|
+
if (v && typeof v === "object") return Object.fromEntries(Object.entries(v).map(([k2, x2]) => [k2, walk4(x2)]));
|
|
407933
|
+
return v;
|
|
407934
|
+
};
|
|
407935
|
+
const doc2 = walk4(document2);
|
|
407936
|
+
await Promise.all(pending8);
|
|
407937
|
+
return { doc: doc2, media: media2 };
|
|
407938
|
+
}
|
|
407939
|
+
async function uploadMedia2(t3, key5, media2) {
|
|
407940
|
+
const queue2 = [...media2];
|
|
407941
|
+
const worker2 = async () => {
|
|
407942
|
+
for (let next2 = queue2.shift(); next2; next2 = queue2.shift()) {
|
|
407943
|
+
const [hash3, { bytes: bytes2, type }] = next2;
|
|
407944
|
+
await callJson(t3, "POST", `/files/${encodeURIComponent(key5)}/media`, {
|
|
407945
|
+
body: bytes2,
|
|
407946
|
+
contentType: type || "application/octet-stream",
|
|
407947
|
+
headers: { "x-media-hash": hash3 }
|
|
407948
|
+
});
|
|
407949
|
+
}
|
|
407950
|
+
};
|
|
407951
|
+
await Promise.all(Array.from({ length: Math.min(4, queue2.length) }, worker2));
|
|
407952
|
+
}
|
|
407953
|
+
function gzipJson(value3) {
|
|
407954
|
+
return { body: gzipSync(JSON.stringify(value3)), contentType: "application/json", headers: { "content-encoding": "gzip" } };
|
|
407955
|
+
}
|
|
407841
407956
|
async function runPull(args2, flags, target2, out) {
|
|
407842
407957
|
const [key5, dest] = args2;
|
|
407843
407958
|
if (!key5) throw usage("Usage: popcraft pull <key> [file.popcraft]");
|
|
@@ -409760,7 +409875,7 @@ init_resources();
|
|
|
409760
409875
|
init_desktop();
|
|
409761
409876
|
init_hypery();
|
|
409762
409877
|
import { createInterface } from "node:readline";
|
|
409763
|
-
var VERSION2 = "0.
|
|
409878
|
+
var VERSION2 = "0.33.0";
|
|
409764
409879
|
var HELP = `popcraft ${VERSION2} \u2014 the PopCraft command line
|
|
409765
409880
|
|
|
409766
409881
|
Files (headless, on .popcraft files):
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@popcraft/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "The PopCraft command line: edit .popcraft files headlessly, call the REST API, publish to the marketplace and manage the desktop app's local plugins, themes, fonts, skills and agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://popcraft.app/docs/api/cli",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"esbuild": "0.28.2"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@popcraft/kit": "0.
|
|
37
|
+
"@popcraft/kit": "0.33.0"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "node build.mjs",
|