@raisindb/client 0.1.16 → 0.1.17
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 +281 -70
- package/dist/chunk-DJDP5CX6.mjs +866 -0
- package/dist/chunk-DJDP5CX6.mjs.map +1 -0
- package/dist/chunk-JRFBP4WK.mjs +170 -0
- package/dist/chunk-JRFBP4WK.mjs.map +1 -0
- package/dist/chunk-OLJOZIIU.mjs +1348 -0
- package/dist/chunk-OLJOZIIU.mjs.map +1 -0
- package/dist/chunk-T2ZSNYFG.mjs +248 -0
- package/dist/chunk-T2ZSNYFG.mjs.map +1 -0
- package/dist/chunk-VZX3ACSO.mjs +190 -0
- package/dist/chunk-VZX3ACSO.mjs.map +1 -0
- package/dist/chunk-WFBAWOVM.mjs +532 -0
- package/dist/chunk-WFBAWOVM.mjs.map +1 -0
- package/dist/conversation-list-store-CNcVagmw.d.mts +6120 -0
- package/dist/conversation-list-store-CNcVagmw.d.ts +6120 -0
- package/dist/index-DQjE-4Oj.d.ts +301 -0
- package/dist/index-FkFH4HHQ.d.mts +301 -0
- package/dist/index.d.mts +66 -6108
- package/dist/index.d.ts +66 -6108
- package/dist/index.js +859 -109
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +639 -3108
- package/dist/index.mjs.map +1 -0
- package/dist/react.d.mts +4 -0
- package/dist/react.d.ts +4 -0
- package/dist/react.js +2500 -0
- package/dist/react.js.map +1 -0
- package/dist/react.mjs +9 -0
- package/dist/react.mjs.map +1 -0
- package/dist/svelte-sql-62EaYoeM.d.ts +52 -0
- package/dist/svelte-sql-CgT-Ij-P.d.mts +52 -0
- package/dist/svelte.d.mts +288 -0
- package/dist/svelte.d.ts +288 -0
- package/dist/svelte.js +2413 -0
- package/dist/svelte.js.map +1 -0
- package/dist/svelte.mjs +25 -0
- package/dist/svelte.mjs.map +1 -0
- package/dist/vue.d.mts +197 -0
- package/dist/vue.d.ts +197 -0
- package/dist/vue.js +1441 -0
- package/dist/vue.js.map +1 -0
- package/dist/vue.mjs +9 -0
- package/dist/vue.mjs.map +1 -0
- package/package.json +18 -3
package/dist/index.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,19 +15,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// src/index.ts
|
|
31
|
-
var
|
|
32
|
-
__export(
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
33
23
|
AllNodeEventTypes: () => AllNodeEventTypes,
|
|
34
24
|
Archetypes: () => Archetypes,
|
|
35
25
|
AuthManager: () => AuthManager,
|
|
@@ -49,6 +39,7 @@ __export(index_exports, {
|
|
|
49
39
|
DEFAULT_RETRY_BASE_DELAY: () => DEFAULT_RETRY_BASE_DELAY,
|
|
50
40
|
DEFAULT_RETRY_MAX_DELAY: () => DEFAULT_RETRY_MAX_DELAY,
|
|
51
41
|
DEFAULT_RETRY_OPTIONS: () => DEFAULT_RETRY_OPTIONS,
|
|
42
|
+
DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS: () => DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS,
|
|
52
43
|
Database: () => Database,
|
|
53
44
|
ElementTypes: () => ElementTypes,
|
|
54
45
|
EventHandler: () => EventHandler,
|
|
@@ -59,6 +50,7 @@ __export(index_exports, {
|
|
|
59
50
|
HttpDatabase: () => HttpDatabase,
|
|
60
51
|
HttpFunctionsApi: () => HttpFunctionsApi,
|
|
61
52
|
HttpWorkspaceClient: () => HttpWorkspaceClient,
|
|
53
|
+
InboxApi: () => InboxApi,
|
|
62
54
|
LocalStorageTokenStorage: () => LocalStorageTokenStorage,
|
|
63
55
|
LogLevel: () => LogLevel,
|
|
64
56
|
MemoryTokenStorage: () => MemoryTokenStorage,
|
|
@@ -69,6 +61,7 @@ __export(index_exports, {
|
|
|
69
61
|
NodeOperations: () => NodeOperations,
|
|
70
62
|
NodeTypes: () => NodeTypes,
|
|
71
63
|
RAISIN_CONTEXT_KEY: () => RAISIN_CONTEXT_KEY,
|
|
64
|
+
RETRY_STRATEGIES: () => RETRY_STRATEGIES,
|
|
72
65
|
RaisinAbortError: () => RaisinAbortError,
|
|
73
66
|
RaisinAuthError: () => RaisinAuthError,
|
|
74
67
|
RaisinClient: () => RaisinClient,
|
|
@@ -104,6 +97,7 @@ __export(index_exports, {
|
|
|
104
97
|
createFlowAdapter: () => createFlowAdapter,
|
|
105
98
|
createLoader: () => createLoader,
|
|
106
99
|
createRaisinReact: () => createRaisinReact,
|
|
100
|
+
createRaisinVue: () => createRaisinVue,
|
|
107
101
|
createRequestScopedClient: () => createRequestScopedClient,
|
|
108
102
|
createSSRClient: () => createSSRClient,
|
|
109
103
|
createSqlAdapter: () => createSqlAdapter,
|
|
@@ -116,13 +110,18 @@ __export(index_exports, {
|
|
|
116
110
|
getErrorMessage: () => getErrorMessage,
|
|
117
111
|
getLogLevel: () => getLogLevel,
|
|
118
112
|
getLoggerConfig: () => getLoggerConfig,
|
|
113
|
+
getRefDisplayName: () => getRefDisplayName,
|
|
114
|
+
getRefPath: () => getRefPath,
|
|
119
115
|
isEventMessage: () => isEventMessage,
|
|
116
|
+
isFlowDefinitionContainer: () => isFlowDefinitionContainer,
|
|
117
|
+
isFlowDefinitionStep: () => isFlowDefinitionStep,
|
|
120
118
|
isHttpClient: () => isHttpClient,
|
|
121
119
|
isResponseEnvelope: () => isResponseEnvelope,
|
|
122
120
|
isRetryableError: () => isRetryableError,
|
|
123
121
|
isTerminalEvent: () => isTerminalEvent,
|
|
124
122
|
isWebSocketClient: () => isWebSocketClient,
|
|
125
123
|
logger: () => logger,
|
|
124
|
+
normalizeHomePath: () => normalizeHomePath,
|
|
126
125
|
projectPlansFromMessages: () => projectPlansFromMessages,
|
|
127
126
|
rowsToObjects: () => rowsToObjects,
|
|
128
127
|
setLogLevel: () => setLogLevel,
|
|
@@ -132,7 +131,7 @@ __export(index_exports, {
|
|
|
132
131
|
useFlow: () => useFlow,
|
|
133
132
|
withRetry: () => withRetry
|
|
134
133
|
});
|
|
135
|
-
module.exports = __toCommonJS(
|
|
134
|
+
module.exports = __toCommonJS(src_exports);
|
|
136
135
|
|
|
137
136
|
// src/client.ts
|
|
138
137
|
var import_events4 = require("events");
|
|
@@ -326,7 +325,8 @@ var Connection = class extends import_events.EventEmitter {
|
|
|
326
325
|
autoReconnect: options.autoReconnect ?? true,
|
|
327
326
|
heartbeatInterval: options.heartbeatInterval ?? 3e4,
|
|
328
327
|
heartbeatTimeout: options.heartbeatTimeout ?? 5e3,
|
|
329
|
-
protocols: options.protocols
|
|
328
|
+
protocols: options.protocols,
|
|
329
|
+
headers: options.headers
|
|
330
330
|
};
|
|
331
331
|
this.reconnectManager = new ReconnectManager(options.reconnectOptions);
|
|
332
332
|
this.WebSocketImpl = getWebSocketImpl();
|
|
@@ -342,10 +342,10 @@ var Connection = class extends import_events.EventEmitter {
|
|
|
342
342
|
this.setState("connecting" /* Connecting */);
|
|
343
343
|
return new Promise((resolve, reject) => {
|
|
344
344
|
try {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
this.options.
|
|
348
|
-
);
|
|
345
|
+
const isBrowserWebSocket = typeof WebSocket !== "undefined" && this.WebSocketImpl === WebSocket;
|
|
346
|
+
this.ws = isBrowserWebSocket || !this.options.headers ? new this.WebSocketImpl(this.url, this.options.protocols) : new this.WebSocketImpl(this.url, this.options.protocols, {
|
|
347
|
+
headers: this.options.headers
|
|
348
|
+
});
|
|
349
349
|
this.ws.binaryType = "arraybuffer";
|
|
350
350
|
this.ws.onopen = () => {
|
|
351
351
|
this.setState("connected" /* Connected */);
|
|
@@ -434,6 +434,16 @@ var Connection = class extends import_events.EventEmitter {
|
|
|
434
434
|
isConnected() {
|
|
435
435
|
return this.state === "connected" /* Connected */;
|
|
436
436
|
}
|
|
437
|
+
/**
|
|
438
|
+
* Whether auto-reconnect is enabled for this connection.
|
|
439
|
+
*
|
|
440
|
+
* Used by the client to decide whether requests issued while the
|
|
441
|
+
* connection is down can be queued (the connection will come back) or
|
|
442
|
+
* should fail immediately.
|
|
443
|
+
*/
|
|
444
|
+
isAutoReconnectEnabled() {
|
|
445
|
+
return this.options.autoReconnect;
|
|
446
|
+
}
|
|
437
447
|
/**
|
|
438
448
|
* Reconnect to the server
|
|
439
449
|
*/
|
|
@@ -1010,6 +1020,14 @@ var EventHandler = class {
|
|
|
1010
1020
|
* If a subscription with identical filters already exists, the callback
|
|
1011
1021
|
* is added to the existing subscription instead of creating a new one.
|
|
1012
1022
|
*
|
|
1023
|
+
* Path filter semantics (matched server-side):
|
|
1024
|
+
* - A plain path matches **only that exact node** — there is no implicit
|
|
1025
|
+
* prefix matching.
|
|
1026
|
+
* - `*` matches exactly one path segment (e.g. `/inbox/*` matches
|
|
1027
|
+
* `/inbox/a` but not `/inbox/a/b`).
|
|
1028
|
+
* - `**` matches recursively (e.g. `/inbox/**` matches all descendants
|
|
1029
|
+
* of `/inbox`, but not `/inbox` itself).
|
|
1030
|
+
*
|
|
1013
1031
|
* @param filters - Event filters
|
|
1014
1032
|
* @param callback - Callback function for events
|
|
1015
1033
|
* @returns Subscription object
|
|
@@ -1200,14 +1218,29 @@ var EventHandler = class {
|
|
|
1200
1218
|
* Restore subscriptions after reconnect
|
|
1201
1219
|
*
|
|
1202
1220
|
* Re-subscribes to the server with the original filters for all active
|
|
1203
|
-
* subscription entries.
|
|
1221
|
+
* subscription entries. Failed entries are kept (with their callbacks)
|
|
1222
|
+
* and marked pending so a retry call can re-attempt them without
|
|
1223
|
+
* duplicating already-restored subscriptions.
|
|
1224
|
+
*
|
|
1225
|
+
* @param options.retry - When true, only re-attempts entries that failed
|
|
1226
|
+
* in a previous call (instead of re-subscribing everything)
|
|
1227
|
+
* @throws Error if any subscription could not be restored
|
|
1204
1228
|
*/
|
|
1205
|
-
async restoreSubscriptions() {
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1229
|
+
async restoreSubscriptions(options) {
|
|
1230
|
+
if (!options?.retry) {
|
|
1231
|
+
for (const entry of this.filterSubscriptions.values()) {
|
|
1232
|
+
this.subscriptions.delete(entry.serverId);
|
|
1233
|
+
entry.restorePending = true;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
const entriesToRestore = Array.from(this.filterSubscriptions.entries()).filter(([, entry]) => entry.restorePending);
|
|
1237
|
+
let failureCount = 0;
|
|
1238
|
+
let lastError;
|
|
1209
1239
|
for (const [hash, entry] of entriesToRestore) {
|
|
1210
|
-
if (entry.callbacks.size === 0)
|
|
1240
|
+
if (entry.callbacks.size === 0) {
|
|
1241
|
+
entry.restorePending = false;
|
|
1242
|
+
continue;
|
|
1243
|
+
}
|
|
1211
1244
|
try {
|
|
1212
1245
|
const payload = { filters: entry.filters };
|
|
1213
1246
|
const response = await this.sendRequest(
|
|
@@ -1215,22 +1248,24 @@ var EventHandler = class {
|
|
|
1215
1248
|
"subscribe" /* Subscribe */
|
|
1216
1249
|
);
|
|
1217
1250
|
const newServerId = response.subscription_id;
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
filters: entry.filters,
|
|
1221
|
-
callbacks: entry.callbacks
|
|
1222
|
-
});
|
|
1251
|
+
entry.serverId = newServerId;
|
|
1252
|
+
entry.restorePending = false;
|
|
1223
1253
|
this.subscriptions.set(newServerId, hash);
|
|
1224
1254
|
for (const callback of entry.callbacks) {
|
|
1225
1255
|
this.callbackToHash.set(callback, hash);
|
|
1226
1256
|
}
|
|
1227
1257
|
} catch (error) {
|
|
1228
1258
|
logger.error("Failed to restore subscription:", error);
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
}
|
|
1259
|
+
failureCount++;
|
|
1260
|
+
lastError = error;
|
|
1232
1261
|
}
|
|
1233
1262
|
}
|
|
1263
|
+
if (failureCount > 0) {
|
|
1264
|
+
const message = lastError instanceof Error ? lastError.message : String(lastError);
|
|
1265
|
+
throw new Error(
|
|
1266
|
+
`Failed to restore ${failureCount} subscription(s) after reconnect: ${message}`
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1234
1269
|
}
|
|
1235
1270
|
};
|
|
1236
1271
|
var EventSubscriptions = class {
|
|
@@ -1265,7 +1300,15 @@ var EventSubscriptions = class {
|
|
|
1265
1300
|
/**
|
|
1266
1301
|
* Subscribe to events for a specific path
|
|
1267
1302
|
*
|
|
1268
|
-
*
|
|
1303
|
+
* Path pattern semantics (matched server-side):
|
|
1304
|
+
* - A plain path matches **only that exact node** — there is no implicit
|
|
1305
|
+
* prefix matching, so `/folder` does NOT match `/folder/child`.
|
|
1306
|
+
* - `*` matches exactly one path segment: `/folder/*` matches
|
|
1307
|
+
* `/folder/child` but not `/folder/child/grandchild`.
|
|
1308
|
+
* - `**` matches recursively: `/folder/**` matches every descendant of
|
|
1309
|
+
* `/folder` (but not `/folder` itself).
|
|
1310
|
+
*
|
|
1311
|
+
* @param path - Path pattern (e.g. "/folder", "/folder/*", "/folder/**")
|
|
1269
1312
|
* @param callback - Callback function for events
|
|
1270
1313
|
* @param options - Optional subscription options
|
|
1271
1314
|
* @param options.includeNode - Include full node data in event payload (default: false)
|
|
@@ -1897,7 +1940,17 @@ var NodeFileSource = class {
|
|
|
1897
1940
|
return;
|
|
1898
1941
|
}
|
|
1899
1942
|
if (!this._fsPromises) {
|
|
1900
|
-
|
|
1943
|
+
if (!isNodeEnvironment()) {
|
|
1944
|
+
throw new Error(
|
|
1945
|
+
"NodeFileSource requires Node.js (fs/promises is not available in browsers). In the browser, use a File or Blob object instead."
|
|
1946
|
+
);
|
|
1947
|
+
}
|
|
1948
|
+
const specifier = "fs/promises";
|
|
1949
|
+
this._fsPromises = await import(
|
|
1950
|
+
/* @vite-ignore */
|
|
1951
|
+
/* webpackIgnore: true */
|
|
1952
|
+
specifier
|
|
1953
|
+
);
|
|
1901
1954
|
}
|
|
1902
1955
|
const stats = await this._fsPromises.stat(this._filePath);
|
|
1903
1956
|
this._size = stats.size;
|
|
@@ -3241,6 +3294,7 @@ var SSEClient = class {
|
|
|
3241
3294
|
this._lastEventId = options.lastEventId;
|
|
3242
3295
|
this.autoReconnect = options.reconnect?.enabled ?? true;
|
|
3243
3296
|
this.externalSignal = options.signal;
|
|
3297
|
+
this.inactivityTimeoutMs = options.inactivityTimeoutMs;
|
|
3244
3298
|
this.eventTypeSet = options.eventTypes?.length ? new Set(options.eventTypes) : null;
|
|
3245
3299
|
this.reconnectManager = new ReconnectManager({
|
|
3246
3300
|
initialDelay: options.reconnect?.initialDelay ?? 1e3,
|
|
@@ -3384,6 +3438,23 @@ var SSEClient = class {
|
|
|
3384
3438
|
if (err.name === "AbortError" || err instanceof RaisinAbortError) {
|
|
3385
3439
|
return;
|
|
3386
3440
|
}
|
|
3441
|
+
if (err instanceof RaisinTimeoutError && err.code === "SSE_INACTIVITY_TIMEOUT") {
|
|
3442
|
+
logger.warn("SSE inactivity timeout:", err.message);
|
|
3443
|
+
if (!this.autoReconnect) {
|
|
3444
|
+
this.setState("disconnected");
|
|
3445
|
+
onError?.(err);
|
|
3446
|
+
throw err;
|
|
3447
|
+
}
|
|
3448
|
+
this.setState("reconnecting");
|
|
3449
|
+
const scheduled2 = await this.waitForReconnect();
|
|
3450
|
+
if (!scheduled2) {
|
|
3451
|
+
logger.warn("SSE max reconnection attempts reached");
|
|
3452
|
+
this.setState("disconnected");
|
|
3453
|
+
onError?.(err);
|
|
3454
|
+
throw err;
|
|
3455
|
+
}
|
|
3456
|
+
continue;
|
|
3457
|
+
}
|
|
3387
3458
|
logger.error("SSE connection error:", err.message);
|
|
3388
3459
|
onError?.(err);
|
|
3389
3460
|
if (!this.autoReconnect) {
|
|
@@ -3432,7 +3503,9 @@ var SSEClient = class {
|
|
|
3432
3503
|
fetchOptions.headers["Content-Type"] = "application/json";
|
|
3433
3504
|
fetchOptions.body = JSON.stringify(this.options.body);
|
|
3434
3505
|
}
|
|
3435
|
-
const response = await this.
|
|
3506
|
+
const response = await this.withInactivityTimeout(
|
|
3507
|
+
this.fetchImpl(this.url, fetchOptions)
|
|
3508
|
+
);
|
|
3436
3509
|
if (!response.ok) {
|
|
3437
3510
|
const text = await response.text().catch(() => "");
|
|
3438
3511
|
const msg = `SSE connection failed: ${response.status} ${response.statusText}${text ? ` - ${text}` : ""}`;
|
|
@@ -3455,7 +3528,7 @@ var SSEClient = class {
|
|
|
3455
3528
|
let buffer = "";
|
|
3456
3529
|
try {
|
|
3457
3530
|
while (true) {
|
|
3458
|
-
const { done, value } = await reader.read();
|
|
3531
|
+
const { done, value } = await this.withInactivityTimeout(reader.read());
|
|
3459
3532
|
if (done) break;
|
|
3460
3533
|
buffer += decoder.decode(value, { stream: true });
|
|
3461
3534
|
const blocks = buffer.split("\n\n");
|
|
@@ -3486,9 +3559,48 @@ var SSEClient = class {
|
|
|
3486
3559
|
}
|
|
3487
3560
|
}
|
|
3488
3561
|
} finally {
|
|
3489
|
-
|
|
3562
|
+
try {
|
|
3563
|
+
reader.releaseLock();
|
|
3564
|
+
} catch {
|
|
3565
|
+
}
|
|
3490
3566
|
}
|
|
3491
3567
|
}
|
|
3568
|
+
/**
|
|
3569
|
+
* Race a stream operation against the inactivity timeout.
|
|
3570
|
+
*
|
|
3571
|
+
* If no bytes (or response) arrive within `inactivityTimeoutMs`, the
|
|
3572
|
+
* internal connection is aborted and the operation rejects with a
|
|
3573
|
+
* `RaisinTimeoutError` (code `SSE_INACTIVITY_TIMEOUT`). The timer is
|
|
3574
|
+
* effectively reset on every chunk because each `reader.read()` is
|
|
3575
|
+
* wrapped individually.
|
|
3576
|
+
*/
|
|
3577
|
+
withInactivityTimeout(promise) {
|
|
3578
|
+
const timeoutMs = this.inactivityTimeoutMs;
|
|
3579
|
+
if (!timeoutMs || timeoutMs <= 0) return promise;
|
|
3580
|
+
return new Promise((resolve, reject) => {
|
|
3581
|
+
const timer = setTimeout(() => {
|
|
3582
|
+
promise.catch(() => void 0);
|
|
3583
|
+
this.abortController?.abort();
|
|
3584
|
+
reject(
|
|
3585
|
+
new RaisinTimeoutError(
|
|
3586
|
+
`SSE stream inactive for ${timeoutMs}ms`,
|
|
3587
|
+
"SSE_INACTIVITY_TIMEOUT",
|
|
3588
|
+
timeoutMs
|
|
3589
|
+
)
|
|
3590
|
+
);
|
|
3591
|
+
}, timeoutMs);
|
|
3592
|
+
promise.then(
|
|
3593
|
+
(value) => {
|
|
3594
|
+
clearTimeout(timer);
|
|
3595
|
+
resolve(value);
|
|
3596
|
+
},
|
|
3597
|
+
(error) => {
|
|
3598
|
+
clearTimeout(timer);
|
|
3599
|
+
reject(error);
|
|
3600
|
+
}
|
|
3601
|
+
);
|
|
3602
|
+
});
|
|
3603
|
+
}
|
|
3492
3604
|
/**
|
|
3493
3605
|
* Wait for the reconnect manager to schedule a reconnection attempt.
|
|
3494
3606
|
* Returns true if reconnection was scheduled, false if max attempts reached.
|
|
@@ -3513,7 +3625,24 @@ function isRecoveredDoneEvent(event) {
|
|
|
3513
3625
|
return typeof done.content !== "string" || done.content.trim().length === 0;
|
|
3514
3626
|
}
|
|
3515
3627
|
|
|
3628
|
+
// src/utils/home-path.ts
|
|
3629
|
+
var ACCESS_CONTROL_PREFIX = "/raisin:access_control";
|
|
3630
|
+
function normalizeHomePath(home) {
|
|
3631
|
+
if (home === null || home === void 0) return null;
|
|
3632
|
+
let path = home.trim();
|
|
3633
|
+
if (path.length === 0) return null;
|
|
3634
|
+
if (path === ACCESS_CONTROL_PREFIX) return "/";
|
|
3635
|
+
if (path.startsWith(`${ACCESS_CONTROL_PREFIX}/`)) {
|
|
3636
|
+
path = path.slice(ACCESS_CONTROL_PREFIX.length);
|
|
3637
|
+
}
|
|
3638
|
+
while (path.length > 1 && path.endsWith("/")) {
|
|
3639
|
+
path = path.slice(0, -1);
|
|
3640
|
+
}
|
|
3641
|
+
return path;
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3516
3644
|
// src/conversations.ts
|
|
3645
|
+
var DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS = 12e4;
|
|
3517
3646
|
var ConversationManager = class {
|
|
3518
3647
|
constructor(baseUrl, repository, authManager, options = {}, executeSql) {
|
|
3519
3648
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
@@ -3535,10 +3664,11 @@ var ConversationManager = class {
|
|
|
3535
3664
|
);
|
|
3536
3665
|
if (!result?.rows?.[0]) throw new Error("User not authenticated");
|
|
3537
3666
|
const row = result.rows[0];
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3667
|
+
const userHome = normalizeHomePath(row.home);
|
|
3668
|
+
if (!userHome) throw new Error("User home path not found");
|
|
3669
|
+
this.cachedUserHome = userHome;
|
|
3670
|
+
this.cachedUserId = row.user_id || userHome;
|
|
3671
|
+
return { userId: this.cachedUserId, userHome };
|
|
3542
3672
|
}
|
|
3543
3673
|
// ==========================================================================
|
|
3544
3674
|
// Conversation listing
|
|
@@ -3733,13 +3863,15 @@ var ConversationManager = class {
|
|
|
3733
3863
|
fetch: this.fetchImpl,
|
|
3734
3864
|
signal: options?.signal,
|
|
3735
3865
|
method: "POST",
|
|
3736
|
-
body: { channel: streamTarget.channel, path: streamTarget.path }
|
|
3866
|
+
body: { channel: streamTarget.channel, path: streamTarget.path },
|
|
3867
|
+
inactivityTimeoutMs: options?.inactivityTimeoutMs ?? DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS
|
|
3737
3868
|
});
|
|
3738
3869
|
const iterator = sse[Symbol.asyncIterator]();
|
|
3739
3870
|
let pendingFirst = iterator.next();
|
|
3740
3871
|
try {
|
|
3741
3872
|
await sse.waitUntilConnected();
|
|
3742
3873
|
} catch {
|
|
3874
|
+
pendingFirst?.catch(() => void 0);
|
|
3743
3875
|
pendingFirst = null;
|
|
3744
3876
|
sse.close();
|
|
3745
3877
|
logger.debug("SSE connection failed, falling back to create-only");
|
|
@@ -3776,6 +3908,15 @@ var ConversationManager = class {
|
|
|
3776
3908
|
return;
|
|
3777
3909
|
}
|
|
3778
3910
|
}
|
|
3911
|
+
} catch (error) {
|
|
3912
|
+
if (error instanceof RaisinTimeoutError && error.code === "SSE_INACTIVITY_TIMEOUT") {
|
|
3913
|
+
logger.warn(
|
|
3914
|
+
`[ConversationManager] SSE stream inactive for ${error.timeoutMs}ms, ending turn with synthetic waiting event`
|
|
3915
|
+
);
|
|
3916
|
+
yield { type: "waiting", timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
3917
|
+
return;
|
|
3918
|
+
}
|
|
3919
|
+
throw error;
|
|
3779
3920
|
} finally {
|
|
3780
3921
|
sse.close();
|
|
3781
3922
|
}
|
|
@@ -4538,31 +4679,29 @@ var FlowClient = class _FlowClient {
|
|
|
4538
4679
|
* Respond to a human task within a flow.
|
|
4539
4680
|
*
|
|
4540
4681
|
* When a flow is waiting on a human_task step (approval, input, review),
|
|
4541
|
-
* use this method to submit the response
|
|
4682
|
+
* use this method to submit the response. Completion is validated
|
|
4683
|
+
* (caller must be the task's assignee or an admin) and resumes the flow.
|
|
4542
4684
|
*
|
|
4543
|
-
*
|
|
4544
|
-
*
|
|
4545
|
-
*
|
|
4685
|
+
* Note: prefer `InboxApi` for full inbox functionality (listing tasks,
|
|
4686
|
+
* task details); this is a convenience passthrough to the same endpoint.
|
|
4687
|
+
*
|
|
4688
|
+
* @param instanceId - Flow instance ID (unused; kept for API stability)
|
|
4689
|
+
* @param taskId - The inbox task node ID (or path)
|
|
4690
|
+
* @param response - The response data
|
|
4546
4691
|
*
|
|
4547
4692
|
* @example
|
|
4548
4693
|
* ```typescript
|
|
4549
4694
|
* // Approve a task
|
|
4550
|
-
* await flows.respondToHumanTask('instance-123', '
|
|
4695
|
+
* await flows.respondToHumanTask('instance-123', 'task-abc', {
|
|
4551
4696
|
* action: 'approve',
|
|
4552
4697
|
* comment: 'Looks good!',
|
|
4553
4698
|
* });
|
|
4554
|
-
*
|
|
4555
|
-
* // Provide input for an input task
|
|
4556
|
-
* await flows.respondToHumanTask('instance-123', 'step-3', {
|
|
4557
|
-
* name: 'John Doe',
|
|
4558
|
-
* email: 'john@example.com',
|
|
4559
|
-
* });
|
|
4560
4699
|
* ```
|
|
4561
4700
|
*/
|
|
4562
|
-
async respondToHumanTask(
|
|
4701
|
+
async respondToHumanTask(_instanceId, taskId, response, options) {
|
|
4563
4702
|
await this.request({
|
|
4564
4703
|
method: "POST",
|
|
4565
|
-
path: `/api/
|
|
4704
|
+
path: `/api/inbox/${this.repository}/tasks/${encodeURIComponent(taskId)}/complete`,
|
|
4566
4705
|
body: { response },
|
|
4567
4706
|
signal: options?.signal
|
|
4568
4707
|
});
|
|
@@ -4701,6 +4840,134 @@ var FlowClient = class _FlowClient {
|
|
|
4701
4840
|
}
|
|
4702
4841
|
};
|
|
4703
4842
|
|
|
4843
|
+
// src/inbox.ts
|
|
4844
|
+
var InboxApi = class {
|
|
4845
|
+
constructor(baseUrl, repository, authManager, options = {}) {
|
|
4846
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
4847
|
+
this.repository = repository;
|
|
4848
|
+
this.authManager = authManager;
|
|
4849
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
4850
|
+
this.requestTimeout = options.requestTimeout ?? 3e4;
|
|
4851
|
+
}
|
|
4852
|
+
/**
|
|
4853
|
+
* List the caller's inbox tasks.
|
|
4854
|
+
*
|
|
4855
|
+
* Tasks are sorted pending-first, then by priority (highest first) and
|
|
4856
|
+
* due time (earliest first).
|
|
4857
|
+
*/
|
|
4858
|
+
async listTasks(options = {}) {
|
|
4859
|
+
const params = new URLSearchParams();
|
|
4860
|
+
if (options.status) params.set("status", options.status);
|
|
4861
|
+
if (options.assignee) params.set("assignee", options.assignee);
|
|
4862
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
4863
|
+
return this.request({
|
|
4864
|
+
method: "GET",
|
|
4865
|
+
path: `/api/inbox/${this.repository}${query}`,
|
|
4866
|
+
signal: options.signal
|
|
4867
|
+
});
|
|
4868
|
+
}
|
|
4869
|
+
/**
|
|
4870
|
+
* Get a single inbox task by ID (or path).
|
|
4871
|
+
*/
|
|
4872
|
+
async getTask(taskId, options) {
|
|
4873
|
+
return this.request({
|
|
4874
|
+
method: "GET",
|
|
4875
|
+
path: `/api/inbox/${this.repository}/tasks/${encodeURIComponent(taskId)}`,
|
|
4876
|
+
signal: options?.signal
|
|
4877
|
+
});
|
|
4878
|
+
}
|
|
4879
|
+
/**
|
|
4880
|
+
* Complete an inbox task.
|
|
4881
|
+
*
|
|
4882
|
+
* The caller must be the task's assignee (or an admin). Completion marks
|
|
4883
|
+
* the task done, records who decided, and resumes the owning flow.
|
|
4884
|
+
*
|
|
4885
|
+
* @param taskId - Task node ID (or path)
|
|
4886
|
+
* @param response - The response payload:
|
|
4887
|
+
* - approval tasks: `{ action: '<option value>', comment?: string }`
|
|
4888
|
+
* - input tasks: the input value(s) matching the task's input_schema
|
|
4889
|
+
* - review/action tasks: any acknowledgement payload
|
|
4890
|
+
*
|
|
4891
|
+
* @example
|
|
4892
|
+
* ```typescript
|
|
4893
|
+
* await inbox.completeTask('task-123', { action: 'approve' });
|
|
4894
|
+
* ```
|
|
4895
|
+
*/
|
|
4896
|
+
async completeTask(taskId, response, options) {
|
|
4897
|
+
return this.request({
|
|
4898
|
+
method: "POST",
|
|
4899
|
+
path: `/api/inbox/${this.repository}/tasks/${encodeURIComponent(taskId)}/complete`,
|
|
4900
|
+
body: { response },
|
|
4901
|
+
signal: options?.signal
|
|
4902
|
+
});
|
|
4903
|
+
}
|
|
4904
|
+
// ==========================================================================
|
|
4905
|
+
// Internal HTTP request helper
|
|
4906
|
+
// ==========================================================================
|
|
4907
|
+
async request(options) {
|
|
4908
|
+
const url = `${this.baseUrl}${options.path}`;
|
|
4909
|
+
const headers = {
|
|
4910
|
+
"Content-Type": "application/json"
|
|
4911
|
+
};
|
|
4912
|
+
const token = this.authManager.getAccessToken();
|
|
4913
|
+
if (token) {
|
|
4914
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
4915
|
+
}
|
|
4916
|
+
const controller = new AbortController();
|
|
4917
|
+
const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);
|
|
4918
|
+
if (options.signal) {
|
|
4919
|
+
if (options.signal.aborted) {
|
|
4920
|
+
clearTimeout(timeoutId);
|
|
4921
|
+
throw new RaisinAbortError();
|
|
4922
|
+
}
|
|
4923
|
+
options.signal.addEventListener("abort", () => controller.abort(), {
|
|
4924
|
+
once: true
|
|
4925
|
+
});
|
|
4926
|
+
}
|
|
4927
|
+
try {
|
|
4928
|
+
const response = await this.fetchImpl(url, {
|
|
4929
|
+
method: options.method,
|
|
4930
|
+
headers,
|
|
4931
|
+
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
4932
|
+
signal: controller.signal
|
|
4933
|
+
});
|
|
4934
|
+
clearTimeout(timeoutId);
|
|
4935
|
+
if (!response.ok) {
|
|
4936
|
+
const errorText = await response.text();
|
|
4937
|
+
let errorMessage;
|
|
4938
|
+
try {
|
|
4939
|
+
const errorJson = JSON.parse(errorText);
|
|
4940
|
+
errorMessage = errorJson.message || errorJson.error || errorText;
|
|
4941
|
+
} catch {
|
|
4942
|
+
errorMessage = errorText || `HTTP ${response.status}: ${response.statusText}`;
|
|
4943
|
+
}
|
|
4944
|
+
throw classifyHttpError(response.status, errorMessage);
|
|
4945
|
+
}
|
|
4946
|
+
const contentType = response.headers.get("content-type");
|
|
4947
|
+
if (contentType?.includes("application/json")) {
|
|
4948
|
+
return await response.json();
|
|
4949
|
+
}
|
|
4950
|
+
return void 0;
|
|
4951
|
+
} catch (error) {
|
|
4952
|
+
clearTimeout(timeoutId);
|
|
4953
|
+
if (error instanceof RaisinAbortError || error instanceof RaisinTimeoutError) {
|
|
4954
|
+
throw error;
|
|
4955
|
+
}
|
|
4956
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
4957
|
+
if (options.signal?.aborted) {
|
|
4958
|
+
throw new RaisinAbortError();
|
|
4959
|
+
}
|
|
4960
|
+
throw new RaisinTimeoutError(
|
|
4961
|
+
`Request timeout after ${this.requestTimeout}ms`,
|
|
4962
|
+
"REQUEST_TIMEOUT",
|
|
4963
|
+
this.requestTimeout
|
|
4964
|
+
);
|
|
4965
|
+
}
|
|
4966
|
+
throw error;
|
|
4967
|
+
}
|
|
4968
|
+
}
|
|
4969
|
+
};
|
|
4970
|
+
|
|
4704
4971
|
// src/database.ts
|
|
4705
4972
|
var Database = class _Database {
|
|
4706
4973
|
constructor(repository, context, sendRequest, eventHandler, branch, revision, getUploadManager, getSignAssetUrl, httpOptions) {
|
|
@@ -4977,8 +5244,44 @@ var Database = class _Database {
|
|
|
4977
5244
|
}
|
|
4978
5245
|
return this._flowClient;
|
|
4979
5246
|
}
|
|
5247
|
+
/**
|
|
5248
|
+
* Get a pre-configured InboxApi for human-in-the-loop tasks.
|
|
5249
|
+
*
|
|
5250
|
+
* Requires the Database to have been created via `RaisinClient.database()`
|
|
5251
|
+
* (which automatically provides HTTP context).
|
|
5252
|
+
*
|
|
5253
|
+
* @example
|
|
5254
|
+
* ```typescript
|
|
5255
|
+
* const db = client.database('my-repo');
|
|
5256
|
+
* const { tasks } = await db.inbox.listTasks({ status: 'pending' });
|
|
5257
|
+
* await db.inbox.completeTask(tasks[0].id, { action: 'approve' });
|
|
5258
|
+
* ```
|
|
5259
|
+
*/
|
|
5260
|
+
get inbox() {
|
|
5261
|
+
if (!this._inboxApi) {
|
|
5262
|
+
if (!this.httpOptions?.httpBaseUrl || !this.httpOptions?.authManager) {
|
|
5263
|
+
throw new Error(
|
|
5264
|
+
"db.inbox requires HTTP context. Use client.database() to get a Database with inbox support."
|
|
5265
|
+
);
|
|
5266
|
+
}
|
|
5267
|
+
this._inboxApi = new InboxApi(
|
|
5268
|
+
this.httpOptions.httpBaseUrl,
|
|
5269
|
+
this.repository,
|
|
5270
|
+
this.httpOptions.authManager
|
|
5271
|
+
);
|
|
5272
|
+
}
|
|
5273
|
+
return this._inboxApi;
|
|
5274
|
+
}
|
|
4980
5275
|
/**
|
|
4981
5276
|
* Get EventHandler for subscribing to real-time events
|
|
5277
|
+
*
|
|
5278
|
+
* Path filter semantics for subscriptions (matched server-side):
|
|
5279
|
+
* - A plain path matches **only that exact node** — there is no implicit
|
|
5280
|
+
* prefix matching.
|
|
5281
|
+
* - `*` matches exactly one path segment (`/inbox/*` matches `/inbox/a`,
|
|
5282
|
+
* not `/inbox/a/b`).
|
|
5283
|
+
* - `**` matches recursively (`/inbox/**` matches all descendants of
|
|
5284
|
+
* `/inbox`, but not `/inbox` itself).
|
|
4982
5285
|
*/
|
|
4983
5286
|
events() {
|
|
4984
5287
|
return this.eventHandler;
|
|
@@ -6306,9 +6609,13 @@ var RaisinHttpClient = class extends import_events3.EventEmitter {
|
|
|
6306
6609
|
body: payload,
|
|
6307
6610
|
skipAuth: true
|
|
6308
6611
|
});
|
|
6309
|
-
|
|
6612
|
+
if (response.data.token) {
|
|
6613
|
+
this.authManager.storage.setAccessToken(response.data.token);
|
|
6614
|
+
} else {
|
|
6615
|
+
this.authManager.setTokens(response.data);
|
|
6616
|
+
}
|
|
6310
6617
|
this._currentUser = {
|
|
6311
|
-
userId: "admin",
|
|
6618
|
+
userId: response.data.user_id ?? "admin",
|
|
6312
6619
|
anonymous: false
|
|
6313
6620
|
};
|
|
6314
6621
|
this.emit("authenticated", response.data);
|
|
@@ -7196,7 +7503,7 @@ var HttpWorkspaceClient = class {
|
|
|
7196
7503
|
};
|
|
7197
7504
|
|
|
7198
7505
|
// src/client.ts
|
|
7199
|
-
var
|
|
7506
|
+
var _RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
7200
7507
|
constructor(url, options = {}) {
|
|
7201
7508
|
super();
|
|
7202
7509
|
this._currentUser = null;
|
|
@@ -7210,23 +7517,41 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7210
7517
|
// Reconnection tracking
|
|
7211
7518
|
this._previousConnectionState = "disconnected" /* Disconnected */;
|
|
7212
7519
|
this._reconnectedListeners = /* @__PURE__ */ new Set();
|
|
7520
|
+
this._everConnected = false;
|
|
7521
|
+
// Requests queued while the connection is re-establishing.
|
|
7522
|
+
// Flushed after reconnect + re-auth; bounded by MAX_QUEUED_REQUESTS.
|
|
7523
|
+
this._queuedRequests = [];
|
|
7524
|
+
/**
|
|
7525
|
+
* Backoff delays (ms) between subscription-restore retries after reconnect.
|
|
7526
|
+
* @internal - overridable in tests
|
|
7527
|
+
*/
|
|
7528
|
+
this._restoreRetryDelaysMs = [1e3, 3e3, 9e3];
|
|
7213
7529
|
// Upload manager (uses HTTP under the hood)
|
|
7214
7530
|
this._uploadManager = null;
|
|
7215
7531
|
if (options.logLevel !== void 0) {
|
|
7216
7532
|
setLogLevel(options.logLevel);
|
|
7217
7533
|
}
|
|
7534
|
+
const connectionUrl = this.buildConnectionUrl(url, options.repository);
|
|
7218
7535
|
this.options = {
|
|
7219
7536
|
requestTimeout: options.requestTimeout ?? 3e4,
|
|
7220
|
-
tenantId: options.tenantId ?? this.extractTenantFromUrl(
|
|
7537
|
+
tenantId: options.tenantId ?? this.extractTenantFromUrl(connectionUrl),
|
|
7221
7538
|
defaultBranch: options.defaultBranch ?? "main"
|
|
7222
7539
|
};
|
|
7223
|
-
this._httpBaseUrl = options.httpBaseUrl ?? this.deriveHttpUrl(
|
|
7224
|
-
this._repository = this.extractRepositoryFromUrl(
|
|
7540
|
+
this._httpBaseUrl = options.httpBaseUrl ?? this.deriveHttpUrl(connectionUrl);
|
|
7541
|
+
this._repository = options.repository ?? this.extractRepositoryFromUrl(connectionUrl);
|
|
7225
7542
|
this._context = {
|
|
7226
7543
|
tenant_id: this.options.tenantId,
|
|
7227
7544
|
branch: this.options.defaultBranch
|
|
7228
7545
|
};
|
|
7229
|
-
|
|
7546
|
+
const explicitTenant = options.tenantId ?? (this.extractTenantFromUrl(url) !== "default" ? this.options.tenantId : void 0);
|
|
7547
|
+
const connectionOptions = {
|
|
7548
|
+
...options.connection,
|
|
7549
|
+
headers: {
|
|
7550
|
+
...explicitTenant ? { "x-tenant-id": explicitTenant } : {},
|
|
7551
|
+
...options.connection?.headers
|
|
7552
|
+
}
|
|
7553
|
+
};
|
|
7554
|
+
this.connection = this.createConnection(connectionUrl, connectionOptions);
|
|
7230
7555
|
this.requestTracker = new RequestTracker({
|
|
7231
7556
|
defaultTimeout: this.options.requestTimeout
|
|
7232
7557
|
});
|
|
@@ -7236,6 +7561,14 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7236
7561
|
);
|
|
7237
7562
|
this.setupConnectionHandlers();
|
|
7238
7563
|
}
|
|
7564
|
+
/**
|
|
7565
|
+
* Create the underlying WebSocket connection.
|
|
7566
|
+
* Seam for tests to inject a fake connection.
|
|
7567
|
+
* @internal
|
|
7568
|
+
*/
|
|
7569
|
+
createConnection(url, options) {
|
|
7570
|
+
return new Connection(url, options);
|
|
7571
|
+
}
|
|
7239
7572
|
/**
|
|
7240
7573
|
* Derive HTTP URL from WebSocket URL
|
|
7241
7574
|
* ws://host:port/path -> http://host:port
|
|
@@ -7251,15 +7584,45 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7251
7584
|
return "http://localhost:8081";
|
|
7252
7585
|
}
|
|
7253
7586
|
}
|
|
7587
|
+
/**
|
|
7588
|
+
* Build the WebSocket connection URL.
|
|
7589
|
+
*
|
|
7590
|
+
* When a repository option is provided and the URL carries no path
|
|
7591
|
+
* (e.g. `ws://host:8081`), build the tenant-less `/ws/{repository}`
|
|
7592
|
+
* route internally. URLs that already carry a path are used as-is.
|
|
7593
|
+
*/
|
|
7594
|
+
buildConnectionUrl(url, repository) {
|
|
7595
|
+
if (!repository) {
|
|
7596
|
+
return url;
|
|
7597
|
+
}
|
|
7598
|
+
try {
|
|
7599
|
+
const wsUrl = url.replace(/^raisin:\/\//, "ws://").replace(/^raisins:\/\//, "wss://");
|
|
7600
|
+
const parsed = new URL(wsUrl);
|
|
7601
|
+
const hasPath = parsed.pathname.split("/").some((p) => p.length > 0);
|
|
7602
|
+
if (hasPath) {
|
|
7603
|
+
return url;
|
|
7604
|
+
}
|
|
7605
|
+
return `${url.replace(/\/+$/, "")}/ws/${repository}`;
|
|
7606
|
+
} catch {
|
|
7607
|
+
return url;
|
|
7608
|
+
}
|
|
7609
|
+
}
|
|
7254
7610
|
/**
|
|
7255
7611
|
* Extract repository from URL
|
|
7256
|
-
* URL
|
|
7612
|
+
* URL forms: /ws/{repo} (tenant-less, preferred), /sys/{tenant}/{repo}
|
|
7613
|
+
* (operator/multi-tenant), /{tenant}/{repo} (legacy).
|
|
7257
7614
|
*/
|
|
7258
7615
|
extractRepositoryFromUrl(url) {
|
|
7259
7616
|
try {
|
|
7260
7617
|
const wsUrl = url.replace(/^raisin:\/\//, "ws://").replace(/^raisins:\/\//, "wss://");
|
|
7261
7618
|
const parsed = new URL(wsUrl);
|
|
7262
7619
|
const parts = parsed.pathname.split("/").filter((p) => p.length > 0);
|
|
7620
|
+
if (parts[0] === "ws") {
|
|
7621
|
+
return parts.length > 1 ? parts[1] : "";
|
|
7622
|
+
}
|
|
7623
|
+
if (parts[0] === "sys") {
|
|
7624
|
+
return parts.length > 2 ? parts[2] : "";
|
|
7625
|
+
}
|
|
7263
7626
|
return parts.length > 1 ? parts[1] : "";
|
|
7264
7627
|
} catch {
|
|
7265
7628
|
return "";
|
|
@@ -7267,14 +7630,24 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7267
7630
|
}
|
|
7268
7631
|
/**
|
|
7269
7632
|
* Extract tenant ID from URL
|
|
7270
|
-
* URL
|
|
7633
|
+
* URL forms: /ws/{repo} (tenant-less — no tenant in URL),
|
|
7634
|
+
* /sys/{tenant}/{repo} (canonical), /{tenant}/{repo} (legacy).
|
|
7635
|
+
* When the URL doesn't carry a tenant, fall back to 'default' — the
|
|
7636
|
+
* server's tenant middleware resolves it anyway (production derives the
|
|
7637
|
+
* tenant from the request itself), so an explicit tenantId is optional.
|
|
7271
7638
|
*/
|
|
7272
7639
|
extractTenantFromUrl(url) {
|
|
7273
7640
|
try {
|
|
7274
7641
|
const wsUrl = url.replace(/^raisin:\/\//, "ws://").replace(/^raisins:\/\//, "wss://");
|
|
7275
7642
|
const parsed = new URL(wsUrl);
|
|
7276
7643
|
const parts = parsed.pathname.split("/").filter((p) => p.length > 0);
|
|
7277
|
-
|
|
7644
|
+
if (parts[0] === "ws") {
|
|
7645
|
+
return "default";
|
|
7646
|
+
}
|
|
7647
|
+
if (parts[0] === "sys") {
|
|
7648
|
+
return parts.length > 1 ? parts[1] : "default";
|
|
7649
|
+
}
|
|
7650
|
+
return parts.length >= 2 ? parts[0] : "default";
|
|
7278
7651
|
} catch (error) {
|
|
7279
7652
|
return "default";
|
|
7280
7653
|
}
|
|
@@ -7288,7 +7661,11 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7288
7661
|
});
|
|
7289
7662
|
this.connection.on("stateChange", (state) => {
|
|
7290
7663
|
const wasDisconnected = this._previousConnectionState === "disconnected" /* Disconnected */ || this._previousConnectionState === "reconnecting" /* Reconnecting */;
|
|
7664
|
+
if (state === "connected" /* Connected */) {
|
|
7665
|
+
this._everConnected = true;
|
|
7666
|
+
}
|
|
7291
7667
|
if (state === "disconnected" /* Disconnected */ || state === "closed" /* Closed */) {
|
|
7668
|
+
this._queuedRequests = [];
|
|
7292
7669
|
this.requestTracker.cancelAll();
|
|
7293
7670
|
}
|
|
7294
7671
|
if (state === "connected" /* Connected */ && wasDisconnected && this._previousConnectionState !== "disconnected" /* Disconnected */) {
|
|
@@ -7353,19 +7730,36 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7353
7730
|
};
|
|
7354
7731
|
logger.debug(`Anonymous user info stored: ${message.user_id}`);
|
|
7355
7732
|
this._updateReadyState();
|
|
7733
|
+
this._flushQueuedRequests();
|
|
7356
7734
|
if (hasActiveSubscriptions) {
|
|
7357
7735
|
this._restoreSubscriptionsAndNotify();
|
|
7358
7736
|
}
|
|
7359
7737
|
} else {
|
|
7360
7738
|
logger.info(`[handleConnectedMessage] Stored token found, auto-authenticating...`);
|
|
7361
|
-
this.autoReauthenticate().then(async () => {
|
|
7739
|
+
this.autoReauthenticate().then(async (authenticated) => {
|
|
7740
|
+
if (authenticated) {
|
|
7741
|
+
this._flushQueuedRequests();
|
|
7742
|
+
} else {
|
|
7743
|
+
this._rejectQueuedRequests(
|
|
7744
|
+
new RaisinAuthError(
|
|
7745
|
+
"Re-authentication failed after reconnect",
|
|
7746
|
+
"AUTH_TOKEN_EXPIRED",
|
|
7747
|
+
401
|
|
7748
|
+
)
|
|
7749
|
+
);
|
|
7750
|
+
}
|
|
7362
7751
|
if (hasActiveSubscriptions) {
|
|
7363
7752
|
await this._restoreSubscriptionsAndNotify();
|
|
7364
7753
|
}
|
|
7365
7754
|
}).catch((err) => {
|
|
7366
7755
|
logger.error(`[handleConnectedMessage] Auto-authenticate failed:`, err);
|
|
7756
|
+
this._rejectQueuedRequests(
|
|
7757
|
+
err instanceof Error ? err : new Error("Re-authentication failed after reconnect")
|
|
7758
|
+
);
|
|
7367
7759
|
});
|
|
7368
7760
|
}
|
|
7761
|
+
} else {
|
|
7762
|
+
this._flushQueuedRequests();
|
|
7369
7763
|
}
|
|
7370
7764
|
this.emit("connected", {
|
|
7371
7765
|
connectionId: message.connection_id,
|
|
@@ -7374,18 +7768,41 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7374
7768
|
});
|
|
7375
7769
|
}
|
|
7376
7770
|
/**
|
|
7377
|
-
* Restore subscriptions after reconnection and notify listeners
|
|
7771
|
+
* Restore subscriptions after reconnection and notify listeners.
|
|
7772
|
+
*
|
|
7773
|
+
* Retries with backoff (see `_restoreRetryDelaysMs`); on final failure a
|
|
7774
|
+
* `subscription_restore_failed` event is emitted so applications can
|
|
7775
|
+
* resync their state (e.g. reload lists and re-subscribe manually).
|
|
7378
7776
|
* @internal
|
|
7379
7777
|
*/
|
|
7380
7778
|
async _restoreSubscriptionsAndNotify() {
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7779
|
+
const delays = this._restoreRetryDelaysMs;
|
|
7780
|
+
let lastError;
|
|
7781
|
+
for (let attempt = 0; attempt <= delays.length; attempt++) {
|
|
7782
|
+
try {
|
|
7783
|
+
logger.info(
|
|
7784
|
+
`[_restoreSubscriptionsAndNotify] Restoring subscriptions (attempt ${attempt + 1}/${delays.length + 1})...`
|
|
7785
|
+
);
|
|
7786
|
+
await this.eventHandler.restoreSubscriptions({ retry: attempt > 0 });
|
|
7787
|
+
logger.info("[_restoreSubscriptionsAndNotify] Subscriptions restored successfully");
|
|
7788
|
+
this._emitReconnected();
|
|
7789
|
+
return;
|
|
7790
|
+
} catch (error) {
|
|
7791
|
+
lastError = error;
|
|
7792
|
+
logger.error(
|
|
7793
|
+
`[_restoreSubscriptionsAndNotify] Restore attempt ${attempt + 1} failed:`,
|
|
7794
|
+
error
|
|
7795
|
+
);
|
|
7796
|
+
if (attempt < delays.length) {
|
|
7797
|
+
await new Promise((resolve) => setTimeout(resolve, delays[attempt]));
|
|
7798
|
+
}
|
|
7799
|
+
}
|
|
7388
7800
|
}
|
|
7801
|
+
logger.error("[_restoreSubscriptionsAndNotify] Giving up after retries; events may be stale");
|
|
7802
|
+
this.emit(
|
|
7803
|
+
"subscription_restore_failed",
|
|
7804
|
+
lastError instanceof Error ? lastError : new Error(String(lastError))
|
|
7805
|
+
);
|
|
7389
7806
|
}
|
|
7390
7807
|
/**
|
|
7391
7808
|
* Emit reconnected event to all listeners
|
|
@@ -7404,13 +7821,15 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7404
7821
|
}
|
|
7405
7822
|
/**
|
|
7406
7823
|
* Auto-reauthenticate with stored JWT on reconnection
|
|
7824
|
+
*
|
|
7825
|
+
* @returns true if the session was re-authenticated, false otherwise
|
|
7407
7826
|
* @internal
|
|
7408
7827
|
*/
|
|
7409
7828
|
async autoReauthenticate() {
|
|
7410
7829
|
const token = this.authManager.storage.getAccessToken();
|
|
7411
7830
|
if (!token) {
|
|
7412
7831
|
logger.warn("[autoReauthenticate] No stored token");
|
|
7413
|
-
return;
|
|
7832
|
+
return false;
|
|
7414
7833
|
}
|
|
7415
7834
|
const payload = AuthManager.parseToken(token);
|
|
7416
7835
|
if (payload?.exp && typeof payload.exp === "number") {
|
|
@@ -7422,18 +7841,20 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7422
7841
|
this.authManager.clear();
|
|
7423
7842
|
this._currentUser = null;
|
|
7424
7843
|
this._emitAuthEvent("SESSION_EXPIRED");
|
|
7425
|
-
return;
|
|
7844
|
+
return false;
|
|
7426
7845
|
}
|
|
7427
7846
|
const newToken = this.authManager.storage.getAccessToken();
|
|
7428
7847
|
if (newToken) {
|
|
7429
7848
|
await this.authenticate({ type: "jwt", token: newToken });
|
|
7849
|
+
return true;
|
|
7430
7850
|
}
|
|
7431
|
-
return;
|
|
7851
|
+
return false;
|
|
7432
7852
|
}
|
|
7433
7853
|
}
|
|
7434
7854
|
try {
|
|
7435
7855
|
await this.authenticate({ type: "jwt", token });
|
|
7436
7856
|
logger.info("[autoReauthenticate] Successfully re-authenticated");
|
|
7857
|
+
return true;
|
|
7437
7858
|
} catch (err) {
|
|
7438
7859
|
logger.error("[autoReauthenticate] Failed to authenticate:", err);
|
|
7439
7860
|
const refreshed = await this.refreshToken();
|
|
@@ -7441,11 +7862,14 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7441
7862
|
const newToken = this.authManager.storage.getAccessToken();
|
|
7442
7863
|
if (newToken) {
|
|
7443
7864
|
await this.authenticate({ type: "jwt", token: newToken });
|
|
7865
|
+
return true;
|
|
7444
7866
|
}
|
|
7867
|
+
return false;
|
|
7445
7868
|
} else {
|
|
7446
7869
|
this.authManager.clear();
|
|
7447
7870
|
this._currentUser = null;
|
|
7448
7871
|
this._emitAuthEvent("SESSION_EXPIRED");
|
|
7872
|
+
return false;
|
|
7449
7873
|
}
|
|
7450
7874
|
}
|
|
7451
7875
|
}
|
|
@@ -7561,18 +7985,18 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7561
7985
|
}
|
|
7562
7986
|
const url = `${this._httpBaseUrl}/auth/${repository}/login`;
|
|
7563
7987
|
logger.debug("[loginWithEmail] POST", url);
|
|
7564
|
-
const response = await
|
|
7988
|
+
const response = await this._fetchWithTimeout(url, {
|
|
7565
7989
|
method: "POST",
|
|
7566
7990
|
headers: { "Content-Type": "application/json" },
|
|
7567
7991
|
body: JSON.stringify({ email, password })
|
|
7568
7992
|
});
|
|
7569
7993
|
if (!response.ok) {
|
|
7570
7994
|
const error = await response.json().catch(() => ({ message: response.statusText }));
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7995
|
+
throw new RaisinAuthError(
|
|
7996
|
+
error.message || "Login failed",
|
|
7997
|
+
error.code || "LOGIN_FAILED",
|
|
7998
|
+
response.status
|
|
7999
|
+
);
|
|
7576
8000
|
}
|
|
7577
8001
|
const tokens = await response.json();
|
|
7578
8002
|
logger.info("[loginWithEmail] HTTP login successful, user_id:", tokens.identity.id);
|
|
@@ -7605,7 +8029,7 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7605
8029
|
anonymous: false,
|
|
7606
8030
|
node: userNode ?? void 0
|
|
7607
8031
|
};
|
|
7608
|
-
const expiresInMs = tokens.expires_at
|
|
8032
|
+
const expiresInMs = _RaisinClient.expiresAtToMs(tokens.expires_at) - Date.now() - 5 * 60 * 1e3;
|
|
7609
8033
|
if (expiresInMs > 0) {
|
|
7610
8034
|
this.scheduleAutoRefresh(expiresInMs);
|
|
7611
8035
|
}
|
|
@@ -7629,18 +8053,18 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7629
8053
|
async registerWithEmail(email, password, repository, displayName) {
|
|
7630
8054
|
logger.info("[registerWithEmail] Starting registration...");
|
|
7631
8055
|
const url = `${this._httpBaseUrl}/auth/${repository}/register`;
|
|
7632
|
-
const response = await
|
|
8056
|
+
const response = await this._fetchWithTimeout(url, {
|
|
7633
8057
|
method: "POST",
|
|
7634
8058
|
headers: { "Content-Type": "application/json" },
|
|
7635
8059
|
body: JSON.stringify({ email, password, display_name: displayName })
|
|
7636
8060
|
});
|
|
7637
8061
|
if (!response.ok) {
|
|
7638
8062
|
const error = await response.json().catch(() => ({ message: response.statusText }));
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
8063
|
+
throw new RaisinAuthError(
|
|
8064
|
+
error.message || "Registration failed",
|
|
8065
|
+
error.code || "REGISTRATION_FAILED",
|
|
8066
|
+
response.status
|
|
8067
|
+
);
|
|
7644
8068
|
}
|
|
7645
8069
|
const tokens = await response.json();
|
|
7646
8070
|
logger.info("[registerWithEmail] Registration successful, user_id:", tokens.identity.id);
|
|
@@ -7671,7 +8095,7 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7671
8095
|
anonymous: false,
|
|
7672
8096
|
node: userNode ?? void 0
|
|
7673
8097
|
};
|
|
7674
|
-
const expiresInMs = tokens.expires_at
|
|
8098
|
+
const expiresInMs = _RaisinClient.expiresAtToMs(tokens.expires_at) - Date.now() - 5 * 60 * 1e3;
|
|
7675
8099
|
if (expiresInMs > 0) {
|
|
7676
8100
|
this.scheduleAutoRefresh(expiresInMs);
|
|
7677
8101
|
}
|
|
@@ -7767,7 +8191,7 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7767
8191
|
if (refreshToken) {
|
|
7768
8192
|
try {
|
|
7769
8193
|
const url = this._repository ? `${this._httpBaseUrl}/auth/${this._repository}/refresh` : `${this._httpBaseUrl}/auth/refresh`;
|
|
7770
|
-
const response = await
|
|
8194
|
+
const response = await this._fetchWithTimeout(url, {
|
|
7771
8195
|
method: "POST",
|
|
7772
8196
|
headers: { "Content-Type": "application/json" },
|
|
7773
8197
|
body: JSON.stringify({ refresh_token: refreshToken })
|
|
@@ -7776,7 +8200,7 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7776
8200
|
const tokens = await response.json();
|
|
7777
8201
|
this.authManager.storage.setAccessToken(tokens.access_token);
|
|
7778
8202
|
this.authManager.storage.setRefreshToken(tokens.refresh_token);
|
|
7779
|
-
const expiresInMs = tokens.expires_at
|
|
8203
|
+
const expiresInMs = _RaisinClient.expiresAtToMs(tokens.expires_at) - Date.now() - 5 * 60 * 1e3;
|
|
7780
8204
|
if (expiresInMs > 0) {
|
|
7781
8205
|
this.scheduleAutoRefresh(expiresInMs);
|
|
7782
8206
|
}
|
|
@@ -7893,7 +8317,7 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7893
8317
|
try {
|
|
7894
8318
|
logger.info("[refreshToken] Refreshing access token...");
|
|
7895
8319
|
const url = this._repository ? `${this._httpBaseUrl}/auth/${this._repository}/refresh` : `${this._httpBaseUrl}/auth/refresh`;
|
|
7896
|
-
const response = await
|
|
8320
|
+
const response = await this._fetchWithTimeout(url, {
|
|
7897
8321
|
method: "POST",
|
|
7898
8322
|
headers: { "Content-Type": "application/json" },
|
|
7899
8323
|
body: JSON.stringify({ refresh_token: refreshToken })
|
|
@@ -7923,7 +8347,7 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7923
8347
|
if (this.authManager.storage instanceof LocalStorageTokenStorage) {
|
|
7924
8348
|
this.authManager.storage.setUser(user);
|
|
7925
8349
|
}
|
|
7926
|
-
const expiresInMs = tokens.expires_at
|
|
8350
|
+
const expiresInMs = _RaisinClient.expiresAtToMs(tokens.expires_at) - Date.now() - 5 * 60 * 1e3;
|
|
7927
8351
|
if (expiresInMs > 0) {
|
|
7928
8352
|
this.scheduleAutoRefresh(expiresInMs);
|
|
7929
8353
|
}
|
|
@@ -7936,6 +8360,53 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7936
8360
|
return null;
|
|
7937
8361
|
}
|
|
7938
8362
|
}
|
|
8363
|
+
/**
|
|
8364
|
+
* Fetch with a timeout derived from `requestTimeout`.
|
|
8365
|
+
*
|
|
8366
|
+
* Aborts the request after `requestTimeout` ms and rejects with a
|
|
8367
|
+
* `RaisinTimeoutError`. If the caller provides its own AbortSignal in
|
|
8368
|
+
* `init.signal`, it is respected: an external abort rejects with the
|
|
8369
|
+
* original AbortError instead of a timeout error.
|
|
8370
|
+
* @internal
|
|
8371
|
+
*/
|
|
8372
|
+
async _fetchWithTimeout(url, init = {}) {
|
|
8373
|
+
const timeoutMs = this.options.requestTimeout;
|
|
8374
|
+
const controller = new AbortController();
|
|
8375
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
8376
|
+
const externalSignal = init.signal ?? void 0;
|
|
8377
|
+
if (externalSignal) {
|
|
8378
|
+
if (externalSignal.aborted) {
|
|
8379
|
+
controller.abort();
|
|
8380
|
+
} else {
|
|
8381
|
+
externalSignal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
8382
|
+
}
|
|
8383
|
+
}
|
|
8384
|
+
try {
|
|
8385
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
8386
|
+
} catch (error) {
|
|
8387
|
+
if (error instanceof Error && error.name === "AbortError" && !externalSignal?.aborted) {
|
|
8388
|
+
throw new RaisinTimeoutError(
|
|
8389
|
+
`Request to ${url} timed out after ${timeoutMs}ms`,
|
|
8390
|
+
"REQUEST_TIMEOUT",
|
|
8391
|
+
timeoutMs
|
|
8392
|
+
);
|
|
8393
|
+
}
|
|
8394
|
+
throw error;
|
|
8395
|
+
} finally {
|
|
8396
|
+
clearTimeout(timer);
|
|
8397
|
+
}
|
|
8398
|
+
}
|
|
8399
|
+
/**
|
|
8400
|
+
* Normalize a token `expires_at` value to epoch milliseconds.
|
|
8401
|
+
*
|
|
8402
|
+
* Server endpoints are inconsistent: some return seconds, others
|
|
8403
|
+
* milliseconds. Anything above 1e11 can't be a seconds-epoch (year 5138),
|
|
8404
|
+
* so treat it as milliseconds.
|
|
8405
|
+
* @internal
|
|
8406
|
+
*/
|
|
8407
|
+
static expiresAtToMs(expiresAt) {
|
|
8408
|
+
return expiresAt > 1e11 ? expiresAt : expiresAt * 1e3;
|
|
8409
|
+
}
|
|
7939
8410
|
/**
|
|
7940
8411
|
* Schedule automatic token refresh
|
|
7941
8412
|
* @internal
|
|
@@ -7944,11 +8415,12 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7944
8415
|
if (this._refreshTimer) {
|
|
7945
8416
|
clearTimeout(this._refreshTimer);
|
|
7946
8417
|
}
|
|
7947
|
-
|
|
8418
|
+
const clamped = Math.min(Math.max(delayMs, 3e4), 2147483647);
|
|
8419
|
+
logger.debug(`[scheduleAutoRefresh] Scheduling refresh in ${Math.round(clamped / 1e3 / 60)} minutes`);
|
|
7948
8420
|
this._refreshTimer = setTimeout(async () => {
|
|
7949
8421
|
logger.info("[autoRefresh] Auto-refreshing token...");
|
|
7950
8422
|
await this.refreshToken();
|
|
7951
|
-
},
|
|
8423
|
+
}, clamped);
|
|
7952
8424
|
}
|
|
7953
8425
|
/**
|
|
7954
8426
|
* Get a database/repository interface
|
|
@@ -7972,10 +8444,26 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7972
8444
|
}
|
|
7973
8445
|
/**
|
|
7974
8446
|
* Send a request to the server
|
|
8447
|
+
*
|
|
8448
|
+
* If the connection is temporarily down (connecting/reconnecting, or
|
|
8449
|
+
* disconnected with auto-reconnect enabled), the request is queued and
|
|
8450
|
+
* flushed once the connection is re-established and re-authenticated.
|
|
8451
|
+
* Queued requests are still subject to their own request timeout, and the
|
|
8452
|
+
* queue is bounded (overflow rejects immediately).
|
|
7975
8453
|
*/
|
|
7976
8454
|
async sendRequestInternal(payload, requestType, contextOverride, requestOptions) {
|
|
7977
|
-
|
|
7978
|
-
|
|
8455
|
+
const connected = this.connection.isConnected();
|
|
8456
|
+
if (!connected) {
|
|
8457
|
+
const state = this.connection.getState();
|
|
8458
|
+
const willReconnect = state === "connecting" /* Connecting */ || state === "reconnecting" /* Reconnecting */ || state === "disconnected" /* Disconnected */ && this._everConnected && this.connection.isAutoReconnectEnabled();
|
|
8459
|
+
if (!willReconnect) {
|
|
8460
|
+
throw new Error("Not connected to server");
|
|
8461
|
+
}
|
|
8462
|
+
if (this._queuedRequests.length >= _RaisinClient.MAX_QUEUED_REQUESTS) {
|
|
8463
|
+
throw new Error(
|
|
8464
|
+
`Request queue is full (${_RaisinClient.MAX_QUEUED_REQUESTS} requests pending while reconnecting)`
|
|
8465
|
+
);
|
|
8466
|
+
}
|
|
7979
8467
|
}
|
|
7980
8468
|
const requestId = this.requestTracker.generateRequestId();
|
|
7981
8469
|
const context = contextOverride || this._context;
|
|
@@ -7994,8 +8482,15 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
7994
8482
|
try {
|
|
7995
8483
|
const encoded = encodeMessage(request);
|
|
7996
8484
|
logger.debug(`Encoded request - ID: ${requestId}, type: ${requestType}, size: ${encoded.length} bytes`);
|
|
7997
|
-
|
|
7998
|
-
|
|
8485
|
+
if (connected) {
|
|
8486
|
+
this.connection.send(encoded);
|
|
8487
|
+
logger.debug(`Request sent - ID: ${requestId}`);
|
|
8488
|
+
} else {
|
|
8489
|
+
this._queuedRequests.push({ requestId, encoded });
|
|
8490
|
+
logger.debug(
|
|
8491
|
+
`Request queued while reconnecting - ID: ${requestId}, queue size: ${this._queuedRequests.length}`
|
|
8492
|
+
);
|
|
8493
|
+
}
|
|
7999
8494
|
} catch (error) {
|
|
8000
8495
|
logger.error(`Failed to send request - ID: ${requestId}:`, error);
|
|
8001
8496
|
this.requestTracker.rejectRequest(
|
|
@@ -8006,6 +8501,42 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
8006
8501
|
}
|
|
8007
8502
|
return responsePromise;
|
|
8008
8503
|
}
|
|
8504
|
+
/**
|
|
8505
|
+
* Flush requests queued while the connection was re-establishing.
|
|
8506
|
+
* Called after the connection is connected and (re-)authenticated.
|
|
8507
|
+
* @internal
|
|
8508
|
+
*/
|
|
8509
|
+
_flushQueuedRequests() {
|
|
8510
|
+
if (this._queuedRequests.length === 0) return;
|
|
8511
|
+
const queued = this._queuedRequests;
|
|
8512
|
+
this._queuedRequests = [];
|
|
8513
|
+
logger.info(`[_flushQueuedRequests] Flushing ${queued.length} queued request(s)`);
|
|
8514
|
+
for (const { requestId, encoded } of queued) {
|
|
8515
|
+
if (!this.requestTracker.hasPendingRequest(requestId)) continue;
|
|
8516
|
+
try {
|
|
8517
|
+
this.connection.send(encoded);
|
|
8518
|
+
} catch (error) {
|
|
8519
|
+
this.requestTracker.rejectRequest(
|
|
8520
|
+
requestId,
|
|
8521
|
+
error instanceof Error ? error : new Error("Failed to send queued request")
|
|
8522
|
+
);
|
|
8523
|
+
}
|
|
8524
|
+
}
|
|
8525
|
+
}
|
|
8526
|
+
/**
|
|
8527
|
+
* Reject all requests queued while the connection was re-establishing
|
|
8528
|
+
* (e.g. re-authentication failed after reconnect).
|
|
8529
|
+
* @internal
|
|
8530
|
+
*/
|
|
8531
|
+
_rejectQueuedRequests(error) {
|
|
8532
|
+
if (this._queuedRequests.length === 0) return;
|
|
8533
|
+
const queued = this._queuedRequests;
|
|
8534
|
+
this._queuedRequests = [];
|
|
8535
|
+
logger.warn(`[_rejectQueuedRequests] Rejecting ${queued.length} queued request(s): ${error.message}`);
|
|
8536
|
+
for (const { requestId } of queued) {
|
|
8537
|
+
this.requestTracker.rejectRequest(requestId, error);
|
|
8538
|
+
}
|
|
8539
|
+
}
|
|
8009
8540
|
/**
|
|
8010
8541
|
* Get the HTTP base URL derived from the WebSocket URL
|
|
8011
8542
|
*/
|
|
@@ -8331,6 +8862,7 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
8331
8862
|
*/
|
|
8332
8863
|
async _subscribeToUserHome(repository, userHome) {
|
|
8333
8864
|
await this._unsubscribeFromUserHome();
|
|
8865
|
+
userHome = normalizeHomePath(userHome) ?? userHome;
|
|
8334
8866
|
try {
|
|
8335
8867
|
const db = this.database(repository);
|
|
8336
8868
|
const pathParts = userHome.split("/").filter((p) => p.length > 0);
|
|
@@ -8630,7 +9162,7 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
8630
9162
|
const branch = options.branch ?? this._context.branch ?? "main";
|
|
8631
9163
|
const pathWithProperty = options.propertyPath ? `${options.path}@${options.propertyPath}` : options.path;
|
|
8632
9164
|
const endpoint = `/api/repository/${options.repository}/${branch}/head/${options.workspace}${pathWithProperty}/raisin:sign`;
|
|
8633
|
-
const response = await
|
|
9165
|
+
const response = await this._fetchWithTimeout(`${this._httpBaseUrl}${endpoint}`, {
|
|
8634
9166
|
method: "POST",
|
|
8635
9167
|
headers: {
|
|
8636
9168
|
"Content-Type": "application/json",
|
|
@@ -8685,6 +9217,9 @@ var RaisinClient = class _RaisinClient extends import_events4.EventEmitter {
|
|
|
8685
9217
|
return _RaisinClient.forSSR(baseUrl, options);
|
|
8686
9218
|
}
|
|
8687
9219
|
};
|
|
9220
|
+
/** Hard cap on requests held while reconnecting; overflow rejects immediately. */
|
|
9221
|
+
_RaisinClient.MAX_QUEUED_REQUESTS = 100;
|
|
9222
|
+
var RaisinClient = _RaisinClient;
|
|
8688
9223
|
|
|
8689
9224
|
// src/node-builder.ts
|
|
8690
9225
|
var NodeBuilder = class _NodeBuilder {
|
|
@@ -9019,6 +9554,29 @@ function isTerminalEvent(event) {
|
|
|
9019
9554
|
return event.type === "flow_completed" || event.type === "flow_failed";
|
|
9020
9555
|
}
|
|
9021
9556
|
|
|
9557
|
+
// src/types/flow-definition.ts
|
|
9558
|
+
function getRefDisplayName(ref) {
|
|
9559
|
+
const path = ref["raisin:path"] || ref["raisin:ref"];
|
|
9560
|
+
const segments = path.split("/").filter(Boolean);
|
|
9561
|
+
return segments[segments.length - 1] || path;
|
|
9562
|
+
}
|
|
9563
|
+
function getRefPath(ref) {
|
|
9564
|
+
return ref["raisin:path"] || ref["raisin:ref"];
|
|
9565
|
+
}
|
|
9566
|
+
var RETRY_STRATEGIES = {
|
|
9567
|
+
none: { max_retries: 0, base_delay_ms: 0, max_delay_ms: 0 },
|
|
9568
|
+
quick: { max_retries: 3, base_delay_ms: 1e3, max_delay_ms: 1e4 },
|
|
9569
|
+
standard: { max_retries: 5, base_delay_ms: 2e3, max_delay_ms: 6e4 },
|
|
9570
|
+
aggressive: { max_retries: 10, base_delay_ms: 5e3, max_delay_ms: 12e4 },
|
|
9571
|
+
llm: { max_retries: 5, base_delay_ms: 1e4, max_delay_ms: 12e4 }
|
|
9572
|
+
};
|
|
9573
|
+
function isFlowDefinitionStep(node) {
|
|
9574
|
+
return node.node_type === "raisin:FlowStep";
|
|
9575
|
+
}
|
|
9576
|
+
function isFlowDefinitionContainer(node) {
|
|
9577
|
+
return node.node_type === "raisin:FlowContainer";
|
|
9578
|
+
}
|
|
9579
|
+
|
|
9022
9580
|
// src/utils/plan-projection.ts
|
|
9023
9581
|
function asRecord(value) {
|
|
9024
9582
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
@@ -9357,10 +9915,12 @@ var ConversationStore = class {
|
|
|
9357
9915
|
}
|
|
9358
9916
|
switch (event.type) {
|
|
9359
9917
|
case "text_chunk":
|
|
9918
|
+
this.markStreamingActivity();
|
|
9360
9919
|
this._streamingText += event.text;
|
|
9361
9920
|
this.notify();
|
|
9362
9921
|
break;
|
|
9363
9922
|
case "thought_chunk":
|
|
9923
|
+
this.markStreamingActivity();
|
|
9364
9924
|
this.notify();
|
|
9365
9925
|
break;
|
|
9366
9926
|
case "assistant_message":
|
|
@@ -9369,6 +9929,7 @@ var ConversationStore = class {
|
|
|
9369
9929
|
this.notify();
|
|
9370
9930
|
break;
|
|
9371
9931
|
case "tool_call_started": {
|
|
9932
|
+
this.markStreamingActivity();
|
|
9372
9933
|
logger.debug("[ConversationStore] Tool started:", event.functionName);
|
|
9373
9934
|
const info = {
|
|
9374
9935
|
id: event.toolCallId,
|
|
@@ -9381,6 +9942,7 @@ var ConversationStore = class {
|
|
|
9381
9942
|
break;
|
|
9382
9943
|
}
|
|
9383
9944
|
case "tool_call_completed": {
|
|
9945
|
+
this.markStreamingActivity();
|
|
9384
9946
|
logger.debug("[ConversationStore] Tool completed:", event.toolCallId);
|
|
9385
9947
|
const idx = this._activeToolCalls.findIndex((tc) => tc.id === event.toolCallId);
|
|
9386
9948
|
if (idx >= 0) {
|
|
@@ -9455,6 +10017,7 @@ var ConversationStore = class {
|
|
|
9455
10017
|
logger.error("[ConversationStore] Turn failed", event.error);
|
|
9456
10018
|
this._error = event.error;
|
|
9457
10019
|
this._isStreaming = false;
|
|
10020
|
+
this._isWaiting = false;
|
|
9458
10021
|
this._streamingText = "";
|
|
9459
10022
|
this._activeToolCalls = [];
|
|
9460
10023
|
this.clearStreamingTimer();
|
|
@@ -9492,6 +10055,26 @@ var ConversationStore = class {
|
|
|
9492
10055
|
}
|
|
9493
10056
|
}
|
|
9494
10057
|
}
|
|
10058
|
+
/**
|
|
10059
|
+
* Agent activity observed while the store thought the turn was over.
|
|
10060
|
+
*
|
|
10061
|
+
* This happens when execution continues WITHOUT a user message — plan
|
|
10062
|
+
* approval in approve_then_auto / step_by_step (approvePlan() returns an
|
|
10063
|
+
* enqueue receipt and the agent starts executing), or agent-initiated
|
|
10064
|
+
* follow-ups. The events arrive over the persistent live subscription
|
|
10065
|
+
* (no history replay), so activity is always "now": re-enter streaming
|
|
10066
|
+
* state so UIs show progress and the end-of-turn handling (done/waiting
|
|
10067
|
+
* → deferred reload) runs again for this continuation.
|
|
10068
|
+
*/
|
|
10069
|
+
markStreamingActivity() {
|
|
10070
|
+
if (this._isStreaming) return;
|
|
10071
|
+
logger.debug("[ConversationStore] Agent activity while idle \u2014 re-entering streaming state");
|
|
10072
|
+
this._isStreaming = true;
|
|
10073
|
+
this._isWaiting = false;
|
|
10074
|
+
this._streamingText = "";
|
|
10075
|
+
this.resetStreamingTimer();
|
|
10076
|
+
this.startWatchdog();
|
|
10077
|
+
}
|
|
9495
10078
|
/**
|
|
9496
10079
|
* If accumulated streaming text hasn't been captured in an assistant_message,
|
|
9497
10080
|
* synthesize one.
|
|
@@ -9725,6 +10308,14 @@ var ConversationStore = class {
|
|
|
9725
10308
|
};
|
|
9726
10309
|
|
|
9727
10310
|
// src/stores/conversation-list-store.ts
|
|
10311
|
+
function buildChatsSubscriptionFilters(userHome) {
|
|
10312
|
+
const home = normalizeHomePath(userHome) ?? userHome;
|
|
10313
|
+
return {
|
|
10314
|
+
workspace: "raisin:access_control",
|
|
10315
|
+
path: `${home}/inbox/chats/**`,
|
|
10316
|
+
event_types: ["node:created", "node:updated"]
|
|
10317
|
+
};
|
|
10318
|
+
}
|
|
9728
10319
|
var ConversationListStore = class {
|
|
9729
10320
|
constructor(options) {
|
|
9730
10321
|
this.subscribers = /* @__PURE__ */ new Set();
|
|
@@ -9870,13 +10461,8 @@ var ConversationListStore = class {
|
|
|
9870
10461
|
const rows = result.rows;
|
|
9871
10462
|
const userHome = rows?.[0]?.home;
|
|
9872
10463
|
if (!userHome) return;
|
|
9873
|
-
const chatsPath = `${userHome}/inbox/chats`;
|
|
9874
10464
|
this._realtimeSubscription = await events.subscribe(
|
|
9875
|
-
|
|
9876
|
-
workspace: "raisin:access_control",
|
|
9877
|
-
path: chatsPath,
|
|
9878
|
-
event_types: ["node:created", "node:updated"]
|
|
9879
|
-
},
|
|
10465
|
+
buildChatsSubscriptionFilters(userHome),
|
|
9880
10466
|
async (event) => {
|
|
9881
10467
|
const eventData = event;
|
|
9882
10468
|
const nodeId = eventData.payload?.node_id;
|
|
@@ -9982,7 +10568,7 @@ function useConversation(react, options) {
|
|
|
9982
10568
|
var INITIAL_LIST_SNAPSHOT = {
|
|
9983
10569
|
conversations: [],
|
|
9984
10570
|
totalUnreadCount: 0,
|
|
9985
|
-
isLoading:
|
|
10571
|
+
isLoading: true,
|
|
9986
10572
|
error: null
|
|
9987
10573
|
};
|
|
9988
10574
|
function useConversationList(react, options) {
|
|
@@ -10860,6 +11446,160 @@ function createRaisinReact(react) {
|
|
|
10860
11446
|
useFlow: useFlow2
|
|
10861
11447
|
};
|
|
10862
11448
|
}
|
|
11449
|
+
|
|
11450
|
+
// src/integrations/vue/vue-auth.ts
|
|
11451
|
+
function createUseAuth2(vue) {
|
|
11452
|
+
return function useAuth(client) {
|
|
11453
|
+
const adapter = createAuthAdapter(client);
|
|
11454
|
+
const snapshot = vue.ref(adapter.getSnapshot());
|
|
11455
|
+
const unsubscribe = adapter.subscribe((s) => {
|
|
11456
|
+
snapshot.value = s;
|
|
11457
|
+
});
|
|
11458
|
+
vue.onUnmounted(() => {
|
|
11459
|
+
unsubscribe();
|
|
11460
|
+
adapter.destroy();
|
|
11461
|
+
});
|
|
11462
|
+
return {
|
|
11463
|
+
user: vue.computed(() => snapshot.value.user),
|
|
11464
|
+
isAuthenticated: vue.computed(() => snapshot.value.isAuthenticated),
|
|
11465
|
+
isLoading: vue.computed(() => snapshot.value.isLoading),
|
|
11466
|
+
login: adapter.login,
|
|
11467
|
+
register: adapter.register,
|
|
11468
|
+
logout: adapter.logout,
|
|
11469
|
+
initSession: adapter.initSession
|
|
11470
|
+
};
|
|
11471
|
+
};
|
|
11472
|
+
}
|
|
11473
|
+
|
|
11474
|
+
// src/integrations/vue/vue-connection.ts
|
|
11475
|
+
function createUseConnection2(vue) {
|
|
11476
|
+
return function useConnection(client) {
|
|
11477
|
+
const adapter = createConnectionAdapter(client);
|
|
11478
|
+
const snapshot = vue.ref(adapter.getSnapshot());
|
|
11479
|
+
const unsubscribe = adapter.subscribe((s) => {
|
|
11480
|
+
snapshot.value = s;
|
|
11481
|
+
});
|
|
11482
|
+
vue.onUnmounted(() => {
|
|
11483
|
+
unsubscribe();
|
|
11484
|
+
adapter.destroy();
|
|
11485
|
+
});
|
|
11486
|
+
return {
|
|
11487
|
+
state: vue.computed(() => snapshot.value.state),
|
|
11488
|
+
isConnected: vue.computed(() => snapshot.value.isConnected),
|
|
11489
|
+
isReady: vue.computed(() => snapshot.value.isReady),
|
|
11490
|
+
connect: adapter.connect,
|
|
11491
|
+
disconnect: adapter.disconnect
|
|
11492
|
+
};
|
|
11493
|
+
};
|
|
11494
|
+
}
|
|
11495
|
+
|
|
11496
|
+
// src/integrations/vue/vue-sql.ts
|
|
11497
|
+
function createUseSql2(vue) {
|
|
11498
|
+
return function useSql(database, sql, params, options) {
|
|
11499
|
+
const adapter = createSqlAdapter(database, sql, params, options);
|
|
11500
|
+
const snapshot = vue.ref(adapter.getSnapshot());
|
|
11501
|
+
const unsubscribe = adapter.subscribe((s) => {
|
|
11502
|
+
snapshot.value = s;
|
|
11503
|
+
});
|
|
11504
|
+
vue.onUnmounted(() => {
|
|
11505
|
+
unsubscribe();
|
|
11506
|
+
adapter.destroy();
|
|
11507
|
+
});
|
|
11508
|
+
return {
|
|
11509
|
+
data: vue.computed(() => snapshot.value.data),
|
|
11510
|
+
isLoading: vue.computed(() => snapshot.value.isLoading),
|
|
11511
|
+
error: vue.computed(() => snapshot.value.error),
|
|
11512
|
+
refetch: adapter.refetch
|
|
11513
|
+
};
|
|
11514
|
+
};
|
|
11515
|
+
}
|
|
11516
|
+
|
|
11517
|
+
// src/integrations/vue/vue-subscription.ts
|
|
11518
|
+
function createUseSubscription2(vue) {
|
|
11519
|
+
return function useSubscription(database, filters, callback) {
|
|
11520
|
+
const adapter = createSubscriptionAdapter(database, filters, callback);
|
|
11521
|
+
vue.onUnmounted(() => adapter.destroy());
|
|
11522
|
+
return {
|
|
11523
|
+
unsubscribe: () => adapter.destroy()
|
|
11524
|
+
};
|
|
11525
|
+
};
|
|
11526
|
+
}
|
|
11527
|
+
|
|
11528
|
+
// src/integrations/vue/vue-conversation.ts
|
|
11529
|
+
function createUseConversation(vue) {
|
|
11530
|
+
return function useConversation2(options) {
|
|
11531
|
+
const store = new ConversationStore(options);
|
|
11532
|
+
const snapshot = vue.ref(store.getSnapshot());
|
|
11533
|
+
const unsubscribe = store.subscribe((s) => {
|
|
11534
|
+
snapshot.value = s;
|
|
11535
|
+
});
|
|
11536
|
+
vue.onUnmounted(() => {
|
|
11537
|
+
unsubscribe();
|
|
11538
|
+
store.destroy();
|
|
11539
|
+
});
|
|
11540
|
+
return {
|
|
11541
|
+
conversation: vue.computed(() => snapshot.value.conversation),
|
|
11542
|
+
messages: vue.computed(() => snapshot.value.messages),
|
|
11543
|
+
isStreaming: vue.computed(() => snapshot.value.isStreaming),
|
|
11544
|
+
isWaiting: vue.computed(() => snapshot.value.isWaiting),
|
|
11545
|
+
streamingText: vue.computed(() => snapshot.value.streamingText),
|
|
11546
|
+
error: vue.computed(() => snapshot.value.error),
|
|
11547
|
+
activeToolCalls: vue.computed(() => snapshot.value.activeToolCalls),
|
|
11548
|
+
plans: vue.computed(() => snapshot.value.plans),
|
|
11549
|
+
isLoading: vue.computed(() => snapshot.value.isLoading),
|
|
11550
|
+
conversationPath: vue.computed(() => snapshot.value.conversationPath),
|
|
11551
|
+
sendMessage: (content) => store.sendMessage(content),
|
|
11552
|
+
approvePlan: async (planPath) => {
|
|
11553
|
+
await store.approvePlan(planPath);
|
|
11554
|
+
},
|
|
11555
|
+
rejectPlan: async (planPath, feedback) => {
|
|
11556
|
+
await store.rejectPlan(planPath, feedback);
|
|
11557
|
+
},
|
|
11558
|
+
stop: () => store.stop(),
|
|
11559
|
+
loadMessages: () => store.loadMessages(),
|
|
11560
|
+
store
|
|
11561
|
+
};
|
|
11562
|
+
};
|
|
11563
|
+
}
|
|
11564
|
+
function createUseConversationList(vue) {
|
|
11565
|
+
return function useConversationList2(options) {
|
|
11566
|
+
const store = new ConversationListStore(options);
|
|
11567
|
+
const snapshot = vue.ref(store.getSnapshot());
|
|
11568
|
+
const unsubscribe = store.subscribe((s) => {
|
|
11569
|
+
snapshot.value = s;
|
|
11570
|
+
});
|
|
11571
|
+
store.load().catch((err) => {
|
|
11572
|
+
logger.error("[useConversationList] Initial load failed:", err);
|
|
11573
|
+
});
|
|
11574
|
+
vue.onUnmounted(() => {
|
|
11575
|
+
unsubscribe();
|
|
11576
|
+
store.destroy();
|
|
11577
|
+
});
|
|
11578
|
+
return {
|
|
11579
|
+
conversations: vue.computed(() => snapshot.value.conversations),
|
|
11580
|
+
totalUnreadCount: vue.computed(() => snapshot.value.totalUnreadCount),
|
|
11581
|
+
isLoading: vue.computed(() => snapshot.value.isLoading),
|
|
11582
|
+
error: vue.computed(() => snapshot.value.error),
|
|
11583
|
+
createConversation: (opts) => store.createConversation(opts),
|
|
11584
|
+
deleteConversation: (conversationPath) => store.deleteConversation(conversationPath),
|
|
11585
|
+
markAsRead: (conversationPath) => store.markAsRead(conversationPath),
|
|
11586
|
+
refresh: () => store.load(),
|
|
11587
|
+
store
|
|
11588
|
+
};
|
|
11589
|
+
};
|
|
11590
|
+
}
|
|
11591
|
+
|
|
11592
|
+
// src/integrations/vue/index.ts
|
|
11593
|
+
function createRaisinVue(vue) {
|
|
11594
|
+
return {
|
|
11595
|
+
useAuth: createUseAuth2(vue),
|
|
11596
|
+
useConnection: createUseConnection2(vue),
|
|
11597
|
+
useSql: createUseSql2(vue),
|
|
11598
|
+
useSubscription: createUseSubscription2(vue),
|
|
11599
|
+
useConversation: createUseConversation(vue),
|
|
11600
|
+
useConversationList: createUseConversationList(vue)
|
|
11601
|
+
};
|
|
11602
|
+
}
|
|
10863
11603
|
// Annotate the CommonJS export names for ESM import in node:
|
|
10864
11604
|
0 && (module.exports = {
|
|
10865
11605
|
AllNodeEventTypes,
|
|
@@ -10881,6 +11621,7 @@ function createRaisinReact(react) {
|
|
|
10881
11621
|
DEFAULT_RETRY_BASE_DELAY,
|
|
10882
11622
|
DEFAULT_RETRY_MAX_DELAY,
|
|
10883
11623
|
DEFAULT_RETRY_OPTIONS,
|
|
11624
|
+
DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS,
|
|
10884
11625
|
Database,
|
|
10885
11626
|
ElementTypes,
|
|
10886
11627
|
EventHandler,
|
|
@@ -10891,6 +11632,7 @@ function createRaisinReact(react) {
|
|
|
10891
11632
|
HttpDatabase,
|
|
10892
11633
|
HttpFunctionsApi,
|
|
10893
11634
|
HttpWorkspaceClient,
|
|
11635
|
+
InboxApi,
|
|
10894
11636
|
LocalStorageTokenStorage,
|
|
10895
11637
|
LogLevel,
|
|
10896
11638
|
MemoryTokenStorage,
|
|
@@ -10901,6 +11643,7 @@ function createRaisinReact(react) {
|
|
|
10901
11643
|
NodeOperations,
|
|
10902
11644
|
NodeTypes,
|
|
10903
11645
|
RAISIN_CONTEXT_KEY,
|
|
11646
|
+
RETRY_STRATEGIES,
|
|
10904
11647
|
RaisinAbortError,
|
|
10905
11648
|
RaisinAuthError,
|
|
10906
11649
|
RaisinClient,
|
|
@@ -10936,6 +11679,7 @@ function createRaisinReact(react) {
|
|
|
10936
11679
|
createFlowAdapter,
|
|
10937
11680
|
createLoader,
|
|
10938
11681
|
createRaisinReact,
|
|
11682
|
+
createRaisinVue,
|
|
10939
11683
|
createRequestScopedClient,
|
|
10940
11684
|
createSSRClient,
|
|
10941
11685
|
createSqlAdapter,
|
|
@@ -10948,13 +11692,18 @@ function createRaisinReact(react) {
|
|
|
10948
11692
|
getErrorMessage,
|
|
10949
11693
|
getLogLevel,
|
|
10950
11694
|
getLoggerConfig,
|
|
11695
|
+
getRefDisplayName,
|
|
11696
|
+
getRefPath,
|
|
10951
11697
|
isEventMessage,
|
|
11698
|
+
isFlowDefinitionContainer,
|
|
11699
|
+
isFlowDefinitionStep,
|
|
10952
11700
|
isHttpClient,
|
|
10953
11701
|
isResponseEnvelope,
|
|
10954
11702
|
isRetryableError,
|
|
10955
11703
|
isTerminalEvent,
|
|
10956
11704
|
isWebSocketClient,
|
|
10957
11705
|
logger,
|
|
11706
|
+
normalizeHomePath,
|
|
10958
11707
|
projectPlansFromMessages,
|
|
10959
11708
|
rowsToObjects,
|
|
10960
11709
|
setLogLevel,
|
|
@@ -10964,3 +11713,4 @@ function createRaisinReact(react) {
|
|
|
10964
11713
|
useFlow,
|
|
10965
11714
|
withRetry
|
|
10966
11715
|
});
|
|
11716
|
+
//# sourceMappingURL=index.js.map
|