@wix/himalaya-cli 0.830.0 → 0.832.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/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts
CHANGED
|
@@ -140,7 +140,16 @@ export interface Modifiers {
|
|
|
140
140
|
* Absent (or <= 0) keeps the node at its intrinsic size. Use this — not
|
|
141
141
|
* `fillMaxWidth` — when a node should claim the remaining space *beside* its
|
|
142
142
|
* siblings; a full-bleed fill grabs the whole axis and starves them. Ignored
|
|
143
|
-
* outside an HStack/VStack.
|
|
143
|
+
* outside an HStack/VStack.
|
|
144
|
+
* CAVEAT — row-sharing controls have NO intrinsic width to measure first: in an
|
|
145
|
+
* HStack a `Button` and a `Toggle` are implicitly weighted, so they DIVIDE the
|
|
146
|
+
* row with your weighted child instead of taking a width ahead of it —
|
|
147
|
+
* `[VStack(weight:1), Button, Button]` is a three-way split, not "the VStack gets
|
|
148
|
+
* the remainder". The RELIABLE opt-outs are `iconOnly` and `tertiary`/`link` with
|
|
149
|
+
* `fullWidth` unset. `fullWidth: false` is NOT reliable here: only Android honors
|
|
150
|
+
* it in a weighted row (`wantsRowStretch`); iOS (`WeightedStack`) and web still
|
|
151
|
+
* hand the button a share. Otherwise give the actions their own row.
|
|
152
|
+
* See `himi docs designing-himi-screens` §4. */
|
|
144
153
|
weight?: number;
|
|
145
154
|
/** RTL — pin the subtree's writing direction: `"ltr"` | `"rtl"` | `"locale"`
|
|
146
155
|
* (inherit). The common RTL pattern is the inverse of `Text.textDirection`: pin a
|
package/dist/cli.mjs
CHANGED
|
@@ -40331,6 +40331,205 @@ var init_net_scenario = __esm({
|
|
|
40331
40331
|
}
|
|
40332
40332
|
});
|
|
40333
40333
|
|
|
40334
|
+
// ../../core/dev-server/src/capability-fixtures.ts
|
|
40335
|
+
function capabilityIdsIn(bundleJs) {
|
|
40336
|
+
const out = /* @__PURE__ */ new Set();
|
|
40337
|
+
for (const m of bundleJs.matchAll(/["'`]capability\.([a-z_]+)\.([A-Za-z]+)["'`]/g)) {
|
|
40338
|
+
if (m[1] === "local_database") continue;
|
|
40339
|
+
out.add(`capability.${m[1]}.${m[2]}`);
|
|
40340
|
+
}
|
|
40341
|
+
return [...out].sort();
|
|
40342
|
+
}
|
|
40343
|
+
var decodeItem, MEDIA_EXT, MEDIA_MIME, FILE, CALL, MEDIA_STATUS, CAPABILITY_SUCCESS;
|
|
40344
|
+
var init_capability_fixtures = __esm({
|
|
40345
|
+
"../../core/dev-server/src/capability-fixtures.ts"() {
|
|
40346
|
+
decodeItem = (raw) => {
|
|
40347
|
+
if (typeof raw !== "string") return {};
|
|
40348
|
+
try {
|
|
40349
|
+
const v = JSON.parse(raw);
|
|
40350
|
+
return v && typeof v === "object" ? v : {};
|
|
40351
|
+
} catch {
|
|
40352
|
+
return {};
|
|
40353
|
+
}
|
|
40354
|
+
};
|
|
40355
|
+
MEDIA_EXT = (url) => {
|
|
40356
|
+
if (typeof url !== "string") return null;
|
|
40357
|
+
let path;
|
|
40358
|
+
try {
|
|
40359
|
+
path = new URL(url).pathname;
|
|
40360
|
+
} catch {
|
|
40361
|
+
path = url.split("#")[0].split("?")[0];
|
|
40362
|
+
}
|
|
40363
|
+
const segment = path.split("/").pop() ?? "";
|
|
40364
|
+
const m = /\.([a-z0-9]{2,5})$/i.exec(segment);
|
|
40365
|
+
return m ? m[1].toLowerCase() : null;
|
|
40366
|
+
};
|
|
40367
|
+
MEDIA_MIME = {
|
|
40368
|
+
mp4: "video/mp4",
|
|
40369
|
+
m4v: "video/mp4",
|
|
40370
|
+
mov: "video/quicktime",
|
|
40371
|
+
webm: "video/webm",
|
|
40372
|
+
mp3: "audio/mpeg",
|
|
40373
|
+
m4a: "audio/mp4",
|
|
40374
|
+
aac: "audio/aac",
|
|
40375
|
+
wav: "audio/wav",
|
|
40376
|
+
ogg: "audio/ogg"
|
|
40377
|
+
};
|
|
40378
|
+
FILE = (name) => ({ uri: `file:///crawl/${name}`, name, mimeType: "audio/m4a", sizeBytes: 4096 });
|
|
40379
|
+
CALL = (peerId, state, clock) => ({
|
|
40380
|
+
callId: "crawl-call-1",
|
|
40381
|
+
kind: "audio",
|
|
40382
|
+
state,
|
|
40383
|
+
peerId,
|
|
40384
|
+
muted: false,
|
|
40385
|
+
route: "earpiece",
|
|
40386
|
+
startedAtMs: clock
|
|
40387
|
+
});
|
|
40388
|
+
MEDIA_STATUS = (clock, autoplay = true) => ({
|
|
40389
|
+
// A real host reports `paused` when a queue is set with `autoplay: false` — which is exactly what
|
|
40390
|
+
// video-courses does. Always answering "playing" exercises the wrong branch and hides the
|
|
40391
|
+
// paused-state behaviour the screen actually has.
|
|
40392
|
+
state: autoplay ? "playing" : "paused",
|
|
40393
|
+
currentIndex: 0,
|
|
40394
|
+
positionMs: 1e3,
|
|
40395
|
+
durationMs: 6e5,
|
|
40396
|
+
rate: 1,
|
|
40397
|
+
bufferedMs: 6e4,
|
|
40398
|
+
queue: [{ id: "lesson-1", title: "Lesson one", url: "https://crawl.invalid/lesson-1.mp4", durationMs: 6e5 }],
|
|
40399
|
+
currentItem: { id: "lesson-1", title: "Lesson one", url: "https://crawl.invalid/lesson-1.mp4", durationMs: 6e5 },
|
|
40400
|
+
startedAtMs: clock
|
|
40401
|
+
});
|
|
40402
|
+
CAPABILITY_SUCCESS = {
|
|
40403
|
+
// --- audio-record ---------------------------------------------------------------------------
|
|
40404
|
+
"capability.audio_record.startSession": (p, ctx) => ({
|
|
40405
|
+
session: {
|
|
40406
|
+
id: "crawl-session-1",
|
|
40407
|
+
mode: p.mode === "background" ? "background" : "foreground",
|
|
40408
|
+
state: "recording",
|
|
40409
|
+
startedAtMs: ctx.clock,
|
|
40410
|
+
segmentCount: 1
|
|
40411
|
+
}
|
|
40412
|
+
}),
|
|
40413
|
+
"capability.audio_record.getSession": (_p, ctx) => ({
|
|
40414
|
+
session: { id: "crawl-session-1", mode: "foreground", state: "recording", startedAtMs: ctx.clock, segmentCount: 1 }
|
|
40415
|
+
}),
|
|
40416
|
+
"capability.audio_record.stopSession": (_p, ctx) => ({
|
|
40417
|
+
session: { id: "crawl-session-1", mode: "foreground", state: "stopped", startedAtMs: ctx.clock, segmentCount: 1 }
|
|
40418
|
+
}),
|
|
40419
|
+
"capability.audio_record.listSegments": (_p, ctx) => ({
|
|
40420
|
+
segments: [
|
|
40421
|
+
{ id: "seg-1", sequence: 0, file: FILE("segment-1.m4a"), startedAtMs: ctx.clock, endedAtMs: ctx.clock + 3e4, durationMs: 3e4, transcriptionState: "complete" }
|
|
40422
|
+
]
|
|
40423
|
+
}),
|
|
40424
|
+
"capability.audio_record.listSessions": (_p, ctx) => ({
|
|
40425
|
+
sessions: [{ id: "crawl-session-1", mode: "foreground", state: "stopped", startedAtMs: ctx.clock, segmentCount: 1 }]
|
|
40426
|
+
}),
|
|
40427
|
+
"capability.audio_record.getPermissionStatus": () => ({ status: "granted" }),
|
|
40428
|
+
"capability.audio_record.requestPermission": () => ({ status: "granted" }),
|
|
40429
|
+
// --- speech ---------------------------------------------------------------------------------
|
|
40430
|
+
"capability.speech.availability": () => ({ recognition: "full", synthesis: "full" }),
|
|
40431
|
+
"capability.speech.transcribeFile": () => ({
|
|
40432
|
+
complete: true,
|
|
40433
|
+
language: "en-US",
|
|
40434
|
+
segments: [{ id: "t-1", text: "crawl transcript", startMs: 0, endMs: 3e4 }]
|
|
40435
|
+
}),
|
|
40436
|
+
"capability.speech.recognizeOnce": () => ({ transcript: "crawl transcript", cancelled: false }),
|
|
40437
|
+
// --- speaker-diarization --------------------------------------------------------------------
|
|
40438
|
+
"capability.speaker_diarization.availability": () => ({ diarization: "full" }),
|
|
40439
|
+
"capability.speaker_diarization.analyzeFile": () => ({
|
|
40440
|
+
speakers: ["speaker-1", "speaker-2"],
|
|
40441
|
+
segments: [
|
|
40442
|
+
{ id: "d-1", speakerId: "speaker-1", startMs: 0, endMs: 15e3 },
|
|
40443
|
+
{ id: "d-2", speakerId: "speaker-2", startMs: 15e3, endMs: 3e4 }
|
|
40444
|
+
],
|
|
40445
|
+
complete: true,
|
|
40446
|
+
deferred: false
|
|
40447
|
+
}),
|
|
40448
|
+
// --- on-device-ai ---------------------------------------------------------------------------
|
|
40449
|
+
"capability.on_device_ai.availability": () => ({ textGeneration: "full" }),
|
|
40450
|
+
"capability.on_device_ai.generateText": () => ({ success: true, text: "crawl summary" }),
|
|
40451
|
+
// --- pdf / open-url / share (coach-lab, himi-social) ------------------------------------------
|
|
40452
|
+
"capability.pdf.isAvailable": () => ({ availability: "full" }),
|
|
40453
|
+
"capability.pdf.open": () => ({ opened: true }),
|
|
40454
|
+
"capability.open_url.canOpen": () => ({ canOpen: true }),
|
|
40455
|
+
"capability.open_url.open": () => ({ opened: true }),
|
|
40456
|
+
"capability.share.availability": () => ({ availability: "full" }),
|
|
40457
|
+
"capability.share.share": () => ({ completed: true }),
|
|
40458
|
+
// --- photos (himi-social) ---------------------------------------------------------------------
|
|
40459
|
+
"capability.photos.getSavePermissionStatus": () => ({ status: "granted" }),
|
|
40460
|
+
"capability.photos.saveToLibrary": () => ({ saved: true }),
|
|
40461
|
+
"capability.photos.pick": () => ({
|
|
40462
|
+
items: [{ uri: "file:///crawl/photo-1.jpg", name: "photo-1.jpg", mimeType: "image/jpeg", sizeBytes: 20480 }]
|
|
40463
|
+
}),
|
|
40464
|
+
// --- calls (msgr) -----------------------------------------------------------------------------
|
|
40465
|
+
//
|
|
40466
|
+
// `callStateFrom` drops anything without a non-empty string `callId`, and coerces an unrecognised
|
|
40467
|
+
// `state`/`route` to "failed"/"earpiece" rather than rejecting — so a wrong enum here would not
|
|
40468
|
+
// throw, it would quietly put every call in a failed phase and look like an app bug.
|
|
40469
|
+
"capability.calls.availability": () => ({ availability: "full" }),
|
|
40470
|
+
"capability.calls.getPermissionStatus": () => ({ status: "granted" }),
|
|
40471
|
+
"capability.calls.requestPermission": () => ({ status: "granted" }),
|
|
40472
|
+
"capability.calls.listCalls": () => ({ calls: [] }),
|
|
40473
|
+
"capability.calls.start": (p, ctx) => ({ call: CALL(String(p.peerId ?? "peer-1"), "dialing", ctx.clock) }),
|
|
40474
|
+
"capability.calls.offer": (p, ctx) => ({ call: CALL(String(p.peerId ?? "peer-1"), "ringing", ctx.clock) }),
|
|
40475
|
+
"capability.calls.answer": (_p, ctx) => ({ call: CALL("peer-1", "connected", ctx.clock) }),
|
|
40476
|
+
"capability.calls.getState": (_p, ctx) => ({ call: CALL("peer-1", "connected", ctx.clock) }),
|
|
40477
|
+
"capability.calls.reject": (_p, ctx) => ({ call: CALL("peer-1", "ended", ctx.clock) }),
|
|
40478
|
+
"capability.calls.hangup": (_p, ctx) => ({ call: CALL("peer-1", "ended", ctx.clock) }),
|
|
40479
|
+
"capability.calls.setMuted": (_p, ctx) => ({ call: { ...CALL("peer-1", "connected", ctx.clock), muted: true } }),
|
|
40480
|
+
"capability.calls.setSpeaker": (_p, ctx) => ({ call: { ...CALL("peer-1", "connected", ctx.clock), route: "speaker" } }),
|
|
40481
|
+
// --- media-playback / calendar (video-courses-preview) ----------------------------------------
|
|
40482
|
+
"capability.media_playback.getCapabilities": () => ({ download: true, pictureInPicture: true }),
|
|
40483
|
+
// `autoplay` arrives stringified — the binding sends `String(options.autoplay === true)`.
|
|
40484
|
+
"capability.media_playback.setQueue": (p, ctx) => MEDIA_STATUS(ctx.clock, p.autoplay === true || p.autoplay === "true"),
|
|
40485
|
+
"capability.media_playback.status": (_p, ctx) => MEDIA_STATUS(ctx.clock),
|
|
40486
|
+
"capability.media_playback.getState": (_p, ctx) => MEDIA_STATUS(ctx.clock),
|
|
40487
|
+
// `status` defaults to "failed" when absent and must be one of the MediaDownloadResult literals;
|
|
40488
|
+
// `file` is the handle. Returning `state`/`localUri` modelled a FAILED download while intending
|
|
40489
|
+
// completion, so video-courses took its failure-label branch under a fixture meant to succeed.
|
|
40490
|
+
//
|
|
40491
|
+
// ECHOES THE REQUESTED ITEM. Hard-coding `id: "lesson-1"` overrode the binding's `r?.id ?? item.id`
|
|
40492
|
+
// fallback, so ANY other caller — the demo bundle downloads `demo-tone` — got a lesson-1 handle
|
|
40493
|
+
// back and the crawl labelled the wrong download. A fixture that ignores its request and answers
|
|
40494
|
+
// a constant is the same defect as a screen that renders one.
|
|
40495
|
+
"capability.media_playback.download": (p, ctx) => {
|
|
40496
|
+
const item = decodeItem(p.item);
|
|
40497
|
+
const id = item.id ?? "crawl-item";
|
|
40498
|
+
const ext = MEDIA_EXT(item.url);
|
|
40499
|
+
const name = ext ? `${id}.${ext}` : id;
|
|
40500
|
+
return {
|
|
40501
|
+
id,
|
|
40502
|
+
status: "downloaded",
|
|
40503
|
+
progress: 1,
|
|
40504
|
+
file: { uri: `file:///crawl/${name}`, name, mimeType: ext && MEDIA_MIME[ext] || "application/octet-stream", sizeBytes: 1048576, modifiedAt: ctx.clock }
|
|
40505
|
+
};
|
|
40506
|
+
},
|
|
40507
|
+
"capability.calendar.getPermissionStatus": () => ({ status: "granted" }),
|
|
40508
|
+
"capability.calendar.requestPermission": () => ({ status: "granted" }),
|
|
40509
|
+
"capability.calendar.listEvents": () => ({ events: [] }),
|
|
40510
|
+
"capability.calendar.createEvent": () => ({ id: "crawl-event-1" }),
|
|
40511
|
+
// --- files ----------------------------------------------------------------------------------
|
|
40512
|
+
// `list` reads `r.items` as FileStat[] — `{ handle, modifiedAt }`, not a bare handle — and `stat`
|
|
40513
|
+
// reads `r.stat`. Returning `files`/`file` gave the binding an empty list and a null stat, so the
|
|
40514
|
+
// file flow could not reach its read/remove paths at all. `write` returns the handle itself,
|
|
40515
|
+
// which `toHandle` normalises, NOT an envelope.
|
|
40516
|
+
"capability.files.list": (_p, ctx) => ({ items: [{ handle: FILE("segment-1.m4a"), modifiedAt: ctx.clock }] }),
|
|
40517
|
+
"capability.files.stat": (_p, ctx) => ({ stat: { handle: FILE("segment-1.m4a"), modifiedAt: ctx.clock } }),
|
|
40518
|
+
"capability.files.readText": () => ({ text: "crawl file contents" }),
|
|
40519
|
+
// ECHOES THE REQUESTED PATH. `files.write` returns this object DIRECTLY to `toHandle`, whose
|
|
40520
|
+
// fallback to the requested path only applies when a field is absent — so a hard-coded handle
|
|
40521
|
+
// made every write resolve to the same file, and a consumer passing that handle onward (an export
|
|
40522
|
+
// writing `exports/<id>.gpx`) referenced something that does not exist.
|
|
40523
|
+
"capability.files.write": (p, ctx) => {
|
|
40524
|
+
const path = typeof p.path === "string" && p.path ? p.path : "crawl/written.txt";
|
|
40525
|
+
const name = path.split("/").pop() || path;
|
|
40526
|
+
return { uri: `file:///${path.replace(/^\/+/, "")}`, name, mimeType: typeof p.mimeType === "string" ? p.mimeType : "application/octet-stream", sizeBytes: 1024, modifiedAt: ctx.clock };
|
|
40527
|
+
},
|
|
40528
|
+
"capability.files.remove": () => ({ removed: true })
|
|
40529
|
+
};
|
|
40530
|
+
}
|
|
40531
|
+
});
|
|
40532
|
+
|
|
40334
40533
|
// ../../core/dev-server/src/crawl-relations.ts
|
|
40335
40534
|
function inversePartner(action, declared) {
|
|
40336
40535
|
if (/^toggle/i.test(action)) return null;
|
|
@@ -40467,6 +40666,7 @@ __export(screen_crawl_exports, {
|
|
|
40467
40666
|
bootAndSnapshotState: () => bootAndSnapshotState,
|
|
40468
40667
|
bootScreenWorker: () => bootScreenWorker,
|
|
40469
40668
|
crawlScreen: () => crawlScreen,
|
|
40669
|
+
crawlScreenCapabilitySuccess: () => crawlScreenCapabilitySuccess,
|
|
40470
40670
|
crawlScreenDeep: () => crawlScreenDeep,
|
|
40471
40671
|
crawlScreenHostile: () => crawlScreenHostile,
|
|
40472
40672
|
crawlScreenJourney: () => crawlScreenJourney,
|
|
@@ -40746,7 +40946,7 @@ function declaredCapabilitiesOf(descriptor) {
|
|
|
40746
40946
|
const list = Array.isArray(lb?.declaredCapabilities) ? lb.declaredCapabilities : [];
|
|
40747
40947
|
return new Set(list.filter((c) => typeof c === "string"));
|
|
40748
40948
|
}
|
|
40749
|
-
function hostDispatch(localDbSchema, declaredCapabilities = /* @__PURE__ */ new Set()) {
|
|
40949
|
+
function hostDispatch(localDbSchema, declaredCapabilities = /* @__PURE__ */ new Set(), capabilitySuccess = false, clock = 0) {
|
|
40750
40950
|
return async (action, params) => {
|
|
40751
40951
|
if (/memberIdentity|member\.identity|currentMember/i.test(action)) {
|
|
40752
40952
|
return { id: "crawl-member-0001", loggedIn: true, memberId: "crawl-member-0001" };
|
|
@@ -40759,6 +40959,10 @@ function hostDispatch(localDbSchema, declaredCapabilities = /* @__PURE__ */ new
|
|
|
40759
40959
|
);
|
|
40760
40960
|
}
|
|
40761
40961
|
if (cap[1] === "local_database") return localDatabaseAnswer(localDbSchema, cap[2], params ?? {});
|
|
40962
|
+
if (capabilitySuccess) {
|
|
40963
|
+
const answer = CAPABILITY_SUCCESS[action];
|
|
40964
|
+
if (answer) return answer(params ?? {}, { clock });
|
|
40965
|
+
}
|
|
40762
40966
|
}
|
|
40763
40967
|
return null;
|
|
40764
40968
|
};
|
|
@@ -40865,9 +41069,13 @@ async function bootScreenWorker(opts) {
|
|
|
40865
41069
|
wixCall: opts.wixCall,
|
|
40866
41070
|
input,
|
|
40867
41071
|
budgetMs: opts.budgetMs ?? 2e3,
|
|
40868
|
-
|
|
41072
|
+
// THE SAME CLOCK THE WORKER IS PINNED TO, one line below. `?? 0` gave the fixtures epoch 1970
|
|
41073
|
+
// while the worker believed it was 2026, so a modelled session carried a timestamp fifty-six
|
|
41074
|
+
// years before the "now" the app computes against — inconsistent rendered dates, and any
|
|
41075
|
+
// time-dependent branch taking the wrong arm.
|
|
41076
|
+
dispatch: hostDispatch(opts.localDbSchema, declaredCapabilitiesOf(opts.descriptor), opts.capabilitySuccess === true, opts.clock ?? CRAWL_CLOCK),
|
|
40869
41077
|
deviceParity: true,
|
|
40870
|
-
clock: opts.clock ??
|
|
41078
|
+
clock: opts.clock ?? CRAWL_CLOCK,
|
|
40871
41079
|
seed: opts.seed ?? 1,
|
|
40872
41080
|
skipLoad: !!(appear && parseWorkerAction(appear.actionId)),
|
|
40873
41081
|
...opts.evaluator ? { evaluator: opts.evaluator } : {}
|
|
@@ -40941,6 +41149,18 @@ async function withSwallowedRejections(fn) {
|
|
|
40941
41149
|
else globalThis.removeEventListener?.("unhandledrejection", swallow);
|
|
40942
41150
|
}
|
|
40943
41151
|
}
|
|
41152
|
+
async function crawlScreenCapabilitySuccess(opts) {
|
|
41153
|
+
return withSwallowedRejections(async () => {
|
|
41154
|
+
const declared = declaredCapabilitiesOf(opts.descriptor);
|
|
41155
|
+
const modelled = opts.bundleJs ? capabilityIdsIn(opts.bundleJs).filter((id) => CAPABILITY_SUCCESS[id] && grants(declared, id.split(".")[1])) : [];
|
|
41156
|
+
if (!modelled.length) return { findings: [], modelled: 0 };
|
|
41157
|
+
const r = await crawlScreenInner({ ...opts, capabilitySuccess: true });
|
|
41158
|
+
return {
|
|
41159
|
+
findings: r.findings.map((f) => ({ ...f, axis: f.axis ? `capability:success+${f.axis}` : "capability:success" })),
|
|
41160
|
+
modelled: modelled.length
|
|
41161
|
+
};
|
|
41162
|
+
});
|
|
41163
|
+
}
|
|
40944
41164
|
async function crawlScreen(opts) {
|
|
40945
41165
|
return withSwallowedRejections(() => crawlScreenInner(opts));
|
|
40946
41166
|
}
|
|
@@ -40972,6 +41192,7 @@ async function crawlScreenJourney(opts) {
|
|
|
40972
41192
|
clock: opts.clock,
|
|
40973
41193
|
seed: opts.seed,
|
|
40974
41194
|
localDbSchema: opts.localDbSchema,
|
|
41195
|
+
capabilitySuccess: opts.capabilitySuccess === true,
|
|
40975
41196
|
...opts.evaluator ? { evaluator: opts.evaluator } : {}
|
|
40976
41197
|
});
|
|
40977
41198
|
const sites = actionSitesForDescriptor(opts.descriptor);
|
|
@@ -41145,7 +41366,7 @@ async function crawlScreenInner(opts) {
|
|
|
41145
41366
|
actionsSkipped.push({ action: s.actionId, why: "embedded-preview" });
|
|
41146
41367
|
return false;
|
|
41147
41368
|
});
|
|
41148
|
-
const boot = (skipAppear = false) => bundleJs ? bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, inputOverride: opts.inputOverride, budgetMs: opts.budgetMs, clock: opts.clock, seed: opts.seed, skipAppear, localDbSchema: opts.localDbSchema, ...opts.evaluator ? { evaluator: opts.evaluator } : {} }) : null;
|
|
41369
|
+
const boot = (skipAppear = false) => bundleJs ? bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, inputOverride: opts.inputOverride, budgetMs: opts.budgetMs, clock: opts.clock, seed: opts.seed, skipAppear, localDbSchema: opts.localDbSchema, capabilitySuccess: opts.capabilitySuccess === true, ...opts.evaluator ? { evaluator: opts.evaluator } : {} }) : null;
|
|
41149
41370
|
const check = (trigger, state, errors, defects = {}) => {
|
|
41150
41371
|
for (const [svc, paths] of Object.entries(defects)) {
|
|
41151
41372
|
for (const p of paths) {
|
|
@@ -41422,7 +41643,7 @@ async function crawlScreenHostileInner(opts, variant5) {
|
|
|
41422
41643
|
};
|
|
41423
41644
|
let w;
|
|
41424
41645
|
try {
|
|
41425
|
-
w = await bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, budgetMs: opts.budgetMs, clock: opts.clock, seed: opts.seed, localDbSchema: opts.localDbSchema, ...opts.evaluator ? { evaluator: opts.evaluator } : {} });
|
|
41646
|
+
w = await bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, budgetMs: opts.budgetMs, clock: opts.clock, seed: opts.seed, localDbSchema: opts.localDbSchema, capabilitySuccess: opts.capabilitySuccess === true, ...opts.evaluator ? { evaluator: opts.evaluator } : {} });
|
|
41426
41647
|
} catch (e) {
|
|
41427
41648
|
return [{
|
|
41428
41649
|
screen: screenId,
|
|
@@ -41567,7 +41788,7 @@ async function bootAndSnapshotState(opts) {
|
|
|
41567
41788
|
const { call: wixCall } = layeredTransport({ rules: opts.rules, cmsSeed: opts.cmsSeed, canned: opts.canned });
|
|
41568
41789
|
let w;
|
|
41569
41790
|
try {
|
|
41570
|
-
w = await bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, budgetMs: opts.budgetMs, localDbSchema: opts.localDbSchema, ...opts.evaluator ? { evaluator: opts.evaluator } : {} });
|
|
41791
|
+
w = await bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, budgetMs: opts.budgetMs, localDbSchema: opts.localDbSchema, capabilitySuccess: opts.capabilitySuccess === true, ...opts.evaluator ? { evaluator: opts.evaluator } : {} });
|
|
41571
41792
|
} catch {
|
|
41572
41793
|
return null;
|
|
41573
41794
|
}
|
|
@@ -41618,7 +41839,8 @@ async function crawlScreenDeep(opts, deep) {
|
|
|
41618
41839
|
budgetMs: opts.budgetMs,
|
|
41619
41840
|
clock: opts.clock,
|
|
41620
41841
|
seed: opts.seed,
|
|
41621
|
-
localDbSchema: opts.localDbSchema
|
|
41842
|
+
localDbSchema: opts.localDbSchema,
|
|
41843
|
+
capabilitySuccess: opts.capabilitySuccess === true
|
|
41622
41844
|
});
|
|
41623
41845
|
const pathLabel = (path) => path.map((i) => sites[i].actionId.replace(/^tier5\./, "")).join(" \u2192 ");
|
|
41624
41846
|
while (queue.length) {
|
|
@@ -41780,6 +42002,7 @@ async function crawlScreenRelations(opts) {
|
|
|
41780
42002
|
clock: opts.clock,
|
|
41781
42003
|
seed: opts.seed,
|
|
41782
42004
|
localDbSchema: opts.localDbSchema,
|
|
42005
|
+
capabilitySuccess: opts.capabilitySuccess === true,
|
|
41783
42006
|
...opts.evaluator ? { evaluator: opts.evaluator } : {}
|
|
41784
42007
|
});
|
|
41785
42008
|
const replay = async (path, rowFor = () => null) => {
|
|
@@ -41920,7 +42143,7 @@ async function crawlScreenRelations(opts) {
|
|
|
41920
42143
|
return { findings: dedupe(findings), checked, byKind };
|
|
41921
42144
|
});
|
|
41922
42145
|
}
|
|
41923
|
-
var ACTION_KEYS, UNTRACKED_ITEMS, NESTED_ITEMS_SEP, REJECT_ALL_MESSAGE, VLQ, WIX_DATA_QUERY, WIX_DATA_ANY, CAPABILITY_ACTION, BLANK_WHEN_BOUND, UNBINDABLE_ROW;
|
|
42146
|
+
var ACTION_KEYS, UNTRACKED_ITEMS, NESTED_ITEMS_SEP, REJECT_ALL_MESSAGE, VLQ, WIX_DATA_QUERY, WIX_DATA_ANY, CAPABILITY_ACTION, CRAWL_CLOCK, BLANK_WHEN_BOUND, UNBINDABLE_ROW;
|
|
41924
42147
|
var init_screen_crawl = __esm({
|
|
41925
42148
|
"../../core/dev-server/src/screen-crawl.ts"() {
|
|
41926
42149
|
init_validate_descriptor_core();
|
|
@@ -41930,6 +42153,7 @@ var init_screen_crawl = __esm({
|
|
|
41930
42153
|
init_FakeServiceProvider();
|
|
41931
42154
|
init_actionParams();
|
|
41932
42155
|
init_implications();
|
|
42156
|
+
init_capability_fixtures();
|
|
41933
42157
|
init_crawl_relations();
|
|
41934
42158
|
ACTION_KEYS = [
|
|
41935
42159
|
"action",
|
|
@@ -41950,6 +42174,7 @@ var init_screen_crawl = __esm({
|
|
|
41950
42174
|
WIX_DATA_QUERY = /\/wix-data\/v2\/items\/query$/;
|
|
41951
42175
|
WIX_DATA_ANY = /\/wix-data\//;
|
|
41952
42176
|
CAPABILITY_ACTION = /^capability\.([a-z0-9_]+)\.([A-Za-z0-9_]+)$/;
|
|
42177
|
+
CRAWL_CLOCK = Date.parse("2026-01-01T00:00:00.000Z");
|
|
41953
42178
|
BLANK_WHEN_BOUND = {
|
|
41954
42179
|
Marquee: ["items", "itemsPath", "text"],
|
|
41955
42180
|
MediaPlayer: ["items", "itemsPath"]
|
|
@@ -43530,6 +43755,7 @@ async function runCrawl(opts) {
|
|
|
43530
43755
|
const hostileFindings = [];
|
|
43531
43756
|
const relationFindings = [];
|
|
43532
43757
|
let relationsChecked = 0;
|
|
43758
|
+
let capabilityModelled = 0;
|
|
43533
43759
|
const relationsByKind = { inverse: 0, refresh: 0, loadMore: 0, filter: 0 };
|
|
43534
43760
|
const deepFindings = [];
|
|
43535
43761
|
const journeyFindings = [];
|
|
@@ -43608,6 +43834,20 @@ async function runCrawl(opts) {
|
|
|
43608
43834
|
const already = new Set(r.findings.map(keyOf));
|
|
43609
43835
|
for (const f of rr.findings) if (!already.has(keyOf(f))) relationFindings.push(f);
|
|
43610
43836
|
}
|
|
43837
|
+
if (deps.crawlScreenCapabilitySuccess && baked.bundleJs) {
|
|
43838
|
+
const cr = await deps.crawlScreenCapabilitySuccess(args);
|
|
43839
|
+
capabilityModelled += cr.modelled;
|
|
43840
|
+
const keyOfC = deps.findingKey ?? ((f) => `${f.invariant}|${f.at ?? ""}|${f.screen}|${f.message}`);
|
|
43841
|
+
const seen = new Set([...r.findings, ...relationFindings].map(keyOfC));
|
|
43842
|
+
for (const f of cr.findings) if (!seen.has(keyOfC(f))) relationFindings.push(f);
|
|
43843
|
+
if (cr.modelled > 0 && deps.crawlScreenRelations) {
|
|
43844
|
+
const rs = await deps.crawlScreenRelations({ ...args, capabilitySuccess: true });
|
|
43845
|
+
const seen2 = new Set([...r.findings, ...relationFindings].map(keyOfC));
|
|
43846
|
+
for (const f of rs.findings) {
|
|
43847
|
+
if (!seen2.has(keyOfC(f))) relationFindings.push({ ...f, axis: f.axis ? `capability:success+${f.axis}` : "capability:success" });
|
|
43848
|
+
}
|
|
43849
|
+
}
|
|
43850
|
+
}
|
|
43611
43851
|
await finishScreenCoverage();
|
|
43612
43852
|
}
|
|
43613
43853
|
const keep = (f) => {
|
|
@@ -43748,6 +43988,7 @@ async function runCrawl(opts) {
|
|
|
43748
43988
|
...retired.length ? { retired } : {},
|
|
43749
43989
|
...opts.deep && opts.deep >= 2 ? { deep: { depth: opts.deep, ...deepTotals } } : {},
|
|
43750
43990
|
...deps.crawlScreenRelations ? { relations: { checked: relationsChecked, byKind: relationsByKind } } : {},
|
|
43991
|
+
...deps.crawlScreenCapabilitySuccess ? { capabilities: { modelled: capabilityModelled } } : {},
|
|
43751
43992
|
...journeyResults.length ? { journeys: journeyResults } : {},
|
|
43752
43993
|
...results.some((r) => r.observations) ? { observations: Object.fromEntries(results.filter((r) => r.observations).map((r) => [r.screen, r.observations])) } : {}
|
|
43753
43994
|
};
|
|
@@ -45175,15 +45416,15 @@ function createFunctionDataCapability(options) {
|
|
|
45175
45416
|
const decode = (result) => {
|
|
45176
45417
|
if (!result || typeof result !== "object") return result;
|
|
45177
45418
|
const output = structuredClone(result);
|
|
45178
|
-
const
|
|
45419
|
+
const decodeItem2 = (item) => {
|
|
45179
45420
|
if (!item || typeof item !== "object") return item;
|
|
45180
45421
|
const record2 = item;
|
|
45181
45422
|
if (!record2.data || typeof record2.data !== "object" || Array.isArray(record2.data)) return item;
|
|
45182
45423
|
return { ...record2, data: Object.fromEntries(Object.entries(record2.data).map(([key2, value]) => [physicalFields.get(key2) ?? key2, value])) };
|
|
45183
45424
|
};
|
|
45184
|
-
if (Array.isArray(output.dataItems)) output.dataItems = output.dataItems.map(
|
|
45185
|
-
if (Array.isArray(output.items)) output.items = output.items.map(
|
|
45186
|
-
if (output.dataItem !== void 0) output.dataItem =
|
|
45425
|
+
if (Array.isArray(output.dataItems)) output.dataItems = output.dataItems.map(decodeItem2);
|
|
45426
|
+
if (Array.isArray(output.items)) output.items = output.items.map(decodeItem2);
|
|
45427
|
+
if (output.dataItem !== void 0) output.dataItem = decodeItem2(output.dataItem);
|
|
45187
45428
|
return output;
|
|
45188
45429
|
};
|
|
45189
45430
|
return Object.freeze({
|
|
@@ -59976,6 +60217,7 @@ async function loadAuthoring() {
|
|
|
59976
60217
|
crawlScreenJourney: crawl.crawlScreenJourney,
|
|
59977
60218
|
crawlScreenHostile: crawl.crawlScreenHostile,
|
|
59978
60219
|
crawlScreenRelations: crawl.crawlScreenRelations,
|
|
60220
|
+
crawlScreenCapabilitySuccess: crawl.crawlScreenCapabilitySuccess,
|
|
59979
60221
|
findingKey: crawl.findingKey,
|
|
59980
60222
|
startWorkerCoverage: cov.startWorkerCoverage,
|
|
59981
60223
|
uncoveredFunctions: cov.uncoveredFunctions,
|
|
@@ -60562,7 +60804,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
60562
60804
|
return results.every((result2) => result2.ok) ? 0 : 1;
|
|
60563
60805
|
}
|
|
60564
60806
|
const app = await appId(dir);
|
|
60565
|
-
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2, crawlScreen: crawlScreen2, crawlScreenJourney: crawlScreenJourney2, crawlScreenHostile: crawlScreenHostile2, crawlScreenRelations: crawlScreenRelations2, findingKey: findingKey2, startWorkerCoverage: startWorkerCoverage2, uncoveredFunctions: uncoveredFunctions2, crawlScreenDeep: crawlScreenDeep2, crawlSignature: crawlSignature2, recordScreenTraffic: recordScreenTraffic2, mintVisitor: mintVisitor2, webWixCall: webWixCall2, freezeTrafficToMocks: freezeTrafficToMocks2, bootAndSnapshotState: bootAndSnapshotState2, renderDescriptorWeb: renderDescriptorWeb2, renderPngBatch: renderPngBatch2, pngAvailable: pngAvailable2, crawlBlockingPasses } = await loadAuthoring();
|
|
60807
|
+
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2, crawlScreen: crawlScreen2, crawlScreenJourney: crawlScreenJourney2, crawlScreenHostile: crawlScreenHostile2, crawlScreenRelations: crawlScreenRelations2, crawlScreenCapabilitySuccess: crawlScreenCapabilitySuccess2, findingKey: findingKey2, startWorkerCoverage: startWorkerCoverage2, uncoveredFunctions: uncoveredFunctions2, crawlScreenDeep: crawlScreenDeep2, crawlSignature: crawlSignature2, recordScreenTraffic: recordScreenTraffic2, mintVisitor: mintVisitor2, webWixCall: webWixCall2, freezeTrafficToMocks: freezeTrafficToMocks2, bootAndSnapshotState: bootAndSnapshotState2, renderDescriptorWeb: renderDescriptorWeb2, renderPngBatch: renderPngBatch2, pngAvailable: pngAvailable2, crawlBlockingPasses } = await loadAuthoring();
|
|
60566
60808
|
const { readTestConfig: readTestConfig2, runCrawl: runCrawl2, formatReport: formatReport2, readCannedResponses: readCannedResponses2, makeRecordingWixCall: makeRecordingWixCall2, runRecordPass: runRecordPass2, runShotsPass: runShotsPass2, defaultNetRules: defaultNetRules2, readNetRules: readNetRules2, scopeDescriptors: scopeDescriptors2, writeRecordedMocks: writeRecordedMocks2 } = await Promise.resolve().then(() => (init_test(), test_exports));
|
|
60567
60809
|
let config;
|
|
60568
60810
|
try {
|
|
@@ -60800,7 +61042,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
60800
61042
|
...deep ? { deep } : {},
|
|
60801
61043
|
...offline ? { offline: true } : {},
|
|
60802
61044
|
...offline || flags["no-hostile"] === true ? { hostile: false } : {},
|
|
60803
|
-
deps: { crawlScreen: crawlScreen2, crawlScreenJourney: crawlScreenJourney2, crawlScreenHostile: crawlScreenHostile2, crawlScreenRelations: crawlScreenRelations2, findingKey: findingKey2, startWorkerCoverage: startWorkerCoverage2, uncoveredFunctions: uncoveredFunctions2, crawlScreenDeep: crawlScreenDeep2, crawlSignature: crawlSignature2 }
|
|
61045
|
+
deps: { crawlScreen: crawlScreen2, crawlScreenJourney: crawlScreenJourney2, crawlScreenHostile: crawlScreenHostile2, crawlScreenRelations: crawlScreenRelations2, crawlScreenCapabilitySuccess: crawlScreenCapabilitySuccess2, findingKey: findingKey2, startWorkerCoverage: startWorkerCoverage2, uncoveredFunctions: uncoveredFunctions2, crawlScreenDeep: crawlScreenDeep2, crawlSignature: crawlSignature2 }
|
|
60804
61046
|
});
|
|
60805
61047
|
} catch (e) {
|
|
60806
61048
|
io.error(JSON.stringify({ error: e.message }));
|
|
@@ -881,7 +881,7 @@
|
|
|
881
881
|
"ScreenDescriptor": "export interface ScreenDescriptor {\n screenId: string;\n renderer: RendererKind;\n title?: string;\n /** Present when `renderer` is `sdui_intent` or `sdui_layout`. */\n payload?: Component;\n /** A component pinned ABOVE the scrolling payload (sticky tab-header / toolbar).\n * Rendered by the host outside the screen scroll, so it stays put as content\n * scrolls. Optional; absent = no sticky header. */\n stickyHeader?: Component;\n /** A component pinned BELOW the scrolling payload (sticky footer — price/confirm\n * bar, peeking bottom-sheet). Rendered outside the screen scroll by the host. */\n stickyFooter?: Component;\n /** When true, the host wraps the screen in a scroll that starts pinned to the\n * bottom and shows a floating \"jump to latest\" button whenever the user scrolls\n * up (a chat transcript). Tapping it animates back to the bottom. Absent/false =\n * a normal top-anchored scroll. Honored by the app host (Router). */\n scrollToBottom?: boolean;\n /** Present when `renderer` is `webview_native_bridge` or `webview_ds`. */\n url?: string;\n capabilitiesRequired?: string[];\n schemaVersion: number;\n togglesApplied?: string[];\n /** Per-session flag/experiment assignments baked in for this request. */\n assignments?: import(\"./flags.js\").Assignment[];\n /** Per-screen top bar (trailing actions +\n * leading/style override). Fully replaces `NavigationConfig.topBarDefault`. */\n topBar?: TopBarConfig;\n etag?: string;\n cacheControl?: CacheControl;\n telemetryScreenName?: string;\n bundleSri?: string;\n manifestVersion?: number;\n /**\n * Present on Tier-5 screens. The presence of this field is the tier-5\n * signal — there is no separate `tier: 5` flag.\n */\n logicBundle?: LogicBundleRef;\n /**\n * Static per-screen input injected as `globalThis.himalaya.input` before the\n * Tier-5 worker bundle evaluates — the worker reads it synchronously in `load()`\n * (e.g. `himalaya.input.id` for a detail screen, or a baked catalog like\n * `himalaya.input.cmsCollections`).\n *\n * A push merges its navigation parameters into this object on web, iOS, and Android.\n * For example, `himi.open({ screenId: \"event\", id: \"$item.id\" })` makes the id\n * available as `himalaya.input.id` in the pushed worker; static `input` remains the\n * fallback for values baked into a descriptor or a templated route. The host also\n * supplies `screenId`. See docs/tier-5-add-a-screen.md → \"Navigate to a detail screen\".\n *\n * Arbitrary JSON object; consumed by the web host (ScreenController) and the\n * native JSWorker.\n */\n input?: Record<string, unknown>;\n /**\n * Tier 3 / Tier 4 — behavior of the hosted WebView. Ignored by SDUI tiers.\n * Authored in the descriptor builder (git); served OTA verbatim.\n */\n webViewConfig?: WebViewConfig;\n}",
|
|
882
882
|
"Component": "export interface Component {\n id: string;\n body: ComponentBody;\n modifiers?: Modifiers;\n minVersion?: number;\n}",
|
|
883
883
|
"LogicBundleRef": "export interface LogicBundleRef {\n url: string;\n /** \"sha256-...\" SRI string. */\n integrity: string;\n contentType?: string;\n /** SDK capability ids the bundle is permitted to import / invoke. */\n declaredCapabilities: string[];\n /** Bundle refuses to load on a binary older than this (semver). */\n minBinaryVersion?: string;\n /** Bundle's own semver. */\n bundleVersion?: string;\n /** Base64 detached publisher signature over the bundle bytes\n * (authenticity beyond SRI). Verified by a host-injected verifier when present;\n * unsigned bundles load as today. */\n signature?: string;\n /** The publisher key id a host pins, paired with `signature`. */\n keyId?: string;\n /** Ambient refresh (gap G2): the host invokes `action` (a `tier5.<svc>.<action>`\n * path) every `intervalMs` while the screen is visible — workers have no timer\n * of their own, so the host owns the cadence. */\n refresh?: { intervalMs: number; action: string };\n}",
|
|
884
|
-
"Modifiers": "export interface Modifiers {\n padding?: EdgeInsets;\n background?: TokenRef;\n cornerRadius?: number;\n /** Fixed intrinsic width (pt/dp/px). Honored by iOS (`FrameIfPresent`), Android\n * (frame) and web (`modifiers.ts`). With no `ScrollView` in the vocabulary and\n * regions clipped at `maxHeight`, `width`/`height`/`fillMaxWidth` are the main\n * sizing tools for embed/host content. */\n width?: number;\n /** Fixed intrinsic height (pt/dp/px). See `width`. */\n height?: number;\n /** Fill the available cross-axis width (keeps any fixed `height`). Mirrors\n * Compose `fillMaxWidth` / SwiftUI `.frame(maxWidth: .infinity)`. See `width`. */\n fillMaxWidth?: boolean;\n /** CAP the node's laid-out width at this many points. It CONSTRAINS, it\n * does not SET: a node narrower than the cap keeps its intrinsic width, so a\n * short chat bubble stays short while a long one stops at the cap — the\n * asymmetry `width` cannot express and `weight` cannot either (weights divide\n * the *available* space, so every child lands on the same fraction).\n * The cap covers the node's TOTAL width, padding + border included (CSS\n * `max-width` under `box-sizing: border-box`). `fillMaxWidth` grabs the axis but\n * THE CAP WINS — fill + cap is exactly `maxWidth` wide; a literal `width` larger\n * than the cap is clamped to it too. POINTS, not a fraction: a modifier is\n * resolved with no portable notion of \"the row\" on any renderer — compose a\n * percentage from a weighted sibling gap instead. `0`/absent = no cap. */\n maxWidth?: number;\n /** Flex weight along the parent stack's MAIN axis (HStack = width, VStack =\n * height). The stack measures its intrinsic (unweighted) children first, then\n * divides what is LEFT among the weighted ones in proportion to their weights:\n * two children at `1` split the leftover equally, `2` and `1` split it 2:1.\n * Absent (or <= 0) keeps the node at its intrinsic size. Use this — not\n * `fillMaxWidth` — when a node should claim the remaining space *beside* its\n * siblings; a full-bleed fill grabs the whole axis and starves them. Ignored\n * outside an HStack/VStack. */\n weight?: number;\n /** RTL — pin the subtree's writing direction: `\"ltr\"` | `\"rtl\"` | `\"locale\"`\n * (inherit). The common RTL pattern is the inverse of `Text.textDirection`: pin a\n * container `ltr` (a logotype, an attachment-tile row, a composer button row)\n * inside an otherwise-RTL screen. Absent = inherit the ambient direction. #1060. */\n layoutDirection?: \"ltr\" | \"rtl\" | \"locale\";\n /** Absolute visual translation (pt/dp/px). Applied as the OUTERMOST transform so\n * it shifts the fully-styled node WITHOUT changing its layout footprint — lets a\n * ZStack place polar/absolute children (e.g. AgentOrbit). Negative allowed. */\n offsetX?: number;\n offsetY?: number;\n onTap?: Action;\n /** Double-tap gesture (e.g. Instagram double-tap-to-like). Distinct from onTap. */\n onDoubleTap?: Action;\n accessibilityLabel?: string;\n hidden?: boolean;\n /** Data-bound conditional visibility: a `\"$service:<svc>.<field>\"`\n * or `\"$item.<field>\"` sentinel resolving to a bool at render; when true the\n * subtree fully COLLAPSES (zero layout, like `hidden`), overriding the\n * literal `hidden`. */\n hiddenPath?: string;\n /** Long-press gesture modifier. */\n onLongPress?: Action;\n /** Fires once when the component first appears on screen. */\n onAppear?: Action;\n /** Scoped token overrides for the subtree. */\n theme?: ThemeOverrides;\n /** Names a token from the app's `shadows` registry. */\n shadow?: TokenRef;\n /** Names a token from the app's `gradients` registry (background fill). */\n backgroundGradient?: TokenRef;\n /** Value-driven gradient: a `$service:`/`$item.` path resolving to a gradient\n * TOKEN NAME used as the live background (e.g. weather sky day→night). */\n backgroundGradientPath?: string;\n /** Value-driven background COLOR: a `$service:`/`$item.` path resolving to a\n * color TOKEN NAME used as the live background. Honored on iOS + Android\n * (`BoundBackgroundIfPresent`); web render support is tracked in #1057. */\n backgroundColorPath?: string;\n /** Value-driven background IMAGE: a `$service:`/`$item.` path resolving to an\n * image URL used as the live background. Honored on iOS + Android; web render\n * support is tracked in #1057. */\n backgroundImagePath?: string;\n /** #1051 — MEASURE (publish): report this node's laid-out size into the renderer's\n * self-contained (worker-free) measure store under the named keys, so a SIBLING can\n * feed the number back into its own layout via a `$measure:<key>` binding. The SDUI\n * equivalent of SwiftUI `.onGeometryChange` / Compose `onGloballyPositioned`; the\n * canonical use is a pinned bottom bar whose measured height becomes a scroll view's\n * bottom inset (sticky-footer + scroll-inset, unrepresentable before — #1051). */\n onMeasure?: Measure;\n /** #1051 — bound height: a `\"$measure:<key>\"` (measure store) or\n * `\"$service:<svc>.<field>\"` / `\"$item.<field>\"` (worker/row state) sentinel resolving\n * to a NUMBER at render. Wins over the literal `height`. String path only, so a\n * binding can never blank the node (never overload the numeric `height`). */\n heightPath?: string;\n /** #1051 — bound width. See `heightPath`. Wins over the literal `width`. */\n widthPath?: string;\n /** #1051 — bound TOP inset (the header-height → top-inset idiom). A `$measure:`/\n * `$service:`/`$item.` sentinel resolving to a number; added as top padding. */\n paddingTopPath?: string;\n /** #1051 — bound BOTTOM inset (the sticky-footer-height → bottom-inset idiom). A\n * `$measure:`/`$service:`/`$item.` sentinel resolving to a number; added as bottom\n * padding so the last scroll row clears a pinned bottom bar. */\n paddingBottomPath?: string;\n /** #1053 — INLINE gradient background paint. Distinct from `backgroundGradient`\n * (which names a `gradients` registry token an embed host can't register): this\n * carries its stops/colours in the descriptor, so it works anywhere. Painted as\n * a surface (behind children), below `material`/`backgroundGradient` if those are\n * also set. */\n gradient?: Gradient;\n /** #1053 — gradient ALPHA MASK: the node shows through where the gradient is\n * opaque and fades where it's transparent (a transparent-token stop = fully\n * clear). The material-under-gradient-scrim / scroll-fade-out idiom. Mirrors iOS\n * `.mask()`, Android `BlendMode.DstIn`, web `mask-image`. */\n mask?: Gradient;\n /** Inline border/stroke. */\n border?: Border;\n /** Subtree alpha 0.0–1.0; absent = opaque. */\n opacity?: number;\n /** #433 — constrain the subtree to a width:height ratio (e.g. `1` = square,\n * `1.777` = 16:9). Width-driven: the height derives from the resolved width.\n * Lets a data-bound Grid cell / photo tile hold its shape at any width. */\n aspectRatio?: number;\n /** Names a token from the app's `motions` registry; the subtree\n * fades + slides up on first appearance. */\n appear?: TokenRef;\n /** Surface material token (flat/glass/frosted). */\n material?: TokenRef;\n /** Per-node construction-language override. */\n variant?: string;\n /** Per-node density / motion override. */\n density?: string;\n motion?: string;\n /** Motion grammar (Batch 1) — press/tap feedback style\n * (auto|none|scale|highlight|scaleHighlight|lift); timing comes from `motion`.\n * Applied only when the node is interactive. Unknown degrades to `auto`. */\n pressFeedback?: string;\n /** Motion grammar (Batch 1) — press-coupled haptic\n * (none|selection|light|medium|heavy|success|warning|error); fires with onTap.\n * Default none (opt-in). Web is a no-op. */\n haptic?: string;\n /** Motion grammar (Batch 1) — animate this container's size changes instead of\n * snapping (iOS `.animation(value:)`, Android `animateContentSize`, web height\n * transition). Curve from the active `motion` personality. */\n animateContentSize?: boolean;\n /** Motion grammar (Batch 1) — enter/exit transition; supersedes `appear` when\n * both are present. */\n transition?: Transition;\n /** Motion grammar (Batch 2, scroll-driven) — defer the `transition` enter until\n * the node first crosses into the scroll viewport (reveal-on-scroll). Gated by\n * reduced motion (shown immediately when reduced). */\n revealOnScroll?: boolean;\n /** Motion grammar (Batch 2, scroll-driven) — parallax factor: the node drifts\n * vertically at this fraction of the scroll delta as it moves through the\n * viewport. Gated by reduced motion. Generalizes CollapsingHeader parallaxFactor. */\n parallax?: number;\n /** Motion grammar (Batch 4, rich visual) — when a backgroundGradient is present,\n * continuously drift/rotate it (animated gradient). Gated by reduced motion. */\n animatedGradient?: boolean;\n /** Motion grammar (Batch 3, hero/nav) — shared-element key: a matching\n * transitionId on the source + destination screen morphs that element across\n * navigation (web View Transitions / iOS matchedTransitionSource / Android\n * SharedTransitionLayout). Gated by reduced motion. */\n transitionId?: string;\n /** Motion grammar (Batch 4, rich visual) — render the backgroundGradient as a\n * mesh (overlapping multi-point blend) rather than a linear sweep; combine with\n * animatedGradient to drift it. */\n meshGradient?: boolean;\n /** Motion grammar (Batch 4, celebration) — burst a one-shot confetti overlay\n * within the node on appear. Gated by reduced motion. */\n confetti?: boolean;\n /** Motion grammar (Batch 2, scroll-driven) — pin this node to the top of its\n * scroll container (sticky section header). Functional positioning; not gated\n * by reduced motion. */\n sticky?: boolean;\n /** Motion grammar (Batch 2, scroll-driven) — turn this thin node into a\n * reading-progress bar that fills left→right with scroll (scaleX). web reads\n * window scroll; native reads the host scroll fraction. Functional. */\n scrollProgress?: boolean;\n /** Motion grammar (Batch 4, rich vector) — a named built-in vector animation\n * (\"loader\" | \"success\" | \"pulse\"), dependency-free. Gated by reduced motion.\n * Arbitrary Lottie/Rive JSON is the lib-backed superset follow-up. */\n vectorAnim?: string;\n /** Motion grammar (Batch 1, choreography) — delay this node's ENTER transition\n * by N ms so a screen can SEQUENCE its entrance beyond list stagger (\"title\n * fades, subtitle slides in 100ms later\"). Adds to any list `staggerMs`. Gated\n * by reduced motion. 0/absent = no extra delay. */\n enterDelayMs?: number;\n /** Motion grammar (Phase-3, per-node MotionSpec) — overrides the PRESS-feedback\n * curve with a `motions`-registry token, mirroring `Transition.motion` for the\n * enter curve. Absent → press uses the global `motion` personality. */\n pressMotion?: TokenRef;\n /** Motion grammar (Phase-3, gesture-driven) — finger-tracked drag-to-dismiss; past\n * threshold along `direction` it animates off and fires `action`, else springs back. */\n swipeDismiss?: SwipeDismiss;\n /** Motion grammar (Phase-4, reduced-motion) — per-node escape from the reduced-motion\n * gate. Default true (respect). false = \"must move anyway\" (transition/press animate\n * even when reduced motion is on). */\n respectReducedMotion?: boolean;\n /** #1052 — uniform scale (1 = no change). */\n scale?: number;\n /** #1052 — rotation in DEGREES. */\n rotation?: number;\n /** #1052 — stacking order within a ZStack/overlay. */\n zIndex?: number;\n /** #1052 — gaussian blur radius (pt/dp/px). */\n blur?: number;\n /** #1052 — `false` = decorative (ignores taps, unlike `hidden` which stays hit-testable);\n * `true` = force hit-testable (a clear tap target). */\n hitTestable?: boolean;\n /** #1052 — explicit drop shadow (colour + radius + offset), for upward / multi-layer\n * shadows the `shadow` token can't express. */\n boxShadow?: Shadow;\n}",
|
|
884
|
+
"Modifiers": "export interface Modifiers {\n padding?: EdgeInsets;\n background?: TokenRef;\n cornerRadius?: number;\n /** Fixed intrinsic width (pt/dp/px). Honored by iOS (`FrameIfPresent`), Android\n * (frame) and web (`modifiers.ts`). With no `ScrollView` in the vocabulary and\n * regions clipped at `maxHeight`, `width`/`height`/`fillMaxWidth` are the main\n * sizing tools for embed/host content. */\n width?: number;\n /** Fixed intrinsic height (pt/dp/px). See `width`. */\n height?: number;\n /** Fill the available cross-axis width (keeps any fixed `height`). Mirrors\n * Compose `fillMaxWidth` / SwiftUI `.frame(maxWidth: .infinity)`. See `width`. */\n fillMaxWidth?: boolean;\n /** CAP the node's laid-out width at this many points. It CONSTRAINS, it\n * does not SET: a node narrower than the cap keeps its intrinsic width, so a\n * short chat bubble stays short while a long one stops at the cap — the\n * asymmetry `width` cannot express and `weight` cannot either (weights divide\n * the *available* space, so every child lands on the same fraction).\n * The cap covers the node's TOTAL width, padding + border included (CSS\n * `max-width` under `box-sizing: border-box`). `fillMaxWidth` grabs the axis but\n * THE CAP WINS — fill + cap is exactly `maxWidth` wide; a literal `width` larger\n * than the cap is clamped to it too. POINTS, not a fraction: a modifier is\n * resolved with no portable notion of \"the row\" on any renderer — compose a\n * percentage from a weighted sibling gap instead. `0`/absent = no cap. */\n maxWidth?: number;\n /** Flex weight along the parent stack's MAIN axis (HStack = width, VStack =\n * height). The stack measures its intrinsic (unweighted) children first, then\n * divides what is LEFT among the weighted ones in proportion to their weights:\n * two children at `1` split the leftover equally, `2` and `1` split it 2:1.\n * Absent (or <= 0) keeps the node at its intrinsic size. Use this — not\n * `fillMaxWidth` — when a node should claim the remaining space *beside* its\n * siblings; a full-bleed fill grabs the whole axis and starves them. Ignored\n * outside an HStack/VStack.\n * CAVEAT — row-sharing controls have NO intrinsic width to measure first: in an\n * HStack a `Button` and a `Toggle` are implicitly weighted, so they DIVIDE the\n * row with your weighted child instead of taking a width ahead of it —\n * `[VStack(weight:1), Button, Button]` is a three-way split, not \"the VStack gets\n * the remainder\". The RELIABLE opt-outs are `iconOnly` and `tertiary`/`link` with\n * `fullWidth` unset. `fullWidth: false` is NOT reliable here: only Android honors\n * it in a weighted row (`wantsRowStretch`); iOS (`WeightedStack`) and web still\n * hand the button a share. Otherwise give the actions their own row.\n * See `himi docs designing-himi-screens` §4. */\n weight?: number;\n /** RTL — pin the subtree's writing direction: `\"ltr\"` | `\"rtl\"` | `\"locale\"`\n * (inherit). The common RTL pattern is the inverse of `Text.textDirection`: pin a\n * container `ltr` (a logotype, an attachment-tile row, a composer button row)\n * inside an otherwise-RTL screen. Absent = inherit the ambient direction. #1060. */\n layoutDirection?: \"ltr\" | \"rtl\" | \"locale\";\n /** Absolute visual translation (pt/dp/px). Applied as the OUTERMOST transform so\n * it shifts the fully-styled node WITHOUT changing its layout footprint — lets a\n * ZStack place polar/absolute children (e.g. AgentOrbit). Negative allowed. */\n offsetX?: number;\n offsetY?: number;\n onTap?: Action;\n /** Double-tap gesture (e.g. Instagram double-tap-to-like). Distinct from onTap. */\n onDoubleTap?: Action;\n accessibilityLabel?: string;\n hidden?: boolean;\n /** Data-bound conditional visibility: a `\"$service:<svc>.<field>\"`\n * or `\"$item.<field>\"` sentinel resolving to a bool at render; when true the\n * subtree fully COLLAPSES (zero layout, like `hidden`), overriding the\n * literal `hidden`. */\n hiddenPath?: string;\n /** Long-press gesture modifier. */\n onLongPress?: Action;\n /** Fires once when the component first appears on screen. */\n onAppear?: Action;\n /** Scoped token overrides for the subtree. */\n theme?: ThemeOverrides;\n /** Names a token from the app's `shadows` registry. */\n shadow?: TokenRef;\n /** Names a token from the app's `gradients` registry (background fill). */\n backgroundGradient?: TokenRef;\n /** Value-driven gradient: a `$service:`/`$item.` path resolving to a gradient\n * TOKEN NAME used as the live background (e.g. weather sky day→night). */\n backgroundGradientPath?: string;\n /** Value-driven background COLOR: a `$service:`/`$item.` path resolving to a\n * color TOKEN NAME used as the live background. Honored on iOS + Android\n * (`BoundBackgroundIfPresent`); web render support is tracked in #1057. */\n backgroundColorPath?: string;\n /** Value-driven background IMAGE: a `$service:`/`$item.` path resolving to an\n * image URL used as the live background. Honored on iOS + Android; web render\n * support is tracked in #1057. */\n backgroundImagePath?: string;\n /** #1051 — MEASURE (publish): report this node's laid-out size into the renderer's\n * self-contained (worker-free) measure store under the named keys, so a SIBLING can\n * feed the number back into its own layout via a `$measure:<key>` binding. The SDUI\n * equivalent of SwiftUI `.onGeometryChange` / Compose `onGloballyPositioned`; the\n * canonical use is a pinned bottom bar whose measured height becomes a scroll view's\n * bottom inset (sticky-footer + scroll-inset, unrepresentable before — #1051). */\n onMeasure?: Measure;\n /** #1051 — bound height: a `\"$measure:<key>\"` (measure store) or\n * `\"$service:<svc>.<field>\"` / `\"$item.<field>\"` (worker/row state) sentinel resolving\n * to a NUMBER at render. Wins over the literal `height`. String path only, so a\n * binding can never blank the node (never overload the numeric `height`). */\n heightPath?: string;\n /** #1051 — bound width. See `heightPath`. Wins over the literal `width`. */\n widthPath?: string;\n /** #1051 — bound TOP inset (the header-height → top-inset idiom). A `$measure:`/\n * `$service:`/`$item.` sentinel resolving to a number; added as top padding. */\n paddingTopPath?: string;\n /** #1051 — bound BOTTOM inset (the sticky-footer-height → bottom-inset idiom). A\n * `$measure:`/`$service:`/`$item.` sentinel resolving to a number; added as bottom\n * padding so the last scroll row clears a pinned bottom bar. */\n paddingBottomPath?: string;\n /** #1053 — INLINE gradient background paint. Distinct from `backgroundGradient`\n * (which names a `gradients` registry token an embed host can't register): this\n * carries its stops/colours in the descriptor, so it works anywhere. Painted as\n * a surface (behind children), below `material`/`backgroundGradient` if those are\n * also set. */\n gradient?: Gradient;\n /** #1053 — gradient ALPHA MASK: the node shows through where the gradient is\n * opaque and fades where it's transparent (a transparent-token stop = fully\n * clear). The material-under-gradient-scrim / scroll-fade-out idiom. Mirrors iOS\n * `.mask()`, Android `BlendMode.DstIn`, web `mask-image`. */\n mask?: Gradient;\n /** Inline border/stroke. */\n border?: Border;\n /** Subtree alpha 0.0–1.0; absent = opaque. */\n opacity?: number;\n /** #433 — constrain the subtree to a width:height ratio (e.g. `1` = square,\n * `1.777` = 16:9). Width-driven: the height derives from the resolved width.\n * Lets a data-bound Grid cell / photo tile hold its shape at any width. */\n aspectRatio?: number;\n /** Names a token from the app's `motions` registry; the subtree\n * fades + slides up on first appearance. */\n appear?: TokenRef;\n /** Surface material token (flat/glass/frosted). */\n material?: TokenRef;\n /** Per-node construction-language override. */\n variant?: string;\n /** Per-node density / motion override. */\n density?: string;\n motion?: string;\n /** Motion grammar (Batch 1) — press/tap feedback style\n * (auto|none|scale|highlight|scaleHighlight|lift); timing comes from `motion`.\n * Applied only when the node is interactive. Unknown degrades to `auto`. */\n pressFeedback?: string;\n /** Motion grammar (Batch 1) — press-coupled haptic\n * (none|selection|light|medium|heavy|success|warning|error); fires with onTap.\n * Default none (opt-in). Web is a no-op. */\n haptic?: string;\n /** Motion grammar (Batch 1) — animate this container's size changes instead of\n * snapping (iOS `.animation(value:)`, Android `animateContentSize`, web height\n * transition). Curve from the active `motion` personality. */\n animateContentSize?: boolean;\n /** Motion grammar (Batch 1) — enter/exit transition; supersedes `appear` when\n * both are present. */\n transition?: Transition;\n /** Motion grammar (Batch 2, scroll-driven) — defer the `transition` enter until\n * the node first crosses into the scroll viewport (reveal-on-scroll). Gated by\n * reduced motion (shown immediately when reduced). */\n revealOnScroll?: boolean;\n /** Motion grammar (Batch 2, scroll-driven) — parallax factor: the node drifts\n * vertically at this fraction of the scroll delta as it moves through the\n * viewport. Gated by reduced motion. Generalizes CollapsingHeader parallaxFactor. */\n parallax?: number;\n /** Motion grammar (Batch 4, rich visual) — when a backgroundGradient is present,\n * continuously drift/rotate it (animated gradient). Gated by reduced motion. */\n animatedGradient?: boolean;\n /** Motion grammar (Batch 3, hero/nav) — shared-element key: a matching\n * transitionId on the source + destination screen morphs that element across\n * navigation (web View Transitions / iOS matchedTransitionSource / Android\n * SharedTransitionLayout). Gated by reduced motion. */\n transitionId?: string;\n /** Motion grammar (Batch 4, rich visual) — render the backgroundGradient as a\n * mesh (overlapping multi-point blend) rather than a linear sweep; combine with\n * animatedGradient to drift it. */\n meshGradient?: boolean;\n /** Motion grammar (Batch 4, celebration) — burst a one-shot confetti overlay\n * within the node on appear. Gated by reduced motion. */\n confetti?: boolean;\n /** Motion grammar (Batch 2, scroll-driven) — pin this node to the top of its\n * scroll container (sticky section header). Functional positioning; not gated\n * by reduced motion. */\n sticky?: boolean;\n /** Motion grammar (Batch 2, scroll-driven) — turn this thin node into a\n * reading-progress bar that fills left→right with scroll (scaleX). web reads\n * window scroll; native reads the host scroll fraction. Functional. */\n scrollProgress?: boolean;\n /** Motion grammar (Batch 4, rich vector) — a named built-in vector animation\n * (\"loader\" | \"success\" | \"pulse\"), dependency-free. Gated by reduced motion.\n * Arbitrary Lottie/Rive JSON is the lib-backed superset follow-up. */\n vectorAnim?: string;\n /** Motion grammar (Batch 1, choreography) — delay this node's ENTER transition\n * by N ms so a screen can SEQUENCE its entrance beyond list stagger (\"title\n * fades, subtitle slides in 100ms later\"). Adds to any list `staggerMs`. Gated\n * by reduced motion. 0/absent = no extra delay. */\n enterDelayMs?: number;\n /** Motion grammar (Phase-3, per-node MotionSpec) — overrides the PRESS-feedback\n * curve with a `motions`-registry token, mirroring `Transition.motion` for the\n * enter curve. Absent → press uses the global `motion` personality. */\n pressMotion?: TokenRef;\n /** Motion grammar (Phase-3, gesture-driven) — finger-tracked drag-to-dismiss; past\n * threshold along `direction` it animates off and fires `action`, else springs back. */\n swipeDismiss?: SwipeDismiss;\n /** Motion grammar (Phase-4, reduced-motion) — per-node escape from the reduced-motion\n * gate. Default true (respect). false = \"must move anyway\" (transition/press animate\n * even when reduced motion is on). */\n respectReducedMotion?: boolean;\n /** #1052 — uniform scale (1 = no change). */\n scale?: number;\n /** #1052 — rotation in DEGREES. */\n rotation?: number;\n /** #1052 — stacking order within a ZStack/overlay. */\n zIndex?: number;\n /** #1052 — gaussian blur radius (pt/dp/px). */\n blur?: number;\n /** #1052 — `false` = decorative (ignores taps, unlike `hidden` which stays hit-testable);\n * `true` = force hit-testable (a clear tap target). */\n hitTestable?: boolean;\n /** #1052 — explicit drop shadow (colour + radius + offset), for upward / multi-layer\n * shadows the `shadow` token can't express. */\n boxShadow?: Shadow;\n}",
|
|
885
885
|
"TokenRef": "export interface TokenRef {\n token: TokenName;\n}",
|
|
886
886
|
"Action": "export interface Action {\n actionId: string;\n /** Backwards-compatible string-only params. Prefer `args` for typed payloads. */\n params?: Record<string, string>;\n /** Typed action args; nested objects/arrays preserved end-to-end. */\n args?: Record<string, Value>;\n /** Navigation hint for the router; ignored for non-nav actions. */\n presentation?: Presentation;\n}",
|
|
887
887
|
"Presentation": "export type Presentation =\n | \"push\"\n | \"sheet\"\n | \"replace\"\n | \"dismiss\"\n | \"back\"\n | \"full_screen\"\n | \"alert\"\n | \"snackbar\";",
|
|
@@ -1976,7 +1976,16 @@ export interface Modifiers {
|
|
|
1976
1976
|
* Absent (or <= 0) keeps the node at its intrinsic size. Use this — not
|
|
1977
1977
|
* `fillMaxWidth` — when a node should claim the remaining space *beside* its
|
|
1978
1978
|
* siblings; a full-bleed fill grabs the whole axis and starves them. Ignored
|
|
1979
|
-
* outside an HStack/VStack.
|
|
1979
|
+
* outside an HStack/VStack.
|
|
1980
|
+
* CAVEAT — row-sharing controls have NO intrinsic width to measure first: in an
|
|
1981
|
+
* HStack a `Button` and a `Toggle` are implicitly weighted, so they DIVIDE the
|
|
1982
|
+
* row with your weighted child instead of taking a width ahead of it —
|
|
1983
|
+
* `[VStack(weight:1), Button, Button]` is a three-way split, not "the VStack gets
|
|
1984
|
+
* the remainder". The RELIABLE opt-outs are `iconOnly` and `tertiary`/`link` with
|
|
1985
|
+
* `fullWidth` unset. `fullWidth: false` is NOT reliable here: only Android honors
|
|
1986
|
+
* it in a weighted row (`wantsRowStretch`); iOS (`WeightedStack`) and web still
|
|
1987
|
+
* hand the button a share. Otherwise give the actions their own row.
|
|
1988
|
+
* See `himi docs designing-himi-screens` §4. */
|
|
1980
1989
|
weight?: number;
|
|
1981
1990
|
/** RTL — pin the subtree's writing direction: `"ltr"` | `"rtl"` | `"locale"`
|
|
1982
1991
|
* (inherit). The common RTL pattern is the inverse of `Text.textDirection`: pin a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.832.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": "e11f7e039210de169e2608faa2fcb6cdbd90f8df91336bcba6398dbe"
|
|
67
67
|
}
|