@hachther/akilio-widget 0.7.0 → 1.1.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 (45) hide show
  1. package/README.md +331 -26
  2. package/dist/_headers +16 -0
  3. package/dist/akilio-widget.min.js +45 -44
  4. package/dist/assets/EmailIcon.d.ts +2 -0
  5. package/dist/assets/FormIcon.d.ts +2 -0
  6. package/dist/assets/PhoneIcon.d.ts +2 -0
  7. package/dist/components/BrandLogo.d.ts +7 -1
  8. package/dist/components/CartPanel.d.ts +13 -0
  9. package/dist/components/CommerceActions.d.ts +11 -0
  10. package/dist/components/Composer.d.ts +7 -1
  11. package/dist/components/ContactActions.d.ts +2 -2
  12. package/dist/components/EmptyState.d.ts +3 -7
  13. package/dist/components/Icons.d.ts +3 -0
  14. package/dist/components/IdentityVerification.d.ts +14 -0
  15. package/dist/components/InlineDecisionCard.d.ts +2 -0
  16. package/dist/components/Launcher.d.ts +6 -1
  17. package/dist/components/MessageBubble.d.ts +9 -2
  18. package/dist/components/MessageList.d.ts +1 -1
  19. package/dist/components/ProductCard.d.ts +4 -2
  20. package/dist/components/ProductCards.d.ts +6 -1
  21. package/dist/components/ProductDetail.d.ts +12 -0
  22. package/dist/components/ProductVariantSelector.d.ts +9 -0
  23. package/dist/components/SectionPrompt.d.ts +2 -0
  24. package/dist/components/TextSelectionPrompt.d.ts +2 -0
  25. package/dist/components/VoiceRecorder.d.ts +11 -0
  26. package/dist/hooks/current-cart.d.ts +14 -0
  27. package/dist/hooks/proactive-summary.d.ts +1 -0
  28. package/dist/hooks/storage.d.ts +2 -0
  29. package/dist/index.d.ts +5 -1
  30. package/dist/index.min.js +10412 -7169
  31. package/dist/index.umd.min.cjs +37 -36
  32. package/dist/lib/cart-capabilities.d.ts +4 -0
  33. package/dist/lib/client.d.ts +35 -2
  34. package/dist/lib/copy.d.ts +8 -2
  35. package/dist/lib/storefront-cart.d.ts +5 -0
  36. package/dist/loader.js +46 -0
  37. package/dist/locales/en.d.ts +161 -0
  38. package/dist/locales/fr.d.ts +161 -0
  39. package/dist/locales/index.d.ts +3 -0
  40. package/dist/releases/1.1.0/akilio-widget.min.js +46 -0
  41. package/dist/style.css +1842 -81
  42. package/dist/types.d.ts +569 -31
  43. package/dist/vanilla.d.ts +1 -0
  44. package/dist/widget-manifest.json +8 -0
  45. package/package.json +5 -3
package/README.md CHANGED
@@ -63,10 +63,7 @@ placed at the bottom-left or displayed as a vertical tab in the middle of the
63
63
  right viewport edge:
64
64
 
65
65
  ```tsx
66
- <AkilioWidget
67
- projectKey='your-project-key'
68
- launcherPosition='right-middle'
69
- />
66
+ <AkilioWidget projectKey='your-project-key' launcherPosition='right-middle' />
70
67
  ```
71
68
 
72
69
  Supported values are `bottom-right`, `bottom-left`, and `right-middle`. The
@@ -76,6 +73,22 @@ the compact bottom-right launcher and the normal mobile presentation.
76
73
 
77
74
  The standalone equivalent is `data-launcher-position="right-middle"`.
78
75
 
76
+ ## Adaptive launcher
77
+
78
+ The built-in launcher defaults to Akilio’s compact adaptive experience: it
79
+ appears as an icon, expands once with a page-aware invitation, then stays quiet.
80
+ It can show a single answer-ready signal when a response completes while chat is
81
+ closed. Discovery and dismissal are remembered per project, and motion is
82
+ automatically reduced for visitors who request it.
83
+
84
+ Use the original persistent label while validating the new experience:
85
+
86
+ ```tsx
87
+ <AkilioWidget launcherExperience='static' />
88
+ ```
89
+
90
+ Standalone scripts use `data-launcher-experience="static"`.
91
+
79
92
  ## Page-end contextual prompt
80
93
 
81
94
  Documentation pages can show a compact “Ask about this page” input when the
@@ -181,11 +194,7 @@ and is dismissed when the visitor closes it, opens the widget, or presses
181
194
  Escape. Dismissal is stored per project and tour version.
182
195
 
183
196
  ```tsx
184
- <AkilioWidget
185
- enableTour
186
- tourDelayMs={3000}
187
- tourVersion="v1"
188
- />
197
+ <AkilioWidget enableTour tourDelayMs={3000} tourVersion='v1' />
189
198
  ```
190
199
 
191
200
  Standalone attributes are `data-enable-tour`, `data-tour-delay-ms`, and
@@ -203,12 +212,14 @@ preferences.
203
212
  ## Capability-driven chat actions
204
213
 
205
214
  The widget reads `capabilities.chat` from the public project configuration. An
206
- enabled `summarize_page` intent that supports the `widget` surface is shown as
207
- an explicit “Summarize this page” action when its `page.url` requirement is
208
- available. Selecting it sends `intent: "summarize_page"` and the current page
209
- context to the chat endpoint. Unsupported, disabled, wrong-surface, or
210
- unmet-requirement actions are not displayed. Older API responses without the
211
- capability catalog retain the previous suggestion behavior.
215
+ enabled `summarize_page` intent that supports the `widget` surface is shown in
216
+ an action tray immediately above the composer when its `page.url` requirement
217
+ is available. Selecting it sends `intent: "summarize_page"` and the current
218
+ page context to the chat endpoint. Unsupported, disabled, wrong-surface, or
219
+ unmet-requirement actions are not displayed. The action tray remains available
220
+ throughout the conversation and is temporarily hidden while a response streams.
221
+ Older API responses without the capability catalog retain the previous
222
+ suggestion behavior.
212
223
 
213
224
  An enabled `contact` intent adds a “Contact the team” action. Contact responses
214
225
  can display validated `email`, `phone`, and `form` links from `contact_options`.
@@ -245,7 +256,11 @@ dist/index.min.js
245
256
  dist/index.umd.min.cjs
246
257
  dist/index.d.ts
247
258
  dist/style.css
259
+ dist/loader.js
260
+ dist/widget-manifest.json
261
+ dist/releases/0.7.0/akilio-widget.min.js
248
262
  dist/akilio-widget.min.js
263
+ dist/_headers
249
264
  ```
250
265
 
251
266
  ## React
@@ -315,10 +330,13 @@ The token resolver is evaluated for every request, so a host application can rot
315
330
 
316
331
  ## Standalone script
317
332
 
333
+ For production websites, use the stable loader URL:
334
+
318
335
  ```html
319
336
  <script
320
337
  data-akilio-widget
321
- src="/assets/akilio-widget.min.js"
338
+ data-cfasync="false"
339
+ src="https://cdn.example.com/widget/loader.js"
322
340
  data-api-base-url="https://api.akilio-ai.com"
323
341
  data-project-key="ask_pk_xxx"
324
342
  data-mode="floating"
@@ -334,19 +352,76 @@ For an inline widget:
334
352
 
335
353
  ```html
336
354
  <div id="support-assistant" style="height: 680px"></div>
337
- <script src="/assets/akilio-widget.min.js" data-auto-init="false"></script>
355
+ <script
356
+ src="https://cdn.example.com/widget/loader.js"
357
+ data-akilio-widget
358
+ data-auto-init="false"
359
+ ></script>
338
360
  <script>
339
- window.Akilio.mount({
340
- target: '#support-assistant',
341
- apiBaseUrl: 'https://api.akilio-ai.com',
342
- projectKey: 'ask_pk_xxx',
343
- mode: 'inline',
344
- colorMode: 'system',
345
- accessToken: 'short-lived-widget-token',
361
+ window.addEventListener('akilio:loader-ready', () => {
362
+ window.Akilio.mount({
363
+ target: '#support-assistant',
364
+ apiBaseUrl: 'https://api.akilio-ai.com',
365
+ projectKey: 'ask_pk_xxx',
366
+ mode: 'inline',
367
+ colorMode: 'system',
368
+ accessToken: 'short-lived-widget-token',
369
+ });
346
370
  });
347
371
  </script>
348
372
  ```
349
373
 
374
+ `loader.js` is revalidated by the browser and loads the immutable release file
375
+ for the current package version. Deploy the complete `dist` directory without
376
+ deleting earlier `dist/releases/*` versions. Each build also keeps
377
+ `akilio-widget.min.js` as a non-immutable compatibility file.
378
+
379
+ For optional Cloudflare Pages deployments, the generated `dist/_headers` requires browser and edge
380
+ revalidation for `loader.js` and `widget-manifest.json`. Files under
381
+ `releases/*` receive a one-year immutable browser and edge cache. Configure
382
+ Cloudflare Browser Cache TTL to **Respect Existing Headers** for this path so a
383
+ cache rule does not keep the loader stale.
384
+
385
+ Cloudflare R2 does not use `_headers`; the R2 deployment command writes the
386
+ equivalent `Cache-Control` metadata on each uploaded object.
387
+
388
+ Publishing a new package version updates only the loader and manifest pointers;
389
+ existing embed snippets do not change and a manual cache purge is not normally
390
+ required. The manifest includes the active version, release path, byte size,
391
+ and SHA-256 digest for deployment verification.
392
+
393
+ ### Deploy to Cloudflare R2
394
+
395
+ Set the R2 bucket name in your local `.env` or shell environment:
396
+
397
+ ```bash
398
+ CLOUDFLARE_R2_BUCKET=your-r2-bucket
399
+ # Optional folder within the bucket:
400
+ CLOUDFLARE_R2_PREFIX=widget
401
+ ```
402
+
403
+ Then validate, build, and publish the CDN assets with:
404
+
405
+ ```bash
406
+ npm run deploy:r2
407
+ ```
408
+
409
+ You can also provide the target without storing it in `.env`:
410
+
411
+ ```bash
412
+ npm run deploy:r2 -- --bucket your-r2-bucket --prefix widget
413
+ ```
414
+
415
+ Wrangler uses an existing local Cloudflare login. In CI, provide
416
+ `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` as protected environment
417
+ variables. Never commit a Cloudflare API token.
418
+
419
+ The deploy command uploads the immutable versioned bundle first, followed by
420
+ the compatibility bundle, manifest, and finally `loader.js`. The versioned file
421
+ receives a one-year immutable cache policy. Stable files receive
422
+ `max-age=0, must-revalidate`, so the CDN entry point can discover each release.
423
+ Add `--dry-run` to build and inspect the target object paths without uploading.
424
+
350
425
  The standalone API can hide the launcher and control the chat imperatively:
351
426
 
352
427
  ```js
@@ -476,7 +551,10 @@ The package itself is now safe to import in an SSR module. The component must st
476
551
 
477
552
  ## Ecommerce responses
478
553
 
479
- When the chat API returns a `commerce` capability, the widget automatically displays its products below the assistant answer. No additional configuration is required.
554
+ When the chat API returns a `commerce` capability, the widget renders a compact
555
+ commerce surface inside the assistant message. Direct matches, recommendations,
556
+ comparisons, compatible products, bundles, upsells, and cross-sells receive
557
+ capability-aware headings and layouts.
480
558
 
481
559
  ```tsx
482
560
  <AkilioWidget
@@ -488,7 +566,42 @@ When the chat API returns a `commerce` capability, the widget automatically disp
488
566
  />
489
567
  ```
490
568
 
491
- Product links open in a new tab. The widget also sends an authenticated commerce event to `/api/v1/commerce/events/` using the response capability (`search` or `recommendation`).
569
+ Product links open through the existing product callback. Trusted
570
+ `commerce.actions` are matched only to products returned in the same response.
571
+ `add_to_cart` proposals require a second explicit confirmation, then use the
572
+ backend's one-time capability-confirmation flow and an idempotency key before a
573
+ cart tool is executed. The provider cart ID is retained in `sessionStorage` for
574
+ subsequent additions during the same browser session. The widget also records
575
+ authenticated commerce events.
576
+
577
+ The widget refreshes `GET /commerce/cart/current/` whenever its chat panel is
578
+ opened. The header cart control shows the returned line items and only exposes a
579
+ checkout link supplied by the backend. A chat response with `cart_state` causes
580
+ an immediate refresh, ensuring the local cart display follows server-side cart
581
+ changes without treating the compact summary as the source of truth.
582
+
583
+ ### `/chat/` response contract
584
+
585
+ `AkilioChatResponse` follows the public OpenAPI `ChatResponse` schema. It
586
+ supports documented conversation context, answer content, citations, commerce,
587
+ suggestions, warnings, market resolution, grounding/refusal flags, escalation,
588
+ contact options, customer actions, agent tools, and intent decisions. Commerce
589
+ products and actions are runtime-validated before they are rendered because the
590
+ OpenAPI schema deliberately leaves those objects extensible.
591
+
592
+ The documented response does not include top-level `images`, `rich_actions`,
593
+ `forms`, or `cart` fields. The widget does not treat those fields as part of its
594
+ public chat contract. Add them to the backend OpenAPI schema before introducing
595
+ matching widget rendering.
596
+
597
+ ## Human handoff
598
+
599
+ When a configured contact action is submitted, the widget sends its consented
600
+ request to `POST /chat/contact-requests/` with the conversation and assistant
601
+ message that offered the action. `POST /chat/handoffs/` is an equivalent backend
602
+ alias. The backend derives the conversation summary, intent, customer context,
603
+ and action context from the validated conversation. The widget renders the
604
+ browser-safe handoff delivery status returned by the API.
492
605
 
493
606
  ## Assistant mode
494
607
 
@@ -519,3 +632,195 @@ For the standalone build:
519
632
  ## Follow-up suggestions
520
633
 
521
634
  When `/api/v1/chat/` returns a `suggestions` array, the widget displays accessible suggestion chips under that assistant response. Selecting a chip sends it as the next user message. Suggestions are retained in local history and restored from server conversation message metadata or structured content when supplied by the API.
635
+
636
+ ## Widget Core (AKI-WIDGET-001)
637
+
638
+ Built-in interface translations cover English and French (including regional
639
+ locales such as `fr-CA`). Supply `locale` and `copy` for other languages; missing
640
+ translations fall back to English. The widget sets its language and direction
641
+ for common right-to-left locales. The standalone script reads the page language.
642
+ The backend receives the requested locale for generated responses.
643
+
644
+ White-label policy hides Akilio marks in the launcher, discovery tip, header,
645
+ messages, and confirmation cards. Default text becomes neutral; explicitly
646
+ configured project titles and copy remain under the integrator's control.
647
+
648
+ History, preferences, configuration, and anonymous continuation credentials use
649
+ browser storage with an in-memory fallback when storage is blocked or full.
650
+ Persistent storage is required to resume after a full page reload; memory-only
651
+ sessions remain usable during the current visit. History is scoped by project
652
+ and locale and retains the latest 60 messages.
653
+
654
+ Mobile forms use 16px inputs and main controls have 44px touch targets, alongside
655
+ viewport sizing and safe-area padding. Physical-device keyboard testing and live
656
+ backend acceptance testing are still required before production sign-off.
657
+
658
+ ## Adding languages
659
+
660
+ Translations live in `src/locales/en.ts` and `src/locales/fr.ts`. To ship a new
661
+ built-in language:
662
+
663
+ 1. Copy `en.ts` to a new file such as `es.ts` and rename the export to `es`.
664
+ 2. Translate every message, the starter questions, and the `whiteLabel` wording.
665
+ Preserve placeholders such as `{seconds}`. Set `direction` to `ltr` or `rtl`.
666
+ 3. Import the pack in `src/locales/index.ts` and add it to `builtInLanguages`.
667
+ 4. Run `npm run typecheck`, `npm test`, and `npm run build`.
668
+
669
+ Each complete pack uses `satisfies AkilioLanguagePack`, so missing translation
670
+ keys are reported by TypeScript when the interface grows.
671
+
672
+ You can also add languages without rebuilding the widget using the `translations`
673
+ option. Partial packs are supported; untranslated text falls back to English:
674
+
675
+ ```tsx
676
+ import type { AkilioTranslations } from '@hachther/akilio-widget';
677
+
678
+ const translations = {
679
+ es: {
680
+ direction: 'ltr',
681
+ messages: {
682
+ title: 'Asistente',
683
+ launcher: 'Hacer una pregunta',
684
+ submit: 'Enviar',
685
+ placeholder: 'Escribe tu pregunta...',
686
+ suggestions: ['¿Cómo puedo contactar con el equipo?'],
687
+ },
688
+ whiteLabel: {
689
+ title: 'Asistente',
690
+ launcher: 'Hacer una pregunta',
691
+ configFailed: 'No se puede cargar la configuración.',
692
+ },
693
+ },
694
+ } satisfies AkilioTranslations;
695
+
696
+ <AkilioWidget
697
+ projectKey='your-project-key'
698
+ locale='es-MX'
699
+ translations={translations}
700
+ />;
701
+ ```
702
+
703
+ The same dictionary works with `window.Akilio.mount({ projectKey: 'your-project-key',
704
+ locale: 'es-MX', translations })`. For script integrations, use programmatic mounting
705
+ with auto-init disabled when supplying dictionaries.
706
+
707
+ Locale matching ignores case and accepts underscores. The fallback order is the
708
+ most specific locale, then its parent language/script, then English. For example,
709
+ `zh-Hant-TW` inherits from `zh-Hant`, `zh`, and `en`. Custom dictionaries override
710
+ built-ins at the same locale. Existing project title, placeholder, and starter
711
+ questions still take precedence; the `copy` prop remains the final text override.
712
+ White-label wording is stored separately from branded defaults. Dictionaries are
713
+ scoped to each widget, so one integration cannot change another's translations.
714
+
715
+ Changing `locale` or `translations` props updates React UI copy. The requested
716
+ locale is still sent to the backend; adding UI translations does not configure
717
+ backend response languages. This framework uses plain text messages and existing
718
+ named placeholders, not ICU plural rules.
719
+
720
+ ## Business branding (AKI-WIDGET-002)
721
+
722
+ ```tsx
723
+ <AkilioWidget
724
+ projectKey='your-project-key'
725
+ agentName='Alex'
726
+ welcomeMessage='Welcome to Acme. How can I help?'
727
+ starterPrompts={['Explore our services', 'Contact the team']}
728
+ launcherPosition='bottom-left'
729
+ theme={{
730
+ logo_url: 'https://example.com/logo.png',
731
+ brand_name: 'Acme',
732
+ primary_color: '#123456',
733
+ primary_dark_color: '#102030',
734
+ primary_foreground_color: '#ffffff',
735
+ }}
736
+ />
737
+ ```
738
+
739
+ Business logos appear in the launcher, discovery tip, header, empty state,
740
+ assistant answers, and human-help confirmation cards. HTTP(S) and relative image
741
+ URLs are accepted. Failed or invalid images fall back to the Akilio mark when
742
+ branding is enabled, or a neutral icon when branding is hidden. Required
743
+ “Powered by Akilio” attribution remains visible with a business logo.
744
+
745
+ Name priority: `copy.title`, `agentName`, host `theme.brand_name`, server
746
+ `theme_config.brand_name`, server `title`, then language defaults. Welcome text
747
+ uses `copy.emptyState`, `welcomeMessage`, server `welcome_message`, then language
748
+ defaults. The welcome message appears before the first conversation message.
749
+
750
+ Before configuration arrives, starter prompts use `starterPrompts` and then
751
+ language suggestions. Once available, `starter_questions` from the public
752
+ configuration endpoint is authoritative, including an explicit empty array that
753
+ hides prompts. Up to four are shown; server-advertised capability actions remain
754
+ independent of starter prompts.
755
+
756
+ Standalone embeds accept the same options via `Akilio.mount()` or these attributes:
757
+
758
+ ```html
759
+ <script
760
+ src="https://your-cdn.example/widget/loader.js"
761
+ data-akilio-widget
762
+ data-project-key="your-project-key"
763
+ data-agent-name="Alex"
764
+ data-brand-name="Acme"
765
+ data-logo-url="https://example.com/logo.png"
766
+ data-welcome-message="Welcome to Acme. How can I help?"
767
+ data-starter-prompts='["Explore our services", "Contact the team"]'
768
+ data-theme='{"primary_color":"#123456"}'
769
+ data-launcher-position="bottom-left"
770
+ ></script>
771
+ ```
772
+
773
+ Use `data-starter-prompts='[]'` to hide prompts. Dedicated logo/name attributes
774
+ override corresponding values in `data-theme`. Malformed prompt JSON falls back
775
+ to configuration defaults. Custom React launchers and external HTML buttons using
776
+ `launcher: 'hidden'` with `open()`, `close()`, or `toggle()` remain supported.
777
+ ### Direct product-card cart actions
778
+
779
+ Product cards and product details expose Add to cart automatically when backend
780
+ capability discovery includes executable `commerce.add_to_cart`. Available
781
+ variants receive direct actions independent of the LLM response. Clicking the
782
+ button supplies consent; backend capability confirmation is still executed.
783
+ Shopify products on their own storefront use the Shopify adapter. The selected variant is added through
784
+ the Shopify Ajax Cart API, sharing the website's browser cart, without a chat or
785
+ LLM round trip. Cards retain their variant selector, display update feedback,
786
+ and link to the storefront cart after success. Themes can listen for the
787
+ `akilio:cart-updated` window event to refresh their cart counter or drawer.
788
+
789
+ The backend product payload supplies `cart_provider: "shopify"` to select the
790
+ native adapter when applicable. Other products execute the advertised backend
791
+ cart capability. Actions are hidden for unavailable products and blocked
792
+ business-rule decisions. A backend-managed cart does not necessarily share the
793
+ website browser cart; direct website-cart adapters beyond Shopify are not implemented.
794
+
795
+ ### Voice messages
796
+
797
+ The composer now supports recording, playback preview, send, and cancel on browsers
798
+ with MediaRecorder and microphone permission. HTTPS (or supported localhost access)
799
+ is required. Recording is capped at five minutes and 10 MiB. EN/FR copy can be
800
+ overridden through the existing translation/copy configuration.
801
+
802
+ Sending uploads to the authenticated public chat voice endpoint, polls private
803
+ transcription status, then submits the transcript through normal chat. The backend
804
+ must include the shared voice migrations and a transcription worker (or the existing
805
+ explicit development synchronous-processing mode). Voice input produces text replies;
806
+ this does not enable synthesized voice responses.
807
+
808
+ Voice uploads and polling use the existing widget bearer-token/origin mechanism.
809
+ Microphone capture stops when the panel closes or consent becomes unavailable.
810
+ Update your distributed bundle to make these controls available in deployed widgets.
811
+
812
+ ### Email verification
813
+
814
+ Once a conversation exists, the widget offers **Verify your email** above the composer. The inline form requests an email code, displays the server's masked email, confirms the code, and restores the verified badge from the conversation's server session. It supports resend cooldowns, expiry, cancellation, retry limits, unavailable providers, and English/French copy overrides (`identity*` keys).
815
+
816
+ Verification uses the dedicated `/customer-identity/verifications/`, `/{id}/confirm/`, `/{id}/resend/`, and `/customer-identity/session/` routes under `apiBaseUrl`, with the existing widget authentication. Codes are submitted directly as strings and cleared from the input; they are never chat messages or widget analytics events. Challenge IDs and pending questions are held only in memory. The server determines verification and authorization.
817
+
818
+ A chat response (including a streaming final response) may include `identity_verification_required: { methods: ['email'], purpose: 'identity' }` (`step_up` is also supported). This opens the form. On successful confirmation and an authoritative session lookup, the widget submits the paused question once in the same conversation without duplicating the user's chat bubble. Cancel or a new question discards that continuation. This is a new optional response contract; the backend must emit it when protected actions require verification. It does not itself enforce access to protected actions.
819
+
820
+ The actual verification provider remains a backend integration. Until that provider is configured, delivery returns an unavailable message. No eSauti calls or credentials are implemented in the widget.
821
+
822
+ ### Multiple widget installations
823
+
824
+ Create installations in Portal → Widget. Each has its own public key, assigned Agent, appearance and allowed domains. Use `widgetKey` with the React component or `data-widget-key` on the script tag. The existing `projectKey` / `data-project-key` spelling remains supported. Keys identify installations; the workspace remains the tenant boundary. New conversations use the assigned Agent, while existing conversations retain their original Agent.
825
+
826
+ Managed installations: omit host text/theme and presentation props to follow published Agent text and widget appearance. Public configuration supplies layout, launcher, tour, sound and contextual-prompt options; explicit host props still take precedence. Existing embeds with inline overrides must remove those overrides or replace their snippet once to follow portal publications.
package/dist/_headers ADDED
@@ -0,0 +1,16 @@
1
+ # Cloudflare Pages response headers
2
+ /loader.js
3
+ Cache-Control: public, max-age=0, must-revalidate
4
+ Cloudflare-CDN-Cache-Control: no-cache
5
+
6
+ /widget-manifest.json
7
+ Cache-Control: public, max-age=0, must-revalidate
8
+ Cloudflare-CDN-Cache-Control: no-cache
9
+
10
+ /akilio-widget.min.js
11
+ Cache-Control: public, max-age=0, must-revalidate
12
+ Cloudflare-CDN-Cache-Control: no-cache
13
+
14
+ /releases/*
15
+ Cache-Control: public, max-age=31536000, immutable
16
+ Cloudflare-CDN-Cache-Control: public, max-age=31536000, immutable