@spoosh/core 0.15.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +380 -78
- package/dist/index.d.ts +380 -78
- package/dist/index.js +268 -6
- package/dist/index.mjs +268 -6
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ __export(src_exports, {
|
|
|
26
26
|
__DEV__: () => __DEV__,
|
|
27
27
|
buildUrl: () => buildUrl,
|
|
28
28
|
clone: () => clone,
|
|
29
|
+
composeAdapter: () => composeAdapter,
|
|
29
30
|
containsFile: () => containsFile,
|
|
30
31
|
createClient: () => createClient,
|
|
31
32
|
createEventEmitter: () => createEventEmitter,
|
|
@@ -39,12 +40,14 @@ __export(src_exports, {
|
|
|
39
40
|
createSelectorProxy: () => createSelectorProxy,
|
|
40
41
|
createSpooshPlugin: () => createSpooshPlugin,
|
|
41
42
|
createStateManager: () => createStateManager,
|
|
43
|
+
createSubscriptionController: () => createSubscriptionController,
|
|
42
44
|
createTracer: () => createTracer,
|
|
43
45
|
executeFetch: () => executeFetch,
|
|
44
46
|
extractMethodFromSelector: () => extractMethodFromSelector,
|
|
45
47
|
extractPathFromSelector: () => extractPathFromSelector,
|
|
46
48
|
fetchTransport: () => fetchTransport,
|
|
47
49
|
form: () => form,
|
|
50
|
+
generateSelfTagFromKey: () => generateSelfTagFromKey,
|
|
48
51
|
generateTags: () => generateTags,
|
|
49
52
|
getContentType: () => getContentType,
|
|
50
53
|
isAbortError: () => isAbortError,
|
|
@@ -716,7 +719,7 @@ function createSelectorProxy(onCapture) {
|
|
|
716
719
|
{},
|
|
717
720
|
{
|
|
718
721
|
get(_, prop) {
|
|
719
|
-
if (
|
|
722
|
+
if (typeof prop === "string" && prop === prop.toUpperCase()) {
|
|
720
723
|
const selectorFn = (options) => {
|
|
721
724
|
onCapture?.({
|
|
722
725
|
call: { path, method: prop, options },
|
|
@@ -759,7 +762,19 @@ function createInitialState() {
|
|
|
759
762
|
function generateSelfTagFromKey(key) {
|
|
760
763
|
try {
|
|
761
764
|
const parsed = JSON.parse(key);
|
|
762
|
-
|
|
765
|
+
const rawPath = parsed.path;
|
|
766
|
+
if (!rawPath) return void 0;
|
|
767
|
+
const path = Array.isArray(rawPath) ? rawPath.join("/") : rawPath;
|
|
768
|
+
const params = parsed.options?.params ?? parsed.pageRequest?.params;
|
|
769
|
+
if (!params) return path;
|
|
770
|
+
return path.split("/").map((segment) => {
|
|
771
|
+
if (segment.startsWith(":")) {
|
|
772
|
+
const paramName = segment.slice(1);
|
|
773
|
+
const value = params[paramName];
|
|
774
|
+
return value !== void 0 ? String(value) : segment;
|
|
775
|
+
}
|
|
776
|
+
return segment;
|
|
777
|
+
}).join("/");
|
|
763
778
|
} catch {
|
|
764
779
|
return void 0;
|
|
765
780
|
}
|
|
@@ -996,7 +1011,7 @@ function createPluginExecutor(initialPlugins = []) {
|
|
|
996
1011
|
const createPluginAccessor = (context) => ({
|
|
997
1012
|
get(name) {
|
|
998
1013
|
const plugin = plugins.find((p) => p.name === name);
|
|
999
|
-
return plugin?.
|
|
1014
|
+
return plugin?.internal?.(context);
|
|
1000
1015
|
}
|
|
1001
1016
|
});
|
|
1002
1017
|
const executeLifecycleImpl = async (phase, operationType, context) => {
|
|
@@ -1063,6 +1078,9 @@ function createPluginExecutor(initialPlugins = []) {
|
|
|
1063
1078
|
getPlugins() {
|
|
1064
1079
|
return frozenPlugins;
|
|
1065
1080
|
},
|
|
1081
|
+
getPluginsForOperation(operationType) {
|
|
1082
|
+
return frozenPlugins.filter((p) => p.operations.includes(operationType));
|
|
1083
|
+
},
|
|
1066
1084
|
registerContextEnhancer(enhancer) {
|
|
1067
1085
|
contextEnhancers.push(enhancer);
|
|
1068
1086
|
},
|
|
@@ -1095,6 +1113,7 @@ var Spoosh = class _Spoosh {
|
|
|
1095
1113
|
baseUrl;
|
|
1096
1114
|
defaultOptions;
|
|
1097
1115
|
_plugins;
|
|
1116
|
+
_transports = /* @__PURE__ */ new Map();
|
|
1098
1117
|
/**
|
|
1099
1118
|
* Creates a new Spoosh instance.
|
|
1100
1119
|
*
|
|
@@ -1119,10 +1138,13 @@ var Spoosh = class _Spoosh {
|
|
|
1119
1138
|
* });
|
|
1120
1139
|
* ```
|
|
1121
1140
|
*/
|
|
1122
|
-
constructor(baseUrl, defaultOptions, plugins) {
|
|
1141
|
+
constructor(baseUrl, defaultOptions, plugins, transports) {
|
|
1123
1142
|
this.baseUrl = baseUrl;
|
|
1124
1143
|
this.defaultOptions = defaultOptions || {};
|
|
1125
1144
|
this._plugins = plugins || [];
|
|
1145
|
+
if (transports) {
|
|
1146
|
+
this._transports = transports;
|
|
1147
|
+
}
|
|
1126
1148
|
}
|
|
1127
1149
|
/**
|
|
1128
1150
|
* Adds plugins to the Spoosh instance.
|
|
@@ -1146,8 +1168,37 @@ var Spoosh = class _Spoosh {
|
|
|
1146
1168
|
return new _Spoosh(
|
|
1147
1169
|
this.baseUrl,
|
|
1148
1170
|
this.defaultOptions,
|
|
1149
|
-
plugins
|
|
1171
|
+
plugins,
|
|
1172
|
+
this._transports
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
/**
|
|
1176
|
+
* Registers transport implementations for real-time operations.
|
|
1177
|
+
*
|
|
1178
|
+
* @param transports - Array of transport instances to register
|
|
1179
|
+
* @returns This Spoosh instance for method chaining
|
|
1180
|
+
*
|
|
1181
|
+
* @example
|
|
1182
|
+
* ```ts
|
|
1183
|
+
* import { sse } from '@spoosh/transport-sse';
|
|
1184
|
+
*
|
|
1185
|
+
* const spoosh = new Spoosh<Schema, Error>('/api')
|
|
1186
|
+
* .withTransports([sse()])
|
|
1187
|
+
* .use([...]);
|
|
1188
|
+
* ```
|
|
1189
|
+
*/
|
|
1190
|
+
withTransports(transports) {
|
|
1191
|
+
const newTransports = new Map(this._transports);
|
|
1192
|
+
for (const transport of transports) {
|
|
1193
|
+
newTransports.set(transport.name, transport);
|
|
1194
|
+
}
|
|
1195
|
+
const instance = new _Spoosh(
|
|
1196
|
+
this.baseUrl,
|
|
1197
|
+
this.defaultOptions,
|
|
1198
|
+
this._plugins,
|
|
1199
|
+
newTransports
|
|
1150
1200
|
);
|
|
1201
|
+
return instance;
|
|
1151
1202
|
}
|
|
1152
1203
|
/**
|
|
1153
1204
|
* Cached instance of the underlying SpooshInstance.
|
|
@@ -1174,6 +1225,7 @@ var Spoosh = class _Spoosh {
|
|
|
1174
1225
|
stateManager,
|
|
1175
1226
|
eventEmitter,
|
|
1176
1227
|
pluginExecutor,
|
|
1228
|
+
transports: this._transports,
|
|
1177
1229
|
config: {
|
|
1178
1230
|
baseUrl: this.baseUrl,
|
|
1179
1231
|
defaultOptions: this.defaultOptions
|
|
@@ -1181,7 +1233,8 @@ var Spoosh = class _Spoosh {
|
|
|
1181
1233
|
_types: {
|
|
1182
1234
|
schema: void 0,
|
|
1183
1235
|
defaultError: void 0,
|
|
1184
|
-
plugins: this._plugins
|
|
1236
|
+
plugins: this._plugins,
|
|
1237
|
+
transports: void 0
|
|
1185
1238
|
}
|
|
1186
1239
|
};
|
|
1187
1240
|
}
|
|
@@ -1291,6 +1344,18 @@ var Spoosh = class _Spoosh {
|
|
|
1291
1344
|
get _types() {
|
|
1292
1345
|
return this.getInstance()._types;
|
|
1293
1346
|
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Map of registered transport implementations.
|
|
1349
|
+
*
|
|
1350
|
+
* @example
|
|
1351
|
+
* ```ts
|
|
1352
|
+
* const { transports } = client;
|
|
1353
|
+
* const sseTransport = transports.get('sse');
|
|
1354
|
+
* ```
|
|
1355
|
+
*/
|
|
1356
|
+
get transports() {
|
|
1357
|
+
return this.getInstance().transports;
|
|
1358
|
+
}
|
|
1294
1359
|
};
|
|
1295
1360
|
|
|
1296
1361
|
// src/createClient.ts
|
|
@@ -1302,6 +1367,16 @@ function createClient(baseUrl, defaultOptions) {
|
|
|
1302
1367
|
});
|
|
1303
1368
|
}
|
|
1304
1369
|
|
|
1370
|
+
// src/transport/compose.ts
|
|
1371
|
+
function composeAdapter(baseAdapter, plugins) {
|
|
1372
|
+
return plugins.reduce((adapter, plugin) => {
|
|
1373
|
+
if (plugin.wrapAdapter) {
|
|
1374
|
+
return plugin.wrapAdapter(adapter);
|
|
1375
|
+
}
|
|
1376
|
+
return adapter;
|
|
1377
|
+
}, baseAdapter);
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1305
1380
|
// src/controllers/base/controller.ts
|
|
1306
1381
|
function createOperationController(options) {
|
|
1307
1382
|
const {
|
|
@@ -2245,3 +2320,190 @@ function createQueueController(config, context) {
|
|
|
2245
2320
|
}
|
|
2246
2321
|
};
|
|
2247
2322
|
}
|
|
2323
|
+
|
|
2324
|
+
// src/controllers/subscription/controller.ts
|
|
2325
|
+
function createSubscriptionController(options) {
|
|
2326
|
+
const {
|
|
2327
|
+
channel,
|
|
2328
|
+
baseAdapter,
|
|
2329
|
+
pluginExecutor,
|
|
2330
|
+
operationType,
|
|
2331
|
+
stateManager,
|
|
2332
|
+
eventEmitter,
|
|
2333
|
+
queryKey,
|
|
2334
|
+
path,
|
|
2335
|
+
method,
|
|
2336
|
+
instanceId
|
|
2337
|
+
} = options;
|
|
2338
|
+
const plugins = pluginExecutor.getPluginsForOperation(operationType);
|
|
2339
|
+
const adapter = composeAdapter(
|
|
2340
|
+
baseAdapter,
|
|
2341
|
+
plugins
|
|
2342
|
+
);
|
|
2343
|
+
let handle = null;
|
|
2344
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
2345
|
+
let subscriptionVersion = 0;
|
|
2346
|
+
let cachedState = {
|
|
2347
|
+
data: void 0,
|
|
2348
|
+
error: void 0,
|
|
2349
|
+
isConnected: false
|
|
2350
|
+
};
|
|
2351
|
+
const updateStateFromHandle = () => {
|
|
2352
|
+
if (!handle) return;
|
|
2353
|
+
const newData = handle.getData();
|
|
2354
|
+
const newError = handle.getError();
|
|
2355
|
+
if (newData !== cachedState.data || newError !== cachedState.error) {
|
|
2356
|
+
cachedState = {
|
|
2357
|
+
data: newData,
|
|
2358
|
+
error: newError,
|
|
2359
|
+
isConnected: true
|
|
2360
|
+
};
|
|
2361
|
+
}
|
|
2362
|
+
};
|
|
2363
|
+
const notify = () => {
|
|
2364
|
+
subscribers.forEach((callback) => callback());
|
|
2365
|
+
};
|
|
2366
|
+
const createContext = () => {
|
|
2367
|
+
const baseCtx = pluginExecutor.createContext({
|
|
2368
|
+
operationType,
|
|
2369
|
+
path,
|
|
2370
|
+
method,
|
|
2371
|
+
queryKey,
|
|
2372
|
+
tags: [],
|
|
2373
|
+
requestTimestamp: Date.now(),
|
|
2374
|
+
instanceId,
|
|
2375
|
+
request: { headers: {} },
|
|
2376
|
+
temp: /* @__PURE__ */ new Map(),
|
|
2377
|
+
stateManager,
|
|
2378
|
+
eventEmitter
|
|
2379
|
+
});
|
|
2380
|
+
return {
|
|
2381
|
+
...baseCtx,
|
|
2382
|
+
channel
|
|
2383
|
+
};
|
|
2384
|
+
};
|
|
2385
|
+
return {
|
|
2386
|
+
subscribe: ((callbackOrVoid) => {
|
|
2387
|
+
if (callbackOrVoid === void 0) {
|
|
2388
|
+
subscriptionVersion++;
|
|
2389
|
+
const thisVersion = subscriptionVersion;
|
|
2390
|
+
if (handle) {
|
|
2391
|
+
handle.unsubscribe();
|
|
2392
|
+
handle = null;
|
|
2393
|
+
}
|
|
2394
|
+
cachedState = { data: void 0, error: void 0, isConnected: false };
|
|
2395
|
+
notify();
|
|
2396
|
+
const ctx = createContext();
|
|
2397
|
+
ctx.onData = (data) => {
|
|
2398
|
+
if (thisVersion !== subscriptionVersion) {
|
|
2399
|
+
return;
|
|
2400
|
+
}
|
|
2401
|
+
cachedState = {
|
|
2402
|
+
data,
|
|
2403
|
+
error: cachedState.error,
|
|
2404
|
+
isConnected: true
|
|
2405
|
+
};
|
|
2406
|
+
notify();
|
|
2407
|
+
};
|
|
2408
|
+
ctx.onError = (error) => {
|
|
2409
|
+
if (thisVersion !== subscriptionVersion) {
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
cachedState = {
|
|
2413
|
+
data: cachedState.data,
|
|
2414
|
+
error,
|
|
2415
|
+
isConnected: cachedState.isConnected
|
|
2416
|
+
};
|
|
2417
|
+
notify();
|
|
2418
|
+
};
|
|
2419
|
+
ctx.onDisconnect = () => {
|
|
2420
|
+
if (thisVersion !== subscriptionVersion) {
|
|
2421
|
+
return;
|
|
2422
|
+
}
|
|
2423
|
+
cachedState = {
|
|
2424
|
+
...cachedState,
|
|
2425
|
+
isConnected: false
|
|
2426
|
+
};
|
|
2427
|
+
notify();
|
|
2428
|
+
};
|
|
2429
|
+
return adapter.subscribe(ctx).then((newHandle) => {
|
|
2430
|
+
if (thisVersion !== subscriptionVersion) {
|
|
2431
|
+
newHandle.unsubscribe();
|
|
2432
|
+
return newHandle;
|
|
2433
|
+
}
|
|
2434
|
+
handle = newHandle;
|
|
2435
|
+
const handleError = newHandle.getError();
|
|
2436
|
+
if (handleError) {
|
|
2437
|
+
cachedState = {
|
|
2438
|
+
...cachedState,
|
|
2439
|
+
error: handleError,
|
|
2440
|
+
isConnected: false
|
|
2441
|
+
};
|
|
2442
|
+
} else {
|
|
2443
|
+
updateStateFromHandle();
|
|
2444
|
+
cachedState = {
|
|
2445
|
+
...cachedState,
|
|
2446
|
+
isConnected: true
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
notify();
|
|
2450
|
+
return handle;
|
|
2451
|
+
}).catch((err) => {
|
|
2452
|
+
if (thisVersion !== subscriptionVersion) {
|
|
2453
|
+
return null;
|
|
2454
|
+
}
|
|
2455
|
+
cachedState = {
|
|
2456
|
+
...cachedState,
|
|
2457
|
+
error: err,
|
|
2458
|
+
isConnected: false
|
|
2459
|
+
};
|
|
2460
|
+
notify();
|
|
2461
|
+
return null;
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
subscribers.add(callbackOrVoid);
|
|
2465
|
+
return () => {
|
|
2466
|
+
subscribers.delete(callbackOrVoid);
|
|
2467
|
+
};
|
|
2468
|
+
}),
|
|
2469
|
+
emit: async (message) => {
|
|
2470
|
+
const ctx = createContext();
|
|
2471
|
+
ctx.message = message;
|
|
2472
|
+
return adapter.emit(ctx);
|
|
2473
|
+
},
|
|
2474
|
+
unsubscribe: () => {
|
|
2475
|
+
subscriptionVersion++;
|
|
2476
|
+
if (handle) {
|
|
2477
|
+
handle.unsubscribe();
|
|
2478
|
+
handle = null;
|
|
2479
|
+
}
|
|
2480
|
+
cachedState = {
|
|
2481
|
+
...cachedState,
|
|
2482
|
+
isConnected: false
|
|
2483
|
+
};
|
|
2484
|
+
notify();
|
|
2485
|
+
},
|
|
2486
|
+
getState: () => cachedState,
|
|
2487
|
+
mount: () => {
|
|
2488
|
+
},
|
|
2489
|
+
unmount: () => {
|
|
2490
|
+
subscriptionVersion++;
|
|
2491
|
+
if (handle) {
|
|
2492
|
+
handle.unsubscribe();
|
|
2493
|
+
handle = null;
|
|
2494
|
+
}
|
|
2495
|
+
cachedState = {
|
|
2496
|
+
...cachedState,
|
|
2497
|
+
isConnected: false
|
|
2498
|
+
};
|
|
2499
|
+
notify();
|
|
2500
|
+
},
|
|
2501
|
+
setDisconnected: () => {
|
|
2502
|
+
cachedState = {
|
|
2503
|
+
...cachedState,
|
|
2504
|
+
isConnected: false
|
|
2505
|
+
};
|
|
2506
|
+
notify();
|
|
2507
|
+
}
|
|
2508
|
+
};
|
|
2509
|
+
}
|