@wix/himalaya-cli 0.853.0 → 0.854.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 (48) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-analytics.mjs +3 -3
  2. package/dist/cli.mjs +1 -0
  3. package/guides/sdk-reference.json +4 -2
  4. package/package.json +2 -2
  5. package/templates/beauty-salon-owner/config.ts +34 -4
  6. package/templates/beauty-salon-owner/dev/index.ts +0 -94
  7. package/templates/beauty-salon-owner/tier5-src/_shared/aria-chat.ts +73 -4
  8. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-aria/index.ts +7 -0
  9. package/templates/community-club-owner/config.ts +34 -4
  10. package/templates/community-club-owner/dev/index.ts +0 -94
  11. package/templates/community-club-owner/tier5-src/_shared/aria-chat.ts +73 -4
  12. package/templates/community-club-owner/tier5-src/himi-owner-lite-aria/index.ts +7 -0
  13. package/templates/events-meetups-owner/config.ts +34 -4
  14. package/templates/events-meetups-owner/dev/index.ts +0 -94
  15. package/templates/events-meetups-owner/tier5-src/_shared/aria-chat.ts +73 -4
  16. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-aria/index.ts +7 -0
  17. package/templates/gym-fitness-owner/config.ts +34 -4
  18. package/templates/gym-fitness-owner/dev/index.ts +0 -94
  19. package/templates/gym-fitness-owner/tier5-src/_shared/aria-chat.ts +73 -4
  20. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-aria/index.ts +7 -0
  21. package/templates/nonprofit-cause-owner/config.ts +34 -4
  22. package/templates/nonprofit-cause-owner/dev/index.ts +0 -94
  23. package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-chat.ts +73 -4
  24. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-aria/index.ts +7 -0
  25. package/templates/owner-lite/config.ts +34 -4
  26. package/templates/owner-lite/dev/index.ts +0 -94
  27. package/templates/owner-lite/tier5-src/_shared/aria-chat.ts +73 -4
  28. package/templates/owner-lite/tier5-src/himi-owner-lite-aria/index.ts +7 -0
  29. package/templates/podcast-creator-owner/config.ts +34 -4
  30. package/templates/podcast-creator-owner/dev/index.ts +0 -94
  31. package/templates/podcast-creator-owner/tier5-src/_shared/aria-chat.ts +73 -4
  32. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-aria/index.ts +7 -0
  33. package/templates/portfolio-creative-owner/config.ts +34 -4
  34. package/templates/portfolio-creative-owner/dev/index.ts +0 -94
  35. package/templates/portfolio-creative-owner/tier5-src/_shared/aria-chat.ts +73 -4
  36. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-aria/index.ts +7 -0
  37. package/templates/restaurant-owner/config.ts +34 -4
  38. package/templates/restaurant-owner/dev/index.ts +0 -94
  39. package/templates/restaurant-owner/tier5-src/_shared/aria-chat.ts +73 -4
  40. package/templates/restaurant-owner/tier5-src/himi-owner-lite-aria/index.ts +7 -0
  41. package/templates/retail-store-owner/config.ts +34 -4
  42. package/templates/retail-store-owner/dev/index.ts +0 -94
  43. package/templates/retail-store-owner/tier5-src/_shared/aria-chat.ts +73 -4
  44. package/templates/retail-store-owner/tier5-src/himi-owner-lite-aria/index.ts +7 -0
  45. package/templates/yoga-studio-owner/config.ts +34 -4
  46. package/templates/yoga-studio-owner/dev/index.ts +0 -94
  47. package/templates/yoga-studio-owner/tier5-src/_shared/aria-chat.ts +73 -4
  48. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-aria/index.ts +7 -0
@@ -119,16 +119,16 @@ function getSiteAnalytics(opts) {
119
119
  ];
120
120
  return wixCall(
121
121
  "GET",
122
- `https://www.wixapis.com/analytics/v2/site-analytics/data?${params.join("&")}`
122
+ `/analytics/v2/site-analytics/data?${params.join("&")}`
123
123
  );
124
124
  }
125
125
  function getSiteTimeZone() {
126
126
  return wixCall(
127
127
  "GET",
128
- "https://www.wixapis.com/site-properties/v4/properties?fields.paths=timeZone"
128
+ "/site-properties/v4/properties?fields.paths=timeZone"
129
129
  ).then((r) => r?.properties?.timeZone);
130
130
  }
131
- var SEMANTIC_BASE = "https://www.wixapis.com/analytics/semantic-model/v3/semantic-models";
131
+ var SEMANTIC_BASE = "/analytics/semantic-model/v3/semantic-models";
132
132
  var MAX_QUERY_FIELDS = 60;
133
133
  function normalizeField(raw) {
134
134
  const f = raw ?? {};
package/dist/cli.mjs CHANGED
@@ -4729,6 +4729,7 @@ function resolveTranslation(value, catalog, sourceCatalog) {
4729
4729
  var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
4730
4730
  var init_bindings = __esm({
4731
4731
  "../../core/ts/src/bindings.ts"() {
4732
+ "use strict";
4732
4733
  BINDING_SIGILS = ["service", "flag", "item", "t"];
4733
4734
  BINDING_SIGIL_RE = new RegExp(
4734
4735
  `^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
@@ -3871,13 +3871,15 @@
3871
3871
  "name": "getSiteAnalytics",
3872
3872
  "kind": "function",
3873
3873
  "jsdoc": "/**\n * Site analytics for `measurementTypes` over `[startDate, endDate)`.\n *\n * Options object rather than positional parameters: `timeZone` is the third thing\n * that materially changes the result and the list was already at its readable\n * limit.\n */",
3874
- "decl": "export function getSiteAnalytics(opts: GetSiteAnalyticsOptions): Promise<WixAnalyticsResponse>;"
3874
+ "decl": "export function getSiteAnalytics(opts: GetSiteAnalyticsOptions): Promise<WixAnalyticsResponse>;",
3875
+ "http": "GET /analytics/v2/site-analytics/data?{…}"
3875
3876
  },
3876
3877
  {
3877
3878
  "name": "getSiteTimeZone",
3878
3879
  "kind": "function",
3879
3880
  "jsdoc": "/**\n * The site's IANA time zone, for `timeZone` / `interval.timezone`.\n *\n * This is a Site Properties call, not an analytics one, and strictly belongs to a\n * `@himalaya/wix-site-properties` domain that does not exist. It lives here\n * because every analytics query needs it and the alternative is each caller\n * hand-rolling the same raw `wixApi` request. A deliberate trade-off, recorded so\n * the next reader does not take it for an accident.\n */",
3880
- "decl": "export function getSiteTimeZone(): Promise<string | undefined>;"
3881
+ "decl": "export function getSiteTimeZone(): Promise<string | undefined>;",
3882
+ "http": "GET /site-properties/v4/properties?fields.paths=timeZone"
3881
3883
  },
3882
3884
  {
3883
3885
  "name": "SemanticFieldType",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.853.0",
3
+ "version": "0.854.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": "5d79108b6439f6c7de6012f0ddff4f0777d116aea3ca7ac25f2c84c7"
66
+ "falconPackageHash": "5adfd6ba9551cfc305ff63e7d506c64fe0b3874c74bd3561fe465869"
67
67
  }
@@ -103,15 +103,15 @@ export default defineApp({
103
103
  "paramKeys": [
104
104
  "conversationId"
105
105
  ],
106
- "parentScreenId": "himi_owner_lite_manage",
107
- "tabId": "manage"
106
+ "parentScreenId": "",
107
+ "tabId": "aria"
108
108
  },
109
109
  {
110
110
  "screenId": "himi_owner_lite_aria_history",
111
111
  "isPublic": false,
112
112
  "paramKeys": [],
113
113
  "parentScreenId": "himi_owner_lite_aria",
114
- "tabId": "manage"
114
+ "tabId": "aria"
115
115
  },
116
116
  {
117
117
  "screenId": "himi_owner_lite_brief",
@@ -521,7 +521,7 @@ export default defineApp({
521
521
  "isPublic": false,
522
522
  "paramKeys": [],
523
523
  "parentScreenId": "",
524
- "tabId": "account"
524
+ "tabId": ""
525
525
  }
526
526
  ],
527
527
  "tabBar": {
@@ -533,6 +533,36 @@ export default defineApp({
533
533
  "icon": "home",
534
534
  "selectedIcon": "home_fill"
535
535
  },
536
+ {
537
+ "id": "aria",
538
+ "screenId": "himi_owner_lite_aria",
539
+ "label": "Aria",
540
+ "icon": "ai"
541
+ },
542
+ {
543
+ "id": "manage",
544
+ "screenId": "himi_owner_lite_manage",
545
+ "label": "Salon",
546
+ "icon": "grid",
547
+ "selectedIcon": "grid_fill"
548
+ }
549
+ ]
550
+ },
551
+ "sidebar": {
552
+ "items": [
553
+ {
554
+ "id": "home",
555
+ "screenId": "himi_owner_lite_home",
556
+ "label": "Today",
557
+ "icon": "home",
558
+ "selectedIcon": "home_fill"
559
+ },
560
+ {
561
+ "id": "aria",
562
+ "screenId": "himi_owner_lite_aria",
563
+ "label": "Aria",
564
+ "icon": "ai"
565
+ },
536
566
  {
537
567
  "id": "manage",
538
568
  "screenId": "himi_owner_lite_manage",
@@ -50769,100 +50769,6 @@ const SCREENS = runtimeSetting({
50769
50769
  "haptic": "light",
50770
50770
  "accessibilityLabel": "himi_owner_lite.manage_analytics"
50771
50771
  }
50772
- },
50773
- {
50774
- "id": "",
50775
- "body": {
50776
- "package": "himalaya",
50777
- "type": "HStack",
50778
- "props": {
50779
- "spacing": 12,
50780
- "children": [
50781
- {
50782
- "id": "",
50783
- "body": {
50784
- "package": "himalaya",
50785
- "type": "HStack",
50786
- "props": {
50787
- "spacing": 12,
50788
- "children": [
50789
- {
50790
- "id": "",
50791
- "body": {
50792
- "package": "himalaya",
50793
- "type": "Icon",
50794
- "props": {
50795
- "name": "chat",
50796
- "size": 20,
50797
- "tint": "accentPrimary"
50798
- }
50799
- }
50800
- },
50801
- {
50802
- "id": "",
50803
- "body": {
50804
- "package": "himalaya",
50805
- "type": "Text",
50806
- "props": {
50807
- "text": "Ask Aria",
50808
- "style": "bodyEmphasis"
50809
- }
50810
- }
50811
- }
50812
- ]
50813
- }
50814
- }
50815
- },
50816
- {
50817
- "id": "",
50818
- "body": {
50819
- "package": "himalaya",
50820
- "type": "Spacer",
50821
- "props": {}
50822
- }
50823
- },
50824
- {
50825
- "id": "",
50826
- "body": {
50827
- "package": "himalaya",
50828
- "type": "Icon",
50829
- "props": {
50830
- "name": "chevron_right",
50831
- "size": 16,
50832
- "tint": "textTertiary"
50833
- }
50834
- }
50835
- }
50836
- ]
50837
- }
50838
- },
50839
- "modifiers": {
50840
- "background": {
50841
- "token": "surfaceElevated"
50842
- },
50843
- "border": {
50844
- "width": 1,
50845
- "color": {
50846
- "token": "border"
50847
- }
50848
- },
50849
- "cornerRadius": 12,
50850
- "padding": {
50851
- "leading": 14,
50852
- "trailing": 14,
50853
- "top": 14,
50854
- "bottom": 14
50855
- },
50856
- "onTap": {
50857
- "actionId": "himi.open",
50858
- "params": {
50859
- "screenId": "himi_owner_lite_aria"
50860
- }
50861
- },
50862
- "pressFeedback": "scale",
50863
- "haptic": "light",
50864
- "accessibilityLabel": "himi_owner_lite.manage_aria"
50865
- }
50866
50772
  }
50867
50773
  ]
50868
50774
  }
@@ -153,6 +153,10 @@ export interface AriaChatLabels {
153
153
  typing?: Resolvable<string>;
154
154
  /** Status line when the wait ran out without a reply. */
155
155
  slow?: Resolvable<string>;
156
+ /** Shown instead of a raw transport error when this HOST cannot reach Wix at
157
+ * all — it carries no Wix app binding to sign the chat-service call with.
158
+ * See `isWixAccountUnreachable`, and note what it is NOT: a signed-out user. */
159
+ unavailable?: Resolvable<string>;
156
160
  }
157
161
 
158
162
  export interface AriaChatOptions {
@@ -271,6 +275,62 @@ export function hostOf(url: string): string {
271
275
  return PLAIN_HOST.test(host) ? host : "";
272
276
  }
273
277
 
278
+ /** The web bridge's DESIGNED refusals — the ones that mean "this host cannot
279
+ * reach Wix", as opposed to "the chat-service is broken".
280
+ *
281
+ * Matched by NAME, never by the 501 status alone: 501 is also what an unrelated
282
+ * gateway failure carries, and an unknown future refusal should stay loud rather
283
+ * than be quietly absorbed into a reassuring sentence.
284
+ *
285
+ * - `webwix_bridge_no_client_id` — the host carries no Wix app binding at all,
286
+ * so nothing can be signed and no Wix call leaves the browser.
287
+ * - `webwix_owner_only` — the call targets an owner-scoped Wix host
288
+ * (`*.wix.com`) rather than the `wixapis.com` gateway the web bridge is
289
+ * host-locked to. Aria's chat-service lives on `manage.wix.com`, so on web
290
+ * this is the refusal it gets once a site IS connected: structural, and not
291
+ * fixed by any amount of signing in or re-binding.
292
+ * - `webwix_owner_mint_failed` — no owner session for this business on this
293
+ * host. The shell already puts its own "Sign in to Wix again" affordance up
294
+ * for this one, so Aria says the same neutral thing rather than competing
295
+ * with it.
296
+ *
297
+ * ALL THREE READ THE SAME WAY TO AN OWNER: Aria cannot work on this surface,
298
+ * and nothing they do in the chat will change it. None of them is a reason to
299
+ * show red, and none is a reason to tell them to sign in — an earlier version
300
+ * of this said "Sign in to your Wix account" and was wrong on exactly that
301
+ * point, since the owner is typically already signed in.
302
+ *
303
+ * Aria cannot degrade to sample rows the way the data screens do — there is no
304
+ * conversation to invent — so it degrades to the greeting plus one plain
305
+ * sentence in the NEUTRAL status line. */
306
+ const DESIGNED_BRIDGE_REFUSALS = [
307
+ "webwix_bridge_no_client_id",
308
+ "webwix_owner_only",
309
+ "webwix_owner_mint_failed",
310
+ ];
311
+
312
+ export function isWixAccountUnreachable(e: unknown): boolean {
313
+ const msg = String((e as Error)?.message ?? e ?? "");
314
+ return DESIGNED_BRIDGE_REFUSALS.some((name) => msg.includes(name));
315
+ }
316
+
317
+ /** Which of the screen's two message slots a failure belongs in.
318
+ *
319
+ * Both already exist and they say different things: `error` renders in `danger`
320
+ * and `statusText` in `textSecondary`. "This host has no owner session" is not
321
+ * a fault, so putting it in the red slot still tells the owner something broke
322
+ * and sends them looking for a breakage that is not there — the words would be
323
+ * right and the colour would be lying. It goes in the neutral slot instead.
324
+ *
325
+ * Always returns BOTH keys so the two can never show at once: a real error
326
+ * clears any stale status line, and the signed-out sentence clears any red text
327
+ * left over from an earlier failure. */
328
+ function failureSlots(e: unknown, unavailable: () => string): { error: string; statusText: string } {
329
+ return isWixAccountUnreachable(e)
330
+ ? { error: "", statusText: unavailable() }
331
+ : { error: String((e as Error)?.message ?? e), statusText: "" };
332
+ }
333
+
274
334
  /** Is this url somewhere Wix itself serves?
275
335
  *
276
336
  * Guarded by `PLAIN_HOST` first. The suffix tests are string operations, so
@@ -528,6 +588,13 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
528
588
  const you = () => res(o.labels?.you ?? "You");
529
589
  const typingText = () => res(o.labels?.typing ?? `${assistant()} is typing…`);
530
590
  const slowText = () => res(o.labels?.slow ?? `${assistant()} is taking a while…`);
591
+ // States the fact and stops. It deliberately gives no instruction, because
592
+ // there is none the owner could follow: they are signed in, and the thing that
593
+ // is missing is the app's own Wix binding. "Here" is doing real work — it says
594
+ // the limit is this surface, not their account and not Aria.
595
+ const unavailableText = () => res(
596
+ o.labels?.unavailable ?? `${assistant()} can't reach your Wix account from here.`,
597
+ );
531
598
  const promptList = () => res(o.prompts);
532
599
  const siteOf = o.siteId ?? (() => "");
533
600
  const resumeOf = o.resumeConversationId ?? inputConversationId;
@@ -686,12 +753,14 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
686
753
  } catch (e) {
687
754
  inFlightSend = null;
688
755
  return {
689
- ...base, status: "ready", statusText: "", _pending: "",
756
+ ...base, status: "ready", _pending: "",
690
757
  // `_siteId` moves with the id or neither does: a conversation remembered
691
758
  // without the site it belongs to reads as another business's on the next
692
759
  // send, and gets replaced instead of retried.
693
760
  _convId: convId, _siteId: convId === s._convId ? s._siteId : site,
694
- error: String((e as Error)?.message ?? e),
761
+ // Sets BOTH error and statusText, so it must come after the `statusText: ""`
762
+ // this object used to carry — otherwise the literal would blank the sentence.
763
+ ...failureSlots(e, unavailableText),
695
764
  };
696
765
  }
697
766
  }
@@ -756,7 +825,7 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
756
825
  messages: greetingOnly(), ...observed([]), prompts: promptList() };
757
826
  } catch (e) {
758
827
  // Even if create fails, show the greeting; submit retries the create.
759
- return { ...s, status: "ready", _convId: "", _siteId: site, _pending: "", error: String((e as Error)?.message ?? e),
828
+ return { ...s, status: "ready", _convId: "", _siteId: site, _pending: "", ...failureSlots(e, unavailableText),
760
829
  messages: greetingOnly(), ...observed([]), prompts: promptList() };
761
830
  }
762
831
  },
@@ -801,7 +870,7 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
801
870
  return slow({ ...s, status: "ready", _convId: conversationIdOf(res), _siteId: site, input: "", statusText: "", error: "",
802
871
  _pending: "", messages: greetingOnly(), ...observed([]), prompts: promptList(), ok: false });
803
872
  } catch (e) {
804
- return slow({ ...s, status: "ready", _convId: "", _siteId: site, input: "", error: String((e as Error)?.message ?? e),
873
+ return slow({ ...s, status: "ready", _convId: "", _siteId: site, input: "", ...failureSlots(e, unavailableText),
805
874
  _pending: "", messages: greetingOnly(), ...observed([]), prompts: promptList(), ok: false });
806
875
  }
807
876
  },
@@ -141,6 +141,13 @@ const core = createAriaChat({
141
141
  you: () => copyParam("ownerAria.you", "You"),
142
142
  typing: () => copyParam("ownerAria.typing", "Aria is typing…"),
143
143
  slow: () => copyParam("ownerAria.slow", "Aria is taking a while…"),
144
+ // Shown when the HOST carries no Wix app binding, so no Wix call can leave
145
+ // the browser (the web preview). Through copyParam like every other string
146
+ // here — a default baked into the shared core cannot be localized by this
147
+ // app's copy pack, and a non-English owner would have read this one line in
148
+ // English. Says no "sign in": the owner already is, and the missing piece is
149
+ // the app's binding, so there is no action for them to take.
150
+ unavailable: () => copyParam("ownerAria.unavailable", "Aria can't reach your Wix account from here."),
144
151
  },
145
152
  historyKey: "ol.aria.history.v1",
146
153
  // No local title cache in THIS app. __HIMI_APP_NAME__ is multi-account and
@@ -103,15 +103,15 @@ export default defineApp({
103
103
  "paramKeys": [
104
104
  "conversationId"
105
105
  ],
106
- "parentScreenId": "himi_owner_lite_manage",
107
- "tabId": "manage"
106
+ "parentScreenId": "",
107
+ "tabId": "aria"
108
108
  },
109
109
  {
110
110
  "screenId": "himi_owner_lite_aria_history",
111
111
  "isPublic": false,
112
112
  "paramKeys": [],
113
113
  "parentScreenId": "himi_owner_lite_aria",
114
- "tabId": "manage"
114
+ "tabId": "aria"
115
115
  },
116
116
  {
117
117
  "screenId": "himi_owner_lite_brief",
@@ -505,7 +505,7 @@ export default defineApp({
505
505
  "isPublic": false,
506
506
  "paramKeys": [],
507
507
  "parentScreenId": "",
508
- "tabId": "account"
508
+ "tabId": ""
509
509
  }
510
510
  ],
511
511
  "tabBar": {
@@ -517,6 +517,36 @@ export default defineApp({
517
517
  "icon": "home",
518
518
  "selectedIcon": "home_fill"
519
519
  },
520
+ {
521
+ "id": "aria",
522
+ "screenId": "himi_owner_lite_aria",
523
+ "label": "Aria",
524
+ "icon": "ai"
525
+ },
526
+ {
527
+ "id": "manage",
528
+ "screenId": "himi_owner_lite_manage",
529
+ "label": "Club",
530
+ "icon": "grid",
531
+ "selectedIcon": "grid_fill"
532
+ }
533
+ ]
534
+ },
535
+ "sidebar": {
536
+ "items": [
537
+ {
538
+ "id": "home",
539
+ "screenId": "himi_owner_lite_home",
540
+ "label": "Committee",
541
+ "icon": "home",
542
+ "selectedIcon": "home_fill"
543
+ },
544
+ {
545
+ "id": "aria",
546
+ "screenId": "himi_owner_lite_aria",
547
+ "label": "Aria",
548
+ "icon": "ai"
549
+ },
520
550
  {
521
551
  "id": "manage",
522
552
  "screenId": "himi_owner_lite_manage",
@@ -50769,100 +50769,6 @@ const SCREENS = runtimeSetting({
50769
50769
  "haptic": "light",
50770
50770
  "accessibilityLabel": "himi_owner_lite.manage_analytics"
50771
50771
  }
50772
- },
50773
- {
50774
- "id": "",
50775
- "body": {
50776
- "package": "himalaya",
50777
- "type": "HStack",
50778
- "props": {
50779
- "spacing": 12,
50780
- "children": [
50781
- {
50782
- "id": "",
50783
- "body": {
50784
- "package": "himalaya",
50785
- "type": "HStack",
50786
- "props": {
50787
- "spacing": 12,
50788
- "children": [
50789
- {
50790
- "id": "",
50791
- "body": {
50792
- "package": "himalaya",
50793
- "type": "Icon",
50794
- "props": {
50795
- "name": "chat",
50796
- "size": 20,
50797
- "tint": "accentPrimary"
50798
- }
50799
- }
50800
- },
50801
- {
50802
- "id": "",
50803
- "body": {
50804
- "package": "himalaya",
50805
- "type": "Text",
50806
- "props": {
50807
- "text": "Ask Aria",
50808
- "style": "bodyEmphasis"
50809
- }
50810
- }
50811
- }
50812
- ]
50813
- }
50814
- }
50815
- },
50816
- {
50817
- "id": "",
50818
- "body": {
50819
- "package": "himalaya",
50820
- "type": "Spacer",
50821
- "props": {}
50822
- }
50823
- },
50824
- {
50825
- "id": "",
50826
- "body": {
50827
- "package": "himalaya",
50828
- "type": "Icon",
50829
- "props": {
50830
- "name": "chevron_right",
50831
- "size": 16,
50832
- "tint": "textTertiary"
50833
- }
50834
- }
50835
- }
50836
- ]
50837
- }
50838
- },
50839
- "modifiers": {
50840
- "background": {
50841
- "token": "surfaceElevated"
50842
- },
50843
- "border": {
50844
- "width": 1,
50845
- "color": {
50846
- "token": "border"
50847
- }
50848
- },
50849
- "cornerRadius": 12,
50850
- "padding": {
50851
- "leading": 14,
50852
- "trailing": 14,
50853
- "top": 14,
50854
- "bottom": 14
50855
- },
50856
- "onTap": {
50857
- "actionId": "himi.open",
50858
- "params": {
50859
- "screenId": "himi_owner_lite_aria"
50860
- }
50861
- },
50862
- "pressFeedback": "scale",
50863
- "haptic": "light",
50864
- "accessibilityLabel": "himi_owner_lite.manage_aria"
50865
- }
50866
50772
  }
50867
50773
  ]
50868
50774
  }
@@ -153,6 +153,10 @@ export interface AriaChatLabels {
153
153
  typing?: Resolvable<string>;
154
154
  /** Status line when the wait ran out without a reply. */
155
155
  slow?: Resolvable<string>;
156
+ /** Shown instead of a raw transport error when this HOST cannot reach Wix at
157
+ * all — it carries no Wix app binding to sign the chat-service call with.
158
+ * See `isWixAccountUnreachable`, and note what it is NOT: a signed-out user. */
159
+ unavailable?: Resolvable<string>;
156
160
  }
157
161
 
158
162
  export interface AriaChatOptions {
@@ -271,6 +275,62 @@ export function hostOf(url: string): string {
271
275
  return PLAIN_HOST.test(host) ? host : "";
272
276
  }
273
277
 
278
+ /** The web bridge's DESIGNED refusals — the ones that mean "this host cannot
279
+ * reach Wix", as opposed to "the chat-service is broken".
280
+ *
281
+ * Matched by NAME, never by the 501 status alone: 501 is also what an unrelated
282
+ * gateway failure carries, and an unknown future refusal should stay loud rather
283
+ * than be quietly absorbed into a reassuring sentence.
284
+ *
285
+ * - `webwix_bridge_no_client_id` — the host carries no Wix app binding at all,
286
+ * so nothing can be signed and no Wix call leaves the browser.
287
+ * - `webwix_owner_only` — the call targets an owner-scoped Wix host
288
+ * (`*.wix.com`) rather than the `wixapis.com` gateway the web bridge is
289
+ * host-locked to. Aria's chat-service lives on `manage.wix.com`, so on web
290
+ * this is the refusal it gets once a site IS connected: structural, and not
291
+ * fixed by any amount of signing in or re-binding.
292
+ * - `webwix_owner_mint_failed` — no owner session for this business on this
293
+ * host. The shell already puts its own "Sign in to Wix again" affordance up
294
+ * for this one, so Aria says the same neutral thing rather than competing
295
+ * with it.
296
+ *
297
+ * ALL THREE READ THE SAME WAY TO AN OWNER: Aria cannot work on this surface,
298
+ * and nothing they do in the chat will change it. None of them is a reason to
299
+ * show red, and none is a reason to tell them to sign in — an earlier version
300
+ * of this said "Sign in to your Wix account" and was wrong on exactly that
301
+ * point, since the owner is typically already signed in.
302
+ *
303
+ * Aria cannot degrade to sample rows the way the data screens do — there is no
304
+ * conversation to invent — so it degrades to the greeting plus one plain
305
+ * sentence in the NEUTRAL status line. */
306
+ const DESIGNED_BRIDGE_REFUSALS = [
307
+ "webwix_bridge_no_client_id",
308
+ "webwix_owner_only",
309
+ "webwix_owner_mint_failed",
310
+ ];
311
+
312
+ export function isWixAccountUnreachable(e: unknown): boolean {
313
+ const msg = String((e as Error)?.message ?? e ?? "");
314
+ return DESIGNED_BRIDGE_REFUSALS.some((name) => msg.includes(name));
315
+ }
316
+
317
+ /** Which of the screen's two message slots a failure belongs in.
318
+ *
319
+ * Both already exist and they say different things: `error` renders in `danger`
320
+ * and `statusText` in `textSecondary`. "This host has no owner session" is not
321
+ * a fault, so putting it in the red slot still tells the owner something broke
322
+ * and sends them looking for a breakage that is not there — the words would be
323
+ * right and the colour would be lying. It goes in the neutral slot instead.
324
+ *
325
+ * Always returns BOTH keys so the two can never show at once: a real error
326
+ * clears any stale status line, and the signed-out sentence clears any red text
327
+ * left over from an earlier failure. */
328
+ function failureSlots(e: unknown, unavailable: () => string): { error: string; statusText: string } {
329
+ return isWixAccountUnreachable(e)
330
+ ? { error: "", statusText: unavailable() }
331
+ : { error: String((e as Error)?.message ?? e), statusText: "" };
332
+ }
333
+
274
334
  /** Is this url somewhere Wix itself serves?
275
335
  *
276
336
  * Guarded by `PLAIN_HOST` first. The suffix tests are string operations, so
@@ -528,6 +588,13 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
528
588
  const you = () => res(o.labels?.you ?? "You");
529
589
  const typingText = () => res(o.labels?.typing ?? `${assistant()} is typing…`);
530
590
  const slowText = () => res(o.labels?.slow ?? `${assistant()} is taking a while…`);
591
+ // States the fact and stops. It deliberately gives no instruction, because
592
+ // there is none the owner could follow: they are signed in, and the thing that
593
+ // is missing is the app's own Wix binding. "Here" is doing real work — it says
594
+ // the limit is this surface, not their account and not Aria.
595
+ const unavailableText = () => res(
596
+ o.labels?.unavailable ?? `${assistant()} can't reach your Wix account from here.`,
597
+ );
531
598
  const promptList = () => res(o.prompts);
532
599
  const siteOf = o.siteId ?? (() => "");
533
600
  const resumeOf = o.resumeConversationId ?? inputConversationId;
@@ -686,12 +753,14 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
686
753
  } catch (e) {
687
754
  inFlightSend = null;
688
755
  return {
689
- ...base, status: "ready", statusText: "", _pending: "",
756
+ ...base, status: "ready", _pending: "",
690
757
  // `_siteId` moves with the id or neither does: a conversation remembered
691
758
  // without the site it belongs to reads as another business's on the next
692
759
  // send, and gets replaced instead of retried.
693
760
  _convId: convId, _siteId: convId === s._convId ? s._siteId : site,
694
- error: String((e as Error)?.message ?? e),
761
+ // Sets BOTH error and statusText, so it must come after the `statusText: ""`
762
+ // this object used to carry — otherwise the literal would blank the sentence.
763
+ ...failureSlots(e, unavailableText),
695
764
  };
696
765
  }
697
766
  }
@@ -756,7 +825,7 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
756
825
  messages: greetingOnly(), ...observed([]), prompts: promptList() };
757
826
  } catch (e) {
758
827
  // Even if create fails, show the greeting; submit retries the create.
759
- return { ...s, status: "ready", _convId: "", _siteId: site, _pending: "", error: String((e as Error)?.message ?? e),
828
+ return { ...s, status: "ready", _convId: "", _siteId: site, _pending: "", ...failureSlots(e, unavailableText),
760
829
  messages: greetingOnly(), ...observed([]), prompts: promptList() };
761
830
  }
762
831
  },
@@ -801,7 +870,7 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
801
870
  return slow({ ...s, status: "ready", _convId: conversationIdOf(res), _siteId: site, input: "", statusText: "", error: "",
802
871
  _pending: "", messages: greetingOnly(), ...observed([]), prompts: promptList(), ok: false });
803
872
  } catch (e) {
804
- return slow({ ...s, status: "ready", _convId: "", _siteId: site, input: "", error: String((e as Error)?.message ?? e),
873
+ return slow({ ...s, status: "ready", _convId: "", _siteId: site, input: "", ...failureSlots(e, unavailableText),
805
874
  _pending: "", messages: greetingOnly(), ...observed([]), prompts: promptList(), ok: false });
806
875
  }
807
876
  },