@vielzeug/sourcerer 1.1.0 → 2.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/README.md +19 -74
- package/dist/_dev.cjs +1 -1
- package/dist/_dev.cjs.map +1 -1
- package/dist/_dev.js +2 -8
- package/dist/_dev.js.map +1 -1
- package/dist/asyncSource.cjs +1 -1
- package/dist/asyncSource.cjs.map +1 -1
- package/dist/asyncSource.d.ts +14 -58
- package/dist/asyncSource.d.ts.map +1 -1
- package/dist/asyncSource.js +28 -27
- package/dist/asyncSource.js.map +1 -1
- package/dist/cursorSource.cjs +1 -1
- package/dist/cursorSource.cjs.map +1 -1
- package/dist/cursorSource.d.ts +3 -3
- package/dist/cursorSource.d.ts.map +1 -1
- package/dist/cursorSource.js +76 -109
- package/dist/cursorSource.js.map +1 -1
- package/dist/devtools.cjs +1 -1
- package/dist/devtools.cjs.map +1 -1
- package/dist/devtools.d.ts +4 -50
- package/dist/devtools.d.ts.map +1 -1
- package/dist/devtools.js +3 -15
- package/dist/devtools.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +2 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -13
- package/dist/infiniteSource.cjs +1 -1
- package/dist/infiniteSource.cjs.map +1 -1
- package/dist/infiniteSource.d.ts +3 -3
- package/dist/infiniteSource.d.ts.map +1 -1
- package/dist/infiniteSource.js +71 -106
- package/dist/infiniteSource.js.map +1 -1
- package/dist/localSource.cjs +1 -1
- package/dist/localSource.cjs.map +1 -1
- package/dist/localSource.d.ts +2 -22
- package/dist/localSource.d.ts.map +1 -1
- package/dist/localSource.js +58 -104
- package/dist/localSource.js.map +1 -1
- package/dist/pageSource.cjs +2 -0
- package/dist/pageSource.cjs.map +1 -0
- package/dist/pageSource.d.ts +4 -0
- package/dist/pageSource.d.ts.map +1 -0
- package/dist/pageSource.js +96 -0
- package/dist/pageSource.js.map +1 -0
- package/dist/pagination.cjs +1 -1
- package/dist/pagination.cjs.map +1 -1
- package/dist/pagination.d.ts +5 -30
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +21 -27
- package/dist/pagination.js.map +1 -1
- package/dist/requestController.cjs +2 -0
- package/dist/requestController.cjs.map +1 -0
- package/dist/requestController.d.ts +13 -0
- package/dist/requestController.d.ts.map +1 -0
- package/dist/requestController.js +29 -0
- package/dist/requestController.js.map +1 -0
- package/dist/sourceStore.cjs +2 -0
- package/dist/sourceStore.cjs.map +1 -0
- package/dist/sourceStore.d.ts +10 -0
- package/dist/sourceStore.d.ts.map +1 -0
- package/dist/sourceStore.js +38 -0
- package/dist/sourceStore.js.map +1 -0
- package/dist/sourcerer.cjs +1 -1
- package/dist/sourcerer.cjs.map +1 -1
- package/dist/sourcerer.iife.js +1 -1
- package/dist/sourcerer.iife.js.map +1 -1
- package/dist/sourcerer.js +1 -1
- package/dist/sourcerer.js.map +1 -1
- package/dist/types.d.ts +128 -355
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -7
- package/dist/_utils.cjs +0 -2
- package/dist/_utils.cjs.map +0 -1
- package/dist/_utils.d.ts +0 -28
- package/dist/_utils.d.ts.map +0 -1
- package/dist/_utils.js +0 -20
- package/dist/_utils.js.map +0 -1
- package/dist/asyncSearch.cjs +0 -2
- package/dist/asyncSearch.cjs.map +0 -1
- package/dist/asyncSearch.d.ts +0 -13
- package/dist/asyncSearch.d.ts.map +0 -1
- package/dist/asyncSearch.js +0 -28
- package/dist/asyncSearch.js.map +0 -1
- package/dist/codecs.cjs +0 -2
- package/dist/codecs.cjs.map +0 -1
- package/dist/codecs.d.ts +0 -30
- package/dist/codecs.d.ts.map +0 -1
- package/dist/codecs.js +0 -38
- package/dist/codecs.js.map +0 -1
- package/dist/core.cjs +0 -2
- package/dist/core.cjs.map +0 -1
- package/dist/core.d.ts +0 -71
- package/dist/core.d.ts.map +0 -1
- package/dist/core.js +0 -59
- package/dist/core.js.map +0 -1
- package/dist/derive.cjs +0 -2
- package/dist/derive.cjs.map +0 -1
- package/dist/derive.d.ts +0 -29
- package/dist/derive.d.ts.map +0 -1
- package/dist/derive.js +0 -38
- package/dist/derive.js.map +0 -1
- package/dist/errors.cjs +0 -2
- package/dist/errors.cjs.map +0 -1
- package/dist/errors.d.ts +0 -62
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -29
- package/dist/errors.js.map +0 -1
- package/dist/fetchManager.cjs +0 -2
- package/dist/fetchManager.cjs.map +0 -1
- package/dist/fetchManager.d.ts +0 -40
- package/dist/fetchManager.d.ts.map +0 -1
- package/dist/fetchManager.js +0 -41
- package/dist/fetchManager.js.map +0 -1
- package/dist/merge.cjs +0 -2
- package/dist/merge.cjs.map +0 -1
- package/dist/merge.d.ts +0 -35
- package/dist/merge.d.ts.map +0 -1
- package/dist/merge.js +0 -41
- package/dist/merge.js.map +0 -1
- package/dist/prefetch.cjs +0 -2
- package/dist/prefetch.cjs.map +0 -1
- package/dist/prefetch.d.ts +0 -32
- package/dist/prefetch.d.ts.map +0 -1
- package/dist/prefetch.js +0 -38
- package/dist/prefetch.js.map +0 -1
- package/dist/presets.cjs +0 -2
- package/dist/presets.cjs.map +0 -1
- package/dist/presets.d.ts +0 -17
- package/dist/presets.d.ts.map +0 -1
- package/dist/presets.js +0 -43
- package/dist/presets.js.map +0 -1
- package/dist/remoteSource.cjs +0 -2
- package/dist/remoteSource.cjs.map +0 -1
- package/dist/remoteSource.d.ts +0 -4
- package/dist/remoteSource.d.ts.map +0 -1
- package/dist/remoteSource.js +0 -165
- package/dist/remoteSource.js.map +0 -1
- package/dist/state.cjs +0 -2
- package/dist/state.cjs.map +0 -1
- package/dist/state.d.ts +0 -23
- package/dist/state.d.ts.map +0 -1
- package/dist/state.js +0 -14
- package/dist/state.js.map +0 -1
package/dist/errors.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
//#region src/errors.ts
|
|
2
|
-
var e = class e extends Error {
|
|
3
|
-
#e;
|
|
4
|
-
constructor(e, t = {}) {
|
|
5
|
-
super(e, t.cause === void 0 ? void 0 : { cause: t.cause }), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype), this.#e = t;
|
|
6
|
-
}
|
|
7
|
-
get attempt() {
|
|
8
|
-
return this.#e.attempt ?? 0;
|
|
9
|
-
}
|
|
10
|
-
get context() {
|
|
11
|
-
return this.#e.context;
|
|
12
|
-
}
|
|
13
|
-
static is(t) {
|
|
14
|
-
return t instanceof e;
|
|
15
|
-
}
|
|
16
|
-
}, t = class extends e {
|
|
17
|
-
timeoutMs;
|
|
18
|
-
constructor(e) {
|
|
19
|
-
super(`Source.ready() timed out after ${e}ms`), this.timeoutMs = e;
|
|
20
|
-
}
|
|
21
|
-
}, n = class extends e {
|
|
22
|
-
constructor() {
|
|
23
|
-
super("Source disposed while waiting for ready()");
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
//#endregion
|
|
27
|
-
export { n as SourcererDisposedError, e as SourcererError, t as SourcererTimeoutError };
|
|
28
|
-
|
|
29
|
-
//# sourceMappingURL=errors.js.map
|
package/dist/errors.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","names":["#opts"],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Structured context carried by `SourcererError`.\n * Discriminated on `kind` — narrow with `error.context?.kind` to access typed fields.\n *\n * @example\n * ```ts\n * if (source.meta.error?.context?.kind === 'remote') {\n * console.log('Failed page', source.meta.error.context.page);\n * }\n * ```\n */\nexport type SourcererErrorContext =\n | Readonly<{ kind: 'cursor'; limit: number; search?: string }>\n | Readonly<{ kind: 'infinite'; limit: number; page: number; search?: string }>\n | Readonly<{ kind: 'remote'; limit: number; page: number; search?: string }>;\n\n/**\n * Base class for all sourcerer errors. Catch with `instanceof SourcererError` to handle any\n * sourcerer-originated error regardless of specific subtype.\n *\n * Carries the original cause, structured context, and the attempt number.\n *\n * @example\n * ```ts\n * if (source.meta.error) {\n * console.error(source.meta.error.message, source.meta.error.context);\n * }\n * ```\n */\nexport class SourcererError extends Error {\n readonly #opts: {\n readonly attempt?: number;\n readonly cause?: unknown;\n readonly context?: SourcererErrorContext;\n };\n\n constructor(\n message: string,\n opts: {\n readonly attempt?: number;\n readonly cause?: unknown;\n readonly context?: SourcererErrorContext;\n } = {},\n ) {\n super(message, opts.cause !== undefined ? { cause: opts.cause } : undefined);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n this.#opts = opts;\n }\n\n get attempt(): number {\n return this.#opts.attempt ?? 0;\n }\n\n /** Context bag for the error — safe to log. */\n get context(): SourcererErrorContext | undefined {\n return this.#opts.context;\n }\n\n static is(err: unknown): err is SourcererError {\n return err instanceof SourcererError;\n }\n}\n\n/** Thrown by `ready()` when the source timed out waiting for the first successful fetch. */\nexport class SourcererTimeoutError extends SourcererError {\n /** The configured timeout in milliseconds. */\n readonly timeoutMs: number;\n\n constructor(timeoutMs: number) {\n super(`Source.ready() timed out after ${timeoutMs}ms`);\n this.timeoutMs = timeoutMs;\n }\n}\n\n/** Thrown by `ready()` when the source is disposed while waiting. */\nexport class SourcererDisposedError extends SourcererError {\n constructor() {\n super('Source disposed while waiting for ready()');\n }\n}\n"],"mappings":";AA6BA,IAAa,IAAb,MAAa,UAAuB,MAAM;CACxC;CAMA,YACE,GACA,IAII,CAAC,GACL;EAIA,AAHA,MAAM,GAAS,EAAK,UAAU,KAAA,IAAoC,KAAA,IAAxB,EAAE,OAAO,EAAK,MAAM,CAAa,GAC3E,KAAK,OAAO,IAAI,OAAO,MACvB,OAAO,eAAe,MAAM,IAAI,OAAO,SAAS,GAChD,KAAKA,KAAQ;CACf;CAEA,IAAI,UAAkB;EACpB,OAAO,KAAKA,GAAM,WAAW;CAC/B;CAGA,IAAI,UAA6C;EAC/C,OAAO,KAAKA,GAAM;CACpB;CAEA,OAAO,GAAG,GAAqC;EAC7C,OAAO,aAAe;CACxB;AACF,GAGa,IAAb,cAA2C,EAAe;CAExD;CAEA,YAAY,GAAmB;EAE7B,AADA,MAAM,kCAAkC,EAAU,GAAG,GACrD,KAAK,YAAY;CACnB;AACF,GAGa,IAAb,cAA4C,EAAe;CACzD,cAAc;EACZ,MAAM,2CAA2C;CACnD;AACF"}
|
package/dist/fetchManager.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
function e(e){let t=new Map,n=``,r=0;return{dispose(){for(let e of t.values())e.controller.abort();t.clear(),r=0},get pendingCount(){return r},async run(i,a,o){let s=e(i);n=s;for(let[e,n]of t)e!==s&&(n.controller.abort(),t.delete(e));let c=t.get(s);if(c){r++,o();try{await c.promise}finally{r--,o()}return}let l=new AbortController;r++,o();let u=a(i,l.signal,()=>s===n).finally(()=>{t.delete(s),r--,o()});t.set(s,{controller:l,promise:u}),await u}}}exports.createFetchManager=e;
|
|
2
|
-
//# sourceMappingURL=fetchManager.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetchManager.cjs","names":[],"sources":["../src/fetchManager.ts"],"sourcesContent":["/**\n * Internal fetch deduplication and in-flight request manager.\n *\n * - Deduplicates identical concurrent queries: joiners await the existing in-flight promise.\n * - Aborts superseded in-flight requests when a new query key arrives.\n * - Tracks pending count so callers can reflect loading state.\n *\n * Not exported from the public API — consumed via `asyncSource.ts` by remoteSource,\n * cursorSource, and infiniteSource.\n *\n * Deliberately not `@vielzeug/courier`'s query cache: retry itself already comes from the\n * one shared implementation both packages use (`retry` from `@vielzeug/arsenal` — see\n * `_utils.ts`), so there's no retry logic duplicated here to remove. What's left — \"only one\n * query is ever active per source instance; a new query always supersedes and aborts the\n * previous one, regardless of key\" — is a narrower, different contract than courier's, which\n * is a shared cross-consumer cache keyed by query (many independent entries, each with its own\n * staleness window, meant to be read by multiple observers). Forcing this single-active-query\n * source to route through a per-key shared cache would need as much glue code to reconcile the\n * two models as this file already is, for no behavioral win. See `docs/sourcerer/examples/\n * sourcerer-with-courier.md` for the actually-intended integration point: pass a courier-backed\n * client call as the `fetch` callback into `createRemoteSource()` — composition at the\n * transport layer, not inside this dedup manager.\n */\n\ntype InFlightEntry = { controller: AbortController; promise: Promise<void> };\n\nexport type FetchManager<TQuery> = {\n /** Abort all in-flight requests and clear the registry. */\n dispose(): void;\n /** Number of currently in-flight requests (including joiners). */\n readonly pendingCount: number;\n /**\n * Run a fetch for query `q`.\n *\n * - If an identical key is already in-flight, joins as a waiter.\n * - If a different key is in-flight, aborts it and starts a new request.\n * - Calls `onPendingChange()` whenever `pendingCount` changes.\n * - Passes an `isLatest()` predicate to `execute` so it can skip stale responses.\n */\n run(\n q: TQuery,\n execute: (q: TQuery, signal: AbortSignal, isLatest: () => boolean) => Promise<void>,\n onPendingChange: () => void,\n ): Promise<void>;\n};\n\nexport function createFetchManager<TQuery>(keyOf: (q: TQuery) => string): FetchManager<TQuery> {\n const inflight = new Map<string, InFlightEntry>();\n let latestKey = '';\n let _pendingCount = 0;\n\n return {\n dispose() {\n for (const entry of inflight.values()) {\n entry.controller.abort();\n }\n\n inflight.clear();\n _pendingCount = 0;\n },\n\n get pendingCount() {\n return _pendingCount;\n },\n\n async run(q, execute, onPendingChange) {\n const key = keyOf(q);\n\n latestKey = key;\n\n // Abort and remove all superseded in-flight requests.\n for (const [k, entry] of inflight) {\n if (k !== key) {\n entry.controller.abort();\n inflight.delete(k);\n }\n }\n\n // Join an identical in-flight request rather than issuing a duplicate.\n const existing = inflight.get(key);\n\n if (existing) {\n _pendingCount++;\n onPendingChange();\n\n try {\n await existing.promise;\n } finally {\n _pendingCount--;\n onPendingChange();\n }\n\n return;\n }\n\n // New request.\n const controller = new AbortController();\n\n _pendingCount++;\n onPendingChange();\n\n const promise = execute(q, controller.signal, () => key === latestKey).finally(() => {\n inflight.delete(key);\n _pendingCount--;\n onPendingChange();\n });\n\n inflight.set(key, { controller, promise });\n await promise;\n },\n };\n}\n"],"mappings":"AA8CA,SAAgB,EAA2B,EAAoD,CAC7F,IAAM,EAAW,IAAI,IACjB,EAAY,GACZ,EAAgB,EAEpB,MAAO,CACL,SAAU,CACR,IAAK,IAAM,KAAS,EAAS,OAAO,EAClC,EAAM,WAAW,MAAM,EAGzB,EAAS,MAAM,EACf,EAAgB,CAClB,EAEA,IAAI,cAAe,CACjB,OAAO,CACT,EAEA,MAAM,IAAI,EAAG,EAAS,EAAiB,CACrC,IAAM,EAAM,EAAM,CAAC,EAEnB,EAAY,EAGZ,IAAK,GAAM,CAAC,EAAG,KAAU,EACnB,IAAM,IACR,EAAM,WAAW,MAAM,EACvB,EAAS,OAAO,CAAC,GAKrB,IAAM,EAAW,EAAS,IAAI,CAAG,EAEjC,GAAI,EAAU,CACZ,IACA,EAAgB,EAEhB,GAAI,CACF,MAAM,EAAS,OACjB,QAAU,CACR,IACA,EAAgB,CAClB,CAEA,MACF,CAGA,IAAM,EAAa,IAAI,gBAEvB,IACA,EAAgB,EAEhB,IAAM,EAAU,EAAQ,EAAG,EAAW,WAAc,IAAQ,CAAS,CAAC,CAAC,YAAc,CACnF,EAAS,OAAO,CAAG,EACnB,IACA,EAAgB,CAClB,CAAC,EAED,EAAS,IAAI,EAAK,CAAE,aAAY,SAAQ,CAAC,EACzC,MAAM,CACR,CACF,CACF"}
|
package/dist/fetchManager.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Internal fetch deduplication and in-flight request manager.
|
|
3
|
-
*
|
|
4
|
-
* - Deduplicates identical concurrent queries: joiners await the existing in-flight promise.
|
|
5
|
-
* - Aborts superseded in-flight requests when a new query key arrives.
|
|
6
|
-
* - Tracks pending count so callers can reflect loading state.
|
|
7
|
-
*
|
|
8
|
-
* Not exported from the public API — consumed via `asyncSource.ts` by remoteSource,
|
|
9
|
-
* cursorSource, and infiniteSource.
|
|
10
|
-
*
|
|
11
|
-
* Deliberately not `@vielzeug/courier`'s query cache: retry itself already comes from the
|
|
12
|
-
* one shared implementation both packages use (`retry` from `@vielzeug/arsenal` — see
|
|
13
|
-
* `_utils.ts`), so there's no retry logic duplicated here to remove. What's left — "only one
|
|
14
|
-
* query is ever active per source instance; a new query always supersedes and aborts the
|
|
15
|
-
* previous one, regardless of key" — is a narrower, different contract than courier's, which
|
|
16
|
-
* is a shared cross-consumer cache keyed by query (many independent entries, each with its own
|
|
17
|
-
* staleness window, meant to be read by multiple observers). Forcing this single-active-query
|
|
18
|
-
* source to route through a per-key shared cache would need as much glue code to reconcile the
|
|
19
|
-
* two models as this file already is, for no behavioral win. See `docs/sourcerer/examples/
|
|
20
|
-
* sourcerer-with-courier.md` for the actually-intended integration point: pass a courier-backed
|
|
21
|
-
* client call as the `fetch` callback into `createRemoteSource()` — composition at the
|
|
22
|
-
* transport layer, not inside this dedup manager.
|
|
23
|
-
*/
|
|
24
|
-
export type FetchManager<TQuery> = {
|
|
25
|
-
/** Abort all in-flight requests and clear the registry. */
|
|
26
|
-
dispose(): void;
|
|
27
|
-
/** Number of currently in-flight requests (including joiners). */
|
|
28
|
-
readonly pendingCount: number;
|
|
29
|
-
/**
|
|
30
|
-
* Run a fetch for query `q`.
|
|
31
|
-
*
|
|
32
|
-
* - If an identical key is already in-flight, joins as a waiter.
|
|
33
|
-
* - If a different key is in-flight, aborts it and starts a new request.
|
|
34
|
-
* - Calls `onPendingChange()` whenever `pendingCount` changes.
|
|
35
|
-
* - Passes an `isLatest()` predicate to `execute` so it can skip stale responses.
|
|
36
|
-
*/
|
|
37
|
-
run(q: TQuery, execute: (q: TQuery, signal: AbortSignal, isLatest: () => boolean) => Promise<void>, onPendingChange: () => void): Promise<void>;
|
|
38
|
-
};
|
|
39
|
-
export declare function createFetchManager<TQuery>(keyOf: (q: TQuery) => string): FetchManager<TQuery>;
|
|
40
|
-
//# sourceMappingURL=fetchManager.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetchManager.d.ts","sourceRoot":"","sources":["../src/fetchManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,MAAM,MAAM,YAAY,CAAC,MAAM,IAAI;IACjC,2DAA2D;IAC3D,OAAO,IAAI,IAAI,CAAC;IAChB,kEAAkE;IAClE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;;;;OAOG;IACH,GAAG,CACD,CAAC,EAAE,MAAM,EACT,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,EACnF,eAAe,EAAE,MAAM,IAAI,GAC1B,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAiE7F"}
|
package/dist/fetchManager.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
//#region src/fetchManager.ts
|
|
2
|
-
function e(e) {
|
|
3
|
-
let t = /* @__PURE__ */ new Map(), n = "", r = 0;
|
|
4
|
-
return {
|
|
5
|
-
dispose() {
|
|
6
|
-
for (let e of t.values()) e.controller.abort();
|
|
7
|
-
t.clear(), r = 0;
|
|
8
|
-
},
|
|
9
|
-
get pendingCount() {
|
|
10
|
-
return r;
|
|
11
|
-
},
|
|
12
|
-
async run(i, a, o) {
|
|
13
|
-
let s = e(i);
|
|
14
|
-
n = s;
|
|
15
|
-
for (let [e, n] of t) e !== s && (n.controller.abort(), t.delete(e));
|
|
16
|
-
let c = t.get(s);
|
|
17
|
-
if (c) {
|
|
18
|
-
r++, o();
|
|
19
|
-
try {
|
|
20
|
-
await c.promise;
|
|
21
|
-
} finally {
|
|
22
|
-
r--, o();
|
|
23
|
-
}
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
let l = new AbortController();
|
|
27
|
-
r++, o();
|
|
28
|
-
let u = a(i, l.signal, () => s === n).finally(() => {
|
|
29
|
-
t.delete(s), r--, o();
|
|
30
|
-
});
|
|
31
|
-
t.set(s, {
|
|
32
|
-
controller: l,
|
|
33
|
-
promise: u
|
|
34
|
-
}), await u;
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
//#endregion
|
|
39
|
-
export { e as createFetchManager };
|
|
40
|
-
|
|
41
|
-
//# sourceMappingURL=fetchManager.js.map
|
package/dist/fetchManager.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetchManager.js","names":[],"sources":["../src/fetchManager.ts"],"sourcesContent":["/**\n * Internal fetch deduplication and in-flight request manager.\n *\n * - Deduplicates identical concurrent queries: joiners await the existing in-flight promise.\n * - Aborts superseded in-flight requests when a new query key arrives.\n * - Tracks pending count so callers can reflect loading state.\n *\n * Not exported from the public API — consumed via `asyncSource.ts` by remoteSource,\n * cursorSource, and infiniteSource.\n *\n * Deliberately not `@vielzeug/courier`'s query cache: retry itself already comes from the\n * one shared implementation both packages use (`retry` from `@vielzeug/arsenal` — see\n * `_utils.ts`), so there's no retry logic duplicated here to remove. What's left — \"only one\n * query is ever active per source instance; a new query always supersedes and aborts the\n * previous one, regardless of key\" — is a narrower, different contract than courier's, which\n * is a shared cross-consumer cache keyed by query (many independent entries, each with its own\n * staleness window, meant to be read by multiple observers). Forcing this single-active-query\n * source to route through a per-key shared cache would need as much glue code to reconcile the\n * two models as this file already is, for no behavioral win. See `docs/sourcerer/examples/\n * sourcerer-with-courier.md` for the actually-intended integration point: pass a courier-backed\n * client call as the `fetch` callback into `createRemoteSource()` — composition at the\n * transport layer, not inside this dedup manager.\n */\n\ntype InFlightEntry = { controller: AbortController; promise: Promise<void> };\n\nexport type FetchManager<TQuery> = {\n /** Abort all in-flight requests and clear the registry. */\n dispose(): void;\n /** Number of currently in-flight requests (including joiners). */\n readonly pendingCount: number;\n /**\n * Run a fetch for query `q`.\n *\n * - If an identical key is already in-flight, joins as a waiter.\n * - If a different key is in-flight, aborts it and starts a new request.\n * - Calls `onPendingChange()` whenever `pendingCount` changes.\n * - Passes an `isLatest()` predicate to `execute` so it can skip stale responses.\n */\n run(\n q: TQuery,\n execute: (q: TQuery, signal: AbortSignal, isLatest: () => boolean) => Promise<void>,\n onPendingChange: () => void,\n ): Promise<void>;\n};\n\nexport function createFetchManager<TQuery>(keyOf: (q: TQuery) => string): FetchManager<TQuery> {\n const inflight = new Map<string, InFlightEntry>();\n let latestKey = '';\n let _pendingCount = 0;\n\n return {\n dispose() {\n for (const entry of inflight.values()) {\n entry.controller.abort();\n }\n\n inflight.clear();\n _pendingCount = 0;\n },\n\n get pendingCount() {\n return _pendingCount;\n },\n\n async run(q, execute, onPendingChange) {\n const key = keyOf(q);\n\n latestKey = key;\n\n // Abort and remove all superseded in-flight requests.\n for (const [k, entry] of inflight) {\n if (k !== key) {\n entry.controller.abort();\n inflight.delete(k);\n }\n }\n\n // Join an identical in-flight request rather than issuing a duplicate.\n const existing = inflight.get(key);\n\n if (existing) {\n _pendingCount++;\n onPendingChange();\n\n try {\n await existing.promise;\n } finally {\n _pendingCount--;\n onPendingChange();\n }\n\n return;\n }\n\n // New request.\n const controller = new AbortController();\n\n _pendingCount++;\n onPendingChange();\n\n const promise = execute(q, controller.signal, () => key === latestKey).finally(() => {\n inflight.delete(key);\n _pendingCount--;\n onPendingChange();\n });\n\n inflight.set(key, { controller, promise });\n await promise;\n },\n };\n}\n"],"mappings":";AA8CA,SAAgB,EAA2B,GAAoD;CAC7F,IAAM,oBAAW,IAAI,IAA2B,GAC5C,IAAY,IACZ,IAAgB;CAEpB,OAAO;EACL,UAAU;GACR,KAAK,IAAM,KAAS,EAAS,OAAO,GAClC,EAAM,WAAW,MAAM;GAIzB,AADA,EAAS,MAAM,GACf,IAAgB;EAClB;EAEA,IAAI,eAAe;GACjB,OAAO;EACT;EAEA,MAAM,IAAI,GAAG,GAAS,GAAiB;GACrC,IAAM,IAAM,EAAM,CAAC;GAEnB,IAAY;GAGZ,KAAK,IAAM,CAAC,GAAG,MAAU,GACvB,AAAI,MAAM,MACR,EAAM,WAAW,MAAM,GACvB,EAAS,OAAO,CAAC;GAKrB,IAAM,IAAW,EAAS,IAAI,CAAG;GAEjC,IAAI,GAAU;IAEZ,AADA,KACA,EAAgB;IAEhB,IAAI;KACF,MAAM,EAAS;IACjB,UAAU;KAER,AADA,KACA,EAAgB;IAClB;IAEA;GACF;GAGA,IAAM,IAAa,IAAI,gBAAgB;GAGvC,AADA,KACA,EAAgB;GAEhB,IAAM,IAAU,EAAQ,GAAG,EAAW,cAAc,MAAQ,CAAS,CAAC,CAAC,cAAc;IAGnF,AAFA,EAAS,OAAO,CAAG,GACnB,KACA,EAAgB;GAClB,CAAC;GAGD,AADA,EAAS,IAAI,GAAK;IAAE;IAAY;GAAQ,CAAC,GACzC,MAAM;EACR;CACF;AACF"}
|
package/dist/merge.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require("./core.cjs");function t(t,n){let r=e.createSourceCore(),i=n(t.map(e=>e.current)),a=t.map(e=>e.subscribe(()=>{i=n(t.map(e=>e.current)),r.notify()})),o={get current(){return i},get disposalSignal(){return r.disposalSignal},dispose(){if(!r.isDisposed){for(let e of a)e();r.dispose()}},get disposed(){return r.isDisposed},subscribe(e){return r.subscribe(e)},[Symbol.dispose](){o.dispose()}},s=t.map(e=>e.disposalSignal).filter(e=>e instanceof AbortSignal);if(s.length===t.length&&s.length>0){let e=s.filter(e=>!e.aborted).length;if(e===0)o.dispose();else for(let t of s)t.aborted||t.addEventListener(`abort`,()=>{e--,e===0&&o.dispose()},{once:!0})}return o}exports.mergeSource=t;
|
|
2
|
-
//# sourceMappingURL=merge.cjs.map
|
package/dist/merge.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"merge.cjs","names":[],"sources":["../src/merge.ts"],"sourcesContent":["import type { MergedSource } from './types';\n\nimport { createSourceCore } from './core';\n\n/**\n * Combines multiple reactive sources into a single read-only view by applying\n * a user-supplied `combine` function over all sources' `current` arrays.\n *\n * The merged source recalculates whenever any parent source changes. Useful for\n * offline/online hybrid UIs (local + remote merged), multi-dataset views, or\n * pagination across multiple backends.\n *\n * Call `dispose()` to unsubscribe from all parent sources. If every parent exposes a\n * `disposalSignal` (the standard `ReactiveSource` shape does), the merge auto-disposes once\n * every parent has disposed — mirroring `deriveSource()`'s single-parent auto-dispose, scaled\n * to N parents. If any parent lacks `disposalSignal` (a minimal duck-typed source), auto-dispose\n * doesn't activate — call `dispose()` yourself.\n *\n * @example\n * ```ts\n * const local = createLocalSource(localCache, { limit: 50 });\n * const remote = createRemoteSource({ fetch: fetchUsers, limit: 50 });\n *\n * // Show local cache items first, then remote items (deduped by id).\n * const merged = mergeSource([local, remote], (all) => {\n * const seen = new Set<number>();\n * return all.flat().filter((u) => !seen.has(u.id) && seen.add(u.id));\n * });\n *\n * merged.subscribe(() => console.log(merged.current));\n * ```\n */\nexport function mergeSource<T>(\n sources: ReadonlyArray<{\n readonly current: readonly T[];\n readonly disposalSignal?: AbortSignal;\n subscribe(listener: () => void): () => void;\n }>,\n combine: (allItems: ReadonlyArray<readonly T[]>) => readonly T[],\n): MergedSource<T> {\n const core = createSourceCore();\n let cachedCurrent: readonly T[] = combine(sources.map((s) => s.current));\n\n const unsubscribeFns = sources.map((source) =>\n source.subscribe(() => {\n cachedCurrent = combine(sources.map((s) => s.current));\n core.notify();\n }),\n );\n\n const source: MergedSource<T> = {\n get current() {\n return cachedCurrent;\n },\n\n get disposalSignal() {\n return core.disposalSignal;\n },\n\n dispose() {\n if (core.isDisposed) return;\n\n for (const unsub of unsubscribeFns) {\n unsub();\n }\n\n core.dispose();\n },\n\n get disposed() {\n return core.isDisposed;\n },\n\n subscribe(listener) {\n return core.subscribe(listener);\n },\n\n [Symbol.dispose]() {\n source.dispose();\n },\n };\n\n // Mirrors deriveSource()'s parent-lifetime tracking, scaled to N parents: once every\n // parent has disposed there's nothing left this merge could ever reflect, so it disposes\n // itself too instead of staying alive holding now-permanently-stale combined state.\n // Only tracked when every source actually exposes a disposalSignal — mergeSource() also\n // accepts minimal duck-typed sources (per its parameter type) that may not have one.\n // Routed through `source.dispose()` above, not `core.dispose()` directly, so there's exactly\n // one cleanup path (including unsubscribing from parents) regardless of what triggered it.\n const disposalSignals = sources\n .map((s) => s.disposalSignal)\n .filter((s): s is AbortSignal => s instanceof AbortSignal);\n\n if (disposalSignals.length === sources.length && disposalSignals.length > 0) {\n let pendingCount = disposalSignals.filter((s) => !s.aborted).length;\n\n if (pendingCount === 0) {\n // Every parent was already disposed before mergeSource() was even called.\n source.dispose();\n } else {\n for (const signal of disposalSignals) {\n if (signal.aborted) continue;\n\n signal.addEventListener(\n 'abort',\n () => {\n pendingCount--;\n\n if (pendingCount === 0) source.dispose();\n },\n { once: true },\n );\n }\n }\n }\n\n return source;\n}\n"],"mappings":"8BAgCA,SAAgB,EACd,EAKA,EACiB,CACjB,IAAM,EAAO,EAAA,iBAAiB,EAC1B,EAA8B,EAAQ,EAAQ,IAAK,GAAM,EAAE,OAAO,CAAC,EAEjE,EAAiB,EAAQ,IAAK,GAClC,EAAO,cAAgB,CACrB,EAAgB,EAAQ,EAAQ,IAAK,GAAM,EAAE,OAAO,CAAC,EACrD,EAAK,OAAO,CACd,CAAC,CACH,EAEM,EAA0B,CAC9B,IAAI,SAAU,CACZ,OAAO,CACT,EAEA,IAAI,gBAAiB,CACnB,OAAO,EAAK,cACd,EAEA,SAAU,CACJ,MAAK,WAET,KAAK,IAAM,KAAS,EAClB,EAAM,EAGR,EAAK,QAAQ,CAHL,CAIV,EAEA,IAAI,UAAW,CACb,OAAO,EAAK,UACd,EAEA,UAAU,EAAU,CAClB,OAAO,EAAK,UAAU,CAAQ,CAChC,EAEA,CAAC,OAAO,UAAW,CACjB,EAAO,QAAQ,CACjB,CACF,EASM,EAAkB,EACrB,IAAK,GAAM,EAAE,cAAc,CAAC,CAC5B,OAAQ,GAAwB,aAAa,WAAW,EAE3D,GAAI,EAAgB,SAAW,EAAQ,QAAU,EAAgB,OAAS,EAAG,CAC3E,IAAI,EAAe,EAAgB,OAAQ,GAAM,CAAC,EAAE,OAAO,CAAC,CAAC,OAE7D,GAAI,IAAiB,EAEnB,EAAO,QAAQ,OAEf,IAAK,IAAM,KAAU,EACf,EAAO,SAEX,EAAO,iBACL,YACM,CACJ,IAEI,IAAiB,GAAG,EAAO,QAAQ,CACzC,EACA,CAAE,KAAM,EAAK,CACf,CAGN,CAEA,OAAO,CACT"}
|
package/dist/merge.d.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { MergedSource } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Combines multiple reactive sources into a single read-only view by applying
|
|
4
|
-
* a user-supplied `combine` function over all sources' `current` arrays.
|
|
5
|
-
*
|
|
6
|
-
* The merged source recalculates whenever any parent source changes. Useful for
|
|
7
|
-
* offline/online hybrid UIs (local + remote merged), multi-dataset views, or
|
|
8
|
-
* pagination across multiple backends.
|
|
9
|
-
*
|
|
10
|
-
* Call `dispose()` to unsubscribe from all parent sources. If every parent exposes a
|
|
11
|
-
* `disposalSignal` (the standard `ReactiveSource` shape does), the merge auto-disposes once
|
|
12
|
-
* every parent has disposed — mirroring `deriveSource()`'s single-parent auto-dispose, scaled
|
|
13
|
-
* to N parents. If any parent lacks `disposalSignal` (a minimal duck-typed source), auto-dispose
|
|
14
|
-
* doesn't activate — call `dispose()` yourself.
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```ts
|
|
18
|
-
* const local = createLocalSource(localCache, { limit: 50 });
|
|
19
|
-
* const remote = createRemoteSource({ fetch: fetchUsers, limit: 50 });
|
|
20
|
-
*
|
|
21
|
-
* // Show local cache items first, then remote items (deduped by id).
|
|
22
|
-
* const merged = mergeSource([local, remote], (all) => {
|
|
23
|
-
* const seen = new Set<number>();
|
|
24
|
-
* return all.flat().filter((u) => !seen.has(u.id) && seen.add(u.id));
|
|
25
|
-
* });
|
|
26
|
-
*
|
|
27
|
-
* merged.subscribe(() => console.log(merged.current));
|
|
28
|
-
* ```
|
|
29
|
-
*/
|
|
30
|
-
export declare function mergeSource<T>(sources: ReadonlyArray<{
|
|
31
|
-
readonly current: readonly T[];
|
|
32
|
-
readonly disposalSignal?: AbortSignal;
|
|
33
|
-
subscribe(listener: () => void): () => void;
|
|
34
|
-
}>, combine: (allItems: ReadonlyArray<readonly T[]>) => readonly T[]): MergedSource<T>;
|
|
35
|
-
//# sourceMappingURL=merge.d.ts.map
|
package/dist/merge.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI5C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,OAAO,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;IAC/B,QAAQ,CAAC,cAAc,CAAC,EAAE,WAAW,CAAC;IACtC,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC7C,CAAC,EACF,OAAO,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC,EAAE,GAC/D,YAAY,CAAC,CAAC,CAAC,CA8EjB"}
|
package/dist/merge.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { createSourceCore as e } from "./core.js";
|
|
2
|
-
//#region src/merge.ts
|
|
3
|
-
function t(t, n) {
|
|
4
|
-
let r = e(), i = n(t.map((e) => e.current)), a = t.map((e) => e.subscribe(() => {
|
|
5
|
-
i = n(t.map((e) => e.current)), r.notify();
|
|
6
|
-
})), o = {
|
|
7
|
-
get current() {
|
|
8
|
-
return i;
|
|
9
|
-
},
|
|
10
|
-
get disposalSignal() {
|
|
11
|
-
return r.disposalSignal;
|
|
12
|
-
},
|
|
13
|
-
dispose() {
|
|
14
|
-
if (!r.isDisposed) {
|
|
15
|
-
for (let e of a) e();
|
|
16
|
-
r.dispose();
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
get disposed() {
|
|
20
|
-
return r.isDisposed;
|
|
21
|
-
},
|
|
22
|
-
subscribe(e) {
|
|
23
|
-
return r.subscribe(e);
|
|
24
|
-
},
|
|
25
|
-
[Symbol.dispose]() {
|
|
26
|
-
o.dispose();
|
|
27
|
-
}
|
|
28
|
-
}, s = t.map((e) => e.disposalSignal).filter((e) => e instanceof AbortSignal);
|
|
29
|
-
if (s.length === t.length && s.length > 0) {
|
|
30
|
-
let e = s.filter((e) => !e.aborted).length;
|
|
31
|
-
if (e === 0) o.dispose();
|
|
32
|
-
else for (let t of s) t.aborted || t.addEventListener("abort", () => {
|
|
33
|
-
e--, e === 0 && o.dispose();
|
|
34
|
-
}, { once: !0 });
|
|
35
|
-
}
|
|
36
|
-
return o;
|
|
37
|
-
}
|
|
38
|
-
//#endregion
|
|
39
|
-
export { t as mergeSource };
|
|
40
|
-
|
|
41
|
-
//# sourceMappingURL=merge.js.map
|
package/dist/merge.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"merge.js","names":[],"sources":["../src/merge.ts"],"sourcesContent":["import type { MergedSource } from './types';\n\nimport { createSourceCore } from './core';\n\n/**\n * Combines multiple reactive sources into a single read-only view by applying\n * a user-supplied `combine` function over all sources' `current` arrays.\n *\n * The merged source recalculates whenever any parent source changes. Useful for\n * offline/online hybrid UIs (local + remote merged), multi-dataset views, or\n * pagination across multiple backends.\n *\n * Call `dispose()` to unsubscribe from all parent sources. If every parent exposes a\n * `disposalSignal` (the standard `ReactiveSource` shape does), the merge auto-disposes once\n * every parent has disposed — mirroring `deriveSource()`'s single-parent auto-dispose, scaled\n * to N parents. If any parent lacks `disposalSignal` (a minimal duck-typed source), auto-dispose\n * doesn't activate — call `dispose()` yourself.\n *\n * @example\n * ```ts\n * const local = createLocalSource(localCache, { limit: 50 });\n * const remote = createRemoteSource({ fetch: fetchUsers, limit: 50 });\n *\n * // Show local cache items first, then remote items (deduped by id).\n * const merged = mergeSource([local, remote], (all) => {\n * const seen = new Set<number>();\n * return all.flat().filter((u) => !seen.has(u.id) && seen.add(u.id));\n * });\n *\n * merged.subscribe(() => console.log(merged.current));\n * ```\n */\nexport function mergeSource<T>(\n sources: ReadonlyArray<{\n readonly current: readonly T[];\n readonly disposalSignal?: AbortSignal;\n subscribe(listener: () => void): () => void;\n }>,\n combine: (allItems: ReadonlyArray<readonly T[]>) => readonly T[],\n): MergedSource<T> {\n const core = createSourceCore();\n let cachedCurrent: readonly T[] = combine(sources.map((s) => s.current));\n\n const unsubscribeFns = sources.map((source) =>\n source.subscribe(() => {\n cachedCurrent = combine(sources.map((s) => s.current));\n core.notify();\n }),\n );\n\n const source: MergedSource<T> = {\n get current() {\n return cachedCurrent;\n },\n\n get disposalSignal() {\n return core.disposalSignal;\n },\n\n dispose() {\n if (core.isDisposed) return;\n\n for (const unsub of unsubscribeFns) {\n unsub();\n }\n\n core.dispose();\n },\n\n get disposed() {\n return core.isDisposed;\n },\n\n subscribe(listener) {\n return core.subscribe(listener);\n },\n\n [Symbol.dispose]() {\n source.dispose();\n },\n };\n\n // Mirrors deriveSource()'s parent-lifetime tracking, scaled to N parents: once every\n // parent has disposed there's nothing left this merge could ever reflect, so it disposes\n // itself too instead of staying alive holding now-permanently-stale combined state.\n // Only tracked when every source actually exposes a disposalSignal — mergeSource() also\n // accepts minimal duck-typed sources (per its parameter type) that may not have one.\n // Routed through `source.dispose()` above, not `core.dispose()` directly, so there's exactly\n // one cleanup path (including unsubscribing from parents) regardless of what triggered it.\n const disposalSignals = sources\n .map((s) => s.disposalSignal)\n .filter((s): s is AbortSignal => s instanceof AbortSignal);\n\n if (disposalSignals.length === sources.length && disposalSignals.length > 0) {\n let pendingCount = disposalSignals.filter((s) => !s.aborted).length;\n\n if (pendingCount === 0) {\n // Every parent was already disposed before mergeSource() was even called.\n source.dispose();\n } else {\n for (const signal of disposalSignals) {\n if (signal.aborted) continue;\n\n signal.addEventListener(\n 'abort',\n () => {\n pendingCount--;\n\n if (pendingCount === 0) source.dispose();\n },\n { once: true },\n );\n }\n }\n }\n\n return source;\n}\n"],"mappings":";;AAgCA,SAAgB,EACd,GAKA,GACiB;CACjB,IAAM,IAAO,EAAiB,GAC1B,IAA8B,EAAQ,EAAQ,KAAK,MAAM,EAAE,OAAO,CAAC,GAEjE,IAAiB,EAAQ,KAAK,MAClC,EAAO,gBAAgB;EAErB,AADA,IAAgB,EAAQ,EAAQ,KAAK,MAAM,EAAE,OAAO,CAAC,GACrD,EAAK,OAAO;CACd,CAAC,CACH,GAEM,IAA0B;EAC9B,IAAI,UAAU;GACZ,OAAO;EACT;EAEA,IAAI,iBAAiB;GACnB,OAAO,EAAK;EACd;EAEA,UAAU;GACJ,OAAK,YAET;SAAK,IAAM,KAAS,GAClB,EAAM;IAGR,EAAK,QAAQ;GAHL;EAIV;EAEA,IAAI,WAAW;GACb,OAAO,EAAK;EACd;EAEA,UAAU,GAAU;GAClB,OAAO,EAAK,UAAU,CAAQ;EAChC;EAEA,CAAC,OAAO,WAAW;GACjB,EAAO,QAAQ;EACjB;CACF,GASM,IAAkB,EACrB,KAAK,MAAM,EAAE,cAAc,CAAC,CAC5B,QAAQ,MAAwB,aAAa,WAAW;CAE3D,IAAI,EAAgB,WAAW,EAAQ,UAAU,EAAgB,SAAS,GAAG;EAC3E,IAAI,IAAe,EAAgB,QAAQ,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;EAE7D,IAAI,MAAiB,GAEnB,EAAO,QAAQ;OAEf,KAAK,IAAM,KAAU,GACf,EAAO,WAEX,EAAO,iBACL,eACM;GAGJ,AAFA,KAEI,MAAiB,KAAG,EAAO,QAAQ;EACzC,GACA,EAAE,MAAM,GAAK,CACf;CAGN;CAEA,OAAO;AACT"}
|
package/dist/prefetch.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require("./remoteSource.cjs");var t=e=>{let t=e.query;return{items:e.current,...t.search&&{search:t.search},page:e.meta.pageNumber,total:e.meta.totalItems}};async function n(n){let r=e.createRemoteSource({...n,autoFetch:!1});try{if(await r.refresh(),r.meta.error)throw r.meta.error;return t(r)}finally{r.dispose()}}async function r(n){let r=e.createRemoteSource({...n,autoFetch:!1});if(await r.refresh(),r.meta.error)throw r.dispose(),r.meta.error;return{snapshot:t(r),source:r}}exports.prefetchSource=n,exports.prefetchSourceAndKeep=r;
|
|
2
|
-
//# sourceMappingURL=prefetch.cjs.map
|
package/dist/prefetch.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prefetch.cjs","names":[],"sources":["../src/prefetch.ts"],"sourcesContent":["import type { RemoteConfig, RemoteSource, SourceSnapshot } from './types';\n\nimport { createRemoteSource } from './remoteSource';\n\ntype PrefetchConfig<T, TFilter, TSort> = Omit<RemoteConfig<T, TFilter, TSort>, 'autoFetch' | 'refreshInterval'>;\n\nconst buildSnapshot = <T, TFilter, TSort>(source: RemoteSource<T, TFilter, TSort>): SourceSnapshot<T> => {\n const q = source.query;\n\n return {\n items: source.current,\n ...(q.search && { search: q.search }),\n page: source.meta.pageNumber,\n total: source.meta.totalItems,\n };\n};\n\n/**\n * Fetches a single page of data and returns a serialisable `SourceSnapshot`.\n * The underlying source is created, fetched, then immediately disposed.\n * Use for SSR / static-generation where you only need the data, not a live source.\n *\n * @example\n * ```ts\n * const snapshot = await prefetchSource({ fetch: fetchUsers, limit: 20 });\n * ```\n */\nexport async function prefetchSource<T, TFilter = unknown, TSort = unknown>(\n cfg: PrefetchConfig<T, TFilter, TSort>,\n): Promise<SourceSnapshot<T>> {\n const source = createRemoteSource<T, TFilter, TSort>({ ...cfg, autoFetch: false });\n\n try {\n await source.refresh();\n\n if (source.meta.error) throw source.meta.error;\n\n return buildSnapshot(source);\n } finally {\n source.dispose();\n }\n}\n\n/**\n * Fetches a single page of data and returns both a serialisable `SourceSnapshot` and the\n * still-live `RemoteSource`. Useful when you need the snapshot for SSR serialisation\n * **and** the live source for subsequent client-side updates without a double-fetch.\n *\n * **The caller is responsible for disposing the returned source.**\n *\n * @example\n * ```ts\n * const { snapshot, source } = await prefetchSourceAndKeep({ fetch: fetchUsers, limit: 20 });\n * // hydrate HTML with snapshot, pass source to client\n * ```\n */\nexport async function prefetchSourceAndKeep<T, TFilter = unknown, TSort = unknown>(\n cfg: PrefetchConfig<T, TFilter, TSort>,\n): Promise<{ snapshot: SourceSnapshot<T>; source: RemoteSource<T, TFilter, TSort> }> {\n const source = createRemoteSource<T, TFilter, TSort>({ ...cfg, autoFetch: false });\n\n await source.refresh();\n\n if (source.meta.error) {\n source.dispose();\n throw source.meta.error;\n }\n\n return { snapshot: buildSnapshot(source), source };\n}\n"],"mappings":"sCAMA,IAAM,EAAoC,GAA+D,CACvG,IAAM,EAAI,EAAO,MAEjB,MAAO,CACL,MAAO,EAAO,QACd,GAAI,EAAE,QAAU,CAAE,OAAQ,EAAE,MAAO,EACnC,KAAM,EAAO,KAAK,WAClB,MAAO,EAAO,KAAK,UACrB,CACF,EAYA,eAAsB,EACpB,EAC4B,CAC5B,IAAM,EAAS,EAAA,mBAAsC,CAAE,GAAG,EAAK,UAAW,EAAM,CAAC,EAEjF,GAAI,CAGF,GAFA,MAAM,EAAO,QAAQ,EAEjB,EAAO,KAAK,MAAO,MAAM,EAAO,KAAK,MAEzC,OAAO,EAAc,CAAM,CAC7B,QAAU,CACR,EAAO,QAAQ,CACjB,CACF,CAeA,eAAsB,EACpB,EACmF,CACnF,IAAM,EAAS,EAAA,mBAAsC,CAAE,GAAG,EAAK,UAAW,EAAM,CAAC,EAIjF,GAFA,MAAM,EAAO,QAAQ,EAEjB,EAAO,KAAK,MAEd,MADA,EAAO,QAAQ,EACT,EAAO,KAAK,MAGpB,MAAO,CAAE,SAAU,EAAc,CAAM,EAAG,QAAO,CACnD"}
|
package/dist/prefetch.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { RemoteConfig, RemoteSource, SourceSnapshot } from './types';
|
|
2
|
-
type PrefetchConfig<T, TFilter, TSort> = Omit<RemoteConfig<T, TFilter, TSort>, 'autoFetch' | 'refreshInterval'>;
|
|
3
|
-
/**
|
|
4
|
-
* Fetches a single page of data and returns a serialisable `SourceSnapshot`.
|
|
5
|
-
* The underlying source is created, fetched, then immediately disposed.
|
|
6
|
-
* Use for SSR / static-generation where you only need the data, not a live source.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* const snapshot = await prefetchSource({ fetch: fetchUsers, limit: 20 });
|
|
11
|
-
* ```
|
|
12
|
-
*/
|
|
13
|
-
export declare function prefetchSource<T, TFilter = unknown, TSort = unknown>(cfg: PrefetchConfig<T, TFilter, TSort>): Promise<SourceSnapshot<T>>;
|
|
14
|
-
/**
|
|
15
|
-
* Fetches a single page of data and returns both a serialisable `SourceSnapshot` and the
|
|
16
|
-
* still-live `RemoteSource`. Useful when you need the snapshot for SSR serialisation
|
|
17
|
-
* **and** the live source for subsequent client-side updates without a double-fetch.
|
|
18
|
-
*
|
|
19
|
-
* **The caller is responsible for disposing the returned source.**
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```ts
|
|
23
|
-
* const { snapshot, source } = await prefetchSourceAndKeep({ fetch: fetchUsers, limit: 20 });
|
|
24
|
-
* // hydrate HTML with snapshot, pass source to client
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export declare function prefetchSourceAndKeep<T, TFilter = unknown, TSort = unknown>(cfg: PrefetchConfig<T, TFilter, TSort>): Promise<{
|
|
28
|
-
snapshot: SourceSnapshot<T>;
|
|
29
|
-
source: RemoteSource<T, TFilter, TSort>;
|
|
30
|
-
}>;
|
|
31
|
-
export {};
|
|
32
|
-
//# sourceMappingURL=prefetch.d.ts.map
|
package/dist/prefetch.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prefetch.d.ts","sourceRoot":"","sources":["../src/prefetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAI1E,KAAK,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAAC,CAAC;AAahH;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,KAAK,GAAG,OAAO,EACxE,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,GACrC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAY5B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,KAAK,GAAG,OAAO,EAC/E,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,GACrC,OAAO,CAAC;IAAE,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAAC,MAAM,EAAE,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CAAA;CAAE,CAAC,CAWnF"}
|
package/dist/prefetch.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { createRemoteSource as e } from "./remoteSource.js";
|
|
2
|
-
//#region src/prefetch.ts
|
|
3
|
-
var t = (e) => {
|
|
4
|
-
let t = e.query;
|
|
5
|
-
return {
|
|
6
|
-
items: e.current,
|
|
7
|
-
...t.search && { search: t.search },
|
|
8
|
-
page: e.meta.pageNumber,
|
|
9
|
-
total: e.meta.totalItems
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
async function n(n) {
|
|
13
|
-
let r = e({
|
|
14
|
-
...n,
|
|
15
|
-
autoFetch: !1
|
|
16
|
-
});
|
|
17
|
-
try {
|
|
18
|
-
if (await r.refresh(), r.meta.error) throw r.meta.error;
|
|
19
|
-
return t(r);
|
|
20
|
-
} finally {
|
|
21
|
-
r.dispose();
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
async function r(n) {
|
|
25
|
-
let r = e({
|
|
26
|
-
...n,
|
|
27
|
-
autoFetch: !1
|
|
28
|
-
});
|
|
29
|
-
if (await r.refresh(), r.meta.error) throw r.dispose(), r.meta.error;
|
|
30
|
-
return {
|
|
31
|
-
snapshot: t(r),
|
|
32
|
-
source: r
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
//#endregion
|
|
36
|
-
export { n as prefetchSource, r as prefetchSourceAndKeep };
|
|
37
|
-
|
|
38
|
-
//# sourceMappingURL=prefetch.js.map
|
package/dist/prefetch.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prefetch.js","names":[],"sources":["../src/prefetch.ts"],"sourcesContent":["import type { RemoteConfig, RemoteSource, SourceSnapshot } from './types';\n\nimport { createRemoteSource } from './remoteSource';\n\ntype PrefetchConfig<T, TFilter, TSort> = Omit<RemoteConfig<T, TFilter, TSort>, 'autoFetch' | 'refreshInterval'>;\n\nconst buildSnapshot = <T, TFilter, TSort>(source: RemoteSource<T, TFilter, TSort>): SourceSnapshot<T> => {\n const q = source.query;\n\n return {\n items: source.current,\n ...(q.search && { search: q.search }),\n page: source.meta.pageNumber,\n total: source.meta.totalItems,\n };\n};\n\n/**\n * Fetches a single page of data and returns a serialisable `SourceSnapshot`.\n * The underlying source is created, fetched, then immediately disposed.\n * Use for SSR / static-generation where you only need the data, not a live source.\n *\n * @example\n * ```ts\n * const snapshot = await prefetchSource({ fetch: fetchUsers, limit: 20 });\n * ```\n */\nexport async function prefetchSource<T, TFilter = unknown, TSort = unknown>(\n cfg: PrefetchConfig<T, TFilter, TSort>,\n): Promise<SourceSnapshot<T>> {\n const source = createRemoteSource<T, TFilter, TSort>({ ...cfg, autoFetch: false });\n\n try {\n await source.refresh();\n\n if (source.meta.error) throw source.meta.error;\n\n return buildSnapshot(source);\n } finally {\n source.dispose();\n }\n}\n\n/**\n * Fetches a single page of data and returns both a serialisable `SourceSnapshot` and the\n * still-live `RemoteSource`. Useful when you need the snapshot for SSR serialisation\n * **and** the live source for subsequent client-side updates without a double-fetch.\n *\n * **The caller is responsible for disposing the returned source.**\n *\n * @example\n * ```ts\n * const { snapshot, source } = await prefetchSourceAndKeep({ fetch: fetchUsers, limit: 20 });\n * // hydrate HTML with snapshot, pass source to client\n * ```\n */\nexport async function prefetchSourceAndKeep<T, TFilter = unknown, TSort = unknown>(\n cfg: PrefetchConfig<T, TFilter, TSort>,\n): Promise<{ snapshot: SourceSnapshot<T>; source: RemoteSource<T, TFilter, TSort> }> {\n const source = createRemoteSource<T, TFilter, TSort>({ ...cfg, autoFetch: false });\n\n await source.refresh();\n\n if (source.meta.error) {\n source.dispose();\n throw source.meta.error;\n }\n\n return { snapshot: buildSnapshot(source), source };\n}\n"],"mappings":";;AAMA,IAAM,KAAoC,MAA+D;CACvG,IAAM,IAAI,EAAO;CAEjB,OAAO;EACL,OAAO,EAAO;EACd,GAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO;EACnC,MAAM,EAAO,KAAK;EAClB,OAAO,EAAO,KAAK;CACrB;AACF;AAYA,eAAsB,EACpB,GAC4B;CAC5B,IAAM,IAAS,EAAsC;EAAE,GAAG;EAAK,WAAW;CAAM,CAAC;CAEjF,IAAI;EAGF,IAFA,MAAM,EAAO,QAAQ,GAEjB,EAAO,KAAK,OAAO,MAAM,EAAO,KAAK;EAEzC,OAAO,EAAc,CAAM;CAC7B,UAAU;EACR,EAAO,QAAQ;CACjB;AACF;AAeA,eAAsB,EACpB,GACmF;CACnF,IAAM,IAAS,EAAsC;EAAE,GAAG;EAAK,WAAW;CAAM,CAAC;CAIjF,IAFA,MAAM,EAAO,QAAQ,GAEjB,EAAO,KAAK,OAEd,MADA,EAAO,QAAQ,GACT,EAAO,KAAK;CAGpB,OAAO;EAAE,UAAU,EAAc,CAAM;EAAG;CAAO;AACnD"}
|
package/dist/presets.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var e=e=>{if(e==null)return``;if(typeof e==`bigint`||typeof e==`boolean`||typeof e==`number`||typeof e==`string`)return String(e);if(e instanceof Date)return e.toISOString();try{return JSON.stringify(e)??``}catch{return String(e)}},t=(e,t,n=!1)=>{let r=n?t:t.toLowerCase();return t=>{let i=e(t)??``;return(n?i:i.toLowerCase()).includes(r)}},n=(e,t)=>n=>Object.is(e(n),t),r=(e,t)=>{let n=e=>e instanceof Date?e.getTime():e,r=t.min===void 0?void 0:n(t.min),i=t.max===void 0?void 0:n(t.max);return t=>{let a=n(e(t));return!(r!==void 0&&a<r||i!==void 0&&a>i)}},i=(e,t=`asc`)=>{let n=t===`asc`?1:-1;return(t,r)=>{let i=e(t),a=e(r);return i instanceof Date&&a instanceof Date?(i.getTime()-a.getTime())*n:i<a?-1*n:i>a?1*n:0}},a=(t,n={})=>{let r=Array.isArray(t)?t:[t],i=n.caseSensitive===!0;return(t,n)=>{if(n.length===0)return t;let a=i?n:n.toLowerCase();return t.filter(t=>r.some(n=>{let r=e(n(t));return(i?r:r.toLowerCase()).includes(a)}))}};exports.filterContains=t,exports.filterEquals=n,exports.filterRange=r,exports.searchBy=a,exports.sortBy=i;
|
|
2
|
-
//# sourceMappingURL=presets.cjs.map
|
package/dist/presets.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"presets.cjs","names":[],"sources":["../src/presets.ts"],"sourcesContent":["import type { Predicate, Sorter } from './types';\n\ntype Direction = 'asc' | 'desc';\n\ntype PrimitiveComparable = number | string | Date;\ntype SearchByGetter<T> = (item: T) => unknown;\ntype SearchByOptions = Readonly<{ caseSensitive?: boolean }>;\n\nconst toSearchableString = (value: unknown): string => {\n if (value === null || value === undefined) return '';\n\n if (\n typeof value === 'bigint' ||\n typeof value === 'boolean' ||\n typeof value === 'number' ||\n typeof value === 'string'\n ) {\n return String(value);\n }\n\n if (value instanceof Date) return value.toISOString();\n\n try {\n return JSON.stringify(value) ?? '';\n } catch {\n return String(value);\n }\n};\n\nexport const filterContains = <T>(\n getValue: (item: T) => string | null | undefined,\n query: string,\n caseSensitive = false,\n): Predicate<T> => {\n const needle = caseSensitive ? query : query.toLowerCase();\n\n return (item) => {\n const value = getValue(item) ?? '';\n const haystack = caseSensitive ? value : value.toLowerCase();\n\n return haystack.includes(needle);\n };\n};\n\nexport const filterEquals = <T, V>(getValue: (item: T) => V, expected: V): Predicate<T> => {\n return (item) => Object.is(getValue(item), expected);\n};\n\nexport const filterRange = <T>(\n getValue: (item: T) => Date | number,\n bounds: Readonly<{ max?: Date | number; min?: Date | number }>,\n): Predicate<T> => {\n const toNum = (v: Date | number): number => (v instanceof Date ? v.getTime() : v);\n\n const min = bounds.min !== undefined ? toNum(bounds.min) : undefined;\n const max = bounds.max !== undefined ? toNum(bounds.max) : undefined;\n\n return (item) => {\n const value = toNum(getValue(item));\n\n if (min !== undefined && value < min) return false;\n\n if (max !== undefined && value > max) return false;\n\n return true;\n };\n};\n\nexport const sortBy = <T, V extends PrimitiveComparable>(\n getValue: (item: T) => V,\n direction: Direction = 'asc',\n): Sorter<T> => {\n const sign = direction === 'asc' ? 1 : -1;\n\n return (a, b) => {\n const left = getValue(a);\n const right = getValue(b);\n\n if (left instanceof Date && right instanceof Date) {\n return (left.getTime() - right.getTime()) * sign;\n }\n\n if (left < right) return -1 * sign;\n\n if (left > right) return 1 * sign;\n\n return 0;\n };\n};\n\nexport const searchBy = <T>(\n getValue: SearchByGetter<T> | readonly SearchByGetter<T>[],\n opts: SearchByOptions = {},\n): ((items: readonly T[], query: string) => readonly T[]) => {\n const getters = Array.isArray(getValue) ? getValue : [getValue];\n const caseSensitive = opts.caseSensitive === true;\n\n return (items, query) => {\n if (query.length === 0) return items;\n\n const needle = caseSensitive ? query : query.toLowerCase();\n\n return items.filter((item) => {\n return getters.some((getter) => {\n const raw = toSearchableString(getter(item));\n const haystack = caseSensitive ? raw : raw.toLowerCase();\n\n return haystack.includes(needle);\n });\n });\n };\n};\n"],"mappings":"AAQA,IAAM,EAAsB,GAA2B,CACrD,GAAI,GAAU,KAA6B,MAAO,GAElD,GACE,OAAO,GAAU,UACjB,OAAO,GAAU,WACjB,OAAO,GAAU,UACjB,OAAO,GAAU,SAEjB,OAAO,OAAO,CAAK,EAGrB,GAAI,aAAiB,KAAM,OAAO,EAAM,YAAY,EAEpD,GAAI,CACF,OAAO,KAAK,UAAU,CAAK,GAAK,EAClC,MAAQ,CACN,OAAO,OAAO,CAAK,CACrB,CACF,EAEa,GACX,EACA,EACA,EAAgB,KACC,CACjB,IAAM,EAAS,EAAgB,EAAQ,EAAM,YAAY,EAEzD,MAAQ,IAAS,CACf,IAAM,EAAQ,EAAS,CAAI,GAAK,GAGhC,OAFiB,EAAgB,EAAQ,EAAM,YAAY,EAAA,CAE3C,SAAS,CAAM,CACjC,CACF,EAEa,GAAsB,EAA0B,IACnD,GAAS,OAAO,GAAG,EAAS,CAAI,EAAG,CAAQ,EAGxC,GACX,EACA,IACiB,CACjB,IAAM,EAAS,GAA8B,aAAa,KAAO,EAAE,QAAQ,EAAI,EAEzE,EAAM,EAAO,MAAQ,IAAA,GAAgC,IAAA,GAApB,EAAM,EAAO,GAAG,EACjD,EAAM,EAAO,MAAQ,IAAA,GAAgC,IAAA,GAApB,EAAM,EAAO,GAAG,EAEvD,MAAQ,IAAS,CACf,IAAM,EAAQ,EAAM,EAAS,CAAI,CAAC,EAMlC,MAFA,EAFI,IAAQ,IAAA,IAAa,EAAQ,GAE7B,IAAQ,IAAA,IAAa,EAAQ,EAGnC,CACF,EAEa,GACX,EACA,EAAuB,QACT,CACd,IAAM,EAAO,IAAc,MAAQ,EAAI,GAEvC,OAAQ,EAAG,IAAM,CACf,IAAM,EAAO,EAAS,CAAC,EACjB,EAAQ,EAAS,CAAC,EAUxB,OARI,aAAgB,MAAQ,aAAiB,MACnC,EAAK,QAAQ,EAAI,EAAM,QAAQ,GAAK,EAG1C,EAAO,EAAc,GAAK,EAE1B,EAAO,EAAc,EAAI,EAEtB,CACT,CACF,EAEa,GACX,EACA,EAAwB,CAAC,IACkC,CAC3D,IAAM,EAAU,MAAM,QAAQ,CAAQ,EAAI,EAAW,CAAC,CAAQ,EACxD,EAAgB,EAAK,gBAAkB,GAE7C,OAAQ,EAAO,IAAU,CACvB,GAAI,EAAM,SAAW,EAAG,OAAO,EAE/B,IAAM,EAAS,EAAgB,EAAQ,EAAM,YAAY,EAEzD,OAAO,EAAM,OAAQ,GACZ,EAAQ,KAAM,GAAW,CAC9B,IAAM,EAAM,EAAmB,EAAO,CAAI,CAAC,EAG3C,OAFiB,EAAgB,EAAM,EAAI,YAAY,EAAA,CAEvC,SAAS,CAAM,CACjC,CAAC,CACF,CACH,CACF"}
|
package/dist/presets.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { Predicate, Sorter } from './types';
|
|
2
|
-
type Direction = 'asc' | 'desc';
|
|
3
|
-
type PrimitiveComparable = number | string | Date;
|
|
4
|
-
type SearchByGetter<T> = (item: T) => unknown;
|
|
5
|
-
type SearchByOptions = Readonly<{
|
|
6
|
-
caseSensitive?: boolean;
|
|
7
|
-
}>;
|
|
8
|
-
export declare const filterContains: <T>(getValue: (item: T) => string | null | undefined, query: string, caseSensitive?: boolean) => Predicate<T>;
|
|
9
|
-
export declare const filterEquals: <T, V>(getValue: (item: T) => V, expected: V) => Predicate<T>;
|
|
10
|
-
export declare const filterRange: <T>(getValue: (item: T) => Date | number, bounds: Readonly<{
|
|
11
|
-
max?: Date | number;
|
|
12
|
-
min?: Date | number;
|
|
13
|
-
}>) => Predicate<T>;
|
|
14
|
-
export declare const sortBy: <T, V extends PrimitiveComparable>(getValue: (item: T) => V, direction?: Direction) => Sorter<T>;
|
|
15
|
-
export declare const searchBy: <T>(getValue: SearchByGetter<T> | readonly SearchByGetter<T>[], opts?: SearchByOptions) => ((items: readonly T[], query: string) => readonly T[]);
|
|
16
|
-
export {};
|
|
17
|
-
//# sourceMappingURL=presets.d.ts.map
|
package/dist/presets.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjD,KAAK,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhC,KAAK,mBAAmB,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAClD,KAAK,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;AAC9C,KAAK,eAAe,GAAG,QAAQ,CAAC;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAuB7D,eAAO,MAAM,cAAc,GAAI,CAAC,EAC9B,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,EAChD,OAAO,MAAM,EACb,uBAAqB,KACpB,SAAS,CAAC,CAAC,CASb,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,KAAG,SAAS,CAAC,CAAC,CAErF,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,CAAC,EAC3B,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,EACpC,QAAQ,QAAQ,CAAC;IAAE,GAAG,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,CAAC,KAC7D,SAAS,CAAC,CAAC,CAeb,CAAC;AAEF,eAAO,MAAM,MAAM,GAAI,CAAC,EAAE,CAAC,SAAS,mBAAmB,EACrD,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EACxB,YAAW,SAAiB,KAC3B,MAAM,CAAC,CAAC,CAiBV,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,CAAC,EACxB,UAAU,cAAc,CAAC,CAAC,CAAC,GAAG,SAAS,cAAc,CAAC,CAAC,CAAC,EAAE,EAC1D,OAAM,eAAoB,KACzB,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC,EAAE,CAkBvD,CAAC"}
|
package/dist/presets.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
//#region src/presets.ts
|
|
2
|
-
var e = (e) => {
|
|
3
|
-
if (e == null) return "";
|
|
4
|
-
if (typeof e == "bigint" || typeof e == "boolean" || typeof e == "number" || typeof e == "string") return String(e);
|
|
5
|
-
if (e instanceof Date) return e.toISOString();
|
|
6
|
-
try {
|
|
7
|
-
return JSON.stringify(e) ?? "";
|
|
8
|
-
} catch {
|
|
9
|
-
return String(e);
|
|
10
|
-
}
|
|
11
|
-
}, t = (e, t, n = !1) => {
|
|
12
|
-
let r = n ? t : t.toLowerCase();
|
|
13
|
-
return (t) => {
|
|
14
|
-
let i = e(t) ?? "";
|
|
15
|
-
return (n ? i : i.toLowerCase()).includes(r);
|
|
16
|
-
};
|
|
17
|
-
}, n = (e, t) => (n) => Object.is(e(n), t), r = (e, t) => {
|
|
18
|
-
let n = (e) => e instanceof Date ? e.getTime() : e, r = t.min === void 0 ? void 0 : n(t.min), i = t.max === void 0 ? void 0 : n(t.max);
|
|
19
|
-
return (t) => {
|
|
20
|
-
let a = n(e(t));
|
|
21
|
-
return !(r !== void 0 && a < r || i !== void 0 && a > i);
|
|
22
|
-
};
|
|
23
|
-
}, i = (e, t = "asc") => {
|
|
24
|
-
let n = t === "asc" ? 1 : -1;
|
|
25
|
-
return (t, r) => {
|
|
26
|
-
let i = e(t), a = e(r);
|
|
27
|
-
return i instanceof Date && a instanceof Date ? (i.getTime() - a.getTime()) * n : i < a ? -1 * n : i > a ? 1 * n : 0;
|
|
28
|
-
};
|
|
29
|
-
}, a = (t, n = {}) => {
|
|
30
|
-
let r = Array.isArray(t) ? t : [t], i = n.caseSensitive === !0;
|
|
31
|
-
return (t, n) => {
|
|
32
|
-
if (n.length === 0) return t;
|
|
33
|
-
let a = i ? n : n.toLowerCase();
|
|
34
|
-
return t.filter((t) => r.some((n) => {
|
|
35
|
-
let r = e(n(t));
|
|
36
|
-
return (i ? r : r.toLowerCase()).includes(a);
|
|
37
|
-
}));
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
|
-
//#endregion
|
|
41
|
-
export { t as filterContains, n as filterEquals, r as filterRange, a as searchBy, i as sortBy };
|
|
42
|
-
|
|
43
|
-
//# sourceMappingURL=presets.js.map
|
package/dist/presets.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"presets.js","names":[],"sources":["../src/presets.ts"],"sourcesContent":["import type { Predicate, Sorter } from './types';\n\ntype Direction = 'asc' | 'desc';\n\ntype PrimitiveComparable = number | string | Date;\ntype SearchByGetter<T> = (item: T) => unknown;\ntype SearchByOptions = Readonly<{ caseSensitive?: boolean }>;\n\nconst toSearchableString = (value: unknown): string => {\n if (value === null || value === undefined) return '';\n\n if (\n typeof value === 'bigint' ||\n typeof value === 'boolean' ||\n typeof value === 'number' ||\n typeof value === 'string'\n ) {\n return String(value);\n }\n\n if (value instanceof Date) return value.toISOString();\n\n try {\n return JSON.stringify(value) ?? '';\n } catch {\n return String(value);\n }\n};\n\nexport const filterContains = <T>(\n getValue: (item: T) => string | null | undefined,\n query: string,\n caseSensitive = false,\n): Predicate<T> => {\n const needle = caseSensitive ? query : query.toLowerCase();\n\n return (item) => {\n const value = getValue(item) ?? '';\n const haystack = caseSensitive ? value : value.toLowerCase();\n\n return haystack.includes(needle);\n };\n};\n\nexport const filterEquals = <T, V>(getValue: (item: T) => V, expected: V): Predicate<T> => {\n return (item) => Object.is(getValue(item), expected);\n};\n\nexport const filterRange = <T>(\n getValue: (item: T) => Date | number,\n bounds: Readonly<{ max?: Date | number; min?: Date | number }>,\n): Predicate<T> => {\n const toNum = (v: Date | number): number => (v instanceof Date ? v.getTime() : v);\n\n const min = bounds.min !== undefined ? toNum(bounds.min) : undefined;\n const max = bounds.max !== undefined ? toNum(bounds.max) : undefined;\n\n return (item) => {\n const value = toNum(getValue(item));\n\n if (min !== undefined && value < min) return false;\n\n if (max !== undefined && value > max) return false;\n\n return true;\n };\n};\n\nexport const sortBy = <T, V extends PrimitiveComparable>(\n getValue: (item: T) => V,\n direction: Direction = 'asc',\n): Sorter<T> => {\n const sign = direction === 'asc' ? 1 : -1;\n\n return (a, b) => {\n const left = getValue(a);\n const right = getValue(b);\n\n if (left instanceof Date && right instanceof Date) {\n return (left.getTime() - right.getTime()) * sign;\n }\n\n if (left < right) return -1 * sign;\n\n if (left > right) return 1 * sign;\n\n return 0;\n };\n};\n\nexport const searchBy = <T>(\n getValue: SearchByGetter<T> | readonly SearchByGetter<T>[],\n opts: SearchByOptions = {},\n): ((items: readonly T[], query: string) => readonly T[]) => {\n const getters = Array.isArray(getValue) ? getValue : [getValue];\n const caseSensitive = opts.caseSensitive === true;\n\n return (items, query) => {\n if (query.length === 0) return items;\n\n const needle = caseSensitive ? query : query.toLowerCase();\n\n return items.filter((item) => {\n return getters.some((getter) => {\n const raw = toSearchableString(getter(item));\n const haystack = caseSensitive ? raw : raw.toLowerCase();\n\n return haystack.includes(needle);\n });\n });\n };\n};\n"],"mappings":";AAQA,IAAM,KAAsB,MAA2B;CACrD,IAAI,KAAU,MAA6B,OAAO;CAElD,IACE,OAAO,KAAU,YACjB,OAAO,KAAU,aACjB,OAAO,KAAU,YACjB,OAAO,KAAU,UAEjB,OAAO,OAAO,CAAK;CAGrB,IAAI,aAAiB,MAAM,OAAO,EAAM,YAAY;CAEpD,IAAI;EACF,OAAO,KAAK,UAAU,CAAK,KAAK;CAClC,QAAQ;EACN,OAAO,OAAO,CAAK;CACrB;AACF,GAEa,KACX,GACA,GACA,IAAgB,OACC;CACjB,IAAM,IAAS,IAAgB,IAAQ,EAAM,YAAY;CAEzD,QAAQ,MAAS;EACf,IAAM,IAAQ,EAAS,CAAI,KAAK;EAGhC,QAFiB,IAAgB,IAAQ,EAAM,YAAY,EAAA,CAE3C,SAAS,CAAM;CACjC;AACF,GAEa,KAAsB,GAA0B,OACnD,MAAS,OAAO,GAAG,EAAS,CAAI,GAAG,CAAQ,GAGxC,KACX,GACA,MACiB;CACjB,IAAM,KAAS,MAA8B,aAAa,OAAO,EAAE,QAAQ,IAAI,GAEzE,IAAM,EAAO,QAAQ,KAAA,IAAgC,KAAA,IAApB,EAAM,EAAO,GAAG,GACjD,IAAM,EAAO,QAAQ,KAAA,IAAgC,KAAA,IAApB,EAAM,EAAO,GAAG;CAEvD,QAAQ,MAAS;EACf,IAAM,IAAQ,EAAM,EAAS,CAAI,CAAC;EAMlC,OAFA,EAFI,MAAQ,KAAA,KAAa,IAAQ,KAE7B,MAAQ,KAAA,KAAa,IAAQ;CAGnC;AACF,GAEa,KACX,GACA,IAAuB,UACT;CACd,IAAM,IAAO,MAAc,QAAQ,IAAI;CAEvC,QAAQ,GAAG,MAAM;EACf,IAAM,IAAO,EAAS,CAAC,GACjB,IAAQ,EAAS,CAAC;EAUxB,OARI,aAAgB,QAAQ,aAAiB,QACnC,EAAK,QAAQ,IAAI,EAAM,QAAQ,KAAK,IAG1C,IAAO,IAAc,KAAK,IAE1B,IAAO,IAAc,IAAI,IAEtB;CACT;AACF,GAEa,KACX,GACA,IAAwB,CAAC,MACkC;CAC3D,IAAM,IAAU,MAAM,QAAQ,CAAQ,IAAI,IAAW,CAAC,CAAQ,GACxD,IAAgB,EAAK,kBAAkB;CAE7C,QAAQ,GAAO,MAAU;EACvB,IAAI,EAAM,WAAW,GAAG,OAAO;EAE/B,IAAM,IAAS,IAAgB,IAAQ,EAAM,YAAY;EAEzD,OAAO,EAAM,QAAQ,MACZ,EAAQ,MAAM,MAAW;GAC9B,IAAM,IAAM,EAAmB,EAAO,CAAI,CAAC;GAG3C,QAFiB,IAAgB,IAAM,EAAI,YAAY,EAAA,CAEvC,SAAS,CAAM;EACjC,CAAC,CACF;CACH;AACF"}
|
package/dist/remoteSource.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require("./_utils.cjs"),t=require("./errors.cjs"),n=require("./asyncSearch.cjs"),r=require("./asyncSource.cjs"),i=require("./pagination.cjs");let a=require("@vielzeug/arsenal");function o(o){let s=o.queryKey??e.defaultKeyOf,c=o.staleTime??0,l=e.clampPositiveInt(o.limit??20,`createRemoteSource`,`limit`),u=1,d=``,f=o.filter,p=o.sort,m=[],h=0,g=null,_=0,v=``,y=null;o.snapshot&&(m=o.snapshot.items,h=o.snapshot.total,o.snapshot.page!==void 0&&(u=o.snapshot.page),o.snapshot.search&&(d=o.snapshot.search),_=Date.now());let b=[],x=i.createMeta({error:null,isLoading:!1,isSearchPending:!1,pageNumber:1,pageSize:l,totalItems:0}),S=()=>{let e=i.pageCount(h,l),t=i.clampPage(u,e);b=m,x=i.createMeta({error:g,isLoading:C.pendingCount()>0,isSearchPending:C.core.isScheduled,pageNumber:t,pageSize:l,totalItems:h})},C=r.createAsyncSource(o,s,S),{autoFetch:w,debounceMs:T,retryAttempts:E,retryDelay:D}=C;S();let O=()=>{C.disposed||C.core.notify()},k=n.createAsyncSearchCoordinator(C.core,O),A=e=>{y?.active&&(y.active=!1,y=null),m=e.items,h=e.total,u=i.clampPage(u,i.pageCount(h,l))},j=()=>({...f!==void 0&&{filter:f},...p!==void 0&&{sort:p},...d&&{search:d},limit:l,page:u}),M=n=>{let r=s(n);return c>0&&r===v&&h>0&&Date.now()-_<c&&!y?.active?Promise.resolve():(g=null,C.fetch(n,async(n,i,s)=>{let c=Date.now();try{let e=await(0,a.retry)(e=>o.fetch(n,e),{delay:D,signal:i,times:E+1});s()&&(A(e),g=null,v=r,_=Date.now(),o.onFetch?.({durationMs:Date.now()-c,query:n,status:`success`}))}catch(r){if(i.aborted)return;s()&&(y?.active?(y.active=!1,m=y.prevItems,h=y.prevTotal,y=null):(m=[],h=0),g=new t.SourcererError(e.extractError(r),{cause:r,context:{kind:`remote`,limit:n.limit,page:n.page,...n.search&&{search:n.search}}}),o.onFetch?.({durationMs:Date.now()-c,error:g,query:n,status:`error`}))}},()=>{O(),k.settleIfIdle(C.pendingCount())}))},N=()=>M(j());return w&&N(),C.startRefreshInterval(()=>void N()),{get current(){return b},get disposalSignal(){return C.disposalSignal},dispose:()=>{k.cancel(),k.dispose(),C.dispose()},get disposed(){return C.disposed},goTo(t){let n=h>0?i.clampPage(t,i.pageCount(h,l)):e.clampPositiveInt(t,`source.goTo`,`target`);return n===u?Promise.resolve():(u=n,N())},goToLast(){let e=i.pageCount(h,l);return u===e?Promise.resolve():(u=e,N())},get meta(){return x},next(){let e=i.pageCount(h,l);return u>=e?Promise.resolve():(u++,N())},optimisticUpdate(e,n){if(y?.active)throw new t.SourcererError(`An optimistic update is already active. Rollback the previous update before starting another.`);let r=m,i=h;y={active:!0,prevItems:r,prevTotal:i};try{m=e(m)}catch(e){throw y=null,e}return h=n?.total??h,O(),()=>{y?.active&&(y.active=!1,m=r,h=i,y=null,O())}},patch(t){let n=!1;if(t.limit!==void 0){let r=e.clampPositiveInt(t.limit,`source.patch`,`limit`);r!==l&&(l=r,n=!0)}if(`filter`in t&&(f=t.filter,n=!0),`sort`in t&&(p=t.sort,n=!0),`search`in t&&(t.search!==d||C.core.isScheduled)&&(d=t.search??``,n=!0),t.page!==void 0){let r=h>0?i.clampPage(t.page,i.pageCount(h,l)):e.clampPositiveInt(t.page,`source.patch`,`page`);r!==u&&(u=r,n=!0)}return n?(k.cancel(),(t.limit!==void 0||`filter`in t||`sort`in t||`search`in t)&&t.page===void 0&&(u=1),N()):Promise.resolve()},prev(){return u<=1?Promise.resolve():(u--,N())},get query(){return{...f!==void 0&&{filter:f},...p!==void 0&&{sort:p},...d&&{search:d},limit:l,page:u}},ready(e){return C.ready(e)},refresh(){return N()},reset(){return k.cancel(),d=``,u=1,f=o.filter,p=o.sort,N()},search(e,t){return t?.immediate?e===d&&!C.core.isScheduled?Promise.resolve():(k.cancel(),d=e,u=1,N()):e===d?Promise.resolve():(d=e,u=1,k.schedule(()=>void N(),T))},subscribe:e=>C.core.subscribe(e),[Symbol.dispose]:()=>{k.cancel(),k.dispose(),C.dispose()}}}exports.createRemoteSource=o;
|
|
2
|
-
//# sourceMappingURL=remoteSource.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"remoteSource.cjs","names":[],"sources":["../src/remoteSource.ts"],"sourcesContent":["import type { RemoteConfig, RemoteSource, RemoteSourceQuery, SearchOptions } from './types';\n\nimport { clampPositiveInt, defaultKeyOf, extractError, retry } from './_utils';\nimport { createAsyncSearchCoordinator } from './asyncSearch';\nimport { createAsyncSource } from './asyncSource';\nimport { SourcererError } from './errors';\nimport { clampPage, createMeta, pageCount } from './pagination';\n\n/** Creates a remote page-based source that fetches data from a network endpoint. */\nexport function createRemoteSource<T, TFilter = unknown, TSort = unknown>(\n cfg: RemoteConfig<T, TFilter, TSort>,\n): RemoteSource<T, TFilter, TSort> {\n const keyOf = cfg.queryKey ?? defaultKeyOf;\n\n // ── Config defaults ─────────────────────────────────────────────────────────\n const staleTimeMs = cfg.staleTime ?? 0;\n\n // ── Mutable state ───────────────────────────────────────────────────────────\n let limit = clampPositiveInt(cfg.limit ?? 20, 'createRemoteSource', 'limit');\n let page = 1;\n let search = '';\n let filter: TFilter | undefined = cfg.filter;\n let sort: TSort | undefined = cfg.sort;\n let items: readonly T[] = [];\n let total = 0;\n let error: SourcererError | null = null;\n let lastFetchTime = 0;\n let lastFetchKey = '';\n\n // Optimistic update state.\n let optimistic: { active: boolean; prevItems: readonly T[]; prevTotal: number } | null = null;\n\n // ── Snapshot pre-population ─────────────────────────────────────────────────\n if (cfg.snapshot) {\n items = cfg.snapshot.items;\n total = cfg.snapshot.total;\n\n if (cfg.snapshot.page !== undefined) page = cfg.snapshot.page;\n\n if (cfg.snapshot.search) search = cfg.snapshot.search;\n\n lastFetchTime = Date.now();\n }\n\n // ── Cached accessors ────────────────────────────────────────────────────────\n let cachedCurrent: readonly T[] = [];\n let cachedMeta = createMeta({\n error: null,\n isLoading: false,\n isSearchPending: false,\n pageNumber: 1,\n pageSize: limit,\n totalItems: 0,\n });\n\n const refreshMeta = () => {\n const pages = pageCount(total, limit);\n const safePage = clampPage(page, pages);\n\n // items is already the current page from the server — no local slicing needed.\n cachedCurrent = items;\n cachedMeta = createMeta({\n error,\n isLoading: base.pendingCount() > 0,\n isSearchPending: base.core.isScheduled,\n pageNumber: safePage,\n pageSize: limit,\n totalItems: total,\n });\n };\n\n // onBeforeNotify ensures refreshMeta() runs before any subscriber observes the new state,\n // eliminating the need for a parallel listeners Set.\n const base = createAsyncSource<RemoteSourceQuery<TFilter, TSort>>(cfg, keyOf, refreshMeta);\n const { autoFetch, debounceMs, retryAttempts, retryDelay } = base;\n\n // Initialise cache before first fetch.\n refreshMeta();\n\n const notifyListeners = () => {\n if (base.disposed) return;\n\n base.core.notify();\n };\n const searchCoordinator = createAsyncSearchCoordinator(base.core, notifyListeners);\n\n // ── Assign result ───────────────────────────────────────────────────────────\n const assign = (result: Readonly<{ items: readonly T[]; total: number }>) => {\n if (optimistic?.active) {\n optimistic.active = false;\n optimistic = null;\n }\n\n items = result.items;\n total = result.total;\n page = clampPage(page, pageCount(total, limit));\n };\n\n // ── Core fetch ──────────────────────────────────────────────────────────────\n const toRemoteQuery = (): RemoteSourceQuery<TFilter, TSort> => ({\n ...(filter !== undefined && { filter }),\n ...(sort !== undefined && { sort }),\n ...(search && { search }),\n limit,\n page,\n });\n\n const fetchQuery = (q: RemoteSourceQuery<TFilter, TSort>): Promise<void> => {\n const key = keyOf(q);\n\n if (\n staleTimeMs > 0 &&\n key === lastFetchKey &&\n total > 0 &&\n Date.now() - lastFetchTime < staleTimeMs &&\n !optimistic?.active\n ) {\n return Promise.resolve();\n }\n\n error = null;\n\n return base.fetch(\n q,\n async (q: RemoteSourceQuery<TFilter, TSort>, signal, isLatest) => {\n const startTime = Date.now();\n\n try {\n const result = await retry((sig) => cfg.fetch(q, sig!), {\n delay: retryDelay,\n signal,\n times: retryAttempts + 1,\n });\n\n if (isLatest()) {\n assign(result);\n error = null;\n lastFetchKey = key;\n lastFetchTime = Date.now();\n cfg.onFetch?.({ durationMs: Date.now() - startTime, query: q, status: 'success' });\n }\n } catch (reason: unknown) {\n if (signal.aborted) return;\n\n if (isLatest()) {\n if (optimistic?.active) {\n optimistic.active = false;\n items = optimistic.prevItems;\n total = optimistic.prevTotal;\n optimistic = null;\n } else {\n items = [];\n total = 0;\n }\n\n error = new SourcererError(extractError(reason), {\n cause: reason,\n context: { kind: 'remote', limit: q.limit, page: q.page, ...(q.search && { search: q.search }) },\n });\n cfg.onFetch?.({ durationMs: Date.now() - startTime, error, query: q, status: 'error' });\n }\n }\n },\n () => {\n notifyListeners();\n\n searchCoordinator.settleIfIdle(base.pendingCount());\n },\n );\n };\n\n const doUpdate = () => fetchQuery(toRemoteQuery());\n\n // ── Auto-fetch + refresh interval ───────────────────────────────────────────\n if (autoFetch) void doUpdate();\n\n base.startRefreshInterval(() => void doUpdate());\n\n // ── Public API ──────────────────────────────────────────────────────────────\n return {\n get current() {\n return cachedCurrent;\n },\n\n get disposalSignal() {\n return base.disposalSignal;\n },\n\n dispose: () => {\n searchCoordinator.cancel();\n searchCoordinator.dispose();\n base.dispose();\n },\n\n get disposed() {\n return base.disposed;\n },\n\n goTo(target) {\n const clamped =\n total > 0 ? clampPage(target, pageCount(total, limit)) : clampPositiveInt(target, 'source.goTo', 'target');\n\n if (clamped === page) return Promise.resolve();\n\n page = clamped;\n\n return doUpdate();\n },\n\n goToLast() {\n const last = pageCount(total, limit);\n\n if (page === last) return Promise.resolve();\n\n page = last;\n\n return doUpdate();\n },\n\n get meta() {\n return cachedMeta;\n },\n\n next() {\n const pages = pageCount(total, limit);\n\n if (page >= pages) return Promise.resolve();\n\n page++;\n\n return doUpdate();\n },\n\n optimisticUpdate(mutator, options) {\n if (optimistic?.active) {\n throw new SourcererError(\n 'An optimistic update is already active. Rollback the previous update before starting another.',\n );\n }\n\n const prevItems = items;\n const prevTotal = total;\n\n optimistic = { active: true, prevItems, prevTotal };\n\n try {\n items = mutator(items);\n } catch (e: unknown) {\n optimistic = null;\n throw e;\n }\n\n total = options?.total ?? total;\n notifyListeners();\n\n return () => {\n if (optimistic?.active) {\n optimistic.active = false;\n items = prevItems;\n total = prevTotal;\n optimistic = null;\n notifyListeners();\n }\n };\n },\n\n patch(changes) {\n let changed = false;\n\n if (changes.limit !== undefined) {\n const next = clampPositiveInt(changes.limit, 'source.patch', 'limit');\n\n if (next !== limit) {\n limit = next;\n changed = true;\n }\n }\n\n if ('filter' in changes) {\n filter = changes.filter;\n changed = true;\n }\n\n if ('sort' in changes) {\n sort = changes.sort;\n changed = true;\n }\n\n // `|| base.core.isScheduled` also catches patching in the same search text as an already-pending\n // debounced search() call — that still needs flushing, not silently dropping as a no-op.\n if ('search' in changes && (changes.search !== search || base.core.isScheduled)) {\n search = changes.search ?? '';\n changed = true;\n }\n\n if (changes.page !== undefined) {\n const next =\n total > 0\n ? clampPage(changes.page, pageCount(total, limit))\n : clampPositiveInt(changes.page, 'source.patch', 'page');\n\n if (next !== page) {\n page = next;\n changed = true;\n }\n }\n\n if (!changed) return Promise.resolve();\n\n // patch() is documented as a single atomic fetch — cancel any debounced search()\n // still pending so it doesn't fire a second, redundant fetch afterwards.\n searchCoordinator.cancel();\n\n // Reset to page 1 when non-page query fields changed without explicit page\n if (\n (changes.limit !== undefined || 'filter' in changes || 'sort' in changes || 'search' in changes) &&\n changes.page === undefined\n ) {\n page = 1;\n }\n\n return doUpdate();\n },\n\n prev() {\n if (page <= 1) return Promise.resolve();\n\n page--;\n\n return doUpdate();\n },\n\n get query() {\n return {\n ...(filter !== undefined && { filter }),\n ...(sort !== undefined && { sort }),\n ...(search && { search }),\n limit,\n page,\n };\n },\n\n ready(timeout) {\n return base.ready(timeout);\n },\n\n refresh() {\n return doUpdate();\n },\n\n reset() {\n searchCoordinator.cancel();\n search = '';\n page = 1;\n filter = cfg.filter;\n sort = cfg.sort;\n\n return doUpdate();\n },\n\n search(q, opts?: SearchOptions): Promise<void> {\n if (opts?.immediate) {\n // A pending debounced search for this same text still needs flushing —\n // `q === search` alone doesn't mean the fetch already happened.\n if (q === search && !base.core.isScheduled) return Promise.resolve();\n\n searchCoordinator.cancel();\n search = q;\n page = 1;\n\n return doUpdate();\n }\n\n if (q === search) return Promise.resolve();\n\n search = q;\n page = 1;\n\n return searchCoordinator.schedule(() => void doUpdate(), debounceMs);\n },\n\n subscribe: (listener) => base.core.subscribe(listener),\n\n [Symbol.dispose]: () => {\n searchCoordinator.cancel();\n searchCoordinator.dispose();\n base.dispose();\n },\n };\n}\n"],"mappings":"yLASA,SAAgB,EACd,EACiC,CACjC,IAAM,EAAQ,EAAI,UAAY,EAAA,aAGxB,EAAc,EAAI,WAAa,EAGjC,EAAQ,EAAA,iBAAiB,EAAI,OAAS,GAAI,qBAAsB,OAAO,EACvE,EAAO,EACP,EAAS,GACT,EAA8B,EAAI,OAClC,EAA0B,EAAI,KAC9B,EAAsB,CAAC,EACvB,EAAQ,EACR,EAA+B,KAC/B,EAAgB,EAChB,EAAe,GAGf,EAAqF,KAGrF,EAAI,WACN,EAAQ,EAAI,SAAS,MACrB,EAAQ,EAAI,SAAS,MAEjB,EAAI,SAAS,OAAS,IAAA,KAAW,EAAO,EAAI,SAAS,MAErD,EAAI,SAAS,SAAQ,EAAS,EAAI,SAAS,QAE/C,EAAgB,KAAK,IAAI,GAI3B,IAAI,EAA8B,CAAC,EAC/B,EAAa,EAAA,WAAW,CAC1B,MAAO,KACP,UAAW,GACX,gBAAiB,GACjB,WAAY,EACZ,SAAU,EACV,WAAY,CACd,CAAC,EAEK,MAAoB,CACxB,IAAM,EAAQ,EAAA,UAAU,EAAO,CAAK,EAC9B,EAAW,EAAA,UAAU,EAAM,CAAK,EAGtC,EAAgB,EAChB,EAAa,EAAA,WAAW,CACtB,QACA,UAAW,EAAK,aAAa,EAAI,EACjC,gBAAiB,EAAK,KAAK,YAC3B,WAAY,EACZ,SAAU,EACV,WAAY,CACd,CAAC,CACH,EAIM,EAAO,EAAA,kBAAqD,EAAK,EAAO,CAAW,EACnF,CAAE,YAAW,aAAY,gBAAe,cAAe,EAG7D,EAAY,EAEZ,IAAM,MAAwB,CACxB,EAAK,UAET,EAAK,KAAK,OAAO,CACnB,EACM,EAAoB,EAAA,6BAA6B,EAAK,KAAM,CAAe,EAG3E,EAAU,GAA6D,CACvE,GAAY,SACd,EAAW,OAAS,GACpB,EAAa,MAGf,EAAQ,EAAO,MACf,EAAQ,EAAO,MACf,EAAO,EAAA,UAAU,EAAM,EAAA,UAAU,EAAO,CAAK,CAAC,CAChD,EAGM,OAA0D,CAC9D,GAAI,IAAW,IAAA,IAAa,CAAE,QAAO,EACrC,GAAI,IAAS,IAAA,IAAa,CAAE,MAAK,EACjC,GAAI,GAAU,CAAE,QAAO,EACvB,QACA,MACF,GAEM,EAAc,GAAwD,CAC1E,IAAM,EAAM,EAAM,CAAC,EAcnB,OAXE,EAAc,GACd,IAAQ,GACR,EAAQ,GACR,KAAK,IAAI,EAAI,EAAgB,GAC7B,CAAC,GAAY,OAEN,QAAQ,QAAQ,GAGzB,EAAQ,KAED,EAAK,MACV,EACA,MAAO,EAAsC,EAAQ,IAAa,CAChE,IAAM,EAAY,KAAK,IAAI,EAE3B,GAAI,CACF,IAAM,EAAS,MAAA,EAAA,EAAA,MAAA,CAAa,GAAQ,EAAI,MAAM,EAAG,CAAI,EAAG,CACtD,MAAO,EACP,SACA,MAAO,EAAgB,CACzB,CAAC,EAEG,EAAS,IACX,EAAO,CAAM,EACb,EAAQ,KACR,EAAe,EACf,EAAgB,KAAK,IAAI,EACzB,EAAI,UAAU,CAAE,WAAY,KAAK,IAAI,EAAI,EAAW,MAAO,EAAG,OAAQ,SAAU,CAAC,EAErF,OAAS,EAAiB,CACxB,GAAI,EAAO,QAAS,OAEhB,EAAS,IACP,GAAY,QACd,EAAW,OAAS,GACpB,EAAQ,EAAW,UACnB,EAAQ,EAAW,UACnB,EAAa,OAEb,EAAQ,CAAC,EACT,EAAQ,GAGV,EAAQ,IAAI,EAAA,eAAe,EAAA,aAAa,CAAM,EAAG,CAC/C,MAAO,EACP,QAAS,CAAE,KAAM,SAAU,MAAO,EAAE,MAAO,KAAM,EAAE,KAAM,GAAI,EAAE,QAAU,CAAE,OAAQ,EAAE,MAAO,CAAG,CACjG,CAAC,EACD,EAAI,UAAU,CAAE,WAAY,KAAK,IAAI,EAAI,EAAW,QAAO,MAAO,EAAG,OAAQ,OAAQ,CAAC,EAE1F,CACF,MACM,CACJ,EAAgB,EAEhB,EAAkB,aAAa,EAAK,aAAa,CAAC,CACpD,CACF,EACF,EAEM,MAAiB,EAAW,EAAc,CAAC,EAQjD,OALI,GAAW,EAAc,EAE7B,EAAK,yBAA2B,KAAK,EAAS,CAAC,EAGxC,CACL,IAAI,SAAU,CACZ,OAAO,CACT,EAEA,IAAI,gBAAiB,CACnB,OAAO,EAAK,cACd,EAEA,YAAe,CACb,EAAkB,OAAO,EACzB,EAAkB,QAAQ,EAC1B,EAAK,QAAQ,CACf,EAEA,IAAI,UAAW,CACb,OAAO,EAAK,QACd,EAEA,KAAK,EAAQ,CACX,IAAM,EACJ,EAAQ,EAAI,EAAA,UAAU,EAAQ,EAAA,UAAU,EAAO,CAAK,CAAC,EAAI,EAAA,iBAAiB,EAAQ,cAAe,QAAQ,EAM3G,OAJI,IAAY,EAAa,QAAQ,QAAQ,GAE7C,EAAO,EAEA,EAAS,EAClB,EAEA,UAAW,CACT,IAAM,EAAO,EAAA,UAAU,EAAO,CAAK,EAMnC,OAJI,IAAS,EAAa,QAAQ,QAAQ,GAE1C,EAAO,EAEA,EAAS,EAClB,EAEA,IAAI,MAAO,CACT,OAAO,CACT,EAEA,MAAO,CACL,IAAM,EAAQ,EAAA,UAAU,EAAO,CAAK,EAMpC,OAJI,GAAQ,EAAc,QAAQ,QAAQ,GAE1C,IAEO,EAAS,EAClB,EAEA,iBAAiB,EAAS,EAAS,CACjC,GAAI,GAAY,OACd,MAAM,IAAI,EAAA,eACR,+FACF,EAGF,IAAM,EAAY,EACZ,EAAY,EAElB,EAAa,CAAE,OAAQ,GAAM,YAAW,WAAU,EAElD,GAAI,CACF,EAAQ,EAAQ,CAAK,CACvB,OAAS,EAAY,CAEnB,KADA,GAAa,KACP,CACR,CAKA,MAHA,GAAQ,GAAS,OAAS,EAC1B,EAAgB,MAEH,CACP,GAAY,SACd,EAAW,OAAS,GACpB,EAAQ,EACR,EAAQ,EACR,EAAa,KACb,EAAgB,EAEpB,CACF,EAEA,MAAM,EAAS,CACb,IAAI,EAAU,GAEd,GAAI,EAAQ,QAAU,IAAA,GAAW,CAC/B,IAAM,EAAO,EAAA,iBAAiB,EAAQ,MAAO,eAAgB,OAAO,EAEhE,IAAS,IACX,EAAQ,EACR,EAAU,GAEd,CAmBA,GAjBI,WAAY,IACd,EAAS,EAAQ,OACjB,EAAU,IAGR,SAAU,IACZ,EAAO,EAAQ,KACf,EAAU,IAKR,WAAY,IAAY,EAAQ,SAAW,GAAU,EAAK,KAAK,eACjE,EAAS,EAAQ,QAAU,GAC3B,EAAU,IAGR,EAAQ,OAAS,IAAA,GAAW,CAC9B,IAAM,EACJ,EAAQ,EACJ,EAAA,UAAU,EAAQ,KAAM,EAAA,UAAU,EAAO,CAAK,CAAC,EAC/C,EAAA,iBAAiB,EAAQ,KAAM,eAAgB,MAAM,EAEvD,IAAS,IACX,EAAO,EACP,EAAU,GAEd,CAgBA,OAdK,GAIL,EAAkB,OAAO,GAItB,EAAQ,QAAU,IAAA,IAAa,WAAY,GAAW,SAAU,GAAW,WAAY,IACxF,EAAQ,OAAS,IAAA,KAEjB,EAAO,GAGF,EAAS,GAdK,QAAQ,QAAQ,CAevC,EAEA,MAAO,CAKL,OAJI,GAAQ,EAAU,QAAQ,QAAQ,GAEtC,IAEO,EAAS,EAClB,EAEA,IAAI,OAAQ,CACV,MAAO,CACL,GAAI,IAAW,IAAA,IAAa,CAAE,QAAO,EACrC,GAAI,IAAS,IAAA,IAAa,CAAE,MAAK,EACjC,GAAI,GAAU,CAAE,QAAO,EACvB,QACA,MACF,CACF,EAEA,MAAM,EAAS,CACb,OAAO,EAAK,MAAM,CAAO,CAC3B,EAEA,SAAU,CACR,OAAO,EAAS,CAClB,EAEA,OAAQ,CAON,OANA,EAAkB,OAAO,EACzB,EAAS,GACT,EAAO,EACP,EAAS,EAAI,OACb,EAAO,EAAI,KAEJ,EAAS,CAClB,EAEA,OAAO,EAAG,EAAqC,CAkB7C,OAjBI,GAAM,UAGJ,IAAM,GAAU,CAAC,EAAK,KAAK,YAAoB,QAAQ,QAAQ,GAEnE,EAAkB,OAAO,EACzB,EAAS,EACT,EAAO,EAEA,EAAS,GAGd,IAAM,EAAe,QAAQ,QAAQ,GAEzC,EAAS,EACT,EAAO,EAEA,EAAkB,aAAe,KAAK,EAAS,EAAG,CAAU,EACrE,EAEA,UAAY,GAAa,EAAK,KAAK,UAAU,CAAQ,GAEpD,OAAO,aAAgB,CACtB,EAAkB,OAAO,EACzB,EAAkB,QAAQ,EAC1B,EAAK,QAAQ,CACf,CACF,CACF"}
|
package/dist/remoteSource.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { RemoteConfig, RemoteSource } from './types';
|
|
2
|
-
/** Creates a remote page-based source that fetches data from a network endpoint. */
|
|
3
|
-
export declare function createRemoteSource<T, TFilter = unknown, TSort = unknown>(cfg: RemoteConfig<T, TFilter, TSort>): RemoteSource<T, TFilter, TSort>;
|
|
4
|
-
//# sourceMappingURL=remoteSource.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"remoteSource.d.ts","sourceRoot":"","sources":["../src/remoteSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAoC,MAAM,SAAS,CAAC;AAQ5F,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,KAAK,GAAG,OAAO,EACtE,GAAG,EAAE,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,GACnC,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CA0XjC"}
|