@spoosh/core 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +11 -7
- package/dist/index.d.ts +11 -7
- package/dist/index.js +49 -41
- package/dist/index.mjs +49 -41
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -287,9 +287,10 @@ type PluginHandler<TData = unknown, TError = unknown> = (context: PluginContext<
|
|
|
287
287
|
type PluginUpdateHandler<TData = unknown, TError = unknown> = (context: PluginContext<TData, TError>, previousContext: PluginContext<TData, TError>) => void | Promise<void>;
|
|
288
288
|
/**
|
|
289
289
|
* Handler called after every response, regardless of early returns from middleware.
|
|
290
|
-
*
|
|
290
|
+
* Can return a new response to transform it, or void for side effects only.
|
|
291
|
+
* Returned responses are chained through plugins in order.
|
|
291
292
|
*/
|
|
292
|
-
type PluginResponseHandler<TData = unknown, TError = unknown> = (context: PluginContext<TData, TError>, response: SpooshResponse<TData, TError>) => void | Promise<void>;
|
|
293
|
+
type PluginResponseHandler<TData = unknown, TError = unknown> = (context: PluginContext<TData, TError>, response: SpooshResponse<TData, TError>) => SpooshResponse<TData, TError> | void | Promise<SpooshResponse<TData, TError> | void>;
|
|
293
294
|
type PluginLifecycle<TData = unknown, TError = unknown> = {
|
|
294
295
|
/** Called on component mount */
|
|
295
296
|
onMount?: PluginHandler<TData, TError>;
|
|
@@ -333,7 +334,7 @@ type PluginTypeConfig = {
|
|
|
333
334
|
*
|
|
334
335
|
* Plugins can implement:
|
|
335
336
|
* - `middleware`: Wraps the fetch flow for full control (intercept, retry, transform)
|
|
336
|
-
* - `
|
|
337
|
+
* - `afterResponse`: Called after every response, regardless of early returns
|
|
337
338
|
* - `lifecycle`: Component lifecycle hooks (onMount, onUpdate, onUnmount)
|
|
338
339
|
* - `exports`: Functions/variables accessible to other plugins
|
|
339
340
|
*
|
|
@@ -353,7 +354,7 @@ type PluginTypeConfig = {
|
|
|
353
354
|
* const result = await next();
|
|
354
355
|
* return result;
|
|
355
356
|
* },
|
|
356
|
-
*
|
|
357
|
+
* afterResponse(context, response) {
|
|
357
358
|
* // Always runs after response
|
|
358
359
|
* },
|
|
359
360
|
* lifecycle: {
|
|
@@ -370,8 +371,11 @@ interface SpooshPlugin<T extends PluginTypeConfig = PluginTypeConfig> {
|
|
|
370
371
|
operations: OperationType[];
|
|
371
372
|
/** Middleware for controlling the fetch flow. Called in plugin order, composing a chain. */
|
|
372
373
|
middleware?: PluginMiddleware;
|
|
373
|
-
/**
|
|
374
|
-
|
|
374
|
+
/**
|
|
375
|
+
* Called after middleware chain completes, regardless of early returns.
|
|
376
|
+
* Return a new response to transform it, or void for side effects only.
|
|
377
|
+
*/
|
|
378
|
+
afterResponse?: PluginResponseHandler;
|
|
375
379
|
/** Component lifecycle hooks (setup, cleanup, option changes) */
|
|
376
380
|
lifecycle?: PluginLifecycle;
|
|
377
381
|
/** Expose functions/variables for other plugins to access via `context.plugins.get(name)` */
|
|
@@ -568,7 +572,7 @@ type PluginExecutor = {
|
|
|
568
572
|
executeLifecycle: <TData, TError>(phase: "onMount" | "onUnmount", operationType: OperationType, context: PluginContext<TData, TError>) => Promise<void>;
|
|
569
573
|
/** Execute onUpdate lifecycle with previous context */
|
|
570
574
|
executeUpdateLifecycle: <TData, TError>(operationType: OperationType, context: PluginContext<TData, TError>, previousContext: PluginContext<TData, TError>) => Promise<void>;
|
|
571
|
-
/** Execute middleware chain with a core fetch function, then run
|
|
575
|
+
/** Execute middleware chain with a core fetch function, then run afterResponse handlers */
|
|
572
576
|
executeMiddleware: <TData, TError>(operationType: OperationType, context: PluginContext<TData, TError>, coreFetch: () => Promise<SpooshResponse<TData, TError>>) => Promise<SpooshResponse<TData, TError>>;
|
|
573
577
|
getPlugins: () => readonly SpooshPlugin[];
|
|
574
578
|
/** Creates a full PluginContext with plugins accessor injected */
|
package/dist/index.d.ts
CHANGED
|
@@ -287,9 +287,10 @@ type PluginHandler<TData = unknown, TError = unknown> = (context: PluginContext<
|
|
|
287
287
|
type PluginUpdateHandler<TData = unknown, TError = unknown> = (context: PluginContext<TData, TError>, previousContext: PluginContext<TData, TError>) => void | Promise<void>;
|
|
288
288
|
/**
|
|
289
289
|
* Handler called after every response, regardless of early returns from middleware.
|
|
290
|
-
*
|
|
290
|
+
* Can return a new response to transform it, or void for side effects only.
|
|
291
|
+
* Returned responses are chained through plugins in order.
|
|
291
292
|
*/
|
|
292
|
-
type PluginResponseHandler<TData = unknown, TError = unknown> = (context: PluginContext<TData, TError>, response: SpooshResponse<TData, TError>) => void | Promise<void>;
|
|
293
|
+
type PluginResponseHandler<TData = unknown, TError = unknown> = (context: PluginContext<TData, TError>, response: SpooshResponse<TData, TError>) => SpooshResponse<TData, TError> | void | Promise<SpooshResponse<TData, TError> | void>;
|
|
293
294
|
type PluginLifecycle<TData = unknown, TError = unknown> = {
|
|
294
295
|
/** Called on component mount */
|
|
295
296
|
onMount?: PluginHandler<TData, TError>;
|
|
@@ -333,7 +334,7 @@ type PluginTypeConfig = {
|
|
|
333
334
|
*
|
|
334
335
|
* Plugins can implement:
|
|
335
336
|
* - `middleware`: Wraps the fetch flow for full control (intercept, retry, transform)
|
|
336
|
-
* - `
|
|
337
|
+
* - `afterResponse`: Called after every response, regardless of early returns
|
|
337
338
|
* - `lifecycle`: Component lifecycle hooks (onMount, onUpdate, onUnmount)
|
|
338
339
|
* - `exports`: Functions/variables accessible to other plugins
|
|
339
340
|
*
|
|
@@ -353,7 +354,7 @@ type PluginTypeConfig = {
|
|
|
353
354
|
* const result = await next();
|
|
354
355
|
* return result;
|
|
355
356
|
* },
|
|
356
|
-
*
|
|
357
|
+
* afterResponse(context, response) {
|
|
357
358
|
* // Always runs after response
|
|
358
359
|
* },
|
|
359
360
|
* lifecycle: {
|
|
@@ -370,8 +371,11 @@ interface SpooshPlugin<T extends PluginTypeConfig = PluginTypeConfig> {
|
|
|
370
371
|
operations: OperationType[];
|
|
371
372
|
/** Middleware for controlling the fetch flow. Called in plugin order, composing a chain. */
|
|
372
373
|
middleware?: PluginMiddleware;
|
|
373
|
-
/**
|
|
374
|
-
|
|
374
|
+
/**
|
|
375
|
+
* Called after middleware chain completes, regardless of early returns.
|
|
376
|
+
* Return a new response to transform it, or void for side effects only.
|
|
377
|
+
*/
|
|
378
|
+
afterResponse?: PluginResponseHandler;
|
|
375
379
|
/** Component lifecycle hooks (setup, cleanup, option changes) */
|
|
376
380
|
lifecycle?: PluginLifecycle;
|
|
377
381
|
/** Expose functions/variables for other plugins to access via `context.plugins.get(name)` */
|
|
@@ -568,7 +572,7 @@ type PluginExecutor = {
|
|
|
568
572
|
executeLifecycle: <TData, TError>(phase: "onMount" | "onUnmount", operationType: OperationType, context: PluginContext<TData, TError>) => Promise<void>;
|
|
569
573
|
/** Execute onUpdate lifecycle with previous context */
|
|
570
574
|
executeUpdateLifecycle: <TData, TError>(operationType: OperationType, context: PluginContext<TData, TError>, previousContext: PluginContext<TData, TError>) => Promise<void>;
|
|
571
|
-
/** Execute middleware chain with a core fetch function, then run
|
|
575
|
+
/** Execute middleware chain with a core fetch function, then run afterResponse handlers */
|
|
572
576
|
executeMiddleware: <TData, TError>(operationType: OperationType, context: PluginContext<TData, TError>, coreFetch: () => Promise<SpooshResponse<TData, TError>>) => Promise<SpooshResponse<TData, TError>>;
|
|
573
577
|
getPlugins: () => readonly SpooshPlugin[];
|
|
574
578
|
/** Creates a full PluginContext with plugins accessor injected */
|
package/dist/index.js
CHANGED
|
@@ -836,11 +836,14 @@ function createPluginExecutor(initialPlugins = []) {
|
|
|
836
836
|
response = await chain();
|
|
837
837
|
}
|
|
838
838
|
for (const plugin of applicablePlugins) {
|
|
839
|
-
if (plugin.
|
|
840
|
-
await plugin.
|
|
839
|
+
if (plugin.afterResponse) {
|
|
840
|
+
const newResponse = await plugin.afterResponse(
|
|
841
841
|
context,
|
|
842
842
|
response
|
|
843
843
|
);
|
|
844
|
+
if (newResponse) {
|
|
845
|
+
response = newResponse;
|
|
846
|
+
}
|
|
844
847
|
}
|
|
845
848
|
}
|
|
846
849
|
return response;
|
|
@@ -1144,12 +1147,14 @@ function createOperationController(options) {
|
|
|
1144
1147
|
const cached = stateManager.getCache(queryKey);
|
|
1145
1148
|
if (cached) {
|
|
1146
1149
|
stateManager.setCache(queryKey, {
|
|
1147
|
-
state: { ...cached.state, ...updater }
|
|
1150
|
+
state: { ...cached.state, ...updater },
|
|
1151
|
+
stale: false
|
|
1148
1152
|
});
|
|
1149
1153
|
} else {
|
|
1150
1154
|
stateManager.setCache(queryKey, {
|
|
1151
1155
|
state: { ...createInitialState(), ...updater },
|
|
1152
|
-
tags
|
|
1156
|
+
tags,
|
|
1157
|
+
stale: false
|
|
1153
1158
|
});
|
|
1154
1159
|
}
|
|
1155
1160
|
};
|
|
@@ -1175,13 +1180,6 @@ function createOperationController(options) {
|
|
|
1175
1180
|
try {
|
|
1176
1181
|
const response = await fetchFn(context.requestOptions);
|
|
1177
1182
|
context.response = response;
|
|
1178
|
-
if (response.data !== void 0 && !response.error) {
|
|
1179
|
-
updateState({
|
|
1180
|
-
data: response.data,
|
|
1181
|
-
error: void 0,
|
|
1182
|
-
timestamp: Date.now()
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1185
1183
|
return response;
|
|
1186
1184
|
} catch (err) {
|
|
1187
1185
|
const errorResponse = {
|
|
@@ -1199,11 +1197,19 @@ function createOperationController(options) {
|
|
|
1199
1197
|
});
|
|
1200
1198
|
return fetchPromise;
|
|
1201
1199
|
};
|
|
1202
|
-
|
|
1200
|
+
const finalResponse = await pluginExecutor.executeMiddleware(
|
|
1203
1201
|
operationType,
|
|
1204
1202
|
context,
|
|
1205
1203
|
coreFetch
|
|
1206
1204
|
);
|
|
1205
|
+
if (finalResponse.data !== void 0 && !finalResponse.error) {
|
|
1206
|
+
updateState({
|
|
1207
|
+
data: finalResponse.data,
|
|
1208
|
+
error: void 0,
|
|
1209
|
+
timestamp: Date.now()
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
return finalResponse;
|
|
1207
1213
|
},
|
|
1208
1214
|
getState() {
|
|
1209
1215
|
const cached = stateManager.getCache(queryKey);
|
|
@@ -1462,34 +1468,6 @@ function createInfiniteReadController(options) {
|
|
|
1462
1468
|
aborted: true
|
|
1463
1469
|
};
|
|
1464
1470
|
}
|
|
1465
|
-
if (response.data !== void 0 && !response.error) {
|
|
1466
|
-
pageRequests.set(pageKey, mergedRequest);
|
|
1467
|
-
if (direction === "next") {
|
|
1468
|
-
if (!pageKeys.includes(pageKey)) {
|
|
1469
|
-
pageKeys = [...pageKeys, pageKey];
|
|
1470
|
-
}
|
|
1471
|
-
} else {
|
|
1472
|
-
if (!pageKeys.includes(pageKey)) {
|
|
1473
|
-
pageKeys = [pageKey, ...pageKeys];
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
saveToTracker();
|
|
1477
|
-
subscribeToPages();
|
|
1478
|
-
stateManager.setCache(pageKey, {
|
|
1479
|
-
state: {
|
|
1480
|
-
data: response.data,
|
|
1481
|
-
error: void 0,
|
|
1482
|
-
timestamp: Date.now()
|
|
1483
|
-
},
|
|
1484
|
-
tags,
|
|
1485
|
-
stale: false
|
|
1486
|
-
});
|
|
1487
|
-
}
|
|
1488
|
-
if (response.data !== void 0 && !response.error) {
|
|
1489
|
-
latestError = void 0;
|
|
1490
|
-
} else if (response.error) {
|
|
1491
|
-
latestError = response.error;
|
|
1492
|
-
}
|
|
1493
1471
|
return response;
|
|
1494
1472
|
} catch (err) {
|
|
1495
1473
|
if (signal.aborted) {
|
|
@@ -1517,7 +1495,37 @@ function createInfiniteReadController(options) {
|
|
|
1517
1495
|
stateManager.setPendingPromise(pageKey, fetchPromise);
|
|
1518
1496
|
return fetchPromise;
|
|
1519
1497
|
};
|
|
1520
|
-
await pluginExecutor.executeMiddleware(
|
|
1498
|
+
const finalResponse = await pluginExecutor.executeMiddleware(
|
|
1499
|
+
"infiniteRead",
|
|
1500
|
+
context,
|
|
1501
|
+
coreFetch
|
|
1502
|
+
);
|
|
1503
|
+
if (finalResponse.data !== void 0 && !finalResponse.error) {
|
|
1504
|
+
pageRequests.set(pageKey, mergedRequest);
|
|
1505
|
+
if (direction === "next") {
|
|
1506
|
+
if (!pageKeys.includes(pageKey)) {
|
|
1507
|
+
pageKeys = [...pageKeys, pageKey];
|
|
1508
|
+
}
|
|
1509
|
+
} else {
|
|
1510
|
+
if (!pageKeys.includes(pageKey)) {
|
|
1511
|
+
pageKeys = [pageKey, ...pageKeys];
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
saveToTracker();
|
|
1515
|
+
subscribeToPages();
|
|
1516
|
+
stateManager.setCache(pageKey, {
|
|
1517
|
+
state: {
|
|
1518
|
+
data: finalResponse.data,
|
|
1519
|
+
error: void 0,
|
|
1520
|
+
timestamp: Date.now()
|
|
1521
|
+
},
|
|
1522
|
+
tags,
|
|
1523
|
+
stale: false
|
|
1524
|
+
});
|
|
1525
|
+
latestError = void 0;
|
|
1526
|
+
} else if (finalResponse.error) {
|
|
1527
|
+
latestError = finalResponse.error;
|
|
1528
|
+
}
|
|
1521
1529
|
};
|
|
1522
1530
|
const controller = {
|
|
1523
1531
|
getState() {
|
package/dist/index.mjs
CHANGED
|
@@ -780,11 +780,14 @@ function createPluginExecutor(initialPlugins = []) {
|
|
|
780
780
|
response = await chain();
|
|
781
781
|
}
|
|
782
782
|
for (const plugin of applicablePlugins) {
|
|
783
|
-
if (plugin.
|
|
784
|
-
await plugin.
|
|
783
|
+
if (plugin.afterResponse) {
|
|
784
|
+
const newResponse = await plugin.afterResponse(
|
|
785
785
|
context,
|
|
786
786
|
response
|
|
787
787
|
);
|
|
788
|
+
if (newResponse) {
|
|
789
|
+
response = newResponse;
|
|
790
|
+
}
|
|
788
791
|
}
|
|
789
792
|
}
|
|
790
793
|
return response;
|
|
@@ -1088,12 +1091,14 @@ function createOperationController(options) {
|
|
|
1088
1091
|
const cached = stateManager.getCache(queryKey);
|
|
1089
1092
|
if (cached) {
|
|
1090
1093
|
stateManager.setCache(queryKey, {
|
|
1091
|
-
state: { ...cached.state, ...updater }
|
|
1094
|
+
state: { ...cached.state, ...updater },
|
|
1095
|
+
stale: false
|
|
1092
1096
|
});
|
|
1093
1097
|
} else {
|
|
1094
1098
|
stateManager.setCache(queryKey, {
|
|
1095
1099
|
state: { ...createInitialState(), ...updater },
|
|
1096
|
-
tags
|
|
1100
|
+
tags,
|
|
1101
|
+
stale: false
|
|
1097
1102
|
});
|
|
1098
1103
|
}
|
|
1099
1104
|
};
|
|
@@ -1119,13 +1124,6 @@ function createOperationController(options) {
|
|
|
1119
1124
|
try {
|
|
1120
1125
|
const response = await fetchFn(context.requestOptions);
|
|
1121
1126
|
context.response = response;
|
|
1122
|
-
if (response.data !== void 0 && !response.error) {
|
|
1123
|
-
updateState({
|
|
1124
|
-
data: response.data,
|
|
1125
|
-
error: void 0,
|
|
1126
|
-
timestamp: Date.now()
|
|
1127
|
-
});
|
|
1128
|
-
}
|
|
1129
1127
|
return response;
|
|
1130
1128
|
} catch (err) {
|
|
1131
1129
|
const errorResponse = {
|
|
@@ -1143,11 +1141,19 @@ function createOperationController(options) {
|
|
|
1143
1141
|
});
|
|
1144
1142
|
return fetchPromise;
|
|
1145
1143
|
};
|
|
1146
|
-
|
|
1144
|
+
const finalResponse = await pluginExecutor.executeMiddleware(
|
|
1147
1145
|
operationType,
|
|
1148
1146
|
context,
|
|
1149
1147
|
coreFetch
|
|
1150
1148
|
);
|
|
1149
|
+
if (finalResponse.data !== void 0 && !finalResponse.error) {
|
|
1150
|
+
updateState({
|
|
1151
|
+
data: finalResponse.data,
|
|
1152
|
+
error: void 0,
|
|
1153
|
+
timestamp: Date.now()
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
return finalResponse;
|
|
1151
1157
|
},
|
|
1152
1158
|
getState() {
|
|
1153
1159
|
const cached = stateManager.getCache(queryKey);
|
|
@@ -1406,34 +1412,6 @@ function createInfiniteReadController(options) {
|
|
|
1406
1412
|
aborted: true
|
|
1407
1413
|
};
|
|
1408
1414
|
}
|
|
1409
|
-
if (response.data !== void 0 && !response.error) {
|
|
1410
|
-
pageRequests.set(pageKey, mergedRequest);
|
|
1411
|
-
if (direction === "next") {
|
|
1412
|
-
if (!pageKeys.includes(pageKey)) {
|
|
1413
|
-
pageKeys = [...pageKeys, pageKey];
|
|
1414
|
-
}
|
|
1415
|
-
} else {
|
|
1416
|
-
if (!pageKeys.includes(pageKey)) {
|
|
1417
|
-
pageKeys = [pageKey, ...pageKeys];
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
saveToTracker();
|
|
1421
|
-
subscribeToPages();
|
|
1422
|
-
stateManager.setCache(pageKey, {
|
|
1423
|
-
state: {
|
|
1424
|
-
data: response.data,
|
|
1425
|
-
error: void 0,
|
|
1426
|
-
timestamp: Date.now()
|
|
1427
|
-
},
|
|
1428
|
-
tags,
|
|
1429
|
-
stale: false
|
|
1430
|
-
});
|
|
1431
|
-
}
|
|
1432
|
-
if (response.data !== void 0 && !response.error) {
|
|
1433
|
-
latestError = void 0;
|
|
1434
|
-
} else if (response.error) {
|
|
1435
|
-
latestError = response.error;
|
|
1436
|
-
}
|
|
1437
1415
|
return response;
|
|
1438
1416
|
} catch (err) {
|
|
1439
1417
|
if (signal.aborted) {
|
|
@@ -1461,7 +1439,37 @@ function createInfiniteReadController(options) {
|
|
|
1461
1439
|
stateManager.setPendingPromise(pageKey, fetchPromise);
|
|
1462
1440
|
return fetchPromise;
|
|
1463
1441
|
};
|
|
1464
|
-
await pluginExecutor.executeMiddleware(
|
|
1442
|
+
const finalResponse = await pluginExecutor.executeMiddleware(
|
|
1443
|
+
"infiniteRead",
|
|
1444
|
+
context,
|
|
1445
|
+
coreFetch
|
|
1446
|
+
);
|
|
1447
|
+
if (finalResponse.data !== void 0 && !finalResponse.error) {
|
|
1448
|
+
pageRequests.set(pageKey, mergedRequest);
|
|
1449
|
+
if (direction === "next") {
|
|
1450
|
+
if (!pageKeys.includes(pageKey)) {
|
|
1451
|
+
pageKeys = [...pageKeys, pageKey];
|
|
1452
|
+
}
|
|
1453
|
+
} else {
|
|
1454
|
+
if (!pageKeys.includes(pageKey)) {
|
|
1455
|
+
pageKeys = [pageKey, ...pageKeys];
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
saveToTracker();
|
|
1459
|
+
subscribeToPages();
|
|
1460
|
+
stateManager.setCache(pageKey, {
|
|
1461
|
+
state: {
|
|
1462
|
+
data: finalResponse.data,
|
|
1463
|
+
error: void 0,
|
|
1464
|
+
timestamp: Date.now()
|
|
1465
|
+
},
|
|
1466
|
+
tags,
|
|
1467
|
+
stale: false
|
|
1468
|
+
});
|
|
1469
|
+
latestError = void 0;
|
|
1470
|
+
} else if (finalResponse.error) {
|
|
1471
|
+
latestError = finalResponse.error;
|
|
1472
|
+
}
|
|
1465
1473
|
};
|
|
1466
1474
|
const controller = {
|
|
1467
1475
|
getState() {
|