@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.mjs
CHANGED
|
@@ -646,7 +646,7 @@ function createSelectorProxy(onCapture) {
|
|
|
646
646
|
{},
|
|
647
647
|
{
|
|
648
648
|
get(_, prop) {
|
|
649
|
-
if (
|
|
649
|
+
if (typeof prop === "string" && prop === prop.toUpperCase()) {
|
|
650
650
|
const selectorFn = (options) => {
|
|
651
651
|
onCapture?.({
|
|
652
652
|
call: { path, method: prop, options },
|
|
@@ -689,7 +689,19 @@ function createInitialState() {
|
|
|
689
689
|
function generateSelfTagFromKey(key) {
|
|
690
690
|
try {
|
|
691
691
|
const parsed = JSON.parse(key);
|
|
692
|
-
|
|
692
|
+
const rawPath = parsed.path;
|
|
693
|
+
if (!rawPath) return void 0;
|
|
694
|
+
const path = Array.isArray(rawPath) ? rawPath.join("/") : rawPath;
|
|
695
|
+
const params = parsed.options?.params ?? parsed.pageRequest?.params;
|
|
696
|
+
if (!params) return path;
|
|
697
|
+
return path.split("/").map((segment) => {
|
|
698
|
+
if (segment.startsWith(":")) {
|
|
699
|
+
const paramName = segment.slice(1);
|
|
700
|
+
const value = params[paramName];
|
|
701
|
+
return value !== void 0 ? String(value) : segment;
|
|
702
|
+
}
|
|
703
|
+
return segment;
|
|
704
|
+
}).join("/");
|
|
693
705
|
} catch {
|
|
694
706
|
return void 0;
|
|
695
707
|
}
|
|
@@ -926,7 +938,7 @@ function createPluginExecutor(initialPlugins = []) {
|
|
|
926
938
|
const createPluginAccessor = (context) => ({
|
|
927
939
|
get(name) {
|
|
928
940
|
const plugin = plugins.find((p) => p.name === name);
|
|
929
|
-
return plugin?.
|
|
941
|
+
return plugin?.internal?.(context);
|
|
930
942
|
}
|
|
931
943
|
});
|
|
932
944
|
const executeLifecycleImpl = async (phase, operationType, context) => {
|
|
@@ -993,6 +1005,9 @@ function createPluginExecutor(initialPlugins = []) {
|
|
|
993
1005
|
getPlugins() {
|
|
994
1006
|
return frozenPlugins;
|
|
995
1007
|
},
|
|
1008
|
+
getPluginsForOperation(operationType) {
|
|
1009
|
+
return frozenPlugins.filter((p) => p.operations.includes(operationType));
|
|
1010
|
+
},
|
|
996
1011
|
registerContextEnhancer(enhancer) {
|
|
997
1012
|
contextEnhancers.push(enhancer);
|
|
998
1013
|
},
|
|
@@ -1025,6 +1040,7 @@ var Spoosh = class _Spoosh {
|
|
|
1025
1040
|
baseUrl;
|
|
1026
1041
|
defaultOptions;
|
|
1027
1042
|
_plugins;
|
|
1043
|
+
_transports = /* @__PURE__ */ new Map();
|
|
1028
1044
|
/**
|
|
1029
1045
|
* Creates a new Spoosh instance.
|
|
1030
1046
|
*
|
|
@@ -1049,10 +1065,13 @@ var Spoosh = class _Spoosh {
|
|
|
1049
1065
|
* });
|
|
1050
1066
|
* ```
|
|
1051
1067
|
*/
|
|
1052
|
-
constructor(baseUrl, defaultOptions, plugins) {
|
|
1068
|
+
constructor(baseUrl, defaultOptions, plugins, transports) {
|
|
1053
1069
|
this.baseUrl = baseUrl;
|
|
1054
1070
|
this.defaultOptions = defaultOptions || {};
|
|
1055
1071
|
this._plugins = plugins || [];
|
|
1072
|
+
if (transports) {
|
|
1073
|
+
this._transports = transports;
|
|
1074
|
+
}
|
|
1056
1075
|
}
|
|
1057
1076
|
/**
|
|
1058
1077
|
* Adds plugins to the Spoosh instance.
|
|
@@ -1076,8 +1095,37 @@ var Spoosh = class _Spoosh {
|
|
|
1076
1095
|
return new _Spoosh(
|
|
1077
1096
|
this.baseUrl,
|
|
1078
1097
|
this.defaultOptions,
|
|
1079
|
-
plugins
|
|
1098
|
+
plugins,
|
|
1099
|
+
this._transports
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Registers transport implementations for real-time operations.
|
|
1104
|
+
*
|
|
1105
|
+
* @param transports - Array of transport instances to register
|
|
1106
|
+
* @returns This Spoosh instance for method chaining
|
|
1107
|
+
*
|
|
1108
|
+
* @example
|
|
1109
|
+
* ```ts
|
|
1110
|
+
* import { sse } from '@spoosh/transport-sse';
|
|
1111
|
+
*
|
|
1112
|
+
* const spoosh = new Spoosh<Schema, Error>('/api')
|
|
1113
|
+
* .withTransports([sse()])
|
|
1114
|
+
* .use([...]);
|
|
1115
|
+
* ```
|
|
1116
|
+
*/
|
|
1117
|
+
withTransports(transports) {
|
|
1118
|
+
const newTransports = new Map(this._transports);
|
|
1119
|
+
for (const transport of transports) {
|
|
1120
|
+
newTransports.set(transport.name, transport);
|
|
1121
|
+
}
|
|
1122
|
+
const instance = new _Spoosh(
|
|
1123
|
+
this.baseUrl,
|
|
1124
|
+
this.defaultOptions,
|
|
1125
|
+
this._plugins,
|
|
1126
|
+
newTransports
|
|
1080
1127
|
);
|
|
1128
|
+
return instance;
|
|
1081
1129
|
}
|
|
1082
1130
|
/**
|
|
1083
1131
|
* Cached instance of the underlying SpooshInstance.
|
|
@@ -1104,6 +1152,7 @@ var Spoosh = class _Spoosh {
|
|
|
1104
1152
|
stateManager,
|
|
1105
1153
|
eventEmitter,
|
|
1106
1154
|
pluginExecutor,
|
|
1155
|
+
transports: this._transports,
|
|
1107
1156
|
config: {
|
|
1108
1157
|
baseUrl: this.baseUrl,
|
|
1109
1158
|
defaultOptions: this.defaultOptions
|
|
@@ -1111,7 +1160,8 @@ var Spoosh = class _Spoosh {
|
|
|
1111
1160
|
_types: {
|
|
1112
1161
|
schema: void 0,
|
|
1113
1162
|
defaultError: void 0,
|
|
1114
|
-
plugins: this._plugins
|
|
1163
|
+
plugins: this._plugins,
|
|
1164
|
+
transports: void 0
|
|
1115
1165
|
}
|
|
1116
1166
|
};
|
|
1117
1167
|
}
|
|
@@ -1221,6 +1271,18 @@ var Spoosh = class _Spoosh {
|
|
|
1221
1271
|
get _types() {
|
|
1222
1272
|
return this.getInstance()._types;
|
|
1223
1273
|
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Map of registered transport implementations.
|
|
1276
|
+
*
|
|
1277
|
+
* @example
|
|
1278
|
+
* ```ts
|
|
1279
|
+
* const { transports } = client;
|
|
1280
|
+
* const sseTransport = transports.get('sse');
|
|
1281
|
+
* ```
|
|
1282
|
+
*/
|
|
1283
|
+
get transports() {
|
|
1284
|
+
return this.getInstance().transports;
|
|
1285
|
+
}
|
|
1224
1286
|
};
|
|
1225
1287
|
|
|
1226
1288
|
// src/createClient.ts
|
|
@@ -1232,6 +1294,16 @@ function createClient(baseUrl, defaultOptions) {
|
|
|
1232
1294
|
});
|
|
1233
1295
|
}
|
|
1234
1296
|
|
|
1297
|
+
// src/transport/compose.ts
|
|
1298
|
+
function composeAdapter(baseAdapter, plugins) {
|
|
1299
|
+
return plugins.reduce((adapter, plugin) => {
|
|
1300
|
+
if (plugin.wrapAdapter) {
|
|
1301
|
+
return plugin.wrapAdapter(adapter);
|
|
1302
|
+
}
|
|
1303
|
+
return adapter;
|
|
1304
|
+
}, baseAdapter);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1235
1307
|
// src/controllers/base/controller.ts
|
|
1236
1308
|
function createOperationController(options) {
|
|
1237
1309
|
const {
|
|
@@ -2175,6 +2247,193 @@ function createQueueController(config, context) {
|
|
|
2175
2247
|
}
|
|
2176
2248
|
};
|
|
2177
2249
|
}
|
|
2250
|
+
|
|
2251
|
+
// src/controllers/subscription/controller.ts
|
|
2252
|
+
function createSubscriptionController(options) {
|
|
2253
|
+
const {
|
|
2254
|
+
channel,
|
|
2255
|
+
baseAdapter,
|
|
2256
|
+
pluginExecutor,
|
|
2257
|
+
operationType,
|
|
2258
|
+
stateManager,
|
|
2259
|
+
eventEmitter,
|
|
2260
|
+
queryKey,
|
|
2261
|
+
path,
|
|
2262
|
+
method,
|
|
2263
|
+
instanceId
|
|
2264
|
+
} = options;
|
|
2265
|
+
const plugins = pluginExecutor.getPluginsForOperation(operationType);
|
|
2266
|
+
const adapter = composeAdapter(
|
|
2267
|
+
baseAdapter,
|
|
2268
|
+
plugins
|
|
2269
|
+
);
|
|
2270
|
+
let handle = null;
|
|
2271
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
2272
|
+
let subscriptionVersion = 0;
|
|
2273
|
+
let cachedState = {
|
|
2274
|
+
data: void 0,
|
|
2275
|
+
error: void 0,
|
|
2276
|
+
isConnected: false
|
|
2277
|
+
};
|
|
2278
|
+
const updateStateFromHandle = () => {
|
|
2279
|
+
if (!handle) return;
|
|
2280
|
+
const newData = handle.getData();
|
|
2281
|
+
const newError = handle.getError();
|
|
2282
|
+
if (newData !== cachedState.data || newError !== cachedState.error) {
|
|
2283
|
+
cachedState = {
|
|
2284
|
+
data: newData,
|
|
2285
|
+
error: newError,
|
|
2286
|
+
isConnected: true
|
|
2287
|
+
};
|
|
2288
|
+
}
|
|
2289
|
+
};
|
|
2290
|
+
const notify = () => {
|
|
2291
|
+
subscribers.forEach((callback) => callback());
|
|
2292
|
+
};
|
|
2293
|
+
const createContext = () => {
|
|
2294
|
+
const baseCtx = pluginExecutor.createContext({
|
|
2295
|
+
operationType,
|
|
2296
|
+
path,
|
|
2297
|
+
method,
|
|
2298
|
+
queryKey,
|
|
2299
|
+
tags: [],
|
|
2300
|
+
requestTimestamp: Date.now(),
|
|
2301
|
+
instanceId,
|
|
2302
|
+
request: { headers: {} },
|
|
2303
|
+
temp: /* @__PURE__ */ new Map(),
|
|
2304
|
+
stateManager,
|
|
2305
|
+
eventEmitter
|
|
2306
|
+
});
|
|
2307
|
+
return {
|
|
2308
|
+
...baseCtx,
|
|
2309
|
+
channel
|
|
2310
|
+
};
|
|
2311
|
+
};
|
|
2312
|
+
return {
|
|
2313
|
+
subscribe: ((callbackOrVoid) => {
|
|
2314
|
+
if (callbackOrVoid === void 0) {
|
|
2315
|
+
subscriptionVersion++;
|
|
2316
|
+
const thisVersion = subscriptionVersion;
|
|
2317
|
+
if (handle) {
|
|
2318
|
+
handle.unsubscribe();
|
|
2319
|
+
handle = null;
|
|
2320
|
+
}
|
|
2321
|
+
cachedState = { data: void 0, error: void 0, isConnected: false };
|
|
2322
|
+
notify();
|
|
2323
|
+
const ctx = createContext();
|
|
2324
|
+
ctx.onData = (data) => {
|
|
2325
|
+
if (thisVersion !== subscriptionVersion) {
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
cachedState = {
|
|
2329
|
+
data,
|
|
2330
|
+
error: cachedState.error,
|
|
2331
|
+
isConnected: true
|
|
2332
|
+
};
|
|
2333
|
+
notify();
|
|
2334
|
+
};
|
|
2335
|
+
ctx.onError = (error) => {
|
|
2336
|
+
if (thisVersion !== subscriptionVersion) {
|
|
2337
|
+
return;
|
|
2338
|
+
}
|
|
2339
|
+
cachedState = {
|
|
2340
|
+
data: cachedState.data,
|
|
2341
|
+
error,
|
|
2342
|
+
isConnected: cachedState.isConnected
|
|
2343
|
+
};
|
|
2344
|
+
notify();
|
|
2345
|
+
};
|
|
2346
|
+
ctx.onDisconnect = () => {
|
|
2347
|
+
if (thisVersion !== subscriptionVersion) {
|
|
2348
|
+
return;
|
|
2349
|
+
}
|
|
2350
|
+
cachedState = {
|
|
2351
|
+
...cachedState,
|
|
2352
|
+
isConnected: false
|
|
2353
|
+
};
|
|
2354
|
+
notify();
|
|
2355
|
+
};
|
|
2356
|
+
return adapter.subscribe(ctx).then((newHandle) => {
|
|
2357
|
+
if (thisVersion !== subscriptionVersion) {
|
|
2358
|
+
newHandle.unsubscribe();
|
|
2359
|
+
return newHandle;
|
|
2360
|
+
}
|
|
2361
|
+
handle = newHandle;
|
|
2362
|
+
const handleError = newHandle.getError();
|
|
2363
|
+
if (handleError) {
|
|
2364
|
+
cachedState = {
|
|
2365
|
+
...cachedState,
|
|
2366
|
+
error: handleError,
|
|
2367
|
+
isConnected: false
|
|
2368
|
+
};
|
|
2369
|
+
} else {
|
|
2370
|
+
updateStateFromHandle();
|
|
2371
|
+
cachedState = {
|
|
2372
|
+
...cachedState,
|
|
2373
|
+
isConnected: true
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
notify();
|
|
2377
|
+
return handle;
|
|
2378
|
+
}).catch((err) => {
|
|
2379
|
+
if (thisVersion !== subscriptionVersion) {
|
|
2380
|
+
return null;
|
|
2381
|
+
}
|
|
2382
|
+
cachedState = {
|
|
2383
|
+
...cachedState,
|
|
2384
|
+
error: err,
|
|
2385
|
+
isConnected: false
|
|
2386
|
+
};
|
|
2387
|
+
notify();
|
|
2388
|
+
return null;
|
|
2389
|
+
});
|
|
2390
|
+
}
|
|
2391
|
+
subscribers.add(callbackOrVoid);
|
|
2392
|
+
return () => {
|
|
2393
|
+
subscribers.delete(callbackOrVoid);
|
|
2394
|
+
};
|
|
2395
|
+
}),
|
|
2396
|
+
emit: async (message) => {
|
|
2397
|
+
const ctx = createContext();
|
|
2398
|
+
ctx.message = message;
|
|
2399
|
+
return adapter.emit(ctx);
|
|
2400
|
+
},
|
|
2401
|
+
unsubscribe: () => {
|
|
2402
|
+
subscriptionVersion++;
|
|
2403
|
+
if (handle) {
|
|
2404
|
+
handle.unsubscribe();
|
|
2405
|
+
handle = null;
|
|
2406
|
+
}
|
|
2407
|
+
cachedState = {
|
|
2408
|
+
...cachedState,
|
|
2409
|
+
isConnected: false
|
|
2410
|
+
};
|
|
2411
|
+
notify();
|
|
2412
|
+
},
|
|
2413
|
+
getState: () => cachedState,
|
|
2414
|
+
mount: () => {
|
|
2415
|
+
},
|
|
2416
|
+
unmount: () => {
|
|
2417
|
+
subscriptionVersion++;
|
|
2418
|
+
if (handle) {
|
|
2419
|
+
handle.unsubscribe();
|
|
2420
|
+
handle = null;
|
|
2421
|
+
}
|
|
2422
|
+
cachedState = {
|
|
2423
|
+
...cachedState,
|
|
2424
|
+
isConnected: false
|
|
2425
|
+
};
|
|
2426
|
+
notify();
|
|
2427
|
+
},
|
|
2428
|
+
setDisconnected: () => {
|
|
2429
|
+
cachedState = {
|
|
2430
|
+
...cachedState,
|
|
2431
|
+
isConnected: false
|
|
2432
|
+
};
|
|
2433
|
+
notify();
|
|
2434
|
+
}
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2178
2437
|
export {
|
|
2179
2438
|
HTTP_METHODS,
|
|
2180
2439
|
Semaphore,
|
|
@@ -2182,6 +2441,7 @@ export {
|
|
|
2182
2441
|
__DEV__,
|
|
2183
2442
|
buildUrl,
|
|
2184
2443
|
clone,
|
|
2444
|
+
composeAdapter,
|
|
2185
2445
|
containsFile,
|
|
2186
2446
|
createClient,
|
|
2187
2447
|
createEventEmitter,
|
|
@@ -2195,12 +2455,14 @@ export {
|
|
|
2195
2455
|
createSelectorProxy,
|
|
2196
2456
|
createSpooshPlugin,
|
|
2197
2457
|
createStateManager,
|
|
2458
|
+
createSubscriptionController,
|
|
2198
2459
|
createTracer,
|
|
2199
2460
|
executeFetch,
|
|
2200
2461
|
extractMethodFromSelector,
|
|
2201
2462
|
extractPathFromSelector,
|
|
2202
2463
|
fetchTransport,
|
|
2203
2464
|
form,
|
|
2465
|
+
generateSelfTagFromKey,
|
|
2204
2466
|
generateTags,
|
|
2205
2467
|
getContentType,
|
|
2206
2468
|
isAbortError,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spoosh/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Type-safe API toolkit with plugin middleware system",
|
|
6
6
|
"keywords": [
|
|
@@ -39,6 +39,6 @@
|
|
|
39
39
|
"build": "tsup",
|
|
40
40
|
"typecheck": "tsc --noEmit",
|
|
41
41
|
"lint": "eslint src --max-warnings 0",
|
|
42
|
-
"format": "prettier --write 'src/**/*.ts'"
|
|
42
|
+
"format": "prettier --write 'src/**/*.ts' '*.md'"
|
|
43
43
|
}
|
|
44
44
|
}
|