@businessdash/sdk 0.9.60 → 0.9.80

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 (239) hide show
  1. package/README.md +991 -295
  2. package/assets/biab-sw.js +92 -0
  3. package/dist/account-core/index.d.ts +126 -0
  4. package/dist/account-core/index.d.ts.map +1 -0
  5. package/dist/account-core/index.js +191 -0
  6. package/dist/account-core/index.js.map +1 -0
  7. package/dist/account.d.ts +11 -0
  8. package/dist/account.d.ts.map +1 -0
  9. package/dist/account.js +11 -0
  10. package/dist/account.js.map +1 -0
  11. package/dist/auth-handler.d.ts +1 -1
  12. package/dist/auth-links.d.ts +33 -0
  13. package/dist/auth-links.d.ts.map +1 -0
  14. package/dist/auth-links.js +64 -0
  15. package/dist/auth-links.js.map +1 -0
  16. package/dist/blog-core/index.d.ts +112 -0
  17. package/dist/blog-core/index.d.ts.map +1 -0
  18. package/dist/blog-core/index.js +330 -0
  19. package/dist/blog-core/index.js.map +1 -0
  20. package/dist/blog.d.ts +11 -0
  21. package/dist/blog.d.ts.map +1 -0
  22. package/dist/blog.js +11 -0
  23. package/dist/blog.js.map +1 -0
  24. package/dist/chat-core/index.d.ts +97 -0
  25. package/dist/chat-core/index.d.ts.map +1 -0
  26. package/dist/chat-core/index.js +237 -0
  27. package/dist/chat-core/index.js.map +1 -0
  28. package/dist/chat.d.ts +11 -0
  29. package/dist/chat.d.ts.map +1 -0
  30. package/dist/chat.js +11 -0
  31. package/dist/chat.js.map +1 -0
  32. package/dist/checkout-core/index.d.ts +65 -0
  33. package/dist/checkout-core/index.d.ts.map +1 -0
  34. package/dist/checkout-core/index.js +159 -0
  35. package/dist/checkout-core/index.js.map +1 -0
  36. package/dist/checkout.d.ts +10 -0
  37. package/dist/checkout.d.ts.map +1 -0
  38. package/dist/checkout.js +10 -0
  39. package/dist/checkout.js.map +1 -0
  40. package/dist/cli.js +133 -25
  41. package/dist/cli.js.map +1 -1
  42. package/dist/client.d.ts +622 -1
  43. package/dist/client.d.ts.map +1 -1
  44. package/dist/client.js +888 -1
  45. package/dist/client.js.map +1 -1
  46. package/dist/consent-core/index.cjs +107 -0
  47. package/dist/consent-core/index.d.ts +103 -0
  48. package/dist/consent-core/index.d.ts.map +1 -0
  49. package/dist/consent-core/index.js +157 -0
  50. package/dist/consent-core/index.js.map +1 -0
  51. package/dist/contracts.d.ts +3526 -767
  52. package/dist/contracts.d.ts.map +1 -1
  53. package/dist/contracts.js +571 -4
  54. package/dist/contracts.js.map +1 -1
  55. package/dist/data-model-schema.d.ts +1 -1
  56. package/dist/data-model-schema.d.ts.map +1 -1
  57. package/dist/element.d.ts +30 -0
  58. package/dist/element.d.ts.map +1 -1
  59. package/dist/element.js +56 -0
  60. package/dist/element.js.map +1 -1
  61. package/dist/embed-protocol.d.ts +86 -0
  62. package/dist/embed-protocol.d.ts.map +1 -0
  63. package/dist/embed-protocol.js +60 -0
  64. package/dist/embed-protocol.js.map +1 -0
  65. package/dist/framework-support.d.ts +122 -0
  66. package/dist/framework-support.d.ts.map +1 -0
  67. package/dist/framework-support.js +323 -0
  68. package/dist/framework-support.js.map +1 -0
  69. package/dist/index.cjs +1355 -24
  70. package/dist/legal-core/index.cjs +115 -0
  71. package/dist/legal-core/index.d.ts +160 -0
  72. package/dist/legal-core/index.d.ts.map +1 -0
  73. package/dist/legal-core/index.js +220 -0
  74. package/dist/legal-core/index.js.map +1 -0
  75. package/dist/marketing-core/index.d.ts +66 -0
  76. package/dist/marketing-core/index.d.ts.map +1 -0
  77. package/dist/marketing-core/index.js +154 -0
  78. package/dist/marketing-core/index.js.map +1 -0
  79. package/dist/marketing.d.ts +7 -0
  80. package/dist/marketing.d.ts.map +1 -0
  81. package/dist/marketing.js +7 -0
  82. package/dist/marketing.js.map +1 -0
  83. package/dist/mcp-adapters/index.d.ts +135 -0
  84. package/dist/mcp-adapters/index.d.ts.map +1 -0
  85. package/dist/mcp-adapters/index.js +187 -0
  86. package/dist/mcp-adapters/index.js.map +1 -0
  87. package/dist/mcp-adapters.d.ts +7 -0
  88. package/dist/mcp-adapters.d.ts.map +1 -0
  89. package/dist/mcp-adapters.js +7 -0
  90. package/dist/mcp-adapters.js.map +1 -0
  91. package/dist/model3d-core/index.cjs +95 -0
  92. package/dist/model3d-core/index.d.ts +167 -0
  93. package/dist/model3d-core/index.d.ts.map +1 -0
  94. package/dist/model3d-core/index.js +158 -0
  95. package/dist/model3d-core/index.js.map +1 -0
  96. package/dist/notifications-core/index.cjs +315 -0
  97. package/dist/notifications-core/index.d.ts +229 -0
  98. package/dist/notifications-core/index.d.ts.map +1 -0
  99. package/dist/notifications-core/index.js +445 -0
  100. package/dist/notifications-core/index.js.map +1 -0
  101. package/dist/portal-core/index.d.ts +451 -0
  102. package/dist/portal-core/index.d.ts.map +1 -0
  103. package/dist/portal-core/index.js +819 -0
  104. package/dist/portal-core/index.js.map +1 -0
  105. package/dist/portal.d.ts +7 -0
  106. package/dist/portal.d.ts.map +1 -0
  107. package/dist/portal.js +7 -0
  108. package/dist/portal.js.map +1 -0
  109. package/dist/push-core/index.cjs +171 -0
  110. package/dist/push-core/index.d.ts +149 -0
  111. package/dist/push-core/index.d.ts.map +1 -0
  112. package/dist/push-core/index.js +231 -0
  113. package/dist/push-core/index.js.map +1 -0
  114. package/dist/react-marketing.d.ts +1 -17
  115. package/dist/react-marketing.d.ts.map +1 -1
  116. package/dist/react-marketing.js +4 -0
  117. package/dist/react-marketing.js.map +1 -1
  118. package/dist/react.d.ts +294 -101
  119. package/dist/react.d.ts.map +1 -1
  120. package/dist/react.js +302 -246
  121. package/dist/react.js.map +1 -1
  122. package/dist/seed-core/index.d.ts +354 -0
  123. package/dist/seed-core/index.d.ts.map +1 -0
  124. package/dist/seed-core/index.js +420 -0
  125. package/dist/seed-core/index.js.map +1 -0
  126. package/dist/seed.d.ts +7 -0
  127. package/dist/seed.d.ts.map +1 -0
  128. package/dist/seed.js +7 -0
  129. package/dist/seed.js.map +1 -0
  130. package/dist/seo-core/blog.d.ts +94 -0
  131. package/dist/seo-core/blog.d.ts.map +1 -0
  132. package/dist/seo-core/blog.js +149 -0
  133. package/dist/seo-core/blog.js.map +1 -0
  134. package/dist/seo-core/commerce.d.ts +64 -0
  135. package/dist/seo-core/commerce.d.ts.map +1 -0
  136. package/dist/seo-core/commerce.js +87 -0
  137. package/dist/seo-core/commerce.js.map +1 -0
  138. package/dist/seo-core/index.cjs +751 -0
  139. package/dist/seo-core/index.d.ts +226 -0
  140. package/dist/seo-core/index.d.ts.map +1 -0
  141. package/dist/seo-core/index.js +455 -0
  142. package/dist/seo-core/index.js.map +1 -0
  143. package/dist/seo-core/local.d.ts +181 -0
  144. package/dist/seo-core/local.d.ts.map +1 -0
  145. package/dist/seo-core/local.js +193 -0
  146. package/dist/seo-core/local.js.map +1 -0
  147. package/dist/sitemap-core/index.cjs +167 -0
  148. package/dist/sitemap-core/index.d.ts +155 -0
  149. package/dist/sitemap-core/index.d.ts.map +1 -0
  150. package/dist/sitemap-core/index.js +195 -0
  151. package/dist/sitemap-core/index.js.map +1 -0
  152. package/dist/social-core/index.d.ts +74 -0
  153. package/dist/social-core/index.d.ts.map +1 -0
  154. package/dist/social-core/index.js +72 -0
  155. package/dist/social-core/index.js.map +1 -0
  156. package/dist/social.d.ts +7 -0
  157. package/dist/social.d.ts.map +1 -0
  158. package/dist/social.js +7 -0
  159. package/dist/social.js.map +1 -0
  160. package/dist/solid-compat.d.ts +204 -0
  161. package/dist/solid-compat.d.ts.map +1 -0
  162. package/dist/solid-compat.js +221 -0
  163. package/dist/solid-compat.js.map +1 -0
  164. package/dist/store-core/index.d.ts +141 -0
  165. package/dist/store-core/index.d.ts.map +1 -0
  166. package/dist/store-core/index.js +277 -0
  167. package/dist/store-core/index.js.map +1 -0
  168. package/dist/store.d.ts +12 -0
  169. package/dist/store.d.ts.map +1 -0
  170. package/dist/store.js +12 -0
  171. package/dist/store.js.map +1 -0
  172. package/dist/vanilla.d.ts +111 -0
  173. package/dist/vanilla.d.ts.map +1 -1
  174. package/dist/vanilla.js +206 -0
  175. package/dist/vanilla.js.map +1 -1
  176. package/dist/verify-core/index.d.ts +98 -0
  177. package/dist/verify-core/index.d.ts.map +1 -0
  178. package/dist/verify-core/index.js +186 -0
  179. package/dist/verify-core/index.js.map +1 -0
  180. package/dist/verify.d.ts +8 -0
  181. package/dist/verify.d.ts.map +1 -0
  182. package/dist/verify.js +8 -0
  183. package/dist/verify.js.map +1 -0
  184. package/openapi.json +4516 -1311
  185. package/package.json +128 -11
  186. package/src/account-core/index.ts +309 -0
  187. package/src/account.ts +11 -0
  188. package/src/angular/headless.ts +519 -0
  189. package/src/angular/index.ts +3 -0
  190. package/src/auth-links.ts +76 -0
  191. package/src/blog-core/index.ts +423 -0
  192. package/src/blog.ts +11 -0
  193. package/src/chat-core/index.ts +335 -0
  194. package/src/chat.ts +11 -0
  195. package/src/checkout-core/index.ts +225 -0
  196. package/src/checkout.ts +10 -0
  197. package/src/cli.ts +184 -28
  198. package/src/client.ts +1097 -0
  199. package/src/consent-core/index.ts +213 -0
  200. package/src/contracts.ts +768 -11
  201. package/src/data-model-schema.ts +1 -1
  202. package/src/element.ts +102 -0
  203. package/src/embed-protocol.ts +100 -0
  204. package/src/framework-support.ts +440 -0
  205. package/src/legal-core/index.ts +276 -0
  206. package/src/marketing-core/index.ts +209 -0
  207. package/src/marketing.ts +7 -0
  208. package/src/mcp-adapters/index.ts +264 -0
  209. package/src/mcp-adapters.ts +7 -0
  210. package/src/model3d-core/index.ts +248 -0
  211. package/src/notifications-core/index.ts +650 -0
  212. package/src/portal-core/index.ts +1564 -0
  213. package/src/portal.ts +7 -0
  214. package/src/push-core/index.ts +335 -0
  215. package/src/qwik.tsx +602 -2
  216. package/src/react-marketing.tsx +5 -0
  217. package/src/react.tsx +434 -319
  218. package/src/seed-core/index.ts +735 -0
  219. package/src/seed.ts +7 -0
  220. package/src/seo-core/blog.ts +216 -0
  221. package/src/seo-core/commerce.ts +138 -0
  222. package/src/seo-core/index.ts +605 -0
  223. package/src/seo-core/local.ts +333 -0
  224. package/src/sitemap-core/index.ts +296 -0
  225. package/src/social-core/index.ts +103 -0
  226. package/src/social.ts +7 -0
  227. package/src/solid-compat.tsx +347 -0
  228. package/src/solid-surfaces.tsx +1311 -0
  229. package/src/solid.tsx +82 -60
  230. package/src/store-core/index.ts +426 -0
  231. package/src/store.ts +12 -0
  232. package/src/svelte/SocialLinks.svelte +84 -0
  233. package/src/svelte/headless.ts +435 -0
  234. package/src/svelte/index.ts +9 -0
  235. package/src/vanilla.ts +367 -0
  236. package/src/verify-core/index.ts +288 -0
  237. package/src/verify.ts +8 -0
  238. package/src/vue/headless.ts +527 -0
  239. package/src/vue/index.ts +3 -0
@@ -0,0 +1,167 @@
1
+ /**
2
+ * `@businessdash/sdk/model3d` — 3D product models on the org's own site.
3
+ *
4
+ * ## This ships no renderer, and that is the point
5
+ *
6
+ * A three.js build is ~600KB before your model. `<model-viewer>` is ~300KB. An
7
+ * SDK that pulled either down on every product page would be an SDK people rip
8
+ * out, and it would make the choice of engine ours rather than yours.
9
+ *
10
+ * So this decides WHAT to show and hands you the facts. You mount whichever
11
+ * viewer you already use, or none.
12
+ *
13
+ * ```ts
14
+ * const plan = planProductModel(product);
15
+ * if (plan.ar) showArLink(plan.ar.url); // zero JS, native iOS
16
+ * if (plan.viewer) mountYourViewer(plan.viewer.url, plan.viewer.format);
17
+ * if (plan.download) showLink(plan.download.url, plan.download.label);
18
+ * ```
19
+ *
20
+ * ## The three formats do genuinely different jobs
21
+ *
22
+ * **AR Quick Look (`.usdz`)** — the one worth having. On iOS, iPadOS and
23
+ * visionOS Safari an `<a rel="ar">` opens the model in the room, in the camera,
24
+ * with no JavaScript at all. No library, no canvas, no WebGL. Where it applies
25
+ * it beats an embedded viewer on every axis, so it is checked first.
26
+ *
27
+ * **Web viewer (`.glb`/`.gltf`/`.obj`/`.stl`)** — the rotatable canvas. `.glb`
28
+ * carries its own materials and is what you want; `.obj` and `.stl` are
29
+ * geometry only and render in a neutral grey, which is fine for a machined part
30
+ * and disappointing for a sofa.
31
+ *
32
+ * **CAD download (`.step`/`.stp`/`.iges`)** — NOT renderable, deliberately.
33
+ * STEP is a boundary-representation format needing a geometry kernel; the
34
+ * browser WASM builds of OpenCascade that can tessellate it are 10–30MB, which
35
+ * is not something to pull down for a product photo. It is also the wrong shape
36
+ * for who asks: an engineer evaluating a bracket wants the file in their own CAD
37
+ * package, not a spinning preview.
38
+ *
39
+ * ## Absent is the normal case
40
+ *
41
+ * These fields are stripped unless the org holds the `ecommerce.product_3d`
42
+ * add-on, and most businesses never attach a model. Every function here treats
43
+ * missing as ordinary and returns nothing to render.
44
+ *
45
+ * @module
46
+ */
47
+ /** The product fields this reads. Anything with these keys works. */
48
+ export type ModelBearingProduct = {
49
+ id?: string;
50
+ model3dUrl?: string | null;
51
+ model3dUsdzUrl?: string | null;
52
+ /** The API reports availability, never the URL. See `download` below. */
53
+ model3dCadAvailable?: boolean;
54
+ model3dCadName?: string | null;
55
+ };
56
+ /** What a web viewer can load. */
57
+ export type WebModelFormat = "glb" | "gltf" | "obj" | "stl";
58
+ /** What a CAD download might be. */
59
+ export type CadFormat = "step" | "iges" | "native";
60
+ export type ModelPlan = {
61
+ /**
62
+ * Present when the model can be placed in the room on this device.
63
+ *
64
+ * Only on Apple platforms, and only with a `.usdz`. Render as
65
+ * `<a rel="ar" href={url}><img …/></a>` — the `<img>` child is required by
66
+ * Quick Look, and the link needs no JavaScript whatsoever.
67
+ */
68
+ ar: {
69
+ url: string;
70
+ } | null;
71
+ /**
72
+ * Present when there is a model a WebGL viewer can load.
73
+ *
74
+ * `neutralMaterial` is true for `.obj` and `.stl`, which carry geometry but
75
+ * no materials — worth knowing, because a viewer that lights them like a
76
+ * `.glb` renders a black silhouette.
77
+ */
78
+ viewer: {
79
+ url: string;
80
+ format: WebModelFormat;
81
+ neutralMaterial: boolean;
82
+ } | null;
83
+ /**
84
+ * Present when the org attached a CAD file.
85
+ *
86
+ * `url` points at the platform's gated endpoint, never at the file — that
87
+ * route requires cookies, rate-limits the caller and re-checks the
88
+ * entitlement before handing anything over. Render it as an ordinary link;
89
+ * the visitor's browser sends its cookie automatically.
90
+ *
91
+ * `format` is inferred from the filename when the org supplied one, so a
92
+ * page can say "STEP" rather than "CAD" without a round trip.
93
+ */
94
+ download: {
95
+ url: string;
96
+ label: string;
97
+ format: CadFormat;
98
+ } | null;
99
+ /** True when there is nothing 3D at all — the common case. */
100
+ empty: boolean;
101
+ };
102
+ /** Which web viewer format a URL is, if any. */
103
+ export declare function webModelFormat(url: string | null | undefined): WebModelFormat | null;
104
+ /** Which CAD family a URL belongs to. Unknown extensions are `native`. */
105
+ export declare function cadFormat(url: string | null | undefined): CadFormat | null;
106
+ /**
107
+ * Does THIS browser support AR Quick Look?
108
+ *
109
+ * Feature-detected rather than sniffed: Safari advertises support by
110
+ * recognising `rel="ar"` on an anchor. That is Apple's own documented check and
111
+ * it survives the next user-agent change, which a regex on "iPhone" does not.
112
+ *
113
+ * False on the server, so a plan built during SSR omits the AR branch. Re-plan
114
+ * on the client if you want the link to appear without a navigation — the check
115
+ * is a few microseconds.
116
+ */
117
+ export declare function supportsArQuickLook(): boolean;
118
+ export type PlanProductModelOptions = {
119
+ /**
120
+ * Override the AR capability check.
121
+ *
122
+ * Pass `true` during SSR when you know the request came from an Apple
123
+ * device, or `false` to suppress AR entirely.
124
+ */
125
+ arSupported?: boolean;
126
+ /**
127
+ * Where your app proxies `GET storefront/products/{id}/cad`.
128
+ *
129
+ * Required for `download` to appear, and required to be YOUR route rather
130
+ * than the platform's: the API key is a server secret, so the browser
131
+ * cannot call the platform endpoint directly. Proxy it and pass your own
132
+ * path — `cadDownloadUrl: `/api/products/${product.id}/cad``.
133
+ *
134
+ * Without it the plan reports no download even when a file exists, which is
135
+ * the safe direction: a dead link is worse than an absent one.
136
+ */
137
+ cadDownloadUrl?: string;
138
+ };
139
+ /**
140
+ * Decide what to render for one product.
141
+ *
142
+ * AR is not exclusive with the viewer — a product can offer both, and on an
143
+ * iPhone the usual arrangement is a canvas with a "View in your room" button
144
+ * over it. The plan reports each independently rather than picking for you.
145
+ */
146
+ export declare function planProductModel(product: ModelBearingProduct, options?: PlanProductModelOptions): ModelPlan;
147
+ /**
148
+ * The attributes an AR Quick Look anchor needs.
149
+ *
150
+ * Spread onto your own `<a>`. Quick Look requires an `<img>` or equivalent
151
+ * child — an empty anchor silently does nothing, which is the single most
152
+ * common way this gets implemented wrong.
153
+ */
154
+ export declare function arLinkAttributes(url: string): {
155
+ href: string;
156
+ rel: string;
157
+ };
158
+ /**
159
+ * True when the org has the 3D add-on, judged from a product payload.
160
+ *
161
+ * The API omits these keys entirely without `ecommerce.product_3d`, so their
162
+ * absence distinguishes "not paid for" from "paid for, none attached" — where
163
+ * the key is present and null. Useful for deciding whether to show an upsell
164
+ * rather than nothing.
165
+ */
166
+ export declare function hasModel3dEntitlement(product: object): boolean;
167
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/model3d-core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,qEAAqE;AACrE,MAAM,MAAM,mBAAmB,GAAG;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,kCAAkC;AAClC,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;AAE5D,oCAAoC;AACpC,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEnD,MAAM,MAAM,SAAS,GAAG;IACvB;;;;;;OAMG;IACH,EAAE,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3B;;;;;;OAMG;IACH,MAAM,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,cAAc,CAAC;QACvB,eAAe,EAAE,OAAO,CAAC;KACzB,GAAG,IAAI,CAAC;IACT;;;;;;;;;;OAUG;IACH,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE,GAAG,IAAI,CAAC;IACnE,8DAA8D;IAC9D,KAAK,EAAE,OAAO,CAAC;CACf,CAAC;AAUF,gDAAgD;AAChD,wBAAgB,cAAc,CAC7B,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC5B,cAAc,GAAG,IAAI,CAMvB;AAED,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,GAAG,IAAI,CAM1E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAI7C;AAED,MAAM,MAAM,uBAAuB,GAAG;IACrC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,mBAAmB,EAC5B,OAAO,GAAE,uBAA4B,GACnC,SAAS,CAkCX;AAQD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACZ,CAEA;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAM9D"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * `@businessdash/sdk/model3d` — 3D product models on the org's own site.
3
+ *
4
+ * ## This ships no renderer, and that is the point
5
+ *
6
+ * A three.js build is ~600KB before your model. `<model-viewer>` is ~300KB. An
7
+ * SDK that pulled either down on every product page would be an SDK people rip
8
+ * out, and it would make the choice of engine ours rather than yours.
9
+ *
10
+ * So this decides WHAT to show and hands you the facts. You mount whichever
11
+ * viewer you already use, or none.
12
+ *
13
+ * ```ts
14
+ * const plan = planProductModel(product);
15
+ * if (plan.ar) showArLink(plan.ar.url); // zero JS, native iOS
16
+ * if (plan.viewer) mountYourViewer(plan.viewer.url, plan.viewer.format);
17
+ * if (plan.download) showLink(plan.download.url, plan.download.label);
18
+ * ```
19
+ *
20
+ * ## The three formats do genuinely different jobs
21
+ *
22
+ * **AR Quick Look (`.usdz`)** — the one worth having. On iOS, iPadOS and
23
+ * visionOS Safari an `<a rel="ar">` opens the model in the room, in the camera,
24
+ * with no JavaScript at all. No library, no canvas, no WebGL. Where it applies
25
+ * it beats an embedded viewer on every axis, so it is checked first.
26
+ *
27
+ * **Web viewer (`.glb`/`.gltf`/`.obj`/`.stl`)** — the rotatable canvas. `.glb`
28
+ * carries its own materials and is what you want; `.obj` and `.stl` are
29
+ * geometry only and render in a neutral grey, which is fine for a machined part
30
+ * and disappointing for a sofa.
31
+ *
32
+ * **CAD download (`.step`/`.stp`/`.iges`)** — NOT renderable, deliberately.
33
+ * STEP is a boundary-representation format needing a geometry kernel; the
34
+ * browser WASM builds of OpenCascade that can tessellate it are 10–30MB, which
35
+ * is not something to pull down for a product photo. It is also the wrong shape
36
+ * for who asks: an engineer evaluating a bracket wants the file in their own CAD
37
+ * package, not a spinning preview.
38
+ *
39
+ * ## Absent is the normal case
40
+ *
41
+ * These fields are stripped unless the org holds the `ecommerce.product_3d`
42
+ * add-on, and most businesses never attach a model. Every function here treats
43
+ * missing as ordinary and returns nothing to render.
44
+ *
45
+ * @module
46
+ */
47
+ /** Lowercased extension, ignoring query strings and fragments. */
48
+ function extensionOf(url) {
49
+ const path = url.split(/[?#]/)[0] ?? "";
50
+ const last = path.slice(path.lastIndexOf("/") + 1);
51
+ const dot = last.lastIndexOf(".");
52
+ return dot === -1 ? "" : last.slice(dot + 1).toLowerCase();
53
+ }
54
+ /** Which web viewer format a URL is, if any. */
55
+ export function webModelFormat(url) {
56
+ if (!url)
57
+ return null;
58
+ const ext = extensionOf(url);
59
+ return ext === "glb" || ext === "gltf" || ext === "obj" || ext === "stl"
60
+ ? ext
61
+ : null;
62
+ }
63
+ /** Which CAD family a URL belongs to. Unknown extensions are `native`. */
64
+ export function cadFormat(url) {
65
+ if (!url)
66
+ return null;
67
+ const ext = extensionOf(url);
68
+ if (ext === "step" || ext === "stp")
69
+ return "step";
70
+ if (ext === "iges" || ext === "igs")
71
+ return "iges";
72
+ return ext ? "native" : null;
73
+ }
74
+ /**
75
+ * Does THIS browser support AR Quick Look?
76
+ *
77
+ * Feature-detected rather than sniffed: Safari advertises support by
78
+ * recognising `rel="ar"` on an anchor. That is Apple's own documented check and
79
+ * it survives the next user-agent change, which a regex on "iPhone" does not.
80
+ *
81
+ * False on the server, so a plan built during SSR omits the AR branch. Re-plan
82
+ * on the client if you want the link to appear without a navigation — the check
83
+ * is a few microseconds.
84
+ */
85
+ export function supportsArQuickLook() {
86
+ if (typeof document === "undefined")
87
+ return false;
88
+ const anchor = document.createElement("a");
89
+ return Boolean(anchor.relList?.supports?.("ar"));
90
+ }
91
+ /**
92
+ * Decide what to render for one product.
93
+ *
94
+ * AR is not exclusive with the viewer — a product can offer both, and on an
95
+ * iPhone the usual arrangement is a canvas with a "View in your room" button
96
+ * over it. The plan reports each independently rather than picking for you.
97
+ */
98
+ export function planProductModel(product, options = {}) {
99
+ const arSupported = options.arSupported ?? supportsArQuickLook();
100
+ const usdz = product.model3dUsdzUrl?.trim() || null;
101
+ const ar = arSupported && usdz ? { url: usdz } : null;
102
+ const viewerUrl = product.model3dUrl?.trim() || null;
103
+ const format = webModelFormat(viewerUrl);
104
+ const viewer = viewerUrl && format
105
+ ? {
106
+ url: viewerUrl,
107
+ format,
108
+ // .obj and .stl are geometry only. A viewer lighting them like
109
+ // a .glb renders a black silhouette.
110
+ neutralMaterial: format === "obj" || format === "stl",
111
+ }
112
+ : null;
113
+ const cadName = product.model3dCadName?.trim() || null;
114
+ // Inferred from the filename, since the URL is never in the payload. Falls
115
+ // back to `native`, which only changes the default label.
116
+ const cad = product.model3dCadAvailable
117
+ ? (cadFormat(cadName) ?? "native")
118
+ : null;
119
+ const download = cad && options.cadDownloadUrl
120
+ ? {
121
+ url: options.cadDownloadUrl,
122
+ label: cadName || defaultCadLabel(cad),
123
+ format: cad,
124
+ }
125
+ : null;
126
+ return { ar, viewer, download, empty: !ar && !viewer && !download && !usdz };
127
+ }
128
+ function defaultCadLabel(format) {
129
+ if (format === "step")
130
+ return "Download STEP file";
131
+ if (format === "iges")
132
+ return "Download IGES file";
133
+ return "Download CAD file";
134
+ }
135
+ /**
136
+ * The attributes an AR Quick Look anchor needs.
137
+ *
138
+ * Spread onto your own `<a>`. Quick Look requires an `<img>` or equivalent
139
+ * child — an empty anchor silently does nothing, which is the single most
140
+ * common way this gets implemented wrong.
141
+ */
142
+ export function arLinkAttributes(url) {
143
+ return { href: url, rel: "ar" };
144
+ }
145
+ /**
146
+ * True when the org has the 3D add-on, judged from a product payload.
147
+ *
148
+ * The API omits these keys entirely without `ecommerce.product_3d`, so their
149
+ * absence distinguishes "not paid for" from "paid for, none attached" — where
150
+ * the key is present and null. Useful for deciding whether to show an upsell
151
+ * rather than nothing.
152
+ */
153
+ export function hasModel3dEntitlement(product) {
154
+ return ("model3dUrl" in product ||
155
+ "model3dUsdzUrl" in product ||
156
+ "model3dCadAvailable" in product);
157
+ }
158
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/model3d-core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAuDH,kEAAkE;AAClE,SAAS,WAAW,CAAC,GAAW;IAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AAC5D,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,cAAc,CAC7B,GAA8B;IAE9B,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,GAAG,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,KAAK,IAAI,GAAG,KAAK,KAAK;QACvE,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,IAAI,CAAC;AACT,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,SAAS,CAAC,GAA8B;IACvD,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,MAAM,CAAC;IACnD,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,MAAM,CAAC;IACnD,OAAO,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB;IAClC,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IAClD,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAC3C,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AAClD,CAAC;AAwBD;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAC/B,OAA4B,EAC5B,UAAmC,EAAE;IAErC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,mBAAmB,EAAE,CAAC;IACjE,MAAM,IAAI,GAAG,OAAO,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IACpD,MAAM,EAAE,GAAG,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAEtD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IACrD,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,MAAM,GACX,SAAS,IAAI,MAAM;QAClB,CAAC,CAAC;YACA,GAAG,EAAE,SAAS;YACd,MAAM;YACN,+DAA+D;YAC/D,qCAAqC;YACrC,eAAe,EAAE,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,KAAK;SACrD;QACF,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IACvD,2EAA2E;IAC3E,0DAA0D;IAC1D,MAAM,GAAG,GAAG,OAAO,CAAC,mBAAmB;QACtC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC;QAClC,CAAC,CAAC,IAAI,CAAC;IACR,MAAM,QAAQ,GACb,GAAG,IAAI,OAAO,CAAC,cAAc;QAC5B,CAAC,CAAC;YACA,GAAG,EAAE,OAAO,CAAC,cAAc;YAC3B,KAAK,EAAE,OAAO,IAAI,eAAe,CAAC,GAAG,CAAC;YACtC,MAAM,EAAE,GAAG;SACX;QACF,CAAC,CAAC,IAAI,CAAC;IAET,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;AAC9E,CAAC;AAED,SAAS,eAAe,CAAC,MAAiB;IACzC,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,oBAAoB,CAAC;IACnD,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,oBAAoB,CAAC;IACnD,OAAO,mBAAmB,CAAC;AAC5B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAI3C,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AACjC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACpD,OAAO,CACN,YAAY,IAAI,OAAO;QACvB,gBAAgB,IAAI,OAAO;QAC3B,qBAAqB,IAAI,OAAO,CAChC,CAAC;AACH,CAAC"}
@@ -0,0 +1,315 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/notifications-core/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ createNotificationFeed: () => createNotificationFeed,
24
+ portalSource: () => portalSource,
25
+ pushSource: () => pushSource,
26
+ toToast: () => toToast
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+ function dedupeKey(input) {
30
+ if (input.id) return input.id;
31
+ const entity = typeof input.data?.entityId === "string" ? input.data.entityId : "";
32
+ return [input.kind ?? "unknown", input.orgId ?? "", entity, input.title].join(
33
+ "|"
34
+ );
35
+ }
36
+ function createNotificationFeed(options = {}) {
37
+ const handlers = /* @__PURE__ */ new Set();
38
+ const history = [];
39
+ const seen = /* @__PURE__ */ new Map();
40
+ const teardowns = [];
41
+ const dedupeWindowMs = options.dedupeWindowMs ?? 5 * 60 * 1e3;
42
+ const historyLimit = options.historyLimit ?? 50;
43
+ let running = false;
44
+ let destroyed = false;
45
+ function fail(cause) {
46
+ options.onError?.(
47
+ cause instanceof Error ? cause : new Error(String(cause))
48
+ );
49
+ }
50
+ function deliver(input) {
51
+ if (destroyed) return;
52
+ const key = dedupeKey(input);
53
+ const now = Date.now();
54
+ for (const [id, at] of seen) {
55
+ if (now - at > dedupeWindowMs) seen.delete(id);
56
+ }
57
+ if (seen.has(key)) return;
58
+ seen.set(key, now);
59
+ const notification = {
60
+ id: input.id ?? key,
61
+ source: input.source ?? "local",
62
+ category: input.category ?? "transactional",
63
+ kind: input.kind ?? "notification",
64
+ title: input.title,
65
+ body: input.body ?? null,
66
+ url: input.url ?? null,
67
+ severity: input.severity ?? "info",
68
+ occurredAt: input.occurredAt ?? new Date(now).toISOString(),
69
+ orgId: input.orgId ?? null,
70
+ data: input.data ?? {}
71
+ };
72
+ history.unshift(notification);
73
+ if (history.length > historyLimit) history.length = historyLimit;
74
+ for (const handler of handlers) {
75
+ try {
76
+ handler(notification);
77
+ } catch (cause) {
78
+ fail(cause);
79
+ }
80
+ }
81
+ }
82
+ return {
83
+ subscribe(handler) {
84
+ handlers.add(handler);
85
+ return () => {
86
+ handlers.delete(handler);
87
+ };
88
+ },
89
+ emit(input) {
90
+ deliver({ ...input, source: input.source ?? "local" });
91
+ },
92
+ start() {
93
+ if (running || destroyed) return;
94
+ running = true;
95
+ const sources = [
96
+ pushSource({
97
+ ...options.closeOsNotificationWhenFocused === void 0 ? {} : {
98
+ closeOsNotificationWhenFocused: options.closeOsNotificationWhenFocused
99
+ },
100
+ onError: fail
101
+ }),
102
+ ...options.portal ? [
103
+ portalSource({
104
+ portal: options.portal,
105
+ ...options.pollIntervalMs === void 0 ? {} : { intervalMs: options.pollIntervalMs }
106
+ })
107
+ ] : [],
108
+ ...options.sources ?? []
109
+ ];
110
+ for (const source of sources) {
111
+ try {
112
+ teardowns.push(source(deliver));
113
+ } catch (cause) {
114
+ fail(cause);
115
+ }
116
+ }
117
+ },
118
+ stop() {
119
+ running = false;
120
+ while (teardowns.length) {
121
+ try {
122
+ teardowns.pop()?.();
123
+ } catch (cause) {
124
+ fail(cause);
125
+ }
126
+ }
127
+ },
128
+ recent() {
129
+ return [...history];
130
+ },
131
+ destroy() {
132
+ this.stop();
133
+ destroyed = true;
134
+ handlers.clear();
135
+ history.length = 0;
136
+ seen.clear();
137
+ }
138
+ };
139
+ }
140
+ function pushSource(options = {}) {
141
+ return (emit) => {
142
+ if (typeof navigator === "undefined" || !("serviceWorker" in navigator) || typeof window === "undefined") {
143
+ return () => void 0;
144
+ }
145
+ const listener = (event) => {
146
+ const message = event.data;
147
+ if (message?.type !== "businessdash:push" || !message.payload) return;
148
+ const payload = message.payload;
149
+ const data = typeof payload.data === "object" && payload.data !== null ? payload.data : {};
150
+ emit({
151
+ ...typeof payload.id === "string" ? { id: payload.id } : {},
152
+ source: "push",
153
+ ...typeof payload.category === "string" ? { category: payload.category } : {},
154
+ ...typeof payload.kind === "string" ? { kind: payload.kind } : {},
155
+ title: typeof payload.title === "string" ? payload.title : "Notification",
156
+ body: typeof payload.body === "string" ? payload.body : null,
157
+ url: typeof payload.url === "string" ? payload.url : null,
158
+ ...typeof payload.orgId === "string" ? { orgId: payload.orgId } : {},
159
+ ...typeof payload.occurredAt === "string" ? { occurredAt: payload.occurredAt } : {},
160
+ data
161
+ });
162
+ if (options.closeOsNotificationWhenFocused && document.visibilityState === "visible") {
163
+ navigator.serviceWorker.ready.then(
164
+ (registration) => registration.getNotifications(
165
+ typeof payload.tag === "string" ? { tag: payload.tag } : {}
166
+ )
167
+ ).then((notifications) => {
168
+ for (const notification of notifications) notification.close();
169
+ }).catch((cause) => options.onError?.(cause));
170
+ }
171
+ };
172
+ navigator.serviceWorker.addEventListener("message", listener);
173
+ return () => {
174
+ navigator.serviceWorker.removeEventListener("message", listener);
175
+ };
176
+ };
177
+ }
178
+ function portalSource(options) {
179
+ const intervalMs = Math.max(15e3, options.intervalMs ?? 6e4);
180
+ return (emit) => {
181
+ let stopped = false;
182
+ let baseline = null;
183
+ let timer = null;
184
+ function readWatermark() {
185
+ const snapshot = options.portal.snapshot();
186
+ return {
187
+ unreadMessages: snapshot.unreadMessageCount,
188
+ orderStatuses: new Map(
189
+ (snapshot.orders?.items ?? []).map((o) => [o.id, String(o.status)])
190
+ ),
191
+ invoiceStatuses: new Map(
192
+ (snapshot.invoices?.items ?? []).map((i) => [i.id, String(i.status)])
193
+ ),
194
+ shipmentStatuses: new Map(
195
+ (snapshot.shipments?.items ?? []).map((sh) => [
196
+ sh.id,
197
+ String(sh.status ?? "unknown")
198
+ ])
199
+ )
200
+ };
201
+ }
202
+ function diff(previous, next) {
203
+ const orgId = options.portal.snapshot().context?.organization?.id ?? null;
204
+ if (next.unreadMessages > previous.unreadMessages) {
205
+ const delta = next.unreadMessages - previous.unreadMessages;
206
+ emit({
207
+ source: "poll",
208
+ category: "messages",
209
+ kind: "message.received",
210
+ title: delta === 1 ? "New message" : `${delta} new messages`,
211
+ body: "You have a new message from the team.",
212
+ severity: "info",
213
+ orgId,
214
+ // Keyed on the resulting count rather than the delta, so two
215
+ // tabs polling at different moments agree on the id.
216
+ data: { entityId: `unread:${next.unreadMessages}` }
217
+ });
218
+ }
219
+ for (const [id, status] of next.orderStatuses) {
220
+ const before = previous.orderStatuses.get(id);
221
+ if (before === void 0 || before === status) continue;
222
+ emit({
223
+ source: "poll",
224
+ category: "transactional",
225
+ kind: `order.${status}`,
226
+ title: orderTitle(status),
227
+ body: null,
228
+ severity: status === "cancelled" ? "warning" : "info",
229
+ orgId,
230
+ data: { entityId: `order:${id}:${status}`, orderId: id, status }
231
+ });
232
+ }
233
+ for (const [id, status] of next.invoiceStatuses) {
234
+ const before = previous.invoiceStatuses.get(id);
235
+ if (before === void 0 || before === status) continue;
236
+ emit({
237
+ source: "poll",
238
+ category: "transactional",
239
+ kind: `invoice.${status}`,
240
+ title: status === "paid" ? "Invoice paid" : status === "overdue" ? "Invoice overdue" : "Invoice updated",
241
+ body: null,
242
+ severity: status === "overdue" ? "error" : "info",
243
+ orgId,
244
+ data: { entityId: `invoice:${id}:${status}`, invoiceId: id, status }
245
+ });
246
+ }
247
+ for (const [id, status] of next.shipmentStatuses) {
248
+ const before = previous.shipmentStatuses.get(id);
249
+ if (before === void 0 || before === status) continue;
250
+ emit({
251
+ source: "poll",
252
+ category: "transactional",
253
+ kind: `shipment.${status}`,
254
+ title: status === "delivered" ? "Your order was delivered" : status === "out_for_delivery" ? "Out for delivery" : "Shipping update",
255
+ body: null,
256
+ severity: "info",
257
+ orgId,
258
+ data: {
259
+ entityId: `shipment:${id}:${status}`,
260
+ shipmentId: id,
261
+ status
262
+ }
263
+ });
264
+ }
265
+ }
266
+ async function tick() {
267
+ if (stopped) return;
268
+ await Promise.allSettled([
269
+ options.portal.loadOrders(),
270
+ options.portal.loadInvoices(),
271
+ options.portal.loadShipments(),
272
+ options.portal.loadMessages()
273
+ ]);
274
+ if (stopped) return;
275
+ const next = readWatermark();
276
+ if (baseline) diff(baseline, next);
277
+ baseline = next;
278
+ }
279
+ baseline = readWatermark();
280
+ timer = setInterval(() => void tick(), intervalMs);
281
+ return () => {
282
+ stopped = true;
283
+ if (timer) clearInterval(timer);
284
+ };
285
+ };
286
+ }
287
+ function orderTitle(status) {
288
+ switch (status) {
289
+ case "shipped":
290
+ return "Your order shipped";
291
+ case "delivered":
292
+ return "Your order was delivered";
293
+ case "cancelled":
294
+ return "Your order was cancelled";
295
+ case "refunded":
296
+ return "Your refund was issued";
297
+ default:
298
+ return "Order updated";
299
+ }
300
+ }
301
+ function toToast(notification) {
302
+ return {
303
+ title: notification.title,
304
+ description: notification.body ?? void 0,
305
+ variant: notification.severity === "error" ? "destructive" : notification.severity === "warning" ? "warning" : notification.severity === "success" ? "success" : "default",
306
+ action: notification.url ? { label: "View", url: notification.url } : void 0
307
+ };
308
+ }
309
+ // Annotate the CommonJS export names for ESM import in node:
310
+ 0 && (module.exports = {
311
+ createNotificationFeed,
312
+ portalSource,
313
+ pushSource,
314
+ toToast
315
+ });