@tipsy-studio/sdk 0.0.2 → 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 +182 -12
- package/dist/chunk-NLCN4YRK.js +318 -0
- package/dist/chunk-NLCN4YRK.js.map +1 -0
- package/dist/index.cjs +324 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +164 -1
- package/dist/index.d.ts +164 -1
- package/dist/index.js +1 -1
- package/dist/react.cjs +293 -150
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +7 -100
- package/dist/react.d.ts +7 -100
- package/dist/react.js +34 -212
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,165 @@
|
|
|
1
|
+
declare const TIPSY_BRIDGE_PROTOCOL = "tipsy-bridge-v1";
|
|
2
|
+
declare const TIPSY_INIT_RETRY_MS = 500;
|
|
3
|
+
declare const RESPOND_METHOD = "sdk.respond";
|
|
4
|
+
type TipsyRole = "system" | "user" | "assistant";
|
|
5
|
+
type TipsyMessage = {
|
|
6
|
+
role: TipsyRole;
|
|
7
|
+
content: string;
|
|
8
|
+
};
|
|
9
|
+
type TipsyUsage = {
|
|
10
|
+
prompt_tokens: number;
|
|
11
|
+
completion_tokens: number;
|
|
12
|
+
total_tokens: number;
|
|
13
|
+
};
|
|
14
|
+
type TipsyTextResponseFormat = {
|
|
15
|
+
type: "text";
|
|
16
|
+
};
|
|
17
|
+
type TipsyJsonSchemaResponseFormat = {
|
|
18
|
+
type: "json_schema";
|
|
19
|
+
name: string;
|
|
20
|
+
schema: Record<string, unknown>;
|
|
21
|
+
};
|
|
22
|
+
type TipsyRespondResponseFormat = TipsyTextResponseFormat | TipsyJsonSchemaResponseFormat;
|
|
23
|
+
type TipsyRespondRequestBase = {
|
|
24
|
+
messages: TipsyMessage[];
|
|
25
|
+
model_id?: string | null;
|
|
26
|
+
response_format: TipsyRespondResponseFormat;
|
|
27
|
+
};
|
|
28
|
+
type TipsyRespondStreamRequest = TipsyRespondRequestBase & {
|
|
29
|
+
stream: true;
|
|
30
|
+
};
|
|
31
|
+
type TipsyRespondNonStreamRequest = TipsyRespondRequestBase & {
|
|
32
|
+
stream: false;
|
|
33
|
+
};
|
|
34
|
+
type TipsyRespondRequest = TipsyRespondStreamRequest | TipsyRespondNonStreamRequest;
|
|
35
|
+
type TipsyRespondEnvelope<T = unknown> = {
|
|
36
|
+
code: number;
|
|
37
|
+
msg: string;
|
|
38
|
+
trace_id: string;
|
|
39
|
+
data: {
|
|
40
|
+
message_id: string;
|
|
41
|
+
result: T;
|
|
42
|
+
response_format: TipsyTextResponseFormat | {
|
|
43
|
+
type: "json_schema";
|
|
44
|
+
name: string;
|
|
45
|
+
};
|
|
46
|
+
usage: TipsyUsage;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
type TipsyRespondTextStreamEvent = {
|
|
50
|
+
type: "delta";
|
|
51
|
+
delta: string;
|
|
52
|
+
};
|
|
53
|
+
type TipsyRespondJsonStreamEvent<T = unknown> = {
|
|
54
|
+
type: "delta";
|
|
55
|
+
snapshot: Partial<T> | T;
|
|
56
|
+
};
|
|
57
|
+
type TipsyRespondMetaEvent = {
|
|
58
|
+
type: "meta";
|
|
59
|
+
message_id: string;
|
|
60
|
+
usage: TipsyUsage;
|
|
61
|
+
trace_id: string;
|
|
62
|
+
};
|
|
63
|
+
type TipsyRespondStreamEvent<T = unknown> = TipsyRespondTextStreamEvent | TipsyRespondJsonStreamEvent<T> | TipsyRespondMetaEvent;
|
|
64
|
+
type TipsyRespondResult<T = unknown> = {
|
|
65
|
+
message_id: string;
|
|
66
|
+
result: T;
|
|
67
|
+
response_format: TipsyTextResponseFormat | {
|
|
68
|
+
type: "json_schema";
|
|
69
|
+
name: string;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
type TipsyBridgeErrorCode = "UNAUTHORIZED" | "BAD_REQUEST" | "NETWORK_ERROR" | "STREAM_PARSE_ERROR" | "ORIGIN_MISMATCH" | "UNSUPPORTED_METHOD" | "INTERNAL_ERROR";
|
|
73
|
+
type TipsyBridgeError = {
|
|
74
|
+
code: TipsyBridgeErrorCode;
|
|
75
|
+
message: string;
|
|
76
|
+
};
|
|
77
|
+
type TipsyBridgeRequestMap = {
|
|
78
|
+
[RESPOND_METHOD]: TipsyRespondRequest;
|
|
79
|
+
};
|
|
80
|
+
type TipsyBridgeStreamMap = {
|
|
81
|
+
[RESPOND_METHOD]: TipsyRespondStreamEvent;
|
|
82
|
+
};
|
|
83
|
+
type TipsyBridgeResponseMap = {
|
|
84
|
+
[RESPOND_METHOD]: TipsyRespondEnvelope | TipsyRespondResult;
|
|
85
|
+
};
|
|
86
|
+
type TipsyInitMessage = {
|
|
87
|
+
protocol: typeof TIPSY_BRIDGE_PROTOCOL;
|
|
88
|
+
type: "tipsy:init";
|
|
89
|
+
};
|
|
90
|
+
type TipsyInitAckMessage = {
|
|
91
|
+
protocol: typeof TIPSY_BRIDGE_PROTOCOL;
|
|
92
|
+
type: "tipsy:init:ack";
|
|
93
|
+
};
|
|
94
|
+
type TipsyRequestMessage<M extends keyof TipsyBridgeRequestMap> = {
|
|
95
|
+
protocol: typeof TIPSY_BRIDGE_PROTOCOL;
|
|
96
|
+
type: "tipsy:request";
|
|
97
|
+
requestId: string;
|
|
98
|
+
method: M;
|
|
99
|
+
params: TipsyBridgeRequestMap[M];
|
|
100
|
+
};
|
|
101
|
+
type TipsyStreamMessage<M extends keyof TipsyBridgeStreamMap> = {
|
|
102
|
+
protocol: typeof TIPSY_BRIDGE_PROTOCOL;
|
|
103
|
+
type: "tipsy:stream";
|
|
104
|
+
requestId: string;
|
|
105
|
+
payload: {
|
|
106
|
+
method: M;
|
|
107
|
+
event: TipsyBridgeStreamMap[M];
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
type TipsyResponseMessage<M extends keyof TipsyBridgeResponseMap> = {
|
|
111
|
+
protocol: typeof TIPSY_BRIDGE_PROTOCOL;
|
|
112
|
+
type: "tipsy:response";
|
|
113
|
+
requestId: string;
|
|
114
|
+
payload: {
|
|
115
|
+
method: M;
|
|
116
|
+
result: TipsyBridgeResponseMap[M];
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
type TipsyErrorMessage = {
|
|
120
|
+
protocol: typeof TIPSY_BRIDGE_PROTOCOL;
|
|
121
|
+
type: "tipsy:error";
|
|
122
|
+
requestId?: string;
|
|
123
|
+
error: TipsyBridgeError;
|
|
124
|
+
};
|
|
125
|
+
type TipsyAbortMessage = {
|
|
126
|
+
protocol: typeof TIPSY_BRIDGE_PROTOCOL;
|
|
127
|
+
type: "tipsy:abort";
|
|
128
|
+
requestId: string;
|
|
129
|
+
};
|
|
130
|
+
type TipsyBridgeMessage = TipsyInitMessage | TipsyInitAckMessage | TipsyRequestMessage<keyof TipsyBridgeRequestMap> | TipsyStreamMessage<keyof TipsyBridgeStreamMap> | TipsyResponseMessage<keyof TipsyBridgeResponseMap> | TipsyErrorMessage | TipsyAbortMessage;
|
|
131
|
+
type TipsyRequestController<M extends keyof TipsyBridgeRequestMap> = {
|
|
132
|
+
signal?: AbortSignal;
|
|
133
|
+
onEvent?: (event: TipsyBridgeStreamMap[M]) => void;
|
|
134
|
+
};
|
|
135
|
+
type TipsyRespondController<T = unknown> = {
|
|
136
|
+
signal?: AbortSignal;
|
|
137
|
+
onEvent?: (event: TipsyRespondStreamEvent<T>) => void;
|
|
138
|
+
};
|
|
139
|
+
declare class TipsyBridgeClientError extends Error {
|
|
140
|
+
code: TipsyBridgeErrorCode;
|
|
141
|
+
constructor(error: TipsyBridgeError);
|
|
142
|
+
}
|
|
143
|
+
declare function getParentOriginFromReferrer(): string | null;
|
|
144
|
+
declare function normalizeTargetOrigin(value?: string): string;
|
|
145
|
+
declare function isBridgeMessage(value: unknown): value is TipsyBridgeMessage;
|
|
146
|
+
declare function createRequestId(): string;
|
|
1
147
|
|
|
2
|
-
|
|
148
|
+
type TipsyStudioClientOptions = {
|
|
149
|
+
targetOrigin?: string;
|
|
150
|
+
sourceWindow?: Window;
|
|
151
|
+
targetWindow?: Window;
|
|
152
|
+
};
|
|
153
|
+
type TipsyStudioClient = {
|
|
154
|
+
isReady: () => boolean;
|
|
155
|
+
subscribe: (listener: (isReady: boolean) => void) => () => void;
|
|
156
|
+
waitForReady: (signal?: AbortSignal) => Promise<void>;
|
|
157
|
+
call: <M extends keyof TipsyBridgeRequestMap>(method: M, params: TipsyBridgeRequestMap[M], controller?: TipsyRequestController<M>) => Promise<TipsyBridgeResponseMap[M]>;
|
|
158
|
+
respond<T = string>(request: TipsyRespondNonStreamRequest, controller?: TipsyRespondController<T>): Promise<TipsyRespondEnvelope<T>>;
|
|
159
|
+
respond<T = string>(request: TipsyRespondStreamRequest, controller?: TipsyRespondController<T>): Promise<TipsyRespondResult<T>>;
|
|
160
|
+
respond<T = string>(request: TipsyRespondRequest, controller?: TipsyRespondController<T>): Promise<TipsyRespondEnvelope<T> | TipsyRespondResult<T>>;
|
|
161
|
+
destroy: () => void;
|
|
162
|
+
};
|
|
163
|
+
declare function createTipsyStudioClient(options?: TipsyStudioClientOptions): TipsyStudioClient;
|
|
164
|
+
|
|
165
|
+
export { RESPOND_METHOD, TIPSY_BRIDGE_PROTOCOL, TIPSY_INIT_RETRY_MS, type TipsyAbortMessage, TipsyBridgeClientError, type TipsyBridgeError, type TipsyBridgeErrorCode, type TipsyBridgeMessage, type TipsyBridgeRequestMap, type TipsyBridgeResponseMap, type TipsyBridgeStreamMap, type TipsyJsonSchemaResponseFormat, type TipsyMessage, type TipsyRequestController, type TipsyRequestMessage, type TipsyRespondController, type TipsyRespondEnvelope, type TipsyRespondMetaEvent, type TipsyRespondNonStreamRequest, type TipsyRespondRequest, type TipsyRespondResponseFormat, type TipsyRespondResult, type TipsyRespondStreamEvent, type TipsyRespondStreamRequest, type TipsyRole, type TipsyStudioClient, type TipsyStudioClientOptions, type TipsyTextResponseFormat, type TipsyUsage, createRequestId, createTipsyStudioClient, getParentOriginFromReferrer, isBridgeMessage, normalizeTargetOrigin };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
export { RESPOND_METHOD, TIPSY_BRIDGE_PROTOCOL, TIPSY_INIT_RETRY_MS, TipsyBridgeClientError, createRequestId, createTipsyStudioClient, getParentOriginFromReferrer, isBridgeMessage, normalizeTargetOrigin } from './chunk-NLCN4YRK.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/react.cjs
CHANGED
|
@@ -7,7 +7,7 @@ var react = require('react');
|
|
|
7
7
|
// src/bridge.ts
|
|
8
8
|
var TIPSY_BRIDGE_PROTOCOL = "tipsy-bridge-v1";
|
|
9
9
|
var TIPSY_INIT_RETRY_MS = 500;
|
|
10
|
-
var
|
|
10
|
+
var RESPOND_METHOD = "sdk.respond";
|
|
11
11
|
var TipsyBridgeClientError = class extends Error {
|
|
12
12
|
constructor(error) {
|
|
13
13
|
super(error.message);
|
|
@@ -57,171 +57,319 @@ function createRequestId() {
|
|
|
57
57
|
return `tipsy_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
// src/
|
|
61
|
-
var
|
|
62
|
-
function
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}, [resolvedTargetOrigin]);
|
|
77
|
-
react.useEffect(() => {
|
|
78
|
-
if (typeof window === "undefined") {
|
|
79
|
-
return void 0;
|
|
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;
|
|
80
76
|
}
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
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) {
|
|
91
126
|
return;
|
|
92
127
|
}
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
type: "tipsy:init"
|
|
96
|
-
};
|
|
97
|
-
window.parent.postMessage(initMessage, targetOriginRef.current);
|
|
98
|
-
};
|
|
99
|
-
const intervalId = window.setInterval(postInit, TIPSY_INIT_RETRY_MS);
|
|
100
|
-
postInit();
|
|
101
|
-
const handleMessage = (event) => {
|
|
102
|
-
if (window.parent === window || event.source !== window.parent) {
|
|
128
|
+
const pending = pendingRequests.get(event.data.requestId);
|
|
129
|
+
if (!pending) {
|
|
103
130
|
return;
|
|
104
131
|
}
|
|
105
|
-
|
|
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 !== event.data.payload.method) {
|
|
106
140
|
return;
|
|
107
141
|
}
|
|
108
|
-
|
|
142
|
+
pending.onEvent?.(event.data.payload.event);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (event.data.type === "tipsy:response") {
|
|
146
|
+
const pending = pendingRequests.get(event.data.requestId);
|
|
147
|
+
if (!pending || pending.method !== event.data.payload.method) {
|
|
109
148
|
return;
|
|
110
149
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
150
|
+
pendingRequests.delete(event.data.requestId);
|
|
151
|
+
pending.cleanupAbortListener?.();
|
|
152
|
+
pending.resolve(event.data.payload.result);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const ensureConnected = () => {
|
|
156
|
+
if (isDestroyed || isConnected || !sourceWindow) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
sourceWindow.addEventListener("message", handleMessage);
|
|
160
|
+
initIntervalId = sourceWindow.setInterval(postInit, TIPSY_INIT_RETRY_MS);
|
|
161
|
+
isConnected = true;
|
|
162
|
+
postInit();
|
|
163
|
+
};
|
|
164
|
+
const ensureBridgeAvailable = () => {
|
|
165
|
+
if (!sourceWindow || !targetWindow) {
|
|
166
|
+
throw new TipsyBridgeClientError({
|
|
167
|
+
code: "NETWORK_ERROR",
|
|
168
|
+
message: "Tipsy bridge is only available inside an iframe."
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const waitForReady = async (signal) => {
|
|
173
|
+
if (isDestroyed) {
|
|
174
|
+
throw new TipsyBridgeClientError({
|
|
175
|
+
code: "NETWORK_ERROR",
|
|
176
|
+
message: "Tipsy bridge was disconnected."
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
ensureBridgeAvailable();
|
|
180
|
+
ensureConnected();
|
|
181
|
+
const activeSourceWindow = sourceWindow;
|
|
182
|
+
if (!activeSourceWindow) {
|
|
183
|
+
throw new TipsyBridgeClientError({
|
|
184
|
+
code: "NETWORK_ERROR",
|
|
185
|
+
message: "Tipsy bridge is only available inside an iframe."
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
if (isReady) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
for (let attempt = 0; attempt < TIPSY_READY_WAIT_RETRY_COUNT; attempt += 1) {
|
|
192
|
+
if (signal?.aborted) {
|
|
193
|
+
throw new DOMException("The operation was aborted.", "AbortError");
|
|
115
194
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
195
|
+
postInit();
|
|
196
|
+
await new Promise((resolve, reject) => {
|
|
197
|
+
let timeoutId = 0;
|
|
198
|
+
const handleReady = () => {
|
|
199
|
+
activeSourceWindow.clearTimeout(timeoutId);
|
|
200
|
+
signal?.removeEventListener("abort", handleAbort);
|
|
201
|
+
readyWaiters.delete(handleReady);
|
|
202
|
+
resolve();
|
|
203
|
+
};
|
|
204
|
+
const handleAbort = () => {
|
|
205
|
+
activeSourceWindow.clearTimeout(timeoutId);
|
|
206
|
+
readyWaiters.delete(handleReady);
|
|
207
|
+
signal?.removeEventListener("abort", handleAbort);
|
|
208
|
+
reject(new DOMException("The operation was aborted.", "AbortError"));
|
|
209
|
+
};
|
|
210
|
+
readyWaiters.add(handleReady);
|
|
211
|
+
timeoutId = activeSourceWindow.setTimeout(() => {
|
|
212
|
+
readyWaiters.delete(handleReady);
|
|
213
|
+
signal?.removeEventListener("abort", handleAbort);
|
|
214
|
+
resolve();
|
|
215
|
+
}, TIPSY_INIT_RETRY_MS);
|
|
216
|
+
signal?.addEventListener("abort", handleAbort, { once: true });
|
|
217
|
+
});
|
|
218
|
+
if (isReady) {
|
|
126
219
|
return;
|
|
127
220
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
221
|
+
}
|
|
222
|
+
throw new TipsyBridgeClientError({
|
|
223
|
+
code: "NETWORK_ERROR",
|
|
224
|
+
message: "Tipsy bridge is not ready."
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
function respond(request, controller) {
|
|
228
|
+
return client.call(RESPOND_METHOD, request, {
|
|
229
|
+
signal: controller?.signal,
|
|
230
|
+
onEvent: controller?.onEvent
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
const client = {
|
|
234
|
+
isReady: () => isReady,
|
|
235
|
+
subscribe(listener) {
|
|
236
|
+
listeners.add(listener);
|
|
237
|
+
listener(isReady);
|
|
238
|
+
ensureConnected();
|
|
239
|
+
return () => {
|
|
240
|
+
listeners.delete(listener);
|
|
241
|
+
};
|
|
242
|
+
},
|
|
243
|
+
async waitForReady(signal) {
|
|
244
|
+
await waitForReady(signal);
|
|
245
|
+
},
|
|
246
|
+
async call(method, params, controller) {
|
|
247
|
+
if (isDestroyed) {
|
|
248
|
+
throw new TipsyBridgeClientError({
|
|
249
|
+
code: "NETWORK_ERROR",
|
|
250
|
+
message: "Tipsy bridge was disconnected."
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
await waitForReady(controller?.signal);
|
|
254
|
+
const requestId = createRequestId();
|
|
255
|
+
return await new Promise(
|
|
256
|
+
(resolve, reject) => {
|
|
257
|
+
const pending = {
|
|
258
|
+
method,
|
|
259
|
+
resolve: (value) => resolve(value),
|
|
260
|
+
reject,
|
|
261
|
+
onEvent: controller?.onEvent
|
|
262
|
+
};
|
|
263
|
+
pendingRequests.set(requestId, pending);
|
|
264
|
+
const abortSignal = controller?.signal;
|
|
265
|
+
const handleAbort = () => {
|
|
266
|
+
if (!pendingRequests.has(requestId)) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
pendingRequests.delete(requestId);
|
|
270
|
+
pending.cleanupAbortListener?.();
|
|
271
|
+
postMessageToTarget({
|
|
272
|
+
protocol: TIPSY_BRIDGE_PROTOCOL,
|
|
273
|
+
type: "tipsy:abort",
|
|
274
|
+
requestId
|
|
275
|
+
});
|
|
276
|
+
reject(new DOMException("The operation was aborted.", "AbortError"));
|
|
277
|
+
};
|
|
278
|
+
pending.cleanupAbortListener = () => {
|
|
279
|
+
abortSignal?.removeEventListener("abort", handleAbort);
|
|
280
|
+
};
|
|
281
|
+
if (abortSignal?.aborted) {
|
|
282
|
+
handleAbort();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
abortSignal?.addEventListener("abort", handleAbort, { once: true });
|
|
286
|
+
postMessageToTarget({
|
|
287
|
+
protocol: TIPSY_BRIDGE_PROTOCOL,
|
|
288
|
+
type: "tipsy:request",
|
|
289
|
+
requestId,
|
|
290
|
+
method,
|
|
291
|
+
params
|
|
292
|
+
});
|
|
132
293
|
}
|
|
133
|
-
|
|
294
|
+
);
|
|
295
|
+
},
|
|
296
|
+
respond,
|
|
297
|
+
destroy() {
|
|
298
|
+
if (isDestroyed) {
|
|
134
299
|
return;
|
|
135
300
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
301
|
+
isDestroyed = true;
|
|
302
|
+
resolveReadyWaiters();
|
|
303
|
+
emitReadyChange(false);
|
|
304
|
+
listeners.clear();
|
|
305
|
+
if (isConnected && sourceWindow) {
|
|
306
|
+
if (initIntervalId !== null) {
|
|
307
|
+
sourceWindow.clearInterval(initIntervalId);
|
|
140
308
|
}
|
|
141
|
-
|
|
142
|
-
pending.onComplete?.(event.data.payload);
|
|
143
|
-
pending.resolve(event.data.payload);
|
|
309
|
+
sourceWindow.removeEventListener("message", handleMessage);
|
|
144
310
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return () => {
|
|
148
|
-
cancelled = true;
|
|
149
|
-
readyRef.current = false;
|
|
150
|
-
setIsReady(false);
|
|
151
|
-
window.clearInterval(intervalId);
|
|
152
|
-
window.removeEventListener("message", handleMessage);
|
|
311
|
+
initIntervalId = null;
|
|
312
|
+
isConnected = false;
|
|
153
313
|
rejectPending({
|
|
154
314
|
code: "NETWORK_ERROR",
|
|
155
315
|
message: "Tipsy bridge was disconnected."
|
|
156
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);
|
|
334
|
+
react.useEffect(() => {
|
|
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);
|
|
157
348
|
};
|
|
158
|
-
}, []);
|
|
349
|
+
}, [targetOrigin]);
|
|
159
350
|
const contextValue = react.useMemo(() => {
|
|
351
|
+
const notReadyError = new TipsyBridgeClientError({
|
|
352
|
+
code: "NETWORK_ERROR",
|
|
353
|
+
message: "Tipsy bridge is not ready."
|
|
354
|
+
});
|
|
355
|
+
const respond = ((request, controller) => {
|
|
356
|
+
if (!client) {
|
|
357
|
+
return Promise.reject(notReadyError);
|
|
358
|
+
}
|
|
359
|
+
return client.respond(request, controller);
|
|
360
|
+
});
|
|
160
361
|
return {
|
|
161
362
|
isReady,
|
|
162
363
|
targetOrigin: resolvedTargetOrigin,
|
|
163
|
-
call(method,
|
|
164
|
-
if (
|
|
165
|
-
return Promise.reject(
|
|
166
|
-
new TipsyBridgeClientError({
|
|
167
|
-
code: "NETWORK_ERROR",
|
|
168
|
-
message: "Tipsy bridge is only available inside an iframe."
|
|
169
|
-
})
|
|
170
|
-
);
|
|
364
|
+
call(method, params, controller) {
|
|
365
|
+
if (!client) {
|
|
366
|
+
return Promise.reject(notReadyError);
|
|
171
367
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
code: "NETWORK_ERROR",
|
|
176
|
-
message: "Tipsy bridge is not ready."
|
|
177
|
-
})
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
const requestId = createRequestId();
|
|
181
|
-
return new Promise(
|
|
182
|
-
(resolve, reject) => {
|
|
183
|
-
const pending = {
|
|
184
|
-
method,
|
|
185
|
-
resolve: (value) => resolve(value),
|
|
186
|
-
reject,
|
|
187
|
-
onData: method === CHAT_COMPLETIONS_METHOD ? controller?.onData : void 0,
|
|
188
|
-
onComplete: method === CHAT_COMPLETIONS_METHOD ? controller?.onComplete : void 0
|
|
189
|
-
};
|
|
190
|
-
pendingRef.current.set(requestId, pending);
|
|
191
|
-
const abortSignal = controller?.signal;
|
|
192
|
-
const handleAbort = () => {
|
|
193
|
-
if (!pendingRef.current.has(requestId)) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
pendingRef.current.delete(requestId);
|
|
197
|
-
const abortMessage = {
|
|
198
|
-
protocol: TIPSY_BRIDGE_PROTOCOL,
|
|
199
|
-
type: "tipsy:abort",
|
|
200
|
-
requestId
|
|
201
|
-
};
|
|
202
|
-
window.parent.postMessage(abortMessage, targetOriginRef.current);
|
|
203
|
-
reject(
|
|
204
|
-
new DOMException("The operation was aborted.", "AbortError")
|
|
205
|
-
);
|
|
206
|
-
};
|
|
207
|
-
if (abortSignal?.aborted) {
|
|
208
|
-
handleAbort();
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
abortSignal?.addEventListener("abort", handleAbort, { once: true });
|
|
212
|
-
const requestMessage = {
|
|
213
|
-
protocol: TIPSY_BRIDGE_PROTOCOL,
|
|
214
|
-
type: "tipsy:request",
|
|
215
|
-
requestId,
|
|
216
|
-
method,
|
|
217
|
-
payload
|
|
218
|
-
};
|
|
219
|
-
window.parent.postMessage(requestMessage, targetOriginRef.current);
|
|
220
|
-
}
|
|
221
|
-
);
|
|
222
|
-
}
|
|
368
|
+
return client.call(method, params, controller);
|
|
369
|
+
},
|
|
370
|
+
respond
|
|
223
371
|
};
|
|
224
|
-
}, [isReady, resolvedTargetOrigin]);
|
|
372
|
+
}, [client, isReady, resolvedTargetOrigin]);
|
|
225
373
|
return react.createElement(
|
|
226
374
|
TipsyStudioContext.Provider,
|
|
227
375
|
{ value: contextValue },
|
|
@@ -235,22 +383,17 @@ function useTipsyStudio() {
|
|
|
235
383
|
}
|
|
236
384
|
return context;
|
|
237
385
|
}
|
|
238
|
-
function useTipsyChat() {
|
|
239
|
-
const studio = useTipsyStudio();
|
|
240
|
-
return react.useMemo(() => {
|
|
241
|
-
return {
|
|
242
|
-
completions(input, controller) {
|
|
243
|
-
return studio.call(CHAT_COMPLETIONS_METHOD, input, controller);
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
}, [studio]);
|
|
247
|
-
}
|
|
248
386
|
|
|
249
|
-
exports.
|
|
387
|
+
exports.RESPOND_METHOD = RESPOND_METHOD;
|
|
250
388
|
exports.TIPSY_BRIDGE_PROTOCOL = TIPSY_BRIDGE_PROTOCOL;
|
|
389
|
+
exports.TIPSY_INIT_RETRY_MS = TIPSY_INIT_RETRY_MS;
|
|
251
390
|
exports.TipsyBridgeClientError = TipsyBridgeClientError;
|
|
252
391
|
exports.TipsyStudioProvider = TipsyStudioProvider;
|
|
253
|
-
exports.
|
|
392
|
+
exports.createRequestId = createRequestId;
|
|
393
|
+
exports.createTipsyStudioClient = createTipsyStudioClient;
|
|
394
|
+
exports.getParentOriginFromReferrer = getParentOriginFromReferrer;
|
|
395
|
+
exports.isBridgeMessage = isBridgeMessage;
|
|
396
|
+
exports.normalizeTargetOrigin = normalizeTargetOrigin;
|
|
254
397
|
exports.useTipsyStudio = useTipsyStudio;
|
|
255
398
|
//# sourceMappingURL=react.cjs.map
|
|
256
399
|
//# sourceMappingURL=react.cjs.map
|