@wix/himalaya-cli 0.1576.0 → 0.1578.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 (95) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/clipboard/src/index.d.ts +32 -1
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/haptic/src/index.d.ts +69 -5
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/sdk-types/src/capabilities.generated.d.ts +2 -2
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/ui/src/index.d.ts +19 -2
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +6 -0
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/loyalty/src/index.d.ts +64 -6
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/online-programs/src/index.d.ts +87 -0
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/audio-record.mjs +2 -2
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calendar.mjs +2 -2
  10. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calls.mjs +2 -2
  11. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/clipboard.mjs +58 -1
  12. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/contacts.mjs +2 -2
  13. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/haptic.mjs +73 -4
  14. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/location.mjs +2 -2
  15. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/motion.mjs +2 -2
  16. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/photos.mjs +2 -2
  17. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdk-types.mjs +2 -2
  18. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/tasks.mjs +2 -2
  19. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/ui.mjs +5 -0
  20. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-loyalty.mjs +15 -3
  21. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-online-programs.mjs +42 -0
  22. package/dist/cli.mjs +7245 -6889
  23. package/dist/preview-assets.generated.bin +0 -0
  24. package/fixtures/wix-canned.json +56 -3
  25. package/guides/one-app-section-mappings.md +1 -1
  26. package/guides/one-app-to-himi-app.md +50 -1
  27. package/guides/qa-builds.md +14 -6
  28. package/guides/sdk-reference.json +249 -17
  29. package/guides/web-page-sdk-reference.md +2 -2
  30. package/package.json +2 -2
  31. package/templates/beauty-salon/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  32. package/templates/beauty-salon/tier5-src/_shared/owner-load-error.ts +8 -0
  33. package/templates/beauty-salon-owner/dev/index.ts +52 -27
  34. package/templates/beauty-salon-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  35. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  36. package/templates/branded-lite/config.ts +7 -0
  37. package/templates/branded-lite/dev/index.ts +833 -0
  38. package/templates/branded-lite/himalaya.content.json +3 -0
  39. package/templates/branded-lite/l10n/en.json +4 -2
  40. package/templates/branded-lite/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  41. package/templates/branded-lite/tier5-src/_shared/owner-load-error.ts +8 -0
  42. package/templates/branded-lite/tier5-src/himi-branded-lite-member-programs/index.ts +658 -0
  43. package/templates/community-club/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  44. package/templates/community-club/tier5-src/_shared/owner-load-error.ts +8 -0
  45. package/templates/community-club-owner/dev/index.ts +52 -27
  46. package/templates/community-club-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  47. package/templates/community-club-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  48. package/templates/events-meetups/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  49. package/templates/events-meetups/tier5-src/_shared/owner-load-error.ts +8 -0
  50. package/templates/events-meetups-owner/dev/index.ts +52 -27
  51. package/templates/events-meetups-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  52. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  53. package/templates/gym-fitness/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  54. package/templates/gym-fitness/tier5-src/_shared/owner-load-error.ts +8 -0
  55. package/templates/gym-fitness-owner/dev/index.ts +52 -27
  56. package/templates/gym-fitness-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  57. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  58. package/templates/himi-chat/tier5-src/_shared/owner-load-error.ts +8 -0
  59. package/templates/nonprofit-cause/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  60. package/templates/nonprofit-cause/tier5-src/_shared/owner-load-error.ts +8 -0
  61. package/templates/nonprofit-cause-owner/dev/index.ts +52 -27
  62. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  63. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  64. package/templates/owner-lite/dev/index.ts +52 -27
  65. package/templates/owner-lite/tier5-src/_shared/owner-load-error.ts +8 -0
  66. package/templates/owner-lite/tier5-src/himi-owner-lite-post/index.ts +20 -8
  67. package/templates/podcast-creator/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  68. package/templates/podcast-creator/tier5-src/_shared/owner-load-error.ts +8 -0
  69. package/templates/podcast-creator-owner/dev/index.ts +52 -27
  70. package/templates/podcast-creator-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  71. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  72. package/templates/portfolio-creative/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  73. package/templates/portfolio-creative/tier5-src/_shared/owner-load-error.ts +8 -0
  74. package/templates/portfolio-creative-owner/dev/index.ts +52 -27
  75. package/templates/portfolio-creative-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  76. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  77. package/templates/restaurant/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  78. package/templates/restaurant/tier5-src/_shared/owner-load-error.ts +8 -0
  79. package/templates/restaurant-owner/dev/index.ts +52 -27
  80. package/templates/restaurant-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  81. package/templates/restaurant-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  82. package/templates/retail-store/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  83. package/templates/retail-store/tier5-src/_shared/owner-load-error.ts +8 -0
  84. package/templates/retail-store-owner/dev/index.ts +52 -27
  85. package/templates/retail-store-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  86. package/templates/retail-store-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
  87. package/templates/yoga-studio/config.ts +7 -0
  88. package/templates/yoga-studio/dev/index.ts +833 -0
  89. package/templates/yoga-studio/himalaya.content.json +3 -0
  90. package/templates/yoga-studio/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  91. package/templates/yoga-studio/tier5-src/_shared/owner-load-error.ts +8 -0
  92. package/templates/yoga-studio/tier5-src/himi-branded-lite-member-programs/index.ts +658 -0
  93. package/templates/yoga-studio-owner/dev/index.ts +52 -27
  94. package/templates/yoga-studio-owner/tier5-src/_shared/owner-load-error.ts +8 -0
  95. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-post/index.ts +20 -8
Binary file
@@ -528,6 +528,59 @@
528
528
  "total": 0
529
529
  }
530
530
  },
531
+ "POST /online-programs/v3/participants/query": {
532
+ "participants": [
533
+ {
534
+ "id": "part-0001",
535
+ "programId": "prog-0001",
536
+ "memberId": "mem-0001",
537
+ "enrollmentStatus": "JOINED",
538
+ "progressStatus": "IN_PROGRESS",
539
+ "createdDate": "2026-10-01T09:00:00.000Z",
540
+ "progress": {
541
+ "totalStepsCompleted": 12,
542
+ "totalStepsAvailable": 30,
543
+ "completionPercentage": 40
544
+ }
545
+ }
546
+ ],
547
+ "pagingMetadata": {
548
+ "count": 1,
549
+ "cursors": {
550
+ "next": null
551
+ }
552
+ }
553
+ },
554
+ "POST /online-programs/v3/participants/stats": {
555
+ "participationStats": [
556
+ {
557
+ "programId": "prog-0001",
558
+ "participantsCount": 18
559
+ },
560
+ {
561
+ "programId": "prog-0002",
562
+ "participantsCount": 7
563
+ }
564
+ ]
565
+ },
566
+ "GET /_api/program-categories-service/v3/categories": {
567
+ "categories": [
568
+ {
569
+ "id": "cat-0001",
570
+ "label": "Brewing",
571
+ "assignedTo": [
572
+ "prog-0001"
573
+ ]
574
+ },
575
+ {
576
+ "id": "cat-0002",
577
+ "label": "Roasting",
578
+ "assignedTo": [
579
+ "prog-0002"
580
+ ]
581
+ }
582
+ ]
583
+ },
531
584
  "POST /online-programs/v3/programs/query": {
532
585
  "programs": [
533
586
  {
@@ -954,17 +1007,17 @@
954
1007
  "total": 2
955
1008
  }
956
1009
  },
957
- "GET /loyalty/v1/program": {
1010
+ "GET /loyalty-programs/v1/program": {
958
1011
  "loyaltyProgram": {
959
1012
  "name": "Roastery Rewards",
960
1013
  "status": "ACTIVE",
961
1014
  "pointDefinition": {
962
1015
  "customName": "beans",
963
- "icon": "STAR"
1016
+ "icon": { "url": "fixture-star.svg" }
964
1017
  }
965
1018
  }
966
1019
  },
967
- "GET /loyalty/v1/rewards": {
1020
+ "GET /loyalty-rewards/v1/rewards": {
968
1021
  "rewards": [
969
1022
  {
970
1023
  "id": "rw-0001",
@@ -47,7 +47,7 @@ The **Himalaya implementation** cell is blank for every unassigned row. Notes on
47
47
 
48
48
  | Source sectionDefinitionId | Source viewer component | Himalaya implementation | Placement / reuse | Class | Settings, actions and gaps |
49
49
  | --- | --- | --- | --- | --- | --- |
50
- | `achievements_list_section` | `wix-one-app-achievements.SectionMemberChallengesScreen` | [Programs list/detail](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/apps/himi-branded-lite/dev/index.ts) + [programs worker](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/core/dev-server/tier5-bundles-src/himi-branded-lite-programs/index.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") | Existing base; adaptation needed | Partial | Reuse Online Programs catalog/enrolment logic; the program-detail worker explicitly identifies the legacy CHALLENGES app ID. Translate the section selection and source extraProps.limit=2; inline composition is still required. |
50
+ | `achievements_list_section` | `wix-one-app-achievements.SectionMemberChallengesScreen` | [Programs list/detail](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/apps/himi-branded-lite/dev/index.ts) + [programs worker](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/core/dev-server/tier5-bundles-src/himi-branded-lite-programs/index.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") | Existing base; member list added | Partial | `himi_member_programs` (worker `himi-branded-lite-member-programs`) is the member list: each card carries the signed-in member's standing from Participants v3 / Join Applications v3 (Joined, Program complete, Program ended, Pending request, Request approved, Invited, Participation suspended), a progress bar once started, the price before joining, the "All programs / Programs I joined" and category filters, cursor paging and pull-to-refresh; an ended program the member never joined is dropped. Still open: the 2-card section mode with "See all" (`extraProps.limit=2`, inline composition), join / cancel-request actions on the card itself (the card opens the program, which owns them), and Pricing Plans benefits ("Included in your plan"). |
51
51
  | `achievements_carousel_section` | `wix-one-app-achievements.MemberChallengesCarousel` | [Programs data/detail](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/core/dev-server/tier5-bundles-src/himi-branded-lite-programs/index.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") + [Core Carousel](https://github.com/wix-private/himalaya/blob/97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67/core/dev-server/src/builder.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") | Existing base; adaptation needed | Partial | Reuse the Programs feature and compose a carousel; preserve source extraProps.limit=5 and selected programs. No ready-made legacy Challenges carousel adapter is claimed. |
52
52
  | `achievements_participant_carousel_section` | `wix-one-app-achievements.ParticipantChallengesCarousel` | | | Empty | The public Programs catalog is not a member-participating-programs carousel. No verified consumer participant/progress list implementation was found. |
53
53
 
@@ -255,7 +255,10 @@ Apply these interpretation rules:
255
255
  bar that cannot be inspected is reported as unverified. The maintained `inviteAction`
256
256
  builder is recognized; its conditional ID and hidden binding must also appear in
257
257
  `topBarDefault.actions` with a configured `navLogicBundle`, even when the screen
258
- overrides its bar. A screen-only binding is not subscribed. Platform definitions establish
258
+ overrides its bar. Observer/listener badges require live count bindings with
259
+ matching action IDs/value paths in the nav default and an accessible label.
260
+ Static counts cannot stand in for unavailable source data. A screen-only
261
+ binding is not subscribed. Platform definitions establish
259
262
  a feature to account for; they do not alone prove visibility or access for every
260
263
  visitor or member. Resolve those rules separately. This check is specific to this
261
264
  migration workflow; it does not change the behavior of `himi validate`.
@@ -446,6 +449,52 @@ Apply these interpretation rules:
446
449
  shared. No invitation is created while migrating or just loading the screen.
447
450
  Source Invite produces an `interaction` coverage row requiring behavioral proof;
448
451
  unresolved transport or permissions remain gaps, never silent omission.
452
+ - **Preserve source badge behavior.** Collected button definitions retain
453
+ `badgeObserverId`, `badgeListenerId` and `showBadgeOnVisitorMode`. Keep the
454
+ counter's actual site/member/shopper scope and visitor policy; the source's
455
+ ordinary observer/listener button defaults to member-only observation when the
456
+ visitor flag is absent. Coverage inventories these counters as separate
457
+ behavioral obligations for raw, iOS and Android definitions. It also inventories
458
+ custom-component behavior: a custom component can own a counter internally,
459
+ without observer/listener fields. Do not infer a count badge for every custom
460
+ component. Inspect its implementation and retain unknown behavior as unresolved.
461
+
462
+ Use a live `badge: { kind: "count", valuePath: "$service:sourceBadges.count" }`
463
+ only after implementing the actual source counter. Preserve the source button
464
+ ID, or map its current `top-bar` coverage row to the target `screenId` and
465
+ `controlId` when renaming it. A sibling action's badge cannot satisfy that row;
466
+ changed source definitions invalidate the mapping. Declare the same action ID
467
+ and value path in `navigation.topBarDefault.actions` and any complete screen
468
+ override, with `navLogicBundle`. Action IDs must be unique in each bar; distinct
469
+ source counters need distinct target actions within each source platform. Both
470
+ actions need their own tap handler and accessible label. Do not supply a static
471
+ `value` as a fallback. The top-bar check establishes inspectable wiring, not
472
+ the counter's data source, availability, refresh, permission or accessibility
473
+ behavior. A configured worker URL alone proves none of those.
474
+
475
+ Keep a successful zero as `0` and unavailable as `null`; verify positive, zero,
476
+ failed/missing reads and source/site/account replacement, including a delayed
477
+ response from the previous identity. Verify badge visibility and screen-reader
478
+ output against the source. A persistent nav worker needs a supported refresh
479
+ path; a screen-only load, page-row count or foreground push receipt count is
480
+ insufficient. The source Member notification aggregate is MOBILE/UNSEEN, capped
481
+ at100. `countUnseenNotifications({ site: boundMetaSiteId })` reads that aggregate
482
+ through the source Member route. It requires the updated native core, rebuilt
483
+ consuming binaries and published SDK; default web and old binaries remain
484
+ unavailable for this reader. Never replace that refusal with zero.
485
+ Chat counts unread rooms, while legacy cart counters can include unsynced local
486
+ quantities; a different shopper's or headless cart's zero is not a substitute.
487
+ If the source reader/refresh path is unverified, leave that badge unresolved.
488
+ Changing a button definition or its visitor policy invalidates its previous
489
+ coverage mapping and requires new behavioral evidence. `coverage sync` replaces
490
+ changed or moved header rows for the same source button within its bar with
491
+ unmapped rows. A one-to-one change between an observer/listener badge and a
492
+ custom component is a replacement. A different button at an old index, or a
493
+ remaining custom behavior after its explicit badge is removed, cannot hide a
494
+ removal. Older ledger rows without stable `sourceButtonId` metadata require
495
+ explicit reconciliation when changed; syncing unchanged evidence adds that
496
+ metadata. Removing a button or behavior without a replacement still requires
497
+ explicit ledger reconciliation.
449
498
  - Verify the migrated app's native top bar, bottom tabs, back navigation and
450
499
  configured actions on the affected devices, including RTL. A web screenshot
451
500
  alone does not prove native navigation or control availability. Record any
@@ -1210,12 +1210,20 @@ himi dist --app <app> --platform android --aab --wait --target bo
1210
1210
  a bundle id saved in between is refused and stays changeable). The owner must already have the app
1211
1211
  in App Store Connect under that bundle id. The files
1212
1212
  and the key are never stored: the pool and the upload each fetch them again, the job keeps only
1213
- their hashes. The upload runs on the first status read after the pool validated the IPA; any read
1214
- the caller may make of the app moves it on, since the owner was proven when the build started (the
1215
- Containers server's reads carry a project token, not the owner's Wix login). So a caller keeps
1216
- reading the job until `customerAppStore.status` is `UPLOADED` or `FAILED`, not only until the job
1217
- is `SUCCESS`: a read that stops early, or gives up mid-upload, leaves the IPA waiting (a claimed
1218
- upload is retried by a read 15 minutes later).
1213
+ their hashes. The upload starts on its own once the pool reports the validated IPA: the pool's
1214
+ callback starts it in the background, and so does every list read of the app's builds (the owner
1215
+ card's poll) while it can be claimed, which also picks up one a stopped serve pod left. A status
1216
+ read still uploads too; any read the caller may make of the app moves it on, since the owner was
1217
+ proven when the build started (the Containers server's reads carry a project token, not the
1218
+ owner's Wix login). A caller reads the job until `customerAppStore.status` is `UPLOADED` or
1219
+ `FAILED` to learn how it ended; it no longer has to read for the upload to happen. An attempt that
1220
+ fails on a passing error (a 429 or 5xx from mobile-apps-containers-builder or Apple, a timeout, a
1221
+ download that broke off) goes back to `READY_FOR_UPLOAD` with `failedAttempts`, `retryAt` and
1222
+ `lastError`, and is tried again 1, 5 and 15 minutes later. The 4th failed attempt (an attempt
1223
+ whose 15-minute lease ran out counts as one) and any error the owner must fix (no app in App Store
1224
+ Connect, a refused key, a closed version) end `FAILED`, with `error`. When the IPA's 7-day link is
1225
+ within an hour of lapsing, the upload signs a fresh one from the stored bucket and key (the plane's
1226
+ `DIST_ARTIFACT_AWS_*` key pair; without it, the recorded link).
1219
1227
  Refusals, each with `code` equal to `error`: `store_build_ios_only`, `store_build_version_invalid`
1220
1228
  and `store_build_shell_unsupported` 400, `store_build_site_forbidden` 403, `store_id_missing`,
1221
1229
  `store_app_site_taken`, `release_predates_store_builds`, `apple_credentials_missing`,
@@ -1017,6 +1017,12 @@
1017
1017
  "source": "core/sdk/clipboard/src/index.ts",
1018
1018
  "description": "Tier-5 typed binding for the system clipboard.",
1019
1019
  "api": [
1020
+ {
1021
+ "name": "\"@himalaya/sdk-types\"",
1022
+ "kind": "reexport",
1023
+ "jsdoc": "",
1024
+ "decl": "export type { FileHandle } from \"@himalaya/sdk-types\";"
1025
+ },
1020
1026
  {
1021
1027
  "name": "writeText",
1022
1028
  "kind": "function",
@@ -1035,11 +1041,59 @@
1035
1041
  "jsdoc": "/** Whether the clipboard holds text — no content access, no iOS paste banner. On\n * web this can't be known without reading, so it returns true pessimistically;\n * treat it as a hint, not a guarantee. */",
1036
1042
  "decl": "export async function hasText(): Promise<boolean>;"
1037
1043
  },
1044
+ {
1045
+ "name": "MAX_IMAGE_BYTES",
1046
+ "kind": "const",
1047
+ "jsdoc": "/** Largest image writeImage accepts (20 MB). Hosts enforce it too. */",
1048
+ "decl": "export const MAX_IMAGE_BYTES = 20 * 1024 * 1024;"
1049
+ },
1050
+ {
1051
+ "name": "IMAGE_MIME_TYPES",
1052
+ "kind": "const",
1053
+ "jsdoc": "/** Image MIME types writeImage copies. HEIC is iOS/macOS only (Android and web\n * reject it `unsupported_type`); web accepts PNG only. The host sniffs the file's\n * bytes, so a handle is judged by its content, not its `mimeType` — the binding only\n * refuses up front a handle whose type is plainly not an image (e.g. application/pdf). */",
1054
+ "decl": "export const IMAGE_MIME_TYPES: readonly string[] = [\"image/png\", \"image/jpeg\", \"image/webp\", \"image/heic\"];"
1055
+ },
1056
+ {
1057
+ "name": "ClipboardImageErrorCode",
1058
+ "kind": "type",
1059
+ "jsdoc": "/** Why writeImage rejected. */",
1060
+ "decl": "export type ClipboardImageErrorCode = \"unsupported_type\" | \"too_large\" | \"not_allowed\" | \"not_found\" | \"unavailable\";"
1061
+ },
1062
+ {
1063
+ "name": "ClipboardImageError",
1064
+ "kind": "interface",
1065
+ "jsdoc": "/** A writeImage rejection: an `Error` named \"ClipboardImageError\" carrying a stable\n * `code`. (A plain Error, not a subclass — Tier-5 bundles target an engine without\n * class syntax.) Branch on `isClipboardImageError(e) && e.code === \"too_large\"`. */",
1066
+ "decl": "export interface ClipboardImageError extends Error {\n name: \"ClipboardImageError\";\n code: ClipboardImageErrorCode;\n}"
1067
+ },
1068
+ {
1069
+ "name": "clipboardImageError",
1070
+ "kind": "function",
1071
+ "jsdoc": "/** Build a coded writeImage rejection. */",
1072
+ "decl": "export function clipboardImageError(code: ClipboardImageErrorCode, message?: string): ClipboardImageError;"
1073
+ },
1074
+ {
1075
+ "name": "isClipboardImageError",
1076
+ "kind": "function",
1077
+ "jsdoc": "/** Whether `e` is a coded writeImage rejection. */",
1078
+ "decl": "export function isClipboardImageError(e: unknown): e is ClipboardImageError;"
1079
+ },
1080
+ {
1081
+ "name": "writeImage",
1082
+ "kind": "function",
1083
+ "jsdoc": "/** Copy an image file the worker already holds to the clipboard. Accepts a\n * `FileHandle` (from files / camera / photos) or its substrate `uri`. Rejects with a\n * `ClipboardImageError` (see `isClipboardImageError`) whose `code` is `unsupported_type` (not PNG/JPEG/WebP/HEIC, or\n * not supported on this host), `too_large` (over 20 MB), `not_allowed` (outside the\n * app's files substrate), `not_found`, or `unavailable` (no image clipboard here). */",
1084
+ "decl": "export async function writeImage(file: FileHandle | string): Promise<void>;"
1085
+ },
1086
+ {
1087
+ "name": "hasImage",
1088
+ "kind": "function",
1089
+ "jsdoc": "/** Whether the clipboard currently holds an image — without reading it (no iOS paste\n * banner). Web cannot know without a permission-gated read, so it answers false. */",
1090
+ "decl": "export async function hasImage(): Promise<boolean>;"
1091
+ },
1038
1092
  {
1039
1093
  "name": "version",
1040
1094
  "kind": "const",
1041
1095
  "jsdoc": "/** Capability version, for bundles that gate on min binary version. */",
1042
- "decl": "export const version = 1;"
1096
+ "decl": "export const version = 2;"
1043
1097
  }
1044
1098
  ]
1045
1099
  },
@@ -1550,20 +1604,68 @@
1550
1604
  {
1551
1605
  "name": "HapticPattern",
1552
1606
  "kind": "type",
1553
- "jsdoc": "/** Maps to a native impact/notification/selection generator. */",
1554
- "decl": "export type HapticPattern =\n | \"selection\"\n | \"light\"\n | \"medium\"\n | \"heavy\"\n | \"success\"\n | \"warning\"\n | \"error\";"
1607
+ "jsdoc": "/**\n * Maps to a native impact/notification/selection generator.\n *\n * - `rigid` / `soft` — iOS `UIImpactFeedbackGenerator.FeedbackStyle.rigid` / `.soft`.\n * Android: `rigid` is a short full-amplitude click (`VibrationEffect.EFFECT_CLICK`-like),\n * `soft` a longer low-amplitude tick (`PRIMITIVE_LOW_TICK`-like); on a device without\n * amplitude control both are plain one-shots of different length.\n */",
1608
+ "decl": "export type HapticPattern =\n | \"selection\"\n | \"light\"\n | \"medium\"\n | \"heavy\"\n | \"rigid\"\n | \"soft\"\n | \"success\"\n | \"warning\"\n | \"error\";"
1609
+ },
1610
+ {
1611
+ "name": "PlayOptions",
1612
+ "kind": "interface",
1613
+ "jsdoc": "",
1614
+ "decl": "export interface PlayOptions {\n /**\n * 0..1, clamped. Scales the strength of an IMPACT style (`light`, `medium`, `heavy`,\n * `rigid`, `soft`): iOS `impactOccurred(intensity:)`, Android amplitude where the\n * vibrator has amplitude control. Ignored for `selection` and the notification styles\n * (`success`, `warning`, `error`) — those have a fixed system strength — and on web.\n */\n intensity?: number;\n}"
1615
+ },
1616
+ {
1617
+ "name": "HapticStep",
1618
+ "kind": "interface",
1619
+ "jsdoc": "",
1620
+ "decl": "export interface HapticStep {\n pattern: HapticPattern;\n /** Milliseconds to wait BEFORE this step plays (≥ 0). */\n delayMs: number;\n /** Same meaning as {@link PlayOptions.intensity}. */\n intensity?: number;\n}"
1621
+ },
1622
+ {
1623
+ "name": "HapticResult",
1624
+ "kind": "type",
1625
+ "jsdoc": "/**\n * What a verb reports. `ok: false` is honest: `unavailable` (this surface has no haptic\n * hardware/API — web without `navigator.vibrate`, macOS) or `unsupported_binary` (the\n * native app predates the verb; nothing played, nothing broke).\n */",
1626
+ "decl": "export type HapticResult = { ok: true } | { ok: false; reason: \"unavailable\" | \"unsupported_binary\" };"
1627
+ },
1628
+ {
1629
+ "name": "MAX_SEQUENCE_STEPS",
1630
+ "kind": "const",
1631
+ "jsdoc": "/** Most steps one {@link sequence} may carry. */",
1632
+ "decl": "export const MAX_SEQUENCE_STEPS = 32;"
1633
+ },
1634
+ {
1635
+ "name": "MAX_DURATION_MS",
1636
+ "kind": "const",
1637
+ "jsdoc": "/** Longest a {@link sequence} or {@link vibrate} pattern may run, in milliseconds. */",
1638
+ "decl": "export const MAX_DURATION_MS = 10_000;"
1639
+ },
1640
+ {
1641
+ "name": "clampIntensity",
1642
+ "kind": "function",
1643
+ "jsdoc": "/** Clamp an intensity into 0..1; `undefined` / non-finite → `undefined` (system default). */",
1644
+ "decl": "export function clampIntensity(intensity: number | undefined): number | undefined;"
1555
1645
  },
1556
1646
  {
1557
1647
  "name": "play",
1558
1648
  "kind": "function",
1559
- "jsdoc": "/**\n * Play a haptic feedback pattern. Fire-and-forget; resolves once handed to the\n * platform. A no-op on web and for unknown patterns.\n */",
1560
- "decl": "export async function play(pattern: HapticPattern = \"light\"): Promise<void>;"
1649
+ "jsdoc": "/**\n * Play a haptic feedback pattern. Fire-and-forget; resolves once handed to the\n * platform. Unknown pattern names keep their historical behaviour (the platform's\n * default tap). `intensity` applies to impact styles only — see {@link PlayOptions}.\n */",
1650
+ "decl": "export async function play(pattern: HapticPattern = \"light\", options: PlayOptions = {}): Promise<HapticResult>;"
1651
+ },
1652
+ {
1653
+ "name": "sequence",
1654
+ "kind": "function",
1655
+ "jsdoc": "/**\n * Play `steps` in order, waiting each step's `delayMs` before it plays. Runs natively\n * as ONE bridge call (the timing does not depend on the worker), so a drum roll or a\n * countdown keeps its rhythm. A new `sequence` cancels one still running. Resolves once\n * the sequence has been scheduled.\n *\n * Rejects (`RangeError`) with more than {@link MAX_SEQUENCE_STEPS} steps, a negative or\n * non-finite delay, or delays totalling over {@link MAX_DURATION_MS}. An empty list just\n * cancels a running sequence.\n */",
1656
+ "decl": "export async function sequence(steps: HapticStep[]): Promise<HapticResult>;"
1657
+ },
1658
+ {
1659
+ "name": "vibrate",
1660
+ "kind": "function",
1661
+ "jsdoc": "/**\n * Raw vibration: `patternMs` alternates OFF / ON durations in milliseconds, starting\n * with an off gap (`[0, 200, 100, 400]` = buzz 200, pause 100, buzz 400).\n *\n * Android plays it as `VibrationEffect.createWaveform`. iOS approximates: with Core\n * Haptics each ON span is a continuous event (a transient one under 30 ms); without it,\n * each ON span becomes one `heavy` impact at its start. Web uses `navigator.vibrate`.\n *\n * Rejects (`RangeError`) on an empty list, a negative or non-finite duration, or a\n * pattern totalling over {@link MAX_DURATION_MS}.\n */",
1662
+ "decl": "export async function vibrate(patternMs: number[]): Promise<HapticResult>;"
1561
1663
  },
1562
1664
  {
1563
1665
  "name": "version",
1564
1666
  "kind": "const",
1565
1667
  "jsdoc": "/** Capability version, for bundles that gate on a min binary version. */",
1566
- "decl": "export const version = 1;"
1668
+ "decl": "export const version = 2;"
1567
1669
  }
1568
1670
  ]
1569
1671
  },
@@ -4867,7 +4969,13 @@
4867
4969
  "name": "AlertOptions",
4868
4970
  "kind": "interface",
4869
4971
  "jsdoc": "",
4870
- "decl": "export interface AlertOptions {\n /** Required — the native presenters drop alerts with an empty title. */\n title: string;\n message?: string;\n /** Confirm button label. Default \"Confirm\". */\n confirmLabel?: string;\n /** Cancel button label. OMIT for a single-button alert (no cancel button). */\n cancelLabel?: string;\n /** Style the confirm button with the `danger` token. */\n destructive?: boolean;\n}"
4972
+ "decl": "export interface AlertOptions {\n /** Required — the native presenters drop alerts with an empty title. */\n title: string;\n message?: string;\n /** Confirm button label. Default \"Confirm\". */\n confirmLabel?: string;\n /** Cancel button label. OMIT for a single-button alert (no cancel button). */\n cancelLabel?: string;\n /** Style the confirm button with the `danger` token. A destructive confirm is not the\n * affirmative button: its `confirm.actionId` still runs, but without gesture credit. */\n destructive?: boolean;\n /** The affirmative button's ACTION. Pressing it runs `actionId` as a NEW invocation\n * with user-gesture origin (so an app service's `app.<svc>.<action>` may return `_nav` and\n * navigate — the \"Ready — View\" alert). `label` replaces `confirmLabel`. The id is checked when\n * you set it, against this worker: a `capability.<id>.*` needs `<id>` allowed, an `app.*` from a\n * screen worker needs `app_services` and an exported action, a `tier5.*` must be this worker's\n * own; anything else rejects (`action_not_allowed`). Cancel and dismissal run nothing. */\n confirm?: AlertConfirm;\n}"
4973
+ },
4974
+ {
4975
+ "name": "AlertConfirm",
4976
+ "kind": "interface",
4977
+ "jsdoc": "/** The affirmative button of an `alert()`: its label and the action its press runs. */",
4978
+ "decl": "export interface AlertConfirm {\n label: string;\n actionId: string;\n /** Passed to the action (JSON types kept). */\n args?: Record<string, unknown>;\n}"
4871
4979
  },
4872
4980
  {
4873
4981
  "name": "AlertResult",
@@ -4878,7 +4986,7 @@
4878
4986
  {
4879
4987
  "name": "alert",
4880
4988
  "kind": "function",
4881
- "jsdoc": "/** Present a modal alert on the current screen. Resolves when the user picks a\n * button. Rejects with `ui_busy` while another alert() is pending, and with\n * `no_ui_host` if the app has no presenter attached. */",
4989
+ "jsdoc": "/** Present a modal alert on the current screen. Resolves when the user picks a\n * button. Rejects with `ui_busy` while another alert() is pending, and with\n * `no_ui_host` if the app has no presenter attached — or, from an APP SERVICE, when no\n * shell is in the foreground (re-show it from `onForeground`). An app service's alert shows on\n * whatever screen is open. */",
4882
4990
  "decl": "export async function alert(options: AlertOptions): Promise<AlertResult>;"
4883
4991
  },
4884
4992
  {
@@ -22898,44 +23006,70 @@
22898
23006
  "jsdoc": "/** The per-call header map for `opts`, or undefined when there is nothing to add — so\n * the no-options path calls the bridge with exactly the 3 arguments it always did. */",
22899
23007
  "decl": "export function wixCall<T>(method: string, path: string, body?: unknown, readOptions?: WixCallOptions): Promise<T>;"
22900
23008
  },
23009
+ {
23010
+ "name": "WixLoyaltyImage",
23011
+ "kind": "interface",
23012
+ "jsdoc": "",
23013
+ "decl": "export interface WixLoyaltyImage {\n id?: string;\n url?: string;\n height?: number;\n width?: number;\n altText?: string;\n filename?: string;\n}"
23014
+ },
23015
+ {
23016
+ "name": "WixLoyaltyRewardConfig",
23017
+ "kind": "interface",
23018
+ "jsdoc": "",
23019
+ "decl": "export interface WixLoyaltyRewardConfig {\n tierId?: string;\n costInPoints?: number;\n amount?: number;\n percentage?: number;\n}"
23020
+ },
22901
23021
  {
22902
23022
  "name": "WixLoyaltyProgram",
22903
23023
  "kind": "interface",
22904
23024
  "jsdoc": "",
22905
- "decl": "export interface WixLoyaltyProgram {\n id?: string;\n name?: string;\n /** ACTIVE | DRAFT | PAUSED */\n status?: string;\n pointDefinition?: { customName?: string; icon?: string };\n}"
23025
+ "decl": "export interface WixLoyaltyProgram {\n id?: string;\n name?: string;\n /** ACTIVE | DRAFT | PAUSED */\n status?: string;\n pointDefinition?: { customName?: string; icon?: WixLoyaltyImage };\n}"
22906
23026
  },
22907
23027
  {
22908
23028
  "name": "WixLoyaltyReward",
22909
23029
  "kind": "interface",
22910
23030
  "jsdoc": "",
22911
- "decl": "export interface WixLoyaltyReward {\n id: string;\n name?: string;\n type?: string;\n requiredPoints?: number;\n active?: boolean;\n}"
23031
+ "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?: { tierId?: string; costInPoints?: number; amount?: string }[] };\n couponReward?: {\n fixedAmount?: { configsByTier?: WixLoyaltyRewardConfig[] };\n percentage?: { configsByTier?: WixLoyaltyRewardConfig[] };\n freeShipping?: { configsByTier?: WixLoyaltyRewardConfig[] };\n };\n active?: boolean;\n}"
22912
23032
  },
22913
23033
  {
22914
23034
  "name": "WixLoyaltyTier",
22915
23035
  "kind": "interface",
22916
23036
  "jsdoc": "",
22917
- "decl": "export interface WixLoyaltyTier {\n /** REST returns `id` (proto `_id`). */\n id?: string;\n tierDefinition?: { name?: string; icon?: string };\n requiredPoints?: number;\n}"
23037
+ "decl": "export interface WixLoyaltyTier {\n /** REST returns `id` (proto `_id`). */\n id?: string;\n tierDefinition?: { name?: string; icon?: WixLoyaltyImage };\n requiredPoints?: number;\n}"
23038
+ },
23039
+ {
23040
+ "name": "WixLoyaltyEarningRule",
23041
+ "kind": "interface",
23042
+ "jsdoc": "",
23043
+ "decl": "export interface WixLoyaltyEarningRule {\n id?: string;\n title?: string;\n status?: string;\n triggerActivityType?: string;\n fixedAmount?: { configs?: { tierId?: string; points?: number }[] };\n conversionRate?: { field?: string; configs?: { tierId?: string; moneyAmount?: number; points?: number }[] };\n}"
22918
23044
  },
22919
23045
  {
22920
23046
  "name": "getLoyaltyProgram",
22921
23047
  "kind": "function",
22922
- "jsdoc": "/** GET /loyalty/v1/program → { loyaltyProgram }. */",
23048
+ "jsdoc": "/** GET /loyalty-programs/v1/program → { loyaltyProgram }. */",
22923
23049
  "decl": "export function getLoyaltyProgram(readOptions?: WixCallOptions): Promise<{ loyaltyProgram?: WixLoyaltyProgram; program?: WixLoyaltyProgram }>;",
22924
- "http": "GET /loyalty/v1/program"
23050
+ "http": "GET /loyalty-programs/v1/program"
22925
23051
  },
22926
23052
  {
22927
23053
  "name": "listLoyaltyRewards",
22928
23054
  "kind": "function",
22929
- "jsdoc": "/** GET /loyalty/v1/rewards → { rewards }. */",
23055
+ "jsdoc": "/** GET /loyalty-rewards/v1/rewards → { rewards }. */",
22930
23056
  "decl": "export function listLoyaltyRewards(readOptions?: WixCallOptions): Promise<{ rewards?: WixLoyaltyReward[] }>;",
22931
- "http": "GET /loyalty/v1/rewards"
23057
+ "http": "GET /loyalty-rewards/v1/rewards"
22932
23058
  },
22933
23059
  {
22934
23060
  "name": "listLoyaltyTiers",
22935
23061
  "kind": "function",
22936
- "jsdoc": "/** GET /loyalty/v1/tiers → { tiers }. The PUBLIC program tier ladder\n * (wix.loyalty.v1.tier) — NOT the private per-customer tiers-program dashboard. */",
23062
+ "jsdoc": "/** GET /loyalty-tiers/v1/tiers → { tiers }. The program tier ladder. */",
22937
23063
  "decl": "export function listLoyaltyTiers(readOptions?: WixCallOptions): Promise<{ tiers?: WixLoyaltyTier[] }>;",
22938
- "http": "GET /loyalty/v1/tiers"
23064
+ "http": "GET /loyalty-tiers/v1/tiers"
23065
+ },
23066
+ {
23067
+ "name": "listLoyaltyEarningRules",
23068
+ "kind": "function",
23069
+ "jsdoc": "/** Active and inactive earning rules in their raw REST shape; callers choose visibility.\n * @scope visitor\n */",
23070
+ "decl": "export function listLoyaltyEarningRules(readOptions?: WixCallOptions): Promise<{ earningRules?: WixLoyaltyEarningRule[] }>;",
23071
+ "http": "GET /_api/loyalty-earning-rules/v1/earning-rules/rules",
23072
+ "scope": "visitor"
22939
23073
  },
22940
23074
  {
22941
23075
  "name": "LoyaltyOverview",
@@ -24094,6 +24228,104 @@
24094
24228
  "kind": "function",
24095
24229
  "jsdoc": "/** The cashier handle to settle, or \"\" when no payable order is available. */",
24096
24230
  "decl": "export function payableIdOf(participant?: WixJoinedParticipant): string;"
24231
+ },
24232
+ {
24233
+ "name": "MEMBER_ENROLLMENT_STATUSES",
24234
+ "kind": "const",
24235
+ "jsdoc": "/** `Participant.enrollmentStatus` values the member list filters on. */",
24236
+ "decl": "export const MEMBER_ENROLLMENT_STATUSES = {\n joined: \"JOINED\",\n suspended: \"SUSPENDED\",\n unknown: \"UNKNOWN_ENROLLMENT_STATUS\",\n} as const;"
24237
+ },
24238
+ {
24239
+ "name": "MEMBER_FINISHED_PROGRESS_STATUSES",
24240
+ "kind": "const",
24241
+ "jsdoc": "/** `Participant.progressStatus` values that still count as a membership once the enrollment is over. */",
24242
+ "decl": "export const MEMBER_FINISHED_PROGRESS_STATUSES = [\"COMPLETED\", \"FAILED\"] as const;"
24243
+ },
24244
+ {
24245
+ "name": "WixMemberParticipantsQuery",
24246
+ "kind": "interface",
24247
+ "jsdoc": "",
24248
+ "decl": "export interface WixMemberParticipantsQuery {\n /** The signed-in member's id (`getMyMember().member.id`). Required: without it the query is the roster of everyone. */\n memberId: string;\n /** The `pagingMetadata.cursors.next` of the previous page; omit for the first page. */\n cursor?: string;\n /** Page size, default 100 (the upstream page cap for this query). */\n limit?: number;\n}"
24249
+ },
24250
+ {
24251
+ "name": "WixQueryMemberParticipantsResponse",
24252
+ "kind": "interface",
24253
+ "jsdoc": "",
24254
+ "decl": "export interface WixQueryMemberParticipantsResponse extends WixQueryParticipantsResponse {\n pagingMetadata?: WixQueryParticipantsResponse[\"pagingMetadata\"] & { cursors?: { next?: string | null } };\n}"
24255
+ },
24256
+ {
24257
+ "name": "queryMemberParticipants",
24258
+ "kind": "function",
24259
+ "jsdoc": "/**\n * POST /online-programs/v3/participants/query — the MEMBER'S participations, cursor-paged, with\n * progress. Joined and suspended enrollments, plus completed/failed ones whose enrollment has\n * ended, so a finished program still shows its outcome; left, removed and auto-removed\n * memberships are excluded. The query language has no `programId: {$in}` on this\n * endpoint, so callers match memberships to displayed programs locally.\n *\n * @scope member — requires the signed-in site member; `memberId` must be that member's own id\n * (`getMyMember().member.id`). An empty `participants` list means the member has no such\n * membership, never that the read failed: a failure rejects.\n */",
24260
+ "decl": "export function queryMemberParticipants(opts: WixMemberParticipantsQuery): Promise<WixQueryMemberParticipantsResponse>;",
24261
+ "http": "POST /online-programs/v3/participants/query",
24262
+ "scope": "member"
24263
+ },
24264
+ {
24265
+ "name": "WixProgramParticipationStats",
24266
+ "kind": "interface",
24267
+ "jsdoc": "",
24268
+ "decl": "export interface WixProgramParticipationStats {\n programId?: string;\n participantsCount?: number;\n autoRemovedCount?: number;\n}"
24269
+ },
24270
+ {
24271
+ "name": "WixGetParticipationStatsResponse",
24272
+ "kind": "interface",
24273
+ "jsdoc": "",
24274
+ "decl": "export interface WixGetParticipationStatsResponse { participationStats?: WixProgramParticipationStats[] }"
24275
+ },
24276
+ {
24277
+ "name": "getParticipationStats",
24278
+ "kind": "function",
24279
+ "jsdoc": "/** POST /online-programs/v3/participants/stats — participant counts for a batch of programs (one call per page).\n * `programIds` must be non-empty (an empty batch returns `{ participationStats: [] }` without a call);\n * a program missing from the answer has no count, not zero.\n * @scope visitor — counts are public; an anonymous visitor session is enough. */",
24280
+ "decl": "export function getParticipationStats(programIds: string[]): Promise<WixGetParticipationStatsResponse>;",
24281
+ "http": "POST /online-programs/v3/participants/stats",
24282
+ "scope": "visitor"
24283
+ },
24284
+ {
24285
+ "name": "WixJoinApplicationStatus",
24286
+ "kind": "type",
24287
+ "jsdoc": "/** `JoinApplication.status` — the member's standing BEFORE a participant exists (a private or paid program). */",
24288
+ "decl": "export type WixJoinApplicationStatus =\n | \"INVITED\"\n | \"APPROVAL_PENDING\"\n | \"APPROVED\"\n | \"PAYMENT_PENDING\"\n | \"SUSPENDED\"\n | \"DECLINED\"\n | \"CANCELLED\"\n | string;"
24289
+ },
24290
+ {
24291
+ "name": "WixJoinApplication",
24292
+ "kind": "interface",
24293
+ "jsdoc": "",
24294
+ "decl": "export interface WixJoinApplication {\n id?: string;\n programId?: string;\n memberId?: string;\n status?: WixJoinApplicationStatus;\n paymentStatus?: string;\n /** Set once the application became a participant. */\n participantId?: string;\n createdDate?: string;\n updatedDate?: string;\n}"
24295
+ },
24296
+ {
24297
+ "name": "WixGetCurrentJoinApplicationResponse",
24298
+ "kind": "interface",
24299
+ "jsdoc": "",
24300
+ "decl": "export interface WixGetCurrentJoinApplicationResponse { joinApplication?: WixJoinApplication }"
24301
+ },
24302
+ {
24303
+ "name": "getCurrentJoinApplication",
24304
+ "kind": "function",
24305
+ "jsdoc": "/** GET /online-programs/participants/v3/join-applications/current/{programId} — the signed-in member's\n * own application to ONE program, or none. Used per card only where an application can exist\n * (a private or a priced program the member has not joined). An answer with no `joinApplication`\n * means the member never applied.\n * @scope member — requires the signed-in site member; a visitor session has no application to read. */",
24306
+ "decl": "export function getCurrentJoinApplication(programId: string): Promise<WixGetCurrentJoinApplicationResponse>;",
24307
+ "http": "GET /online-programs/participants/v3/join-applications/current/{…}",
24308
+ "scope": "member"
24309
+ },
24310
+ {
24311
+ "name": "WixProgramCategory",
24312
+ "kind": "interface",
24313
+ "jsdoc": "",
24314
+ "decl": "export interface WixProgramCategory {\n id?: string;\n label?: string;\n /** Program ids the category is assigned to. */\n assignedTo?: string[];\n}"
24315
+ },
24316
+ {
24317
+ "name": "WixListProgramCategoriesResponse",
24318
+ "kind": "interface",
24319
+ "jsdoc": "",
24320
+ "decl": "export interface WixListProgramCategoriesResponse { categories?: WixProgramCategory[] }"
24321
+ },
24322
+ {
24323
+ "name": "listProgramCategories",
24324
+ "kind": "function",
24325
+ "jsdoc": "/** GET /_api/program-categories-service/v3/categories — every program category of the site (the\n * category filter's options). `/_api/…` paths ride the same bridge as the public ones (forms,\n * bookings-v2 and ecom already do). An empty `categories` list means the site has none.\n * @scope member — the One App member programs list calls it with the member's identity. NOT verified\n * live here: codegen/wix/auto/lock.json lists only the APP identity (ONLINE_PROGRAMS.CATEGORY_READ), so a\n * visitor or member token can get 403. A caller must treat a rejection as \"no category filter\", never\n * as an error screen. */",
24326
+ "decl": "export function listProgramCategories(): Promise<WixListProgramCategoriesResponse>;",
24327
+ "http": "GET /_api/program-categories-service/v3/categories",
24328
+ "scope": "member"
24097
24329
  }
24098
24330
  ]
24099
24331
  },
@@ -22,12 +22,12 @@ the SDK sources, so it matches the shipped SDKs.
22
22
  - [`calendar`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fcalendar?format=md) — Device calendar. 6 methods.
23
23
  - [`calls`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fcalls?format=md) — Real-time 1:1 audio calls (Stage 1). 16 methods.
24
24
  - [`camera`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fcamera?format=md) — Camera capability. 4 methods · returns FileHandles.
25
- - [`clipboard`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fclipboard?format=md) — System clipboard. 3 methods.
25
+ - [`clipboard`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fclipboard?format=md) — System clipboard. 5 methods.
26
26
  - [`contacts`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fcontacts?format=md) — Device address book. 4 methods.
27
27
  - [`file_picker`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Ffile_picker?format=md) — User-mediated document access OUTSIDE the app sandbox. 3 methods · returns FileHandles.
28
28
  - [`files`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Ffiles?format=md) — App-scoped document storage. 6 methods · returns FileHandles.
29
29
  - [`godot`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fgodot?format=md) — A Godot game surface. 3 methods · not in Brandy.
30
- - [`haptic`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fhaptic?format=md) — Haptic capability. 1 method.
30
+ - [`haptic`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fhaptic?format=md) — Haptic capability. 3 methods.
31
31
  - [`health`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fhealth?format=md) — Platform HEALTH store. 5 methods.
32
32
  - [`himi_apps`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fhimi_apps?format=md) — Cross-app open / host queries. 4 methods · not in Brandy.
33
33
  - [`iap`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fiap?format=md) — In-app-purchase capability. 9 methods.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1576.0",
3
+ "version": "0.1578.0",
4
4
  "type": "module",
5
5
  "description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
6
6
  "keywords": [
@@ -71,5 +71,5 @@
71
71
  "artifactId": "himalaya-cli"
72
72
  }
73
73
  },
74
- "falconPackageHash": "b3770b71ba8570708ab97e43a149a8ee2880f9fea27a618d80902862"
74
+ "falconPackageHash": "0a206d4a3d13e9f1302334dcaeb9d70a507f8c916a8ac190fe8bfd8e"
75
75
  }
@@ -119,6 +119,7 @@ export const HOSTED_SCREEN_VERTICALS: Readonly<Record<string, readonly BrandedLi
119
119
  himi_portfolio: ["portfolio"],
120
120
  himi_portfolio_project: ["portfolio"],
121
121
  himi_programs: ["programs"],
122
+ himi_member_programs: ["programs"],
122
123
  himi_reservations: ["reservations"],
123
124
  himi_reserve: ["restaurants"],
124
125
  himi_review: ["reviews"],
@@ -194,6 +194,14 @@ export function isTransportFailure(e: unknown): boolean {
194
194
  return TRANSPORT.some((re) => re.test(msg));
195
195
  }
196
196
 
197
+ /** A failed READ says nothing about the record's existence when Wix is
198
+ * unreachable, overloaded or failing. Unlike the legacy bridge predicate this
199
+ * is independent of preview mode; a live preview's gateway failure is one too. */
200
+ export function readWasUnreachable(e: unknown): boolean {
201
+ const msg = String((e as Error)?.message ?? e ?? "");
202
+ return isTransportFailure(e) || /HTTP (?:408|429|5\d{2})\b/.test(msg);
203
+ }
204
+
197
205
  /** Transport failures that happen while CONNECTING — no connection, no route, no such host,
198
206
  * connection refused — so the request provably never left the device. Every other
199
207
  * transport failure (a timeout, a reset, a bad or truncated response, a browser's fetch