@logixjs/query 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Engine.cjs +77 -0
- package/dist/Engine.cjs.map +1 -0
- package/dist/Engine.d.cts +57 -0
- package/dist/Engine.d.ts +57 -0
- package/dist/Engine.js +8 -0
- package/dist/Engine.js.map +1 -0
- package/dist/Query.cjs +457 -0
- package/dist/Query.cjs.map +1 -0
- package/dist/Query.d.cts +61 -0
- package/dist/Query.d.ts +61 -0
- package/dist/Query.js +10 -0
- package/dist/Query.js.map +1 -0
- package/dist/TanStack-C3mxN6Aj.d.cts +40 -0
- package/dist/TanStack-jQhqYG8i.d.ts +40 -0
- package/dist/TanStack.cjs +139 -0
- package/dist/TanStack.cjs.map +1 -0
- package/dist/TanStack.d.cts +5 -0
- package/dist/TanStack.d.ts +5 -0
- package/dist/TanStack.js +10 -0
- package/dist/TanStack.js.map +1 -0
- package/dist/Traits.cjs +65 -0
- package/dist/Traits.cjs.map +1 -0
- package/dist/Traits.d.cts +76 -0
- package/dist/Traits.d.ts +76 -0
- package/dist/Traits.js +10 -0
- package/dist/Traits.js.map +1 -0
- package/dist/chunk-L745BR5P.js +124 -0
- package/dist/chunk-L745BR5P.js.map +1 -0
- package/dist/chunk-NXFX6RIH.js +355 -0
- package/dist/chunk-NXFX6RIH.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-THVAADR2.js +53 -0
- package/dist/chunk-THVAADR2.js.map +1 -0
- package/dist/chunk-V3F5KWNH.js +30 -0
- package/dist/chunk-V3F5KWNH.js.map +1 -0
- package/dist/index.cjs +582 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
Engine: () => Engine,
|
|
34
|
+
TanStack: () => TanStack_exports,
|
|
35
|
+
make: () => make,
|
|
36
|
+
source: () => source,
|
|
37
|
+
traits: () => toStateTraitSpec
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(index_exports);
|
|
40
|
+
|
|
41
|
+
// src/Query.ts
|
|
42
|
+
var Logix4 = __toESM(require("@logixjs/core"), 1);
|
|
43
|
+
var import_effect5 = require("effect");
|
|
44
|
+
|
|
45
|
+
// src/internal/logics/auto-trigger.ts
|
|
46
|
+
var Logix = __toESM(require("@logixjs/core"), 1);
|
|
47
|
+
var import_effect3 = require("effect");
|
|
48
|
+
|
|
49
|
+
// src/Engine.ts
|
|
50
|
+
var import_effect2 = require("effect");
|
|
51
|
+
|
|
52
|
+
// src/internal/middleware/middleware.ts
|
|
53
|
+
var import_effect = require("effect");
|
|
54
|
+
var middleware = (config) => /* @__PURE__ */ (() => {
|
|
55
|
+
let cachedEngine;
|
|
56
|
+
return (op) => {
|
|
57
|
+
if (op.kind !== "service" && op.kind !== "trait-source" || !op.meta?.resourceId || !op.meta.keyHash) {
|
|
58
|
+
return op.effect;
|
|
59
|
+
}
|
|
60
|
+
const resourceId = op.meta.resourceId;
|
|
61
|
+
if (config?.useFor && !config.useFor(resourceId)) {
|
|
62
|
+
return op.effect;
|
|
63
|
+
}
|
|
64
|
+
const keyHash = op.meta.keyHash;
|
|
65
|
+
if (cachedEngine) {
|
|
66
|
+
if (cachedEngine.fetchFast) {
|
|
67
|
+
return cachedEngine.fetchFast(resourceId, keyHash, op.effect);
|
|
68
|
+
}
|
|
69
|
+
return cachedEngine.fetch({ resourceId, keyHash, effect: op.effect });
|
|
70
|
+
}
|
|
71
|
+
return import_effect.Effect.serviceOption(Engine).pipe(
|
|
72
|
+
import_effect.Effect.flatMap((engineOpt) => {
|
|
73
|
+
if (import_effect.Option.isNone(engineOpt)) {
|
|
74
|
+
return import_effect.Effect.fail(
|
|
75
|
+
new Error(
|
|
76
|
+
`[Query.Engine.middleware] Missing Query.Engine in the Runtime scope; please provide Query.Engine.layer(Query.TanStack.engine(new QueryClient())) (recommended) or Query.Engine.layer(customEngine).`
|
|
77
|
+
)
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
cachedEngine = engineOpt.value;
|
|
81
|
+
if (cachedEngine.fetchFast) {
|
|
82
|
+
return cachedEngine.fetchFast(resourceId, keyHash, op.effect);
|
|
83
|
+
}
|
|
84
|
+
return cachedEngine.fetch({ resourceId, keyHash, effect: op.effect });
|
|
85
|
+
})
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
})();
|
|
89
|
+
|
|
90
|
+
// src/Engine.ts
|
|
91
|
+
var EngineTagImpl = class extends import_effect2.Context.Tag("@logixjs/query/Engine")() {
|
|
92
|
+
};
|
|
93
|
+
var Engine = Object.assign(EngineTagImpl, {
|
|
94
|
+
layer: (engine2) => import_effect2.Layer.succeed(EngineTagImpl, engine2),
|
|
95
|
+
middleware: (config) => middleware(config)
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// src/internal/logics/auto-trigger.ts
|
|
99
|
+
var defaultTriggers = ["onMount", "onKeyChange"];
|
|
100
|
+
var getTriggers = (triggers) => triggers ?? defaultTriggers;
|
|
101
|
+
var isManualOnly = (triggers) => triggers.length === 1 && triggers[0] === "manual";
|
|
102
|
+
var getSnapshotKeyHash = (snapshot) => {
|
|
103
|
+
if (!snapshot || typeof snapshot !== "object") return void 0;
|
|
104
|
+
const keyHash = snapshot.keyHash;
|
|
105
|
+
return typeof keyHash === "string" ? keyHash : void 0;
|
|
106
|
+
};
|
|
107
|
+
var getSnapshotStatus = (snapshot) => {
|
|
108
|
+
if (!snapshot || typeof snapshot !== "object") return void 0;
|
|
109
|
+
const status = snapshot.status;
|
|
110
|
+
return typeof status === "string" ? status : void 0;
|
|
111
|
+
};
|
|
112
|
+
var autoTrigger = (module2, config) => module2.logic(($) => {
|
|
113
|
+
const pending = /* @__PURE__ */ new Map();
|
|
114
|
+
const lastKeyHash = /* @__PURE__ */ new Map();
|
|
115
|
+
const hydrateFromFreshCache = (name, q, keyHash) => import_effect3.Effect.gen(function* () {
|
|
116
|
+
const engineOpt = yield* import_effect3.Effect.serviceOption(Engine);
|
|
117
|
+
if (engineOpt._tag === "None") return false;
|
|
118
|
+
const engine2 = engineOpt.value;
|
|
119
|
+
if (!engine2.peekFresh) return false;
|
|
120
|
+
const dataOpt = yield* engine2.peekFresh({
|
|
121
|
+
resourceId: q.resource.id,
|
|
122
|
+
keyHash
|
|
123
|
+
});
|
|
124
|
+
if (dataOpt._tag === "None") return false;
|
|
125
|
+
const snapshot = Logix.Resource.Snapshot.success({
|
|
126
|
+
keyHash,
|
|
127
|
+
data: dataOpt.value
|
|
128
|
+
});
|
|
129
|
+
yield* $.state.mutate((draft) => {
|
|
130
|
+
;
|
|
131
|
+
draft.queries[name] = snapshot;
|
|
132
|
+
});
|
|
133
|
+
return true;
|
|
134
|
+
});
|
|
135
|
+
const cancelPending = (name) => import_effect3.Effect.gen(function* () {
|
|
136
|
+
const prev = pending.get(name);
|
|
137
|
+
if (!prev) return;
|
|
138
|
+
pending.delete(name);
|
|
139
|
+
yield* import_effect3.Fiber.interruptFork(prev);
|
|
140
|
+
});
|
|
141
|
+
const sourcePathOf = (name) => `queries.${name}`;
|
|
142
|
+
const refresh = (name, options) => $.traits.source.refresh(sourcePathOf(name), options);
|
|
143
|
+
const scheduleDebounced = (name, ms) => import_effect3.Effect.gen(function* () {
|
|
144
|
+
yield* cancelPending(name);
|
|
145
|
+
const fiber = yield* import_effect3.Effect.forkScoped(
|
|
146
|
+
import_effect3.Effect.sleep(import_effect3.Duration.millis(ms)).pipe(
|
|
147
|
+
import_effect3.Effect.zipRight(refresh(name)),
|
|
148
|
+
import_effect3.Effect.ensuring(import_effect3.Effect.sync(() => pending.delete(name))),
|
|
149
|
+
import_effect3.Effect.catchAllCause(() => import_effect3.Effect.void)
|
|
150
|
+
)
|
|
151
|
+
);
|
|
152
|
+
pending.set(name, fiber);
|
|
153
|
+
});
|
|
154
|
+
const computeKeyHash = (state, q) => {
|
|
155
|
+
const getAtPath = (root, path) => {
|
|
156
|
+
const parts = path.split(".");
|
|
157
|
+
let cur = root;
|
|
158
|
+
for (const p of parts) {
|
|
159
|
+
if (cur == null) return void 0;
|
|
160
|
+
cur = cur[p];
|
|
161
|
+
}
|
|
162
|
+
return cur;
|
|
163
|
+
};
|
|
164
|
+
try {
|
|
165
|
+
const keyState = { params: state.params, ui: state.ui };
|
|
166
|
+
const args = q.deps.map((dep) => getAtPath(keyState, dep));
|
|
167
|
+
const key = q.key(...args);
|
|
168
|
+
if (key === void 0) return void 0;
|
|
169
|
+
return Logix.Resource.keyHash(key);
|
|
170
|
+
} catch {
|
|
171
|
+
return void 0;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
const maybeAutoRefresh = (phase, stateOverride) => import_effect3.Effect.gen(function* () {
|
|
175
|
+
const state = stateOverride ?? (yield* $.state.read);
|
|
176
|
+
for (const [name, q] of Object.entries(config.queries)) {
|
|
177
|
+
const queryName = name;
|
|
178
|
+
const triggers = getTriggers(q.triggers);
|
|
179
|
+
if (isManualOnly(triggers)) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (phase === "mount" && !triggers.includes("onMount")) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (phase === "keyChange" && !triggers.includes("onKeyChange")) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const keyHash = computeKeyHash(state, q);
|
|
189
|
+
const snapshot = state?.queries?.[queryName];
|
|
190
|
+
const snapshotKeyHash = getSnapshotKeyHash(snapshot);
|
|
191
|
+
const snapshotStatus = getSnapshotStatus(snapshot);
|
|
192
|
+
if (keyHash === void 0) {
|
|
193
|
+
lastKeyHash.set(queryName, void 0);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const last = lastKeyHash.get(queryName);
|
|
197
|
+
if (snapshotStatus && snapshotStatus !== "idle" && snapshotKeyHash === keyHash && last === keyHash) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (snapshotStatus && snapshotStatus !== "idle" && snapshotKeyHash === keyHash) {
|
|
201
|
+
lastKeyHash.set(queryName, keyHash);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
lastKeyHash.set(queryName, keyHash);
|
|
205
|
+
const hydrated = yield* hydrateFromFreshCache(queryName, q, keyHash);
|
|
206
|
+
if (hydrated) {
|
|
207
|
+
yield* cancelPending(queryName);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const debounceMs = q.debounceMs ?? 0;
|
|
211
|
+
if (phase === "keyChange" && debounceMs > 0) {
|
|
212
|
+
yield* scheduleDebounced(queryName, debounceMs);
|
|
213
|
+
} else {
|
|
214
|
+
yield* cancelPending(queryName);
|
|
215
|
+
yield* refresh(queryName);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
const refreshAll = (options) => import_effect3.Effect.forEach(
|
|
220
|
+
Object.keys(config.queries),
|
|
221
|
+
(name) => cancelPending(name).pipe(import_effect3.Effect.zipRight(refresh(name, options)))
|
|
222
|
+
).pipe(import_effect3.Effect.asVoid);
|
|
223
|
+
const setup = $.lifecycle.onStart(maybeAutoRefresh("mount"));
|
|
224
|
+
const run = import_effect3.Effect.suspend(
|
|
225
|
+
() => import_effect3.Effect.all(
|
|
226
|
+
[
|
|
227
|
+
// params/ui changes: handled by Query's default logic, avoiding scattered UI-side useEffect triggers.
|
|
228
|
+
$.onAction("setParams").runFork(
|
|
229
|
+
(action) => import_effect3.Effect.gen(function* () {
|
|
230
|
+
const state = yield* $.state.read;
|
|
231
|
+
const next = { ...state, params: action.payload };
|
|
232
|
+
yield* maybeAutoRefresh("keyChange", next);
|
|
233
|
+
})
|
|
234
|
+
),
|
|
235
|
+
$.onAction("setUi").runFork(
|
|
236
|
+
(action) => import_effect3.Effect.gen(function* () {
|
|
237
|
+
const state = yield* $.state.read;
|
|
238
|
+
const next = { ...state, ui: action.payload };
|
|
239
|
+
yield* maybeAutoRefresh("keyChange", next);
|
|
240
|
+
})
|
|
241
|
+
),
|
|
242
|
+
// Manual refresh: not restricted by triggers (manual-only still allows explicit refresh).
|
|
243
|
+
$.onAction("refresh").runFork(
|
|
244
|
+
(action) => import_effect3.Effect.gen(function* () {
|
|
245
|
+
const target = action.payload;
|
|
246
|
+
if (typeof target === "string" && target.length > 0) {
|
|
247
|
+
yield* cancelPending(target);
|
|
248
|
+
yield* refresh(target, { force: true });
|
|
249
|
+
} else {
|
|
250
|
+
yield* refreshAll({ force: true });
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
)
|
|
254
|
+
],
|
|
255
|
+
{ concurrency: "unbounded" }
|
|
256
|
+
).pipe(import_effect3.Effect.asVoid)
|
|
257
|
+
);
|
|
258
|
+
return { setup, run };
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// src/internal/logics/invalidate.ts
|
|
262
|
+
var Logix2 = __toESM(require("@logixjs/core"), 1);
|
|
263
|
+
var import_effect4 = require("effect");
|
|
264
|
+
var toInvalidateTargets = (request, queries) => {
|
|
265
|
+
if (request.kind === "byResource") {
|
|
266
|
+
return Object.entries(queries).filter(([, q]) => q.resource.id === request.resourceId).map(([name, q]) => ({ name, resourceId: q.resource.id }));
|
|
267
|
+
}
|
|
268
|
+
if (request.kind === "byParams") {
|
|
269
|
+
return Object.entries(queries).filter(([, q]) => q.resource.id === request.resourceId).map(([name, q]) => ({ name, resourceId: q.resource.id }));
|
|
270
|
+
}
|
|
271
|
+
const entries = Object.entries(queries);
|
|
272
|
+
const tagged = entries.filter(([, q]) => Array.isArray(q.tags) && q.tags.includes(request.tag));
|
|
273
|
+
const selected = tagged.length > 0 ? tagged : entries;
|
|
274
|
+
return selected.map(([name, q]) => ({ name, resourceId: q.resource.id }));
|
|
275
|
+
};
|
|
276
|
+
var invalidate = (module2, config) => module2.logic(
|
|
277
|
+
($) => import_effect4.Effect.gen(function* () {
|
|
278
|
+
yield* $.onAction("invalidate").runFork(
|
|
279
|
+
(action) => import_effect4.Effect.gen(function* () {
|
|
280
|
+
const request = action.payload;
|
|
281
|
+
yield* Logix2.TraitLifecycle.scopedExecute($, {
|
|
282
|
+
kind: "query:invalidate",
|
|
283
|
+
request
|
|
284
|
+
});
|
|
285
|
+
const engineOpt = yield* import_effect4.Effect.serviceOption(Engine);
|
|
286
|
+
if (engineOpt._tag !== "None") {
|
|
287
|
+
yield* engineOpt.value.invalidate(request);
|
|
288
|
+
}
|
|
289
|
+
const targets = toInvalidateTargets(request, config.queries);
|
|
290
|
+
const sourcePathOf = (name) => `queries.${name}`;
|
|
291
|
+
yield* import_effect4.Effect.forEach(
|
|
292
|
+
targets,
|
|
293
|
+
(t) => $.traits.source.refresh(sourcePathOf(t.name), { force: true })
|
|
294
|
+
).pipe(import_effect4.Effect.asVoid);
|
|
295
|
+
})
|
|
296
|
+
);
|
|
297
|
+
})
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
// src/Traits.ts
|
|
301
|
+
var Logix3 = __toESM(require("@logixjs/core"), 1);
|
|
302
|
+
var source = (config) => config;
|
|
303
|
+
var toStateTraitSpec = (input) => {
|
|
304
|
+
const out = {};
|
|
305
|
+
for (const [name, q] of Object.entries(input.queries)) {
|
|
306
|
+
const triggers = q.triggers ?? ["onMount", "onKeyChange"];
|
|
307
|
+
if (triggers.includes("manual") && triggers.length > 1) {
|
|
308
|
+
throw new Error(
|
|
309
|
+
`[Query.traits] "manual" must be exclusive, but got triggers=[${triggers.join(", ")}] for query "${name}".`
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
out[`queries.${name}`] = Logix3.StateTrait.source({
|
|
313
|
+
// deps: used for graph building/diagnostics/future reverse-closure; Query also reuses deps to converge triggers.
|
|
314
|
+
deps: q.deps,
|
|
315
|
+
resource: q.resource.id,
|
|
316
|
+
triggers,
|
|
317
|
+
debounceMs: q.debounceMs,
|
|
318
|
+
concurrency: q.concurrency === "exhaust" ? "exhaust-trailing" : q.concurrency,
|
|
319
|
+
key: (...depsValues) => q.key(...depsValues)
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
return out;
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// src/Query.ts
|
|
326
|
+
var InvalidateRequestSchema = import_effect5.Schema.Union(
|
|
327
|
+
import_effect5.Schema.Struct({
|
|
328
|
+
kind: import_effect5.Schema.Literal("byResource"),
|
|
329
|
+
resourceId: import_effect5.Schema.String
|
|
330
|
+
}),
|
|
331
|
+
import_effect5.Schema.Struct({
|
|
332
|
+
kind: import_effect5.Schema.Literal("byParams"),
|
|
333
|
+
resourceId: import_effect5.Schema.String,
|
|
334
|
+
keyHash: import_effect5.Schema.String
|
|
335
|
+
}),
|
|
336
|
+
import_effect5.Schema.Struct({
|
|
337
|
+
kind: import_effect5.Schema.Literal("byTag"),
|
|
338
|
+
tag: import_effect5.Schema.String
|
|
339
|
+
})
|
|
340
|
+
);
|
|
341
|
+
var assertQueryName = (name) => {
|
|
342
|
+
if (!name) {
|
|
343
|
+
throw new Error(`[Query.make] query name must be non-empty`);
|
|
344
|
+
}
|
|
345
|
+
if (name.includes(".")) {
|
|
346
|
+
throw new Error(`[Query.make] query name must not include "."; got "${name}"`);
|
|
347
|
+
}
|
|
348
|
+
if (name === "params" || name === "ui" || name === "queries") {
|
|
349
|
+
throw new Error(`[Query.make] query name "${name}" is reserved`);
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
var make = (id, config) => {
|
|
353
|
+
const queryBuilder = {
|
|
354
|
+
source: (q) => q
|
|
355
|
+
};
|
|
356
|
+
const queries = (() => {
|
|
357
|
+
const raw = config.queries;
|
|
358
|
+
if (!raw) return {};
|
|
359
|
+
return raw(queryBuilder);
|
|
360
|
+
})();
|
|
361
|
+
const queriesForTraits = queries;
|
|
362
|
+
for (const name of Object.keys(queries)) {
|
|
363
|
+
assertQueryName(name);
|
|
364
|
+
}
|
|
365
|
+
const RefreshTargetSchema = (() => {
|
|
366
|
+
const names = Object.keys(queries);
|
|
367
|
+
if (names.length === 0) return import_effect5.Schema.Never;
|
|
368
|
+
if (names.length === 1) {
|
|
369
|
+
return import_effect5.Schema.Literal(names[0]);
|
|
370
|
+
}
|
|
371
|
+
const asUnionMembers = (items) => {
|
|
372
|
+
if (items.length < 2) {
|
|
373
|
+
throw new Error(`[Query.make] internal error: expected at least 2 query names for union`);
|
|
374
|
+
}
|
|
375
|
+
return items;
|
|
376
|
+
};
|
|
377
|
+
const members = names.map((n) => import_effect5.Schema.Literal(n));
|
|
378
|
+
return import_effect5.Schema.Union(...asUnionMembers(members));
|
|
379
|
+
})();
|
|
380
|
+
const UiSchema = import_effect5.Schema.Unknown;
|
|
381
|
+
const QueriesSchema = import_effect5.Schema.Struct(
|
|
382
|
+
Object.fromEntries(Object.keys(queries).map((k) => [k, import_effect5.Schema.Unknown]))
|
|
383
|
+
);
|
|
384
|
+
const StateSchema = import_effect5.Schema.Struct({
|
|
385
|
+
params: config.params,
|
|
386
|
+
ui: UiSchema,
|
|
387
|
+
queries: QueriesSchema
|
|
388
|
+
});
|
|
389
|
+
const Actions = {
|
|
390
|
+
setParams: config.params,
|
|
391
|
+
setUi: UiSchema,
|
|
392
|
+
refresh: import_effect5.Schema.UndefinedOr(RefreshTargetSchema),
|
|
393
|
+
invalidate: InvalidateRequestSchema
|
|
394
|
+
};
|
|
395
|
+
const reducers = {
|
|
396
|
+
setParams: (state, action, sink) => {
|
|
397
|
+
sink?.("params");
|
|
398
|
+
return { ...state, params: action.payload ?? state.params };
|
|
399
|
+
},
|
|
400
|
+
setUi: (state, action, sink) => {
|
|
401
|
+
sink?.("ui");
|
|
402
|
+
return { ...state, ui: action.payload ?? state.ui };
|
|
403
|
+
},
|
|
404
|
+
refresh: (state) => state,
|
|
405
|
+
invalidate: (state) => state
|
|
406
|
+
};
|
|
407
|
+
const queryTraits = Object.keys(queriesForTraits).length > 0 ? toStateTraitSpec({ queries: queriesForTraits }) : void 0;
|
|
408
|
+
const traits = queryTraits || config.traits ? {
|
|
409
|
+
...queryTraits,
|
|
410
|
+
...config.traits
|
|
411
|
+
} : void 0;
|
|
412
|
+
const module2 = Logix4.Module.make(id, {
|
|
413
|
+
state: StateSchema,
|
|
414
|
+
actions: Actions,
|
|
415
|
+
reducers,
|
|
416
|
+
traits
|
|
417
|
+
});
|
|
418
|
+
const logics = [
|
|
419
|
+
autoTrigger(module2.tag, { queries: queriesForTraits }),
|
|
420
|
+
invalidate(module2.tag, { queries: queriesForTraits })
|
|
421
|
+
];
|
|
422
|
+
const initial = (params) => ({
|
|
423
|
+
params: params ?? config.initialParams,
|
|
424
|
+
ui: config.ui ?? {},
|
|
425
|
+
queries: Object.fromEntries(
|
|
426
|
+
Object.keys(queries).map((k) => [k, Logix4.Resource.Snapshot.idle()])
|
|
427
|
+
)
|
|
428
|
+
});
|
|
429
|
+
const controller = {
|
|
430
|
+
make: (runtime) => {
|
|
431
|
+
const dispatch = runtime.dispatch;
|
|
432
|
+
const actions = module2.actions;
|
|
433
|
+
return {
|
|
434
|
+
runtime,
|
|
435
|
+
getState: runtime.getState,
|
|
436
|
+
dispatch,
|
|
437
|
+
controller: {
|
|
438
|
+
setParams: (params) => dispatch(actions.setParams(params)),
|
|
439
|
+
setUi: (ui) => dispatch(actions.setUi(ui)),
|
|
440
|
+
refresh: (target) => dispatch(actions.refresh(target)),
|
|
441
|
+
invalidate: (request) => dispatch(actions.invalidate(request))
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
module2.controller = controller;
|
|
447
|
+
const EXTEND_HANDLE = /* @__PURE__ */ Symbol.for("logix.module.handle.extend");
|
|
448
|
+
module2.tag[EXTEND_HANDLE] = (runtime, base) => {
|
|
449
|
+
const c = controller.make(runtime);
|
|
450
|
+
return {
|
|
451
|
+
...base,
|
|
452
|
+
controller: c.controller
|
|
453
|
+
};
|
|
454
|
+
};
|
|
455
|
+
return module2.implement({
|
|
456
|
+
initial: initial(),
|
|
457
|
+
logics: [...logics]
|
|
458
|
+
});
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// src/TanStack.ts
|
|
462
|
+
var TanStack_exports = {};
|
|
463
|
+
__export(TanStack_exports, {
|
|
464
|
+
engine: () => engine,
|
|
465
|
+
observe: () => observe
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
// src/internal/engine/tanstack.ts
|
|
469
|
+
var import_effect6 = require("effect");
|
|
470
|
+
var makeQueryKey = (resourceId, keyHash) => [resourceId, keyHash];
|
|
471
|
+
var engine = (queryClient, config) => {
|
|
472
|
+
const byResourceId = /* @__PURE__ */ new Map();
|
|
473
|
+
const maxEntriesPerResource = config?.maxEntriesPerResource ?? 2e3;
|
|
474
|
+
try {
|
|
475
|
+
const queryCache = queryClient.getQueryCache?.();
|
|
476
|
+
if (queryCache && typeof queryCache.clear === "function") {
|
|
477
|
+
const original = queryCache.clear.bind(queryCache);
|
|
478
|
+
queryCache.clear = () => {
|
|
479
|
+
byResourceId.clear();
|
|
480
|
+
return original();
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
} catch {
|
|
484
|
+
}
|
|
485
|
+
const ensureBucket = (resourceId) => {
|
|
486
|
+
let bucket = byResourceId.get(resourceId);
|
|
487
|
+
if (!bucket) {
|
|
488
|
+
bucket = /* @__PURE__ */ new Map();
|
|
489
|
+
byResourceId.set(resourceId, bucket);
|
|
490
|
+
}
|
|
491
|
+
return bucket;
|
|
492
|
+
};
|
|
493
|
+
const evictIfNeeded = (bucket) => {
|
|
494
|
+
if (maxEntriesPerResource === Infinity) return;
|
|
495
|
+
if (!Number.isFinite(maxEntriesPerResource) || maxEntriesPerResource <= 0) return;
|
|
496
|
+
while (bucket.size > maxEntriesPerResource) {
|
|
497
|
+
const firstKey = bucket.keys().next().value;
|
|
498
|
+
if (firstKey === void 0) return;
|
|
499
|
+
bucket.delete(firstKey);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
const fetchFast = (resourceId, keyHash, effect) => import_effect6.Effect.suspend(() => {
|
|
503
|
+
const hit = byResourceId.get(resourceId)?.get(keyHash);
|
|
504
|
+
if (hit !== void 0) {
|
|
505
|
+
return import_effect6.Effect.succeed(hit);
|
|
506
|
+
}
|
|
507
|
+
return import_effect6.Effect.map(effect, (out) => {
|
|
508
|
+
if (out !== void 0) {
|
|
509
|
+
const bucket = ensureBucket(resourceId);
|
|
510
|
+
bucket.set(keyHash, out);
|
|
511
|
+
evictIfNeeded(bucket);
|
|
512
|
+
}
|
|
513
|
+
return out;
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
return {
|
|
517
|
+
fetch: ({ resourceId, keyHash, effect }) => fetchFast(resourceId, keyHash, effect),
|
|
518
|
+
fetchFast,
|
|
519
|
+
invalidate: (request) => import_effect6.Effect.gen(function* () {
|
|
520
|
+
yield* import_effect6.Effect.sync(() => {
|
|
521
|
+
if (request.kind === "byParams") {
|
|
522
|
+
const bucket = byResourceId.get(request.resourceId);
|
|
523
|
+
if (!bucket) return;
|
|
524
|
+
bucket.delete(request.keyHash);
|
|
525
|
+
if (bucket.size === 0) {
|
|
526
|
+
byResourceId.delete(request.resourceId);
|
|
527
|
+
}
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
if (request.kind === "byResource") {
|
|
531
|
+
byResourceId.delete(request.resourceId);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
byResourceId.clear();
|
|
535
|
+
});
|
|
536
|
+
yield* import_effect6.Effect.tryPromise({
|
|
537
|
+
try: () => {
|
|
538
|
+
if (request.kind === "byResource") {
|
|
539
|
+
return queryClient.invalidateQueries({
|
|
540
|
+
queryKey: [request.resourceId]
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
if (request.kind === "byParams") {
|
|
544
|
+
return queryClient.invalidateQueries({
|
|
545
|
+
queryKey: makeQueryKey(request.resourceId, request.keyHash)
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
return queryClient.invalidateQueries({
|
|
549
|
+
predicate: (q) => {
|
|
550
|
+
const tags = q.meta?.tags;
|
|
551
|
+
return Array.isArray(tags) && tags.includes(request.tag);
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
},
|
|
555
|
+
catch: (e) => e
|
|
556
|
+
}).pipe(import_effect6.Effect.asVoid);
|
|
557
|
+
}),
|
|
558
|
+
peekFresh: ({ resourceId, keyHash }) => import_effect6.Effect.sync(() => {
|
|
559
|
+
const hit = byResourceId.get(resourceId)?.get(keyHash);
|
|
560
|
+
return hit === void 0 ? import_effect6.Option.none() : import_effect6.Option.some(hit);
|
|
561
|
+
})
|
|
562
|
+
};
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
// src/internal/tanstack/observer.ts
|
|
566
|
+
var import_effect7 = require("effect");
|
|
567
|
+
var import_query_core = require("@tanstack/query-core");
|
|
568
|
+
var observe = (params) => import_effect7.Effect.gen(function* () {
|
|
569
|
+
const observer = new import_query_core.QueryObserver(params.queryClient, params.options);
|
|
570
|
+
const unsubscribe = observer.subscribe(params.onResult);
|
|
571
|
+
yield* import_effect7.Effect.addFinalizer(() => import_effect7.Effect.sync(() => unsubscribe()));
|
|
572
|
+
return observer;
|
|
573
|
+
});
|
|
574
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
575
|
+
0 && (module.exports = {
|
|
576
|
+
Engine,
|
|
577
|
+
TanStack,
|
|
578
|
+
make,
|
|
579
|
+
source,
|
|
580
|
+
traits
|
|
581
|
+
});
|
|
582
|
+
//# sourceMappingURL=index.cjs.map
|