@wix/himalaya-cli 0.838.0 → 0.840.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.
@@ -84,8 +84,9 @@ An adopted `wixId` declaration is **optional for reads**. A worker may call
84
84
  read even when `config.ts` has no `cms` block; declaring it records the expected
85
85
  schema for humans and `himi validate`, but does not grant or enable that read.
86
86
 
87
- `himi cms query` labels every collection on the site `owned`, `adopted`, or
88
- `foreign`, so the blast radius is visible before you run anything.
87
+ `himi cms query --all` labels every collection on the site `owned`, `adopted`, or
88
+ `foreign`, so the blast radius is visible before you run anything. (Without `--all`
89
+ it reads only the ids you declare — see [below](#himi-cms-query--read-only).)
89
90
 
90
91
  ### `site analyze --apply` adopts, it never claims
91
92
 
@@ -275,7 +276,8 @@ boots as — an unauthenticated visitor — rather than as one it has no way to
275
276
  export WIX_SITE_ID=<msid> # or pass --site <msid> to every command
276
277
 
277
278
  himi validate # offline: prefix, field types, displayField, seed keys, permissions
278
- himi cms query # READ-ONLY: what exists, who owns it, where it drifts
279
+ himi cms query --all # READ-ONLY: what the SITE has, including collections you never declared
280
+ himi cms query # READ-ONLY: just your declared ids — what exists, who owns it, where it drifts
279
281
  himi cms create # provision the owned collections (idempotent)
280
282
  himi cms seed # fill the EMPTY owned collections from `seed:`
281
283
  himi push --draft # ship the content package; does NOT touch the site
@@ -287,13 +289,67 @@ publishing a release is exactly the surprise this design avoids.
287
289
 
288
290
  ### `himi cms query` — read-only
289
291
 
290
- Every collection on the site, labeled `owned` / `adopted` / `foreign`, with item
291
- counts for the declared ones and a `drift` list: declared-but-missing collections,
292
- missing fields, undeclared extra fields, and type mismatches. Run it first, and run
293
- it after `create` to confirm.
292
+ **By default it reads only the ids you declared.** One targeted `GET` per declared
293
+ collection, and the report says so with `siteScanned: false`. You get item counts and
294
+ a `drift` list: declared-but-missing collections, missing fields, undeclared extra
295
+ fields, and type mismatches. Run it first, and run it after `create` to confirm.
294
296
 
295
- Item counts are fetched only for *declared* collections — a site inventory doesn't
296
- fan out a query per foreign collection.
297
+ The default never lists the site, so it cannot show you a collection you did not
298
+ declare — **including one this app owns**. A leftover `himi_<app>_*` from a renamed
299
+ declaration is labeled `owned` when the scan finds it, but only `--all` looks.
300
+
301
+ The default stays off the site-wide list on purpose: that list is ~1MB and 46–60s on
302
+ a real site (194 collections on one test site) and its socket gets reset mid-transfer,
303
+ while the per-id reads it actually needs are ~3KB each.
304
+
305
+ #### `--all` — scan the site and discover what to adopt
306
+
307
+ `himi cms query --all --site <msid>` additionally lists the whole site and describes
308
+ every **foreign** collection — one this app neither owns nor declares:
309
+
310
+ ```json
311
+ {
312
+ "siteScanned": true,
313
+ "foreign": {
314
+ "count": 31,
315
+ "collections": [
316
+ { "id": "QaRecipes", "displayName": "Recipes", "readRole": "ANYONE", "itemCount": null,
317
+ "fields": [ { "key": "title", "type": "TEXT" }, { "key": "cookMinutes", "type": "NUMBER" } ] }
318
+ ],
319
+ "truncated": 6
320
+ }
321
+ }
322
+ ```
323
+
324
+ That is enough to write the adopted declaration without a second call: `wixId` is the
325
+ `id`, and the `fields` carry the keys **and** the types a declaration must mirror (Wix
326
+ cannot retype a field in place, so a wrong type is a refusal, not a warning). A field
327
+ with no `type` is one the site did not report a type for — read that collection directly
328
+ before declaring it, rather than guessing; the scan will not invent one for you.
329
+
330
+ - **It works with no `cms` block at all.** Discovering what to declare is precisely the
331
+ case where nothing is declared yet, so `--all` is the one flag for which a missing
332
+ `cms` block is *not* "nothing to do".
333
+ - **Foreign collections are never item-counted** (`itemCount: null`). A row count is one
334
+ query each, and fanning that across a whole site is the cost this scan must not pay.
335
+ Declare or adopt the collection and the count arrives with the next `himi cms query`.
336
+ - **Only the first 25 are described.** `foreign.count` is how many the scan listed and
337
+ `foreign.truncated` says how many of those went undescribed, so a short list is never
338
+ mistaken for a short site. For the full per-collection picture — field types,
339
+ read/write roles and sample rows — use
340
+ [`himi site analyze --site <msid>`](wix-business-context.md).
341
+ - **`foreign.count` is not a site census.** `GET /data/v2/collections` is paged and this
342
+ scan reads one page. When Wix reports a total larger than that page,
343
+ `unlistedCollections` says how many the listing left out; when Wix reports no total,
344
+ neither field can tell you, so treat `foreign.count` as "foreign collections in what we
345
+ listed" and use `site analyze` if you need certainty about a very large site.
346
+
347
+ **The scan is owner-scoped, and there is no tokenless alternative.** It needs
348
+ `--site <msid>` (or `WIX_SITE_ID`) and owner auth via `wix token`, because enumerating
349
+ collections is `GET /data/v2/collections`, which requires the *Manage Data
350
+ Collections* scope. A visitor/anonymous token can read the **items** of an
351
+ `ANYONE`-read collection whose id you already have, but it can never list collections —
352
+ so no CLI work can make the tokenless path discover them.
297
353
 
298
354
  ### `himi cms create` — additive and idempotent
299
355
 
@@ -101,7 +101,7 @@
101
101
  "bindings": [
102
102
  "text"
103
103
  ],
104
- "propsSource": "export type TextProps = TextContent & {\n style?: TokenName;\n /** Foreground color token (default \"textPrimary\"). */\n color?: TokenName;\n /** Tail-truncate after N lines (absent = unlimited). */\n maxLines?: number;\n /** Render `text` as a constrained Markdown subset. */\n markdown?: boolean;\n /** Capability enrichments. */\n textAlign?: \"leading\" | \"center\" | \"trailing\" | \"justify\";\n /** Base writing direction. \"auto\" (or \"rtl\") makes a bidi paragraph resolve +\n * align by its own strong-directional content (Hebrew/Arabic → right-aligned,\n * RTL layout), matching per-message direction in chat bubbles. Absent/\"ltr\" =\n * the current left-to-right behavior. Both renderers honor it (parity). */\n textDirection?: \"auto\" | \"ltr\" | \"rtl\";\n decoration?: \"underline\" | \"strikethrough\";\n lineSpacing?: number;\n /** Per-item gate (usually an `$item.` field pre-substituted per row): when it\n * resolves empty, the text collapses to zero size instead of taking layout. */\n collapseWhenEmpty?: boolean;\n /** Motion grammar (Batch 1, item 4) — count-up tween for a numeric value on\n * change; non-numeric values render instantly. Gated by reduced motion. */\n animateValue?: boolean;\n /** Motion grammar — reveal the (post-substitution literal) text word-by-word,\n * once per distinct content, like a chat assistant \"typing\" its reply. Each\n * content animates a single time (progress is remembered), so list re-renders\n * and scrolls don't restart it. Gated by reduced motion (snaps to full).\n * Both renderers honor it (parity). Default nil/false. */\n animateReveal?: boolean;\n};"
104
+ "propsSource": "export type TextProps = TextContent & {\n style?: TokenName;\n /** Foreground color token (default \"textPrimary\"). */\n color?: TokenName;\n /** Tail-truncate after N lines (absent = unlimited). */\n maxLines?: number;\n /** Lever D — a live time value (countdown/relative) the OS ticks with no refresh.\n * When present it OVERRIDES `text`. Widget-safe render only. */\n timeRef?: WidgetTimeRef;\n /** Render `text` as a constrained Markdown subset. */\n markdown?: boolean;\n /** Capability enrichments. */\n textAlign?: \"leading\" | \"center\" | \"trailing\" | \"justify\";\n /** Base writing direction. \"auto\" (or \"rtl\") makes a bidi paragraph resolve +\n * align by its own strong-directional content (Hebrew/Arabic → right-aligned,\n * RTL layout), matching per-message direction in chat bubbles. Absent/\"ltr\" =\n * the current left-to-right behavior. Both renderers honor it (parity). */\n textDirection?: \"auto\" | \"ltr\" | \"rtl\";\n decoration?: \"underline\" | \"strikethrough\";\n lineSpacing?: number;\n /** Per-item gate (usually an `$item.` field pre-substituted per row): when it\n * resolves empty, the text collapses to zero size instead of taking layout. */\n collapseWhenEmpty?: boolean;\n /** Motion grammar (Batch 1, item 4) — count-up tween for a numeric value on\n * change; non-numeric values render instantly. Gated by reduced motion. */\n animateValue?: boolean;\n /** Motion grammar — reveal the (post-substitution literal) text word-by-word,\n * once per distinct content, like a chat assistant \"typing\" its reply. Each\n * content animates a single time (progress is remembered), so list re-renders\n * and scrolls don't restart it. Gated by reduced motion (snaps to full).\n * Both renderers honor it (parity). Default nil/false. */\n animateReveal?: boolean;\n};"
105
105
  },
106
106
  {
107
107
  "name": "Image",
@@ -388,7 +388,7 @@
388
388
  "bindings": [
389
389
  "avatarsPath"
390
390
  ],
391
- "propsSource": "export interface AvatarStripProps {\n /** `$service:` binding → a live array of `{imageUrl, initials}` (overrides `avatars`). */\n avatarsPath?: string;\n /** Literal fallback (Tier 0–4); ignored if `avatarsPath` resolves. */\n avatars?: AvatarStripAvatar[];\n /** Diameter in points (default 40). */\n size?: number;\n /** 0..1; shift = size * (1 - overlapRatio) (default 0.67). */\n overlapRatio?: number;\n /** Max avatars before overflow (default 4). */\n maxVisible?: number;\n /** Default true. */\n showOverflow?: boolean;\n /** Explicit overflow; if 0/absent computed from total. */\n overflowCount?: number;\n /** Literal caption (or `$service:` upstream-resolved). */\n caption?: string;\n /** Fired when tapping any avatar. */\n onTap?: Action;\n}"
391
+ "propsSource": "export interface AvatarStripProps {\n /** `$service:` binding → a live array of `{imageUrl, initials}` (overrides `avatars`). */\n avatarsPath?: string;\n /** Literal fallback (Tier 0–4); ignored if `avatarsPath` resolves. */\n avatars?: AvatarStripAvatar[];\n /** Diameter in points (default 40). */\n size?: number;\n /** 0..1; shift = size * (1 - overlapRatio) (default 0.67). */\n overlapRatio?: number;\n /** Max avatars before overflow (default 4). */\n maxVisible?: number;\n /** Default true. */\n showOverflow?: boolean;\n /** Explicit overflow; if 0/absent computed from total. */\n overflowCount?: number;\n /** Literal caption (or `$service:` upstream-resolved). */\n caption?: string;\n /** Fired when tapping any avatar. */\n onTap?: Action;\n /** Gradient token painted as a ring around each avatar — the \"story\" ring.\n * Resolved through the gradient tokens, not the colour ones. */\n ringGradient?: TokenName;\n}"
392
392
  },
393
393
  {
394
394
  "name": "Banner",
@@ -651,7 +651,7 @@
651
651
  "valuePath",
652
652
  "tintPath"
653
653
  ],
654
- "propsSource": "export interface GaugeProps {\n value?: number;\n /** `$service:`/`$item.` binding → a live number (overrides `value`). */\n valuePath?: string;\n min?: number;\n max?: number;\n label?: string;\n kind?: \"radial\" | \"linear\";\n tint?: TokenName;\n /** Motion grammar (Batch 1, item 4) — tween the fill on value change instead of\n * snapping; gated by reduced motion. Mirror of ProgressBarProps.animated. */\n animated?: boolean;\n /** #1055 — `$service:`/`$item.` binding resolving to a tint TOKEN NAME (overrides `tint`). Binding-aware. */\n tintPath?: string;\n}"
654
+ "propsSource": "export interface GaugeProps {\n value?: number;\n /** `$service:`/`$item.` binding → a live number (overrides `value`). */\n valuePath?: string;\n min?: number;\n max?: number;\n label?: string;\n kind?: \"radial\" | \"linear\";\n tint?: TokenName;\n /** Concentric multi-ring gauge, drawn outer→inner. When present it overrides the\n * single `value`/`valuePath` radial. */\n rings?: GaugeRing[];\n /** Motion grammar (Batch 1, item 4) — tween the fill on value change instead of\n * snapping; gated by reduced motion. Mirror of ProgressBarProps.animated. */\n animated?: boolean;\n /** #1055 — `$service:`/`$item.` binding resolving to a tint TOKEN NAME (overrides `tint`). Binding-aware. */\n tintPath?: string;\n}"
655
655
  },
656
656
  {
657
657
  "name": "Rating",
@@ -887,6 +887,8 @@
887
887
  "Presentation": "export type Presentation =\n | \"push\"\n | \"sheet\"\n | \"replace\"\n | \"dismiss\"\n | \"back\"\n | \"full_screen\"\n | \"alert\"\n | \"snackbar\";",
888
888
  "FilterChip": "export interface FilterChip {\n id: string;\n label: string;\n leadingIcon?: IconRef;\n count?: number;\n}",
889
889
  "TabItem": "export interface TabItem {\n id: string;\n label: string;\n badge?: string;\n}",
890
+ "GaugeRing": "export interface GaugeRing {\n /** Fraction 0..1 for this ring. */\n value?: number;\n /** `$service:`/`$item.` binding → a live number (overrides `value`). */\n valuePath?: string;\n tint?: TokenName;\n}",
891
+ "WidgetTimeRef": "export interface WidgetTimeRef {\n /** Epoch seconds the style counts from/to. */\n at: number;\n /** SwiftUI `Text.DateStyle` / Android time style (default \"timer\"). */\n style?: \"timer\" | \"relative\" | \"date\" | \"time\" | \"offset\";\n}",
890
892
  "Border": "export interface Border {\n width: number;\n color: TokenRef;\n}"
891
893
  }
892
894
  }
@@ -167,7 +167,7 @@ So `border` nests an object and `boxShadow`/`backgroundGradient` nest strings. R
167
167
  element interface (printed below) rather than extrapolating from the level.
168
168
 
169
169
  - Modifier-level (`TokenRef` object): `modifiers.background`, `modifiers.shadow`, `modifiers.backgroundGradient`, `modifiers.appear`, `modifiers.material`, `modifiers.pressMotion`, `modifiers.border.color`.
170
- - Component-prop-level (bare `TokenName` string): `Card.background`, `Text.style`, `Text.color`, `Image.placeholder`, `Image.tint`, `Icon.tint`, `Toggle.trackOn`, `Toggle.trackOff`, `Toggle.thumb`, `Badge.token`, `Tag.token`, `ProgressBar.tint`, `ProgressBar.trackColor`, `ListItem.titleStyle`, `ListItem.subtitleStyle`, `ListItem.titleColor`, `ListItem.subtitleColor`, `ListItem.overlineColor`, `Slider.tint`, `ActivityIndicator.tint`, `Chip.token`, `Label.style`, `Label.color`, `Gauge.tint`, `Rating.color`, `Chart.color`, `DonutChart.color`, `VoiceNote.tint`, `Marquee.style`, `Marquee.color`, `Fab.tint`.
170
+ - Component-prop-level (bare `TokenName` string): `Card.background`, `Text.style`, `Text.color`, `Image.placeholder`, `Image.tint`, `Icon.tint`, `Toggle.trackOn`, `Toggle.trackOff`, `Toggle.thumb`, `Badge.token`, `Tag.token`, `ProgressBar.tint`, `ProgressBar.trackColor`, `AvatarStrip.ringGradient`, `ListItem.titleStyle`, `ListItem.subtitleStyle`, `ListItem.titleColor`, `ListItem.subtitleColor`, `ListItem.overlineColor`, `Slider.tint`, `ActivityIndicator.tint`, `Chip.token`, `Label.style`, `Label.color`, `Gauge.tint`, `Rating.color`, `Chart.color`, `DonutChart.color`, `VoiceNote.tint`, `Marquee.style`, `Marquee.color`, `Fab.tint`.
171
171
 
172
172
  There is **no `modifiers.color` and no `modifiers.tint`** — a `tint` is always a component
173
173
  prop. Of the two nested slots spelled `color`, `modifiers.border.color` is a `TokenRef`
@@ -366,6 +366,9 @@ export type TextProps = TextContent & {
366
366
  color?: TokenName;
367
367
  /** Tail-truncate after N lines (absent = unlimited). */
368
368
  maxLines?: number;
369
+ /** Lever D — a live time value (countdown/relative) the OS ticks with no refresh.
370
+ * When present it OVERRIDES `text`. Widget-safe render only. */
371
+ timeRef?: WidgetTimeRef;
369
372
  /** Render `text` as a constrained Markdown subset. */
370
373
  markdown?: boolean;
371
374
  /** Capability enrichments. */
@@ -915,6 +918,9 @@ export interface AvatarStripProps {
915
918
  caption?: string;
916
919
  /** Fired when tapping any avatar. */
917
920
  onTap?: Action;
921
+ /** Gradient token painted as a ring around each avatar — the "story" ring.
922
+ * Resolved through the gradient tokens, not the colour ones. */
923
+ ringGradient?: TokenName;
918
924
  }
919
925
  ```
920
926
 
@@ -1265,6 +1271,9 @@ export interface GaugeProps {
1265
1271
  label?: string;
1266
1272
  kind?: "radial" | "linear";
1267
1273
  tint?: TokenName;
1274
+ /** Concentric multi-ring gauge, drawn outer→inner. When present it overrides the
1275
+ * single `value`/`valuePath` radial. */
1276
+ rings?: GaugeRing[];
1268
1277
  /** Motion grammar (Batch 1, item 4) — tween the fill on value change instead of
1269
1278
  * snapping; gated by reduced motion. Mirror of ProgressBarProps.animated. */
1270
1279
  animated?: boolean;
@@ -1913,12 +1922,15 @@ export interface LogicBundleRef {
1913
1922
  }
1914
1923
  ```
1915
1924
 
1916
- ## Element shapes (list & tab items)
1925
+ ## Element shapes (list & tab items, and other typed prop objects)
1917
1926
 
1918
- A few props take an array of typed **element objects** rather than nested components:
1919
- `FilterChips.chips` is a `FilterChip[]`, and `SegmentedControl.options` / `Tabs.tabs` are a
1920
- `TabItem[]`. The prop blocks above name those arrays; here are the element interfaces themselves
1921
- (each item's own fields — `id` is what an `onChange` reports back).
1927
+ A few props take a typed **object** rather than nested components. Some are arrays of them:
1928
+ `FilterChips.chips` is a `FilterChip[]`, `SegmentedControl.options` / `Tabs.tabs` are a
1929
+ `TabItem[]`, and `Gauge.rings` is a `GaugeRing[]` (concentric rings, drawn outer→inner).
1930
+ One is a single object: `Text.timeRef` is a `WidgetTimeRef`, the widget-safe live clock —
1931
+ note its `at` is REQUIRED and is in epoch SECONDS. The prop blocks above name these types;
1932
+ here are the interfaces themselves (for the arrays, each item's own fields — `id` is what an
1933
+ `onChange` reports back).
1922
1934
 
1923
1935
  ```ts
1924
1936
  export interface FilterChip {
@@ -1933,6 +1945,21 @@ export interface TabItem {
1933
1945
  label: string;
1934
1946
  badge?: string;
1935
1947
  }
1948
+
1949
+ export interface GaugeRing {
1950
+ /** Fraction 0..1 for this ring. */
1951
+ value?: number;
1952
+ /** `$service:`/`$item.` binding → a live number (overrides `value`). */
1953
+ valuePath?: string;
1954
+ tint?: TokenName;
1955
+ }
1956
+
1957
+ export interface WidgetTimeRef {
1958
+ /** Epoch seconds the style counts from/to. */
1959
+ at: number;
1960
+ /** SwiftUI `Text.DateStyle` / Android time style (default "timer"). */
1961
+ style?: "timer" | "relative" | "date" | "time" | "offset";
1962
+ }
1936
1963
  ```
1937
1964
 
1938
1965
  ## Modifiers
@@ -184,7 +184,9 @@ images stay as `static.wixstatic.com` URLs in descriptors — do not vendor
184
184
 
185
185
  ### 4. CMS, verticals, forms, pages
186
186
 
187
- - **CMS the site already has** — `himi cms query`, then **adopt** with `wixId` in
187
+ - **CMS the site already has** — `himi cms query --all --site <msid>` (owner-scoped;
188
+ it is the only door that reveals a collection id you do not already know), then
189
+ **adopt** with `wixId` in
188
190
  `config.ts` (`himi docs cms-collections`). Read-only. Never seed or alter a
189
191
  collection you did not create. Create `himi_<appSlug>_*` only for storage the
190
192
  site does not have.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.838.0",
3
+ "version": "0.840.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": "9fd823cad2c263e2917b872794458e3c97e9ffc0040e182088a08fa5"
66
+ "falconPackageHash": "3cc7ad5aafc738871bc07293ce79f445509b78f308bb192a30fb8a3a"
67
67
  }