@flamingo-stack/openframe-frontend-core 0.0.719 → 0.0.721
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.
- package/dist/assets/index.cjs +6 -0
- package/dist/assets/index.d.ts +1 -0
- package/dist/assets/index.d.ts.map +1 -1
- package/dist/assets/index.js +5 -1
- package/dist/assets/mobile-app-qr.d.ts +17 -0
- package/dist/assets/mobile-app-qr.d.ts.map +1 -0
- package/dist/{chunk-2JLP2X2M.js → chunk-2P2M27EW.js} +2396 -2369
- package/dist/{chunk-IWCPXJEE.js → chunk-2TXGR7IK.js} +138 -63
- package/dist/{chunk-FVQJBII6.js → chunk-3LY7V3RF.js} +3 -3
- package/dist/{chunk-HCFNEKO3.cjs → chunk-3R32ZNA2.cjs} +46 -46
- package/dist/{chunk-WSDT7LYL.js → chunk-3UBWDR65.js} +1 -1
- package/dist/{chunk-NZ5BHDFZ.js → chunk-44Q6MV7C.js} +2 -2
- package/dist/{chunk-CMZ3QTFQ.js → chunk-4I3K6LEH.js} +24 -0
- package/dist/{chunk-ZXCZYMN4.cjs → chunk-4LY6R4TN.cjs} +137 -62
- package/dist/{chunk-EAHOB64X.js → chunk-57UTI7ZH.js} +106 -42
- package/dist/{chunk-XGHGGBM3.js → chunk-5QXE5HMV.js} +4 -4
- package/dist/{chunk-NYWESHOQ.cjs → chunk-6AJIOW3S.cjs} +57 -57
- package/dist/{chunk-4QFWGLZO.js → chunk-6YBUQAOH.js} +1 -1
- package/dist/{chunk-JHQ334WS.js → chunk-742BGXNX.js} +2 -0
- package/dist/{chunk-D6PMVWDI.js → chunk-74N742ZG.js} +6 -6
- package/dist/{chunk-AECTRMGQ.cjs → chunk-7GRPR7XA.cjs} +13 -1
- package/dist/{chunk-4HJRHEXD.cjs → chunk-7Z5FMQYR.cjs} +22 -22
- package/dist/chunk-AFTRPEXO.js +13 -0
- package/dist/{chunk-WBNAEYTQ.cjs → chunk-BYUIFT7Q.cjs} +6 -6
- package/dist/{chunk-LCLDFMDF.cjs → chunk-BYVVE7HP.cjs} +58 -58
- package/dist/{chunk-JPD4NXH6.js → chunk-CO3FOZIH.js} +1 -1
- package/dist/{chunk-E7YCPY7K.cjs → chunk-D2DH6VZL.cjs} +3 -3
- package/dist/{chunk-HWVUR735.cjs → chunk-DFM572VH.cjs} +2 -2
- package/dist/{chunk-YDPKUAP4.js → chunk-DJ4IFQNQ.js} +2 -0
- package/dist/{chunk-5U3KWQXP.js → chunk-E6SMMMKV.js} +13 -13
- package/dist/chunk-EWPR7662.cjs +13 -0
- package/dist/{chunk-SWAVO7BB.cjs → chunk-F7ORKKEF.cjs} +108 -108
- package/dist/{chunk-AGVXKD4K.js → chunk-FSQQZFVG.js} +12 -0
- package/dist/{chunk-ETYLOZOB.cjs → chunk-GCK75D7F.cjs} +109 -22
- package/dist/{chunk-ZKNZ2CXW.cjs → chunk-GGBYZKMS.cjs} +11 -11
- package/dist/{chunk-Y4MB25KW.js → chunk-GYAXV3MZ.js} +3 -3
- package/dist/{chunk-UWQWMGJ7.cjs → chunk-HJMSNOBT.cjs} +1040 -696
- package/dist/{chunk-DFQYAYBH.cjs → chunk-HQIOMFJH.cjs} +2 -0
- package/dist/{chunk-JH2SIWPQ.js → chunk-HXB7SEYG.js} +1611 -1267
- package/dist/{chunk-LE5WKGJV.cjs → chunk-I2254QN6.cjs} +16 -16
- package/dist/{chunk-PSVSEN4J.cjs → chunk-IMTY3GRR.cjs} +2 -0
- package/dist/{chunk-ILNN6QRW.js → chunk-JDBZ4ZHU.js} +3 -3
- package/dist/{chunk-GQ7JJUIT.cjs → chunk-K2JUJ37D.cjs} +25 -1
- package/dist/{chunk-6YPTUHM7.js → chunk-K76ACBR3.js} +3 -3
- package/dist/{chunk-2NASBO7O.js → chunk-KFOAV77K.js} +2 -2
- package/dist/{chunk-CU6NWO2M.js → chunk-LAXKEBDD.js} +14 -18
- package/dist/{chunk-5YAGX5DY.js → chunk-LGKMR7NZ.js} +7 -7
- package/dist/{chunk-E2V2EH2G.cjs → chunk-LODMNSQY.cjs} +16 -16
- package/dist/{chunk-4D6NMPOO.js → chunk-NJ5TBTJG.js} +7 -7
- package/dist/{chunk-TDZ76NCB.cjs → chunk-NMPVK53I.cjs} +29 -29
- package/dist/{chunk-TTVOLEUS.js → chunk-NPSJE7J3.js} +90 -3
- package/dist/{chunk-H5VIMBRN.cjs → chunk-O5EHOJZD.cjs} +4 -4
- package/dist/{chunk-KT3U3ZRP.cjs → chunk-OKE5BIQH.cjs} +8 -8
- package/dist/{chunk-DC4RTYWK.cjs → chunk-QLTXT562.cjs} +5 -5
- package/dist/{chunk-H5V7GRN5.js → chunk-QQCFPMAA.js} +5 -7
- package/dist/{chunk-7BREFV7G.cjs → chunk-QYS4YVEP.cjs} +34 -36
- package/dist/{chunk-7BCY77W6.js → chunk-RCI3PALX.js} +8 -10
- package/dist/{chunk-P3JMAMHP.js → chunk-REETLEL5.js} +1 -1
- package/dist/{chunk-4JIGEK7C.cjs → chunk-RJMWJAJO.cjs} +97 -33
- package/dist/{chunk-WS7WRR5Z.cjs → chunk-RQZQHLNS.cjs} +86 -90
- package/dist/{chunk-FFT56TYB.cjs → chunk-RUZIICXT.cjs} +2 -2
- package/dist/{chunk-AJHSQ5XK.js → chunk-S63QBBT7.js} +6 -6
- package/dist/{chunk-TELAANY6.js → chunk-UXU7Y5BH.js} +2 -2
- package/dist/{chunk-NQVS4G7G.cjs → chunk-UZTOI6FJ.cjs} +773 -746
- package/dist/{chunk-DFEPUYTF.cjs → chunk-VFICDEYJ.cjs} +45 -47
- package/dist/{chunk-LOZLHG2U.cjs → chunk-XE2K53GH.cjs} +20 -20
- package/dist/{chunk-QBCDSTLE.cjs → chunk-XXO52RZR.cjs} +26 -26
- package/dist/{chunk-TTEFN6VO.js → chunk-ZLUFEWZZ.js} +10 -10
- package/dist/{chunk-MA4Q5RBP.cjs → chunk-ZSOFLPQN.cjs} +9 -9
- package/dist/{chunk-KBJJQFYU.js → chunk-ZZEKXGFS.js} +2 -2
- package/dist/{cloud-tenants-FBUO66GW.cjs → cloud-tenants-HZHKRUIW.cjs} +16 -16
- package/dist/{cloud-tenants-DNBPNQNP.js → cloud-tenants-Q4TCJS5Y.js} +15 -15
- package/dist/components/calendar.cjs +4 -4
- package/dist/components/calendar.js +1 -1
- package/dist/components/case-studies/index.cjs +30 -30
- package/dist/components/case-studies/index.js +16 -16
- package/dist/components/chat/ask-prompts.d.ts +10 -2
- package/dist/components/chat/ask-prompts.d.ts.map +1 -1
- package/dist/components/chat/assistant-ask-prompts.d.ts +27 -0
- package/dist/components/chat/assistant-ask-prompts.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
- package/dist/components/chat/hooks/index.d.ts +1 -0
- package/dist/components/chat/hooks/index.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-ask-prompts.d.ts +63 -0
- package/dist/components/chat/hooks/use-ask-prompts.d.ts.map +1 -0
- package/dist/components/chat/index.cjs +27 -10
- package/dist/components/chat/index.d.ts +1 -0
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +26 -9
- package/dist/components/chat/utils/icon-library.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +17 -17
- package/dist/components/contact/index.js +16 -16
- package/dist/components/docs/index.cjs +20 -20
- package/dist/components/docs/index.js +19 -19
- package/dist/components/embeds/index.cjs +17 -17
- package/dist/components/embeds/index.js +16 -16
- package/dist/components/faq/faq-ask-card.d.ts +44 -0
- package/dist/components/faq/faq-ask-card.d.ts.map +1 -0
- package/dist/components/faq/faq-document-page.d.ts +5 -1
- package/dist/components/faq/faq-document-page.d.ts.map +1 -1
- package/dist/components/faq/faq-section.d.ts +18 -5
- package/dist/components/faq/faq-section.d.ts.map +1 -1
- package/dist/components/faq/index.cjs +19 -18
- package/dist/components/faq/index.d.ts +1 -0
- package/dist/components/faq/index.d.ts.map +1 -1
- package/dist/components/faq/index.js +18 -17
- package/dist/components/features/auth/auth-benefits-panel.d.ts.map +1 -1
- package/dist/components/features/index.cjs +16 -16
- package/dist/components/features/index.js +15 -15
- package/dist/components/help-center-pages/download-apps-page.d.ts +55 -0
- package/dist/components/help-center-pages/download-apps-page.d.ts.map +1 -0
- package/dist/components/help-center-pages/index.cjs +333 -119
- package/dist/components/help-center-pages/index.d.ts +1 -0
- package/dist/components/help-center-pages/index.d.ts.map +1 -1
- package/dist/components/help-center-pages/index.js +251 -37
- package/dist/components/help-center-pages/trust-center-page.d.ts +4 -1
- package/dist/components/help-center-pages/trust-center-page.d.ts.map +1 -1
- package/dist/components/index.cjs +131 -217
- package/dist/components/index.js +236 -322
- package/dist/components/meeting-scheduler/index.cjs +61 -62
- package/dist/components/meeting-scheduler/index.js +18 -19
- package/dist/components/navigation/index.cjs +19 -19
- package/dist/components/navigation/index.js +18 -18
- package/dist/components/navigation/mingo-ai-button.d.ts +1 -1
- package/dist/components/navigation/mingo-ai-button.d.ts.map +1 -1
- package/dist/components/onboarding-guides/index.cjs +19 -20
- package/dist/components/onboarding-guides/index.js +18 -19
- package/dist/components/product-demo/index.cjs +8 -8
- package/dist/components/product-demo/index.js +8 -8
- package/dist/components/related-content/index.cjs +7 -9
- package/dist/components/related-content/index.js +6 -8
- package/dist/components/tickets/index.cjs +21 -21
- package/dist/components/tickets/index.js +20 -20
- package/dist/components/ui/button/button.d.ts.map +1 -1
- package/dist/components/ui/file-manager/index.cjs +11 -11
- package/dist/components/ui/file-manager/index.js +1 -1
- package/dist/components/ui/index.cjs +34 -16
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +33 -15
- package/dist/components/ui/mobile-app-qr.d.ts +23 -0
- package/dist/components/ui/mobile-app-qr.d.ts.map +1 -0
- package/dist/components/ui/store-badges.d.ts +7 -4
- package/dist/components/ui/store-badges.d.ts.map +1 -1
- package/dist/contexts/assistant-runtime-context.d.ts +74 -0
- package/dist/contexts/assistant-runtime-context.d.ts.map +1 -0
- package/dist/contexts/index.cjs +7 -1
- package/dist/contexts/index.d.ts +1 -0
- package/dist/contexts/index.d.ts.map +1 -1
- package/dist/contexts/index.js +6 -0
- package/dist/{devices-5A5TY4JD.cjs → devices-6XHUFIC6.cjs} +17 -17
- package/dist/{devices-PLDAEUSL.js → devices-NOUGVTES.js} +15 -15
- package/dist/hooks/index.cjs +10 -5
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +9 -4
- package/dist/hooks/use-downloads.d.ts +41 -0
- package/dist/hooks/use-downloads.d.ts.map +1 -0
- package/dist/index.cjs +80 -20
- package/dist/index.js +79 -19
- package/dist/{knowledge-G6Q5KRWV.js → knowledge-2YTUXQ2Z.js} +15 -15
- package/dist/{knowledge-FKTJ723Z.cjs → knowledge-ANEKPMO2.cjs} +17 -17
- package/dist/{logs-CJCXUBU6.cjs → logs-U3IB3HUM.cjs} +25 -25
- package/dist/{logs-QMV6XIC4.js → logs-WVQIONUT.js} +15 -15
- package/dist/{policies-G6D7AX6F.js → policies-66EGDW2H.js} +15 -15
- package/dist/{policies-QMRTK3CY.cjs → policies-UFRN2EQF.cjs} +20 -20
- package/dist/{remote-session-DBD6OSTX.js → remote-session-6WEUJZDC.js} +5 -5
- package/dist/{remote-session-2JVI7RVA.cjs → remote-session-A75X5NPC.cjs} +7 -7
- package/dist/{software-update-PNZMRDBT.cjs → software-update-2MHKL76D.cjs} +20 -20
- package/dist/{software-update-6BQM6BKH.js → software-update-3ZD3MXF3.js} +15 -15
- package/dist/{tickets-board-BHLPAVNJ.cjs → tickets-board-IFWMIZ35.cjs} +9 -9
- package/dist/{tickets-board-PYDNELSK.js → tickets-board-MYXG3V72.js} +4 -4
- package/dist/types/downloads.d.ts +67 -0
- package/dist/types/downloads.d.ts.map +1 -0
- package/dist/types/index.cjs +24 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +16 -1
- package/dist/utils/index.cjs +46 -2
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +40 -3
- package/dist/utils/list-url.d.ts.map +1 -1
- package/dist/utils/mobile-app.cjs +46 -0
- package/dist/utils/mobile-app.d.ts +40 -0
- package/dist/utils/mobile-app.d.ts.map +1 -0
- package/dist/utils/mobile-app.js +40 -0
- package/dist/utils/source-icons.d.ts.map +1 -1
- package/dist/utils/trial.d.ts +18 -0
- package/dist/utils/trial.d.ts.map +1 -0
- package/package.json +7 -1
- package/src/assets/index.ts +1 -0
- package/src/assets/mobile-app-qr.ts +19 -0
- package/src/components/chat/ask-prompts.tsx +25 -3
- package/src/components/chat/assistant-ask-prompts.tsx +78 -0
- package/src/components/chat/entity-cards/dispatch.tsx +38 -4
- package/src/components/chat/hooks/index.ts +12 -0
- package/src/components/chat/hooks/use-ask-prompts.ts +188 -0
- package/src/components/chat/index.ts +1 -0
- package/src/components/chat/utils/icon-library.tsx +6 -0
- package/src/components/faq/faq-ask-card.tsx +115 -0
- package/src/components/faq/faq-document-page.tsx +6 -1
- package/src/components/faq/faq-section.tsx +27 -5
- package/src/components/faq/index.ts +1 -0
- package/src/components/features/auth/auth-benefits-panel.tsx +5 -4
- package/src/components/help-center-pages/download-apps-page.tsx +364 -0
- package/src/components/help-center-pages/index.ts +1 -0
- package/src/components/help-center-pages/trust-center-page.tsx +5 -2
- package/src/components/navigation/mingo-ai-button.tsx +27 -6
- package/src/components/ui/button/button.tsx +3 -0
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/mobile-app-qr.tsx +40 -0
- package/src/components/ui/store-badges.tsx +17 -9
- package/src/contexts/assistant-runtime-context.tsx +84 -0
- package/src/contexts/index.ts +9 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-downloads.ts +138 -0
- package/src/types/downloads.ts +82 -0
- package/src/types/index.ts +1 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/list-url.ts +4 -0
- package/src/utils/mobile-app.ts +57 -0
- package/src/utils/source-icons.ts +10 -2
- package/src/utils/trial.ts +19 -0
- package/dist/chunk-6X3O67OL.cjs +0 -89
- package/dist/chunk-AUMKE74M.cjs +0 -16
- package/dist/chunk-G3GRYDMS.js +0 -16
- package/dist/chunk-RR6PY34K.js +0 -89
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Assistant runtime context: what a PAGE needs to offer the host's chat
|
|
5
|
+
* assistant ("Ask Mingo"): whether a chat is there to open, the assistant's
|
|
6
|
+
* name and glyph, where its questions are read from, and HOW the chat is
|
|
7
|
+
* opened and asked.
|
|
8
|
+
*
|
|
9
|
+
* A sibling of `ChatRuntimeContext` (which configures the chat panel itself)
|
|
10
|
+
* and `EndpointsRuntimeContext`. It is its own context because its values
|
|
11
|
+
* change with the visitor (signed in or not, chat mounted or not), and a new
|
|
12
|
+
* `ChatRuntime` identity re-renders the whole chat tree.
|
|
13
|
+
*
|
|
14
|
+
* The NEAREST provider wins, so a page region that carries its own chat (an
|
|
15
|
+
* embedded chat beside the content) mounts a provider whose `open` opens THAT
|
|
16
|
+
* chat: every "ask" surface under it (`FaqSection`'s card, `AskPrompts`,
|
|
17
|
+
* `AskCard`) then opens and fills it, with no prop on any of them.
|
|
18
|
+
*
|
|
19
|
+
* No provider, or `available: false`: the "ask" surfaces render nothing.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { createContext, useContext, type ReactNode } from 'react';
|
|
23
|
+
|
|
24
|
+
/** What an "ask" surface asks the chat to do. */
|
|
25
|
+
export interface AssistantOpenRequest {
|
|
26
|
+
/** A question to send once the chat is open. Absent: the chat only opens. */
|
|
27
|
+
prompt?: string;
|
|
28
|
+
/** The topic of the surface that asked (a FAQ's topic, a page section). */
|
|
29
|
+
topic?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** What an "ask" surface reports after a question was sent (analytics). */
|
|
33
|
+
export interface AssistantAskEvent {
|
|
34
|
+
/** The id of the question that was asked. */
|
|
35
|
+
promptId: string;
|
|
36
|
+
/** The topic of the surface that asked. */
|
|
37
|
+
topic?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The wording of the card beside a FAQ. `{assistant}` is replaced by the assistant's name. */
|
|
41
|
+
export interface AssistantAskCardCopy {
|
|
42
|
+
title?: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
/** How many questions the card offers. */
|
|
45
|
+
count?: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface AssistantRuntime {
|
|
49
|
+
/** A chat is mounted for this visitor: an "ask" click has something to open. */
|
|
50
|
+
available: boolean;
|
|
51
|
+
/** The assistant's configured name. */
|
|
52
|
+
name?: string | null;
|
|
53
|
+
/** The assistant's configured glyph. Absent: the packaged Mingo mark. */
|
|
54
|
+
icon?: ReactNode;
|
|
55
|
+
/** The chat source the default `open` addresses its `ask-ai:open` event to. */
|
|
56
|
+
source?: string;
|
|
57
|
+
/**
|
|
58
|
+
* GET endpoint the questions are read from:
|
|
59
|
+
* `<url>?count=<n>§ion=<topic>&exclude=<id,id>` → `{ prompts: AskPrompt[] }`
|
|
60
|
+
* `section` is ANY string: the host decides what topics exist (the hub: the
|
|
61
|
+
* `section` attribute of a quick action, set in chat config), so a new topic
|
|
62
|
+
* needs no change here. Hub: '/api/quick-actions/questions'. Absent: an "ask"
|
|
63
|
+
* surface shows its launcher with no questions.
|
|
64
|
+
*/
|
|
65
|
+
askPromptsUrl?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Open the chat and, with `prompt`, ask it. Absent: the `ask-ai:open` event
|
|
68
|
+
* of `source` (`openAskAi`), which the mounted `EmbeddableChat` listens for.
|
|
69
|
+
* A host whose chat is opened another way (an embedded chat, a different
|
|
70
|
+
* panel) supplies its own.
|
|
71
|
+
*/
|
|
72
|
+
open?: (request: AssistantOpenRequest) => void;
|
|
73
|
+
/** After a question was sent (analytics). */
|
|
74
|
+
onAsk?: (event: AssistantAskEvent) => void;
|
|
75
|
+
/** The wording of the card beside a FAQ. Absent: the lib's own. */
|
|
76
|
+
askCard?: AssistantAskCardCopy;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const AssistantRuntimeContext = createContext<AssistantRuntime | null>(null);
|
|
80
|
+
|
|
81
|
+
/** The nearest assistant runtime, or null when no provider is mounted. */
|
|
82
|
+
export function useAssistantRuntime(): AssistantRuntime | null {
|
|
83
|
+
return useContext(AssistantRuntimeContext);
|
|
84
|
+
}
|
package/src/contexts/index.ts
CHANGED
|
@@ -30,4 +30,13 @@ export {
|
|
|
30
30
|
|
|
31
31
|
export { ChatRuntimeContext, useChatRuntime, useRequiredChatRuntime, type ChatRuntime } from './chat-runtime-context';
|
|
32
32
|
|
|
33
|
+
export {
|
|
34
|
+
AssistantRuntimeContext,
|
|
35
|
+
useAssistantRuntime,
|
|
36
|
+
type AssistantAskCardCopy,
|
|
37
|
+
type AssistantAskEvent,
|
|
38
|
+
type AssistantOpenRequest,
|
|
39
|
+
type AssistantRuntime,
|
|
40
|
+
} from './assistant-runtime-context';
|
|
41
|
+
|
|
33
42
|
export { useOuterOrDefault } from './use-outer-or-default';
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useSyncExternalStore } from 'react';
|
|
4
|
+
import { DOWNLOADS_API_PATH, type AppDownload, type DownloadsPublic } from '../types/downloads';
|
|
5
|
+
import { contentFetch } from '../utils/embed-content-fetch';
|
|
6
|
+
import { desktopOsOf } from '../utils/visitor-os';
|
|
7
|
+
import { useVisitorOs } from './ui/use-visitor-os';
|
|
8
|
+
|
|
9
|
+
export interface DownloadsState {
|
|
10
|
+
/** The server's answer; null until it lands. */
|
|
11
|
+
data: DownloadsPublic | null;
|
|
12
|
+
isLoading: boolean;
|
|
13
|
+
error: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface Entry {
|
|
17
|
+
state: DownloadsState;
|
|
18
|
+
request: Promise<void> | null;
|
|
19
|
+
listeners: Set<() => void>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const IDLE: DownloadsState = { data: null, isLoading: false, error: false };
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* One entry per endpoint for the life of the page. Every download button on a
|
|
26
|
+
* page asks the same question, so they share ONE request and one answer: the
|
|
27
|
+
* list changes only when the server is redeployed, never while a page is open.
|
|
28
|
+
*/
|
|
29
|
+
const entries = new Map<string, Entry>();
|
|
30
|
+
|
|
31
|
+
function entryFor(endpoint: string): Entry {
|
|
32
|
+
let entry = entries.get(endpoint);
|
|
33
|
+
if (!entry) {
|
|
34
|
+
entry = { state: IDLE, request: null, listeners: new Set() };
|
|
35
|
+
entries.set(endpoint, entry);
|
|
36
|
+
}
|
|
37
|
+
return entry;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function publish(endpoint: string, state: DownloadsState) {
|
|
41
|
+
const entry = entryFor(endpoint);
|
|
42
|
+
entry.state = state;
|
|
43
|
+
for (const listener of entry.listeners) listener();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function load(endpoint: string, force = false): void {
|
|
47
|
+
const entry = entryFor(endpoint);
|
|
48
|
+
if (entry.request || (entry.state.data && !force)) return;
|
|
49
|
+
publish(endpoint, { data: entry.state.data, isLoading: true, error: false });
|
|
50
|
+
entry.request = contentFetch(endpoint)
|
|
51
|
+
.then(async response => {
|
|
52
|
+
if (!response.ok) throw new Error(`Request failed (${response.status})`);
|
|
53
|
+
publish(endpoint, { data: (await response.json()) as DownloadsPublic, isLoading: false, error: false });
|
|
54
|
+
})
|
|
55
|
+
.catch(() => publish(endpoint, { data: entry.state.data, isLoading: false, error: true }))
|
|
56
|
+
.finally(() => {
|
|
57
|
+
entry.request = null;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Test seam: forget every answer. */
|
|
62
|
+
export function resetDownloadsStore(): void {
|
|
63
|
+
entries.clear();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface UseDownloadsOptions {
|
|
67
|
+
/** GET endpoint for the public projection. Default `DOWNLOADS_API_PATH`; embedders pass their proxy path. */
|
|
68
|
+
endpoint?: string;
|
|
69
|
+
/** The server's copy (a host that read it during SSR): no request is made. */
|
|
70
|
+
initialData?: DownloadsPublic;
|
|
71
|
+
/** False: nothing is requested (a host that does not offer the desktop app). Default true. */
|
|
72
|
+
enabled?: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* What the OpenFrame desktop app is installed from, read FROM THE SERVER
|
|
77
|
+
* (`GET /api/downloads`). The links and package names live in the server's
|
|
78
|
+
* environment; no client holds a copy of its own. Every caller on a page shares
|
|
79
|
+
* one request.
|
|
80
|
+
*/
|
|
81
|
+
export function useDownloads({ endpoint = DOWNLOADS_API_PATH, initialData, enabled = true }: UseDownloadsOptions = {}) {
|
|
82
|
+
const entry = entryFor(endpoint);
|
|
83
|
+
// A server copy is the answer: held from the first render (server and client alike), and never re-requested.
|
|
84
|
+
// Written during render so THIS caller's first paint has it; a render cannot notify other callers.
|
|
85
|
+
if (initialData && entry.state.data !== initialData && !entry.request) {
|
|
86
|
+
entry.state = { data: initialData, isLoading: false, error: false };
|
|
87
|
+
}
|
|
88
|
+
// So the callers that rendered before this one (a header button above the page) are told after
|
|
89
|
+
// the commit: they re-read the shared answer instead of staying on the empty one they first saw.
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (!initialData) return;
|
|
92
|
+
for (const listener of entry.listeners) listener();
|
|
93
|
+
}, [entry, initialData]);
|
|
94
|
+
const subscribe = useCallback(
|
|
95
|
+
(listener: () => void) => {
|
|
96
|
+
entry.listeners.add(listener);
|
|
97
|
+
return () => {
|
|
98
|
+
entry.listeners.delete(listener);
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
[entry],
|
|
102
|
+
);
|
|
103
|
+
const state = useSyncExternalStore(
|
|
104
|
+
subscribe,
|
|
105
|
+
() => entry.state,
|
|
106
|
+
() => entry.state,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (enabled) load(endpoint);
|
|
111
|
+
}, [enabled, endpoint]);
|
|
112
|
+
|
|
113
|
+
const reload = useCallback(() => load(endpoint, true), [endpoint]);
|
|
114
|
+
// Until the effect has asked, an enabled caller with no answer is loading, not empty.
|
|
115
|
+
const isLoading = state.isLoading || (enabled && !state.data && !state.error);
|
|
116
|
+
return { data: state.data, isLoading, error: state.error, reload };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface VisitorDesktopDownload {
|
|
120
|
+
/** False until the visitor's system AND the server's list are both known. */
|
|
121
|
+
known: boolean;
|
|
122
|
+
/** This visitor's installer (the first one for their system); null when nothing installs on it. */
|
|
123
|
+
download: AppDownload | null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The installer a download button offers THIS visitor: the server's first
|
|
128
|
+
* installer for the system they are on. `enabled: false` asks for nothing.
|
|
129
|
+
*/
|
|
130
|
+
export function useVisitorDesktopDownload(options: UseDownloadsOptions = {}): VisitorDesktopDownload {
|
|
131
|
+
const enabled = options.enabled ?? true;
|
|
132
|
+
const visitor = useVisitorOs();
|
|
133
|
+
const { data, error } = useDownloads(options);
|
|
134
|
+
if (!enabled || !visitor.known || (!data && !error)) return { known: false, download: null };
|
|
135
|
+
const os = desktopOsOf(visitor.os);
|
|
136
|
+
const download = data?.desktop.find(row => row.kind === 'binary' && row.url && row.os === os) ?? null;
|
|
137
|
+
return { known: true, download };
|
|
138
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The download page's wire shape and vocabulary: what the OpenFrame apps are
|
|
3
|
+
* installed from. The hub answers `DOWNLOADS_API_PATH` with `DownloadsPublic`;
|
|
4
|
+
* the lib's `<DownloadAppsPage>` renders it (hub SSR, openframe-frontend through
|
|
5
|
+
* its `/content` proxy, the embedding example).
|
|
6
|
+
*/
|
|
7
|
+
import type { DesktopOs } from '../utils/visitor-os';
|
|
8
|
+
|
|
9
|
+
/** GET endpoint for the public downloads projection (the hub's path; embedders prefix their proxy). */
|
|
10
|
+
export const DOWNLOADS_API_PATH = '/api/downloads';
|
|
11
|
+
|
|
12
|
+
/** How long a copy stays fresh: the CDN window of the route, and the page's revalidation age. */
|
|
13
|
+
export const DOWNLOADS_CACHE_SECONDS = 300;
|
|
14
|
+
|
|
15
|
+
export const DOWNLOADS_TITLE = 'Download OpenFrame';
|
|
16
|
+
export const DOWNLOADS_TAGLINE =
|
|
17
|
+
'Install it on the computer you manage IT from, and on your phone. One account everywhere.';
|
|
18
|
+
/** The title and subtitle when a host offers the mobile app only. */
|
|
19
|
+
export const DOWNLOADS_MOBILE_TITLE = 'Get the OpenFrame app';
|
|
20
|
+
export const DOWNLOADS_MOBILE_TAGLINE =
|
|
21
|
+
'Alerts and tickets on your phone, signed in with the account you already have.';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* What a row is: an installer file, or a one-line package manager install. THE
|
|
25
|
+
* one declaration: the type, the server's rows and every reader derive from it.
|
|
26
|
+
*/
|
|
27
|
+
export const APP_DOWNLOAD_KINDS = ['binary', 'command'] as const;
|
|
28
|
+
export type AppDownloadKind = (typeof APP_DOWNLOAD_KINDS)[number];
|
|
29
|
+
|
|
30
|
+
/** One way to install the desktop app on one system. */
|
|
31
|
+
export interface AppDownload {
|
|
32
|
+
id: string;
|
|
33
|
+
kind: AppDownloadKind;
|
|
34
|
+
os: DesktopOs;
|
|
35
|
+
/** `universal`, `x64`, `arm64`; null for a command. */
|
|
36
|
+
architecture: string | null;
|
|
37
|
+
/** The installer's address (`binary`). */
|
|
38
|
+
url: string | null;
|
|
39
|
+
/** The whole command to paste (`command`). */
|
|
40
|
+
command: string | null;
|
|
41
|
+
/** "macOS 13+". */
|
|
42
|
+
minOsLabel: string | null;
|
|
43
|
+
/** The package manager's name (`command`), or the button's own words (`binary`). */
|
|
44
|
+
label: string | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Where the mobile app is installed from. A store the server names no listing for is null, and is not offered. */
|
|
48
|
+
export interface MobileAppLinks {
|
|
49
|
+
appStoreUrl: string | null;
|
|
50
|
+
googlePlayUrl: string | null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Everything the download page shows. All of it is the server's: the lib holds
|
|
55
|
+
* no link of its own and falls back to none, so what is missing is not drawn.
|
|
56
|
+
*/
|
|
57
|
+
export interface DownloadsPublic {
|
|
58
|
+
/** The desktop installers and install commands, in the order they are offered. Per system, the first installer is the default. */
|
|
59
|
+
desktop: AppDownload[];
|
|
60
|
+
/** The mobile app's store listings. */
|
|
61
|
+
mobile: MobileAppLinks;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** A system's name on a button and a card. */
|
|
65
|
+
export const DESKTOP_OS_LABELS: Record<DesktopOs, string> = { mac: 'Mac', windows: 'Windows', linux: 'Linux' };
|
|
66
|
+
|
|
67
|
+
/** An architecture's name beside a button, when a system has more than one installer. */
|
|
68
|
+
export const DOWNLOAD_ARCHITECTURE_LABELS: Record<string, string> = {
|
|
69
|
+
universal: 'Apple Silicon and Intel',
|
|
70
|
+
x64: 'x64',
|
|
71
|
+
arm64: 'ARM',
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** What a host learns when a visitor takes an install action on the page. */
|
|
75
|
+
export interface DownloadActionEvent {
|
|
76
|
+
/** `installer`: a download button. `command`: a copied install command. */
|
|
77
|
+
action: 'installer' | 'command';
|
|
78
|
+
/** The row's id (`mac`, `windows-arm64`, `homebrew`). */
|
|
79
|
+
id: string;
|
|
80
|
+
os: DesktopOs;
|
|
81
|
+
architecture: string | null;
|
|
82
|
+
}
|
package/src/types/index.ts
CHANGED
package/src/utils/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ export {
|
|
|
17
17
|
// source of truth). Re-exported here so existing callers that pull from
|
|
18
18
|
// the barrel keep working without changing imports.
|
|
19
19
|
export { formatDate, formatNumber, formatPrice, formatBytes } from './format';
|
|
20
|
+
export { TRIAL_DAYS, TRIAL_LABELS } from './trial';
|
|
20
21
|
export {
|
|
21
22
|
VENDOR_CLASSIFICATIONS,
|
|
22
23
|
OPENFRAME_CLASSIFICATIONS,
|
|
@@ -117,6 +118,8 @@ export * from './video-bite-id';
|
|
|
117
118
|
// OS type utilities
|
|
118
119
|
export * from './os-utils';
|
|
119
120
|
export * from './visitor-os';
|
|
121
|
+
// Also exported via the granular subpath `./utils/mobile-app` (server and Edge consumers).
|
|
122
|
+
export * from './mobile-app';
|
|
120
123
|
// Phone utilities
|
|
121
124
|
export * from './country-phone-utils';
|
|
122
125
|
export * from './compliance-standards';
|
package/src/utils/list-url.ts
CHANGED
|
@@ -116,6 +116,10 @@ const BUILDERS: Record<string, (ids: string[], base: string) => string> = {
|
|
|
116
116
|
design_doc: (ids, b) => `${b}/api/design-docs?ids=${ids.join(',')}`,
|
|
117
117
|
openframe_tenant: (ids, b) => `${b}/api/openframe-tenants?ids=${ids.join(',')}`,
|
|
118
118
|
prospect_call: (ids, b) => `${b}/api/prospect-calls?ids=${ids.join(',')}`,
|
|
119
|
+
// The public website's own pages (live source; ChatRef-shaped items like the objects above).
|
|
120
|
+
site_page: (ids, b) => `${b}/api/site-pages?ids=${ids.join(',')}`,
|
|
121
|
+
// The OpenMSP vendor directory (indexed source).
|
|
122
|
+
vendor: (ids, b) => `${b}/api/vendors/cards?ids=${ids.join(',')}`,
|
|
119
123
|
// Code intelligence — per-object card hydration, same `handleEntityCardList`
|
|
120
124
|
// shape as the internal objects above.
|
|
121
125
|
code_rule: (ids, b) => `${b}/api/code-rules/cards?ids=${ids.join(',')}`,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The download page's own addresses: where it lives, the parameter that sends a
|
|
3
|
+
* phone on to its store, and the URL the install QR code encodes. The store
|
|
4
|
+
* listings and installer links are NOT here: they are the server's
|
|
5
|
+
* (`DownloadsPublic`, read through `useDownloads`).
|
|
6
|
+
*
|
|
7
|
+
* Pure and server-safe; also published as the granular subpath
|
|
8
|
+
* `./utils/mobile-app`, for an Edge proxy and other server-only consumers.
|
|
9
|
+
*/
|
|
10
|
+
import type { MobileAppLinks } from '../types/downloads';
|
|
11
|
+
import { detectVisitorOs } from './visitor-os';
|
|
12
|
+
|
|
13
|
+
/** The website's download page: every installer and the mobile app. */
|
|
14
|
+
export const DOWNLOAD_PAGE_PATH = '/download';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* On the download page: "send a phone or a tablet on to its store". The install
|
|
18
|
+
* QR code carries it, because whoever scans a code is holding the phone the app
|
|
19
|
+
* goes on. Anyone who opens the page without it reads the page.
|
|
20
|
+
*/
|
|
21
|
+
export const DOWNLOAD_PAGE_STORE_PARAM = 'store';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The one URL the install QR code encodes: the website's download page, asking
|
|
25
|
+
* it to send a phone on to its store.
|
|
26
|
+
*
|
|
27
|
+
* Absolute and on the production host on purpose: a code must point at
|
|
28
|
+
* production whichever deployment rendered the page it came from. `MobileAppQr`
|
|
29
|
+
* draws this value as committed path data, so the two change together: see the
|
|
30
|
+
* regeneration note on that component.
|
|
31
|
+
*/
|
|
32
|
+
export const MOBILE_APP_INSTALL_URL = `https://www.flamingo.run${DOWNLOAD_PAGE_PATH}?${DOWNLOAD_PAGE_STORE_PARAM}=1`;
|
|
33
|
+
|
|
34
|
+
/** The download page as it is printed for a human to read or type: no scheme, no `www`, no query. */
|
|
35
|
+
export const MOBILE_APP_INSTALL_HOST_PATH = MOBILE_APP_INSTALL_URL.replace(/^https:\/\/(www\.)?/, '').replace(
|
|
36
|
+
/\?.*$/,
|
|
37
|
+
'',
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The store for a phone or tablet, or `null` for every other system and for a
|
|
42
|
+
* store the server names no listing for (`links` is the server's answer).
|
|
43
|
+
*
|
|
44
|
+
* The server passes the request's User-Agent; a browser also passes
|
|
45
|
+
* `navigator.maxTouchPoints`, the only signal that tells an iPad asking for the
|
|
46
|
+
* desktop site (it calls itself a Macintosh) from a real Mac.
|
|
47
|
+
*/
|
|
48
|
+
export function resolveMobileStoreUrl(
|
|
49
|
+
links: MobileAppLinks,
|
|
50
|
+
userAgent: string | null | undefined,
|
|
51
|
+
maxTouchPoints?: number,
|
|
52
|
+
): string | null {
|
|
53
|
+
const os = detectVisitorOs(userAgent, { maxTouchPoints });
|
|
54
|
+
if (os === 'ios') return links.appStoreUrl;
|
|
55
|
+
if (os === 'android') return links.googlePlayUrl;
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
@@ -54,8 +54,12 @@ export const SOURCE_ICON_NAMES: Record<string, string> = {
|
|
|
54
54
|
'audience-mssp': 'shield-lock',
|
|
55
55
|
'audience-it-team': 'buildings',
|
|
56
56
|
|
|
57
|
-
// Trust (single-record live source over the public Vanta projection)
|
|
58
|
-
'trust-center': 'shield',
|
|
57
|
+
// Trust (single-record live source over the public Vanta projection): the icon its menu entry draws
|
|
58
|
+
'trust-center': 'shield-check',
|
|
59
|
+
// The public website's own pages (live source): the site's own mark, as a glyph in the slot's colour
|
|
60
|
+
'website-pages': 'flamingo-logo-grey',
|
|
61
|
+
// The OpenMSP vendor directory: the icon the site menu's "Tool directory" entry draws (it reads this one)
|
|
62
|
+
vendors: 'package-search',
|
|
59
63
|
|
|
60
64
|
// Financials
|
|
61
65
|
'investor-updates': 'mail',
|
|
@@ -145,6 +149,8 @@ export const SOURCE_LABELS_BY_TABLE: Record<string, string> = {
|
|
|
145
149
|
|
|
146
150
|
// Trust
|
|
147
151
|
'trust-center': 'Trust Center',
|
|
152
|
+
'website-pages': 'Website',
|
|
153
|
+
vendors: 'Vendor Directory',
|
|
148
154
|
|
|
149
155
|
// Financials
|
|
150
156
|
'investor-updates': 'Investor Updates',
|
|
@@ -248,6 +254,8 @@ export const DEFAULT_DOCUMENT_TYPE_TO_TABLE_ID: Record<string, string> = {
|
|
|
248
254
|
|
|
249
255
|
// Trust
|
|
250
256
|
trust_center: 'trust-center',
|
|
257
|
+
site_page: 'website-pages',
|
|
258
|
+
vendor: 'vendors',
|
|
251
259
|
|
|
252
260
|
// Financials
|
|
253
261
|
investor_update: 'investor-updates',
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The free trial's facts and the words every surface says them with: the
|
|
3
|
+
* sign-up panel here, and the host site's trial buttons, trust rows and pricing
|
|
4
|
+
* copy. Stated once, so a trial that changes length changes everywhere.
|
|
5
|
+
*
|
|
6
|
+
* Server-safe (no React, no DOM).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** How long the free trial runs, in days. */
|
|
10
|
+
export const TRIAL_DAYS = 14;
|
|
11
|
+
|
|
12
|
+
/** The reassurance labels shown beside a trial button. */
|
|
13
|
+
export const TRIAL_LABELS = {
|
|
14
|
+
/** "14 day free trial" */
|
|
15
|
+
length: `${TRIAL_DAYS} day free trial`,
|
|
16
|
+
noCard: 'No card required',
|
|
17
|
+
cancel: 'Cancel Anytime',
|
|
18
|
+
noContract: 'No Contract',
|
|
19
|
+
} as const;
|
package/dist/chunk-6X3O67OL.cjs
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var _chunkAUMKE74Mcjs = require('./chunk-AUMKE74M.cjs');
|
|
5
|
-
|
|
6
|
-
// src/hooks/use-self-fetch.ts
|
|
7
|
-
var _react = require('react');
|
|
8
|
-
function useSelfFetch(url, options) {
|
|
9
|
-
const initialData = _optionalChain([options, 'optionalAccess', _ => _.initialData]);
|
|
10
|
-
const revalidateOnVisibleAfterMs = _optionalChain([options, 'optionalAccess', _2 => _2.revalidateOnVisibleAfterMs]);
|
|
11
|
-
const [data, setData] = _react.useState.call(void 0, _nullishCoalesce(initialData, () => ( null)));
|
|
12
|
-
const [dataUrl, setDataUrl] = _react.useState.call(void 0, initialData !== void 0 ? url : null);
|
|
13
|
-
const [isLoading, setIsLoading] = _react.useState.call(void 0, initialData === void 0 && url !== null);
|
|
14
|
-
const [error, setError] = _react.useState.call(void 0, false);
|
|
15
|
-
const [reloadKey, setReloadKey] = _react.useState.call(void 0, 0);
|
|
16
|
-
const [mountedAt] = _react.useState.call(void 0, () => Date.now());
|
|
17
|
-
const dataAtRef = _react.useRef.call(void 0, initialData !== void 0 ? mountedAt : 0);
|
|
18
|
-
const dataUrlRef = _react.useRef.call(void 0, initialData !== void 0 ? url : null);
|
|
19
|
-
const [syncedProps, setSyncedProps] = _react.useState.call(void 0, { url, initialData });
|
|
20
|
-
if (syncedProps.url !== url || syncedProps.initialData !== initialData) {
|
|
21
|
-
setSyncedProps({ url, initialData });
|
|
22
|
-
if (syncedProps.initialData !== initialData && initialData !== void 0) {
|
|
23
|
-
setData(initialData);
|
|
24
|
-
setDataUrl(url);
|
|
25
|
-
}
|
|
26
|
-
if (syncedProps.url !== url && url === null) {
|
|
27
|
-
setIsLoading(false);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
_react.useEffect.call(void 0, () => {
|
|
31
|
-
if (url === null) return void 0;
|
|
32
|
-
if (dataUrlRef.current === url) return void 0;
|
|
33
|
-
const ctrl = new AbortController();
|
|
34
|
-
let cancelled = false;
|
|
35
|
-
async function load() {
|
|
36
|
-
try {
|
|
37
|
-
setIsLoading(true);
|
|
38
|
-
setError(false);
|
|
39
|
-
const res = await _chunkAUMKE74Mcjs.contentFetch.call(void 0, url, { signal: ctrl.signal });
|
|
40
|
-
if (!res.ok) throw new Error(`Request failed (${res.status})`);
|
|
41
|
-
const json = await res.json();
|
|
42
|
-
if (!cancelled) {
|
|
43
|
-
setData(json);
|
|
44
|
-
setDataUrl(url);
|
|
45
|
-
dataUrlRef.current = url;
|
|
46
|
-
dataAtRef.current = Date.now();
|
|
47
|
-
}
|
|
48
|
-
} catch (err) {
|
|
49
|
-
if (cancelled || _optionalChain([err, 'optionalAccess', _3 => _3.name]) === "AbortError") return;
|
|
50
|
-
setError(true);
|
|
51
|
-
console.error("useSelfFetch:", url, err);
|
|
52
|
-
} finally {
|
|
53
|
-
if (!cancelled) setIsLoading(false);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
void load();
|
|
57
|
-
return () => {
|
|
58
|
-
cancelled = true;
|
|
59
|
-
ctrl.abort();
|
|
60
|
-
};
|
|
61
|
-
}, [url, reloadKey]);
|
|
62
|
-
const forceReload = () => {
|
|
63
|
-
dataUrlRef.current = null;
|
|
64
|
-
setReloadKey((k) => k + 1);
|
|
65
|
-
};
|
|
66
|
-
_react.useEffect.call(void 0, () => {
|
|
67
|
-
if (!revalidateOnVisibleAfterMs || url === null) return void 0;
|
|
68
|
-
const onVisible = () => {
|
|
69
|
-
if (document.visibilityState !== "visible") return;
|
|
70
|
-
if (Date.now() - dataAtRef.current < revalidateOnVisibleAfterMs) return;
|
|
71
|
-
forceReload();
|
|
72
|
-
};
|
|
73
|
-
document.addEventListener("visibilitychange", onVisible);
|
|
74
|
-
return () => document.removeEventListener("visibilitychange", onVisible);
|
|
75
|
-
}, [url, revalidateOnVisibleAfterMs]);
|
|
76
|
-
return {
|
|
77
|
-
data,
|
|
78
|
-
dataUrl,
|
|
79
|
-
setData,
|
|
80
|
-
isLoading,
|
|
81
|
-
error,
|
|
82
|
-
// Force a re-fetch of the current url (error-retry affordance).
|
|
83
|
-
reload: forceReload
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
exports.useSelfFetch = useSelfFetch;
|
package/dist/chunk-AUMKE74M.cjs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var _chunkULWVKHSIcjs = require('./chunk-ULWVKHSI.cjs');
|
|
6
|
-
|
|
7
|
-
// src/utils/embed-content-fetch.ts
|
|
8
|
-
var contentFetch = (input, init) => {
|
|
9
|
-
if (!_chunkULWVKHSIcjs.hasEmbedAuthAdapter.call(void 0, )) return fetch(input, init);
|
|
10
|
-
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
11
|
-
return _chunkULWVKHSIcjs.embedAuthedFetch.call(void 0, url, init);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
exports.contentFetch = contentFetch;
|
package/dist/chunk-G3GRYDMS.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import {
|
|
3
|
-
embedAuthedFetch,
|
|
4
|
-
hasEmbedAuthAdapter
|
|
5
|
-
} from "./chunk-ADBE7QF3.js";
|
|
6
|
-
|
|
7
|
-
// src/utils/embed-content-fetch.ts
|
|
8
|
-
var contentFetch = (input, init) => {
|
|
9
|
-
if (!hasEmbedAuthAdapter()) return fetch(input, init);
|
|
10
|
-
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
11
|
-
return embedAuthedFetch(url, init);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
contentFetch
|
|
16
|
-
};
|