@wix/himalaya-cli 0.1437.0 → 0.1438.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 +121 -22
- package/guides/base44-app-to-himi-app.md +18 -6
- package/guides/himi-json-output.md +6 -1
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -6939,7 +6939,7 @@ function validator(schema) {
|
|
|
6939
6939
|
}
|
|
6940
6940
|
function compileV2(html, profile, options) {
|
|
6941
6941
|
const diagnostics = [], sourceMap2 = {}, dependencies = [options.file];
|
|
6942
|
-
const
|
|
6942
|
+
const requiredCapabilities2 = /* @__PURE__ */ new Set();
|
|
6943
6943
|
const $2 = cheerio2.load(html, { sourceCodeLocationInfo: true });
|
|
6944
6944
|
const loc = (el2) => ({ file: options.file, line: el2?.sourceCodeLocation?.startLine ?? 1, column: el2?.sourceCodeLocation?.startCol ?? 1 });
|
|
6945
6945
|
const error = (el2, code, message, hint) => diagnostics.push({ ...loc(el2), code, severity: "error", message, ...hint ? { hint } : {} });
|
|
@@ -6973,7 +6973,7 @@ function compileV2(html, profile, options) {
|
|
|
6973
6973
|
} else error(script, "HHP-SCRIPT", "Use one external application/himalaya-controller script. Inline/page JavaScript is unavailable.");
|
|
6974
6974
|
}
|
|
6975
6975
|
let info4;
|
|
6976
|
-
for (const cap of moduleCapabilities(controller?.source ?? directService?.source ?? "", controller?.file ?? options.file, profile))
|
|
6976
|
+
for (const cap of moduleCapabilities(controller?.source ?? directService?.source ?? "", controller?.file ?? options.file, profile)) requiredCapabilities2.add(cap);
|
|
6977
6977
|
if (controller) {
|
|
6978
6978
|
dependencies.push(controller.file);
|
|
6979
6979
|
info4 = analyzeController(controller.source, controller.file, profile, diagnostics);
|
|
@@ -7049,7 +7049,7 @@ function compileV2(html, profile, options) {
|
|
|
7049
7049
|
if (!info4?.handlers.has(action.slice(`tier5.${serviceName}.`.length))) error(el2, "HHP-EVENT", `Unknown structured handler ${action}.`);
|
|
7050
7050
|
} else if (action.startsWith("capability.")) {
|
|
7051
7051
|
const [, cap, method] = action.split(".");
|
|
7052
|
-
|
|
7052
|
+
requiredCapabilities2.add(cap);
|
|
7053
7053
|
if (!grants(profile.declaredCapabilities, cap)) error(el2, "HHP-CAPABILITY-MISSING", `Action requires declared capability ${cap}.`);
|
|
7054
7054
|
if (!own5(profile.capabilities, cap)?.methods.includes(method)) error(el2, "HHP-EVENT", `Unknown capability method ${action}.`);
|
|
7055
7055
|
} else if (!profile.handlers?.includes(action)) error(el2, "HHP-EVENT", `Action ${action} is not declared by this app.`);
|
|
@@ -7288,7 +7288,7 @@ function compileV2(html, profile, options) {
|
|
|
7288
7288
|
if (tag === "a") {
|
|
7289
7289
|
if (attrs.href?.startsWith("#")) props.action = { actionId: "himi.open", params: { screenId: attrs.href.slice(1) } };
|
|
7290
7290
|
else if (/^https:\/\//.test(attrs.href ?? "")) {
|
|
7291
|
-
|
|
7291
|
+
requiredCapabilities2.add("open_url");
|
|
7292
7292
|
if (!grants(profile.declaredCapabilities, "open_url")) error(el2, "HHP-CAPABILITY-MISSING", "External links require open_url.");
|
|
7293
7293
|
props.action = { actionId: "capability.open_url.open", args: { url: attrs.href } };
|
|
7294
7294
|
} else error(el2, "HHP-LINK", "Links require #screenId or an HTTPS URL.");
|
|
@@ -7419,7 +7419,7 @@ ${directService.source}
|
|
|
7419
7419
|
bundleName,
|
|
7420
7420
|
sourceMap: sourceMap2,
|
|
7421
7421
|
dependencies,
|
|
7422
|
-
manifest: { profileVersion: "hhp/2", catalogVersion: profile.catalogVersion, screenId, bundleName, serviceName: info4 ? serviceName : null, requiredCapabilities: [...
|
|
7422
|
+
manifest: { profileVersion: "hhp/2", catalogVersion: profile.catalogVersion, screenId, bundleName, serviceName: info4 ? serviceName : null, requiredCapabilities: [...requiredCapabilities2].sort(), inputSha256: createHash6("sha256").update(html).digest("hex") }
|
|
7423
7423
|
};
|
|
7424
7424
|
}
|
|
7425
7425
|
var camel, semantic, actionAliases, ajv, validators;
|
|
@@ -15051,7 +15051,7 @@ async function compileContentHhp(root, opts = {}) {
|
|
|
15051
15051
|
seen.add(file3);
|
|
15052
15052
|
const source = readFileSync16(file3, "utf8");
|
|
15053
15053
|
inspectModule(source, file3, profile, diagnostics);
|
|
15054
|
-
for (const cap of moduleCapabilities(source, file3, profile))
|
|
15054
|
+
for (const cap of moduleCapabilities(source, file3, profile)) requiredCapabilities2.add(cap);
|
|
15055
15055
|
const sf2 = ts3.createSourceFile(file3, source, ts3.ScriptTarget.Latest, true);
|
|
15056
15056
|
for (const stmt of sf2.statements) if ((ts3.isImportDeclaration(stmt) || ts3.isExportDeclaration(stmt)) && stmt.moduleSpecifier && ts3.isStringLiteral(stmt.moduleSpecifier) && stmt.moduleSpecifier.text.startsWith(".")) {
|
|
15057
15057
|
let imported = localPath(root, stmt.moduleSpecifier.text, file3);
|
|
@@ -15066,9 +15066,9 @@ async function compileContentHhp(root, opts = {}) {
|
|
|
15066
15066
|
diagnostics.push(...result2.diagnostics);
|
|
15067
15067
|
results.push(result2);
|
|
15068
15068
|
const seen = /* @__PURE__ */ new Set();
|
|
15069
|
-
const
|
|
15069
|
+
const requiredCapabilities2 = new Set(result2.manifest.requiredCapabilities);
|
|
15070
15070
|
for (const dependency of result2.dependencies.filter((f2) => /\.tsx?$/.test(f2))) inspect2(dependency);
|
|
15071
|
-
result2.manifest.requiredCapabilities = [...
|
|
15071
|
+
result2.manifest.requiredCapabilities = [...requiredCapabilities2].sort();
|
|
15072
15072
|
outputs.set(`dev/hhp/${id}.descriptor.json`, JSON.stringify(result2.descriptor, null, 2) + "\n");
|
|
15073
15073
|
outputs.set(`dev/hhp/${id}.map.json`, JSON.stringify({ ...result2.manifest, nodes: Object.fromEntries(Object.entries(result2.sourceMap).map(([key3, node]) => [key3, { ...node, file: relative3(root, node.file).split(sep6).join("/") }])) }, null, 2) + "\n");
|
|
15074
15074
|
if (result2.worker && result2.bundleName) {
|
|
@@ -22774,6 +22774,9 @@ var init_plan = __esm({
|
|
|
22774
22774
|
});
|
|
22775
22775
|
|
|
22776
22776
|
// ../../core/sdk/capability-catalog/src/builtins.ts
|
|
22777
|
+
function hasBuiltin(platform, id) {
|
|
22778
|
+
return CAPABILITY_BUILTINS[platform].includes(id);
|
|
22779
|
+
}
|
|
22777
22780
|
var IOS_BUILTINS, WEB_BUILTINS, CAPABILITY_BUILTINS;
|
|
22778
22781
|
var init_builtins = __esm({
|
|
22779
22782
|
"../../core/sdk/capability-catalog/src/builtins.ts"() {
|
|
@@ -23282,6 +23285,10 @@ function binaryCoreSatellitePath(product) {
|
|
|
23282
23285
|
function mavenArtifactForGradleProject(project) {
|
|
23283
23286
|
return project.replace(/^:/, "");
|
|
23284
23287
|
}
|
|
23288
|
+
function binaryModuleLinks(buildSet2) {
|
|
23289
|
+
const { spm, gradle } = modulesFor(buildSet2);
|
|
23290
|
+
return { spm, maven: gradle.map((g2) => `${BINARY_CORE_MAVEN_GROUP}:${mavenArtifactForGradleProject(g2)}`) };
|
|
23291
|
+
}
|
|
23285
23292
|
function coreVersionHasModules(version4) {
|
|
23286
23293
|
const parse4 = (v2) => /^(\d+)\.(\d+)\.(\d+)/.exec(v2.trim())?.slice(1).map(Number);
|
|
23287
23294
|
const a2 = parse4(version4);
|
|
@@ -23340,6 +23347,58 @@ var init_binary_core = __esm({
|
|
|
23340
23347
|
});
|
|
23341
23348
|
|
|
23342
23349
|
// ../../core/sdk/capability-catalog/src/index.ts
|
|
23350
|
+
var src_exports = {};
|
|
23351
|
+
__export(src_exports, {
|
|
23352
|
+
BINARY_CORE_ANDROID_PUBLISH_BUILDS: () => BINARY_CORE_ANDROID_PUBLISH_BUILDS,
|
|
23353
|
+
BINARY_CORE_IOS_PATH_ONLY_SATELLITES: () => BINARY_CORE_IOS_PATH_ONLY_SATELLITES,
|
|
23354
|
+
BINARY_CORE_IOS_SATELLITES: () => BINARY_CORE_IOS_SATELLITES,
|
|
23355
|
+
BINARY_CORE_IOS_TRAIT_SATELLITES: () => BINARY_CORE_IOS_TRAIT_SATELLITES,
|
|
23356
|
+
BINARY_CORE_IOS_TRAIT_SELECTOR: () => BINARY_CORE_IOS_TRAIT_SELECTOR,
|
|
23357
|
+
BINARY_CORE_MAVEN_GROUP: () => BINARY_CORE_MAVEN_GROUP,
|
|
23358
|
+
BINARY_CORE_MODULES_SINCE: () => BINARY_CORE_MODULES_SINCE,
|
|
23359
|
+
BINARY_CORE_PRE_SPLIT_USAGE_STRINGS: () => BINARY_CORE_PRE_SPLIT_USAGE_STRINGS,
|
|
23360
|
+
BINARY_CORE_SPM_PACKAGE: () => BINARY_CORE_SPM_PACKAGE,
|
|
23361
|
+
BINARY_CORE_USAGE_STRINGS: () => BINARY_CORE_USAGE_STRINGS,
|
|
23362
|
+
BRIDGE_CAPABILITY_IDS: () => BRIDGE_CAPABILITY_IDS,
|
|
23363
|
+
CAPABILITY_BUILTINS: () => CAPABILITY_BUILTINS,
|
|
23364
|
+
CAPABILITY_IMPLIES: () => CAPABILITY_IMPLIES,
|
|
23365
|
+
CAPABILITY_NATIVE: () => CAPABILITY_NATIVE,
|
|
23366
|
+
CATALOG_CAPABILITY_IDS: () => CATALOG_CAPABILITY_IDS,
|
|
23367
|
+
COMPONENT_MODULES: () => COMPONENT_MODULES,
|
|
23368
|
+
KNOWN_CAPABILITY_IDS: () => KNOWN_CAPABILITY_IDS,
|
|
23369
|
+
NATIVE_MODULES: () => NATIVE_MODULES,
|
|
23370
|
+
NOT_DIST_ADDABLE: () => NOT_DIST_ADDABLE,
|
|
23371
|
+
androidPlanFor: () => androidPlanFor,
|
|
23372
|
+
binaryCoreSatellitePath: () => binaryCoreSatellitePath,
|
|
23373
|
+
binaryCoreSatelliteTrait: () => binaryCoreSatelliteTrait,
|
|
23374
|
+
binaryCoreUsageStringsFor: () => binaryCoreUsageStringsFor,
|
|
23375
|
+
binaryCoreVersion: () => binaryCoreVersion,
|
|
23376
|
+
binaryModuleLinks: () => binaryModuleLinks,
|
|
23377
|
+
capabilitiesOfModule: () => capabilitiesOfModule,
|
|
23378
|
+
capabilitiesUsedBy: () => capabilitiesUsedBy,
|
|
23379
|
+
capabilityDispatchesIn: () => capabilityDispatchesIn,
|
|
23380
|
+
catalogKey: () => catalogKey,
|
|
23381
|
+
componentModuleRequirements: () => componentModuleRequirements,
|
|
23382
|
+
coreVersionHasModules: () => coreVersionHasModules,
|
|
23383
|
+
distAddRefusal: () => distAddRefusal,
|
|
23384
|
+
distributionOptIns: () => distributionOptIns,
|
|
23385
|
+
expandCapabilities: () => expandCapabilities,
|
|
23386
|
+
grants: () => grants,
|
|
23387
|
+
hasBuiltin: () => hasBuiltin,
|
|
23388
|
+
iosPlanFor: () => iosPlanFor,
|
|
23389
|
+
isBinaryCore: () => isBinaryCore,
|
|
23390
|
+
isKnownCapability: () => isKnownCapability,
|
|
23391
|
+
linksModule: () => linksModule,
|
|
23392
|
+
macosPlanFor: () => macosPlanFor,
|
|
23393
|
+
mavenArtifactForGradleProject: () => mavenArtifactForGradleProject,
|
|
23394
|
+
moduleForGradleProject: () => moduleForGradleProject,
|
|
23395
|
+
moduleForSpmProduct: () => moduleForSpmProduct,
|
|
23396
|
+
modulesFor: () => modulesFor,
|
|
23397
|
+
nativeRequirementsFor: () => nativeRequirementsFor,
|
|
23398
|
+
needsNativeBuild: () => needsNativeBuild,
|
|
23399
|
+
unlinkedComponentModules: () => unlinkedComponentModules,
|
|
23400
|
+
usageStringCopyFor: () => usageStringCopyFor
|
|
23401
|
+
});
|
|
23343
23402
|
var init_src2 = __esm({
|
|
23344
23403
|
"../../core/sdk/capability-catalog/src/index.ts"() {
|
|
23345
23404
|
init_types();
|
|
@@ -131112,8 +131171,8 @@ var init_AppRegistry = __esm({
|
|
|
131112
131171
|
});
|
|
131113
131172
|
|
|
131114
131173
|
// ../../core/web-renderer/src/index.ts
|
|
131115
|
-
var
|
|
131116
|
-
__export(
|
|
131174
|
+
var src_exports2 = {};
|
|
131175
|
+
__export(src_exports2, {
|
|
131117
131176
|
Bound: () => Bound,
|
|
131118
131177
|
BoundList: () => BoundList,
|
|
131119
131178
|
FakeServiceProvider: () => FakeServiceProvider,
|
|
@@ -131474,7 +131533,7 @@ async function renderDescriptorWeb(descriptor, tokens2, scheme, wantPng, service
|
|
|
131474
131533
|
) : void 0;
|
|
131475
131534
|
let html;
|
|
131476
131535
|
try {
|
|
131477
|
-
const { renderDescriptorToHtml: renderDescriptorToHtml2 } = await Promise.resolve().then(() => (init_src5(),
|
|
131536
|
+
const { renderDescriptorToHtml: renderDescriptorToHtml2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
|
|
131478
131537
|
html = renderDescriptorToHtml2(
|
|
131479
131538
|
payload,
|
|
131480
131539
|
tokens2 ?? {},
|
|
@@ -131744,7 +131803,7 @@ async function pngFontFaceCss(tokens2, opts = {}) {
|
|
|
131744
131803
|
return rules.join("");
|
|
131745
131804
|
}
|
|
131746
131805
|
async function idiomFontFaceCss(idiomContext) {
|
|
131747
|
-
const { controlIdiomFor: controlIdiomFor2, idiomControls: idiomControls2 } = await Promise.resolve().then(() => (init_src5(),
|
|
131806
|
+
const { controlIdiomFor: controlIdiomFor2, idiomControls: idiomControls2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
|
|
131748
131807
|
const bundled = idiomControls2(controlIdiomFor2(idiomContext)).font.bundled;
|
|
131749
131808
|
if (!bundled) return "";
|
|
131750
131809
|
try {
|
|
@@ -140282,7 +140341,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140282
140341
|
};
|
|
140283
140342
|
let handlers;
|
|
140284
140343
|
let minBinaryVersion = null;
|
|
140285
|
-
const
|
|
140344
|
+
const requiredCapabilities2 = new Set(config.capabilities ?? []);
|
|
140286
140345
|
const capabilityUsage = {
|
|
140287
140346
|
app: [...config.capabilities ?? []],
|
|
140288
140347
|
...Array.isArray(config.capabilityEnvelope) ? { envelope: [...config.capabilityEnvelope] } : {},
|
|
@@ -140293,7 +140352,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140293
140352
|
const ids = Array.isArray(declared) ? declared.filter((c2) => typeof c2 === "string") : [];
|
|
140294
140353
|
const components2 = [...collectComponentTypes(descriptor)].sort();
|
|
140295
140354
|
capabilityUsage.screens.push({ screenId, bundle, declared: ids, components: components2 });
|
|
140296
|
-
for (const c2 of componentModuleRequirements(components2, [...
|
|
140355
|
+
for (const c2 of componentModuleRequirements(components2, [...requiredCapabilities2, ...ids])) requiredCapabilities2.add(c2);
|
|
140297
140356
|
};
|
|
140298
140357
|
const requiredNativeComponents = /* @__PURE__ */ new Set();
|
|
140299
140358
|
const tierScreens = [];
|
|
@@ -140537,7 +140596,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140537
140596
|
minBinaryVersion = maximumBinaryVersion(minBinaryVersion, lb.minBinaryVersion);
|
|
140538
140597
|
const declared = lb.declaredCapabilities ?? lb.declared_capabilities;
|
|
140539
140598
|
if (Array.isArray(declared)) {
|
|
140540
|
-
for (const capability of declared) if (typeof capability === "string")
|
|
140599
|
+
for (const capability of declared) if (typeof capability === "string") requiredCapabilities2.add(capability);
|
|
140541
140600
|
}
|
|
140542
140601
|
noteScreenCapabilities(screenId, bundleName, declared, descriptor);
|
|
140543
140602
|
} else {
|
|
@@ -140687,7 +140746,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140687
140746
|
minBinaryVersion = maximumBinaryVersion(minBinaryVersion, lb.minBinaryVersion);
|
|
140688
140747
|
const declared = lb.declaredCapabilities ?? lb.declared_capabilities;
|
|
140689
140748
|
if (Array.isArray(declared)) {
|
|
140690
|
-
for (const c2 of declared) if (typeof c2 === "string")
|
|
140749
|
+
for (const c2 of declared) if (typeof c2 === "string") requiredCapabilities2.add(c2);
|
|
140691
140750
|
}
|
|
140692
140751
|
noteScreenCapabilities(screenId, bundleName, declared, descriptor);
|
|
140693
140752
|
} else {
|
|
@@ -140855,7 +140914,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140855
140914
|
// whose source catalog serves copy (native screens, #4221/#4250) now carries `en` here.
|
|
140856
140915
|
...Object.keys(catalogs).length ? { catalogs } : {},
|
|
140857
140916
|
playerRequirements: {
|
|
140858
|
-
capabilities: [...
|
|
140917
|
+
capabilities: [...requiredCapabilities2].sort(),
|
|
140859
140918
|
nativeComponents: [...requiredNativeComponents].sort(),
|
|
140860
140919
|
// `none` is the scaffold's spelling of "no auth" (`new-app --auth=none`), not a provider a
|
|
140861
140920
|
// host must carry — recording it blocked every such app in the Player picker (#3695).
|
|
@@ -167797,10 +167856,13 @@ __export(plan_exports, {
|
|
|
167797
167856
|
RESERVED_SCREEN_IDS: () => RESERVED_SCREEN_IDS,
|
|
167798
167857
|
displayName: () => displayName2,
|
|
167799
167858
|
gateFor: () => gateFor,
|
|
167859
|
+
hasLinkField: () => hasLinkField,
|
|
167800
167860
|
humanize: () => humanize,
|
|
167861
|
+
missingCapabilities: () => missingCapabilities,
|
|
167801
167862
|
planEntity: () => planEntity,
|
|
167802
167863
|
planEntityScreens: () => planEntityScreens,
|
|
167803
167864
|
pluralize: () => pluralize,
|
|
167865
|
+
requiredCapabilities: () => requiredCapabilities,
|
|
167804
167866
|
rowTitleField: () => rowTitleField,
|
|
167805
167867
|
snake: () => snake
|
|
167806
167868
|
});
|
|
@@ -167876,6 +167938,12 @@ function fieldReadOnly(f2) {
|
|
|
167876
167938
|
const rls = f2.rls;
|
|
167877
167939
|
return !!rls && typeof rls === "object" && "write" in rls && rls.write !== true;
|
|
167878
167940
|
}
|
|
167941
|
+
function requiredCapabilities(sp) {
|
|
167942
|
+
return ["base44", ...sp.plans.some(hasLinkField) ? ["open_url"] : []];
|
|
167943
|
+
}
|
|
167944
|
+
function missingCapabilities(sp, declared) {
|
|
167945
|
+
return requiredCapabilities(sp).filter((c2) => !declared.has(c2)).map((capability) => ({ capability, entities: (capability === "open_url" ? sp.plans.filter(hasLinkField) : sp.plans).map((p2) => p2.name) }));
|
|
167946
|
+
}
|
|
167879
167947
|
function ruleFor(spec, op) {
|
|
167880
167948
|
const rls = spec.rls;
|
|
167881
167949
|
if (!rls || typeof rls !== "object") return void 0;
|
|
@@ -167954,7 +168022,7 @@ function planEntityScreens(specs, app = "") {
|
|
|
167954
168022
|
if (names2.length <= ENTITY_TAB_SLOTS) return { plans, tabs: names2, more: [] };
|
|
167955
168023
|
return { plans, tabs: names2.slice(0, ENTITY_TAB_SLOTS - 1), more: names2.slice(ENTITY_TAB_SLOTS - 1) };
|
|
167956
168024
|
}
|
|
167957
|
-
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;
|
|
168025
|
+
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, hasLinkField, nounOf;
|
|
167958
168026
|
var init_plan4 = __esm({
|
|
167959
168027
|
"src/base44-screens/plan.ts"() {
|
|
167960
168028
|
init_base44_schema();
|
|
@@ -167980,6 +168048,7 @@ var init_plan4 = __esm({
|
|
|
167980
168048
|
isDate = (f2) => f2.type === "string" && (f2.format === "date" || f2.format === "date-time");
|
|
167981
168049
|
isImage = (f2) => f2.type === "string" && !isEnum(f2) && (f2.format === "file" || IMAGE_KEY.test(f2.key));
|
|
167982
168050
|
isLongText = (f2) => f2.type === "string" && !isEnum(f2) && (f2.format === "richtext" || LONG_TEXT.test(f2.key));
|
|
168051
|
+
hasLinkField = (p2) => p2.detail.some((d2) => d2.show === "link");
|
|
167983
168052
|
nounOf = (display) => display.split(" ").map((w2) => /^[A-Z]{2,}s?$/.test(w2) ? w2 : w2.toLowerCase()).join(" ");
|
|
167984
168053
|
}
|
|
167985
168054
|
});
|
|
@@ -168031,13 +168100,25 @@ export default defineEntityList(PLAN);
|
|
|
168031
168100
|
`;
|
|
168032
168101
|
}
|
|
168033
168102
|
function renderDetailEntry(p2) {
|
|
168034
|
-
|
|
168103
|
+
if (!hasLinkField(p2)) {
|
|
168104
|
+
return `// One ${p2.name} (${p2.ids.detail}), pushed from ${p2.ids.list} with its id \u2014 generated by \`himi base44 screens\`.
|
|
168035
168105
|
// The behaviour lives in the shared engine (../_shared/entity-detail.ts); this file only names the
|
|
168036
168106
|
// entity's plan.
|
|
168037
168107
|
import { defineEntityDetail } from "../_shared/entity-detail.js";
|
|
168038
168108
|
import { PLAN } from "../_shared/${planFile(p2)}.js";
|
|
168039
168109
|
|
|
168040
168110
|
export default defineEntityDetail(PLAN);
|
|
168111
|
+
`;
|
|
168112
|
+
}
|
|
168113
|
+
return `// One ${p2.name} (${p2.ids.detail}), pushed from ${p2.ids.list} with its id \u2014 generated by \`himi base44 screens\`.
|
|
168114
|
+
// The behaviour lives in the shared engine (../_shared/entity-detail.ts); this file names the
|
|
168115
|
+
// entity's plan and hands it \`open\`, which an email / URL fact opens through (the open_url
|
|
168116
|
+
// capability \u2014 only an entity with such a field imports it).
|
|
168117
|
+
import { open } from "@himalaya/open-url";
|
|
168118
|
+
import { defineEntityDetail } from "../_shared/entity-detail.js";
|
|
168119
|
+
import { PLAN } from "../_shared/${planFile(p2)}.js";
|
|
168120
|
+
|
|
168121
|
+
export default defineEntityDetail(PLAN, { open });
|
|
168041
168122
|
`;
|
|
168042
168123
|
}
|
|
168043
168124
|
function renderDevRegistrations(sp) {
|
|
@@ -184778,7 +184859,9 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
184778
184859
|
base44.entities entity (base44-starter packages), write
|
|
184779
184860
|
controls gated by each entity's rls. Re-running is a
|
|
184780
184861
|
no-op; a hand-edited generated file is skipped-edited
|
|
184781
|
-
unless --force.
|
|
184862
|
+
unless --force. An email / URL field opens through
|
|
184863
|
+
open_url, so config.ts capabilities must list it
|
|
184864
|
+
(else missing_capability). Never calls Base44.
|
|
184782
184865
|
himi base44 entities create [--app <a> | --content <dir>] [--yes] [--allow-destructive]
|
|
184783
184866
|
[--apply-permissions] [--empty-app-ok]
|
|
184784
184867
|
create/update the app's OWNED Himi<App>* entities. Base44's
|
|
@@ -192866,9 +192949,12 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192866
192949
|
}
|
|
192867
192950
|
const app = await appId(dir);
|
|
192868
192951
|
let base44;
|
|
192952
|
+
let appCapabilities;
|
|
192869
192953
|
try {
|
|
192870
192954
|
const { loadAppConfigModule: loadAppConfigModule2 } = await Promise.resolve().then(() => (init_app_config_loader(), app_config_loader_exports));
|
|
192871
|
-
|
|
192955
|
+
const loaded = await loadAppConfigModule2(dir);
|
|
192956
|
+
base44 = loaded?.base44;
|
|
192957
|
+
appCapabilities = loaded?.capabilities;
|
|
192872
192958
|
} catch (e2) {
|
|
192873
192959
|
const finding = (await Promise.resolve().then(() => (init_base44_lint(), base44_lint_exports))).base44DefineAppFinding(e2);
|
|
192874
192960
|
if (finding) {
|
|
@@ -192887,7 +192973,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192887
192973
|
io2.error(JSON.stringify({ ok: false, code: "invalid_config", app, issues: errors, hint: '`himi validate` reports these with pass: "base44"' }));
|
|
192888
192974
|
return 1;
|
|
192889
192975
|
}
|
|
192890
|
-
const { planEntityScreens: planEntityScreens2, PlanError: PlanError2 } = await Promise.resolve().then(() => (init_plan4(), plan_exports));
|
|
192976
|
+
const { planEntityScreens: planEntityScreens2, PlanError: PlanError2, missingCapabilities: missingCapabilities2, requiredCapabilities: requiredCapabilities2 } = await Promise.resolve().then(() => (init_plan4(), plan_exports));
|
|
192891
192977
|
let sp;
|
|
192892
192978
|
try {
|
|
192893
192979
|
sp = planEntityScreens2(specs, app);
|
|
@@ -192895,6 +192981,18 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192895
192981
|
if (e2 instanceof PlanError2) return fail6(e2.code, e2.message, { app, ...e2.extra });
|
|
192896
192982
|
throw e2;
|
|
192897
192983
|
}
|
|
192984
|
+
const { catalogKey: catalogKey2, expandCapabilities: expandCapabilities2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
|
|
192985
|
+
const declaredCaps = expandCapabilities2((Array.isArray(appCapabilities) ? appCapabilities : []).filter((c2) => typeof c2 === "string").map(catalogKey2));
|
|
192986
|
+
const missingCaps = missingCapabilities2(sp, declaredCaps);
|
|
192987
|
+
if (missingCaps.length) {
|
|
192988
|
+
const [first] = missingCaps;
|
|
192989
|
+
return fail6("missing_capability", `config.ts capabilities does not declare "${first.capability}", which the generated screens need (${first.entities.join(", ")})`, {
|
|
192990
|
+
app,
|
|
192991
|
+
capability: first.capability,
|
|
192992
|
+
missing: missingCaps,
|
|
192993
|
+
hint: `add it \u2014 capabilities: [..., ${missingCaps.map((m2) => `"${m2.capability}"`).join(", ")}] \u2014 then re-run; the native config follows from the capability catalog (himi docs capabilities). Nothing was written.`
|
|
192994
|
+
});
|
|
192995
|
+
}
|
|
192898
192996
|
const rendered = gen.renderAll(sp);
|
|
192899
192997
|
const dryRun = flags["dry-run"] === true;
|
|
192900
192998
|
const { files } = gen.writeGenerated(dir, rendered, { force: flags.force === true, dryRun });
|
|
@@ -192905,6 +193003,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192905
193003
|
...dryRun ? { dryRun: true } : {},
|
|
192906
193004
|
files,
|
|
192907
193005
|
plans: sp.plans.map((p2) => ({ entity: p2.name, physical: p2.entity, list: p2.ids.list, detail: p2.ids.detail, gates: p2.gates })),
|
|
193006
|
+
capabilities: requiredCapabilities2(sp),
|
|
192908
193007
|
tabs: sp.tabs,
|
|
192909
193008
|
more: sp.more,
|
|
192910
193009
|
...orphaned.length ? { orphaned, note: "generated files for entities no longer declared \u2014 never deleted; remove them by hand if the screens should go" } : {},
|
|
@@ -139,12 +139,12 @@ Write `.himi/screen-plan.md` before editing code. For each entity in `book.entit
|
|
|
139
139
|
| `string` + long text (`description`, `notes`, `body`, …) | `Text` with `maxLines` | `TextField` with `multilineMaxLines` |
|
|
140
140
|
| `string` + `enum` | `Badge` / `Text` | `SegmentedControl` (≤ 4 values) or `Picker` |
|
|
141
141
|
| `string` + `format: date` / `date-time` | formatted `Text` | `DatePicker` |
|
|
142
|
-
| `string` + `format: email` / `uri` |
|
|
142
|
+
| `string` + `format: email` / `uri` | a tappable row: an email opens mail, a URL the in-app browser, through `@himalaya/open-url` (needs `open_url`, below) | `TextField` with `keyboard: "email"` / `"url"` |
|
|
143
143
|
| `string` holding an image URL (`image`, `photo`, `avatar`, `*_url`) | `Image` | read-only, see [file upload](#what-the-sdk-cannot-do) |
|
|
144
144
|
| `number` / `integer` | `Text` (with unit) | `Stepper` (small ranges) or numeric `TextField` |
|
|
145
145
|
| `boolean` | `Badge` or `Text` | `Toggle` |
|
|
146
|
-
| `array` of strings |
|
|
147
|
-
| `object` / nested `array` of objects |
|
|
146
|
+
| `array` of strings | read-only `FilterChips` (no selection, no `onChange`) | `ChipsInput` |
|
|
147
|
+
| `object` / nested `array` of objects | a labelled sub-section of key/value rows, one level deep: one row per key (an array: one row per item, `Item 1`, …), a deeper value inline as `Key: value · …` | none. Edit it on the web app |
|
|
148
148
|
| built-ins `id`, `created_date`, `updated_date`, `created_by` | "Created …" metadata row | never editable |
|
|
149
149
|
|
|
150
150
|
4. **Respect the entity's rules.** `rls` (and field-level `rls`) decide what the signed-in user
|
|
@@ -161,7 +161,17 @@ Write `.himi/screen-plan.md` before editing code. For each entity in `book.entit
|
|
|
161
161
|
A field whose field-level `rls.write` is not `true` is read-only in the form. The gate is
|
|
162
162
|
advisory: a denied call still fails with Base44's message, and every screen paints that error
|
|
163
163
|
rather than swallowing it.
|
|
164
|
-
5. **
|
|
164
|
+
5. **Declare `open_url` when an entity has an email or URL field.** The detail opens those facts
|
|
165
|
+
through `@himalaya/open-url`, so the app must list the capability:
|
|
166
|
+
`capabilities: ["base44", "open_url"]` in `config.ts`. Without it `himi base44 screens` writes
|
|
167
|
+
nothing and fails with `code: "missing_capability"` (`capability: "open_url"`, and `missing[]`
|
|
168
|
+
names the entities that need it). The binary's native config follows from that list (the
|
|
169
|
+
capability catalog, `himi docs capabilities`), so a shell built without it needs a new
|
|
170
|
+
`himi dist`. Only the detail of an entity with such a field imports `@himalaya/open-url` and
|
|
171
|
+
declares `open_url`. A value that is not an address or an http(s) URL (`javascript:`, an app
|
|
172
|
+
scheme) is shown as plain text and never opened. A link, chips or section fact with no value
|
|
173
|
+
shows a `—` row instead.
|
|
174
|
+
6. **Use the sample rows** (`sampleRows`, already redacted) to size rows and choose the subtitle,
|
|
165
175
|
never as data the app ships.
|
|
166
176
|
|
|
167
177
|
Compose each screen with [`designing-himi-screens`](designing-himi-screens.md)
|
|
@@ -202,8 +212,10 @@ Re-running is safe. Each generated file starts with
|
|
|
202
212
|
`skipped-edited` and left alone, and the command still exits 0. Pass `--force` to overwrite it;
|
|
203
213
|
- files for an entity you removed from `config.ts` are reported in `orphaned[]` and never deleted.
|
|
204
214
|
|
|
205
|
-
`--dry-run` reports the same outcomes without writing.
|
|
206
|
-
(`
|
|
215
|
+
`--dry-run` reports the same outcomes without writing. On success `capabilities[]` lists what the
|
|
216
|
+
generated screens need (`base44`, plus `open_url` with a link field). Failures carry a top-level
|
|
217
|
+
`code` (`no_entities_block`, `entity_id_collision`, `missing_capability`,
|
|
218
|
+
`content_dir_not_base44_starter`), per
|
|
207
219
|
[`himi-json-output`](himi-json-output.md). The generator never calls Base44.
|
|
208
220
|
|
|
209
221
|
To change a screen beyond what the plan expresses (a filtered list, a child section, a custom
|
|
@@ -324,9 +324,14 @@ on stderr (exit 1):
|
|
|
324
324
|
- `no_entities_block`: `config.ts` declares no `base44.entities`, so there is nothing to generate.
|
|
325
325
|
- `entity_id_collision`: two entities would generate the same screen id (or one would shadow
|
|
326
326
|
`b44_functions` / `b44_account` / `b44_more`); `entity`, `screenId` and `with` name the clash.
|
|
327
|
+
- `missing_capability`: an entity has an email / URL field, which the detail opens through
|
|
328
|
+
`@himalaya/open-url`, and `config.ts` `capabilities` does not list `open_url`. `capability` names
|
|
329
|
+
it and `missing[]` gives `{ capability, entities }` per missing id. Nothing is written. Add it to
|
|
330
|
+
`capabilities` and re-run.
|
|
327
331
|
- `config_unloadable` / `invalid_config`: as for `himi base44 entities` above.
|
|
328
332
|
|
|
329
|
-
On success (`ok: true`, stdout, exit 0) `
|
|
333
|
+
On success (`ok: true`, stdout, exit 0) `capabilities[]` lists the ids the generated screens need
|
|
334
|
+
(`base44`, plus `open_url` with a link field), and `files[]` gives every generated path with its `outcome`:
|
|
330
335
|
`written`, `unchanged`, or `skipped-edited` (the file was edited by hand and was left alone; pass
|
|
331
336
|
`--force` to overwrite it). A skipped file is not a failure. `orphaned[]`, when present, lists
|
|
332
337
|
generated files for entities no longer declared. They are never deleted.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1438.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"artifactId": "himalaya-cli"
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
|
-
"falconPackageHash": "
|
|
74
|
+
"falconPackageHash": "ecadfa529dda6d1f49570340c04988f711cb239a5209ce8c69e31e86"
|
|
75
75
|
}
|