@wix/himalaya-cli 0.1571.0 → 0.1572.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/stdlib/wix-sdk/members-feed-viewer/src/index.d.ts +6 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-members-feed-viewer.mjs +18 -0
- package/dist/cli.mjs +379 -83
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/index.json +7 -0
- package/guides/map-one-app-coverage.js +117 -0
- package/guides/one-app-to-himi-app.md +87 -7
- package/guides/recipe-one-app-coverage-mapping.md +74 -0
- package/guides/sdk-reference.json +6 -0
- package/package.json +2 -2
- package/templates/beauty-salon-owner/dev/index.ts +2 -3
- package/templates/branded-lite/tier5-src/himi-branded-lite-programs/index.ts +28 -11
- package/templates/community-club-owner/dev/index.ts +2 -3
- package/templates/events-meetups-owner/dev/index.ts +2 -3
- package/templates/gym-fitness-owner/dev/index.ts +2 -3
- package/templates/nonprofit-cause-owner/dev/index.ts +2 -3
- package/templates/owner-lite/dev/index.ts +2 -3
- package/templates/podcast-creator-owner/dev/index.ts +2 -3
- package/templates/portfolio-creative-owner/dev/index.ts +2 -3
- package/templates/restaurant-owner/dev/index.ts +2 -3
- package/templates/retail-store-owner/dev/index.ts +2 -3
- package/templates/yoga-studio/tier5-src/himi-branded-lite-programs/index.ts +28 -11
- package/templates/yoga-studio-owner/dev/index.ts +2 -3
|
Binary file
|
package/guides/index.json
CHANGED
|
@@ -296,6 +296,12 @@
|
|
|
296
296
|
"category": "Wix SDK",
|
|
297
297
|
"file": "one-app-to-himi-app.md"
|
|
298
298
|
},
|
|
299
|
+
{
|
|
300
|
+
"id": "recipe-one-app-coverage-mapping",
|
|
301
|
+
"title": "Recipe: map One App coverage decisions",
|
|
302
|
+
"category": "Recipes",
|
|
303
|
+
"file": "recipe-one-app-coverage-mapping.md"
|
|
304
|
+
},
|
|
299
305
|
{
|
|
300
306
|
"id": "one-app-reference",
|
|
301
307
|
"title": "One App reconstruction references and provenance",
|
|
@@ -441,6 +447,7 @@
|
|
|
441
447
|
"showcaseFile": "stocks-dashboard.descriptor.json"
|
|
442
448
|
},
|
|
443
449
|
"examples": [
|
|
450
|
+
"map-one-app-coverage.js",
|
|
444
451
|
"counter.service.ts",
|
|
445
452
|
"counter-t5.descriptor.json",
|
|
446
453
|
"stocks-dashboard.descriptor.json",
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Local reference recipe, not a readiness check. See himi docs recipe-one-app-coverage-mapping.
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import { lstatSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const object = value => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8
|
+
const sameTarget = (a, b) => a?.screenId === b?.screenId && a?.controlId === b?.controlId;
|
|
9
|
+
const needsControl = row => row.kind === "interaction" || row.kind === "top-bar";
|
|
10
|
+
|
|
11
|
+
function idsIn(value, ids = new Set()) {
|
|
12
|
+
if (Array.isArray(value)) value.forEach(item => idsIn(item, ids));
|
|
13
|
+
else if (object(value)) {
|
|
14
|
+
const component = typeof value.body?.type === "string" || (typeof value.type === "string" && object(value.props));
|
|
15
|
+
if (component && typeof value.id === "string" && !value.id.includes("$")) ids.add(value.id);
|
|
16
|
+
for (const [key, item] of Object.entries(value)) if (key !== "params" && key !== "metadata") idsIn(item, ids);
|
|
17
|
+
}
|
|
18
|
+
return ids;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function controlIds(screen) {
|
|
22
|
+
const ids = idsIn([screen.payload, screen.stickyHeader, screen.stickyFooter]);
|
|
23
|
+
for (const action of screen.topBar?.actions ?? []) {
|
|
24
|
+
if (typeof action.id === "string" && !action.id.includes("$")) ids.add(action.id);
|
|
25
|
+
}
|
|
26
|
+
return ids;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Inputs are explicit decisions and the full authored descriptor map, with effective top bars. */
|
|
30
|
+
export function mapCoverage(ledger, decisions, screens) {
|
|
31
|
+
if (ledger?.version !== 1 || ledger.workflow !== "one-app-to-himi-app" || !Array.isArray(ledger.requirements)
|
|
32
|
+
|| !Array.isArray(decisions) || !object(screens)) throw new Error("Expected a coverage ledger, decision array and authored screen map.");
|
|
33
|
+
const coverage = structuredClone(ledger);
|
|
34
|
+
const rows = coverage.requirements;
|
|
35
|
+
if (new Set(rows.map(row => row.id)).size !== rows.length) throw new Error("Duplicate ledger row IDs; run coverage check.");
|
|
36
|
+
const issues = [];
|
|
37
|
+
const selected = new Map();
|
|
38
|
+
const invalidate = row => {
|
|
39
|
+
row.status = "unresolved";
|
|
40
|
+
delete row.target;
|
|
41
|
+
delete row.verification;
|
|
42
|
+
delete row.adaptation;
|
|
43
|
+
};
|
|
44
|
+
const targetProblem = (row, target) => {
|
|
45
|
+
if (!object(target) || Object.keys(target).some(key => !["screenId", "controlId"].includes(key))) return "Expected only screenId and optional controlId.";
|
|
46
|
+
if (typeof target.screenId !== "string" || !target.screenId.trim()) return "An explicit target screenId is required.";
|
|
47
|
+
const screen = Object.hasOwn(screens, target.screenId) && screens[target.screenId];
|
|
48
|
+
if (!object(screen) || screen.screenId !== target.screenId) return "Target screen is absent from the authored descriptor map.";
|
|
49
|
+
if (needsControl(row) && (typeof target.controlId !== "string" || !target.controlId.trim())) return "This row requires an explicit controlId.";
|
|
50
|
+
if (target.controlId !== undefined && !controlIds(screen).has(target.controlId)) return "Target control ID is absent from that screen, including its effective top bar.";
|
|
51
|
+
};
|
|
52
|
+
// A removed target cannot retain a passing record merely because no decision mentions it.
|
|
53
|
+
for (const row of rows) if (row.kind !== "design" && targetProblem(row, row.target)) invalidate(row);
|
|
54
|
+
for (const [index, decision] of decisions.entries()) {
|
|
55
|
+
if (!object(decision)) { issues.push({ decision: index, reason: "Expected an explicit row/source decision." }); continue; }
|
|
56
|
+
const matches = rows.filter(row => typeof decision.id === "string" ? row.id === decision.id
|
|
57
|
+
: typeof decision.source === "string" && row.source === decision.source && row.kind === decision.kind && row.platform === decision.platform);
|
|
58
|
+
if (matches.length !== 1) { issues.push({ decision: index, reason: "Unknown or ambiguous row/source; use the exact row ID or kind/source/platform." }); continue; }
|
|
59
|
+
const row = matches[0];
|
|
60
|
+
if (row.kind === "design") { issues.push({ decision: index, id: row.id, reason: "Design rows belong to validate-design, not screen mapping." }); continue; }
|
|
61
|
+
const allowed = typeof decision.id === "string" ? ["id", "target"] : ["source", "kind", "platform", "target"];
|
|
62
|
+
const problem = Object.keys(decision).some(key => !allowed.includes(key)) ? "Decisions cannot set status, verification, adaptation or other row fields."
|
|
63
|
+
: targetProblem(row, decision.target);
|
|
64
|
+
if (selected.has(row.id)) {
|
|
65
|
+
selected.set(row.id, null);
|
|
66
|
+
invalidate(row);
|
|
67
|
+
issues.push({ decision: index, id: row.id, reason: "Duplicate decisions for this row; left unresolved." });
|
|
68
|
+
} else {
|
|
69
|
+
selected.set(row.id, problem ? null : decision.target);
|
|
70
|
+
if (problem) { invalidate(row); issues.push({ decision: index, id: row.id, reason: problem }); }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (const [id, target] of selected) {
|
|
74
|
+
if (!target) continue;
|
|
75
|
+
const row = rows.find(row => row.id === id);
|
|
76
|
+
if (!sameTarget(row.target, target)) {
|
|
77
|
+
invalidate(row);
|
|
78
|
+
row.target = { ...target };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
coverage,
|
|
83
|
+
issues,
|
|
84
|
+
unmapped: rows.filter(row => row.kind !== "design" && !row.target).map(({ id, kind, source, platform }) => ({ id, kind, source, ...(platform ? { platform } : {}) })),
|
|
85
|
+
// Inventory checks cannot validate retained proof against the author's current built release.
|
|
86
|
+
needsVerification: rows.map(row => row.id),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function main(args) {
|
|
91
|
+
const [content, evidence, decisionsFile, screensFile, ...flags] = args;
|
|
92
|
+
if (!screensFile || flags.some(flag => flag !== "--write") || flags.length > 1) throw new Error("Usage: node map-one-app-coverage.js <content> <evidence-dir> <decisions.json> <screens.json> [--write]");
|
|
93
|
+
// Reuse the installed CLI's actual source hashes, derived row IDs and schema checks. No sync/write.
|
|
94
|
+
execFileSync(process.env.HIMI_BIN ?? "himi", ["one-app", "coverage", "check", "--content", content, "--evidence-dir", evidence, "--json", "--skip-version-check"], { stdio: ["ignore", "pipe", "pipe"] });
|
|
95
|
+
const ledgerFile = resolve(content, "ONE-APP-COVERAGE.json");
|
|
96
|
+
if (!lstatSync(ledgerFile).isFile() || lstatSync(ledgerFile).isSymbolicLink()) throw new Error("The ledger must be a regular file.");
|
|
97
|
+
const read = file => JSON.parse(readFileSync(file, "utf8"));
|
|
98
|
+
const result = mapCoverage(read(ledgerFile), read(decisionsFile), read(screensFile));
|
|
99
|
+
if (flags.includes("--write")) {
|
|
100
|
+
for (let directory = resolve(content);; directory = dirname(directory)) {
|
|
101
|
+
const stat = lstatSync(directory);
|
|
102
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) throw new Error("Use a physical content directory without symlinked parents for --write.");
|
|
103
|
+
if (directory === dirname(directory)) break;
|
|
104
|
+
}
|
|
105
|
+
writeFileSync(ledgerFile, JSON.stringify(result.coverage, null, 2) + "\n");
|
|
106
|
+
}
|
|
107
|
+
console.log(JSON.stringify({ ...result, written: flags.includes("--write") }, null, 2));
|
|
108
|
+
return result.issues.length || result.unmapped.length ? 1 : 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (process.argv[1] && realpathSync(fileURLToPath(import.meta.url)) === realpathSync(process.argv[1])) {
|
|
112
|
+
try { process.exitCode = main(process.argv.slice(2)); }
|
|
113
|
+
catch (error) {
|
|
114
|
+
console.error(JSON.stringify({ ok: false, code: "coverage_mapping_input_invalid", error: error.message }));
|
|
115
|
+
process.exitCode = 1;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -136,6 +136,50 @@ Missing or virtual map points stay absent; an address alone is not coordinates.
|
|
|
136
136
|
If a transient failure makes this read unavailable, the manifest records
|
|
137
137
|
`business_contact_unavailable`. Keep contact coverage unresolved until the data is
|
|
138
138
|
verified, rather than inventing an address or silently omitting the section.
|
|
139
|
+
|
|
140
|
+
### Native widget defaults
|
|
141
|
+
|
|
142
|
+
Empty settings do not mean an empty native widget. Coverage derives separate
|
|
143
|
+
`native-widget` obligations for each placement from the runtime checklist below,
|
|
144
|
+
including repeated sections, detached pages and Business Profile placements.
|
|
145
|
+
These are behaviors to compare, not claims that the target implements them.
|
|
146
|
+
The CLI's versioned native-widget inventory supplies these rows automatically.
|
|
147
|
+
|
|
148
|
+
| Source section type | Effective behavior to verify |
|
|
149
|
+
| --- | --- |
|
|
150
|
+
| `bookings_services_list_section` | Search, category and location filters. |
|
|
151
|
+
| `single_group_feed_section`, `groups_feed_section` | Post actions, attachments, comments/post destination, topic filter and the group's Members / Library / Rules / Media destinations. |
|
|
152
|
+
| `platform_general_contact_section`, `platform_general_contact_section_bp` | Business address and map, respecting authored visibility and available coordinates. |
|
|
153
|
+
| `achievements_list_section` | Category filter, including All Categories with no categories; actual visitor/member login, access/join/payment/Continue states; participants line; default limit 2 and See All when applicable. |
|
|
154
|
+
| `achievements_carousel_section` | The same Program state/display rules, default limit 5 and page dots. |
|
|
155
|
+
| `newBlog_postlist_vertical_section` | See All Posts when a limited list has more results, preserving its scope. |
|
|
156
|
+
| `events_list_section` | Date badge, Share and the appropriate RSVP/ticket action. |
|
|
157
|
+
| `platform_general_members_section`, `platform_general_members_section_bp` | Effective member strip and directory journey: totals/search, alphabetical sections, Follow, activity/privacy. Distinguish badge chips from actual viewed-member program progress. |
|
|
158
|
+
|
|
159
|
+
This initial checklist comes from reported native source-device observations
|
|
160
|
+
on 2026-11-02 across two migrations, not editor demo records.
|
|
161
|
+
Program settings are also backed by the pinned
|
|
162
|
+
[Program section implementation](https://github.com/wix-private/wix-one-app-achievements/tree/f844eee1fe7cc7732531c3deaa7dca777e53c548/sections "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency").
|
|
163
|
+
Its absent category selection means All/future categories; explicit empty selection
|
|
164
|
+
means none. MANUAL order prioritizes selected IDs without excluding other records.
|
|
165
|
+
Use current collected settings and source-device behavior to resolve each instance.
|
|
166
|
+
An explicit disable/override is source evidence: faithfully preserving it requires
|
|
167
|
+
no adaptation waiver, and this checklist must not force the disabled control on.
|
|
168
|
+
Data/access-dependent controls need the relevant source state; never fabricate
|
|
169
|
+
participants or derive program completion from a badge title.
|
|
170
|
+
|
|
171
|
+
The table is not exhaustive. Other section types get an explicit unverified-defaults
|
|
172
|
+
obligation; inventory their effective source behavior rather than assuming there
|
|
173
|
+
are no defaults. Changing the behavior contract creates new requirement identities.
|
|
174
|
+
Recollection invalidates status/check evidence while preserving unchanged mappings.
|
|
175
|
+
|
|
176
|
+
Compare every tab in the actual Player or Branded Lite host with the source app
|
|
177
|
+
on device and live data under the same site and visitor/member identity. The editor
|
|
178
|
+
can show demo members/badges or blank verticals; editor-only observations remain
|
|
179
|
+
unverified. Until missing behavior is implemented, retain an honest unresolved,
|
|
180
|
+
conditional or explicitly authorized adapted row. Do not mark it supported merely
|
|
181
|
+
because its placement exists.
|
|
182
|
+
|
|
139
183
|
`business-context.json.memberCount` preserves a valid Business aggregate
|
|
140
184
|
`members.count` when available. For source `platform_general_members_section` or
|
|
141
185
|
`platform_general_members_section_bp` widgets, collection instead reads the
|
|
@@ -235,10 +279,30 @@ Apply these interpretation rules:
|
|
|
235
279
|
because a missing scheme falls back to the light value. Rebuild after `--fix`.
|
|
236
280
|
For Branded apps, known source typography IDs (for example `lato`) become family
|
|
237
281
|
names (`Lato`); tokens whose names contain title/heading/headline/display/hero use the heading family; other
|
|
238
|
-
typography tokens use the body family. Numeric metrics stay unchanged.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
282
|
+
typography tokens use the body family. Numeric metrics stay unchanged. Read each
|
|
283
|
+
source heading/body family and check `himi fonts list`; use `himi fonts add <Family>`
|
|
284
|
+
when it is available. A known source family that Himi does not ship (for example
|
|
285
|
+
`spaceGrotesk` → Space Grotesk) is still compared with the actual target family.
|
|
286
|
+
Choose an available replacement, such as `$system`, only with the owner's explicit
|
|
287
|
+
instruction; this is an adaptation, never a font match. Sync the coverage ledger
|
|
288
|
+
against the current source evidence, then mark the corresponding `design` requirement
|
|
289
|
+
`adapted` with `adaptation.instruction` citing that instruction and
|
|
290
|
+
`adaptation.explanation` naming the source, replacement and reason. Bind a base font decision
|
|
291
|
+
to the exact reported `target` string in `adaptation.target` (for example,
|
|
292
|
+
`"body: $system, caption: $system"`); a later replacement requires a new decision.
|
|
293
|
+
When an active idiom changes the font, name it in `adaptation.idioms` and copy its
|
|
294
|
+
reported target into `adaptation.idiomTargets[idiom]`. An overlay that keeps the base
|
|
295
|
+
fonts needs no separate font approval. When the base already matches, an idiom-only
|
|
296
|
+
decision needs only `idioms` and `idiomTargets`, without a base `target`.
|
|
297
|
+
Rerun `himi one-app validate-design` to produce
|
|
298
|
+
the source-to-target report; without that adaptation the difference fails the check.
|
|
299
|
+
`--fix` imports supported source families but never chooses a fallback or writes
|
|
300
|
+
an unavailable family. Unknown source IDs, unsupported target families and missing
|
|
301
|
+
or invalid target typography metrics remain unresolved even with an adaptation.
|
|
302
|
+
Omitted families also remain unresolved: renderer defaults differ across surfaces;
|
|
303
|
+
author `$system` explicitly when that is the approved replacement. `--fix` may fill
|
|
304
|
+
omitted families from a supported source while preserving valid numeric metrics.
|
|
305
|
+
Build/font validation still has
|
|
242
306
|
to prove the font bytes are available. Unresolved fonts and contrast also fail
|
|
243
307
|
the plain check used by push, not only `--record`.
|
|
244
308
|
Branded accent text must reach 4.5:1: `textOnAccent` against the fill, and `accentText` against the target page and declared neutral
|
|
@@ -578,9 +642,10 @@ Run `himi one-app coverage init --evidence-dir .himi/one-app --content .` to
|
|
|
578
642
|
create `ONE-APP-COVERAGE.json` from the verified source graph. After edits or a
|
|
579
643
|
CLI upgrade, run `coverage sync` and review new rows; `coverage check` fails when
|
|
580
644
|
the file is absent or source requirements have appeared, disappeared or changed.
|
|
581
|
-
Rows cover source graph warnings and app-wide design values as well as routes and
|
|
645
|
+
Rows cover native widget behavior, source graph warnings and app-wide design values as well as routes and
|
|
582
646
|
controls. This is an inventory of migration obligations, not proof that their target
|
|
583
|
-
actions work.
|
|
647
|
+
actions work. For explicit batch target decisions without inventing verification, use the
|
|
648
|
+
[executable ledger mapping recipe](https://apps.wix.com/_api/himi-serve/docs/recipe-one-app-coverage-mapping.md).
|
|
584
649
|
|
|
585
650
|
Preserve the existing app mark after scaffolding: run `himi icon from-one-app
|
|
586
651
|
--content . --evidence-dir .himi/one-app`. This reads the hash-verified collected
|
|
@@ -602,7 +667,7 @@ satisfied by the design check instead. Set its `status` to `supported`, `adapted
|
|
|
602
667
|
`unresolved`. For an adaptation, cite the user's instruction and explain the
|
|
603
668
|
change. Each resolved row needs a `verification` record using the required check
|
|
604
669
|
ID for its kind (`route-walkthrough`, `visual-comparison`, `behavior-crawl`,
|
|
605
|
-
`topbar-control`, `access-state`, `design-token`,
|
|
670
|
+
`topbar-control`, `access-state`, `design-token`, `source-resolution`, or `native-widget-behavior`), a safe relative path to
|
|
606
671
|
a JSON check record, and the exact release payload SHA-256 in `releaseHash`.
|
|
607
672
|
The JSON file's `checks[]` must contain a passed record with that requirement ID,
|
|
608
673
|
check ID, release hash, target mapping, and a relative `artifact` path to the
|
|
@@ -638,6 +703,21 @@ For example, one entry in the referenced JSON file is:
|
|
|
638
703
|
The artifact must exist. Review the actual route and state shown in it before
|
|
639
704
|
recording a pass; a valid record is an index to the check, not a substitute for it.
|
|
640
705
|
|
|
706
|
+
For a `native-widget` row use `check: "native-widget-behavior"` and include
|
|
707
|
+
`sourceBaseline` and `targetContext` in that check record. For example:
|
|
708
|
+
|
|
709
|
+
```json
|
|
710
|
+
{"checks":[{"requirementId":"<widget-row-id>","check":"native-widget-behavior","releaseHash":"<64-hex-sha256>","status":"passed","target":{"screenId":"home"},"artifact":".himi/one-app/device/target.png","sourceBaseline":{"kind":"native-device","artifact":".himi/one-app/device/source.png","siteId":"<same-site-id>","identityContext":"visitor-session-1"},"targetContext":{"siteId":"<same-site-id>","identityContext":"visitor-session-1"}}]}
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
`identityContext` is a private, opaque label for the compared identity, never a
|
|
714
|
+
credential, email address or session token. Both artifacts must be local safe
|
|
715
|
+
relative paths. The check rejects editor baselines and mismatched site/identity
|
|
716
|
+
labels. It checks record consistency; it cannot establish that screenshots are
|
|
717
|
+
authentic or that the observed behavior matches them. Review the artifacts and
|
|
718
|
+
exercise each effective control, including authored overrides and access states.
|
|
719
|
+
This comparison does not replace the QA APK/native proof below.
|
|
720
|
+
|
|
641
721
|
After publishing a draft, build a QA APK pinned to that draft release with
|
|
642
722
|
`himi dist --platform android --release <draft-id> --allow-draft`. Install
|
|
643
723
|
and walk through every requirement on the device. Save
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Recipe: map a One App coverage ledger
|
|
2
|
+
|
|
3
|
+
Use explicit reconstruction decisions to map a large `ONE-APP-COVERAGE.json` without
|
|
4
|
+
rewriting its source-derived IDs. This recipe only assigns targets. It never records a
|
|
5
|
+
passed check, chooses a customer route, or makes an unresolved requirement supported.
|
|
6
|
+
|
|
7
|
+
Run the existing coverage commands first:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
himi one-app coverage init --evidence-dir .himi/one-app --content .
|
|
11
|
+
# After source recollection or a CLI upgrade, use coverage sync and review its changes.
|
|
12
|
+
himi one-app coverage check --evidence-dir .himi/one-app --content .
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The runnable example is installed by `himi init` and refreshed by `himi agent-init` at
|
|
16
|
+
`.agents/skills/himalaya/examples/map-one-app-coverage.js`. It uses the installed
|
|
17
|
+
`himi one-app coverage check` before reading the ledger, so stale hashes, invented rows
|
|
18
|
+
and changed source requirements refuse the operation. It does not execute app workers
|
|
19
|
+
or call Wix. Keep decisions, descriptors and reports under `.himi/`.
|
|
20
|
+
|
|
21
|
+
Write `.himi/one-app/mapping-decisions.json` as an array. Select each row by its exact
|
|
22
|
+
`id`, or by exact `kind`, JSON-pointer `source`, and `platform` when present:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
[
|
|
26
|
+
{ "kind": "route", "source": "/screens/source_home", "target": { "screenId": "home" } },
|
|
27
|
+
{ "id": "<interaction-row-id-from-the-ledger>", "target": { "screenId": "home", "controlId": "view_products" } }
|
|
28
|
+
]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Copy source pointers and IDs from the ledger; do not derive them from labels, row
|
|
32
|
+
positions, or guessed routes. An ambiguous source selector requires the row ID. Each
|
|
33
|
+
decision may set only its target, never status, adaptation or verification. A `design`
|
|
34
|
+
row is app-wide and belongs to `validate-design`; leave it out of mapping decisions.
|
|
35
|
+
|
|
36
|
+
Generate `.himi/one-app/mapping-screens.json` from the **same authored descriptor data**
|
|
37
|
+
used by the app generator: `{ "home": { "screenId": "home", "payload": { … } }, … }`.
|
|
38
|
+
Include every authored screen and each screen's effective top bar (its override or the
|
|
39
|
+
actual `navigation.topBarDefault`). Serialize builders at generation time. Do not
|
|
40
|
+
invent a screen/control inventory to make a decision pass. Missing or dynamically
|
|
41
|
+
unresolved IDs stay unmapped. Control-ID presence is only an identity check; a real
|
|
42
|
+
interaction or top-bar check must still prove the behavior.
|
|
43
|
+
|
|
44
|
+
Inspect a dry run first, then write the reviewed mappings:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
node .agents/skills/himalaya/examples/map-one-app-coverage.js \
|
|
48
|
+
. .himi/one-app .himi/one-app/mapping-decisions.json .himi/one-app/mapping-screens.json \
|
|
49
|
+
> .himi/one-app/mapping-review.json
|
|
50
|
+
# Review coverage, issues, unmapped and needsVerification in that JSON.
|
|
51
|
+
node .agents/skills/himalaya/examples/map-one-app-coverage.js \
|
|
52
|
+
. .himi/one-app .himi/one-app/mapping-decisions.json .himi/one-app/mapping-screens.json --write
|
|
53
|
+
himi one-app coverage check --evidence-dir .himi/one-app --content .
|
|
54
|
+
himi one-app validate-topbar --evidence-dir .himi/one-app --content .
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
For `--write`, use the physical app directory, without symlinked parent directories;
|
|
58
|
+
the ledger itself must also be a regular file. Running the installed script through a
|
|
59
|
+
symlink is supported. Without `--write` the ledger is unchanged. Exit 1 means there are invalid decisions or
|
|
60
|
+
unmapped rows; the JSON lists them. With `--write`, valid decisions are retained while
|
|
61
|
+
unknown targets, missing controls and duplicate decisions leave their rows unresolved.
|
|
62
|
+
An unknown source/row creates no requirement and is reported in `issues`.
|
|
63
|
+
|
|
64
|
+
A changed mapping loses its old verification and adaptation and becomes `unresolved`.
|
|
65
|
+
An unchanged mapping retains its existing evidence; unrelated valid rows, IDs and source
|
|
66
|
+
hashes are preserved. A target removed from the authored map also loses its old evidence.
|
|
67
|
+
`needsVerification` lists every row: this recipe cannot validate retained proof against
|
|
68
|
+
the current built release. Use `coverage verify --release-hash <sha256>` with the real
|
|
69
|
+
release hash to check it, including unchanged mappings and previously saved records.
|
|
70
|
+
Mapping output is not a readiness verdict. Decide supported/adapted/conditional status
|
|
71
|
+
only after implementing and testing the corresponding behavior, with the required
|
|
72
|
+
artifact and exact release hash. Run `validate-design --fix`, rebuild, then record the
|
|
73
|
+
final design/UX/coverage evidence before pushing; repeat affected records after content
|
|
74
|
+
changes. The main migration guide defines those checks and their limitations.
|
|
@@ -23606,6 +23606,12 @@
|
|
|
23606
23606
|
"jsdoc": "/** List the signed-in member's notifications, newest first. MOBILE channel. */",
|
|
23607
23607
|
"decl": "export async function queryNotifications(limit = 25, options?: WixCallOptions): Promise<MfvNotification[]>;"
|
|
23608
23608
|
},
|
|
23609
|
+
{
|
|
23610
|
+
"name": "countUnseenNotifications",
|
|
23611
|
+
"kind": "function",
|
|
23612
|
+
"jsdoc": "/** Source member-app MOBILE/UNSEEN aggregate, capped at 100. Requires a bound\n * single-site Member transport; old native binaries and web reject. A missing,\n * malformed or failed result is unavailable, never an authoritative zero. */",
|
|
23613
|
+
"decl": "export async function countUnseenNotifications(options: { site: string }): Promise<number>;"
|
|
23614
|
+
},
|
|
23609
23615
|
{
|
|
23610
23616
|
"name": "markRead",
|
|
23611
23617
|
"kind": "function",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1572.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"artifactId": "himalaya-cli"
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
|
-
"falconPackageHash": "
|
|
74
|
+
"falconPackageHash": "20229381643935ec0f9390addc404f459d7040e7dfd5b634ab41385c"
|
|
75
75
|
}
|
|
@@ -52829,8 +52829,7 @@ const SCREENS = runtimeSetting({
|
|
|
52829
52829
|
"params": {
|
|
52830
52830
|
"screenId": "himi_owner_lite_search",
|
|
52831
52831
|
"title": "Search records",
|
|
52832
|
-
"subtitle": "Across your business areas"
|
|
52833
|
-
"search": "drawer"
|
|
52832
|
+
"subtitle": "Across your business areas"
|
|
52834
52833
|
}
|
|
52835
52834
|
},
|
|
52836
52835
|
"pressFeedback": "scale",
|
|
@@ -54349,7 +54348,7 @@ const SCREENS = runtimeSetting({
|
|
|
54349
54348
|
"actionId": "tier5.himiOwnerLiteSearch.search"
|
|
54350
54349
|
},
|
|
54351
54350
|
"debounceMs": 200,
|
|
54352
|
-
"
|
|
54351
|
+
"loadingPath": "$service:himiOwnerLiteSearch.anyLoading"
|
|
54353
54352
|
}
|
|
54354
54353
|
}
|
|
54355
54354
|
},
|
|
@@ -112,13 +112,10 @@ function programFields(p: WixProgram): Omit<ProgramRow, "priceLine"> {
|
|
|
112
112
|
initial: initials(name),
|
|
113
113
|
hasImage: !!image,
|
|
114
114
|
noImage: !image,
|
|
115
|
-
// The
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
// liveSeedRoute({ prefix: "himi_program_" }) already seeds and `currentInputId`
|
|
120
|
-
// resolves through its prefix path.
|
|
121
|
-
detailScreenId: `himi_program_${id}`,
|
|
115
|
+
// The canonical route is baked even offline. Hosts pass the row's `id` as
|
|
116
|
+
// worker input (WS-C); suffixed routes only exist for the preview seed's
|
|
117
|
+
// first 50 records and cannot open a complete live catalog in production.
|
|
118
|
+
detailScreenId: "himi_program",
|
|
122
119
|
};
|
|
123
120
|
}
|
|
124
121
|
|
|
@@ -157,9 +154,29 @@ function errored(state: State): State {
|
|
|
157
154
|
};
|
|
158
155
|
}
|
|
159
156
|
|
|
160
|
-
async function fetchPrograms(): Promise<WixProgram[]> {
|
|
161
|
-
const
|
|
162
|
-
|
|
157
|
+
async function fetchPrograms(isCurrent: () => boolean): Promise<WixProgram[] | undefined> {
|
|
158
|
+
const programs = new Map<string, WixProgram>();
|
|
159
|
+
const seen = new Set<string>();
|
|
160
|
+
let cursor = "";
|
|
161
|
+
do {
|
|
162
|
+
// Wix cursors carry the initial sort/filter. Repeating either on a continuation
|
|
163
|
+
// is rejected with INVALID_CURSOR, even when their values have not changed.
|
|
164
|
+
const response = await queryPrograms(cursor
|
|
165
|
+
? { cursorPaging: { limit: 50, cursor } }
|
|
166
|
+
: { cursorPaging: { limit: 50 }, sort: [{ fieldName: "createdDate", order: "DESC" }] });
|
|
167
|
+
if (!isCurrent()) return undefined;
|
|
168
|
+
for (const program of response.programs ?? []) {
|
|
169
|
+
if (program.id && !isDraft(program)) programs.set(program.id, program);
|
|
170
|
+
}
|
|
171
|
+
const paging = response.pagingMetadata;
|
|
172
|
+
const next = paging?.hasNext === false ? "" : paging?.cursors?.next ?? "";
|
|
173
|
+
if ((paging?.hasNext && !next) || (next && seen.has(next))) {
|
|
174
|
+
throw new Error("Invalid program catalog cursor");
|
|
175
|
+
}
|
|
176
|
+
if (next) seen.add(next);
|
|
177
|
+
cursor = next;
|
|
178
|
+
} while (cursor);
|
|
179
|
+
return [...programs.values()];
|
|
163
180
|
}
|
|
164
181
|
|
|
165
182
|
// ── Content and App Store prices ─────
|
|
@@ -180,7 +197,7 @@ let loadSeq = 0;
|
|
|
180
197
|
async function load(_state: State, arg?: unknown): Promise<undefined> {
|
|
181
198
|
stashCopy(arg);
|
|
182
199
|
const seq = ++loadSeq;
|
|
183
|
-
const programs = await fetchPrograms().catch(() => undefined);
|
|
200
|
+
const programs = await fetchPrograms(() => seq === loadSeq).catch(() => undefined);
|
|
184
201
|
if (seq !== loadSeq) return undefined;
|
|
185
202
|
content = programs ? { status: "ready", programs: programs.map(programContent) } : { ...content, status: "error" };
|
|
186
203
|
void svc.pricingPublish();
|
|
@@ -52829,8 +52829,7 @@ const SCREENS = runtimeSetting({
|
|
|
52829
52829
|
"params": {
|
|
52830
52830
|
"screenId": "himi_owner_lite_search",
|
|
52831
52831
|
"title": "Search records",
|
|
52832
|
-
"subtitle": "Across your business areas"
|
|
52833
|
-
"search": "drawer"
|
|
52832
|
+
"subtitle": "Across your business areas"
|
|
52834
52833
|
}
|
|
52835
52834
|
},
|
|
52836
52835
|
"pressFeedback": "scale",
|
|
@@ -54349,7 +54348,7 @@ const SCREENS = runtimeSetting({
|
|
|
54349
54348
|
"actionId": "tier5.himiOwnerLiteSearch.search"
|
|
54350
54349
|
},
|
|
54351
54350
|
"debounceMs": 200,
|
|
54352
|
-
"
|
|
54351
|
+
"loadingPath": "$service:himiOwnerLiteSearch.anyLoading"
|
|
54353
54352
|
}
|
|
54354
54353
|
}
|
|
54355
54354
|
},
|
|
@@ -52446,8 +52446,7 @@ const SCREENS = runtimeSetting({
|
|
|
52446
52446
|
"params": {
|
|
52447
52447
|
"screenId": "himi_owner_lite_search",
|
|
52448
52448
|
"title": "Search records",
|
|
52449
|
-
"subtitle": "Across your business areas"
|
|
52450
|
-
"search": "drawer"
|
|
52449
|
+
"subtitle": "Across your business areas"
|
|
52451
52450
|
}
|
|
52452
52451
|
},
|
|
52453
52452
|
"pressFeedback": "scale",
|
|
@@ -53966,7 +53965,7 @@ const SCREENS = runtimeSetting({
|
|
|
53966
53965
|
"actionId": "tier5.himiOwnerLiteSearch.search"
|
|
53967
53966
|
},
|
|
53968
53967
|
"debounceMs": 200,
|
|
53969
|
-
"
|
|
53968
|
+
"loadingPath": "$service:himiOwnerLiteSearch.anyLoading"
|
|
53970
53969
|
}
|
|
53971
53970
|
}
|
|
53972
53971
|
},
|
|
@@ -52905,8 +52905,7 @@ const SCREENS = runtimeSetting({
|
|
|
52905
52905
|
"params": {
|
|
52906
52906
|
"screenId": "himi_owner_lite_search",
|
|
52907
52907
|
"title": "Search records",
|
|
52908
|
-
"subtitle": "Across your business areas"
|
|
52909
|
-
"search": "drawer"
|
|
52908
|
+
"subtitle": "Across your business areas"
|
|
52910
52909
|
}
|
|
52911
52910
|
},
|
|
52912
52911
|
"pressFeedback": "scale",
|
|
@@ -54425,7 +54424,7 @@ const SCREENS = runtimeSetting({
|
|
|
54425
54424
|
"actionId": "tier5.himiOwnerLiteSearch.search"
|
|
54426
54425
|
},
|
|
54427
54426
|
"debounceMs": 200,
|
|
54428
|
-
"
|
|
54427
|
+
"loadingPath": "$service:himiOwnerLiteSearch.anyLoading"
|
|
54429
54428
|
}
|
|
54430
54429
|
}
|
|
54431
54430
|
},
|
|
@@ -52522,8 +52522,7 @@ const SCREENS = runtimeSetting({
|
|
|
52522
52522
|
"params": {
|
|
52523
52523
|
"screenId": "himi_owner_lite_search",
|
|
52524
52524
|
"title": "Search records",
|
|
52525
|
-
"subtitle": "Across your business areas"
|
|
52526
|
-
"search": "drawer"
|
|
52525
|
+
"subtitle": "Across your business areas"
|
|
52527
52526
|
}
|
|
52528
52527
|
},
|
|
52529
52528
|
"pressFeedback": "scale",
|
|
@@ -54042,7 +54041,7 @@ const SCREENS = runtimeSetting({
|
|
|
54042
54041
|
"actionId": "tier5.himiOwnerLiteSearch.search"
|
|
54043
54042
|
},
|
|
54044
54043
|
"debounceMs": 200,
|
|
54045
|
-
"
|
|
54044
|
+
"loadingPath": "$service:himiOwnerLiteSearch.anyLoading"
|
|
54046
54045
|
}
|
|
54047
54046
|
}
|
|
54048
54047
|
},
|
|
@@ -52904,8 +52904,7 @@ const SCREENS = runtimeSetting({
|
|
|
52904
52904
|
"params": {
|
|
52905
52905
|
"screenId": "himi_owner_lite_search",
|
|
52906
52906
|
"title": "Search records",
|
|
52907
|
-
"subtitle": "Across your business areas"
|
|
52908
|
-
"search": "drawer"
|
|
52907
|
+
"subtitle": "Across your business areas"
|
|
52909
52908
|
}
|
|
52910
52909
|
},
|
|
52911
52910
|
"pressFeedback": "scale",
|
|
@@ -54422,7 +54421,7 @@ const SCREENS = runtimeSetting({
|
|
|
54422
54421
|
"actionId": "tier5.himiOwnerLiteSearch.search"
|
|
54423
54422
|
},
|
|
54424
54423
|
"debounceMs": 200,
|
|
54425
|
-
"
|
|
54424
|
+
"loadingPath": "$service:himiOwnerLiteSearch.anyLoading"
|
|
54426
54425
|
}
|
|
54427
54426
|
}
|
|
54428
54427
|
},
|
|
@@ -52829,8 +52829,7 @@ const SCREENS = runtimeSetting({
|
|
|
52829
52829
|
"params": {
|
|
52830
52830
|
"screenId": "himi_owner_lite_search",
|
|
52831
52831
|
"title": "Search records",
|
|
52832
|
-
"subtitle": "Across your business areas"
|
|
52833
|
-
"search": "drawer"
|
|
52832
|
+
"subtitle": "Across your business areas"
|
|
52834
52833
|
}
|
|
52835
52834
|
},
|
|
52836
52835
|
"pressFeedback": "scale",
|
|
@@ -54349,7 +54348,7 @@ const SCREENS = runtimeSetting({
|
|
|
54349
54348
|
"actionId": "tier5.himiOwnerLiteSearch.search"
|
|
54350
54349
|
},
|
|
54351
54350
|
"debounceMs": 200,
|
|
54352
|
-
"
|
|
54351
|
+
"loadingPath": "$service:himiOwnerLiteSearch.anyLoading"
|
|
54353
54352
|
}
|
|
54354
54353
|
}
|
|
54355
54354
|
},
|
|
@@ -52829,8 +52829,7 @@ const SCREENS = runtimeSetting({
|
|
|
52829
52829
|
"params": {
|
|
52830
52830
|
"screenId": "himi_owner_lite_search",
|
|
52831
52831
|
"title": "Search records",
|
|
52832
|
-
"subtitle": "Across your business areas"
|
|
52833
|
-
"search": "drawer"
|
|
52832
|
+
"subtitle": "Across your business areas"
|
|
52834
52833
|
}
|
|
52835
52834
|
},
|
|
52836
52835
|
"pressFeedback": "scale",
|
|
@@ -54349,7 +54348,7 @@ const SCREENS = runtimeSetting({
|
|
|
54349
54348
|
"actionId": "tier5.himiOwnerLiteSearch.search"
|
|
54350
54349
|
},
|
|
54351
54350
|
"debounceMs": 200,
|
|
54352
|
-
"
|
|
54351
|
+
"loadingPath": "$service:himiOwnerLiteSearch.anyLoading"
|
|
54353
54352
|
}
|
|
54354
54353
|
}
|
|
54355
54354
|
},
|
|
@@ -52905,8 +52905,7 @@ const SCREENS = runtimeSetting({
|
|
|
52905
52905
|
"params": {
|
|
52906
52906
|
"screenId": "himi_owner_lite_search",
|
|
52907
52907
|
"title": "Search records",
|
|
52908
|
-
"subtitle": "Across your business areas"
|
|
52909
|
-
"search": "drawer"
|
|
52908
|
+
"subtitle": "Across your business areas"
|
|
52910
52909
|
}
|
|
52911
52910
|
},
|
|
52912
52911
|
"pressFeedback": "scale",
|
|
@@ -54425,7 +54424,7 @@ const SCREENS = runtimeSetting({
|
|
|
54425
54424
|
"actionId": "tier5.himiOwnerLiteSearch.search"
|
|
54426
54425
|
},
|
|
54427
54426
|
"debounceMs": 200,
|
|
54428
|
-
"
|
|
54427
|
+
"loadingPath": "$service:himiOwnerLiteSearch.anyLoading"
|
|
54429
54428
|
}
|
|
54430
54429
|
}
|
|
54431
54430
|
},
|
|
@@ -52741,8 +52741,7 @@ const SCREENS = runtimeSetting({
|
|
|
52741
52741
|
"params": {
|
|
52742
52742
|
"screenId": "himi_owner_lite_search",
|
|
52743
52743
|
"title": "Search records",
|
|
52744
|
-
"subtitle": "Across your business areas"
|
|
52745
|
-
"search": "drawer"
|
|
52744
|
+
"subtitle": "Across your business areas"
|
|
52746
52745
|
}
|
|
52747
52746
|
},
|
|
52748
52747
|
"pressFeedback": "scale",
|
|
@@ -54261,7 +54260,7 @@ const SCREENS = runtimeSetting({
|
|
|
54261
54260
|
"actionId": "tier5.himiOwnerLiteSearch.search"
|
|
54262
54261
|
},
|
|
54263
54262
|
"debounceMs": 200,
|
|
54264
|
-
"
|
|
54263
|
+
"loadingPath": "$service:himiOwnerLiteSearch.anyLoading"
|
|
54265
54264
|
}
|
|
54266
54265
|
}
|
|
54267
54266
|
},
|