@spooky-sync/client-solid 0.0.1-canary.113 → 0.0.1-canary.117
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/AGENTS.md +2 -0
- package/README.md +20 -0
- package/dist/index.cjs +55 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +32 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/skills/sp00ky-solid/SKILL.md +72 -1
- package/src/index.ts +18 -0
- package/src/lib/Sp00kyProvider.ts +19 -0
- package/src/lib/create-preload.ts +111 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ColumnSchema,
|
|
3
|
+
FinalQuery,
|
|
4
|
+
SchemaStructure,
|
|
5
|
+
TableNames,
|
|
6
|
+
} from '@spooky-sync/query-builder';
|
|
7
|
+
import { createEffect, useContext } from 'solid-js';
|
|
8
|
+
import { SyncedDb } from '..';
|
|
9
|
+
import type { Sp00kyQueryResultPromise, PreloadOptions as CorePreloadOptions } from '@spooky-sync/core';
|
|
10
|
+
import { Sp00kyContext } from './context';
|
|
11
|
+
|
|
12
|
+
type PreloadArg<
|
|
13
|
+
S extends SchemaStructure,
|
|
14
|
+
TableName extends TableNames<S>,
|
|
15
|
+
T extends { columns: Record<string, ColumnSchema> },
|
|
16
|
+
RelatedFields extends Record<string, any>,
|
|
17
|
+
IsOne extends boolean,
|
|
18
|
+
> =
|
|
19
|
+
| FinalQuery<S, TableName, T, RelatedFields, IsOne, Sp00kyQueryResultPromise>
|
|
20
|
+
| (() =>
|
|
21
|
+
| FinalQuery<S, TableName, T, RelatedFields, IsOne, Sp00kyQueryResultPromise>
|
|
22
|
+
| null
|
|
23
|
+
| undefined);
|
|
24
|
+
|
|
25
|
+
type PreloadOptions = CorePreloadOptions & {
|
|
26
|
+
/** Only preload while this returns true (defaults to always). */
|
|
27
|
+
enabled?: () => boolean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Overload: context-based (no explicit db)
|
|
31
|
+
export function createPreload<
|
|
32
|
+
S extends SchemaStructure,
|
|
33
|
+
TableName extends TableNames<S>,
|
|
34
|
+
T extends { columns: Record<string, ColumnSchema> },
|
|
35
|
+
RelatedFields extends Record<string, any>,
|
|
36
|
+
IsOne extends boolean,
|
|
37
|
+
>(
|
|
38
|
+
finalQuery: PreloadArg<S, TableName, T, RelatedFields, IsOne>,
|
|
39
|
+
options?: PreloadOptions,
|
|
40
|
+
): void;
|
|
41
|
+
|
|
42
|
+
// Overload: explicit db
|
|
43
|
+
export function createPreload<
|
|
44
|
+
S extends SchemaStructure,
|
|
45
|
+
TableName extends TableNames<S>,
|
|
46
|
+
T extends { columns: Record<string, ColumnSchema> },
|
|
47
|
+
RelatedFields extends Record<string, any>,
|
|
48
|
+
IsOne extends boolean,
|
|
49
|
+
>(
|
|
50
|
+
db: SyncedDb<S>,
|
|
51
|
+
finalQuery: PreloadArg<S, TableName, T, RelatedFields, IsOne>,
|
|
52
|
+
options?: PreloadOptions,
|
|
53
|
+
): void;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Reactive, fire-and-forget prewarm. Resolves the query (calling it if it's a
|
|
57
|
+
* function so it tracks reactive deps), dedupes on the query's stable identity
|
|
58
|
+
* hash, and warms it into the local cache via `db.preload`. No subscription and
|
|
59
|
+
* no cleanup: preload registers nothing that needs tearing down.
|
|
60
|
+
*
|
|
61
|
+
* Typical use: inside a list row, preload the detail query the user is likely
|
|
62
|
+
* to open next, so navigation paints from cache instead of the network.
|
|
63
|
+
*/
|
|
64
|
+
export function createPreload<
|
|
65
|
+
S extends SchemaStructure,
|
|
66
|
+
TableName extends TableNames<S>,
|
|
67
|
+
T extends { columns: Record<string, ColumnSchema> },
|
|
68
|
+
RelatedFields extends Record<string, any>,
|
|
69
|
+
IsOne extends boolean,
|
|
70
|
+
>(
|
|
71
|
+
dbOrQuery: SyncedDb<S> | PreloadArg<S, TableName, T, RelatedFields, IsOne>,
|
|
72
|
+
queryOrOptions?: PreloadArg<S, TableName, T, RelatedFields, IsOne> | PreloadOptions,
|
|
73
|
+
maybeOptions?: PreloadOptions,
|
|
74
|
+
): void {
|
|
75
|
+
let db: SyncedDb<S>;
|
|
76
|
+
let finalQuery: PreloadArg<S, TableName, T, RelatedFields, IsOne>;
|
|
77
|
+
let options: PreloadOptions | undefined;
|
|
78
|
+
|
|
79
|
+
if (dbOrQuery instanceof SyncedDb) {
|
|
80
|
+
db = dbOrQuery;
|
|
81
|
+
finalQuery = queryOrOptions as PreloadArg<S, TableName, T, RelatedFields, IsOne>;
|
|
82
|
+
options = maybeOptions;
|
|
83
|
+
} else {
|
|
84
|
+
const contextDb = useContext(Sp00kyContext);
|
|
85
|
+
if (!contextDb) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
'createPreload: No db argument provided and no Sp00kyContext found. ' +
|
|
88
|
+
'Either pass a SyncedDb instance or wrap your app in <Sp00kyProvider>.',
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
db = contextDb as SyncedDb<S>;
|
|
92
|
+
finalQuery = dbOrQuery;
|
|
93
|
+
options = queryOrOptions as PreloadOptions | undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let prevHash: number | undefined;
|
|
97
|
+
|
|
98
|
+
createEffect(() => {
|
|
99
|
+
if (!(options?.enabled?.() ?? true)) return;
|
|
100
|
+
|
|
101
|
+
const query = typeof finalQuery === 'function' ? finalQuery() : finalQuery;
|
|
102
|
+
if (!query) return;
|
|
103
|
+
|
|
104
|
+
// Dedupe on the query's stable identity hash so a reactive re-run with an
|
|
105
|
+
// unchanged query doesn't refetch (the core also dedupes per session).
|
|
106
|
+
if (query.hash === prevHash) return;
|
|
107
|
+
prevHash = query.hash;
|
|
108
|
+
|
|
109
|
+
void db.getSp00ky().preload(query, { refresh: options?.refresh, staleTime: options?.staleTime });
|
|
110
|
+
});
|
|
111
|
+
}
|