@wix/himalaya-cli 0.1437.0 → 0.1439.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 +466 -86
- 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;
|
|
@@ -8078,7 +8078,6 @@ function resolveTranslation(value, catalog3, sourceCatalog) {
|
|
|
8078
8078
|
var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
|
|
8079
8079
|
var init_bindings = __esm({
|
|
8080
8080
|
"../../core/ts/src/bindings.ts"() {
|
|
8081
|
-
"use strict";
|
|
8082
8081
|
BINDING_SIGILS = ["service", "flag", "item", "t"];
|
|
8083
8082
|
BINDING_SIGIL_RE = new RegExp(
|
|
8084
8083
|
`^\\$(?:${BINDING_SIGILS.filter((s2) => s2 !== "t").join("|")})\\b|^\\$t:`
|
|
@@ -15051,7 +15050,7 @@ async function compileContentHhp(root, opts = {}) {
|
|
|
15051
15050
|
seen.add(file3);
|
|
15052
15051
|
const source = readFileSync16(file3, "utf8");
|
|
15053
15052
|
inspectModule(source, file3, profile, diagnostics);
|
|
15054
|
-
for (const cap of moduleCapabilities(source, file3, profile))
|
|
15053
|
+
for (const cap of moduleCapabilities(source, file3, profile)) requiredCapabilities2.add(cap);
|
|
15055
15054
|
const sf2 = ts3.createSourceFile(file3, source, ts3.ScriptTarget.Latest, true);
|
|
15056
15055
|
for (const stmt of sf2.statements) if ((ts3.isImportDeclaration(stmt) || ts3.isExportDeclaration(stmt)) && stmt.moduleSpecifier && ts3.isStringLiteral(stmt.moduleSpecifier) && stmt.moduleSpecifier.text.startsWith(".")) {
|
|
15057
15056
|
let imported = localPath(root, stmt.moduleSpecifier.text, file3);
|
|
@@ -15066,9 +15065,9 @@ async function compileContentHhp(root, opts = {}) {
|
|
|
15066
15065
|
diagnostics.push(...result2.diagnostics);
|
|
15067
15066
|
results.push(result2);
|
|
15068
15067
|
const seen = /* @__PURE__ */ new Set();
|
|
15069
|
-
const
|
|
15068
|
+
const requiredCapabilities2 = new Set(result2.manifest.requiredCapabilities);
|
|
15070
15069
|
for (const dependency of result2.dependencies.filter((f2) => /\.tsx?$/.test(f2))) inspect2(dependency);
|
|
15071
|
-
result2.manifest.requiredCapabilities = [...
|
|
15070
|
+
result2.manifest.requiredCapabilities = [...requiredCapabilities2].sort();
|
|
15072
15071
|
outputs.set(`dev/hhp/${id}.descriptor.json`, JSON.stringify(result2.descriptor, null, 2) + "\n");
|
|
15073
15072
|
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
15073
|
if (result2.worker && result2.bundleName) {
|
|
@@ -17852,6 +17851,7 @@ function resolveIdiom(tokens2, ctx = {}) {
|
|
|
17852
17851
|
var IDIOM_CONTEXTS, UNSAFE_KEYS;
|
|
17853
17852
|
var init_idiom = __esm({
|
|
17854
17853
|
"../../core/ts/src/idiom.ts"() {
|
|
17854
|
+
"use strict";
|
|
17855
17855
|
IDIOM_CONTEXTS = {
|
|
17856
17856
|
ios: { native: ["ios"] },
|
|
17857
17857
|
android: { native: ["material"] },
|
|
@@ -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,
|
|
@@ -131175,12 +131234,14 @@ __export(render_descriptor_exports, {
|
|
|
131175
131234
|
clientEnvFor: () => clientEnvFor,
|
|
131176
131235
|
collectNativeOnly: () => collectNativeOnly,
|
|
131177
131236
|
isMissingPlaywrightExecutable: () => isMissingPlaywrightExecutable,
|
|
131237
|
+
launchPngBrowser: () => launchPngBrowser,
|
|
131178
131238
|
nodeHidden: () => nodeHidden,
|
|
131179
131239
|
pngAvailable: () => pngAvailable,
|
|
131180
131240
|
pngPageHtml: () => pngPageHtml,
|
|
131181
131241
|
renderDescriptorWeb: () => renderDescriptorWeb,
|
|
131182
131242
|
renderPngBatch: () => renderPngBatch,
|
|
131183
131243
|
renderSchemeFor: () => renderSchemeFor,
|
|
131244
|
+
setPngEgress: () => setPngEgress,
|
|
131184
131245
|
setPngFontCss: () => setPngFontCss,
|
|
131185
131246
|
stabilizePngPage: () => stabilizePngPage,
|
|
131186
131247
|
withRetry: () => withRetry2
|
|
@@ -131474,7 +131535,7 @@ async function renderDescriptorWeb(descriptor, tokens2, scheme, wantPng, service
|
|
|
131474
131535
|
) : void 0;
|
|
131475
131536
|
let html;
|
|
131476
131537
|
try {
|
|
131477
|
-
const { renderDescriptorToHtml: renderDescriptorToHtml2 } = await Promise.resolve().then(() => (init_src5(),
|
|
131538
|
+
const { renderDescriptorToHtml: renderDescriptorToHtml2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
|
|
131478
131539
|
html = renderDescriptorToHtml2(
|
|
131479
131540
|
payload,
|
|
131480
131541
|
tokens2 ?? {},
|
|
@@ -131571,8 +131632,24 @@ async function stabilizePngPage(page, scheme) {
|
|
|
131571
131632
|
await new Promise((resolve66) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve66())));
|
|
131572
131633
|
}, scheme);
|
|
131573
131634
|
}
|
|
131574
|
-
|
|
131575
|
-
|
|
131635
|
+
function setPngEgress(start) {
|
|
131636
|
+
const prev = pngEgress;
|
|
131637
|
+
pngEgress = start;
|
|
131638
|
+
return prev;
|
|
131639
|
+
}
|
|
131640
|
+
async function pngEgressStart() {
|
|
131641
|
+
if (pngEgress !== void 0) return pngEgress;
|
|
131642
|
+
const spec = "./png-egress.js";
|
|
131643
|
+
try {
|
|
131644
|
+
return (await import(
|
|
131645
|
+
/* @vite-ignore */
|
|
131646
|
+
spec
|
|
131647
|
+
)).startEgressProxy;
|
|
131648
|
+
} catch {
|
|
131649
|
+
return null;
|
|
131650
|
+
}
|
|
131651
|
+
}
|
|
131652
|
+
async function launchPngBrowser() {
|
|
131576
131653
|
let chromium;
|
|
131577
131654
|
try {
|
|
131578
131655
|
({ chromium } = await import("playwright"));
|
|
@@ -131580,13 +131657,41 @@ async function renderPngBatch(items) {
|
|
|
131580
131657
|
return null;
|
|
131581
131658
|
}
|
|
131582
131659
|
if (!chromium) return null;
|
|
131660
|
+
const start = await pngEgressStart();
|
|
131661
|
+
if (!start) return null;
|
|
131662
|
+
let egress;
|
|
131663
|
+
try {
|
|
131664
|
+
egress = await start();
|
|
131665
|
+
} catch {
|
|
131666
|
+
return null;
|
|
131667
|
+
}
|
|
131583
131668
|
const launch = chromium.launch.bind(chromium);
|
|
131584
131669
|
let browser;
|
|
131585
131670
|
try {
|
|
131586
|
-
browser = await withRetry2(() => launch(
|
|
131671
|
+
browser = await withRetry2(() => launch({
|
|
131672
|
+
proxy: { server: egress.url, bypass: "<-loopback>" },
|
|
131673
|
+
args: ["--force-webrtc-ip-handling-policy=disable_non_proxied_udp", "--webrtc-ip-handling-policy=disable_non_proxied_udp"]
|
|
131674
|
+
}), 3);
|
|
131587
131675
|
} catch {
|
|
131676
|
+
await egress.close().catch(() => {
|
|
131677
|
+
});
|
|
131588
131678
|
return null;
|
|
131589
131679
|
}
|
|
131680
|
+
return {
|
|
131681
|
+
browser,
|
|
131682
|
+
close: async () => {
|
|
131683
|
+
await browser.close().catch(() => {
|
|
131684
|
+
});
|
|
131685
|
+
await egress.close().catch(() => {
|
|
131686
|
+
});
|
|
131687
|
+
}
|
|
131688
|
+
};
|
|
131689
|
+
}
|
|
131690
|
+
async function renderPngBatch(items) {
|
|
131691
|
+
if (!items.length) return [];
|
|
131692
|
+
const launched = await launchPngBrowser();
|
|
131693
|
+
if (!launched) return null;
|
|
131694
|
+
const { browser } = launched;
|
|
131590
131695
|
try {
|
|
131591
131696
|
const out2 = [];
|
|
131592
131697
|
for (const it2 of items) {
|
|
@@ -131607,11 +131712,10 @@ async function renderPngBatch(items) {
|
|
|
131607
131712
|
}
|
|
131608
131713
|
return out2;
|
|
131609
131714
|
} finally {
|
|
131610
|
-
await
|
|
131611
|
-
});
|
|
131715
|
+
await launched.close();
|
|
131612
131716
|
}
|
|
131613
131717
|
}
|
|
131614
|
-
var A11Y_MODIFIER_KEYS, TREE_TEXT_VALUE_PROPS, asStringOrNumber, asStringOnly, asOtpCode, VALUE_PATH_TEXT, MEDIA_PLAYER_QUEUE_PROPERTIES, NATIVE_ONLY_TYPES, HOST_PAGE_FONT, pngFontCss;
|
|
131718
|
+
var A11Y_MODIFIER_KEYS, TREE_TEXT_VALUE_PROPS, asStringOrNumber, asStringOnly, asOtpCode, VALUE_PATH_TEXT, MEDIA_PLAYER_QUEUE_PROPERTIES, NATIVE_ONLY_TYPES, HOST_PAGE_FONT, pngFontCss, pngEgress;
|
|
131615
131719
|
var init_render_descriptor = __esm({
|
|
131616
131720
|
"../../core/dev-server/src/render-descriptor.ts"() {
|
|
131617
131721
|
init_tokens2();
|
|
@@ -131655,6 +131759,229 @@ var init_render_descriptor = __esm({
|
|
|
131655
131759
|
}
|
|
131656
131760
|
});
|
|
131657
131761
|
|
|
131762
|
+
// ../../core/dev-server/src/png-egress.ts
|
|
131763
|
+
import http from "node:http";
|
|
131764
|
+
import net from "node:net";
|
|
131765
|
+
import { lookup as lookup2 } from "node:dns/promises";
|
|
131766
|
+
function isPublicAddress(ip) {
|
|
131767
|
+
const family = net.isIP(ip);
|
|
131768
|
+
if (family === 0) return false;
|
|
131769
|
+
return family === 4 ? !BLOCKED_V4.check(ip, "ipv4") : !BLOCKED_V6.check(ip, "ipv6");
|
|
131770
|
+
}
|
|
131771
|
+
function originKey(origin) {
|
|
131772
|
+
try {
|
|
131773
|
+
const u2 = new URL(origin);
|
|
131774
|
+
return hostPortKey(u2.hostname, u2.port || (u2.protocol === "https:" ? "443" : "80"));
|
|
131775
|
+
} catch {
|
|
131776
|
+
return null;
|
|
131777
|
+
}
|
|
131778
|
+
}
|
|
131779
|
+
function hostPortKey(host, port) {
|
|
131780
|
+
return `${host.replace(/^\[|\]$/g, "").replace(/\.$/, "").toLowerCase()}:${port}`;
|
|
131781
|
+
}
|
|
131782
|
+
function allowPngOrigins(origins) {
|
|
131783
|
+
const keys = origins.map(originKey).filter((k2) => !!k2);
|
|
131784
|
+
for (const k2 of keys) allowedOrigins.set(k2, (allowedOrigins.get(k2) ?? 0) + 1);
|
|
131785
|
+
return () => {
|
|
131786
|
+
for (const k2 of keys) {
|
|
131787
|
+
const n2 = (allowedOrigins.get(k2) ?? 1) - 1;
|
|
131788
|
+
if (n2 <= 0) allowedOrigins.delete(k2);
|
|
131789
|
+
else allowedOrigins.set(k2, n2);
|
|
131790
|
+
}
|
|
131791
|
+
};
|
|
131792
|
+
}
|
|
131793
|
+
function ownOrigins(port, publicBase) {
|
|
131794
|
+
return [`http://localhost:${port}`, `http://127.0.0.1:${port}`, `http://[::1]:${port}`, ...publicBase ? [publicBase] : []];
|
|
131795
|
+
}
|
|
131796
|
+
async function resolveEgress(host, port, allow = allowedOrigins) {
|
|
131797
|
+
const bare = host.replace(/^\[|\]$/g, "");
|
|
131798
|
+
let addrs;
|
|
131799
|
+
try {
|
|
131800
|
+
addrs = net.isIP(bare) ? [{ address: bare, family: net.isIP(bare) }] : await lookup2(bare.replace(/\.$/, ""), { all: true, order: "ipv4first" });
|
|
131801
|
+
} catch {
|
|
131802
|
+
return null;
|
|
131803
|
+
}
|
|
131804
|
+
if (!addrs.length) return null;
|
|
131805
|
+
if (allow.has(hostPortKey(host, port))) return addrs;
|
|
131806
|
+
return addrs.every((a2) => isPublicAddress(a2.address)) ? addrs : null;
|
|
131807
|
+
}
|
|
131808
|
+
function connectFirst(addrs, port, track) {
|
|
131809
|
+
return new Promise((resolve66, reject) => {
|
|
131810
|
+
const tryAt = (i2) => {
|
|
131811
|
+
if (i2 >= addrs.length) return reject(new Error("no address answered"));
|
|
131812
|
+
const s2 = net.connect({ host: addrs[i2].address, family: addrs[i2].family, port });
|
|
131813
|
+
track(s2);
|
|
131814
|
+
s2.setTimeout(CONNECT_TIMEOUT_MS, () => s2.destroy(new Error("connect timeout")));
|
|
131815
|
+
const onFail = () => {
|
|
131816
|
+
s2.destroy();
|
|
131817
|
+
tryAt(i2 + 1);
|
|
131818
|
+
};
|
|
131819
|
+
s2.once("error", onFail);
|
|
131820
|
+
s2.once("connect", () => {
|
|
131821
|
+
s2.off("error", onFail);
|
|
131822
|
+
s2.setTimeout(0);
|
|
131823
|
+
resolve66(s2);
|
|
131824
|
+
});
|
|
131825
|
+
};
|
|
131826
|
+
tryAt(0);
|
|
131827
|
+
});
|
|
131828
|
+
}
|
|
131829
|
+
async function startEgressProxy() {
|
|
131830
|
+
const blocked = [];
|
|
131831
|
+
const sockets = /* @__PURE__ */ new Set();
|
|
131832
|
+
const track = (s2) => {
|
|
131833
|
+
sockets.add(s2);
|
|
131834
|
+
s2.once("close", () => sockets.delete(s2));
|
|
131835
|
+
};
|
|
131836
|
+
const guard = (s2) => {
|
|
131837
|
+
track(s2);
|
|
131838
|
+
s2.on("error", () => s2.destroy());
|
|
131839
|
+
};
|
|
131840
|
+
const server = http.createServer(async (req, res) => {
|
|
131841
|
+
let u2;
|
|
131842
|
+
try {
|
|
131843
|
+
u2 = new URL(req.url ?? "");
|
|
131844
|
+
} catch {
|
|
131845
|
+
res.writeHead(400).end();
|
|
131846
|
+
return;
|
|
131847
|
+
}
|
|
131848
|
+
const port2 = Number(u2.port || 80);
|
|
131849
|
+
const addrs = u2.protocol === "http:" ? await resolveEgress(u2.hostname, port2) : null;
|
|
131850
|
+
if (!addrs) {
|
|
131851
|
+
blocked.push(hostPortKey(u2.hostname, port2));
|
|
131852
|
+
res.writeHead(403).end();
|
|
131853
|
+
return;
|
|
131854
|
+
}
|
|
131855
|
+
let sock;
|
|
131856
|
+
try {
|
|
131857
|
+
sock = await connectFirst(addrs, port2, guard);
|
|
131858
|
+
} catch {
|
|
131859
|
+
res.writeHead(502).end();
|
|
131860
|
+
return;
|
|
131861
|
+
}
|
|
131862
|
+
const headers2 = { ...req.headers, host: u2.host };
|
|
131863
|
+
delete headers2["proxy-connection"];
|
|
131864
|
+
const upstream = http.request({ createConnection: () => sock, method: req.method, path: `${u2.pathname}${u2.search}`, headers: headers2 }, (up) => {
|
|
131865
|
+
res.writeHead(up.statusCode ?? 502, up.headers);
|
|
131866
|
+
up.pipe(res);
|
|
131867
|
+
});
|
|
131868
|
+
upstream.on("error", () => {
|
|
131869
|
+
if (!res.headersSent) res.writeHead(502);
|
|
131870
|
+
res.end();
|
|
131871
|
+
});
|
|
131872
|
+
req.pipe(upstream);
|
|
131873
|
+
});
|
|
131874
|
+
server.on("connection", guard);
|
|
131875
|
+
server.on("clientError", (_e2, socket) => socket.destroy());
|
|
131876
|
+
server.on("connect", async (req, socket, head) => {
|
|
131877
|
+
guard(socket);
|
|
131878
|
+
const m2 = /^\[?([^\]]+?)\]?:(\d+)$/.exec(req.url ?? "");
|
|
131879
|
+
const addrs = m2 ? await resolveEgress(m2[1], Number(m2[2])) : null;
|
|
131880
|
+
if (!m2 || !addrs) {
|
|
131881
|
+
blocked.push(m2 ? hostPortKey(m2[1], m2[2]) : String(req.url));
|
|
131882
|
+
socket.end("HTTP/1.1 403 Forbidden\r\n\r\n");
|
|
131883
|
+
return;
|
|
131884
|
+
}
|
|
131885
|
+
let upstream;
|
|
131886
|
+
try {
|
|
131887
|
+
upstream = await connectFirst(addrs, Number(m2[2]), guard);
|
|
131888
|
+
} catch {
|
|
131889
|
+
socket.end("HTTP/1.1 502 Bad Gateway\r\n\r\n");
|
|
131890
|
+
return;
|
|
131891
|
+
}
|
|
131892
|
+
socket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
131893
|
+
if (head.length) upstream.write(head);
|
|
131894
|
+
upstream.pipe(socket);
|
|
131895
|
+
socket.pipe(upstream);
|
|
131896
|
+
});
|
|
131897
|
+
server.on("upgrade", async (req, socket, head) => {
|
|
131898
|
+
guard(socket);
|
|
131899
|
+
let u2;
|
|
131900
|
+
try {
|
|
131901
|
+
u2 = new URL(req.url ?? "");
|
|
131902
|
+
} catch {
|
|
131903
|
+
socket.destroy();
|
|
131904
|
+
return;
|
|
131905
|
+
}
|
|
131906
|
+
const port2 = Number(u2.port || 80);
|
|
131907
|
+
const addrs = await resolveEgress(u2.hostname, port2);
|
|
131908
|
+
if (!addrs) {
|
|
131909
|
+
blocked.push(hostPortKey(u2.hostname, port2));
|
|
131910
|
+
socket.end("HTTP/1.1 403 Forbidden\r\n\r\n");
|
|
131911
|
+
return;
|
|
131912
|
+
}
|
|
131913
|
+
let upstream;
|
|
131914
|
+
try {
|
|
131915
|
+
upstream = await connectFirst(addrs, port2, guard);
|
|
131916
|
+
} catch {
|
|
131917
|
+
socket.end("HTTP/1.1 502 Bad Gateway\r\n\r\n");
|
|
131918
|
+
return;
|
|
131919
|
+
}
|
|
131920
|
+
const lines = [`${req.method} ${u2.pathname}${u2.search} HTTP/1.1`];
|
|
131921
|
+
for (let i2 = 0; i2 < req.rawHeaders.length; i2 += 2) lines.push(`${req.rawHeaders[i2]}: ${req.rawHeaders[i2 + 1]}`);
|
|
131922
|
+
upstream.write(`${lines.join("\r\n")}\r
|
|
131923
|
+
\r
|
|
131924
|
+
`);
|
|
131925
|
+
if (head.length) upstream.write(head);
|
|
131926
|
+
upstream.pipe(socket);
|
|
131927
|
+
socket.pipe(upstream);
|
|
131928
|
+
});
|
|
131929
|
+
await new Promise((resolve66, reject) => {
|
|
131930
|
+
server.once("error", reject);
|
|
131931
|
+
server.listen(0, "127.0.0.1", () => resolve66());
|
|
131932
|
+
});
|
|
131933
|
+
const { port } = server.address();
|
|
131934
|
+
return {
|
|
131935
|
+
url: `http://127.0.0.1:${port}`,
|
|
131936
|
+
blocked,
|
|
131937
|
+
close: () => new Promise((resolve66) => {
|
|
131938
|
+
server.close(() => resolve66());
|
|
131939
|
+
for (const s2 of sockets) s2.destroy();
|
|
131940
|
+
server.closeAllConnections?.();
|
|
131941
|
+
})
|
|
131942
|
+
};
|
|
131943
|
+
}
|
|
131944
|
+
var BLOCKED_V4, BLOCKED_V6, CONNECT_TIMEOUT_MS, allowedOrigins;
|
|
131945
|
+
var init_png_egress = __esm({
|
|
131946
|
+
"../../core/dev-server/src/png-egress.ts"() {
|
|
131947
|
+
BLOCKED_V4 = new net.BlockList();
|
|
131948
|
+
BLOCKED_V6 = new net.BlockList();
|
|
131949
|
+
for (const [addr, prefix] of [
|
|
131950
|
+
["0.0.0.0", 8],
|
|
131951
|
+
["10.0.0.0", 8],
|
|
131952
|
+
["100.64.0.0", 10],
|
|
131953
|
+
["127.0.0.0", 8],
|
|
131954
|
+
["169.254.0.0", 16],
|
|
131955
|
+
["172.16.0.0", 12],
|
|
131956
|
+
["192.0.0.0", 24],
|
|
131957
|
+
["192.0.2.0", 24],
|
|
131958
|
+
["192.88.99.0", 24],
|
|
131959
|
+
["192.168.0.0", 16],
|
|
131960
|
+
["198.18.0.0", 15],
|
|
131961
|
+
["198.51.100.0", 24],
|
|
131962
|
+
["203.0.113.0", 24],
|
|
131963
|
+
["224.0.0.0", 4],
|
|
131964
|
+
["240.0.0.0", 4]
|
|
131965
|
+
]) BLOCKED_V4.addSubnet(addr, prefix, "ipv4");
|
|
131966
|
+
for (const [addr, prefix] of [
|
|
131967
|
+
["::", 96],
|
|
131968
|
+
["::ffff:0:0", 96],
|
|
131969
|
+
["64:ff9b::", 96],
|
|
131970
|
+
["64:ff9b:1::", 48],
|
|
131971
|
+
["100::", 64],
|
|
131972
|
+
["2001::", 23],
|
|
131973
|
+
["2001:db8::", 32],
|
|
131974
|
+
["2002::", 16],
|
|
131975
|
+
["fc00::", 7],
|
|
131976
|
+
["fe80::", 10],
|
|
131977
|
+
["fec0::", 10],
|
|
131978
|
+
["ff00::", 8]
|
|
131979
|
+
]) BLOCKED_V6.addSubnet(addr, prefix, "ipv6");
|
|
131980
|
+
CONNECT_TIMEOUT_MS = 1e4;
|
|
131981
|
+
allowedOrigins = /* @__PURE__ */ new Map();
|
|
131982
|
+
}
|
|
131983
|
+
});
|
|
131984
|
+
|
|
131658
131985
|
// ../../core/dev-server/src/render-fonts.ts
|
|
131659
131986
|
import { existsSync as existsSync45, readFileSync as readFileSync49 } from "node:fs";
|
|
131660
131987
|
import { extname, join as join44 } from "node:path";
|
|
@@ -131744,7 +132071,7 @@ async function pngFontFaceCss(tokens2, opts = {}) {
|
|
|
131744
132071
|
return rules.join("");
|
|
131745
132072
|
}
|
|
131746
132073
|
async function idiomFontFaceCss(idiomContext) {
|
|
131747
|
-
const { controlIdiomFor: controlIdiomFor2, idiomControls: idiomControls2 } = await Promise.resolve().then(() => (init_src5(),
|
|
132074
|
+
const { controlIdiomFor: controlIdiomFor2, idiomControls: idiomControls2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
|
|
131748
132075
|
const bundled = idiomControls2(controlIdiomFor2(idiomContext)).font.bundled;
|
|
131749
132076
|
if (!bundled) return "";
|
|
131750
132077
|
try {
|
|
@@ -136245,6 +136572,17 @@ function createDevServer(opts = {}) {
|
|
|
136245
136572
|
})();
|
|
136246
136573
|
};
|
|
136247
136574
|
const httpServer = createServer3(handleRequest);
|
|
136575
|
+
let disallowOwnOrigins;
|
|
136576
|
+
httpServer.on("listening", () => {
|
|
136577
|
+
const addr = httpServer.address();
|
|
136578
|
+
if (!addr || typeof addr === "string") return;
|
|
136579
|
+
disallowOwnOrigins?.();
|
|
136580
|
+
disallowOwnOrigins = allowPngOrigins(ownOrigins(addr.port, process.env.HIMALAYA_DEV_PUBLIC_URL));
|
|
136581
|
+
});
|
|
136582
|
+
httpServer.on("close", () => {
|
|
136583
|
+
disallowOwnOrigins?.();
|
|
136584
|
+
disallowOwnOrigins = void 0;
|
|
136585
|
+
});
|
|
136248
136586
|
httpServer.inject = (request) => injectRequest(handleRequest, request);
|
|
136249
136587
|
httpServer.on("clientError", (err, socket) => {
|
|
136250
136588
|
console.error(`[himalaya-dev] malformed request rejected by the HTTP parser: ${err.code ?? ""} ${err.message}`);
|
|
@@ -136320,6 +136658,7 @@ var init_src6 = __esm({
|
|
|
136320
136658
|
init_check();
|
|
136321
136659
|
init_openapi();
|
|
136322
136660
|
init_render_descriptor();
|
|
136661
|
+
init_png_egress();
|
|
136323
136662
|
init_render_fonts();
|
|
136324
136663
|
init_app_config();
|
|
136325
136664
|
init_tier();
|
|
@@ -136331,6 +136670,7 @@ var init_src6 = __esm({
|
|
|
136331
136670
|
init_descriptor_postprocess();
|
|
136332
136671
|
ROOT6 = resolve38(fileURLToPath22(new URL("../../..", import.meta.url)));
|
|
136333
136672
|
setPngFontCss(async (tokens2, idiomContext) => await pngFontFaceCss(tokens2) + (idiomContext ? await idiomFontFaceCss(idiomContext) : ""));
|
|
136673
|
+
setPngEgress(startEgressProxy);
|
|
136334
136674
|
TIER3_ROOT = resolve38(ROOT6, "core/dev-server/web");
|
|
136335
136675
|
TIER4_ROOT = resolve38(ROOT6, "core/dev-server/tier4-bundles");
|
|
136336
136676
|
tier4Verifier = new TierFourVerifier(TIER4_ROOT);
|
|
@@ -140282,7 +140622,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140282
140622
|
};
|
|
140283
140623
|
let handlers;
|
|
140284
140624
|
let minBinaryVersion = null;
|
|
140285
|
-
const
|
|
140625
|
+
const requiredCapabilities2 = new Set(config.capabilities ?? []);
|
|
140286
140626
|
const capabilityUsage = {
|
|
140287
140627
|
app: [...config.capabilities ?? []],
|
|
140288
140628
|
...Array.isArray(config.capabilityEnvelope) ? { envelope: [...config.capabilityEnvelope] } : {},
|
|
@@ -140293,7 +140633,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140293
140633
|
const ids = Array.isArray(declared) ? declared.filter((c2) => typeof c2 === "string") : [];
|
|
140294
140634
|
const components2 = [...collectComponentTypes(descriptor)].sort();
|
|
140295
140635
|
capabilityUsage.screens.push({ screenId, bundle, declared: ids, components: components2 });
|
|
140296
|
-
for (const c2 of componentModuleRequirements(components2, [...
|
|
140636
|
+
for (const c2 of componentModuleRequirements(components2, [...requiredCapabilities2, ...ids])) requiredCapabilities2.add(c2);
|
|
140297
140637
|
};
|
|
140298
140638
|
const requiredNativeComponents = /* @__PURE__ */ new Set();
|
|
140299
140639
|
const tierScreens = [];
|
|
@@ -140537,7 +140877,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140537
140877
|
minBinaryVersion = maximumBinaryVersion(minBinaryVersion, lb.minBinaryVersion);
|
|
140538
140878
|
const declared = lb.declaredCapabilities ?? lb.declared_capabilities;
|
|
140539
140879
|
if (Array.isArray(declared)) {
|
|
140540
|
-
for (const capability of declared) if (typeof capability === "string")
|
|
140880
|
+
for (const capability of declared) if (typeof capability === "string") requiredCapabilities2.add(capability);
|
|
140541
140881
|
}
|
|
140542
140882
|
noteScreenCapabilities(screenId, bundleName, declared, descriptor);
|
|
140543
140883
|
} else {
|
|
@@ -140687,7 +141027,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140687
141027
|
minBinaryVersion = maximumBinaryVersion(minBinaryVersion, lb.minBinaryVersion);
|
|
140688
141028
|
const declared = lb.declaredCapabilities ?? lb.declared_capabilities;
|
|
140689
141029
|
if (Array.isArray(declared)) {
|
|
140690
|
-
for (const c2 of declared) if (typeof c2 === "string")
|
|
141030
|
+
for (const c2 of declared) if (typeof c2 === "string") requiredCapabilities2.add(c2);
|
|
140691
141031
|
}
|
|
140692
141032
|
noteScreenCapabilities(screenId, bundleName, declared, descriptor);
|
|
140693
141033
|
} else {
|
|
@@ -140855,7 +141195,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
140855
141195
|
// whose source catalog serves copy (native screens, #4221/#4250) now carries `en` here.
|
|
140856
141196
|
...Object.keys(catalogs).length ? { catalogs } : {},
|
|
140857
141197
|
playerRequirements: {
|
|
140858
|
-
capabilities: [...
|
|
141198
|
+
capabilities: [...requiredCapabilities2].sort(),
|
|
140859
141199
|
nativeComponents: [...requiredNativeComponents].sort(),
|
|
140860
141200
|
// `none` is the scaffold's spelling of "no auth" (`new-app --auth=none`), not a provider a
|
|
140861
141201
|
// host must carry — recording it blocked every such app in the Player picker (#3695).
|
|
@@ -150220,7 +150560,7 @@ function defineAppLiteral(file2) {
|
|
|
150220
150560
|
return void 0;
|
|
150221
150561
|
}
|
|
150222
150562
|
function loginOf(app) {
|
|
150223
|
-
const auth =
|
|
150563
|
+
const auth = lookup3(app, "auth");
|
|
150224
150564
|
if (auth.kind !== "written") return { kind: auth.kind === "absent" ? "other" : "opaque" };
|
|
150225
150565
|
const value = unwrap(auth.node.initializer);
|
|
150226
150566
|
if (ts5.isObjectLiteralExpression(value)) return { kind: "other" };
|
|
@@ -150248,7 +150588,7 @@ function unwrap(node) {
|
|
|
150248
150588
|
}
|
|
150249
150589
|
return current;
|
|
150250
150590
|
}
|
|
150251
|
-
function
|
|
150591
|
+
function lookup3(literal, name) {
|
|
150252
150592
|
let found = { kind: "absent" };
|
|
150253
150593
|
for (const p2 of literal.properties) {
|
|
150254
150594
|
const key3 = p2.name && (ts5.isIdentifier(p2.name) || ts5.isStringLiteral(p2.name)) ? p2.name.text : void 0;
|
|
@@ -150259,7 +150599,7 @@ function lookup2(literal, name) {
|
|
|
150259
150599
|
}
|
|
150260
150600
|
function stringValue(node, name) {
|
|
150261
150601
|
const literal = unwrap(node);
|
|
150262
|
-
const found = ts5.isObjectLiteralExpression(literal) ?
|
|
150602
|
+
const found = ts5.isObjectLiteralExpression(literal) ? lookup3(literal, name) : void 0;
|
|
150263
150603
|
const value = found?.kind === "written" ? found.node.initializer : void 0;
|
|
150264
150604
|
return value && ts5.isStringLiteralLike(value) ? value.text : void 0;
|
|
150265
150605
|
}
|
|
@@ -150371,7 +150711,7 @@ function enablePushInConfig(source, options) {
|
|
|
150371
150711
|
};
|
|
150372
150712
|
}
|
|
150373
150713
|
function planPush(app, pingAppName, plan) {
|
|
150374
|
-
const push =
|
|
150714
|
+
const push = lookup3(app, "push");
|
|
150375
150715
|
if (push.kind === "absent") {
|
|
150376
150716
|
plan.appended.push([
|
|
150377
150717
|
ROUTES_COMMENT,
|
|
@@ -150402,7 +150742,7 @@ function planPush(app, pingAppName, plan) {
|
|
|
150402
150742
|
}
|
|
150403
150743
|
function planRetiredFamily(block, plan) {
|
|
150404
150744
|
const literal = unwrap(block);
|
|
150405
|
-
const found = ts6.isObjectLiteralExpression(literal) ?
|
|
150745
|
+
const found = ts6.isObjectLiteralExpression(literal) ? lookup3(literal, "pingAppName") : void 0;
|
|
150406
150746
|
const value = found?.kind === "written" ? unwrap(found.node.initializer) : void 0;
|
|
150407
150747
|
const replacement = value && ts6.isStringLiteralLike(value) ? replacementPingFamily(value.text) : void 0;
|
|
150408
150748
|
if (!value || !replacement) return;
|
|
@@ -150410,7 +150750,7 @@ function planRetiredFamily(block, plan) {
|
|
|
150410
150750
|
plan.applied.push(`pingAppName ${JSON.stringify(replacement)} in place of ${value.getText()}`);
|
|
150411
150751
|
}
|
|
150412
150752
|
function planCapability(app, plan) {
|
|
150413
|
-
const capabilities =
|
|
150753
|
+
const capabilities = lookup3(app, "capabilities");
|
|
150414
150754
|
if (capabilities.kind === "absent") {
|
|
150415
150755
|
plan.appended.push(['capabilities: ["push"],']);
|
|
150416
150756
|
plan.applied.push("push capability");
|
|
@@ -150440,7 +150780,7 @@ function planAuthSite(login, file2, site, plan) {
|
|
|
150440
150780
|
);
|
|
150441
150781
|
return;
|
|
150442
150782
|
}
|
|
150443
|
-
const siteId =
|
|
150783
|
+
const siteId = lookup3(login.literal, "siteId");
|
|
150444
150784
|
if (siteId.kind === "absent") {
|
|
150445
150785
|
plan.splices.push(appendProperties(login.literal, file2, [`${wanted},`]));
|
|
150446
150786
|
plan.applied.push("auth siteId");
|
|
@@ -150527,8 +150867,8 @@ async function ask(question, deps) {
|
|
|
150527
150867
|
function defer(dir, input, scope, reason) {
|
|
150528
150868
|
return recordPushDeferral(dir, { reason, scope, missing: missingPushInputs(input, scope), identity: input, resume: resume(dir) });
|
|
150529
150869
|
}
|
|
150530
|
-
function renderPushStatus(
|
|
150531
|
-
const body =
|
|
150870
|
+
function renderPushStatus(http2, refresh = false) {
|
|
150871
|
+
const body = http2.body ?? {};
|
|
150532
150872
|
const verification = obj2(body.verification);
|
|
150533
150873
|
const state = typeof body.state === "string" && STATES.has(body.state) ? body.state : "unknown";
|
|
150534
150874
|
const mode = verification.mode === "live" ? "live" : verification.mode === "cached" ? "cached" : "unavailable";
|
|
@@ -150537,10 +150877,10 @@ function renderPushStatus(http, refresh = false) {
|
|
|
150537
150877
|
return [name, typeof value === "string" && CHECK_STATES.has(value) ? value : "unknown"];
|
|
150538
150878
|
}));
|
|
150539
150879
|
const rawCode = typeof body.error === "string" ? body.error.split(":")[0] : void 0;
|
|
150540
|
-
const responseError =
|
|
150541
|
-
const error = responseError ?? (!
|
|
150880
|
+
const responseError = http2.error ?? (rawCode ? ERROR_CODES.has(rawCode) ? rawCode : "push_setup_failed" : void 0);
|
|
150881
|
+
const error = responseError ?? (!http2.ok ? "push_setup_failed" : refresh && mode !== "live" ? "live_verification_unavailable" : void 0);
|
|
150542
150882
|
return {
|
|
150543
|
-
ok:
|
|
150883
|
+
ok: http2.ok && state === "ready" && !error && (!refresh || verification.backendConfigurationReady === true),
|
|
150544
150884
|
state,
|
|
150545
150885
|
verificationMode: mode,
|
|
150546
150886
|
backendConfigurationReady: verification.backendConfigurationReady === true,
|
|
@@ -150552,8 +150892,8 @@ function renderPushStatus(http, refresh = false) {
|
|
|
150552
150892
|
note: "Backend setup is separate from building the app, device registration and notification delivery."
|
|
150553
150893
|
};
|
|
150554
150894
|
}
|
|
150555
|
-
function report(
|
|
150556
|
-
const status = renderPushStatus(
|
|
150895
|
+
function report(http2, flags, io2, dir, config) {
|
|
150896
|
+
const status = renderPushStatus(http2, flags.refresh === true);
|
|
150557
150897
|
const result = config && !config.pushOn ? { ...status, ok: false, error: status.error ?? (config.rolledBack ? "config_edit_rolled_back" : "config_push_not_on") } : status;
|
|
150558
150898
|
const local = readPushOnboarding(dir).push;
|
|
150559
150899
|
io2.log(JSON.stringify({ ...result, ...local ? { localOnboarding: "deferred" } : {}, ...config ? { config } : {} }, null, 2));
|
|
@@ -154670,7 +155010,7 @@ async function runCrawl(opts) {
|
|
|
154670
155010
|
for (const d2 of list) if (d2.screenId !== rep.screenId) coveredBy.set(d2.screenId, rep.screenId);
|
|
154671
155011
|
}
|
|
154672
155012
|
}
|
|
154673
|
-
const
|
|
155013
|
+
const net2 = opts.offline ? null : opts.netPath ? { rules: readNetRules(resolve51(opts.netPath)), from: opts.netPath } : defaultNetRules(opts.dir);
|
|
154674
155014
|
const suppressions = opts.config?.skip ?? [];
|
|
154675
155015
|
const suppressed = [];
|
|
154676
155016
|
const matchSuppression = (screen, actionId, componentId, invariant) => suppressions.find((s2) => (s2.screen === void 0 || s2.screen === screen) && (s2.action === void 0 || s2.action === actionId) && (s2.component === void 0 || s2.component === componentId) && (s2.invariant === void 0 || s2.invariant === invariant));
|
|
@@ -154698,7 +155038,7 @@ async function runCrawl(opts) {
|
|
|
154698
155038
|
bundleMap: baked.bundleMap ?? null,
|
|
154699
155039
|
knownScreenIds,
|
|
154700
155040
|
...opts.linkableScreenIds?.size ? { linkableScreenIds: opts.linkableScreenIds } : {},
|
|
154701
|
-
rules:
|
|
155041
|
+
rules: net2?.rules ?? null,
|
|
154702
155042
|
...opts.cmsSeed && Object.keys(opts.cmsSeed).length ? { cmsSeed: opts.cmsSeed } : {},
|
|
154703
155043
|
...opts.canned?.count ? { canned: opts.canned.byKey } : {},
|
|
154704
155044
|
...localDbSchema?.length ? { localDbSchema } : {},
|
|
@@ -154840,7 +155180,7 @@ async function runCrawl(opts) {
|
|
|
154840
155180
|
bundleJs: baked.bundleJs,
|
|
154841
155181
|
bundleMap: baked.bundleMap ?? null,
|
|
154842
155182
|
knownScreenIds,
|
|
154843
|
-
rules:
|
|
155183
|
+
rules: net2?.rules ?? null,
|
|
154844
155184
|
...opts.cmsSeed && Object.keys(opts.cmsSeed).length ? { cmsSeed: opts.cmsSeed } : {},
|
|
154845
155185
|
...opts.canned?.count ? { canned: opts.canned.byKey } : {},
|
|
154846
155186
|
...localDbSchema?.length ? { localDbSchema } : {},
|
|
@@ -154907,7 +155247,7 @@ async function runCrawl(opts) {
|
|
|
154907
155247
|
// so a run over static or bundle-less screens injects the dependency and replays nothing —
|
|
154908
155248
|
// and the label then advertised "+ relations" beside `relations.checked: 0`. This is the
|
|
154909
155249
|
// second time this line has overstated itself: it first claimed the axis unconditionally.
|
|
154910
|
-
transport: describeTransport(
|
|
155250
|
+
transport: describeTransport(net2, opts, {
|
|
154911
155251
|
relations: relationsChecked > 0,
|
|
154912
155252
|
hostile: opts.hostile !== false && Boolean(deps.crawlScreenHostile),
|
|
154913
155253
|
deep: Boolean(opts.deep && opts.deep >= 2 && deps.crawlScreenDeep)
|
|
@@ -154945,9 +155285,9 @@ async function runCrawl(opts) {
|
|
|
154945
155285
|
...results.some((r2) => r2.observations) ? { observations: Object.fromEntries(results.filter((r2) => r2.observations).map((r2) => [r2.screen, r2.observations])) } : {}
|
|
154946
155286
|
};
|
|
154947
155287
|
}
|
|
154948
|
-
function describeTransport(
|
|
155288
|
+
function describeTransport(net2, opts, ran) {
|
|
154949
155289
|
const layers3 = [];
|
|
154950
|
-
if (
|
|
155290
|
+
if (net2) layers3.push(`mocked (${net2.from})`);
|
|
154951
155291
|
const cmsCount = Object.keys(opts.cmsSeed ?? {}).length;
|
|
154952
155292
|
if (cmsCount) layers3.push(`cms (${cmsCount} seeded collection${cmsCount === 1 ? "" : "s"})`);
|
|
154953
155293
|
if (opts.canned?.count) layers3.push(`canned (${opts.canned.count} frozen endpoints, ${opts.canned.from} \u2014 exercises code paths, not API-contract truth)`);
|
|
@@ -164024,7 +164364,7 @@ function siteFinding(app, siteId, fileName) {
|
|
|
164024
164364
|
const check = `make sure the app's member login uses siteId ${JSON.stringify(siteId)}: a build bakes the purchases app only for the site its login resolves to.`;
|
|
164025
164365
|
const login = loginOf(app);
|
|
164026
164366
|
if (login.kind !== "member") return { instruction: `${fileName} does not write auth as a WixConsumerAuthProvider({ \u2026 }) call it can read, so ${check}` };
|
|
164027
|
-
const found =
|
|
164367
|
+
const found = lookup3(login.literal, "siteId");
|
|
164028
164368
|
const value = found.kind === "written" ? unwrap(found.node.initializer) : void 0;
|
|
164029
164369
|
if (!value || !ts8.isStringLiteralLike(value)) return { instruction: `auth's siteId is not written as a literal, so ${check}` };
|
|
164030
164370
|
if (value.text.toLowerCase() === siteId.toLowerCase()) return {};
|
|
@@ -164035,7 +164375,7 @@ function bundleFinding(app, { bundleId, storeBundleId }, fileName) {
|
|
|
164035
164375
|
if (storeBundleId === bundleId) return {};
|
|
164036
164376
|
return { conflict: `store/store.config.yaml builds bundle "${storeBundleId}", but the purchases app is registered for "${bundleId}". ${fileName} was not edited.` };
|
|
164037
164377
|
}
|
|
164038
|
-
const found =
|
|
164378
|
+
const found = lookup3(app, "bundleId");
|
|
164039
164379
|
const value = found.kind === "written" ? unwrap(found.node.initializer) : void 0;
|
|
164040
164380
|
if (!value || !ts8.isStringLiteralLike(value)) {
|
|
164041
164381
|
return { instruction: `${fileName} does not write bundleId as a literal: make sure this app builds bundle ${JSON.stringify(bundleId)}, the one the purchases app is registered for.` };
|
|
@@ -164044,11 +164384,11 @@ function bundleFinding(app, { bundleId, storeBundleId }, fileName) {
|
|
|
164044
164384
|
return { conflict: `${fileName} builds bundle "${value.text}", but the purchases app is registered for "${bundleId}". This is another app's config, so it was not edited.` };
|
|
164045
164385
|
}
|
|
164046
164386
|
function bindingFinding(app, file2, purchasesAppId, wanted, fileName) {
|
|
164047
|
-
const wixIap =
|
|
164387
|
+
const wixIap = lookup3(app, "wixIap");
|
|
164048
164388
|
if (wixIap.kind === "absent") return { splice: appendProperties(app, file2, [`${wanted},`]), applied: "wixIap.purchasesAppId" };
|
|
164049
164389
|
const literal = wixIap.kind === "written" ? unwrap(wixIap.node.initializer) : void 0;
|
|
164050
164390
|
if (!literal || !ts8.isObjectLiteralExpression(literal)) return { instruction: `${fileName} computes wixIap, so it was not edited: it must evaluate to ${wanted}.` };
|
|
164051
|
-
const current =
|
|
164391
|
+
const current = lookup3(literal, "purchasesAppId");
|
|
164052
164392
|
if (current.kind === "absent") return { splice: appendProperties(literal, file2, [`purchasesAppId: ${JSON.stringify(purchasesAppId)},`]), applied: "wixIap.purchasesAppId" };
|
|
164053
164393
|
const value = current.kind === "written" ? unwrap(current.node.initializer) : void 0;
|
|
164054
164394
|
if (!value || !ts8.isStringLiteralLike(value)) return { instruction: `${fileName} computes wixIap.purchasesAppId, so it was not edited: it must evaluate to ${JSON.stringify(purchasesAppId)}.` };
|
|
@@ -164056,7 +164396,7 @@ function bindingFinding(app, file2, purchasesAppId, wanted, fileName) {
|
|
|
164056
164396
|
return { conflict: `${fileName} already binds purchases app "${value.text}", but this site's purchases app for the bundle is "${purchasesAppId}". Nothing was changed; fix whichever is stale.` };
|
|
164057
164397
|
}
|
|
164058
164398
|
function capabilityFinding(app, fileName) {
|
|
164059
|
-
const capabilities =
|
|
164399
|
+
const capabilities = lookup3(app, "capabilities");
|
|
164060
164400
|
const list = capabilities.kind === "written" ? unwrap(capabilities.node.initializer) : void 0;
|
|
164061
164401
|
if (capabilities.kind !== "absent" && (!list || !ts8.isArrayLiteralExpression(list))) {
|
|
164062
164402
|
return { instruction: `Add "iap" to capabilities: the purchases app is baked only into a build that declares it, and ${fileName} does not list capabilities inline.` };
|
|
@@ -164756,14 +165096,13 @@ function createReviewScreenRenderer() {
|
|
|
164756
165096
|
}
|
|
164757
165097
|
return built;
|
|
164758
165098
|
}
|
|
165099
|
+
let closeLaunched;
|
|
164759
165100
|
async function launch() {
|
|
164760
|
-
|
|
164761
|
-
|
|
164762
|
-
|
|
164763
|
-
|
|
164764
|
-
|
|
164765
|
-
}
|
|
164766
|
-
return chromium.launch();
|
|
165101
|
+
const { launchPngBrowser: launchPngBrowser2 } = await Promise.resolve().then(() => (init_render_descriptor(), render_descriptor_exports));
|
|
165102
|
+
const launched = await launchPngBrowser2();
|
|
165103
|
+
if (!launched) throw new Error("taking a screenshot needs Playwright's Chromium: run `npx playwright install chromium`");
|
|
165104
|
+
closeLaunched = launched.close;
|
|
165105
|
+
return launched.browser;
|
|
164767
165106
|
}
|
|
164768
165107
|
return {
|
|
164769
165108
|
async render({ contentDir: contentDir2, screenId, input, host, entityId }) {
|
|
@@ -164806,7 +165145,8 @@ function createReviewScreenRenderer() {
|
|
|
164806
165145
|
return pngAvailable2();
|
|
164807
165146
|
},
|
|
164808
165147
|
async close() {
|
|
164809
|
-
if (browser) await
|
|
165148
|
+
if (browser) await browser.catch(() => void 0);
|
|
165149
|
+
await closeLaunched?.().catch(() => {
|
|
164810
165150
|
});
|
|
164811
165151
|
}
|
|
164812
165152
|
};
|
|
@@ -167114,8 +167454,8 @@ async function runNotifyPing(flags, io2, deps = {}) {
|
|
|
167114
167454
|
requestId: requestId2,
|
|
167115
167455
|
...flags["dry-run"] === true ? { dryRun: true } : {}
|
|
167116
167456
|
};
|
|
167117
|
-
const
|
|
167118
|
-
return report2(
|
|
167457
|
+
const http2 = await pushSendRequest({ target: session.target, wixToken: session.wixToken, siteToken: siteToken2, body, previewTag: session.previewTag, fetchImpl: deps.fetchImpl });
|
|
167458
|
+
return report2(http2, body, flags, io2);
|
|
167119
167459
|
}
|
|
167120
167460
|
async function runAllMembers(args) {
|
|
167121
167461
|
const { input, siteToken: siteToken2, session, requestId: requestId2, flags, io: io2, deps } = args;
|
|
@@ -167204,25 +167544,25 @@ function flagRefusal(flags) {
|
|
|
167204
167544
|
if (SWITCHES.some((f2) => flags[f2] !== void 0 && typeof flags[f2] !== "boolean")) return "invalid_boolean_flag";
|
|
167205
167545
|
return void 0;
|
|
167206
167546
|
}
|
|
167207
|
-
function report2(
|
|
167208
|
-
const code = refusalCode2(
|
|
167547
|
+
function report2(http2, sent, flags, io2) {
|
|
167548
|
+
const code = refusalCode2(http2);
|
|
167209
167549
|
if (code === "send_outcome_unknown") {
|
|
167210
167550
|
return refuse6(io2, code, `Ping may have accepted it. Re-run the same command with --request-id ${sent.requestId}: Ping runs one request at most once per site for 24 hours.`, 1, { requestId: sent.requestId });
|
|
167211
167551
|
}
|
|
167212
|
-
if (code === "rate_limited" &&
|
|
167213
|
-
return refuse6(io2, code, `Test sends are limited per owner; retry in ${
|
|
167552
|
+
if (code === "rate_limited" && http2.retryAfterSec) {
|
|
167553
|
+
return refuse6(io2, code, `Test sends are limited per owner; retry in ${http2.retryAfterSec} seconds.`, 1, { retryAfterSec: http2.retryAfterSec });
|
|
167214
167554
|
}
|
|
167215
167555
|
if (code) return refuse6(io2, code, HINTS[code], 1);
|
|
167216
|
-
if (flags.json === true) io2.log(JSON.stringify(
|
|
167217
|
-
else io2.log(summary(
|
|
167556
|
+
if (flags.json === true) io2.log(JSON.stringify(http2.body, null, 2));
|
|
167557
|
+
else io2.log(summary(http2.body ?? {}, sent));
|
|
167218
167558
|
return 0;
|
|
167219
167559
|
}
|
|
167220
|
-
function refusalCode2(
|
|
167221
|
-
if (
|
|
167222
|
-
if (
|
|
167223
|
-
const code = String(
|
|
167560
|
+
function refusalCode2(http2) {
|
|
167561
|
+
if (http2.error) return http2.error === "push_send_unreachable" ? "send_outcome_unknown" : http2.error;
|
|
167562
|
+
if (http2.ok && (http2.body?.state === "accepted" || http2.body?.state === "dry_run")) return void 0;
|
|
167563
|
+
const code = String(http2.body?.error ?? "");
|
|
167224
167564
|
if (KNOWN_CODES.has(code)) return code;
|
|
167225
|
-
return
|
|
167565
|
+
return http2.ok || http2.status >= 500 ? "send_outcome_unknown" : "push_send_failed";
|
|
167226
167566
|
}
|
|
167227
167567
|
function summary(result, sent) {
|
|
167228
167568
|
if (result.state === "dry_run") {
|
|
@@ -167797,10 +168137,13 @@ __export(plan_exports, {
|
|
|
167797
168137
|
RESERVED_SCREEN_IDS: () => RESERVED_SCREEN_IDS,
|
|
167798
168138
|
displayName: () => displayName2,
|
|
167799
168139
|
gateFor: () => gateFor,
|
|
168140
|
+
hasLinkField: () => hasLinkField,
|
|
167800
168141
|
humanize: () => humanize,
|
|
168142
|
+
missingCapabilities: () => missingCapabilities,
|
|
167801
168143
|
planEntity: () => planEntity,
|
|
167802
168144
|
planEntityScreens: () => planEntityScreens,
|
|
167803
168145
|
pluralize: () => pluralize,
|
|
168146
|
+
requiredCapabilities: () => requiredCapabilities,
|
|
167804
168147
|
rowTitleField: () => rowTitleField,
|
|
167805
168148
|
snake: () => snake
|
|
167806
168149
|
});
|
|
@@ -167876,6 +168219,12 @@ function fieldReadOnly(f2) {
|
|
|
167876
168219
|
const rls = f2.rls;
|
|
167877
168220
|
return !!rls && typeof rls === "object" && "write" in rls && rls.write !== true;
|
|
167878
168221
|
}
|
|
168222
|
+
function requiredCapabilities(sp) {
|
|
168223
|
+
return ["base44", ...sp.plans.some(hasLinkField) ? ["open_url"] : []];
|
|
168224
|
+
}
|
|
168225
|
+
function missingCapabilities(sp, declared) {
|
|
168226
|
+
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) }));
|
|
168227
|
+
}
|
|
167879
168228
|
function ruleFor(spec, op) {
|
|
167880
168229
|
const rls = spec.rls;
|
|
167881
168230
|
if (!rls || typeof rls !== "object") return void 0;
|
|
@@ -167954,7 +168303,7 @@ function planEntityScreens(specs, app = "") {
|
|
|
167954
168303
|
if (names2.length <= ENTITY_TAB_SLOTS) return { plans, tabs: names2, more: [] };
|
|
167955
168304
|
return { plans, tabs: names2.slice(0, ENTITY_TAB_SLOTS - 1), more: names2.slice(ENTITY_TAB_SLOTS - 1) };
|
|
167956
168305
|
}
|
|
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;
|
|
168306
|
+
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
168307
|
var init_plan4 = __esm({
|
|
167959
168308
|
"src/base44-screens/plan.ts"() {
|
|
167960
168309
|
init_base44_schema();
|
|
@@ -167980,6 +168329,7 @@ var init_plan4 = __esm({
|
|
|
167980
168329
|
isDate = (f2) => f2.type === "string" && (f2.format === "date" || f2.format === "date-time");
|
|
167981
168330
|
isImage = (f2) => f2.type === "string" && !isEnum(f2) && (f2.format === "file" || IMAGE_KEY.test(f2.key));
|
|
167982
168331
|
isLongText = (f2) => f2.type === "string" && !isEnum(f2) && (f2.format === "richtext" || LONG_TEXT.test(f2.key));
|
|
168332
|
+
hasLinkField = (p2) => p2.detail.some((d2) => d2.show === "link");
|
|
167983
168333
|
nounOf = (display) => display.split(" ").map((w2) => /^[A-Z]{2,}s?$/.test(w2) ? w2 : w2.toLowerCase()).join(" ");
|
|
167984
168334
|
}
|
|
167985
168335
|
});
|
|
@@ -168031,13 +168381,25 @@ export default defineEntityList(PLAN);
|
|
|
168031
168381
|
`;
|
|
168032
168382
|
}
|
|
168033
168383
|
function renderDetailEntry(p2) {
|
|
168034
|
-
|
|
168384
|
+
if (!hasLinkField(p2)) {
|
|
168385
|
+
return `// One ${p2.name} (${p2.ids.detail}), pushed from ${p2.ids.list} with its id \u2014 generated by \`himi base44 screens\`.
|
|
168035
168386
|
// The behaviour lives in the shared engine (../_shared/entity-detail.ts); this file only names the
|
|
168036
168387
|
// entity's plan.
|
|
168037
168388
|
import { defineEntityDetail } from "../_shared/entity-detail.js";
|
|
168038
168389
|
import { PLAN } from "../_shared/${planFile(p2)}.js";
|
|
168039
168390
|
|
|
168040
168391
|
export default defineEntityDetail(PLAN);
|
|
168392
|
+
`;
|
|
168393
|
+
}
|
|
168394
|
+
return `// One ${p2.name} (${p2.ids.detail}), pushed from ${p2.ids.list} with its id \u2014 generated by \`himi base44 screens\`.
|
|
168395
|
+
// The behaviour lives in the shared engine (../_shared/entity-detail.ts); this file names the
|
|
168396
|
+
// entity's plan and hands it \`open\`, which an email / URL fact opens through (the open_url
|
|
168397
|
+
// capability \u2014 only an entity with such a field imports it).
|
|
168398
|
+
import { open } from "@himalaya/open-url";
|
|
168399
|
+
import { defineEntityDetail } from "../_shared/entity-detail.js";
|
|
168400
|
+
import { PLAN } from "../_shared/${planFile(p2)}.js";
|
|
168401
|
+
|
|
168402
|
+
export default defineEntityDetail(PLAN, { open });
|
|
168041
168403
|
`;
|
|
168042
168404
|
}
|
|
168043
168405
|
function renderDevRegistrations(sp) {
|
|
@@ -168763,8 +169125,8 @@ function readEntities(files, dirs) {
|
|
|
168763
169125
|
function functionSignature(code) {
|
|
168764
169126
|
if (code === void 0) return { kind: "unknown" };
|
|
168765
169127
|
const methods = [...new Set([...code.matchAll(/\b(?:req|request)\.method\s*[!=]==?\s*["'](GET|POST|PUT|PATCH|DELETE)["']/g)].map((m2) => m2[1]))];
|
|
168766
|
-
const
|
|
168767
|
-
return { kind:
|
|
169128
|
+
const http2 = /\bDeno\.serve\s*\(|\bserve\s*\(\s*(?:async\s*)?\(?\s*req/.test(code);
|
|
169129
|
+
return { kind: http2 ? "http" : "invoke", ...methods.length ? { methods } : {} };
|
|
168768
169130
|
}
|
|
168769
169131
|
function automationsOf(v2) {
|
|
168770
169132
|
if (!Array.isArray(v2)) return void 0;
|
|
@@ -170755,9 +171117,9 @@ function cmsStatusNote(taxonomy) {
|
|
|
170755
171117
|
bits.push("skipped: no owner token \u2014 re-run with `--site <msid>` (owner auth) to list the site's collections");
|
|
170756
171118
|
break;
|
|
170757
171119
|
case "error": {
|
|
170758
|
-
const
|
|
170759
|
-
const remedy =
|
|
170760
|
-
bits.push(`error${
|
|
171120
|
+
const http2 = taxonomy.cmsErrorStatus;
|
|
171121
|
+
const remedy = http2 === 429 ? "the site rate-limited the listing \u2014 wait and re-run" : http2 != null && http2 >= 500 ? "Wix Data failed upstream \u2014 retry later, and investigate the service if it persists" : http2 === 401 || http2 === 403 ? "check the owner token is current and carries the Wix Data read permission, then re-run" : "check the owner token and the `--site <msid>` you passed, then re-run";
|
|
171122
|
+
bits.push(`error${http2 ? ` HTTP ${http2}` : ""}: the listing call failed \u2014 ${remedy}`);
|
|
170761
171123
|
break;
|
|
170762
171124
|
}
|
|
170763
171125
|
default:
|
|
@@ -174974,7 +175336,7 @@ var init_dist = __esm({
|
|
|
174974
175336
|
return promiseCallback.reject(new Error(SAME_SITE_CONTEXT_VAL_ERR));
|
|
174975
175337
|
}
|
|
174976
175338
|
}
|
|
174977
|
-
const
|
|
175339
|
+
const http2 = options.http ?? true;
|
|
174978
175340
|
const now = Date.now();
|
|
174979
175341
|
const expireCheck = options.expire ?? true;
|
|
174980
175342
|
const allPaths = options.allPaths ?? false;
|
|
@@ -174995,7 +175357,7 @@ var init_dist = __esm({
|
|
|
174995
175357
|
if (c2.secure && !potentiallyTrustworthy) {
|
|
174996
175358
|
return false;
|
|
174997
175359
|
}
|
|
174998
|
-
if (c2.httpOnly && !
|
|
175360
|
+
if (c2.httpOnly && !http2) {
|
|
174999
175361
|
return false;
|
|
175000
175362
|
}
|
|
175001
175363
|
if (sameSiteLevel) {
|
|
@@ -184778,7 +185140,9 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
184778
185140
|
base44.entities entity (base44-starter packages), write
|
|
184779
185141
|
controls gated by each entity's rls. Re-running is a
|
|
184780
185142
|
no-op; a hand-edited generated file is skipped-edited
|
|
184781
|
-
unless --force.
|
|
185143
|
+
unless --force. An email / URL field opens through
|
|
185144
|
+
open_url, so config.ts capabilities must list it
|
|
185145
|
+
(else missing_capability). Never calls Base44.
|
|
184782
185146
|
himi base44 entities create [--app <a> | --content <dir>] [--yes] [--allow-destructive]
|
|
184783
185147
|
[--apply-permissions] [--empty-app-ok]
|
|
184784
185148
|
create/update the app's OWNED Himi<App>* entities. Base44's
|
|
@@ -185040,7 +185404,7 @@ function execNpmConfig(file2, args, options) {
|
|
|
185040
185404
|
});
|
|
185041
185405
|
}
|
|
185042
185406
|
var npmScopedWixRegistry = createScopedRegistryResolver();
|
|
185043
|
-
async function scopedRegistryBefore(
|
|
185407
|
+
async function scopedRegistryBefore(lookup4, deadline, onTimeout) {
|
|
185044
185408
|
let cancel = () => {
|
|
185045
185409
|
};
|
|
185046
185410
|
const expired = new Promise((resolve66) => {
|
|
@@ -185051,16 +185415,16 @@ async function scopedRegistryBefore(lookup3, deadline, onTimeout) {
|
|
|
185051
185415
|
cancel = () => clearTimeout(timer);
|
|
185052
185416
|
});
|
|
185053
185417
|
try {
|
|
185054
|
-
return await Promise.race([Promise.resolve().then(() =>
|
|
185418
|
+
return await Promise.race([Promise.resolve().then(() => lookup4(Math.max(0, deadline - Date.now()))), expired]);
|
|
185055
185419
|
} catch {
|
|
185056
185420
|
return void 0;
|
|
185057
185421
|
} finally {
|
|
185058
185422
|
cancel();
|
|
185059
185423
|
}
|
|
185060
185424
|
}
|
|
185061
|
-
function lookupOnce(
|
|
185425
|
+
function lookupOnce(lookup4) {
|
|
185062
185426
|
let first;
|
|
185063
|
-
return (budgetMs) => first ??= Promise.resolve().then(() =>
|
|
185427
|
+
return (budgetMs) => first ??= Promise.resolve().then(() => lookup4(budgetMs));
|
|
185064
185428
|
}
|
|
185065
185429
|
function registryCandidates(env, scoped) {
|
|
185066
185430
|
const ordered = [isTrustedRegistry(scoped) ? normalizeRegistry(scoped) : void 0, trustedConfiguredRegistry(env), PUBLIC_NPM_REGISTRY];
|
|
@@ -192866,9 +193230,12 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192866
193230
|
}
|
|
192867
193231
|
const app = await appId(dir);
|
|
192868
193232
|
let base44;
|
|
193233
|
+
let appCapabilities;
|
|
192869
193234
|
try {
|
|
192870
193235
|
const { loadAppConfigModule: loadAppConfigModule2 } = await Promise.resolve().then(() => (init_app_config_loader(), app_config_loader_exports));
|
|
192871
|
-
|
|
193236
|
+
const loaded = await loadAppConfigModule2(dir);
|
|
193237
|
+
base44 = loaded?.base44;
|
|
193238
|
+
appCapabilities = loaded?.capabilities;
|
|
192872
193239
|
} catch (e2) {
|
|
192873
193240
|
const finding = (await Promise.resolve().then(() => (init_base44_lint(), base44_lint_exports))).base44DefineAppFinding(e2);
|
|
192874
193241
|
if (finding) {
|
|
@@ -192887,7 +193254,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192887
193254
|
io2.error(JSON.stringify({ ok: false, code: "invalid_config", app, issues: errors, hint: '`himi validate` reports these with pass: "base44"' }));
|
|
192888
193255
|
return 1;
|
|
192889
193256
|
}
|
|
192890
|
-
const { planEntityScreens: planEntityScreens2, PlanError: PlanError2 } = await Promise.resolve().then(() => (init_plan4(), plan_exports));
|
|
193257
|
+
const { planEntityScreens: planEntityScreens2, PlanError: PlanError2, missingCapabilities: missingCapabilities2, requiredCapabilities: requiredCapabilities2 } = await Promise.resolve().then(() => (init_plan4(), plan_exports));
|
|
192891
193258
|
let sp;
|
|
192892
193259
|
try {
|
|
192893
193260
|
sp = planEntityScreens2(specs, app);
|
|
@@ -192895,6 +193262,18 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192895
193262
|
if (e2 instanceof PlanError2) return fail6(e2.code, e2.message, { app, ...e2.extra });
|
|
192896
193263
|
throw e2;
|
|
192897
193264
|
}
|
|
193265
|
+
const { catalogKey: catalogKey2, expandCapabilities: expandCapabilities2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
|
|
193266
|
+
const declaredCaps = expandCapabilities2((Array.isArray(appCapabilities) ? appCapabilities : []).filter((c2) => typeof c2 === "string").map(catalogKey2));
|
|
193267
|
+
const missingCaps = missingCapabilities2(sp, declaredCaps);
|
|
193268
|
+
if (missingCaps.length) {
|
|
193269
|
+
const [first] = missingCaps;
|
|
193270
|
+
return fail6("missing_capability", `config.ts capabilities does not declare "${first.capability}", which the generated screens need (${first.entities.join(", ")})`, {
|
|
193271
|
+
app,
|
|
193272
|
+
capability: first.capability,
|
|
193273
|
+
missing: missingCaps,
|
|
193274
|
+
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.`
|
|
193275
|
+
});
|
|
193276
|
+
}
|
|
192898
193277
|
const rendered = gen.renderAll(sp);
|
|
192899
193278
|
const dryRun = flags["dry-run"] === true;
|
|
192900
193279
|
const { files } = gen.writeGenerated(dir, rendered, { force: flags.force === true, dryRun });
|
|
@@ -192905,6 +193284,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
192905
193284
|
...dryRun ? { dryRun: true } : {},
|
|
192906
193285
|
files,
|
|
192907
193286
|
plans: sp.plans.map((p2) => ({ entity: p2.name, physical: p2.entity, list: p2.ids.list, detail: p2.ids.detail, gates: p2.gates })),
|
|
193287
|
+
capabilities: requiredCapabilities2(sp),
|
|
192908
193288
|
tabs: sp.tabs,
|
|
192909
193289
|
more: sp.more,
|
|
192910
193290
|
...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.1439.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": "517214ad79ba1f66fcc679a54a5edf1e5242a258037728e41501f8ce"
|
|
75
75
|
}
|