@cms.ai/brand_brain 0.0.1
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 +95 -0
- package/dist/index.cjs +1748 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +395 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +395 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1741 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/index.cjs +1789 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +387 -0
- package/dist/react/index.d.cts.map +1 -0
- package/dist/react/index.d.mts +387 -0
- package/dist/react/index.d.mts.map +1 -0
- package/dist/react/index.mjs +1788 -0
- package/dist/react/index.mjs.map +1 -0
- package/package.json +80 -0
- package/src/GuideClient.ts +239 -0
- package/src/analytics.test.ts +25 -0
- package/src/analytics.ts +36 -0
- package/src/api.ts +26 -0
- package/src/chat-stream.test.ts +55 -0
- package/src/chat-stream.ts +130 -0
- package/src/index.ts +2 -0
- package/src/react/index.ts +2 -0
- package/src/react/useGuide.ts +101 -0
- package/src/types.ts +316 -0
|
@@ -0,0 +1,1789 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let react = require("react");
|
|
3
|
+
//#region ../../node_modules/.pnpm/@orpc+shared@1.14.0_@opentelemetry+api@1.9.0/node_modules/@orpc/shared/dist/index.mjs
|
|
4
|
+
function resolveMaybeOptionalOptions(rest) {
|
|
5
|
+
return rest[0] ?? {};
|
|
6
|
+
}
|
|
7
|
+
function toArray(value) {
|
|
8
|
+
return Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value];
|
|
9
|
+
}
|
|
10
|
+
const ORPC_NAME = "orpc";
|
|
11
|
+
const ORPC_SHARED_PACKAGE_NAME = "@orpc/shared";
|
|
12
|
+
const ORPC_SHARED_PACKAGE_VERSION = "1.14.0";
|
|
13
|
+
var AbortError = class extends Error {
|
|
14
|
+
constructor(...rest) {
|
|
15
|
+
super(...rest);
|
|
16
|
+
this.name = "AbortError";
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
function once(fn) {
|
|
20
|
+
let cached;
|
|
21
|
+
return () => {
|
|
22
|
+
if (cached) return cached.result;
|
|
23
|
+
const result = fn();
|
|
24
|
+
cached = { result };
|
|
25
|
+
return result;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function sequential(fn) {
|
|
29
|
+
let lastOperationPromise = Promise.resolve();
|
|
30
|
+
return (...args) => {
|
|
31
|
+
return lastOperationPromise = lastOperationPromise.catch(() => {}).then(() => {
|
|
32
|
+
return fn(...args);
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const SPAN_ERROR_STATUS = 2;
|
|
37
|
+
const GLOBAL_OTEL_CONFIG_KEY = `__${ORPC_SHARED_PACKAGE_NAME}@${ORPC_SHARED_PACKAGE_VERSION}/otel/config__`;
|
|
38
|
+
function getGlobalOtelConfig() {
|
|
39
|
+
return globalThis[GLOBAL_OTEL_CONFIG_KEY];
|
|
40
|
+
}
|
|
41
|
+
function startSpan(name, options = {}, context) {
|
|
42
|
+
return (getGlobalOtelConfig()?.tracer)?.startSpan(name, options, context);
|
|
43
|
+
}
|
|
44
|
+
function setSpanError(span, error, options = {}) {
|
|
45
|
+
if (!span) return;
|
|
46
|
+
const exception = toOtelException(error);
|
|
47
|
+
span.recordException(exception);
|
|
48
|
+
if (!options.signal?.aborted || options.signal.reason !== error) span.setStatus({
|
|
49
|
+
code: SPAN_ERROR_STATUS,
|
|
50
|
+
message: exception.message
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function toOtelException(error) {
|
|
54
|
+
if (error instanceof Error) {
|
|
55
|
+
const exception = {
|
|
56
|
+
message: error.message,
|
|
57
|
+
name: error.name,
|
|
58
|
+
stack: error.stack
|
|
59
|
+
};
|
|
60
|
+
if ("code" in error && (typeof error.code === "string" || typeof error.code === "number")) exception.code = error.code;
|
|
61
|
+
return exception;
|
|
62
|
+
}
|
|
63
|
+
return { message: String(error) };
|
|
64
|
+
}
|
|
65
|
+
async function runWithSpan({ name, context, ...options }, fn) {
|
|
66
|
+
const tracer = getGlobalOtelConfig()?.tracer;
|
|
67
|
+
if (!tracer) return fn();
|
|
68
|
+
const callback = async (span) => {
|
|
69
|
+
try {
|
|
70
|
+
return await fn(span);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
setSpanError(span, e, options);
|
|
73
|
+
throw e;
|
|
74
|
+
} finally {
|
|
75
|
+
span.end();
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
if (context) return tracer.startActiveSpan(name, options, context, callback);
|
|
79
|
+
else return tracer.startActiveSpan(name, options, callback);
|
|
80
|
+
}
|
|
81
|
+
async function runInSpanContext(span, fn) {
|
|
82
|
+
const otelConfig = getGlobalOtelConfig();
|
|
83
|
+
if (!span || !otelConfig) return fn();
|
|
84
|
+
const ctx = otelConfig.trace.setSpan(otelConfig.context.active(), span);
|
|
85
|
+
return otelConfig.context.with(ctx, fn);
|
|
86
|
+
}
|
|
87
|
+
function isAsyncIteratorObject(maybe) {
|
|
88
|
+
if (!maybe || typeof maybe !== "object") return false;
|
|
89
|
+
return "next" in maybe && typeof maybe.next === "function" && Symbol.asyncIterator in maybe && typeof maybe[Symbol.asyncIterator] === "function";
|
|
90
|
+
}
|
|
91
|
+
const asyncDisposeSymbol = Symbol.asyncDispose ?? Symbol.for("asyncDispose");
|
|
92
|
+
var AsyncIteratorClass = class {
|
|
93
|
+
#isDone = false;
|
|
94
|
+
#isExecuteComplete = false;
|
|
95
|
+
#cleanup;
|
|
96
|
+
#next;
|
|
97
|
+
constructor(next, cleanup) {
|
|
98
|
+
this.#cleanup = cleanup;
|
|
99
|
+
this.#next = sequential(async () => {
|
|
100
|
+
if (this.#isDone) return {
|
|
101
|
+
done: true,
|
|
102
|
+
value: void 0
|
|
103
|
+
};
|
|
104
|
+
try {
|
|
105
|
+
const result = await next();
|
|
106
|
+
if (result.done) this.#isDone = true;
|
|
107
|
+
return result;
|
|
108
|
+
} catch (err) {
|
|
109
|
+
this.#isDone = true;
|
|
110
|
+
throw err;
|
|
111
|
+
} finally {
|
|
112
|
+
if (this.#isDone && !this.#isExecuteComplete) {
|
|
113
|
+
this.#isExecuteComplete = true;
|
|
114
|
+
await this.#cleanup("next");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
next() {
|
|
120
|
+
return this.#next();
|
|
121
|
+
}
|
|
122
|
+
async return(value) {
|
|
123
|
+
this.#isDone = true;
|
|
124
|
+
if (!this.#isExecuteComplete) {
|
|
125
|
+
this.#isExecuteComplete = true;
|
|
126
|
+
await this.#cleanup("return");
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
done: true,
|
|
130
|
+
value
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async throw(err) {
|
|
134
|
+
this.#isDone = true;
|
|
135
|
+
if (!this.#isExecuteComplete) {
|
|
136
|
+
this.#isExecuteComplete = true;
|
|
137
|
+
await this.#cleanup("throw");
|
|
138
|
+
}
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* asyncDispose symbol only available in esnext, we should fallback to Symbol.for('asyncDispose')
|
|
143
|
+
*/
|
|
144
|
+
async [asyncDisposeSymbol]() {
|
|
145
|
+
this.#isDone = true;
|
|
146
|
+
if (!this.#isExecuteComplete) {
|
|
147
|
+
this.#isExecuteComplete = true;
|
|
148
|
+
await this.#cleanup("dispose");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
[Symbol.asyncIterator]() {
|
|
152
|
+
return this;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
function asyncIteratorWithSpan({ name, ...options }, iterator) {
|
|
156
|
+
let span;
|
|
157
|
+
return new AsyncIteratorClass(async () => {
|
|
158
|
+
span ??= startSpan(name);
|
|
159
|
+
try {
|
|
160
|
+
const result = await runInSpanContext(span, () => iterator.next());
|
|
161
|
+
span?.addEvent(result.done ? "completed" : "yielded");
|
|
162
|
+
return result;
|
|
163
|
+
} catch (err) {
|
|
164
|
+
setSpanError(span, err, options);
|
|
165
|
+
throw err;
|
|
166
|
+
}
|
|
167
|
+
}, async (reason) => {
|
|
168
|
+
try {
|
|
169
|
+
if (reason !== "next") await runInSpanContext(span, () => iterator.return?.());
|
|
170
|
+
} catch (err) {
|
|
171
|
+
setSpanError(span, err, options);
|
|
172
|
+
throw err;
|
|
173
|
+
} finally {
|
|
174
|
+
span?.end();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function intercept(interceptors, options, main) {
|
|
179
|
+
const next = (options2, index) => {
|
|
180
|
+
const interceptor = interceptors[index];
|
|
181
|
+
if (!interceptor) return main(options2);
|
|
182
|
+
return interceptor({
|
|
183
|
+
...options2,
|
|
184
|
+
next: (newOptions = options2) => next(newOptions, index + 1)
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
return next(options, 0);
|
|
188
|
+
}
|
|
189
|
+
function parseEmptyableJSON(text) {
|
|
190
|
+
if (!text) return;
|
|
191
|
+
return JSON.parse(text);
|
|
192
|
+
}
|
|
193
|
+
function stringifyJSON(value) {
|
|
194
|
+
return JSON.stringify(value);
|
|
195
|
+
}
|
|
196
|
+
function getConstructor(value) {
|
|
197
|
+
if (!isTypescriptObject(value)) return null;
|
|
198
|
+
return Object.getPrototypeOf(value)?.constructor;
|
|
199
|
+
}
|
|
200
|
+
function isObject(value) {
|
|
201
|
+
if (!value || typeof value !== "object") return false;
|
|
202
|
+
const proto = Object.getPrototypeOf(value);
|
|
203
|
+
return proto === Object.prototype || !proto || !proto.constructor;
|
|
204
|
+
}
|
|
205
|
+
function isTypescriptObject(value) {
|
|
206
|
+
return !!value && (typeof value === "object" || typeof value === "function");
|
|
207
|
+
}
|
|
208
|
+
function value(value2, ...args) {
|
|
209
|
+
if (typeof value2 === "function") return value2(...args);
|
|
210
|
+
return value2;
|
|
211
|
+
}
|
|
212
|
+
function preventNativeAwait(target) {
|
|
213
|
+
return new Proxy(target, { get(target2, prop, receiver) {
|
|
214
|
+
const value2 = Reflect.get(target2, prop, receiver);
|
|
215
|
+
if (prop !== "then" || typeof value2 !== "function") return value2;
|
|
216
|
+
return new Proxy(value2, { apply(targetFn, thisArg, args) {
|
|
217
|
+
if (args.length !== 2 || args.some((arg) => !isNativeFunction(arg))) return Reflect.apply(targetFn, thisArg, args);
|
|
218
|
+
let shouldOmit = true;
|
|
219
|
+
args[0].call(thisArg, preventNativeAwait(new Proxy(target2, { get: (target3, prop2, receiver2) => {
|
|
220
|
+
if (shouldOmit && prop2 === "then") {
|
|
221
|
+
shouldOmit = false;
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
return Reflect.get(target3, prop2, receiver2);
|
|
225
|
+
} })));
|
|
226
|
+
} });
|
|
227
|
+
} });
|
|
228
|
+
}
|
|
229
|
+
const NATIVE_FUNCTION_REGEX = /^\s*function\s*\(\)\s*\{\s*\[native code\]\s*\}\s*$/;
|
|
230
|
+
function isNativeFunction(fn) {
|
|
231
|
+
return typeof fn === "function" && NATIVE_FUNCTION_REGEX.test(fn.toString());
|
|
232
|
+
}
|
|
233
|
+
function tryDecodeURIComponent(value) {
|
|
234
|
+
try {
|
|
235
|
+
return decodeURIComponent(value);
|
|
236
|
+
} catch {
|
|
237
|
+
return value;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region ../../node_modules/.pnpm/@orpc+client@1.14.0_@opentelemetry+api@1.9.0/node_modules/@orpc/client/dist/shared/client.KWZYf6QD.mjs
|
|
242
|
+
const ORPC_CLIENT_PACKAGE_NAME = "@orpc/client";
|
|
243
|
+
const ORPC_CLIENT_PACKAGE_VERSION = "1.14.0";
|
|
244
|
+
const COMMON_ORPC_ERROR_DEFS = {
|
|
245
|
+
BAD_REQUEST: {
|
|
246
|
+
status: 400,
|
|
247
|
+
message: "Bad Request"
|
|
248
|
+
},
|
|
249
|
+
UNAUTHORIZED: {
|
|
250
|
+
status: 401,
|
|
251
|
+
message: "Unauthorized"
|
|
252
|
+
},
|
|
253
|
+
FORBIDDEN: {
|
|
254
|
+
status: 403,
|
|
255
|
+
message: "Forbidden"
|
|
256
|
+
},
|
|
257
|
+
NOT_FOUND: {
|
|
258
|
+
status: 404,
|
|
259
|
+
message: "Not Found"
|
|
260
|
+
},
|
|
261
|
+
METHOD_NOT_SUPPORTED: {
|
|
262
|
+
status: 405,
|
|
263
|
+
message: "Method Not Supported"
|
|
264
|
+
},
|
|
265
|
+
NOT_ACCEPTABLE: {
|
|
266
|
+
status: 406,
|
|
267
|
+
message: "Not Acceptable"
|
|
268
|
+
},
|
|
269
|
+
TIMEOUT: {
|
|
270
|
+
status: 408,
|
|
271
|
+
message: "Request Timeout"
|
|
272
|
+
},
|
|
273
|
+
CONFLICT: {
|
|
274
|
+
status: 409,
|
|
275
|
+
message: "Conflict"
|
|
276
|
+
},
|
|
277
|
+
PRECONDITION_FAILED: {
|
|
278
|
+
status: 412,
|
|
279
|
+
message: "Precondition Failed"
|
|
280
|
+
},
|
|
281
|
+
PAYLOAD_TOO_LARGE: {
|
|
282
|
+
status: 413,
|
|
283
|
+
message: "Payload Too Large"
|
|
284
|
+
},
|
|
285
|
+
UNSUPPORTED_MEDIA_TYPE: {
|
|
286
|
+
status: 415,
|
|
287
|
+
message: "Unsupported Media Type"
|
|
288
|
+
},
|
|
289
|
+
UNPROCESSABLE_CONTENT: {
|
|
290
|
+
status: 422,
|
|
291
|
+
message: "Unprocessable Content"
|
|
292
|
+
},
|
|
293
|
+
TOO_MANY_REQUESTS: {
|
|
294
|
+
status: 429,
|
|
295
|
+
message: "Too Many Requests"
|
|
296
|
+
},
|
|
297
|
+
CLIENT_CLOSED_REQUEST: {
|
|
298
|
+
status: 499,
|
|
299
|
+
message: "Client Closed Request"
|
|
300
|
+
},
|
|
301
|
+
INTERNAL_SERVER_ERROR: {
|
|
302
|
+
status: 500,
|
|
303
|
+
message: "Internal Server Error"
|
|
304
|
+
},
|
|
305
|
+
NOT_IMPLEMENTED: {
|
|
306
|
+
status: 501,
|
|
307
|
+
message: "Not Implemented"
|
|
308
|
+
},
|
|
309
|
+
BAD_GATEWAY: {
|
|
310
|
+
status: 502,
|
|
311
|
+
message: "Bad Gateway"
|
|
312
|
+
},
|
|
313
|
+
SERVICE_UNAVAILABLE: {
|
|
314
|
+
status: 503,
|
|
315
|
+
message: "Service Unavailable"
|
|
316
|
+
},
|
|
317
|
+
GATEWAY_TIMEOUT: {
|
|
318
|
+
status: 504,
|
|
319
|
+
message: "Gateway Timeout"
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
function fallbackORPCErrorStatus(code, status) {
|
|
323
|
+
return status ?? COMMON_ORPC_ERROR_DEFS[code]?.status ?? 500;
|
|
324
|
+
}
|
|
325
|
+
function fallbackORPCErrorMessage(code, message) {
|
|
326
|
+
return message || COMMON_ORPC_ERROR_DEFS[code]?.message || code;
|
|
327
|
+
}
|
|
328
|
+
const GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL = Symbol.for(`__${ORPC_CLIENT_PACKAGE_NAME}@${ORPC_CLIENT_PACKAGE_VERSION}/error/ORPC_ERROR_CONSTRUCTORS__`);
|
|
329
|
+
globalThis[GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL] ??= /* @__PURE__ */ new WeakSet();
|
|
330
|
+
const globalORPCErrorConstructors = globalThis[GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL];
|
|
331
|
+
var ORPCError = class extends Error {
|
|
332
|
+
defined;
|
|
333
|
+
code;
|
|
334
|
+
status;
|
|
335
|
+
data;
|
|
336
|
+
constructor(code, ...rest) {
|
|
337
|
+
const options = resolveMaybeOptionalOptions(rest);
|
|
338
|
+
if (options.status !== void 0 && !isORPCErrorStatus(options.status)) throw new Error("[ORPCError] Invalid error status code.");
|
|
339
|
+
const message = fallbackORPCErrorMessage(code, options.message);
|
|
340
|
+
super(message, options);
|
|
341
|
+
this.code = code;
|
|
342
|
+
this.status = fallbackORPCErrorStatus(code, options.status);
|
|
343
|
+
this.defined = options.defined ?? false;
|
|
344
|
+
this.data = options.data;
|
|
345
|
+
}
|
|
346
|
+
toJSON() {
|
|
347
|
+
return {
|
|
348
|
+
defined: this.defined,
|
|
349
|
+
code: this.code,
|
|
350
|
+
status: this.status,
|
|
351
|
+
message: this.message,
|
|
352
|
+
data: this.data
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Workaround for Next.js where different contexts use separate
|
|
357
|
+
* dependency graphs, causing multiple ORPCError constructors existing and breaking
|
|
358
|
+
* `instanceof` checks across contexts.
|
|
359
|
+
*
|
|
360
|
+
* This is particularly problematic with "Optimized SSR", where orpc-client
|
|
361
|
+
* executes in one context but is invoked from another. When an error is thrown
|
|
362
|
+
* in the execution context, `instanceof ORPCError` checks fail in the
|
|
363
|
+
* invocation context due to separate class constructors.
|
|
364
|
+
*
|
|
365
|
+
* @todo Remove this and related code if Next.js resolves the multiple dependency graph issue.
|
|
366
|
+
*/
|
|
367
|
+
static [Symbol.hasInstance](instance) {
|
|
368
|
+
if (globalORPCErrorConstructors.has(this)) {
|
|
369
|
+
const constructor = getConstructor(instance);
|
|
370
|
+
if (constructor && globalORPCErrorConstructors.has(constructor)) return true;
|
|
371
|
+
}
|
|
372
|
+
return super[Symbol.hasInstance](instance);
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
globalORPCErrorConstructors.add(ORPCError);
|
|
376
|
+
function toORPCError(error) {
|
|
377
|
+
return error instanceof ORPCError ? error : new ORPCError("INTERNAL_SERVER_ERROR", {
|
|
378
|
+
message: "Internal server error",
|
|
379
|
+
cause: error
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
function isORPCErrorStatus(status) {
|
|
383
|
+
return status < 200 || status >= 400;
|
|
384
|
+
}
|
|
385
|
+
function isORPCErrorJson(json) {
|
|
386
|
+
if (!isObject(json)) return false;
|
|
387
|
+
const validKeys = [
|
|
388
|
+
"defined",
|
|
389
|
+
"code",
|
|
390
|
+
"status",
|
|
391
|
+
"message",
|
|
392
|
+
"data"
|
|
393
|
+
];
|
|
394
|
+
if (Object.keys(json).some((k) => !validKeys.includes(k))) return false;
|
|
395
|
+
return "defined" in json && typeof json.defined === "boolean" && "code" in json && typeof json.code === "string" && "status" in json && typeof json.status === "number" && isORPCErrorStatus(json.status) && "message" in json && typeof json.message === "string";
|
|
396
|
+
}
|
|
397
|
+
function createORPCErrorFromJson(json, options = {}) {
|
|
398
|
+
return new ORPCError(json.code, {
|
|
399
|
+
...options,
|
|
400
|
+
...json
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
//#endregion
|
|
404
|
+
//#region ../../node_modules/.pnpm/@orpc+standard-server@1.14.0_@opentelemetry+api@1.9.0/node_modules/@orpc/standard-server/dist/index.mjs
|
|
405
|
+
var EventEncoderError = class extends TypeError {};
|
|
406
|
+
var EventDecoderError = class extends TypeError {};
|
|
407
|
+
var ErrorEvent = class extends Error {
|
|
408
|
+
data;
|
|
409
|
+
constructor(options) {
|
|
410
|
+
super(options?.message ?? "An error event was received", options);
|
|
411
|
+
this.data = options?.data;
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
function decodeEventMessage(encoded) {
|
|
415
|
+
const lines = encoded.replace(/\n+$/, "").split(/\n/);
|
|
416
|
+
const message = {
|
|
417
|
+
data: void 0,
|
|
418
|
+
event: void 0,
|
|
419
|
+
id: void 0,
|
|
420
|
+
retry: void 0,
|
|
421
|
+
comments: []
|
|
422
|
+
};
|
|
423
|
+
for (const line of lines) {
|
|
424
|
+
const index = line.indexOf(":");
|
|
425
|
+
const key = index === -1 ? line : line.slice(0, index);
|
|
426
|
+
const value = index === -1 ? "" : line.slice(index + 1).replace(/^\s/, "");
|
|
427
|
+
if (index === 0) message.comments.push(value);
|
|
428
|
+
else if (key === "data") {
|
|
429
|
+
message.data ??= "";
|
|
430
|
+
message.data += `${value}
|
|
431
|
+
`;
|
|
432
|
+
} else if (key === "event") message.event = value;
|
|
433
|
+
else if (key === "id") message.id = value;
|
|
434
|
+
else if (key === "retry") {
|
|
435
|
+
const maybeInteger = Number.parseInt(value);
|
|
436
|
+
if (Number.isInteger(maybeInteger) && maybeInteger >= 0 && maybeInteger.toString() === value) message.retry = maybeInteger;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
message.data = message.data?.replace(/\n$/, "");
|
|
440
|
+
return message;
|
|
441
|
+
}
|
|
442
|
+
var EventDecoder = class {
|
|
443
|
+
constructor(options = {}) {
|
|
444
|
+
this.options = options;
|
|
445
|
+
}
|
|
446
|
+
incomplete = "";
|
|
447
|
+
feed(chunk) {
|
|
448
|
+
this.incomplete += chunk;
|
|
449
|
+
const lastCompleteIndex = this.incomplete.lastIndexOf("\n\n");
|
|
450
|
+
if (lastCompleteIndex === -1) return;
|
|
451
|
+
const completes = this.incomplete.slice(0, lastCompleteIndex).split(/\n\n/);
|
|
452
|
+
this.incomplete = this.incomplete.slice(lastCompleteIndex + 2);
|
|
453
|
+
for (const encoded of completes) {
|
|
454
|
+
const message = decodeEventMessage(`${encoded}
|
|
455
|
+
|
|
456
|
+
`);
|
|
457
|
+
if (this.options.onEvent) this.options.onEvent(message);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
end() {
|
|
461
|
+
if (this.incomplete) throw new EventDecoderError("Event Iterator ended before complete");
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
var EventDecoderStream = class extends TransformStream {
|
|
465
|
+
constructor() {
|
|
466
|
+
let decoder;
|
|
467
|
+
super({
|
|
468
|
+
start(controller) {
|
|
469
|
+
decoder = new EventDecoder({ onEvent: (event) => {
|
|
470
|
+
controller.enqueue(event);
|
|
471
|
+
} });
|
|
472
|
+
},
|
|
473
|
+
transform(chunk) {
|
|
474
|
+
decoder.feed(chunk);
|
|
475
|
+
},
|
|
476
|
+
flush() {
|
|
477
|
+
decoder.end();
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
function assertEventId(id) {
|
|
483
|
+
if (id.includes("\n")) throw new EventEncoderError("Event's id must not contain a newline character");
|
|
484
|
+
}
|
|
485
|
+
function assertEventName(event) {
|
|
486
|
+
if (event.includes("\n")) throw new EventEncoderError("Event's event must not contain a newline character");
|
|
487
|
+
}
|
|
488
|
+
function assertEventRetry(retry) {
|
|
489
|
+
if (!Number.isInteger(retry) || retry < 0) throw new EventEncoderError("Event's retry must be a integer and >= 0");
|
|
490
|
+
}
|
|
491
|
+
function assertEventComment(comment) {
|
|
492
|
+
if (comment.includes("\n")) throw new EventEncoderError("Event's comment must not contain a newline character");
|
|
493
|
+
}
|
|
494
|
+
function encodeEventData(data) {
|
|
495
|
+
const lines = data?.split(/\n/) ?? [];
|
|
496
|
+
let output = "";
|
|
497
|
+
for (const line of lines) output += `data: ${line}
|
|
498
|
+
`;
|
|
499
|
+
return output;
|
|
500
|
+
}
|
|
501
|
+
function encodeEventComments(comments) {
|
|
502
|
+
let output = "";
|
|
503
|
+
for (const comment of comments ?? []) {
|
|
504
|
+
assertEventComment(comment);
|
|
505
|
+
output += `: ${comment}
|
|
506
|
+
`;
|
|
507
|
+
}
|
|
508
|
+
return output;
|
|
509
|
+
}
|
|
510
|
+
function encodeEventMessage(message) {
|
|
511
|
+
let output = "";
|
|
512
|
+
output += encodeEventComments(message.comments);
|
|
513
|
+
if (message.event !== void 0) {
|
|
514
|
+
assertEventName(message.event);
|
|
515
|
+
output += `event: ${message.event}
|
|
516
|
+
`;
|
|
517
|
+
}
|
|
518
|
+
if (message.retry !== void 0) {
|
|
519
|
+
assertEventRetry(message.retry);
|
|
520
|
+
output += `retry: ${message.retry}
|
|
521
|
+
`;
|
|
522
|
+
}
|
|
523
|
+
if (message.id !== void 0) {
|
|
524
|
+
assertEventId(message.id);
|
|
525
|
+
output += `id: ${message.id}
|
|
526
|
+
`;
|
|
527
|
+
}
|
|
528
|
+
output += encodeEventData(message.data);
|
|
529
|
+
output += "\n";
|
|
530
|
+
return output;
|
|
531
|
+
}
|
|
532
|
+
const EVENT_SOURCE_META_SYMBOL = Symbol("ORPC_EVENT_SOURCE_META");
|
|
533
|
+
function withEventMeta(container, meta) {
|
|
534
|
+
if (meta.id === void 0 && meta.retry === void 0 && !meta.comments?.length) return container;
|
|
535
|
+
if (meta.id !== void 0) assertEventId(meta.id);
|
|
536
|
+
if (meta.retry !== void 0) assertEventRetry(meta.retry);
|
|
537
|
+
if (meta.comments !== void 0) for (const comment of meta.comments) assertEventComment(comment);
|
|
538
|
+
return new Proxy(container, { get(target, prop, receiver) {
|
|
539
|
+
if (prop === EVENT_SOURCE_META_SYMBOL) return meta;
|
|
540
|
+
return Reflect.get(target, prop, receiver);
|
|
541
|
+
} });
|
|
542
|
+
}
|
|
543
|
+
function getEventMeta(container) {
|
|
544
|
+
return isTypescriptObject(container) ? Reflect.get(container, EVENT_SOURCE_META_SYMBOL) : void 0;
|
|
545
|
+
}
|
|
546
|
+
function generateContentDisposition(filename, disposition = "inline") {
|
|
547
|
+
return `${disposition}; filename="${filename.replace(/[^\x20-\x7E]/g, "_").replace(/"/g, "\\\"")}"; filename*=utf-8''${encodeURIComponent(filename).replace(/['()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`).replace(/%(7C|60|5E)/g, (str, hex) => String.fromCharCode(Number.parseInt(hex, 16)))}`;
|
|
548
|
+
}
|
|
549
|
+
function getFilenameFromContentDisposition(contentDisposition) {
|
|
550
|
+
const encodedFilenameStarMatch = contentDisposition.match(/filename\*=(UTF-8'')?([^;]*)/i);
|
|
551
|
+
if (encodedFilenameStarMatch && typeof encodedFilenameStarMatch[2] === "string") return tryDecodeURIComponent(encodedFilenameStarMatch[2]);
|
|
552
|
+
const encodedFilenameMatch = contentDisposition.match(/filename="((?:\\"|[^"])*)"/i);
|
|
553
|
+
if (encodedFilenameMatch && typeof encodedFilenameMatch[1] === "string") return encodedFilenameMatch[1].replace(/\\"/g, "\"");
|
|
554
|
+
}
|
|
555
|
+
function mergeStandardHeaders(a, b) {
|
|
556
|
+
const merged = { ...a };
|
|
557
|
+
for (const key in b) if (Array.isArray(b[key])) merged[key] = [...toArray(merged[key]), ...b[key]];
|
|
558
|
+
else if (b[key] !== void 0) if (Array.isArray(merged[key])) merged[key] = [...merged[key], b[key]];
|
|
559
|
+
else if (merged[key] !== void 0) merged[key] = [merged[key], b[key]];
|
|
560
|
+
else merged[key] = b[key];
|
|
561
|
+
return merged;
|
|
562
|
+
}
|
|
563
|
+
//#endregion
|
|
564
|
+
//#region ../../node_modules/.pnpm/@orpc+client@1.14.0_@opentelemetry+api@1.9.0/node_modules/@orpc/client/dist/shared/client.BLtwTQUg.mjs
|
|
565
|
+
function mapEventIterator(iterator, maps) {
|
|
566
|
+
const mapError = async (error) => {
|
|
567
|
+
let mappedError = await maps.error(error);
|
|
568
|
+
if (mappedError !== error) {
|
|
569
|
+
const meta = getEventMeta(error);
|
|
570
|
+
if (meta && isTypescriptObject(mappedError)) mappedError = withEventMeta(mappedError, meta);
|
|
571
|
+
}
|
|
572
|
+
return mappedError;
|
|
573
|
+
};
|
|
574
|
+
return new AsyncIteratorClass(async () => {
|
|
575
|
+
const { done, value } = await (async () => {
|
|
576
|
+
try {
|
|
577
|
+
return await iterator.next();
|
|
578
|
+
} catch (error) {
|
|
579
|
+
throw await mapError(error);
|
|
580
|
+
}
|
|
581
|
+
})();
|
|
582
|
+
let mappedValue = await maps.value(value, done);
|
|
583
|
+
if (mappedValue !== value) {
|
|
584
|
+
const meta = getEventMeta(value);
|
|
585
|
+
if (meta && isTypescriptObject(mappedValue)) mappedValue = withEventMeta(mappedValue, meta);
|
|
586
|
+
}
|
|
587
|
+
return {
|
|
588
|
+
done,
|
|
589
|
+
value: mappedValue
|
|
590
|
+
};
|
|
591
|
+
}, async () => {
|
|
592
|
+
try {
|
|
593
|
+
await iterator.return?.();
|
|
594
|
+
} catch (error) {
|
|
595
|
+
throw await mapError(error);
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
//#endregion
|
|
600
|
+
//#region ../../node_modules/.pnpm/@orpc+client@1.14.0_@opentelemetry+api@1.9.0/node_modules/@orpc/client/dist/index.mjs
|
|
601
|
+
function resolveFriendlyClientOptions(options) {
|
|
602
|
+
return {
|
|
603
|
+
...options,
|
|
604
|
+
context: options.context ?? {}
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
function createORPCClient(link, options = {}) {
|
|
608
|
+
const path = options.path ?? [];
|
|
609
|
+
const procedureClient = async (...[input, options2 = {}]) => {
|
|
610
|
+
return await link.call(path, input, resolveFriendlyClientOptions(options2));
|
|
611
|
+
};
|
|
612
|
+
return preventNativeAwait(new Proxy(procedureClient, { get(target, key) {
|
|
613
|
+
if (typeof key !== "string") return Reflect.get(target, key);
|
|
614
|
+
return createORPCClient(link, {
|
|
615
|
+
...options,
|
|
616
|
+
path: [...path, key]
|
|
617
|
+
});
|
|
618
|
+
} }));
|
|
619
|
+
}
|
|
620
|
+
//#endregion
|
|
621
|
+
//#region ../../node_modules/.pnpm/@orpc+standard-server-fetch@1.14.0_@opentelemetry+api@1.9.0/node_modules/@orpc/standard-server-fetch/dist/index.mjs
|
|
622
|
+
function toEventIterator(stream, options = {}) {
|
|
623
|
+
const reader = (stream?.pipeThrough(new TextDecoderStream()).pipeThrough(new EventDecoderStream()))?.getReader();
|
|
624
|
+
let span;
|
|
625
|
+
let isCancelled = false;
|
|
626
|
+
return new AsyncIteratorClass(async () => {
|
|
627
|
+
span ??= startSpan("consume_event_iterator_stream");
|
|
628
|
+
try {
|
|
629
|
+
while (true) {
|
|
630
|
+
if (reader === void 0) return {
|
|
631
|
+
done: true,
|
|
632
|
+
value: void 0
|
|
633
|
+
};
|
|
634
|
+
const { done, value } = await runInSpanContext(span, () => reader.read());
|
|
635
|
+
if (done) {
|
|
636
|
+
if (isCancelled) throw new AbortError("Stream was cancelled");
|
|
637
|
+
return {
|
|
638
|
+
done: true,
|
|
639
|
+
value: void 0
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
switch (value.event) {
|
|
643
|
+
case "message": {
|
|
644
|
+
let message = parseEmptyableJSON(value.data);
|
|
645
|
+
if (isTypescriptObject(message)) message = withEventMeta(message, value);
|
|
646
|
+
span?.addEvent("message");
|
|
647
|
+
return {
|
|
648
|
+
done: false,
|
|
649
|
+
value: message
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
case "error": {
|
|
653
|
+
let error = new ErrorEvent({ data: parseEmptyableJSON(value.data) });
|
|
654
|
+
error = withEventMeta(error, value);
|
|
655
|
+
span?.addEvent("error");
|
|
656
|
+
throw error;
|
|
657
|
+
}
|
|
658
|
+
case "done": {
|
|
659
|
+
let done2 = parseEmptyableJSON(value.data);
|
|
660
|
+
if (isTypescriptObject(done2)) done2 = withEventMeta(done2, value);
|
|
661
|
+
span?.addEvent("done");
|
|
662
|
+
return {
|
|
663
|
+
done: true,
|
|
664
|
+
value: done2
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
default: span?.addEvent("maybe_keepalive");
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
} catch (e) {
|
|
671
|
+
if (!(e instanceof ErrorEvent)) setSpanError(span, e, options);
|
|
672
|
+
throw e;
|
|
673
|
+
}
|
|
674
|
+
}, async (reason) => {
|
|
675
|
+
try {
|
|
676
|
+
if (reason !== "next") {
|
|
677
|
+
isCancelled = true;
|
|
678
|
+
span?.addEvent("cancelled");
|
|
679
|
+
}
|
|
680
|
+
await runInSpanContext(span, () => reader?.cancel());
|
|
681
|
+
} catch (e) {
|
|
682
|
+
setSpanError(span, e, options);
|
|
683
|
+
throw e;
|
|
684
|
+
} finally {
|
|
685
|
+
span?.end();
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
function toEventStream(iterator, options = {}) {
|
|
690
|
+
const keepAliveEnabled = options.eventIteratorKeepAliveEnabled ?? true;
|
|
691
|
+
const keepAliveInterval = options.eventIteratorKeepAliveInterval ?? 5e3;
|
|
692
|
+
const keepAliveComment = options.eventIteratorKeepAliveComment ?? "";
|
|
693
|
+
const initialCommentEnabled = options.eventIteratorInitialCommentEnabled ?? true;
|
|
694
|
+
const initialComment = options.eventIteratorInitialComment ?? "";
|
|
695
|
+
let cancelled = false;
|
|
696
|
+
let timeout;
|
|
697
|
+
let span;
|
|
698
|
+
return new ReadableStream({
|
|
699
|
+
start(controller) {
|
|
700
|
+
span = startSpan("stream_event_iterator");
|
|
701
|
+
if (initialCommentEnabled) controller.enqueue(encodeEventMessage({ comments: [initialComment] }));
|
|
702
|
+
},
|
|
703
|
+
async pull(controller) {
|
|
704
|
+
try {
|
|
705
|
+
if (keepAliveEnabled) timeout = setInterval(() => {
|
|
706
|
+
controller.enqueue(encodeEventMessage({ comments: [keepAliveComment] }));
|
|
707
|
+
span?.addEvent("keepalive");
|
|
708
|
+
}, keepAliveInterval);
|
|
709
|
+
const value = await runInSpanContext(span, () => iterator.next());
|
|
710
|
+
clearInterval(timeout);
|
|
711
|
+
if (cancelled) return;
|
|
712
|
+
const meta = getEventMeta(value.value);
|
|
713
|
+
if (!value.done || value.value !== void 0 || meta !== void 0) {
|
|
714
|
+
const event = value.done ? "done" : "message";
|
|
715
|
+
controller.enqueue(encodeEventMessage({
|
|
716
|
+
...meta,
|
|
717
|
+
event,
|
|
718
|
+
data: stringifyJSON(value.value)
|
|
719
|
+
}));
|
|
720
|
+
span?.addEvent(event);
|
|
721
|
+
}
|
|
722
|
+
if (value.done) {
|
|
723
|
+
controller.close();
|
|
724
|
+
span?.end();
|
|
725
|
+
}
|
|
726
|
+
} catch (err) {
|
|
727
|
+
clearInterval(timeout);
|
|
728
|
+
if (cancelled) return;
|
|
729
|
+
if (err instanceof ErrorEvent) {
|
|
730
|
+
controller.enqueue(encodeEventMessage({
|
|
731
|
+
...getEventMeta(err),
|
|
732
|
+
event: "error",
|
|
733
|
+
data: stringifyJSON(err.data)
|
|
734
|
+
}));
|
|
735
|
+
span?.addEvent("error");
|
|
736
|
+
controller.close();
|
|
737
|
+
} else {
|
|
738
|
+
setSpanError(span, err);
|
|
739
|
+
controller.error(err);
|
|
740
|
+
}
|
|
741
|
+
span?.end();
|
|
742
|
+
}
|
|
743
|
+
},
|
|
744
|
+
async cancel() {
|
|
745
|
+
try {
|
|
746
|
+
cancelled = true;
|
|
747
|
+
clearInterval(timeout);
|
|
748
|
+
span?.addEvent("cancelled");
|
|
749
|
+
await runInSpanContext(span, () => iterator.return?.());
|
|
750
|
+
} catch (e) {
|
|
751
|
+
setSpanError(span, e);
|
|
752
|
+
throw e;
|
|
753
|
+
} finally {
|
|
754
|
+
span?.end();
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}).pipeThrough(new TextEncoderStream());
|
|
758
|
+
}
|
|
759
|
+
function toStandardBody(re, options = {}) {
|
|
760
|
+
return runWithSpan({
|
|
761
|
+
name: "parse_standard_body",
|
|
762
|
+
signal: options.signal
|
|
763
|
+
}, async () => {
|
|
764
|
+
const contentDisposition = re.headers.get("content-disposition");
|
|
765
|
+
if (typeof contentDisposition === "string") {
|
|
766
|
+
const fileName = getFilenameFromContentDisposition(contentDisposition) ?? "blob";
|
|
767
|
+
const blob2 = await re.blob();
|
|
768
|
+
return new File([blob2], fileName, { type: blob2.type });
|
|
769
|
+
}
|
|
770
|
+
const contentType = re.headers.get("content-type");
|
|
771
|
+
if (!contentType || contentType.startsWith("application/json")) return parseEmptyableJSON(await re.text());
|
|
772
|
+
if (contentType.startsWith("multipart/form-data")) return await re.formData();
|
|
773
|
+
if (contentType.startsWith("application/x-www-form-urlencoded")) {
|
|
774
|
+
const text = await re.text();
|
|
775
|
+
return new URLSearchParams(text);
|
|
776
|
+
}
|
|
777
|
+
if (contentType.startsWith("text/event-stream")) return toEventIterator(re.body, options);
|
|
778
|
+
if (contentType.startsWith("text/plain")) return await re.text();
|
|
779
|
+
const blob = await re.blob();
|
|
780
|
+
return new File([blob], "blob", { type: blob.type });
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
function toFetchBody(body, headers, options = {}) {
|
|
784
|
+
if (body instanceof ReadableStream) return body;
|
|
785
|
+
const currentContentDisposition = headers.get("content-disposition");
|
|
786
|
+
headers.delete("content-type");
|
|
787
|
+
headers.delete("content-disposition");
|
|
788
|
+
if (body === void 0) return;
|
|
789
|
+
if (body instanceof Blob) {
|
|
790
|
+
headers.set("content-type", body.type);
|
|
791
|
+
headers.set("content-length", body.size.toString());
|
|
792
|
+
headers.set("content-disposition", currentContentDisposition ?? generateContentDisposition(body instanceof File ? body.name : "blob"));
|
|
793
|
+
return body;
|
|
794
|
+
}
|
|
795
|
+
if (body instanceof FormData) return body;
|
|
796
|
+
if (body instanceof URLSearchParams) return body;
|
|
797
|
+
if (isAsyncIteratorObject(body)) {
|
|
798
|
+
headers.set("content-type", "text/event-stream");
|
|
799
|
+
return toEventStream(body, options);
|
|
800
|
+
}
|
|
801
|
+
headers.set("content-type", "application/json");
|
|
802
|
+
return stringifyJSON(body);
|
|
803
|
+
}
|
|
804
|
+
function toStandardHeaders$1(headers, standardHeaders = {}) {
|
|
805
|
+
headers.forEach((value, key) => {
|
|
806
|
+
if (Array.isArray(standardHeaders[key])) standardHeaders[key].push(value);
|
|
807
|
+
else if (standardHeaders[key] !== void 0) standardHeaders[key] = [standardHeaders[key], value];
|
|
808
|
+
else standardHeaders[key] = value;
|
|
809
|
+
});
|
|
810
|
+
return standardHeaders;
|
|
811
|
+
}
|
|
812
|
+
function toFetchHeaders(headers, fetchHeaders = new Headers()) {
|
|
813
|
+
for (const [key, value] of Object.entries(headers)) if (Array.isArray(value)) for (const v of value) fetchHeaders.append(key, v);
|
|
814
|
+
else if (value !== void 0) fetchHeaders.append(key, value);
|
|
815
|
+
return fetchHeaders;
|
|
816
|
+
}
|
|
817
|
+
function toFetchRequest(request, options = {}) {
|
|
818
|
+
const headers = toFetchHeaders(request.headers);
|
|
819
|
+
const body = toFetchBody(request.body, headers, options);
|
|
820
|
+
return new Request(request.url, {
|
|
821
|
+
signal: request.signal,
|
|
822
|
+
method: request.method,
|
|
823
|
+
headers,
|
|
824
|
+
body
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
function toStandardLazyResponse(response, options = {}) {
|
|
828
|
+
return {
|
|
829
|
+
body: once(() => toStandardBody(response, options)),
|
|
830
|
+
status: response.status,
|
|
831
|
+
get headers() {
|
|
832
|
+
const headers = toStandardHeaders$1(response.headers);
|
|
833
|
+
Object.defineProperty(this, "headers", {
|
|
834
|
+
value: headers,
|
|
835
|
+
writable: true
|
|
836
|
+
});
|
|
837
|
+
return headers;
|
|
838
|
+
},
|
|
839
|
+
set headers(value) {
|
|
840
|
+
Object.defineProperty(this, "headers", {
|
|
841
|
+
value,
|
|
842
|
+
writable: true
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
//#endregion
|
|
848
|
+
//#region ../../node_modules/.pnpm/@orpc+client@1.14.0_@opentelemetry+api@1.9.0/node_modules/@orpc/client/dist/shared/client.DrB9nq_G.mjs
|
|
849
|
+
var CompositeStandardLinkPlugin = class {
|
|
850
|
+
plugins;
|
|
851
|
+
constructor(plugins = []) {
|
|
852
|
+
this.plugins = [...plugins].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
853
|
+
}
|
|
854
|
+
init(options) {
|
|
855
|
+
for (const plugin of this.plugins) plugin.init?.(options);
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
var StandardLink = class {
|
|
859
|
+
constructor(codec, sender, options = {}) {
|
|
860
|
+
this.codec = codec;
|
|
861
|
+
this.sender = sender;
|
|
862
|
+
new CompositeStandardLinkPlugin(options.plugins).init(options);
|
|
863
|
+
this.interceptors = toArray(options.interceptors);
|
|
864
|
+
this.clientInterceptors = toArray(options.clientInterceptors);
|
|
865
|
+
}
|
|
866
|
+
interceptors;
|
|
867
|
+
clientInterceptors;
|
|
868
|
+
call(path, input, options) {
|
|
869
|
+
return runWithSpan({
|
|
870
|
+
name: `${ORPC_NAME}.${path.join("/")}`,
|
|
871
|
+
signal: options.signal
|
|
872
|
+
}, (span) => {
|
|
873
|
+
span?.setAttribute("rpc.system", ORPC_NAME);
|
|
874
|
+
span?.setAttribute("rpc.method", path.join("."));
|
|
875
|
+
if (isAsyncIteratorObject(input)) input = asyncIteratorWithSpan({
|
|
876
|
+
name: "consume_event_iterator_input",
|
|
877
|
+
signal: options.signal
|
|
878
|
+
}, input);
|
|
879
|
+
return intercept(this.interceptors, {
|
|
880
|
+
...options,
|
|
881
|
+
path,
|
|
882
|
+
input
|
|
883
|
+
}, async ({ path: path2, input: input2, ...options2 }) => {
|
|
884
|
+
const otelConfig = getGlobalOtelConfig();
|
|
885
|
+
let otelContext;
|
|
886
|
+
const currentSpan = otelConfig?.trace.getActiveSpan() ?? span;
|
|
887
|
+
if (currentSpan && otelConfig) otelContext = otelConfig?.trace.setSpan(otelConfig.context.active(), currentSpan);
|
|
888
|
+
const request = await runWithSpan({
|
|
889
|
+
name: "encode_request",
|
|
890
|
+
context: otelContext
|
|
891
|
+
}, () => this.codec.encode(path2, input2, options2));
|
|
892
|
+
const response = await intercept(this.clientInterceptors, {
|
|
893
|
+
...options2,
|
|
894
|
+
input: input2,
|
|
895
|
+
path: path2,
|
|
896
|
+
request
|
|
897
|
+
}, ({ input: input3, path: path3, request: request2, ...options3 }) => {
|
|
898
|
+
return runWithSpan({
|
|
899
|
+
name: "send_request",
|
|
900
|
+
signal: options3.signal,
|
|
901
|
+
context: otelContext
|
|
902
|
+
}, () => this.sender.call(request2, options3, path3, input3));
|
|
903
|
+
});
|
|
904
|
+
const output = await runWithSpan({
|
|
905
|
+
name: "decode_response",
|
|
906
|
+
context: otelContext
|
|
907
|
+
}, () => this.codec.decode(response, options2, path2, input2));
|
|
908
|
+
if (isAsyncIteratorObject(output)) return asyncIteratorWithSpan({
|
|
909
|
+
name: "consume_event_iterator_output",
|
|
910
|
+
signal: options2.signal
|
|
911
|
+
}, output);
|
|
912
|
+
return output;
|
|
913
|
+
});
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
};
|
|
917
|
+
const STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES = {
|
|
918
|
+
BIGINT: 0,
|
|
919
|
+
DATE: 1,
|
|
920
|
+
NAN: 2,
|
|
921
|
+
UNDEFINED: 3,
|
|
922
|
+
URL: 4,
|
|
923
|
+
REGEXP: 5,
|
|
924
|
+
SET: 6,
|
|
925
|
+
MAP: 7
|
|
926
|
+
};
|
|
927
|
+
var StandardRPCJsonSerializer = class {
|
|
928
|
+
customSerializers;
|
|
929
|
+
constructor(options = {}) {
|
|
930
|
+
this.customSerializers = options.customJsonSerializers ?? [];
|
|
931
|
+
if (this.customSerializers.length !== new Set(this.customSerializers.map((custom) => custom.type)).size) throw new Error("Custom serializer type must be unique.");
|
|
932
|
+
}
|
|
933
|
+
serialize(data, segments = [], meta = [], maps = [], blobs = []) {
|
|
934
|
+
for (const custom of this.customSerializers) if (custom.condition(data)) {
|
|
935
|
+
const result = this.serialize(custom.serialize(data), segments, meta, maps, blobs);
|
|
936
|
+
meta.push([custom.type, ...segments]);
|
|
937
|
+
return result;
|
|
938
|
+
}
|
|
939
|
+
if (data instanceof Blob) {
|
|
940
|
+
maps.push(segments);
|
|
941
|
+
blobs.push(data);
|
|
942
|
+
return [
|
|
943
|
+
data,
|
|
944
|
+
meta,
|
|
945
|
+
maps,
|
|
946
|
+
blobs
|
|
947
|
+
];
|
|
948
|
+
}
|
|
949
|
+
if (typeof data === "bigint") {
|
|
950
|
+
meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.BIGINT, ...segments]);
|
|
951
|
+
return [
|
|
952
|
+
data.toString(),
|
|
953
|
+
meta,
|
|
954
|
+
maps,
|
|
955
|
+
blobs
|
|
956
|
+
];
|
|
957
|
+
}
|
|
958
|
+
if (data instanceof Date) {
|
|
959
|
+
meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.DATE, ...segments]);
|
|
960
|
+
if (Number.isNaN(data.getTime())) return [
|
|
961
|
+
null,
|
|
962
|
+
meta,
|
|
963
|
+
maps,
|
|
964
|
+
blobs
|
|
965
|
+
];
|
|
966
|
+
return [
|
|
967
|
+
data.toISOString(),
|
|
968
|
+
meta,
|
|
969
|
+
maps,
|
|
970
|
+
blobs
|
|
971
|
+
];
|
|
972
|
+
}
|
|
973
|
+
if (Number.isNaN(data)) {
|
|
974
|
+
meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.NAN, ...segments]);
|
|
975
|
+
return [
|
|
976
|
+
null,
|
|
977
|
+
meta,
|
|
978
|
+
maps,
|
|
979
|
+
blobs
|
|
980
|
+
];
|
|
981
|
+
}
|
|
982
|
+
if (data instanceof URL) {
|
|
983
|
+
meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.URL, ...segments]);
|
|
984
|
+
return [
|
|
985
|
+
data.toString(),
|
|
986
|
+
meta,
|
|
987
|
+
maps,
|
|
988
|
+
blobs
|
|
989
|
+
];
|
|
990
|
+
}
|
|
991
|
+
if (data instanceof RegExp) {
|
|
992
|
+
meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.REGEXP, ...segments]);
|
|
993
|
+
return [
|
|
994
|
+
data.toString(),
|
|
995
|
+
meta,
|
|
996
|
+
maps,
|
|
997
|
+
blobs
|
|
998
|
+
];
|
|
999
|
+
}
|
|
1000
|
+
if (data instanceof Set) {
|
|
1001
|
+
const result = this.serialize(Array.from(data), segments, meta, maps, blobs);
|
|
1002
|
+
meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.SET, ...segments]);
|
|
1003
|
+
return result;
|
|
1004
|
+
}
|
|
1005
|
+
if (data instanceof Map) {
|
|
1006
|
+
const result = this.serialize(Array.from(data.entries()), segments, meta, maps, blobs);
|
|
1007
|
+
meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.MAP, ...segments]);
|
|
1008
|
+
return result;
|
|
1009
|
+
}
|
|
1010
|
+
if (Array.isArray(data)) return [
|
|
1011
|
+
data.map((v, i) => {
|
|
1012
|
+
if (v === void 0) {
|
|
1013
|
+
meta.push([
|
|
1014
|
+
STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.UNDEFINED,
|
|
1015
|
+
...segments,
|
|
1016
|
+
i
|
|
1017
|
+
]);
|
|
1018
|
+
return null;
|
|
1019
|
+
}
|
|
1020
|
+
return this.serialize(v, [...segments, i], meta, maps, blobs)[0];
|
|
1021
|
+
}),
|
|
1022
|
+
meta,
|
|
1023
|
+
maps,
|
|
1024
|
+
blobs
|
|
1025
|
+
];
|
|
1026
|
+
if (isObject(data)) {
|
|
1027
|
+
const json = {};
|
|
1028
|
+
for (const k in data) {
|
|
1029
|
+
if (k === "toJSON" && typeof data[k] === "function") continue;
|
|
1030
|
+
json[k] = this.serialize(data[k], [...segments, k], meta, maps, blobs)[0];
|
|
1031
|
+
}
|
|
1032
|
+
return [
|
|
1033
|
+
json,
|
|
1034
|
+
meta,
|
|
1035
|
+
maps,
|
|
1036
|
+
blobs
|
|
1037
|
+
];
|
|
1038
|
+
}
|
|
1039
|
+
return [
|
|
1040
|
+
data,
|
|
1041
|
+
meta,
|
|
1042
|
+
maps,
|
|
1043
|
+
blobs
|
|
1044
|
+
];
|
|
1045
|
+
}
|
|
1046
|
+
deserialize(json, meta, maps, getBlob) {
|
|
1047
|
+
const ref = { data: json };
|
|
1048
|
+
if (maps && getBlob) maps.forEach((segments, i) => {
|
|
1049
|
+
let currentRef = ref;
|
|
1050
|
+
let preSegment = "data";
|
|
1051
|
+
segments.forEach((segment) => {
|
|
1052
|
+
currentRef = currentRef[preSegment];
|
|
1053
|
+
preSegment = segment;
|
|
1054
|
+
if (!Object.hasOwn(currentRef, preSegment)) throw new Error(`Security error: accessing non-existent path during deserialization. Path segment: ${preSegment}`);
|
|
1055
|
+
});
|
|
1056
|
+
currentRef[preSegment] = getBlob(i);
|
|
1057
|
+
});
|
|
1058
|
+
for (const item of meta) {
|
|
1059
|
+
const type = item[0];
|
|
1060
|
+
let currentRef = ref;
|
|
1061
|
+
let preSegment = "data";
|
|
1062
|
+
for (let i = 1; i < item.length; i++) {
|
|
1063
|
+
currentRef = currentRef[preSegment];
|
|
1064
|
+
preSegment = item[i];
|
|
1065
|
+
if (!Object.hasOwn(currentRef, preSegment)) throw new Error(`Security error: accessing non-existent path during deserialization. Path segment: ${preSegment}`);
|
|
1066
|
+
}
|
|
1067
|
+
for (const custom of this.customSerializers) if (custom.type === type) {
|
|
1068
|
+
currentRef[preSegment] = custom.deserialize(currentRef[preSegment]);
|
|
1069
|
+
break;
|
|
1070
|
+
}
|
|
1071
|
+
switch (type) {
|
|
1072
|
+
case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.BIGINT:
|
|
1073
|
+
currentRef[preSegment] = BigInt(currentRef[preSegment]);
|
|
1074
|
+
break;
|
|
1075
|
+
case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.DATE:
|
|
1076
|
+
currentRef[preSegment] = new Date(currentRef[preSegment] ?? "Invalid Date");
|
|
1077
|
+
break;
|
|
1078
|
+
case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.NAN:
|
|
1079
|
+
currentRef[preSegment] = NaN;
|
|
1080
|
+
break;
|
|
1081
|
+
case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.UNDEFINED:
|
|
1082
|
+
currentRef[preSegment] = void 0;
|
|
1083
|
+
break;
|
|
1084
|
+
case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.URL:
|
|
1085
|
+
currentRef[preSegment] = new URL(currentRef[preSegment]);
|
|
1086
|
+
break;
|
|
1087
|
+
case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.REGEXP: {
|
|
1088
|
+
const [, pattern, flags] = currentRef[preSegment].match(/^\/(.*)\/([a-z]*)$/);
|
|
1089
|
+
currentRef[preSegment] = new RegExp(pattern, flags);
|
|
1090
|
+
break;
|
|
1091
|
+
}
|
|
1092
|
+
case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.SET:
|
|
1093
|
+
currentRef[preSegment] = new Set(currentRef[preSegment]);
|
|
1094
|
+
break;
|
|
1095
|
+
case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.MAP:
|
|
1096
|
+
currentRef[preSegment] = new Map(currentRef[preSegment]);
|
|
1097
|
+
break;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
return ref.data;
|
|
1101
|
+
}
|
|
1102
|
+
};
|
|
1103
|
+
function toHttpPath(path) {
|
|
1104
|
+
return `/${path.map(encodeURIComponent).join("/")}`;
|
|
1105
|
+
}
|
|
1106
|
+
function toStandardHeaders(headers) {
|
|
1107
|
+
if (typeof headers.forEach === "function") return toStandardHeaders$1(headers);
|
|
1108
|
+
return headers;
|
|
1109
|
+
}
|
|
1110
|
+
function getMalformedResponseErrorCode(status) {
|
|
1111
|
+
return Object.entries(COMMON_ORPC_ERROR_DEFS).find(([, def]) => def.status === status)?.[0] ?? "MALFORMED_ORPC_ERROR_RESPONSE";
|
|
1112
|
+
}
|
|
1113
|
+
var StandardRPCLinkCodec = class {
|
|
1114
|
+
constructor(serializer, options) {
|
|
1115
|
+
this.serializer = serializer;
|
|
1116
|
+
this.baseUrl = options.url;
|
|
1117
|
+
this.maxUrlLength = options.maxUrlLength ?? 2083;
|
|
1118
|
+
this.fallbackMethod = options.fallbackMethod ?? "POST";
|
|
1119
|
+
this.expectedMethod = options.method ?? this.fallbackMethod;
|
|
1120
|
+
this.headers = options.headers ?? {};
|
|
1121
|
+
}
|
|
1122
|
+
baseUrl;
|
|
1123
|
+
maxUrlLength;
|
|
1124
|
+
fallbackMethod;
|
|
1125
|
+
expectedMethod;
|
|
1126
|
+
headers;
|
|
1127
|
+
async encode(path, input, options) {
|
|
1128
|
+
let headers = toStandardHeaders(await value(this.headers, options, path, input));
|
|
1129
|
+
if (options.lastEventId !== void 0) headers = mergeStandardHeaders(headers, { "last-event-id": options.lastEventId });
|
|
1130
|
+
const expectedMethod = await value(this.expectedMethod, options, path, input);
|
|
1131
|
+
const baseUrl = await value(this.baseUrl, options, path, input);
|
|
1132
|
+
const url = new URL(baseUrl);
|
|
1133
|
+
url.pathname = `${url.pathname.replace(/\/$/, "")}${toHttpPath(path)}`;
|
|
1134
|
+
const serialized = this.serializer.serialize(input);
|
|
1135
|
+
if (expectedMethod === "GET" && !(serialized instanceof FormData) && !isAsyncIteratorObject(serialized)) {
|
|
1136
|
+
const maxUrlLength = await value(this.maxUrlLength, options, path, input);
|
|
1137
|
+
const getUrl = new URL(url);
|
|
1138
|
+
getUrl.searchParams.append("data", stringifyJSON(serialized));
|
|
1139
|
+
if (getUrl.toString().length <= maxUrlLength) return {
|
|
1140
|
+
body: void 0,
|
|
1141
|
+
method: expectedMethod,
|
|
1142
|
+
headers,
|
|
1143
|
+
url: getUrl,
|
|
1144
|
+
signal: options.signal
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
return {
|
|
1148
|
+
url,
|
|
1149
|
+
method: expectedMethod === "GET" ? this.fallbackMethod : expectedMethod,
|
|
1150
|
+
headers,
|
|
1151
|
+
body: serialized,
|
|
1152
|
+
signal: options.signal
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
async decode(response) {
|
|
1156
|
+
const isOk = !isORPCErrorStatus(response.status);
|
|
1157
|
+
const deserialized = await (async () => {
|
|
1158
|
+
let isBodyOk = false;
|
|
1159
|
+
try {
|
|
1160
|
+
const body = await response.body();
|
|
1161
|
+
isBodyOk = true;
|
|
1162
|
+
return this.serializer.deserialize(body);
|
|
1163
|
+
} catch (error) {
|
|
1164
|
+
if (!isBodyOk) throw new Error("Cannot parse response body, please check the response body and content-type.", { cause: error });
|
|
1165
|
+
throw new Error("Invalid RPC response format.", { cause: error });
|
|
1166
|
+
}
|
|
1167
|
+
})();
|
|
1168
|
+
if (!isOk) {
|
|
1169
|
+
if (isORPCErrorJson(deserialized)) throw createORPCErrorFromJson(deserialized);
|
|
1170
|
+
throw new ORPCError(getMalformedResponseErrorCode(response.status), {
|
|
1171
|
+
status: response.status,
|
|
1172
|
+
data: {
|
|
1173
|
+
...response,
|
|
1174
|
+
body: deserialized
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
return deserialized;
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
var StandardRPCSerializer = class {
|
|
1182
|
+
constructor(jsonSerializer) {
|
|
1183
|
+
this.jsonSerializer = jsonSerializer;
|
|
1184
|
+
}
|
|
1185
|
+
serialize(data) {
|
|
1186
|
+
if (isAsyncIteratorObject(data)) return mapEventIterator(data, {
|
|
1187
|
+
value: async (value) => this.#serialize(value, false),
|
|
1188
|
+
error: async (e) => {
|
|
1189
|
+
return new ErrorEvent({
|
|
1190
|
+
data: this.#serialize(toORPCError(e).toJSON(), false),
|
|
1191
|
+
cause: e
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1195
|
+
return this.#serialize(data, true);
|
|
1196
|
+
}
|
|
1197
|
+
#serialize(data, enableFormData) {
|
|
1198
|
+
const [json, meta_, maps, blobs] = this.jsonSerializer.serialize(data);
|
|
1199
|
+
const meta = meta_.length === 0 ? void 0 : meta_;
|
|
1200
|
+
if (!enableFormData || blobs.length === 0) return {
|
|
1201
|
+
json,
|
|
1202
|
+
meta
|
|
1203
|
+
};
|
|
1204
|
+
const form = new FormData();
|
|
1205
|
+
form.set("data", stringifyJSON({
|
|
1206
|
+
json,
|
|
1207
|
+
meta,
|
|
1208
|
+
maps
|
|
1209
|
+
}));
|
|
1210
|
+
blobs.forEach((blob, i) => {
|
|
1211
|
+
form.set(i.toString(), blob);
|
|
1212
|
+
});
|
|
1213
|
+
return form;
|
|
1214
|
+
}
|
|
1215
|
+
deserialize(data) {
|
|
1216
|
+
if (isAsyncIteratorObject(data)) return mapEventIterator(data, {
|
|
1217
|
+
value: async (value) => this.#deserialize(value),
|
|
1218
|
+
error: async (e) => {
|
|
1219
|
+
if (!(e instanceof ErrorEvent)) return e;
|
|
1220
|
+
const deserialized = this.#deserialize(e.data);
|
|
1221
|
+
if (isORPCErrorJson(deserialized)) return createORPCErrorFromJson(deserialized, { cause: e });
|
|
1222
|
+
return new ErrorEvent({
|
|
1223
|
+
data: deserialized,
|
|
1224
|
+
cause: e
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
});
|
|
1228
|
+
return this.#deserialize(data);
|
|
1229
|
+
}
|
|
1230
|
+
#deserialize(data) {
|
|
1231
|
+
if (data === void 0) return;
|
|
1232
|
+
if (!(data instanceof FormData)) return this.jsonSerializer.deserialize(data.json, data.meta ?? []);
|
|
1233
|
+
const serialized = JSON.parse(data.get("data"));
|
|
1234
|
+
return this.jsonSerializer.deserialize(serialized.json, serialized.meta ?? [], serialized.maps, (i) => data.get(i.toString()));
|
|
1235
|
+
}
|
|
1236
|
+
};
|
|
1237
|
+
var StandardRPCLink = class extends StandardLink {
|
|
1238
|
+
constructor(linkClient, options) {
|
|
1239
|
+
const linkCodec = new StandardRPCLinkCodec(new StandardRPCSerializer(new StandardRPCJsonSerializer(options)), options);
|
|
1240
|
+
super(linkCodec, linkClient, options);
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1243
|
+
//#endregion
|
|
1244
|
+
//#region ../../node_modules/.pnpm/@orpc+client@1.14.0_@opentelemetry+api@1.9.0/node_modules/@orpc/client/dist/adapters/fetch/index.mjs
|
|
1245
|
+
var CompositeLinkFetchPlugin = class extends CompositeStandardLinkPlugin {
|
|
1246
|
+
initRuntimeAdapter(options) {
|
|
1247
|
+
for (const plugin of this.plugins) plugin.initRuntimeAdapter?.(options);
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
var LinkFetchClient = class {
|
|
1251
|
+
fetch;
|
|
1252
|
+
toFetchRequestOptions;
|
|
1253
|
+
adapterInterceptors;
|
|
1254
|
+
constructor(options) {
|
|
1255
|
+
new CompositeLinkFetchPlugin(options.plugins).initRuntimeAdapter(options);
|
|
1256
|
+
this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
1257
|
+
this.toFetchRequestOptions = options;
|
|
1258
|
+
this.adapterInterceptors = toArray(options.adapterInterceptors);
|
|
1259
|
+
}
|
|
1260
|
+
async call(standardRequest, options, path, input) {
|
|
1261
|
+
const request = toFetchRequest(standardRequest, this.toFetchRequestOptions);
|
|
1262
|
+
return toStandardLazyResponse(await intercept(this.adapterInterceptors, {
|
|
1263
|
+
...options,
|
|
1264
|
+
request,
|
|
1265
|
+
path,
|
|
1266
|
+
input,
|
|
1267
|
+
init: { redirect: "manual" }
|
|
1268
|
+
}, ({ request: request2, path: path2, input: input2, init, ...options2 }) => this.fetch(request2, init, options2, path2, input2)), { signal: request.signal });
|
|
1269
|
+
}
|
|
1270
|
+
};
|
|
1271
|
+
var RPCLink = class extends StandardRPCLink {
|
|
1272
|
+
constructor(options) {
|
|
1273
|
+
const linkClient = new LinkFetchClient(options);
|
|
1274
|
+
super(linkClient, options);
|
|
1275
|
+
}
|
|
1276
|
+
};
|
|
1277
|
+
//#endregion
|
|
1278
|
+
//#region ../orpc/src/shared/client.ts
|
|
1279
|
+
function createLink(options) {
|
|
1280
|
+
return new RPCLink({
|
|
1281
|
+
url: options.baseUrl,
|
|
1282
|
+
headers: async () => {
|
|
1283
|
+
const baseHeaders = { "Content-Type": "application/json" };
|
|
1284
|
+
const customHeaders = typeof options.headers === "function" ? await options.headers() : options.headers;
|
|
1285
|
+
if (customHeaders) Object.assign(baseHeaders, customHeaders);
|
|
1286
|
+
if (options.getAuthToken) {
|
|
1287
|
+
const token = await options.getAuthToken();
|
|
1288
|
+
if (token) baseHeaders["Cookie"] = `tourial-session=${token}`;
|
|
1289
|
+
}
|
|
1290
|
+
return baseHeaders;
|
|
1291
|
+
},
|
|
1292
|
+
fetch: options.fetch || options.onResponse ? async (request, init) => {
|
|
1293
|
+
const response = await (options.fetch || globalThis.fetch)(request, init);
|
|
1294
|
+
if (options.onResponse) await options.onResponse(response);
|
|
1295
|
+
return response;
|
|
1296
|
+
} : void 0
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
//#endregion
|
|
1300
|
+
//#region ../orpc/src/live/client.ts
|
|
1301
|
+
/**
|
|
1302
|
+
* Create an HTTP client for calling live oRPC API endpoints
|
|
1303
|
+
*/
|
|
1304
|
+
function createLiveHttpClient(options) {
|
|
1305
|
+
return createORPCClient(createLink(options));
|
|
1306
|
+
}
|
|
1307
|
+
//#endregion
|
|
1308
|
+
//#region src/api.ts
|
|
1309
|
+
/**
|
|
1310
|
+
* Normalize a branded-host origin into the `/api/v3` base the live API is served
|
|
1311
|
+
* under. Accepts a bare origin ("https://guide.acme.com") or a URL that already
|
|
1312
|
+
* ends with `/api/v3`.
|
|
1313
|
+
*/
|
|
1314
|
+
function toApiBaseUrl(baseUrl) {
|
|
1315
|
+
const trimmed = baseUrl.replace(/\/+$/, "");
|
|
1316
|
+
return trimmed.endsWith("/api/v3") ? trimmed : `${trimmed}/api/v3`;
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Wrap a fetch implementation so every request carries the visitor cookies.
|
|
1320
|
+
* This is the load-bearing piece: the branded host is same-site with the
|
|
1321
|
+
* customer's page, so `credentials: "include"` lets the existing
|
|
1322
|
+
* `navless-live-*` cookies attach in every browser.
|
|
1323
|
+
*/
|
|
1324
|
+
function withCredentials(fetchImpl) {
|
|
1325
|
+
return (input, init) => fetchImpl(input, {
|
|
1326
|
+
...init,
|
|
1327
|
+
credentials: "include"
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
/** Build the typed live oRPC client, reusing @navless/orpc's client factory. */
|
|
1331
|
+
function createApiClient(apiBaseUrl, fetchImpl) {
|
|
1332
|
+
return createLiveHttpClient({
|
|
1333
|
+
baseUrl: apiBaseUrl,
|
|
1334
|
+
fetch: withCredentials(fetchImpl)
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
//#endregion
|
|
1338
|
+
//#region src/analytics.ts
|
|
1339
|
+
const UTM_KEYS = [
|
|
1340
|
+
"utm_source",
|
|
1341
|
+
"utm_medium",
|
|
1342
|
+
"utm_campaign",
|
|
1343
|
+
"utm_term",
|
|
1344
|
+
"utm_content"
|
|
1345
|
+
];
|
|
1346
|
+
const INTEGRATION_COOKIE_KEYS = ["hubspotutk", "_mkto_trk"];
|
|
1347
|
+
/** Pull UTM attribution params out of a `location.search` string. */
|
|
1348
|
+
function extractUTMParams(search) {
|
|
1349
|
+
const params = new URLSearchParams(search);
|
|
1350
|
+
const result = {};
|
|
1351
|
+
for (const key of UTM_KEYS) {
|
|
1352
|
+
const value = params.get(key);
|
|
1353
|
+
if (value) result[key] = value;
|
|
1354
|
+
}
|
|
1355
|
+
return result;
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Pull first-party integration cookies (HubSpot, Marketo) out of a
|
|
1359
|
+
* `document.cookie` string so they can be forwarded for CRM stitching.
|
|
1360
|
+
*/
|
|
1361
|
+
function extractIntegrationCookies(cookieString) {
|
|
1362
|
+
const cookies = {};
|
|
1363
|
+
for (const key of INTEGRATION_COOKIE_KEYS) {
|
|
1364
|
+
const match = cookieString.match(new RegExp(`(?:^|;\\s*)${key}=([^;]*)`));
|
|
1365
|
+
if (match?.[1]) cookies[key] = decodeURIComponent(match[1]);
|
|
1366
|
+
}
|
|
1367
|
+
return cookies;
|
|
1368
|
+
}
|
|
1369
|
+
/** Read `document.cookie`, swallowing the SecurityError thrown in opaque origins. */
|
|
1370
|
+
function safeCookieString() {
|
|
1371
|
+
if (typeof document === "undefined") return "";
|
|
1372
|
+
try {
|
|
1373
|
+
return document.cookie;
|
|
1374
|
+
} catch {
|
|
1375
|
+
return "";
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
//#endregion
|
|
1379
|
+
//#region src/types.ts
|
|
1380
|
+
/** AG-UI protocol frame types written by the guide SSE stream. */
|
|
1381
|
+
const SSEMessageType = {
|
|
1382
|
+
RunStarted: "RUN_STARTED",
|
|
1383
|
+
RunFinished: "RUN_FINISHED",
|
|
1384
|
+
RunError: "RUN_ERROR",
|
|
1385
|
+
TextMessageStart: "TEXT_MESSAGE_START",
|
|
1386
|
+
TextMessageContent: "TEXT_MESSAGE_CONTENT",
|
|
1387
|
+
TextMessageEnd: "TEXT_MESSAGE_END",
|
|
1388
|
+
Custom: "CUSTOM"
|
|
1389
|
+
};
|
|
1390
|
+
/** The `name` on `CUSTOM` guide events (skill payloads). */
|
|
1391
|
+
const GuideEvent = {
|
|
1392
|
+
SkillStart: "skill_start",
|
|
1393
|
+
SkillContent: "skill_content",
|
|
1394
|
+
SkillDocuments: "skill_documents",
|
|
1395
|
+
SkillRecommendations: "skill_recommendations",
|
|
1396
|
+
SkillCTAs: "skill_ctas",
|
|
1397
|
+
SkillDiagnoseHeader: "skill_diagnose_header",
|
|
1398
|
+
SkillDiagnoseQuestion: "skill_diagnose_question",
|
|
1399
|
+
SkillPlaylistItems: "skill_playlist_items",
|
|
1400
|
+
SkillPlaylistHeader: "skill_playlist_header",
|
|
1401
|
+
SkillPlaylistRationale: "skill_playlist_rationale",
|
|
1402
|
+
SkillHowToOutline: "skill_howto_outline",
|
|
1403
|
+
SkillHowToSteps: "skill_howto_steps",
|
|
1404
|
+
SkillBusinessCaseChooser: "skill_businesscase_chooser",
|
|
1405
|
+
SkillBusinessCaseDelta: "skill_businesscase_delta",
|
|
1406
|
+
SkillSolutionDesignHeader: "skill_solutiondesign_header",
|
|
1407
|
+
SkillSolutionDesignDiagram: "skill_solutiondesign_diagram",
|
|
1408
|
+
SkillEnd: "skill_end",
|
|
1409
|
+
SkillError: "skill_error",
|
|
1410
|
+
SkillGate: "skill_gate",
|
|
1411
|
+
InputSuggestions: "input_suggestions"
|
|
1412
|
+
};
|
|
1413
|
+
/** Analytics events fired by the SDK bootstrap. */
|
|
1414
|
+
const EmbedTrackingEvent = {
|
|
1415
|
+
EmbedLoaded: "embed_loaded",
|
|
1416
|
+
EmbedPageView: "embed_page_view",
|
|
1417
|
+
EmbedTriggerClicked: "embed_trigger_clicked",
|
|
1418
|
+
EmbedSideTabClicked: "embed_side_tab_clicked",
|
|
1419
|
+
EmbedSideTabDismissed: "embed_side_tab_dismissed"
|
|
1420
|
+
};
|
|
1421
|
+
//#endregion
|
|
1422
|
+
//#region src/chat-stream.ts
|
|
1423
|
+
const DATA_PREFIX = "data:";
|
|
1424
|
+
const DONE_SENTINEL = "[DONE]";
|
|
1425
|
+
/**
|
|
1426
|
+
* Stream a guide chat turn. POSTs the conversation to the SSE route
|
|
1427
|
+
* (`/api/v3/guide/conversation`) and yields normalized {@link GuideStreamEvent}s
|
|
1428
|
+
* until the server writes `data: [DONE]`. This is the one endpoint that is not
|
|
1429
|
+
* part of the typed oRPC router, so it is spoken by hand here.
|
|
1430
|
+
*/
|
|
1431
|
+
async function* streamConversation(params) {
|
|
1432
|
+
const { apiBaseUrl, guideId, messages, forcedSkill, fetchImpl, signal } = params;
|
|
1433
|
+
const body = {
|
|
1434
|
+
guideId,
|
|
1435
|
+
messages: messages.map((m) => ({
|
|
1436
|
+
role: m.role,
|
|
1437
|
+
content: m.content
|
|
1438
|
+
}))
|
|
1439
|
+
};
|
|
1440
|
+
if (forcedSkill) body.forcedSkill = forcedSkill;
|
|
1441
|
+
const response = await fetchImpl(`${apiBaseUrl}/guide/conversation`, {
|
|
1442
|
+
method: "POST",
|
|
1443
|
+
headers: { "Content-Type": "application/json" },
|
|
1444
|
+
credentials: "include",
|
|
1445
|
+
body: JSON.stringify(body),
|
|
1446
|
+
signal
|
|
1447
|
+
});
|
|
1448
|
+
if (!response.ok || !response.body) throw new Error(`[brand_brain] Conversation request failed with status ${response.status}`);
|
|
1449
|
+
const reader = response.body.getReader();
|
|
1450
|
+
const decoder = new TextDecoder();
|
|
1451
|
+
let buffer = "";
|
|
1452
|
+
try {
|
|
1453
|
+
for (;;) {
|
|
1454
|
+
const { done, value } = await reader.read();
|
|
1455
|
+
if (done) break;
|
|
1456
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1457
|
+
let separatorIndex = buffer.indexOf("\n\n");
|
|
1458
|
+
while (separatorIndex !== -1) {
|
|
1459
|
+
const rawEvent = buffer.slice(0, separatorIndex);
|
|
1460
|
+
buffer = buffer.slice(separatorIndex + 2);
|
|
1461
|
+
separatorIndex = buffer.indexOf("\n\n");
|
|
1462
|
+
const dataLine = rawEvent.split("\n").find((line) => line.startsWith(DATA_PREFIX));
|
|
1463
|
+
if (!dataLine) continue;
|
|
1464
|
+
const data = dataLine.slice(5).trim();
|
|
1465
|
+
if (data === DONE_SENTINEL) return;
|
|
1466
|
+
const mapped = mapFrame(JSON.parse(data));
|
|
1467
|
+
if (mapped) yield mapped;
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
} finally {
|
|
1471
|
+
reader.releaseLock();
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
function mapFrame(frame) {
|
|
1475
|
+
switch (frame.type) {
|
|
1476
|
+
case SSEMessageType.RunStarted: return {
|
|
1477
|
+
type: "run-started",
|
|
1478
|
+
runId: frame.runId ?? ""
|
|
1479
|
+
};
|
|
1480
|
+
case SSEMessageType.RunFinished: return {
|
|
1481
|
+
type: "run-finished",
|
|
1482
|
+
finishReason: frame.finishReason
|
|
1483
|
+
};
|
|
1484
|
+
case SSEMessageType.RunError: return {
|
|
1485
|
+
type: "error",
|
|
1486
|
+
message: frame.error?.message ?? "Unknown error",
|
|
1487
|
+
code: frame.error?.code
|
|
1488
|
+
};
|
|
1489
|
+
case SSEMessageType.TextMessageStart: return {
|
|
1490
|
+
type: "message-start",
|
|
1491
|
+
messageId: frame.messageId ?? "",
|
|
1492
|
+
role: frame.role ?? "assistant"
|
|
1493
|
+
};
|
|
1494
|
+
case SSEMessageType.TextMessageContent: return {
|
|
1495
|
+
type: "text",
|
|
1496
|
+
messageId: frame.messageId ?? "",
|
|
1497
|
+
delta: frame.delta ?? ""
|
|
1498
|
+
};
|
|
1499
|
+
case SSEMessageType.TextMessageEnd: return {
|
|
1500
|
+
type: "message-end",
|
|
1501
|
+
messageId: frame.messageId ?? ""
|
|
1502
|
+
};
|
|
1503
|
+
case SSEMessageType.Custom: return mapCustomFrame(frame);
|
|
1504
|
+
default: return null;
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
function mapCustomFrame(frame) {
|
|
1508
|
+
if (!frame.name) return null;
|
|
1509
|
+
const value = frame.value ?? {};
|
|
1510
|
+
if (frame.name === GuideEvent.SkillGate) return {
|
|
1511
|
+
type: "gate",
|
|
1512
|
+
skill: value.skill,
|
|
1513
|
+
prompt: value.prompt,
|
|
1514
|
+
skillInstanceId: value.skillInstanceId
|
|
1515
|
+
};
|
|
1516
|
+
if (frame.name === GuideEvent.SkillError) return {
|
|
1517
|
+
type: "error",
|
|
1518
|
+
message: value.message ?? "Skill error",
|
|
1519
|
+
code: value.errorType
|
|
1520
|
+
};
|
|
1521
|
+
return {
|
|
1522
|
+
type: "skill",
|
|
1523
|
+
name: frame.name,
|
|
1524
|
+
value
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
//#endregion
|
|
1528
|
+
//#region src/GuideClient.ts
|
|
1529
|
+
function resolveDomain(config) {
|
|
1530
|
+
if (config.domain) return config.domain;
|
|
1531
|
+
if (typeof window !== "undefined") return window.location.hostname;
|
|
1532
|
+
throw new Error("[brand_brain] `domain` is required when running without a browser `window`.");
|
|
1533
|
+
}
|
|
1534
|
+
/**
|
|
1535
|
+
* The client returned by {@link initGuide}. Holds the resolved guide, the
|
|
1536
|
+
* credentialed live API client, and the in-memory conversation history. Every
|
|
1537
|
+
* method reuses an existing public endpoint — the SDK adds no server surface.
|
|
1538
|
+
*/
|
|
1539
|
+
var GuideClient = class GuideClient {
|
|
1540
|
+
#api;
|
|
1541
|
+
constructor(params) {
|
|
1542
|
+
this.history = [];
|
|
1543
|
+
this.conversations = {
|
|
1544
|
+
getOrCreate: () => this.#api.conversations.getOrCreate({
|
|
1545
|
+
guideId: this.guide.id,
|
|
1546
|
+
accountId: this.guide.accountId
|
|
1547
|
+
}),
|
|
1548
|
+
list: () => this.#api.conversations.list({
|
|
1549
|
+
guideId: this.guide.id,
|
|
1550
|
+
accountId: this.guide.accountId
|
|
1551
|
+
}),
|
|
1552
|
+
get: (conversationId, options) => this.#api.conversations.get({
|
|
1553
|
+
conversationId,
|
|
1554
|
+
accountId: this.guide.accountId,
|
|
1555
|
+
...options
|
|
1556
|
+
}),
|
|
1557
|
+
delete: (conversationId) => this.#api.conversations.delete({
|
|
1558
|
+
conversationId,
|
|
1559
|
+
accountId: this.guide.accountId
|
|
1560
|
+
})
|
|
1561
|
+
};
|
|
1562
|
+
this.skills = {
|
|
1563
|
+
listHistory: () => this.#api.skillInstances.listHistory({
|
|
1564
|
+
accountId: this.guide.accountId,
|
|
1565
|
+
guideId: this.guide.id
|
|
1566
|
+
}),
|
|
1567
|
+
get: (skillInstanceId) => this.#api.skillInstances.get({ skillInstanceId }),
|
|
1568
|
+
update: (skillInstanceId, data) => this.#api.skillInstances.update({
|
|
1569
|
+
skillInstanceId,
|
|
1570
|
+
data
|
|
1571
|
+
}),
|
|
1572
|
+
selectDraft: (draftId) => this.#api.skillInstances.selectDraft({ draftId }),
|
|
1573
|
+
markShared: (skillInstanceId) => this.#api.skillInstances.markShared({ skillInstanceId }),
|
|
1574
|
+
importShared: (sourceSkillInstanceId) => this.#api.skillInstances.importShared({
|
|
1575
|
+
sourceSkillInstanceId,
|
|
1576
|
+
accountId: this.guide.accountId
|
|
1577
|
+
})
|
|
1578
|
+
};
|
|
1579
|
+
this.guide = params.guide;
|
|
1580
|
+
this.apiBaseUrl = params.apiBaseUrl;
|
|
1581
|
+
this.domain = params.domain;
|
|
1582
|
+
this.fetchImpl = params.fetchImpl;
|
|
1583
|
+
this.#api = createApiClient(this.apiBaseUrl, this.fetchImpl);
|
|
1584
|
+
}
|
|
1585
|
+
static async init(config) {
|
|
1586
|
+
const fetchImpl = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
1587
|
+
const apiBaseUrl = toApiBaseUrl(config.baseUrl);
|
|
1588
|
+
const domain = resolveDomain(config);
|
|
1589
|
+
const guide = await createApiClient(apiBaseUrl, fetchImpl).guides.resolve({
|
|
1590
|
+
domain,
|
|
1591
|
+
slug: config.slug
|
|
1592
|
+
});
|
|
1593
|
+
const client = new GuideClient({
|
|
1594
|
+
guide,
|
|
1595
|
+
apiBaseUrl,
|
|
1596
|
+
domain,
|
|
1597
|
+
fetchImpl
|
|
1598
|
+
});
|
|
1599
|
+
await client.applyInitialConsent(config.consent ?? "auto", guide.gdprEnabled);
|
|
1600
|
+
if (config.trackLoad ?? true) client.trackLoad();
|
|
1601
|
+
return client;
|
|
1602
|
+
}
|
|
1603
|
+
/** The account this guide belongs to (used implicitly by history calls). */
|
|
1604
|
+
get accountId() {
|
|
1605
|
+
return this.guide.accountId;
|
|
1606
|
+
}
|
|
1607
|
+
/** The in-memory conversation history accumulated by {@link ask}. */
|
|
1608
|
+
get messages() {
|
|
1609
|
+
return this.history;
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Send a message and stream the reply. Yields text deltas for the chat bubble
|
|
1613
|
+
* plus every structured skill event; the full 7-skill surface flows through
|
|
1614
|
+
* one stream. The user + assistant turns are appended to {@link messages}.
|
|
1615
|
+
*/
|
|
1616
|
+
async *ask(message, options = {}) {
|
|
1617
|
+
this.history.push({
|
|
1618
|
+
id: crypto.randomUUID(),
|
|
1619
|
+
role: "user",
|
|
1620
|
+
content: message
|
|
1621
|
+
});
|
|
1622
|
+
let assistant = null;
|
|
1623
|
+
for await (const event of streamConversation({
|
|
1624
|
+
apiBaseUrl: this.apiBaseUrl,
|
|
1625
|
+
guideId: this.guide.id,
|
|
1626
|
+
messages: this.history,
|
|
1627
|
+
forcedSkill: options.forcedSkill,
|
|
1628
|
+
fetchImpl: this.fetchImpl,
|
|
1629
|
+
signal: options.signal
|
|
1630
|
+
})) {
|
|
1631
|
+
if (event.type === "message-start") {
|
|
1632
|
+
assistant = {
|
|
1633
|
+
id: event.messageId || crypto.randomUUID(),
|
|
1634
|
+
role: "assistant",
|
|
1635
|
+
content: ""
|
|
1636
|
+
};
|
|
1637
|
+
this.history.push(assistant);
|
|
1638
|
+
} else if (event.type === "text" && assistant) assistant.content += event.delta;
|
|
1639
|
+
yield event;
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
/** Clear the in-memory conversation history (server-side history is unaffected). */
|
|
1643
|
+
reset() {
|
|
1644
|
+
this.history.length = 0;
|
|
1645
|
+
}
|
|
1646
|
+
/** Grant consent tiers. `essential` is always forced true server-side. */
|
|
1647
|
+
async setConsent(levels) {
|
|
1648
|
+
await this.#api.visitors.setConsent({
|
|
1649
|
+
domain: this.domain,
|
|
1650
|
+
consent: levels
|
|
1651
|
+
});
|
|
1652
|
+
}
|
|
1653
|
+
/** Read the current visitor's tracking + consent + email status. */
|
|
1654
|
+
getStatus() {
|
|
1655
|
+
return this.#api.visitors.getVisitorStatus();
|
|
1656
|
+
}
|
|
1657
|
+
/** Capture a lead email (sends a magic link when verification is required). */
|
|
1658
|
+
submitGate(email, options = {}) {
|
|
1659
|
+
return this.#api.visitors.submitGate({
|
|
1660
|
+
email,
|
|
1661
|
+
domain: this.domain,
|
|
1662
|
+
guideId: this.guide.id,
|
|
1663
|
+
...options
|
|
1664
|
+
});
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Fire an analytics event. Fire-and-forget — never throws into the host page.
|
|
1668
|
+
* Uses a raw request (the same shape the embed script posts) so it stays
|
|
1669
|
+
* decoupled from the typed client's event enum.
|
|
1670
|
+
*/
|
|
1671
|
+
track(eventType, properties) {
|
|
1672
|
+
this.fetchImpl(`${this.apiBaseUrl}/events/track`, {
|
|
1673
|
+
method: "POST",
|
|
1674
|
+
headers: { "Content-Type": "application/json" },
|
|
1675
|
+
credentials: "include",
|
|
1676
|
+
body: JSON.stringify({ json: {
|
|
1677
|
+
domain: this.domain,
|
|
1678
|
+
guideId: this.guide.id,
|
|
1679
|
+
eventType,
|
|
1680
|
+
properties: properties ?? {}
|
|
1681
|
+
} })
|
|
1682
|
+
}).catch(() => {});
|
|
1683
|
+
}
|
|
1684
|
+
/** Fire the initial `embed_loaded` (with attribution) + first page view. */
|
|
1685
|
+
trackLoad() {
|
|
1686
|
+
const search = typeof window !== "undefined" ? window.location.search : "";
|
|
1687
|
+
const parentUrl = typeof window !== "undefined" ? window.location.href : void 0;
|
|
1688
|
+
const referrer = typeof document !== "undefined" ? document.referrer : void 0;
|
|
1689
|
+
this.track(EmbedTrackingEvent.EmbedLoaded, {
|
|
1690
|
+
referrer,
|
|
1691
|
+
parentUrl,
|
|
1692
|
+
utmParams: extractUTMParams(search),
|
|
1693
|
+
integrationCookies: extractIntegrationCookies(safeCookieString())
|
|
1694
|
+
});
|
|
1695
|
+
this.trackPageView();
|
|
1696
|
+
}
|
|
1697
|
+
/** Record a page view (call on client-side route changes in an SPA). */
|
|
1698
|
+
trackPageView(url) {
|
|
1699
|
+
const pageUrl = url ?? (typeof window !== "undefined" ? window.location.href : void 0);
|
|
1700
|
+
this.track(EmbedTrackingEvent.EmbedPageView, { pageUrl });
|
|
1701
|
+
}
|
|
1702
|
+
/** End the current visit (best to call on `pagehide`). */
|
|
1703
|
+
async endSession() {
|
|
1704
|
+
await this.#api.sessions.endSession();
|
|
1705
|
+
}
|
|
1706
|
+
async applyInitialConsent(consent, gdprEnabled) {
|
|
1707
|
+
if (consent === false) return;
|
|
1708
|
+
try {
|
|
1709
|
+
if (consent === "auto") {
|
|
1710
|
+
if (!gdprEnabled) await this.setConsent({
|
|
1711
|
+
functional: true,
|
|
1712
|
+
analytical: true
|
|
1713
|
+
});
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
await this.setConsent(consent);
|
|
1717
|
+
} catch {}
|
|
1718
|
+
}
|
|
1719
|
+
};
|
|
1720
|
+
/** Bootstrap a guide session and return a ready-to-use {@link GuideClient}. */
|
|
1721
|
+
async function initGuide(config) {
|
|
1722
|
+
return GuideClient.init(config);
|
|
1723
|
+
}
|
|
1724
|
+
//#endregion
|
|
1725
|
+
//#region src/react/useGuide.ts
|
|
1726
|
+
/**
|
|
1727
|
+
* React binding over {@link initGuide}. Bootstraps once per `baseUrl`+`slug`,
|
|
1728
|
+
* mirrors the streamed reply into state, and ends the session on unmount —
|
|
1729
|
+
* encapsulating the streaming/cleanup patterns so generated UIs stay correct.
|
|
1730
|
+
*/
|
|
1731
|
+
function useGuide(config) {
|
|
1732
|
+
const [client, setClient] = (0, react.useState)(null);
|
|
1733
|
+
const [messages, setMessages] = (0, react.useState)([]);
|
|
1734
|
+
const [isStreaming, setIsStreaming] = (0, react.useState)(false);
|
|
1735
|
+
const [error, setError] = (0, react.useState)(null);
|
|
1736
|
+
const { baseUrl, slug } = config;
|
|
1737
|
+
const configRef = (0, react.useRef)(config);
|
|
1738
|
+
configRef.current = config;
|
|
1739
|
+
(0, react.useEffect)(() => {
|
|
1740
|
+
let active = true;
|
|
1741
|
+
let created = null;
|
|
1742
|
+
initGuide(configRef.current).then((instance) => {
|
|
1743
|
+
if (!active) {
|
|
1744
|
+
instance.endSession();
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1747
|
+
created = instance;
|
|
1748
|
+
setClient(instance);
|
|
1749
|
+
setError(null);
|
|
1750
|
+
}).catch((err) => {
|
|
1751
|
+
if (active) setError(err instanceof Error ? err : new Error(String(err)));
|
|
1752
|
+
});
|
|
1753
|
+
return () => {
|
|
1754
|
+
active = false;
|
|
1755
|
+
created?.endSession();
|
|
1756
|
+
};
|
|
1757
|
+
}, [baseUrl, slug]);
|
|
1758
|
+
const ask = (0, react.useCallback)(async (message, options) => {
|
|
1759
|
+
if (!client) return;
|
|
1760
|
+
setIsStreaming(true);
|
|
1761
|
+
setError(null);
|
|
1762
|
+
try {
|
|
1763
|
+
for await (const event of client.ask(message, options)) if (event.type === "text" || event.type === "message-start") setMessages([...client.messages]);
|
|
1764
|
+
setMessages([...client.messages]);
|
|
1765
|
+
} catch (err) {
|
|
1766
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1767
|
+
} finally {
|
|
1768
|
+
setIsStreaming(false);
|
|
1769
|
+
}
|
|
1770
|
+
}, [client]);
|
|
1771
|
+
const reset = (0, react.useCallback)(() => {
|
|
1772
|
+
client?.reset();
|
|
1773
|
+
setMessages([]);
|
|
1774
|
+
}, [client]);
|
|
1775
|
+
return {
|
|
1776
|
+
client,
|
|
1777
|
+
guide: client?.guide ?? null,
|
|
1778
|
+
messages,
|
|
1779
|
+
isReady: client !== null,
|
|
1780
|
+
isStreaming,
|
|
1781
|
+
error,
|
|
1782
|
+
ask,
|
|
1783
|
+
reset
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
//#endregion
|
|
1787
|
+
exports.useGuide = useGuide;
|
|
1788
|
+
|
|
1789
|
+
//# sourceMappingURL=index.cjs.map
|