@tipsy-studio/sdk 0.0.1 → 0.0.3

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/react.cjs CHANGED
@@ -2,16 +2,398 @@
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/client.ts
61
+ var TIPSY_READY_WAIT_RETRY_COUNT = 6;
62
+ function createTipsyStudioClient(options = {}) {
63
+ const sourceWindow = options.sourceWindow ?? (typeof window !== "undefined" ? window : void 0);
64
+ const targetWindow = options.targetWindow ?? (sourceWindow && sourceWindow.parent !== sourceWindow ? sourceWindow.parent : void 0);
65
+ const targetOrigin = normalizeTargetOrigin(options.targetOrigin);
66
+ const pendingRequests = /* @__PURE__ */ new Map();
67
+ const readyWaiters = /* @__PURE__ */ new Set();
68
+ const listeners = /* @__PURE__ */ new Set();
69
+ let isDestroyed = false;
70
+ let isConnected = false;
71
+ let isReady = false;
72
+ let initIntervalId = null;
73
+ const emitReadyChange = (nextReady) => {
74
+ if (isReady === nextReady) {
75
+ return;
76
+ }
77
+ isReady = nextReady;
78
+ for (const listener of listeners) {
79
+ listener(isReady);
80
+ }
81
+ };
82
+ const resolveReadyWaiters = () => {
83
+ const waiters = Array.from(readyWaiters.values());
84
+ readyWaiters.clear();
85
+ for (const resolve of waiters) {
86
+ resolve();
87
+ }
88
+ };
89
+ const rejectPending = (error) => {
90
+ const requests = Array.from(pendingRequests.values());
91
+ pendingRequests.clear();
92
+ for (const pending of requests) {
93
+ pending.cleanupAbortListener?.();
94
+ pending.reject(new TipsyBridgeClientError(error));
95
+ }
96
+ };
97
+ const postMessageToTarget = (message) => {
98
+ targetWindow?.postMessage(message, targetOrigin);
99
+ };
100
+ const postInit = () => {
101
+ if (isDestroyed || isReady || !targetWindow) {
102
+ return;
103
+ }
104
+ postMessageToTarget({
105
+ protocol: TIPSY_BRIDGE_PROTOCOL,
106
+ type: "tipsy:init"
107
+ });
108
+ };
109
+ const handleMessage = (event) => {
110
+ if (isDestroyed || event.source !== targetWindow) {
111
+ return;
112
+ }
113
+ if (targetOrigin !== "*" && event.origin !== targetOrigin) {
114
+ return;
115
+ }
116
+ if (!isBridgeMessage(event.data)) {
117
+ return;
118
+ }
119
+ if (event.data.type === "tipsy:init:ack") {
120
+ emitReadyChange(true);
121
+ resolveReadyWaiters();
122
+ return;
123
+ }
124
+ if (event.data.type === "tipsy:error") {
125
+ if (!event.data.requestId) {
126
+ return;
127
+ }
128
+ const pending = pendingRequests.get(event.data.requestId);
129
+ if (!pending) {
130
+ return;
131
+ }
132
+ pendingRequests.delete(event.data.requestId);
133
+ pending.cleanupAbortListener?.();
134
+ pending.reject(new TipsyBridgeClientError(event.data.error));
135
+ return;
136
+ }
137
+ if (event.data.type === "tipsy:stream") {
138
+ const pending = pendingRequests.get(event.data.requestId);
139
+ if (!pending || pending.method !== CHAT_COMPLETIONS_METHOD) {
140
+ return;
141
+ }
142
+ pending.onData?.(event.data.payload);
143
+ return;
144
+ }
145
+ if (event.data.type === "tipsy:response") {
146
+ const pending = pendingRequests.get(event.data.requestId);
147
+ if (!pending) {
148
+ return;
149
+ }
150
+ pendingRequests.delete(event.data.requestId);
151
+ pending.cleanupAbortListener?.();
152
+ pending.onComplete?.(event.data.payload);
153
+ pending.resolve(event.data.payload);
154
+ }
155
+ };
156
+ const ensureConnected = () => {
157
+ if (isDestroyed || isConnected || !sourceWindow) {
158
+ return;
159
+ }
160
+ sourceWindow.addEventListener("message", handleMessage);
161
+ initIntervalId = sourceWindow.setInterval(postInit, TIPSY_INIT_RETRY_MS);
162
+ isConnected = true;
163
+ postInit();
164
+ };
165
+ const ensureBridgeAvailable = () => {
166
+ if (!sourceWindow || !targetWindow) {
167
+ throw new TipsyBridgeClientError({
168
+ code: "NETWORK_ERROR",
169
+ message: "Tipsy bridge is only available inside an iframe."
170
+ });
171
+ }
172
+ };
173
+ const waitForReady = async (signal) => {
174
+ if (isDestroyed) {
175
+ throw new TipsyBridgeClientError({
176
+ code: "NETWORK_ERROR",
177
+ message: "Tipsy bridge was disconnected."
178
+ });
179
+ }
180
+ ensureBridgeAvailable();
181
+ ensureConnected();
182
+ const activeSourceWindow = sourceWindow;
183
+ if (!activeSourceWindow) {
184
+ throw new TipsyBridgeClientError({
185
+ code: "NETWORK_ERROR",
186
+ message: "Tipsy bridge is only available inside an iframe."
187
+ });
188
+ }
189
+ if (isReady) {
190
+ return;
191
+ }
192
+ for (let attempt = 0; attempt < TIPSY_READY_WAIT_RETRY_COUNT; attempt += 1) {
193
+ if (signal?.aborted) {
194
+ throw new DOMException("The operation was aborted.", "AbortError");
195
+ }
196
+ postInit();
197
+ await new Promise((resolve, reject) => {
198
+ let timeoutId = 0;
199
+ const handleReady = () => {
200
+ activeSourceWindow.clearTimeout(timeoutId);
201
+ signal?.removeEventListener("abort", handleAbort);
202
+ readyWaiters.delete(handleReady);
203
+ resolve();
204
+ };
205
+ const handleAbort = () => {
206
+ activeSourceWindow.clearTimeout(timeoutId);
207
+ readyWaiters.delete(handleReady);
208
+ signal?.removeEventListener("abort", handleAbort);
209
+ reject(new DOMException("The operation was aborted.", "AbortError"));
210
+ };
211
+ readyWaiters.add(handleReady);
212
+ timeoutId = activeSourceWindow.setTimeout(() => {
213
+ readyWaiters.delete(handleReady);
214
+ signal?.removeEventListener("abort", handleAbort);
215
+ resolve();
216
+ }, TIPSY_INIT_RETRY_MS);
217
+ signal?.addEventListener("abort", handleAbort, { once: true });
218
+ });
219
+ if (isReady) {
220
+ return;
221
+ }
222
+ }
223
+ throw new TipsyBridgeClientError({
224
+ code: "NETWORK_ERROR",
225
+ message: "Tipsy bridge is not ready."
226
+ });
227
+ };
228
+ const client = {
229
+ isReady: () => isReady,
230
+ subscribe(listener) {
231
+ listeners.add(listener);
232
+ listener(isReady);
233
+ ensureConnected();
234
+ return () => {
235
+ listeners.delete(listener);
236
+ };
237
+ },
238
+ async waitForReady(signal) {
239
+ await waitForReady(signal);
240
+ },
241
+ async call(method, payload, controller) {
242
+ if (isDestroyed) {
243
+ throw new TipsyBridgeClientError({
244
+ code: "NETWORK_ERROR",
245
+ message: "Tipsy bridge was disconnected."
246
+ });
247
+ }
248
+ await waitForReady(controller?.signal);
249
+ const requestId = createRequestId();
250
+ return await new Promise(
251
+ (resolve, reject) => {
252
+ const pending = {
253
+ method,
254
+ resolve: (value) => resolve(value),
255
+ reject,
256
+ onData: method === CHAT_COMPLETIONS_METHOD ? controller?.onData : void 0,
257
+ onComplete: method === CHAT_COMPLETIONS_METHOD ? controller?.onComplete : void 0
258
+ };
259
+ pendingRequests.set(requestId, pending);
260
+ const abortSignal = controller?.signal;
261
+ const handleAbort = () => {
262
+ if (!pendingRequests.has(requestId)) {
263
+ return;
264
+ }
265
+ pendingRequests.delete(requestId);
266
+ pending.cleanupAbortListener?.();
267
+ postMessageToTarget({
268
+ protocol: TIPSY_BRIDGE_PROTOCOL,
269
+ type: "tipsy:abort",
270
+ requestId
271
+ });
272
+ reject(new DOMException("The operation was aborted.", "AbortError"));
273
+ };
274
+ pending.cleanupAbortListener = () => {
275
+ abortSignal?.removeEventListener("abort", handleAbort);
276
+ };
277
+ if (abortSignal?.aborted) {
278
+ handleAbort();
279
+ return;
280
+ }
281
+ abortSignal?.addEventListener("abort", handleAbort, { once: true });
282
+ postMessageToTarget({
283
+ protocol: TIPSY_BRIDGE_PROTOCOL,
284
+ type: "tipsy:request",
285
+ requestId,
286
+ method,
287
+ payload
288
+ });
289
+ }
290
+ );
291
+ },
292
+ chat: {
293
+ completions(input, controller) {
294
+ return client.call(CHAT_COMPLETIONS_METHOD, input, controller);
295
+ }
296
+ },
297
+ destroy() {
298
+ if (isDestroyed) {
299
+ return;
300
+ }
301
+ isDestroyed = true;
302
+ resolveReadyWaiters();
303
+ emitReadyChange(false);
304
+ listeners.clear();
305
+ if (isConnected && sourceWindow) {
306
+ if (initIntervalId !== null) {
307
+ sourceWindow.clearInterval(initIntervalId);
308
+ }
309
+ sourceWindow.removeEventListener("message", handleMessage);
310
+ }
311
+ initIntervalId = null;
312
+ isConnected = false;
313
+ rejectPending({
314
+ code: "NETWORK_ERROR",
315
+ message: "Tipsy bridge was disconnected."
316
+ });
317
+ }
318
+ };
319
+ return client;
320
+ }
321
+
322
+ // src/react.ts
323
+ var TipsyStudioContext = react.createContext(null);
324
+ function TipsyStudioProvider({
325
+ children,
326
+ targetOrigin
327
+ }) {
328
+ const resolvedTargetOrigin = react.useMemo(
329
+ () => normalizeTargetOrigin(targetOrigin),
330
+ [targetOrigin]
331
+ );
332
+ const [isReady, setIsReady] = react.useState(false);
333
+ const [client, setClient] = react.useState(null);
8
334
  react.useEffect(() => {
9
- setMounted(true);
10
- console.log("npm \u5305\u6D4B\u8BD5\u901A\u8FC7666");
11
- }, []);
12
- return mounted;
335
+ const nextClient = createTipsyStudioClient({ targetOrigin });
336
+ setClient(nextClient);
337
+ setIsReady(nextClient.isReady());
338
+ const unsubscribe = nextClient.subscribe((nextIsReady) => {
339
+ setIsReady(nextIsReady);
340
+ });
341
+ return () => {
342
+ unsubscribe();
343
+ nextClient.destroy();
344
+ setClient(
345
+ (currentClient) => currentClient === nextClient ? null : currentClient
346
+ );
347
+ setIsReady(false);
348
+ };
349
+ }, [targetOrigin]);
350
+ const contextValue = react.useMemo(() => {
351
+ return {
352
+ isReady,
353
+ targetOrigin: resolvedTargetOrigin,
354
+ call(method, payload, controller) {
355
+ if (!client) {
356
+ return Promise.reject(
357
+ new TipsyBridgeClientError({
358
+ code: "NETWORK_ERROR",
359
+ message: "Tipsy bridge is not ready."
360
+ })
361
+ );
362
+ }
363
+ return client.call(method, payload, controller);
364
+ }
365
+ };
366
+ }, [client, isReady, resolvedTargetOrigin]);
367
+ return react.createElement(
368
+ TipsyStudioContext.Provider,
369
+ { value: contextValue },
370
+ children
371
+ );
372
+ }
373
+ function useTipsyStudio() {
374
+ const context = react.useContext(TipsyStudioContext);
375
+ if (!context) {
376
+ throw new Error("useTipsyStudio must be used within TipsyStudioProvider.");
377
+ }
378
+ return context;
379
+ }
380
+ function useTipsyChat() {
381
+ const studio = useTipsyStudio();
382
+ return react.useMemo(() => {
383
+ return {
384
+ completions(input, controller) {
385
+ return studio.call(CHAT_COMPLETIONS_METHOD, input, controller);
386
+ }
387
+ };
388
+ }, [studio]);
13
389
  }
14
390
 
15
- exports.useMounted = useMounted;
391
+ exports.CHAT_COMPLETIONS_METHOD = CHAT_COMPLETIONS_METHOD;
392
+ exports.TIPSY_BRIDGE_PROTOCOL = TIPSY_BRIDGE_PROTOCOL;
393
+ exports.TipsyBridgeClientError = TipsyBridgeClientError;
394
+ exports.TipsyStudioProvider = TipsyStudioProvider;
395
+ exports.createTipsyStudioClient = createTipsyStudioClient;
396
+ exports.useTipsyChat = useTipsyChat;
397
+ exports.useTipsyStudio = useTipsyStudio;
16
398
  //# sourceMappingURL=react.cjs.map
17
399
  //# 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/client.ts","../src/react.ts"],"names":["createContext","useMemo","useState","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 CHAT_COMPLETIONS_METHOD,\n TIPSY_BRIDGE_PROTOCOL,\n TIPSY_INIT_RETRY_MS,\n type TipsyAbortMessage,\n type TipsyBridgeError,\n TipsyBridgeClientError,\n type TipsyBridgeRequestMap,\n type TipsyBridgeResponseMap,\n type TipsyChatCompletionChunk,\n type TipsyChatCompletionController,\n type TipsyChatCompletionInput,\n type TipsyChatCompletionResult,\n type TipsyInitMessage,\n type TipsyRequestController,\n type TipsyRequestMessage,\n createRequestId,\n isBridgeMessage,\n normalizeTargetOrigin,\n} from \"./bridge\";\n\nconst TIPSY_READY_WAIT_RETRY_COUNT = 6;\n\ntype PendingRequest = {\n method: keyof TipsyBridgeRequestMap;\n resolve: (value: TipsyBridgeResponseMap[keyof TipsyBridgeResponseMap]) => void;\n reject: (reason?: unknown) => void;\n onData?: (chunk: TipsyChatCompletionChunk) => void;\n onComplete?: (result: TipsyChatCompletionResult) => void;\n cleanupAbortListener?: () => void;\n};\n\nexport type TipsyStudioClientOptions = {\n targetOrigin?: string;\n sourceWindow?: Window;\n targetWindow?: Window;\n};\n\nexport type TipsyStudioClient = {\n isReady: () => boolean;\n subscribe: (listener: (isReady: boolean) => void) => () => void;\n waitForReady: (signal?: AbortSignal) => Promise<void>;\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 chat: {\n completions: (\n input: TipsyChatCompletionInput,\n controller?: TipsyChatCompletionController,\n ) => Promise<TipsyChatCompletionResult>;\n };\n destroy: () => void;\n};\n\nexport function createTipsyStudioClient(\n options: TipsyStudioClientOptions = {},\n): TipsyStudioClient {\n const sourceWindow =\n options.sourceWindow ?? (typeof window !== \"undefined\" ? window : undefined);\n const targetWindow =\n options.targetWindow ??\n (sourceWindow && sourceWindow.parent !== sourceWindow\n ? sourceWindow.parent\n : undefined);\n const targetOrigin = normalizeTargetOrigin(options.targetOrigin);\n\n const pendingRequests = new Map<string, PendingRequest>();\n const readyWaiters = new Set<() => void>();\n const listeners = new Set<(isReady: boolean) => void>();\n\n let isDestroyed = false;\n let isConnected = false;\n let isReady = false;\n let initIntervalId: number | null = null;\n\n const emitReadyChange = (nextReady: boolean) => {\n if (isReady === nextReady) {\n return;\n }\n\n isReady = nextReady;\n for (const listener of listeners) {\n listener(isReady);\n }\n };\n\n const resolveReadyWaiters = () => {\n const waiters = Array.from(readyWaiters.values());\n readyWaiters.clear();\n for (const resolve of waiters) {\n resolve();\n }\n };\n\n const rejectPending = (error: TipsyBridgeError) => {\n const requests = Array.from(pendingRequests.values());\n pendingRequests.clear();\n for (const pending of requests) {\n pending.cleanupAbortListener?.();\n pending.reject(new TipsyBridgeClientError(error));\n }\n };\n\n const postMessageToTarget = (message: TipsyInitMessage | TipsyAbortMessage | TipsyRequestMessage<keyof TipsyBridgeRequestMap>) => {\n targetWindow?.postMessage(message, targetOrigin);\n };\n\n const postInit = () => {\n if (isDestroyed || isReady || !targetWindow) {\n return;\n }\n\n postMessageToTarget({\n protocol: TIPSY_BRIDGE_PROTOCOL,\n type: \"tipsy:init\",\n });\n };\n\n const handleMessage = (event: MessageEvent) => {\n if (isDestroyed || event.source !== targetWindow) {\n return;\n }\n\n if (targetOrigin !== \"*\" && event.origin !== targetOrigin) {\n return;\n }\n\n if (!isBridgeMessage(event.data)) {\n return;\n }\n\n if (event.data.type === \"tipsy:init:ack\") {\n emitReadyChange(true);\n resolveReadyWaiters();\n return;\n }\n\n if (event.data.type === \"tipsy:error\") {\n if (!event.data.requestId) {\n return;\n }\n\n const pending = pendingRequests.get(event.data.requestId);\n if (!pending) {\n return;\n }\n\n pendingRequests.delete(event.data.requestId);\n pending.cleanupAbortListener?.();\n pending.reject(new TipsyBridgeClientError(event.data.error));\n return;\n }\n\n if (event.data.type === \"tipsy:stream\") {\n const pending = pendingRequests.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 = pendingRequests.get(event.data.requestId);\n if (!pending) {\n return;\n }\n\n pendingRequests.delete(event.data.requestId);\n pending.cleanupAbortListener?.();\n pending.onComplete?.(event.data.payload as TipsyChatCompletionResult);\n pending.resolve(event.data.payload);\n }\n };\n\n const ensureConnected = () => {\n if (isDestroyed || isConnected || !sourceWindow) {\n return;\n }\n\n sourceWindow.addEventListener(\"message\", handleMessage);\n initIntervalId = sourceWindow.setInterval(postInit, TIPSY_INIT_RETRY_MS);\n isConnected = true;\n postInit();\n };\n\n const ensureBridgeAvailable = () => {\n if (!sourceWindow || !targetWindow) {\n throw new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge is only available inside an iframe.\",\n });\n }\n };\n\n const waitForReady = async (signal?: AbortSignal) => {\n if (isDestroyed) {\n throw new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge was disconnected.\",\n });\n }\n\n ensureBridgeAvailable();\n ensureConnected();\n const activeSourceWindow = sourceWindow;\n\n if (!activeSourceWindow) {\n throw new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge is only available inside an iframe.\",\n });\n }\n\n if (isReady) {\n return;\n }\n\n for (let attempt = 0; attempt < TIPSY_READY_WAIT_RETRY_COUNT; attempt += 1) {\n if (signal?.aborted) {\n throw new DOMException(\"The operation was aborted.\", \"AbortError\");\n }\n\n postInit();\n\n await new Promise<void>((resolve, reject) => {\n let timeoutId = 0;\n\n const handleReady = () => {\n activeSourceWindow.clearTimeout(timeoutId);\n signal?.removeEventListener(\"abort\", handleAbort);\n readyWaiters.delete(handleReady);\n resolve();\n };\n\n const handleAbort = () => {\n activeSourceWindow.clearTimeout(timeoutId);\n readyWaiters.delete(handleReady);\n signal?.removeEventListener(\"abort\", handleAbort);\n reject(new DOMException(\"The operation was aborted.\", \"AbortError\"));\n };\n\n readyWaiters.add(handleReady);\n timeoutId = activeSourceWindow.setTimeout(() => {\n readyWaiters.delete(handleReady);\n signal?.removeEventListener(\"abort\", handleAbort);\n resolve();\n }, TIPSY_INIT_RETRY_MS);\n\n signal?.addEventListener(\"abort\", handleAbort, { once: true });\n });\n\n if (isReady) {\n return;\n }\n }\n\n throw new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge is not ready.\",\n });\n };\n\n const client: TipsyStudioClient = {\n isReady: () => isReady,\n subscribe(listener) {\n listeners.add(listener);\n listener(isReady);\n ensureConnected();\n\n return () => {\n listeners.delete(listener);\n };\n },\n async waitForReady(signal) {\n await waitForReady(signal);\n },\n async call(method, payload, controller) {\n if (isDestroyed) {\n throw new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge was disconnected.\",\n });\n }\n\n await waitForReady(controller?.signal);\n\n const requestId = createRequestId();\n\n return await 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 pendingRequests.set(requestId, pending);\n\n const abortSignal = controller?.signal;\n const handleAbort = () => {\n if (!pendingRequests.has(requestId)) {\n return;\n }\n\n pendingRequests.delete(requestId);\n pending.cleanupAbortListener?.();\n postMessageToTarget({\n protocol: TIPSY_BRIDGE_PROTOCOL,\n type: \"tipsy:abort\",\n requestId,\n });\n reject(new DOMException(\"The operation was aborted.\", \"AbortError\"));\n };\n\n pending.cleanupAbortListener = () => {\n abortSignal?.removeEventListener(\"abort\", handleAbort);\n };\n\n if (abortSignal?.aborted) {\n handleAbort();\n return;\n }\n\n abortSignal?.addEventListener(\"abort\", handleAbort, { once: true });\n\n postMessageToTarget({\n protocol: TIPSY_BRIDGE_PROTOCOL,\n type: \"tipsy:request\",\n requestId,\n method,\n payload,\n });\n },\n );\n },\n chat: {\n completions(input, controller) {\n return client.call(CHAT_COMPLETIONS_METHOD, input, controller);\n },\n },\n destroy() {\n if (isDestroyed) {\n return;\n }\n\n isDestroyed = true;\n resolveReadyWaiters();\n emitReadyChange(false);\n listeners.clear();\n\n if (isConnected && sourceWindow) {\n if (initIntervalId !== null) {\n sourceWindow.clearInterval(initIntervalId);\n }\n sourceWindow.removeEventListener(\"message\", handleMessage);\n }\n\n initIntervalId = null;\n isConnected = false;\n rejectPending({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge was disconnected.\",\n });\n },\n };\n\n return client;\n}\n","import {\n createElement,\n createContext,\n type PropsWithChildren,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport {\n CHAT_COMPLETIONS_METHOD,\n TipsyBridgeClientError,\n type TipsyBridgeRequestMap,\n type TipsyBridgeResponseMap,\n type TipsyRequestController,\n type TipsyChatCompletionController,\n type TipsyChatCompletionInput,\n normalizeTargetOrigin,\n} from \"./bridge\";\nimport { createTipsyStudioClient, type TipsyStudioClient } from \"./client\";\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\";\nexport { createTipsyStudioClient, type TipsyStudioClient, type TipsyStudioClientOptions } from \"./client\";\n\nexport type TipsyStudioProviderProps = PropsWithChildren<{\n targetOrigin?: string;\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 [client, setClient] = useState<TipsyStudioClient | null>(null);\n\n useEffect(() => {\n const nextClient = createTipsyStudioClient({ targetOrigin });\n setClient(nextClient);\n setIsReady(nextClient.isReady());\n\n const unsubscribe = nextClient.subscribe((nextIsReady) => {\n setIsReady(nextIsReady);\n });\n\n return () => {\n unsubscribe();\n nextClient.destroy();\n setClient((currentClient) =>\n currentClient === nextClient ? null : currentClient,\n );\n setIsReady(false);\n };\n }, [targetOrigin]);\n\n const contextValue = useMemo<TipsyStudioContextValue>(() => {\n return {\n isReady,\n targetOrigin: resolvedTargetOrigin,\n call(method, payload, controller) {\n if (!client) {\n return Promise.reject(\n new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge is not ready.\",\n }),\n );\n }\n\n return client.call(method, payload, controller);\n },\n };\n }, [client, 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,20 @@
1
- type UseMountedReturn = boolean;
2
- declare function useMounted(): UseMountedReturn;
1
+ import { TipsyBridgeRequestMap, TipsyChatCompletionController, TipsyRequestController, TipsyBridgeResponseMap, TipsyChatCompletionInput, TipsyChatCompletionResult } from './index.cjs';
2
+ export { CHAT_COMPLETIONS_METHOD, TIPSY_BRIDGE_PROTOCOL, TipsyAbortMessage, TipsyBridgeClientError, TipsyBridgeError, TipsyBridgeMessage, TipsyChatCompletionChunk, TipsyChatCompletionRawChunk, TipsyChatMessage, TipsyStudioClient, TipsyStudioClientOptions, createTipsyStudioClient } from './index.cjs';
3
+ import * as react from 'react';
4
+ import { PropsWithChildren } from 'react';
3
5
 
4
- export { type UseMountedReturn, useMounted };
6
+ type TipsyStudioProviderProps = PropsWithChildren<{
7
+ targetOrigin?: string;
8
+ }>;
9
+ type TipsyStudioContextValue = {
10
+ isReady: boolean;
11
+ targetOrigin: string;
12
+ call: <M extends keyof TipsyBridgeRequestMap>(method: M, payload: TipsyBridgeRequestMap[M], controller?: M extends "chat.completions" ? TipsyChatCompletionController : TipsyRequestController) => Promise<TipsyBridgeResponseMap[M]>;
13
+ };
14
+ declare function TipsyStudioProvider({ children, targetOrigin, }: TipsyStudioProviderProps): react.FunctionComponentElement<react.ProviderProps<TipsyStudioContextValue | null>>;
15
+ declare function useTipsyStudio(): TipsyStudioContextValue;
16
+ declare function useTipsyChat(): {
17
+ completions(input: TipsyChatCompletionInput, controller?: TipsyChatCompletionController): Promise<TipsyChatCompletionResult>;
18
+ };
19
+
20
+ export { TipsyBridgeRequestMap, TipsyBridgeResponseMap, TipsyChatCompletionController, TipsyChatCompletionInput, TipsyChatCompletionResult, TipsyStudioProvider, type TipsyStudioProviderProps, useTipsyChat, useTipsyStudio };
package/dist/react.d.ts CHANGED
@@ -1,4 +1,20 @@
1
- type UseMountedReturn = boolean;
2
- declare function useMounted(): UseMountedReturn;
1
+ import { TipsyBridgeRequestMap, TipsyChatCompletionController, TipsyRequestController, TipsyBridgeResponseMap, TipsyChatCompletionInput, TipsyChatCompletionResult } from './index.js';
2
+ export { CHAT_COMPLETIONS_METHOD, TIPSY_BRIDGE_PROTOCOL, TipsyAbortMessage, TipsyBridgeClientError, TipsyBridgeError, TipsyBridgeMessage, TipsyChatCompletionChunk, TipsyChatCompletionRawChunk, TipsyChatMessage, TipsyStudioClient, TipsyStudioClientOptions, createTipsyStudioClient } from './index.js';
3
+ import * as react from 'react';
4
+ import { PropsWithChildren } from 'react';
3
5
 
4
- export { type UseMountedReturn, useMounted };
6
+ type TipsyStudioProviderProps = PropsWithChildren<{
7
+ targetOrigin?: string;
8
+ }>;
9
+ type TipsyStudioContextValue = {
10
+ isReady: boolean;
11
+ targetOrigin: string;
12
+ call: <M extends keyof TipsyBridgeRequestMap>(method: M, payload: TipsyBridgeRequestMap[M], controller?: M extends "chat.completions" ? TipsyChatCompletionController : TipsyRequestController) => Promise<TipsyBridgeResponseMap[M]>;
13
+ };
14
+ declare function TipsyStudioProvider({ children, targetOrigin, }: TipsyStudioProviderProps): react.FunctionComponentElement<react.ProviderProps<TipsyStudioContextValue | null>>;
15
+ declare function useTipsyStudio(): TipsyStudioContextValue;
16
+ declare function useTipsyChat(): {
17
+ completions(input: TipsyChatCompletionInput, controller?: TipsyChatCompletionController): Promise<TipsyChatCompletionResult>;
18
+ };
19
+
20
+ export { TipsyBridgeRequestMap, TipsyBridgeResponseMap, TipsyChatCompletionController, TipsyChatCompletionInput, TipsyChatCompletionResult, TipsyStudioProvider, type TipsyStudioProviderProps, useTipsyChat, useTipsyStudio };
package/dist/react.js CHANGED
@@ -1,15 +1,75 @@
1
- import { useState, useEffect } from 'react';
1
+ import { normalizeTargetOrigin, createTipsyStudioClient, TipsyBridgeClientError, CHAT_COMPLETIONS_METHOD } from './chunk-2TOC6J52.js';
2
+ export { CHAT_COMPLETIONS_METHOD, TIPSY_BRIDGE_PROTOCOL, TipsyBridgeClientError, createTipsyStudioClient } from './chunk-2TOC6J52.js';
3
+ import { createContext, useMemo, useState, useEffect, createElement, useContext } from 'react';
2
4
 
3
- // src/hooks/useMounted.ts
4
- function useMounted() {
5
- const [mounted, setMounted] = useState(false);
5
+ var TipsyStudioContext = createContext(null);
6
+ function TipsyStudioProvider({
7
+ children,
8
+ targetOrigin
9
+ }) {
10
+ const resolvedTargetOrigin = useMemo(
11
+ () => normalizeTargetOrigin(targetOrigin),
12
+ [targetOrigin]
13
+ );
14
+ const [isReady, setIsReady] = useState(false);
15
+ const [client, setClient] = useState(null);
6
16
  useEffect(() => {
7
- setMounted(true);
8
- console.log("npm \u5305\u6D4B\u8BD5\u901A\u8FC7666");
9
- }, []);
10
- return mounted;
17
+ const nextClient = createTipsyStudioClient({ targetOrigin });
18
+ setClient(nextClient);
19
+ setIsReady(nextClient.isReady());
20
+ const unsubscribe = nextClient.subscribe((nextIsReady) => {
21
+ setIsReady(nextIsReady);
22
+ });
23
+ return () => {
24
+ unsubscribe();
25
+ nextClient.destroy();
26
+ setClient(
27
+ (currentClient) => currentClient === nextClient ? null : currentClient
28
+ );
29
+ setIsReady(false);
30
+ };
31
+ }, [targetOrigin]);
32
+ const contextValue = useMemo(() => {
33
+ return {
34
+ isReady,
35
+ targetOrigin: resolvedTargetOrigin,
36
+ call(method, payload, controller) {
37
+ if (!client) {
38
+ return Promise.reject(
39
+ new TipsyBridgeClientError({
40
+ code: "NETWORK_ERROR",
41
+ message: "Tipsy bridge is not ready."
42
+ })
43
+ );
44
+ }
45
+ return client.call(method, payload, controller);
46
+ }
47
+ };
48
+ }, [client, isReady, resolvedTargetOrigin]);
49
+ return createElement(
50
+ TipsyStudioContext.Provider,
51
+ { value: contextValue },
52
+ children
53
+ );
54
+ }
55
+ function useTipsyStudio() {
56
+ const context = useContext(TipsyStudioContext);
57
+ if (!context) {
58
+ throw new Error("useTipsyStudio must be used within TipsyStudioProvider.");
59
+ }
60
+ return context;
61
+ }
62
+ function useTipsyChat() {
63
+ const studio = useTipsyStudio();
64
+ return useMemo(() => {
65
+ return {
66
+ completions(input, controller) {
67
+ return studio.call(CHAT_COMPLETIONS_METHOD, input, controller);
68
+ }
69
+ };
70
+ }, [studio]);
11
71
  }
12
72
 
13
- export { useMounted };
73
+ export { TipsyStudioProvider, useTipsyChat, useTipsyStudio };
14
74
  //# sourceMappingURL=react.js.map
15
75
  //# 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/react.ts"],"names":[],"mappings":";;;;AAsDA,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,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAmC,IAAI,CAAA;AAEnE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAA,GAAa,uBAAA,CAAwB,EAAE,YAAA,EAAc,CAAA;AAC3D,IAAA,SAAA,CAAU,UAAU,CAAA;AACpB,IAAA,UAAA,CAAW,UAAA,CAAW,SAAS,CAAA;AAE/B,IAAA,MAAM,WAAA,GAAc,UAAA,CAAW,SAAA,CAAU,CAAC,WAAA,KAAgB;AACxD,MAAA,UAAA,CAAW,WAAW,CAAA;AAAA,IACxB,CAAC,CAAA;AAED,IAAA,OAAO,MAAM;AACX,MAAA,WAAA,EAAY;AACZ,MAAA,UAAA,CAAW,OAAA,EAAQ;AACnB,MAAA,SAAA;AAAA,QAAU,CAAC,aAAA,KACT,aAAA,KAAkB,UAAA,GAAa,IAAA,GAAO;AAAA,OACxC;AACA,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,YAAY,CAAC,CAAA;AAEjB,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,CAAC,MAAA,EAAQ;AACX,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,OAAO,MAAA,CAAO,IAAA,CAAK,MAAA,EAAQ,OAAA,EAAS,UAAU,CAAA;AAAA,MAChD;AAAA,KACF;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,OAAA,EAAS,oBAAoB,CAAC,CAAA;AAE1C,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":["import {\n createElement,\n createContext,\n type PropsWithChildren,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport {\n CHAT_COMPLETIONS_METHOD,\n TipsyBridgeClientError,\n type TipsyBridgeRequestMap,\n type TipsyBridgeResponseMap,\n type TipsyRequestController,\n type TipsyChatCompletionController,\n type TipsyChatCompletionInput,\n normalizeTargetOrigin,\n} from \"./bridge\";\nimport { createTipsyStudioClient, type TipsyStudioClient } from \"./client\";\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\";\nexport { createTipsyStudioClient, type TipsyStudioClient, type TipsyStudioClientOptions } from \"./client\";\n\nexport type TipsyStudioProviderProps = PropsWithChildren<{\n targetOrigin?: string;\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 [client, setClient] = useState<TipsyStudioClient | null>(null);\n\n useEffect(() => {\n const nextClient = createTipsyStudioClient({ targetOrigin });\n setClient(nextClient);\n setIsReady(nextClient.isReady());\n\n const unsubscribe = nextClient.subscribe((nextIsReady) => {\n setIsReady(nextIsReady);\n });\n\n return () => {\n unsubscribe();\n nextClient.destroy();\n setClient((currentClient) =>\n currentClient === nextClient ? null : currentClient,\n );\n setIsReady(false);\n };\n }, [targetOrigin]);\n\n const contextValue = useMemo<TipsyStudioContextValue>(() => {\n return {\n isReady,\n targetOrigin: resolvedTargetOrigin,\n call(method, payload, controller) {\n if (!client) {\n return Promise.reject(\n new TipsyBridgeClientError({\n code: \"NETWORK_ERROR\",\n message: \"Tipsy bridge is not ready.\",\n }),\n );\n }\n\n return client.call(method, payload, controller);\n },\n };\n }, [client, 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.3",
4
4
  "description": "React sdk for Tipsy Studio apps.",
5
5
  "license": "MIT",
6
6
  "type": "module",