@snail-js/api 0.1.27 → 1.0.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/LICENSE +21 -0
- package/README.md +125 -605
- package/dist/adapter/plain.d.ts +12 -0
- package/dist/adapter/plain.d.ts.map +1 -0
- package/dist/adapter/react.d.ts +14 -0
- package/dist/adapter/react.d.ts.map +1 -0
- package/dist/adapter/registry.d.ts +16 -0
- package/dist/adapter/registry.d.ts.map +1 -0
- package/dist/adapter/vue.d.ts +15 -0
- package/dist/adapter/vue.d.ts.map +1 -0
- package/dist/chunks/custom-UchOSg_s.js +466 -0
- package/dist/chunks/custom-UchOSg_s.js.map +1 -0
- package/dist/chunks/download-lBC7oOTT.js +160 -0
- package/dist/chunks/download-lBC7oOTT.js.map +1 -0
- package/dist/chunks/object-Ct0w-h4i.js +74 -0
- package/dist/chunks/object-Ct0w-h4i.js.map +1 -0
- package/dist/chunks/plugin-D3RDffDG.js +742 -0
- package/dist/chunks/plugin-D3RDffDG.js.map +1 -0
- package/dist/chunks/react-C1em-gxy.js +62 -0
- package/dist/chunks/react-C1em-gxy.js.map +1 -0
- package/dist/chunks/request-qeRhihEF.js +40 -0
- package/dist/chunks/request-qeRhihEF.js.map +1 -0
- package/dist/chunks/response-D-ubkAFl.js +127 -0
- package/dist/chunks/response-D-ubkAFl.js.map +1 -0
- package/dist/chunks/use-download-FAjtdJ58.js +1816 -0
- package/dist/chunks/use-download-FAjtdJ58.js.map +1 -0
- package/dist/chunks/vue-Dd9EhkQ3.js +34 -0
- package/dist/chunks/vue-Dd9EhkQ3.js.map +1 -0
- package/dist/core/args.d.ts +54 -0
- package/dist/core/args.d.ts.map +1 -0
- package/dist/core/connection.d.ts +15 -0
- package/dist/core/connection.d.ts.map +1 -0
- package/dist/core/context.d.ts +124 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/http-stream.d.ts +28 -0
- package/dist/core/http-stream.d.ts.map +1 -0
- package/dist/core/logger.d.ts +22 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/metadata.d.ts +92 -0
- package/dist/core/metadata.d.ts.map +1 -0
- package/dist/core/metadata.keys.d.ts +41 -0
- package/dist/core/metadata.keys.d.ts.map +1 -0
- package/dist/core/method.d.ts +177 -0
- package/dist/core/method.d.ts.map +1 -0
- package/dist/core/plugin-manager.d.ts +106 -0
- package/dist/core/plugin-manager.d.ts.map +1 -0
- package/dist/core/plugin.d.ts +113 -0
- package/dist/core/plugin.d.ts.map +1 -0
- package/dist/core/reconnect.d.ts +22 -0
- package/dist/core/reconnect.d.ts.map +1 -0
- package/dist/core/resolve-stream.d.ts +45 -0
- package/dist/core/resolve-stream.d.ts.map +1 -0
- package/dist/core/resolve.d.ts +50 -0
- package/dist/core/resolve.d.ts.map +1 -0
- package/dist/core/response.d.ts +60 -0
- package/dist/core/response.d.ts.map +1 -0
- package/dist/core/server.d.ts +132 -0
- package/dist/core/server.d.ts.map +1 -0
- package/dist/core/sse.d.ts +27 -0
- package/dist/core/sse.d.ts.map +1 -0
- package/dist/core/state-bag.d.ts +36 -0
- package/dist/core/state-bag.d.ts.map +1 -0
- package/dist/core/websocket.d.ts +29 -0
- package/dist/core/websocket.d.ts.map +1 -0
- package/dist/decorators/api.d.ts +24 -4
- package/dist/decorators/api.d.ts.map +1 -0
- package/dist/decorators/args.d.ts +77 -14
- package/dist/decorators/args.d.ts.map +1 -0
- package/dist/decorators/custom.d.ts +81 -0
- package/dist/decorators/custom.d.ts.map +1 -0
- package/dist/decorators/header.d.ts +22 -0
- package/dist/decorators/header.d.ts.map +1 -0
- package/dist/decorators/index.d.ts +17 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/dist/decorators/methods.d.ts +33 -0
- package/dist/decorators/methods.d.ts.map +1 -0
- package/dist/decorators/progress.d.ts +24 -6
- package/dist/decorators/progress.d.ts.map +1 -0
- package/dist/decorators/server.d.ts +28 -7
- package/dist/decorators/server.d.ts.map +1 -0
- package/dist/decorators/stream.d.ts +113 -0
- package/dist/decorators/stream.d.ts.map +1 -0
- package/dist/default/options.d.ts +19 -0
- package/dist/default/options.d.ts.map +1 -0
- package/dist/error/base.d.ts +20 -0
- package/dist/error/base.d.ts.map +1 -0
- package/dist/error/decorator.d.ts +14 -0
- package/dist/error/decorator.d.ts.map +1 -0
- package/dist/error/hook.d.ts +14 -0
- package/dist/error/hook.d.ts.map +1 -0
- package/dist/error/index.d.ts +8 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/error/options.d.ts +12 -0
- package/dist/error/options.d.ts.map +1 -0
- package/dist/error/plugin.d.ts +11 -0
- package/dist/error/plugin.d.ts.map +1 -0
- package/dist/error/request.d.ts +29 -0
- package/dist/error/request.d.ts.map +1 -0
- package/dist/error/response.d.ts +36 -0
- package/dist/error/response.d.ts.map +1 -0
- package/dist/index.d.ts +56 -11
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2034 -0
- package/dist/index.js.map +1 -0
- package/dist/locale/en.d.ts +5 -0
- package/dist/locale/en.d.ts.map +1 -0
- package/dist/locale/index.d.ts +57 -0
- package/dist/locale/index.d.ts.map +1 -0
- package/dist/locale/types.d.ts +11 -0
- package/dist/locale/types.d.ts.map +1 -0
- package/dist/locale/zh.d.ts +5 -0
- package/dist/locale/zh.d.ts.map +1 -0
- package/dist/plugins/cache/adapters/indexeddb.d.ts +52 -0
- package/dist/plugins/cache/adapters/indexeddb.d.ts.map +1 -0
- package/dist/plugins/cache/adapters/memory.d.ts +60 -0
- package/dist/plugins/cache/adapters/memory.d.ts.map +1 -0
- package/dist/plugins/cache/adapters/web-storage.d.ts +43 -0
- package/dist/plugins/cache/adapters/web-storage.d.ts.map +1 -0
- package/dist/plugins/cache/decorators.d.ts +62 -0
- package/dist/plugins/cache/decorators.d.ts.map +1 -0
- package/dist/plugins/cache/index.d.ts +41 -0
- package/dist/plugins/cache/index.d.ts.map +1 -0
- package/dist/plugins/cache/key.d.ts +48 -0
- package/dist/plugins/cache/key.d.ts.map +1 -0
- package/dist/plugins/cache/manager.d.ts +124 -0
- package/dist/plugins/cache/manager.d.ts.map +1 -0
- package/dist/plugins/cache/plugin.d.ts +64 -0
- package/dist/plugins/cache/plugin.d.ts.map +1 -0
- package/dist/plugins/cache/type.d.ts +116 -0
- package/dist/plugins/cache/type.d.ts.map +1 -0
- package/dist/plugins/index.d.ts +75 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +2265 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/interceptor/decorators.d.ts +44 -0
- package/dist/plugins/interceptor/decorators.d.ts.map +1 -0
- package/dist/plugins/interceptor/index.d.ts +31 -0
- package/dist/plugins/interceptor/index.d.ts.map +1 -0
- package/dist/plugins/interceptor/manager.d.ts +27 -0
- package/dist/plugins/interceptor/manager.d.ts.map +1 -0
- package/dist/plugins/interceptor/plugin.d.ts +65 -0
- package/dist/plugins/interceptor/plugin.d.ts.map +1 -0
- package/dist/plugins/interceptor/type.d.ts +45 -0
- package/dist/plugins/interceptor/type.d.ts.map +1 -0
- package/dist/plugins/pool/index.d.ts +26 -0
- package/dist/plugins/pool/index.d.ts.map +1 -0
- package/dist/plugins/pool/plugin.d.ts +83 -0
- package/dist/plugins/pool/plugin.d.ts.map +1 -0
- package/dist/plugins/pool/scheduler.d.ts +153 -0
- package/dist/plugins/pool/scheduler.d.ts.map +1 -0
- package/dist/plugins/pool/type.d.ts +38 -0
- package/dist/plugins/pool/type.d.ts.map +1 -0
- package/dist/plugins/react/index.d.ts +20 -0
- package/dist/plugins/react/index.d.ts.map +1 -0
- package/dist/plugins/react/index.js +145 -0
- package/dist/plugins/react/index.js.map +1 -0
- package/dist/plugins/react/plugin.d.ts +33 -0
- package/dist/plugins/react/plugin.d.ts.map +1 -0
- package/dist/plugins/react/type.d.ts +32 -0
- package/dist/plugins/react/type.d.ts.map +1 -0
- package/dist/plugins/transform/decorators.d.ts +54 -0
- package/dist/plugins/transform/decorators.d.ts.map +1 -0
- package/dist/plugins/transform/hydrate.d.ts +47 -0
- package/dist/plugins/transform/hydrate.d.ts.map +1 -0
- package/dist/plugins/transform/index.d.ts +41 -0
- package/dist/plugins/transform/index.d.ts.map +1 -0
- package/dist/plugins/transform/plugin.d.ts +20 -0
- package/dist/plugins/transform/plugin.d.ts.map +1 -0
- package/dist/plugins/transform/type.d.ts +67 -0
- package/dist/plugins/transform/type.d.ts.map +1 -0
- package/dist/plugins/validate/decorators.d.ts +24 -0
- package/dist/plugins/validate/decorators.d.ts.map +1 -0
- package/dist/plugins/validate/index.d.ts +40 -0
- package/dist/plugins/validate/index.d.ts.map +1 -0
- package/dist/plugins/validate/plugin.d.ts +13 -0
- package/dist/plugins/validate/plugin.d.ts.map +1 -0
- package/dist/plugins/validate/type.d.ts +54 -0
- package/dist/plugins/validate/type.d.ts.map +1 -0
- package/dist/plugins/version/decorators.d.ts +22 -0
- package/dist/plugins/version/decorators.d.ts.map +1 -0
- package/dist/plugins/version/index.d.ts +23 -0
- package/dist/plugins/version/index.d.ts.map +1 -0
- package/dist/plugins/version/plugin.d.ts +13 -0
- package/dist/plugins/version/plugin.d.ts.map +1 -0
- package/dist/plugins/version/type.d.ts +47 -0
- package/dist/plugins/version/type.d.ts.map +1 -0
- package/dist/plugins/vue/index.d.ts +21 -0
- package/dist/plugins/vue/index.d.ts.map +1 -0
- package/dist/plugins/vue/index.js +114 -0
- package/dist/plugins/vue/index.js.map +1 -0
- package/dist/plugins/vue/plugin.d.ts +15 -0
- package/dist/plugins/vue/plugin.d.ts.map +1 -0
- package/dist/plugins/vue/type.d.ts +34 -0
- package/dist/plugins/vue/type.d.ts.map +1 -0
- package/dist/strategies/index.d.ts +2 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +29 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/strategies/plain.d.ts +2 -0
- package/dist/strategies/plain.d.ts.map +1 -0
- package/dist/strategies/plain.js +23 -0
- package/dist/strategies/plain.js.map +1 -0
- package/dist/strategies/react.d.ts +2 -0
- package/dist/strategies/react.d.ts.map +1 -0
- package/dist/strategies/react.js +30 -0
- package/dist/strategies/react.js.map +1 -0
- package/dist/strategies/shared/adapter.d.ts +23 -0
- package/dist/strategies/shared/adapter.d.ts.map +1 -0
- package/dist/strategies/shared/dom.d.ts +53 -0
- package/dist/strategies/shared/dom.d.ts.map +1 -0
- package/dist/strategies/shared/error.d.ts +30 -0
- package/dist/strategies/shared/error.d.ts.map +1 -0
- package/dist/strategies/shared/method.d.ts +51 -0
- package/dist/strategies/shared/method.d.ts.map +1 -0
- package/dist/strategies/shared/public.d.ts +33 -0
- package/dist/strategies/shared/public.d.ts.map +1 -0
- package/dist/strategies/shared/queue.d.ts +30 -0
- package/dist/strategies/shared/queue.d.ts.map +1 -0
- package/dist/strategies/shared/retry.d.ts +51 -0
- package/dist/strategies/shared/retry.d.ts.map +1 -0
- package/dist/strategies/shared/state.d.ts +117 -0
- package/dist/strategies/shared/state.d.ts.map +1 -0
- package/dist/strategies/shared/timing.d.ts +53 -0
- package/dist/strategies/shared/timing.d.ts.map +1 -0
- package/dist/strategies/shared/watcher.d.ts +37 -0
- package/dist/strategies/shared/watcher.d.ts.map +1 -0
- package/dist/strategies/use-auto-request.d.ts +77 -0
- package/dist/strategies/use-auto-request.d.ts.map +1 -0
- package/dist/strategies/use-download.d.ts +103 -0
- package/dist/strategies/use-download.d.ts.map +1 -0
- package/dist/strategies/use-fetcher.d.ts +52 -0
- package/dist/strategies/use-fetcher.d.ts.map +1 -0
- package/dist/strategies/use-pagination.d.ts +101 -0
- package/dist/strategies/use-pagination.d.ts.map +1 -0
- package/dist/strategies/use-request.d.ts +50 -0
- package/dist/strategies/use-request.d.ts.map +1 -0
- package/dist/strategies/use-retriable-request.d.ts +46 -0
- package/dist/strategies/use-retriable-request.d.ts.map +1 -0
- package/dist/strategies/use-sse.d.ts +103 -0
- package/dist/strategies/use-sse.d.ts.map +1 -0
- package/dist/strategies/use-token-auth.d.ts +88 -0
- package/dist/strategies/use-token-auth.d.ts.map +1 -0
- package/dist/strategies/use-uploader.d.ts +88 -0
- package/dist/strategies/use-uploader.d.ts.map +1 -0
- package/dist/strategies/use-watcher.d.ts +69 -0
- package/dist/strategies/use-watcher.d.ts.map +1 -0
- package/dist/typings/adapter.d.ts +61 -0
- package/dist/typings/adapter.d.ts.map +1 -0
- package/dist/typings/api.d.ts +122 -0
- package/dist/typings/api.d.ts.map +1 -0
- package/dist/typings/args.d.ts +51 -0
- package/dist/typings/args.d.ts.map +1 -0
- package/dist/typings/index.d.ts +8 -12
- package/dist/typings/index.d.ts.map +1 -0
- package/dist/typings/meta.d.ts +44 -0
- package/dist/typings/meta.d.ts.map +1 -0
- package/dist/typings/plugin.d.ts +114 -0
- package/dist/typings/plugin.d.ts.map +1 -0
- package/dist/typings/response.d.ts +118 -0
- package/dist/typings/response.d.ts.map +1 -0
- package/dist/typings/server.d.ts +83 -0
- package/dist/typings/server.d.ts.map +1 -0
- package/dist/typings/stream.d.ts +150 -0
- package/dist/typings/stream.d.ts.map +1 -0
- package/dist/utils/download.d.ts +97 -0
- package/dist/utils/download.d.ts.map +1 -0
- package/dist/utils/emitter.d.ts +36 -0
- package/dist/utils/emitter.d.ts.map +1 -0
- package/dist/utils/index.d.ts +6 -1
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/is.d.ts +22 -0
- package/dist/utils/is.d.ts.map +1 -0
- package/dist/utils/object.d.ts +44 -0
- package/dist/utils/object.d.ts.map +1 -0
- package/dist/utils/url.d.ts +44 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/package.json +90 -27
- package/README_EN.md +0 -607
- package/dist/cache/index.d.ts +0 -9
- package/dist/cache/indexDBCache.d.ts +0 -13
- package/dist/cache/localstorageCache.d.ts +0 -10
- package/dist/cache/memoryCache.d.ts +0 -11
- package/dist/core/index.d.ts +0 -4
- package/dist/core/snailApi.d.ts +0 -22
- package/dist/core/snailMethod.d.ts +0 -49
- package/dist/core/snailServer.d.ts +0 -35
- package/dist/core/snailSse.d.ts +0 -20
- package/dist/decorators/cache.d.ts +0 -15
- package/dist/decorators/method.d.ts +0 -38
- package/dist/decorators/sse.d.ts +0 -30
- package/dist/decorators/strategy.d.ts +0 -10
- package/dist/decorators/versioning.d.ts +0 -16
- package/dist/eventEmmit/index.d.ts +0 -1
- package/dist/eventEmmit/snail.event.d.ts +0 -10
- package/dist/snail-api.js +0 -4868
- package/dist/snail-api.umd.cjs +0 -4872
- package/dist/strategies/jwtStrategy.d.ts +0 -4
- package/dist/typings/api.option.d.ts +0 -10
- package/dist/typings/apiProxy.d.ts +0 -8
- package/dist/typings/cache.management.option.d.ts +0 -25
- package/dist/typings/cache.type.d.ts +0 -23
- package/dist/typings/content.type.d.ts +0 -5
- package/dist/typings/request.body.d.ts +0 -3
- package/dist/typings/response.data.d.ts +0 -13
- package/dist/typings/snail.event.d.ts +0 -6
- package/dist/typings/snail.method.d.ts +0 -14
- package/dist/typings/snail.option.d.ts +0 -16
- package/dist/typings/sse.d.ts +0 -15
- package/dist/typings/strategy.d.ts +0 -5
- package/dist/typings/versioning.option.d.ts +0 -30
- package/dist/utils/function.d.ts +0 -31
- package/dist/versioning/index.d.ts +0 -1
- package/dist/versioning/versioning.d.ts +0 -12
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { SnailStateRef } from "../typings/adapter.js";
|
|
2
|
+
import type { StrategyMethod } from "./shared/method.js";
|
|
3
|
+
import type { RetryOptions, RetryPredicate } from "./shared/retry.js";
|
|
4
|
+
import type { StrategyState } from "./shared/state.js";
|
|
5
|
+
import type { UseRequestOptions } from "./use-request.js";
|
|
6
|
+
/** Options accepted by {@link useRetriableRequest}. */
|
|
7
|
+
export interface UseRetriableRequestOptions<TData> extends UseRequestOptions<TData>, RetryOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Decide whether one failed attempt deserves another.
|
|
10
|
+
*
|
|
11
|
+
* Receives the attempted number of the *next* try (1-based), so a caller can
|
|
12
|
+
* cap retries by reason as well as by count. The default retries everything
|
|
13
|
+
* except a cancellation, which is never retried: the caller asked for the
|
|
14
|
+
* request to stop, and a retry would ignore that instruction.
|
|
15
|
+
*/
|
|
16
|
+
retryOn?: RetryPredicate;
|
|
17
|
+
}
|
|
18
|
+
/** What {@link useRetriableRequest} returns. */
|
|
19
|
+
export interface UseRetriableRequestResult<TData, TArgs extends readonly unknown[] = readonly unknown[]> extends StrategyState<TData> {
|
|
20
|
+
send(...args: TArgs): Promise<TData>;
|
|
21
|
+
/** Attempts made by the most recent `send()`. Starts at `0`. */
|
|
22
|
+
readonly attempts: SnailStateRef<number>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A request that heals itself.
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* const save = useRetriableRequest(api.save, { retries: 3, delayMs: 200 });
|
|
29
|
+
* await save.send(payload); // may hit the network up to 4 times
|
|
30
|
+
* save.attempts.value; // how many tries it actually took
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* ## Cancellation is the hard part
|
|
34
|
+
*
|
|
35
|
+
* The hook keeps its own `AbortController` for the backoff *between* attempts,
|
|
36
|
+
* because at that moment there is no in-flight request to cancel. `abort()` trips
|
|
37
|
+
* both, so a `abort()` during a 30 second delay rejects immediately instead of
|
|
38
|
+
* leaving the caller's promise pending until the timer fires. A cancellation is
|
|
39
|
+
* never counted as a failed attempt and never written to `error`.
|
|
40
|
+
*
|
|
41
|
+
* `attempts` is exposed because it is genuinely useful for telemetry ("this call
|
|
42
|
+
* needed three tries") and because it makes the retry loop testable without
|
|
43
|
+
* counting requests.
|
|
44
|
+
*/
|
|
45
|
+
export declare function useRetriableRequest<TArgs extends readonly unknown[], TData>(method: StrategyMethod<TArgs, TData>, options?: UseRetriableRequestOptions<TData>): UseRetriableRequestResult<TData, TArgs>;
|
|
46
|
+
//# sourceMappingURL=use-retriable-request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-retriable-request.d.ts","sourceRoot":"","sources":["../../src/strategies/use-retriable-request.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAMtD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,uDAAuD;AACvD,MAAM,WAAW,0BAA0B,CAAC,KAAK,CAC/C,SAAQ,iBAAiB,CAAC,KAAK,CAAC,EAC9B,YAAY;IACd;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,gDAAgD;AAChD,MAAM,WAAW,yBAAyB,CACxC,KAAK,EACL,KAAK,SAAS,SAAS,OAAO,EAAE,GAAG,SAAS,OAAO,EAAE,CACrD,SAAQ,aAAa,CAAC,KAAK,CAAC;IAC5B,IAAI,CAAC,GAAG,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAErC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,EAAE,KAAK,EACzE,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,EACpC,OAAO,GAAE,0BAA0B,CAAC,KAAK,CAAM,GAC9C,yBAAyB,CAAC,KAAK,EAAE,KAAK,CAAC,CA2EzC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { SnailStateAdapter, SnailStateRef } from "../typings/adapter.js";
|
|
2
|
+
import type { SnailSseEndpoint, SnailSseMessage } from "../typings/stream.js";
|
|
3
|
+
/**
|
|
4
|
+
* A connection that can report the events it parsed.
|
|
5
|
+
*
|
|
6
|
+
* `SnailConnection` deliberately exposes only `close`/`connected`/`opened`/
|
|
7
|
+
* `closed`, because a connection whose messages are delivered to `@SseEvent()`
|
|
8
|
+
* handlers on the endpoint class needs no other surface. `useSSE` has no such
|
|
9
|
+
* class, so it looks for this extension on the connection and, failing that, on
|
|
10
|
+
* the endpoint. Without either, `connected` still tracks the transport but
|
|
11
|
+
* `messages` stays empty — see the note on {@link useSSE}.
|
|
12
|
+
*/
|
|
13
|
+
export interface SseConnectionTap {
|
|
14
|
+
/** Register a message listener. Returns an unsubscribe function. */
|
|
15
|
+
onMessage?(listener: (message: SnailSseMessage) => void): () => void;
|
|
16
|
+
}
|
|
17
|
+
/** A `SnailSseEndpoint` that can also hand out messages directly. */
|
|
18
|
+
export interface SseEndpoint extends SnailSseEndpoint {
|
|
19
|
+
/**
|
|
20
|
+
* Register a message listener for the connections this endpoint opens.
|
|
21
|
+
*
|
|
22
|
+
* Preferred over {@link SseConnectionTap} because it can be called once, before
|
|
23
|
+
* `open()`, which is the only way to be sure no message between the connect and
|
|
24
|
+
* the subscription is lost.
|
|
25
|
+
*/
|
|
26
|
+
subscribe?(listener: (message: SnailSseMessage) => void): () => void;
|
|
27
|
+
}
|
|
28
|
+
/** Options accepted by {@link useSSE}. */
|
|
29
|
+
export interface UseSseOptions {
|
|
30
|
+
/** State adapter. Defaults to the globally registered one. */
|
|
31
|
+
adapter?: SnailStateAdapter;
|
|
32
|
+
/**
|
|
33
|
+
* Open the connection as soon as the hook is created. Defaults to `false`,
|
|
34
|
+
* matching `SnailSseEndpoint`'s "nothing connects until `open()`" contract.
|
|
35
|
+
*/
|
|
36
|
+
immediate?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Maximum buffered messages. Defaults to `100`, dropping the oldest first.
|
|
39
|
+
*
|
|
40
|
+
* Bounded on purpose: an SSE feed that runs for hours with an unbounded array
|
|
41
|
+
* is a memory leak that ends in a frozen tab, and no view can render a hundred
|
|
42
|
+
* thousand rows anyway.
|
|
43
|
+
*/
|
|
44
|
+
maxMessages?: number;
|
|
45
|
+
/** Keep only the messages this returns `true` for. */
|
|
46
|
+
filter?: (message: SnailSseMessage) => boolean;
|
|
47
|
+
/** Called for every accepted message, after the buffer was updated. */
|
|
48
|
+
onMessage?: (message: SnailSseMessage) => void;
|
|
49
|
+
}
|
|
50
|
+
/** What {@link useSSE} returns. */
|
|
51
|
+
export interface UseSseResult {
|
|
52
|
+
/** Buffered messages, oldest first. */
|
|
53
|
+
readonly messages: SnailStateRef<SnailSseMessage[]>;
|
|
54
|
+
/** The most recent accepted message. */
|
|
55
|
+
readonly lastMessage: SnailStateRef<SnailSseMessage | undefined>;
|
|
56
|
+
/** `true` between a successful connect and the next close. */
|
|
57
|
+
readonly connected: SnailStateRef<boolean>;
|
|
58
|
+
/** Why the connection failed, or why a filter/handler threw. */
|
|
59
|
+
readonly error: SnailStateRef<unknown>;
|
|
60
|
+
/** Connect. A no-op while an open connection is already live. */
|
|
61
|
+
open(): void;
|
|
62
|
+
/** Disconnect, stop the reconnect loop and detach the listener. */
|
|
63
|
+
close(): void;
|
|
64
|
+
/** Empty the message buffer. Leaves the connection alone. */
|
|
65
|
+
clear(): void;
|
|
66
|
+
/** Resolved values, subscribing the current component when the adapter supports it. */
|
|
67
|
+
bind(): {
|
|
68
|
+
messages: SnailSseMessage[];
|
|
69
|
+
lastMessage: SnailSseMessage | undefined;
|
|
70
|
+
connected: boolean;
|
|
71
|
+
error: unknown;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Consume a Server-Sent Events endpoint as reactive state.
|
|
76
|
+
*
|
|
77
|
+
* ```ts
|
|
78
|
+
* const events = Service.createSse(Events);
|
|
79
|
+
* const feed = useSSE(events, { maxMessages: 50 });
|
|
80
|
+
* feed.open();
|
|
81
|
+
* feed.messages.value; // SnailSseMessage[]
|
|
82
|
+
* feed.close();
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* ## The message tap
|
|
86
|
+
*
|
|
87
|
+
* `Service.createSse()` returns an object whose only member is `open()`, and the
|
|
88
|
+
* messages it parses are dispatched to the decorated class's methods
|
|
89
|
+
* (`@SseEvent()`), not to the caller. `useSSE` therefore accepts an endpoint that
|
|
90
|
+
* additionally implements `subscribe(listener)`, or a connection that implements
|
|
91
|
+
* `onMessage(listener)`. Both extend the core contract without changing it; an
|
|
92
|
+
* endpoint that implements neither still reports `connected`/`error` faithfully,
|
|
93
|
+
* it just never fills `messages`.
|
|
94
|
+
*
|
|
95
|
+
* ## Never an unhandled rejection
|
|
96
|
+
*
|
|
97
|
+
* A rejected `opened` promise is exactly how a failed SSE connect is reported, and
|
|
98
|
+
* nothing else in the application will ever await it. Both `opened` and `closed`
|
|
99
|
+
* are handled here, so a dead server cannot take the process down with an
|
|
100
|
+
* unhandled rejection.
|
|
101
|
+
*/
|
|
102
|
+
export declare function useSSE(endpoint: SseEndpoint, options?: UseSseOptions): UseSseResult;
|
|
103
|
+
//# sourceMappingURL=use-sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-sse.d.ts","sourceRoot":"","sources":["../../src/strategies/use-sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAA8B,MAAM,oBAAoB,CAAC;AACvG,OAAO,KAAK,EAAmB,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAI5F;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACtE;AAED,qEAAqE;AACrE,MAAM,WAAW,WAAY,SAAQ,gBAAgB;IACnD;;;;;;OAMG;IACH,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACtE;AAED,0CAA0C;AAC1C,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAE5B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,sDAAsD;IACtD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC;IAE/C,uEAAuE;IACvE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CAChD;AAED,mCAAmC;AACnC,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,eAAe,EAAE,CAAC,CAAC;IAEpD,wCAAwC;IACxC,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;IAEjE,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAE3C,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAEvC,iEAAiE;IACjE,IAAI,IAAI,IAAI,CAAC;IAEb,mEAAmE;IACnE,KAAK,IAAI,IAAI,CAAC;IAEd,6DAA6D;IAC7D,KAAK,IAAI,IAAI,CAAC;IAEd,uFAAuF;IACvF,IAAI,IAAI;QACN,QAAQ,EAAE,eAAe,EAAE,CAAC;QAC5B,WAAW,EAAE,eAAe,GAAG,SAAS,CAAC;QACzC,SAAS,EAAE,OAAO,CAAC;QACnB,KAAK,EAAE,OAAO,CAAC;KAChB,CAAC;CACH;AAsBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,GAAE,aAAkB,GAAG,YAAY,CAyHvF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { SnailPluginObject } from "../typings/plugin.js";
|
|
2
|
+
/** Options accepted by {@link useTokenAuth}. */
|
|
3
|
+
export interface TokenAuthOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Current token, from wherever the application keeps it.
|
|
6
|
+
*
|
|
7
|
+
* May be async (a secure store, a cookie API). Returning `null`/`undefined` is
|
|
8
|
+
* normal — it means "not logged in", and the header is simply not injected.
|
|
9
|
+
*/
|
|
10
|
+
token: () => string | null | undefined | Promise<string | null | undefined>;
|
|
11
|
+
/**
|
|
12
|
+
* Obtain a fresh token.
|
|
13
|
+
*
|
|
14
|
+
* Called **at most once** per wave of 401s; see the class documentation on
|
|
15
|
+
* {@link useTokenAuth}. It must resolve with the new token; rejecting aborts the
|
|
16
|
+
* whole queue.
|
|
17
|
+
*/
|
|
18
|
+
refresh: () => Promise<string>;
|
|
19
|
+
/** Header to write. Defaults to `"authorization"`. */
|
|
20
|
+
header?: string;
|
|
21
|
+
/** Prefix before the token. Defaults to `"Bearer"`; pass `""` for a raw token. */
|
|
22
|
+
scheme?: string;
|
|
23
|
+
/** Called when a 401 could not be recovered — the refresh failed, or the replay 401'd again. */
|
|
24
|
+
onUnauthorized?: (error: unknown) => void;
|
|
25
|
+
}
|
|
26
|
+
/** What {@link useTokenAuth} hands back. */
|
|
27
|
+
export interface TokenAuthHandle {
|
|
28
|
+
/** Install with `Service.use(auth.plugin)`. */
|
|
29
|
+
readonly plugin: SnailPluginObject<TokenAuthOptions>;
|
|
30
|
+
/** Replace the cached token, e.g. after a successful login. */
|
|
31
|
+
setToken(token: string | null | undefined): void;
|
|
32
|
+
/** The cached token. Synchronous: an async `token()` cannot be awaited here. */
|
|
33
|
+
getToken(): string | undefined;
|
|
34
|
+
/** Forget the cached token so `token()` is consulted again on the next request. */
|
|
35
|
+
clearToken(): void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Bearer-token authentication with single-flight refresh, as a plugin.
|
|
39
|
+
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* const auth = useTokenAuth({
|
|
42
|
+
* token: () => localStorage.getItem("token"),
|
|
43
|
+
* refresh: async () => (await api.refresh().send()).token,
|
|
44
|
+
* onUnauthorized: () => router.push("/login")
|
|
45
|
+
* });
|
|
46
|
+
*
|
|
47
|
+
* Service.use(auth.plugin);
|
|
48
|
+
* auth.setToken("...");
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* ## Why a plugin and not a hook
|
|
52
|
+
*
|
|
53
|
+
* A token is global: every request of the service has to carry it, and a 401 on
|
|
54
|
+
* any one of them has to invalidate the token for all of them. A per-method hook
|
|
55
|
+
* could not see the other requests, so refresh coordination would be impossible.
|
|
56
|
+
*
|
|
57
|
+
* ## Exactly one refresh per wave of 401s
|
|
58
|
+
*
|
|
59
|
+
* Three parallel requests, one expired token, three 401s. Refreshing per request
|
|
60
|
+
* would fire three refreshes and, with a rotating refresh token, two of them would
|
|
61
|
+
* fail and log the user out. Two mechanisms prevent that:
|
|
62
|
+
*
|
|
63
|
+
* 1. a request that 401s while a refresh is already in flight **joins** it instead
|
|
64
|
+
* of starting a second one;
|
|
65
|
+
* 2. a request whose 401 was produced by a token that has since been replaced
|
|
66
|
+
* replays directly, without refreshing again.
|
|
67
|
+
*
|
|
68
|
+
* The token each request was sent with is remembered in `ctx.state` (which the core
|
|
69
|
+
* clears per send), and that is what makes rule 2 decidable without keeping
|
|
70
|
+
* timers around.
|
|
71
|
+
*
|
|
72
|
+
* ## Replaying
|
|
73
|
+
*
|
|
74
|
+
* `onError` cannot recover a failure — the core rethrows after every `onError`
|
|
75
|
+
* hook — so the recovery lives in `beforeRequest`, around `await next()`. The
|
|
76
|
+
* replay re-runs the `requestInterceptor` reduce, the transport and the
|
|
77
|
+
* `afterResponse` chain, so headers a plugin signs are recomputed for the retried
|
|
78
|
+
* call. `beforeRequest` hooks are deliberately *not* re-entered: the refresh
|
|
79
|
+
* decision has already been made, and re-entering could loop.
|
|
80
|
+
*
|
|
81
|
+
* ## What this cannot recover
|
|
82
|
+
*
|
|
83
|
+
* Only a **transport** 401 (HTTP 401). A backend that reports `{ code: 401 }` with
|
|
84
|
+
* HTTP 200 fails in `finalize`, after the chain, where no hook can intervene; that
|
|
85
|
+
* response reaches the caller as a `SnailResponseError`.
|
|
86
|
+
*/
|
|
87
|
+
export declare function useTokenAuth(options: TokenAuthOptions): TokenAuthHandle;
|
|
88
|
+
//# sourceMappingURL=use-token-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-token-auth.d.ts","sourceRoot":"","sources":["../../src/strategies/use-token-auth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtE,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,KAAK,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAE5E;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/B,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,gGAAgG;IAChG,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C;AAED,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;IAErD,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;IAEjD,gFAAgF;IAChF,QAAQ,IAAI,MAAM,GAAG,SAAS,CAAC;IAE/B,mFAAmF;IACnF,UAAU,IAAI,IAAI,CAAC;CACpB;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAoKvE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { SnailStateRef, SnailStrategyCommonOptions } from "../typings/adapter.js";
|
|
2
|
+
import type { StrategyMethod } from "./shared/method.js";
|
|
3
|
+
import type { StrategyState } from "./shared/state.js";
|
|
4
|
+
/** Lifecycle of one queued file. */
|
|
5
|
+
export type UploadFileStatus = "pending" | "uploading" | "success" | "error";
|
|
6
|
+
/** Everything the hook tracks about one file. */
|
|
7
|
+
export interface UploadFileState {
|
|
8
|
+
/** Stable id, used by `retry(id)`. */
|
|
9
|
+
readonly id: string;
|
|
10
|
+
/** The file itself. */
|
|
11
|
+
readonly file: File;
|
|
12
|
+
readonly status: UploadFileStatus;
|
|
13
|
+
/** `0`–`1`, from the transport when it reports progress, otherwise completed-or-not. */
|
|
14
|
+
readonly progress: number;
|
|
15
|
+
/** Failure of this file. Untouched for a cancellation. */
|
|
16
|
+
readonly error: unknown;
|
|
17
|
+
/** Unwrapped payload of this file's successful response. */
|
|
18
|
+
readonly response: unknown;
|
|
19
|
+
}
|
|
20
|
+
/** Snapshot handed to `onProgress`. */
|
|
21
|
+
export interface UploaderProgress {
|
|
22
|
+
/** Average progress across every queued file, `0`–`1`. */
|
|
23
|
+
progress: number;
|
|
24
|
+
files: readonly UploadFileState[];
|
|
25
|
+
}
|
|
26
|
+
/** Options accepted by {@link useUploader}. */
|
|
27
|
+
export interface UseUploaderOptions<TData> extends SnailStrategyCommonOptions {
|
|
28
|
+
/** Files in flight at once. Defaults to `3`. */
|
|
29
|
+
concurrency?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Accept more than one file per `upload()` call.
|
|
32
|
+
*
|
|
33
|
+
* Defaults to `true`. When `false`, only the first entry of a `FileList` is
|
|
34
|
+
* queued and the rest are dropped — a single-file avatar input should not
|
|
35
|
+
* silently upload 40 holiday photos because a user multi-selected.
|
|
36
|
+
*/
|
|
37
|
+
multiple?: boolean;
|
|
38
|
+
/** Called whenever aggregate or per-file progress changes. */
|
|
39
|
+
onProgress?: (state: UploaderProgress) => void;
|
|
40
|
+
/** FormData field the file is written to. Defaults to `"file"`. */
|
|
41
|
+
fieldName?: string;
|
|
42
|
+
}
|
|
43
|
+
/** What {@link useUploader} returns. */
|
|
44
|
+
export interface UseUploaderResult<TData> extends StrategyState<TData> {
|
|
45
|
+
/**
|
|
46
|
+
* Queue files and resolve once the queue drains.
|
|
47
|
+
*
|
|
48
|
+
* Never rejects: per-file failures live on `files[i].error`, and one bad file
|
|
49
|
+
* must not abort the batch — that is the difference between "3 of 5 uploaded"
|
|
50
|
+
* and "nothing happened".
|
|
51
|
+
*/
|
|
52
|
+
upload(files: File | File[] | FileList | null | undefined): Promise<void>;
|
|
53
|
+
/** Every queued file, in queue order. */
|
|
54
|
+
readonly files: SnailStateRef<UploadFileState[]>;
|
|
55
|
+
/** Aggregate progress, `0`–`1`. Reaches `1` when every file succeeded. */
|
|
56
|
+
readonly progress: SnailStateRef<number>;
|
|
57
|
+
/** Re-queue one failed file. */
|
|
58
|
+
retry(id: string): void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Upload files with a bounded number of parallel requests.
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* const uploader = useUploader(api.upload, { concurrency: 2 });
|
|
65
|
+
* await uploader.upload(input.files);
|
|
66
|
+
* uploader.files.value; // per-file status, progress, error, response
|
|
67
|
+
* uploader.retry(id); // re-queue one failure
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* ## Progress
|
|
71
|
+
*
|
|
72
|
+
* Per-file progress comes from the transport via axios' `onUploadProgress`, which
|
|
73
|
+
* the hook attaches to the **live** request config of each file (see
|
|
74
|
+
* `shared/method.ts` for why that has to happen right after `send()` starts). The
|
|
75
|
+
* aggregate is the mean of the per-file values, and a finished file counts as `1`
|
|
76
|
+
* regardless of what the transport reported — a mocked or `fetch`-based adapter
|
|
77
|
+
* reports nothing at all, and without that rule the bar would stop at `0`.
|
|
78
|
+
*
|
|
79
|
+
* ## `data` and `code`
|
|
80
|
+
*
|
|
81
|
+
* The state handles are shared by the whole batch, so `data` holds the payload of
|
|
82
|
+
* the most recently finished file. Use `files[i].response` for anything
|
|
83
|
+
* per-file. `error` mirrors the file list: it holds the first failed file's error
|
|
84
|
+
* while any file is in the `error` state, and clears itself once the last failure
|
|
85
|
+
* has been retried successfully.
|
|
86
|
+
*/
|
|
87
|
+
export declare function useUploader<TData>(method: StrategyMethod<[FormData], TData>, options?: UseUploaderOptions<TData>): UseUploaderResult<TData>;
|
|
88
|
+
//# sourceMappingURL=use-uploader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-uploader.d.ts","sourceRoot":"","sources":["../../src/strategies/use-uploader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAGpF,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,oCAAoC;AACpC,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7E,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,uBAAuB;IACvB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAEpB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAElC,wFAAwF;IACxF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAExB,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;CACnC;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB,CAAC,KAAK,CAAE,SAAQ,0BAA0B;IAC3E,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAE/C,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wCAAwC;AACxC,MAAM,WAAW,iBAAiB,CAAC,KAAK,CAAE,SAAQ,aAAa,CAAC,KAAK,CAAC;IACpE;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1E,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,eAAe,EAAE,CAAC,CAAC;IAEjD,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAEzC,gCAAgC;IAChC,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAmBD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAC/B,MAAM,EAAE,cAAc,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,EACzC,OAAO,GAAE,kBAAkB,CAAC,KAAK,CAAM,GACtC,iBAAiB,CAAC,KAAK,CAAC,CAkJ1B"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { SnailStateRef } from "../typings/adapter.js";
|
|
2
|
+
import type { StrategyMethod } from "./shared/method.js";
|
|
3
|
+
import type { UseRequestOptions, UseRequestResult } from "./use-request.js";
|
|
4
|
+
/** Options accepted by {@link useWatcher}. */
|
|
5
|
+
export interface UseWatcherOptions<TData> extends UseRequestOptions<TData> {
|
|
6
|
+
/**
|
|
7
|
+
* Values that trigger a re-send when they change.
|
|
8
|
+
*
|
|
9
|
+
* Must be a function returning **plain values** — `() => [page.value]`. State
|
|
10
|
+
* handles are unwrapped too when the adapter can identify them (see
|
|
11
|
+
* `shared/watcher.ts`), but the handle form is a heuristic: only a `{ value }`
|
|
12
|
+
* object is recognised, so a genuine data object with a lone `value` key is
|
|
13
|
+
* indistinguishable from a handle.
|
|
14
|
+
*/
|
|
15
|
+
watching: () => readonly unknown[];
|
|
16
|
+
/**
|
|
17
|
+
* Wait for this many milliseconds of quiet, then send once.
|
|
18
|
+
*
|
|
19
|
+
* Takes precedence over `throttle` when both are set: the two express opposite
|
|
20
|
+
* intents ("wait until it settles" vs "send immediately, then at most once per
|
|
21
|
+
* window"), and silently honouring one of them is better than a hybrid whose
|
|
22
|
+
* behaviour depends on the call order.
|
|
23
|
+
*/
|
|
24
|
+
debounce?: number;
|
|
25
|
+
/** Send on the leading edge, then at most once per window. */
|
|
26
|
+
throttle?: number;
|
|
27
|
+
}
|
|
28
|
+
/** What {@link useWatcher} returns. */
|
|
29
|
+
export interface UseWatcherResult<TData, TArgs extends readonly unknown[] = readonly unknown[]> extends UseRequestResult<TData, TArgs> {
|
|
30
|
+
/**
|
|
31
|
+
* Whether `send()` collapses unchanged watched values.
|
|
32
|
+
*
|
|
33
|
+
* `true` (default) is the watching behaviour. Setting it to `false` turns every
|
|
34
|
+
* `send()` into an unconditional request, which is the escape hatch for a manual
|
|
35
|
+
* "refresh" button while the same hook keeps watching fields.
|
|
36
|
+
*/
|
|
37
|
+
readonly watching: SnailStateRef<boolean>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Re-send a request when watched values move.
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* const keyword = createState("");
|
|
44
|
+
* const search = useWatcher(searchApi.find, {
|
|
45
|
+
* watching: () => [keyword.value],
|
|
46
|
+
* debounce: 200
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* keyword.value = "a"; await search.send(); // sends
|
|
50
|
+
* await search.send(); // same values → no request
|
|
51
|
+
* keyword.value = "ab"; await search.send(); // sends again
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* ## Why `send()` is the evaluation trigger
|
|
55
|
+
*
|
|
56
|
+
* `SnailStateAdapter` exposes `create`/`read`/`write` and an optional
|
|
57
|
+
* `subscribe`; it has no `watch` or `effect`, and the core deliberately keeps
|
|
58
|
+
* framework reactivity out of the strategy layer. So there is nothing to fire at
|
|
59
|
+
* the *moment* a value changes. The hook therefore evaluates `watching()` when
|
|
60
|
+
* `send()` is called and treats an unchanged snapshot as a no-op, which keeps the
|
|
61
|
+
* behaviour deterministic and framework-free: a Vue/React integration can call
|
|
62
|
+
* `send()` from its own reactive effect, and a script calls it directly.
|
|
63
|
+
*
|
|
64
|
+
* `debounce`/`throttle` then collapse the *bursts* of `send()` calls a reactive
|
|
65
|
+
* effect produces. Every collapsed caller's promise settles with the single
|
|
66
|
+
* request's outcome, so no `await` is ever left hanging.
|
|
67
|
+
*/
|
|
68
|
+
export declare function useWatcher<TArgs extends readonly unknown[], TData>(method: StrategyMethod<TArgs, TData>, options: UseWatcherOptions<TData>): UseWatcherResult<TData, TArgs>;
|
|
69
|
+
//# sourceMappingURL=use-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-watcher.d.ts","sourceRoot":"","sources":["../../src/strategies/use-watcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAItD,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEzE,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB,CAAC,KAAK,CAAE,SAAQ,iBAAiB,CAAC,KAAK,CAAC;IACxE;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,SAAS,OAAO,EAAE,CAAC;IAEnC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,uCAAuC;AACvC,MAAM,WAAW,gBAAgB,CAC/B,KAAK,EACL,KAAK,SAAS,SAAS,OAAO,EAAE,GAAG,SAAS,OAAO,EAAE,CACrD,SAAQ,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC;IACtC;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,UAAU,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,EAAE,KAAK,EAChE,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,EACpC,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,GAChC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CA4GhC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework state abstraction used by the request strategies.
|
|
3
|
+
*
|
|
4
|
+
* A strategy needs to hand the caller values that update as the request
|
|
5
|
+
* progresses. "Updates" means something different in every framework, so the
|
|
6
|
+
* strategies never touch `ref()` or `useState()` directly — they go through a
|
|
7
|
+
* {@link SnailStateAdapter}.
|
|
8
|
+
*
|
|
9
|
+
* A state handle is intentionally minimal: anything with a mutable `value`
|
|
10
|
+
* property qualifies, which is exactly what a Vue `Ref<T>` is.
|
|
11
|
+
*/
|
|
12
|
+
/** A tracked value. Vue's `Ref<T>` structurally satisfies this. */
|
|
13
|
+
export interface SnailStateRef<T = unknown> {
|
|
14
|
+
value: T;
|
|
15
|
+
}
|
|
16
|
+
/** Bridge between the strategies and one UI framework's reactivity system. */
|
|
17
|
+
export interface SnailStateAdapter {
|
|
18
|
+
/** Identifier used in error messages, e.g. `"vue"`. */
|
|
19
|
+
readonly name: string;
|
|
20
|
+
/** Create a tracked value with an initial value. */
|
|
21
|
+
create<T>(initial: T): SnailStateRef<T>;
|
|
22
|
+
/** Read the current value. */
|
|
23
|
+
read<T>(ref: SnailStateRef<T>): T;
|
|
24
|
+
/** Write a new value. */
|
|
25
|
+
write<T>(ref: SnailStateRef<T>, value: T): void;
|
|
26
|
+
/**
|
|
27
|
+
* Subscribe to changes.
|
|
28
|
+
*
|
|
29
|
+
* Required by frameworks that re-render on subscription (React). Vue's
|
|
30
|
+
* `ref()` is tracked by the render effect itself, so its adapter omits this.
|
|
31
|
+
*/
|
|
32
|
+
subscribe?<T>(ref: SnailStateRef<T>, listener: (value: T) => void): () => void;
|
|
33
|
+
/**
|
|
34
|
+
* Read a state during render, subscribing the current component.
|
|
35
|
+
*
|
|
36
|
+
* React's `useSyncExternalStore` lives here; Vue needs nothing.
|
|
37
|
+
*/
|
|
38
|
+
useBind?<T>(ref: SnailStateRef<T>): T;
|
|
39
|
+
/** `true` when a value already is a state handle of this framework. */
|
|
40
|
+
isState?(value: unknown): boolean;
|
|
41
|
+
/** Release whatever the adapter allocated for this state. */
|
|
42
|
+
dispose?<T>(ref: SnailStateRef<T>): void;
|
|
43
|
+
}
|
|
44
|
+
/** Options shared by every request strategy. */
|
|
45
|
+
export interface SnailStrategyCommonOptions {
|
|
46
|
+
/** Run the request as soon as the strategy is created. Defaults to `false`. */
|
|
47
|
+
immediate?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* State adapter to use.
|
|
50
|
+
*
|
|
51
|
+
* Defaults to the globally registered adapter (Vue in the default entry).
|
|
52
|
+
*/
|
|
53
|
+
adapter?: SnailStateAdapter;
|
|
54
|
+
/** Called after a successful request. */
|
|
55
|
+
onSuccess?: (data: unknown) => void;
|
|
56
|
+
/** Called after a failed request. */
|
|
57
|
+
onError?: (error: unknown) => void;
|
|
58
|
+
/** Called once the request settles, successfully or not. */
|
|
59
|
+
onFinish?: () => void;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/typings/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,mEAAmE;AACnE,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,KAAK,EAAE,CAAC,CAAC;CACV;AAED,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,oDAAoD;IACpD,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IAExC,8BAA8B;IAC9B,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAElC,yBAAyB;IACzB,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAEhD;;;;;OAKG;IACH,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAE/E;;;;OAIG;IACH,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEtC,uEAAuE;IACvE,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAElC,6DAA6D;IAC7D,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAC1C;AAED,gDAAgD;AAChD,MAAM,WAAW,0BAA0B;IACzC,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAE5B,yCAAyC;IACzC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAEpC,qCAAqC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAEnC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { AxiosRequestConfig, Method } from "axios";
|
|
2
|
+
import type { SnailEnvelopeSchema, SnailResult } from "./response.js";
|
|
3
|
+
/** Every request verb this library can decorate. */
|
|
4
|
+
export type SnailMethodType = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
|
5
|
+
/** `SnailMethodType` in the lowercase form axios expects. */
|
|
6
|
+
export type SnailMethodTypeLower = Lowercase<SnailMethodType>;
|
|
7
|
+
/** Options accepted by `@Api(...)`. */
|
|
8
|
+
export interface SnailApiOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Path prefix shared by every method of the class.
|
|
11
|
+
*
|
|
12
|
+
* Joined with the server `baseURL` and the method path, in that order.
|
|
13
|
+
*/
|
|
14
|
+
url?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Unique identifier of this api class.
|
|
17
|
+
*
|
|
18
|
+
* Defaults to the class name. Used for logging, cache namespacing and
|
|
19
|
+
* `@HitSource` resolution.
|
|
20
|
+
*/
|
|
21
|
+
name?: string;
|
|
22
|
+
/** Per-api timeout, overriding the server timeout. */
|
|
23
|
+
timeout?: number;
|
|
24
|
+
/** Per-api adapter, overriding the server adapter. */
|
|
25
|
+
adapter?: AxiosRequestConfig["adapter"];
|
|
26
|
+
/** Per-api `responseType`, overriding the server value. */
|
|
27
|
+
responseType?: AxiosRequestConfig["responseType"];
|
|
28
|
+
/** Per-api `withCredentials`, overriding the server value. */
|
|
29
|
+
withCredentials?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Options accepted by the request-method decorators.
|
|
33
|
+
*
|
|
34
|
+
* Extends `AxiosRequestConfig` so any axios knob can be set per method, minus
|
|
35
|
+
* the fields the library owns (`url` and `method`).
|
|
36
|
+
*/
|
|
37
|
+
export interface SnailMethodOptions extends Omit<AxiosRequestConfig, "url" | "method" | "params" | "data"> {
|
|
38
|
+
/** Extra query params baked into the request. */
|
|
39
|
+
params?: Record<string, any>;
|
|
40
|
+
/** Static body baked into the request (mutually exclusive with `@Data()`). */
|
|
41
|
+
data?: unknown;
|
|
42
|
+
}
|
|
43
|
+
/** What `@Get("/x", { ... })` receives as its second argument. */
|
|
44
|
+
export type SnailMethodDecoratorOptions = SnailMethodOptions;
|
|
45
|
+
/** A `Method` value axios understands. */
|
|
46
|
+
export type SnailAxiosMethod = Method;
|
|
47
|
+
/**
|
|
48
|
+
* The payload type of a decorated method, inferred from its declared return type.
|
|
49
|
+
*
|
|
50
|
+
* ```ts
|
|
51
|
+
* @Get("/:id")
|
|
52
|
+
* getUser(@Params("id") id: string): Promise<User> { return null!; }
|
|
53
|
+
* // ^^^^^^^^^^^^^^ → User
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* A method that declares nothing (implicitly `void`) yields `unknown`, which the
|
|
57
|
+
* caller can still override with an explicit generic:
|
|
58
|
+
* `userApi.getUser<MyShape>("1")`.
|
|
59
|
+
*/
|
|
60
|
+
export type SnailPayloadOf<R> = Awaited<R> extends void ? unknown : Awaited<R> extends undefined ? unknown : Awaited<R>;
|
|
61
|
+
/**
|
|
62
|
+
* The proxy returned by `Service.createApi(UserApi)`.
|
|
63
|
+
*
|
|
64
|
+
* Every method carrying a request-method decorator becomes a function that
|
|
65
|
+
* builds a `SnailMethod` instead of running the original body — the decorated
|
|
66
|
+
* method exists only to declare the request's argument and return types:
|
|
67
|
+
*
|
|
68
|
+
* ```ts
|
|
69
|
+
* @Api("/user")
|
|
70
|
+
* class UserApi {
|
|
71
|
+
* @Get("/:id")
|
|
72
|
+
* getUser(@Params("id") id: string): Promise<User> { return null!; }
|
|
73
|
+
* }
|
|
74
|
+
*
|
|
75
|
+
* const userApi = Service.createApi(UserApi);
|
|
76
|
+
* const method = userApi.getUser("1"); // no request yet
|
|
77
|
+
* const { data } = await method.send(); // `data` is `User`
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* Methods without a request-method decorator are passed through untouched, so an
|
|
81
|
+
* api class may keep helpers next to its endpoints.
|
|
82
|
+
*/
|
|
83
|
+
export type SnailApiProxy<TClass, S = SnailEnvelopeSchema, D extends string = "data", C extends string = "code", M extends string = "message"> = {
|
|
84
|
+
[K in keyof TClass]: TClass[K] extends (...args: infer A) => infer R ? <TData = SnailPayloadOf<R>>(...args: A) => import("../core/method.js").SnailMethod<S, TData, D, C, M> : TClass[K];
|
|
85
|
+
};
|
|
86
|
+
/** Static description of one decorated method, extracted from its decorators. */
|
|
87
|
+
export interface SnailMethodMeta {
|
|
88
|
+
/** Server name. */
|
|
89
|
+
serverName: string;
|
|
90
|
+
/** Api class name. */
|
|
91
|
+
apiName: string;
|
|
92
|
+
/** Method name on the api class. */
|
|
93
|
+
methodName: string;
|
|
94
|
+
/** Fully qualified name: `server.api.method`. */
|
|
95
|
+
fullName: string;
|
|
96
|
+
/** Request verb. */
|
|
97
|
+
method: SnailMethodType;
|
|
98
|
+
/** Api prefix joined with the method path. */
|
|
99
|
+
url: string;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Per-call overrides.
|
|
103
|
+
*
|
|
104
|
+
* Mostly a convenience: prefer passing arguments to the proxied method. Kept for
|
|
105
|
+
* the cases where a strategy needs to inject a value the signature does not
|
|
106
|
+
* carry.
|
|
107
|
+
*/
|
|
108
|
+
export interface SnailSendOptions<TData = unknown> {
|
|
109
|
+
/** Override the body for this single call. */
|
|
110
|
+
data?: TData;
|
|
111
|
+
/** Override query params for this single call. */
|
|
112
|
+
query?: Record<string, any>;
|
|
113
|
+
/** Override path params for this single call. */
|
|
114
|
+
pathParams?: Record<string, any>;
|
|
115
|
+
/** Override headers for this single call. */
|
|
116
|
+
headers?: Record<string, any>;
|
|
117
|
+
/** Abort signal for this single call. */
|
|
118
|
+
signal?: AbortSignal;
|
|
119
|
+
}
|
|
120
|
+
/** Re-exported for convenience. */
|
|
121
|
+
export type { SnailResult };
|
|
122
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/typings/api.ts"],"names":[],"mappings":"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"}
|