@tipsy-studio/sdk 0.0.1 → 0.0.2

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @tipsy-studio/sdk
2
2
 
3
- React sdk for Tipsy Studio apps.
3
+ React SDK for Tipsy Studio iframe apps.
4
4
 
5
5
  ## Install
6
6
 
@@ -13,13 +13,53 @@ npm install @tipsy-studio/sdk react
13
13
  React-specific exports are available from the `/react` subpath.
14
14
 
15
15
  ```tsx
16
- import { useMounted } from "@tipsy-studio/sdk/react";
16
+ import { TipsyStudioProvider, useTipsyChat } from "@tipsy-studio/sdk/react";
17
17
 
18
- export function Demo() {
19
- const mounted = useMounted();
18
+ function ChatButton() {
19
+ const chat = useTipsyChat();
20
+
21
+ async function handleClick() {
22
+ const textParts: string[] = [];
23
+
24
+ const result = await chat.completions(
25
+ {
26
+ messages: [
27
+ {
28
+ role: "system",
29
+ content: "You are a helpful assistant.",
30
+ },
31
+ ],
32
+ stream: true,
33
+ },
34
+ {
35
+ onData(chunk) {
36
+ textParts.push(chunk.chunk);
37
+ },
38
+ onComplete() {
39
+ console.log("stream complete", textParts.join(""));
40
+ },
41
+ },
42
+ );
20
43
 
21
- if (!mounted) return null;
44
+ console.log(result.raw);
45
+ }
46
+
47
+ return <button onClick={handleClick}>Run chat</button>;
48
+ }
22
49
 
23
- return <div>Client content</div>;
50
+ export function Demo() {
51
+ return (
52
+ <TipsyStudioProvider>
53
+ <ChatButton />
54
+ </TipsyStudioProvider>
55
+ );
24
56
  }
25
57
  ```
58
+
59
+ If the parent page uses a fixed allowlist, pass `targetOrigin` explicitly:
60
+
61
+ ```tsx
62
+ <TipsyStudioProvider targetOrigin="https://tipsy.chat">
63
+ <App />
64
+ </TipsyStudioProvider>
65
+ ```
package/dist/react.cjs CHANGED
@@ -2,16 +2,255 @@
2
2
 
3
3
  var react = require('react');
4
4
 
5
- // src/hooks/useMounted.ts
6
- function useMounted() {
7
- const [mounted, setMounted] = react.useState(false);
5
+ // src/react.ts
6
+
7
+ // src/bridge.ts
8
+ var TIPSY_BRIDGE_PROTOCOL = "tipsy-bridge-v1";
9
+ var TIPSY_INIT_RETRY_MS = 500;
10
+ var CHAT_COMPLETIONS_METHOD = "chat.completions";
11
+ var TipsyBridgeClientError = class extends Error {
12
+ constructor(error) {
13
+ super(error.message);
14
+ this.name = "TipsyBridgeClientError";
15
+ this.code = error.code;
16
+ }
17
+ };
18
+ function getParentOriginFromReferrer() {
19
+ if (typeof document === "undefined" || !document.referrer) {
20
+ return null;
21
+ }
22
+ try {
23
+ return new URL(document.referrer).origin;
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+ function normalizeTargetOrigin(value) {
29
+ if (value && value.trim()) {
30
+ return value;
31
+ }
32
+ return getParentOriginFromReferrer() ?? "*";
33
+ }
34
+ function isBridgeMessage(value) {
35
+ if (!value || typeof value !== "object") {
36
+ return false;
37
+ }
38
+ const candidate = value;
39
+ if (candidate.protocol !== TIPSY_BRIDGE_PROTOCOL) {
40
+ return false;
41
+ }
42
+ const validTypes = /* @__PURE__ */ new Set([
43
+ "tipsy:init",
44
+ "tipsy:init:ack",
45
+ "tipsy:request",
46
+ "tipsy:stream",
47
+ "tipsy:response",
48
+ "tipsy:error",
49
+ "tipsy:abort"
50
+ ]);
51
+ return typeof candidate.type === "string" && validTypes.has(candidate.type);
52
+ }
53
+ function createRequestId() {
54
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
55
+ return crypto.randomUUID();
56
+ }
57
+ return `tipsy_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
58
+ }
59
+
60
+ // src/react.ts
61
+ var TipsyStudioContext = react.createContext(null);
62
+ function TipsyStudioProvider({
63
+ children,
64
+ targetOrigin
65
+ }) {
66
+ const resolvedTargetOrigin = react.useMemo(
67
+ () => normalizeTargetOrigin(targetOrigin),
68
+ [targetOrigin]
69
+ );
70
+ const [isReady, setIsReady] = react.useState(false);
71
+ const pendingRef = react.useRef(/* @__PURE__ */ new Map());
72
+ const readyRef = react.useRef(false);
73
+ const targetOriginRef = react.useRef(resolvedTargetOrigin);
74
+ react.useEffect(() => {
75
+ targetOriginRef.current = resolvedTargetOrigin;
76
+ }, [resolvedTargetOrigin]);
8
77
  react.useEffect(() => {
9
- setMounted(true);
10
- console.log("npm \u5305\u6D4B\u8BD5\u901A\u8FC7666");
78
+ if (typeof window === "undefined") {
79
+ return void 0;
80
+ }
81
+ let cancelled = false;
82
+ const rejectPending = (error) => {
83
+ const pendingRequests = Array.from(pendingRef.current.values());
84
+ pendingRef.current.clear();
85
+ for (const pending of pendingRequests) {
86
+ pending.reject(new TipsyBridgeClientError(error));
87
+ }
88
+ };
89
+ const postInit = () => {
90
+ if (cancelled || readyRef.current || window.parent === window) {
91
+ return;
92
+ }
93
+ const initMessage = {
94
+ protocol: TIPSY_BRIDGE_PROTOCOL,
95
+ type: "tipsy:init"
96
+ };
97
+ window.parent.postMessage(initMessage, targetOriginRef.current);
98
+ };
99
+ const intervalId = window.setInterval(postInit, TIPSY_INIT_RETRY_MS);
100
+ postInit();
101
+ const handleMessage = (event) => {
102
+ if (window.parent === window || event.source !== window.parent) {
103
+ return;
104
+ }
105
+ if (targetOriginRef.current !== "*" && event.origin !== targetOriginRef.current) {
106
+ return;
107
+ }
108
+ if (!isBridgeMessage(event.data)) {
109
+ return;
110
+ }
111
+ if (event.data.type === "tipsy:init:ack") {
112
+ readyRef.current = true;
113
+ setIsReady(true);
114
+ return;
115
+ }
116
+ if (event.data.type === "tipsy:error") {
117
+ if (!event.data.requestId) {
118
+ return;
119
+ }
120
+ const pending = pendingRef.current.get(event.data.requestId);
121
+ if (!pending) {
122
+ return;
123
+ }
124
+ pendingRef.current.delete(event.data.requestId);
125
+ pending.reject(new TipsyBridgeClientError(event.data.error));
126
+ return;
127
+ }
128
+ if (event.data.type === "tipsy:stream") {
129
+ const pending = pendingRef.current.get(event.data.requestId);
130
+ if (!pending || pending.method !== CHAT_COMPLETIONS_METHOD) {
131
+ return;
132
+ }
133
+ pending.onData?.(event.data.payload);
134
+ return;
135
+ }
136
+ if (event.data.type === "tipsy:response") {
137
+ const pending = pendingRef.current.get(event.data.requestId);
138
+ if (!pending) {
139
+ return;
140
+ }
141
+ pendingRef.current.delete(event.data.requestId);
142
+ pending.onComplete?.(event.data.payload);
143
+ pending.resolve(event.data.payload);
144
+ }
145
+ };
146
+ window.addEventListener("message", handleMessage);
147
+ return () => {
148
+ cancelled = true;
149
+ readyRef.current = false;
150
+ setIsReady(false);
151
+ window.clearInterval(intervalId);
152
+ window.removeEventListener("message", handleMessage);
153
+ rejectPending({
154
+ code: "NETWORK_ERROR",
155
+ message: "Tipsy bridge was disconnected."
156
+ });
157
+ };
11
158
  }, []);
12
- return mounted;
159
+ const contextValue = react.useMemo(() => {
160
+ return {
161
+ isReady,
162
+ targetOrigin: resolvedTargetOrigin,
163
+ call(method, payload, controller) {
164
+ if (typeof window === "undefined" || window.parent === window) {
165
+ return Promise.reject(
166
+ new TipsyBridgeClientError({
167
+ code: "NETWORK_ERROR",
168
+ message: "Tipsy bridge is only available inside an iframe."
169
+ })
170
+ );
171
+ }
172
+ if (!readyRef.current) {
173
+ return Promise.reject(
174
+ new TipsyBridgeClientError({
175
+ code: "NETWORK_ERROR",
176
+ message: "Tipsy bridge is not ready."
177
+ })
178
+ );
179
+ }
180
+ const requestId = createRequestId();
181
+ return new Promise(
182
+ (resolve, reject) => {
183
+ const pending = {
184
+ method,
185
+ resolve: (value) => resolve(value),
186
+ reject,
187
+ onData: method === CHAT_COMPLETIONS_METHOD ? controller?.onData : void 0,
188
+ onComplete: method === CHAT_COMPLETIONS_METHOD ? controller?.onComplete : void 0
189
+ };
190
+ pendingRef.current.set(requestId, pending);
191
+ const abortSignal = controller?.signal;
192
+ const handleAbort = () => {
193
+ if (!pendingRef.current.has(requestId)) {
194
+ return;
195
+ }
196
+ pendingRef.current.delete(requestId);
197
+ const abortMessage = {
198
+ protocol: TIPSY_BRIDGE_PROTOCOL,
199
+ type: "tipsy:abort",
200
+ requestId
201
+ };
202
+ window.parent.postMessage(abortMessage, targetOriginRef.current);
203
+ reject(
204
+ new DOMException("The operation was aborted.", "AbortError")
205
+ );
206
+ };
207
+ if (abortSignal?.aborted) {
208
+ handleAbort();
209
+ return;
210
+ }
211
+ abortSignal?.addEventListener("abort", handleAbort, { once: true });
212
+ const requestMessage = {
213
+ protocol: TIPSY_BRIDGE_PROTOCOL,
214
+ type: "tipsy:request",
215
+ requestId,
216
+ method,
217
+ payload
218
+ };
219
+ window.parent.postMessage(requestMessage, targetOriginRef.current);
220
+ }
221
+ );
222
+ }
223
+ };
224
+ }, [isReady, resolvedTargetOrigin]);
225
+ return react.createElement(
226
+ TipsyStudioContext.Provider,
227
+ { value: contextValue },
228
+ children
229
+ );
230
+ }
231
+ function useTipsyStudio() {
232
+ const context = react.useContext(TipsyStudioContext);
233
+ if (!context) {
234
+ throw new Error("useTipsyStudio must be used within TipsyStudioProvider.");
235
+ }
236
+ return context;
237
+ }
238
+ function useTipsyChat() {
239
+ const studio = useTipsyStudio();
240
+ return react.useMemo(() => {
241
+ return {
242
+ completions(input, controller) {
243
+ return studio.call(CHAT_COMPLETIONS_METHOD, input, controller);
244
+ }
245
+ };
246
+ }, [studio]);
13
247
  }
14
248
 
15
- exports.useMounted = useMounted;
249
+ exports.CHAT_COMPLETIONS_METHOD = CHAT_COMPLETIONS_METHOD;
250
+ exports.TIPSY_BRIDGE_PROTOCOL = TIPSY_BRIDGE_PROTOCOL;
251
+ exports.TipsyBridgeClientError = TipsyBridgeClientError;
252
+ exports.TipsyStudioProvider = TipsyStudioProvider;
253
+ exports.useTipsyChat = useTipsyChat;
254
+ exports.useTipsyStudio = useTipsyStudio;
16
255
  //# sourceMappingURL=react.cjs.map
17
256
  //# sourceMappingURL=react.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useMounted.ts"],"names":["useState","useEffect"],"mappings":";;;;;AAIO,SAAS,UAAA,GAA+B;AAC7C,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAS,KAAK,CAAA;AAE5C,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,OAAA,CAAQ,IAAI,uCAAc,CAAA;AAAA,EAC5B,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,OAAA;AACT","file":"react.cjs","sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type UseMountedReturn = boolean;\n\nexport function useMounted(): UseMountedReturn {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n console.log(\"npm 包测试通过666\");\n }, []);\n\n return mounted;\n}\n"]}
1
+ {"version":3,"sources":["../src/bridge.ts","../src/react.ts"],"names":["createContext","useMemo","useState","useRef","useEffect","createElement","useContext"],"mappings":"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","file":"react.cjs","sourcesContent":["export const TIPSY_BRIDGE_PROTOCOL = \"tipsy-bridge-v1\";\nexport const TIPSY_INIT_RETRY_MS = 500;\nexport const CHAT_COMPLETIONS_METHOD = \"chat.completions\";\n\ntype TipsyBridgeMessageType =\n | \"tipsy:init\"\n | \"tipsy:init:ack\"\n | \"tipsy:request\"\n | \"tipsy:stream\"\n | \"tipsy:response\"\n | \"tipsy:error\"\n | \"tipsy:abort\";\n\ntype TipsyRole = \"system\" | \"user\" | \"assistant\";\n\nexport type TipsyChatMessage = {\n role: TipsyRole;\n content: string;\n};\n\nexport type TipsyChatCompletionInput = {\n messages: TipsyChatMessage[];\n stream: true;\n};\n\nexport type TipsyChatCompletionRawChunk = {\n type?: string;\n choices?: Array<{\n delta?: {\n content?: string;\n reasoning?: string;\n };\n }>;\n isFinished?: boolean;\n [key: string]: unknown;\n};\n\nexport type TipsyChatCompletionChunk = {\n type: \"stream\";\n chunk: string;\n raw: TipsyChatCompletionRawChunk;\n isFinished: false;\n};\n\nexport type TipsyChatCompletionResult = {\n type: \"done\";\n raw: TipsyChatCompletionRawChunk;\n isFinished: true;\n};\n\nexport type TipsyBridgeErrorCode =\n | \"UNAUTHORIZED\"\n | \"BAD_REQUEST\"\n | \"NETWORK_ERROR\"\n | \"STREAM_PARSE_ERROR\"\n | \"ORIGIN_MISMATCH\"\n | \"UNSUPPORTED_METHOD\"\n | \"INTERNAL_ERROR\";\n\nexport type TipsyBridgeError = {\n code: TipsyBridgeErrorCode;\n message: string;\n};\n\nexport type TipsyBridgeRequestMap = {\n [CHAT_COMPLETIONS_METHOD]: TipsyChatCompletionInput;\n};\n\nexport type TipsyBridgeResponseMap = {\n [CHAT_COMPLETIONS_METHOD]: TipsyChatCompletionResult;\n};\n\nexport type TipsyInitMessage = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:init\";\n};\n\ntype TipsyInitAckMessage = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:init:ack\";\n};\n\nexport type TipsyRequestMessage<M extends keyof TipsyBridgeRequestMap> = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:request\";\n requestId: string;\n method: M;\n payload: TipsyBridgeRequestMap[M];\n};\n\ntype TipsyStreamMessage = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:stream\";\n requestId: string;\n payload: TipsyChatCompletionChunk;\n};\n\ntype TipsyResponseMessage<M extends keyof TipsyBridgeResponseMap> = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:response\";\n requestId: string;\n payload: TipsyBridgeResponseMap[M];\n};\n\ntype TipsyErrorMessage = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:error\";\n requestId?: string;\n error: TipsyBridgeError;\n};\n\nexport type TipsyAbortMessage = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:abort\";\n requestId: string;\n};\n\nexport type TipsyBridgeMessage =\n | TipsyInitMessage\n | TipsyInitAckMessage\n | TipsyRequestMessage<keyof TipsyBridgeRequestMap>\n | TipsyStreamMessage\n | TipsyResponseMessage<keyof TipsyBridgeResponseMap>\n | TipsyErrorMessage\n | TipsyAbortMessage;\n\nexport type TipsyRequestController = {\n signal?: AbortSignal;\n};\n\nexport type TipsyChatCompletionController = TipsyRequestController & {\n onData?: (chunk: TipsyChatCompletionChunk) => void;\n onComplete?: (result: TipsyChatCompletionResult) => void;\n};\n\nexport class TipsyBridgeClientError extends Error {\n code: TipsyBridgeErrorCode;\n\n constructor(error: TipsyBridgeError) {\n super(error.message);\n this.name = \"TipsyBridgeClientError\";\n this.code = error.code;\n }\n}\n\nexport function getParentOriginFromReferrer(): string | null {\n if (typeof document === \"undefined\" || !document.referrer) {\n return null;\n }\n\n try {\n return new URL(document.referrer).origin;\n } catch {\n return null;\n }\n}\n\nexport function normalizeTargetOrigin(value?: string): string {\n if (value && value.trim()) {\n return value;\n }\n\n return getParentOriginFromReferrer() ?? \"*\";\n}\n\nexport function isBridgeMessage(value: unknown): value is TipsyBridgeMessage {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<TipsyBridgeMessage>;\n if (candidate.protocol !== TIPSY_BRIDGE_PROTOCOL) {\n return false;\n }\n\n const validTypes = new Set<TipsyBridgeMessageType>([\n \"tipsy:init\",\n \"tipsy:init:ack\",\n \"tipsy:request\",\n \"tipsy:stream\",\n \"tipsy:response\",\n \"tipsy:error\",\n \"tipsy:abort\",\n ]);\n\n return typeof candidate.type === \"string\" && validTypes.has(candidate.type);\n}\n\nexport function createRequestId() {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return crypto.randomUUID();\n }\n\n return `tipsy_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;\n}\n","import {\n createElement,\n createContext,\n type PropsWithChildren,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n CHAT_COMPLETIONS_METHOD,\n TIPSY_BRIDGE_PROTOCOL,\n TIPSY_INIT_RETRY_MS,\n type TipsyAbortMessage,\n type TipsyBridgeError,\n type TipsyBridgeRequestMap,\n type TipsyBridgeResponseMap,\n type TipsyInitMessage,\n type TipsyRequestController,\n type TipsyRequestMessage,\n TipsyBridgeClientError,\n type TipsyChatCompletionChunk,\n type TipsyChatCompletionController,\n type TipsyChatCompletionInput,\n type TipsyChatCompletionResult,\n createRequestId,\n isBridgeMessage,\n normalizeTargetOrigin,\n} from \"./bridge\";\nexport {\n CHAT_COMPLETIONS_METHOD,\n TIPSY_BRIDGE_PROTOCOL,\n TipsyBridgeClientError,\n type TipsyAbortMessage,\n type TipsyBridgeError,\n type TipsyBridgeMessage,\n type TipsyBridgeRequestMap,\n type TipsyBridgeResponseMap,\n type TipsyChatCompletionChunk,\n type TipsyChatCompletionController,\n type TipsyChatCompletionInput,\n type TipsyChatCompletionRawChunk,\n type TipsyChatCompletionResult,\n type TipsyChatMessage,\n} from \"./bridge\";\n\nexport type TipsyStudioProviderProps = PropsWithChildren<{\n targetOrigin?: string;\n}>;\n\ntype PendingRequest = {\n method: keyof TipsyBridgeRequestMap;\n resolve: (value: TipsyChatCompletionResult) => void;\n reject: (reason?: unknown) => void;\n onData?: (chunk: TipsyChatCompletionChunk) => void;\n onComplete?: (result: TipsyChatCompletionResult) => void;\n};\n\ntype TipsyStudioContextValue = {\n isReady: boolean;\n targetOrigin: string;\n call: <M extends keyof TipsyBridgeRequestMap>(\n method: M,\n payload: TipsyBridgeRequestMap[M],\n controller?: M extends \"chat.completions\"\n ? TipsyChatCompletionController\n : TipsyRequestController,\n ) => Promise<TipsyBridgeResponseMap[M]>;\n};\n\nconst TipsyStudioContext = createContext<TipsyStudioContextValue | null>(null);\n\nexport function TipsyStudioProvider({\n children,\n targetOrigin,\n}: TipsyStudioProviderProps) {\n const resolvedTargetOrigin = useMemo(\n () => normalizeTargetOrigin(targetOrigin),\n [targetOrigin],\n );\n const [isReady, setIsReady] = useState(false);\n const pendingRef = useRef<Map<string, PendingRequest>>(new Map());\n const readyRef = useRef(false);\n const targetOriginRef = useRef(resolvedTargetOrigin);\n\n useEffect(() => {\n targetOriginRef.current = resolvedTargetOrigin;\n }, [resolvedTargetOrigin]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n let cancelled = false;\n\n const rejectPending = (error: TipsyBridgeError) => {\n const pendingRequests = Array.from(pendingRef.current.values());\n pendingRef.current.clear();\n for (const pending of pendingRequests) {\n pending.reject(new TipsyBridgeClientError(error));\n }\n };\n\n const postInit = () => {\n if (cancelled || readyRef.current || window.parent === window) {\n return;\n }\n\n const initMessage: TipsyInitMessage = {\n protocol: TIPSY_BRIDGE_PROTOCOL,\n type: \"tipsy:init\",\n };\n\n window.parent.postMessage(initMessage, targetOriginRef.current);\n };\n\n const intervalId = window.setInterval(postInit, TIPSY_INIT_RETRY_MS);\n postInit();\n\n const handleMessage = (event: MessageEvent) => {\n if (window.parent === window || event.source !== window.parent) {\n return;\n }\n\n if (\n targetOriginRef.current !== \"*\" &&\n event.origin !== targetOriginRef.current\n ) {\n return;\n }\n\n if (!isBridgeMessage(event.data)) {\n return;\n }\n\n if (event.data.type === \"tipsy:init:ack\") {\n readyRef.current = true;\n setIsReady(true);\n return;\n }\n\n if (event.data.type === \"tipsy:error\") {\n if (!event.data.requestId) {\n return;\n }\n\n const pending = pendingRef.current.get(event.data.requestId);\n if (!pending) {\n return;\n }\n\n pendingRef.current.delete(event.data.requestId);\n pending.reject(new TipsyBridgeClientError(event.data.error));\n return;\n }\n\n if (event.data.type === \"tipsy:stream\") {\n const pending = pendingRef.current.get(event.data.requestId);\n if (!pending || pending.method !== CHAT_COMPLETIONS_METHOD) {\n return;\n }\n\n pending.onData?.(event.data.payload);\n return;\n }\n\n if (event.data.type === \"tipsy:response\") {\n const pending = pendingRef.current.get(event.data.requestId);\n if (!pending) {\n return;\n }\n\n pendingRef.current.delete(event.data.requestId);\n pending.onComplete?.(event.data.payload as TipsyChatCompletionResult);\n pending.resolve(event.data.payload as TipsyChatCompletionResult);\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n\n return () => {\n cancelled = true;\n readyRef.current = false;\n setIsReady(false);\n window.clearInterval(intervalId);\n window.removeEventListener(\"message\", handleMessage);\n rejectPending({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge was disconnected.\",\n });\n };\n }, []);\n\n const contextValue = useMemo<TipsyStudioContextValue>(() => {\n return {\n isReady,\n targetOrigin: resolvedTargetOrigin,\n call(method, payload, controller) {\n if (typeof window === \"undefined\" || window.parent === window) {\n return Promise.reject(\n new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge is only available inside an iframe.\",\n }),\n );\n }\n\n if (!readyRef.current) {\n return Promise.reject(\n new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge is not ready.\",\n }),\n );\n }\n\n const requestId = createRequestId();\n\n return new Promise<TipsyBridgeResponseMap[typeof method]>(\n (resolve, reject) => {\n const pending: PendingRequest = {\n method,\n resolve: (value) =>\n resolve(value as TipsyBridgeResponseMap[typeof method]),\n reject,\n onData:\n method === CHAT_COMPLETIONS_METHOD\n ? (controller as TipsyChatCompletionController | undefined)\n ?.onData\n : undefined,\n onComplete:\n method === CHAT_COMPLETIONS_METHOD\n ? (controller as TipsyChatCompletionController | undefined)\n ?.onComplete\n : undefined,\n };\n\n pendingRef.current.set(requestId, pending);\n\n const abortSignal = controller?.signal;\n const handleAbort = () => {\n if (!pendingRef.current.has(requestId)) {\n return;\n }\n\n pendingRef.current.delete(requestId);\n const abortMessage: TipsyAbortMessage = {\n protocol: TIPSY_BRIDGE_PROTOCOL,\n type: \"tipsy:abort\",\n requestId,\n };\n window.parent.postMessage(abortMessage, targetOriginRef.current);\n reject(\n new DOMException(\"The operation was aborted.\", \"AbortError\"),\n );\n };\n\n if (abortSignal?.aborted) {\n handleAbort();\n return;\n }\n\n abortSignal?.addEventListener(\"abort\", handleAbort, { once: true });\n\n const requestMessage: TipsyRequestMessage<typeof method> = {\n protocol: TIPSY_BRIDGE_PROTOCOL,\n type: \"tipsy:request\",\n requestId,\n method,\n payload,\n };\n\n window.parent.postMessage(requestMessage, targetOriginRef.current);\n },\n );\n },\n };\n }, [isReady, resolvedTargetOrigin]);\n\n return createElement(\n TipsyStudioContext.Provider,\n { value: contextValue },\n children,\n );\n}\n\nexport function useTipsyStudio() {\n const context = useContext(TipsyStudioContext);\n\n if (!context) {\n throw new Error(\"useTipsyStudio must be used within TipsyStudioProvider.\");\n }\n\n return context;\n}\n\nexport function useTipsyChat() {\n const studio = useTipsyStudio();\n\n return useMemo(() => {\n return {\n completions(\n input: TipsyChatCompletionInput,\n controller?: TipsyChatCompletionController,\n ) {\n return studio.call(CHAT_COMPLETIONS_METHOD, input, controller);\n },\n };\n }, [studio]);\n}\n"]}
package/dist/react.d.cts CHANGED
@@ -1,4 +1,113 @@
1
- type UseMountedReturn = boolean;
2
- declare function useMounted(): UseMountedReturn;
1
+ import * as react from 'react';
2
+ import { PropsWithChildren } from 'react';
3
3
 
4
- export { type UseMountedReturn, useMounted };
4
+ declare const TIPSY_BRIDGE_PROTOCOL = "tipsy-bridge-v1";
5
+ declare const CHAT_COMPLETIONS_METHOD = "chat.completions";
6
+ type TipsyRole = "system" | "user" | "assistant";
7
+ type TipsyChatMessage = {
8
+ role: TipsyRole;
9
+ content: string;
10
+ };
11
+ type TipsyChatCompletionInput = {
12
+ messages: TipsyChatMessage[];
13
+ stream: true;
14
+ };
15
+ type TipsyChatCompletionRawChunk = {
16
+ type?: string;
17
+ choices?: Array<{
18
+ delta?: {
19
+ content?: string;
20
+ reasoning?: string;
21
+ };
22
+ }>;
23
+ isFinished?: boolean;
24
+ [key: string]: unknown;
25
+ };
26
+ type TipsyChatCompletionChunk = {
27
+ type: "stream";
28
+ chunk: string;
29
+ raw: TipsyChatCompletionRawChunk;
30
+ isFinished: false;
31
+ };
32
+ type TipsyChatCompletionResult = {
33
+ type: "done";
34
+ raw: TipsyChatCompletionRawChunk;
35
+ isFinished: true;
36
+ };
37
+ type TipsyBridgeErrorCode = "UNAUTHORIZED" | "BAD_REQUEST" | "NETWORK_ERROR" | "STREAM_PARSE_ERROR" | "ORIGIN_MISMATCH" | "UNSUPPORTED_METHOD" | "INTERNAL_ERROR";
38
+ type TipsyBridgeError = {
39
+ code: TipsyBridgeErrorCode;
40
+ message: string;
41
+ };
42
+ type TipsyBridgeRequestMap = {
43
+ [CHAT_COMPLETIONS_METHOD]: TipsyChatCompletionInput;
44
+ };
45
+ type TipsyBridgeResponseMap = {
46
+ [CHAT_COMPLETIONS_METHOD]: TipsyChatCompletionResult;
47
+ };
48
+ type TipsyInitMessage = {
49
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
50
+ type: "tipsy:init";
51
+ };
52
+ type TipsyInitAckMessage = {
53
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
54
+ type: "tipsy:init:ack";
55
+ };
56
+ type TipsyRequestMessage<M extends keyof TipsyBridgeRequestMap> = {
57
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
58
+ type: "tipsy:request";
59
+ requestId: string;
60
+ method: M;
61
+ payload: TipsyBridgeRequestMap[M];
62
+ };
63
+ type TipsyStreamMessage = {
64
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
65
+ type: "tipsy:stream";
66
+ requestId: string;
67
+ payload: TipsyChatCompletionChunk;
68
+ };
69
+ type TipsyResponseMessage<M extends keyof TipsyBridgeResponseMap> = {
70
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
71
+ type: "tipsy:response";
72
+ requestId: string;
73
+ payload: TipsyBridgeResponseMap[M];
74
+ };
75
+ type TipsyErrorMessage = {
76
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
77
+ type: "tipsy:error";
78
+ requestId?: string;
79
+ error: TipsyBridgeError;
80
+ };
81
+ type TipsyAbortMessage = {
82
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
83
+ type: "tipsy:abort";
84
+ requestId: string;
85
+ };
86
+ type TipsyBridgeMessage = TipsyInitMessage | TipsyInitAckMessage | TipsyRequestMessage<keyof TipsyBridgeRequestMap> | TipsyStreamMessage | TipsyResponseMessage<keyof TipsyBridgeResponseMap> | TipsyErrorMessage | TipsyAbortMessage;
87
+ type TipsyRequestController = {
88
+ signal?: AbortSignal;
89
+ };
90
+ type TipsyChatCompletionController = TipsyRequestController & {
91
+ onData?: (chunk: TipsyChatCompletionChunk) => void;
92
+ onComplete?: (result: TipsyChatCompletionResult) => void;
93
+ };
94
+ declare class TipsyBridgeClientError extends Error {
95
+ code: TipsyBridgeErrorCode;
96
+ constructor(error: TipsyBridgeError);
97
+ }
98
+
99
+ type TipsyStudioProviderProps = PropsWithChildren<{
100
+ targetOrigin?: string;
101
+ }>;
102
+ type TipsyStudioContextValue = {
103
+ isReady: boolean;
104
+ targetOrigin: string;
105
+ call: <M extends keyof TipsyBridgeRequestMap>(method: M, payload: TipsyBridgeRequestMap[M], controller?: M extends "chat.completions" ? TipsyChatCompletionController : TipsyRequestController) => Promise<TipsyBridgeResponseMap[M]>;
106
+ };
107
+ declare function TipsyStudioProvider({ children, targetOrigin, }: TipsyStudioProviderProps): react.FunctionComponentElement<react.ProviderProps<TipsyStudioContextValue | null>>;
108
+ declare function useTipsyStudio(): TipsyStudioContextValue;
109
+ declare function useTipsyChat(): {
110
+ completions(input: TipsyChatCompletionInput, controller?: TipsyChatCompletionController): Promise<TipsyChatCompletionResult>;
111
+ };
112
+
113
+ export { CHAT_COMPLETIONS_METHOD, TIPSY_BRIDGE_PROTOCOL, type TipsyAbortMessage, TipsyBridgeClientError, type TipsyBridgeError, type TipsyBridgeMessage, type TipsyBridgeRequestMap, type TipsyBridgeResponseMap, type TipsyChatCompletionChunk, type TipsyChatCompletionController, type TipsyChatCompletionInput, type TipsyChatCompletionRawChunk, type TipsyChatCompletionResult, type TipsyChatMessage, TipsyStudioProvider, type TipsyStudioProviderProps, useTipsyChat, useTipsyStudio };
package/dist/react.d.ts CHANGED
@@ -1,4 +1,113 @@
1
- type UseMountedReturn = boolean;
2
- declare function useMounted(): UseMountedReturn;
1
+ import * as react from 'react';
2
+ import { PropsWithChildren } from 'react';
3
3
 
4
- export { type UseMountedReturn, useMounted };
4
+ declare const TIPSY_BRIDGE_PROTOCOL = "tipsy-bridge-v1";
5
+ declare const CHAT_COMPLETIONS_METHOD = "chat.completions";
6
+ type TipsyRole = "system" | "user" | "assistant";
7
+ type TipsyChatMessage = {
8
+ role: TipsyRole;
9
+ content: string;
10
+ };
11
+ type TipsyChatCompletionInput = {
12
+ messages: TipsyChatMessage[];
13
+ stream: true;
14
+ };
15
+ type TipsyChatCompletionRawChunk = {
16
+ type?: string;
17
+ choices?: Array<{
18
+ delta?: {
19
+ content?: string;
20
+ reasoning?: string;
21
+ };
22
+ }>;
23
+ isFinished?: boolean;
24
+ [key: string]: unknown;
25
+ };
26
+ type TipsyChatCompletionChunk = {
27
+ type: "stream";
28
+ chunk: string;
29
+ raw: TipsyChatCompletionRawChunk;
30
+ isFinished: false;
31
+ };
32
+ type TipsyChatCompletionResult = {
33
+ type: "done";
34
+ raw: TipsyChatCompletionRawChunk;
35
+ isFinished: true;
36
+ };
37
+ type TipsyBridgeErrorCode = "UNAUTHORIZED" | "BAD_REQUEST" | "NETWORK_ERROR" | "STREAM_PARSE_ERROR" | "ORIGIN_MISMATCH" | "UNSUPPORTED_METHOD" | "INTERNAL_ERROR";
38
+ type TipsyBridgeError = {
39
+ code: TipsyBridgeErrorCode;
40
+ message: string;
41
+ };
42
+ type TipsyBridgeRequestMap = {
43
+ [CHAT_COMPLETIONS_METHOD]: TipsyChatCompletionInput;
44
+ };
45
+ type TipsyBridgeResponseMap = {
46
+ [CHAT_COMPLETIONS_METHOD]: TipsyChatCompletionResult;
47
+ };
48
+ type TipsyInitMessage = {
49
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
50
+ type: "tipsy:init";
51
+ };
52
+ type TipsyInitAckMessage = {
53
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
54
+ type: "tipsy:init:ack";
55
+ };
56
+ type TipsyRequestMessage<M extends keyof TipsyBridgeRequestMap> = {
57
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
58
+ type: "tipsy:request";
59
+ requestId: string;
60
+ method: M;
61
+ payload: TipsyBridgeRequestMap[M];
62
+ };
63
+ type TipsyStreamMessage = {
64
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
65
+ type: "tipsy:stream";
66
+ requestId: string;
67
+ payload: TipsyChatCompletionChunk;
68
+ };
69
+ type TipsyResponseMessage<M extends keyof TipsyBridgeResponseMap> = {
70
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
71
+ type: "tipsy:response";
72
+ requestId: string;
73
+ payload: TipsyBridgeResponseMap[M];
74
+ };
75
+ type TipsyErrorMessage = {
76
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
77
+ type: "tipsy:error";
78
+ requestId?: string;
79
+ error: TipsyBridgeError;
80
+ };
81
+ type TipsyAbortMessage = {
82
+ protocol: typeof TIPSY_BRIDGE_PROTOCOL;
83
+ type: "tipsy:abort";
84
+ requestId: string;
85
+ };
86
+ type TipsyBridgeMessage = TipsyInitMessage | TipsyInitAckMessage | TipsyRequestMessage<keyof TipsyBridgeRequestMap> | TipsyStreamMessage | TipsyResponseMessage<keyof TipsyBridgeResponseMap> | TipsyErrorMessage | TipsyAbortMessage;
87
+ type TipsyRequestController = {
88
+ signal?: AbortSignal;
89
+ };
90
+ type TipsyChatCompletionController = TipsyRequestController & {
91
+ onData?: (chunk: TipsyChatCompletionChunk) => void;
92
+ onComplete?: (result: TipsyChatCompletionResult) => void;
93
+ };
94
+ declare class TipsyBridgeClientError extends Error {
95
+ code: TipsyBridgeErrorCode;
96
+ constructor(error: TipsyBridgeError);
97
+ }
98
+
99
+ type TipsyStudioProviderProps = PropsWithChildren<{
100
+ targetOrigin?: string;
101
+ }>;
102
+ type TipsyStudioContextValue = {
103
+ isReady: boolean;
104
+ targetOrigin: string;
105
+ call: <M extends keyof TipsyBridgeRequestMap>(method: M, payload: TipsyBridgeRequestMap[M], controller?: M extends "chat.completions" ? TipsyChatCompletionController : TipsyRequestController) => Promise<TipsyBridgeResponseMap[M]>;
106
+ };
107
+ declare function TipsyStudioProvider({ children, targetOrigin, }: TipsyStudioProviderProps): react.FunctionComponentElement<react.ProviderProps<TipsyStudioContextValue | null>>;
108
+ declare function useTipsyStudio(): TipsyStudioContextValue;
109
+ declare function useTipsyChat(): {
110
+ completions(input: TipsyChatCompletionInput, controller?: TipsyChatCompletionController): Promise<TipsyChatCompletionResult>;
111
+ };
112
+
113
+ export { CHAT_COMPLETIONS_METHOD, TIPSY_BRIDGE_PROTOCOL, type TipsyAbortMessage, TipsyBridgeClientError, type TipsyBridgeError, type TipsyBridgeMessage, type TipsyBridgeRequestMap, type TipsyBridgeResponseMap, type TipsyChatCompletionChunk, type TipsyChatCompletionController, type TipsyChatCompletionInput, type TipsyChatCompletionRawChunk, type TipsyChatCompletionResult, type TipsyChatMessage, TipsyStudioProvider, type TipsyStudioProviderProps, useTipsyChat, useTipsyStudio };
package/dist/react.js CHANGED
@@ -1,15 +1,249 @@
1
- import { useState, useEffect } from 'react';
1
+ import { createContext, useMemo, useState, useRef, useEffect, createElement, useContext } from 'react';
2
2
 
3
- // src/hooks/useMounted.ts
4
- function useMounted() {
5
- const [mounted, setMounted] = useState(false);
3
+ // src/react.ts
4
+
5
+ // src/bridge.ts
6
+ var TIPSY_BRIDGE_PROTOCOL = "tipsy-bridge-v1";
7
+ var TIPSY_INIT_RETRY_MS = 500;
8
+ var CHAT_COMPLETIONS_METHOD = "chat.completions";
9
+ var TipsyBridgeClientError = class extends Error {
10
+ constructor(error) {
11
+ super(error.message);
12
+ this.name = "TipsyBridgeClientError";
13
+ this.code = error.code;
14
+ }
15
+ };
16
+ function getParentOriginFromReferrer() {
17
+ if (typeof document === "undefined" || !document.referrer) {
18
+ return null;
19
+ }
20
+ try {
21
+ return new URL(document.referrer).origin;
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+ function normalizeTargetOrigin(value) {
27
+ if (value && value.trim()) {
28
+ return value;
29
+ }
30
+ return getParentOriginFromReferrer() ?? "*";
31
+ }
32
+ function isBridgeMessage(value) {
33
+ if (!value || typeof value !== "object") {
34
+ return false;
35
+ }
36
+ const candidate = value;
37
+ if (candidate.protocol !== TIPSY_BRIDGE_PROTOCOL) {
38
+ return false;
39
+ }
40
+ const validTypes = /* @__PURE__ */ new Set([
41
+ "tipsy:init",
42
+ "tipsy:init:ack",
43
+ "tipsy:request",
44
+ "tipsy:stream",
45
+ "tipsy:response",
46
+ "tipsy:error",
47
+ "tipsy:abort"
48
+ ]);
49
+ return typeof candidate.type === "string" && validTypes.has(candidate.type);
50
+ }
51
+ function createRequestId() {
52
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
53
+ return crypto.randomUUID();
54
+ }
55
+ return `tipsy_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
56
+ }
57
+
58
+ // src/react.ts
59
+ var TipsyStudioContext = createContext(null);
60
+ function TipsyStudioProvider({
61
+ children,
62
+ targetOrigin
63
+ }) {
64
+ const resolvedTargetOrigin = useMemo(
65
+ () => normalizeTargetOrigin(targetOrigin),
66
+ [targetOrigin]
67
+ );
68
+ const [isReady, setIsReady] = useState(false);
69
+ const pendingRef = useRef(/* @__PURE__ */ new Map());
70
+ const readyRef = useRef(false);
71
+ const targetOriginRef = useRef(resolvedTargetOrigin);
72
+ useEffect(() => {
73
+ targetOriginRef.current = resolvedTargetOrigin;
74
+ }, [resolvedTargetOrigin]);
6
75
  useEffect(() => {
7
- setMounted(true);
8
- console.log("npm \u5305\u6D4B\u8BD5\u901A\u8FC7666");
76
+ if (typeof window === "undefined") {
77
+ return void 0;
78
+ }
79
+ let cancelled = false;
80
+ const rejectPending = (error) => {
81
+ const pendingRequests = Array.from(pendingRef.current.values());
82
+ pendingRef.current.clear();
83
+ for (const pending of pendingRequests) {
84
+ pending.reject(new TipsyBridgeClientError(error));
85
+ }
86
+ };
87
+ const postInit = () => {
88
+ if (cancelled || readyRef.current || window.parent === window) {
89
+ return;
90
+ }
91
+ const initMessage = {
92
+ protocol: TIPSY_BRIDGE_PROTOCOL,
93
+ type: "tipsy:init"
94
+ };
95
+ window.parent.postMessage(initMessage, targetOriginRef.current);
96
+ };
97
+ const intervalId = window.setInterval(postInit, TIPSY_INIT_RETRY_MS);
98
+ postInit();
99
+ const handleMessage = (event) => {
100
+ if (window.parent === window || event.source !== window.parent) {
101
+ return;
102
+ }
103
+ if (targetOriginRef.current !== "*" && event.origin !== targetOriginRef.current) {
104
+ return;
105
+ }
106
+ if (!isBridgeMessage(event.data)) {
107
+ return;
108
+ }
109
+ if (event.data.type === "tipsy:init:ack") {
110
+ readyRef.current = true;
111
+ setIsReady(true);
112
+ return;
113
+ }
114
+ if (event.data.type === "tipsy:error") {
115
+ if (!event.data.requestId) {
116
+ return;
117
+ }
118
+ const pending = pendingRef.current.get(event.data.requestId);
119
+ if (!pending) {
120
+ return;
121
+ }
122
+ pendingRef.current.delete(event.data.requestId);
123
+ pending.reject(new TipsyBridgeClientError(event.data.error));
124
+ return;
125
+ }
126
+ if (event.data.type === "tipsy:stream") {
127
+ const pending = pendingRef.current.get(event.data.requestId);
128
+ if (!pending || pending.method !== CHAT_COMPLETIONS_METHOD) {
129
+ return;
130
+ }
131
+ pending.onData?.(event.data.payload);
132
+ return;
133
+ }
134
+ if (event.data.type === "tipsy:response") {
135
+ const pending = pendingRef.current.get(event.data.requestId);
136
+ if (!pending) {
137
+ return;
138
+ }
139
+ pendingRef.current.delete(event.data.requestId);
140
+ pending.onComplete?.(event.data.payload);
141
+ pending.resolve(event.data.payload);
142
+ }
143
+ };
144
+ window.addEventListener("message", handleMessage);
145
+ return () => {
146
+ cancelled = true;
147
+ readyRef.current = false;
148
+ setIsReady(false);
149
+ window.clearInterval(intervalId);
150
+ window.removeEventListener("message", handleMessage);
151
+ rejectPending({
152
+ code: "NETWORK_ERROR",
153
+ message: "Tipsy bridge was disconnected."
154
+ });
155
+ };
9
156
  }, []);
10
- return mounted;
157
+ const contextValue = useMemo(() => {
158
+ return {
159
+ isReady,
160
+ targetOrigin: resolvedTargetOrigin,
161
+ call(method, payload, controller) {
162
+ if (typeof window === "undefined" || window.parent === window) {
163
+ return Promise.reject(
164
+ new TipsyBridgeClientError({
165
+ code: "NETWORK_ERROR",
166
+ message: "Tipsy bridge is only available inside an iframe."
167
+ })
168
+ );
169
+ }
170
+ if (!readyRef.current) {
171
+ return Promise.reject(
172
+ new TipsyBridgeClientError({
173
+ code: "NETWORK_ERROR",
174
+ message: "Tipsy bridge is not ready."
175
+ })
176
+ );
177
+ }
178
+ const requestId = createRequestId();
179
+ return new Promise(
180
+ (resolve, reject) => {
181
+ const pending = {
182
+ method,
183
+ resolve: (value) => resolve(value),
184
+ reject,
185
+ onData: method === CHAT_COMPLETIONS_METHOD ? controller?.onData : void 0,
186
+ onComplete: method === CHAT_COMPLETIONS_METHOD ? controller?.onComplete : void 0
187
+ };
188
+ pendingRef.current.set(requestId, pending);
189
+ const abortSignal = controller?.signal;
190
+ const handleAbort = () => {
191
+ if (!pendingRef.current.has(requestId)) {
192
+ return;
193
+ }
194
+ pendingRef.current.delete(requestId);
195
+ const abortMessage = {
196
+ protocol: TIPSY_BRIDGE_PROTOCOL,
197
+ type: "tipsy:abort",
198
+ requestId
199
+ };
200
+ window.parent.postMessage(abortMessage, targetOriginRef.current);
201
+ reject(
202
+ new DOMException("The operation was aborted.", "AbortError")
203
+ );
204
+ };
205
+ if (abortSignal?.aborted) {
206
+ handleAbort();
207
+ return;
208
+ }
209
+ abortSignal?.addEventListener("abort", handleAbort, { once: true });
210
+ const requestMessage = {
211
+ protocol: TIPSY_BRIDGE_PROTOCOL,
212
+ type: "tipsy:request",
213
+ requestId,
214
+ method,
215
+ payload
216
+ };
217
+ window.parent.postMessage(requestMessage, targetOriginRef.current);
218
+ }
219
+ );
220
+ }
221
+ };
222
+ }, [isReady, resolvedTargetOrigin]);
223
+ return createElement(
224
+ TipsyStudioContext.Provider,
225
+ { value: contextValue },
226
+ children
227
+ );
228
+ }
229
+ function useTipsyStudio() {
230
+ const context = useContext(TipsyStudioContext);
231
+ if (!context) {
232
+ throw new Error("useTipsyStudio must be used within TipsyStudioProvider.");
233
+ }
234
+ return context;
235
+ }
236
+ function useTipsyChat() {
237
+ const studio = useTipsyStudio();
238
+ return useMemo(() => {
239
+ return {
240
+ completions(input, controller) {
241
+ return studio.call(CHAT_COMPLETIONS_METHOD, input, controller);
242
+ }
243
+ };
244
+ }, [studio]);
11
245
  }
12
246
 
13
- export { useMounted };
247
+ export { CHAT_COMPLETIONS_METHOD, TIPSY_BRIDGE_PROTOCOL, TipsyBridgeClientError, TipsyStudioProvider, useTipsyChat, useTipsyStudio };
14
248
  //# sourceMappingURL=react.js.map
15
249
  //# sourceMappingURL=react.js.map
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useMounted.ts"],"names":[],"mappings":";;;AAIO,SAAS,UAAA,GAA+B;AAC7C,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAE5C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,OAAA,CAAQ,IAAI,uCAAc,CAAA;AAAA,EAC5B,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,OAAA;AACT","file":"react.js","sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type UseMountedReturn = boolean;\n\nexport function useMounted(): UseMountedReturn {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n console.log(\"npm 包测试通过666\");\n }, []);\n\n return mounted;\n}\n"]}
1
+ {"version":3,"sources":["../src/bridge.ts","../src/react.ts"],"names":[],"mappings":";;;;;AAAO,IAAM,qBAAA,GAAwB;AAC9B,IAAM,mBAAA,GAAsB,GAAA;AAC5B,IAAM,uBAAA,GAA0B;AAqIhC,IAAM,sBAAA,GAAN,cAAqC,KAAA,CAAM;AAAA,EAGhD,YAAY,KAAA,EAAyB;AACnC,IAAA,KAAA,CAAM,MAAM,OAAO,CAAA;AACnB,IAAA,IAAA,CAAK,IAAA,GAAO,wBAAA;AACZ,IAAA,IAAA,CAAK,OAAO,KAAA,CAAM,IAAA;AAAA,EACpB;AACF;AAEO,SAAS,2BAAA,GAA6C;AAC3D,EAAA,IAAI,OAAO,QAAA,KAAa,WAAA,IAAe,CAAC,SAAS,QAAA,EAAU;AACzD,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAA,CAAE,MAAA;AAAA,EACpC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEO,SAAS,sBAAsB,KAAA,EAAwB;AAC5D,EAAA,IAAI,KAAA,IAAS,KAAA,CAAM,IAAA,EAAK,EAAG;AACzB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,6BAA4B,IAAK,GAAA;AAC1C;AAEO,SAAS,gBAAgB,KAAA,EAA6C;AAC3E,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACvC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,SAAA,GAAY,KAAA;AAClB,EAAA,IAAI,SAAA,CAAU,aAAa,qBAAA,EAAuB;AAChD,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,UAAA,uBAAiB,GAAA,CAA4B;AAAA,IACjD,YAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,OAAO,OAAO,SAAA,CAAU,IAAA,KAAS,YAAY,UAAA,CAAW,GAAA,CAAI,UAAU,IAAI,CAAA;AAC5E;AAEO,SAAS,eAAA,GAAkB;AAChC,EAAA,IACE,OAAO,MAAA,KAAW,WAAA,IAClB,OAAO,MAAA,CAAO,eAAe,UAAA,EAC7B;AACA,IAAA,OAAO,OAAO,UAAA,EAAW;AAAA,EAC3B;AAEA,EAAA,OAAO,CAAA,MAAA,EAAS,IAAA,CAAK,GAAA,EAAK,IAAI,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AACvE;;;AC9HA,IAAM,kBAAA,GAAqB,cAA8C,IAAI,CAAA;AAEtE,SAAS,mBAAA,CAAoB;AAAA,EAClC,QAAA;AAAA,EACA;AACF,CAAA,EAA6B;AAC3B,EAAA,MAAM,oBAAA,GAAuB,OAAA;AAAA,IAC3B,MAAM,sBAAsB,YAAY,CAAA;AAAA,IACxC,CAAC,YAAY;AAAA,GACf;AACA,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,UAAA,GAAa,MAAA,iBAAoC,IAAI,GAAA,EAAK,CAAA;AAChE,EAAA,MAAM,QAAA,GAAW,OAAO,KAAK,CAAA;AAC7B,EAAA,MAAM,eAAA,GAAkB,OAAO,oBAAoB,CAAA;AAEnD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,eAAA,CAAgB,OAAA,GAAU,oBAAA;AAAA,EAC5B,CAAA,EAAG,CAAC,oBAAoB,CAAC,CAAA;AAEzB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,IAAI,SAAA,GAAY,KAAA;AAEhB,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAA4B;AACjD,MAAA,MAAM,kBAAkB,KAAA,CAAM,IAAA,CAAK,UAAA,CAAW,OAAA,CAAQ,QAAQ,CAAA;AAC9D,MAAA,UAAA,CAAW,QAAQ,KAAA,EAAM;AACzB,MAAA,KAAA,MAAW,WAAW,eAAA,EAAiB;AACrC,QAAA,OAAA,CAAQ,MAAA,CAAO,IAAI,sBAAA,CAAuB,KAAK,CAAC,CAAA;AAAA,MAClD;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,WAAW,MAAM;AACrB,MAAA,IAAI,SAAA,IAAa,QAAA,CAAS,OAAA,IAAW,MAAA,CAAO,WAAW,MAAA,EAAQ;AAC7D,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,WAAA,GAAgC;AAAA,QACpC,QAAA,EAAU,qBAAA;AAAA,QACV,IAAA,EAAM;AAAA,OACR;AAEA,MAAA,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,WAAA,EAAa,eAAA,CAAgB,OAAO,CAAA;AAAA,IAChE,CAAA;AAEA,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,WAAA,CAAY,QAAA,EAAU,mBAAmB,CAAA;AACnE,IAAA,QAAA,EAAS;AAET,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAwB;AAC7C,MAAA,IAAI,OAAO,MAAA,KAAW,MAAA,IAAU,KAAA,CAAM,MAAA,KAAW,OAAO,MAAA,EAAQ;AAC9D,QAAA;AAAA,MACF;AAEA,MAAA,IACE,gBAAgB,OAAA,KAAY,GAAA,IAC5B,KAAA,CAAM,MAAA,KAAW,gBAAgB,OAAA,EACjC;AACA,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,eAAA,CAAgB,KAAA,CAAM,IAAI,CAAA,EAAG;AAChC,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,KAAA,CAAM,IAAA,CAAK,IAAA,KAAS,gBAAA,EAAkB;AACxC,QAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,QAAA,UAAA,CAAW,IAAI,CAAA;AACf,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,KAAA,CAAM,IAAA,CAAK,IAAA,KAAS,aAAA,EAAe;AACrC,QAAA,IAAI,CAAC,KAAA,CAAM,IAAA,CAAK,SAAA,EAAW;AACzB,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,UAAU,UAAA,CAAW,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,KAAK,SAAS,CAAA;AAC3D,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA;AAAA,QACF;AAEA,QAAA,UAAA,CAAW,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA;AAC9C,QAAA,OAAA,CAAQ,OAAO,IAAI,sBAAA,CAAuB,KAAA,CAAM,IAAA,CAAK,KAAK,CAAC,CAAA;AAC3D,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,KAAA,CAAM,IAAA,CAAK,IAAA,KAAS,cAAA,EAAgB;AACtC,QAAA,MAAM,UAAU,UAAA,CAAW,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,KAAK,SAAS,CAAA;AAC3D,QAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,uBAAA,EAAyB;AAC1D,UAAA;AAAA,QACF;AAEA,QAAA,OAAA,CAAQ,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,OAAO,CAAA;AACnC,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,KAAA,CAAM,IAAA,CAAK,IAAA,KAAS,gBAAA,EAAkB;AACxC,QAAA,MAAM,UAAU,UAAA,CAAW,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,KAAK,SAAS,CAAA;AAC3D,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA;AAAA,QACF;AAEA,QAAA,UAAA,CAAW,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA;AAC9C,QAAA,OAAA,CAAQ,UAAA,GAAa,KAAA,CAAM,IAAA,CAAK,OAAoC,CAAA;AACpE,QAAA,OAAA,CAAQ,OAAA,CAAQ,KAAA,CAAM,IAAA,CAAK,OAAoC,CAAA;AAAA,MACjE;AAAA,IACF,CAAA;AAEA,IAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,aAAa,CAAA;AAEhD,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AACnB,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA,MAAA,CAAO,cAAc,UAAU,CAAA;AAC/B,MAAA,MAAA,CAAO,mBAAA,CAAoB,WAAW,aAAa,CAAA;AACnD,MAAA,aAAA,CAAc;AAAA,QACZ,IAAA,EAAM,eAAA;AAAA,QACN,OAAA,EAAS;AAAA,OACV,CAAA;AAAA,IACH,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,YAAA,GAAe,QAAiC,MAAM;AAC1D,IAAA,OAAO;AAAA,MACL,OAAA;AAAA,MACA,YAAA,EAAc,oBAAA;AAAA,MACd,IAAA,CAAK,MAAA,EAAQ,OAAA,EAAS,UAAA,EAAY;AAChC,QAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,WAAW,MAAA,EAAQ;AAC7D,UAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,YACb,IAAI,sBAAA,CAAuB;AAAA,cACzB,IAAA,EAAM,eAAA;AAAA,cACN,OAAA,EAAS;AAAA,aACV;AAAA,WACH;AAAA,QACF;AAEA,QAAA,IAAI,CAAC,SAAS,OAAA,EAAS;AACrB,UAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,YACb,IAAI,sBAAA,CAAuB;AAAA,cACzB,IAAA,EAAM,eAAA;AAAA,cACN,OAAA,EAAS;AAAA,aACV;AAAA,WACH;AAAA,QACF;AAEA,QAAA,MAAM,YAAY,eAAA,EAAgB;AAElC,QAAA,OAAO,IAAI,OAAA;AAAA,UACT,CAAC,SAAS,MAAA,KAAW;AACnB,YAAA,MAAM,OAAA,GAA0B;AAAA,cAC9B,MAAA;AAAA,cACA,OAAA,EAAS,CAAC,KAAA,KACR,OAAA,CAAQ,KAA8C,CAAA;AAAA,cACxD,MAAA;AAAA,cACA,MAAA,EACE,MAAA,KAAW,uBAAA,GACN,UAAA,EACG,MAAA,GACJ,MAAA;AAAA,cACN,UAAA,EACE,MAAA,KAAW,uBAAA,GACN,UAAA,EACG,UAAA,GACJ;AAAA,aACR;AAEA,YAAA,UAAA,CAAW,OAAA,CAAQ,GAAA,CAAI,SAAA,EAAW,OAAO,CAAA;AAEzC,YAAA,MAAM,cAAc,UAAA,EAAY,MAAA;AAChC,YAAA,MAAM,cAAc,MAAM;AACxB,cAAA,IAAI,CAAC,UAAA,CAAW,OAAA,CAAQ,GAAA,CAAI,SAAS,CAAA,EAAG;AACtC,gBAAA;AAAA,cACF;AAEA,cAAA,UAAA,CAAW,OAAA,CAAQ,OAAO,SAAS,CAAA;AACnC,cAAA,MAAM,YAAA,GAAkC;AAAA,gBACtC,QAAA,EAAU,qBAAA;AAAA,gBACV,IAAA,EAAM,aAAA;AAAA,gBACN;AAAA,eACF;AACA,cAAA,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,YAAA,EAAc,eAAA,CAAgB,OAAO,CAAA;AAC/D,cAAA,MAAA;AAAA,gBACE,IAAI,YAAA,CAAa,4BAAA,EAA8B,YAAY;AAAA,eAC7D;AAAA,YACF,CAAA;AAEA,YAAA,IAAI,aAAa,OAAA,EAAS;AACxB,cAAA,WAAA,EAAY;AACZ,cAAA;AAAA,YACF;AAEA,YAAA,WAAA,EAAa,iBAAiB,OAAA,EAAS,WAAA,EAAa,EAAE,IAAA,EAAM,MAAM,CAAA;AAElE,YAAA,MAAM,cAAA,GAAqD;AAAA,cACzD,QAAA,EAAU,qBAAA;AAAA,cACV,IAAA,EAAM,eAAA;AAAA,cACN,SAAA;AAAA,cACA,MAAA;AAAA,cACA;AAAA,aACF;AAEA,YAAA,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,cAAA,EAAgB,eAAA,CAAgB,OAAO,CAAA;AAAA,UACnE;AAAA,SACF;AAAA,MACF;AAAA,KACF;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,oBAAoB,CAAC,CAAA;AAElC,EAAA,OAAO,aAAA;AAAA,IACL,kBAAA,CAAmB,QAAA;AAAA,IACnB,EAAE,OAAO,YAAA,EAAa;AAAA,IACtB;AAAA,GACF;AACF;AAEO,SAAS,cAAA,GAAiB;AAC/B,EAAA,MAAM,OAAA,GAAU,WAAW,kBAAkB,CAAA;AAE7C,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,yDAAyD,CAAA;AAAA,EAC3E;AAEA,EAAA,OAAO,OAAA;AACT;AAEO,SAAS,YAAA,GAAe;AAC7B,EAAA,MAAM,SAAS,cAAA,EAAe;AAE9B,EAAA,OAAO,QAAQ,MAAM;AACnB,IAAA,OAAO;AAAA,MACL,WAAA,CACE,OACA,UAAA,EACA;AACA,QAAA,OAAO,MAAA,CAAO,IAAA,CAAK,uBAAA,EAAyB,KAAA,EAAO,UAAU,CAAA;AAAA,MAC/D;AAAA,KACF;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AACb","file":"react.js","sourcesContent":["export const TIPSY_BRIDGE_PROTOCOL = \"tipsy-bridge-v1\";\nexport const TIPSY_INIT_RETRY_MS = 500;\nexport const CHAT_COMPLETIONS_METHOD = \"chat.completions\";\n\ntype TipsyBridgeMessageType =\n | \"tipsy:init\"\n | \"tipsy:init:ack\"\n | \"tipsy:request\"\n | \"tipsy:stream\"\n | \"tipsy:response\"\n | \"tipsy:error\"\n | \"tipsy:abort\";\n\ntype TipsyRole = \"system\" | \"user\" | \"assistant\";\n\nexport type TipsyChatMessage = {\n role: TipsyRole;\n content: string;\n};\n\nexport type TipsyChatCompletionInput = {\n messages: TipsyChatMessage[];\n stream: true;\n};\n\nexport type TipsyChatCompletionRawChunk = {\n type?: string;\n choices?: Array<{\n delta?: {\n content?: string;\n reasoning?: string;\n };\n }>;\n isFinished?: boolean;\n [key: string]: unknown;\n};\n\nexport type TipsyChatCompletionChunk = {\n type: \"stream\";\n chunk: string;\n raw: TipsyChatCompletionRawChunk;\n isFinished: false;\n};\n\nexport type TipsyChatCompletionResult = {\n type: \"done\";\n raw: TipsyChatCompletionRawChunk;\n isFinished: true;\n};\n\nexport type TipsyBridgeErrorCode =\n | \"UNAUTHORIZED\"\n | \"BAD_REQUEST\"\n | \"NETWORK_ERROR\"\n | \"STREAM_PARSE_ERROR\"\n | \"ORIGIN_MISMATCH\"\n | \"UNSUPPORTED_METHOD\"\n | \"INTERNAL_ERROR\";\n\nexport type TipsyBridgeError = {\n code: TipsyBridgeErrorCode;\n message: string;\n};\n\nexport type TipsyBridgeRequestMap = {\n [CHAT_COMPLETIONS_METHOD]: TipsyChatCompletionInput;\n};\n\nexport type TipsyBridgeResponseMap = {\n [CHAT_COMPLETIONS_METHOD]: TipsyChatCompletionResult;\n};\n\nexport type TipsyInitMessage = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:init\";\n};\n\ntype TipsyInitAckMessage = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:init:ack\";\n};\n\nexport type TipsyRequestMessage<M extends keyof TipsyBridgeRequestMap> = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:request\";\n requestId: string;\n method: M;\n payload: TipsyBridgeRequestMap[M];\n};\n\ntype TipsyStreamMessage = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:stream\";\n requestId: string;\n payload: TipsyChatCompletionChunk;\n};\n\ntype TipsyResponseMessage<M extends keyof TipsyBridgeResponseMap> = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:response\";\n requestId: string;\n payload: TipsyBridgeResponseMap[M];\n};\n\ntype TipsyErrorMessage = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:error\";\n requestId?: string;\n error: TipsyBridgeError;\n};\n\nexport type TipsyAbortMessage = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:abort\";\n requestId: string;\n};\n\nexport type TipsyBridgeMessage =\n | TipsyInitMessage\n | TipsyInitAckMessage\n | TipsyRequestMessage<keyof TipsyBridgeRequestMap>\n | TipsyStreamMessage\n | TipsyResponseMessage<keyof TipsyBridgeResponseMap>\n | TipsyErrorMessage\n | TipsyAbortMessage;\n\nexport type TipsyRequestController = {\n signal?: AbortSignal;\n};\n\nexport type TipsyChatCompletionController = TipsyRequestController & {\n onData?: (chunk: TipsyChatCompletionChunk) => void;\n onComplete?: (result: TipsyChatCompletionResult) => void;\n};\n\nexport class TipsyBridgeClientError extends Error {\n code: TipsyBridgeErrorCode;\n\n constructor(error: TipsyBridgeError) {\n super(error.message);\n this.name = \"TipsyBridgeClientError\";\n this.code = error.code;\n }\n}\n\nexport function getParentOriginFromReferrer(): string | null {\n if (typeof document === \"undefined\" || !document.referrer) {\n return null;\n }\n\n try {\n return new URL(document.referrer).origin;\n } catch {\n return null;\n }\n}\n\nexport function normalizeTargetOrigin(value?: string): string {\n if (value && value.trim()) {\n return value;\n }\n\n return getParentOriginFromReferrer() ?? \"*\";\n}\n\nexport function isBridgeMessage(value: unknown): value is TipsyBridgeMessage {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<TipsyBridgeMessage>;\n if (candidate.protocol !== TIPSY_BRIDGE_PROTOCOL) {\n return false;\n }\n\n const validTypes = new Set<TipsyBridgeMessageType>([\n \"tipsy:init\",\n \"tipsy:init:ack\",\n \"tipsy:request\",\n \"tipsy:stream\",\n \"tipsy:response\",\n \"tipsy:error\",\n \"tipsy:abort\",\n ]);\n\n return typeof candidate.type === \"string\" && validTypes.has(candidate.type);\n}\n\nexport function createRequestId() {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return crypto.randomUUID();\n }\n\n return `tipsy_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;\n}\n","import {\n createElement,\n createContext,\n type PropsWithChildren,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n CHAT_COMPLETIONS_METHOD,\n TIPSY_BRIDGE_PROTOCOL,\n TIPSY_INIT_RETRY_MS,\n type TipsyAbortMessage,\n type TipsyBridgeError,\n type TipsyBridgeRequestMap,\n type TipsyBridgeResponseMap,\n type TipsyInitMessage,\n type TipsyRequestController,\n type TipsyRequestMessage,\n TipsyBridgeClientError,\n type TipsyChatCompletionChunk,\n type TipsyChatCompletionController,\n type TipsyChatCompletionInput,\n type TipsyChatCompletionResult,\n createRequestId,\n isBridgeMessage,\n normalizeTargetOrigin,\n} from \"./bridge\";\nexport {\n CHAT_COMPLETIONS_METHOD,\n TIPSY_BRIDGE_PROTOCOL,\n TipsyBridgeClientError,\n type TipsyAbortMessage,\n type TipsyBridgeError,\n type TipsyBridgeMessage,\n type TipsyBridgeRequestMap,\n type TipsyBridgeResponseMap,\n type TipsyChatCompletionChunk,\n type TipsyChatCompletionController,\n type TipsyChatCompletionInput,\n type TipsyChatCompletionRawChunk,\n type TipsyChatCompletionResult,\n type TipsyChatMessage,\n} from \"./bridge\";\n\nexport type TipsyStudioProviderProps = PropsWithChildren<{\n targetOrigin?: string;\n}>;\n\ntype PendingRequest = {\n method: keyof TipsyBridgeRequestMap;\n resolve: (value: TipsyChatCompletionResult) => void;\n reject: (reason?: unknown) => void;\n onData?: (chunk: TipsyChatCompletionChunk) => void;\n onComplete?: (result: TipsyChatCompletionResult) => void;\n};\n\ntype TipsyStudioContextValue = {\n isReady: boolean;\n targetOrigin: string;\n call: <M extends keyof TipsyBridgeRequestMap>(\n method: M,\n payload: TipsyBridgeRequestMap[M],\n controller?: M extends \"chat.completions\"\n ? TipsyChatCompletionController\n : TipsyRequestController,\n ) => Promise<TipsyBridgeResponseMap[M]>;\n};\n\nconst TipsyStudioContext = createContext<TipsyStudioContextValue | null>(null);\n\nexport function TipsyStudioProvider({\n children,\n targetOrigin,\n}: TipsyStudioProviderProps) {\n const resolvedTargetOrigin = useMemo(\n () => normalizeTargetOrigin(targetOrigin),\n [targetOrigin],\n );\n const [isReady, setIsReady] = useState(false);\n const pendingRef = useRef<Map<string, PendingRequest>>(new Map());\n const readyRef = useRef(false);\n const targetOriginRef = useRef(resolvedTargetOrigin);\n\n useEffect(() => {\n targetOriginRef.current = resolvedTargetOrigin;\n }, [resolvedTargetOrigin]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n let cancelled = false;\n\n const rejectPending = (error: TipsyBridgeError) => {\n const pendingRequests = Array.from(pendingRef.current.values());\n pendingRef.current.clear();\n for (const pending of pendingRequests) {\n pending.reject(new TipsyBridgeClientError(error));\n }\n };\n\n const postInit = () => {\n if (cancelled || readyRef.current || window.parent === window) {\n return;\n }\n\n const initMessage: TipsyInitMessage = {\n protocol: TIPSY_BRIDGE_PROTOCOL,\n type: \"tipsy:init\",\n };\n\n window.parent.postMessage(initMessage, targetOriginRef.current);\n };\n\n const intervalId = window.setInterval(postInit, TIPSY_INIT_RETRY_MS);\n postInit();\n\n const handleMessage = (event: MessageEvent) => {\n if (window.parent === window || event.source !== window.parent) {\n return;\n }\n\n if (\n targetOriginRef.current !== \"*\" &&\n event.origin !== targetOriginRef.current\n ) {\n return;\n }\n\n if (!isBridgeMessage(event.data)) {\n return;\n }\n\n if (event.data.type === \"tipsy:init:ack\") {\n readyRef.current = true;\n setIsReady(true);\n return;\n }\n\n if (event.data.type === \"tipsy:error\") {\n if (!event.data.requestId) {\n return;\n }\n\n const pending = pendingRef.current.get(event.data.requestId);\n if (!pending) {\n return;\n }\n\n pendingRef.current.delete(event.data.requestId);\n pending.reject(new TipsyBridgeClientError(event.data.error));\n return;\n }\n\n if (event.data.type === \"tipsy:stream\") {\n const pending = pendingRef.current.get(event.data.requestId);\n if (!pending || pending.method !== CHAT_COMPLETIONS_METHOD) {\n return;\n }\n\n pending.onData?.(event.data.payload);\n return;\n }\n\n if (event.data.type === \"tipsy:response\") {\n const pending = pendingRef.current.get(event.data.requestId);\n if (!pending) {\n return;\n }\n\n pendingRef.current.delete(event.data.requestId);\n pending.onComplete?.(event.data.payload as TipsyChatCompletionResult);\n pending.resolve(event.data.payload as TipsyChatCompletionResult);\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n\n return () => {\n cancelled = true;\n readyRef.current = false;\n setIsReady(false);\n window.clearInterval(intervalId);\n window.removeEventListener(\"message\", handleMessage);\n rejectPending({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge was disconnected.\",\n });\n };\n }, []);\n\n const contextValue = useMemo<TipsyStudioContextValue>(() => {\n return {\n isReady,\n targetOrigin: resolvedTargetOrigin,\n call(method, payload, controller) {\n if (typeof window === \"undefined\" || window.parent === window) {\n return Promise.reject(\n new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge is only available inside an iframe.\",\n }),\n );\n }\n\n if (!readyRef.current) {\n return Promise.reject(\n new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge is not ready.\",\n }),\n );\n }\n\n const requestId = createRequestId();\n\n return new Promise<TipsyBridgeResponseMap[typeof method]>(\n (resolve, reject) => {\n const pending: PendingRequest = {\n method,\n resolve: (value) =>\n resolve(value as TipsyBridgeResponseMap[typeof method]),\n reject,\n onData:\n method === CHAT_COMPLETIONS_METHOD\n ? (controller as TipsyChatCompletionController | undefined)\n ?.onData\n : undefined,\n onComplete:\n method === CHAT_COMPLETIONS_METHOD\n ? (controller as TipsyChatCompletionController | undefined)\n ?.onComplete\n : undefined,\n };\n\n pendingRef.current.set(requestId, pending);\n\n const abortSignal = controller?.signal;\n const handleAbort = () => {\n if (!pendingRef.current.has(requestId)) {\n return;\n }\n\n pendingRef.current.delete(requestId);\n const abortMessage: TipsyAbortMessage = {\n protocol: TIPSY_BRIDGE_PROTOCOL,\n type: \"tipsy:abort\",\n requestId,\n };\n window.parent.postMessage(abortMessage, targetOriginRef.current);\n reject(\n new DOMException(\"The operation was aborted.\", \"AbortError\"),\n );\n };\n\n if (abortSignal?.aborted) {\n handleAbort();\n return;\n }\n\n abortSignal?.addEventListener(\"abort\", handleAbort, { once: true });\n\n const requestMessage: TipsyRequestMessage<typeof method> = {\n protocol: TIPSY_BRIDGE_PROTOCOL,\n type: \"tipsy:request\",\n requestId,\n method,\n payload,\n };\n\n window.parent.postMessage(requestMessage, targetOriginRef.current);\n },\n );\n },\n };\n }, [isReady, resolvedTargetOrigin]);\n\n return createElement(\n TipsyStudioContext.Provider,\n { value: contextValue },\n children,\n );\n}\n\nexport function useTipsyStudio() {\n const context = useContext(TipsyStudioContext);\n\n if (!context) {\n throw new Error(\"useTipsyStudio must be used within TipsyStudioProvider.\");\n }\n\n return context;\n}\n\nexport function useTipsyChat() {\n const studio = useTipsyStudio();\n\n return useMemo(() => {\n return {\n completions(\n input: TipsyChatCompletionInput,\n controller?: TipsyChatCompletionController,\n ) {\n return studio.call(CHAT_COMPLETIONS_METHOD, input, controller);\n },\n };\n }, [studio]);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tipsy-studio/sdk",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "React sdk for Tipsy Studio apps.",
5
5
  "license": "MIT",
6
6
  "type": "module",