@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/Engine.cjs
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/Engine.ts
|
|
21
|
+
var Engine_exports = {};
|
|
22
|
+
__export(Engine_exports, {
|
|
23
|
+
Engine: () => Engine
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(Engine_exports);
|
|
26
|
+
var import_effect2 = require("effect");
|
|
27
|
+
|
|
28
|
+
// src/internal/middleware/middleware.ts
|
|
29
|
+
var import_effect = require("effect");
|
|
30
|
+
var middleware = (config) => /* @__PURE__ */ (() => {
|
|
31
|
+
let cachedEngine;
|
|
32
|
+
return (op) => {
|
|
33
|
+
if (op.kind !== "service" && op.kind !== "trait-source" || !op.meta?.resourceId || !op.meta.keyHash) {
|
|
34
|
+
return op.effect;
|
|
35
|
+
}
|
|
36
|
+
const resourceId = op.meta.resourceId;
|
|
37
|
+
if (config?.useFor && !config.useFor(resourceId)) {
|
|
38
|
+
return op.effect;
|
|
39
|
+
}
|
|
40
|
+
const keyHash = op.meta.keyHash;
|
|
41
|
+
if (cachedEngine) {
|
|
42
|
+
if (cachedEngine.fetchFast) {
|
|
43
|
+
return cachedEngine.fetchFast(resourceId, keyHash, op.effect);
|
|
44
|
+
}
|
|
45
|
+
return cachedEngine.fetch({ resourceId, keyHash, effect: op.effect });
|
|
46
|
+
}
|
|
47
|
+
return import_effect.Effect.serviceOption(Engine).pipe(
|
|
48
|
+
import_effect.Effect.flatMap((engineOpt) => {
|
|
49
|
+
if (import_effect.Option.isNone(engineOpt)) {
|
|
50
|
+
return import_effect.Effect.fail(
|
|
51
|
+
new Error(
|
|
52
|
+
`[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).`
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
cachedEngine = engineOpt.value;
|
|
57
|
+
if (cachedEngine.fetchFast) {
|
|
58
|
+
return cachedEngine.fetchFast(resourceId, keyHash, op.effect);
|
|
59
|
+
}
|
|
60
|
+
return cachedEngine.fetch({ resourceId, keyHash, effect: op.effect });
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
})();
|
|
65
|
+
|
|
66
|
+
// src/Engine.ts
|
|
67
|
+
var EngineTagImpl = class extends import_effect2.Context.Tag("@logixjs/query/Engine")() {
|
|
68
|
+
};
|
|
69
|
+
var Engine = Object.assign(EngineTagImpl, {
|
|
70
|
+
layer: (engine) => import_effect2.Layer.succeed(EngineTagImpl, engine),
|
|
71
|
+
middleware: (config) => middleware(config)
|
|
72
|
+
});
|
|
73
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
74
|
+
0 && (module.exports = {
|
|
75
|
+
Engine
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=Engine.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Engine.ts","../src/internal/middleware/middleware.ts"],"sourcesContent":["import type * as EffectOp from '@logixjs/core/EffectOp'\nimport { Context, Effect, Layer, Option } from 'effect'\nimport { middleware as middlewareImpl, type MiddlewareConfig } from './internal/middleware/middleware.js'\n\nexport type InvalidateRequest =\n | { readonly kind: 'byResource'; readonly resourceId: string }\n | { readonly kind: 'byParams'; readonly resourceId: string; readonly keyHash: string }\n | { readonly kind: 'byTag'; readonly tag: string }\n\nexport interface Engine {\n readonly fetch: <A>(args: {\n readonly resourceId: string\n readonly keyHash: string\n readonly effect: Effect.Effect<A, unknown, any>\n /**\n * MUST be serializable and slim; recommended default is undefined (lazy),\n * and only populate it when diagnostics/devtools require it.\n */\n readonly meta?: unknown\n }) => Effect.Effect<A, unknown, any>\n\n /**\n * perf: optional fast path to avoid allocations on the hot path.\n * Semantics must match `fetch({ ... })`.\n */\n readonly fetchFast?: <A>(\n resourceId: string,\n keyHash: string,\n effect: Effect.Effect<A, unknown, any>,\n meta?: unknown,\n ) => Effect.Effect<A, unknown, any>\n\n readonly invalidate: (request: InvalidateRequest) => Effect.Effect<void, unknown, any>\n\n /**\n * Read-only fast path: must not trigger IO; used to short-circuit to success before refresh,\n * avoiding loading jitter.\n */\n readonly peekFresh?: <A>(args: {\n readonly resourceId: string\n readonly keyHash: string\n }) => Effect.Effect<Option.Option<A>, never, any>\n}\n\nclass EngineTagImpl extends Context.Tag('@logixjs/query/Engine')<EngineTagImpl, Engine>() {}\n\nexport const Engine = Object.assign(EngineTagImpl, {\n layer: (engine: Engine): Layer.Layer<EngineTagImpl, never, never> => Layer.succeed(EngineTagImpl, engine),\n middleware: (config?: MiddlewareConfig): EffectOp.Middleware => middlewareImpl(config),\n})\n\nexport type { MiddlewareConfig }\n","import type * as EffectOp from '@logixjs/core/EffectOp'\nimport { Effect, Option } from 'effect'\nimport { Engine } from '../../Engine.js'\nimport type { Engine as EngineService } from '../../Engine.js'\n\nexport interface MiddlewareConfig {\n /**\n * Default: only applies to EffectOp that carries resourceId+keyHash (from StateTrait.source).\n * Optional: further filter by resourceId.\n */\n readonly useFor?: (resourceId: string) => boolean\n}\n\n/**\n * Query middleware (EffectOp): external engine takeover point.\n * - Delegates ResourceSpec.load execution to Engine (cache / in-flight dedupe / invalidation, etc.)\n * - Still preserves Logix Runtime's keyHash gating and ResourceSnapshot source-of-truth semantics\n */\nexport const middleware = (config?: MiddlewareConfig): EffectOp.Middleware =>\n (() => {\n // perf: within the same Runtime instance, Engine injection is stable.\n // Cache it in the middleware closure to avoid a Context lookup on every fetch.\n let cachedEngine: EngineService | undefined\n\n return (op) => {\n if ((op.kind !== 'service' && op.kind !== 'trait-source') || !op.meta?.resourceId || !op.meta.keyHash) {\n return op.effect as any\n }\n\n const resourceId = op.meta.resourceId\n if (config?.useFor && !config.useFor(resourceId)) {\n return op.effect as any\n }\n\n const keyHash = op.meta.keyHash as string\n\n if (cachedEngine) {\n if (cachedEngine.fetchFast) {\n return cachedEngine.fetchFast(resourceId, keyHash, op.effect as any)\n }\n return cachedEngine.fetch({ resourceId, keyHash, effect: op.effect as any })\n }\n\n return Effect.serviceOption(Engine).pipe(\n Effect.flatMap((engineOpt) => {\n if (Option.isNone(engineOpt)) {\n return Effect.fail(\n new Error(\n `[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).`,\n ),\n )\n }\n cachedEngine = engineOpt.value\n if (cachedEngine.fetchFast) {\n return cachedEngine.fetchFast(resourceId, keyHash, op.effect as any)\n }\n return cachedEngine.fetch({ resourceId, keyHash, effect: op.effect as any })\n }),\n ) as any\n }\n })()\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,IAAAA,iBAA+C;;;ACA/C,oBAA+B;AAiBxB,IAAM,aAAa,CAAC,WACxB,uBAAM;AAGL,MAAI;AAEJ,SAAO,CAAC,OAAO;AACb,QAAK,GAAG,SAAS,aAAa,GAAG,SAAS,kBAAmB,CAAC,GAAG,MAAM,cAAc,CAAC,GAAG,KAAK,SAAS;AACrG,aAAO,GAAG;AAAA,IACZ;AAEA,UAAM,aAAa,GAAG,KAAK;AAC3B,QAAI,QAAQ,UAAU,CAAC,OAAO,OAAO,UAAU,GAAG;AAChD,aAAO,GAAG;AAAA,IACZ;AAEA,UAAM,UAAU,GAAG,KAAK;AAExB,QAAI,cAAc;AAChB,UAAI,aAAa,WAAW;AAC1B,eAAO,aAAa,UAAU,YAAY,SAAS,GAAG,MAAa;AAAA,MACrE;AACA,aAAO,aAAa,MAAM,EAAE,YAAY,SAAS,QAAQ,GAAG,OAAc,CAAC;AAAA,IAC7E;AAEA,WAAO,qBAAO,cAAc,MAAM,EAAE;AAAA,MAClC,qBAAO,QAAQ,CAAC,cAAc;AAC5B,YAAI,qBAAO,OAAO,SAAS,GAAG;AAC5B,iBAAO,qBAAO;AAAA,YACZ,IAAI;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,uBAAe,UAAU;AACzB,YAAI,aAAa,WAAW;AAC1B,iBAAO,aAAa,UAAU,YAAY,SAAS,GAAG,MAAa;AAAA,QACrE;AACA,eAAO,aAAa,MAAM,EAAE,YAAY,SAAS,QAAQ,GAAG,OAAc,CAAC;AAAA,MAC7E,CAAC;AAAA,IACH;AAAA,EACF;AACF,GAAG;;;ADhBL,IAAM,gBAAN,cAA4B,uBAAQ,IAAI,uBAAuB,EAAyB,EAAE;AAAC;AAEpF,IAAM,SAAS,OAAO,OAAO,eAAe;AAAA,EACjD,OAAO,CAAC,WAA6D,qBAAM,QAAQ,eAAe,MAAM;AAAA,EACxG,YAAY,CAAC,WAAmD,WAAe,MAAM;AACvF,CAAC;","names":["import_effect"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as EffectOp from '@logixjs/core/EffectOp';
|
|
2
|
+
import { Effect, Option, Context, Layer } from 'effect';
|
|
3
|
+
|
|
4
|
+
interface MiddlewareConfig {
|
|
5
|
+
/**
|
|
6
|
+
* Default: only applies to EffectOp that carries resourceId+keyHash (from StateTrait.source).
|
|
7
|
+
* Optional: further filter by resourceId.
|
|
8
|
+
*/
|
|
9
|
+
readonly useFor?: (resourceId: string) => boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type InvalidateRequest = {
|
|
13
|
+
readonly kind: 'byResource';
|
|
14
|
+
readonly resourceId: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'byParams';
|
|
17
|
+
readonly resourceId: string;
|
|
18
|
+
readonly keyHash: string;
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'byTag';
|
|
21
|
+
readonly tag: string;
|
|
22
|
+
};
|
|
23
|
+
declare const EngineTagImpl_base: Context.TagClass<EngineTagImpl, "@logixjs/query/Engine", Engine>;
|
|
24
|
+
declare class EngineTagImpl extends EngineTagImpl_base {
|
|
25
|
+
}
|
|
26
|
+
interface Engine {
|
|
27
|
+
readonly fetch: <A>(args: {
|
|
28
|
+
readonly resourceId: string;
|
|
29
|
+
readonly keyHash: string;
|
|
30
|
+
readonly effect: Effect.Effect<A, unknown, any>;
|
|
31
|
+
/**
|
|
32
|
+
* MUST be serializable and slim; recommended default is undefined (lazy),
|
|
33
|
+
* and only populate it when diagnostics/devtools require it.
|
|
34
|
+
*/
|
|
35
|
+
readonly meta?: unknown;
|
|
36
|
+
}) => Effect.Effect<A, unknown, any>;
|
|
37
|
+
/**
|
|
38
|
+
* perf: optional fast path to avoid allocations on the hot path.
|
|
39
|
+
* Semantics must match `fetch({ ... })`.
|
|
40
|
+
*/
|
|
41
|
+
readonly fetchFast?: <A>(resourceId: string, keyHash: string, effect: Effect.Effect<A, unknown, any>, meta?: unknown) => Effect.Effect<A, unknown, any>;
|
|
42
|
+
readonly invalidate: (request: InvalidateRequest) => Effect.Effect<void, unknown, any>;
|
|
43
|
+
/**
|
|
44
|
+
* Read-only fast path: must not trigger IO; used to short-circuit to success before refresh,
|
|
45
|
+
* avoiding loading jitter.
|
|
46
|
+
*/
|
|
47
|
+
readonly peekFresh?: <A>(args: {
|
|
48
|
+
readonly resourceId: string;
|
|
49
|
+
readonly keyHash: string;
|
|
50
|
+
}) => Effect.Effect<Option.Option<A>, never, any>;
|
|
51
|
+
}
|
|
52
|
+
declare const Engine: typeof EngineTagImpl & {
|
|
53
|
+
layer: (engine: Engine) => Layer.Layer<EngineTagImpl, never, never>;
|
|
54
|
+
middleware: (config?: MiddlewareConfig) => EffectOp.Middleware;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export { Engine, type InvalidateRequest, type MiddlewareConfig };
|
package/dist/Engine.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as EffectOp from '@logixjs/core/EffectOp';
|
|
2
|
+
import { Effect, Option, Context, Layer } from 'effect';
|
|
3
|
+
|
|
4
|
+
interface MiddlewareConfig {
|
|
5
|
+
/**
|
|
6
|
+
* Default: only applies to EffectOp that carries resourceId+keyHash (from StateTrait.source).
|
|
7
|
+
* Optional: further filter by resourceId.
|
|
8
|
+
*/
|
|
9
|
+
readonly useFor?: (resourceId: string) => boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type InvalidateRequest = {
|
|
13
|
+
readonly kind: 'byResource';
|
|
14
|
+
readonly resourceId: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'byParams';
|
|
17
|
+
readonly resourceId: string;
|
|
18
|
+
readonly keyHash: string;
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'byTag';
|
|
21
|
+
readonly tag: string;
|
|
22
|
+
};
|
|
23
|
+
declare const EngineTagImpl_base: Context.TagClass<EngineTagImpl, "@logixjs/query/Engine", Engine>;
|
|
24
|
+
declare class EngineTagImpl extends EngineTagImpl_base {
|
|
25
|
+
}
|
|
26
|
+
interface Engine {
|
|
27
|
+
readonly fetch: <A>(args: {
|
|
28
|
+
readonly resourceId: string;
|
|
29
|
+
readonly keyHash: string;
|
|
30
|
+
readonly effect: Effect.Effect<A, unknown, any>;
|
|
31
|
+
/**
|
|
32
|
+
* MUST be serializable and slim; recommended default is undefined (lazy),
|
|
33
|
+
* and only populate it when diagnostics/devtools require it.
|
|
34
|
+
*/
|
|
35
|
+
readonly meta?: unknown;
|
|
36
|
+
}) => Effect.Effect<A, unknown, any>;
|
|
37
|
+
/**
|
|
38
|
+
* perf: optional fast path to avoid allocations on the hot path.
|
|
39
|
+
* Semantics must match `fetch({ ... })`.
|
|
40
|
+
*/
|
|
41
|
+
readonly fetchFast?: <A>(resourceId: string, keyHash: string, effect: Effect.Effect<A, unknown, any>, meta?: unknown) => Effect.Effect<A, unknown, any>;
|
|
42
|
+
readonly invalidate: (request: InvalidateRequest) => Effect.Effect<void, unknown, any>;
|
|
43
|
+
/**
|
|
44
|
+
* Read-only fast path: must not trigger IO; used to short-circuit to success before refresh,
|
|
45
|
+
* avoiding loading jitter.
|
|
46
|
+
*/
|
|
47
|
+
readonly peekFresh?: <A>(args: {
|
|
48
|
+
readonly resourceId: string;
|
|
49
|
+
readonly keyHash: string;
|
|
50
|
+
}) => Effect.Effect<Option.Option<A>, never, any>;
|
|
51
|
+
}
|
|
52
|
+
declare const Engine: typeof EngineTagImpl & {
|
|
53
|
+
layer: (engine: Engine) => Layer.Layer<EngineTagImpl, never, never>;
|
|
54
|
+
middleware: (config?: MiddlewareConfig) => EffectOp.Middleware;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export { Engine, type InvalidateRequest, type MiddlewareConfig };
|
package/dist/Engine.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/Query.cjs
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
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/Query.ts
|
|
31
|
+
var Query_exports = {};
|
|
32
|
+
__export(Query_exports, {
|
|
33
|
+
make: () => make
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(Query_exports);
|
|
36
|
+
var Logix4 = __toESM(require("@logixjs/core"), 1);
|
|
37
|
+
var import_effect5 = require("effect");
|
|
38
|
+
|
|
39
|
+
// src/internal/logics/auto-trigger.ts
|
|
40
|
+
var Logix = __toESM(require("@logixjs/core"), 1);
|
|
41
|
+
var import_effect3 = require("effect");
|
|
42
|
+
|
|
43
|
+
// src/Engine.ts
|
|
44
|
+
var import_effect2 = require("effect");
|
|
45
|
+
|
|
46
|
+
// src/internal/middleware/middleware.ts
|
|
47
|
+
var import_effect = require("effect");
|
|
48
|
+
var middleware = (config) => /* @__PURE__ */ (() => {
|
|
49
|
+
let cachedEngine;
|
|
50
|
+
return (op) => {
|
|
51
|
+
if (op.kind !== "service" && op.kind !== "trait-source" || !op.meta?.resourceId || !op.meta.keyHash) {
|
|
52
|
+
return op.effect;
|
|
53
|
+
}
|
|
54
|
+
const resourceId = op.meta.resourceId;
|
|
55
|
+
if (config?.useFor && !config.useFor(resourceId)) {
|
|
56
|
+
return op.effect;
|
|
57
|
+
}
|
|
58
|
+
const keyHash = op.meta.keyHash;
|
|
59
|
+
if (cachedEngine) {
|
|
60
|
+
if (cachedEngine.fetchFast) {
|
|
61
|
+
return cachedEngine.fetchFast(resourceId, keyHash, op.effect);
|
|
62
|
+
}
|
|
63
|
+
return cachedEngine.fetch({ resourceId, keyHash, effect: op.effect });
|
|
64
|
+
}
|
|
65
|
+
return import_effect.Effect.serviceOption(Engine).pipe(
|
|
66
|
+
import_effect.Effect.flatMap((engineOpt) => {
|
|
67
|
+
if (import_effect.Option.isNone(engineOpt)) {
|
|
68
|
+
return import_effect.Effect.fail(
|
|
69
|
+
new Error(
|
|
70
|
+
`[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).`
|
|
71
|
+
)
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
cachedEngine = engineOpt.value;
|
|
75
|
+
if (cachedEngine.fetchFast) {
|
|
76
|
+
return cachedEngine.fetchFast(resourceId, keyHash, op.effect);
|
|
77
|
+
}
|
|
78
|
+
return cachedEngine.fetch({ resourceId, keyHash, effect: op.effect });
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
})();
|
|
83
|
+
|
|
84
|
+
// src/Engine.ts
|
|
85
|
+
var EngineTagImpl = class extends import_effect2.Context.Tag("@logixjs/query/Engine")() {
|
|
86
|
+
};
|
|
87
|
+
var Engine = Object.assign(EngineTagImpl, {
|
|
88
|
+
layer: (engine) => import_effect2.Layer.succeed(EngineTagImpl, engine),
|
|
89
|
+
middleware: (config) => middleware(config)
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// src/internal/logics/auto-trigger.ts
|
|
93
|
+
var defaultTriggers = ["onMount", "onKeyChange"];
|
|
94
|
+
var getTriggers = (triggers) => triggers ?? defaultTriggers;
|
|
95
|
+
var isManualOnly = (triggers) => triggers.length === 1 && triggers[0] === "manual";
|
|
96
|
+
var getSnapshotKeyHash = (snapshot) => {
|
|
97
|
+
if (!snapshot || typeof snapshot !== "object") return void 0;
|
|
98
|
+
const keyHash = snapshot.keyHash;
|
|
99
|
+
return typeof keyHash === "string" ? keyHash : void 0;
|
|
100
|
+
};
|
|
101
|
+
var getSnapshotStatus = (snapshot) => {
|
|
102
|
+
if (!snapshot || typeof snapshot !== "object") return void 0;
|
|
103
|
+
const status = snapshot.status;
|
|
104
|
+
return typeof status === "string" ? status : void 0;
|
|
105
|
+
};
|
|
106
|
+
var autoTrigger = (module2, config) => module2.logic(($) => {
|
|
107
|
+
const pending = /* @__PURE__ */ new Map();
|
|
108
|
+
const lastKeyHash = /* @__PURE__ */ new Map();
|
|
109
|
+
const hydrateFromFreshCache = (name, q, keyHash) => import_effect3.Effect.gen(function* () {
|
|
110
|
+
const engineOpt = yield* import_effect3.Effect.serviceOption(Engine);
|
|
111
|
+
if (engineOpt._tag === "None") return false;
|
|
112
|
+
const engine = engineOpt.value;
|
|
113
|
+
if (!engine.peekFresh) return false;
|
|
114
|
+
const dataOpt = yield* engine.peekFresh({
|
|
115
|
+
resourceId: q.resource.id,
|
|
116
|
+
keyHash
|
|
117
|
+
});
|
|
118
|
+
if (dataOpt._tag === "None") return false;
|
|
119
|
+
const snapshot = Logix.Resource.Snapshot.success({
|
|
120
|
+
keyHash,
|
|
121
|
+
data: dataOpt.value
|
|
122
|
+
});
|
|
123
|
+
yield* $.state.mutate((draft) => {
|
|
124
|
+
;
|
|
125
|
+
draft.queries[name] = snapshot;
|
|
126
|
+
});
|
|
127
|
+
return true;
|
|
128
|
+
});
|
|
129
|
+
const cancelPending = (name) => import_effect3.Effect.gen(function* () {
|
|
130
|
+
const prev = pending.get(name);
|
|
131
|
+
if (!prev) return;
|
|
132
|
+
pending.delete(name);
|
|
133
|
+
yield* import_effect3.Fiber.interruptFork(prev);
|
|
134
|
+
});
|
|
135
|
+
const sourcePathOf = (name) => `queries.${name}`;
|
|
136
|
+
const refresh = (name, options) => $.traits.source.refresh(sourcePathOf(name), options);
|
|
137
|
+
const scheduleDebounced = (name, ms) => import_effect3.Effect.gen(function* () {
|
|
138
|
+
yield* cancelPending(name);
|
|
139
|
+
const fiber = yield* import_effect3.Effect.forkScoped(
|
|
140
|
+
import_effect3.Effect.sleep(import_effect3.Duration.millis(ms)).pipe(
|
|
141
|
+
import_effect3.Effect.zipRight(refresh(name)),
|
|
142
|
+
import_effect3.Effect.ensuring(import_effect3.Effect.sync(() => pending.delete(name))),
|
|
143
|
+
import_effect3.Effect.catchAllCause(() => import_effect3.Effect.void)
|
|
144
|
+
)
|
|
145
|
+
);
|
|
146
|
+
pending.set(name, fiber);
|
|
147
|
+
});
|
|
148
|
+
const computeKeyHash = (state, q) => {
|
|
149
|
+
const getAtPath = (root, path) => {
|
|
150
|
+
const parts = path.split(".");
|
|
151
|
+
let cur = root;
|
|
152
|
+
for (const p of parts) {
|
|
153
|
+
if (cur == null) return void 0;
|
|
154
|
+
cur = cur[p];
|
|
155
|
+
}
|
|
156
|
+
return cur;
|
|
157
|
+
};
|
|
158
|
+
try {
|
|
159
|
+
const keyState = { params: state.params, ui: state.ui };
|
|
160
|
+
const args = q.deps.map((dep) => getAtPath(keyState, dep));
|
|
161
|
+
const key = q.key(...args);
|
|
162
|
+
if (key === void 0) return void 0;
|
|
163
|
+
return Logix.Resource.keyHash(key);
|
|
164
|
+
} catch {
|
|
165
|
+
return void 0;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
const maybeAutoRefresh = (phase, stateOverride) => import_effect3.Effect.gen(function* () {
|
|
169
|
+
const state = stateOverride ?? (yield* $.state.read);
|
|
170
|
+
for (const [name, q] of Object.entries(config.queries)) {
|
|
171
|
+
const queryName = name;
|
|
172
|
+
const triggers = getTriggers(q.triggers);
|
|
173
|
+
if (isManualOnly(triggers)) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (phase === "mount" && !triggers.includes("onMount")) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (phase === "keyChange" && !triggers.includes("onKeyChange")) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const keyHash = computeKeyHash(state, q);
|
|
183
|
+
const snapshot = state?.queries?.[queryName];
|
|
184
|
+
const snapshotKeyHash = getSnapshotKeyHash(snapshot);
|
|
185
|
+
const snapshotStatus = getSnapshotStatus(snapshot);
|
|
186
|
+
if (keyHash === void 0) {
|
|
187
|
+
lastKeyHash.set(queryName, void 0);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const last = lastKeyHash.get(queryName);
|
|
191
|
+
if (snapshotStatus && snapshotStatus !== "idle" && snapshotKeyHash === keyHash && last === keyHash) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (snapshotStatus && snapshotStatus !== "idle" && snapshotKeyHash === keyHash) {
|
|
195
|
+
lastKeyHash.set(queryName, keyHash);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
lastKeyHash.set(queryName, keyHash);
|
|
199
|
+
const hydrated = yield* hydrateFromFreshCache(queryName, q, keyHash);
|
|
200
|
+
if (hydrated) {
|
|
201
|
+
yield* cancelPending(queryName);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const debounceMs = q.debounceMs ?? 0;
|
|
205
|
+
if (phase === "keyChange" && debounceMs > 0) {
|
|
206
|
+
yield* scheduleDebounced(queryName, debounceMs);
|
|
207
|
+
} else {
|
|
208
|
+
yield* cancelPending(queryName);
|
|
209
|
+
yield* refresh(queryName);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
const refreshAll = (options) => import_effect3.Effect.forEach(
|
|
214
|
+
Object.keys(config.queries),
|
|
215
|
+
(name) => cancelPending(name).pipe(import_effect3.Effect.zipRight(refresh(name, options)))
|
|
216
|
+
).pipe(import_effect3.Effect.asVoid);
|
|
217
|
+
const setup = $.lifecycle.onStart(maybeAutoRefresh("mount"));
|
|
218
|
+
const run = import_effect3.Effect.suspend(
|
|
219
|
+
() => import_effect3.Effect.all(
|
|
220
|
+
[
|
|
221
|
+
// params/ui changes: handled by Query's default logic, avoiding scattered UI-side useEffect triggers.
|
|
222
|
+
$.onAction("setParams").runFork(
|
|
223
|
+
(action) => import_effect3.Effect.gen(function* () {
|
|
224
|
+
const state = yield* $.state.read;
|
|
225
|
+
const next = { ...state, params: action.payload };
|
|
226
|
+
yield* maybeAutoRefresh("keyChange", next);
|
|
227
|
+
})
|
|
228
|
+
),
|
|
229
|
+
$.onAction("setUi").runFork(
|
|
230
|
+
(action) => import_effect3.Effect.gen(function* () {
|
|
231
|
+
const state = yield* $.state.read;
|
|
232
|
+
const next = { ...state, ui: action.payload };
|
|
233
|
+
yield* maybeAutoRefresh("keyChange", next);
|
|
234
|
+
})
|
|
235
|
+
),
|
|
236
|
+
// Manual refresh: not restricted by triggers (manual-only still allows explicit refresh).
|
|
237
|
+
$.onAction("refresh").runFork(
|
|
238
|
+
(action) => import_effect3.Effect.gen(function* () {
|
|
239
|
+
const target = action.payload;
|
|
240
|
+
if (typeof target === "string" && target.length > 0) {
|
|
241
|
+
yield* cancelPending(target);
|
|
242
|
+
yield* refresh(target, { force: true });
|
|
243
|
+
} else {
|
|
244
|
+
yield* refreshAll({ force: true });
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
)
|
|
248
|
+
],
|
|
249
|
+
{ concurrency: "unbounded" }
|
|
250
|
+
).pipe(import_effect3.Effect.asVoid)
|
|
251
|
+
);
|
|
252
|
+
return { setup, run };
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// src/internal/logics/invalidate.ts
|
|
256
|
+
var Logix2 = __toESM(require("@logixjs/core"), 1);
|
|
257
|
+
var import_effect4 = require("effect");
|
|
258
|
+
var toInvalidateTargets = (request, queries) => {
|
|
259
|
+
if (request.kind === "byResource") {
|
|
260
|
+
return Object.entries(queries).filter(([, q]) => q.resource.id === request.resourceId).map(([name, q]) => ({ name, resourceId: q.resource.id }));
|
|
261
|
+
}
|
|
262
|
+
if (request.kind === "byParams") {
|
|
263
|
+
return Object.entries(queries).filter(([, q]) => q.resource.id === request.resourceId).map(([name, q]) => ({ name, resourceId: q.resource.id }));
|
|
264
|
+
}
|
|
265
|
+
const entries = Object.entries(queries);
|
|
266
|
+
const tagged = entries.filter(([, q]) => Array.isArray(q.tags) && q.tags.includes(request.tag));
|
|
267
|
+
const selected = tagged.length > 0 ? tagged : entries;
|
|
268
|
+
return selected.map(([name, q]) => ({ name, resourceId: q.resource.id }));
|
|
269
|
+
};
|
|
270
|
+
var invalidate = (module2, config) => module2.logic(
|
|
271
|
+
($) => import_effect4.Effect.gen(function* () {
|
|
272
|
+
yield* $.onAction("invalidate").runFork(
|
|
273
|
+
(action) => import_effect4.Effect.gen(function* () {
|
|
274
|
+
const request = action.payload;
|
|
275
|
+
yield* Logix2.TraitLifecycle.scopedExecute($, {
|
|
276
|
+
kind: "query:invalidate",
|
|
277
|
+
request
|
|
278
|
+
});
|
|
279
|
+
const engineOpt = yield* import_effect4.Effect.serviceOption(Engine);
|
|
280
|
+
if (engineOpt._tag !== "None") {
|
|
281
|
+
yield* engineOpt.value.invalidate(request);
|
|
282
|
+
}
|
|
283
|
+
const targets = toInvalidateTargets(request, config.queries);
|
|
284
|
+
const sourcePathOf = (name) => `queries.${name}`;
|
|
285
|
+
yield* import_effect4.Effect.forEach(
|
|
286
|
+
targets,
|
|
287
|
+
(t) => $.traits.source.refresh(sourcePathOf(t.name), { force: true })
|
|
288
|
+
).pipe(import_effect4.Effect.asVoid);
|
|
289
|
+
})
|
|
290
|
+
);
|
|
291
|
+
})
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
// src/Traits.ts
|
|
295
|
+
var Logix3 = __toESM(require("@logixjs/core"), 1);
|
|
296
|
+
var toStateTraitSpec = (input) => {
|
|
297
|
+
const out = {};
|
|
298
|
+
for (const [name, q] of Object.entries(input.queries)) {
|
|
299
|
+
const triggers = q.triggers ?? ["onMount", "onKeyChange"];
|
|
300
|
+
if (triggers.includes("manual") && triggers.length > 1) {
|
|
301
|
+
throw new Error(
|
|
302
|
+
`[Query.traits] "manual" must be exclusive, but got triggers=[${triggers.join(", ")}] for query "${name}".`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
out[`queries.${name}`] = Logix3.StateTrait.source({
|
|
306
|
+
// deps: used for graph building/diagnostics/future reverse-closure; Query also reuses deps to converge triggers.
|
|
307
|
+
deps: q.deps,
|
|
308
|
+
resource: q.resource.id,
|
|
309
|
+
triggers,
|
|
310
|
+
debounceMs: q.debounceMs,
|
|
311
|
+
concurrency: q.concurrency === "exhaust" ? "exhaust-trailing" : q.concurrency,
|
|
312
|
+
key: (...depsValues) => q.key(...depsValues)
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
return out;
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
// src/Query.ts
|
|
319
|
+
var InvalidateRequestSchema = import_effect5.Schema.Union(
|
|
320
|
+
import_effect5.Schema.Struct({
|
|
321
|
+
kind: import_effect5.Schema.Literal("byResource"),
|
|
322
|
+
resourceId: import_effect5.Schema.String
|
|
323
|
+
}),
|
|
324
|
+
import_effect5.Schema.Struct({
|
|
325
|
+
kind: import_effect5.Schema.Literal("byParams"),
|
|
326
|
+
resourceId: import_effect5.Schema.String,
|
|
327
|
+
keyHash: import_effect5.Schema.String
|
|
328
|
+
}),
|
|
329
|
+
import_effect5.Schema.Struct({
|
|
330
|
+
kind: import_effect5.Schema.Literal("byTag"),
|
|
331
|
+
tag: import_effect5.Schema.String
|
|
332
|
+
})
|
|
333
|
+
);
|
|
334
|
+
var assertQueryName = (name) => {
|
|
335
|
+
if (!name) {
|
|
336
|
+
throw new Error(`[Query.make] query name must be non-empty`);
|
|
337
|
+
}
|
|
338
|
+
if (name.includes(".")) {
|
|
339
|
+
throw new Error(`[Query.make] query name must not include "."; got "${name}"`);
|
|
340
|
+
}
|
|
341
|
+
if (name === "params" || name === "ui" || name === "queries") {
|
|
342
|
+
throw new Error(`[Query.make] query name "${name}" is reserved`);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
var make = (id, config) => {
|
|
346
|
+
const queryBuilder = {
|
|
347
|
+
source: (q) => q
|
|
348
|
+
};
|
|
349
|
+
const queries = (() => {
|
|
350
|
+
const raw = config.queries;
|
|
351
|
+
if (!raw) return {};
|
|
352
|
+
return raw(queryBuilder);
|
|
353
|
+
})();
|
|
354
|
+
const queriesForTraits = queries;
|
|
355
|
+
for (const name of Object.keys(queries)) {
|
|
356
|
+
assertQueryName(name);
|
|
357
|
+
}
|
|
358
|
+
const RefreshTargetSchema = (() => {
|
|
359
|
+
const names = Object.keys(queries);
|
|
360
|
+
if (names.length === 0) return import_effect5.Schema.Never;
|
|
361
|
+
if (names.length === 1) {
|
|
362
|
+
return import_effect5.Schema.Literal(names[0]);
|
|
363
|
+
}
|
|
364
|
+
const asUnionMembers = (items) => {
|
|
365
|
+
if (items.length < 2) {
|
|
366
|
+
throw new Error(`[Query.make] internal error: expected at least 2 query names for union`);
|
|
367
|
+
}
|
|
368
|
+
return items;
|
|
369
|
+
};
|
|
370
|
+
const members = names.map((n) => import_effect5.Schema.Literal(n));
|
|
371
|
+
return import_effect5.Schema.Union(...asUnionMembers(members));
|
|
372
|
+
})();
|
|
373
|
+
const UiSchema = import_effect5.Schema.Unknown;
|
|
374
|
+
const QueriesSchema = import_effect5.Schema.Struct(
|
|
375
|
+
Object.fromEntries(Object.keys(queries).map((k) => [k, import_effect5.Schema.Unknown]))
|
|
376
|
+
);
|
|
377
|
+
const StateSchema = import_effect5.Schema.Struct({
|
|
378
|
+
params: config.params,
|
|
379
|
+
ui: UiSchema,
|
|
380
|
+
queries: QueriesSchema
|
|
381
|
+
});
|
|
382
|
+
const Actions = {
|
|
383
|
+
setParams: config.params,
|
|
384
|
+
setUi: UiSchema,
|
|
385
|
+
refresh: import_effect5.Schema.UndefinedOr(RefreshTargetSchema),
|
|
386
|
+
invalidate: InvalidateRequestSchema
|
|
387
|
+
};
|
|
388
|
+
const reducers = {
|
|
389
|
+
setParams: (state, action, sink) => {
|
|
390
|
+
sink?.("params");
|
|
391
|
+
return { ...state, params: action.payload ?? state.params };
|
|
392
|
+
},
|
|
393
|
+
setUi: (state, action, sink) => {
|
|
394
|
+
sink?.("ui");
|
|
395
|
+
return { ...state, ui: action.payload ?? state.ui };
|
|
396
|
+
},
|
|
397
|
+
refresh: (state) => state,
|
|
398
|
+
invalidate: (state) => state
|
|
399
|
+
};
|
|
400
|
+
const queryTraits = Object.keys(queriesForTraits).length > 0 ? toStateTraitSpec({ queries: queriesForTraits }) : void 0;
|
|
401
|
+
const traits = queryTraits || config.traits ? {
|
|
402
|
+
...queryTraits,
|
|
403
|
+
...config.traits
|
|
404
|
+
} : void 0;
|
|
405
|
+
const module2 = Logix4.Module.make(id, {
|
|
406
|
+
state: StateSchema,
|
|
407
|
+
actions: Actions,
|
|
408
|
+
reducers,
|
|
409
|
+
traits
|
|
410
|
+
});
|
|
411
|
+
const logics = [
|
|
412
|
+
autoTrigger(module2.tag, { queries: queriesForTraits }),
|
|
413
|
+
invalidate(module2.tag, { queries: queriesForTraits })
|
|
414
|
+
];
|
|
415
|
+
const initial = (params) => ({
|
|
416
|
+
params: params ?? config.initialParams,
|
|
417
|
+
ui: config.ui ?? {},
|
|
418
|
+
queries: Object.fromEntries(
|
|
419
|
+
Object.keys(queries).map((k) => [k, Logix4.Resource.Snapshot.idle()])
|
|
420
|
+
)
|
|
421
|
+
});
|
|
422
|
+
const controller = {
|
|
423
|
+
make: (runtime) => {
|
|
424
|
+
const dispatch = runtime.dispatch;
|
|
425
|
+
const actions = module2.actions;
|
|
426
|
+
return {
|
|
427
|
+
runtime,
|
|
428
|
+
getState: runtime.getState,
|
|
429
|
+
dispatch,
|
|
430
|
+
controller: {
|
|
431
|
+
setParams: (params) => dispatch(actions.setParams(params)),
|
|
432
|
+
setUi: (ui) => dispatch(actions.setUi(ui)),
|
|
433
|
+
refresh: (target) => dispatch(actions.refresh(target)),
|
|
434
|
+
invalidate: (request) => dispatch(actions.invalidate(request))
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
module2.controller = controller;
|
|
440
|
+
const EXTEND_HANDLE = /* @__PURE__ */ Symbol.for("logix.module.handle.extend");
|
|
441
|
+
module2.tag[EXTEND_HANDLE] = (runtime, base) => {
|
|
442
|
+
const c = controller.make(runtime);
|
|
443
|
+
return {
|
|
444
|
+
...base,
|
|
445
|
+
controller: c.controller
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
return module2.implement({
|
|
449
|
+
initial: initial(),
|
|
450
|
+
logics: [...logics]
|
|
451
|
+
});
|
|
452
|
+
};
|
|
453
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
454
|
+
0 && (module.exports = {
|
|
455
|
+
make
|
|
456
|
+
});
|
|
457
|
+
//# sourceMappingURL=Query.cjs.map
|