@wix/himalaya-cli 0.849.0 → 0.850.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.
|
@@ -253,6 +253,34 @@ export declare function surfaceById(id: string): PreviewSurface | undefined;
|
|
|
253
253
|
* claim a family allowlist and then be served live bindings.
|
|
254
254
|
*/
|
|
255
255
|
export type SurfaceRenderMode = "frozen" | "interactive";
|
|
256
|
+
/**
|
|
257
|
+
* The widget family a FROZEN surface publishes under, for DISPLAY — or undefined for
|
|
258
|
+
* an interactive app shell.
|
|
259
|
+
*
|
|
260
|
+
* Both gate kinds that mean "frozen" carry a family: `family` because it IS the
|
|
261
|
+
* allowlist key, `projection` because the car still ships its tree under one
|
|
262
|
+
* (`car_list`). That makes this the right thing to name a surface by in a message, and
|
|
263
|
+
* the WRONG thing to branch on — a car and a widget are authored through different
|
|
264
|
+
* doors. Decisions use `isWidgetFamilySurface` below.
|
|
265
|
+
*/
|
|
266
|
+
export declare function surfaceFrozenFamily(surface: PreviewSurface): string | undefined;
|
|
267
|
+
/**
|
|
268
|
+
* Is this surface an OS widget — the `defineWidget` population, as distinct from the
|
|
269
|
+
* car, which is frozen too?
|
|
270
|
+
*
|
|
271
|
+
* Named and shared rather than spelled `gate.kind === "family"` at each call site,
|
|
272
|
+
* because the two places that ask (`surfacesForApp`'s produced verdict, and
|
|
273
|
+
* `himi render --device`'s refusal) must give the same answer or #2499 comes back
|
|
274
|
+
* halfway: a surface one of them classes as a widget and the other does not is either
|
|
275
|
+
* advertised as supported while unrenderable, or refused with advice pointing at a
|
|
276
|
+
* door it was not authored through.
|
|
277
|
+
*
|
|
278
|
+
* The car is excluded deliberately, not incidentally. It is authored with
|
|
279
|
+
* `defineView({ surface: "car" })`, gated by a real `androidauto` key (so it never
|
|
280
|
+
* over-claimed), and its viewport exists for the preview — so `defineWidget` advice and
|
|
281
|
+
* a `/v1/widget/<id>` pointer would both be dead ends for it.
|
|
282
|
+
*/
|
|
283
|
+
export declare function isWidgetFamilySurface(surface: PreviewSurface): boolean;
|
|
256
284
|
export declare function surfaceRenderMode(surface: PreviewSurface): SurfaceRenderMode;
|
|
257
285
|
/**
|
|
258
286
|
* Ladder rungs that are not themselves surfaces — the shared fallbacks a view can
|
|
@@ -316,15 +344,48 @@ export declare function isTargeted(surface: PreviewSurface, platforms: Platforms
|
|
|
316
344
|
export interface SurfaceAvailability {
|
|
317
345
|
readonly surface: PreviewSurface;
|
|
318
346
|
readonly targeted: boolean;
|
|
319
|
-
/** When not targeted
|
|
347
|
+
/** When not targeted because of the BINARY envelope, the exact platforms.json
|
|
348
|
+
* opt-in to add. Drives the picker's tooltip. Absent for a widget family that
|
|
349
|
+
* is untargeted for lack of a widget — no platforms.json key opts that in. */
|
|
320
350
|
readonly optIn?: string;
|
|
351
|
+
/**
|
|
352
|
+
* For a WIDGET FAMILY (`isWidgetFamilySurface`) — does this app actually PRODUCE a
|
|
353
|
+
* snapshot for it? Only present when the caller supplied the produced set;
|
|
354
|
+
* `undefined` means "not measured", which is not the same as `false` and must not be
|
|
355
|
+
* rendered as one.
|
|
356
|
+
*
|
|
357
|
+
* Widget families and NOTHING else, the car included — it is frozen too, but it is
|
|
358
|
+
* gated by a real `androidauto` key (so it never over-claimed) and is authored with
|
|
359
|
+
* `defineView({ surface: "car" })`, so a `defineWidget`-shaped verdict would be the
|
|
360
|
+
* wrong answer rather than a missing one. An app shell has nothing to produce at all.
|
|
361
|
+
*/
|
|
362
|
+
readonly produced?: boolean;
|
|
363
|
+
/** When a widget family is untargeted because nothing produces it, what to author. */
|
|
364
|
+
readonly needs?: string;
|
|
321
365
|
}
|
|
322
366
|
/**
|
|
323
367
|
* The full catalog with a targeted flag — NOT a filtered list. The picker shows
|
|
324
368
|
* every surface and dims the untargeted ones, so authors discover what their app
|
|
325
369
|
* could also be, instead of only seeing what it already is.
|
|
370
|
+
*
|
|
371
|
+
* `producedFamilies` — the widget families this app actually produces a snapshot for
|
|
372
|
+
* (`GET /v1/widgets`, or a scan of its built bundles). Supply it and a frozen surface
|
|
373
|
+
* reports the truth; omit it and the answer is the binary envelope alone, as before.
|
|
374
|
+
*
|
|
375
|
+
* Why it exists (#2499): the four native widget families carry `platformKey: null`
|
|
376
|
+
* (`web_card` and `watch_complication` are the exceptions — they ride `web`/`watchos`),
|
|
377
|
+
* so for those four `isTargeted` short-circuits to `true` and `himi surfaces` reported
|
|
378
|
+
* `widget:ios_home`, `widget:ios_lock`, `widget:android_home` and
|
|
379
|
+
* `widget:ios_live_activity` as targeted for EVERY app — declared widgets or not.
|
|
380
|
+
* A tester read that as support, found
|
|
381
|
+
* `/v1/widgets` empty, and summarized it as "everything advertises the capability
|
|
382
|
+
* except the capability". The envelope answer was not wrong so much as answering a
|
|
383
|
+
* different question: iOS and Android are implicit, so the binary CAN host a widget;
|
|
384
|
+
* whether this app HAS one is a fact about its bundles, and only the produced set
|
|
385
|
+
* carries it. `isTargeted` is deliberately left alone — `resolveSurfaceEnvelope` asks
|
|
386
|
+
* the binary question and must keep getting the binary answer.
|
|
326
387
|
*/
|
|
327
|
-
export declare function surfacesForApp(platforms: PlatformsJson): readonly SurfaceAvailability[];
|
|
388
|
+
export declare function surfacesForApp(platforms: PlatformsJson, producedFamilies?: Iterable<string>): readonly SurfaceAvailability[];
|
|
328
389
|
export interface SurfaceEnvelopeResolution {
|
|
329
390
|
/** Surfaces this app actually runs, in catalog order. */
|
|
330
391
|
readonly enabled: readonly string[];
|
|
@@ -9232,6 +9232,13 @@ var PREVIEW_SURFACES = [
|
|
|
9232
9232
|
function surfaceById(id) {
|
|
9233
9233
|
return PREVIEW_SURFACES.find((s) => s.id === id);
|
|
9234
9234
|
}
|
|
9235
|
+
function surfaceFrozenFamily(surface) {
|
|
9236
|
+
const gate = surface.gate;
|
|
9237
|
+
return gate.kind === "family" || gate.kind === "projection" ? gate.family : void 0;
|
|
9238
|
+
}
|
|
9239
|
+
function isWidgetFamilySurface(surface) {
|
|
9240
|
+
return surface.gate.kind === "family";
|
|
9241
|
+
}
|
|
9235
9242
|
function surfaceRenderMode(surface) {
|
|
9236
9243
|
const { kind } = surface.gate;
|
|
9237
9244
|
return kind === "family" || kind === "projection" ? "frozen" : "interactive";
|
|
@@ -9295,10 +9302,33 @@ function isTargeted(surface, platforms) {
|
|
|
9295
9302
|
if (surface.platformKey === "macos") return platforms.macos !== false;
|
|
9296
9303
|
return platforms[surface.platformKey] === true;
|
|
9297
9304
|
}
|
|
9298
|
-
function surfacesForApp(platforms) {
|
|
9305
|
+
function surfacesForApp(platforms, producedFamilies) {
|
|
9306
|
+
const produced = producedFamilies === void 0 ? void 0 : producedFamilies instanceof Set ? producedFamilies : new Set(producedFamilies);
|
|
9299
9307
|
return PREVIEW_SURFACES.map((surface) => {
|
|
9300
|
-
const
|
|
9301
|
-
|
|
9308
|
+
const inEnvelope = isTargeted(surface, platforms);
|
|
9309
|
+
const family = isWidgetFamilySurface(surface) ? surfaceFrozenFamily(surface) : void 0;
|
|
9310
|
+
if (produced && family !== void 0) {
|
|
9311
|
+
const isProduced = produced.has(family);
|
|
9312
|
+
return inEnvelope && isProduced ? { surface, targeted: true, produced: true } : {
|
|
9313
|
+
surface,
|
|
9314
|
+
targeted: false,
|
|
9315
|
+
produced: isProduced,
|
|
9316
|
+
// The four native families carry no platform key, so there is nothing to
|
|
9317
|
+
// offer; `web_card` and `watch_complication` DO have one, and when that is
|
|
9318
|
+
// the half that is missing it is still the right advice. Hence the guard —
|
|
9319
|
+
// it is load-bearing for two families, not defensive padding.
|
|
9320
|
+
...inEnvelope ? {} : surface.platformKey ? { optIn: `"${surface.platformKey}": true` } : {},
|
|
9321
|
+
...isProduced ? {} : {
|
|
9322
|
+
// The rebuild half is not padding: the produced set is read off BUILT
|
|
9323
|
+
// bundles, so an author who has just written the registration and not
|
|
9324
|
+
// rebuilt lands here too, and "write defineWidget" alone would be advice
|
|
9325
|
+
// to write the code they are looking at.
|
|
9326
|
+
needs: `defineWidget({ family: "${family}", \u2026 }) in a Tier-5 bundle \u2014 and a rebuild, if you just added it`
|
|
9327
|
+
}
|
|
9328
|
+
};
|
|
9329
|
+
}
|
|
9330
|
+
if (inEnvelope) return { surface, targeted: true };
|
|
9331
|
+
return surface.platformKey ? { surface, targeted: false, optIn: `"${surface.platformKey}": true` } : { surface, targeted: false };
|
|
9302
9332
|
});
|
|
9303
9333
|
}
|
|
9304
9334
|
function resolveSurfaceEnvelope(platforms, requested) {
|
|
@@ -12814,6 +12844,7 @@ export {
|
|
|
12814
12844
|
isValidAppId,
|
|
12815
12845
|
isValidStreamPolicy,
|
|
12816
12846
|
isViewTarget,
|
|
12847
|
+
isWidgetFamilySurface,
|
|
12817
12848
|
layoutDirection,
|
|
12818
12849
|
parseNumeric,
|
|
12819
12850
|
primarySubtag,
|
|
@@ -12834,6 +12865,7 @@ export {
|
|
|
12834
12865
|
stripOriginParams,
|
|
12835
12866
|
summarize,
|
|
12836
12867
|
surfaceById,
|
|
12868
|
+
surfaceFrozenFamily,
|
|
12837
12869
|
surfaceRenderMode,
|
|
12838
12870
|
surfacesForApp,
|
|
12839
12871
|
validate,
|
package/dist/cli.mjs
CHANGED
|
@@ -1763,6 +1763,13 @@ var init_widget_vocabulary = __esm({
|
|
|
1763
1763
|
function surfaceById(id) {
|
|
1764
1764
|
return PREVIEW_SURFACES.find((s) => s.id === id);
|
|
1765
1765
|
}
|
|
1766
|
+
function surfaceFrozenFamily(surface) {
|
|
1767
|
+
const gate = surface.gate;
|
|
1768
|
+
return gate.kind === "family" || gate.kind === "projection" ? gate.family : void 0;
|
|
1769
|
+
}
|
|
1770
|
+
function isWidgetFamilySurface(surface) {
|
|
1771
|
+
return surface.gate.kind === "family";
|
|
1772
|
+
}
|
|
1766
1773
|
function surfaceRenderMode(surface) {
|
|
1767
1774
|
const { kind } = surface.gate;
|
|
1768
1775
|
return kind === "family" || kind === "projection" ? "frozen" : "interactive";
|
|
@@ -1787,10 +1794,33 @@ function isTargeted(surface, platforms) {
|
|
|
1787
1794
|
if (surface.platformKey === "macos") return platforms.macos !== false;
|
|
1788
1795
|
return platforms[surface.platformKey] === true;
|
|
1789
1796
|
}
|
|
1790
|
-
function surfacesForApp(platforms) {
|
|
1797
|
+
function surfacesForApp(platforms, producedFamilies) {
|
|
1798
|
+
const produced = producedFamilies === void 0 ? void 0 : producedFamilies instanceof Set ? producedFamilies : new Set(producedFamilies);
|
|
1791
1799
|
return PREVIEW_SURFACES.map((surface) => {
|
|
1792
|
-
const
|
|
1793
|
-
|
|
1800
|
+
const inEnvelope = isTargeted(surface, platforms);
|
|
1801
|
+
const family = isWidgetFamilySurface(surface) ? surfaceFrozenFamily(surface) : void 0;
|
|
1802
|
+
if (produced && family !== void 0) {
|
|
1803
|
+
const isProduced = produced.has(family);
|
|
1804
|
+
return inEnvelope && isProduced ? { surface, targeted: true, produced: true } : {
|
|
1805
|
+
surface,
|
|
1806
|
+
targeted: false,
|
|
1807
|
+
produced: isProduced,
|
|
1808
|
+
// The four native families carry no platform key, so there is nothing to
|
|
1809
|
+
// offer; `web_card` and `watch_complication` DO have one, and when that is
|
|
1810
|
+
// the half that is missing it is still the right advice. Hence the guard —
|
|
1811
|
+
// it is load-bearing for two families, not defensive padding.
|
|
1812
|
+
...inEnvelope ? {} : surface.platformKey ? { optIn: `"${surface.platformKey}": true` } : {},
|
|
1813
|
+
...isProduced ? {} : {
|
|
1814
|
+
// The rebuild half is not padding: the produced set is read off BUILT
|
|
1815
|
+
// bundles, so an author who has just written the registration and not
|
|
1816
|
+
// rebuilt lands here too, and "write defineWidget" alone would be advice
|
|
1817
|
+
// to write the code they are looking at.
|
|
1818
|
+
needs: `defineWidget({ family: "${family}", \u2026 }) in a Tier-5 bundle \u2014 and a rebuild, if you just added it`
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1822
|
+
if (inEnvelope) return { surface, targeted: true };
|
|
1823
|
+
return surface.platformKey ? { surface, targeted: false, optIn: `"${surface.platformKey}": true` } : { surface, targeted: false };
|
|
1794
1824
|
});
|
|
1795
1825
|
}
|
|
1796
1826
|
function resolveSurfaceEnvelope(platforms, requested) {
|
|
@@ -3239,6 +3269,13 @@ var init_build_lib = __esm({
|
|
|
3239
3269
|
});
|
|
3240
3270
|
|
|
3241
3271
|
// ../../core/dev-server/src/tier5-dir.ts
|
|
3272
|
+
var tier5_dir_exports = {};
|
|
3273
|
+
__export(tier5_dir_exports, {
|
|
3274
|
+
bundleOutDir: () => bundleOutDir,
|
|
3275
|
+
hasBuiltBundles: () => hasBuiltBundles,
|
|
3276
|
+
servedBundleName: () => servedBundleName,
|
|
3277
|
+
servedBundleNames: () => servedBundleNames
|
|
3278
|
+
});
|
|
3242
3279
|
import { readdirSync as readdirSync7 } from "node:fs";
|
|
3243
3280
|
import { resolve as resolve9 } from "node:path";
|
|
3244
3281
|
function bundleOutDir(contentDir2) {
|
|
@@ -3251,6 +3288,25 @@ function hasBuiltBundles(contentDir2) {
|
|
|
3251
3288
|
return false;
|
|
3252
3289
|
}
|
|
3253
3290
|
}
|
|
3291
|
+
function servedBundleName(fileName) {
|
|
3292
|
+
if (fileName.endsWith(".bundle.js")) return fileName.slice(0, -".bundle.js".length);
|
|
3293
|
+
if (fileName.endsWith(".js")) return fileName.slice(0, -".js".length);
|
|
3294
|
+
return void 0;
|
|
3295
|
+
}
|
|
3296
|
+
function servedBundleNames(dir) {
|
|
3297
|
+
const names = /* @__PURE__ */ new Set();
|
|
3298
|
+
let entries;
|
|
3299
|
+
try {
|
|
3300
|
+
entries = readdirSync7(dir);
|
|
3301
|
+
} catch {
|
|
3302
|
+
return names;
|
|
3303
|
+
}
|
|
3304
|
+
for (const entry of entries) {
|
|
3305
|
+
const name = servedBundleName(entry);
|
|
3306
|
+
if (name !== void 0) names.add(name);
|
|
3307
|
+
}
|
|
3308
|
+
return names;
|
|
3309
|
+
}
|
|
3254
3310
|
var init_tier5_dir = __esm({
|
|
3255
3311
|
"../../core/dev-server/src/tier5-dir.ts"() {
|
|
3256
3312
|
}
|
|
@@ -4689,7 +4745,6 @@ function resolveTranslation(value, catalog, sourceCatalog) {
|
|
|
4689
4745
|
var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
|
|
4690
4746
|
var init_bindings = __esm({
|
|
4691
4747
|
"../../core/ts/src/bindings.ts"() {
|
|
4692
|
-
"use strict";
|
|
4693
4748
|
BINDING_SIGILS = ["service", "flag", "item", "t"];
|
|
4694
4749
|
BINDING_SIGIL_RE = new RegExp(
|
|
4695
4750
|
`^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
|
|
@@ -26427,7 +26482,6 @@ function shouldRevealError(args) {
|
|
|
26427
26482
|
var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
|
|
26428
26483
|
var init_validation = __esm({
|
|
26429
26484
|
"../../core/ts/src/validation.ts"() {
|
|
26430
|
-
"use strict";
|
|
26431
26485
|
EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
26432
26486
|
URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
26433
26487
|
INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
@@ -29823,7 +29877,6 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
|
|
|
29823
29877
|
var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
|
|
29824
29878
|
var init_worker_subtree = __esm({
|
|
29825
29879
|
"../../core/ts/src/worker-subtree.ts"() {
|
|
29826
|
-
"use strict";
|
|
29827
29880
|
init_worker_subtree_safe_types_generated();
|
|
29828
29881
|
WORKER_SUBTREE_CEILINGS = Object.freeze({
|
|
29829
29882
|
maxEncodedBytes: 65536,
|
|
@@ -36651,6 +36704,16 @@ var init_kits = __esm({
|
|
|
36651
36704
|
});
|
|
36652
36705
|
|
|
36653
36706
|
// ../../core/dev-server/src/widgets.ts
|
|
36707
|
+
var widgets_exports = {};
|
|
36708
|
+
__export(widgets_exports, {
|
|
36709
|
+
buildViewSnapshot: () => buildViewSnapshot,
|
|
36710
|
+
buildWidgetSnapshot: () => buildWidgetSnapshot,
|
|
36711
|
+
describeThrown: () => describeThrown,
|
|
36712
|
+
extractWidgets: () => extractWidgets,
|
|
36713
|
+
freezeOverrideSnapshot: () => freezeOverrideSnapshot,
|
|
36714
|
+
frozenViewManifestEntries: () => frozenViewManifestEntries,
|
|
36715
|
+
viewWidgetId: () => viewWidgetId
|
|
36716
|
+
});
|
|
36654
36717
|
import { createHash as createHash14 } from "node:crypto";
|
|
36655
36718
|
import { inspect } from "node:util";
|
|
36656
36719
|
import { runInNewContext } from "node:vm";
|
|
@@ -38698,7 +38761,7 @@ async function handleDev(req, res, state) {
|
|
|
38698
38761
|
if (req.method === "POST") return await handleWidgetPushPreview(req, res, state);
|
|
38699
38762
|
const widgetId = new URL(url, "http://localhost").searchParams.get("widgetId");
|
|
38700
38763
|
if (req.method === "DELETE") return await handleWidgetClearPreview(res, state, widgetId);
|
|
38701
|
-
return await handleWidgetPreview(res, widgetId);
|
|
38764
|
+
return await handleWidgetPreview(res, widgetId, state.tier5Dir);
|
|
38702
38765
|
}
|
|
38703
38766
|
if (url === "/__dev/seed") {
|
|
38704
38767
|
const seed2 = state.app.module.seed;
|
|
@@ -39319,9 +39382,8 @@ async function listBundles(dir) {
|
|
|
39319
39382
|
continue;
|
|
39320
39383
|
}
|
|
39321
39384
|
for (const entry of entries) {
|
|
39322
|
-
|
|
39323
|
-
|
|
39324
|
-
}
|
|
39385
|
+
const name = servedBundleName(entry);
|
|
39386
|
+
if (name !== void 0) names.add(name);
|
|
39325
39387
|
}
|
|
39326
39388
|
}
|
|
39327
39389
|
const result = [];
|
|
@@ -39348,14 +39410,14 @@ async function handleBundleGet(res, name, dir) {
|
|
|
39348
39410
|
res.statusCode = 200;
|
|
39349
39411
|
res.end(loaded.bytes);
|
|
39350
39412
|
}
|
|
39351
|
-
async function scanWidgets() {
|
|
39413
|
+
async function scanWidgets(dir) {
|
|
39352
39414
|
const out = [];
|
|
39353
39415
|
const seen = /* @__PURE__ */ new Set();
|
|
39354
39416
|
const emitted = /* @__PURE__ */ new Set();
|
|
39355
|
-
for (const { name } of await listBundles()) {
|
|
39417
|
+
for (const { name } of await listBundles(dir)) {
|
|
39356
39418
|
if (seen.has(name)) continue;
|
|
39357
39419
|
seen.add(name);
|
|
39358
|
-
const loaded = await readBundleFile(name);
|
|
39420
|
+
const loaded = await readBundleFile(name, dir);
|
|
39359
39421
|
if (!loaded) continue;
|
|
39360
39422
|
try {
|
|
39361
39423
|
const js = loaded.bytes.toString("utf8");
|
|
@@ -39372,15 +39434,15 @@ async function scanWidgets() {
|
|
|
39372
39434
|
}
|
|
39373
39435
|
return out;
|
|
39374
39436
|
}
|
|
39375
|
-
async function handleWidgetList(res) {
|
|
39376
|
-
sendJson(res, 200, { widgets: await scanWidgets() });
|
|
39437
|
+
async function handleWidgetList(res, dir) {
|
|
39438
|
+
sendJson(res, 200, { widgets: await scanWidgets(dir) });
|
|
39377
39439
|
}
|
|
39378
|
-
async function buildSnapshotForId(widgetId) {
|
|
39440
|
+
async function buildSnapshotForId(widgetId, dir) {
|
|
39379
39441
|
const override = widgetOverrides.get(widgetId);
|
|
39380
39442
|
if (override) return { ok: true, snapshot: override };
|
|
39381
|
-
const entry = (await scanWidgets()).find((w) => w.widgetId === widgetId);
|
|
39443
|
+
const entry = (await scanWidgets(dir)).find((w) => w.widgetId === widgetId);
|
|
39382
39444
|
if (!entry) return { ok: false, status: 404, error: "widget_not_found" };
|
|
39383
|
-
const loaded = await readBundleFile(entry.bundle);
|
|
39445
|
+
const loaded = await readBundleFile(entry.bundle, dir);
|
|
39384
39446
|
if (!loaded) return { ok: false, status: 404, error: "widget_not_found" };
|
|
39385
39447
|
try {
|
|
39386
39448
|
const js = loaded.bytes.toString("utf8");
|
|
@@ -39394,8 +39456,8 @@ async function buildSnapshotForId(widgetId) {
|
|
|
39394
39456
|
return { ok: false, status: 422, error: "widget_invalid", message: err.message };
|
|
39395
39457
|
}
|
|
39396
39458
|
}
|
|
39397
|
-
async function handleWidgetGet(req, res, widgetId) {
|
|
39398
|
-
const built = await buildSnapshotForId(widgetId);
|
|
39459
|
+
async function handleWidgetGet(req, res, widgetId, dir) {
|
|
39460
|
+
const built = await buildSnapshotForId(widgetId, dir);
|
|
39399
39461
|
if (!built.ok) return sendJson(res, built.status, { error: built.error, widgetId, message: built.message });
|
|
39400
39462
|
const etag = `"${built.snapshot.contentEtag}"`;
|
|
39401
39463
|
const ifNoneMatch = req.headers["if-none-match"];
|
|
@@ -39408,9 +39470,9 @@ async function handleWidgetGet(req, res, widgetId) {
|
|
|
39408
39470
|
res.setHeader("cache-control", `max-age=${built.snapshot.refresh.ttlSeconds}`);
|
|
39409
39471
|
sendJson(res, 200, built.snapshot);
|
|
39410
39472
|
}
|
|
39411
|
-
async function handleWidgetPreview(res, widgetId) {
|
|
39473
|
+
async function handleWidgetPreview(res, widgetId, dir) {
|
|
39412
39474
|
if (!widgetId) return sendJson(res, 400, { error: "missing_widgetId" });
|
|
39413
|
-
const built = await buildSnapshotForId(widgetId);
|
|
39475
|
+
const built = await buildSnapshotForId(widgetId, dir);
|
|
39414
39476
|
if (!built.ok) return sendJson(res, built.status, { error: built.error, widgetId, message: built.message });
|
|
39415
39477
|
sendJson(res, 200, built.snapshot);
|
|
39416
39478
|
}
|
|
@@ -40029,10 +40091,10 @@ function createDevServer(opts = {}) {
|
|
|
40029
40091
|
if (bundleMatch && (req.method === "GET" || req.method === "HEAD"))
|
|
40030
40092
|
return await handleBundleGet(res, bundleMatch[1], state.tier5Dir);
|
|
40031
40093
|
if (url.split("?")[0] === "/v1/widgets" && (req.method === "GET" || req.method === "HEAD"))
|
|
40032
|
-
return await handleWidgetList(res);
|
|
40094
|
+
return await handleWidgetList(res, state.tier5Dir);
|
|
40033
40095
|
const widgetMatch = /^\/v1\/widget\/([A-Za-z0-9_.\-]+)$/.exec(url.split("?")[0]);
|
|
40034
40096
|
if (widgetMatch && (req.method === "GET" || req.method === "HEAD"))
|
|
40035
|
-
return await handleWidgetGet(req, res, widgetMatch[1]);
|
|
40097
|
+
return await handleWidgetGet(req, res, widgetMatch[1], state.tier5Dir);
|
|
40036
40098
|
const ahManifest = /^\/v1\/action-handlers\/([A-Za-z0-9_.\-]+)$/.exec(url.split("?")[0]);
|
|
40037
40099
|
if (ahManifest && (req.method === "GET" || req.method === "HEAD"))
|
|
40038
40100
|
return handleActionHandlersManifest(res, ahManifest[1]);
|
|
@@ -40046,7 +40108,10 @@ function createDevServer(opts = {}) {
|
|
|
40046
40108
|
homeScreenId: state.app?.meta.homeScreenId,
|
|
40047
40109
|
screens: state.app?.meta.screenIds ?? [],
|
|
40048
40110
|
templatedPatterns: state.app?.meta.templatedPatterns ?? [],
|
|
40049
|
-
|
|
40111
|
+
// Same dir, same reason as the routes above: an off-repo app's own
|
|
40112
|
+
// bundles must show up in its introspection body, not just the
|
|
40113
|
+
// repo-global ones it didn't build.
|
|
40114
|
+
tier5Bundles: await listBundles(state.tier5Dir),
|
|
40050
40115
|
toggles: state.toggles,
|
|
40051
40116
|
admin: "/web/future/app.html"
|
|
40052
40117
|
});
|
|
@@ -40487,6 +40552,7 @@ __export(build_exports2, {
|
|
|
40487
40552
|
SOURCEMAP_ON_DEMAND_PATH: () => SOURCEMAP_ON_DEMAND_PATH,
|
|
40488
40553
|
bakeCatalogs: () => bakeCatalogs,
|
|
40489
40554
|
bakeNeedsLiveOrigin: () => bakeNeedsLiveOrigin,
|
|
40555
|
+
bakeWidgets: () => bakeWidgets,
|
|
40490
40556
|
buildRelease: () => buildRelease,
|
|
40491
40557
|
buildReleaseFromContent: () => buildReleaseFromContent,
|
|
40492
40558
|
bundleNameFromUrl: () => bundleNameFromUrl,
|
|
@@ -40585,6 +40651,77 @@ function sha2564(buf) {
|
|
|
40585
40651
|
function sri2(buf) {
|
|
40586
40652
|
return "sha256-" + createHash18("sha256").update(buf).digest("base64");
|
|
40587
40653
|
}
|
|
40654
|
+
async function widgetFailureDetail(res) {
|
|
40655
|
+
try {
|
|
40656
|
+
const body = JSON.parse(await res.text());
|
|
40657
|
+
const detail = typeof body.message === "string" && body.message ? body.message : typeof body.error === "string" && body.error ? body.error : "";
|
|
40658
|
+
return detail ? `: ${detail}` : "";
|
|
40659
|
+
} catch {
|
|
40660
|
+
return "";
|
|
40661
|
+
}
|
|
40662
|
+
}
|
|
40663
|
+
function ownBundleNames(dir) {
|
|
40664
|
+
if (!dir) return void 0;
|
|
40665
|
+
return servedBundleNames(dir);
|
|
40666
|
+
}
|
|
40667
|
+
async function bakeWidgets(fetchPath, putWidget, ownBundles) {
|
|
40668
|
+
const widgets = {};
|
|
40669
|
+
const failures = [];
|
|
40670
|
+
const isOurs = (bundle) => ownBundles !== void 0 && bundle !== void 0 && ownBundles.has(bundle);
|
|
40671
|
+
const listRes = await fetchPath("/v1/widgets");
|
|
40672
|
+
if (!listRes.ok) {
|
|
40673
|
+
failures.push({
|
|
40674
|
+
status: listRes.status,
|
|
40675
|
+
message: `the widget manifest could not be read (GET /v1/widgets \u2192 ${listRes.status}) \u2014 this release carries no widget snapshots, whether or not the app declares any`
|
|
40676
|
+
});
|
|
40677
|
+
return { widgets, failures };
|
|
40678
|
+
}
|
|
40679
|
+
let list;
|
|
40680
|
+
try {
|
|
40681
|
+
const parsed = JSON.parse(await listRes.text()).widgets ?? [];
|
|
40682
|
+
if (!Array.isArray(parsed)) throw new Error("widgets is not an array");
|
|
40683
|
+
list = parsed;
|
|
40684
|
+
} catch {
|
|
40685
|
+
failures.push({
|
|
40686
|
+
status: listRes.status,
|
|
40687
|
+
message: "the widget manifest came back malformed \u2014 this release carries no widget snapshots"
|
|
40688
|
+
});
|
|
40689
|
+
return { widgets, failures };
|
|
40690
|
+
}
|
|
40691
|
+
for (const { widgetId, bundle } of list) {
|
|
40692
|
+
const res = await fetchPath(`/v1/widget/${encodeURIComponent(widgetId)}`);
|
|
40693
|
+
if (!res.ok) {
|
|
40694
|
+
if (isOurs(bundle)) {
|
|
40695
|
+
failures.push({
|
|
40696
|
+
widgetId,
|
|
40697
|
+
status: res.status,
|
|
40698
|
+
message: `widget "${widgetId}" is declared but did not produce a snapshot (GET /v1/widget/${widgetId} \u2192 ${res.status}${await widgetFailureDetail(res)}) \u2014 the release does not carry it`
|
|
40699
|
+
});
|
|
40700
|
+
}
|
|
40701
|
+
continue;
|
|
40702
|
+
}
|
|
40703
|
+
let snap;
|
|
40704
|
+
try {
|
|
40705
|
+
snap = JSON.parse(await res.text());
|
|
40706
|
+
} catch {
|
|
40707
|
+
if (isOurs(bundle)) {
|
|
40708
|
+
failures.push({
|
|
40709
|
+
widgetId,
|
|
40710
|
+
status: res.status,
|
|
40711
|
+
message: `widget "${widgetId}" answered ${res.status} with a body that is not a snapshot \u2014 the release does not carry it`
|
|
40712
|
+
});
|
|
40713
|
+
}
|
|
40714
|
+
continue;
|
|
40715
|
+
}
|
|
40716
|
+
const json5 = JSON.stringify(snap);
|
|
40717
|
+
await putWidget(widgetId, json5);
|
|
40718
|
+
widgets[widgetId] = {
|
|
40719
|
+
contentEtag: snap.contentEtag ?? sha2564(json5),
|
|
40720
|
+
ttlSeconds: snap.refresh?.ttlSeconds ?? 0
|
|
40721
|
+
};
|
|
40722
|
+
}
|
|
40723
|
+
return { widgets, failures };
|
|
40724
|
+
}
|
|
40588
40725
|
async function snapshotTokens(app, base, fetchTokens, put) {
|
|
40589
40726
|
const res = await fetchTokens();
|
|
40590
40727
|
if (!res.ok) {
|
|
@@ -40781,6 +40918,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
40781
40918
|
const screenIds = Object.keys(preloaded.module.screens.exact);
|
|
40782
40919
|
const failedToBuild = [];
|
|
40783
40920
|
const missingBundles = [];
|
|
40921
|
+
const widgetBakeFailures = [];
|
|
40784
40922
|
const lint = [];
|
|
40785
40923
|
const renders = [];
|
|
40786
40924
|
const baked = [];
|
|
@@ -41314,21 +41452,16 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
41314
41452
|
}
|
|
41315
41453
|
}
|
|
41316
41454
|
if (store.putWidget) {
|
|
41317
|
-
const
|
|
41318
|
-
|
|
41319
|
-
|
|
41320
|
-
|
|
41321
|
-
|
|
41322
|
-
|
|
41323
|
-
|
|
41324
|
-
|
|
41325
|
-
|
|
41326
|
-
|
|
41327
|
-
contentEtag: snap.contentEtag ?? sha2564(json5),
|
|
41328
|
-
ttlSeconds: snap.refresh?.ttlSeconds ?? 0
|
|
41329
|
-
};
|
|
41330
|
-
}
|
|
41331
|
-
}
|
|
41455
|
+
const bakedWidgets = await bakeWidgets(
|
|
41456
|
+
(path) => devFetch(`${base}${path}`, { headers: { "X-Himalaya-App": app } }),
|
|
41457
|
+
(widgetId, json5) => store.putWidget(app, widgetId, json5),
|
|
41458
|
+
// `opts.tier5Dir`, NOT the `tier5Dir` local — that one falls back to the
|
|
41459
|
+
// repo-global dir, where this package's widgets cannot be told from anyone
|
|
41460
|
+
// else's and the filter would claim every app's rows as ours.
|
|
41461
|
+
ownBundleNames(opts.tier5Dir)
|
|
41462
|
+
);
|
|
41463
|
+
Object.assign(widgets, bakedWidgets.widgets);
|
|
41464
|
+
widgetBakeFailures.push(...bakedWidgets.failures);
|
|
41332
41465
|
}
|
|
41333
41466
|
} finally {
|
|
41334
41467
|
await new Promise((r) => dev.close(() => r()));
|
|
@@ -41417,6 +41550,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
41417
41550
|
return named ? { ...v, message: `${v.message} \u2014 bundle "${named.name}"` } : v;
|
|
41418
41551
|
}),
|
|
41419
41552
|
...tokensSnapshotFailure ? { tokensSnapshotFailure } : {},
|
|
41553
|
+
...widgetBakeFailures.length ? { widgetBakeFailures } : {},
|
|
41420
41554
|
...collect?.lint ? { lint, workers } : {},
|
|
41421
41555
|
...collect?.render ? { renders } : {},
|
|
41422
41556
|
...collect?.descriptors ? { descriptors: baked, linkableScreenIds: [...linkable] } : {},
|
|
@@ -59318,6 +59452,17 @@ function summarizeLint(app, bres, outcome, strict, extraIssues = []) {
|
|
|
59318
59452
|
message: tokensFailure.message
|
|
59319
59453
|
});
|
|
59320
59454
|
}
|
|
59455
|
+
for (const failure of outcome.widgetBakeFailures ?? []) {
|
|
59456
|
+
issues.push({
|
|
59457
|
+
screen: null,
|
|
59458
|
+
pass: "widgets",
|
|
59459
|
+
severity: strict ? "error" : "warning",
|
|
59460
|
+
ruleCode: "widget-not-produced",
|
|
59461
|
+
...failure.widgetId ? { widgetId: failure.widgetId } : {},
|
|
59462
|
+
status: failure.status,
|
|
59463
|
+
message: failure.message
|
|
59464
|
+
});
|
|
59465
|
+
}
|
|
59321
59466
|
const errorIssues = issues.filter((i) => i.severity === "error");
|
|
59322
59467
|
const workers = (outcome.workers ?? []).filter((w) => w.threw || w.console.length);
|
|
59323
59468
|
const workerThrows = workers.filter((w) => w.threw);
|
|
@@ -60408,6 +60553,12 @@ function wixPlayerTestflightTarget(requested) {
|
|
|
60408
60553
|
return target === "bo" || target === "prod" ? target : void 0;
|
|
60409
60554
|
}
|
|
60410
60555
|
var SURFACE_IDS = `${PREVIEW_SURFACES.filter((s) => !s.id.startsWith("widget:")).map((s) => s.id).join("|")}|widget:<family>`;
|
|
60556
|
+
var RENDER_DEVICE_SURFACE_IDS = PREVIEW_SURFACES.filter((s) => s.gate.kind !== "family").map((s) => s.id).join("|");
|
|
60557
|
+
var PRODUCED_HINTS = {
|
|
60558
|
+
"not-measured": "widget production was not measured \u2014 `--measure-widgets` evaluates this package's built bundles (it RUNS their code), or ask a running app: GET /v1/widgets. `himi validate --strict` fails a package whose declared widget does not produce.",
|
|
60559
|
+
unbuilt: "this package has no dist/bundles, so there is nothing to measure \u2014 run `himi build` first. A package with no Tier-5 bundle can declare no widget at all.",
|
|
60560
|
+
"producer-unavailable": "the widget producer is not resolvable in this install, so production cannot be measured here at all \u2014 building this package will not change that. Ask a running app instead: GET /v1/widgets."
|
|
60561
|
+
};
|
|
60411
60562
|
var DEVELOPER_PORTAL_URL = `${ADMIN_ORIGIN_BO}/#/developer`;
|
|
60412
60563
|
var MAX_APP_SOURCE_BYTES_HELP = "4 MiB (4,194,304 bytes)";
|
|
60413
60564
|
var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
@@ -60493,8 +60644,9 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
60493
60644
|
--input '{"id":"\u2026"}' supplies navigation input before the worker boots;
|
|
60494
60645
|
--load-budget <ms> raises/lowers the per-service load() budget (--live defaults to 30000);
|
|
60495
60646
|
--width 390 / --device iphone renders the PNG at phone width (default: desktop);
|
|
60496
|
-
--device also takes
|
|
60647
|
+
--device also takes an app-shell surface id (${RENDER_DEVICE_SURFACE_IDS})
|
|
60497
60648
|
at its catalog viewport width (himi surfaces lists them);
|
|
60649
|
+
a widget family is NOT a device \u2014 fetch /v1/widget/<widgetId>;
|
|
60498
60650
|
--rtl sets ambient direction (dir=rtl + $env:isRTL)
|
|
60499
60651
|
himi icons [--json] the valid Icon.name vocabulary (offline)
|
|
60500
60652
|
himi fonts [list] [--licenses] the curated font vocabulary a typography.*.family may
|
|
@@ -60633,11 +60785,14 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
60633
60785
|
print web + himi:// + agent-preview JSON URLs
|
|
60634
60786
|
--surface ${SURFACE_IDS}
|
|
60635
60787
|
frames the web preview as that surface (?surface=)
|
|
60636
|
-
himi surfaces [--content <dir>] [--app <app> --release <id>]
|
|
60788
|
+
himi surfaces [--content <dir>] [--app <app> --release <id>] [--measure-widgets]
|
|
60637
60789
|
the surface catalog vs the LOCAL package's envelope
|
|
60638
60790
|
(platforms.json): targeted surfaces, the opt-in for the
|
|
60639
60791
|
rest, and (with --app --release) per-surface preview
|
|
60640
60792
|
links. For a pushed release's envelope: himi context
|
|
60793
|
+
--measure-widgets additionally reports which widget
|
|
60794
|
+
families this package PRODUCES \u2014 it evaluates the
|
|
60795
|
+
built bundles, i.e. RUNS their code; off by default
|
|
60641
60796
|
himi context --app <app> --release <id> [--screen <id>] [--include telemetry]
|
|
60642
60797
|
fetch the agent preview envelope (GET /v1/preview/a/\u2026)
|
|
60643
60798
|
himi app-docs list|get <spec|mobile-ux> --app <app> [--release <id>]
|
|
@@ -60862,7 +61017,7 @@ var COMMANDS = [
|
|
|
60862
61017
|
{ name: "share", summary: "publish or revoke a content-addressed `.himi` share link. The package must be a validated archive for an already-published release; the resulting https URL is safe to QR, copy, or open in Himi Player.", required: "--file <package.himi> [--expires-at <ISO>] | revoke --app <app> <shareId>" },
|
|
60863
61018
|
{ name: "run", summary: "serve a .himi package on localhost and open it in a browser \u2014 no serve plane, no dev-server, no setup. Given no argument it builds the current content package first, so `himi run` is the inner loop: edit, run, look at it. The SPA and /v1 are served from ONE origin because Tier-5 bundle fetches on web are same-origin-only. --chrome preview frames the app in a device chassis; --chrome app serves it as a plain web app. Blocks until Ctrl-C, like any dev server. --browser runs the whole plane INSIDE the tab (service worker + in-memory store) so no app code executes in this process or on any pod.", required: "[<package.himi|dir|url>] [--browser] [--content <dir>] [--port <n>] [--chrome preview|app] [--screen <id>] [--surface <id>] [--no-open] [--spa <url>]" },
|
|
60864
61019
|
{ name: "preview", summary: "print the shareable web URL + himi:// deep link + agent /v1/preview JSON URLs for an app+release; --surface frames the web preview as any catalog surface (?surface=)", required: "--app --release [--screen] [--surface]" },
|
|
60865
|
-
{ name: "surfaces", summary: "the surface catalog vs this app's envelope (platforms.json): targeted surfaces, the opt-in key for the rest,
|
|
61020
|
+
{ name: "surfaces", summary: "the surface catalog vs this app's envelope (platforms.json): targeted surfaces, the opt-in key for the rest, per-surface preview links with --app --release, and which widget families the package produces with --measure-widgets (which runs its built bundles)", required: "[--content <dir>] [--app --release] [--measure-widgets]" },
|
|
60866
61021
|
{ name: "context", summary: "fetch the agent preview envelope (GET /v1/preview/a/<app>) \u2014 ok/issues/screens/links; exit 1 if ok:false", required: "--app --release [--screen] [--include telemetry]" },
|
|
60867
61022
|
{ name: "app-docs", summary: "retrieve the public-safe SPEC.md and MOBILE-UX.md carried by an immutable release; `list` is JSON metadata and `get` prints one Markdown document", required: "list|get <spec|mobile-ux> --app <app> [--release <id>]" },
|
|
60868
61023
|
{ name: "telemetry", summary: "head-loop telemetry read-back (GET /v1/telemetry/events + logs): screen_view, action_*, nav/error events, worker_console logs. Default includes recent events + logs; --summary/--crashes add aggregate/crash-stack reads; --follow emits bounded JSONL updates.", required: "--app --release [--screen] [--type] [--since] [--limit] [--follow] [--summary] [--crashes]" },
|
|
@@ -61699,6 +61854,60 @@ async function loadAuthoring() {
|
|
|
61699
61854
|
throw new AuthoringUnavailable();
|
|
61700
61855
|
}
|
|
61701
61856
|
}
|
|
61857
|
+
async function producedWidgetFamilies(dir) {
|
|
61858
|
+
let widgetsModule;
|
|
61859
|
+
let tier5Dir;
|
|
61860
|
+
try {
|
|
61861
|
+
const [w, t] = await Promise.all([
|
|
61862
|
+
Promise.resolve().then(() => (init_widgets(), widgets_exports)),
|
|
61863
|
+
Promise.resolve().then(() => (init_tier5_dir(), tier5_dir_exports))
|
|
61864
|
+
]);
|
|
61865
|
+
widgetsModule = w;
|
|
61866
|
+
tier5Dir = t;
|
|
61867
|
+
} catch {
|
|
61868
|
+
return { families: void 0, source: "producer-unavailable" };
|
|
61869
|
+
}
|
|
61870
|
+
const outDir = tier5Dir.bundleOutDir(dir);
|
|
61871
|
+
try {
|
|
61872
|
+
readdirSync23(outDir);
|
|
61873
|
+
} catch {
|
|
61874
|
+
return { families: void 0, source: "unbuilt" };
|
|
61875
|
+
}
|
|
61876
|
+
const names = [...tier5Dir.servedBundleNames(outDir)];
|
|
61877
|
+
const families = /* @__PURE__ */ new Set();
|
|
61878
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
61879
|
+
for (const name of names) {
|
|
61880
|
+
let js;
|
|
61881
|
+
for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
|
|
61882
|
+
try {
|
|
61883
|
+
js = readFileSync63(join49(outDir, candidate), "utf8");
|
|
61884
|
+
break;
|
|
61885
|
+
} catch {
|
|
61886
|
+
}
|
|
61887
|
+
}
|
|
61888
|
+
if (js === void 0) continue;
|
|
61889
|
+
let extracted;
|
|
61890
|
+
try {
|
|
61891
|
+
extracted = widgetsModule.extractWidgets(js);
|
|
61892
|
+
} catch {
|
|
61893
|
+
continue;
|
|
61894
|
+
}
|
|
61895
|
+
for (const [widgetId, def] of Object.entries(extracted.widgets)) {
|
|
61896
|
+
try {
|
|
61897
|
+
widgetsModule.buildWidgetSnapshot(js, widgetId);
|
|
61898
|
+
families.add(def.family);
|
|
61899
|
+
} catch {
|
|
61900
|
+
}
|
|
61901
|
+
}
|
|
61902
|
+
for (const entry of widgetsModule.frozenViewManifestEntries(extracted.views, emitted)) {
|
|
61903
|
+
try {
|
|
61904
|
+
if (widgetsModule.buildViewSnapshot(js, entry.view.viewId, entry.view.surfaceId)) families.add(entry.family);
|
|
61905
|
+
} catch {
|
|
61906
|
+
}
|
|
61907
|
+
}
|
|
61908
|
+
}
|
|
61909
|
+
return { families, source: "dist/bundles" };
|
|
61910
|
+
}
|
|
61702
61911
|
async function run(argv, io = defaultIO) {
|
|
61703
61912
|
const { _: pos, flags } = parseFlags(argv);
|
|
61704
61913
|
const command = pos[0];
|
|
@@ -62729,7 +62938,21 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
62729
62938
|
if (deviceName) {
|
|
62730
62939
|
renderWidth = DEVICE_WIDTHS[deviceName.toLowerCase()];
|
|
62731
62940
|
if (!renderWidth) {
|
|
62732
|
-
|
|
62941
|
+
const devices = Object.keys(DEVICE_WIDTHS).filter((d) => surfaceById(d)?.gate.kind !== "family");
|
|
62942
|
+
io.error(JSON.stringify({ error: `unknown --device "${deviceName}"`, devices }));
|
|
62943
|
+
return 2;
|
|
62944
|
+
}
|
|
62945
|
+
const surface = surfaceById(deviceName.toLowerCase());
|
|
62946
|
+
if (surface && isWidgetFamilySurface(surface)) {
|
|
62947
|
+
io.error(JSON.stringify({
|
|
62948
|
+
error: `--device "${deviceName}" is a widget family ("${surfaceFrozenFamily(surface)}"), not a viewport. himi render draws a screen; a widget is produced from defineWidget and addressed by widgetId, so rendering the screen at ${renderWidth}px would look like a widget and be none.`,
|
|
62949
|
+
surface: surface.id,
|
|
62950
|
+
renderMode: surfaceRenderMode(surface),
|
|
62951
|
+
instead: [
|
|
62952
|
+
"GET /v1/widgets \u2014 the widgets this app actually produces",
|
|
62953
|
+
"GET /v1/widget/<widgetId> \u2014 the frozen snapshot the OS renders"
|
|
62954
|
+
]
|
|
62955
|
+
}));
|
|
62733
62956
|
return 2;
|
|
62734
62957
|
}
|
|
62735
62958
|
} else if (typeof flags.width === "string" && flags.width) {
|
|
@@ -63918,6 +64141,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
63918
64141
|
const release = str5(flags.release);
|
|
63919
64142
|
const base = serveBase();
|
|
63920
64143
|
const withLinks = !!(app && release && base);
|
|
64144
|
+
const produced = flags["measure-widgets"] === true ? await producedWidgetFamilies(dir) : { families: void 0, source: "not-measured" };
|
|
63921
64145
|
print({
|
|
63922
64146
|
ok: true,
|
|
63923
64147
|
// The verb describes the LOCAL content package (its platforms.json) — for
|
|
@@ -63925,12 +64149,39 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
63925
64149
|
// preview envelope reports `surfaces` from the release manifest).
|
|
63926
64150
|
envelopeSource: "local",
|
|
63927
64151
|
envelope: platforms,
|
|
63928
|
-
|
|
63929
|
-
|
|
64152
|
+
// Narrowed by the produced set when there IS one, and not merely reported
|
|
64153
|
+
// beside it. `enabled` is the short field an agent reads first, so leaving it
|
|
64154
|
+
// as the raw envelope would have kept listing `widget:ios_home` two lines above
|
|
64155
|
+
// a row saying `produced: false, needs: defineWidget(…)` — #2499's exact
|
|
64156
|
+
// over-claim, surviving inside the output added to remove it. `producedSource`
|
|
64157
|
+
// right below says how (or whether) the narrowing was measured.
|
|
64158
|
+
enabled: (() => {
|
|
64159
|
+
const envelope = resolveSurfaceEnvelope(platforms).enabled;
|
|
64160
|
+
if (!produced.families) return envelope;
|
|
64161
|
+
return envelope.filter((id) => {
|
|
64162
|
+
const surface = surfaceById(id);
|
|
64163
|
+
return !surface || !isWidgetFamilySurface(surface) || produced.families.has(surfaceFrozenFamily(surface));
|
|
64164
|
+
});
|
|
64165
|
+
})(),
|
|
64166
|
+
// Says which question the `produced` column answered, and — when it could not
|
|
64167
|
+
// be answered — WHICH way it failed. The three non-answers call for different
|
|
64168
|
+
// things and must not collapse into one: "not-measured" wants `--measure-widgets`
|
|
64169
|
+
// (and consents to running the package's code), "unbuilt" wants `himi build`,
|
|
64170
|
+
// and "producer-unavailable" wants neither — nothing about this package will
|
|
64171
|
+
// change that one.
|
|
64172
|
+
producedSource: produced.source,
|
|
64173
|
+
// …and the hint has to branch on WHICH of them it was, or it hands back advice the
|
|
64174
|
+
// caller has already taken: telling someone who just passed `--measure-widgets`
|
|
64175
|
+
// to pass `--measure-widgets` is exactly the "everything advertises the capability"
|
|
64176
|
+
// shape this issue is about, in miniature.
|
|
64177
|
+
...produced.families ? {} : { producedHint: PRODUCED_HINTS[produced.source] },
|
|
64178
|
+
surfaces: surfacesForApp(platforms, produced.families).map(({ surface, targeted, optIn, produced: isProduced, needs }) => ({
|
|
63930
64179
|
id: surface.id,
|
|
63931
64180
|
label: surface.label,
|
|
63932
64181
|
targeted,
|
|
63933
64182
|
viewport: surface.viewport,
|
|
64183
|
+
...isProduced === void 0 ? {} : { produced: isProduced },
|
|
64184
|
+
...needs ? { needs } : {},
|
|
63934
64185
|
...optIn ? { optIn: `platforms.json: { ${optIn} }` } : {},
|
|
63935
64186
|
...withLinks && targeted ? { previewWeb: previewWebUrl(base, app, release, void 0, surface.id) } : {}
|
|
63936
64187
|
})),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.850.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": [
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"artifactId": "himalaya-cli"
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
|
-
"falconPackageHash": "
|
|
66
|
+
"falconPackageHash": "17dae723ff059af1c4e2d1d27c07a030f3551c1ab3228d66cc5b6795"
|
|
67
67
|
}
|