@voltro/testing 0.86.0 → 0.88.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/CHANGELOG.md +5484 -0
- package/README.md +11 -0
- package/THIRD-PARTY-NOTICES.md +1511 -276
- package/dist/client.d.ts +5 -0
- package/dist/client.js +70 -58
- package/dist/crdt.js +1 -2
- package/dist/dialect.d.ts +20 -0
- package/dist/dialect.js +992 -694
- package/dist/factory.js +1 -2
- package/dist/fieldKeys.js +72 -0
- package/dist/fieldKeysSql.js +13 -0
- package/dist/fixtureRow.js +1 -2
- package/dist/formBindingHarness.js +1 -2
- package/dist/hotStoreSqlParity.js +135 -0
- package/dist/hydrateFixtureRows.js +1 -2
- package/dist/index.d.ts +119 -1
- package/dist/index.js +18 -16
- package/dist/invoke.js +77 -40
- package/dist/mockClock.js +1 -2
- package/dist/mockLLM.js +1 -2
- package/dist/mockWebhooks.js +1 -2
- package/dist/platform.js +1 -2
- package/dist/reachable.js +1 -2
- package/dist/serviceApiMock.js +1 -2
- package/dist/subject.js +1 -2
- package/dist/subscribeContext.js +1 -2
- package/dist/system.d.ts +99 -0
- package/dist/system.js +93 -0
- package/dist/testApps.js +1 -2
- package/dist/testContext.js +133 -113
- package/dist/testEventBus.js +1 -2
- package/dist/testRequest.js +56 -55
- package/dist/withConnections.js +25 -0
- package/dist/workflowRunner.js +1 -2
- package/package.json +17 -10
package/dist/mockClock.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect as e } from "effect";
|
|
2
|
-
|
|
2
|
+
// src/mockClock.ts
|
|
3
3
|
var t = Symbol.for("voltro/testing/mockClock.installed"), n = () => globalThis, r = (e, t) => new Proxy(e, {
|
|
4
4
|
construct: (e, n, r) => Reflect.construct(e, n.length === 0 ? [t()] : n, r),
|
|
5
5
|
apply: () => new e(t()).toString(),
|
|
@@ -74,5 +74,4 @@ var t = Symbol.for("voltro/testing/mockClock.installed"), n = () => globalThis,
|
|
|
74
74
|
default: throw Error(`mockClock: unknown unit '${r}'`);
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
|
-
//#endregion
|
|
78
77
|
export { a as MockClock, c as frozenTime, s as withFrozenTime };
|
package/dist/mockLLM.js
CHANGED
package/dist/mockWebhooks.js
CHANGED
package/dist/platform.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe as e, expect as t, it as n } from "vitest";
|
|
2
|
-
|
|
2
|
+
// src/platformConformance.ts
|
|
3
3
|
var r = (r, i) => {
|
|
4
4
|
let a = i.scratchKey ?? "voltro:conformance", o = async () => i.adapter();
|
|
5
5
|
e(`platform adapter conformance — ${r}`, () => {
|
|
@@ -38,5 +38,4 @@ var r = (r, i) => {
|
|
|
38
38
|
});
|
|
39
39
|
});
|
|
40
40
|
};
|
|
41
|
-
//#endregion
|
|
42
41
|
export { r as platformAdapterConformance };
|
package/dist/reachable.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import e from "node:net";
|
|
2
2
|
import { describe as t } from "vitest";
|
|
3
|
-
|
|
3
|
+
// src/reachable.ts
|
|
4
4
|
var n = (t) => new Promise((n) => {
|
|
5
5
|
let r = new e.Socket(), i = (e) => {
|
|
6
6
|
clearTimeout(a), r.destroy(), n(e);
|
|
@@ -23,5 +23,4 @@ var n = (t) => new Promise((n) => {
|
|
|
23
23
|
n !== void 0 && n !== "" && console.log(`[engine] ${e}: ${n}`);
|
|
24
24
|
} catch {}
|
|
25
25
|
};
|
|
26
|
-
//#endregion
|
|
27
26
|
export { r as describeIfAvailable, i as describeIfReachable, n as isTcpReachable, a as reportEngineVersion };
|
package/dist/serviceApiMock.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect as e, Schema as t } from "effect";
|
|
2
2
|
import { ApiUnavailable as n } from "@voltro/protocol";
|
|
3
|
-
|
|
3
|
+
// src/serviceApiMock.ts
|
|
4
4
|
var r = (r, i, a = {}) => {
|
|
5
5
|
let o = a.name ?? "mock", s = [], c = /* @__PURE__ */ new Map(), l = (e, t) => `${e}\u0000${JSON.stringify(t)}`, u = async (e, a, c) => {
|
|
6
6
|
let l = r[e];
|
|
@@ -49,5 +49,4 @@ var r = (r, i, a = {}) => {
|
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
51
|
};
|
|
52
|
-
//#endregion
|
|
53
52
|
export { r as makeServiceApiMock };
|
package/dist/subject.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { anonymousSubject as e, systemSubject as t } from "@voltro/protocol";
|
|
2
|
-
|
|
2
|
+
// src/subject.ts
|
|
3
3
|
var n = "test-tenant", r = (e, t, n) => ({
|
|
4
4
|
type: e,
|
|
5
5
|
id: t,
|
|
@@ -7,5 +7,4 @@ var n = "test-tenant", r = (e, t, n) => ({
|
|
|
7
7
|
scopes: n.scopes ?? [],
|
|
8
8
|
...n.metadata === void 0 ? {} : { metadata: n.metadata }
|
|
9
9
|
}), i = (e, t = {}) => r("user", e, t), a = (e, t = {}) => r("apiKey", e, t), o = (e, t = {}) => r("serviceAccount", e, t), s = (t = null) => e(t), c = (e = "job:test", n) => n === void 0 ? t(e) : t(e, n);
|
|
10
|
-
//#endregion
|
|
11
10
|
export { n as TEST_TENANT_ID, s as anonymous, a as apiKey, o as serviceAccount, c as system, i as user };
|
package/dist/subscribeContext.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { changeDelete as e, changeInsert as t, changeSoftDelete as n, changeUpdate as r } from "@voltro/database";
|
|
2
2
|
import { createLogger as i } from "@voltro/logger";
|
|
3
|
-
|
|
3
|
+
// src/subscribeContext.ts
|
|
4
4
|
var a = (e = {}) => {
|
|
5
5
|
let t = e.id ?? "test", n = e.store ?? new Proxy({}, { get: (e, t) => {
|
|
6
6
|
throw Error(`makeSubscribeContext: this subscriber reached ctx.store.${String(t)} and the test passed no store. Pass \`{ store: makeTestContext().store }\` so the subscriber and the code under test share one — an empty stand-in would let a read of the wrong table pass.`);
|
|
@@ -12,5 +12,4 @@ var a = (e = {}) => {
|
|
|
12
12
|
...e.publish === void 0 ? {} : { publish: e.publish }
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
|
-
//#endregion
|
|
16
15
|
export { e as changeDelete, t as changeInsert, n as changeSoftDelete, r as changeUpdate, a as makeSubscribeContext };
|
package/dist/system.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { AnyEventDescriptor } from '@voltro/protocol';
|
|
2
|
+
import { Context } from 'effect';
|
|
3
|
+
import { Effect } from 'effect';
|
|
4
|
+
import { Layer } from 'effect';
|
|
5
|
+
import { PluginInspectRequest } from '@voltro/protocol';
|
|
6
|
+
import { PluginInspectResponse } from '@voltro/protocol';
|
|
7
|
+
import { PluginPrivacyRequest } from '@voltro/protocol';
|
|
8
|
+
import { PluginPrivacyTarget } from '@voltro/protocol';
|
|
9
|
+
import { VoltroPlugin } from '@voltro/protocol';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Register the system contract against real exports and descriptor surfaces.
|
|
13
|
+
* Refuses incomplete inventories before registering any tests. This suite does
|
|
14
|
+
* not establish SQL parity, ordinary boot, four dashboard layers or capacity.
|
|
15
|
+
*/
|
|
16
|
+
export declare const systemContractConformance: (plugin: VoltroPlugin, options: SystemContractConformanceOptions) => void;
|
|
17
|
+
|
|
18
|
+
export declare interface SystemContractConformanceOptions {
|
|
19
|
+
readonly manifest: SystemContractManifest;
|
|
20
|
+
/** Actual module namespace imports, never copies of the system exports. */
|
|
21
|
+
readonly strategies: Readonly<Record<string, unknown>>;
|
|
22
|
+
readonly ports: Readonly<Record<string, unknown>>;
|
|
23
|
+
readonly testing: Readonly<Record<string, unknown>>;
|
|
24
|
+
/** Actual descriptors used by discovery/codegen. Hidden events are not inferred. */
|
|
25
|
+
readonly eventCatalog: ReadonlyArray<AnyEventDescriptor>;
|
|
26
|
+
readonly eventFixtures: Readonly<Record<string, SystemEventFixture>>;
|
|
27
|
+
readonly stages: Readonly<Record<'take' | 'configure' | 'hook' | 'override' | 'extendOrReplace', SystemContractProbe>>;
|
|
28
|
+
readonly privacy: Readonly<Record<string, (kind: PluginPrivacyTarget['kind']) => Effect.Effect<SystemPrivacyFixture, unknown>>>;
|
|
29
|
+
/** Exactly one case per contributed endpoint, keyed as "GET path". */
|
|
30
|
+
readonly inspect: Readonly<Record<string, SystemInspectFixture>>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Export this inventory beside the system's public strategies and ports. */
|
|
34
|
+
export declare interface SystemContractManifest {
|
|
35
|
+
readonly slots: Readonly<Record<string, {
|
|
36
|
+
readonly defaultExport: string;
|
|
37
|
+
readonly fixtureExport: string;
|
|
38
|
+
}>>;
|
|
39
|
+
readonly ports: Readonly<Record<string, {
|
|
40
|
+
readonly tagExport: string;
|
|
41
|
+
readonly fakeLayerExport: string;
|
|
42
|
+
readonly fixtureExport: string;
|
|
43
|
+
}>>;
|
|
44
|
+
readonly events: ReadonlyArray<string>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** A measured observation. Use inputs that distinguish defaults from overrides. */
|
|
48
|
+
export declare interface SystemContractProbe {
|
|
49
|
+
readonly run: () => Effect.Effect<unknown, unknown>;
|
|
50
|
+
readonly expected: unknown;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export declare interface SystemEventFixture {
|
|
54
|
+
readonly descriptor: AnyEventDescriptor;
|
|
55
|
+
readonly key: unknown;
|
|
56
|
+
readonly payload: unknown;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export declare interface SystemInspectFixture {
|
|
60
|
+
readonly request: PluginInspectRequest;
|
|
61
|
+
readonly expected: PluginInspectResponse;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export declare interface SystemPortFixture {
|
|
65
|
+
readonly kind: 'port';
|
|
66
|
+
readonly tag: unknown;
|
|
67
|
+
readonly fakeLayer: unknown;
|
|
68
|
+
readonly probe: SystemContractProbe;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Preserve concrete Tag/Layer types; the suite owns scope acquisition and cleanup. */
|
|
72
|
+
export declare const systemPortFixture: <Identifier, Service>(options: {
|
|
73
|
+
readonly tag: Context.Service<Identifier, Service>;
|
|
74
|
+
readonly fakeLayer: Layer.Layer<Identifier>;
|
|
75
|
+
readonly read: Effect.Effect<unknown, unknown, Identifier>;
|
|
76
|
+
readonly expected: unknown;
|
|
77
|
+
}) => SystemPortFixture;
|
|
78
|
+
|
|
79
|
+
/** A fresh, seeded fixture; read() must include peer/tenant rows that must survive. */
|
|
80
|
+
export declare interface SystemPrivacyFixture {
|
|
81
|
+
/** Explicitly reviewed tenant-wide table without subject facts; erase retains every row. */
|
|
82
|
+
readonly subjectData?: 'none';
|
|
83
|
+
readonly request: PluginPrivacyRequest;
|
|
84
|
+
readonly read: () => Effect.Effect<ReadonlyArray<unknown>, unknown>;
|
|
85
|
+
readonly before: ReadonlyArray<unknown>;
|
|
86
|
+
readonly after: ReadonlyArray<unknown>;
|
|
87
|
+
readonly exported: unknown;
|
|
88
|
+
readonly close: Effect.Effect<void>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** A ./testing export that exercises the imported default and configured override. */
|
|
92
|
+
export declare interface SystemSlotFixture {
|
|
93
|
+
readonly kind: 'slot';
|
|
94
|
+
readonly defaultImplementation: unknown;
|
|
95
|
+
readonly defaultProbe: SystemContractProbe;
|
|
96
|
+
readonly overrideProbe: SystemContractProbe;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { }
|
package/dist/system.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { testEventBus as e } from "./testEventBus.js";
|
|
2
|
+
import { Context as t, Effect as n, Layer as r } from "effect";
|
|
3
|
+
import { createPluginPrivacyRegistry as i } from "@voltro/protocol";
|
|
4
|
+
import { describe as a, expect as o, it as s } from "vitest";
|
|
5
|
+
// src/systemContractConformance.ts
|
|
6
|
+
var c = (e) => ({
|
|
7
|
+
kind: "port",
|
|
8
|
+
tag: e.tag,
|
|
9
|
+
fakeLayer: e.fakeLayer,
|
|
10
|
+
probe: {
|
|
11
|
+
run: () => n.scoped(e.read.pipe(n.provide(e.fakeLayer))),
|
|
12
|
+
expected: e.expected
|
|
13
|
+
}
|
|
14
|
+
}), l = (e, t) => {
|
|
15
|
+
if (e.some((e) => !e.trim()) || new Set(e).size !== e.length) throw Error(`Invalid system ${t} inventory`);
|
|
16
|
+
}, u = (e, t, n) => {
|
|
17
|
+
if (l(e, n), l(t, n), JSON.stringify([...e].sort()) !== JSON.stringify([...t].sort())) throw Error(`Incomplete system ${n} fixtures`);
|
|
18
|
+
}, d = (e) => typeof e == "object" && !!e, f = (e) => d(e) && typeof e.run == "function" && e.expected !== void 0, p = (e) => d(e) && e.kind === "slot" && typeof e.defaultImplementation == "function" && f(e.defaultProbe) && f(e.overrideProbe), m = (e) => d(e) && e.kind === "port" && t.isKey(e.tag) && r.isLayer(e.fakeLayer) && f(e.probe), h = (e, t) => `${e} ${t.replace(/^\//, "")}`, g = (t, r) => {
|
|
19
|
+
let { manifest: c } = r, g = t.services !== void 0 || (t.routes?.length ?? 0) > 0 || (t.extendSchema?.tables?.length ?? 0) > 0 || (t.inspectEndpoints?.length ?? 0) > 0 || t.onActivate !== void 0 || t.interceptMutation !== void 0;
|
|
20
|
+
if (!t.name.trim() || !g || Object.keys(c.slots).length === 0) throw Error("System conformance requires an implemented system with strategy slots");
|
|
21
|
+
let _ = (t.extendSchema?.tables ?? []).map((e) => {
|
|
22
|
+
if (!d(e) || typeof e.tableName != "string") throw Error("System conformance requires named table descriptors");
|
|
23
|
+
return e.tableName;
|
|
24
|
+
});
|
|
25
|
+
u(Object.keys(r.stages), [
|
|
26
|
+
"take",
|
|
27
|
+
"configure",
|
|
28
|
+
"hook",
|
|
29
|
+
"override",
|
|
30
|
+
"extendOrReplace"
|
|
31
|
+
], "stages");
|
|
32
|
+
for (let e of Object.values(r.stages)) if (!f(e)) throw Error("System stages require measured probes");
|
|
33
|
+
u(Object.keys(r.privacy), _, "privacy"), u(r.eventCatalog.map((e) => e.name), c.events, "events"), u(Object.keys(r.eventFixtures), c.events, "events");
|
|
34
|
+
let v = t.inspectEndpoints ?? [];
|
|
35
|
+
u(Object.keys(r.inspect), v.map((e) => h(e.method, e.path)), "inspect");
|
|
36
|
+
let y = Object.entries(c.slots).map(([e, t]) => {
|
|
37
|
+
l([e], "slots");
|
|
38
|
+
let n = r.strategies[t.defaultExport], i = r.testing[t.fixtureExport];
|
|
39
|
+
if (typeof n != "function" || !p(i) || i.defaultImplementation !== n) throw Error(`System slot requires its actual default export and fixture: ${e}`);
|
|
40
|
+
return {
|
|
41
|
+
name: e,
|
|
42
|
+
fixture: i
|
|
43
|
+
};
|
|
44
|
+
}), b = Object.entries(c.ports).map(([e, t]) => {
|
|
45
|
+
l([e], "ports");
|
|
46
|
+
let n = r.testing[t.fixtureExport];
|
|
47
|
+
if (!m(n) || n.tag !== r.ports[t.tagExport] || n.fakeLayer !== r.testing[t.fakeLayerExport]) throw Error(`System port requires its actual Tag, fake Layer and fixture: ${e}`);
|
|
48
|
+
return {
|
|
49
|
+
name: e,
|
|
50
|
+
fixture: n
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
for (let e of r.eventCatalog) if (e.kind !== "event" || r.eventFixtures[e.name]?.descriptor !== e) throw Error(`System event requires its actual catalog descriptor: ${e.name}`);
|
|
54
|
+
for (let e of v) {
|
|
55
|
+
let t = r.inspect[h(e.method, e.path)];
|
|
56
|
+
if (t.request.method !== e.method || t.expected.kind !== "json" || (t.expected.status ?? 200) !== 200 || t.expected.data === void 0) throw Error("System inspect fixture must observe successful JSON");
|
|
57
|
+
}
|
|
58
|
+
let x = i([t]);
|
|
59
|
+
if (_.length > 0 && (!t.subjectPrivacy || x.coverage("user").missing.length > 0 || x.coverage("guest").missing.length > 0 || !t.subjectPrivacy.kinds.includes("user") || !t.subjectPrivacy.kinds.includes("guest"))) throw Error("System tables require user and guest erase/export coverage");
|
|
60
|
+
let S = async (e) => {
|
|
61
|
+
o(await n.runPromise(n.suspend(e.run))).toEqual(e.expected);
|
|
62
|
+
};
|
|
63
|
+
a(`system contract — ${t.name}`, () => {
|
|
64
|
+
for (let [e, t] of Object.entries(r.stages)) s(`stage ${e}`, () => S(t));
|
|
65
|
+
for (let { name: e, fixture: t } of y) s(`slot ${e}: exported default and configured override`, async () => {
|
|
66
|
+
o(t.overrideProbe.expected).not.toEqual(t.defaultProbe.expected), await S(t.defaultProbe), await S(t.overrideProbe);
|
|
67
|
+
});
|
|
68
|
+
for (let { name: e, fixture: t } of b) s(`port ${e}: scoped fake Layer`, () => S(t.probe));
|
|
69
|
+
for (let t of r.eventCatalog) s(`event ${t.name}: real validation and delivery`, async () => {
|
|
70
|
+
let n = r.eventFixtures[t.name], i = e(), a = i.subscribe(t, n.key);
|
|
71
|
+
try {
|
|
72
|
+
await i.publish(t, n.key, n.payload), o(a.received).toEqual([n.payload]), o(a.missedCount).toBe(0);
|
|
73
|
+
} finally {
|
|
74
|
+
a.stop(), i.reset();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
for (let e of _) for (let i of ["user", "guest"]) s(`table ${e}: ${i} export, erase, peers and idempotent retry`, () => n.runPromise(n.acquireUseRelease(r.privacy[e](i), (e) => n.gen(function* () {
|
|
78
|
+
o(e.request.target.kind).toBe(i), o(e.before.length).toBeGreaterThan(0), e.subjectData === "none" ? o(e.before).toEqual(e.after) : o(e.before).not.toEqual(e.after), o(yield* e.read()).toEqual(e.before);
|
|
79
|
+
let n = yield* x.exportSubject(e.request);
|
|
80
|
+
o(n.plugins).toEqual([{
|
|
81
|
+
name: t.name,
|
|
82
|
+
data: e.exported
|
|
83
|
+
}]);
|
|
84
|
+
let r = yield* x.eraseSubject(e.request);
|
|
85
|
+
o(r.completed).toEqual([t.name]), o(yield* e.read()).toEqual(e.after), yield* x.eraseSubject(e.request), o(yield* e.read()).toEqual(e.after);
|
|
86
|
+
}), (e) => e.close)));
|
|
87
|
+
for (let e of v) s(`inspect ${h(e.method, e.path)}: actual handler`, async () => {
|
|
88
|
+
let t = r.inspect[h(e.method, e.path)];
|
|
89
|
+
o(await n.runPromise(n.suspend(() => e.handler(t.request)))).toEqual(t.expected);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
export { g as systemContractConformance, c as systemPortFixture };
|
package/dist/testApps.js
CHANGED
|
@@ -4,7 +4,7 @@ import { randomBytes as a } from "node:crypto";
|
|
|
4
4
|
import { spawn as o } from "node:child_process";
|
|
5
5
|
import { createRequire as s } from "node:module";
|
|
6
6
|
import { dirname as c, join as l } from "node:path";
|
|
7
|
-
|
|
7
|
+
// src/testApps.ts
|
|
8
8
|
var u = () => new Promise((e, t) => {
|
|
9
9
|
let n = i.createServer();
|
|
10
10
|
n.once("error", t), n.listen(0, "127.0.0.1", () => {
|
|
@@ -107,5 +107,4 @@ var u = () => new Promise((e, t) => {
|
|
|
107
107
|
stop: C
|
|
108
108
|
};
|
|
109
109
|
};
|
|
110
|
-
//#endregion
|
|
111
110
|
export { h as startTestApps };
|
package/dist/testContext.js
CHANGED
|
@@ -1,48 +1,50 @@
|
|
|
1
1
|
import { MockClock as e } from "./mockClock.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
import { recordTestRawStore as t, registerTestFieldKeys as n } from "./fieldKeys.js";
|
|
3
|
+
import { MockWebhooks as r } from "./mockWebhooks.js";
|
|
4
|
+
import { testEventBus as i } from "./testEventBus.js";
|
|
5
|
+
import { MockLLM as a } from "./mockLLM.js";
|
|
6
|
+
import { allRegisteredTables as o, clearRelationsRegistry as s, registerRelations as c } from "@voltro/database";
|
|
7
|
+
import { Effect as l, Layer as u } from "effect";
|
|
8
|
+
import { anonymousSubject as d, composeRpcInterceptors as f, tenantScopedSubject as p } from "@voltro/protocol";
|
|
9
|
+
import { InMemoryDataStore as m, NO_ROW_FILTER as h, appValidation as g, applyRowFilterToDescriptor as _, clearSystemStoreHandle as v, getRowFilter as y, getSystemStoreHandle as b, installComputedQueryCacheCapture as x, makeAppAccess as S, makeConnectionState as ee, makeDataLoader as te, makeEventPublisher as ne, makeFieldCipher as C, makeOutboxFacade as w, makeSchemaRegistry as T, queryCachePolicy as E, recordingStore as D, resolveRowFilterScopeFor as O, resolveTransactionSubject as k, runProvidedEffect as A, setFieldCipher as j, setSystemStoreHandle as M, wrapStoreWithMixinBehaviour as N } from "@voltro/runtime";
|
|
10
|
+
import { installEnvSnapshot as re } from "@voltro/env";
|
|
11
|
+
import { Cache as ie, layerMemory as ae } from "@voltro/cache";
|
|
12
|
+
// src/testContext.ts
|
|
13
|
+
var P = (e) => e, F = "00000000000000000000000000000000", I = /* @__PURE__ */ new WeakMap(), L = /* @__PURE__ */ new WeakMap(), R = (e, t) => {
|
|
14
|
+
let n = L.get(e);
|
|
13
15
|
if (n === void 0) throw Error("withRpcConnection requires a context created by makeTestContext");
|
|
14
16
|
return n(t);
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
+
}, z = /* @__PURE__ */ new WeakMap(), B = /* @__PURE__ */ new WeakMap(), V = /* @__PURE__ */ new WeakMap(), H = (e) => V.get(e) ?? [], U = /* @__PURE__ */ new WeakMap(), W = /* @__PURE__ */ new WeakMap(), G = (e) => W.get(e), K = (e, t, n) => {
|
|
18
|
+
U.set(e, {
|
|
17
19
|
publicApi: t,
|
|
18
20
|
...n === void 0 ? {} : { remoteAddr: n }
|
|
19
21
|
});
|
|
20
|
-
},
|
|
21
|
-
let n =
|
|
22
|
+
}, q = (e) => U.get(e), J = /* @__PURE__ */ new WeakMap(), oe = (e, t) => {
|
|
23
|
+
let n = V.get(e) ?? [], r = t === "mutation" ? "interceptMutation" : t === "query" ? "interceptQuery" : "interceptAction", i = [];
|
|
22
24
|
for (let e of n) {
|
|
23
25
|
let t = e[r];
|
|
24
26
|
typeof t == "function" && i.push(t);
|
|
25
27
|
}
|
|
26
|
-
return
|
|
27
|
-
},
|
|
28
|
-
let t = (
|
|
29
|
-
if (r.length !== 0) return
|
|
30
|
-
},
|
|
31
|
-
let t =
|
|
28
|
+
return f(i);
|
|
29
|
+
}, se = (e) => {
|
|
30
|
+
let t = (V.get(e) ?? []).map((e) => e.services).filter((e) => e !== void 0), n = J.get(e) ?? [], r = [...t, ...n];
|
|
31
|
+
if (r.length !== 0) return u.mergeAll(...r);
|
|
32
|
+
}, ce = (e) => {
|
|
33
|
+
let t = z.get(e);
|
|
32
34
|
t !== void 0 && (t.length = 0);
|
|
33
|
-
},
|
|
34
|
-
let t =
|
|
35
|
+
}, Y = async (e) => {
|
|
36
|
+
let t = z.get(e);
|
|
35
37
|
if (t === void 0 || t.length === 0) return;
|
|
36
38
|
let n = [...t];
|
|
37
39
|
t.length = 0;
|
|
38
40
|
for (let e of n) await e();
|
|
39
|
-
},
|
|
40
|
-
let n =
|
|
41
|
+
}, X = (e) => B.get(e) ?? [], Z = async (e, t) => {
|
|
42
|
+
let n = I.get(e);
|
|
41
43
|
return n === void 0 ? e.store.transactional(async (n) => t({
|
|
42
44
|
...e,
|
|
43
45
|
store: n
|
|
44
46
|
})) : n(t);
|
|
45
|
-
},
|
|
47
|
+
}, le = (e) => {
|
|
46
48
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map(), r = (n) => {
|
|
47
49
|
let r = t.get(n);
|
|
48
50
|
return r === void 0 ? !1 : r.expiresAt !== null && r.expiresAt <= e() ? (t.delete(n), !1) : !0;
|
|
@@ -81,7 +83,7 @@ var A = (e) => e, j = "00000000000000000000000000000000", M = /* @__PURE__ */ ne
|
|
|
81
83
|
return i(e, o, n.ttlMs, n.tags), o;
|
|
82
84
|
}
|
|
83
85
|
};
|
|
84
|
-
},
|
|
86
|
+
}, ue = (e) => {
|
|
85
87
|
let t = /* @__PURE__ */ new Map(), n = (n) => {
|
|
86
88
|
let r = t.get(n);
|
|
87
89
|
return r === void 0 ? !1 : r.expiresAt !== null && r.expiresAt <= e() ? (t.delete(n), !1) : !0;
|
|
@@ -109,140 +111,158 @@ var A = (e) => e, j = "00000000000000000000000000000000", M = /* @__PURE__ */ ne
|
|
|
109
111
|
t.clear();
|
|
110
112
|
}
|
|
111
113
|
};
|
|
112
|
-
},
|
|
113
|
-
let n =
|
|
114
|
-
|
|
114
|
+
}, de = async (e, t) => {
|
|
115
|
+
let n = b();
|
|
116
|
+
M(e);
|
|
115
117
|
try {
|
|
116
118
|
return await t();
|
|
117
119
|
} finally {
|
|
118
|
-
n === void 0 ?
|
|
120
|
+
n === void 0 ? v() : M(n);
|
|
119
121
|
}
|
|
120
|
-
}, Q = /* @__PURE__ */ new Set(),
|
|
122
|
+
}, Q = /* @__PURE__ */ new Set(), fe = (e) => {
|
|
121
123
|
Q.has(e) || (Q.add(e), console.warn(e));
|
|
122
|
-
},
|
|
123
|
-
let r =
|
|
124
|
+
}, pe = (e, t, n) => {
|
|
125
|
+
let r = me, i;
|
|
124
126
|
return () => {
|
|
125
|
-
let a = t ??
|
|
126
|
-
return t !== void 0 &&
|
|
127
|
+
let a = t ?? y();
|
|
128
|
+
return t !== void 0 && y() !== void 0 && t !== y() && fe("[voltro:testing] this test passes `rowFilter:` while a DIFFERENT filter is registered via `setRowFilter`. The option wins, so this test does not exercise your app's registration. Drop `rowFilter:` to run the real process-global one."), (i === void 0 || a !== r) && (r = a, i = de(n, () => A(O(a, e, (e) => {
|
|
127
129
|
console.error("[voltro:testing] row filter failed to load — reads refused for this subject", e);
|
|
128
130
|
})))), i;
|
|
129
131
|
};
|
|
130
|
-
},
|
|
131
|
-
if (n === "query") return async (n) => e.query(
|
|
132
|
+
}, me = Symbol("unresolved"), $ = (e, t) => new Proxy(e, { get: (e, n) => {
|
|
133
|
+
if (n === "query") return async (n) => e.query(_(await t(), n));
|
|
132
134
|
let r = Reflect.get(e, n, e);
|
|
133
135
|
return typeof r == "function" ? r.bind(e) : r;
|
|
134
|
-
} }),
|
|
135
|
-
if (
|
|
136
|
+
} }), he = (u = {}) => {
|
|
137
|
+
if (re({
|
|
136
138
|
...process.env,
|
|
137
|
-
...
|
|
138
|
-
}),
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
...u.env ?? {}
|
|
140
|
+
}), u.fieldEncryptionKey !== void 0 && u.fieldKeys !== void 0) throw Error("makeTestContext: pass `fieldEncryptionKey` or `fieldKeys`, not both — one is a keyring of one key");
|
|
141
|
+
if (u.fieldEncryptionKey !== void 0 && j(C(u.fieldEncryptionKey)), u.fieldKeys !== void 0 && n(u.fieldKeys), u.relations !== void 0) {
|
|
142
|
+
s();
|
|
143
|
+
for (let e of u.relations) c(e);
|
|
141
144
|
}
|
|
142
|
-
let
|
|
143
|
-
for (let e of
|
|
144
|
-
let
|
|
145
|
-
dataStore:
|
|
146
|
-
schemaRegistry:
|
|
145
|
+
let f = u.tables ?? o(), _ = T(f), v = new m(u.store ?? {});
|
|
146
|
+
for (let e of u.plugins ?? []) e.bindDataStore?.(v);
|
|
147
|
+
let y = {
|
|
148
|
+
dataStore: v,
|
|
149
|
+
schemaRegistry: _
|
|
147
150
|
};
|
|
148
|
-
|
|
149
|
-
let
|
|
150
|
-
|
|
151
|
+
M(y);
|
|
152
|
+
let b = new e(u.clockStart);
|
|
153
|
+
x();
|
|
154
|
+
let O = l.runSync(ie.make.pipe(l.provide(ae({ now: () => b.now() }))));
|
|
155
|
+
v.onChange((e) => {
|
|
156
|
+
l.runSync(O.invalidateTag(e.table).pipe(l.ignore));
|
|
157
|
+
});
|
|
158
|
+
let A = [], P = {
|
|
159
|
+
wrapDynamic: (e, t, n, r) => O.wrapDynamic(e, t, n, r),
|
|
160
|
+
policyFor: E,
|
|
161
|
+
codeIdentity: "test",
|
|
162
|
+
maxEntryBytes: 1048576,
|
|
163
|
+
notice: (e, t, n) => {
|
|
164
|
+
A.push(n);
|
|
165
|
+
}
|
|
166
|
+
}, R = new r(), H = i(), U = new a(u.llmResponses ?? []), G = le(() => b.now()), K = ue(() => b.now()), q = (e, n, r = v, i, a = !1) => {
|
|
167
|
+
let o = {
|
|
151
168
|
subject: e,
|
|
152
|
-
traceId:
|
|
153
|
-
...
|
|
154
|
-
},
|
|
155
|
-
bus:
|
|
169
|
+
traceId: F,
|
|
170
|
+
...n === void 0 ? {} : { connection: n }
|
|
171
|
+
}, s = i?.queued ?? [], c = i?.nudges ?? [], l = ne({
|
|
172
|
+
bus: H.bus,
|
|
156
173
|
tenantId: e.tenantId ?? null,
|
|
157
|
-
...
|
|
158
|
-
|
|
174
|
+
...r === v ? {} : { deferToCommit: (e) => {
|
|
175
|
+
s.push(async () => {
|
|
159
176
|
e();
|
|
160
177
|
});
|
|
161
178
|
} }
|
|
162
|
-
}), d =
|
|
163
|
-
apis:
|
|
164
|
-
transaction: async (
|
|
165
|
-
let o =
|
|
166
|
-
if (o !== e) return
|
|
167
|
-
if (
|
|
168
|
-
let s, l = await
|
|
169
|
-
let
|
|
179
|
+
}), d = te({ store: r }), f = a ? async () => h : pe(e, u.rowFilter, y), m = {
|
|
180
|
+
apis: u.apis ?? Object.freeze({}),
|
|
181
|
+
transaction: async (t, i) => {
|
|
182
|
+
let o = k(e, i?.tenantId, r !== v);
|
|
183
|
+
if (o !== e) return q(o, n, v, void 0, !0).transaction(t);
|
|
184
|
+
if (r !== v) return t(m);
|
|
185
|
+
let s, l = await r.transactional(async (r) => {
|
|
186
|
+
let i = q(e, n, r, {
|
|
170
187
|
queued: [],
|
|
171
188
|
nudges: []
|
|
172
|
-
},
|
|
173
|
-
return s =
|
|
189
|
+
}, a), o = await t(i);
|
|
190
|
+
return s = i, o;
|
|
174
191
|
});
|
|
175
|
-
return s !== void 0 && (await
|
|
192
|
+
return s !== void 0 && (await Y(s), c.push(...X(s))), l;
|
|
176
193
|
},
|
|
177
|
-
clock:
|
|
178
|
-
webhooks:
|
|
194
|
+
clock: b,
|
|
195
|
+
webhooks: R,
|
|
179
196
|
events: l,
|
|
180
|
-
eventBus:
|
|
181
|
-
llm:
|
|
182
|
-
...
|
|
183
|
-
request:
|
|
184
|
-
...
|
|
185
|
-
|
|
197
|
+
eventBus: H,
|
|
198
|
+
llm: U,
|
|
199
|
+
...u.ai === void 0 ? {} : { ai: u.ai },
|
|
200
|
+
request: o,
|
|
201
|
+
...n === void 0 ? {} : { connectionState: ee(n, r === v ? void 0 : (e) => {
|
|
202
|
+
s.push(e);
|
|
186
203
|
}) },
|
|
187
|
-
validation:
|
|
188
|
-
access:
|
|
189
|
-
cache:
|
|
190
|
-
kv:
|
|
191
|
-
store:
|
|
204
|
+
validation: g,
|
|
205
|
+
access: S(e),
|
|
206
|
+
cache: G,
|
|
207
|
+
kv: K,
|
|
208
|
+
store: N(D($(r, f)), {
|
|
192
209
|
subject: e,
|
|
193
|
-
schemaRegistry:
|
|
194
|
-
rowFilter:
|
|
210
|
+
schemaRegistry: _,
|
|
211
|
+
rowFilter: h
|
|
195
212
|
}),
|
|
196
|
-
storeForTenant: (t) =>
|
|
197
|
-
subject:
|
|
198
|
-
schemaRegistry:
|
|
199
|
-
rowFilter:
|
|
213
|
+
storeForTenant: (t) => N($(r, f), {
|
|
214
|
+
subject: p(e, t),
|
|
215
|
+
schemaRegistry: _,
|
|
216
|
+
rowFilter: h
|
|
200
217
|
}),
|
|
201
|
-
outbox:
|
|
202
|
-
store:
|
|
218
|
+
outbox: w({
|
|
219
|
+
store: r,
|
|
203
220
|
subject: e,
|
|
204
|
-
traceId:
|
|
221
|
+
traceId: F,
|
|
205
222
|
nudge: () => {
|
|
206
|
-
c.push(
|
|
223
|
+
c.push(F);
|
|
207
224
|
},
|
|
208
225
|
afterCommit: (e) => {
|
|
209
|
-
|
|
226
|
+
s.push(e);
|
|
210
227
|
}
|
|
211
228
|
}),
|
|
212
229
|
load: d.load,
|
|
213
230
|
loadMany: d.loadMany,
|
|
214
|
-
withSubject: (e,
|
|
215
|
-
queued:
|
|
231
|
+
withSubject: (e, t) => Promise.resolve(t(q(e, n, r, {
|
|
232
|
+
queued: s,
|
|
216
233
|
nudges: c
|
|
217
234
|
}))),
|
|
218
|
-
withTenant: (
|
|
235
|
+
withTenant: (t, i) => Promise.resolve(i(q({
|
|
219
236
|
...e,
|
|
220
|
-
tenantId:
|
|
221
|
-
},
|
|
222
|
-
queued:
|
|
237
|
+
tenantId: t
|
|
238
|
+
}, n, r, {
|
|
239
|
+
queued: s,
|
|
223
240
|
nudges: c
|
|
224
241
|
}))),
|
|
225
|
-
asSubject: (e) =>
|
|
226
|
-
queued:
|
|
242
|
+
asSubject: (e) => q(e, n, r, {
|
|
243
|
+
queued: s,
|
|
227
244
|
nudges: c
|
|
228
245
|
}),
|
|
229
|
-
asTenant: (
|
|
246
|
+
asTenant: (t) => q({
|
|
230
247
|
...e,
|
|
231
|
-
tenantId:
|
|
232
|
-
},
|
|
233
|
-
queued:
|
|
248
|
+
tenantId: t
|
|
249
|
+
}, n, r, {
|
|
250
|
+
queued: s,
|
|
234
251
|
nudges: c
|
|
235
252
|
})
|
|
236
253
|
};
|
|
237
|
-
return
|
|
238
|
-
queued:
|
|
254
|
+
return z.set(m, s), L.set(m, (t) => q(e, t, r, {
|
|
255
|
+
queued: s,
|
|
239
256
|
nudges: c
|
|
240
|
-
})),
|
|
241
|
-
|
|
257
|
+
})), B.set(m, c), V.set(m, u.plugins ?? []), J.set(m, u.layers ?? []), W.set(m, {
|
|
258
|
+
deps: P,
|
|
259
|
+
rowFilter: async () => u.rowFilter === void 0 ? void 0 : f(),
|
|
260
|
+
notices: A
|
|
261
|
+
}), I.set(m, (t) => r.transactional((r) => t(q(e, n, r, {
|
|
262
|
+
queued: s,
|
|
242
263
|
nudges: c
|
|
243
|
-
})))),
|
|
264
|
+
})))), t(m, v), m;
|
|
244
265
|
};
|
|
245
|
-
return
|
|
266
|
+
return q(u.subject ?? d(null), u.connection);
|
|
246
267
|
};
|
|
247
|
-
|
|
248
|
-
export { ae as makeTestContext, B as markRestInvocation, A as mockStore, q as outboxNudgesOf, R as pluginsOf, G as resetAfterCommit, V as restInvocationOf, U as rpcInterceptorFor, K as runAfterCommit, J as runInStoreTransaction, W as serviceLayerFor, P as withRpcConnection };
|
|
268
|
+
export { he as makeTestContext, K as markRestInvocation, P as mockStore, X as outboxNudgesOf, H as pluginsOf, G as queryCacheOf, ce as resetAfterCommit, q as restInvocationOf, oe as rpcInterceptorFor, Y as runAfterCommit, Z as runInStoreTransaction, se as serviceLayerFor, R as withRpcConnection };
|