@wix/himalaya-cli 0.1611.0 → 0.1613.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/dev-server/src/builder.d.ts +5 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +12 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/loyalty/src/extensions.d.ts +2 -6
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/loyalty/src/index.d.ts +78 -6
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +4 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-loyalty.mjs +8 -0
- package/dist/cli.mjs +616 -107
- package/dist/preview-assets.generated.bin +0 -0
- package/fixtures/wix-canned.json +41 -0
- package/guides/component-reference.json +7 -4
- package/guides/component-reference.md +14 -3
- package/guides/getting-started.md +3 -2
- package/guides/himi-json-output.md +3 -0
- package/guides/himi-skill.md +3 -2
- package/guides/himi-test.md +65 -2
- package/guides/one-app-section-mappings.md +3 -4
- package/guides/one-app-to-himi-app.md +1 -1
- package/guides/recipe-form-submit.md +9 -0
- package/guides/sdk-reference.json +44 -4
- package/package.json +2 -2
- package/stdlib/fonts/catalog.json +141 -0
- package/templates/branded-lite/dev/index.ts +84 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-loyalty/index.ts +99 -9
|
Binary file
|
package/fixtures/wix-canned.json
CHANGED
|
@@ -1047,6 +1047,47 @@
|
|
|
1047
1047
|
}
|
|
1048
1048
|
]
|
|
1049
1049
|
},
|
|
1050
|
+
"GET /loyalty-tiers/v1/tiers/program": {
|
|
1051
|
+
"programSettings": {
|
|
1052
|
+
"status": "ACTIVE",
|
|
1053
|
+
"baseTierDefinition": {
|
|
1054
|
+
"name": "Bronze"
|
|
1055
|
+
},
|
|
1056
|
+
"rollingWindow": {
|
|
1057
|
+
"durationInMonths": 12
|
|
1058
|
+
}
|
|
1059
|
+
},
|
|
1060
|
+
"tiers": [
|
|
1061
|
+
{
|
|
1062
|
+
"id": "tier-0001",
|
|
1063
|
+
"tierDefinition": {
|
|
1064
|
+
"name": "Silver"
|
|
1065
|
+
},
|
|
1066
|
+
"requiredPoints": 500
|
|
1067
|
+
},
|
|
1068
|
+
{
|
|
1069
|
+
"id": "tier-0002",
|
|
1070
|
+
"tierDefinition": {
|
|
1071
|
+
"name": "Gold"
|
|
1072
|
+
},
|
|
1073
|
+
"requiredPoints": 1000
|
|
1074
|
+
}
|
|
1075
|
+
]
|
|
1076
|
+
},
|
|
1077
|
+
"GET /loyalty-coupons/v1/coupons/my-coupons": {
|
|
1078
|
+
"loyaltyCoupons": [
|
|
1079
|
+
{
|
|
1080
|
+
"id": "lc-0001",
|
|
1081
|
+
"rewardName": "Free filter coffee",
|
|
1082
|
+
"status": "ACTIVE",
|
|
1083
|
+
"couponReference": {
|
|
1084
|
+
"couponId": "cp-0001",
|
|
1085
|
+
"code": "BEANS-0001",
|
|
1086
|
+
"deleted": false
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
]
|
|
1090
|
+
},
|
|
1050
1091
|
"POST /reviews/v1/reviews/query": {
|
|
1051
1092
|
"reviews": [
|
|
1052
1093
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "GENERATED by core/web-embed/authoring/gen-reference.mjs from core/ts/src/schema.ts — do not hand-edit. The schema is the source of truth; regenerate on schema changes.",
|
|
3
3
|
"schemaSource": "core/ts/src/schema.ts",
|
|
4
|
-
"bindingGrammar": "$service:<service>.<path> (worker state) · $item.<field> (list row) · $flag:<key> (feature flag) · $env:<key> (client environment — #1056). Bindings resolve in the text/value props marked 'binding-aware' below — INCLUDING Modifiers token refs — but only `background` and `border.color`, which are the two whose token a binding actually fills: a worker can drive per-item theming (e.g. a game board's per-square color), not just text. `shadow` is NOT binding-aware on any renderer, and a gradient is driven by its own `backgroundGradientPath` prop resolving to a gradient token NAME, not by a binding inside a token ref — so `shadow: { token: \"$item.x\" }` and `backgroundGradient: { token: \"$item.x\" }` keep the sentinel and silently lose the per-item styling. Colour slots split by LEVEL, not by component: inside modifiers a colour is a TokenRef OBJECT ({ token: \"…\" }), inside props it is a bare TokenName STRING — there is no modifiers.color or modifiers.tint (see the 'Token slots' section in component-reference.md). A few input props render the LITERAL and are NOT binding-aware — notably SearchField.placeholder and Chip.label; SearchField.value is live and binding-aware like other content props. Bindings also CANNOT target strict-enum fields (style, size, alignment, severity, presentation, contentMode, …) — those fail at render, not validation. $env: is client-resolved (no worker) and valid in modifiers.hiddenPath and FragmentSlot.casePath ONLY — keys reduceMotion/colorScheme/sizeClass/isRTL, e.g. hiddenPath:\"$env:reduceMotion\" or hiddenPath:\"$env:colorScheme==light\", casePath:\"$env:colorScheme\"; unknown key fails open (shown / defaultCase).",
|
|
4
|
+
"bindingGrammar": "$service:<service>.<path> (worker state) · $item.<field> (list row) · $flag:<key> (feature flag) · $env:<key> (client environment — #1056). Bindings resolve in the text/value props marked 'binding-aware' below — INCLUDING Modifiers token refs — but only `background` and `border.color`, which are the two whose token a binding actually fills: a worker can drive per-item theming (e.g. a game board's per-square color), not just text. `shadow` is NOT binding-aware on any renderer, and a gradient is driven by its own `backgroundGradientPath` prop resolving to a gradient token NAME, not by a binding inside a token ref — so `shadow: { token: \"$item.x\" }` and `backgroundGradient: { token: \"$item.x\" }` keep the sentinel and silently lose the per-item styling. Colour slots split by LEVEL, not by component: inside modifiers a colour is a TokenRef OBJECT ({ token: \"…\" }), inside props it is a bare TokenName STRING — there is no modifiers.color or modifiers.tint (see the 'Token slots' section in component-reference.md). A few input props render the LITERAL and are NOT binding-aware — notably SearchField.placeholder and Chip.label; SearchField.value is live and binding-aware like other content props. Bindings also CANNOT target strict-enum fields (style, size, alignment, severity, presentation, contentMode, …) — those fail at render, not validation. $env: is client-resolved (no worker) and valid in modifiers.hiddenPath and FragmentSlot.casePath ONLY — keys reduceMotion/colorScheme/sizeClass/isRTL/keyboardVisible, e.g. hiddenPath:\"$env:reduceMotion\" or hiddenPath:\"$env:colorScheme==light\", casePath:\"$env:colorScheme\"; unknown key fails open (shown / defaultCase).",
|
|
5
5
|
"componentCount": 88,
|
|
6
6
|
"notImplementedComponents": [
|
|
7
7
|
"Text",
|
|
@@ -515,14 +515,17 @@
|
|
|
515
515
|
"currentIndexPath",
|
|
516
516
|
"itemsPath"
|
|
517
517
|
],
|
|
518
|
-
"propsSource": "export interface CarouselProps {\n /** Opt-in paging for itemsPath; absent preserves the horizontal card rail. */\n paged?: boolean;\n /**
|
|
518
|
+
"propsSource": "export interface CarouselProps {\n /** Opt-in paging for itemsPath; absent preserves the horizontal card rail. */\n paged?: boolean;\n /** #4673 — `$service:` path to the page index, two-way with `onChange`: a CHANGE of the resolved\n * value animates the carousel there (instantly under reduced motion); a swipe still fires\n * `onChange` with `args.index`, which the worker writes back. Out of range ⇒ clamped; not an\n * integer ⇒ ignored; equal to the current page ⇒ nothing; a move the binding made fires no\n * `onChange`. Drives literal `items` and `paged` bound ones; inside a bound row a substituted\n * literal places the page like `currentIndex`. A rail (`itemsPath` without `paged`) ignores it. */\n currentIndexPath?: string;\n items: Component[];\n currentIndex?: number;\n onChange?: Action;\n autoplayIntervalMs?: number;\n /** `$service:` binding → a live array to render as slides (overrides `items`). */\n itemsPath?: string;\n /** 0 (default) = all slides mounted; N ⇒ mount current ± N, unmount the rest. */\n liveWindow?: number;\n}"
|
|
519
519
|
},
|
|
520
520
|
{
|
|
521
521
|
"name": "Pager",
|
|
522
522
|
"category": "Navigation primitives",
|
|
523
523
|
"propsType": "PagerProps",
|
|
524
|
-
"bindings": [
|
|
525
|
-
|
|
524
|
+
"bindings": [
|
|
525
|
+
"currentIndexPath",
|
|
526
|
+
"pagesPath"
|
|
527
|
+
],
|
|
528
|
+
"propsSource": "export interface PagerProps {\n pages: Component[];\n currentIndex?: number;\n onChange?: Action;\n showIndicator?: boolean;\n /** As {@link CarouselProps.liveWindow}. */\n liveWindow?: number;\n /** #4673 — as {@link CarouselProps.currentIndexPath}: a worker-driven page, two-way with `onChange`. */\n currentIndexPath?: string;\n /** #4673 — `$service:` path to an array: `pages[0]` is the page TEMPLATE, instantiated once per\n * element with `$item.` substitution (as `Carousel.itemsPath`). Pages are keyed by `$item.id`, so\n * the page on screen stays on screen when items are inserted before it. */\n pagesPath?: string;\n}"
|
|
526
529
|
},
|
|
527
530
|
{
|
|
528
531
|
"name": "StepIndicator",
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
**88 core component types.** Every component body is `{ "package": "himalaya", "type": "<Type>", "props": { … } }`.
|
|
7
7
|
Binding grammar: `$service:<service>.<path>` (worker state) · `$item.<field>` (list row template) · `$flag:<key>` (feature flag) · `$env:<key>` (client environment — #1056).
|
|
8
8
|
Bindings resolve in the text/value props marked **binding-aware** below — **including two `Modifiers` token refs**, `background` and `border.color`, which are the only two whose token a binding actually fills: a worker can drive per-item **theming** (e.g. a game board's per-square color, `background: { token: "$item.bg" }`), not just text content. `shadow` and `backgroundGradient` are `TokenRef`s but are **not** binding-aware on any renderer — `shadow: { token: "$item.x" }` keeps the sentinel as a literal token name and silently loses the per-item styling, and a gradient is driven by its own `backgroundGradientPath` prop resolving to a gradient token NAME, not by a binding inside a token ref.
|
|
9
|
-
`$env:` is **client-resolved** (no worker) and valid in `modifiers.hiddenPath` and `FragmentSlot.casePath` **only** — keys `reduceMotion` / `colorScheme` / `sizeClass` / `isRTL
|
|
9
|
+
`$env:` is **client-resolved** (no worker) and valid in `modifiers.hiddenPath` and `FragmentSlot.casePath` **only** — keys `reduceMotion` / `colorScheme` / `sizeClass` / `isRTL` / `keyboardVisible` (an on-screen keyboard is up — `hiddenPath: "$env:keyboardVisible"` hides a header while typing), with an optional `==`/`!=` comparison (e.g. `hiddenPath: "$env:reduceMotion"`, `hiddenPath: "$env:colorScheme==light"`, `casePath: "$env:colorScheme"`). An unknown key fails open (shown / `defaultCase`).
|
|
10
10
|
A few input props render the **literal** and are **not** binding-aware — notably `SearchField.placeholder` and `Chip.label`. `SearchField.value` is live/binding-aware like other content props.
|
|
11
11
|
They **cannot target strict-enum fields** (`style`, `size`, `alignment`, `severity`, `presentation`, `contentMode`, …) — those fail at render time, not validation.
|
|
12
12
|
|
|
@@ -63,7 +63,7 @@ See also **[Modifiers](#modifiers)** (the `modifiers` block) and **[Actions](#ac
|
|
|
63
63
|
| `Tabs` | Navigation primitives | `optionsPath`, `activeColorPath`, `selectedId` |
|
|
64
64
|
| `SegmentedControl` | Navigation primitives | `optionsPath`, `selectedId` |
|
|
65
65
|
| `Carousel` | Navigation primitives | `currentIndexPath`, `itemsPath` |
|
|
66
|
-
| `Pager` | Navigation primitives |
|
|
66
|
+
| `Pager` | Navigation primitives | `currentIndexPath`, `pagesPath` |
|
|
67
67
|
| `StepIndicator` | Navigation primitives | — |
|
|
68
68
|
| `CollapsingHeader` | Navigation primitives | — |
|
|
69
69
|
| `AvatarStrip` | Navigation primitives | `avatarsPath` |
|
|
@@ -1075,7 +1075,12 @@ export interface SegmentedControlProps {
|
|
|
1075
1075
|
export interface CarouselProps {
|
|
1076
1076
|
/** Opt-in paging for itemsPath; absent preserves the horizontal card rail. */
|
|
1077
1077
|
paged?: boolean;
|
|
1078
|
-
/**
|
|
1078
|
+
/** #4673 — `$service:` path to the page index, two-way with `onChange`: a CHANGE of the resolved
|
|
1079
|
+
* value animates the carousel there (instantly under reduced motion); a swipe still fires
|
|
1080
|
+
* `onChange` with `args.index`, which the worker writes back. Out of range ⇒ clamped; not an
|
|
1081
|
+
* integer ⇒ ignored; equal to the current page ⇒ nothing; a move the binding made fires no
|
|
1082
|
+
* `onChange`. Drives literal `items` and `paged` bound ones; inside a bound row a substituted
|
|
1083
|
+
* literal places the page like `currentIndex`. A rail (`itemsPath` without `paged`) ignores it. */
|
|
1079
1084
|
currentIndexPath?: string;
|
|
1080
1085
|
items: Component[];
|
|
1081
1086
|
currentIndex?: number;
|
|
@@ -1098,6 +1103,12 @@ export interface PagerProps {
|
|
|
1098
1103
|
showIndicator?: boolean;
|
|
1099
1104
|
/** As {@link CarouselProps.liveWindow}. */
|
|
1100
1105
|
liveWindow?: number;
|
|
1106
|
+
/** #4673 — as {@link CarouselProps.currentIndexPath}: a worker-driven page, two-way with `onChange`. */
|
|
1107
|
+
currentIndexPath?: string;
|
|
1108
|
+
/** #4673 — `$service:` path to an array: `pages[0]` is the page TEMPLATE, instantiated once per
|
|
1109
|
+
* element with `$item.` substitution (as `Carousel.itemsPath`). Pages are keyed by `$item.id`, so
|
|
1110
|
+
* the page on screen stays on screen when items are inserted before it. */
|
|
1111
|
+
pagesPath?: string;
|
|
1101
1112
|
}
|
|
1102
1113
|
```
|
|
1103
1114
|
|
|
@@ -256,8 +256,9 @@ product. Right after `init`:
|
|
|
256
256
|
typed input → submit → the persisted result with a typed journey in `himi-test.json`
|
|
257
257
|
(`.himi/himi-test.stub.json` has a skeleton per form: fill the values and expected text)
|
|
258
258
|
(`--deep` replays action chains but never types a field value), then prove the destination
|
|
259
|
-
and cancel/back recovery separately
|
|
260
|
-
|
|
259
|
+
and cancel/back recovery separately. For device-local records, add explicit `coldVisits`
|
|
260
|
+
assertions from `himi docs himi-test` so another cold worker must read the same saved record.
|
|
261
|
+
Cold visits do not drive navigation or prove warm repaint/relaunch: drive those in the UI. A fresh-screen crawl alone
|
|
261
262
|
does not prove a flow.
|
|
262
263
|
|
|
263
264
|
Before authoring a multi-screen mobile app, ensure the customer-approved `SPEC.md` and
|
|
@@ -44,7 +44,10 @@ keeps its existing fields and adds the code:
|
|
|
44
44
|
|
|
45
45
|
| Code | Meaning |
|
|
46
46
|
| --- | --- |
|
|
47
|
+
| `test_journey_budget_exceeded` | The authored config exceeds a shared journey/visit/worker-segment/step/assertion work bound. Exit 2 with `ok: false` and the existing `error` on stderr before compilation or worker boot. Tokenless `POST /v1/test` uses the same code with HTTP422 before upload compilation/evaluation. Split the evaluation into separately identified bounded runs; no truncated pass is emitted. |
|
|
47
48
|
| `test_journey_failed` | At least one unsuppressed authored journey failed: its destination is absent, initialization/action failed, or the expected rendered values were missing. The existing `failures`, `journeys`, counts and exit 1 remain. This includes cold-entry journeys with `steps: []`. |
|
|
49
|
+
| `test_browser_cold_visits_unsupported` | `--browser` was requested with an authored `coldVisits` contract. Exit 2 before compilation or opening a browser; run without `--browser` to exercise those visits. The browser loop cannot certify saved-record return behavior. |
|
|
50
|
+
| `test_browser_journeys_unsupported` | `--browser` was requested with authored journeys that have no `coldVisits`. Exit 2 before compilation or opening a browser. The single-screen browser loop does not execute authored steps or root `expectText`/`absentText` assertions; run without `--browser` to execute that contract. The existing cold-visit code remains in use when any journey has `coldVisits`. |
|
|
48
51
|
| `test_input_evidence_requires_json` | `--input-evidence` was requested without explicit `--json`. Exit 2 before build or worker execution. |
|
|
49
52
|
| `test_input_evidence_unsupported_mode` | `--input-evidence` was combined with `--browser`, or the content is a functions package rather than an app worker crawl. Exit 2 before execution. |
|
|
50
53
|
| `test_input_evidence_unavailable` | The isolated input crawl cannot establish all contained realms, cannot read a stable source archive before/after the crawl, or fails to return one complete JSON report (including interruption, process timeout or output limit). Exit 1; no host-realm fallback or positive input acceptance. |
|
package/guides/himi-skill.md
CHANGED
|
@@ -279,8 +279,9 @@ product. Right after `init`:
|
|
|
279
279
|
typed input → submit → the persisted result with a typed journey in `himi-test.json`
|
|
280
280
|
(`.himi/himi-test.stub.json` has a skeleton per form: fill the values and expected text)
|
|
281
281
|
(`--deep` replays action chains but never types a field value), then prove the destination
|
|
282
|
-
and cancel/back recovery separately
|
|
283
|
-
|
|
282
|
+
and cancel/back recovery separately. For device-local records, add explicit `coldVisits`
|
|
283
|
+
assertions from `himi docs himi-test` so another cold worker must read the same saved record.
|
|
284
|
+
Cold visits do not drive navigation or prove warm repaint/relaunch: drive those in the UI. A fresh-screen crawl alone
|
|
284
285
|
does not prove a flow.
|
|
285
286
|
|
|
286
287
|
Before authoring a multi-screen mobile app, ensure the customer-approved `SPEC.md` and
|
package/guides/himi-test.md
CHANGED
|
@@ -110,7 +110,7 @@ The receipt has these fields:
|
|
|
110
110
|
| `execution` | CLI-established `devModule`, `appConfig`, `workerBoot` and `workerAction` modes, each `quickjs-wasm`. A v1 report missing these fields predates the contained CLI path; do not accept it as contained execution. This marker is meaningful only when captured from the trusted pinned producer. |
|
|
111
111
|
| `probes` | Each synthesized typed dispatch's screen/component/action/hook, contract control and injected field/value, actual argument list, precondition input/current value/state hash, post-state hash, and observed state/navigation/request/host-call/throw results. Zero probes is not proof that required controls ran. |
|
|
112
112
|
| `journeys` | Actual screen/input, each attempted step's scope, raw `declaredPayload`, effective row-resolved `descriptorPayload`, exact `testOverrides`, final merged `payload`, pre/post state hashes, executed/threw/not-dispatched status, final visible observations and evaluator-computed assertions. Unavailable actions remain not-dispatched, never successful steps. |
|
|
113
|
-
| `unavailableScreens`, `unavailableJourneys` | Requested coverage for which the evaluator did not supply v1 evidence, including older engines, invalid/collapsed screens and unavailable journeys. With positional screen IDs, these lists contain only requested roots; requested unknown IDs remain unavailable. Unrelated configured journeys do not run or fail a scoped run. These gaps are not accepted behavior. |
|
|
113
|
+
| `unavailableScreens`, `unavailableJourneys` | Requested coverage for which the evaluator did not supply evaluated v1 evidence, including older engines, invalid/collapsed screens and explicitly unavailable source journeys. An unavailable source can still retain evaluated nested cold-visit receipts. With positional screen IDs, these lists contain only requested roots; requested unknown IDs remain unavailable. Unrelated configured journeys do not run or fail a scoped run. These gaps are not accepted behavior. |
|
|
114
114
|
|
|
115
115
|
State hashes fingerprint the exact serialized worker snapshot captured at the dispatch
|
|
116
116
|
boundary. `currentValuePresent` distinguishes an absent current value from null.
|
|
@@ -189,6 +189,69 @@ edge would hand it — so the journey boots the way a real tap into it would. Ke
|
|
|
189
189
|
navigation in the ordinary edge pass, which boots the destination with real source
|
|
190
190
|
parameters. Pair dynamic journeys with app-specific `dev/net-mocks.json` fixtures.
|
|
191
191
|
|
|
192
|
+
### Prove a local mutation survives a cold visit
|
|
193
|
+
|
|
194
|
+
A success message proves only the current screen's outcome. It does not prove that another
|
|
195
|
+
screen can read the saved record. Add `coldVisits` to a typed journey when the approved flow
|
|
196
|
+
requires another screen worker to read a created, edited or removed authoritative local record:
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"journeys": [{
|
|
201
|
+
"name": "create then read the same record",
|
|
202
|
+
"screen": "record_form",
|
|
203
|
+
"steps": [{
|
|
204
|
+
"action": "tier5.records.save",
|
|
205
|
+
"params": { "id": "probe-record", "title": "Field notebook", "notes": "Keep this note" }
|
|
206
|
+
}],
|
|
207
|
+
"expectText": ["Saved"],
|
|
208
|
+
"coldVisits": [
|
|
209
|
+
{ "screen": "record_list", "expectText": ["Field notebook"] },
|
|
210
|
+
{ "screen": "record_detail", "input": { "id": "probe-record" },
|
|
211
|
+
"expectText": ["Field notebook", "Keep this note"] },
|
|
212
|
+
{ "screen": "record_list", "expectText": ["Field notebook"] }
|
|
213
|
+
]
|
|
214
|
+
}]
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Use the app's actual screen/action names, field payloads and independently chosen expected
|
|
219
|
+
values. Every visit boots a **new worker realm** with only that destination's descriptor and
|
|
220
|
+
`input`; module variables and service state do not cross. Visits within one journey share a
|
|
221
|
+
private hermetic `local_database`, `secure_storage` and app-scoped `himalaya.storage` store. Each journey starts with empty
|
|
222
|
+
stores. Destination capability declarations and the app's local-entity schema still apply.
|
|
223
|
+
The ordinary crawl's other axes keep their fresh stores.
|
|
224
|
+
|
|
225
|
+
A visit can also have `steps`, using the same declared worker-action contract as the initial
|
|
226
|
+
journey. For a destructive flow, request removal then cancel, cold-visit the list and require
|
|
227
|
+
the selected row plus an unrelated row. In a separate sequence, confirm, then require the
|
|
228
|
+
unrelated row and use `"absentText": ["unique removed title"]`. `absentText` works on the
|
|
229
|
+
initial journey too. Both text checks use substrings of the resolved visible render tree;
|
|
230
|
+
choose distinct values that cannot be satisfied by another row or a static heading. Assert
|
|
231
|
+
all required fields and displayed totals, not just a generic success line. A missing screen,
|
|
232
|
+
failed expectation or unexecuted visit fails the journey; JSON reports include a receipt for
|
|
233
|
+
each cold visit.
|
|
234
|
+
|
|
235
|
+
Authored work is admitted as a whole before any worker executes: at most 32 journeys,
|
|
236
|
+
32 cold visits per journey,128 total worker segments (sources plus visits),512 total
|
|
237
|
+
steps and2048 total positive/absent assertions. These shared limits apply to the CLI,
|
|
238
|
+
`POST /v1/test` and direct crawl callers. Over-budget work is rejected with
|
|
239
|
+
`test_journey_budget_exceeded`; visits or receipts are never silently truncated. Split a
|
|
240
|
+
larger evaluation into separately identified runs. A bundleless source retains an
|
|
241
|
+
explicit `worker-unavailable` receipt and every later visit's positional outcome.
|
|
242
|
+
Validation-blocked destination workers do not execute, but their baked descriptor
|
|
243
|
+
input and explicit visit overrides are retained in their unavailable receipt.
|
|
244
|
+
|
|
245
|
+
A same-screen favorite may legitimately use a retained worker snapshot; this no-snapshot check does not test that contract.
|
|
246
|
+
|
|
247
|
+
This is **headless local-store proof**, not a router drive or a real browser database
|
|
248
|
+
relaunch. It does not hydrate worker snapshots, run app services, synchronize with a backend,
|
|
249
|
+
or prove warm-screen refresh, native behavior, account switching or deployed-service
|
|
250
|
+
acceptance. Keep the normal navigation edge checks and drive the actual UI through return
|
|
251
|
+
and reload/relaunch on each required platform. Inspect storage separately when the row
|
|
252
|
+
exists but the screen is stale. The state ownership choices remain in
|
|
253
|
+
[tier-5-add-a-screen.md](tier-5-add-a-screen.md#state-does-not-cross-screens-automatically).
|
|
254
|
+
|
|
192
255
|
Journeys run only the initialization the bundle and descriptor actually declare: module-scope
|
|
193
256
|
calls and the root `onAppear`. Unlike the discovery crawl's convenience `load()` sweep, they do
|
|
194
257
|
not call an otherwise uncalled loader. A declaration of `actions.load` alone does not initialize
|
|
@@ -575,7 +638,7 @@ behavior. This instruction does not add an automatic suppression or retry gate t
|
|
|
575
638
|
| `--budget <ms>` | Per-action settle budget (default 2000). |
|
|
576
639
|
| `--native` | Also decode every baked descriptor, and the release's `tokens.json`, with the real native decoders; bare `--native` runs whichever toolchains are present and names each one it could NOT check in a top-level `skippedPlatforms: [{ platform, reason }]` (never a pass), while `--native ios` or `--native android` selects one and exits 2 when it is unavailable. The Android SDK is found from `ANDROID_HOME`, then `ANDROID_SDK_ROOT`, then `sdk.dir` in the source checkout's Android test harness `local.properties`, then the default install path (`~/Library/Android/sdk` on macOS, `~/Android/Sdk` on Linux). **Source-checkout only** — the decoder oracles are that tree's own HimalayaCore Swift package and Gradle harness, which a published install does not ship, so it cannot run this at all (and its coverage ledger stays silent about native decoding rather than suggesting it). |
|
|
577
640
|
| `--all-screens` | Crawl every templated instance instead of one representative per structure. |
|
|
578
|
-
| `--browser` / `--no-open` / `--timeout <ms>` | Run the loop in your own browser tab (one screen per run; refuses record/net/offline/hostile/deep/budget/shots/native). |
|
|
641
|
+
| `--browser` / `--no-open` / `--timeout <ms>` | Run the loop in your own browser tab (one screen per run; refuses all authored journeys, including root assertions and `coldVisits`, and record/net/offline/hostile/deep/budget/shots/native). |
|
|
579
642
|
| `himi test <screenId>…` | Focus one or more screens — the record and shots passes scope with them. |
|
|
580
643
|
|
|
581
644
|
**Screenshots** are on by default when a headless browser is installed: one PNG per screen
|
|
@@ -25,8 +25,8 @@ Source snapshots: Catalyst `617c06d43d2a5608b6876d724553269b1e5346f0`; Himalaya
|
|
|
25
25
|
| Module | 13 |
|
|
26
26
|
| Primitive | 7 |
|
|
27
27
|
| Composition | 9 |
|
|
28
|
-
| Partial |
|
|
29
|
-
| Empty |
|
|
28
|
+
| Partial | 25 |
|
|
29
|
+
| Empty | 23 |
|
|
30
30
|
| Total | 77 |
|
|
31
31
|
|
|
32
32
|
## Mappings by server group
|
|
@@ -127,7 +127,7 @@ carousel placement remain separate gaps; the mappings above stay Partial.
|
|
|
127
127
|
|
|
128
128
|
| Source sectionDefinitionId | Source viewer component | Himalaya implementation | Placement / reuse | Class | Settings, actions and gaps |
|
|
129
129
|
| --- | --- | --- | --- | --- | --- |
|
|
130
|
-
| `loyalty_status_section` | `loyalty.components.StatusSection` |
|
|
130
|
+
| `loyalty_status_section` | `loyalty.components.StatusSection` | [himi_loyalty member card](https://github.com/wix-private/himalaya/blob/adf4c8b47fd237307b278a5dbb8198a94b7feb69/apps/himi-branded-lite/dev/index.ts) (`buildLoyalty` points card) + [loyalty worker](https://github.com/wix-private/himalaya/blob/adf4c8b47fd237307b278a5dbb8198a94b7feb69/core/dev-server/tier5-bundles-src/himi-branded-lite-loyalty/index.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") | Existing base; adaptation needed | Partial | The member card on `himi_loyalty` reads the signed-in member's balance (`getCurrentMemberLoyaltyAccount`) and, beside it, the tiers program and the claimed coupons; it shows the balance, the tier name, the points-expiry line and `Rewards available (N)` (rewards the balance covers on the member's tier + ACTIVE claimed coupons), each blank when its read fails. Visitors get the sign-in gate. Not carried over: the referral-coupon share of the count (no referral spec in codegen) and the one-app `View` link (the catalog it opens is on the same screen). |
|
|
131
131
|
| `loyalty_offering_section` | `loyalty.components.OfferingSection` | [himi_loyalty](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/apps/himi-branded-lite/dev/index.ts) + [rewards worker](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/core/dev-server/tier5-bundles-src/himi-branded-lite-loyalty/index.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") | Existing base; adaptation needed | Partial | Reuse program/reward reads and required-points presentation. Preserve offering selection. Member earning/redemption operations are not established by this read-only rewards list. |
|
|
132
132
|
|
|
133
133
|
### 8. referrals-section-definitions.json
|
|
@@ -355,7 +355,6 @@ These are the exact definitions whose target cells above remain empty. “Not fo
|
|
|
355
355
|
| `events-section-definitions.json` | `events_discussion_section` | No event-scoped discussion implementation was found. Groups/social feed and Blog comments must not be selected automatically. |
|
|
356
356
|
| `events-section-definitions.json` | `events_guests_section` | The Events detail has only a best-effort attendee summary/avatar strip using an owner-scoped guest query. It is not a full consumer guest-list section; leave the mapping unassigned. |
|
|
357
357
|
| `groups-section-definitions.json` | `single_group_feed_section` | A feed exists, but it selects a relevant/home group internally and does not accept the configured fixed-group selector. No verified single-group feed adapter exists; keep this target empty until a policy/implementation is chosen. |
|
|
358
|
-
| `loyalty-section-definitions.json` | `loyalty_status_section` | The existing Loyalty worker lists the program and rewards but does not load this member's points balance/tier/status. A rewards catalog is not a loyalty-status widget. |
|
|
359
358
|
| `referrals-section-definitions.json` | `referrals_refer_section` | No consumer referral-code/link sharing and referral-status feature was found. Do not map to Loyalty or generic sharing without a user decision. A visitor-readable program read exists; see the row above. |
|
|
360
359
|
| `referrals-section-definitions.json` | `referrals_description_section` | No referral-program description/data implementation was found. Text primitives alone do not resolve the business-bound referral content. A visitor-readable program read exists; see the row above. |
|
|
361
360
|
| `photoalbum-section-definitions.json` | `photoAlbums_list_section` | Existing Photo Albums code is an empty-state placeholder with no album API wired. Pro Gallery uses a different data source and is not a substitute; choose an implementation explicitly. |
|
|
@@ -345,7 +345,7 @@ Apply these interpretation rules:
|
|
|
345
345
|
typography tokens use the body family. Numeric metrics stay unchanged. Read each
|
|
346
346
|
source heading/body family and check `himi fonts list`; use `himi fonts add <Family>`
|
|
347
347
|
when it is available. A known source family that Himi does not ship (for example
|
|
348
|
-
`
|
|
348
|
+
`sora` → Sora) is still compared with the actual target family.
|
|
349
349
|
Choose an available replacement, such as `$system`, only with the owner's explicit
|
|
350
350
|
instruction; this is an adaptation, never a font match. Sync the coverage ledger
|
|
351
351
|
against the current source evidence, then mark the corresponding `design` requirement
|
|
@@ -233,3 +233,12 @@ shape (heading swap, `savedScreenId`, back-navigation).
|
|
|
233
233
|
- `himi docs recipe-dynamic-list` — the list the created entity lands in.
|
|
234
234
|
- `himi components Form` / `FormField` / `TextField` / `Toggle` / `Picker`.
|
|
235
235
|
- `.agents/skills/himalaya/examples/form-submit.*` (written into the app by `himi init` / `himi agent-init`) — this recipe, runnable.
|
|
236
|
+
|
|
237
|
+
## Verify the saved record outside this worker
|
|
238
|
+
|
|
239
|
+
For a local create/edit flow, a saved banner alone is insufficient. Add a typed journey
|
|
240
|
+
with [cold visits](../himi-test.md#prove-a-local-mutation-survives-a-cold-visit) that reads
|
|
241
|
+
the same record from its list and detail, checks all entered fields and relevant totals,
|
|
242
|
+
and preserves an unrelated record. Then drive return and reload in the actual UI. Choose
|
|
243
|
+
the storage owner using [the cross-screen state contract](../tier-5-add-a-screen.md#state-does-not-cross-screens-automatically);
|
|
244
|
+
a worker snapshot is not a shared record store.
|
|
@@ -23425,19 +23425,43 @@
|
|
|
23425
23425
|
"name": "WixLoyaltyRewardConfig",
|
|
23426
23426
|
"kind": "interface",
|
|
23427
23427
|
"jsdoc": "",
|
|
23428
|
-
"decl": "export interface WixLoyaltyRewardConfig {\n tierId?: string;\n costInPoints?: number;\n amount?: number;\n percentage?: number;\n}"
|
|
23428
|
+
"decl": "export interface WixLoyaltyRewardConfig {\n tierId?: string;\n costInPoints?: number;\n amount?: string | number;\n percentage?: number;\n}"
|
|
23429
|
+
},
|
|
23430
|
+
{
|
|
23431
|
+
"name": "WixLoyaltyTierConfig",
|
|
23432
|
+
"kind": "type",
|
|
23433
|
+
"jsdoc": "/** One reward price row: what the reward costs a member on tier `tierId` (absent = the base tier). */",
|
|
23434
|
+
"decl": "export type WixLoyaltyTierConfig = WixLoyaltyRewardConfig;"
|
|
23429
23435
|
},
|
|
23430
23436
|
{
|
|
23431
23437
|
"name": "WixLoyaltyProgram",
|
|
23432
23438
|
"kind": "interface",
|
|
23433
23439
|
"jsdoc": "",
|
|
23434
|
-
"decl": "export interface WixLoyaltyProgram {\n id?: string;\n name?: string;\n /** ACTIVE | DRAFT | PAUSED */\n status?: string;\n pointDefinition?: { customName?: string; icon?: WixLoyaltyImage };\n}"
|
|
23440
|
+
"decl": "export interface WixLoyaltyProgram {\n id?: string;\n name?: string;\n /** ACTIVE | DRAFT | PAUSED */\n status?: string;\n pointDefinition?: { customName?: string; icon?: WixLoyaltyImage };\n /** Which premium loyalty features the site's plan unlocks. Absent on older responses. */\n premiumFeatures?: { loyaltyProgram?: boolean; tiers?: boolean; pointsExpiration?: boolean };\n /** The program-level expiry POLICY (not a member's date — that is `WixLoyaltyAccount.pointsExpiration`). */\n pointsExpiration?: { status?: string; monthsOfInactivity?: number; expiringPointsPercentage?: number };\n}"
|
|
23435
23441
|
},
|
|
23436
23442
|
{
|
|
23437
23443
|
"name": "WixLoyaltyReward",
|
|
23438
23444
|
"kind": "interface",
|
|
23439
23445
|
"jsdoc": "",
|
|
23440
|
-
"decl": "export interface WixLoyaltyReward {\n id: string;\n name?: string;\n type?: string;\n /** Legacy adapter field. REST costs live in the reward's tier configurations. */\n requiredPoints?: number;\n discountAmount?: { configsByTier?:
|
|
23446
|
+
"decl": "export interface WixLoyaltyReward {\n id: string;\n name?: string;\n /** DISCOUNT_AMOUNT | COUPON_REWARD | COUPON | SPI_DISCOUNT_AMOUNT | … */\n type?: string;\n /** Legacy adapter field. REST costs live in the reward's tier configurations. */\n requiredPoints?: number;\n discountAmount?: { configsByTier?: WixLoyaltyRewardConfig[] };\n couponReward?: {\n fixedAmount?: { configsByTier?: WixLoyaltyRewardConfig[] };\n percentage?: { configsByTier?: WixLoyaltyRewardConfig[] };\n freeShipping?: { configsByTier?: WixLoyaltyRewardConfig[] };\n };\n active?: boolean;\n}"
|
|
23447
|
+
},
|
|
23448
|
+
{
|
|
23449
|
+
"name": "WixLoyaltyAccount",
|
|
23450
|
+
"kind": "interface",
|
|
23451
|
+
"jsdoc": "/** The signed-in member's loyalty account (wix.loyalty.v1.account, `/my-account`). */",
|
|
23452
|
+
"decl": "export interface WixLoyaltyAccount {\n id?: string;\n points?: { balance?: number; earned?: number; adjusted?: number; redeemed?: number; expired?: number };\n /** The member's current tier; absent or without `id` while on the base tier. */\n tier?: { id?: string; points?: number };\n /** The member's own expiry — when and how many points lapse next. */\n pointsExpiration?: { expirationDate?: string; expiringPointsAmount?: number };\n rewardAvailable?: boolean;\n}"
|
|
23453
|
+
},
|
|
23454
|
+
{
|
|
23455
|
+
"name": "WixLoyaltyTiersProgram",
|
|
23456
|
+
"kind": "interface",
|
|
23457
|
+
"jsdoc": "/** The tiers program: settings (ACTIVE | PAUSED, the base tier's definition) plus the custom tiers. */",
|
|
23458
|
+
"decl": "export interface WixLoyaltyTiersProgram {\n tiers?: WixLoyaltyTier[];\n programSettings?: {\n status?: string;\n baseTierDefinition?: { name?: string; description?: string; icon?: unknown };\n rollingWindow?: { durationInMonths?: number };\n };\n}"
|
|
23459
|
+
},
|
|
23460
|
+
{
|
|
23461
|
+
"name": "WixLoyaltyCoupon",
|
|
23462
|
+
"kind": "interface",
|
|
23463
|
+
"jsdoc": "/** A reward the member already claimed as a coupon (wix.loyalty.v1.coupon). */",
|
|
23464
|
+
"decl": "export interface WixLoyaltyCoupon {\n id?: string;\n rewardName?: string;\n /** ACTIVE | APPLIED | DELETED */\n status?: string;\n couponReference?: { couponId?: string; code?: string; deleted?: boolean };\n}"
|
|
23441
23465
|
},
|
|
23442
23466
|
{
|
|
23443
23467
|
"name": "WixLoyaltyTier",
|
|
@@ -23480,6 +23504,22 @@
|
|
|
23480
23504
|
"http": "GET /_api/loyalty-earning-rules/v1/earning-rules/rules",
|
|
23481
23505
|
"scope": "visitor"
|
|
23482
23506
|
},
|
|
23507
|
+
{
|
|
23508
|
+
"name": "getLoyaltyTiersProgram",
|
|
23509
|
+
"kind": "function",
|
|
23510
|
+
"jsdoc": "/** GET /loyalty-tiers/v1/tiers/program → { tiers, programSettings }. The custom tiers plus the\n * settings that carry the BASE tier's name — the one a member with no `tier.id` is on.\n *\n * @scope visitor — readable without signing in. */",
|
|
23511
|
+
"decl": "export function getLoyaltyTiersProgram(readOptions?: WixCallOptions): Promise<WixLoyaltyTiersProgram>;",
|
|
23512
|
+
"http": "GET /loyalty-tiers/v1/tiers/program",
|
|
23513
|
+
"scope": "visitor"
|
|
23514
|
+
},
|
|
23515
|
+
{
|
|
23516
|
+
"name": "listMyLoyaltyCoupons",
|
|
23517
|
+
"kind": "function",
|
|
23518
|
+
"jsdoc": "/** GET /loyalty-coupons/v1/coupons/my-coupons → { loyaltyCoupons }. The member's claimed\n * rewards; an ACTIVE, undeleted one still counts as a reward available to use.\n *\n * @scope member — requires a signed-in site member. */",
|
|
23519
|
+
"decl": "export function listMyLoyaltyCoupons(readOptions?: WixCallOptions): Promise<{ loyaltyCoupons?: WixLoyaltyCoupon[] }>;",
|
|
23520
|
+
"http": "GET /loyalty-coupons/v1/coupons/my-coupons",
|
|
23521
|
+
"scope": "member"
|
|
23522
|
+
},
|
|
23483
23523
|
{
|
|
23484
23524
|
"name": "LoyaltyOverview",
|
|
23485
23525
|
"kind": "interface",
|
|
@@ -23514,7 +23554,7 @@
|
|
|
23514
23554
|
"name": "getCurrentMemberLoyaltyAccount",
|
|
23515
23555
|
"kind": "function",
|
|
23516
23556
|
"jsdoc": "/** Read the authenticated member's own Loyalty account; no customer ID is accepted.\n * Source contract: loyalty-v1.getCurrentMemberAccount. Anonymous visitors are refused.\n * A signed-in customer recording is still required for migration acceptance.\n * @scope member\n */",
|
|
23517
|
-
"decl": "export function getCurrentMemberLoyaltyAccount(readOptions?: WixCallOptions): Promise<{ account?:
|
|
23557
|
+
"decl": "export function getCurrentMemberLoyaltyAccount(readOptions?: WixCallOptions): Promise<{ account?: WixLoyaltyAccount }>;",
|
|
23518
23558
|
"http": "GET /loyalty-accounts/v1/accounts/my-account",
|
|
23519
23559
|
"scope": "member"
|
|
23520
23560
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1613.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": [
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"artifactId": "himalaya-cli"
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
-
"falconPackageHash": "
|
|
75
|
+
"falconPackageHash": "8d1e7814c00d18146088e2680fe43650535ec12113548c216d4fdbe0"
|
|
76
76
|
}
|
|
@@ -210,6 +210,32 @@
|
|
|
210
210
|
}
|
|
211
211
|
]
|
|
212
212
|
},
|
|
213
|
+
"DM Serif Display": {
|
|
214
|
+
"category": "serif",
|
|
215
|
+
"dir": "ofl/dmserifdisplay",
|
|
216
|
+
"webFallback": "serif",
|
|
217
|
+
"aliases": [
|
|
218
|
+
"dmserifdisplay",
|
|
219
|
+
"dm serif display",
|
|
220
|
+
"dm serif"
|
|
221
|
+
],
|
|
222
|
+
"license": {
|
|
223
|
+
"id": "OFL-1.1",
|
|
224
|
+
"url": "https://raw.githubusercontent.com/google/fonts/8e44913e4ff26fc997e6856c1ec40ff4791c98c5/ofl/dmserifdisplay/OFL.txt",
|
|
225
|
+
"copyright": "Copyright 2014-2018 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. Copyright 2019 Google LLC."
|
|
226
|
+
},
|
|
227
|
+
"faces": [
|
|
228
|
+
{
|
|
229
|
+
"weight": 400,
|
|
230
|
+
"style": "normal",
|
|
231
|
+
"postScriptName": "DMSerifDisplay-Regular",
|
|
232
|
+
"file": "DMSerifDisplay-Regular.ttf",
|
|
233
|
+
"sha256": "8cc3643535edf039aa5d95440a8542735e9197e4f4b8d9303e980fefbf5ab616",
|
|
234
|
+
"sri": "sha256-jMNkNTXt8DmqXZVECoVCc16Rl+T0uNkwPpgP779athY=",
|
|
235
|
+
"bytes": 76580
|
|
236
|
+
}
|
|
237
|
+
]
|
|
238
|
+
},
|
|
213
239
|
"Dancing Script": {
|
|
214
240
|
"category": "handwriting",
|
|
215
241
|
"dir": "ofl/dancingscript",
|
|
@@ -279,6 +305,54 @@
|
|
|
279
305
|
}
|
|
280
306
|
]
|
|
281
307
|
},
|
|
308
|
+
"Fraunces": {
|
|
309
|
+
"category": "serif",
|
|
310
|
+
"dir": "ofl/fraunces",
|
|
311
|
+
"webFallback": "serif",
|
|
312
|
+
"aliases": [
|
|
313
|
+
"fraunces"
|
|
314
|
+
],
|
|
315
|
+
"license": {
|
|
316
|
+
"id": "OFL-1.1",
|
|
317
|
+
"url": "https://raw.githubusercontent.com/google/fonts/8e44913e4ff26fc997e6856c1ec40ff4791c98c5/ofl/fraunces/OFL.txt",
|
|
318
|
+
"copyright": "Copyright 2018 The Fraunces Project Authors (https://github.com/undercasetype/Fraunces)"
|
|
319
|
+
},
|
|
320
|
+
"variable": {
|
|
321
|
+
"axes": {
|
|
322
|
+
"opsz": {
|
|
323
|
+
"min": 9,
|
|
324
|
+
"default": 9,
|
|
325
|
+
"max": 144
|
|
326
|
+
},
|
|
327
|
+
"wght": {
|
|
328
|
+
"min": 100,
|
|
329
|
+
"default": 900,
|
|
330
|
+
"max": 900
|
|
331
|
+
},
|
|
332
|
+
"SOFT": {
|
|
333
|
+
"min": 0,
|
|
334
|
+
"default": 0,
|
|
335
|
+
"max": 100
|
|
336
|
+
},
|
|
337
|
+
"WONK": {
|
|
338
|
+
"min": 0,
|
|
339
|
+
"default": 1,
|
|
340
|
+
"max": 1
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
"faces": [
|
|
345
|
+
{
|
|
346
|
+
"weight": 900,
|
|
347
|
+
"style": "normal",
|
|
348
|
+
"postScriptName": "Fraunces-9ptBlack",
|
|
349
|
+
"file": "Fraunces[SOFT,WONK,opsz,wght].ttf",
|
|
350
|
+
"sha256": "177ff6c0f14e5550a3c624247cd1189611d4eb65d000b14944c63d967958abbb",
|
|
351
|
+
"sri": "sha256-F3/2wPFOVVCjxiQkfNEYlhHU62XQALFJRMY9lnlYq7s=",
|
|
352
|
+
"bytes": 360440
|
|
353
|
+
}
|
|
354
|
+
]
|
|
355
|
+
},
|
|
282
356
|
"IBM Plex Mono": {
|
|
283
357
|
"category": "mono",
|
|
284
358
|
"dir": "ofl/ibmplexmono",
|
|
@@ -863,6 +937,40 @@
|
|
|
863
937
|
}
|
|
864
938
|
]
|
|
865
939
|
},
|
|
940
|
+
"Space Grotesk": {
|
|
941
|
+
"category": "sans",
|
|
942
|
+
"dir": "ofl/spacegrotesk",
|
|
943
|
+
"webFallback": "sans-serif",
|
|
944
|
+
"aliases": [
|
|
945
|
+
"spacegrotesk",
|
|
946
|
+
"space grotesk"
|
|
947
|
+
],
|
|
948
|
+
"license": {
|
|
949
|
+
"id": "OFL-1.1",
|
|
950
|
+
"url": "https://raw.githubusercontent.com/google/fonts/8e44913e4ff26fc997e6856c1ec40ff4791c98c5/ofl/spacegrotesk/OFL.txt",
|
|
951
|
+
"copyright": "Copyright 2020 The Space Grotesk Project Authors (https://github.com/floriankarsten/space-grotesk)"
|
|
952
|
+
},
|
|
953
|
+
"variable": {
|
|
954
|
+
"axes": {
|
|
955
|
+
"wght": {
|
|
956
|
+
"min": 300,
|
|
957
|
+
"default": 300,
|
|
958
|
+
"max": 700
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
},
|
|
962
|
+
"faces": [
|
|
963
|
+
{
|
|
964
|
+
"weight": 300,
|
|
965
|
+
"style": "normal",
|
|
966
|
+
"postScriptName": "SpaceGrotesk-Light",
|
|
967
|
+
"file": "SpaceGrotesk[wght].ttf",
|
|
968
|
+
"sha256": "acad6de1fc93436f5c0f1f4137751ef04f1aea3063e7036535970ffcfbd79f72",
|
|
969
|
+
"sri": "sha256-rK1t4fyTQ29cDx9BN3Ue8E8a6jBj5wNlNZcP/PvXn3I=",
|
|
970
|
+
"bytes": 136676
|
|
971
|
+
}
|
|
972
|
+
]
|
|
973
|
+
},
|
|
866
974
|
"Space Mono": {
|
|
867
975
|
"category": "mono",
|
|
868
976
|
"dir": "ofl/spacemono",
|
|
@@ -897,6 +1005,39 @@
|
|
|
897
1005
|
}
|
|
898
1006
|
]
|
|
899
1007
|
},
|
|
1008
|
+
"Vollkorn": {
|
|
1009
|
+
"category": "serif",
|
|
1010
|
+
"dir": "ofl/vollkorn",
|
|
1011
|
+
"webFallback": "serif",
|
|
1012
|
+
"aliases": [
|
|
1013
|
+
"vollkorn"
|
|
1014
|
+
],
|
|
1015
|
+
"license": {
|
|
1016
|
+
"id": "OFL-1.1",
|
|
1017
|
+
"url": "https://raw.githubusercontent.com/google/fonts/8e44913e4ff26fc997e6856c1ec40ff4791c98c5/ofl/vollkorn/OFL.txt",
|
|
1018
|
+
"copyright": "Copyright 2017 The Vollkorn Project Authors (https://github.com/FAlthausen/Vollkorn-Typeface)"
|
|
1019
|
+
},
|
|
1020
|
+
"variable": {
|
|
1021
|
+
"axes": {
|
|
1022
|
+
"wght": {
|
|
1023
|
+
"min": 400,
|
|
1024
|
+
"default": 400,
|
|
1025
|
+
"max": 900
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
},
|
|
1029
|
+
"faces": [
|
|
1030
|
+
{
|
|
1031
|
+
"weight": 400,
|
|
1032
|
+
"style": "normal",
|
|
1033
|
+
"postScriptName": "Vollkorn-Regular",
|
|
1034
|
+
"file": "Vollkorn[wght].ttf",
|
|
1035
|
+
"sha256": "4ebef434f76f80286204840354a84db79a0dc3c87deeeb791e015b70b2ade49d",
|
|
1036
|
+
"sri": "sha256-Tr70NPdvgChiBIQDVKhNt5oNw8h97ut5HgFbcLKt5J0=",
|
|
1037
|
+
"bytes": 577864
|
|
1038
|
+
}
|
|
1039
|
+
]
|
|
1040
|
+
},
|
|
900
1041
|
"Work Sans": {
|
|
901
1042
|
"category": "sans",
|
|
902
1043
|
"dir": "ofl/worksans",
|