@tipsy-studio/sdk 0.0.3 → 0.0.4
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 +155 -14
- package/dist/{chunk-2TOC6J52.js → chunk-NLCN4YRK.js} +18 -18
- package/dist/chunk-NLCN4YRK.js.map +1 -0
- package/dist/index.cjs +16 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +86 -39
- package/dist/index.d.ts +86 -39
- package/dist/index.js +1 -1
- package/dist/react.cjs +36 -36
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +7 -7
- package/dist/react.d.ts +7 -7
- package/dist/react.js +18 -22
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-2TOC6J52.js.map +0 -1
package/README.md
CHANGED
|
@@ -12,6 +12,8 @@ npm install @tipsy-studio/sdk react
|
|
|
12
12
|
|
|
13
13
|
Plain JavaScript and TypeScript clients are available from the package root.
|
|
14
14
|
|
|
15
|
+
### Non-stream text
|
|
16
|
+
|
|
15
17
|
```ts
|
|
16
18
|
import { createTipsyStudioClient } from "@tipsy-studio/sdk";
|
|
17
19
|
|
|
@@ -19,58 +21,197 @@ const client = createTipsyStudioClient();
|
|
|
19
21
|
|
|
20
22
|
await client.waitForReady();
|
|
21
23
|
|
|
22
|
-
const
|
|
24
|
+
const response = await client.respond<string>({
|
|
25
|
+
messages: [
|
|
26
|
+
{
|
|
27
|
+
role: "system",
|
|
28
|
+
content: "You are a helpful assistant.",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
role: "user",
|
|
32
|
+
content: "Write a short greeting.",
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
stream: false,
|
|
36
|
+
response_format: { type: "text" },
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log(response.data.result);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Stream text
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { createTipsyStudioClient } from "@tipsy-studio/sdk";
|
|
46
|
+
|
|
47
|
+
const client = createTipsyStudioClient();
|
|
48
|
+
|
|
49
|
+
let text = "";
|
|
50
|
+
|
|
51
|
+
const result = await client.respond<string>(
|
|
23
52
|
{
|
|
24
53
|
messages: [
|
|
25
54
|
{
|
|
26
55
|
role: "system",
|
|
27
56
|
content: "You are a helpful assistant.",
|
|
28
57
|
},
|
|
58
|
+
{
|
|
59
|
+
role: "user",
|
|
60
|
+
content: "Write a short greeting.",
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
stream: true,
|
|
64
|
+
response_format: { type: "text" },
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
onEvent(event) {
|
|
68
|
+
if ("delta" in event) {
|
|
69
|
+
text += event.delta;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
console.log(text);
|
|
76
|
+
console.log(result.result);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Non-stream JSON Schema
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { createTipsyStudioClient } from "@tipsy-studio/sdk";
|
|
83
|
+
|
|
84
|
+
type UserProfile = {
|
|
85
|
+
name: string;
|
|
86
|
+
age: number;
|
|
87
|
+
email: string;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const client = createTipsyStudioClient();
|
|
91
|
+
|
|
92
|
+
const response = await client.respond<UserProfile>({
|
|
93
|
+
messages: [
|
|
94
|
+
{
|
|
95
|
+
role: "system",
|
|
96
|
+
content: "Return only JSON that matches the schema.",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
role: "user",
|
|
100
|
+
content: "Extract a user from: Alice is 28 and alice@example.com",
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
stream: false,
|
|
104
|
+
response_format: {
|
|
105
|
+
type: "json_schema",
|
|
106
|
+
name: "UserProfile",
|
|
107
|
+
schema: {
|
|
108
|
+
type: "object",
|
|
109
|
+
additionalProperties: false,
|
|
110
|
+
properties: {
|
|
111
|
+
name: { type: "string" },
|
|
112
|
+
age: { type: "integer" },
|
|
113
|
+
email: { type: "string" },
|
|
114
|
+
},
|
|
115
|
+
required: ["name", "age", "email"],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
console.log(response.data.result.email);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Stream JSON Schema
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { createTipsyStudioClient } from "@tipsy-studio/sdk";
|
|
127
|
+
|
|
128
|
+
type UserProfile = {
|
|
129
|
+
name: string;
|
|
130
|
+
age: number;
|
|
131
|
+
email: string;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const client = createTipsyStudioClient();
|
|
135
|
+
let snapshot: Partial<UserProfile> = {};
|
|
136
|
+
|
|
137
|
+
const result = await client.respond<UserProfile>(
|
|
138
|
+
{
|
|
139
|
+
messages: [
|
|
140
|
+
{
|
|
141
|
+
role: "system",
|
|
142
|
+
content: "Return only JSON that matches the schema.",
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
role: "user",
|
|
146
|
+
content: "Extract a user from: Alice is 28 and alice@example.com",
|
|
147
|
+
},
|
|
29
148
|
],
|
|
30
149
|
stream: true,
|
|
150
|
+
response_format: {
|
|
151
|
+
type: "json_schema",
|
|
152
|
+
name: "UserProfile",
|
|
153
|
+
schema: {
|
|
154
|
+
type: "object",
|
|
155
|
+
additionalProperties: false,
|
|
156
|
+
properties: {
|
|
157
|
+
name: { type: "string" },
|
|
158
|
+
age: { type: "integer" },
|
|
159
|
+
email: { type: "string" },
|
|
160
|
+
},
|
|
161
|
+
required: ["name", "age", "email"],
|
|
162
|
+
},
|
|
163
|
+
},
|
|
31
164
|
},
|
|
32
165
|
{
|
|
33
|
-
|
|
34
|
-
|
|
166
|
+
onEvent(event) {
|
|
167
|
+
if ("snapshot" in event) {
|
|
168
|
+
snapshot = event.snapshot;
|
|
169
|
+
}
|
|
35
170
|
},
|
|
36
171
|
},
|
|
37
172
|
);
|
|
38
173
|
|
|
39
|
-
console.log(
|
|
174
|
+
console.log(snapshot);
|
|
175
|
+
console.log(result.result);
|
|
40
176
|
```
|
|
41
177
|
|
|
42
178
|
React-specific exports remain available from the `/react` subpath.
|
|
43
179
|
|
|
44
180
|
```tsx
|
|
45
|
-
import { TipsyStudioProvider,
|
|
181
|
+
import { TipsyStudioProvider, useTipsyStudio } from "@tipsy-studio/sdk/react";
|
|
46
182
|
|
|
47
183
|
function ChatButton() {
|
|
48
|
-
const
|
|
184
|
+
const studio = useTipsyStudio();
|
|
49
185
|
|
|
50
186
|
async function handleClick() {
|
|
51
|
-
|
|
187
|
+
let text = "";
|
|
52
188
|
|
|
53
|
-
const result = await
|
|
189
|
+
const result = await studio.respond<string>(
|
|
54
190
|
{
|
|
55
191
|
messages: [
|
|
56
192
|
{
|
|
57
193
|
role: "system",
|
|
58
194
|
content: "You are a helpful assistant.",
|
|
59
195
|
},
|
|
196
|
+
{
|
|
197
|
+
role: "user",
|
|
198
|
+
content: "Write a short greeting.",
|
|
199
|
+
},
|
|
60
200
|
],
|
|
61
201
|
stream: true,
|
|
202
|
+
response_format: { type: "text" },
|
|
62
203
|
},
|
|
63
204
|
{
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
console.log("stream complete", textParts.join(""));
|
|
205
|
+
onEvent(event) {
|
|
206
|
+
if ("delta" in event) {
|
|
207
|
+
text += event.delta;
|
|
208
|
+
}
|
|
69
209
|
},
|
|
70
210
|
},
|
|
71
211
|
);
|
|
72
212
|
|
|
73
|
-
console.log(
|
|
213
|
+
console.log(text);
|
|
214
|
+
console.log(result.result);
|
|
74
215
|
}
|
|
75
216
|
|
|
76
217
|
return <button onClick={handleClick}>Run chat</button>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/bridge.ts
|
|
2
2
|
var TIPSY_BRIDGE_PROTOCOL = "tipsy-bridge-v1";
|
|
3
3
|
var TIPSY_INIT_RETRY_MS = 500;
|
|
4
|
-
var
|
|
4
|
+
var RESPOND_METHOD = "sdk.respond";
|
|
5
5
|
var TipsyBridgeClientError = class extends Error {
|
|
6
6
|
constructor(error) {
|
|
7
7
|
super(error.message);
|
|
@@ -130,21 +130,20 @@ function createTipsyStudioClient(options = {}) {
|
|
|
130
130
|
}
|
|
131
131
|
if (event.data.type === "tipsy:stream") {
|
|
132
132
|
const pending = pendingRequests.get(event.data.requestId);
|
|
133
|
-
if (!pending || pending.method !==
|
|
133
|
+
if (!pending || pending.method !== event.data.payload.method) {
|
|
134
134
|
return;
|
|
135
135
|
}
|
|
136
|
-
pending.
|
|
136
|
+
pending.onEvent?.(event.data.payload.event);
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
139
|
if (event.data.type === "tipsy:response") {
|
|
140
140
|
const pending = pendingRequests.get(event.data.requestId);
|
|
141
|
-
if (!pending) {
|
|
141
|
+
if (!pending || pending.method !== event.data.payload.method) {
|
|
142
142
|
return;
|
|
143
143
|
}
|
|
144
144
|
pendingRequests.delete(event.data.requestId);
|
|
145
145
|
pending.cleanupAbortListener?.();
|
|
146
|
-
pending.
|
|
147
|
-
pending.resolve(event.data.payload);
|
|
146
|
+
pending.resolve(event.data.payload.result);
|
|
148
147
|
}
|
|
149
148
|
};
|
|
150
149
|
const ensureConnected = () => {
|
|
@@ -219,6 +218,12 @@ function createTipsyStudioClient(options = {}) {
|
|
|
219
218
|
message: "Tipsy bridge is not ready."
|
|
220
219
|
});
|
|
221
220
|
};
|
|
221
|
+
function respond(request, controller) {
|
|
222
|
+
return client.call(RESPOND_METHOD, request, {
|
|
223
|
+
signal: controller?.signal,
|
|
224
|
+
onEvent: controller?.onEvent
|
|
225
|
+
});
|
|
226
|
+
}
|
|
222
227
|
const client = {
|
|
223
228
|
isReady: () => isReady,
|
|
224
229
|
subscribe(listener) {
|
|
@@ -232,7 +237,7 @@ function createTipsyStudioClient(options = {}) {
|
|
|
232
237
|
async waitForReady(signal) {
|
|
233
238
|
await waitForReady(signal);
|
|
234
239
|
},
|
|
235
|
-
async call(method,
|
|
240
|
+
async call(method, params, controller) {
|
|
236
241
|
if (isDestroyed) {
|
|
237
242
|
throw new TipsyBridgeClientError({
|
|
238
243
|
code: "NETWORK_ERROR",
|
|
@@ -247,8 +252,7 @@ function createTipsyStudioClient(options = {}) {
|
|
|
247
252
|
method,
|
|
248
253
|
resolve: (value) => resolve(value),
|
|
249
254
|
reject,
|
|
250
|
-
|
|
251
|
-
onComplete: method === CHAT_COMPLETIONS_METHOD ? controller?.onComplete : void 0
|
|
255
|
+
onEvent: controller?.onEvent
|
|
252
256
|
};
|
|
253
257
|
pendingRequests.set(requestId, pending);
|
|
254
258
|
const abortSignal = controller?.signal;
|
|
@@ -278,16 +282,12 @@ function createTipsyStudioClient(options = {}) {
|
|
|
278
282
|
type: "tipsy:request",
|
|
279
283
|
requestId,
|
|
280
284
|
method,
|
|
281
|
-
|
|
285
|
+
params
|
|
282
286
|
});
|
|
283
287
|
}
|
|
284
288
|
);
|
|
285
289
|
},
|
|
286
|
-
|
|
287
|
-
completions(input, controller) {
|
|
288
|
-
return client.call(CHAT_COMPLETIONS_METHOD, input, controller);
|
|
289
|
-
}
|
|
290
|
-
},
|
|
290
|
+
respond,
|
|
291
291
|
destroy() {
|
|
292
292
|
if (isDestroyed) {
|
|
293
293
|
return;
|
|
@@ -313,6 +313,6 @@ function createTipsyStudioClient(options = {}) {
|
|
|
313
313
|
return client;
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
export {
|
|
317
|
-
//# sourceMappingURL=chunk-
|
|
318
|
-
//# sourceMappingURL=chunk-
|
|
316
|
+
export { RESPOND_METHOD, TIPSY_BRIDGE_PROTOCOL, TIPSY_INIT_RETRY_MS, TipsyBridgeClientError, createRequestId, createTipsyStudioClient, getParentOriginFromReferrer, isBridgeMessage, normalizeTargetOrigin };
|
|
317
|
+
//# sourceMappingURL=chunk-NLCN4YRK.js.map
|
|
318
|
+
//# sourceMappingURL=chunk-NLCN4YRK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bridge.ts","../src/client.ts"],"names":[],"mappings":"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","file":"chunk-NLCN4YRK.js","sourcesContent":["export const TIPSY_BRIDGE_PROTOCOL = \"tipsy-bridge-v1\";\nexport const TIPSY_INIT_RETRY_MS = 500;\nexport const RESPOND_METHOD = \"sdk.respond\";\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\nexport type TipsyRole = \"system\" | \"user\" | \"assistant\";\n\nexport type TipsyMessage = {\n role: TipsyRole;\n content: string;\n};\n\nexport type TipsyUsage = {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n};\n\nexport type TipsyTextResponseFormat = {\n type: \"text\";\n};\n\nexport type TipsyJsonSchemaResponseFormat = {\n type: \"json_schema\";\n name: string;\n schema: Record<string, unknown>;\n};\n\nexport type TipsyRespondResponseFormat =\n | TipsyTextResponseFormat\n | TipsyJsonSchemaResponseFormat;\n\ntype TipsyRespondRequestBase = {\n messages: TipsyMessage[];\n model_id?: string | null;\n response_format: TipsyRespondResponseFormat;\n};\n\nexport type TipsyRespondStreamRequest = TipsyRespondRequestBase & {\n stream: true;\n};\n\nexport type TipsyRespondNonStreamRequest = TipsyRespondRequestBase & {\n stream: false;\n};\n\nexport type TipsyRespondRequest =\n | TipsyRespondStreamRequest\n | TipsyRespondNonStreamRequest;\n\nexport type TipsyRespondEnvelope<T = unknown> = {\n code: number;\n msg: string;\n trace_id: string;\n data: {\n message_id: string;\n result: T;\n response_format:\n | TipsyTextResponseFormat\n | {\n type: \"json_schema\";\n name: string;\n };\n usage: TipsyUsage;\n };\n};\n\nexport type TipsyRespondTextStreamEvent = {\n type: \"delta\";\n delta: string;\n};\n\nexport type TipsyRespondJsonStreamEvent<T = unknown> = {\n type: \"delta\";\n snapshot: Partial<T> | T;\n};\n\nexport type TipsyRespondMetaEvent = {\n type: \"meta\";\n message_id: string;\n usage: TipsyUsage;\n trace_id: string;\n};\n\nexport type TipsyRespondStreamEvent<T = unknown> =\n | TipsyRespondTextStreamEvent\n | TipsyRespondJsonStreamEvent<T>\n | TipsyRespondMetaEvent;\n\nexport type TipsyRespondResult<T = unknown> = {\n message_id: string;\n result: T;\n response_format:\n | TipsyTextResponseFormat\n | {\n type: \"json_schema\";\n name: string;\n };\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 [RESPOND_METHOD]: TipsyRespondRequest;\n};\n\nexport type TipsyBridgeStreamMap = {\n [RESPOND_METHOD]: TipsyRespondStreamEvent;\n};\n\nexport type TipsyBridgeResponseMap = {\n [RESPOND_METHOD]: TipsyRespondEnvelope | TipsyRespondResult;\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 params: TipsyBridgeRequestMap[M];\n};\n\ntype TipsyStreamMessage<M extends keyof TipsyBridgeStreamMap> = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:stream\";\n requestId: string;\n payload: {\n method: M;\n event: TipsyBridgeStreamMap[M];\n };\n};\n\ntype TipsyResponseMessage<M extends keyof TipsyBridgeResponseMap> = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:response\";\n requestId: string;\n payload: {\n method: M;\n result: TipsyBridgeResponseMap[M];\n };\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<keyof TipsyBridgeStreamMap>\n | TipsyResponseMessage<keyof TipsyBridgeResponseMap>\n | TipsyErrorMessage\n | TipsyAbortMessage;\n\nexport type TipsyRequestController<M extends keyof TipsyBridgeRequestMap> = {\n signal?: AbortSignal;\n onEvent?: (event: TipsyBridgeStreamMap[M]) => void;\n};\n\nexport type TipsyRespondController<T = unknown> = {\n signal?: AbortSignal;\n onEvent?: (event: TipsyRespondStreamEvent<T>) => 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 RESPOND_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 TipsyBridgeStreamMap,\n type TipsyInitMessage,\n type TipsyRequestController,\n type TipsyRequestMessage,\n type TipsyRespondController,\n type TipsyRespondEnvelope,\n type TipsyRespondNonStreamRequest,\n type TipsyRespondRequest,\n type TipsyRespondResult,\n type TipsyRespondStreamRequest,\n isBridgeMessage,\n normalizeTargetOrigin,\n createRequestId,\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 onEvent?: (event: any) => 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 params: TipsyBridgeRequestMap[M],\n controller?: TipsyRequestController<M>,\n ) => Promise<TipsyBridgeResponseMap[M]>;\n respond<T = string>(\n request: TipsyRespondNonStreamRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondEnvelope<T>>;\n respond<T = string>(\n request: TipsyRespondStreamRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondResult<T>>;\n respond<T = string>(\n request: TipsyRespondRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondEnvelope<T> | TipsyRespondResult<T>>;\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 = (\n message:\n | TipsyInitMessage\n | TipsyAbortMessage\n | TipsyRequestMessage<keyof TipsyBridgeRequestMap>,\n ) => {\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 !== event.data.payload.method) {\n return;\n }\n\n pending.onEvent?.(event.data.payload.event);\n return;\n }\n\n if (event.data.type === \"tipsy:response\") {\n const pending = pendingRequests.get(event.data.requestId);\n if (!pending || pending.method !== event.data.payload.method) {\n return;\n }\n\n pendingRequests.delete(event.data.requestId);\n pending.cleanupAbortListener?.();\n pending.resolve(event.data.payload.result);\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 function respond<T = string>(\n request: TipsyRespondNonStreamRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondEnvelope<T>>;\n function respond<T = string>(\n request: TipsyRespondStreamRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondResult<T>>;\n function respond<T = string>(\n request: TipsyRespondRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondEnvelope<T> | TipsyRespondResult<T>> {\n return client.call(RESPOND_METHOD, request, {\n signal: controller?.signal,\n onEvent: controller?.onEvent as\n | ((event: TipsyBridgeStreamMap[typeof RESPOND_METHOD]) => void)\n | undefined,\n }) as Promise<TipsyRespondEnvelope<T> | TipsyRespondResult<T>>;\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, params, 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 onEvent: controller?.onEvent as\n | ((event: TipsyBridgeStreamMap[typeof method]) => void)\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 params,\n });\n },\n );\n },\n respond,\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"]}
|
package/dist/index.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/bridge.ts
|
|
4
4
|
var TIPSY_BRIDGE_PROTOCOL = "tipsy-bridge-v1";
|
|
5
5
|
var TIPSY_INIT_RETRY_MS = 500;
|
|
6
|
-
var
|
|
6
|
+
var RESPOND_METHOD = "sdk.respond";
|
|
7
7
|
var TipsyBridgeClientError = class extends Error {
|
|
8
8
|
constructor(error) {
|
|
9
9
|
super(error.message);
|
|
@@ -132,21 +132,20 @@ function createTipsyStudioClient(options = {}) {
|
|
|
132
132
|
}
|
|
133
133
|
if (event.data.type === "tipsy:stream") {
|
|
134
134
|
const pending = pendingRequests.get(event.data.requestId);
|
|
135
|
-
if (!pending || pending.method !==
|
|
135
|
+
if (!pending || pending.method !== event.data.payload.method) {
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
138
|
-
pending.
|
|
138
|
+
pending.onEvent?.(event.data.payload.event);
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
141
|
if (event.data.type === "tipsy:response") {
|
|
142
142
|
const pending = pendingRequests.get(event.data.requestId);
|
|
143
|
-
if (!pending) {
|
|
143
|
+
if (!pending || pending.method !== event.data.payload.method) {
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
146
146
|
pendingRequests.delete(event.data.requestId);
|
|
147
147
|
pending.cleanupAbortListener?.();
|
|
148
|
-
pending.
|
|
149
|
-
pending.resolve(event.data.payload);
|
|
148
|
+
pending.resolve(event.data.payload.result);
|
|
150
149
|
}
|
|
151
150
|
};
|
|
152
151
|
const ensureConnected = () => {
|
|
@@ -221,6 +220,12 @@ function createTipsyStudioClient(options = {}) {
|
|
|
221
220
|
message: "Tipsy bridge is not ready."
|
|
222
221
|
});
|
|
223
222
|
};
|
|
223
|
+
function respond(request, controller) {
|
|
224
|
+
return client.call(RESPOND_METHOD, request, {
|
|
225
|
+
signal: controller?.signal,
|
|
226
|
+
onEvent: controller?.onEvent
|
|
227
|
+
});
|
|
228
|
+
}
|
|
224
229
|
const client = {
|
|
225
230
|
isReady: () => isReady,
|
|
226
231
|
subscribe(listener) {
|
|
@@ -234,7 +239,7 @@ function createTipsyStudioClient(options = {}) {
|
|
|
234
239
|
async waitForReady(signal) {
|
|
235
240
|
await waitForReady(signal);
|
|
236
241
|
},
|
|
237
|
-
async call(method,
|
|
242
|
+
async call(method, params, controller) {
|
|
238
243
|
if (isDestroyed) {
|
|
239
244
|
throw new TipsyBridgeClientError({
|
|
240
245
|
code: "NETWORK_ERROR",
|
|
@@ -249,8 +254,7 @@ function createTipsyStudioClient(options = {}) {
|
|
|
249
254
|
method,
|
|
250
255
|
resolve: (value) => resolve(value),
|
|
251
256
|
reject,
|
|
252
|
-
|
|
253
|
-
onComplete: method === CHAT_COMPLETIONS_METHOD ? controller?.onComplete : void 0
|
|
257
|
+
onEvent: controller?.onEvent
|
|
254
258
|
};
|
|
255
259
|
pendingRequests.set(requestId, pending);
|
|
256
260
|
const abortSignal = controller?.signal;
|
|
@@ -280,16 +284,12 @@ function createTipsyStudioClient(options = {}) {
|
|
|
280
284
|
type: "tipsy:request",
|
|
281
285
|
requestId,
|
|
282
286
|
method,
|
|
283
|
-
|
|
287
|
+
params
|
|
284
288
|
});
|
|
285
289
|
}
|
|
286
290
|
);
|
|
287
291
|
},
|
|
288
|
-
|
|
289
|
-
completions(input, controller) {
|
|
290
|
-
return client.call(CHAT_COMPLETIONS_METHOD, input, controller);
|
|
291
|
-
}
|
|
292
|
-
},
|
|
292
|
+
respond,
|
|
293
293
|
destroy() {
|
|
294
294
|
if (isDestroyed) {
|
|
295
295
|
return;
|
|
@@ -315,7 +315,7 @@ function createTipsyStudioClient(options = {}) {
|
|
|
315
315
|
return client;
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
-
exports.
|
|
318
|
+
exports.RESPOND_METHOD = RESPOND_METHOD;
|
|
319
319
|
exports.TIPSY_BRIDGE_PROTOCOL = TIPSY_BRIDGE_PROTOCOL;
|
|
320
320
|
exports.TIPSY_INIT_RETRY_MS = TIPSY_INIT_RETRY_MS;
|
|
321
321
|
exports.TipsyBridgeClientError = TipsyBridgeClientError;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bridge.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.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"]}
|
|
1
|
+
{"version":3,"sources":["../src/bridge.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export const TIPSY_BRIDGE_PROTOCOL = \"tipsy-bridge-v1\";\nexport const TIPSY_INIT_RETRY_MS = 500;\nexport const RESPOND_METHOD = \"sdk.respond\";\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\nexport type TipsyRole = \"system\" | \"user\" | \"assistant\";\n\nexport type TipsyMessage = {\n role: TipsyRole;\n content: string;\n};\n\nexport type TipsyUsage = {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n};\n\nexport type TipsyTextResponseFormat = {\n type: \"text\";\n};\n\nexport type TipsyJsonSchemaResponseFormat = {\n type: \"json_schema\";\n name: string;\n schema: Record<string, unknown>;\n};\n\nexport type TipsyRespondResponseFormat =\n | TipsyTextResponseFormat\n | TipsyJsonSchemaResponseFormat;\n\ntype TipsyRespondRequestBase = {\n messages: TipsyMessage[];\n model_id?: string | null;\n response_format: TipsyRespondResponseFormat;\n};\n\nexport type TipsyRespondStreamRequest = TipsyRespondRequestBase & {\n stream: true;\n};\n\nexport type TipsyRespondNonStreamRequest = TipsyRespondRequestBase & {\n stream: false;\n};\n\nexport type TipsyRespondRequest =\n | TipsyRespondStreamRequest\n | TipsyRespondNonStreamRequest;\n\nexport type TipsyRespondEnvelope<T = unknown> = {\n code: number;\n msg: string;\n trace_id: string;\n data: {\n message_id: string;\n result: T;\n response_format:\n | TipsyTextResponseFormat\n | {\n type: \"json_schema\";\n name: string;\n };\n usage: TipsyUsage;\n };\n};\n\nexport type TipsyRespondTextStreamEvent = {\n type: \"delta\";\n delta: string;\n};\n\nexport type TipsyRespondJsonStreamEvent<T = unknown> = {\n type: \"delta\";\n snapshot: Partial<T> | T;\n};\n\nexport type TipsyRespondMetaEvent = {\n type: \"meta\";\n message_id: string;\n usage: TipsyUsage;\n trace_id: string;\n};\n\nexport type TipsyRespondStreamEvent<T = unknown> =\n | TipsyRespondTextStreamEvent\n | TipsyRespondJsonStreamEvent<T>\n | TipsyRespondMetaEvent;\n\nexport type TipsyRespondResult<T = unknown> = {\n message_id: string;\n result: T;\n response_format:\n | TipsyTextResponseFormat\n | {\n type: \"json_schema\";\n name: string;\n };\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 [RESPOND_METHOD]: TipsyRespondRequest;\n};\n\nexport type TipsyBridgeStreamMap = {\n [RESPOND_METHOD]: TipsyRespondStreamEvent;\n};\n\nexport type TipsyBridgeResponseMap = {\n [RESPOND_METHOD]: TipsyRespondEnvelope | TipsyRespondResult;\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 params: TipsyBridgeRequestMap[M];\n};\n\ntype TipsyStreamMessage<M extends keyof TipsyBridgeStreamMap> = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:stream\";\n requestId: string;\n payload: {\n method: M;\n event: TipsyBridgeStreamMap[M];\n };\n};\n\ntype TipsyResponseMessage<M extends keyof TipsyBridgeResponseMap> = {\n protocol: typeof TIPSY_BRIDGE_PROTOCOL;\n type: \"tipsy:response\";\n requestId: string;\n payload: {\n method: M;\n result: TipsyBridgeResponseMap[M];\n };\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<keyof TipsyBridgeStreamMap>\n | TipsyResponseMessage<keyof TipsyBridgeResponseMap>\n | TipsyErrorMessage\n | TipsyAbortMessage;\n\nexport type TipsyRequestController<M extends keyof TipsyBridgeRequestMap> = {\n signal?: AbortSignal;\n onEvent?: (event: TipsyBridgeStreamMap[M]) => void;\n};\n\nexport type TipsyRespondController<T = unknown> = {\n signal?: AbortSignal;\n onEvent?: (event: TipsyRespondStreamEvent<T>) => 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 RESPOND_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 TipsyBridgeStreamMap,\n type TipsyInitMessage,\n type TipsyRequestController,\n type TipsyRequestMessage,\n type TipsyRespondController,\n type TipsyRespondEnvelope,\n type TipsyRespondNonStreamRequest,\n type TipsyRespondRequest,\n type TipsyRespondResult,\n type TipsyRespondStreamRequest,\n isBridgeMessage,\n normalizeTargetOrigin,\n createRequestId,\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 onEvent?: (event: any) => 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 params: TipsyBridgeRequestMap[M],\n controller?: TipsyRequestController<M>,\n ) => Promise<TipsyBridgeResponseMap[M]>;\n respond<T = string>(\n request: TipsyRespondNonStreamRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondEnvelope<T>>;\n respond<T = string>(\n request: TipsyRespondStreamRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondResult<T>>;\n respond<T = string>(\n request: TipsyRespondRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondEnvelope<T> | TipsyRespondResult<T>>;\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 = (\n message:\n | TipsyInitMessage\n | TipsyAbortMessage\n | TipsyRequestMessage<keyof TipsyBridgeRequestMap>,\n ) => {\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 !== event.data.payload.method) {\n return;\n }\n\n pending.onEvent?.(event.data.payload.event);\n return;\n }\n\n if (event.data.type === \"tipsy:response\") {\n const pending = pendingRequests.get(event.data.requestId);\n if (!pending || pending.method !== event.data.payload.method) {\n return;\n }\n\n pendingRequests.delete(event.data.requestId);\n pending.cleanupAbortListener?.();\n pending.resolve(event.data.payload.result);\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 function respond<T = string>(\n request: TipsyRespondNonStreamRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondEnvelope<T>>;\n function respond<T = string>(\n request: TipsyRespondStreamRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondResult<T>>;\n function respond<T = string>(\n request: TipsyRespondRequest,\n controller?: TipsyRespondController<T>,\n ): Promise<TipsyRespondEnvelope<T> | TipsyRespondResult<T>> {\n return client.call(RESPOND_METHOD, request, {\n signal: controller?.signal,\n onEvent: controller?.onEvent as\n | ((event: TipsyBridgeStreamMap[typeof RESPOND_METHOD]) => void)\n | undefined,\n }) as Promise<TipsyRespondEnvelope<T> | TipsyRespondResult<T>>;\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, params, 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 onEvent: controller?.onEvent as\n | ((event: TipsyBridgeStreamMap[typeof method]) => void)\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 params,\n });\n },\n );\n },\n respond,\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"]}
|