@wix/himalaya-cli 0.1480.0 → 0.1481.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.
Files changed (30) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/app-module.d.ts +1 -1
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +3 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/state/src/index.d.ts +47 -0
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/app-services-gate.d.ts +86 -0
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/bindings.d.ts +22 -0
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +10 -0
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/index.d.ts +1 -0
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +35 -0
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/validator.d.ts +87 -0
  10. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +148 -3
  11. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +34 -4
  12. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/state.mjs +95 -0
  13. package/dist/cli.mjs +1733 -1175
  14. package/dist/preview-assets.generated.bin +0 -0
  15. package/guides/component-reference.json +1 -1
  16. package/guides/component-reference.md +4 -0
  17. package/guides/sdk-reference.json +32 -2
  18. package/guides/tier-5-add-a-screen.md +50 -2
  19. package/package.json +2 -2
  20. package/templates/beauty-salon-owner/dev/index.ts +624 -59
  21. package/templates/community-club-owner/dev/index.ts +599 -57
  22. package/templates/events-meetups-owner/dev/index.ts +543 -52
  23. package/templates/gym-fitness-owner/dev/index.ts +649 -61
  24. package/templates/nonprofit-cause-owner/dev/index.ts +593 -56
  25. package/templates/owner-lite/dev/index.ts +698 -67
  26. package/templates/podcast-creator-owner/dev/index.ts +599 -57
  27. package/templates/portfolio-creative-owner/dev/index.ts +624 -59
  28. package/templates/restaurant-owner/dev/index.ts +649 -61
  29. package/templates/retail-store-owner/dev/index.ts +574 -55
  30. package/templates/yoga-studio-owner/dev/index.ts +593 -56
@@ -212,7 +212,7 @@ export interface DerivedAppMeta {
212
212
  platforms?: Record<string, boolean>;
213
213
  /** Forwarded from AppConfig.navigation.sidebar — RFC 0010 nav-modes sidebar structure. */
214
214
  sidebar?: import("@wix/himalaya/core").SidebarConfig;
215
- /** Forwarded from AppConfig.navigation.navLogicBundle — RFC 0010 (dynamic-chrome
215
+ /** Forwarded from AppConfig.app.logicBundle, or its alias AppConfig.navigation.navLogicBundle — RFC 0010 (dynamic-chrome
216
216
  * amendment, slots half): the app-level nav worker feeding the `*Path` bindings
217
217
  * on tabs / drawer rows / top-bar actions. Authored with a RELATIVE `url`
218
218
  * (`/v1/bundles/<name>`) and an empty `integrity`; `deriveNavigationConfig`
@@ -53,6 +53,9 @@ export interface ScreenDescriptor {
53
53
  /** RFC 0069 — the chat transcript scroll policy. Mirror of
54
54
  * ScreenDescriptor.transcript_scroll in core.proto. */
55
55
  transcriptScroll?: import("@wix/himalaya/core").TranscriptScroll;
56
+ /** The page's title for a host that shows it in its own navigation bar. Mirror of
57
+ * ScreenDescriptor.host_title in core.proto. */
58
+ hostTitle?: import("@wix/himalaya/core").HostTitle;
56
59
  }
57
60
  /** Tier 3/4 + embeddable WebView behavior. Mirror of WebViewConfig in core.proto
58
61
  * (RFC 0038). All fields optional; zero values reproduce legacy behavior. */
@@ -24,6 +24,22 @@ export interface ServiceDefinition<S> {
24
24
  */
25
25
  perVisit?: readonly (keyof S & string)[];
26
26
  }
27
+ /**
28
+ * App services — `defineService(name, { …, exports })`: what SCREEN-WORKER code may reach when this
29
+ * service is an app service (a `defineService` in the app's `app.logicBundle`). `app.dispatch` to an
30
+ * action not listed, and `app.read` of a path not under a listed state entry, reject `not_exported`.
31
+ * Each `state` entry is a top-level state key or a dotted path under one. Descriptor `$app:` bindings
32
+ * and descriptor-authored `app.*` actions are app-authored and NOT limited by it. Ignored in a screen
33
+ * bundle. The validator checks every entry exists. `A` narrows `actions` to the service's own names.
34
+ *
35
+ * Typed on `defineService`'s parameter, NOT on `ServiceDefinition<S>`: there it would be
36
+ * `ServiceExports<S, Record<string, unknown>>`, and a helper that spreads a `ServiceDefinition<S>`
37
+ * into `defineService` would fail to assign `string[]` to the narrowed action names.
38
+ */
39
+ export interface ServiceExports<S, A = Record<string, unknown>> {
40
+ actions?: readonly (keyof A & string)[];
41
+ state?: readonly ((keyof S & string) | `${keyof S & string}.${string}`)[];
42
+ }
27
43
  export interface ServiceHandle<S> {
28
44
  /** Snapshot of the current state. Cheap; safe to call from anywhere. */
29
45
  getState(): S;
@@ -249,7 +265,38 @@ export declare function encodeSubtree(component: Component): string;
249
265
  */
250
266
  export declare function defineService<S, A extends Record<string, (s: S, ...args: never[]) => S | undefined | Promise<S | undefined>>>(name: string, def: ServiceDefinition<S> & {
251
267
  actions?: A;
268
+ exports?: ServiceExports<S, A>;
252
269
  }): ServiceHandle<S> & {
253
270
  [K in keyof A]: (...args: Parameters<A[K]> extends [unknown, ...infer R] ? R : never[]) => Promise<S>;
254
271
  };
272
+ /** Why an app-service call could not run. Mirrors `APP_SERVICE_ERROR_CODES` in `@himalaya/core`. */
273
+ export type AppServiceErrorCode = "not_booted" | "unavailable" | "no_service" | "no_action" | "not_exported" | "undeclared";
274
+ /**
275
+ * The rejection `app.read` / `app.dispatch` produce: an `Error` named `AppServiceError` with a
276
+ * `code`. Never a null result — "nothing ran" always rejects. A plain `Error` rather than a
277
+ * subclass, because worker bundles target an engine floor that has no `class` syntax.
278
+ */
279
+ export type AppServiceError = Error & {
280
+ readonly code: AppServiceErrorCode;
281
+ };
282
+ /** Is this an `app.read` / `app.dispatch` rejection? Narrows to {@link AppServiceError}. */
283
+ export declare function isAppServiceError(err: unknown): err is AppServiceError;
284
+ /**
285
+ * The app's services, from a SCREEN worker. Requires the bundle to declare the
286
+ * `app_services` capability, and an app whose minimum binary ships app services.
287
+ */
288
+ export declare const app: {
289
+ /**
290
+ * A read-only, point-in-time JSON copy of an exported app-service path (`"jobs.active"`).
291
+ * Resolves `undefined` only for an exported path that is unset; rejects with an
292
+ * {@link AppServiceError} when it cannot answer.
293
+ */
294
+ read(path: string): Promise<unknown>;
295
+ /**
296
+ * Run an exported app-service action (`"jobs.start"`) and resolve with its result payload
297
+ * (never its state). Rejects with an {@link AppServiceError} when the call cannot run, so
298
+ * "it started" can never be confused with "nothing ran".
299
+ */
300
+ dispatch(action: string, args?: unknown): Promise<unknown>;
301
+ };
255
302
  export { validate, isValid as isValidValue, validators, validateAll, type ValidationFailure, type ValidationFailureRule, } from "@wix/himalaya/core/validation";
@@ -0,0 +1,86 @@
1
+ import type { LogicBundleRef } from "./schema.js";
2
+ /**
3
+ * The first binary version that ships RFC 0074's runtime (S3 iOS/macOS, S5 Android, S7 web).
4
+ *
5
+ * UNSET until the release that ships those arms sets it, so no app with shipped binaries
6
+ * qualifies yet — only a declared new app (`app.newApp`) does. Setting it is the one edit that
7
+ * opens the gate for apps whose rollout floor has been raised past it.
8
+ */
9
+ export declare const APP_SERVICES_MIN_BINARY: string | undefined;
10
+ /**
11
+ * The worker bridge functions `app.read` / `app.dispatch` call (RFC 0074 §4/§5/§9). Their names
12
+ * appear verbatim in any built bundle that uses them, which is how the validator (and the S2
13
+ * capability scan) detects a screen bundle reaching app services.
14
+ */
15
+ export declare const APP_SERVICES_BRIDGE_MARKERS: readonly ["__himalaya_app_read", "__himalaya_app_dispatch"];
16
+ /** Why an `app.read` / `app.dispatch` (or an `app.*` dispatch) could not run (RFC 0074 §4/§5). */
17
+ export declare const APP_SERVICE_ERROR_CODES: readonly ["not_booted", "unavailable", "no_service", "no_action", "not_exported", "undeclared"];
18
+ export type AppServiceErrorCode = (typeof APP_SERVICE_ERROR_CODES)[number];
19
+ /** `defineApp({ app })` — RFC 0074 §3. */
20
+ export interface AppServicesConfig {
21
+ /**
22
+ * The app-level worker bundle: every `defineService` in it is an app service. Canonical
23
+ * spelling of `navigation.navLogicBundle` (the RFC 0010 alias, still accepted); declaring
24
+ * both is an error. Bakes into the same wire field (`NavigationConfig.navLogicBundle`, 15).
25
+ */
26
+ logicBundle?: LogicBundleRef;
27
+ /**
28
+ * This app has never shipped a binary older than RFC 0074, so every binary it will ever
29
+ * serve supports app services (RFC 0074 §4: "a brand-new app qualifies from day one").
30
+ * Opens the §4 gate without a rollout floor. Authoring-only: it never reaches the wire.
31
+ * A rollout ring that declares a floor below {@link APP_SERVICES_MIN_BINARY} contradicts it
32
+ * and still fails.
33
+ */
34
+ newApp?: boolean;
35
+ }
36
+ /** The app-level bundle, whichever spelling declared it. */
37
+ export declare function appLogicBundleRef(config: unknown): LogicBundleRef | undefined;
38
+ /** The both-declared error (RFC 0074 §3.1), or null. */
39
+ export declare function appLogicBundleConflict(config: unknown): string | null;
40
+ /** The release floors the gate reads: `apps/<app>/rollout.yaml` rings (core/serve-control). */
41
+ export interface AppServicesRollout {
42
+ rings: readonly {
43
+ name?: string;
44
+ minBinaryVersion?: string;
45
+ }[];
46
+ }
47
+ export interface AppServicesVerdict {
48
+ ok: boolean;
49
+ /** The lowest ring floor, or null when some ring (or the absent rollout) is unbounded. */
50
+ floor: string | null;
51
+ /** One sentence naming the floor, the required version and how to qualify. */
52
+ reason: string;
53
+ }
54
+ /**
55
+ * Numeric `major.minor.patch` compare (`1.10.0` > `1.9.2`), read EXACTLY as serve-control's
56
+ * `semverGte` reads a ring floor (`parts()` in core/serve-control/src/rollout.ts): a leading digit is
57
+ * required and a fourth number is ignored, so `v1.7.0` is 0.0.0 to both. Reading it more leniently here
58
+ * would let the lint gate open on a floor the serve plane ignores. The one deliberate difference is
59
+ * stricter: a pre-release ranks below its release.
60
+ */
61
+ export declare function compareBinaryVersions(a: string, b: string): number;
62
+ /** The lowest `minBinaryVersion` across the rings; null if any ring has none (unbounded) or there are none. */
63
+ export declare function rolloutFloor(rollout: AppServicesRollout | null | undefined): string | null;
64
+ /**
65
+ * RFC 0074 §4 — may this app use app services (`$app:`, `app.*`, `app_services`, the bridges)?
66
+ *
67
+ * Yes when the app's minimum served binary — the LOWEST rollout ring floor, a ring with none
68
+ * meaning "unbounded" — is at or above {@link APP_SERVICES_MIN_BINARY}, or when the app declares
69
+ * `app.newApp` and no ring floor contradicts it. NEVER while the constant is unset — not even for a
70
+ * new app: until a binary ships the runtime (S3/S5/S7), nothing resolves `$app:` or routes `app.*`,
71
+ * so a green lint would ship bindings that never resolve and taps that do nothing.
72
+ */
73
+ export declare function appServicesAllowed(appConfig: unknown, rollout: AppServicesRollout | null | undefined, minBinary?: string | undefined): AppServicesVerdict;
74
+ /**
75
+ * `app.<svc>.<action>` — EXACTLY three segments (RFC 0074 §5). `app.analytics` or
76
+ * `app.a.b.c` are not app-service ids, so `app.` stays usable as a flat handler prefix
77
+ * outside the reserved form.
78
+ */
79
+ export declare function parseAppActionId(actionId: unknown): {
80
+ service: string;
81
+ action: string;
82
+ } | null;
83
+ /** Does this id use the reserved three-segment `app.` form? */
84
+ export declare function isReservedAppActionId(actionId: unknown): boolean;
85
+ /** Does this built bundle call `app.read` / `app.dispatch` (the bridge markers)? */
86
+ export declare function bundleUsesAppServiceBridges(js: string | undefined): boolean;
@@ -11,10 +11,32 @@ export type BindingSigil = (typeof BINDING_SIGILS)[number];
11
11
  * render verbatim becomes an unresolved-binding placeholder. `service`/`flag`/`item`
12
12
  * are long enough for that collision to be implausible; one letter is not, and the
13
13
  * token grammar is always `$t:<key>` anyway.
14
+ *
15
+ * RFC 0074's `$app:` is deliberately NOT in this list yet. Every renderer gates on it (web
16
+ * `isBinding`, RN), and none resolves `$app:` until the runtime arms land (S3/S5/S7): adding it here
17
+ * alone made web/RN blank a field's literal sibling while iOS/Android printed it. It joins with the
18
+ * resolvers, all surfaces at once. Until then `isAppBinding` / `parseAppBinding` below are the
19
+ * validator's grammar, and the per-app gate keeps `$app:` out of served content.
14
20
  */
15
21
  export declare const BINDING_SIGIL_RE: RegExp;
16
22
  /** Is this value a binding rather than a literal? */
17
23
  export declare function isBindingExpr(v: unknown): v is string;
24
+ /** RFC 0074 — the app-service sigil. `$app:<svc>.<path>`, resolved against the app-level worker. */
25
+ export declare const APP_BINDING_PREFIX = "$app:";
26
+ /**
27
+ * Split `$app:<svc>.<path>` into its service and path, or `null` when this is not one.
28
+ *
29
+ * Splits on the FIRST dot, as the runtimes do for `$service:`. A malformed expression (`$app:`,
30
+ * `$app:jobs`, `$app:jobs/active`, a space) returns null rather than a half-parsed result, so a
31
+ * caller cannot subscribe to an empty service or path. Leading/trailing whitespace is not
32
+ * trimmed: the renderers do not trim a bound value either.
33
+ */
34
+ export declare function parseAppBinding(v: unknown): {
35
+ service: string;
36
+ path: string;
37
+ } | null;
38
+ /** Is this an `$app:` expression (well formed or not)? */
39
+ export declare function isAppBinding(v: unknown): v is string;
18
40
  /** RFC 0054 — the localization sigil. `$t:<key>`, resolved against the app catalog. */
19
41
  export declare const TRANSLATION_PREFIX = "$t:";
20
42
  /** Key characters: dotted, lowercase-ish identifiers (`cart.add_to_cart`). */
@@ -2,6 +2,7 @@ import type { DesignTokens } from "./tokens.js";
2
2
  import type { PushRoute, PushPayloadAdapter } from "./push-routes.js";
3
3
  import type { PushScreenMapEntry } from "./wix-push-links.js";
4
4
  import type { NavigationConfig, SplashConfig } from "./schema.js";
5
+ import { type AppServicesConfig } from "./app-services-gate.js";
5
6
  import { type LocaleConfig } from "./locale.js";
6
7
  import { type DistributionConfig } from "./distribution.js";
7
8
  import type { CmsConfig } from "./cms.js";
@@ -428,6 +429,15 @@ export interface AppConfig {
428
429
  workerSubtreeScreens?: string[];
429
430
  /** RFC 0010 — navigation structure + deep-link mapping, served OTA. */
430
431
  navigation?: NavigationConfig;
432
+ /**
433
+ * RFC 0074 — app services. `app.logicBundle` is the app-level worker bundle: every
434
+ * `defineService` in it runs for the whole session, readable from any descriptor as
435
+ * `$app:<svc>.<path>` and callable as `app.<svc>.<action>`. The canonical spelling of
436
+ * `navigation.navLogicBundle` (still accepted as an alias); declaring both is an error. Both
437
+ * bake into the same wire field, so an old binary boots it as a plain nav worker — which is
438
+ * why `$app:` / `app.*` are gated per app on its release floor (see `appServicesAllowed`).
439
+ */
440
+ app?: AppServicesConfig;
431
441
  /**
432
442
  * RFC 0059 — how each surface picks its overlay from `tokens.json`'s `idiom` block.
433
443
  *
@@ -3,6 +3,7 @@ export * from "./stream-policy.js";
3
3
  export * from "./locale.js";
4
4
  export * from "./media.js";
5
5
  export * from "./define-app.js";
6
+ export * from "./app-services-gate.js";
6
7
  export * from "./distribution.js";
7
8
  export * from "./validator.js";
8
9
  export * from "./validation.js";
@@ -3002,6 +3002,9 @@ export interface TopBarConfig {
3002
3002
  visibility?: string;
3003
3003
  /** RFC 0066 §1 — bar fill token. iOS 26 keeps the system glass (amendment R12). */
3004
3004
  background?: TokenRef;
3005
+ /** RFC 0010 "Native top-bar search" — the screen's search, drawn by whoever draws its bar natively (an embed's host
3006
+ * today: iOS `himalayaEmbedSearch`, Android `ProvideHimalayaEmbedSearch`). Read per screen only. */
3007
+ searchable?: SearchableConfig;
3005
3008
  /** RFC 0066 amendment — the screen's logo; overrides `NavigationConfig.topBarLogo`. */
3006
3009
  logo?: TopBarLogo;
3007
3010
  /** RFC 0066 amendment — the title as a menu. */
@@ -3453,6 +3456,34 @@ export interface TranscriptScroll {
3453
3456
  /** Accessible name of the jump-to-latest control. Default "Jump to latest". */
3454
3457
  jumpLabel?: string;
3455
3458
  }
3459
+ /** RFC 0066 §2 as amended by RFC 0010 "Native top-bar search": `TopBarConfig.searchable`. Suggestions and scopes
3460
+ * (fields 6–11) come with the shell slot. The page's own search field hides with `hiddenPath: "$env:topBarSearch"`. */
3461
+ export interface SearchableConfig {
3462
+ placeholder?: string;
3463
+ /** `$service:` path to the current query. */
3464
+ valuePath?: string;
3465
+ /** `args.value` (string), after `debounceMs` of idle time. */
3466
+ onChange?: Action;
3467
+ /** `args.value`; a pending `onChange` fires first. */
3468
+ onSubmit?: Action;
3469
+ /** 0 or less = 250 ms. */
3470
+ debounceMs?: number;
3471
+ /** "automatic" (default, = "bar") | "bar" | "drawer" (a field under the bar) | "button" (a bar button that becomes the field). */
3472
+ placement?: "automatic" | "bar" | "drawer" | "button";
3473
+ /** `$service:` focus token (TextField.focusPath semantics). */
3474
+ focusPath?: string;
3475
+ /** The user ends the search without submitting; the query is cleared first. */
3476
+ onCancel?: Action;
3477
+ /** `$service:` bool: the search is busy. */
3478
+ loadingPath?: string;
3479
+ }
3480
+ /** `ScreenDescriptor.hostTitle`. Each value is a literal, a `$t:` key, or a `$service:` path. */
3481
+ export interface HostTitle {
3482
+ title: string;
3483
+ subtitle?: string;
3484
+ /** Id of the in-content component that draws the title and subtitle, which such a host's region does not draw. */
3485
+ replaces?: string;
3486
+ }
3456
3487
  export interface ScreenDescriptor {
3457
3488
  screenId: string;
3458
3489
  renderer: RendererKind;
@@ -3476,6 +3507,10 @@ export interface ScreenDescriptor {
3476
3507
  * when the reply outgrows it the host follows the tail. A drag pauses
3477
3508
  * following, and only then is a jump-to-latest control shown. */
3478
3509
  transcriptScroll?: TranscriptScroll;
3510
+ /** The page's title for a host that shows it in its own navigation bar (iOS `himalayaEmbedTitle`, Android
3511
+ * `ProvideHimalayaEmbedTitle`): it gets the title as soon as it has the descriptor, before the worker boots, and
3512
+ * `replaces` is not drawn. Every other host ignores it, so the in-content header stays. */
3513
+ hostTitle?: HostTitle;
3479
3514
  /** Present when `renderer` is `webview_native_bridge` or `webview_ds`. */
3480
3515
  url?: string;
3481
3516
  capabilitiesRequired?: string[];
@@ -56,6 +56,21 @@ export declare const screenDescriptorSchema: {
56
56
  };
57
57
  };
58
58
  };
59
+ readonly hostTitle: {
60
+ readonly type: "object";
61
+ readonly additionalProperties: false;
62
+ readonly properties: {
63
+ readonly title: {
64
+ readonly type: "string";
65
+ };
66
+ readonly subtitle: {
67
+ readonly type: "string";
68
+ };
69
+ readonly replaces: {
70
+ readonly type: "string";
71
+ };
72
+ };
73
+ };
59
74
  readonly url: {
60
75
  readonly type: "string";
61
76
  readonly format: "uri";
@@ -359,6 +374,9 @@ export declare const screenDescriptorSchema: {
359
374
  readonly style: {
360
375
  readonly type: "string";
361
376
  };
377
+ readonly searchable: {
378
+ readonly $ref: "#/$defs/searchableConfig";
379
+ };
362
380
  readonly items: {
363
381
  readonly type: "array";
364
382
  readonly items: {
@@ -394,6 +412,39 @@ export declare const screenDescriptorSchema: {
394
412
  };
395
413
  };
396
414
  };
415
+ readonly searchableConfig: {
416
+ readonly type: "object";
417
+ readonly additionalProperties: false;
418
+ readonly properties: {
419
+ readonly placeholder: {
420
+ readonly type: "string";
421
+ };
422
+ readonly valuePath: {
423
+ readonly type: "string";
424
+ };
425
+ readonly onChange: {
426
+ readonly $ref: "#/$defs/action";
427
+ };
428
+ readonly onSubmit: {
429
+ readonly $ref: "#/$defs/action";
430
+ };
431
+ readonly debounceMs: {
432
+ readonly type: "integer";
433
+ };
434
+ readonly placement: {
435
+ readonly type: "string";
436
+ };
437
+ readonly focusPath: {
438
+ readonly type: "string";
439
+ };
440
+ readonly onCancel: {
441
+ readonly $ref: "#/$defs/action";
442
+ };
443
+ readonly loadingPath: {
444
+ readonly type: "string";
445
+ };
446
+ };
447
+ };
397
448
  readonly toolbarItem: {
398
449
  readonly type: "object";
399
450
  readonly additionalProperties: false;
@@ -1655,6 +1706,9 @@ export declare const widgetSnapshotSchema: {
1655
1706
  readonly style: {
1656
1707
  readonly type: "string";
1657
1708
  };
1709
+ readonly searchable: {
1710
+ readonly $ref: "#/$defs/searchableConfig";
1711
+ };
1658
1712
  readonly items: {
1659
1713
  readonly type: "array";
1660
1714
  readonly items: {
@@ -1690,6 +1744,39 @@ export declare const widgetSnapshotSchema: {
1690
1744
  };
1691
1745
  };
1692
1746
  };
1747
+ readonly searchableConfig: {
1748
+ readonly type: "object";
1749
+ readonly additionalProperties: false;
1750
+ readonly properties: {
1751
+ readonly placeholder: {
1752
+ readonly type: "string";
1753
+ };
1754
+ readonly valuePath: {
1755
+ readonly type: "string";
1756
+ };
1757
+ readonly onChange: {
1758
+ readonly $ref: "#/$defs/action";
1759
+ };
1760
+ readonly onSubmit: {
1761
+ readonly $ref: "#/$defs/action";
1762
+ };
1763
+ readonly debounceMs: {
1764
+ readonly type: "integer";
1765
+ };
1766
+ readonly placement: {
1767
+ readonly type: "string";
1768
+ };
1769
+ readonly focusPath: {
1770
+ readonly type: "string";
1771
+ };
1772
+ readonly onCancel: {
1773
+ readonly $ref: "#/$defs/action";
1774
+ };
1775
+ readonly loadingPath: {
1776
+ readonly type: "string";
1777
+ };
1778
+ };
1779
+ };
1693
1780
  readonly toolbarItem: {
1694
1781
  readonly type: "object";
1695
1782
  readonly additionalProperties: false;
@@ -7125,6 +7125,110 @@ function activeMediaItem(props, index = props.startIndex ?? 0) {
7125
7125
  return props.items?.[index];
7126
7126
  }
7127
7127
 
7128
+ // ../../core/ts/src/app-services-gate.ts
7129
+ var APP_SERVICES_MIN_BINARY = void 0;
7130
+ var APP_SERVICES_BRIDGE_MARKERS = ["__himalaya_app_read", "__himalaya_app_dispatch"];
7131
+ var APP_SERVICE_ERROR_CODES = [
7132
+ "not_booted",
7133
+ "unavailable",
7134
+ "no_service",
7135
+ "no_action",
7136
+ "not_exported",
7137
+ "undeclared"
7138
+ ];
7139
+ function appLogicBundleRef(config) {
7140
+ const c = config;
7141
+ return c?.app?.logicBundle ?? c?.navigation?.navLogicBundle ?? void 0;
7142
+ }
7143
+ function appLogicBundleConflict(config) {
7144
+ const c = config;
7145
+ if (c?.app?.logicBundle !== void 0 && c?.navigation?.navLogicBundle !== void 0) {
7146
+ return "app.logicBundle and navigation.navLogicBundle are both declared. They are the same app-level bundle (navigation.navLogicBundle is the RFC 0010 alias), and an app has one. Keep app.logicBundle.";
7147
+ }
7148
+ return null;
7149
+ }
7150
+ function compareBinaryVersions(a, b) {
7151
+ const parts = (v) => {
7152
+ const m = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?/.exec(v.trim()) ?? [];
7153
+ return [Number(m[1] ?? 0), Number(m[2] ?? 0), Number(m[3] ?? 0)];
7154
+ };
7155
+ const x = parts(a);
7156
+ const y = parts(b);
7157
+ for (let i = 0; i < 3; i++) {
7158
+ if (x[i] !== y[i]) return x[i] < y[i] ? -1 : 1;
7159
+ }
7160
+ const pre = (v) => /^\d+(?:\.\d+){0,2}-/.test(v.trim());
7161
+ if (pre(a) !== pre(b)) return pre(a) ? -1 : 1;
7162
+ return 0;
7163
+ }
7164
+ function rolloutFloor(rollout) {
7165
+ const rings = rollout?.rings ?? [];
7166
+ if (rings.length === 0) return null;
7167
+ let floor = null;
7168
+ for (const ring of rings) {
7169
+ const v = typeof ring.minBinaryVersion === "string" ? ring.minBinaryVersion.trim() : "";
7170
+ if (!v) return null;
7171
+ if (floor === null || compareBinaryVersions(v, floor) < 0) floor = v;
7172
+ }
7173
+ return floor;
7174
+ }
7175
+ function appServicesAllowed(appConfig, rollout, minBinary = APP_SERVICES_MIN_BINARY) {
7176
+ const floor = rolloutFloor(rollout);
7177
+ const newApp = appConfig?.app?.newApp === true;
7178
+ const howTo = `raise every ring's minBinaryVersion in rollout.yaml to ${minBinary ?? "the first release that ships RFC 0074 (not cut yet)"}, or declare defineApp({ app: { newApp: true } }) if this app has never shipped an older binary`;
7179
+ if (newApp && minBinary === void 0) {
7180
+ return {
7181
+ ok: false,
7182
+ floor,
7183
+ reason: "app.newApp is declared, but no released binary ships app services yet (APP_SERVICES_MIN_BINARY is unset), so nothing would resolve $app: or route app.* \u2014 the gate opens for new apps in the release that ships the runtime"
7184
+ };
7185
+ }
7186
+ if (newApp) {
7187
+ const lowest = lowestDeclaredFloor(rollout);
7188
+ if (lowest !== null && compareBinaryVersions(lowest, minBinary) < 0) {
7189
+ return {
7190
+ ok: false,
7191
+ floor,
7192
+ reason: `app.newApp is declared, but a rollout ring still serves binaries from ${lowest}, below ${minBinary} (the first binary with app services) \u2014 raise that ring's minBinaryVersion, or drop newApp`
7193
+ };
7194
+ }
7195
+ return { ok: true, floor, reason: "app.newApp: every binary this app serves ships app services" };
7196
+ }
7197
+ if (minBinary === void 0) {
7198
+ return {
7199
+ ok: false,
7200
+ floor,
7201
+ reason: `no released binary ships app services yet (APP_SERVICES_MIN_BINARY is unset) and this app's minimum binary is ${floor ?? "unbounded"} \u2014 ${howTo}`
7202
+ };
7203
+ }
7204
+ if (floor === null) {
7205
+ return { ok: false, floor, reason: `this app's minimum binary is unbounded (a rollout ring has no minBinaryVersion, or there is no rollout.yaml) \u2014 ${howTo}` };
7206
+ }
7207
+ if (compareBinaryVersions(floor, minBinary) < 0) {
7208
+ return { ok: false, floor, reason: `this app's minimum binary is ${floor}, below ${minBinary} (the first binary with app services) \u2014 ${howTo}` };
7209
+ }
7210
+ return { ok: true, floor, reason: `minimum binary ${floor} ships app services (>= ${minBinary})` };
7211
+ }
7212
+ function lowestDeclaredFloor(rollout) {
7213
+ let lowest = null;
7214
+ for (const ring of rollout?.rings ?? []) {
7215
+ const v = typeof ring.minBinaryVersion === "string" ? ring.minBinaryVersion.trim() : "";
7216
+ if (v && (lowest === null || compareBinaryVersions(v, lowest) < 0)) lowest = v;
7217
+ }
7218
+ return lowest;
7219
+ }
7220
+ function parseAppActionId(actionId) {
7221
+ if (typeof actionId !== "string") return null;
7222
+ const m = /^app\.([A-Za-z0-9_-]+)\.([A-Za-z0-9_-]+)$/.exec(actionId);
7223
+ return m ? { service: m[1], action: m[2] } : null;
7224
+ }
7225
+ function isReservedAppActionId(actionId) {
7226
+ return parseAppActionId(actionId) !== null;
7227
+ }
7228
+ function bundleUsesAppServiceBridges(js) {
7229
+ return typeof js === "string" && APP_SERVICES_BRIDGE_MARKERS.some((m) => js.includes(m));
7230
+ }
7231
+
7128
7232
  // ../../core/ts/src/distribution.ts
7129
7233
  var DEFAULT_DISTRIBUTION = { core: "source", coreVersion: null };
7130
7234
  var SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
@@ -7716,6 +7820,8 @@ function validateConfigShape(config) {
7716
7820
  }
7717
7821
  validateLadderConfig(config);
7718
7822
  validateAuthGateScreen(config.auth);
7823
+ const appBundleConflict = appLogicBundleConflict(config);
7824
+ if (appBundleConflict) throw new Error(`defineApp: ${appBundleConflict}`);
7719
7825
  if (config.tier5Cap) {
7720
7826
  const c = config.tier5Cap;
7721
7827
  if (c.percentageOfActiveScreens < 0 || c.percentageOfActiveScreens > 100) {
@@ -8273,8 +8379,9 @@ function isComponentAllowedForFamily(key, family) {
8273
8379
 
8274
8380
  // ../../core/ts/src/bindings.ts
8275
8381
  var BINDING_SIGILS = ["service", "flag", "item", "t"];
8382
+ var COLON_SIGILS = /* @__PURE__ */ new Set(["t"]);
8276
8383
  var BINDING_SIGIL_RE = new RegExp(
8277
- `^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
8384
+ `^\\$(?:${BINDING_SIGILS.filter((s) => !COLON_SIGILS.has(s)).join("|")})\\b|^\\$(?:${[...COLON_SIGILS].join("|")}):`
8278
8385
  );
8279
8386
 
8280
8387
  // ../../core/ts/src/validator.ts
@@ -8317,6 +8424,16 @@ var screenDescriptorSchema = {
8317
8424
  jumpLabel: { type: "string" }
8318
8425
  }
8319
8426
  },
8427
+ // RFC 0010 "Native search in an embed host" companion: the page's title for a host that shows it in its own bar.
8428
+ hostTitle: {
8429
+ type: "object",
8430
+ additionalProperties: false,
8431
+ properties: {
8432
+ title: { type: "string" },
8433
+ subtitle: { type: "string" },
8434
+ replaces: { type: "string" }
8435
+ }
8436
+ },
8320
8437
  url: { type: "string", format: "uri" },
8321
8438
  capabilitiesRequired: {
8322
8439
  type: "array",
@@ -8522,8 +8639,9 @@ var screenDescriptorSchema = {
8522
8639
  leading: { type: "string" },
8523
8640
  style: { type: "string" },
8524
8641
  // RFC 0066 §1 (fields 4–8) + the "top-bar gap items" amendment (#4414, fields
8525
- // 10–14). Discriminators stay free strings (invariant 6). Field 9 (`searchable`)
8526
- // arrives with the RFC 0010 search implementation.
8642
+ // 10–14). Discriminators stay free strings (invariant 6). Field 9 is the RFC 0010
8643
+ // native search.
8644
+ searchable: { $ref: "#/$defs/searchableConfig" },
8527
8645
  items: { type: "array", items: { $ref: "#/$defs/toolbarItem" } },
8528
8646
  titleDisplay: { type: "string" },
8529
8647
  subtitle: { type: "string" },
@@ -8536,6 +8654,22 @@ var screenDescriptorSchema = {
8536
8654
  dirtyPath: { type: "string" }
8537
8655
  }
8538
8656
  },
8657
+ // RFC 0010 "Native top-bar search" (SearchableConfig fields 1–5, 12–15). `placement` stays a free string.
8658
+ searchableConfig: {
8659
+ type: "object",
8660
+ additionalProperties: false,
8661
+ properties: {
8662
+ placeholder: { type: "string" },
8663
+ valuePath: { type: "string" },
8664
+ onChange: { $ref: "#/$defs/action" },
8665
+ onSubmit: { $ref: "#/$defs/action" },
8666
+ debounceMs: { type: "integer" },
8667
+ placement: { type: "string" },
8668
+ focusPath: { type: "string" },
8669
+ onCancel: { $ref: "#/$defs/action" },
8670
+ loadingPath: { type: "string" }
8671
+ }
8672
+ },
8539
8673
  toolbarItem: {
8540
8674
  type: "object",
8541
8675
  additionalProperties: false,
@@ -14536,6 +14670,9 @@ function webViewEmbeddedAppFindings(screens) {
14536
14670
  export {
14537
14671
  ALL_ORIENTATIONS,
14538
14672
  APP_ID_PATTERN,
14673
+ APP_SERVICES_BRIDGE_MARKERS,
14674
+ APP_SERVICES_MIN_BINARY,
14675
+ APP_SERVICE_ERROR_CODES,
14539
14676
  AppRegistryClient,
14540
14677
  BASE44_BUILTIN_FIELDS,
14541
14678
  BASE44_FIELD_TYPES,
@@ -14614,6 +14751,9 @@ export {
14614
14751
  WORKER_SUBTREE_COMMON_ACTION_PATHS,
14615
14752
  WORKER_SUBTREE_SAFE_TYPE_RULES,
14616
14753
  activeMediaItem,
14754
+ appLogicBundleConflict,
14755
+ appLogicBundleRef,
14756
+ appServicesAllowed,
14617
14757
  assertSiteShellConfig,
14618
14758
  baselineMediaCapabilities,
14619
14759
  bucket,
@@ -14621,6 +14761,7 @@ export {
14621
14761
  buildPackageShareUrl,
14622
14762
  buildPlayerPreviewUrl,
14623
14763
  buildTokenRegistry,
14764
+ bundleUsesAppServiceBridges,
14624
14765
  buttonHitSlop,
14625
14766
  buttonVariant,
14626
14767
  canonicalJson,
@@ -14630,6 +14771,7 @@ export {
14630
14771
  chooseCandidate,
14631
14772
  cleanSiteMenuLabel,
14632
14773
  coerceSupportedLocale,
14774
+ compareBinaryVersions,
14633
14775
  dataSchemaScopeOf,
14634
14776
  decideSwitch,
14635
14777
  decodeLaunchFromQuery,
@@ -14655,6 +14797,7 @@ export {
14655
14797
  isComponentAllowedForFamily,
14656
14798
  isPlayerRequirements,
14657
14799
  isRTL,
14800
+ isReservedAppActionId,
14658
14801
  isSupportedLocale,
14659
14802
  isTargeted,
14660
14803
  isValid,
@@ -14669,6 +14812,7 @@ export {
14669
14812
  normalizeServeApp,
14670
14813
  normalizeSiteMenu,
14671
14814
  normalizeSiteOrigin,
14815
+ parseAppActionId,
14672
14816
  parseNumeric,
14673
14817
  physicalEntityName,
14674
14818
  primarySubtag,
@@ -14689,6 +14833,7 @@ export {
14689
14833
  resolveSurfaceNav,
14690
14834
  resolveSurfaceViewKey,
14691
14835
  resolveTabBarPresentation,
14836
+ rolloutFloor,
14692
14837
  screenDescriptorSchema,
14693
14838
  selectIdiomOverlay,
14694
14839
  shipsLocale,