march-hare 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -96
- package/dist/{src/library/action → action}/index.d.ts +19 -15
- package/dist/{src/library/action → action}/utils.d.ts +2 -2
- package/dist/{src/library/boundary → boundary}/components/broadcast/index.d.ts +2 -2
- package/dist/{src/library/boundary → boundary}/components/broadcast/types.d.ts +1 -1
- package/dist/{src/library/boundary → boundary}/components/consumer/components/partition/index.d.ts +1 -1
- package/dist/{src/library/boundary → boundary}/components/consumer/components/partition/types.d.ts +1 -1
- package/dist/{src/library/boundary → boundary}/components/consumer/index.d.ts +5 -5
- package/dist/{src/library/boundary → boundary}/components/consumer/types.d.ts +1 -1
- package/dist/{src/library/boundary → boundary}/components/consumer/utils.d.ts +1 -1
- package/dist/{src/library/boundary → boundary}/components/scope/index.d.ts +3 -3
- package/dist/{src/library/boundary → boundary}/components/scope/types.d.ts +2 -2
- package/dist/{src/library/boundary → boundary}/components/scope/utils.d.ts +2 -2
- package/dist/boundary/components/store/index.d.ts +41 -0
- package/dist/boundary/components/store/types.d.ts +11 -0
- package/dist/boundary/components/store/utils.d.ts +64 -0
- package/dist/{src/library/boundary → boundary}/components/tasks/index.d.ts +2 -2
- package/dist/{src/library/boundary → boundary}/components/tasks/types.d.ts +3 -3
- package/dist/{src/library/boundary → boundary}/components/tasks/utils.d.ts +1 -1
- package/dist/boundary/index.d.ts +21 -0
- package/dist/boundary/types.d.ts +22 -0
- package/dist/cache/index.d.ts +44 -0
- package/dist/cache/types.d.ts +54 -0
- package/dist/{src/library/error → error}/types.d.ts +1 -1
- package/dist/{src/library/error → error}/utils.d.ts +1 -1
- package/dist/{src/library/hooks → hooks}/index.d.ts +3 -3
- package/dist/{src/library/hooks → hooks}/types.d.ts +3 -3
- package/dist/{src/library/hooks → hooks}/utils.d.ts +3 -3
- package/dist/index.d.ts +19 -0
- package/dist/march-hare.js +6 -6
- package/dist/march-hare.umd.cjs +1 -1
- package/dist/resource/index.d.ts +102 -0
- package/dist/resource/types.d.ts +27 -0
- package/dist/resource/utils.d.ts +37 -0
- package/dist/{src/library/types → types}/index.d.ts +162 -21
- package/dist/{src/library/utils → utils}/index.d.ts +3 -43
- package/dist/utils/types.d.ts +18 -0
- package/dist/{src/library/utils → utils}/utils.d.ts +1 -1
- package/package.json +2 -2
- package/dist/src/library/boundary/components/mode/index.d.ts +0 -15
- package/dist/src/library/boundary/components/mode/types.d.ts +0 -7
- package/dist/src/library/boundary/components/mode/utils.d.ts +0 -55
- package/dist/src/library/boundary/index.d.ts +0 -20
- package/dist/src/library/boundary/types.d.ts +0 -4
- package/dist/src/library/index.d.ts +0 -17
- package/dist/src/library/resource/index.d.ts +0 -65
- package/dist/src/library/resource/types.d.ts +0 -150
- package/dist/src/library/resource/utils.d.ts +0 -23
- package/dist/src/library/utils/types.d.ts +0 -101
- /package/dist/{src/library/annotate → annotate}/index.d.ts +0 -0
- /package/dist/{src/library/boundary → boundary}/components/broadcast/utils.d.ts +0 -0
- /package/dist/{src/library/error → error}/index.d.ts +0 -0
- /package/dist/{src/library/utils.d.ts → utils.d.ts} +0 -0
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { Stored, Unset } from '../utils/index.ts';
|
|
2
|
-
export type { Unset } from '../utils/index.ts';
|
|
3
|
-
/**
|
|
4
|
-
* Options accepted by `.if(...)` on a bound resource handle.
|
|
5
|
-
*
|
|
6
|
-
* - `over` – a `Temporal.Duration`, a `DurationLike` object
|
|
7
|
-
* (e.g. `{ minutes: 5 }`), or an ISO 8601 duration string (`"PT5M"`).
|
|
8
|
-
* If the most recent successful run resolved longer ago than this
|
|
9
|
-
* window, the underlying fetcher is called. Otherwise the cached
|
|
10
|
-
* data is returned without hitting the network.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* await user.if({ over: { minutes: 5 } });
|
|
15
|
-
* await user.if({ over: "PT5M" });
|
|
16
|
-
* await user.if({ over: Temporal.Duration.from({ minutes: 5 }) });
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
export type IfOptions = {
|
|
20
|
-
readonly over: Temporal.DurationLike;
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* Fetcher signature accepted by `Resource`. Receives the optional
|
|
24
|
-
* `AbortSignal` first (threaded from the action handler's
|
|
25
|
-
* `context.task.controller.signal`) and the call-site `params` second.
|
|
26
|
-
* Side-effects (dispatching broadcasts, analytics, etc.) belong in the
|
|
27
|
-
* calling `useAction` handler, not inside the fetcher.
|
|
28
|
-
*/
|
|
29
|
-
export type ResourceFetcher<T, P extends object = Record<never, never>> = (signal: AbortSignal | undefined, params: P) => Promise<T>;
|
|
30
|
-
/**
|
|
31
|
-
* Module-scope handle returned by `Resource`. Pass to `useResource` to
|
|
32
|
-
* obtain the bound, component-scoped callable.
|
|
33
|
-
*
|
|
34
|
-
* Every call to the underlying fetcher fires its own request. The most
|
|
35
|
-
* recent successful response is cached in a module-level `WeakMap`
|
|
36
|
-
* keyed by the fetcher itself, so `.if(...)` and `.else(...)` on the
|
|
37
|
-
* bound handle have something to read from.
|
|
38
|
-
*/
|
|
39
|
-
export type ResourceHandle<T, P extends object = Record<never, never>> = {
|
|
40
|
-
/** @internal */
|
|
41
|
-
readonly run: (signal: AbortSignal | undefined, params: P) => Promise<T>;
|
|
42
|
-
/**
|
|
43
|
-
* Most recent successfully-resolved payload, or the shared `unset`
|
|
44
|
-
* sentinel if no successful run has happened yet.
|
|
45
|
-
* @internal
|
|
46
|
-
*/
|
|
47
|
-
readonly data: T | Unset;
|
|
48
|
-
/** @internal */
|
|
49
|
-
readonly at: Temporal.Instant | null;
|
|
50
|
-
/**
|
|
51
|
-
* Populates the cache slot with `data` and `at` without invoking the
|
|
52
|
-
* fetcher. Used by the bound handle's `.else(stored)` overload to
|
|
53
|
-
* hydrate the cache from a {@link Stored} fallback (typically the
|
|
54
|
-
* return value of `Store.get(key)` after a page reload).
|
|
55
|
-
* @internal
|
|
56
|
-
*/
|
|
57
|
-
readonly seed: (data: T, at: Temporal.Instant) => void;
|
|
58
|
-
};
|
|
59
|
-
/**
|
|
60
|
-
* Component-bound handle returned by `useResource`. The handle is itself
|
|
61
|
-
* the fetch callable — `await user(signal?, params?)` triggers a
|
|
62
|
-
* request — with attached read accessors and methods:
|
|
63
|
-
*
|
|
64
|
-
* - `.if({ over }, signal?, params?)` — fetch only if the cached
|
|
65
|
-
* payload is older than the supplied freshness window; otherwise
|
|
66
|
-
* return the cached payload synchronously.
|
|
67
|
-
* - `.else(fallback)` — synchronous read of the cached payload,
|
|
68
|
-
* falling back to the supplied default when nothing has resolved
|
|
69
|
-
* successfully yet. Accepts either a value (terminal, returns
|
|
70
|
-
* `T | U`) or a {@link Stored} (chainable, seeds the cache from the
|
|
71
|
-
* Stored's data/at when the cache is empty and returns the same bound
|
|
72
|
-
* handle for further chaining).
|
|
73
|
-
* - `.snapshot()` — returns a {@link Stored} wrapping the current
|
|
74
|
-
* cache state, symmetric with `Store.get(key)`. Pass straight to
|
|
75
|
-
* `Store.set(key, ...)` to persist the latest successful payload.
|
|
76
|
-
* - `.data` and `.at` — the underlying cache fields. Reading
|
|
77
|
-
* `.snapshot()` is usually clearer.
|
|
78
|
-
*
|
|
79
|
-
* Call signature: `(signal?)` for resources with no params, or
|
|
80
|
-
* `(signal: AbortSignal | null, params: P)` for parameterised
|
|
81
|
-
* resources — pass `null` as the first argument when you have
|
|
82
|
-
* params but no signal to thread.
|
|
83
|
-
*/
|
|
84
|
-
export type BoundResourceHandle<T, P extends object> = [keyof P] extends [never] ? {
|
|
85
|
-
(signal?: AbortSignal): Promise<T>;
|
|
86
|
-
/**
|
|
87
|
-
* Calls the underlying fetcher if the most recent successful run
|
|
88
|
-
* resolved longer ago than `options.over`. Otherwise returns the
|
|
89
|
-
* cached data without hitting the network.
|
|
90
|
-
*/
|
|
91
|
-
readonly if: (options: IfOptions, signal?: AbortSignal) => Promise<T>;
|
|
92
|
-
/**
|
|
93
|
-
* Overloaded fallback accessor.
|
|
94
|
-
*
|
|
95
|
-
* - `(fallback: U)` terminal — returns the cached payload, or
|
|
96
|
-
* `fallback` when nothing has resolved yet. Cached `null` values
|
|
97
|
-
* are returned verbatim.
|
|
98
|
-
* - `(stored: Stored<T>)` chainable — if the cache is empty
|
|
99
|
-
* and the Stored carries data and a timestamp, seeds the cache
|
|
100
|
-
* from it before returning the same bound handle so further
|
|
101
|
-
* `.else(...)` calls compose. Used to hydrate the cache on first
|
|
102
|
-
* render after a page reload, allowing `.if({ over })` to
|
|
103
|
-
* short-circuit on the persisted timestamp.
|
|
104
|
-
*/
|
|
105
|
-
readonly else: {
|
|
106
|
-
(stored: Stored<T>): BoundResourceHandle<T, P>;
|
|
107
|
-
<U>(fallback: U): T | U;
|
|
108
|
-
};
|
|
109
|
-
/**
|
|
110
|
-
* Snapshot of the current cache state in the shared {@link Stored}
|
|
111
|
-
* shape. Empty (`data === unset`, `at === null`) until a fetcher
|
|
112
|
-
* resolves; otherwise carries the most recent payload and the
|
|
113
|
-
* instant it resolved. Pass directly to `Store.set(key, ...)`.
|
|
114
|
-
*/
|
|
115
|
-
readonly snapshot: () => Stored<T>;
|
|
116
|
-
/** Direct read of the cache payload. Prefer `.snapshot()`. */
|
|
117
|
-
readonly data: T | Unset;
|
|
118
|
-
/** Instant the cache was last populated, or `null` if empty. */
|
|
119
|
-
readonly at: Temporal.Instant | null;
|
|
120
|
-
} : {
|
|
121
|
-
(signal: AbortSignal | null, params: P): Promise<T>;
|
|
122
|
-
/**
|
|
123
|
-
* Calls the underlying fetcher if the most recent successful run
|
|
124
|
-
* resolved longer ago than `options.over`. Otherwise returns the
|
|
125
|
-
* cached data without hitting the network.
|
|
126
|
-
*/
|
|
127
|
-
readonly if: (options: IfOptions, signal: AbortSignal | null, params: P) => Promise<T>;
|
|
128
|
-
/**
|
|
129
|
-
* Overloaded fallback accessor.
|
|
130
|
-
*
|
|
131
|
-
* - `(fallback: U)` terminal — returns the cached payload, or
|
|
132
|
-
* `fallback` when nothing has resolved yet.
|
|
133
|
-
* - `(stored: Stored<T>)` chainable — if the cache is empty
|
|
134
|
-
* and the Stored carries data and a timestamp, seeds the cache
|
|
135
|
-
* from it before returning the same bound handle.
|
|
136
|
-
*/
|
|
137
|
-
readonly else: {
|
|
138
|
-
(stored: Stored<T>): BoundResourceHandle<T, P>;
|
|
139
|
-
<U>(fallback: U): T | U;
|
|
140
|
-
};
|
|
141
|
-
/**
|
|
142
|
-
* Snapshot of the current cache state in the shared {@link Stored}
|
|
143
|
-
* shape. Pass directly to `Store.set(key, ...)`.
|
|
144
|
-
*/
|
|
145
|
-
readonly snapshot: () => Stored<T>;
|
|
146
|
-
/** Direct read of the cache payload. Prefer `.snapshot()`. */
|
|
147
|
-
readonly data: T | Unset;
|
|
148
|
-
/** Instant the cache was last populated, or `null` if empty. */
|
|
149
|
-
readonly at: Temporal.Instant | null;
|
|
150
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { unset } from '../utils/index.ts';
|
|
2
|
-
/**
|
|
3
|
-
* Module-level cache shared by every `Resource` declaration. Keyed by
|
|
4
|
-
* the fetcher function itself so each module-scope declaration gets a
|
|
5
|
-
* distinct slot — entries are garbage-collected when the fetcher
|
|
6
|
-
* reference is dropped.
|
|
7
|
-
*
|
|
8
|
-
* @internal
|
|
9
|
-
*/
|
|
10
|
-
export declare const cache: WeakMap<object, {
|
|
11
|
-
data: unknown;
|
|
12
|
-
at: Temporal.Instant;
|
|
13
|
-
}>;
|
|
14
|
-
/**
|
|
15
|
-
* Re-export of the shared `unset` sentinel from {@link "../utils/index.ts"}.
|
|
16
|
-
* Kept under `config` for back-compatibility with existing imports in this
|
|
17
|
-
* module's siblings; new code should import `unset` directly from `utils`.
|
|
18
|
-
*
|
|
19
|
-
* @internal
|
|
20
|
-
*/
|
|
21
|
-
export declare const config: {
|
|
22
|
-
readonly unset: typeof unset;
|
|
23
|
-
};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { unset } from './utils.ts';
|
|
2
|
-
/** Nominal type of the {@link unset} sentinel. */
|
|
3
|
-
export type Unset = typeof unset;
|
|
4
|
-
/**
|
|
5
|
-
* On-disk JSON shape of a {@link Stored} envelope. The Store wrapper
|
|
6
|
-
* encodes a populated Stored as `{ data, at: at.toString() }` so the
|
|
7
|
-
* `Temporal.Instant` survives the string round-trip, and decodes via
|
|
8
|
-
* `Temporal.Instant.from(...)` on read. Adapters never see this shape
|
|
9
|
-
* directly — they shuttle the already-stringified JSON.
|
|
10
|
-
*
|
|
11
|
-
* @template T The payload type carried by the matching {@link Stored}.
|
|
12
|
-
*/
|
|
13
|
-
export type Encoded<T> = {
|
|
14
|
-
readonly data: T;
|
|
15
|
-
readonly at: string;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Common shape for a possibly-present value with a timestamp. Produced by
|
|
19
|
-
* `BoundResourceHandle.snapshot()` (from the in-memory cache) and by
|
|
20
|
-
* `Store.get(key)` (from persistent storage). Both feed into the bound
|
|
21
|
-
* handle's overloaded `.else(...)`, which seeds the cache when given a
|
|
22
|
-
* Stored that carries data and a timestamp.
|
|
23
|
-
*
|
|
24
|
-
* @template T The payload type when present.
|
|
25
|
-
*/
|
|
26
|
-
export type Stored<T> = {
|
|
27
|
-
/** The payload, or {@link unset} when nothing is recorded. */
|
|
28
|
-
readonly data: T | Unset;
|
|
29
|
-
/** When the payload was recorded, or `null` when nothing is recorded. */
|
|
30
|
-
readonly at: Temporal.Instant | null;
|
|
31
|
-
/**
|
|
32
|
-
* Returns {@link data} when present, otherwise the supplied fallback.
|
|
33
|
-
* Symmetric with `BoundResourceHandle.else(...)`'s terminal form.
|
|
34
|
-
*/
|
|
35
|
-
readonly else: <U>(fallback: U) => T | U;
|
|
36
|
-
};
|
|
37
|
-
/**
|
|
38
|
-
* Adapter contract for synchronous key/value storage. Implement once per
|
|
39
|
-
* backend (localStorage, MMKV on React Native, chrome.storage with a sync
|
|
40
|
-
* facade, etc.) and pass to `store`. The adapter shuttles raw strings;
|
|
41
|
-
* JSON encoding and `Temporal.Instant` round-tripping happen inside the
|
|
42
|
-
* Store wrapper, so adapters stay trivial.
|
|
43
|
-
*/
|
|
44
|
-
export type Adapter = {
|
|
45
|
-
/**
|
|
46
|
-
* Return the raw string stored under `key`, or `null` when no entry
|
|
47
|
-
* exists. The Store wrapper handles JSON parsing and `Temporal.Instant`
|
|
48
|
-
* round-tripping, so this stays a plain string getter. Treat any
|
|
49
|
-
* read-time error (decryption, IPC, etc.) as "not found" and return
|
|
50
|
-
* `null` — the Store falls through to its next fallback rather than
|
|
51
|
-
* crashing the render.
|
|
52
|
-
*/
|
|
53
|
-
readonly get: (key: string) => string | null;
|
|
54
|
-
/**
|
|
55
|
-
* Persist the raw string `value` under `key`. The Store guarantees
|
|
56
|
-
* `value` is a JSON-encoded `{ data, at }` envelope produced by a
|
|
57
|
-
* resolved snapshot — never a placeholder. Throwing is fine on quota,
|
|
58
|
-
* private mode, sandboxed iframes, etc.; the Store catches and
|
|
59
|
-
* swallows so a write failure can't poison an already-resolved fetch.
|
|
60
|
-
*/
|
|
61
|
-
readonly set: (key: string, value: string) => void;
|
|
62
|
-
/**
|
|
63
|
-
* Drop the entry at `key`. Idempotent — calling `remove` for a key
|
|
64
|
-
* that isn't present must not throw.
|
|
65
|
-
*/
|
|
66
|
-
readonly remove: (key: string) => void;
|
|
67
|
-
/**
|
|
68
|
-
* Wipe every entry this adapter can see. On a shared backend such as
|
|
69
|
-
* `localStorage` this means the whole origin — third-party SDK state,
|
|
70
|
-
* dismissed banners, route hints, etc. all go with it. Adapter authors
|
|
71
|
-
* should either delegate to the backend's native clear (accepting that
|
|
72
|
-
* scope) or namespace by key prefix and remove only their own.
|
|
73
|
-
*/
|
|
74
|
-
readonly clear: () => void;
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Bound storage instance returned by `store`. Reads return a
|
|
78
|
-
* {@link Stored} handle so the result composes with the Resource bound
|
|
79
|
-
* handle's `.else(...)`; writes accept a Stored and short-circuit on the
|
|
80
|
-
* empty case to avoid persisting placeholder snapshots.
|
|
81
|
-
*/
|
|
82
|
-
export type Store = Pick<Adapter, "remove" | "clear"> & {
|
|
83
|
-
/**
|
|
84
|
-
* Read the entry at `key` as a {@link Stored} envelope. Returns an
|
|
85
|
-
* empty Stored (`data: unset`, `at: null`) when nothing is recorded
|
|
86
|
-
* or when the persisted payload fails to parse — corrupted entries
|
|
87
|
-
* never reach the caller. The result composes directly with a
|
|
88
|
-
* Resource bound handle's `.else(...)` for seeding the cache after
|
|
89
|
-
* a reload.
|
|
90
|
-
*/
|
|
91
|
-
readonly get: <T>(key: string) => Stored<T>;
|
|
92
|
-
/**
|
|
93
|
-
* Persist `value` under `key`. Returns `true` when the entry landed
|
|
94
|
-
* in the adapter, `false` otherwise. A `false` covers two distinct
|
|
95
|
-
* cases: the Stored had no payload yet (`data === unset` or
|
|
96
|
-
* `at === null`), or the adapter threw (quota, private mode, etc.).
|
|
97
|
-
* Callers that care about quota failures should branch on the
|
|
98
|
-
* return; callers writing on every dispatch can safely ignore it.
|
|
99
|
-
*/
|
|
100
|
-
readonly set: <T>(key: string, value: Stored<T>) => boolean;
|
|
101
|
-
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|