@wix/himalaya-cli 0.1433.0 → 0.1434.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/cli.mjs +1517 -634
- package/guides/base44-app-context.md +1 -1
- package/guides/base44-entities.md +117 -7
- package/guides/himi-json-output.md +66 -2
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -240,6 +240,9 @@ function physicalEntityName(spec, app) {
|
|
|
240
240
|
if (isAdoptedEntity(spec)) return spec.base44Name;
|
|
241
241
|
return nonEmpty(spec.name) ? `${base44Prefix(app)}${spec.name}` : "";
|
|
242
242
|
}
|
|
243
|
+
function isOwnedFunction(spec) {
|
|
244
|
+
return !nonEmpty(spec.base44Name) && nonEmpty(spec.name);
|
|
245
|
+
}
|
|
243
246
|
function physicalFunctionName(spec) {
|
|
244
247
|
return nonEmpty(spec.base44Name) ? spec.base44Name : nonEmpty(spec.name) ? spec.name : "";
|
|
245
248
|
}
|
|
@@ -3013,10 +3016,10 @@ function readRetainedAttestations(contentDir2) {
|
|
|
3013
3016
|
const dir = join6(resolve6(contentDir2), ".himi", "attestations");
|
|
3014
3017
|
if (!existsSync3(dir)) return { runs: [], errors: [] };
|
|
3015
3018
|
try {
|
|
3016
|
-
const
|
|
3019
|
+
const names2 = readdirSync3(dir).filter((name) => name.endsWith(".json") && name !== "latest.json");
|
|
3017
3020
|
const parsedRuns = [];
|
|
3018
3021
|
const errors = [];
|
|
3019
|
-
for (const name of
|
|
3022
|
+
for (const name of names2) {
|
|
3020
3023
|
const classified = classifyRetainedRun(dir, name);
|
|
3021
3024
|
if (classified.kind === "current") parsedRuns.push(classified.run);
|
|
3022
3025
|
else if (classified.kind === "legacy") {
|
|
@@ -3029,7 +3032,7 @@ function readRetainedAttestations(contentDir2) {
|
|
|
3029
3032
|
}
|
|
3030
3033
|
const latest = readLatestAttestation(contentDir2);
|
|
3031
3034
|
if (existsSync3(join6(dir, "latest.json")) && !latest) errors.push("attestation history has no valid latest.json");
|
|
3032
|
-
else if (
|
|
3035
|
+
else if (names2.length > 0 && !latest) errors.push("attestation history has no latest.json");
|
|
3033
3036
|
const byHash = new Map(parsedRuns.map((run2) => [run2.selfHash, run2]));
|
|
3034
3037
|
if (byHash.size !== parsedRuns.length) errors.push("attestation history contains duplicate self hashes");
|
|
3035
3038
|
for (const run2 of parsedRuns) {
|
|
@@ -5731,18 +5734,18 @@ function servedBundleName(fileName) {
|
|
|
5731
5734
|
return void 0;
|
|
5732
5735
|
}
|
|
5733
5736
|
function servedBundleNames(dir) {
|
|
5734
|
-
const
|
|
5737
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
5735
5738
|
let entries;
|
|
5736
5739
|
try {
|
|
5737
5740
|
entries = readdirSync7(dir);
|
|
5738
5741
|
} catch {
|
|
5739
|
-
return
|
|
5742
|
+
return names2;
|
|
5740
5743
|
}
|
|
5741
5744
|
for (const entry of entries) {
|
|
5742
5745
|
const name = servedBundleName(entry);
|
|
5743
|
-
if (name !== void 0)
|
|
5746
|
+
if (name !== void 0) names2.add(name);
|
|
5744
5747
|
}
|
|
5745
|
-
return
|
|
5748
|
+
return names2;
|
|
5746
5749
|
}
|
|
5747
5750
|
var init_tier5_dir = __esm({
|
|
5748
5751
|
"../../core/dev-server/src/tier5-dir.ts"() {
|
|
@@ -6004,14 +6007,14 @@ function analyzeService(source, forbidden2) {
|
|
|
6004
6007
|
for (const stmt of sf2.statements) {
|
|
6005
6008
|
if (ts.isImportDeclaration(stmt) && ts.isStringLiteral(stmt.moduleSpecifier)) {
|
|
6006
6009
|
const mod = stmt.moduleSpecifier.text;
|
|
6007
|
-
const
|
|
6010
|
+
const names2 = [];
|
|
6008
6011
|
const ic = stmt.importClause;
|
|
6009
|
-
if (ic?.name)
|
|
6012
|
+
if (ic?.name) names2.push(ic.name.text);
|
|
6010
6013
|
if (ic?.namedBindings) {
|
|
6011
|
-
if (ts.isNamedImports(ic.namedBindings)) for (const el2 of ic.namedBindings.elements)
|
|
6012
|
-
else if (ts.isNamespaceImport(ic.namedBindings))
|
|
6014
|
+
if (ts.isNamedImports(ic.namedBindings)) for (const el2 of ic.namedBindings.elements) names2.push(el2.name.text);
|
|
6015
|
+
else if (ts.isNamespaceImport(ic.namedBindings)) names2.push(ic.namedBindings.name.text);
|
|
6013
6016
|
}
|
|
6014
|
-
info4.imports.push({ module: mod, names, line: lineOfPos(stmt.getStart(sf2)) });
|
|
6017
|
+
info4.imports.push({ module: mod, names: names2, line: lineOfPos(stmt.getStart(sf2)) });
|
|
6015
6018
|
if (mod.startsWith("@himalaya/")) info4.usedModules.add(mod);
|
|
6016
6019
|
}
|
|
6017
6020
|
}
|
|
@@ -6222,7 +6225,7 @@ function analyzeController(source, file2, profile, diagnostics) {
|
|
|
6222
6225
|
if (!initial || typeof initial !== "object" || Array.isArray(initial)) throw new Error("initialState must be a JSON object.");
|
|
6223
6226
|
const paths = /* @__PURE__ */ new Map();
|
|
6224
6227
|
collect2(initial);
|
|
6225
|
-
const
|
|
6228
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
6226
6229
|
for (const handler of handlers.initializer.properties) {
|
|
6227
6230
|
if (!handler.name || ts2.isComputedPropertyName(handler.name) || ts2.isSpreadAssignment(handler)) {
|
|
6228
6231
|
error(handler, "Handlers need static names.");
|
|
@@ -6230,9 +6233,9 @@ function analyzeController(source, file2, profile, diagnostics) {
|
|
|
6230
6233
|
}
|
|
6231
6234
|
const name = handler.name.getText(sf2).replace(/^["']|["']$/g, "");
|
|
6232
6235
|
if (!/^[a-zA-Z_]\w*$/.test(name) || name.startsWith("__hhp") || unsafe.has(name)) error(handler, `Invalid handler name ${name}.`);
|
|
6233
|
-
|
|
6236
|
+
names2.add(name);
|
|
6234
6237
|
}
|
|
6235
|
-
return { state: initial, paths, handlers:
|
|
6238
|
+
return { state: initial, paths, handlers: names2 };
|
|
6236
6239
|
} catch (e2) {
|
|
6237
6240
|
error(state, e2.message);
|
|
6238
6241
|
return;
|
|
@@ -11006,18 +11009,18 @@ function nondeterministicServices(bundleJs, opts = {}) {
|
|
|
11006
11009
|
const threw = boots.filter((b3) => b3.threw !== null).length;
|
|
11007
11010
|
if (threw === boots.length) return [];
|
|
11008
11011
|
const [a2, b2] = boots.map((boot) => boot.services);
|
|
11009
|
-
const
|
|
11010
|
-
if (threw > 0) return
|
|
11011
|
-
return
|
|
11012
|
+
const names2 = [.../* @__PURE__ */ new Set([...Object.keys(a2), ...Object.keys(b2)])];
|
|
11013
|
+
if (threw > 0) return names2.sort();
|
|
11014
|
+
return names2.filter((name) => safeStringify(a2[name]) !== safeStringify(b2[name])).sort();
|
|
11012
11015
|
}
|
|
11013
11016
|
function deviceParityWithheldFrom(root) {
|
|
11014
|
-
const
|
|
11017
|
+
const names2 = new Set(DEVICE_PARITY_CANDIDATES);
|
|
11015
11018
|
for (let o2 = root; o2 && o2 !== Object.prototype; o2 = Object.getPrototypeOf(o2)) {
|
|
11016
|
-
for (const name of Object.getOwnPropertyNames(o2))
|
|
11019
|
+
for (const name of Object.getOwnPropertyNames(o2)) names2.add(name);
|
|
11017
11020
|
}
|
|
11018
|
-
|
|
11019
|
-
|
|
11020
|
-
return [...
|
|
11021
|
+
names2.delete("constructor");
|
|
11022
|
+
names2.delete("__proto__");
|
|
11023
|
+
return [...names2].filter((name) => /^[A-Za-z_$][\w$]*$/.test(name) && !WORKER_ALLOWLIST.has(name)).sort();
|
|
11021
11024
|
}
|
|
11022
11025
|
function setDefaultEvaluator(evaluator) {
|
|
11023
11026
|
defaultEvaluator = evaluator;
|
|
@@ -11925,11 +11928,11 @@ function componentPropFindings(descriptor) {
|
|
|
11925
11928
|
return out2;
|
|
11926
11929
|
}
|
|
11927
11930
|
function enumFieldNames(schema = screenDescriptorSchema) {
|
|
11928
|
-
const
|
|
11931
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
11929
11932
|
const visit = (node, propName5) => {
|
|
11930
11933
|
if (!node || typeof node !== "object") return;
|
|
11931
11934
|
const obj4 = node;
|
|
11932
|
-
if (propName5 && Array.isArray(obj4.enum))
|
|
11935
|
+
if (propName5 && Array.isArray(obj4.enum)) names2.add(propName5);
|
|
11933
11936
|
if (obj4.properties && typeof obj4.properties === "object") {
|
|
11934
11937
|
for (const [k2, v2] of Object.entries(obj4.properties)) visit(v2, k2);
|
|
11935
11938
|
}
|
|
@@ -11944,7 +11947,7 @@ function enumFieldNames(schema = screenDescriptorSchema) {
|
|
|
11944
11947
|
}
|
|
11945
11948
|
};
|
|
11946
11949
|
visit(schema, null);
|
|
11947
|
-
return
|
|
11950
|
+
return names2;
|
|
11948
11951
|
}
|
|
11949
11952
|
function serviceOnlyBindingValues(props, key3) {
|
|
11950
11953
|
const arrayAt = key3.indexOf("[]");
|
|
@@ -14155,17 +14158,17 @@ function devModuleRealm() {
|
|
|
14155
14158
|
return devRealm;
|
|
14156
14159
|
}
|
|
14157
14160
|
function bundleNamesFor(dir) {
|
|
14158
|
-
const
|
|
14161
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
14159
14162
|
for (const root of [bundleOutDir(dir), TIER5_ROOT]) {
|
|
14160
14163
|
if (!root || !existsSync11(root)) continue;
|
|
14161
14164
|
try {
|
|
14162
14165
|
for (const f2 of readdirSync9(root)) {
|
|
14163
|
-
if (f2.endsWith(".bundle.js"))
|
|
14166
|
+
if (f2.endsWith(".bundle.js")) names2.add(basename5(f2, ".bundle.js"));
|
|
14164
14167
|
}
|
|
14165
14168
|
} catch {
|
|
14166
14169
|
}
|
|
14167
14170
|
}
|
|
14168
|
-
return [...
|
|
14171
|
+
return [...names2];
|
|
14169
14172
|
}
|
|
14170
14173
|
function crossContext(ctx, bundleNames, assetNames, integrityMemo, assetMemo) {
|
|
14171
14174
|
const probe = bundleNames[0];
|
|
@@ -19472,10 +19475,10 @@ function glyphNames() {
|
|
|
19472
19475
|
return Object.keys(GLYPHS).sort();
|
|
19473
19476
|
}
|
|
19474
19477
|
async function generateIcon(dir, opts = {}) {
|
|
19475
|
-
const
|
|
19478
|
+
const names2 = glyphNames();
|
|
19476
19479
|
const chosen = opts.glyph ?? DEFAULT_GLYPH;
|
|
19477
|
-
if (!
|
|
19478
|
-
throw new Error(`himi icon: unknown glyph "${chosen}". Available: ${
|
|
19480
|
+
if (!names2.includes(chosen)) {
|
|
19481
|
+
throw new Error(`himi icon: unknown glyph "${chosen}". Available: ${names2.join(", ")}`);
|
|
19479
19482
|
}
|
|
19480
19483
|
const background = opts.background ?? backdropFromTokens(dir);
|
|
19481
19484
|
if (!HEX_COLOR2.test(background)) {
|
|
@@ -19554,9 +19557,9 @@ function renderableFamilies(catalog3 = loadCatalog()) {
|
|
|
19554
19557
|
function findFamily(name, catalog3 = loadCatalog()) {
|
|
19555
19558
|
const exact = catalog3.families[name] ?? catalog3.bundled[name];
|
|
19556
19559
|
if (exact) return exact;
|
|
19557
|
-
const
|
|
19558
|
-
if (!
|
|
19559
|
-
return catalog3.families[
|
|
19560
|
+
const canonical6 = familyIndex(catalog3).get(normalizeFamily(name));
|
|
19561
|
+
if (!canonical6) return void 0;
|
|
19562
|
+
return catalog3.families[canonical6] ?? catalog3.bundled[canonical6];
|
|
19560
19563
|
}
|
|
19561
19564
|
function canonicalFamilyName(name, catalog3 = loadCatalog()) {
|
|
19562
19565
|
if (catalog3.families[name] ?? catalog3.bundled[name] ?? catalog3.system[name]) return name;
|
|
@@ -20694,8 +20697,8 @@ async function navEntryScreens(dir, homeScreenId) {
|
|
|
20694
20697
|
}
|
|
20695
20698
|
async function localDbEntities(dir) {
|
|
20696
20699
|
const schema = (await loadContentConfigQuietly(dir))?.dataSchema;
|
|
20697
|
-
const
|
|
20698
|
-
return
|
|
20700
|
+
const names2 = (schema?.entities ?? []).map((e2) => e2?.name).filter((n2) => typeof n2 === "string" && n2.length > 0);
|
|
20701
|
+
return names2.length ? names2.map((name) => ({ name })) : null;
|
|
20699
20702
|
}
|
|
20700
20703
|
function renderMocksFrom(rules, bad2, seeded) {
|
|
20701
20704
|
if (rules || seeded) {
|
|
@@ -24280,7 +24283,7 @@ function parseOrientationEnvelope(configTs) {
|
|
|
24280
24283
|
};
|
|
24281
24284
|
}
|
|
24282
24285
|
function orientationPlistPlan(env) {
|
|
24283
|
-
const map = (
|
|
24286
|
+
const map = (names2) => ALL_ORIENTATIONS.filter((o2) => names2.includes(o2)).map((o2) => IOS_ORIENTATION[o2]);
|
|
24284
24287
|
return {
|
|
24285
24288
|
UISupportedInterfaceOrientations: map(env.phone),
|
|
24286
24289
|
"UISupportedInterfaceOrientations~ipad": map(env.tablet)
|
|
@@ -25619,12 +25622,12 @@ function carryPlanningJournal(parentDir, appDir3) {
|
|
|
25619
25622
|
}
|
|
25620
25623
|
if (carried.includes(toPosix(PROGRESS_FILE))) {
|
|
25621
25624
|
const hist = join36(parentDir, HISTORY_DIR);
|
|
25622
|
-
let
|
|
25625
|
+
let names2 = [];
|
|
25623
25626
|
try {
|
|
25624
|
-
if (lstatSync8(hist).isDirectory())
|
|
25627
|
+
if (lstatSync8(hist).isDirectory()) names2 = readdirSync21(hist);
|
|
25625
25628
|
} catch {
|
|
25626
25629
|
}
|
|
25627
|
-
for (const name of
|
|
25630
|
+
for (const name of names2) {
|
|
25628
25631
|
const from = join36(hist, name);
|
|
25629
25632
|
if (isSymlink(from) || !lstatSync8(from).isFile()) continue;
|
|
25630
25633
|
const bytes2 = readFileSync35(from);
|
|
@@ -27153,9 +27156,9 @@ function validateScreenMetadata(screens) {
|
|
|
27153
27156
|
labels.set(key3, { viewId, explicit: name !== void 0 || other?.explicit === true });
|
|
27154
27157
|
}
|
|
27155
27158
|
}
|
|
27156
|
-
function screenMetadataFor(definitions2, id,
|
|
27159
|
+
function screenMetadataFor(definitions2, id, canonical6) {
|
|
27157
27160
|
if (definitions2 && Object.hasOwn(definitions2, id)) return definitions2[id];
|
|
27158
|
-
if (
|
|
27161
|
+
if (canonical6 && definitions2 && Object.hasOwn(definitions2, canonical6)) return { ...definitions2[canonical6], viewId: definitions2[canonical6].viewId ?? canonical6 };
|
|
27159
27162
|
return {};
|
|
27160
27163
|
}
|
|
27161
27164
|
function screenViewRepresentatives(screens) {
|
|
@@ -31364,8 +31367,8 @@ function validateStringList(kind, values) {
|
|
|
31364
31367
|
}
|
|
31365
31368
|
return [...values].sort();
|
|
31366
31369
|
}
|
|
31367
|
-
function validateNames(kind,
|
|
31368
|
-
const result = validateStringList(`${kind} names`,
|
|
31370
|
+
function validateNames(kind, names2) {
|
|
31371
|
+
const result = validateStringList(`${kind} names`, names2);
|
|
31369
31372
|
if (new Set(result).size !== result.length) fail2(`${kind} names must not contain duplicates`);
|
|
31370
31373
|
for (const name of result) {
|
|
31371
31374
|
if (kind === "secret" && !/^[A-Z][A-Z0-9_]{0,63}$/.test(name)) fail2(`secret name must be uppercase: "${name}"`);
|
|
@@ -38882,7 +38885,7 @@ var init_icons = __esm({
|
|
|
38882
38885
|
// table by the NORMALIZED name, so those separator-free spellings were in the accepted set and
|
|
38883
38886
|
// are authored in the wild (#473). The validator compares literally against this list, so
|
|
38884
38887
|
// omitting them would silently start flagging descriptors that render perfectly.
|
|
38885
|
-
...Object.entries(ICON_NORMALIZED_INDEX).filter(([,
|
|
38888
|
+
...Object.entries(ICON_NORMALIZED_INDEX).filter(([, canonical6]) => !canonical6.startsWith("_")).map(([normalized]) => normalized)
|
|
38886
38889
|
])
|
|
38887
38890
|
].sort();
|
|
38888
38891
|
FALLBACK = ICON_CATALOG[ICON_FALLBACK];
|
|
@@ -39784,7 +39787,7 @@ function RichContentEditorView({ props, ctx, wrap, nodeId, renderChild, ...dom }
|
|
|
39784
39787
|
const boundSeed = useBoundValue(ctx, seedMode === "binding" ? props.documentPath : "");
|
|
39785
39788
|
const fill = props.fillAvailable === true;
|
|
39786
39789
|
const minHeight = typeof props.minHeight === "number" && props.minHeight >= 0 ? props.minHeight : 240;
|
|
39787
|
-
const
|
|
39790
|
+
const placeholder3 = typeof props.placeholder === "string" ? props.placeholder : "";
|
|
39788
39791
|
const onChangeRef = React4.useRef(props.onChange);
|
|
39789
39792
|
onChangeRef.current = props.onChange;
|
|
39790
39793
|
const bagRef = React4.useRef(bag);
|
|
@@ -39829,7 +39832,7 @@ function RichContentEditorView({ props, ctx, wrap, nodeId, renderChild, ...dom }
|
|
|
39829
39832
|
const session = createRicosHostSession({
|
|
39830
39833
|
send: (msg) => frame.contentWindow?.postMessage({ ricos: 1, msg }, "*"),
|
|
39831
39834
|
seedMode,
|
|
39832
|
-
placeholder:
|
|
39835
|
+
placeholder: placeholder3 || void 0,
|
|
39833
39836
|
locale: ctx.localeTag ?? "en",
|
|
39834
39837
|
rtl: ctx.isRTL ?? document.documentElement.dir === "rtl",
|
|
39835
39838
|
palette: { text: C2("textPrimary", "#13171E"), background: C2("surfacePrimary", "#FFFFFF"), accent: C2("accentPrimary", "#116DFF") },
|
|
@@ -39931,7 +39934,7 @@ function RichContentEditorView({ props, ctx, wrap, nodeId, renderChild, ...dom }
|
|
|
39931
39934
|
if (!live3) {
|
|
39932
39935
|
const { paddingTop: _t2, paddingBottom: _b, paddingLeft: _l2, paddingRight: _r2, ...rootNoSides } = root;
|
|
39933
39936
|
const own5 = { ...rootNoSides, border: `1px solid ${C2("border", "#e3e3e3")}`, borderRadius: 8, padding: 12, boxSizing: "border-box" };
|
|
39934
|
-
return /* @__PURE__ */ jsx5("div", { ...dom, style: addIntrinsicPadding(own5, wrap) ?? own5, children: /* @__PURE__ */ jsx5("span", { style: { color: C2("textSecondary", "#636B78") }, children:
|
|
39937
|
+
return /* @__PURE__ */ jsx5("div", { ...dom, style: addIntrinsicPadding(own5, wrap) ?? own5, children: /* @__PURE__ */ jsx5("span", { style: { color: C2("textSecondary", "#636B78") }, children: placeholder3 || "Rich text editor" }) });
|
|
39935
39938
|
}
|
|
39936
39939
|
if (status === "unavailable") {
|
|
39937
39940
|
return /* @__PURE__ */ jsx5("div", { ...dom, style: root, children: /* @__PURE__ */ jsx5("div", { "data-component-id": `${id}/fallback`, children: props.fallback ? renderChild(props.fallback) : /* @__PURE__ */ jsx5("p", { style: { margin: 0, color: C2("textSecondary", "#636B78") }, children: "Editor unavailable" }) }) });
|
|
@@ -40010,7 +40013,7 @@ function RichContentEditorView({ props, ctx, wrap, nodeId, renderChild, ...dom }
|
|
|
40010
40013
|
ref: iframeRef,
|
|
40011
40014
|
src,
|
|
40012
40015
|
sandbox: "allow-scripts",
|
|
40013
|
-
title:
|
|
40016
|
+
title: placeholder3 || "Rich text editor",
|
|
40014
40017
|
"data-component-id": `${id}/webview`,
|
|
40015
40018
|
style: { flex: "1 1 auto", width: "100%", border: 0, minHeight: fill ? 0 : minHeight, background: "transparent" }
|
|
40016
40019
|
}
|
|
@@ -42718,8 +42721,8 @@ function makePathFromDrawOPS(data) {
|
|
|
42718
42721
|
}
|
|
42719
42722
|
return path2;
|
|
42720
42723
|
}
|
|
42721
|
-
function bindEvents(obj4, element,
|
|
42722
|
-
for (const name of
|
|
42724
|
+
function bindEvents(obj4, element, names2) {
|
|
42725
|
+
for (const name of names2) {
|
|
42723
42726
|
element.addEventListener(name, obj4[name].bind(obj4));
|
|
42724
42727
|
}
|
|
42725
42728
|
}
|
|
@@ -45273,7 +45276,7 @@ var init_pdf = __esm({
|
|
|
45273
45276
|
var defineProperty = Object.defineProperty;
|
|
45274
45277
|
var stringSlice = uncurryThis("".slice);
|
|
45275
45278
|
var replace = uncurryThis("".replace);
|
|
45276
|
-
var
|
|
45279
|
+
var join95 = uncurryThis([].join);
|
|
45277
45280
|
var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function() {
|
|
45278
45281
|
return defineProperty(function() {
|
|
45279
45282
|
}, "length", { value: 8 }).length !== 8;
|
|
@@ -45300,7 +45303,7 @@ var init_pdf = __esm({
|
|
|
45300
45303
|
}
|
|
45301
45304
|
var state = enforceInternalState(value);
|
|
45302
45305
|
if (!hasOwn(state, "source")) {
|
|
45303
|
-
state.source =
|
|
45306
|
+
state.source = join95(TEMPLATE, typeof name == "string" ? name : "");
|
|
45304
45307
|
}
|
|
45305
45308
|
return value;
|
|
45306
45309
|
};
|
|
@@ -45563,13 +45566,13 @@ var init_pdf = __esm({
|
|
|
45563
45566
|
var indexOf = __webpack_require__3(9617).indexOf;
|
|
45564
45567
|
var hiddenKeys = __webpack_require__3(421);
|
|
45565
45568
|
var push = uncurryThis([].push);
|
|
45566
|
-
module.exports = function(object6,
|
|
45569
|
+
module.exports = function(object6, names2) {
|
|
45567
45570
|
var O2 = toIndexedObject(object6);
|
|
45568
45571
|
var i2 = 0;
|
|
45569
45572
|
var result = [];
|
|
45570
45573
|
var key3;
|
|
45571
45574
|
for (key3 in O2) !hasOwn(hiddenKeys, key3) && hasOwn(O2, key3) && push(result, key3);
|
|
45572
|
-
while (
|
|
45575
|
+
while (names2.length > i2) if (hasOwn(O2, key3 = names2[i2++])) {
|
|
45573
45576
|
~indexOf(result, key3) || push(result, key3);
|
|
45574
45577
|
}
|
|
45575
45578
|
return result;
|
|
@@ -47823,7 +47826,7 @@ var init_pdf = __esm({
|
|
|
47823
47826
|
var charAt = uncurryThis("".charAt);
|
|
47824
47827
|
var Uint8Array2 = globalThis2.Uint8Array;
|
|
47825
47828
|
var $Array = globalThis2.Array;
|
|
47826
|
-
var
|
|
47829
|
+
var join95 = uncurryThis([].join);
|
|
47827
47830
|
var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toBase64 || !(function() {
|
|
47828
47831
|
try {
|
|
47829
47832
|
var target = new Uint8Array2();
|
|
@@ -47869,7 +47872,7 @@ var init_pdf = __esm({
|
|
|
47869
47872
|
result[written++] = "=";
|
|
47870
47873
|
}
|
|
47871
47874
|
}
|
|
47872
|
-
return
|
|
47875
|
+
return join95(result, "");
|
|
47873
47876
|
}
|
|
47874
47877
|
});
|
|
47875
47878
|
},
|
|
@@ -47881,7 +47884,7 @@ var init_pdf = __esm({
|
|
|
47881
47884
|
var anUint8Array = __webpack_require__3(4154);
|
|
47882
47885
|
var notDetached = __webpack_require__3(5169);
|
|
47883
47886
|
var numberToString2 = uncurryThis(1.1.toString);
|
|
47884
|
-
var
|
|
47887
|
+
var join95 = uncurryThis([].join);
|
|
47885
47888
|
var $Array = Array;
|
|
47886
47889
|
var Uint8Array2 = globalThis2.Uint8Array;
|
|
47887
47890
|
var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toHex || !(function() {
|
|
@@ -47901,7 +47904,7 @@ var init_pdf = __esm({
|
|
|
47901
47904
|
var hex2 = numberToString2(this[i2], 16);
|
|
47902
47905
|
result[i2] = hex2.length === 1 ? "0" + hex2 : hex2;
|
|
47903
47906
|
}
|
|
47904
|
-
return
|
|
47907
|
+
return join95(result, "");
|
|
47905
47908
|
}
|
|
47906
47909
|
});
|
|
47907
47910
|
},
|
|
@@ -54695,7 +54698,7 @@ var init_pdf = __esm({
|
|
|
54695
54698
|
recordFutureForcedDependency(name, idx) {
|
|
54696
54699
|
return this;
|
|
54697
54700
|
}
|
|
54698
|
-
inheritSimpleDataAsFutureForcedDependencies(
|
|
54701
|
+
inheritSimpleDataAsFutureForcedDependencies(names2) {
|
|
54699
54702
|
return this;
|
|
54700
54703
|
}
|
|
54701
54704
|
inheritPendingDependenciesAsFutureForcedDependencies() {
|
|
@@ -54831,8 +54834,8 @@ var init_pdf = __esm({
|
|
|
54831
54834
|
this.recordIncrementalData(FORCED_DEPENDENCY_LABEL, idx);
|
|
54832
54835
|
return this;
|
|
54833
54836
|
}
|
|
54834
|
-
inheritSimpleDataAsFutureForcedDependencies(
|
|
54835
|
-
for (const name of
|
|
54837
|
+
inheritSimpleDataAsFutureForcedDependencies(names2) {
|
|
54838
|
+
for (const name of names2) {
|
|
54836
54839
|
if (name in this.#simple) {
|
|
54837
54840
|
this.recordFutureForcedDependency(name, this.#simple[name]);
|
|
54838
54841
|
}
|
|
@@ -55038,8 +55041,8 @@ var init_pdf = __esm({
|
|
|
55038
55041
|
this.#dependencyTracker.recordFutureForcedDependency(name, this.#opIdx);
|
|
55039
55042
|
return this;
|
|
55040
55043
|
}
|
|
55041
|
-
inheritSimpleDataAsFutureForcedDependencies(
|
|
55042
|
-
this.#dependencyTracker.inheritSimpleDataAsFutureForcedDependencies(
|
|
55044
|
+
inheritSimpleDataAsFutureForcedDependencies(names2) {
|
|
55045
|
+
this.#dependencyTracker.inheritSimpleDataAsFutureForcedDependencies(names2);
|
|
55043
55046
|
return this;
|
|
55044
55047
|
}
|
|
55045
55048
|
inheritPendingDependenciesAsFutureForcedDependencies() {
|
|
@@ -64948,11 +64951,11 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
64948
64951
|
});
|
|
64949
64952
|
}
|
|
64950
64953
|
}
|
|
64951
|
-
_setEventListeners(element, elementData,
|
|
64954
|
+
_setEventListeners(element, elementData, names2, getter) {
|
|
64952
64955
|
const {
|
|
64953
64956
|
actions
|
|
64954
64957
|
} = this.data;
|
|
64955
|
-
for (const [baseName, eventName] of
|
|
64958
|
+
for (const [baseName, eventName] of names2) {
|
|
64956
64959
|
if (eventName === "Action" || actions?.has(eventName)) {
|
|
64957
64960
|
if (eventName === "Focus" || eventName === "Blur") {
|
|
64958
64961
|
elementData ||= {
|
|
@@ -126398,8 +126401,8 @@ var init_renderNode = __esm({
|
|
|
126398
126401
|
const rawPlaceholder = props.placeholder ?? cfg.placeholder;
|
|
126399
126402
|
const resolvedPlaceholder = useResolvedScalar(rawPlaceholder, ctx);
|
|
126400
126403
|
const placeholderIsBinding = isBinding(rawPlaceholder);
|
|
126401
|
-
const
|
|
126402
|
-
const placeholderName =
|
|
126404
|
+
const placeholder3 = rawPlaceholder == null || placeholderIsBinding && resolvedPlaceholder == null ? "" : placeholderIsBinding ? asTextL10n(resolvedPlaceholder, ctx) : asText2(rawPlaceholder);
|
|
126405
|
+
const placeholderName = placeholder3 || void 0;
|
|
126403
126406
|
const prefixText = useBoundString(props.prefix, ctx);
|
|
126404
126407
|
const suffixText = useBoundString(props.suffix, ctx);
|
|
126405
126408
|
const valueBinding = typeof ctrl === "string" ? ctrl : cfg.value;
|
|
@@ -126636,7 +126639,7 @@ var init_renderNode = __esm({
|
|
|
126636
126639
|
/* @__PURE__ */ jsxs7("div", { style: composedBox, children: [
|
|
126637
126640
|
props.leadingIcon && accIcon(props.leadingIcon),
|
|
126638
126641
|
prefixText && /* @__PURE__ */ jsx10("span", { style: { color: muted, flex: "none" }, children: prefixText }),
|
|
126639
|
-
multilineBox ? /* @__PURE__ */ jsx10("textarea", { "data-component-id": componentId, id: fieldDomId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder:
|
|
126642
|
+
multilineBox ? /* @__PURE__ */ jsx10("textarea", { "data-component-id": componentId, id: fieldDomId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder3, rows: 2, "aria-label": ariaLabelProp ?? placeholderName, "aria-labelledby": labelledBy, "aria-required": required3, "aria-invalid": errored || void 0, "aria-describedby": [errorId, describedByProp].filter(Boolean).join(" ") || void 0, inputMode, autoCapitalize, maxLength, autoCorrect: suggestOff ? "off" : suggestOn ? "on" : void 0, spellCheck: suggestOff ? false : suggestOn ? true : void 0, autoComplete: suggestOff ? "off" : void 0, style: inputBase }) : /* @__PURE__ */ jsx10("input", { "data-component-id": componentId, id: htmlId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, type: secure && !(visibilityToggle && valueVisible) ? "password" : "text", value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder3, "aria-label": ariaLabelProp ?? placeholderName, "aria-labelledby": labelledBy, "aria-required": required3, "aria-invalid": errored || void 0, "aria-describedby": [errorId, describedByProp].filter(Boolean).join(" ") || void 0, inputMode, autoCapitalize, maxLength, autoCorrect: suggestOff ? "off" : suggestOn ? "on" : void 0, spellCheck: suggestOff ? false : suggestOn ? true : void 0, autoComplete: suggestOff ? "off" : void 0, enterKeyHint, style: inputBase }),
|
|
126640
126643
|
suffixText && /* @__PURE__ */ jsx10("span", { style: { color: muted, flex: "none" }, children: suffixText }),
|
|
126641
126644
|
props.clearButton && local && /* @__PURE__ */ jsx10("span", { onClick: () => {
|
|
126642
126645
|
setLocal("");
|
|
@@ -132373,7 +132376,7 @@ function interpretProduce(services, parsed) {
|
|
|
132373
132376
|
return { services, widgets, views };
|
|
132374
132377
|
}
|
|
132375
132378
|
function contentEtag(snapshot2) {
|
|
132376
|
-
const
|
|
132379
|
+
const canonical6 = JSON.stringify({
|
|
132377
132380
|
widgetId: snapshot2.widgetId,
|
|
132378
132381
|
family: snapshot2.family,
|
|
132379
132382
|
size: snapshot2.size,
|
|
@@ -132382,7 +132385,7 @@ function contentEtag(snapshot2) {
|
|
|
132382
132385
|
// Lever A — a timeline change must bump the etag (frame values/times are content).
|
|
132383
132386
|
frames: snapshot2.frames ?? null
|
|
132384
132387
|
});
|
|
132385
|
-
return "sha256-" + createHash20("sha256").update(
|
|
132388
|
+
return "sha256-" + createHash20("sha256").update(canonical6).digest("base64");
|
|
132386
132389
|
}
|
|
132387
132390
|
async function buildWidgetSnapshot(bundleJs, widgetId, opts = {}) {
|
|
132388
132391
|
const { widgets } = await extractWidgets(bundleJs, opts);
|
|
@@ -133721,11 +133724,11 @@ function startBundleSourceWatcher(state) {
|
|
|
133721
133724
|
timer = setTimeout(flush, 120);
|
|
133722
133725
|
return;
|
|
133723
133726
|
}
|
|
133724
|
-
const
|
|
133727
|
+
const names2 = [...pending].sort();
|
|
133725
133728
|
pending.clear();
|
|
133726
|
-
if (
|
|
133729
|
+
if (names2.length === 0) return;
|
|
133727
133730
|
building = true;
|
|
133728
|
-
for (const name of
|
|
133731
|
+
for (const name of names2) {
|
|
133729
133732
|
try {
|
|
133730
133733
|
await rebuildBundleSource(name);
|
|
133731
133734
|
console.log(`[himalaya-dev] rebuilt T5 bundle from source: ${name}`);
|
|
@@ -133913,10 +133916,10 @@ function syncAppDependencyWatchers(state, inputs) {
|
|
|
133913
133916
|
let timer;
|
|
133914
133917
|
const changed = /* @__PURE__ */ new Set();
|
|
133915
133918
|
const watchers = [];
|
|
133916
|
-
for (const [dir,
|
|
133919
|
+
for (const [dir, names2] of byDir) {
|
|
133917
133920
|
try {
|
|
133918
133921
|
const w2 = watch(dir, { persistent: false }, (_event, filename) => {
|
|
133919
|
-
if (!filename || !
|
|
133922
|
+
if (!filename || !names2.has(String(filename))) return;
|
|
133920
133923
|
changed.add(join47(dir, String(filename)));
|
|
133921
133924
|
if (timer) clearTimeout(timer);
|
|
133922
133925
|
timer = setTimeout(() => {
|
|
@@ -135380,7 +135383,7 @@ async function readBundleFile(name, dir) {
|
|
|
135380
135383
|
async function listBundles(dir) {
|
|
135381
135384
|
const fs2 = await import("node:fs/promises");
|
|
135382
135385
|
const roots = dir ? [dir, TIER5_ROOT2] : [TIER5_ROOT2];
|
|
135383
|
-
const
|
|
135386
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
135384
135387
|
for (const root of roots) {
|
|
135385
135388
|
let entries;
|
|
135386
135389
|
try {
|
|
@@ -135390,11 +135393,11 @@ async function listBundles(dir) {
|
|
|
135390
135393
|
}
|
|
135391
135394
|
for (const entry of entries) {
|
|
135392
135395
|
const name = servedBundleName(entry);
|
|
135393
|
-
if (name !== void 0)
|
|
135396
|
+
if (name !== void 0) names2.add(name);
|
|
135394
135397
|
}
|
|
135395
135398
|
}
|
|
135396
135399
|
const result = [];
|
|
135397
|
-
for (const name of
|
|
135400
|
+
for (const name of names2) {
|
|
135398
135401
|
const loaded = await readBundleFile(name, dir);
|
|
135399
135402
|
if (!loaded) continue;
|
|
135400
135403
|
result.push({ name, integrity: loaded.integrity, sizeBytes: loaded.bytes.length });
|
|
@@ -139337,12 +139340,12 @@ function validateDependencyPolicy(packages, policy = {}) {
|
|
|
139337
139340
|
const allowedLicenses = new Set(policy.allowedLicenses ?? ["MIT", "ISC", "BSD-2-Clause", "BSD-3-Clause", "Apache-2.0"]);
|
|
139338
139341
|
const maxBytes = policy.maxBytes ?? 5 * 1024 * 1024;
|
|
139339
139342
|
const maxVulnerability = policy.maxVulnerability ?? "low";
|
|
139340
|
-
const
|
|
139343
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
139341
139344
|
let totalBytes = 0;
|
|
139342
139345
|
for (const dependency of packages) {
|
|
139343
139346
|
if (!/^@[a-z0-9._-]+\/[a-z0-9._-]+$|^[a-z0-9._-]+$/.test(dependency.name) || !pinnedSemver.test(dependency.version)) throw new Error(`dependency ${dependency.name} must use a pinned semver version`);
|
|
139344
|
-
if (
|
|
139345
|
-
|
|
139347
|
+
if (names2.has(dependency.name)) throw new Error(`dependency ${dependency.name} is duplicated`);
|
|
139348
|
+
names2.add(dependency.name);
|
|
139346
139349
|
if (!/^sha512-/.test(dependency.integrity)) throw new Error(`dependency ${dependency.name} is missing an exact lockfile integrity hash`);
|
|
139347
139350
|
if (!allowedLicenses.has(dependency.license)) throw new Error(`dependency ${dependency.name} has blocked license ${dependency.license}`);
|
|
139348
139351
|
if (dependency.scripts?.length) throw new Error(`dependency ${dependency.name} declares install scripts`);
|
|
@@ -140099,8 +140102,8 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140099
140102
|
const LIVE_LOAD_BUDGET_MS = 3e4;
|
|
140100
140103
|
const appLocalDbSchema = (() => {
|
|
140101
140104
|
const entities = config.dataSchema?.entities ?? [];
|
|
140102
|
-
const
|
|
140103
|
-
return
|
|
140105
|
+
const names2 = entities.map((e2) => e2?.name).filter((n2) => typeof n2 === "string" && n2.length > 0);
|
|
140106
|
+
return names2.length ? names2.map((name) => ({ name })) : null;
|
|
140104
140107
|
})();
|
|
140105
140108
|
let liveWixCall = null;
|
|
140106
140109
|
const ensureLiveWixCall = async () => {
|
|
@@ -140590,7 +140593,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140590
140593
|
const src = t2.pattern.source;
|
|
140591
140594
|
const raw = src.startsWith("^") && src.endsWith(DUAL_FORM_TAIL) ? src.slice(1, src.length - DUAL_FORM_TAIL.length) : null;
|
|
140592
140595
|
return { t: t2, canonical: raw && /^[A-Za-z0-9_]+$/.test(raw) ? raw : null };
|
|
140593
|
-
}).filter(({ t: t2, canonical:
|
|
140596
|
+
}).filter(({ t: t2, canonical: canonical6 }) => canonical6 !== null || typeof t2.seedIds === "function");
|
|
140594
140597
|
if (bakeRoutes.length) {
|
|
140595
140598
|
const seedCtx = {
|
|
140596
140599
|
store: preloaded.module.createStore(app),
|
|
@@ -140606,7 +140609,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140606
140609
|
// carry a working URL + digest into the release, not a null.
|
|
140607
140610
|
asset: (name) => resolveAssetForBuild(preloaded.dir, name, base, app)
|
|
140608
140611
|
};
|
|
140609
|
-
for (const { t: t2, canonical:
|
|
140612
|
+
for (const { t: t2, canonical: canonical6 } of bakeRoutes) {
|
|
140610
140613
|
let ids = [];
|
|
140611
140614
|
try {
|
|
140612
140615
|
ids = typeof t2.seedIds === "function" ? await t2.seedIds(seedCtx) ?? [] : [];
|
|
@@ -140617,7 +140620,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140617
140620
|
`[release-build] seedIds threw for templated route ${String(t2.pattern)} in "${app}" \u2014 no instances of it will be baked. If it reaches the network, note that the bake origin is ${base} and a plain bake opens no socket. ${String(err)}`
|
|
140618
140621
|
);
|
|
140619
140622
|
}
|
|
140620
|
-
if (
|
|
140623
|
+
if (canonical6) ids = [canonical6, ...ids.filter((id) => id !== canonical6)];
|
|
140621
140624
|
for (const screenId of ids) {
|
|
140622
140625
|
if (screens[screenId]) continue;
|
|
140623
140626
|
if (screenId.includes("/") || screenId.includes("..")) continue;
|
|
@@ -140664,7 +140667,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140664
140667
|
}
|
|
140665
140668
|
const json8 = pinBakedServerBaseUrl(JSON.stringify(descriptor), base);
|
|
140666
140669
|
await store.putScreen(app, screenId, json8);
|
|
140667
|
-
screens[screenId] = { descriptorHash: sha2564(json8), bundle: bundleName, ...screenMetadataFor(screenMetadata, screenId,
|
|
140670
|
+
screens[screenId] = { descriptorHash: sha2564(json8), bundle: bundleName, ...screenMetadataFor(screenMetadata, screenId, canonical6) };
|
|
140668
140671
|
rememberInput(bundleName, JSON.parse(json8));
|
|
140669
140672
|
if (collect2?.descriptors) {
|
|
140670
140673
|
baked.push({
|
|
@@ -142886,12 +142889,12 @@ function assertCredentialOutsideRepo(label3, p2) {
|
|
|
142886
142889
|
);
|
|
142887
142890
|
}
|
|
142888
142891
|
}
|
|
142889
|
-
function requireEnv(
|
|
142890
|
-
const missing =
|
|
142892
|
+
function requireEnv(names2) {
|
|
142893
|
+
const missing = names2.filter((n2) => !process.env[n2]);
|
|
142891
142894
|
if (missing.length) {
|
|
142892
142895
|
throw new Error(`Missing required environment variable(s): ${missing.join(", ")}`);
|
|
142893
142896
|
}
|
|
142894
|
-
return Object.fromEntries(
|
|
142897
|
+
return Object.fromEntries(names2.map((n2) => [n2, process.env[n2]]));
|
|
142895
142898
|
}
|
|
142896
142899
|
function strip2(line) {
|
|
142897
142900
|
const hash2 = line.indexOf("#");
|
|
@@ -153578,7 +153581,7 @@ function pushRouteAdvisories(pushRoutes) {
|
|
|
153578
153581
|
];
|
|
153579
153582
|
}
|
|
153580
153583
|
function unmappedAdvisory({ destination, vertical, reason, screenId, paramKey }) {
|
|
153581
|
-
const
|
|
153584
|
+
const canonical6 = WIX_MEMBER_PUSH_DESTINATIONS.find((d2) => d2.id === destination)?.canonicalScreen;
|
|
153582
153585
|
if (reason === "param_not_declared") {
|
|
153583
153586
|
return `push-route-unmapped: push.screens sends "${destination}" notifications to "${screenId}" with paramKey "${paramKey}", which "${screenId}" does not declare, so a shell would drop it. Use one of the keys its linkable screen declares, or add "${paramKey}" to its paramKeys.`;
|
|
153584
153587
|
}
|
|
@@ -153588,7 +153591,7 @@ function unmappedAdvisory({ destination, vertical, reason, screenId, paramKey })
|
|
|
153588
153591
|
if (screenId) {
|
|
153589
153592
|
return `push-route-unmapped: push.screens maps "${destination}" to "${screenId}", which is not a linkable screen, so the device could not open it. Add it to navigation.linkableScreens, or map another screen.`;
|
|
153590
153593
|
}
|
|
153591
|
-
return `push-route-unmapped: the site has ${vertical}, but no screen opens "${destination}" notifications. Name that screen "${
|
|
153594
|
+
return `push-route-unmapped: the site has ${vertical}, but no screen opens "${destination}" notifications. Name that screen "${canonical6}", or map it: push.screens: { "${destination}": "<screenId>" }.`;
|
|
153592
153595
|
}
|
|
153593
153596
|
function navSharedIdErrors(nav) {
|
|
153594
153597
|
const items = (key3) => {
|
|
@@ -153726,8 +153729,8 @@ function fieldType(f2) {
|
|
|
153726
153729
|
}
|
|
153727
153730
|
function renderBase44Types(entities, app) {
|
|
153728
153731
|
const candidates = entities.filter((e2) => e2 && typeof e2 === "object" && Array.isArray(e2.fields) && IDENT.test(logicalName(e2)) && physicalEntityName(e2, app));
|
|
153729
|
-
const
|
|
153730
|
-
const exportName = (e2) =>
|
|
153732
|
+
const names2 = exportNames(candidates, app);
|
|
153733
|
+
const exportName = (e2) => names2.get(e2);
|
|
153731
153734
|
const sortKey = (e2) => `${exportName(e2)}\0${physicalEntityName(e2, app)}`;
|
|
153732
153735
|
const usable = [...candidates].sort((a2, b2) => sortKey(a2) < sortKey(b2) ? -1 : sortKey(a2) > sortKey(b2) ? 1 : 0);
|
|
153733
153736
|
const L2 = [
|
|
@@ -154171,8 +154174,8 @@ function hasNote(entry) {
|
|
|
154171
154174
|
return entryHead(entry) !== entry.trim();
|
|
154172
154175
|
}
|
|
154173
154176
|
function namesLine(allowed2) {
|
|
154174
|
-
const
|
|
154175
|
-
return
|
|
154177
|
+
const names2 = [...new Set(allowed2.flatMap(entryNames))];
|
|
154178
|
+
return names2.length ? `it names: ${names2.join(", ")}` : "its entries are only notes, which approve nothing";
|
|
154176
154179
|
}
|
|
154177
154180
|
function isNoneEntry(entry) {
|
|
154178
154181
|
const head = entryHead(entry);
|
|
@@ -156782,8 +156785,8 @@ function describeFunction(definitions2, name) {
|
|
|
156782
156785
|
return definition ? { ...listFunctions([definition])[0], wixIdentity: definition.wixIdentity, wixPermissions: [...definition.wixPermissions], capabilities: [...definition.capabilities], secrets: [...definition.secrets], outboundHosts: [...definition.outboundHosts], inputSchema: definition.input?.kind ?? null, outputSchema: definition.output?.kind ?? null } : null;
|
|
156783
156786
|
}
|
|
156784
156787
|
function materializeFunctionPath(path2, params = {}) {
|
|
156785
|
-
const
|
|
156786
|
-
for (const name of
|
|
156788
|
+
const names2 = [...path2.matchAll(/:([A-Za-z][A-Za-z0-9_]*)/g)].map((match) => match[1]);
|
|
156789
|
+
for (const name of names2) {
|
|
156787
156790
|
if (typeof params[name] !== "string" || params[name] === "") throw new Error(`missing route parameter "${name}"; pass --params {"${name}":"value"}`);
|
|
156788
156791
|
}
|
|
156789
156792
|
return path2.replace(/:([A-Za-z][A-Za-z0-9_]*)/g, (_match, name) => encodeURIComponent(params[name]));
|
|
@@ -163512,7 +163515,7 @@ function skipReason(item, options) {
|
|
|
163512
163515
|
function priceFor(amount, options) {
|
|
163513
163516
|
return { baseTerritory: options.baseTerritory, currency: options.currency, amount: normalizeAmount(amount), rule: "atLeast" };
|
|
163514
163517
|
}
|
|
163515
|
-
function perItemProduct(item, options,
|
|
163518
|
+
function perItemProduct(item, options, names2) {
|
|
163516
163519
|
const plainDescription = item.description ? plainText2(item.description) : "";
|
|
163517
163520
|
const name = nameOf(item);
|
|
163518
163521
|
return {
|
|
@@ -163521,7 +163524,7 @@ function perItemProduct(item, options, names) {
|
|
|
163521
163524
|
entitlement: entityKey(item.source, item.id),
|
|
163522
163525
|
productId: productIdFor(options.target.bundleId, SOURCE_SLUGS[item.source], item.id),
|
|
163523
163526
|
type: "nonConsumable",
|
|
163524
|
-
referenceName:
|
|
163527
|
+
referenceName: names2.claim(name, item.id),
|
|
163525
163528
|
localizations: [{ locale: options.locale, name: displayName(name), description: fit(plainDescription || `Unlock ${name}`, APPLE_LIMITS.description) }],
|
|
163526
163529
|
price: priceFor(item.price.amount, options),
|
|
163527
163530
|
territories: options.territories
|
|
@@ -163537,7 +163540,7 @@ function tierPrice(amount, applePoint, options) {
|
|
|
163537
163540
|
if (!applePoint) return priceFor(amount, options);
|
|
163538
163541
|
return { baseTerritory: options.baseTerritory, currency: options.currency, amount: normalizeAmount(applePoint) };
|
|
163539
163542
|
}
|
|
163540
|
-
function newTier(key3, price, options,
|
|
163543
|
+
function newTier(key3, price, options, names2) {
|
|
163541
163544
|
const label3 = `${price.amount} ${options.currency}`;
|
|
163542
163545
|
return {
|
|
163543
163546
|
unlocks: [],
|
|
@@ -163545,13 +163548,13 @@ function newTier(key3, price, options, names) {
|
|
|
163545
163548
|
entitlement: `tier:${key3}`,
|
|
163546
163549
|
productId: tierProductId(options, key3),
|
|
163547
163550
|
type: "consumable",
|
|
163548
|
-
referenceName:
|
|
163551
|
+
referenceName: names2.claim(`Credit ${label3}`, key3),
|
|
163549
163552
|
localizations: [{ locale: options.locale, name: displayName(`Unlock (${label3})`), description: TIER_DESCRIPTION }],
|
|
163550
163553
|
price,
|
|
163551
163554
|
territories: options.territories
|
|
163552
163555
|
};
|
|
163553
163556
|
}
|
|
163554
|
-
function draftTiers(items, options,
|
|
163557
|
+
function draftTiers(items, options, names2, existingItems) {
|
|
163555
163558
|
const byProductId = new Map(existingItems.map((i2) => [i2.productId, i2]));
|
|
163556
163559
|
const created = [];
|
|
163557
163560
|
for (const item of items) {
|
|
@@ -163561,7 +163564,7 @@ function draftTiers(items, options, names, existingItems) {
|
|
|
163561
163564
|
const productId = tierProductId(options, key3);
|
|
163562
163565
|
let tier = byProductId.get(productId);
|
|
163563
163566
|
if (!tier) {
|
|
163564
|
-
tier = newTier(key3, price, options,
|
|
163567
|
+
tier = newTier(key3, price, options, names2);
|
|
163565
163568
|
byProductId.set(productId, tier);
|
|
163566
163569
|
created.push(tier);
|
|
163567
163570
|
}
|
|
@@ -163584,7 +163587,7 @@ function refreshMergedPrices(items, catalog3, options) {
|
|
|
163584
163587
|
function draftManifest(catalog3, options) {
|
|
163585
163588
|
const existingItems = structuredClone(options.existing?.items ?? []);
|
|
163586
163589
|
const mapped = new Set(existingItems.flatMap((i2) => wixEntitiesOf(i2).map((e2) => entityKey(e2.entityType, e2.entityId))));
|
|
163587
|
-
const
|
|
163590
|
+
const names2 = new ReferenceNames(existingItems);
|
|
163588
163591
|
const skipped = refreshMergedPrices(existingItems, catalog3, options);
|
|
163589
163592
|
const toDraft = [];
|
|
163590
163593
|
let kept = 0;
|
|
@@ -163596,7 +163599,7 @@ function draftManifest(catalog3, options) {
|
|
|
163596
163599
|
else toDraft.push(item);
|
|
163597
163600
|
}
|
|
163598
163601
|
}
|
|
163599
|
-
const drafted = options.mode === "tiers" ? draftTiers(toDraft, options,
|
|
163602
|
+
const drafted = options.mode === "tiers" ? draftTiers(toDraft, options, names2, existingItems) : toDraft.map((item) => perItemProduct(item, options, names2));
|
|
163600
163603
|
const items = [...existingItems, ...drafted];
|
|
163601
163604
|
const newlyMapped = toDraft.length;
|
|
163602
163605
|
if (!items.length) return { skipped, kept, newlyMapped };
|
|
@@ -166214,8 +166217,8 @@ function analyzePlayListing(assets) {
|
|
|
166214
166217
|
}
|
|
166215
166218
|
function playListingAssets(app, locale = "en-US") {
|
|
166216
166219
|
const dir = join81(storeDir(app), "play", locale, "images");
|
|
166217
|
-
const read = (
|
|
166218
|
-
for (const name of
|
|
166220
|
+
const read = (names2) => {
|
|
166221
|
+
for (const name of names2) {
|
|
166219
166222
|
const p2 = join81(dir, name);
|
|
166220
166223
|
try {
|
|
166221
166224
|
if (statSync21(p2).isFile()) return { name, bytes: readFileSync95(p2) };
|
|
@@ -167900,9 +167903,9 @@ function planEntityScreens(specs, app = "") {
|
|
|
167900
167903
|
owners.set(what, `entity "${p2.name}"`);
|
|
167901
167904
|
}
|
|
167902
167905
|
}
|
|
167903
|
-
const
|
|
167904
|
-
if (
|
|
167905
|
-
return { plans, tabs:
|
|
167906
|
+
const names2 = plans.map((p2) => p2.name);
|
|
167907
|
+
if (names2.length <= ENTITY_TAB_SLOTS) return { plans, tabs: names2, more: [] };
|
|
167908
|
+
return { plans, tabs: names2.slice(0, ENTITY_TAB_SLOTS - 1), more: names2.slice(ENTITY_TAB_SLOTS - 1) };
|
|
167906
167909
|
}
|
|
167907
167910
|
var PlanError, RESERVED_SCREEN_IDS, MORE_SCREEN_ID, ENTITY_TAB_SLOTS, OWNER_RULES, pascal, PREFERRED_TITLES, LONG_TEXT, IMAGE_KEY, SEGMENTED_MAX, isPlainString, isEnum, isDate, isImage, isLongText, nounOf;
|
|
167908
167911
|
var init_plan4 = __esm({
|
|
@@ -168117,12 +168120,14 @@ var base44_auth_exports = {};
|
|
|
168117
168120
|
__export(base44_auth_exports, {
|
|
168118
168121
|
BASE44_LOGIN_SCOPE: () => BASE44_LOGIN_SCOPE,
|
|
168119
168122
|
BASE44_OAUTH_CLIENT_ID: () => BASE44_OAUTH_CLIENT_ID,
|
|
168123
|
+
BASE44_WRITE_SCOPE: () => BASE44_WRITE_SCOPE,
|
|
168120
168124
|
base44ApiBase: () => base44ApiBase,
|
|
168121
168125
|
base44DeviceLogin: () => base44DeviceLogin,
|
|
168122
168126
|
base44SessionPath: () => base44SessionPath,
|
|
168123
168127
|
base44Whoami: () => base44Whoami,
|
|
168124
168128
|
currentBase44Auth: () => currentBase44Auth,
|
|
168125
168129
|
deleteBase44Session: () => deleteBase44Session,
|
|
168130
|
+
hasBase44WriteScope: () => hasBase44WriteScope,
|
|
168126
168131
|
importBase44CliSession: () => importBase44CliSession,
|
|
168127
168132
|
jwtClaims: () => jwtClaims,
|
|
168128
168133
|
readBase44Session: () => readBase44Session,
|
|
@@ -168216,7 +168221,7 @@ async function base44DeviceLogin(opts) {
|
|
|
168216
168221
|
const res = await fetchImpl(`${apiBase}/oauth/device/code`, {
|
|
168217
168222
|
method: "POST",
|
|
168218
168223
|
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
168219
|
-
body: JSON.stringify({ client_id: BASE44_OAUTH_CLIENT_ID, scope: BASE44_LOGIN_SCOPE })
|
|
168224
|
+
body: JSON.stringify({ client_id: BASE44_OAUTH_CLIENT_ID, scope: opts.scope ?? BASE44_LOGIN_SCOPE })
|
|
168220
168225
|
});
|
|
168221
168226
|
if (!res.ok) throw new Error(`Base44 refused a device code: HTTP ${res.status}`);
|
|
168222
168227
|
const code = await res.json();
|
|
@@ -168252,6 +168257,13 @@ async function base44DeviceLogin(opts) {
|
|
|
168252
168257
|
}
|
|
168253
168258
|
throw new Error("the Base44 sign-in code expired before it was approved \u2014 run `himi base44 login` again");
|
|
168254
168259
|
}
|
|
168260
|
+
function hasBase44WriteScope(auth) {
|
|
168261
|
+
const c2 = jwtClaims(auth.token);
|
|
168262
|
+
const raw = c2?.scope ?? c2?.scp;
|
|
168263
|
+
const scopes = typeof raw === "string" ? raw.split(/\s+/) : Array.isArray(raw) ? raw.map(String) : void 0;
|
|
168264
|
+
if (!scopes) return "unknown";
|
|
168265
|
+
return scopes.includes("apps:write");
|
|
168266
|
+
}
|
|
168255
168267
|
function importBase44CliSession(home = homedir13(), env = process.env) {
|
|
168256
168268
|
const src = join85(home, ".base44", "auth", "auth.json");
|
|
168257
168269
|
if (!existsSync80(src)) throw new Error(`no Base44 CLI session at ${src} \u2014 run \`npx base44 login\` first, or use \`himi base44 login\``);
|
|
@@ -168279,15 +168291,1063 @@ function base44Whoami(auth, now = Date.now()) {
|
|
|
168279
168291
|
...auth.expiresAt ? { expiresAt: new Date(auth.expiresAt).toISOString(), expired: now >= auth.expiresAt } : {}
|
|
168280
168292
|
};
|
|
168281
168293
|
}
|
|
168282
|
-
var BASE44_OAUTH_CLIENT_ID, BASE44_LOGIN_SCOPE, REFRESH_BUFFER_MS;
|
|
168294
|
+
var BASE44_OAUTH_CLIENT_ID, BASE44_LOGIN_SCOPE, BASE44_WRITE_SCOPE, REFRESH_BUFFER_MS;
|
|
168283
168295
|
var init_base44_auth = __esm({
|
|
168284
168296
|
"src/base44-auth.ts"() {
|
|
168285
168297
|
BASE44_OAUTH_CLIENT_ID = "base44_cli";
|
|
168286
168298
|
BASE44_LOGIN_SCOPE = "apps:read";
|
|
168299
|
+
BASE44_WRITE_SCOPE = "apps:read apps:write";
|
|
168287
168300
|
REFRESH_BUFFER_MS = 6e4;
|
|
168288
168301
|
}
|
|
168289
168302
|
});
|
|
168290
168303
|
|
|
168304
|
+
// src/base44-provision/http.ts
|
|
168305
|
+
function appUrl(t2, appId2, path2) {
|
|
168306
|
+
return new URL(`/api/apps/${encodeURIComponent(appId2)}/${path2}`, t2.apiBase).href;
|
|
168307
|
+
}
|
|
168308
|
+
async function callJson(t2, appId2, method, path2, what, body) {
|
|
168309
|
+
const res = await t2.apiFetch(appUrl(t2, appId2, path2), {
|
|
168310
|
+
method,
|
|
168311
|
+
headers: {
|
|
168312
|
+
Authorization: `Bearer ${t2.auth.token}`,
|
|
168313
|
+
Accept: "application/json",
|
|
168314
|
+
"User-Agent": "himi base44 provision",
|
|
168315
|
+
...body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
168316
|
+
},
|
|
168317
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
168318
|
+
});
|
|
168319
|
+
if (!res.ok) {
|
|
168320
|
+
const text10 = await res.text().catch(() => "");
|
|
168321
|
+
throw new Base44RequestError(res.status, text10.slice(0, 500), what);
|
|
168322
|
+
}
|
|
168323
|
+
const text9 = await res.text();
|
|
168324
|
+
try {
|
|
168325
|
+
return JSON.parse(text9);
|
|
168326
|
+
} catch {
|
|
168327
|
+
throw new Base44RequestError(res.status, `unreadable response: ${text9.slice(0, 200)}`, what);
|
|
168328
|
+
}
|
|
168329
|
+
}
|
|
168330
|
+
function requestFailure(e2) {
|
|
168331
|
+
if (e2 instanceof Base44RequestError) return { ok: false, code: "request_failed", error: e2.message, status: e2.status, ...e2.serverError ? { serverError: e2.serverError } : {} };
|
|
168332
|
+
return { ok: false, code: "request_failed", error: e2 instanceof Error ? e2.message : String(e2) };
|
|
168333
|
+
}
|
|
168334
|
+
function writeScopeFailure(auth) {
|
|
168335
|
+
const w2 = hasBase44WriteScope(auth);
|
|
168336
|
+
if (w2 === true) return void 0;
|
|
168337
|
+
return {
|
|
168338
|
+
ok: false,
|
|
168339
|
+
code: "write_scope_missing",
|
|
168340
|
+
error: w2 === false ? "the Base44 session was minted read-only (apps:read) \u2014 writing needs apps:write" : "the Base44 token's scope cannot be read, so himi will not assume it may write",
|
|
168341
|
+
hint: "run `himi base44 login --write` (or set BASE44_ACCESS_TOKEN to a token whose claims carry apps:write)"
|
|
168342
|
+
};
|
|
168343
|
+
}
|
|
168344
|
+
var Base44RequestError;
|
|
168345
|
+
var init_http2 = __esm({
|
|
168346
|
+
"src/base44-provision/http.ts"() {
|
|
168347
|
+
init_base44_auth();
|
|
168348
|
+
Base44RequestError = class extends Error {
|
|
168349
|
+
constructor(status, serverError, what) {
|
|
168350
|
+
super(`${what}: HTTP ${status}${serverError ? ` \u2014 ${serverError}` : ""}`);
|
|
168351
|
+
this.status = status;
|
|
168352
|
+
this.serverError = serverError;
|
|
168353
|
+
}
|
|
168354
|
+
};
|
|
168355
|
+
}
|
|
168356
|
+
});
|
|
168357
|
+
|
|
168358
|
+
// src/base44-provision/seed.ts
|
|
168359
|
+
var seed_exports = {};
|
|
168360
|
+
__export(seed_exports, {
|
|
168361
|
+
BASE44_SEED_FILE: () => BASE44_SEED_FILE,
|
|
168362
|
+
SeedFileError: () => SeedFileError,
|
|
168363
|
+
readBase44SeedFile: () => readBase44SeedFile,
|
|
168364
|
+
seedBase44Entities: () => seedBase44Entities,
|
|
168365
|
+
writeBase44SeedRows: () => writeBase44SeedRows
|
|
168366
|
+
});
|
|
168367
|
+
import { existsSync as existsSync81, readFileSync as readFileSync102, writeFileSync as writeFileSync36 } from "node:fs";
|
|
168368
|
+
import { join as join86 } from "node:path";
|
|
168369
|
+
function readBase44SeedFile(dir) {
|
|
168370
|
+
const file2 = join86(dir, BASE44_SEED_FILE);
|
|
168371
|
+
if (!existsSync81(file2)) return {};
|
|
168372
|
+
let parsed;
|
|
168373
|
+
try {
|
|
168374
|
+
parsed = JSON.parse(readFileSync102(file2, "utf8"));
|
|
168375
|
+
} catch (e2) {
|
|
168376
|
+
throw new SeedFileError(`${BASE44_SEED_FILE} is not valid JSON (${e2.message}). Fix or delete it.`);
|
|
168377
|
+
}
|
|
168378
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new SeedFileError(`${BASE44_SEED_FILE} must be an object keyed by entity name.`);
|
|
168379
|
+
const out2 = /* @__PURE__ */ Object.create(null);
|
|
168380
|
+
for (const [name, rows] of Object.entries(parsed)) {
|
|
168381
|
+
if (!Array.isArray(rows)) throw new SeedFileError(`${BASE44_SEED_FILE}: "${name}" must be an array of row objects.`);
|
|
168382
|
+
const bad2 = rows.findIndex((r2) => !r2 || typeof r2 !== "object" || Array.isArray(r2));
|
|
168383
|
+
if (bad2 !== -1) throw new SeedFileError(`${BASE44_SEED_FILE}: "${name}" row ${bad2} is not an object.`);
|
|
168384
|
+
out2[name] = rows;
|
|
168385
|
+
}
|
|
168386
|
+
return out2;
|
|
168387
|
+
}
|
|
168388
|
+
async function seedBase44Entities(opts) {
|
|
168389
|
+
const { app, appId: appId2, yes = false } = opts;
|
|
168390
|
+
const report3 = { ok: true, app, appId: appId2, dryRun: !yes, inserted: {}, sources: {}, skipped: [] };
|
|
168391
|
+
if (yes) {
|
|
168392
|
+
const denied2 = writeScopeFailure(opts.auth);
|
|
168393
|
+
if (denied2) return { ...report3, ...denied2 };
|
|
168394
|
+
}
|
|
168395
|
+
let fileRows = {};
|
|
168396
|
+
try {
|
|
168397
|
+
fileRows = opts.dir ? readBase44SeedFile(opts.dir) : {};
|
|
168398
|
+
} catch (e2) {
|
|
168399
|
+
return { ...report3, ok: false, code: "seed_file_invalid", error: e2.message };
|
|
168400
|
+
}
|
|
168401
|
+
const specs = opts.entities.filter((s2) => !!s2 && typeof s2 === "object");
|
|
168402
|
+
const queue = [];
|
|
168403
|
+
let considered = 0;
|
|
168404
|
+
for (const spec of specs) {
|
|
168405
|
+
const name = physicalEntityName(spec, app);
|
|
168406
|
+
if (!name || opts.only && !opts.only.includes(name) && !opts.only.includes(spec.name ?? "")) continue;
|
|
168407
|
+
if (!isOwnedEntity(spec)) {
|
|
168408
|
+
if (opts.only) report3.skipped.push({ entity: name, skipped: "adopted", detail: "adopted entities are read-only \u2014 himi never seeds an entity it does not own" });
|
|
168409
|
+
continue;
|
|
168410
|
+
}
|
|
168411
|
+
if (!name.startsWith(base44Prefix(app))) continue;
|
|
168412
|
+
considered++;
|
|
168413
|
+
const inFile = Object.hasOwn(fileRows, name);
|
|
168414
|
+
const fromFile = inFile ? fileRows[name] : void 0;
|
|
168415
|
+
const rows = inFile ? fromFile ?? [] : spec.seed ?? [];
|
|
168416
|
+
const source = inFile ? "base44-seed.json" : "config.ts";
|
|
168417
|
+
if (!rows.length) {
|
|
168418
|
+
report3.skipped.push({ entity: name, skipped: "no-rows", detail: `no seed rows \u2014 add \`seed\` to this entity in config.ts, or run \`himi base44 entities seed --ai\` and refine ${BASE44_SEED_FILE}` });
|
|
168419
|
+
continue;
|
|
168420
|
+
}
|
|
168421
|
+
if (opts.provisioned && !opts.provisioned.includes(name)) {
|
|
168422
|
+
report3.skipped.push({ entity: name, skipped: "unclaimed", detail: "not recorded in base44-provisioned.json as provisioned by this app \u2014 run `himi base44 entities create --yes` first (or, if it is this app's, record it there)" });
|
|
168423
|
+
report3.ok = false;
|
|
168424
|
+
continue;
|
|
168425
|
+
}
|
|
168426
|
+
let existing;
|
|
168427
|
+
try {
|
|
168428
|
+
existing = await callJson(opts, appId2, "GET", `entities/${encodeURIComponent(name)}?limit=1`, `listing ${name}`);
|
|
168429
|
+
} catch (e2) {
|
|
168430
|
+
const missing = e2 instanceof Base44RequestError && e2.status === 404;
|
|
168431
|
+
report3.skipped.push(missing ? { entity: name, skipped: "missing", detail: "not on the app yet \u2014 run `himi base44 entities create --yes` first" } : { entity: name, skipped: "unreadable", detail: `could not read whether it has rows, so seeding might bury content: ${e2.message}` });
|
|
168432
|
+
report3.ok = false;
|
|
168433
|
+
continue;
|
|
168434
|
+
}
|
|
168435
|
+
const page = Array.isArray(existing) ? existing : Array.isArray(existing?.items) ? existing.items : null;
|
|
168436
|
+
if (page === null) {
|
|
168437
|
+
report3.skipped.push({ entity: name, skipped: "unreadable", detail: "the row listing came back in an unrecognised shape, so emptiness is unknown" });
|
|
168438
|
+
report3.ok = false;
|
|
168439
|
+
continue;
|
|
168440
|
+
}
|
|
168441
|
+
if (page.length > 0) {
|
|
168442
|
+
report3.skipped.push({ entity: name, skipped: "not-empty", detail: "already has rows \u2014 seeding only fills empty entities" });
|
|
168443
|
+
continue;
|
|
168444
|
+
}
|
|
168445
|
+
const declared = new Set((spec.fields ?? []).map((f2) => f2.key));
|
|
168446
|
+
const clean2 = rows.map((row) => Object.fromEntries(Object.entries(row).filter(([k2]) => declared.has(k2))));
|
|
168447
|
+
const dropped = [...new Set(rows.flatMap((r2) => Object.keys(r2).filter((k2) => !declared.has(k2))))];
|
|
168448
|
+
if (dropped.length) (report3.droppedKeys ??= {})[name] = dropped;
|
|
168449
|
+
if (clean2.some((r2) => Object.keys(r2).length === 0)) {
|
|
168450
|
+
return { ...report3, ok: false, code: "seed_file_invalid", error: `${name}: ${clean2.filter((r2) => Object.keys(r2).length === 0).length} seed row(s) have no declared field (dropped: ${dropped.join(", ") || "none"}) \u2014 fix the keys in ${BASE44_SEED_FILE}; nothing was sent` };
|
|
168451
|
+
}
|
|
168452
|
+
queue.push({ name, clean: clean2, source });
|
|
168453
|
+
}
|
|
168454
|
+
for (const { name, clean: clean2, source } of queue) {
|
|
168455
|
+
if (yes) {
|
|
168456
|
+
try {
|
|
168457
|
+
await callJson(opts, appId2, "POST", `entities/${encodeURIComponent(name)}/bulk`, `seeding ${name}`, clean2);
|
|
168458
|
+
} catch (e2) {
|
|
168459
|
+
return { ...report3, ...requestFailure(e2) };
|
|
168460
|
+
}
|
|
168461
|
+
}
|
|
168462
|
+
report3.inserted[name] = clean2.length;
|
|
168463
|
+
report3.sources[name] = source;
|
|
168464
|
+
}
|
|
168465
|
+
if (considered === 0) {
|
|
168466
|
+
return {
|
|
168467
|
+
...report3,
|
|
168468
|
+
ok: false,
|
|
168469
|
+
code: "nothing_to_seed",
|
|
168470
|
+
error: opts.only ? `--only ${opts.only.join(",")} matched no owned entity` : "this app declares no owned Base44 entities to seed",
|
|
168471
|
+
hint: `declare an owned entity with \`name\` (physically ${base44Prefix(app)}<Name>) \u2014 adopted entities are never seeded`
|
|
168472
|
+
};
|
|
168473
|
+
}
|
|
168474
|
+
if (!report3.ok) return { ...report3, code: "seed_incomplete", error: "one or more owned entities could not be seeded; `skipped[]` says why" };
|
|
168475
|
+
return report3;
|
|
168476
|
+
}
|
|
168477
|
+
function placeholder2(f2, i2) {
|
|
168478
|
+
const n2 = i2 + 1;
|
|
168479
|
+
if (f2.enum?.length) return f2.enum[i2 % f2.enum.length];
|
|
168480
|
+
switch (f2.type) {
|
|
168481
|
+
case "number":
|
|
168482
|
+
return n2 * 10;
|
|
168483
|
+
case "integer":
|
|
168484
|
+
return n2;
|
|
168485
|
+
case "boolean":
|
|
168486
|
+
return i2 % 2 === 0;
|
|
168487
|
+
case "array":
|
|
168488
|
+
switch (f2.items?.type) {
|
|
168489
|
+
case "number":
|
|
168490
|
+
case "integer":
|
|
168491
|
+
return [n2];
|
|
168492
|
+
case "boolean":
|
|
168493
|
+
return [i2 % 2 === 0];
|
|
168494
|
+
case "object":
|
|
168495
|
+
return [{}];
|
|
168496
|
+
case "array":
|
|
168497
|
+
return [[]];
|
|
168498
|
+
default:
|
|
168499
|
+
return [`${f2.key}-${n2}`];
|
|
168500
|
+
}
|
|
168501
|
+
case "object":
|
|
168502
|
+
return {};
|
|
168503
|
+
default:
|
|
168504
|
+
switch (f2.format) {
|
|
168505
|
+
case "date":
|
|
168506
|
+
return `2026-0${i2 % 9 + 1}-15`;
|
|
168507
|
+
case "date-time":
|
|
168508
|
+
return `2026-0${i2 % 9 + 1}-15T12:00:00.000Z`;
|
|
168509
|
+
case "time":
|
|
168510
|
+
return `1${i2 % 10}:00`;
|
|
168511
|
+
case "email":
|
|
168512
|
+
return `person${n2}@example.com`;
|
|
168513
|
+
case "uri":
|
|
168514
|
+
case "file":
|
|
168515
|
+
return `https://example.com/${f2.key}-${n2}`;
|
|
168516
|
+
case "uuid":
|
|
168517
|
+
return `00000000-0000-4000-8000-${String(n2).padStart(12, "0")}`;
|
|
168518
|
+
default:
|
|
168519
|
+
return `${f2.key} ${n2}`;
|
|
168520
|
+
}
|
|
168521
|
+
}
|
|
168522
|
+
}
|
|
168523
|
+
function writeBase44SeedRows(opts) {
|
|
168524
|
+
const { dir, app, count: count2 = 8 } = opts;
|
|
168525
|
+
const path2 = join86(dir, BASE44_SEED_FILE);
|
|
168526
|
+
const owned = opts.entities.filter((s2) => !!s2 && typeof s2 === "object" && isOwnedEntity(s2) && (!opts.only || opts.only.includes(physicalEntityName(s2, app)) || opts.only.includes(s2.name ?? "")));
|
|
168527
|
+
if (!owned.length) {
|
|
168528
|
+
return { ok: false, path: path2, entities: {}, agentPrompt: "", next: [], note: opts.only ? `--only ${opts.only.join(",")} matched no owned entity` : `no owned Base44 entities declared \u2014 add one with \`name\` (physically ${base44Prefix(app)}<Name>). Adopted entities are never seeded.` };
|
|
168529
|
+
}
|
|
168530
|
+
let existing = {};
|
|
168531
|
+
if (existsSync81(path2)) {
|
|
168532
|
+
let parsed;
|
|
168533
|
+
try {
|
|
168534
|
+
parsed = JSON.parse(readFileSync102(path2, "utf8"));
|
|
168535
|
+
} catch (e2) {
|
|
168536
|
+
throw new SeedFileError(`${BASE44_SEED_FILE} is not valid JSON (${e2.message}). Refusing to regenerate, because overwriting it would discard the rows already in it.`);
|
|
168537
|
+
}
|
|
168538
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new SeedFileError(`${BASE44_SEED_FILE} must be an object keyed by entity name. Fix or delete it.`);
|
|
168539
|
+
existing = parsed;
|
|
168540
|
+
}
|
|
168541
|
+
const entities = {};
|
|
168542
|
+
const fieldless = [];
|
|
168543
|
+
for (const spec of owned) {
|
|
168544
|
+
const name = physicalEntityName(spec, app);
|
|
168545
|
+
if (!(spec.fields ?? []).length) {
|
|
168546
|
+
fieldless.push(name);
|
|
168547
|
+
continue;
|
|
168548
|
+
}
|
|
168549
|
+
existing[name] = Array.from({ length: count2 }, (_2, i2) => Object.fromEntries((spec.fields ?? []).map((f2) => [f2.key, placeholder2(f2, i2)])));
|
|
168550
|
+
entities[name] = count2;
|
|
168551
|
+
}
|
|
168552
|
+
writeFileSync36(path2, `${JSON.stringify(existing, null, 2)}
|
|
168553
|
+
`);
|
|
168554
|
+
const seedable = owned.filter((s2) => (s2.fields ?? []).length);
|
|
168555
|
+
if (!seedable.length) {
|
|
168556
|
+
return { ok: false, path: path2, entities: {}, agentPrompt: "", next: [], note: `no owned entity has a declared field to seed (${fieldless.join(", ")}) \u2014 declare fields first` };
|
|
168557
|
+
}
|
|
168558
|
+
const schema = seedable.map((s2) => ` ${physicalEntityName(s2, app)}
|
|
168559
|
+
${(s2.fields ?? []).map((f2) => ` ${f2.key} (${f2.type}${f2.format ? `, ${f2.format}` : ""}${f2.enum ? `, one of ${f2.enum.join("|")}` : ""})`).join("\n")}`).join("\n");
|
|
168560
|
+
const agentPrompt = [
|
|
168561
|
+
`Rewrite the placeholder rows in ${BASE44_SEED_FILE} as realistic content for the app "${app}".`,
|
|
168562
|
+
``,
|
|
168563
|
+
`Entities and their fields:`,
|
|
168564
|
+
schema,
|
|
168565
|
+
``,
|
|
168566
|
+
`Rules:`,
|
|
168567
|
+
` - Keep the exact JSON shape: one key per entity name, an array of ${count2} row objects.`,
|
|
168568
|
+
` - Use ONLY the field keys listed above and keep each value's JSON type; an enum field takes one of its listed values.`,
|
|
168569
|
+
` - Make the content specific and plausible for this app's domain. No "Lorem ipsum", no "Sample item 1".`,
|
|
168570
|
+
` - Leave any entity key already in the file that is not listed above untouched.`,
|
|
168571
|
+
``,
|
|
168572
|
+
`Then run \`himi base44 entities create --yes\` followed by \`himi base44 entities seed --yes\`.`
|
|
168573
|
+
].join("\n");
|
|
168574
|
+
return {
|
|
168575
|
+
ok: true,
|
|
168576
|
+
path: path2,
|
|
168577
|
+
entities,
|
|
168578
|
+
agentPrompt,
|
|
168579
|
+
next: [`# review/refine ${path2} (see agentPrompt), then:`, "himi base44 entities seed --yes"],
|
|
168580
|
+
...fieldless.length ? { note: `skipped entities with no declared field (nothing to seed): ${fieldless.join(", ")}` } : {}
|
|
168581
|
+
};
|
|
168582
|
+
}
|
|
168583
|
+
var BASE44_SEED_FILE, SeedFileError;
|
|
168584
|
+
var init_seed = __esm({
|
|
168585
|
+
"src/base44-provision/seed.ts"() {
|
|
168586
|
+
init_base44_schema();
|
|
168587
|
+
init_http2();
|
|
168588
|
+
BASE44_SEED_FILE = "base44-seed.json";
|
|
168589
|
+
SeedFileError = class extends Error {
|
|
168590
|
+
};
|
|
168591
|
+
}
|
|
168592
|
+
});
|
|
168593
|
+
|
|
168594
|
+
// src/base44-analyze/project.ts
|
|
168595
|
+
function parseJsonc(text9) {
|
|
168596
|
+
let out2 = "";
|
|
168597
|
+
let i2 = 0;
|
|
168598
|
+
let inStr = false;
|
|
168599
|
+
while (i2 < text9.length) {
|
|
168600
|
+
const c2 = text9[i2];
|
|
168601
|
+
if (inStr) {
|
|
168602
|
+
out2 += c2;
|
|
168603
|
+
if (c2 === "\\") {
|
|
168604
|
+
out2 += text9[i2 + 1] ?? "";
|
|
168605
|
+
i2 += 2;
|
|
168606
|
+
continue;
|
|
168607
|
+
}
|
|
168608
|
+
if (c2 === '"') inStr = false;
|
|
168609
|
+
i2++;
|
|
168610
|
+
continue;
|
|
168611
|
+
}
|
|
168612
|
+
if (c2 === '"') {
|
|
168613
|
+
inStr = true;
|
|
168614
|
+
out2 += c2;
|
|
168615
|
+
i2++;
|
|
168616
|
+
} else if (c2 === "/" && text9[i2 + 1] === "/") {
|
|
168617
|
+
while (i2 < text9.length && text9[i2] !== "\n") i2++;
|
|
168618
|
+
} else if (c2 === "/" && text9[i2 + 1] === "*") {
|
|
168619
|
+
i2 += 2;
|
|
168620
|
+
while (i2 < text9.length && !(text9[i2] === "*" && text9[i2 + 1] === "/")) i2++;
|
|
168621
|
+
i2 += 2;
|
|
168622
|
+
} else {
|
|
168623
|
+
out2 += c2;
|
|
168624
|
+
i2++;
|
|
168625
|
+
}
|
|
168626
|
+
}
|
|
168627
|
+
return JSON.parse(dropTrailingCommas(out2));
|
|
168628
|
+
}
|
|
168629
|
+
function dropTrailingCommas(text9) {
|
|
168630
|
+
let out2 = "";
|
|
168631
|
+
let inStr = false;
|
|
168632
|
+
for (let i2 = 0; i2 < text9.length; i2++) {
|
|
168633
|
+
const c2 = text9[i2];
|
|
168634
|
+
if (inStr) {
|
|
168635
|
+
out2 += c2;
|
|
168636
|
+
if (c2 === "\\") out2 += text9[++i2] ?? "";
|
|
168637
|
+
else if (c2 === '"') inStr = false;
|
|
168638
|
+
continue;
|
|
168639
|
+
}
|
|
168640
|
+
if (c2 === '"') inStr = true;
|
|
168641
|
+
if (c2 === ",") {
|
|
168642
|
+
let j2 = i2 + 1;
|
|
168643
|
+
while (j2 < text9.length && /\s/.test(text9[j2])) j2++;
|
|
168644
|
+
if (text9[j2] === "}" || text9[j2] === "]") continue;
|
|
168645
|
+
}
|
|
168646
|
+
out2 += c2;
|
|
168647
|
+
}
|
|
168648
|
+
return out2;
|
|
168649
|
+
}
|
|
168650
|
+
function readJson8(files, path2) {
|
|
168651
|
+
const text9 = files.get(path2);
|
|
168652
|
+
if (text9 === void 0) return void 0;
|
|
168653
|
+
try {
|
|
168654
|
+
const v2 = parseJsonc(text9);
|
|
168655
|
+
return v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
|
|
168656
|
+
} catch {
|
|
168657
|
+
return void 0;
|
|
168658
|
+
}
|
|
168659
|
+
}
|
|
168660
|
+
function filesIn(files, dir, re2) {
|
|
168661
|
+
const prefix = dir ? `${dir.replace(/\/+$/, "")}/` : "";
|
|
168662
|
+
return [...files.keys()].filter((p2) => p2.startsWith(prefix) && !p2.slice(prefix.length).includes("/") && re2.test(p2)).sort();
|
|
168663
|
+
}
|
|
168664
|
+
function projectDirs(files) {
|
|
168665
|
+
const cfg = readJson8(files, "base44/config.jsonc") ?? readJson8(files, "base44/config.json") ?? {};
|
|
168666
|
+
const dir = (k2, d2) => {
|
|
168667
|
+
const v2 = cfg[k2];
|
|
168668
|
+
return `base44/${typeof v2 === "string" && v2 && !v2.includes("..") ? v2.replace(/^\.\/|\/+$/g, "") : d2}`;
|
|
168669
|
+
};
|
|
168670
|
+
return {
|
|
168671
|
+
root: "base44",
|
|
168672
|
+
entities: dir("entitiesDir", "entities"),
|
|
168673
|
+
functions: dir("functionsDir", "functions"),
|
|
168674
|
+
agents: dir("agentsDir", "agents"),
|
|
168675
|
+
connectors: dir("connectorsDir", "connectors"),
|
|
168676
|
+
auth: dir("authDir", "auth")
|
|
168677
|
+
};
|
|
168678
|
+
}
|
|
168679
|
+
function fieldsOf(schema) {
|
|
168680
|
+
const required3 = Array.isArray(schema.required) ? schema.required.filter((x2) => typeof x2 === "string") : [];
|
|
168681
|
+
const props = schema.properties && typeof schema.properties === "object" ? schema.properties : {};
|
|
168682
|
+
const fields = Object.entries(props).map(([name, p2]) => ({
|
|
168683
|
+
name,
|
|
168684
|
+
type: Array.isArray(p2?.type) ? p2.type.join("|") : typeof p2?.type === "string" ? p2.type : typeof p2?.$ref === "string" ? `ref:${p2.$ref}` : "unknown",
|
|
168685
|
+
required: required3.includes(name),
|
|
168686
|
+
...typeof p2?.format === "string" ? { format: p2.format } : {},
|
|
168687
|
+
...Array.isArray(p2?.enum) ? { enum: p2.enum } : {},
|
|
168688
|
+
...typeof p2?.description === "string" ? { description: p2.description } : {},
|
|
168689
|
+
...p2?.rls !== void 0 ? { rls: p2.rls } : {}
|
|
168690
|
+
}));
|
|
168691
|
+
return { fields, required: required3 };
|
|
168692
|
+
}
|
|
168693
|
+
function readEntities(files, dirs) {
|
|
168694
|
+
const out2 = [];
|
|
168695
|
+
for (const path2 of [...filesIn(files, dirs.entities, JSON_FILE), ...filesIn(files, "entities", JSON_FILE)]) {
|
|
168696
|
+
const schema = readJson8(files, path2);
|
|
168697
|
+
if (!schema) continue;
|
|
168698
|
+
const base = path2.split("/").pop().replace(JSON_FILE, "");
|
|
168699
|
+
const name = typeof schema.name === "string" && schema.name ? schema.name : base;
|
|
168700
|
+
if (out2.some((e2) => e2.name === name)) continue;
|
|
168701
|
+
const { fields, required: required3 } = fieldsOf(schema);
|
|
168702
|
+
out2.push({
|
|
168703
|
+
name,
|
|
168704
|
+
...typeof schema.title === "string" ? { title: schema.title } : {},
|
|
168705
|
+
...typeof schema.description === "string" ? { description: schema.description } : {},
|
|
168706
|
+
fields,
|
|
168707
|
+
required: required3,
|
|
168708
|
+
schema,
|
|
168709
|
+
...schema.rls && typeof schema.rls === "object" ? { rls: schema.rls } : {},
|
|
168710
|
+
file: path2,
|
|
168711
|
+
source: "project-files"
|
|
168712
|
+
});
|
|
168713
|
+
}
|
|
168714
|
+
return out2;
|
|
168715
|
+
}
|
|
168716
|
+
function functionSignature(code) {
|
|
168717
|
+
if (code === void 0) return { kind: "unknown" };
|
|
168718
|
+
const methods = [...new Set([...code.matchAll(/\b(?:req|request)\.method\s*[!=]==?\s*["'](GET|POST|PUT|PATCH|DELETE)["']/g)].map((m2) => m2[1]))];
|
|
168719
|
+
const http = /\bDeno\.serve\s*\(|\bserve\s*\(\s*(?:async\s*)?\(?\s*req/.test(code);
|
|
168720
|
+
return { kind: http ? "http" : "invoke", ...methods.length ? { methods } : {} };
|
|
168721
|
+
}
|
|
168722
|
+
function automationsOf(v2) {
|
|
168723
|
+
if (!Array.isArray(v2)) return void 0;
|
|
168724
|
+
const out2 = v2.filter((a2) => !!a2 && typeof a2 === "object").map((a2) => ({
|
|
168725
|
+
name: String(a2.name ?? ""),
|
|
168726
|
+
type: String(a2.type ?? "unknown"),
|
|
168727
|
+
...typeof a2.cron_expression === "string" ? { schedule: a2.cron_expression } : typeof a2.repeat_unit === "string" ? { schedule: `every ${a2.repeat_interval ?? 1} ${a2.repeat_unit}` } : {},
|
|
168728
|
+
...typeof a2.entity_name === "string" ? { entity: a2.entity_name } : {}
|
|
168729
|
+
}));
|
|
168730
|
+
return out2.length ? out2 : void 0;
|
|
168731
|
+
}
|
|
168732
|
+
function readFunctions(files, dirs) {
|
|
168733
|
+
const out2 = [];
|
|
168734
|
+
const push = (fn2) => {
|
|
168735
|
+
if (!out2.some((f2) => f2.name === fn2.name)) out2.push(fn2);
|
|
168736
|
+
};
|
|
168737
|
+
const prefix = `${dirs.functions}/`;
|
|
168738
|
+
const under = [...files.keys()].filter((p2) => p2.startsWith(prefix)).sort();
|
|
168739
|
+
for (const cfgPath of under.filter((p2) => /\/function\.jsonc?$/i.test(p2))) {
|
|
168740
|
+
const cfg = readJson8(files, cfgPath);
|
|
168741
|
+
if (!cfg || typeof cfg.name !== "string") continue;
|
|
168742
|
+
const folder = cfgPath.slice(0, cfgPath.lastIndexOf("/"));
|
|
168743
|
+
const entry = typeof cfg.entry === "string" ? `${folder}/${cfg.entry.replace(/^\.\//, "")}` : void 0;
|
|
168744
|
+
push({ name: cfg.name, ...entry ? { sourcePath: entry } : {}, ...functionSignature(entry ? files.get(entry) : void 0), invoke: invokeOf(cfg.name), ...automationsOf(cfg.automations) ? { automations: automationsOf(cfg.automations) } : {}, source: "project-files" });
|
|
168745
|
+
}
|
|
168746
|
+
for (const entry of under.filter((p2) => /\/entry\.[jt]s$/i.test(p2))) {
|
|
168747
|
+
const folder = entry.slice(prefix.length, entry.lastIndexOf("/"));
|
|
168748
|
+
if (!folder || folder.split("/").some((s2) => s2.includes("."))) continue;
|
|
168749
|
+
push({ name: folder, sourcePath: entry, ...functionSignature(files.get(entry)), invoke: invokeOf(folder), source: "project-files" });
|
|
168750
|
+
}
|
|
168751
|
+
for (const file2 of filesIn(files, "functions", CODE_FILE2)) {
|
|
168752
|
+
const name = file2.split("/").pop().replace(CODE_FILE2, "");
|
|
168753
|
+
push({ name, sourcePath: file2, ...functionSignature(files.get(file2)), invoke: invokeOf(name), source: "project-files" });
|
|
168754
|
+
}
|
|
168755
|
+
return out2;
|
|
168756
|
+
}
|
|
168757
|
+
function agentFromConfig(cfg, source) {
|
|
168758
|
+
if (typeof cfg.name !== "string" || !cfg.name) return void 0;
|
|
168759
|
+
const tools = (Array.isArray(cfg.tool_configs) ? cfg.tool_configs : []).filter((t2) => !!t2 && typeof t2 === "object").map((t2) => ({
|
|
168760
|
+
...typeof t2.entity_name === "string" ? { entity: t2.entity_name } : {},
|
|
168761
|
+
...typeof t2.function_name === "string" ? { function: t2.function_name } : {},
|
|
168762
|
+
...Array.isArray(t2.allowed_operations) ? { operations: t2.allowed_operations.map(String) } : {}
|
|
168763
|
+
}));
|
|
168764
|
+
return { name: cfg.name, ...typeof cfg.description === "string" ? { description: cfg.description } : {}, tools, source };
|
|
168765
|
+
}
|
|
168766
|
+
function readAgents(files, dirs) {
|
|
168767
|
+
return filesIn(files, dirs.agents, JSON_FILE).map((p2) => readJson8(files, p2)).map((cfg) => cfg ? agentFromConfig(cfg, "project-files") : void 0).filter((a2) => !!a2);
|
|
168768
|
+
}
|
|
168769
|
+
function readConnectors(files, dirs) {
|
|
168770
|
+
const out2 = [];
|
|
168771
|
+
for (const p2 of filesIn(files, dirs.connectors, JSON_FILE)) {
|
|
168772
|
+
const cfg = readJson8(files, p2);
|
|
168773
|
+
if (!cfg || typeof cfg.type !== "string") continue;
|
|
168774
|
+
out2.push({ type: cfg.type, scopes: Array.isArray(cfg.scopes) ? cfg.scopes.map(String) : [], source: "project-files" });
|
|
168775
|
+
}
|
|
168776
|
+
return out2;
|
|
168777
|
+
}
|
|
168778
|
+
function providersOf(cfg) {
|
|
168779
|
+
const on4 = (camel2, snake2) => cfg[camel2] === true || cfg[snake2] === true;
|
|
168780
|
+
const out2 = [];
|
|
168781
|
+
if (on4("enableUsernamePassword", "enable_username_password")) out2.push("email-password");
|
|
168782
|
+
if (on4("enableGoogleLogin", "enable_google_login")) out2.push("google");
|
|
168783
|
+
if (on4("enableMicrosoftLogin", "enable_microsoft_login")) out2.push("microsoft");
|
|
168784
|
+
if (on4("enableFacebookLogin", "enable_facebook_login")) out2.push("facebook");
|
|
168785
|
+
if (on4("enableAppleLogin", "enable_apple_login")) out2.push("apple");
|
|
168786
|
+
if (on4("enableSSOLogin", "enable_sso_login")) out2.push("sso");
|
|
168787
|
+
return out2;
|
|
168788
|
+
}
|
|
168789
|
+
function readAuthConfig(files, dirs) {
|
|
168790
|
+
for (const p2 of filesIn(files, dirs.auth, JSON_FILE)) {
|
|
168791
|
+
const cfg = readJson8(files, p2);
|
|
168792
|
+
if (cfg && Object.keys(cfg).some((k2) => /^enable/.test(k2))) return { providers: providersOf(cfg), source: "project-files" };
|
|
168793
|
+
}
|
|
168794
|
+
return void 0;
|
|
168795
|
+
}
|
|
168796
|
+
function resolveImport2(files, fromFile, spec) {
|
|
168797
|
+
let base;
|
|
168798
|
+
if (spec.startsWith("@/")) base = `src/${spec.slice(2)}`;
|
|
168799
|
+
else if (spec.startsWith(".")) {
|
|
168800
|
+
const parts = fromFile.split("/").slice(0, -1);
|
|
168801
|
+
for (const seg of spec.split("/")) {
|
|
168802
|
+
if (seg === "..") parts.pop();
|
|
168803
|
+
else if (seg !== ".") parts.push(seg);
|
|
168804
|
+
}
|
|
168805
|
+
base = parts.join("/");
|
|
168806
|
+
} else return void 0;
|
|
168807
|
+
return RESOLVE_EXT.map((e2) => base + e2).find((p2) => files.has(p2));
|
|
168808
|
+
}
|
|
168809
|
+
function importsOf(code) {
|
|
168810
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
168811
|
+
for (const m2 of code.matchAll(/import\s+([^'";]+?)\s+from\s+["']([^"']+)["']/g)) {
|
|
168812
|
+
const clause = m2[1];
|
|
168813
|
+
const spec = m2[2];
|
|
168814
|
+
const def = /^([A-Za-z_$][\w$]*)/.exec(clause);
|
|
168815
|
+
if (def && !clause.startsWith("{")) out2.set(def[1], spec);
|
|
168816
|
+
const named = /\{([^}]*)\}/.exec(clause);
|
|
168817
|
+
if (named) {
|
|
168818
|
+
for (const part3 of named[1].split(",")) {
|
|
168819
|
+
const [orig, alias2] = part3.trim().split(/\s+as\s+/);
|
|
168820
|
+
if (orig) out2.set((alias2 ?? orig).trim(), spec);
|
|
168821
|
+
}
|
|
168822
|
+
}
|
|
168823
|
+
}
|
|
168824
|
+
return out2;
|
|
168825
|
+
}
|
|
168826
|
+
function entitiesReadBy(code, known) {
|
|
168827
|
+
const out2 = /* @__PURE__ */ new Set();
|
|
168828
|
+
for (const m2 of code.matchAll(/\bentities\.([A-Z][A-Za-z0-9_]*)/g)) out2.add(m2[1]);
|
|
168829
|
+
for (const [local, spec] of importsOf(code)) if (/(^|\/)(api\/)?entities(\.[jt]s)?$/.test(spec) && known.includes(local)) out2.add(local);
|
|
168830
|
+
const list = [...out2];
|
|
168831
|
+
return known.length ? list.filter((n2) => known.includes(n2)) : list;
|
|
168832
|
+
}
|
|
168833
|
+
function readRoutes(files, knownEntities) {
|
|
168834
|
+
const out2 = [];
|
|
168835
|
+
const add = (path2, component, fromFile, imports) => {
|
|
168836
|
+
if (out2.some((r2) => r2.path === path2)) return;
|
|
168837
|
+
const spec = component ? imports.get(component) : void 0;
|
|
168838
|
+
const file2 = spec ? resolveImport2(files, fromFile, spec) : void 0;
|
|
168839
|
+
const code = file2 ? files.get(file2) : void 0;
|
|
168840
|
+
out2.push({ path: path2, ...component ? { component } : {}, ...file2 ? { file: file2 } : {}, entities: code ? entitiesReadBy(code, knownEntities) : [], source: "project-files" });
|
|
168841
|
+
};
|
|
168842
|
+
const src = [...files.keys()].filter((p2) => p2.startsWith("src/") && CODE_FILE2.test(p2)).sort();
|
|
168843
|
+
for (const file2 of src) {
|
|
168844
|
+
const code = files.get(file2);
|
|
168845
|
+
if (!/\bRoute\b|\bpath\s*:|\bPAGES\b/.test(code)) continue;
|
|
168846
|
+
const imports = importsOf(code);
|
|
168847
|
+
for (const m2 of code.matchAll(/<Route\b([^>]*?)\/?>/g)) {
|
|
168848
|
+
const path2 = /\bpath\s*=\s*["'{]\s*["'`]?([^"'`}]+)["'`]?\s*}?/.exec(m2[1])?.[1]?.trim();
|
|
168849
|
+
const comp = /\belement\s*=\s*\{\s*<\s*([A-Z][\w.]*)/.exec(m2[1])?.[1];
|
|
168850
|
+
if (path2 && /^(?:\/|\*$|[A-Za-z0-9_:.-]+(?:\/[A-Za-z0-9_:.*-]*)*$)/.test(path2)) add(path2, comp, file2, imports);
|
|
168851
|
+
}
|
|
168852
|
+
for (const m2 of code.matchAll(/\{\s*path\s*:\s*["'`]([^"'`]+)["'`]\s*,\s*(?:element|Component)\s*:\s*<?\s*([A-Z][\w.]*)/g)) add(m2[1], m2[2], file2, imports);
|
|
168853
|
+
const pages2 = /\bPAGES\s*=\s*\{([^}]*)\}/.exec(code);
|
|
168854
|
+
if (pages2) {
|
|
168855
|
+
const main4 = /\bmainPage\s*[:=]\s*["']([A-Za-z0-9_]+)["']/.exec(code)?.[1];
|
|
168856
|
+
for (const pm of pages2[1].matchAll(/["']?([A-Z][A-Za-z0-9_]*)["']?\s*(?::\s*([A-Za-z_$][\w$]*))?\s*(?:,|$)/g)) {
|
|
168857
|
+
const name = pm[1];
|
|
168858
|
+
const comp = pm[2] ?? name;
|
|
168859
|
+
if (main4 === name) add("/", comp, file2, imports);
|
|
168860
|
+
add(`/${name}`, comp, file2, imports);
|
|
168861
|
+
}
|
|
168862
|
+
}
|
|
168863
|
+
}
|
|
168864
|
+
return out2;
|
|
168865
|
+
}
|
|
168866
|
+
var JSON_FILE, CODE_FILE2, invokeOf, RESOLVE_EXT;
|
|
168867
|
+
var init_project = __esm({
|
|
168868
|
+
"src/base44-analyze/project.ts"() {
|
|
168869
|
+
JSON_FILE = /\.jsonc?$/i;
|
|
168870
|
+
CODE_FILE2 = /\.(?:[cm]?[jt]sx?)$/i;
|
|
168871
|
+
invokeOf = (name) => `functions.invoke(${JSON.stringify(name)}, payload)`;
|
|
168872
|
+
RESOLVE_EXT = ["", ".jsx", ".tsx", ".js", ".ts", "/index.jsx", "/index.tsx", "/index.js", "/index.ts"];
|
|
168873
|
+
}
|
|
168874
|
+
});
|
|
168875
|
+
|
|
168876
|
+
// src/base44-provision/functions.ts
|
|
168877
|
+
var functions_exports2 = {};
|
|
168878
|
+
__export(functions_exports2, {
|
|
168879
|
+
FunctionSourceError: () => FunctionSourceError,
|
|
168880
|
+
OWNER_MARKER: () => OWNER_MARKER,
|
|
168881
|
+
deployBase44Functions: () => deployBase44Functions,
|
|
168882
|
+
deployedOwnedBy: () => deployedOwnedBy,
|
|
168883
|
+
markerContent: () => markerContent,
|
|
168884
|
+
readFunctionSource: () => readFunctionSource
|
|
168885
|
+
});
|
|
168886
|
+
import { existsSync as existsSync82, lstatSync as lstatSync21 } from "node:fs";
|
|
168887
|
+
import { join as join87 } from "node:path";
|
|
168888
|
+
function markerContent(app) {
|
|
168889
|
+
return `${JSON.stringify({ app, by: "himi" })}
|
|
168890
|
+
`;
|
|
168891
|
+
}
|
|
168892
|
+
function readFunctionSource(appDir3, name, app) {
|
|
168893
|
+
const rel = `base44/functions/${name}/`;
|
|
168894
|
+
const folder = join87(appDir3, "base44", "functions", name);
|
|
168895
|
+
if (!existsSync82(folder) || !lstatSync21(folder).isDirectory()) throw new FunctionSourceError("function_source_missing", `no source folder at ${rel}`);
|
|
168896
|
+
const { entries, skipped } = collectAppSource(folder);
|
|
168897
|
+
if (skipped.length) throw new FunctionSourceError("function_source_unsafe", `${rel} holds paths himi will not upload (symlinks or denied names): ${skipped.join(", ")} \u2014 remove them`);
|
|
168898
|
+
const secrets = secretFindings(entries);
|
|
168899
|
+
if (secrets.length) throw new FunctionSourceError("function_source_unsafe", `${rel} looks like it holds a credential: ${secrets.map((x2) => `${x2.path} (${x2.reason})`).join(", ")}`);
|
|
168900
|
+
const paths = entries.map((e2) => e2.path);
|
|
168901
|
+
let entry;
|
|
168902
|
+
let automations;
|
|
168903
|
+
const cfg = entries.find((e2) => CONFIG_FILES.has(e2.path));
|
|
168904
|
+
if (cfg) {
|
|
168905
|
+
let parsed;
|
|
168906
|
+
try {
|
|
168907
|
+
parsed = parseJsonc(cfg.bytes.toString("utf8"));
|
|
168908
|
+
} catch (e2) {
|
|
168909
|
+
throw new FunctionSourceError("function_source_missing", `${rel}${cfg.path} is not valid JSON: ${e2.message}`);
|
|
168910
|
+
}
|
|
168911
|
+
if (typeof parsed?.entry === "string") entry = parsed.entry.replace(/^\.\//, "");
|
|
168912
|
+
if (Array.isArray(parsed?.automations)) automations = parsed.automations;
|
|
168913
|
+
}
|
|
168914
|
+
entry ??= ENTRY_CANDIDATES.find((c2) => paths.includes(c2));
|
|
168915
|
+
if (!entry || !paths.includes(entry)) throw new FunctionSourceError("function_source_missing", `no entry file in ${rel} (expected ${entry ?? ENTRY_CANDIDATES.join(" or ")})`);
|
|
168916
|
+
const sources = entries.filter((e2) => !CONFIG_FILES.has(e2.path) && e2.path.split("/").pop() !== OWNER_MARKER);
|
|
168917
|
+
if (sources.length > MAX_FILES) throw new FunctionSourceError("function_source_unsafe", `${rel} has ${sources.length} files \u2014 over the ${MAX_FILES}-file cap`);
|
|
168918
|
+
const bytes2 = sources.reduce((n2, e2) => n2 + e2.bytes.length, 0);
|
|
168919
|
+
if (bytes2 > MAX_BYTES) throw new FunctionSourceError("function_source_unsafe", `${rel} is ${bytes2} bytes \u2014 over the ${MAX_BYTES}-byte cap`);
|
|
168920
|
+
const files = sources.map((e2) => ({ path: e2.path, content: e2.bytes.toString("utf8") }));
|
|
168921
|
+
files.push({ path: OWNER_MARKER, content: markerContent(app) });
|
|
168922
|
+
return { entry, files, ...automations ? { automations } : {} };
|
|
168923
|
+
}
|
|
168924
|
+
function deployedOwnedBy(fn2, app) {
|
|
168925
|
+
const files = Array.isArray(fn2.files) ? fn2.files : [];
|
|
168926
|
+
return files.some((f2) => {
|
|
168927
|
+
if (!f2 || typeof f2 !== "object") return false;
|
|
168928
|
+
const { path: path2, content } = f2;
|
|
168929
|
+
if (typeof path2 !== "string" || path2.split("/").pop() !== OWNER_MARKER || typeof content !== "string") return false;
|
|
168930
|
+
try {
|
|
168931
|
+
return JSON.parse(content).app === app;
|
|
168932
|
+
} catch {
|
|
168933
|
+
return false;
|
|
168934
|
+
}
|
|
168935
|
+
});
|
|
168936
|
+
}
|
|
168937
|
+
async function deployBase44Functions(opts) {
|
|
168938
|
+
const { app, appId: appId2, yes = false } = opts;
|
|
168939
|
+
const report3 = { ok: true, app, appId: appId2, dryRun: !yes, functions: [] };
|
|
168940
|
+
if (yes) {
|
|
168941
|
+
const denied2 = writeScopeFailure(opts.auth);
|
|
168942
|
+
if (denied2) return { ...report3, ...denied2 };
|
|
168943
|
+
}
|
|
168944
|
+
const owned = opts.functions.filter((s2) => !!s2 && typeof s2 === "object" && isOwnedFunction(s2)).map((s2) => physicalFunctionName(s2)).filter((n2) => !opts.only || opts.only.includes(n2));
|
|
168945
|
+
if (!owned.length) {
|
|
168946
|
+
return { ...report3, ok: false, code: "invalid_usage", error: opts.only ? `--only ${opts.only.join(",")} matched no owned function` : "this app declares no owned Base44 functions to deploy", hint: "declare one in config.ts with `base44.functions: [{ name }]` and its source under base44/functions/<name>/" };
|
|
168947
|
+
}
|
|
168948
|
+
const payloads = /* @__PURE__ */ new Map();
|
|
168949
|
+
for (const name of owned) {
|
|
168950
|
+
try {
|
|
168951
|
+
payloads.set(name, readFunctionSource(opts.appDir, name, app));
|
|
168952
|
+
} catch (e2) {
|
|
168953
|
+
if (!(e2 instanceof FunctionSourceError)) throw e2;
|
|
168954
|
+
report3.functions.push({ name, action: "refused", detail: e2.message });
|
|
168955
|
+
return { ...report3, ok: false, code: e2.code, error: `function "${name}": ${e2.message}` };
|
|
168956
|
+
}
|
|
168957
|
+
}
|
|
168958
|
+
let listed;
|
|
168959
|
+
try {
|
|
168960
|
+
listed = await callJson(opts, appId2, "GET", "backend-functions", "listing deployed functions");
|
|
168961
|
+
} catch (e2) {
|
|
168962
|
+
return { ...report3, ...requestFailure(e2), hint: "the deployed functions must be listed to prove no declared name belongs to someone else; nothing was deployed" };
|
|
168963
|
+
}
|
|
168964
|
+
if (!Array.isArray(listed?.functions)) {
|
|
168965
|
+
return { ...report3, ok: false, code: "request_failed", error: "the deployed-functions listing came back without a `functions` array, so no declared name can be proven free \u2014 nothing was deployed" };
|
|
168966
|
+
}
|
|
168967
|
+
const deployed = /* @__PURE__ */ new Map();
|
|
168968
|
+
for (const f2 of listed.functions) {
|
|
168969
|
+
if (f2 && typeof f2 === "object" && typeof f2.name === "string") deployed.set(f2.name, f2);
|
|
168970
|
+
}
|
|
168971
|
+
const taken = owned.filter((n2) => deployed.has(n2) && !deployedOwnedBy(deployed.get(n2), app));
|
|
168972
|
+
if (taken.length) {
|
|
168973
|
+
for (const name of owned) report3.functions.push({ name, action: taken.includes(name) ? "refused" : "deploy", ...taken.includes(name) ? { detail: "already deployed and not himi's for this app" } : {} });
|
|
168974
|
+
return { ...report3, ok: false, code: "function_name_taken", error: `already deployed and not owned by himi for "${app}": ${taken.join(", ")} \u2014 nothing was deployed`, hint: "rename the owned function, or declare the existing one with `base44Name` to invoke it read-only" };
|
|
168975
|
+
}
|
|
168976
|
+
for (const name of owned) {
|
|
168977
|
+
const payload = payloads.get(name);
|
|
168978
|
+
if (!yes) {
|
|
168979
|
+
report3.functions.push({ name, action: "deploy", files: payload.files.length });
|
|
168980
|
+
continue;
|
|
168981
|
+
}
|
|
168982
|
+
try {
|
|
168983
|
+
const r2 = await callJson(opts, appId2, "PUT", `backend-functions/${encodeURIComponent(name)}`, `deploying function "${name}"`, payload);
|
|
168984
|
+
report3.functions.push({ name, action: r2.status === "unchanged" ? "unchanged" : "deployed", files: payload.files.length });
|
|
168985
|
+
} catch (e2) {
|
|
168986
|
+
report3.functions.push({ name, action: "refused", detail: e2.message });
|
|
168987
|
+
return { ...report3, ...requestFailure(e2) };
|
|
168988
|
+
}
|
|
168989
|
+
}
|
|
168990
|
+
return report3;
|
|
168991
|
+
}
|
|
168992
|
+
var OWNER_MARKER, ENTRY_CANDIDATES, CONFIG_FILES, MAX_FILES, MAX_BYTES, FunctionSourceError;
|
|
168993
|
+
var init_functions2 = __esm({
|
|
168994
|
+
"src/base44-provision/functions.ts"() {
|
|
168995
|
+
init_app_source();
|
|
168996
|
+
init_project();
|
|
168997
|
+
init_ownership();
|
|
168998
|
+
init_base44_schema();
|
|
168999
|
+
init_http2();
|
|
169000
|
+
OWNER_MARKER = ".himi-owned";
|
|
169001
|
+
ENTRY_CANDIDATES = ["entry.ts", "entry.js", "index.ts", "index.js"];
|
|
169002
|
+
CONFIG_FILES = /* @__PURE__ */ new Set(["function.jsonc", "function.json"]);
|
|
169003
|
+
MAX_FILES = 200;
|
|
169004
|
+
MAX_BYTES = 5 * 1024 * 1024;
|
|
169005
|
+
FunctionSourceError = class extends Error {
|
|
169006
|
+
constructor(code, message) {
|
|
169007
|
+
super(message);
|
|
169008
|
+
this.code = code;
|
|
169009
|
+
}
|
|
169010
|
+
};
|
|
169011
|
+
}
|
|
169012
|
+
});
|
|
169013
|
+
|
|
169014
|
+
// src/base44-provision/plan.ts
|
|
169015
|
+
function canonical4(v2) {
|
|
169016
|
+
if (Array.isArray(v2)) return `[${v2.map(canonical4).join(",")}]`;
|
|
169017
|
+
if (v2 && typeof v2 === "object") {
|
|
169018
|
+
return `{${Object.keys(v2).sort().map((k2) => `${JSON.stringify(k2)}:${canonical4(v2[k2])}`).join(",")}}`;
|
|
169019
|
+
}
|
|
169020
|
+
return JSON.stringify(v2) ?? "undefined";
|
|
169021
|
+
}
|
|
169022
|
+
function toProperty(f2) {
|
|
169023
|
+
return {
|
|
169024
|
+
type: f2.type,
|
|
169025
|
+
...f2.format !== void 0 ? { format: f2.format } : {},
|
|
169026
|
+
...f2.enum !== void 0 ? { enum: f2.enum } : {},
|
|
169027
|
+
...f2.default !== void 0 ? { default: f2.default } : {},
|
|
169028
|
+
...f2.items !== void 0 ? { items: { type: f2.items.type } } : {},
|
|
169029
|
+
...f2.description !== void 0 ? { description: f2.description } : {},
|
|
169030
|
+
...f2.rls !== void 0 ? { rls: f2.rls } : {}
|
|
169031
|
+
};
|
|
169032
|
+
}
|
|
169033
|
+
function toBase44Schema(spec, app) {
|
|
169034
|
+
return {
|
|
169035
|
+
name: physicalEntityName(spec, app),
|
|
169036
|
+
type: "object",
|
|
169037
|
+
...spec.title !== void 0 ? { title: spec.title } : {},
|
|
169038
|
+
properties: Object.fromEntries((spec.fields ?? []).map((f2) => [f2.key, toProperty(f2)])),
|
|
169039
|
+
...spec.required?.length ? { required: [...spec.required] } : {},
|
|
169040
|
+
...spec.rls !== void 0 ? { rls: spec.rls } : {}
|
|
169041
|
+
};
|
|
169042
|
+
}
|
|
169043
|
+
function propsOf(schema) {
|
|
169044
|
+
const p2 = schema?.properties;
|
|
169045
|
+
return p2 && typeof p2 === "object" && !Array.isArray(p2) ? p2 : {};
|
|
169046
|
+
}
|
|
169047
|
+
function isOwnedPhysical(name, app) {
|
|
169048
|
+
return name.startsWith(base44Prefix(app));
|
|
169049
|
+
}
|
|
169050
|
+
function foreignGuard(snapshot2, next, owned) {
|
|
169051
|
+
const out2 = [];
|
|
169052
|
+
for (const e2 of snapshot2) {
|
|
169053
|
+
if (owned.has(e2.name)) continue;
|
|
169054
|
+
if (!Object.prototype.hasOwnProperty.call(next, e2.name)) {
|
|
169055
|
+
out2.push({ code: "would_delete_foreign_entity", entity: e2.name, detail: `"${e2.name}" is not himi's and would be left out of the full-set sync \u2014 Base44 would delete it and its rows` });
|
|
169056
|
+
} else if (JSON.stringify(next[e2.name]) !== JSON.stringify(e2.schema)) {
|
|
169057
|
+
out2.push({ code: "would_delete_foreign_entity", entity: e2.name, detail: `"${e2.name}" is not himi's and its schema would be altered by the sync` });
|
|
169058
|
+
}
|
|
169059
|
+
}
|
|
169060
|
+
return out2;
|
|
169061
|
+
}
|
|
169062
|
+
function keepRemotePermissions(desired, remote, spec) {
|
|
169063
|
+
const drift = [];
|
|
169064
|
+
if (spec.rls !== void 0 && canonical4(spec.rls) !== canonical4(remote.rls ?? {})) {
|
|
169065
|
+
drift.push({ kind: "permissions", detail: `declared rls ${canonical4(spec.rls)} differs from the live rls ${canonical4(remote.rls ?? {})} \u2014 the live rules are kept (pass --apply-permissions to write the declared ones)` });
|
|
169066
|
+
if (remote.rls === void 0) delete desired.rls;
|
|
169067
|
+
else desired.rls = remote.rls;
|
|
169068
|
+
}
|
|
169069
|
+
const remoteProps = propsOf(remote);
|
|
169070
|
+
const desiredProps = propsOf(desired);
|
|
169071
|
+
for (const f2 of spec.fields ?? []) {
|
|
169072
|
+
const live3 = remoteProps[f2.key];
|
|
169073
|
+
if (!live3 || f2.rls === void 0) continue;
|
|
169074
|
+
if (canonical4(f2.rls) === canonical4(live3.rls ?? {})) continue;
|
|
169075
|
+
drift.push({ kind: "permissions", detail: `field "${f2.key}": declared rls ${canonical4(f2.rls)} differs from the live ${canonical4(live3.rls ?? {})} \u2014 the live rules are kept` });
|
|
169076
|
+
if (live3.rls === void 0) delete desiredProps[f2.key].rls;
|
|
169077
|
+
else desiredProps[f2.key].rls = live3.rls;
|
|
169078
|
+
}
|
|
169079
|
+
return drift;
|
|
169080
|
+
}
|
|
169081
|
+
function inheritUndeclaredPermissions(desired, remote, spec) {
|
|
169082
|
+
if (spec.rls === void 0 && remote.rls !== void 0) desired.rls = remote.rls;
|
|
169083
|
+
const remoteProps = propsOf(remote);
|
|
169084
|
+
const desiredProps = propsOf(desired);
|
|
169085
|
+
for (const f2 of spec.fields ?? []) {
|
|
169086
|
+
if (f2.rls === void 0 && remoteProps[f2.key]?.rls !== void 0) desiredProps[f2.key].rls = remoteProps[f2.key].rls;
|
|
169087
|
+
}
|
|
169088
|
+
}
|
|
169089
|
+
function planEntitySync(declared, snapshot2, opts) {
|
|
169090
|
+
const { app, allowDestructive = false, applyPermissions = false, emptyAppOk = false } = opts;
|
|
169091
|
+
const plan = { next: {}, actions: [], refusals: [], warnings: [], owned: [] };
|
|
169092
|
+
if (snapshot2.length === 0 && !emptyAppOk) {
|
|
169093
|
+
plan.refusals.push({ code: "schema_snapshot_empty", detail: "the project download holds no entity schemas \u2014 if the Base44 app really has no entities, pass --empty-app-ok" });
|
|
169094
|
+
}
|
|
169095
|
+
const specs = declared.filter((s2) => !!s2 && typeof s2 === "object");
|
|
169096
|
+
const owned = new Map(specs.filter(isOwnedEntity).map((s2) => [physicalEntityName(s2, app), s2]));
|
|
169097
|
+
const adopted = new Set(specs.filter(isAdoptedEntity).map((s2) => physicalEntityName(s2, app)));
|
|
169098
|
+
const live3 = new Map(snapshot2.map((e2) => [e2.name, e2]));
|
|
169099
|
+
const provisioned = new Set((opts.provisioned ?? []).filter((n2) => isOwnedPhysical(n2, app)));
|
|
169100
|
+
const ownedHere = /* @__PURE__ */ new Set([...snapshot2.map((e2) => e2.name).filter((n2) => provisioned.has(n2)), ...[...owned.keys()].filter((n2) => !live3.has(n2))]);
|
|
169101
|
+
plan.owned = [...ownedHere].sort();
|
|
169102
|
+
for (const e2 of snapshot2) {
|
|
169103
|
+
if (!ownedHere.has(e2.name)) {
|
|
169104
|
+
plan.next[e2.name] = e2.schema;
|
|
169105
|
+
if (owned.has(e2.name)) {
|
|
169106
|
+
plan.actions.push({ name: e2.name, ownership: "foreign", action: "refused" });
|
|
169107
|
+
plan.refusals.push({ code: "owned_entity_unclaimed", entity: e2.name, detail: `"${e2.name}" is declared and already exists, but this app's base44-provisioned.json does not record provisioning it \u2014 it may be another himi app's (a prefix such as "${base44Prefix(app)}" is shared by longer slugs). If it is this app's, add it to base44-provisioned.json under the Base44 app id; otherwise rename the declaration` });
|
|
169108
|
+
continue;
|
|
169109
|
+
}
|
|
169110
|
+
plan.actions.push({ name: e2.name, ownership: adopted.has(e2.name) ? "adopted" : "foreign", action: "unchanged" });
|
|
169111
|
+
if (isOwnedPhysical(e2.name, app) && !adopted.has(e2.name)) {
|
|
169112
|
+
plan.warnings.push(`"${e2.name}" is in this app's namespace but neither declared nor provisioned by this app here \u2014 left untouched (it may belong to another himi app on this Base44 app)`);
|
|
169113
|
+
}
|
|
169114
|
+
continue;
|
|
169115
|
+
}
|
|
169116
|
+
const spec = owned.get(e2.name);
|
|
169117
|
+
if (!spec) {
|
|
169118
|
+
if (allowDestructive) {
|
|
169119
|
+
plan.actions.push({ name: e2.name, ownership: "owned", action: "delete" });
|
|
169120
|
+
} else {
|
|
169121
|
+
plan.next[e2.name] = e2.schema;
|
|
169122
|
+
plan.actions.push({ name: e2.name, ownership: "owned", action: "refused" });
|
|
169123
|
+
plan.refusals.push({ code: "owned_entity_removal_needs_flag", entity: e2.name, detail: `"${e2.name}" is in this app's namespace but no longer declared \u2014 dropping it deletes the entity and its rows; pass --allow-destructive if that is intended, or declare it again` });
|
|
169124
|
+
}
|
|
169125
|
+
continue;
|
|
169126
|
+
}
|
|
169127
|
+
const desired = toBase44Schema(spec, app);
|
|
169128
|
+
const drift = [];
|
|
169129
|
+
const remoteProps = propsOf(e2.schema);
|
|
169130
|
+
const desiredProps = propsOf(desired);
|
|
169131
|
+
for (const [key3, p2] of Object.entries(desiredProps)) {
|
|
169132
|
+
const r2 = remoteProps[key3];
|
|
169133
|
+
if (!r2) drift.push({ kind: "add-field", detail: `field "${key3}" (${String(p2.type)}) is added` });
|
|
169134
|
+
else {
|
|
169135
|
+
const strip3 = (x2) => {
|
|
169136
|
+
const { rls: _rls, ...rest } = x2;
|
|
169137
|
+
return canonical4(rest);
|
|
169138
|
+
};
|
|
169139
|
+
if (strip3(r2) !== strip3(p2)) drift.push({ kind: "change-field", detail: `field "${key3}" changes from ${strip3(r2)} to ${strip3(p2)}` });
|
|
169140
|
+
}
|
|
169141
|
+
}
|
|
169142
|
+
const removed = Object.keys(remoteProps).filter((k2) => !BUILTINS2.has(k2) && !(k2 in desiredProps));
|
|
169143
|
+
for (const key3 of removed) drift.push({ kind: "remove-field", detail: `field "${key3}" is removed (its values are lost)` });
|
|
169144
|
+
inheritUndeclaredPermissions(desired, e2.schema, spec);
|
|
169145
|
+
if (!applyPermissions) drift.push(...keepRemotePermissions(desired, e2.schema, spec));
|
|
169146
|
+
if (removed.length && !allowDestructive) {
|
|
169147
|
+
plan.next[e2.name] = e2.schema;
|
|
169148
|
+
plan.actions.push({ name: e2.name, ownership: "owned", action: "refused", drift });
|
|
169149
|
+
for (const key3 of removed) {
|
|
169150
|
+
plan.refusals.push({ code: "owned_field_removal_needs_flag", entity: e2.name, detail: `field "${key3}" of "${e2.name}" is no longer declared \u2014 removing it drops its values; pass --allow-destructive if that is intended` });
|
|
169151
|
+
}
|
|
169152
|
+
continue;
|
|
169153
|
+
}
|
|
169154
|
+
plan.next[e2.name] = desired;
|
|
169155
|
+
const changed = canonical4(desired) !== canonical4(e2.schema);
|
|
169156
|
+
plan.actions.push({ name: e2.name, ownership: "owned", action: changed ? "update" : "unchanged", ...drift.length ? { drift } : {} });
|
|
169157
|
+
}
|
|
169158
|
+
for (const [name, spec] of owned) {
|
|
169159
|
+
if (live3.has(name)) continue;
|
|
169160
|
+
plan.next[name] = toBase44Schema(spec, app);
|
|
169161
|
+
plan.actions.push({ name, ownership: "owned", action: "create" });
|
|
169162
|
+
}
|
|
169163
|
+
for (const name of adopted) {
|
|
169164
|
+
if (!live3.has(name)) plan.warnings.push(`adopted entity "${name}" is not on the live app \u2014 himi never creates an entity it does not own`);
|
|
169165
|
+
}
|
|
169166
|
+
plan.refusals.push(...foreignGuard(snapshot2, plan.next, ownedHere));
|
|
169167
|
+
return plan;
|
|
169168
|
+
}
|
|
169169
|
+
var BUILTINS2;
|
|
169170
|
+
var init_plan5 = __esm({
|
|
169171
|
+
"src/base44-provision/plan.ts"() {
|
|
169172
|
+
init_base44_schema();
|
|
169173
|
+
BUILTINS2 = new Set(BASE44_BUILTIN_FIELDS);
|
|
169174
|
+
}
|
|
169175
|
+
});
|
|
169176
|
+
|
|
169177
|
+
// src/base44-provision/snapshot.ts
|
|
169178
|
+
async function readEntitySnapshot(appId2, deps) {
|
|
169179
|
+
const dl2 = await deps.download(appId2);
|
|
169180
|
+
try {
|
|
169181
|
+
const { entries, skipped } = collectAppSource(dl2.dir);
|
|
169182
|
+
const files = new Map(entries.map((e2) => [e2.path, e2.bytes.toString("utf8")]));
|
|
169183
|
+
for (const cfgPath of ["base44/config.jsonc", "base44/config.json"]) {
|
|
169184
|
+
const text9 = files.get(cfgPath);
|
|
169185
|
+
if (text9 === void 0) continue;
|
|
169186
|
+
let cfg;
|
|
169187
|
+
try {
|
|
169188
|
+
cfg = parseJsonc(text9);
|
|
169189
|
+
} catch (e2) {
|
|
169190
|
+
throw new Error(`${cfgPath} does not parse (${e2.message}) \u2014 the entity directory it names cannot be trusted, so the snapshot may be incomplete`);
|
|
169191
|
+
}
|
|
169192
|
+
if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) throw new Error(`${cfgPath} is not a JSON object \u2014 the entity directory it names cannot be trusted`);
|
|
169193
|
+
const dir = cfg.entitiesDir;
|
|
169194
|
+
if (dir !== void 0 && (typeof dir !== "string" || !dir.trim() || /^(?:[\\/]|[A-Za-z]:)/.test(dir) || dir.includes(".."))) throw new Error(`${cfgPath} names entitiesDir ${JSON.stringify(dir)}, which does not stay inside the project \u2014 the snapshot cannot trust it`);
|
|
169195
|
+
}
|
|
169196
|
+
const dirs = projectDirs(files);
|
|
169197
|
+
const entityDirs = [.../* @__PURE__ */ new Set([dirs.entities, "entities"])].map((d2) => `${d2}/`);
|
|
169198
|
+
const isEntityFile = (p2) => entityDirs.some((d2) => p2.startsWith(d2) && !p2.slice(d2.length).includes("/") && JSON_FILE2.test(p2));
|
|
169199
|
+
const dropped = skipped.map((p2) => p2.split(/[\\/]/).join("/")).filter((p2) => entityDirs.some((d2) => p2.startsWith(d2) || d2.startsWith(`${p2}/`)));
|
|
169200
|
+
if (dropped.length) throw new Error(`the download's entity files include ones himi will not read (${dropped.join(", ")}) \u2014 a sync without them would delete those entities`);
|
|
169201
|
+
for (const [path2, text9] of files) {
|
|
169202
|
+
if (!isEntityFile(path2)) continue;
|
|
169203
|
+
let v2;
|
|
169204
|
+
try {
|
|
169205
|
+
v2 = parseJsonc(text9);
|
|
169206
|
+
} catch (e2) {
|
|
169207
|
+
throw new Error(`entity file ${path2} does not parse (${e2.message}) \u2014 a sync without it would delete that entity`);
|
|
169208
|
+
}
|
|
169209
|
+
if (!v2 || typeof v2 !== "object" || Array.isArray(v2)) throw new Error(`entity file ${path2} is not a JSON object \u2014 a sync without it would delete that entity`);
|
|
169210
|
+
}
|
|
169211
|
+
return { entities: readEntities(files, dirs) };
|
|
169212
|
+
} finally {
|
|
169213
|
+
dl2.cleanup();
|
|
169214
|
+
}
|
|
169215
|
+
}
|
|
169216
|
+
var JSON_FILE2;
|
|
169217
|
+
var init_snapshot = __esm({
|
|
169218
|
+
"src/base44-provision/snapshot.ts"() {
|
|
169219
|
+
init_app_source();
|
|
169220
|
+
init_project();
|
|
169221
|
+
JSON_FILE2 = /\.jsonc?$/i;
|
|
169222
|
+
}
|
|
169223
|
+
});
|
|
169224
|
+
|
|
169225
|
+
// src/base44-provision/apply.ts
|
|
169226
|
+
var apply_exports = {};
|
|
169227
|
+
__export(apply_exports, {
|
|
169228
|
+
LEDGER_FILE: () => LEDGER_FILE2,
|
|
169229
|
+
LedgerError: () => LedgerError,
|
|
169230
|
+
createBase44Entities: () => createBase44Entities,
|
|
169231
|
+
fileLedger: () => fileLedger
|
|
169232
|
+
});
|
|
169233
|
+
import { existsSync as existsSync83, readFileSync as readFileSync103, writeFileSync as writeFileSync37 } from "node:fs";
|
|
169234
|
+
import { join as join88 } from "node:path";
|
|
169235
|
+
function fileLedger(dir, appId2) {
|
|
169236
|
+
const path2 = join88(dir, LEDGER_FILE2);
|
|
169237
|
+
const load3 = () => {
|
|
169238
|
+
if (!existsSync83(path2)) return {};
|
|
169239
|
+
let v2;
|
|
169240
|
+
try {
|
|
169241
|
+
v2 = JSON.parse(readFileSync103(path2, "utf8"));
|
|
169242
|
+
} catch (e2) {
|
|
169243
|
+
throw new LedgerError(`${LEDGER_FILE2} is not valid JSON (${e2.message}) \u2014 fix it (a merge conflict?) rather than let himi rewrite it`);
|
|
169244
|
+
}
|
|
169245
|
+
if (!v2 || typeof v2 !== "object" || Array.isArray(v2)) throw new LedgerError(`${LEDGER_FILE2} must be an object keyed by Base44 app id`);
|
|
169246
|
+
return v2;
|
|
169247
|
+
};
|
|
169248
|
+
return {
|
|
169249
|
+
read: () => {
|
|
169250
|
+
const v2 = load3()[appId2];
|
|
169251
|
+
return Array.isArray(v2) ? v2.filter((x2) => typeof x2 === "string") : [];
|
|
169252
|
+
},
|
|
169253
|
+
write: (names2) => {
|
|
169254
|
+
writeFileSync37(path2, `${JSON.stringify({ ...load3(), [appId2]: [...names2].sort() }, null, 2)}
|
|
169255
|
+
`);
|
|
169256
|
+
}
|
|
169257
|
+
};
|
|
169258
|
+
}
|
|
169259
|
+
async function createBase44Entities(opts) {
|
|
169260
|
+
const { app, appId: appId2, yes = false } = opts;
|
|
169261
|
+
const base = { ok: true, app, appId: appId2, prefix: base44Prefix(app), dryRun: !yes };
|
|
169262
|
+
if (yes) {
|
|
169263
|
+
const denied2 = writeScopeFailure(opts.auth);
|
|
169264
|
+
if (denied2) return { ...base, ...denied2 };
|
|
169265
|
+
}
|
|
169266
|
+
let provisioned;
|
|
169267
|
+
try {
|
|
169268
|
+
provisioned = opts.ledger?.read() ?? [];
|
|
169269
|
+
} catch (e2) {
|
|
169270
|
+
return { ...base, ok: false, code: "ledger_unreadable", error: e2.message };
|
|
169271
|
+
}
|
|
169272
|
+
const flags = { app, allowDestructive: opts.allowDestructive, applyPermissions: opts.applyPermissions, emptyAppOk: opts.emptyAppOk, provisioned };
|
|
169273
|
+
const plan = async () => {
|
|
169274
|
+
try {
|
|
169275
|
+
const snap = await readEntitySnapshot(appId2, { download: opts.download });
|
|
169276
|
+
return planEntitySync(opts.entities, snap.entities, flags);
|
|
169277
|
+
} catch (e2) {
|
|
169278
|
+
return { ...base, ok: false, code: "schema_snapshot_unavailable", error: `could not read the app's live entity schemas: ${e2.message}`, hint: "the full-set sync needs a fresh copy of every entity; nothing was sent. Check the session has editor access (`himi base44 whoami`) and re-run." };
|
|
169279
|
+
}
|
|
169280
|
+
};
|
|
169281
|
+
const first = await plan();
|
|
169282
|
+
if ("ok" in first) return first;
|
|
169283
|
+
if (first.refusals.length) {
|
|
169284
|
+
const r2 = first.refusals[0];
|
|
169285
|
+
return { ...base, ok: false, code: r2.code, error: r2.detail, plan: first };
|
|
169286
|
+
}
|
|
169287
|
+
if (!yes) return { ...base, plan: first };
|
|
169288
|
+
const second = await plan();
|
|
169289
|
+
if ("ok" in second) return second;
|
|
169290
|
+
if (second.refusals.length) {
|
|
169291
|
+
const r2 = second.refusals[0];
|
|
169292
|
+
return { ...base, ok: false, code: r2.code, error: r2.detail, plan: second };
|
|
169293
|
+
}
|
|
169294
|
+
if (canonical4(second.next) !== canonical4(first.next) || canonical4(second.actions) !== canonical4(first.actions)) {
|
|
169295
|
+
return { ...base, ok: false, code: "snapshot_changed", error: "the app's entities changed between the plan and the apply \u2014 nothing was sent", hint: "re-run to plan against the current entities", plan: second };
|
|
169296
|
+
}
|
|
169297
|
+
const owned = new Set(second.owned);
|
|
169298
|
+
const ledgerNames = Object.keys(second.next).filter((n2) => owned.has(n2));
|
|
169299
|
+
const maybeApplied = async () => {
|
|
169300
|
+
let live3 = /* @__PURE__ */ new Set();
|
|
169301
|
+
try {
|
|
169302
|
+
live3 = new Set((await readEntitySnapshot(appId2, { download: opts.download })).entities.map((e2) => e2.name));
|
|
169303
|
+
} catch {
|
|
169304
|
+
}
|
|
169305
|
+
return [.../* @__PURE__ */ new Set([...provisioned, ...ledgerNames.filter((n2) => provisioned.includes(n2) || live3.has(n2))])];
|
|
169306
|
+
};
|
|
169307
|
+
let res;
|
|
169308
|
+
try {
|
|
169309
|
+
res = await callJson(opts, appId2, "PUT", "entity-schemas", "syncing entity schemas", { entityNameToSchema: second.next });
|
|
169310
|
+
} catch (e2) {
|
|
169311
|
+
const refused2 = e2 instanceof Base44RequestError && e2.status >= 400 && e2.status < 500;
|
|
169312
|
+
const failure = { ...base, ...requestFailure(e2), plan: second };
|
|
169313
|
+
return refused2 ? failure : recordLedger(opts.ledger, await maybeApplied(), failure);
|
|
169314
|
+
}
|
|
169315
|
+
if (!Array.isArray(res.deleted) || res.deleted.some((n2) => typeof n2 !== "string")) {
|
|
169316
|
+
return recordLedger(opts.ledger, await maybeApplied(), { ...base, ok: false, code: "request_failed", error: "the entity-schemas sync was sent, but its response has no readable deleted[] list (missing, or not all names), so the deletions cannot be checked \u2014 inspect the app's entities", plan: second });
|
|
169317
|
+
}
|
|
169318
|
+
const applied = { created: names(res.created), updated: names(res.updated), deleted: names(res.deleted) };
|
|
169319
|
+
const intended = new Set(second.actions.filter((a2) => a2.action === "delete").map((a2) => a2.name));
|
|
169320
|
+
const foreignDeleted = applied.deleted.filter((n2) => !intended.has(n2));
|
|
169321
|
+
const confirmed = new Set(applied.deleted);
|
|
169322
|
+
const kept = [.../* @__PURE__ */ new Set([...ledgerNames, ...[...intended].filter((n2) => !confirmed.has(n2))])];
|
|
169323
|
+
if (foreignDeleted.length) {
|
|
169324
|
+
return recordLedger(opts.ledger, kept, { ...base, ok: false, code: "foreign_entity_deleted", error: `Base44 reported deleting entities the plan did not drop: ${foreignDeleted.join(", ")}`, foreignDeleted, plan: second, applied });
|
|
169325
|
+
}
|
|
169326
|
+
return recordLedger(opts.ledger, kept, { ...base, plan: second, applied });
|
|
169327
|
+
}
|
|
169328
|
+
function recordLedger(ledger, names2, report3) {
|
|
169329
|
+
try {
|
|
169330
|
+
ledger?.write(names2);
|
|
169331
|
+
return report3;
|
|
169332
|
+
} catch (e2) {
|
|
169333
|
+
const detail = `the sync was sent, but ${LEDGER_FILE2} could not be written (${e2.message}) \u2014 record ${names2.join(", ") || "nothing"} there by hand`;
|
|
169334
|
+
return report3.ok ? { ...report3, ok: false, code: "ledger_unreadable", error: detail } : { ...report3, ledgerError: detail };
|
|
169335
|
+
}
|
|
169336
|
+
}
|
|
169337
|
+
var LEDGER_FILE2, LedgerError, names;
|
|
169338
|
+
var init_apply2 = __esm({
|
|
169339
|
+
"src/base44-provision/apply.ts"() {
|
|
169340
|
+
init_base44_schema();
|
|
169341
|
+
init_http2();
|
|
169342
|
+
init_plan5();
|
|
169343
|
+
init_snapshot();
|
|
169344
|
+
LEDGER_FILE2 = "base44-provisioned.json";
|
|
169345
|
+
LedgerError = class extends Error {
|
|
169346
|
+
};
|
|
169347
|
+
names = (v2) => Array.isArray(v2) ? v2.filter((x2) => typeof x2 === "string") : [];
|
|
169348
|
+
}
|
|
169349
|
+
});
|
|
169350
|
+
|
|
168291
169351
|
// src/site-analyze/net-guard.ts
|
|
168292
169352
|
var net_guard_exports = {};
|
|
168293
169353
|
__export(net_guard_exports, {
|
|
@@ -169303,8 +170363,8 @@ function formLabels(x2, depth = 0, out2 = []) {
|
|
|
169303
170363
|
return out2;
|
|
169304
170364
|
}
|
|
169305
170365
|
function formDetail(f2) {
|
|
169306
|
-
const
|
|
169307
|
-
return
|
|
170366
|
+
const names2 = formLabels(f2).slice(0, 8);
|
|
170367
|
+
return names2.length ? names2.join(", ") : void 0;
|
|
169308
170368
|
}
|
|
169309
170369
|
function side(call, def) {
|
|
169310
170370
|
if (!call) return Promise.resolve({ status: "skipped", count: 0, note: "no-auth", items: [] });
|
|
@@ -169505,8 +170565,8 @@ async function readMemberRoles(call) {
|
|
|
169505
170565
|
}
|
|
169506
170566
|
if (!data) continue;
|
|
169507
170567
|
const raw = asArr(data.roles ?? data.items);
|
|
169508
|
-
const
|
|
169509
|
-
if (
|
|
170568
|
+
const names2 = raw.map((r2) => str7(r2.title ?? r2.name ?? r2.id)).filter((n2) => n2 && !n2.includes("@"));
|
|
170569
|
+
if (names2.length) return { names: names2.slice(0, 24), status: "ok" };
|
|
169510
170570
|
sawEmptyPayload = true;
|
|
169511
170571
|
}
|
|
169512
170572
|
if (sawEmptyPayload) return { names: [], status: "empty" };
|
|
@@ -170353,12 +171413,12 @@ var init_velo = __esm({
|
|
|
170353
171413
|
|
|
170354
171414
|
// src/site-analyze/tokens.ts
|
|
170355
171415
|
function channels2(css) {
|
|
170356
|
-
const
|
|
170357
|
-
if (!
|
|
171416
|
+
const canonical6 = canonicalHex(css);
|
|
171417
|
+
if (!canonical6) return null;
|
|
170358
171418
|
return [
|
|
170359
|
-
parseInt(
|
|
170360
|
-
parseInt(
|
|
170361
|
-
parseInt(
|
|
171419
|
+
parseInt(canonical6.slice(1, 3), 16),
|
|
171420
|
+
parseInt(canonical6.slice(3, 5), 16),
|
|
171421
|
+
parseInt(canonical6.slice(5, 7), 16)
|
|
170362
171422
|
];
|
|
170363
171423
|
}
|
|
170364
171424
|
function isNearWhite(css) {
|
|
@@ -170548,8 +171608,8 @@ var init_brand_font = __esm({
|
|
|
170548
171608
|
});
|
|
170549
171609
|
|
|
170550
171610
|
// src/site-analyze/write-artifacts.ts
|
|
170551
|
-
import { mkdirSync as mkdirSync39, rmSync as rmSync21, writeFileSync as
|
|
170552
|
-
import { join as
|
|
171611
|
+
import { mkdirSync as mkdirSync39, rmSync as rmSync21, writeFileSync as writeFileSync38 } from "node:fs";
|
|
171612
|
+
import { join as join89 } from "node:path";
|
|
170553
171613
|
function attachVeloSources(book, sources, put) {
|
|
170554
171614
|
const byPath = new Map((sources ?? []).map((s2) => [s2.path, s2.text]));
|
|
170555
171615
|
for (const f2 of book.velo.files) {
|
|
@@ -170704,13 +171764,13 @@ async function downloadMedia(book, fetchImpl, put) {
|
|
|
170704
171764
|
}
|
|
170705
171765
|
async function writeBusinessBook(result, opts) {
|
|
170706
171766
|
const out2 = opts.outDir;
|
|
170707
|
-
mkdirSync39(
|
|
170708
|
-
mkdirSync39(
|
|
171767
|
+
mkdirSync39(join89(out2, "evidence/pages"), { recursive: true });
|
|
171768
|
+
mkdirSync39(join89(out2, "media/catalog"), { recursive: true });
|
|
170709
171769
|
const files = [];
|
|
170710
171770
|
const put = (rel, body) => {
|
|
170711
|
-
const p2 =
|
|
170712
|
-
mkdirSync39(
|
|
170713
|
-
|
|
171771
|
+
const p2 = join89(out2, rel);
|
|
171772
|
+
mkdirSync39(join89(p2, ".."), { recursive: true });
|
|
171773
|
+
writeFileSync38(p2, body);
|
|
170714
171774
|
files.push(rel);
|
|
170715
171775
|
};
|
|
170716
171776
|
const book = result.book;
|
|
@@ -170752,7 +171812,7 @@ async function writeBusinessBook(result, opts) {
|
|
|
170752
171812
|
const allGated = shots.length > 0 && gatedPages.length > 0 && usablePages.length === 0;
|
|
170753
171813
|
put("README.md", folderReadme(shots.length > 0 && !allGated, book.look.unavailable, allGated));
|
|
170754
171814
|
put("evidence/probes.json", JSON.stringify(book.probes, null, 2) + "\n");
|
|
170755
|
-
rmSync21(
|
|
171815
|
+
rmSync21(join89(out2, "evidence/mobile-app"), { recursive: true, force: true });
|
|
170756
171816
|
for (const [name, value] of Object.entries(result.mobileAppEvidence ?? {})) {
|
|
170757
171817
|
if (/^[a-z-]+\.json$/.test(name)) put(`evidence/mobile-app/${name}`, JSON.stringify(value, null, 2) + "\n");
|
|
170758
171818
|
}
|
|
@@ -170798,288 +171858,6 @@ var init_write_artifacts = __esm({
|
|
|
170798
171858
|
}
|
|
170799
171859
|
});
|
|
170800
171860
|
|
|
170801
|
-
// src/base44-analyze/project.ts
|
|
170802
|
-
function parseJsonc(text9) {
|
|
170803
|
-
let out2 = "";
|
|
170804
|
-
let i2 = 0;
|
|
170805
|
-
let inStr = false;
|
|
170806
|
-
while (i2 < text9.length) {
|
|
170807
|
-
const c2 = text9[i2];
|
|
170808
|
-
if (inStr) {
|
|
170809
|
-
out2 += c2;
|
|
170810
|
-
if (c2 === "\\") {
|
|
170811
|
-
out2 += text9[i2 + 1] ?? "";
|
|
170812
|
-
i2 += 2;
|
|
170813
|
-
continue;
|
|
170814
|
-
}
|
|
170815
|
-
if (c2 === '"') inStr = false;
|
|
170816
|
-
i2++;
|
|
170817
|
-
continue;
|
|
170818
|
-
}
|
|
170819
|
-
if (c2 === '"') {
|
|
170820
|
-
inStr = true;
|
|
170821
|
-
out2 += c2;
|
|
170822
|
-
i2++;
|
|
170823
|
-
} else if (c2 === "/" && text9[i2 + 1] === "/") {
|
|
170824
|
-
while (i2 < text9.length && text9[i2] !== "\n") i2++;
|
|
170825
|
-
} else if (c2 === "/" && text9[i2 + 1] === "*") {
|
|
170826
|
-
i2 += 2;
|
|
170827
|
-
while (i2 < text9.length && !(text9[i2] === "*" && text9[i2 + 1] === "/")) i2++;
|
|
170828
|
-
i2 += 2;
|
|
170829
|
-
} else {
|
|
170830
|
-
out2 += c2;
|
|
170831
|
-
i2++;
|
|
170832
|
-
}
|
|
170833
|
-
}
|
|
170834
|
-
return JSON.parse(dropTrailingCommas(out2));
|
|
170835
|
-
}
|
|
170836
|
-
function dropTrailingCommas(text9) {
|
|
170837
|
-
let out2 = "";
|
|
170838
|
-
let inStr = false;
|
|
170839
|
-
for (let i2 = 0; i2 < text9.length; i2++) {
|
|
170840
|
-
const c2 = text9[i2];
|
|
170841
|
-
if (inStr) {
|
|
170842
|
-
out2 += c2;
|
|
170843
|
-
if (c2 === "\\") out2 += text9[++i2] ?? "";
|
|
170844
|
-
else if (c2 === '"') inStr = false;
|
|
170845
|
-
continue;
|
|
170846
|
-
}
|
|
170847
|
-
if (c2 === '"') inStr = true;
|
|
170848
|
-
if (c2 === ",") {
|
|
170849
|
-
let j2 = i2 + 1;
|
|
170850
|
-
while (j2 < text9.length && /\s/.test(text9[j2])) j2++;
|
|
170851
|
-
if (text9[j2] === "}" || text9[j2] === "]") continue;
|
|
170852
|
-
}
|
|
170853
|
-
out2 += c2;
|
|
170854
|
-
}
|
|
170855
|
-
return out2;
|
|
170856
|
-
}
|
|
170857
|
-
function readJson8(files, path2) {
|
|
170858
|
-
const text9 = files.get(path2);
|
|
170859
|
-
if (text9 === void 0) return void 0;
|
|
170860
|
-
try {
|
|
170861
|
-
const v2 = parseJsonc(text9);
|
|
170862
|
-
return v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
|
|
170863
|
-
} catch {
|
|
170864
|
-
return void 0;
|
|
170865
|
-
}
|
|
170866
|
-
}
|
|
170867
|
-
function filesIn(files, dir, re2) {
|
|
170868
|
-
const prefix = dir ? `${dir.replace(/\/+$/, "")}/` : "";
|
|
170869
|
-
return [...files.keys()].filter((p2) => p2.startsWith(prefix) && !p2.slice(prefix.length).includes("/") && re2.test(p2)).sort();
|
|
170870
|
-
}
|
|
170871
|
-
function projectDirs(files) {
|
|
170872
|
-
const cfg = readJson8(files, "base44/config.jsonc") ?? readJson8(files, "base44/config.json") ?? {};
|
|
170873
|
-
const dir = (k2, d2) => {
|
|
170874
|
-
const v2 = cfg[k2];
|
|
170875
|
-
return `base44/${typeof v2 === "string" && v2 && !v2.includes("..") ? v2.replace(/^\.\/|\/+$/g, "") : d2}`;
|
|
170876
|
-
};
|
|
170877
|
-
return {
|
|
170878
|
-
root: "base44",
|
|
170879
|
-
entities: dir("entitiesDir", "entities"),
|
|
170880
|
-
functions: dir("functionsDir", "functions"),
|
|
170881
|
-
agents: dir("agentsDir", "agents"),
|
|
170882
|
-
connectors: dir("connectorsDir", "connectors"),
|
|
170883
|
-
auth: dir("authDir", "auth")
|
|
170884
|
-
};
|
|
170885
|
-
}
|
|
170886
|
-
function fieldsOf(schema) {
|
|
170887
|
-
const required3 = Array.isArray(schema.required) ? schema.required.filter((x2) => typeof x2 === "string") : [];
|
|
170888
|
-
const props = schema.properties && typeof schema.properties === "object" ? schema.properties : {};
|
|
170889
|
-
const fields = Object.entries(props).map(([name, p2]) => ({
|
|
170890
|
-
name,
|
|
170891
|
-
type: Array.isArray(p2?.type) ? p2.type.join("|") : typeof p2?.type === "string" ? p2.type : typeof p2?.$ref === "string" ? `ref:${p2.$ref}` : "unknown",
|
|
170892
|
-
required: required3.includes(name),
|
|
170893
|
-
...typeof p2?.format === "string" ? { format: p2.format } : {},
|
|
170894
|
-
...Array.isArray(p2?.enum) ? { enum: p2.enum } : {},
|
|
170895
|
-
...typeof p2?.description === "string" ? { description: p2.description } : {},
|
|
170896
|
-
...p2?.rls !== void 0 ? { rls: p2.rls } : {}
|
|
170897
|
-
}));
|
|
170898
|
-
return { fields, required: required3 };
|
|
170899
|
-
}
|
|
170900
|
-
function readEntities(files, dirs) {
|
|
170901
|
-
const out2 = [];
|
|
170902
|
-
for (const path2 of [...filesIn(files, dirs.entities, JSON_FILE), ...filesIn(files, "entities", JSON_FILE)]) {
|
|
170903
|
-
const schema = readJson8(files, path2);
|
|
170904
|
-
if (!schema) continue;
|
|
170905
|
-
const base = path2.split("/").pop().replace(JSON_FILE, "");
|
|
170906
|
-
const name = typeof schema.name === "string" && schema.name ? schema.name : base;
|
|
170907
|
-
if (out2.some((e2) => e2.name === name)) continue;
|
|
170908
|
-
const { fields, required: required3 } = fieldsOf(schema);
|
|
170909
|
-
out2.push({
|
|
170910
|
-
name,
|
|
170911
|
-
...typeof schema.title === "string" ? { title: schema.title } : {},
|
|
170912
|
-
...typeof schema.description === "string" ? { description: schema.description } : {},
|
|
170913
|
-
fields,
|
|
170914
|
-
required: required3,
|
|
170915
|
-
schema,
|
|
170916
|
-
...schema.rls && typeof schema.rls === "object" ? { rls: schema.rls } : {},
|
|
170917
|
-
file: path2,
|
|
170918
|
-
source: "project-files"
|
|
170919
|
-
});
|
|
170920
|
-
}
|
|
170921
|
-
return out2;
|
|
170922
|
-
}
|
|
170923
|
-
function functionSignature(code) {
|
|
170924
|
-
if (code === void 0) return { kind: "unknown" };
|
|
170925
|
-
const methods = [...new Set([...code.matchAll(/\b(?:req|request)\.method\s*[!=]==?\s*["'](GET|POST|PUT|PATCH|DELETE)["']/g)].map((m2) => m2[1]))];
|
|
170926
|
-
const http = /\bDeno\.serve\s*\(|\bserve\s*\(\s*(?:async\s*)?\(?\s*req/.test(code);
|
|
170927
|
-
return { kind: http ? "http" : "invoke", ...methods.length ? { methods } : {} };
|
|
170928
|
-
}
|
|
170929
|
-
function automationsOf(v2) {
|
|
170930
|
-
if (!Array.isArray(v2)) return void 0;
|
|
170931
|
-
const out2 = v2.filter((a2) => !!a2 && typeof a2 === "object").map((a2) => ({
|
|
170932
|
-
name: String(a2.name ?? ""),
|
|
170933
|
-
type: String(a2.type ?? "unknown"),
|
|
170934
|
-
...typeof a2.cron_expression === "string" ? { schedule: a2.cron_expression } : typeof a2.repeat_unit === "string" ? { schedule: `every ${a2.repeat_interval ?? 1} ${a2.repeat_unit}` } : {},
|
|
170935
|
-
...typeof a2.entity_name === "string" ? { entity: a2.entity_name } : {}
|
|
170936
|
-
}));
|
|
170937
|
-
return out2.length ? out2 : void 0;
|
|
170938
|
-
}
|
|
170939
|
-
function readFunctions(files, dirs) {
|
|
170940
|
-
const out2 = [];
|
|
170941
|
-
const push = (fn2) => {
|
|
170942
|
-
if (!out2.some((f2) => f2.name === fn2.name)) out2.push(fn2);
|
|
170943
|
-
};
|
|
170944
|
-
const prefix = `${dirs.functions}/`;
|
|
170945
|
-
const under = [...files.keys()].filter((p2) => p2.startsWith(prefix)).sort();
|
|
170946
|
-
for (const cfgPath of under.filter((p2) => /\/function\.jsonc?$/i.test(p2))) {
|
|
170947
|
-
const cfg = readJson8(files, cfgPath);
|
|
170948
|
-
if (!cfg || typeof cfg.name !== "string") continue;
|
|
170949
|
-
const folder = cfgPath.slice(0, cfgPath.lastIndexOf("/"));
|
|
170950
|
-
const entry = typeof cfg.entry === "string" ? `${folder}/${cfg.entry.replace(/^\.\//, "")}` : void 0;
|
|
170951
|
-
push({ name: cfg.name, ...entry ? { sourcePath: entry } : {}, ...functionSignature(entry ? files.get(entry) : void 0), invoke: invokeOf(cfg.name), ...automationsOf(cfg.automations) ? { automations: automationsOf(cfg.automations) } : {}, source: "project-files" });
|
|
170952
|
-
}
|
|
170953
|
-
for (const entry of under.filter((p2) => /\/entry\.[jt]s$/i.test(p2))) {
|
|
170954
|
-
const folder = entry.slice(prefix.length, entry.lastIndexOf("/"));
|
|
170955
|
-
if (!folder || folder.split("/").some((s2) => s2.includes("."))) continue;
|
|
170956
|
-
push({ name: folder, sourcePath: entry, ...functionSignature(files.get(entry)), invoke: invokeOf(folder), source: "project-files" });
|
|
170957
|
-
}
|
|
170958
|
-
for (const file2 of filesIn(files, "functions", CODE_FILE2)) {
|
|
170959
|
-
const name = file2.split("/").pop().replace(CODE_FILE2, "");
|
|
170960
|
-
push({ name, sourcePath: file2, ...functionSignature(files.get(file2)), invoke: invokeOf(name), source: "project-files" });
|
|
170961
|
-
}
|
|
170962
|
-
return out2;
|
|
170963
|
-
}
|
|
170964
|
-
function agentFromConfig(cfg, source) {
|
|
170965
|
-
if (typeof cfg.name !== "string" || !cfg.name) return void 0;
|
|
170966
|
-
const tools = (Array.isArray(cfg.tool_configs) ? cfg.tool_configs : []).filter((t2) => !!t2 && typeof t2 === "object").map((t2) => ({
|
|
170967
|
-
...typeof t2.entity_name === "string" ? { entity: t2.entity_name } : {},
|
|
170968
|
-
...typeof t2.function_name === "string" ? { function: t2.function_name } : {},
|
|
170969
|
-
...Array.isArray(t2.allowed_operations) ? { operations: t2.allowed_operations.map(String) } : {}
|
|
170970
|
-
}));
|
|
170971
|
-
return { name: cfg.name, ...typeof cfg.description === "string" ? { description: cfg.description } : {}, tools, source };
|
|
170972
|
-
}
|
|
170973
|
-
function readAgents(files, dirs) {
|
|
170974
|
-
return filesIn(files, dirs.agents, JSON_FILE).map((p2) => readJson8(files, p2)).map((cfg) => cfg ? agentFromConfig(cfg, "project-files") : void 0).filter((a2) => !!a2);
|
|
170975
|
-
}
|
|
170976
|
-
function readConnectors(files, dirs) {
|
|
170977
|
-
const out2 = [];
|
|
170978
|
-
for (const p2 of filesIn(files, dirs.connectors, JSON_FILE)) {
|
|
170979
|
-
const cfg = readJson8(files, p2);
|
|
170980
|
-
if (!cfg || typeof cfg.type !== "string") continue;
|
|
170981
|
-
out2.push({ type: cfg.type, scopes: Array.isArray(cfg.scopes) ? cfg.scopes.map(String) : [], source: "project-files" });
|
|
170982
|
-
}
|
|
170983
|
-
return out2;
|
|
170984
|
-
}
|
|
170985
|
-
function providersOf(cfg) {
|
|
170986
|
-
const on4 = (camel2, snake2) => cfg[camel2] === true || cfg[snake2] === true;
|
|
170987
|
-
const out2 = [];
|
|
170988
|
-
if (on4("enableUsernamePassword", "enable_username_password")) out2.push("email-password");
|
|
170989
|
-
if (on4("enableGoogleLogin", "enable_google_login")) out2.push("google");
|
|
170990
|
-
if (on4("enableMicrosoftLogin", "enable_microsoft_login")) out2.push("microsoft");
|
|
170991
|
-
if (on4("enableFacebookLogin", "enable_facebook_login")) out2.push("facebook");
|
|
170992
|
-
if (on4("enableAppleLogin", "enable_apple_login")) out2.push("apple");
|
|
170993
|
-
if (on4("enableSSOLogin", "enable_sso_login")) out2.push("sso");
|
|
170994
|
-
return out2;
|
|
170995
|
-
}
|
|
170996
|
-
function readAuthConfig(files, dirs) {
|
|
170997
|
-
for (const p2 of filesIn(files, dirs.auth, JSON_FILE)) {
|
|
170998
|
-
const cfg = readJson8(files, p2);
|
|
170999
|
-
if (cfg && Object.keys(cfg).some((k2) => /^enable/.test(k2))) return { providers: providersOf(cfg), source: "project-files" };
|
|
171000
|
-
}
|
|
171001
|
-
return void 0;
|
|
171002
|
-
}
|
|
171003
|
-
function resolveImport2(files, fromFile, spec) {
|
|
171004
|
-
let base;
|
|
171005
|
-
if (spec.startsWith("@/")) base = `src/${spec.slice(2)}`;
|
|
171006
|
-
else if (spec.startsWith(".")) {
|
|
171007
|
-
const parts = fromFile.split("/").slice(0, -1);
|
|
171008
|
-
for (const seg of spec.split("/")) {
|
|
171009
|
-
if (seg === "..") parts.pop();
|
|
171010
|
-
else if (seg !== ".") parts.push(seg);
|
|
171011
|
-
}
|
|
171012
|
-
base = parts.join("/");
|
|
171013
|
-
} else return void 0;
|
|
171014
|
-
return RESOLVE_EXT.map((e2) => base + e2).find((p2) => files.has(p2));
|
|
171015
|
-
}
|
|
171016
|
-
function importsOf(code) {
|
|
171017
|
-
const out2 = /* @__PURE__ */ new Map();
|
|
171018
|
-
for (const m2 of code.matchAll(/import\s+([^'";]+?)\s+from\s+["']([^"']+)["']/g)) {
|
|
171019
|
-
const clause = m2[1];
|
|
171020
|
-
const spec = m2[2];
|
|
171021
|
-
const def = /^([A-Za-z_$][\w$]*)/.exec(clause);
|
|
171022
|
-
if (def && !clause.startsWith("{")) out2.set(def[1], spec);
|
|
171023
|
-
const named = /\{([^}]*)\}/.exec(clause);
|
|
171024
|
-
if (named) {
|
|
171025
|
-
for (const part3 of named[1].split(",")) {
|
|
171026
|
-
const [orig, alias2] = part3.trim().split(/\s+as\s+/);
|
|
171027
|
-
if (orig) out2.set((alias2 ?? orig).trim(), spec);
|
|
171028
|
-
}
|
|
171029
|
-
}
|
|
171030
|
-
}
|
|
171031
|
-
return out2;
|
|
171032
|
-
}
|
|
171033
|
-
function entitiesReadBy(code, known) {
|
|
171034
|
-
const out2 = /* @__PURE__ */ new Set();
|
|
171035
|
-
for (const m2 of code.matchAll(/\bentities\.([A-Z][A-Za-z0-9_]*)/g)) out2.add(m2[1]);
|
|
171036
|
-
for (const [local, spec] of importsOf(code)) if (/(^|\/)(api\/)?entities(\.[jt]s)?$/.test(spec) && known.includes(local)) out2.add(local);
|
|
171037
|
-
const list = [...out2];
|
|
171038
|
-
return known.length ? list.filter((n2) => known.includes(n2)) : list;
|
|
171039
|
-
}
|
|
171040
|
-
function readRoutes(files, knownEntities) {
|
|
171041
|
-
const out2 = [];
|
|
171042
|
-
const add = (path2, component, fromFile, imports) => {
|
|
171043
|
-
if (out2.some((r2) => r2.path === path2)) return;
|
|
171044
|
-
const spec = component ? imports.get(component) : void 0;
|
|
171045
|
-
const file2 = spec ? resolveImport2(files, fromFile, spec) : void 0;
|
|
171046
|
-
const code = file2 ? files.get(file2) : void 0;
|
|
171047
|
-
out2.push({ path: path2, ...component ? { component } : {}, ...file2 ? { file: file2 } : {}, entities: code ? entitiesReadBy(code, knownEntities) : [], source: "project-files" });
|
|
171048
|
-
};
|
|
171049
|
-
const src = [...files.keys()].filter((p2) => p2.startsWith("src/") && CODE_FILE2.test(p2)).sort();
|
|
171050
|
-
for (const file2 of src) {
|
|
171051
|
-
const code = files.get(file2);
|
|
171052
|
-
if (!/\bRoute\b|\bpath\s*:|\bPAGES\b/.test(code)) continue;
|
|
171053
|
-
const imports = importsOf(code);
|
|
171054
|
-
for (const m2 of code.matchAll(/<Route\b([^>]*?)\/?>/g)) {
|
|
171055
|
-
const path2 = /\bpath\s*=\s*["'{]\s*["'`]?([^"'`}]+)["'`]?\s*}?/.exec(m2[1])?.[1]?.trim();
|
|
171056
|
-
const comp = /\belement\s*=\s*\{\s*<\s*([A-Z][\w.]*)/.exec(m2[1])?.[1];
|
|
171057
|
-
if (path2 && /^(?:\/|\*$|[A-Za-z0-9_:.-]+(?:\/[A-Za-z0-9_:.*-]*)*$)/.test(path2)) add(path2, comp, file2, imports);
|
|
171058
|
-
}
|
|
171059
|
-
for (const m2 of code.matchAll(/\{\s*path\s*:\s*["'`]([^"'`]+)["'`]\s*,\s*(?:element|Component)\s*:\s*<?\s*([A-Z][\w.]*)/g)) add(m2[1], m2[2], file2, imports);
|
|
171060
|
-
const pages2 = /\bPAGES\s*=\s*\{([^}]*)\}/.exec(code);
|
|
171061
|
-
if (pages2) {
|
|
171062
|
-
const main4 = /\bmainPage\s*[:=]\s*["']([A-Za-z0-9_]+)["']/.exec(code)?.[1];
|
|
171063
|
-
for (const pm of pages2[1].matchAll(/["']?([A-Z][A-Za-z0-9_]*)["']?\s*(?::\s*([A-Za-z_$][\w$]*))?\s*(?:,|$)/g)) {
|
|
171064
|
-
const name = pm[1];
|
|
171065
|
-
const comp = pm[2] ?? name;
|
|
171066
|
-
if (main4 === name) add("/", comp, file2, imports);
|
|
171067
|
-
add(`/${name}`, comp, file2, imports);
|
|
171068
|
-
}
|
|
171069
|
-
}
|
|
171070
|
-
}
|
|
171071
|
-
return out2;
|
|
171072
|
-
}
|
|
171073
|
-
var JSON_FILE, CODE_FILE2, invokeOf, RESOLVE_EXT;
|
|
171074
|
-
var init_project = __esm({
|
|
171075
|
-
"src/base44-analyze/project.ts"() {
|
|
171076
|
-
JSON_FILE = /\.jsonc?$/i;
|
|
171077
|
-
CODE_FILE2 = /\.(?:[cm]?[jt]sx?)$/i;
|
|
171078
|
-
invokeOf = (name) => `functions.invoke(${JSON.stringify(name)}, payload)`;
|
|
171079
|
-
RESOLVE_EXT = ["", ".jsx", ".tsx", ".js", ".ts", "/index.jsx", "/index.tsx", "/index.js", "/index.ts"];
|
|
171080
|
-
}
|
|
171081
|
-
});
|
|
171082
|
-
|
|
171083
171861
|
// src/base44-analyze/owner.ts
|
|
171084
171862
|
function api(ports, appId2) {
|
|
171085
171863
|
const root = new URL(`/api/apps/${encodeURIComponent(appId2)}`, ports.apiBase).href;
|
|
@@ -171617,11 +172395,11 @@ var init_analyze = __esm({
|
|
|
171617
172395
|
});
|
|
171618
172396
|
|
|
171619
172397
|
// src/base44-analyze/write-artifacts.ts
|
|
171620
|
-
import { existsSync as
|
|
171621
|
-
import { dirname as dirname48, join as
|
|
172398
|
+
import { existsSync as existsSync84, mkdirSync as mkdirSync40, readFileSync as readFileSync104, rmSync as rmSync22, writeFileSync as writeFileSync39 } from "node:fs";
|
|
172399
|
+
import { dirname as dirname48, join as join90, resolve as resolve60, sep as sep19 } from "node:path";
|
|
171622
172400
|
function isBookFolder(dir) {
|
|
171623
172401
|
try {
|
|
171624
|
-
return JSON.parse(
|
|
172402
|
+
return JSON.parse(readFileSync104(join90(dir, "book.json"), "utf8")).kind === "base44-app-book";
|
|
171625
172403
|
} catch {
|
|
171626
172404
|
return false;
|
|
171627
172405
|
}
|
|
@@ -171708,27 +172486,27 @@ function writeBase44Book(result, outDir, opts = {}) {
|
|
|
171708
172486
|
const md = renderBookMd(book);
|
|
171709
172487
|
assertNoSecrets(json8);
|
|
171710
172488
|
assertNoSecrets(md);
|
|
171711
|
-
const owned = ["book.json", "BOOK.md", "source", "screenshots"].filter((n2) =>
|
|
172489
|
+
const owned = ["book.json", "BOOK.md", "source", "screenshots"].filter((n2) => existsSync84(join90(out2, n2)));
|
|
171712
172490
|
if (owned.length) {
|
|
171713
172491
|
if (!isBookFolder(out2)) throw new Error(`refusing to write the app book into ${out2}: it already has ${owned.join(", ")} that ${owned.length === 1 ? "is" : "are"} not from an app book \u2014 pick an empty --out`);
|
|
171714
|
-
for (const d2 of ["source", "screenshots"]) rmSync22(
|
|
172492
|
+
for (const d2 of ["source", "screenshots"]) rmSync22(join90(out2, d2), { recursive: true, force: true });
|
|
171715
172493
|
}
|
|
171716
172494
|
mkdirSync40(out2, { recursive: true });
|
|
171717
|
-
|
|
171718
|
-
|
|
172495
|
+
writeFileSync39(join90(out2, "book.json"), json8);
|
|
172496
|
+
writeFileSync39(join90(out2, "BOOK.md"), md);
|
|
171719
172497
|
files.push("book.json", "BOOK.md");
|
|
171720
172498
|
for (const s2 of shots) {
|
|
171721
|
-
mkdirSync40(
|
|
171722
|
-
|
|
172499
|
+
mkdirSync40(join90(out2, "screenshots"), { recursive: true });
|
|
172500
|
+
writeFileSync39(join90(out2, "screenshots", s2.filename), s2.bytes);
|
|
171723
172501
|
files.push(`screenshots/${s2.filename}`);
|
|
171724
172502
|
}
|
|
171725
|
-
const sourceRoot =
|
|
172503
|
+
const sourceRoot = join90(out2, "source");
|
|
171726
172504
|
for (const f2 of result.sourceFiles) {
|
|
171727
172505
|
if (!safeRel(f2.path)) continue;
|
|
171728
|
-
const dest =
|
|
172506
|
+
const dest = join90(sourceRoot, ...f2.path.split("/"));
|
|
171729
172507
|
if (!dest.startsWith(sourceRoot + sep19)) continue;
|
|
171730
172508
|
mkdirSync40(dirname48(dest), { recursive: true });
|
|
171731
|
-
|
|
172509
|
+
writeFileSync39(dest, f2.bytes);
|
|
171732
172510
|
}
|
|
171733
172511
|
if (result.sourceFiles.length) files.push(`source/ (${result.sourceFiles.length} files)`);
|
|
171734
172512
|
return { outDir: out2, files };
|
|
@@ -175269,9 +176047,9 @@ __export(cli_exports, {
|
|
|
175269
176047
|
systemTar: () => systemTar
|
|
175270
176048
|
});
|
|
175271
176049
|
import { execFile } from "node:child_process";
|
|
175272
|
-
import { mkdirSync as mkdirSync41, mkdtempSync as mkdtempSync5, rmSync as rmSync23, writeFileSync as
|
|
176050
|
+
import { mkdirSync as mkdirSync41, mkdtempSync as mkdtempSync5, rmSync as rmSync23, writeFileSync as writeFileSync40 } from "node:fs";
|
|
175273
176051
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
175274
|
-
import { join as
|
|
176052
|
+
import { join as join91, resolve as resolve61 } from "node:path";
|
|
175275
176053
|
import { promisify } from "node:util";
|
|
175276
176054
|
function projectDownloader(apiFetch, apiBase, token, extract = systemTar) {
|
|
175277
176055
|
return async (appId2) => {
|
|
@@ -175284,12 +176062,12 @@ function projectDownloader(apiFetch, apiBase, token, extract = systemTar) {
|
|
|
175284
176062
|
}
|
|
175285
176063
|
const bytes2 = await readCapped(res, MAX_TARBALL_BYTES);
|
|
175286
176064
|
if (!bytes2) throw new Error(`project download is over the ${MAX_TARBALL_BYTES}-byte cap`);
|
|
175287
|
-
const root = mkdtempSync5(
|
|
176065
|
+
const root = mkdtempSync5(join91(tmpdir6(), "himi-base44-"));
|
|
175288
176066
|
const cleanup = () => rmSync23(root, { recursive: true, force: true });
|
|
175289
176067
|
try {
|
|
175290
|
-
const archive =
|
|
175291
|
-
const dir =
|
|
175292
|
-
|
|
176068
|
+
const archive = join91(root, "project.tar");
|
|
176069
|
+
const dir = join91(root, "project");
|
|
176070
|
+
writeFileSync40(archive, bytes2);
|
|
175293
176071
|
mkdirSync41(dir);
|
|
175294
176072
|
await extract(archive, dir);
|
|
175295
176073
|
return { dir, cleanup };
|
|
@@ -175356,10 +176134,10 @@ __export(base44_entities_exports, {
|
|
|
175356
176134
|
function typeLabel(type, format) {
|
|
175357
176135
|
return format ? `${type} (${format})` : type;
|
|
175358
176136
|
}
|
|
175359
|
-
function
|
|
175360
|
-
if (Array.isArray(v2)) return `[${v2.map(
|
|
176137
|
+
function canonical5(v2) {
|
|
176138
|
+
if (Array.isArray(v2)) return `[${v2.map(canonical5).join(",")}]`;
|
|
175361
176139
|
if (v2 && typeof v2 === "object") {
|
|
175362
|
-
return `{${Object.keys(v2).sort().map((k2) => `${JSON.stringify(k2)}:${
|
|
176140
|
+
return `{${Object.keys(v2).sort().map((k2) => `${JSON.stringify(k2)}:${canonical5(v2[k2])}`).join(",")}}`;
|
|
175363
176141
|
}
|
|
175364
176142
|
return JSON.stringify(v2) ?? "undefined";
|
|
175365
176143
|
}
|
|
@@ -175372,7 +176150,7 @@ function liveItemType(live3, key3) {
|
|
|
175372
176150
|
function diffEntityFields(spec, live3) {
|
|
175373
176151
|
const entity = live3.name;
|
|
175374
176152
|
const out2 = [];
|
|
175375
|
-
const liveFields = new Map(live3.fields.filter((f2) => !
|
|
176153
|
+
const liveFields = new Map(live3.fields.filter((f2) => !BUILTINS3.has(f2.name)).map((f2) => [f2.name, f2]));
|
|
175376
176154
|
for (const f2 of spec.fields ?? []) {
|
|
175377
176155
|
const remote = liveFields.get(f2.key);
|
|
175378
176156
|
const declared = typeLabel(f2.type, f2.format);
|
|
@@ -175395,8 +176173,8 @@ function diffEntityFields(spec, live3) {
|
|
|
175395
176173
|
if (!DECLARABLE_TYPES.has(f2.type)) continue;
|
|
175396
176174
|
out2.push({ entity, kind: "extra-field", detail: `field "${key3}" (${typeLabel(f2.type, f2.format)}) exists on the live entity but is not declared` });
|
|
175397
176175
|
}
|
|
175398
|
-
if (spec.rls !== void 0 &&
|
|
175399
|
-
out2.push({ entity, kind: "rls-mismatch", detail: `declared rls ${
|
|
176176
|
+
if (spec.rls !== void 0 && canonical5(spec.rls) !== canonical5(live3.rls ?? {})) {
|
|
176177
|
+
out2.push({ entity, kind: "rls-mismatch", detail: `declared rls ${canonical5(spec.rls)} differs from the live rls ${canonical5(live3.rls ?? {})} \u2014 informational; nothing is changed` });
|
|
175400
176178
|
}
|
|
175401
176179
|
return out2;
|
|
175402
176180
|
}
|
|
@@ -175479,7 +176257,7 @@ async function queryBase44Entities(opts) {
|
|
|
175479
176257
|
...sourceError ? { sourceError } : {}
|
|
175480
176258
|
};
|
|
175481
176259
|
}
|
|
175482
|
-
var ROW_PAGE, ROW_COUNT_CAP,
|
|
176260
|
+
var ROW_PAGE, ROW_COUNT_CAP, BUILTINS3, DECLARABLE_FORMATS, DECLARABLE_TYPES;
|
|
175483
176261
|
var init_base44_entities2 = __esm({
|
|
175484
176262
|
"src/base44-entities.ts"() {
|
|
175485
176263
|
init_app_source();
|
|
@@ -175487,7 +176265,7 @@ var init_base44_entities2 = __esm({
|
|
|
175487
176265
|
init_base44_schema();
|
|
175488
176266
|
ROW_PAGE = 500;
|
|
175489
176267
|
ROW_COUNT_CAP = 5e3;
|
|
175490
|
-
|
|
176268
|
+
BUILTINS3 = new Set(BASE44_BUILTIN_FIELDS);
|
|
175491
176269
|
DECLARABLE_FORMATS = new Set(BASE44_STRING_FORMATS);
|
|
175492
176270
|
DECLARABLE_TYPES = new Set(BASE44_FIELD_TYPES);
|
|
175493
176271
|
}
|
|
@@ -175574,14 +176352,14 @@ function boundedSetting(value, ceiling) {
|
|
|
175574
176352
|
return value !== void 0 && Number.isFinite(value) && value > 0 ? Math.min(value, ceiling) : ceiling;
|
|
175575
176353
|
}
|
|
175576
176354
|
function semanticFingerprint(structure) {
|
|
175577
|
-
const
|
|
175578
|
-
if (Array.isArray(value)) return `[${value.map((item) =>
|
|
176355
|
+
const canonical6 = (value, root = false) => {
|
|
176356
|
+
if (Array.isArray(value)) return `[${value.map((item) => canonical6(item)).join(",")}]`;
|
|
175579
176357
|
if (isObject2(value)) {
|
|
175580
|
-
return `{${Object.keys(value).filter((key3) => !root || !LIFECYCLE_FIELDS.has(key3)).sort().map((key3) => `${JSON.stringify(key3)}:${
|
|
176358
|
+
return `{${Object.keys(value).filter((key3) => !root || !LIFECYCLE_FIELDS.has(key3)).sort().map((key3) => `${JSON.stringify(key3)}:${canonical6(value[key3])}`).join(",")}}`;
|
|
175581
176359
|
}
|
|
175582
176360
|
return JSON.stringify(value);
|
|
175583
176361
|
};
|
|
175584
|
-
return createHash44("sha256").update(
|
|
176362
|
+
return createHash44("sha256").update(canonical6(structure, true)).digest("hex");
|
|
175585
176363
|
}
|
|
175586
176364
|
async function collectOneApp(input, deps = {}) {
|
|
175587
176365
|
if (typeof input.metaSiteId !== "string" || !UUID.test(input.metaSiteId)) {
|
|
@@ -176205,9 +176983,9 @@ __export(cli_exports2, {
|
|
|
176205
176983
|
ONE_APP_WORKFLOW: () => ONE_APP_WORKFLOW,
|
|
176206
176984
|
runOneAppCommand: () => runOneAppCommand
|
|
176207
176985
|
});
|
|
176208
|
-
import { closeSync as closeSync7, constants as constants4, lstatSync as
|
|
176986
|
+
import { closeSync as closeSync7, constants as constants4, lstatSync as lstatSync22, mkdirSync as mkdirSync42, openSync as openSync6, readFileSync as readFileSync105, realpathSync as realpathSync14, writeFileSync as writeFileSync41 } from "node:fs";
|
|
176209
176987
|
import { createHash as createHash45 } from "node:crypto";
|
|
176210
|
-
import { dirname as dirname49, join as
|
|
176988
|
+
import { dirname as dirname49, join as join92, parse as parse3, resolve as resolve62 } from "node:path";
|
|
176211
176989
|
function readOptions(argv, cwd, commandIncluded) {
|
|
176212
176990
|
let cursor = 0;
|
|
176213
176991
|
const skipGlobalSwitches = () => {
|
|
@@ -176253,9 +177031,9 @@ function readOptions(argv, cwd, commandIncluded) {
|
|
|
176253
177031
|
if (flags["prompt-file"] !== void 0) {
|
|
176254
177032
|
try {
|
|
176255
177033
|
const file2 = resolve62(cwd, flags["prompt-file"]);
|
|
176256
|
-
const stat2 =
|
|
177034
|
+
const stat2 = lstatSync22(file2);
|
|
176257
177035
|
if (!stat2.isFile() || stat2.size > MAX_PROMPT_BYTES) throw new Error("invalid prompt file");
|
|
176258
|
-
prompt =
|
|
177036
|
+
prompt = readFileSync105(file2, "utf8");
|
|
176259
177037
|
} catch {
|
|
176260
177038
|
throw new OneAppError("invalid_prompt", "Use a readable text file of at most 64 KiB for --prompt-file.");
|
|
176261
177039
|
}
|
|
@@ -176271,14 +177049,14 @@ function readOptions(argv, cwd, commandIncluded) {
|
|
|
176271
177049
|
throw new OneAppError("invalid_output_path", "Pass a parent directory with --dir.");
|
|
176272
177050
|
}
|
|
176273
177051
|
const parentDir = resolve62(cwd, flags.dir ?? ".");
|
|
176274
|
-
const workspace =
|
|
177052
|
+
const workspace = join92(parentDir, name);
|
|
176275
177053
|
assertSafeParents(parentDir);
|
|
176276
177054
|
if (pathExists(workspace)) throw new OneAppError("output_exists", "The destination already exists. Choose a new --name or --dir.");
|
|
176277
177055
|
return { metaSiteId, appInstance, prompt, name, parentDir, workspace, target, topTabs };
|
|
176278
177056
|
}
|
|
176279
177057
|
function pathExists(path2) {
|
|
176280
177058
|
try {
|
|
176281
|
-
|
|
177059
|
+
lstatSync22(path2);
|
|
176282
177060
|
return true;
|
|
176283
177061
|
} catch (error) {
|
|
176284
177062
|
if (error.code === "ENOENT") return false;
|
|
@@ -176290,7 +177068,7 @@ function assertSafeParents(path2) {
|
|
|
176290
177068
|
let current = path2;
|
|
176291
177069
|
while (current !== root) {
|
|
176292
177070
|
try {
|
|
176293
|
-
const stat2 =
|
|
177071
|
+
const stat2 = lstatSync22(current);
|
|
176294
177072
|
if (stat2.isSymbolicLink() || !stat2.isDirectory()) {
|
|
176295
177073
|
throw new OneAppError("invalid_output_path", "Choose an output parent without symlinks or non-directory components.");
|
|
176296
177074
|
}
|
|
@@ -176306,7 +177084,7 @@ function assertSafeParents(path2) {
|
|
|
176306
177084
|
function writePrivate(path2, contents, append) {
|
|
176307
177085
|
const fd = openSync6(path2, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_NOFOLLOW | (append ? constants4.O_APPEND : constants4.O_EXCL), 384);
|
|
176308
177086
|
try {
|
|
176309
|
-
|
|
177087
|
+
writeFileSync41(fd, contents, { encoding: "utf8" });
|
|
176310
177088
|
} finally {
|
|
176311
177089
|
closeSync7(fd);
|
|
176312
177090
|
}
|
|
@@ -176328,7 +177106,7 @@ Collect the source mobile app and hand it to the current coding agent. The agent
|
|
|
176328
177106
|
const hashes = {};
|
|
176329
177107
|
const diskWrite = deps.writeFile ?? writePrivate;
|
|
176330
177108
|
const put = (name, content) => {
|
|
176331
|
-
const path2 =
|
|
177109
|
+
const path2 = join92(evidenceDir, name);
|
|
176332
177110
|
try {
|
|
176333
177111
|
assertSafeParents(evidenceDir);
|
|
176334
177112
|
diskWrite(path2, content, false);
|
|
@@ -176344,7 +177122,7 @@ Collect the source mobile app and hand it to the current coding agent. The agent
|
|
|
176344
177122
|
if (!evidenceDir) return;
|
|
176345
177123
|
try {
|
|
176346
177124
|
assertSafeParents(evidenceDir);
|
|
176347
|
-
diskWrite(
|
|
177125
|
+
diskWrite(join92(evidenceDir, "progress.jsonl"), JSON.stringify({ stage, at: now() }) + "\n", true);
|
|
176348
177126
|
} catch {
|
|
176349
177127
|
throw new OneAppError("artifact_write_failed", "Could not record migration progress. Existing files were kept.", { stage });
|
|
176350
177128
|
}
|
|
@@ -176360,7 +177138,7 @@ Collect the source mobile app and hand it to the current coding agent. The agent
|
|
|
176360
177138
|
assertSafeParents(options.parentDir);
|
|
176361
177139
|
mkdirSync42(options.workspace, { mode: 448 });
|
|
176362
177140
|
if (realpathSync14(options.workspace) !== options.workspace) throw new Error("destination changed");
|
|
176363
|
-
evidenceDir =
|
|
177141
|
+
evidenceDir = join92(options.workspace, ".himi", "one-app");
|
|
176364
177142
|
mkdirSync42(evidenceDir, { recursive: true, mode: 448 });
|
|
176365
177143
|
} catch (error) {
|
|
176366
177144
|
if (error.code === "EEXIST") {
|
|
@@ -176729,8 +177507,8 @@ function siteAppPickFrom(value) {
|
|
|
176729
177507
|
function siteAppRequirementsFrom(appId2, entry) {
|
|
176730
177508
|
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return { ok: false, reason: `No release of ${appId2} to judge` };
|
|
176731
177509
|
const e2 = entry;
|
|
176732
|
-
const
|
|
176733
|
-
if (
|
|
177510
|
+
const names2 = e2.id !== void 0 ? e2.id : e2.app;
|
|
177511
|
+
if (names2 !== appId2) return { ok: false, reason: `No release of ${appId2} to judge` };
|
|
176734
177512
|
if (!isPlayerRequirements(e2.playerRequirements)) {
|
|
176735
177513
|
return { ok: false, reason: e2.playerRequirements === void 0 ? `${appId2}'s release does not declare what it requires (republish it)` : `${appId2}'s release declares malformed requirements` };
|
|
176736
177514
|
}
|
|
@@ -177762,8 +178540,8 @@ function placeholderWarnings(findings) {
|
|
|
177762
178540
|
if (contact) out2.push(`template placeholder contact details on the site: ${quote(contact)} \u2014 the Wix template's samples, not the business's; get the real ones before any screen shows them (book.placeholders)`);
|
|
177763
178541
|
const editor = byKind.get("editor-text");
|
|
177764
178542
|
if (editor) out2.push(`${editor.length} unedited Wix editor/template string(s) on the published site, e.g. ${quote(editor.slice(0, 1))} \u2014 dropped from book.copy, never ship them (book.placeholders)`);
|
|
177765
|
-
const
|
|
177766
|
-
if (
|
|
178543
|
+
const names2 = byKind.get("name-mismatch");
|
|
178544
|
+
if (names2) out2.push(`the site names the business inconsistently \u2014 it also says ${quote(names2)}; likely the template's name left in the copy, so confirm with the owner (book.placeholders)`);
|
|
177767
178545
|
const media = byKind.get("duplicate-media");
|
|
177768
178546
|
if (media) out2.push(`${media.length} place(s) repeat one image ${DUPLICATE_MEDIA_MIN}+ times (${media.slice(0, 3).map((m2) => m2.where[0]).join(", ")}) \u2014 template filler, not real photos (book.placeholders)`);
|
|
177769
178547
|
return out2;
|
|
@@ -178497,8 +179275,8 @@ var init_customer_build = __esm({
|
|
|
178497
179275
|
});
|
|
178498
179276
|
|
|
178499
179277
|
// src/site-analyze/apply.ts
|
|
178500
|
-
import { existsSync as
|
|
178501
|
-
import { dirname as dirname50, isAbsolute as isAbsolute8, join as
|
|
179278
|
+
import { existsSync as existsSync85, readFileSync as readFileSync106, writeFileSync as writeFileSync42, copyFileSync as copyFileSync2, mkdirSync as mkdirSync43, realpathSync as realpathSync15, statSync as statSync22 } from "node:fs";
|
|
179279
|
+
import { dirname as dirname50, isAbsolute as isAbsolute8, join as join93, resolve as resolve63, sep as sep20 } from "node:path";
|
|
178502
179280
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
178503
179281
|
function unpairedRedirectNote(overlay) {
|
|
178504
179282
|
if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
|
|
@@ -178513,7 +179291,7 @@ function committedShellProvisioning(path2) {
|
|
|
178513
179291
|
function findRepoRoot(cwd) {
|
|
178514
179292
|
let dir = cwd;
|
|
178515
179293
|
for (let i2 = 0; i2 < 8; i2++) {
|
|
178516
|
-
if (SHELL_NAMES2.some((name) =>
|
|
179294
|
+
if (SHELL_NAMES2.some((name) => existsSync85(join93(dir, shellAppDir(name), "package.json")))) return dir;
|
|
178517
179295
|
const next = dirname50(dir);
|
|
178518
179296
|
if (next === dir) break;
|
|
178519
179297
|
dir = next;
|
|
@@ -178616,11 +179394,11 @@ function sameKnownSite(previous, next) {
|
|
|
178616
179394
|
}
|
|
178617
179395
|
function buildMergedContract(options) {
|
|
178618
179396
|
const { appDir: appDir3, packageDir, overlay } = options;
|
|
178619
|
-
const committedPath =
|
|
178620
|
-
if (!
|
|
179397
|
+
const committedPath = join93(appDir3, "provisioning.json");
|
|
179398
|
+
if (!existsSync85(committedPath)) {
|
|
178621
179399
|
throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
|
|
178622
179400
|
}
|
|
178623
|
-
const committed = JSON.parse(
|
|
179401
|
+
const committed = JSON.parse(readFileSync106(committedPath, "utf8"));
|
|
178624
179402
|
const merged = mergeCustomerOwned(committed, overlay);
|
|
178625
179403
|
const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
|
|
178626
179404
|
const branding = merged.branding ?? {};
|
|
@@ -178632,8 +179410,8 @@ function buildMergedContract(options) {
|
|
|
178632
179410
|
};
|
|
178633
179411
|
const stage = (fromRel, toRel) => {
|
|
178634
179412
|
const from = contained(packageDir, fromRel);
|
|
178635
|
-
const to2 = contained(
|
|
178636
|
-
if (!from || !to2 || !
|
|
179413
|
+
const to2 = contained(join93(appDir3, STAGED), toRel.slice(STAGED.length + 1));
|
|
179414
|
+
if (!from || !to2 || !existsSync85(from)) return void 0;
|
|
178637
179415
|
let real;
|
|
178638
179416
|
let realRoot;
|
|
178639
179417
|
try {
|
|
@@ -178655,11 +179433,11 @@ function buildMergedContract(options) {
|
|
|
178655
179433
|
};
|
|
178656
179434
|
const icon = stage("media/icon.png", `${STAGED}/icon.png`);
|
|
178657
179435
|
if (icon) branding.appIconPath = icon;
|
|
178658
|
-
const facesPath =
|
|
178659
|
-
if (
|
|
179436
|
+
const facesPath = join93(packageDir, "media/fonts/faces.json");
|
|
179437
|
+
if (existsSync85(facesPath)) {
|
|
178660
179438
|
let faces = [];
|
|
178661
179439
|
try {
|
|
178662
|
-
const parsed = JSON.parse(
|
|
179440
|
+
const parsed = JSON.parse(readFileSync106(facesPath, "utf8"));
|
|
178663
179441
|
faces = Array.isArray(parsed) ? parsed : [];
|
|
178664
179442
|
} catch {
|
|
178665
179443
|
faces = [];
|
|
@@ -178680,11 +179458,11 @@ function buildMergedContract(options) {
|
|
|
178680
179458
|
merged.branding = branding;
|
|
178681
179459
|
const body = `${JSON.stringify(merged, null, 2)}
|
|
178682
179460
|
`;
|
|
178683
|
-
const path2 =
|
|
178684
|
-
|
|
178685
|
-
const localPath2 =
|
|
179461
|
+
const path2 = join93(packageDir, "provisioning.contract.json");
|
|
179462
|
+
writeFileSync42(path2, body);
|
|
179463
|
+
const localPath2 = join93(appDir3, LOCAL_CONTRACT_REL);
|
|
178686
179464
|
mkdirSync43(dirname50(localPath2), { recursive: true });
|
|
178687
|
-
|
|
179465
|
+
writeFileSync42(localPath2, body);
|
|
178688
179466
|
staged.push(localPath2);
|
|
178689
179467
|
return { path: path2, staged };
|
|
178690
179468
|
}
|
|
@@ -178703,9 +179481,9 @@ function catalogTypography(overlay, template) {
|
|
|
178703
179481
|
typography[role] = token;
|
|
178704
179482
|
continue;
|
|
178705
179483
|
}
|
|
178706
|
-
const
|
|
178707
|
-
if (
|
|
178708
|
-
typography[role] = { ...token, family:
|
|
179484
|
+
const canonical6 = canonicalFamilyName(family.trim());
|
|
179485
|
+
if (canonical6) {
|
|
179486
|
+
typography[role] = { ...token, family: canonical6 };
|
|
178709
179487
|
continue;
|
|
178710
179488
|
}
|
|
178711
179489
|
const kept = base[role]?.family;
|
|
@@ -178717,10 +179495,10 @@ function catalogTypography(overlay, template) {
|
|
|
178717
179495
|
function staticFaqFor(overlay, overlayPath) {
|
|
178718
179496
|
const own5 = overlay.faq;
|
|
178719
179497
|
if (own5 !== void 0) return deriveStaticFaq(own5);
|
|
178720
|
-
const bookPath =
|
|
178721
|
-
if (!
|
|
179498
|
+
const bookPath = join93(dirname50(resolve63(overlayPath)), "book.json");
|
|
179499
|
+
if (!existsSync85(bookPath)) return void 0;
|
|
178722
179500
|
try {
|
|
178723
|
-
const book = JSON.parse(
|
|
179501
|
+
const book = JSON.parse(readFileSync106(bookPath, "utf8"));
|
|
178724
179502
|
const copy = book?.copy;
|
|
178725
179503
|
if (!copy || typeof copy !== "object" || copy.unavailable) return void 0;
|
|
178726
179504
|
const pairs = deriveStaticFaq(copy.faq);
|
|
@@ -178734,10 +179512,10 @@ function staticGalleriesFor(overlay, overlayPath) {
|
|
|
178734
179512
|
if (overlay.galleries !== void 0) return deriveStaticGalleries(
|
|
178735
179513
|
overlay.galleries.map((gallery) => ({ role: "gallery", title: gallery.title, galleryImageUrls: gallery.photos }))
|
|
178736
179514
|
);
|
|
178737
|
-
const bookPath =
|
|
178738
|
-
if (!
|
|
179515
|
+
const bookPath = join93(dirname50(resolve63(overlayPath)), "book.json");
|
|
179516
|
+
if (!existsSync85(bookPath)) return void 0;
|
|
178739
179517
|
try {
|
|
178740
|
-
const book = JSON.parse(
|
|
179518
|
+
const book = JSON.parse(readFileSync106(bookPath, "utf8"));
|
|
178741
179519
|
if (!book.look || book.look.unavailable || !Array.isArray(book.look.pages)) return void 0;
|
|
178742
179520
|
const galleries = deriveStaticGalleries(book.look.pages);
|
|
178743
179521
|
return galleries.length || book.look.complete === true ? galleries : void 0;
|
|
@@ -178749,8 +179527,8 @@ async function applyOverlays(input) {
|
|
|
178749
179527
|
const cwd = resolve63(input.cwd);
|
|
178750
179528
|
const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
|
|
178751
179529
|
assertKnownShell(shell);
|
|
178752
|
-
const overlay = JSON.parse(
|
|
178753
|
-
const tokens2 = JSON.parse(
|
|
179530
|
+
const overlay = JSON.parse(readFileSync106(input.overlayPath, "utf8"));
|
|
179531
|
+
const tokens2 = JSON.parse(readFileSync106(input.tokensPath, "utf8"));
|
|
178754
179532
|
const faq = staticFaqFor(overlay, input.overlayPath);
|
|
178755
179533
|
if (faq !== void 0) overlay.faq = faq;
|
|
178756
179534
|
const galleries = staticGalleriesFor(overlay, input.overlayPath);
|
|
@@ -178767,9 +179545,9 @@ async function applyOverlays(input) {
|
|
|
178767
179545
|
`shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
|
|
178768
179546
|
);
|
|
178769
179547
|
}
|
|
178770
|
-
const appDir3 =
|
|
178771
|
-
const committedPath =
|
|
178772
|
-
const committedSite =
|
|
179548
|
+
const appDir3 = join93(repoRoot2, shellAppDir(shell));
|
|
179549
|
+
const committedPath = join93(appDir3, "provisioning.json");
|
|
179550
|
+
const committedSite = existsSync85(committedPath) ? JSON.parse(readFileSync106(committedPath, "utf8")).site : void 0;
|
|
178773
179551
|
if (committedSite !== void 0 && overlay.site === void 0) {
|
|
178774
179552
|
throw new Error(
|
|
178775
179553
|
`shell "${shell}" is a site shell: its contract names the customer's website (a \`site\` block), and this overlay has none. Re-run \`himi site analyze --url <site> --shell ${shell}\` to derive the site's page map (edit \`site.pages\` in provisioning.overlay.json if needed), then --apply.`
|
|
@@ -178796,9 +179574,9 @@ async function applyOverlays(input) {
|
|
|
178796
179574
|
note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
|
|
178797
179575
|
};
|
|
178798
179576
|
}
|
|
178799
|
-
const pkgProv =
|
|
179577
|
+
const pkgProv = join93(cwd, "provisioning.json");
|
|
178800
179578
|
assertNotCommitted(pkgProv, input.forbiddenProvisioning);
|
|
178801
|
-
const contentPath =
|
|
179579
|
+
const contentPath = join93(cwd, "himalaya.content.json");
|
|
178802
179580
|
const syncViewNames = (before, after) => {
|
|
178803
179581
|
const content = readContentManifest(cwd);
|
|
178804
179582
|
if (!content) return;
|
|
@@ -178810,26 +179588,26 @@ async function applyOverlays(input) {
|
|
|
178810
179588
|
};
|
|
178811
179589
|
let packageFaq = faq;
|
|
178812
179590
|
let packageGalleries = galleries;
|
|
178813
|
-
if (
|
|
178814
|
-
const cur = JSON.parse(
|
|
179591
|
+
if (existsSync85(pkgProv)) {
|
|
179592
|
+
const cur = JSON.parse(readFileSync106(pkgProv, "utf8"));
|
|
178815
179593
|
if (galleries === void 0 && !sameKnownSite(cur, overlay)) overlay.galleries = [];
|
|
178816
179594
|
const merged = deepMerge4(cur, overlay);
|
|
178817
179595
|
packageFaq = merged.faq;
|
|
178818
179596
|
packageGalleries = merged.galleries;
|
|
178819
179597
|
syncViewNames(cur.site, merged.site);
|
|
178820
|
-
|
|
179598
|
+
writeFileSync42(pkgProv, JSON.stringify(merged, null, 2) + "\n");
|
|
178821
179599
|
wrote.push(pkgProv);
|
|
178822
179600
|
} else {
|
|
178823
179601
|
syncViewNames(void 0, overlay.site);
|
|
178824
|
-
|
|
179602
|
+
writeFileSync42(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
|
|
178825
179603
|
wrote.push(pkgProv);
|
|
178826
179604
|
}
|
|
178827
179605
|
if (Array.isArray(packageGalleries) && packageGalleries.length && !overlay.installedVerticals.includes("galleries")) {
|
|
178828
179606
|
overlay.installedVerticals.push("galleries");
|
|
178829
179607
|
}
|
|
178830
|
-
const pkgTokens =
|
|
178831
|
-
if (
|
|
178832
|
-
const cur = JSON.parse(
|
|
179608
|
+
const pkgTokens = join93(cwd, "tokens.json");
|
|
179609
|
+
if (existsSync85(pkgTokens) && (tokens2.colors || tokens2.typography)) {
|
|
179610
|
+
const cur = JSON.parse(readFileSync106(pkgTokens, "utf8"));
|
|
178833
179611
|
let tokensIn = tokens2;
|
|
178834
179612
|
if (tokens2.typography) {
|
|
178835
179613
|
const fonts = catalogTypography(tokens2.typography, cur.typography);
|
|
@@ -178850,13 +179628,13 @@ async function applyOverlays(input) {
|
|
|
178850
179628
|
if (primary && glow && typeof glow.color === "string") glow.color = primary;
|
|
178851
179629
|
stripBrandFromIdiom(merged);
|
|
178852
179630
|
}
|
|
178853
|
-
|
|
179631
|
+
writeFileSync42(pkgTokens, JSON.stringify(merged, null, 2) + "\n");
|
|
178854
179632
|
wrote.push(pkgTokens);
|
|
178855
179633
|
}
|
|
178856
179634
|
const homeAction = homeRefreshActionId(shell);
|
|
178857
|
-
const homeSrc =
|
|
178858
|
-
if (homeAction &&
|
|
178859
|
-
const prev =
|
|
179635
|
+
const homeSrc = join93(cwd, "dev/index.ts");
|
|
179636
|
+
if (homeAction && existsSync85(homeSrc)) {
|
|
179637
|
+
const prev = readFileSync106(homeSrc, "utf8");
|
|
178860
179638
|
const patched = patchBrandParams(prev, overlay, homeAction);
|
|
178861
179639
|
let next = patched.src;
|
|
178862
179640
|
if (!patched.foreign && faq?.length && prev.includes('"tier5.himiBrandedFaq.load"') && !prev.includes('"staticFaq"')) {
|
|
@@ -178884,20 +179662,20 @@ async function applyOverlays(input) {
|
|
|
178884
179662
|
}
|
|
178885
179663
|
}
|
|
178886
179664
|
if (next !== prev) {
|
|
178887
|
-
|
|
179665
|
+
writeFileSync42(homeSrc, next);
|
|
178888
179666
|
wrote.push(homeSrc);
|
|
178889
179667
|
}
|
|
178890
179668
|
if (patched.unparsed) {
|
|
178891
179669
|
notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
|
|
178892
179670
|
}
|
|
178893
179671
|
}
|
|
178894
|
-
if (!input.iconPath || !
|
|
179672
|
+
if (!input.iconPath || !existsSync85(input.iconPath)) {
|
|
178895
179673
|
const book = input.iconPath ? dirname50(dirname50(resolve63(input.iconPath))) : void 0;
|
|
178896
179674
|
notes.push(
|
|
178897
179675
|
book ? `no icon installed \u2014 ${siteLogoAbsence(book).hint}` : "no icon installed and no business book to say why \u2014 `himi icon generate` draws one from the accent, or `himi icon set <file.png>` installs the customer's own mark"
|
|
178898
179676
|
);
|
|
178899
179677
|
}
|
|
178900
|
-
if (input.iconPath &&
|
|
179678
|
+
if (input.iconPath && existsSync85(input.iconPath)) {
|
|
178901
179679
|
try {
|
|
178902
179680
|
const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
|
|
178903
179681
|
wrote.push(...installed.wrote);
|
|
@@ -178986,7 +179764,7 @@ function patchBrandParams(src, overlay, homeActionId) {
|
|
|
178986
179764
|
return { src: out2 + src.slice(cursor), applied, unparsed, foreign: false };
|
|
178987
179765
|
}
|
|
178988
179766
|
var STAGED;
|
|
178989
|
-
var
|
|
179767
|
+
var init_apply3 = __esm({
|
|
178990
179768
|
"src/site-analyze/apply.ts"() {
|
|
178991
179769
|
init_content_manifest();
|
|
178992
179770
|
init_site_view_metadata();
|
|
@@ -179856,7 +180634,7 @@ __export(cli_exports3, {
|
|
|
179856
180634
|
runSiteAnalyze: () => runSiteAnalyze,
|
|
179857
180635
|
runSiteFunctionCli: () => runSiteFunctionCli
|
|
179858
180636
|
});
|
|
179859
|
-
import { existsSync as
|
|
180637
|
+
import { existsSync as existsSync86, readFileSync as readFileSync107 } from "node:fs";
|
|
179860
180638
|
import { resolve as resolve64 } from "node:path";
|
|
179861
180639
|
function applyNeedsClient(shell) {
|
|
179862
180640
|
if (shell === void 0 || !SHELL_NAMES2.includes(shell)) return true;
|
|
@@ -179924,9 +180702,9 @@ async function runSiteAnalyze(opts) {
|
|
|
179924
180702
|
if (book?.skipped) result.warnings = [...result.warnings ?? [], book.skipped];
|
|
179925
180703
|
const derived = deriveSiteShell({ siteUrl: result.book.input.siteUrl, look: result.book.look, kind, routes });
|
|
179926
180704
|
const prevOverlayPath = resolve64(outDir, "provisioning.overlay.json");
|
|
179927
|
-
const prevSite =
|
|
180705
|
+
const prevSite = existsSync86(prevOverlayPath) ? (() => {
|
|
179928
180706
|
try {
|
|
179929
|
-
return JSON.parse(
|
|
180707
|
+
return JSON.parse(readFileSync107(prevOverlayPath, "utf8")).site;
|
|
179930
180708
|
} catch {
|
|
179931
180709
|
return void 0;
|
|
179932
180710
|
}
|
|
@@ -179945,7 +180723,7 @@ async function runSiteAnalyze(opts) {
|
|
|
179945
180723
|
}
|
|
179946
180724
|
const previousOverlay = resolve64(outDir, "provisioning.overlay.json");
|
|
179947
180725
|
carryOverGoals(
|
|
179948
|
-
|
|
180726
|
+
existsSync86(previousOverlay) ? readFileSync107(previousOverlay, "utf8") : void 0,
|
|
179949
180727
|
result.provisioningOverlay
|
|
179950
180728
|
);
|
|
179951
180729
|
const ownerCall = ownerAuth ? ownerTransportFrom(fetchImpl, ownerAuth) : void 0;
|
|
@@ -180003,7 +180781,7 @@ async function runSiteFunctionCli(opts) {
|
|
|
180003
180781
|
let source;
|
|
180004
180782
|
if (opts.sourcePath) {
|
|
180005
180783
|
const p2 = resolve64(opts.cwd ?? process.cwd(), opts.sourcePath);
|
|
180006
|
-
source =
|
|
180784
|
+
source = readFileSync107(p2, "utf8");
|
|
180007
180785
|
}
|
|
180008
180786
|
let body;
|
|
180009
180787
|
if (opts.bodyRaw != null) {
|
|
@@ -180031,9 +180809,9 @@ async function runSiteFunctionCli(opts) {
|
|
|
180031
180809
|
});
|
|
180032
180810
|
}
|
|
180033
180811
|
function base44BookRoutes(bookPath, siteUrl) {
|
|
180034
|
-
if (!
|
|
180812
|
+
if (!existsSync86(bookPath)) return void 0;
|
|
180035
180813
|
try {
|
|
180036
|
-
const book = JSON.parse(
|
|
180814
|
+
const book = JSON.parse(readFileSync107(bookPath, "utf8"));
|
|
180037
180815
|
if (book.kind !== "base44-app-book" || !Array.isArray(book.routes)) return void 0;
|
|
180038
180816
|
const host = (u2) => {
|
|
180039
180817
|
try {
|
|
@@ -180060,7 +180838,7 @@ var init_cli3 = __esm({
|
|
|
180060
180838
|
init_analyze2();
|
|
180061
180839
|
init_write_artifacts();
|
|
180062
180840
|
init_net_guard();
|
|
180063
|
-
|
|
180841
|
+
init_apply3();
|
|
180064
180842
|
init_site_shell_derive();
|
|
180065
180843
|
init_brandable_shells();
|
|
180066
180844
|
init_crawl_look();
|
|
@@ -180187,10 +180965,10 @@ var init_wix_account2 = __esm({
|
|
|
180187
180965
|
// src/wix-verticals.ts
|
|
180188
180966
|
function resolveVerticals(csv2) {
|
|
180189
180967
|
if (!csv2) return [];
|
|
180190
|
-
const
|
|
180968
|
+
const names2 = csv2.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
180191
180969
|
const out2 = [];
|
|
180192
180970
|
const seen = /* @__PURE__ */ new Set();
|
|
180193
|
-
for (const name of
|
|
180971
|
+
for (const name of names2) {
|
|
180194
180972
|
const appDefId = APP_IDS[name];
|
|
180195
180973
|
if (!appDefId) {
|
|
180196
180974
|
const why = UNAVAILABLE[name];
|
|
@@ -180288,7 +181066,7 @@ __export(site_create_exports, {
|
|
|
180288
181066
|
runSiteList: () => runSiteList,
|
|
180289
181067
|
writeProvisioningBinding: () => writeProvisioningBinding
|
|
180290
181068
|
});
|
|
180291
|
-
import { existsSync as
|
|
181069
|
+
import { existsSync as existsSync87, readFileSync as readFileSync108, writeFileSync as writeFileSync43 } from "node:fs";
|
|
180292
181070
|
import { resolve as resolvePath2 } from "node:path";
|
|
180293
181071
|
function oauthClientName(projectName) {
|
|
180294
181072
|
return `${projectName} client`;
|
|
@@ -180437,7 +181215,7 @@ async function runSiteCreate(opts) {
|
|
|
180437
181215
|
if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
|
|
180438
181216
|
return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
|
|
180439
181217
|
}
|
|
180440
|
-
function writeProvisioningBinding(target, binding2, fs2 = { existsSync:
|
|
181218
|
+
function writeProvisioningBinding(target, binding2, fs2 = { existsSync: existsSync87, readFileSync: readFileSync108, writeFileSync: writeFileSync43 }) {
|
|
180441
181219
|
const msid = binding2.siteId;
|
|
180442
181220
|
const path2 = resolvePath2(target);
|
|
180443
181221
|
const committed = committedShellProvisioning(path2);
|
|
@@ -180523,7 +181301,7 @@ var init_site_create = __esm({
|
|
|
180523
181301
|
init_wix_owner();
|
|
180524
181302
|
init_wix_account2();
|
|
180525
181303
|
init_wix_verticals();
|
|
180526
|
-
|
|
181304
|
+
init_apply3();
|
|
180527
181305
|
init_types2();
|
|
180528
181306
|
init_brandable_shells();
|
|
180529
181307
|
SITE_CREATE_USAGE = `himi site create <name> [--type wix|headless|branded-app|vibe] [--template <guid>] [--verticals ${VERTICAL_NAMES.slice(0, 2).join(",")},\u2026] [--folder <guid>] [--redirect-uri <uri>] [--no-oauth-app] [--write-provisioning [path]] [--site-url <url>] [--json] --yes`;
|
|
@@ -180864,13 +181642,13 @@ function selectVeloSource(files, request, knownSecrets = []) {
|
|
|
180864
181642
|
(word) => !["with", "that", "this", "from", "have", "want", "app", "site", "backend"].includes(word)
|
|
180865
181643
|
).slice(0, 80);
|
|
180866
181644
|
const score = (file2) => {
|
|
180867
|
-
const
|
|
180868
|
-
return words.reduce((sum, word) => sum + (
|
|
181645
|
+
const names2 = file2.path + " " + [...file2.content.matchAll(/export\s+(?:async\s+)?(?:function|const)\s+(\w+)/g)].map((m2) => m2[1]).join(" ");
|
|
181646
|
+
return words.reduce((sum, word) => sum + (names2.toLowerCase().includes(word) ? 10 : 0), 0) + (/http-functions\.[jt]s$|\.web\.[jt]s$|\.jsw$/.test(file2.path) ? 1 : 0);
|
|
180869
181647
|
};
|
|
180870
181648
|
const queue = candidates.filter((file2) => score(file2) > 0).sort((a2, b2) => score(b2) - score(a2) || a2.path.localeCompare(b2.path));
|
|
180871
181649
|
const selected = /* @__PURE__ */ new Map();
|
|
180872
181650
|
let remaining = MAX_TOTAL_CHARS;
|
|
180873
|
-
while (queue.length && selected.size <
|
|
181651
|
+
while (queue.length && selected.size < MAX_FILES2 && remaining > 0) {
|
|
180874
181652
|
const file2 = queue.shift();
|
|
180875
181653
|
if (!file2) break;
|
|
180876
181654
|
if (selected.has(file2.path)) continue;
|
|
@@ -180910,10 +181688,10 @@ function selectVeloSource(files, request, knownSecrets = []) {
|
|
|
180910
181688
|
}
|
|
180911
181689
|
return selected;
|
|
180912
181690
|
}
|
|
180913
|
-
var
|
|
181691
|
+
var MAX_FILES2, MAX_FILE_CHARS, MAX_TOTAL_CHARS, REDACTED2, sensitiveName;
|
|
180914
181692
|
var init_velo_source = __esm({
|
|
180915
181693
|
"src/site-analyze/velo-source.ts"() {
|
|
180916
|
-
|
|
181694
|
+
MAX_FILES2 = 6;
|
|
180917
181695
|
MAX_FILE_CHARS = 8e3;
|
|
180918
181696
|
MAX_TOTAL_CHARS = 24e3;
|
|
180919
181697
|
REDACTED2 = "[REDACTED]";
|
|
@@ -181134,12 +181912,12 @@ var init_context = __esm({
|
|
|
181134
181912
|
});
|
|
181135
181913
|
|
|
181136
181914
|
// src/cli.ts
|
|
181137
|
-
import { mkdtempSync as mkdtempSync6, readFileSync as
|
|
181915
|
+
import { mkdtempSync as mkdtempSync6, readFileSync as readFileSync109, mkdirSync as mkdirSync44, writeFileSync as writeFileSync44, existsSync as existsSync88, rmSync as rmSync24, readdirSync as readdirSync36, statSync as statSync23, lstatSync as lstatSync23, accessSync, constants as constants5, renameSync as renameSync13, cpSync as cpSync3 } from "node:fs";
|
|
181138
181916
|
import { execFile as execFile2, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn7 } from "node:child_process";
|
|
181139
181917
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
181140
181918
|
import { createHash as createHash46, randomUUID as randomUUID11 } from "node:crypto";
|
|
181141
181919
|
import { tmpdir as tmpdir7, homedir as homedir14, hostname as hostname2 } from "node:os";
|
|
181142
|
-
import { join as
|
|
181920
|
+
import { join as join94, resolve as resolve65, relative as relative16, basename as basename21, dirname as dirname51 } from "node:path";
|
|
181143
181921
|
import { fileURLToPath as fileURLToPath29 } from "node:url";
|
|
181144
181922
|
|
|
181145
181923
|
// ../serve-cli/src/client.ts
|
|
@@ -183013,7 +183791,7 @@ function auditUx(content, strict = false) {
|
|
|
183013
183791
|
}
|
|
183014
183792
|
}
|
|
183015
183793
|
const source = walkSource(dir);
|
|
183016
|
-
const
|
|
183794
|
+
const placeholder3 = /\breplace with\b|\bYOUR_[A-Z0-9_]+\b/i;
|
|
183017
183795
|
const previewControl = /\b(?:test|demo|scenario)\s*(?:state|switch|mode)\b/i;
|
|
183018
183796
|
const matches = (pattern) => source.find((file2) => pattern.test(file2.text));
|
|
183019
183797
|
const locate2 = (file2, pattern) => {
|
|
@@ -183024,13 +183802,13 @@ function auditUx(content, strict = false) {
|
|
|
183024
183802
|
const shown2 = hit.length > 60 ? `${hit.slice(0, 60)}\u2026` : hit;
|
|
183025
183803
|
return `${file2.path}:${index + 1}`.concat(shown2 ? ` (\`${shown2}\`)` : "");
|
|
183026
183804
|
};
|
|
183027
|
-
const p2 = matches(
|
|
183805
|
+
const p2 = matches(placeholder3);
|
|
183028
183806
|
if (p2) {
|
|
183029
183807
|
issue(
|
|
183030
183808
|
issues,
|
|
183031
183809
|
strict,
|
|
183032
183810
|
"template-placeholder",
|
|
183033
|
-
`Template placeholder copy remains in executable source at ${locate2(p2,
|
|
183811
|
+
`Template placeholder copy remains in executable source at ${locate2(p2, placeholder3)}; replace it with customer content or a real configuration value.`,
|
|
183034
183812
|
p2.path
|
|
183035
183813
|
);
|
|
183036
183814
|
}
|
|
@@ -183155,7 +183933,8 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
183155
183933
|
"no-mocks",
|
|
183156
183934
|
"from-base44-cli",
|
|
183157
183935
|
"no-browser",
|
|
183158
|
-
"refresh-wix"
|
|
183936
|
+
"refresh-wix",
|
|
183937
|
+
"empty-app-ok"
|
|
183159
183938
|
]);
|
|
183160
183939
|
var SHELL_ENUM = SHELL_NAMES2.join("|");
|
|
183161
183940
|
var SWITCH_FLAGS = new Set([...BOOLEAN_FLAGS].filter((name) => name !== "deep"));
|
|
@@ -183225,8 +184004,8 @@ var str10 = (v2) => typeof v2 === "string" ? v2 : void 0;
|
|
|
183225
184004
|
var num3 = (v2) => typeof v2 === "string" && v2 !== "" && Number.isFinite(Number(v2)) ? Number(v2) : void 0;
|
|
183226
184005
|
function embeddedTemplateCatalog() {
|
|
183227
184006
|
return availableTemplates().map((name) => {
|
|
183228
|
-
const path2 =
|
|
183229
|
-
const meta = JSON.parse(
|
|
184007
|
+
const path2 = join94(templateSourceDir(name), TEMPLATE_META_FILE);
|
|
184008
|
+
const meta = JSON.parse(readFileSync109(path2, "utf8"));
|
|
183230
184009
|
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
183231
184010
|
throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
|
|
183232
184011
|
}
|
|
@@ -183952,9 +184731,25 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
183952
184731
|
controls gated by each entity's rls. Re-running is a
|
|
183953
184732
|
no-op; a hand-edited generated file is skipped-edited
|
|
183954
184733
|
unless --force. Never calls Base44.
|
|
183955
|
-
himi base44
|
|
184734
|
+
himi base44 entities create [--app <a> | --content <dir>] [--yes] [--allow-destructive]
|
|
184735
|
+
[--apply-permissions] [--empty-app-ok]
|
|
184736
|
+
create/update the app's OWNED Himi<App>* entities. Base44's
|
|
184737
|
+
schema write is a full-set sync, so the one PUT carries
|
|
184738
|
+
every live entity (foreign ones verbatim, from a fresh
|
|
184739
|
+
eject read) and refuses before sending if any would drop.
|
|
184740
|
+
Prints the plan; writes only with --yes.
|
|
184741
|
+
himi base44 entities seed [--app <a>] [--yes] [--only A,B] [--ai [--count <n>]]
|
|
184742
|
+
bulk-insert seed rows into EMPTY owned entities only
|
|
184743
|
+
(base44-seed.json wins over config.ts). --ai writes
|
|
184744
|
+
base44-seed.json offline for the agent to refine.
|
|
184745
|
+
himi base44 functions deploy [--app <a>] [--yes] [--only a,b]
|
|
184746
|
+
deploy each owned function from base44/functions/<name>/,
|
|
184747
|
+
one PUT per function; never the bulk sync, never DELETE;
|
|
184748
|
+
refuses a name deployed by someone else.
|
|
184749
|
+
himi base44 login [--write] [--from-base44-cli] | whoami | logout
|
|
183956
184750
|
the Base44 session, in ~/.himi/base44/ (never the repo).
|
|
183957
|
-
|
|
184751
|
+
--write asks for apps:read apps:write (the provisioning
|
|
184752
|
+
verbs need it). BASE44_ACCESS_TOKEN wins, for CI.
|
|
183958
184753
|
himi base44 auth-check --url <https://tenant> [--ios-app-id <PREFIX.bundle.id>]
|
|
183959
184754
|
[--android-package <package> --android-sha256 <fingerprint>]
|
|
183960
184755
|
check the public tenant association files for native
|
|
@@ -184099,7 +184894,7 @@ var COMMANDS2 = [
|
|
|
184099
184894
|
{ name: "notify", summary: "Hosted --all-members requires --yes for a live send; --dry-run checks ownership/readiness and counts approved recipients without sending. `setup` optionally configures Branded/Ping from local customer key files; `status --refresh` reads live backend readiness. Setup may be deferred while building. These use serve-control and require owner plus Wix account authentication. `send`, `tokens`, `doctor`: send a REAL push notification to registered devices (RFC 0036 WS5) \u2014 APNs .p8 over HTTP/2 for iOS, FCM v1 for Android. `send` targets one device (--token / --device <registry id>) or fans out to the whole app (--all), reporting a per-device result; a token the provider says is uninstalled (APNs 410 Unregistered / FCM UNREGISTERED) is auto-disabled, while a merely wrong one (BadDeviceToken \u2014 usually a sandbox/production mismatch) is recorded and left enabled. `tokens` lists the registry. `doctor` reports which credentials resolve and which sender each platform picks. Talks to the admin-server via --admin-url/HIMALAYA_ADMIN_URL, authenticated with --admin-session/HIMALAYA_ADMIN_SESSION. `send --provider ping` is the hosted alternative: the serve plane sends to one site member (--member-email) or all approved members (--all-members) through Ping as Himalaya, with owner login instead of provider keys, and reports acceptance, never delivery. NOT `himi push`, which publishes a release.", required: "setup|status [--content <dir>] [--target <t>] [--refresh] [--yes] [--no-push-setup] | send --provider ping [--content <dir>] [--app <a>] [--site <msid>] (--member-email <email> | --all-members (--dry-run | --yes)) --title <s> [--body <s>] --link <url> [--request-id <uuid>] [--dry-run] [--json] | send|tokens|doctor [--app <a>] [--token <t> | --device <id> | --all] [--title <s>] [--body <s>] [--link <url>] [--platform ios|android] [--badge <n>] [--channel <id>] [--silent] [--dry-run] [--json]" },
|
|
184100
184895
|
{ name: "signing", summary: "READ-ONLY App Store Connect inventory for customer BYO TestFlight readiness. `inspect` lists whether the bundle id, distribution certificate, IOS_APP_STORE profile, and ASC app record exist for --bundle-id / --team-id using a local ASC .p8 (flags or ASC_KEY_* env). Never uploads or mutates Apple resources. Optional --cert-file/--profile-file classify on-disk material.", required: "inspect --bundle-id <id> --team-id <id> --asc-key-file <path> --asc-key-id <id> --asc-issuer-id <id> [--cert-file <p12> --cert-password <pw> --profile-file <mobileprovision>] [--json]" },
|
|
184101
184896
|
{ name: "site", summary: "PROVISION a Wix project, then analyze or extend it. `create` is the one door that makes a site instead of adopting one: POST /funnel/projects/v1/create (a WIX site, a HEADLESS backend, a BRANDED_APP, or a VIBE site), and for headless it also mints the OAuth app whose id IS the `WIX_CLIENT_ID` \u2014 with --redirect-uri already registered, because an unregistered redirect makes native signInDirect fail at redirect-session. `--verticals` REQUIRES `--template` and reports only what Wix confirmed: measured, installing onto a project created from the BLANK template returns 200 while the vertical's API answers 428 forever, because there is no site for it to attach to (the install asks for CREATE_SITE). A real template ships its verticals installed and populated, and installing further ones onto it then works. It MUTATES your Wix account and needs --yes; without it you get the payload and nothing is sent. `list` is the read-only site inventory (with each site's premium flag, which is what explains an installed-but-428 vertical). Auth is the account-scoped `wix token` (no --site), falling back to WIX_API_KEY + WIX_ACCOUNT_ID. `client` is the same OAuth step for a site that ALREADY exists \u2014 the one himi adopts rather than makes \u2014 so a clientId no longer means a manual trip to the dashboard: `client ensure` reconciles rather than mints, because a site can already carry a client with NO registered redirect and shipping that one fails signInDirect at runtime; it reuses a client that carries --redirect-uri, PATCHes one that matches --name but lacks it (unioning, so another app's redirect survives), and creates only when there is nothing to reuse (--new forces a fresh one). --name IS the idempotency key. `client` auth is SITE-scoped (`wix token --site <msid>`) because minting is owner-of-that-site, and --yes gates every mutation: a site that already has a usable client resolves WITHOUT it, but --write-provisioning needs --yes even then because it rewrites a manifest on disk (the dry run's planned.provisioning names the file). That query endpoint IGNORES paging (measured: query.paging, cursorPaging and a top-level paging all return the full set at offset 0), so when pagingMetadata reports more clients than came back, `ensure` REFUSES EVERY outcome \u2014 create, patch AND reuse. Reuse is refused too because pickClient breaks ties on the OLDEST createdDate, so an omitted older same-named MOBILE client with the same redirect would win a later complete read and the resolved clientId would MOVE between runs \u2014 and it gets written into provisioning.json; convergence is what makes a stray duplicate untidy rather than harmful. --name cannot narrow the query (no filter is sent; the name is applied to the rows after they arrive), so the recovery is the dashboard; --new skips the query entirely. A `patched` result is verified against what Wix STORED \u2014 the redirect list is read off the PATCH response, and re-read via GET when the response omits it, because falling back to the list himi just sent would make the guard pass vacuously on exactly the silent no-op it exists to catch. `client list` is the read-only inventory of a site's clients: act on its `shippable` column rather than `hasRedirect`, because shippable ALSO requires a MOBILE applicationType and `ensure` refuses a WEB client \u2014 a WEB one carrying your redirect looks right and is not a candidate \u2014 and it sets truncated:true rather than presenting a partial inventory as the whole one. `analyze --read-only` returns API-only generation context as JSON (identity, access probes, CMS permissions and selected redacted Velo source); it needs no browser and never uploads or applies anything. A URL is optional there: `--url` lets it read the published page's Velo code-app ids (credential-free, pinned transport) so the backend source is found on sites where the owner code-app probe 404s. `analyze` reads a site into a business-book folder (REST + Playwright, GET-only); `--url` alone is the visitor-only pass over the published pages, and `--client-id` adds the vertical probes and the app binding `--apply` requires; `site function` list/get/put/publish/invokes that site's Velo HTTP functions and is not `himi functions` (serve-plane jobs). `--apply` bakes into a brandable shell (a site shell needs no `--client-id`: it is visitor-only and binds no client); `--shell` takes the same names `himi dist --shell` does and defaults to branded-lite, and a shell that ships no prepare:customer is refused by name rather than half-built. `--shell brandy` (the site shell, RFC 0062) also derives the site's page map from its published pages and header menu \u2014 Home first, up to four tabs for the pages a visitor returns to, the rest in the drawer \u2014 into the overlay's `site` block, so it can be edited before `--apply`; only a site shell ever receives that block. It never overwrites any shell's committed apps/<shell>/provisioning.json. `member-app set|clear|show <msid>` is the site's member app in Spaces (#4091): the himi app the site's members open in Spaces Lite instead of Branded Lite. `set --app <id>` takes the site's own app or one your account owns (an owned app not yet tied to the site is linked first; another account's app is refused, 403); `clear` returns the site to Branded Lite; `show` prints the pick plus the COMPUTED verdict \u2014 the picked release's requirements judged against the Spaces host manifest (checkHostCompatibility, `--platform` to judge one phone platform) \u2014 and `reason` when it falls back to Branded Lite. Auth is your `himi login` control token plus the account `wix token`, which the plane uses to verify you own the site.", required: "create <name> [--type wix|headless|branded-app|vibe] [--template <guid>] [--verticals stores,bookings,\u2026] [--folder <guid>] [--redirect-uri <uri>] [--no-oauth-app] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | list | client ensure|list --site <msid> [--name <name>] [--redirect-uri <uri>] [--new] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | analyze --read-only [--site <msid>] [--client-id <id>] [--url <https>] [--json] | analyze --url <https> [--client-id <id>] [--site <msid>] [--out <dir>] [--redirect-uri <uri>] [--apply] [--shell " + SHELL_ENUM + "] | function list|get|put|publish|invoke [--site <msid>] [--url <https>] [--method GET|POST|PUT|DELETE] [--source <file>] [--body <json>] [--publish] [--invoke] | member-app set|clear|show <msid> [--app <id>] [--platform ios|android]" },
|
|
184102
|
-
{ name: "base44", summary: "read a BASE44 app into an app book (book.json + BOOK.md) for the agent building a Himi app from it \u2014 the Base44 counterpart of `site analyze`, READ-ONLY. `analyze --url <published app>` is the VISITOR pass: the app id, name, favicon and colours from the published SPA, its router paths, and screenshots + look tokens from the Playwright crawl. `analyze --app-id <id>` adds the OWNER pass and needs a session: the project source under <out>/source/ (the read half of `base44 eject` \u2014 GET api/apps/<id>/eject \u2014 through the same deny-list and secret scan `himi push` uses, widened by the book's token shapes; `eject` itself is never run because it CREATES a copy of the app), every entity's JSON schema, required fields and RLS rules with up to --sample redacted rows (default 5, 0 = off), backend functions, agents, connectors (names and scopes only, never tokens), secret NAMES (never values), auth visibility + providers, and the route \u2192 component \u2192 entities map from the source router. Every chapter it could not read is listed in `gaps` rather than failing the run. `login` runs Base44's device sign-in and stores the session in ~/.himi/base44/session.json (never the repo; --from-base44-cli imports `npx base44 login`'s session instead); BASE44_ACCESS_TOKEN in the environment wins, for CI. `whoami` prints who is signed in (never the token); `logout` removes the stored session. `auth-check --url <tenant> --ios-app-id <PREFIX.bundle.id>` and/or `--android-package <package> --android-sha256 <fingerprint>` checks public native-login associations and prints missing entries; it never reads an owner token. --json prints the book itself. himi docs base44-app-context. `adopt` turns the book into a reviewable base44-entities.ts of ADOPTED entity + function declarations for config.ts (never edits config.ts, never overwrites); `entities query` is READ-ONLY and reports, per declared entity, ownership, row count and schema drift against the live app, plus foreign entities. `types` writes tier5-src/_shared/base44-entities.ts \u2014 a row type and a typed `entities<Row>()` handle per declared entity, byte-stable \u2014 and `himi validate` reports base44-types-stale when that file falls behind the block (nothing when it is absent). himi docs base44-entities. `screens` (base44-starter packages) writes one generated list + detail screen per declared entity over the template's shared engine, with write controls gated by the entity's rls; an unchanged config reports every file `unchanged`, a hand-edited generated file is `skipped-edited` unless --force; never calls Base44. himi docs base44-app-to-himi-app", required: "analyze (--url <https://\u2026> | --app-id <id>) [--out .himi/base44-book] [--sample <n>] [--json] | adopt [--book .himi/base44-book] [--entities A,B] [--write [path]] [--json] | entities query [--content <dir>] [--all] [--json] | types [--content <dir>] [--json] | screens [--content <dir>] [--force] [--dry-run] [--json] | login [--from-base44-cli] | whoami | logout | auth-check --url <https://tenant> [--ios-app-id <PREFIX.bundle.id>] [--android-package <package> --android-sha256 <fingerprint>]" },
|
|
184897
|
+
{ name: "base44", summary: "read a BASE44 app into an app book (book.json + BOOK.md) for the agent building a Himi app from it \u2014 the Base44 counterpart of `site analyze`, READ-ONLY. `analyze --url <published app>` is the VISITOR pass: the app id, name, favicon and colours from the published SPA, its router paths, and screenshots + look tokens from the Playwright crawl. `analyze --app-id <id>` adds the OWNER pass and needs a session: the project source under <out>/source/ (the read half of `base44 eject` \u2014 GET api/apps/<id>/eject \u2014 through the same deny-list and secret scan `himi push` uses, widened by the book's token shapes; `eject` itself is never run because it CREATES a copy of the app), every entity's JSON schema, required fields and RLS rules with up to --sample redacted rows (default 5, 0 = off), backend functions, agents, connectors (names and scopes only, never tokens), secret NAMES (never values), auth visibility + providers, and the route \u2192 component \u2192 entities map from the source router. Every chapter it could not read is listed in `gaps` rather than failing the run. `login` runs Base44's device sign-in and stores the session in ~/.himi/base44/session.json (never the repo; --from-base44-cli imports `npx base44 login`'s session instead); BASE44_ACCESS_TOKEN in the environment wins, for CI. `whoami` prints who is signed in (never the token); `logout` removes the stored session. `auth-check --url <tenant> --ios-app-id <PREFIX.bundle.id>` and/or `--android-package <package> --android-sha256 <fingerprint>` checks public native-login associations and prints missing entries; it never reads an owner token. --json prints the book itself. himi docs base44-app-context. `adopt` turns the book into a reviewable base44-entities.ts of ADOPTED entity + function declarations for config.ts (never edits config.ts, never overwrites); `entities query` is READ-ONLY and reports, per declared entity, ownership, row count and schema drift against the live app, plus foreign entities. `entities create` provisions the app's OWNED Himi<App>* entities: Base44's schema write is a destructive full-set sync, so the single PUT carries every entity in a freshly read eject snapshot (foreign ones verbatim) and the run refuses BEFORE sending when one would be dropped, the snapshot is unreadable or empty, or it moved since the plan; removing an owned field/entity needs --allow-destructive, rewriting owned RLS needs --apply-permissions. `entities seed` bulk-inserts seed rows into empty owned entities only (--ai writes base44-seed.json offline). `functions deploy` ships owned functions one PUT each, never the bulk sync or DELETE, and refuses a name deployed by someone else. All three print a plan and write only with --yes, which needs a `login --write` (apps:write) session. `types` writes tier5-src/_shared/base44-entities.ts \u2014 a row type and a typed `entities<Row>()` handle per declared entity, byte-stable \u2014 and `himi validate` reports base44-types-stale when that file falls behind the block (nothing when it is absent). himi docs base44-entities. `screens` (base44-starter packages) writes one generated list + detail screen per declared entity over the template's shared engine, with write controls gated by the entity's rls; an unchanged config reports every file `unchanged`, a hand-edited generated file is `skipped-edited` unless --force; never calls Base44. himi docs base44-app-to-himi-app", required: "analyze (--url <https://\u2026> | --app-id <id>) [--out .himi/base44-book] [--sample <n>] [--json] | adopt [--book .himi/base44-book] [--entities A,B] [--write [path]] [--json] | entities query [--content <dir>] [--all] [--json] | entities create [--app <a>] [--yes] [--allow-destructive] [--apply-permissions] [--empty-app-ok] | entities seed [--app <a>] [--yes] [--only A,B] [--ai] | functions deploy [--app <a>] [--yes] [--only a,b] | types [--content <dir>] [--json] | screens [--content <dir>] [--force] [--dry-run] [--json] | login [--write] [--from-base44-cli] | whoami | logout | auth-check --url <https://tenant> [--ios-app-id <PREFIX.bundle.id>] [--android-package <package> --android-sha256 <fingerprint>]" },
|
|
184103
184898
|
{ name: "doctor", summary: 'off-VPN preflight in one shot: probe the PUBLIC data plane (www.wixapis.com \u2014 reachable off-VPN), the INTERNAL serve/control plane for the selected target (VPN-gated), and report auth state (dpx session on disk + stored control token). --dpx additionally runs a live, EADDRINUSE-safe `dpx whoami`. Machine-readable with --json (an unreachable internal plane carries a stable code:"needs_vpn" so an agent branches on the code, not the prose); human-readable otherwise. Never loads the authoring runtime \u2014 works off-repo.', required: "[--target <t>] [--dpx] [--json] [--data-url <url>] [--timeout <ms>]" },
|
|
184104
184899
|
{ name: "upgrade", summary: "install the newest published CLI (`npm i -g @wix/himalaya-cli@latest`) and report what moved. This is the explicit door: himi also updates itself when the running build is more than a week old \u2014 unattended it just does it and re-runs your command, at a terminal it asks first \u2014 and `HIMI_NO_UPDATE_CHECK=1` turns that off, leaving this command as the way to catch up. Reports `unchanged` rather than claiming success when npm exits 0 without moving the version, which is what a registry mirror serving its own pinned copy looks like.", required: "[--json]" },
|
|
184105
184900
|
{ name: "push", summary: "lint + build + publish a release (default --draft: servable via ?release= but NOT live). REFUSES to publish on any error unless --force; --strict promotes warnings. Prints preview + agent-context links. A successful draft push also rebuilds the making-of (.himi/making-of.html, local and offline) and names it as `reel` \u2014 the file to hand the owner beside the preview link. Its postcard carries the home shot only when that shot is newer than the last source edit; a repeat draft's postcard adds what changed since the last one (\"Since the last draft: the home screen changed.\", from the release manifests' screen hashes, remembered in .himi/last-draft.json); otherwise the postcard says why and names `himi render <home> --png`, and the envelope's `postcardPicture: {skipped, render}` leads next[] with that render (the push never renders it itself). The published slug is NAMESPACED per owner \u2014 `<ownerPrefix>.<name>`, composed offline from the control token's ownerPrefix claim, so the CLI and the server derive the identical string and himalaya.content.json is NOT rewritten (a legacy token with no ownerPrefix publishes the declared name unchanged). An app claimed BEFORE namespacing is stored under its FLAT slug, so the claim route answers `alreadyYours` naming that slug and the push adopts it \u2014 reported as `adoptedSlug`, since it is the one case where the published `app` differs from what the declared name composes to. `--no-claim` skips the route that knows this, so a pre-namespacing app pushed with it still fails 403. --visibility public|unlisted decides whether /v1/apps + the Himi Player picker LIST the app (also declarable as `visibility` in himalaya.content.json; omitted, a brand-new app defaults to unlisted \u2014 share by link \u2014 and an existing setting is kept). --account-id names which account owns the app when your Wix session resolves to several (the auto-claim of a brand-new slug cannot guess \u2014 without it a multi-account caller is told to name one). An unforced push of a release that carries SCREENS also refuses when `.himi/ux-audit.json` holds no mobile-UX drive recorded against that release id, or holds one that FAILED (#2955) \u2014 a published draft IS the owner-private preview a customer is handed; `himi ux record` clears it and `--force` overrides it, which the success envelope then says out loud. `--only <selector>` publishes ONLY the named items as a release derived from the app's live release (or `--from-release <id>`), running the identical build + lint gate and simply publishing less; it requires an explicit `--draft` or `--live` because a partial publish has no safe default, never claims a slug, and carries neither attestation nor a source archive (both named in the output). Selectors are comma-separated in ONE `--only`: `changed` (every item whose bytes differ from the base), `screen:<id|glob>`, `bundle:<name>`, `tokens`, `app-config` \u2014 a selected screen drags its logic bundle and a selected bundle drags the screens that reference it, or the bytes land under a key nothing reads. The plane REFUSES (409 binary_capability_gap) a release declaring a PERMISSION-BEARING capability (iOS usage string or entitlement, Android permission \u2014 camera, location, push, \u2026) that the app's last successful `himi dist` was not built with: an OTA push cannot add an OS permission, and on iOS asking for one whose purpose string is missing kills the app. Run `himi dist` first, or pass `--allow-binary-gap` when every installed binary already carries it \u2014 recorded on the release as `allowedBinaryGap`. A gap in a permission-free capability (share, clipboard, \u2026) stays the `needsBinary` advice.", required: "[--content <dir>] [--draft] [--live] [--force] [--strict] [--label] [--notes] [--visibility public|unlisted] [--allow-binary-gap] [--no-claim] [--account-id <id>] [--only <selector>] [--from-release <id>] [--accept-regressions] [--accept-partial] [--app <slug>] (--control-token)" },
|
|
@@ -184141,7 +184936,7 @@ var COMMANDS2 = [
|
|
|
184141
184936
|
];
|
|
184142
184937
|
function cliVersion() {
|
|
184143
184938
|
try {
|
|
184144
|
-
return JSON.parse(
|
|
184939
|
+
return JSON.parse(readFileSync109(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
|
|
184145
184940
|
} catch {
|
|
184146
184941
|
return "unknown";
|
|
184147
184942
|
}
|
|
@@ -184266,7 +185061,7 @@ function ageInDays(publishedAt, now = Date.now()) {
|
|
|
184266
185061
|
}
|
|
184267
185062
|
function packageVersion(path2) {
|
|
184268
185063
|
try {
|
|
184269
|
-
const version4 = JSON.parse(
|
|
185064
|
+
const version4 = JSON.parse(readFileSync109(path2, "utf8")).version;
|
|
184270
185065
|
return typeof version4 === "string" && version4 ? version4 : void 0;
|
|
184271
185066
|
} catch {
|
|
184272
185067
|
return void 0;
|
|
@@ -184275,7 +185070,7 @@ function packageVersion(path2) {
|
|
|
184275
185070
|
function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
|
|
184276
185071
|
let dir = resolve65(fromDir);
|
|
184277
185072
|
for (; ; ) {
|
|
184278
|
-
const version4 = packageVersion(
|
|
185073
|
+
const version4 = packageVersion(join94(dir, "node_modules", "@wix", "himalaya", "package.json"));
|
|
184279
185074
|
if (version4) return { version: version4, source: "local" };
|
|
184280
185075
|
const parent = dirname51(dir);
|
|
184281
185076
|
if (parent === dir) break;
|
|
@@ -184285,7 +185080,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
|
|
|
184285
185080
|
if (bundled) return { version: bundled, source: "bundled" };
|
|
184286
185081
|
try {
|
|
184287
185082
|
const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
184288
|
-
const version4 = root ? packageVersion(
|
|
185083
|
+
const version4 = root ? packageVersion(join94(root, "@wix", "himalaya", "package.json")) : void 0;
|
|
184289
185084
|
return version4 ? { version: version4, source: "global" } : {};
|
|
184290
185085
|
} catch {
|
|
184291
185086
|
return {};
|
|
@@ -184332,11 +185127,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
|
|
|
184332
185127
|
var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
|
|
184333
185128
|
var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
|
|
184334
185129
|
function updateCachePath(env = process.env) {
|
|
184335
|
-
return env.HIMI_UPDATE_CACHE_FILE ??
|
|
185130
|
+
return env.HIMI_UPDATE_CACHE_FILE ?? join94(homedir14(), ".himalaya", "update-check.json");
|
|
184336
185131
|
}
|
|
184337
185132
|
function readUpdateCache(path2) {
|
|
184338
185133
|
try {
|
|
184339
|
-
const parsed = JSON.parse(
|
|
185134
|
+
const parsed = JSON.parse(readFileSync109(path2, "utf8"));
|
|
184340
185135
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
184341
185136
|
} catch {
|
|
184342
185137
|
return {};
|
|
@@ -184345,7 +185140,7 @@ function readUpdateCache(path2) {
|
|
|
184345
185140
|
function writeUpdateCache(path2, cache) {
|
|
184346
185141
|
try {
|
|
184347
185142
|
mkdirSync44(dirname51(path2), { recursive: true, mode: 448 });
|
|
184348
|
-
|
|
185143
|
+
writeFileSync44(path2, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
|
|
184349
185144
|
} catch {
|
|
184350
185145
|
}
|
|
184351
185146
|
}
|
|
@@ -184405,12 +185200,12 @@ function createUpdateRunner(spawn8 = spawnSync5) {
|
|
|
184405
185200
|
},
|
|
184406
185201
|
installedVersion: () => {
|
|
184407
185202
|
const root = globalNodeModulesRoot();
|
|
184408
|
-
return root ? packageVersion(
|
|
185203
|
+
return root ? packageVersion(join94(root, "@wix", "himalaya-cli", "package.json")) : void 0;
|
|
184409
185204
|
},
|
|
184410
185205
|
reexec: (argv) => {
|
|
184411
185206
|
const root = globalNodeModulesRoot();
|
|
184412
|
-
const entry = root ?
|
|
184413
|
-
if (!entry || !
|
|
185207
|
+
const entry = root ? join94(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
|
|
185208
|
+
if (!entry || !existsSync88(entry)) return void 0;
|
|
184414
185209
|
const result = spawnSync5(process.execPath, [entry, ...argv], {
|
|
184415
185210
|
// inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
|
|
184416
185211
|
stdio: "inherit",
|
|
@@ -184457,7 +185252,7 @@ function staleUpdateLockFile(cachePath, now) {
|
|
|
184457
185252
|
for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
|
|
184458
185253
|
let content;
|
|
184459
185254
|
try {
|
|
184460
|
-
content =
|
|
185255
|
+
content = readFileSync109(path2, "utf8");
|
|
184461
185256
|
} catch {
|
|
184462
185257
|
continue;
|
|
184463
185258
|
}
|
|
@@ -184480,14 +185275,14 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
|
|
|
184480
185275
|
const mine = lockStamp(now);
|
|
184481
185276
|
const readLock = (path2) => {
|
|
184482
185277
|
try {
|
|
184483
|
-
return
|
|
185278
|
+
return readFileSync109(path2, "utf8");
|
|
184484
185279
|
} catch {
|
|
184485
185280
|
return void 0;
|
|
184486
185281
|
}
|
|
184487
185282
|
};
|
|
184488
185283
|
const tryCreate = (path2) => {
|
|
184489
185284
|
try {
|
|
184490
|
-
|
|
185285
|
+
writeFileSync44(path2, mine, { flag: "wx", mode: 384 });
|
|
184491
185286
|
return true;
|
|
184492
185287
|
} catch {
|
|
184493
185288
|
return false;
|
|
@@ -185072,7 +185867,7 @@ function executableOnPath(name, env = process.env) {
|
|
|
185072
185867
|
const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
185073
185868
|
for (const dir of entries) {
|
|
185074
185869
|
for (const suffix of suffixes) {
|
|
185075
|
-
const candidate =
|
|
185870
|
+
const candidate = join94(dir, `${name}${suffix}`);
|
|
185076
185871
|
try {
|
|
185077
185872
|
if (!statSync23(candidate).isFile()) continue;
|
|
185078
185873
|
if (process.platform !== "win32") accessSync(candidate, constants5.X_OK);
|
|
@@ -185181,7 +185976,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
185181
185976
|
const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths2(), paths_exports));
|
|
185182
185977
|
const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
|
|
185183
185978
|
const iosYmlPath = iosProjectYml2(app);
|
|
185184
|
-
const iosYml =
|
|
185979
|
+
const iosYml = existsSync88(iosYmlPath) ? readFileSync109(iosYmlPath, "utf8") : "";
|
|
185185
185980
|
let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
|
|
185186
185981
|
if (!optedIn) {
|
|
185187
185982
|
const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
|
|
@@ -185195,14 +185990,14 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
185195
185990
|
}
|
|
185196
185991
|
function readConfigSource(dir) {
|
|
185197
185992
|
try {
|
|
185198
|
-
return
|
|
185993
|
+
return readFileSync109(join94(dir, "config.ts"), "utf8");
|
|
185199
185994
|
} catch {
|
|
185200
185995
|
return null;
|
|
185201
185996
|
}
|
|
185202
185997
|
}
|
|
185203
185998
|
function writePngFile(path2, base64) {
|
|
185204
185999
|
mkdirSync44(dirname51(path2), { recursive: true });
|
|
185205
|
-
|
|
186000
|
+
writeFileSync44(path2, Buffer.from(base64, "base64"));
|
|
185206
186001
|
return path2;
|
|
185207
186002
|
}
|
|
185208
186003
|
async function seedAgentFilesFor(dir, flags, mode = "init") {
|
|
@@ -185249,7 +186044,7 @@ var NoBase44SlotError = class extends Error {
|
|
|
185249
186044
|
};
|
|
185250
186045
|
async function initFromRemoteTemplate(name, parentDir, template, c2, opts = {}) {
|
|
185251
186046
|
const dir = resolve65(parentDir, name);
|
|
185252
|
-
if (
|
|
186047
|
+
if (existsSync88(join94(dir, "himalaya.content.json"))) {
|
|
185253
186048
|
throw new Error(`content package already exists at ${dir}`);
|
|
185254
186049
|
}
|
|
185255
186050
|
const r2 = await c2.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
|
|
@@ -185282,7 +186077,7 @@ function renameRestoredSource(restored, declaredApp, renamed) {
|
|
|
185282
186077
|
function symlinkDestinationIssue(dest) {
|
|
185283
186078
|
let kind;
|
|
185284
186079
|
try {
|
|
185285
|
-
kind =
|
|
186080
|
+
kind = lstatSync23(dest);
|
|
185286
186081
|
} catch {
|
|
185287
186082
|
return null;
|
|
185288
186083
|
}
|
|
@@ -185295,7 +186090,7 @@ function symlinkDestinationIssue(dest) {
|
|
|
185295
186090
|
function restoreDestinationIssue(dest, force) {
|
|
185296
186091
|
const link = symlinkDestinationIssue(dest);
|
|
185297
186092
|
if (link) return link;
|
|
185298
|
-
if (!
|
|
186093
|
+
if (!existsSync88(dest)) return null;
|
|
185299
186094
|
if (!statSync23(dest).isDirectory()) {
|
|
185300
186095
|
return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
|
|
185301
186096
|
}
|
|
@@ -185310,7 +186105,7 @@ function restoreDestinationIssue(dest, force) {
|
|
|
185310
186105
|
function isHimalayaMonorepoCheckout(start) {
|
|
185311
186106
|
let dir = resolve65(start);
|
|
185312
186107
|
for (; ; ) {
|
|
185313
|
-
if (
|
|
186108
|
+
if (existsSync88(join94(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync88(join94(dir, "core", "serve", "src", "server.ts"))) return true;
|
|
185314
186109
|
const parent = dirname51(dir);
|
|
185315
186110
|
if (parent === dir) return false;
|
|
185316
186111
|
dir = parent;
|
|
@@ -185371,7 +186166,7 @@ function materializeForPreview(appDir3, slug, displayName3) {
|
|
|
185371
186166
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
185372
186167
|
);
|
|
185373
186168
|
const repoRoot2 = resolve65(fileURLToPath29(new URL("../../..", import.meta.url)));
|
|
185374
|
-
const root =
|
|
186169
|
+
const root = join94(repoRoot2, "node_modules", ".cache", "himi-template-preview");
|
|
185375
186170
|
const stillRunning = (pid) => {
|
|
185376
186171
|
try {
|
|
185377
186172
|
process.kill(pid, 0);
|
|
@@ -185385,12 +186180,12 @@ function materializeForPreview(appDir3, slug, displayName3) {
|
|
|
185385
186180
|
if (!entry.isDirectory()) continue;
|
|
185386
186181
|
const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
|
|
185387
186182
|
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
|
|
185388
|
-
rmSync24(
|
|
186183
|
+
rmSync24(join94(root, entry.name), { recursive: true, force: true });
|
|
185389
186184
|
}
|
|
185390
186185
|
}
|
|
185391
186186
|
} catch {
|
|
185392
186187
|
}
|
|
185393
|
-
const dest =
|
|
186188
|
+
const dest = join94(root, `${slug}-${process.pid}`);
|
|
185394
186189
|
rmSync24(dest, { recursive: true, force: true });
|
|
185395
186190
|
mkdirSync44(dest, { recursive: true });
|
|
185396
186191
|
try {
|
|
@@ -185403,8 +186198,8 @@ function materializeForPreview(appDir3, slug, displayName3) {
|
|
|
185403
186198
|
}
|
|
185404
186199
|
async function appId(dir) {
|
|
185405
186200
|
try {
|
|
185406
|
-
const { readFileSync:
|
|
185407
|
-
const m2 = JSON.parse(
|
|
186201
|
+
const { readFileSync: readFileSync110 } = await import("node:fs");
|
|
186202
|
+
const m2 = JSON.parse(readFileSync110(join94(dir, "himalaya.content.json"), "utf8"));
|
|
185408
186203
|
if (m2.name) return m2.name;
|
|
185409
186204
|
} catch {
|
|
185410
186205
|
}
|
|
@@ -185412,8 +186207,8 @@ async function appId(dir) {
|
|
|
185412
186207
|
}
|
|
185413
186208
|
async function contentVisibility(dir) {
|
|
185414
186209
|
try {
|
|
185415
|
-
const { readFileSync:
|
|
185416
|
-
const m2 = JSON.parse(
|
|
186210
|
+
const { readFileSync: readFileSync110 } = await import("node:fs");
|
|
186211
|
+
const m2 = JSON.parse(readFileSync110(join94(dir, "himalaya.content.json"), "utf8"));
|
|
185417
186212
|
if (m2.visibility === "public" || m2.visibility === "unlisted") return m2.visibility;
|
|
185418
186213
|
} catch {
|
|
185419
186214
|
}
|
|
@@ -185596,8 +186391,8 @@ Guides in your browser: ${idx.portalUrl}`);
|
|
|
185596
186391
|
const sdks = loadSdkReference();
|
|
185597
186392
|
const arg = pos[1];
|
|
185598
186393
|
if (arg) {
|
|
185599
|
-
const
|
|
185600
|
-
const want =
|
|
186394
|
+
const canonical6 = arg.replace(/^@wix\/himalaya\//, "@himalaya/");
|
|
186395
|
+
const want = canonical6.startsWith("@himalaya/") ? canonical6 : `@himalaya/${canonical6}`;
|
|
185601
186396
|
const s2 = sdks.find((x2) => x2.name === want || x2.name === arg);
|
|
185602
186397
|
if (!s2) {
|
|
185603
186398
|
io2.error(JSON.stringify({ error: `unknown sdk: ${arg}`, sdks: sdks.map((x2) => x2.name) }));
|
|
@@ -185705,7 +186500,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
|
|
|
185705
186500
|
...res.removed.length ? { removed: res.removed, note: "older copies at the app root, moved to .himi/legacy-agent-files/ (a backup, in case one became app code) \u2014 the current ones live in .agents/skills/himalaya/" } : {},
|
|
185706
186501
|
// In a git repo the refresh moves the diff identity an earlier `himi test` attested (that
|
|
185707
186502
|
// hash is shared with the repo gates and deliberately exempts nothing but its own metadata).
|
|
185708
|
-
...
|
|
186503
|
+
...existsSync88(join94(dir, ".himi", "attestations", "latest.json")) ? { next: "if `himi push` then refuses the attestation as stale, re-run `himi test` \u2014 in a git checkout this refresh changed the tree it covered" } : {},
|
|
185709
186504
|
...res.skipped.length ? { skipped: res.skipped } : {},
|
|
185710
186505
|
portalUrl: idx.portalUrl
|
|
185711
186506
|
});
|
|
@@ -185728,7 +186523,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
|
|
|
185728
186523
|
try {
|
|
185729
186524
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
185730
186525
|
const bres = await buildContentForValidation2(dir, { resolution });
|
|
185731
|
-
out2 = mkdtempSync6(
|
|
186526
|
+
out2 = mkdtempSync6(join94(tmpdir7(), "himi-ux-record-"));
|
|
185732
186527
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
185733
186528
|
const outcome = await buildReleaseFromContent2(dir, out2, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
|
|
185734
186529
|
const releaseId = outcome.manifest.releaseId;
|
|
@@ -185900,14 +186695,14 @@ async function producedWidgetFamilies(dir) {
|
|
|
185900
186695
|
} catch {
|
|
185901
186696
|
return { families: void 0, source: "unbuilt" };
|
|
185902
186697
|
}
|
|
185903
|
-
const
|
|
186698
|
+
const names2 = [...tier5Dir.servedBundleNames(outDir)];
|
|
185904
186699
|
const families = /* @__PURE__ */ new Set();
|
|
185905
186700
|
const emitted = /* @__PURE__ */ new Set();
|
|
185906
|
-
for (const name of
|
|
186701
|
+
for (const name of names2) {
|
|
185907
186702
|
let js2;
|
|
185908
186703
|
for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
|
|
185909
186704
|
try {
|
|
185910
|
-
js2 =
|
|
186705
|
+
js2 = readFileSync109(join94(outDir, candidate), "utf8");
|
|
185911
186706
|
break;
|
|
185912
186707
|
} catch {
|
|
185913
186708
|
}
|
|
@@ -185938,7 +186733,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
185938
186733
|
}
|
|
185939
186734
|
return { families, source: "dist/bundles" };
|
|
185940
186735
|
}
|
|
185941
|
-
var boardOpen = (dir) =>
|
|
186736
|
+
var boardOpen = (dir) => existsSync88(join94(dir, ".himi", "studio", "index.html"));
|
|
185942
186737
|
var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
|
|
185943
186738
|
async function leaveForBoard(dir, record2, value) {
|
|
185944
186739
|
if (!boardOpen(dir)) return;
|
|
@@ -185962,7 +186757,7 @@ async function liveMapFor(dir) {
|
|
|
185962
186757
|
}
|
|
185963
186758
|
var commandScratch = new AsyncLocalStorage2();
|
|
185964
186759
|
function commandScratchDir(prefix) {
|
|
185965
|
-
const dir = mkdtempSync6(
|
|
186760
|
+
const dir = mkdtempSync6(join94(tmpdir7(), prefix));
|
|
185966
186761
|
commandScratch.getStore()?.push(dir);
|
|
185967
186762
|
return dir;
|
|
185968
186763
|
}
|
|
@@ -186316,7 +187111,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
186316
187111
|
const owed = openApprovals2(readApprovals2(dir).events).length;
|
|
186317
187112
|
next.push(`carried the planning journal into the app (${carried.join(", ")}${owed ? `; ${owed} approval${owed === 1 ? "" : "s"} still owed` : ""}) \u2014 \`himi progress --brief\` there shows it`);
|
|
186318
187113
|
}
|
|
186319
|
-
const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f2) =>
|
|
187114
|
+
const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f2) => existsSync88(join94(parentDir, f2)));
|
|
186320
187115
|
if (planInParent.length) {
|
|
186321
187116
|
next.push(`${planInParent.join(" and ")} in ${parentDir} ${planInParent.length > 1 ? "are" : "is"} not the app's \u2014 if that is the approved plan, move it over the template's boilerplate in ${dir}`);
|
|
186322
187117
|
}
|
|
@@ -186477,13 +187272,13 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
|
|
|
186477
187272
|
if (adding) {
|
|
186478
187273
|
const from = str10(flags.from);
|
|
186479
187274
|
if (!from) throw new TrimRefusal2('--add <id> needs --from <file> holding the whole new SCREENS entry (` "<id>": { "screenId": "<id>", \u2026 },`)');
|
|
186480
|
-
print(adopt.addScreen(dir, adding,
|
|
187275
|
+
print(adopt.addScreen(dir, adding, readFileSync109(from, "utf8"), { parent: str10(flags.parent), tab: str10(flags.tab), displayName: str10(flags["display-name"]) }));
|
|
186481
187276
|
return 0;
|
|
186482
187277
|
}
|
|
186483
187278
|
if (target) {
|
|
186484
187279
|
const from = str10(flags.from);
|
|
186485
187280
|
if (!from) throw new TrimRefusal2("--write <id> needs --from <file> holding the whole entry, as --show prints it");
|
|
186486
|
-
print(adopt.replaceScreen(dir, target,
|
|
187281
|
+
print(adopt.replaceScreen(dir, target, readFileSync109(from, "utf8")));
|
|
186487
187282
|
return 0;
|
|
186488
187283
|
}
|
|
186489
187284
|
if (show) {
|
|
@@ -186565,7 +187360,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
|
|
|
186565
187360
|
const { keepFromSpec: keepFromSpec2 } = await Promise.resolve().then(() => (init_template_adopt(), template_adopt_exports));
|
|
186566
187361
|
const dir = contentDir(flags);
|
|
186567
187362
|
try {
|
|
186568
|
-
const spec = keepFromSpec2(dir, str10(flags["from-spec"]) ??
|
|
187363
|
+
const spec = keepFromSpec2(dir, str10(flags["from-spec"]) ?? join94(dir, "SPEC.md"));
|
|
186569
187364
|
const own5 = typeof keep === "string" ? keep.split(",").map((k2) => k2.trim()).filter(Boolean) : [];
|
|
186570
187365
|
keep = [.../* @__PURE__ */ new Set([...spec.keep, ...own5])].join(",");
|
|
186571
187366
|
fromSpec = { fromSpec: {
|
|
@@ -186606,7 +187401,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
|
|
|
186606
187401
|
const result = { ...outcome.result, ...fromSpec };
|
|
186607
187402
|
const adoptDir = contentDir(flags);
|
|
186608
187403
|
const kept = flags["dry-run"] !== true && (outcome.code === 0 || outcome.result.forcedKeep === true);
|
|
186609
|
-
if (kept &&
|
|
187404
|
+
if (kept && existsSync88(join94(adoptDir, adoptBits.ADOPT_FILE))) {
|
|
186610
187405
|
try {
|
|
186611
187406
|
const inv = adoptBits.inspectApp(adoptDir);
|
|
186612
187407
|
adoptBits.writeInventory(adoptDir, inv, { companions: "if-missing" });
|
|
@@ -186635,7 +187430,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
|
|
|
186635
187430
|
const sourceDir = resolve65(str10(flags["source-dir"]) ?? appDir3);
|
|
186636
187431
|
let meta;
|
|
186637
187432
|
try {
|
|
186638
|
-
meta = JSON.parse(
|
|
187433
|
+
meta = JSON.parse(readFileSync109(join94(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
186639
187434
|
} catch {
|
|
186640
187435
|
io2.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
|
|
186641
187436
|
return 2;
|
|
@@ -186645,7 +187440,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
|
|
|
186645
187440
|
return 2;
|
|
186646
187441
|
}
|
|
186647
187442
|
try {
|
|
186648
|
-
const appearance = extractTemplateAppearance(JSON.parse(
|
|
187443
|
+
const appearance = extractTemplateAppearance(JSON.parse(readFileSync109(join94(sourceDir, "tokens.json"), "utf8")));
|
|
186649
187444
|
meta = { ...appearance, ...meta };
|
|
186650
187445
|
} catch {
|
|
186651
187446
|
}
|
|
@@ -186667,7 +187462,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
|
|
|
186667
187462
|
const force = flags.force === true;
|
|
186668
187463
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
186669
187464
|
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
186670
|
-
const out2 = mkdtempSync6(
|
|
187465
|
+
const out2 = mkdtempSync6(join94(tmpdir7(), "himi-template-"));
|
|
186671
187466
|
publishScratch.push(out2);
|
|
186672
187467
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
186673
187468
|
const outcome = await buildReleaseFromContent2(buildDir, out2, {
|
|
@@ -186729,7 +187524,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
|
|
|
186729
187524
|
let iconHash;
|
|
186730
187525
|
if (iconPath) {
|
|
186731
187526
|
try {
|
|
186732
|
-
const bytes2 =
|
|
187527
|
+
const bytes2 = readFileSync109(iconPath);
|
|
186733
187528
|
payload.icon = bytes2.toString("base64");
|
|
186734
187529
|
iconHash = createHash46("sha256").update(bytes2).digest("hex");
|
|
186735
187530
|
} catch {
|
|
@@ -187034,7 +187829,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
|
|
|
187034
187829
|
const path2 = dpxSessionTokenPath();
|
|
187035
187830
|
let raw;
|
|
187036
187831
|
try {
|
|
187037
|
-
raw =
|
|
187832
|
+
raw = readFileSync109(path2, "utf8");
|
|
187038
187833
|
} catch {
|
|
187039
187834
|
throw new Error(`no DPX BO session at ${path2}; run dpx auth login, write dpx auth token to that path, then himi login --dpx --target bo`);
|
|
187040
187835
|
}
|
|
@@ -187168,8 +187963,8 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
|
|
|
187168
187963
|
const dir = resolve65(out2);
|
|
187169
187964
|
const files = himiPluginFiles2(skills.skillMd);
|
|
187170
187965
|
for (const f2 of files) {
|
|
187171
|
-
mkdirSync44(dirname51(
|
|
187172
|
-
|
|
187966
|
+
mkdirSync44(dirname51(join94(dir, f2.path)), { recursive: true });
|
|
187967
|
+
writeFileSync44(join94(dir, f2.path), f2.text);
|
|
187173
187968
|
}
|
|
187174
187969
|
print({ ok: true, dir, files: files.map((f2) => f2.path), next: [`claude plugin validate ${dir}`, `claude --plugin-dir ${dir}`] });
|
|
187175
187970
|
return 0;
|
|
@@ -187186,16 +187981,16 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
|
|
|
187186
187981
|
case "studio": {
|
|
187187
187982
|
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
187188
187983
|
const dir = contentDir(flags);
|
|
187189
|
-
if (!
|
|
187984
|
+
if (!existsSync88(join94(dir, "himalaya.content.json"))) {
|
|
187190
187985
|
io2.error(JSON.stringify({ ok: false, error: "not_a_content_package", dir, hint: "run from the app directory (or pass --content <dir>) \u2014 the board reads that package's .himi/" }));
|
|
187191
187986
|
return 2;
|
|
187192
187987
|
}
|
|
187193
187988
|
if (pos[1] === "reel") {
|
|
187194
187989
|
const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
|
|
187195
|
-
const out2 = resolve65(str10(flags.out) ??
|
|
187990
|
+
const out2 = resolve65(str10(flags.out) ?? join94(dir, ".himi", "making-of.html"));
|
|
187196
187991
|
const { html, plan } = buildReel2(dir);
|
|
187197
187992
|
mkdirSync44(dirname51(out2), { recursive: true });
|
|
187198
|
-
|
|
187993
|
+
writeFileSync44(out2, html);
|
|
187199
187994
|
const { pathToFileURL: pathToFileURL9 } = await import("node:url");
|
|
187200
187995
|
const url2 = pathToFileURL9(out2).href;
|
|
187201
187996
|
const open2 = flags["no-open"] !== true;
|
|
@@ -187264,7 +188059,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
|
|
|
187264
188059
|
} = await Promise.resolve().then(() => (init_progress(), progress_exports));
|
|
187265
188060
|
const dir = contentDir(flags);
|
|
187266
188061
|
const journal2 = journalPath2(dir);
|
|
187267
|
-
const isContentPackage =
|
|
188062
|
+
const isContentPackage = existsSync88(join94(dir, "himalaya.content.json"));
|
|
187268
188063
|
const hint = isContentPackage ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
|
|
187269
188064
|
const message = pos.slice(1).join(" ").trim();
|
|
187270
188065
|
const approvalFlags = ["approve", "done", "drop"].filter((f2) => flags[f2] !== void 0);
|
|
@@ -187416,7 +188211,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
|
|
|
187416
188211
|
case "test": {
|
|
187417
188212
|
const dir = contentDir(flags);
|
|
187418
188213
|
const structuredOutput = flags.json === true || io2.isTTY !== true;
|
|
187419
|
-
if (
|
|
188214
|
+
if (existsSync88(join94(dir, "functions"))) {
|
|
187420
188215
|
const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
|
|
187421
188216
|
const loaded = await loadFunctionsApp2(dir);
|
|
187422
188217
|
const results = [];
|
|
@@ -187548,7 +188343,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
|
|
|
187548
188343
|
io2.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
|
|
187549
188344
|
return 2;
|
|
187550
188345
|
}
|
|
187551
|
-
const sources = collectWorkerSources2(
|
|
188346
|
+
const sources = collectWorkerSources2(join94(dir, "tier5-src"), screen.bundleName);
|
|
187552
188347
|
if (!sources) {
|
|
187553
188348
|
io2.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
|
|
187554
188349
|
return 2;
|
|
@@ -187728,7 +188523,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
|
|
|
187728
188523
|
const sp = await runShotsPass2({
|
|
187729
188524
|
descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
|
|
187730
188525
|
tokens: outcome.tokens,
|
|
187731
|
-
outDir:
|
|
188526
|
+
outDir: join94(dir, ".himi", "shots"),
|
|
187732
188527
|
width: 390,
|
|
187733
188528
|
layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {}, ...base44Data ? { base44Data } : {} },
|
|
187734
188529
|
...budgetMs ? { budgetMs } : {},
|
|
@@ -187768,7 +188563,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
|
|
|
187768
188563
|
releaseId: result.releaseId,
|
|
187769
188564
|
releasePayload: release2,
|
|
187770
188565
|
descriptors: attestedDescriptors,
|
|
187771
|
-
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""),
|
|
188566
|
+
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join94(dir, ".himi", "shots", name)])),
|
|
187772
188567
|
coverage: {
|
|
187773
188568
|
screens: crawledScreens.size,
|
|
187774
188569
|
actionsDispatched: result.actions.exercised,
|
|
@@ -187893,7 +188688,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
|
|
|
187893
188688
|
return 2;
|
|
187894
188689
|
}
|
|
187895
188690
|
try {
|
|
187896
|
-
const raw = stateArg.trim().startsWith("{") ? stateArg :
|
|
188691
|
+
const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync109(stateArg.replace(/^@/, ""), "utf8");
|
|
187897
188692
|
injectedState = JSON.parse(raw);
|
|
187898
188693
|
} catch (e2) {
|
|
187899
188694
|
io2.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e2.message}` }));
|
|
@@ -187908,7 +188703,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
|
|
|
187908
188703
|
return 2;
|
|
187909
188704
|
}
|
|
187910
188705
|
try {
|
|
187911
|
-
const raw = inputArg.trim().startsWith("{") ? inputArg :
|
|
188706
|
+
const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync109(inputArg.replace(/^@/, ""), "utf8");
|
|
187912
188707
|
const parsed = JSON.parse(raw);
|
|
187913
188708
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
|
|
187914
188709
|
injectedInput = parsed;
|
|
@@ -187991,7 +188786,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
|
|
|
187991
188786
|
const diagnostics = (outcome.lint ?? []).find((s2) => s2.screenId === screenId)?.issues ?? [];
|
|
187992
188787
|
let pngFile;
|
|
187993
188788
|
let attestationPngFile;
|
|
187994
|
-
const shotPath =
|
|
188789
|
+
const shotPath = join94(dir, ".himi", "shots", `${screenId}.png`);
|
|
187995
188790
|
const pngTarget = typeof flags.png === "string" ? str10(flags.png) : flags.png === true ? shotPath : void 0;
|
|
187996
188791
|
if (pngTarget && r2.pngBase64) {
|
|
187997
188792
|
pngFile = writePngFile(pngTarget, r2.pngBase64);
|
|
@@ -188213,14 +189008,14 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
|
|
|
188213
189008
|
return report3(res.status, { wrote: res.wrote });
|
|
188214
189009
|
}
|
|
188215
189010
|
if (sub === "glyphs") {
|
|
188216
|
-
const
|
|
189011
|
+
const names2 = glyphNames2();
|
|
188217
189012
|
if (flags.json === true) {
|
|
188218
|
-
print({ ok: true, count:
|
|
189013
|
+
print({ ok: true, count: names2.length, default: DEFAULT_GLYPH2, glyphs: names2 });
|
|
188219
189014
|
return 0;
|
|
188220
189015
|
}
|
|
188221
189016
|
io2.log(
|
|
188222
|
-
`${
|
|
188223
|
-
${
|
|
189017
|
+
`${names2.length} glyphs for \`himi icon generate --glyph\`:
|
|
189018
|
+
${names2.join(", ")}
|
|
188224
189019
|
default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so the tile does not assert a business the app is not in`
|
|
188225
189020
|
);
|
|
188226
189021
|
return 0;
|
|
@@ -188325,14 +189120,14 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
188325
189120
|
}
|
|
188326
189121
|
case "icons": {
|
|
188327
189122
|
const { knownIconNames } = await loadAuthoring();
|
|
188328
|
-
const
|
|
189123
|
+
const names2 = [...knownIconNames].sort();
|
|
188329
189124
|
if (flags.json === true) {
|
|
188330
|
-
print({ ok: true, count:
|
|
189125
|
+
print({ ok: true, count: names2.length, icons: names2 });
|
|
188331
189126
|
return 0;
|
|
188332
189127
|
}
|
|
188333
|
-
io2.log(`${
|
|
189128
|
+
io2.log(`${names2.length} icon names \u2014 use one as Icon.name (an unknown name renders a fallback glyph):
|
|
188334
189129
|
`);
|
|
188335
|
-
io2.log(
|
|
189130
|
+
io2.log(names2.join(" "));
|
|
188336
189131
|
return 0;
|
|
188337
189132
|
}
|
|
188338
189133
|
case "pull": {
|
|
@@ -188350,7 +189145,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
188350
189145
|
io2.error(JSON.stringify(linked));
|
|
188351
189146
|
return 1;
|
|
188352
189147
|
}
|
|
188353
|
-
if (
|
|
189148
|
+
if (existsSync88(dest)) {
|
|
188354
189149
|
if (!statSync23(dest).isDirectory()) {
|
|
188355
189150
|
io2.error(JSON.stringify({
|
|
188356
189151
|
error: `${dest} exists and is not a directory`,
|
|
@@ -188363,7 +189158,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
188363
189158
|
io2.error(JSON.stringify({ error: `${dest} already exists and is not empty`, hint: "pass --force to write into it anyway (merging, and naming what it keeps), --replace to restore exactly what was archived, or --out/--name to land somewhere else" }));
|
|
188364
189159
|
return 1;
|
|
188365
189160
|
}
|
|
188366
|
-
if (replace && occupied && !
|
|
189161
|
+
if (replace && occupied && !existsSync88(join94(dest, "himalaya.content.json"))) {
|
|
188367
189162
|
io2.error(JSON.stringify({
|
|
188368
189163
|
error: `${dest} is not a content package \u2014 refusing to --replace it`,
|
|
188369
189164
|
hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
|
|
@@ -189076,7 +189871,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
189076
189871
|
}
|
|
189077
189872
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
189078
189873
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
189079
|
-
const built = mkdtempSync6(
|
|
189874
|
+
const built = mkdtempSync6(join94(tmpdir7(), "himi-pack-"));
|
|
189080
189875
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
189081
189876
|
const outcome = await buildReleaseFromContent2(dir, built, {
|
|
189082
189877
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -189289,7 +190084,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
189289
190084
|
}));
|
|
189290
190085
|
return 1;
|
|
189291
190086
|
}
|
|
189292
|
-
const archive =
|
|
190087
|
+
const archive = readFileSync109(resolve65(file2));
|
|
189293
190088
|
const result = await client2().createPackageShare({
|
|
189294
190089
|
app: opened.header.app,
|
|
189295
190090
|
releaseId: opened.header.releaseId,
|
|
@@ -189386,11 +190181,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
189386
190181
|
const app = await appId(dir2);
|
|
189387
190182
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
189388
190183
|
const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
|
|
189389
|
-
temp = mkdtempSync6(
|
|
190184
|
+
temp = mkdtempSync6(join94(tmpdir7(), "himi-run-build-"));
|
|
189390
190185
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
189391
190186
|
const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
|
|
189392
190187
|
servedMissing = initial.missingBundles;
|
|
189393
|
-
source =
|
|
190188
|
+
source = join94(temp, app);
|
|
189394
190189
|
}
|
|
189395
190190
|
const chromeArg = str10(flags.chrome) ?? "preview";
|
|
189396
190191
|
if (chromeArg !== "preview" && chromeArg !== "app") {
|
|
@@ -189429,7 +190224,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
189429
190224
|
if (!recordKit) return;
|
|
189430
190225
|
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
189431
190226
|
const failure = record2(served2, { ok: true, at: startedAt });
|
|
189432
|
-
if (!recorded) io2.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${
|
|
190227
|
+
if (!recorded) io2.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join94(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
|
|
189433
190228
|
await refreshBoard();
|
|
189434
190229
|
};
|
|
189435
190230
|
const retract = async () => {
|
|
@@ -189465,7 +190260,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
189465
190260
|
const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
|
|
189466
190261
|
const hhpPreviewRoute = watch2 ? (await Promise.resolve().then(() => (init_hhp_preview(), hhp_preview_exports))).hhpPreviewResponse : null;
|
|
189467
190262
|
const bus = watchKit ? new watchKit.ReloadBus() : void 0;
|
|
189468
|
-
if (watch2) served = mkdtempSync6(
|
|
190263
|
+
if (watch2) served = mkdtempSync6(join94(tmpdir7(), "himi-run-served-"));
|
|
189469
190264
|
const running = await runPackage2(source, {
|
|
189470
190265
|
port,
|
|
189471
190266
|
chrome: chromeArg,
|
|
@@ -189494,8 +190289,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
189494
190289
|
await announce(running);
|
|
189495
190290
|
if (watchKit && bus) {
|
|
189496
190291
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
189497
|
-
const live3 =
|
|
189498
|
-
const manifestOf = (tree) => JSON.parse(
|
|
190292
|
+
const live3 = join94(running.releaseRoot, running.app);
|
|
190293
|
+
const manifestOf = (tree) => JSON.parse(readFileSync109(join94(tree, "release-manifest.json"), "utf8"));
|
|
189499
190294
|
let current = manifestOf(live3);
|
|
189500
190295
|
const failed3 = async (message) => {
|
|
189501
190296
|
if (stopping) return;
|
|
@@ -189506,7 +190301,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
189506
190301
|
};
|
|
189507
190302
|
rebuild = watchKit.serialize(async () => {
|
|
189508
190303
|
const t0 = Date.now();
|
|
189509
|
-
const next = mkdtempSync6(
|
|
190304
|
+
const next = mkdtempSync6(join94(tmpdir7(), "himi-run-build-"));
|
|
189510
190305
|
try {
|
|
189511
190306
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
189512
190307
|
if (bres.compileErrors.length) {
|
|
@@ -189523,16 +190318,16 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
189523
190318
|
return;
|
|
189524
190319
|
}
|
|
189525
190320
|
if (stopping) return;
|
|
189526
|
-
const fresh = manifestOf(
|
|
190321
|
+
const fresh = manifestOf(join94(next, running.app));
|
|
189527
190322
|
const diff = watchKit.diffReleases(current, fresh);
|
|
189528
190323
|
const { describeChanges: describeChanges2, headline: headline2 } = await Promise.resolve().then(() => (init_build_changes(), build_changes_exports));
|
|
189529
|
-
const changes = describeChanges2(live3,
|
|
190324
|
+
const changes = describeChanges2(live3, join94(next, running.app), diff);
|
|
189530
190325
|
const retired = `${live3}.retired-${Date.now()}`;
|
|
189531
190326
|
renameSync13(live3, retired);
|
|
189532
190327
|
try {
|
|
189533
|
-
renameSync13(
|
|
190328
|
+
renameSync13(join94(next, running.app), live3);
|
|
189534
190329
|
} catch {
|
|
189535
|
-
cpSync3(
|
|
190330
|
+
cpSync3(join94(next, running.app), live3, { recursive: true });
|
|
189536
190331
|
}
|
|
189537
190332
|
rmSync24(retired, { recursive: true, force: true });
|
|
189538
190333
|
current = fresh;
|
|
@@ -190159,7 +190954,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
190159
190954
|
io2.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
|
|
190160
190955
|
return 2;
|
|
190161
190956
|
}
|
|
190162
|
-
if (!
|
|
190957
|
+
if (!existsSync88(file2)) {
|
|
190163
190958
|
io2.error(JSON.stringify({ error: `no such file: ${file2}` }));
|
|
190164
190959
|
return 2;
|
|
190165
190960
|
}
|
|
@@ -190215,7 +191010,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
190215
191010
|
lintNote: "`himi patch` sends a raw file. Nothing here built or linted your app \u2014 `himi push --only <selector>` is the same edit with the full lint gate in front of it."
|
|
190216
191011
|
};
|
|
190217
191012
|
if (kind === "tokens" || kind === "app-config") {
|
|
190218
|
-
const body =
|
|
191013
|
+
const body = readFileSync109(file2, "utf8");
|
|
190219
191014
|
const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
|
|
190220
191015
|
return runReleasePatch({
|
|
190221
191016
|
...common,
|
|
@@ -190230,7 +191025,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
190230
191025
|
io2.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
|
|
190231
191026
|
return 2;
|
|
190232
191027
|
}
|
|
190233
|
-
const descriptor =
|
|
191028
|
+
const descriptor = readFileSync109(file2, "utf8");
|
|
190234
191029
|
let parsed;
|
|
190235
191030
|
try {
|
|
190236
191031
|
parsed = JSON.parse(descriptor);
|
|
@@ -190287,7 +191082,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
190287
191082
|
extra: { kind, screen: id, file: { path: file2, bytes: Buffer.byteLength(descriptor, "utf8") } }
|
|
190288
191083
|
});
|
|
190289
191084
|
}
|
|
190290
|
-
const bytes2 =
|
|
191085
|
+
const bytes2 = readFileSync109(file2);
|
|
190291
191086
|
const sha2 = createHash46("sha256").update(bytes2).digest("hex");
|
|
190292
191087
|
const forScreens = (str10(flags["for-screen"]) ?? "").split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
190293
191088
|
if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
|
|
@@ -190431,7 +191226,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
190431
191226
|
}
|
|
190432
191227
|
let def;
|
|
190433
191228
|
try {
|
|
190434
|
-
const parsed = JSON.parse(arg.startsWith("@") ?
|
|
191229
|
+
const parsed = JSON.parse(arg.startsWith("@") ? readFileSync109(arg.slice(1), "utf8") : arg);
|
|
190435
191230
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
190436
191231
|
io2.error(JSON.stringify({ error: "invalid_definition", problems: [`--definition must be a JSON object, got ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`] }));
|
|
190437
191232
|
return 2;
|
|
@@ -190713,7 +191508,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
190713
191508
|
const rememberLastDist = async (jobs2) => {
|
|
190714
191509
|
try {
|
|
190715
191510
|
const dir = contentDir(flags);
|
|
190716
|
-
if (!
|
|
191511
|
+
if (!existsSync88(join94(dir, "himalaya.content.json"))) return;
|
|
190717
191512
|
const { lastDistFromJob: lastDistFromJob2, writeLastDist: writeLastDist2 } = await Promise.resolve().then(() => (init_capabilities(), capabilities_exports));
|
|
190718
191513
|
const own5 = await appId(dir);
|
|
190719
191514
|
for (const job of jobs2) {
|
|
@@ -190953,7 +191748,7 @@ ${label3}`);
|
|
|
190953
191748
|
const platform = str10(flags.platform)?.split(",").map((p2) => p2.trim()).filter(Boolean);
|
|
190954
191749
|
{
|
|
190955
191750
|
const distDir = contentDir(flags);
|
|
190956
|
-
if (
|
|
191751
|
+
if (existsSync88(join94(distDir, "himalaya.content.json"))) {
|
|
190957
191752
|
const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
|
|
190958
191753
|
const errors = issues.filter((i2) => i2.severity === "error");
|
|
190959
191754
|
for (const i2 of issues.filter((i3) => i3.severity === "warning")) {
|
|
@@ -191293,7 +192088,7 @@ ${label3}`);
|
|
|
191293
192088
|
const dpxPath = dpxSessionTokenPath();
|
|
191294
192089
|
let dpx;
|
|
191295
192090
|
try {
|
|
191296
|
-
dpx =
|
|
192091
|
+
dpx = readFileSync109(dpxPath, "utf8").trim();
|
|
191297
192092
|
} catch {
|
|
191298
192093
|
io2.error(JSON.stringify({ error: `no dpx session at ${dpxPath} \u2014 run \`dpx auth login\` then \`dpx auth token > ${dpxPath}\` (dpx 2.x keeps its own state in ~/.dpx/auth.json and does NOT write the legacy session file), or omit --dpx` }));
|
|
191299
192094
|
return 1;
|
|
@@ -191756,7 +192551,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
191756
192551
|
const path2 = dpxSessionTokenPath();
|
|
191757
192552
|
let raw;
|
|
191758
192553
|
try {
|
|
191759
|
-
raw =
|
|
192554
|
+
raw = readFileSync109(path2, "utf8");
|
|
191760
192555
|
} catch {
|
|
191761
192556
|
io2.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
|
|
191762
192557
|
return 1;
|
|
@@ -191950,7 +192745,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
191950
192745
|
}
|
|
191951
192746
|
}
|
|
191952
192747
|
const sub = pos[1];
|
|
191953
|
-
const b44Usage = "himi base44 analyze (--url <https://\u2026> | --app-id <id>) [--out .himi/base44-book] [--sample <n>] [--json] | himi base44 adopt [--book .himi/base44-book] [--entities A,B] [--write [path]] [--json] | himi base44 entities query [--content <dir>] [--all] [--json] | himi base44 types [--content <dir>] [--json] | himi base44 screens [--content <dir>] [--force] [--dry-run] [--json] | himi base44 login [--from-base44-cli] | himi base44 whoami | himi base44 logout";
|
|
192748
|
+
const b44Usage = "himi base44 analyze (--url <https://\u2026> | --app-id <id>) [--out .himi/base44-book] [--sample <n>] [--json] | himi base44 adopt [--book .himi/base44-book] [--entities A,B] [--write [path]] [--json] | himi base44 entities query [--content <dir>] [--all] [--json] | himi base44 entities create [--app <a> | --content <dir>] [--yes] [--allow-destructive] [--apply-permissions] [--empty-app-ok] | himi base44 entities seed [--app <a> | --content <dir>] [--yes] [--only A,B] [--ai [--count <n>]] | himi base44 functions deploy [--app <a> | --content <dir>] [--yes] [--only a,b] | himi base44 types [--content <dir>] [--json] | himi base44 screens [--content <dir>] [--force] [--dry-run] [--json] | himi base44 login [--write] [--from-base44-cli] | himi base44 whoami | himi base44 logout";
|
|
191954
192749
|
if (sub === "adopt") {
|
|
191955
192750
|
const { runBase44Adopt: runBase44Adopt2, AdoptError: AdoptError2 } = await Promise.resolve().then(() => (init_base44_adopt(), base44_adopt_exports));
|
|
191956
192751
|
const dir = contentDir(flags);
|
|
@@ -192004,7 +192799,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192004
192799
|
return 1;
|
|
192005
192800
|
};
|
|
192006
192801
|
const gen = await Promise.resolve().then(() => (init_generate(), generate_exports));
|
|
192007
|
-
const missing = gen.ENGINE_FILES.filter((f2) => !
|
|
192802
|
+
const missing = gen.ENGINE_FILES.filter((f2) => !existsSync88(join94(dir, f2)));
|
|
192008
192803
|
if (missing.length) {
|
|
192009
192804
|
return fail6("content_dir_not_base44_starter", `${dir} is not a base44-starter content package: the generated screens import a shared engine it does not have (${missing.join(", ")})`, { missing, hint: "scaffold one with `himi init <name> --template base44-starter --base44-app-id <id>`" });
|
|
192010
192805
|
}
|
|
@@ -192056,12 +192851,37 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192056
192851
|
});
|
|
192057
192852
|
return 0;
|
|
192058
192853
|
}
|
|
192059
|
-
|
|
192060
|
-
|
|
192061
|
-
|
|
192854
|
+
const provisioning = sub === "entities" && (pos[2] === "create" || pos[2] === "seed") || sub === "functions";
|
|
192855
|
+
if (provisioning && flags.only !== void 0 && !str10(flags.only)?.split(",").some((n2) => n2.trim())) {
|
|
192856
|
+
io2.error(JSON.stringify({ ok: false, code: "invalid_usage", error: "--only needs a comma-separated list of names", usage: b44Usage }));
|
|
192857
|
+
return 2;
|
|
192858
|
+
}
|
|
192859
|
+
if (sub === "entities" && pos[2] === "create" && flags.only !== void 0) {
|
|
192860
|
+
io2.error(JSON.stringify({ ok: false, code: "invalid_usage", error: "entities create takes no --only: Base44's schema write is one full-set sync, so it always reconciles every owned entity", usage: b44Usage }));
|
|
192861
|
+
return 2;
|
|
192862
|
+
}
|
|
192863
|
+
if (sub === "functions" && pos[2] !== "deploy") {
|
|
192864
|
+
io2.error(JSON.stringify({ ok: false, code: "invalid_usage", error: pos[2] ? `unknown base44 functions subcommand "${pos[2]}" \u2014 use deploy` : "base44 functions needs a subcommand: deploy", usage: b44Usage }));
|
|
192865
|
+
return 2;
|
|
192866
|
+
}
|
|
192867
|
+
const b44Dir = () => {
|
|
192868
|
+
const slug = str10(flags.app);
|
|
192869
|
+
if (!provisioning || str10(flags.content) !== void 0 || !slug) return contentDir(flags);
|
|
192870
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(slug)) return void 0;
|
|
192871
|
+
const dir = resolve65("apps", slug);
|
|
192872
|
+
return existsSync88(join94(dir, "config.ts")) || existsSync88(join94(dir, "config.mjs")) ? dir : void 0;
|
|
192873
|
+
};
|
|
192874
|
+
if (sub === "entities" || sub === "functions") {
|
|
192875
|
+
if (sub === "entities" && !["query", "create", "seed"].includes(pos[2] ?? "")) {
|
|
192876
|
+
io2.error(JSON.stringify({ ok: false, code: "unknown_subcommand", error: pos[2] ? `unknown base44 entities subcommand "${pos[2]}" \u2014 use query | create | seed` : "base44 entities needs a subcommand: query | create | seed", usage: b44Usage }));
|
|
192062
192877
|
return 2;
|
|
192063
192878
|
}
|
|
192064
|
-
const
|
|
192879
|
+
const resolvedDir = b44Dir();
|
|
192880
|
+
if (!resolvedDir) {
|
|
192881
|
+
io2.error(JSON.stringify({ ok: false, code: "invalid_usage", error: `--app ${str10(flags.app)}: no apps/${str10(flags.app)}/config.ts under ${process.cwd()}`, hint: "run from the repo root, or pass --content <app dir>", usage: b44Usage }));
|
|
192882
|
+
return 2;
|
|
192883
|
+
}
|
|
192884
|
+
const dir = resolvedDir;
|
|
192065
192885
|
const app = await appId(dir);
|
|
192066
192886
|
let base44;
|
|
192067
192887
|
try {
|
|
@@ -192077,21 +192897,82 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192077
192897
|
return 1;
|
|
192078
192898
|
}
|
|
192079
192899
|
if (!base44 || typeof base44 !== "object") {
|
|
192900
|
+
if (provisioning) {
|
|
192901
|
+
io2.error(JSON.stringify({ ok: false, code: "no_app_id", app, error: "no `base44` block in config.ts \u2014 nothing to provision", hint: "add `base44: { appId, entities, functions }` to config.ts. See `himi docs base44-entities`." }));
|
|
192902
|
+
return 1;
|
|
192903
|
+
}
|
|
192080
192904
|
print({ ok: true, code: "no_base44_block", app, declared: 0, note: "no `base44` block in config.ts \u2014 nothing to query. `himi base44 adopt` writes declarations from a book. See `himi docs base44-entities`." });
|
|
192081
192905
|
return 0;
|
|
192082
192906
|
}
|
|
192083
192907
|
const { validateBase44Entities: validateBase44Entities2 } = await Promise.resolve().then(() => (init_base44_schema(), base44_schema_exports));
|
|
192084
192908
|
const errors = validateBase44Entities2(base44, app).filter((i2) => i2.severity === "error");
|
|
192085
|
-
if (typeof base44.appId !== "string" || !base44.appId)
|
|
192909
|
+
if (typeof base44.appId !== "string" || !base44.appId) {
|
|
192910
|
+
if (provisioning) {
|
|
192911
|
+
io2.error(JSON.stringify({ ok: false, code: "no_app_id", app, error: "base44.appId is missing from config.ts", hint: "it is the id in your app's URL: https://app.base44.com/apps/<id>" }));
|
|
192912
|
+
return 1;
|
|
192913
|
+
}
|
|
192914
|
+
errors.unshift({ severity: "error", ruleCode: "shape-invalid", message: "base44.appId is missing" });
|
|
192915
|
+
}
|
|
192086
192916
|
if (errors.length) {
|
|
192087
192917
|
io2.error(JSON.stringify({ ok: false, code: "invalid_config", app, issues: errors, hint: '`himi validate` reports these with pass: "base44"' }));
|
|
192088
192918
|
return 1;
|
|
192089
192919
|
}
|
|
192920
|
+
if (sub === "entities" && pos[2] === "seed" && flags.ai === true) {
|
|
192921
|
+
const { writeBase44SeedRows: writeBase44SeedRows2 } = await Promise.resolve().then(() => (init_seed(), seed_exports));
|
|
192922
|
+
try {
|
|
192923
|
+
const aiOnly = str10(flags.only)?.split(",").map((n2) => n2.trim()).filter(Boolean);
|
|
192924
|
+
const r2 = writeBase44SeedRows2({ dir, app, entities: base44.entities ?? [], count: Number(str10(flags.count)) || 8, ...aiOnly ? { only: aiOnly } : {} });
|
|
192925
|
+
if (r2.ok) print(r2);
|
|
192926
|
+
else io2.error(JSON.stringify({ ...r2, code: "nothing_to_seed" }));
|
|
192927
|
+
return r2.ok ? 0 : 1;
|
|
192928
|
+
} catch (e2) {
|
|
192929
|
+
io2.error(JSON.stringify({ ok: false, code: "seed_file_invalid", app, error: e2.message }));
|
|
192930
|
+
return 1;
|
|
192931
|
+
}
|
|
192932
|
+
}
|
|
192090
192933
|
const auth2 = await (await Promise.resolve().then(() => (init_base44_auth(), base44_auth_exports))).usableBase44Auth();
|
|
192091
192934
|
if (!auth2) {
|
|
192092
|
-
io2.error(JSON.stringify({ ok: false, code: "not_signed_in", app, error:
|
|
192935
|
+
io2.error(JSON.stringify({ ok: false, code: "not_signed_in", app, error: `${sub} ${pos[2]} needs a Base44 session: run \`himi base44 login${provisioning ? " --write" : ""}\` (or set BASE44_ACCESS_TOKEN)` }));
|
|
192093
192936
|
return 2;
|
|
192094
192937
|
}
|
|
192938
|
+
if (provisioning) {
|
|
192939
|
+
const only = str10(flags.only)?.split(",").map((n2) => n2.trim()).filter(Boolean);
|
|
192940
|
+
const transport = { app, appId: base44.appId, apiFetch: fetch, apiBase: auth2.apiBase, auth: auth2, yes: flags.yes === true };
|
|
192941
|
+
let report4;
|
|
192942
|
+
if (sub === "functions") {
|
|
192943
|
+
const { deployBase44Functions: deployBase44Functions2 } = await Promise.resolve().then(() => (init_functions2(), functions_exports2));
|
|
192944
|
+
report4 = await deployBase44Functions2({ ...transport, appDir: dir, functions: base44.functions ?? [], ...only ? { only } : {} });
|
|
192945
|
+
} else if (pos[2] === "seed") {
|
|
192946
|
+
const { seedBase44Entities: seedBase44Entities2 } = await Promise.resolve().then(() => (init_seed(), seed_exports));
|
|
192947
|
+
const { fileLedger: fileLedger2 } = await Promise.resolve().then(() => (init_apply2(), apply_exports));
|
|
192948
|
+
let provisioned;
|
|
192949
|
+
try {
|
|
192950
|
+
provisioned = fileLedger2(dir, base44.appId).read();
|
|
192951
|
+
} catch (e2) {
|
|
192952
|
+
io2.error(JSON.stringify({ ok: false, code: "ledger_unreadable", app, error: e2.message }));
|
|
192953
|
+
return 1;
|
|
192954
|
+
}
|
|
192955
|
+
report4 = await seedBase44Entities2({ ...transport, entities: base44.entities ?? [], dir, provisioned, ...only ? { only } : {} });
|
|
192956
|
+
} else {
|
|
192957
|
+
const { projectDownloader: projectDownloader3 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
192958
|
+
const { createBase44Entities: createBase44Entities2, fileLedger: fileLedger2 } = await Promise.resolve().then(() => (init_apply2(), apply_exports));
|
|
192959
|
+
const r2 = await createBase44Entities2({
|
|
192960
|
+
...transport,
|
|
192961
|
+
ledger: fileLedger2(dir, base44.appId),
|
|
192962
|
+
entities: base44.entities ?? [],
|
|
192963
|
+
download: projectDownloader3(fetch, auth2.apiBase, auth2.token),
|
|
192964
|
+
allowDestructive: flags["allow-destructive"] === true,
|
|
192965
|
+
applyPermissions: flags["apply-permissions"] === true,
|
|
192966
|
+
emptyAppOk: flags["empty-app-ok"] === true
|
|
192967
|
+
});
|
|
192968
|
+
const { next: _next, ...plan } = r2.plan ?? { next: void 0 };
|
|
192969
|
+
report4 = { ...r2, ...r2.plan ? { plan } : {} };
|
|
192970
|
+
}
|
|
192971
|
+
const out2 = { ...report4, ...report4.ok && report4.dryRun ? { next: [`# dry run \u2014 nothing was written. Re-run with --yes to apply.`] } : {} };
|
|
192972
|
+
if (report4.ok) print(out2);
|
|
192973
|
+
else io2.error(JSON.stringify(out2));
|
|
192974
|
+
return report4.ok ? 0 : report4.code === "write_scope_missing" || report4.code === "invalid_usage" ? 2 : 1;
|
|
192975
|
+
}
|
|
192095
192976
|
const { projectDownloader: projectDownloader2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
192096
192977
|
const { queryBase44Entities: queryBase44Entities2 } = await Promise.resolve().then(() => (init_base44_entities2(), base44_entities_exports));
|
|
192097
192978
|
const report3 = await queryBase44Entities2({
|
|
@@ -192117,6 +192998,8 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192117
192998
|
if (sub === "login") {
|
|
192118
192999
|
try {
|
|
192119
193000
|
const r2 = flags["from-base44-cli"] === true ? auth.importBase44CliSession() : await auth.base44DeviceLogin({
|
|
193001
|
+
// #4558: --write mints the apps:write session the provisioning verbs need.
|
|
193002
|
+
...flags.write === true ? { scope: auth.BASE44_WRITE_SCOPE } : {},
|
|
192120
193003
|
io: {
|
|
192121
193004
|
prompt: async ({ verificationUri, userCode }) => {
|
|
192122
193005
|
io2.error(`Approve this sign-in in your browser: ${verificationUri}
|