@cosmicdrift/kumiko-framework 0.367.0 → 0.369.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/AGENTS.md +1 -7
- package/README.md +1 -1
- package/agents/examples/access-control.md +2 -2
- package/agents/examples/anonymous-access-multitenant.md +2 -2
- package/agents/examples/anonymous-access.md +3 -3
- package/agents/examples/apex-landing.md +1 -1
- package/agents/examples/apex-surface-auth.md +6 -7
- package/agents/examples/api-worker-split.md +7 -8
- package/agents/examples/auth-claims.md +2 -1
- package/agents/examples/auth-foundation-providers.md +3 -3
- package/agents/examples/auth-mfa.md +3 -4
- package/agents/examples/basic-entity.md +3 -4
- package/agents/examples/chat-channels.md +4 -4
- package/agents/examples/compliance-profiles-demo.md +2 -3
- package/agents/examples/cross-feature-events.md +4 -4
- package/agents/examples/crypto-shredding-hr.md +14 -9
- package/agents/examples/currencies-global.md +3 -4
- package/agents/examples/currencies-per-tenant.md +3 -4
- package/agents/examples/custom-fields-basic.md +2 -3
- package/agents/examples/custom-handlers.md +3 -5
- package/agents/examples/dashboard-stats.md +2 -3
- package/agents/examples/delivery-notifications.md +5 -6
- package/agents/examples/e2e-generator.md +1 -1
- package/agents/examples/embedded-entity-form.md +2 -3
- package/agents/examples/embedded.md +2 -3
- package/agents/examples/encrypted-tenant-config.md +5 -6
- package/agents/examples/error-contract.md +3 -4
- package/agents/examples/event-sourcing.md +19 -23
- package/agents/examples/feature-toggles.md +4 -4
- package/agents/examples/field-access.md +3 -4
- package/agents/examples/files-post-processing.md +12 -13
- package/agents/examples/golden-path.md +208 -0
- package/agents/examples/idempotency.md +2 -2
- package/agents/examples/inbound-mail-triage.md +7 -7
- package/agents/examples/lane-routing.md +3 -3
- package/agents/examples/ledger-banking.md +2 -3
- package/agents/examples/ledger-invoicing.md +2 -3
- package/agents/examples/legal-pages.md +1 -1
- package/agents/examples/lifecycle-hooks.md +3 -3
- package/agents/examples/managed-config.md +3 -4
- package/agents/examples/managed-pages.md +2 -2
- package/agents/examples/notes-history-basic.md +4 -5
- package/agents/examples/ownership.md +3 -5
- package/agents/examples/pdf-audit-export.md +2 -3
- package/agents/examples/pipeline-basics.md +2 -2
- package/agents/examples/public-share-token.md +3 -3
- package/agents/examples/rate-limiting.md +2 -1
- package/agents/examples/realtime-sse.md +2 -3
- package/agents/examples/record-detail-layout.md +1 -1
- package/agents/examples/reference-data.md +3 -3
- package/agents/examples/relations.md +2 -2
- package/agents/examples/screens-nav.md +1 -1
- package/agents/examples/search.md +2 -2
- package/agents/examples/secrets-demo.md +8 -8
- package/agents/examples/security-baseline.md +2 -2
- package/agents/examples/session-revocation.md +7 -8
- package/agents/examples/state-machine.md +181 -165
- package/agents/examples/tags-basic.md +2 -3
- package/agents/examples/tenant-isolation.md +2 -3
- package/agents/examples/tenant-settings.md +2 -2
- package/agents/examples/tier-admin.md +3 -4
- package/agents/examples/timezones.md +3 -3
- package/agents/examples/user-data-rights.md +12 -8
- package/agents/examples/user-profile.md +3 -3
- package/agents/examples/webhook-step.md +2 -3
- package/agents/examples/wizard-form.md +4 -5
- package/agents/examples/workflow-engine.md +7 -3
- package/agents/examples/writeform-section.md +1 -1
- package/agents/examples.md +1 -0
- package/agents/features.md +4 -4
- package/dist/consumer-cli.js +2 -3
- package/dist/crypto/index.d.ts +1 -1
- package/dist/crypto/index.js +1 -1
- package/dist/crypto/owner-transition-rekey.js +2 -0
- package/dist/crypto/pg-kms-adapter.js +1 -1
- package/dist/crypto/subject-resolver.d.ts +2 -0
- package/dist/crypto/subject-resolver.js +30 -15
- package/dist/db/bun-db-deprecated.d.ts +10 -0
- package/dist/{bun-db/index.js → db/bun-db-deprecated.js} +4 -3
- package/dist/db/config-seed.js +1 -1
- package/dist/db/connection.d.ts +23 -5
- package/dist/db/connection.js +10 -5
- package/dist/db/dialect.js +1 -1
- package/dist/db/entity-field-encryption.d.ts +5 -0
- package/dist/db/entity-field-encryption.js +29 -0
- package/dist/db/entity-table-meta.js +6 -5
- package/dist/db/event-store-executor-read.js +26 -5
- package/dist/db/index.d.ts +4 -4
- package/dist/db/index.js +1 -1
- package/dist/db/migrate-runner.js +1 -1
- package/dist/db/queries/backfill-pii.js +16 -9
- package/dist/db/queries/ddl.js +1 -1
- package/dist/db/queries/event-store.d.ts +2 -0
- package/dist/db/queries/event-store.js +26 -0
- package/dist/db/queries/test-stack.js +1 -1
- package/dist/db/query.d.ts +105 -1
- package/dist/db/query.js +1450 -3
- package/dist/{stack/table-helpers.d.ts → db/table-push.d.ts} +5 -15
- package/dist/{stack/table-helpers.js → db/table-push.js} +6 -46
- package/dist/db/tenant-db.d.ts +11 -0
- package/dist/db/tenant-db.js +51 -12
- package/dist/derivatives/derivatives-context.d.ts +1 -1
- package/dist/derivatives/derivatives-context.js +1 -1
- package/dist/engine/boot-validator/gdpr-storage.js +3 -3
- package/dist/engine/boot-validator/pii-retention.js +3 -3
- package/dist/engine/boot-validator/record-owned.js +3 -3
- package/dist/engine/boot-validator/screens.js +37 -1
- package/dist/engine/bridge-stub.d.ts +4 -0
- package/dist/engine/bridge-stub.js +62 -0
- package/dist/engine/build-config-feature-schema.js +197 -65
- package/dist/engine/event-helpers.d.ts +2 -1
- package/dist/engine/event-helpers.js +1 -0
- package/dist/engine/extension-selector-plugins.d.ts +3 -0
- package/dist/engine/extension-selector-plugins.js +14 -0
- package/dist/engine/feature-config-events-jobs.d.ts +2 -0
- package/dist/engine/feature-config-events-jobs.js +3 -2
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/index.js +1 -0
- package/dist/es-ops/operations-schema.js +1 -1
- package/dist/event-store/admin-api.js +1 -1
- package/dist/event-store/archive.js +1 -1
- package/dist/event-store/errors.d.ts +2 -1
- package/dist/event-store/errors.js +6 -2
- package/dist/event-store/event-store.js +17 -9
- package/dist/event-store/events-schema.js +1 -1
- package/dist/event-store/rebuild-dead-letter.js +3 -3
- package/dist/event-store/snapshot.js +1 -1
- package/dist/event-store/upcaster-dead-letter.js +3 -3
- package/dist/files/create-file-ref-from-bytes.js +1 -1
- package/dist/files/file-routes.js +1 -1
- package/dist/i18n/settings-hub-keys.js +1 -2
- package/dist/internal/stack-support.d.ts +12 -0
- package/dist/internal/stack-support.js +12 -0
- package/dist/internal/testing.d.ts +4 -0
- package/dist/internal/testing.js +5 -0
- package/dist/jobs/job-runner.js +23 -11
- package/dist/migrations/pending-rebuilds.js +1 -1
- package/dist/migrations/pii-event-backfill.js +2 -2
- package/dist/pipeline/dispatch-shared.js +43 -23
- package/dist/pipeline/dispatch-write.js +6 -2
- package/dist/pipeline/dispatcher-utils.js +6 -2
- package/dist/pipeline/event-consumer-state.js +1 -1
- package/dist/pipeline/projection-rebuild.d.ts +1 -0
- package/dist/pipeline/projection-rebuild.js +1 -1
- package/dist/pipeline/projection-state.js +1 -1
- package/dist/pipeline/system-hooks.js +1 -1
- package/dist/schema-cli.js +3 -3
- package/dist/search/purge-subject.js +20 -10
- package/dist/seeding/index.d.ts +1 -0
- package/dist/seeding/index.js +1 -0
- package/dist/stack/index.d.ts +10 -9
- package/dist/stack/index.js +11 -19
- package/dist/testing/e2e-generator.d.ts +5 -49
- package/dist/testing/e2e-generator.js +5 -382
- package/dist/testing/handler-context.d.ts +5 -4
- package/dist/testing/handler-context.js +5 -69
- package/dist/testing/index.d.ts +10 -26
- package/dist/testing/index.js +10 -34
- package/dist/testing/real-providers.d.ts +5 -3
- package/dist/testing/real-providers.js +5 -21
- package/dist/upgrade-cli.js +6 -4
- package/package.json +37 -9
- package/src/changes.json +64 -0
- package/src/scripts/codemod/README.md +43 -0
- package/src/scripts/codemod/codemod-support.ts +276 -0
- package/src/scripts/codemod/db-factory.ts +810 -0
- package/src/scripts/codemod/feature-factory.ts +429 -0
- package/src/scripts/codemod/s3-imports.ts +274 -0
- package/src/scripts/codemod/tenant-db-options.ts +454 -0
- package/src/scripts/codemod/testing-move-targets.ts +161 -0
- package/src/scripts/codemod/testing-move.ts +520 -0
- package/dist/bun-db/connection.d.ts +0 -17
- package/dist/bun-db/connection.js +0 -40
- package/dist/bun-db/index.d.ts +0 -4
- package/dist/bun-db/query.d.ts +0 -106
- package/dist/bun-db/query.js +0 -1457
- package/dist/db/api.d.ts +0 -19
- package/dist/db/api.js +0 -23
- package/dist/db/bun-provider.d.ts +0 -2
- package/dist/db/bun-provider.js +0 -28
- package/dist/db/postgres-provider.d.ts +0 -2
- package/dist/db/postgres-provider.js +0 -21
- package/dist/db/query-api.d.ts +0 -2
- package/dist/db/query-api.js +0 -6
- package/dist/stack/db.d.ts +0 -22
- package/dist/stack/db.js +0 -67
- package/dist/stack/drain-event-consumers.d.ts +0 -4
- package/dist/stack/drain-event-consumers.js +0 -51
- package/dist/stack/drain-jobs.d.ts +0 -22
- package/dist/stack/drain-jobs.js +0 -141
- package/dist/stack/event-collector.d.ts +0 -9
- package/dist/stack/event-collector.js +0 -12
- package/dist/stack/push-entity-projection-tables.d.ts +0 -24
- package/dist/stack/push-entity-projection-tables.js +0 -74
- package/dist/stack/redis.d.ts +0 -17
- package/dist/stack/redis.js +0 -52
- package/dist/stack/request-helper.d.ts +0 -35
- package/dist/stack/request-helper.js +0 -144
- package/dist/stack/test-stack.d.ts +0 -192
- package/dist/stack/test-stack.js +0 -429
- package/dist/testing/access-assertions.d.ts +0 -2
- package/dist/testing/access-assertions.js +0 -13
- package/dist/testing/assertions.d.ts +0 -10
- package/dist/testing/assertions.js +0 -22
- package/dist/testing/boot-validator-fixture.d.ts +0 -3
- package/dist/testing/boot-validator-fixture.js +0 -101
- package/dist/testing/closed-connection-error.d.ts +0 -7
- package/dist/testing/closed-connection-error.js +0 -46
- package/dist/testing/db-cleanup.d.ts +0 -9
- package/dist/testing/db-cleanup.js +0 -31
- package/dist/testing/expect-error.d.ts +0 -2
- package/dist/testing/expect-error.js +0 -22
- package/dist/testing/file-provider-contract.d.ts +0 -2
- package/dist/testing/file-provider-contract.js +0 -102
- package/dist/testing/http-cookies.d.ts +0 -7
- package/dist/testing/http-cookies.js +0 -47
- package/dist/testing/late-bound.d.ts +0 -9
- package/dist/testing/late-bound.js +0 -31
- package/dist/testing/manual-clock.d.ts +0 -14
- package/dist/testing/manual-clock.js +0 -12
- package/dist/testing/multipart-helper.d.ts +0 -22
- package/dist/testing/multipart-helper.js +0 -77
- package/dist/testing/mutable-master-key-provider.d.ts +0 -7
- package/dist/testing/mutable-master-key-provider.js +0 -35
- package/dist/testing/observability-recorder.d.ts +0 -9
- package/dist/testing/observability-recorder.js +0 -29
- package/dist/testing/seed.d.ts +0 -9
- package/dist/testing/seed.js +0 -21
- package/dist/testing/shared-entities.d.ts +0 -286
- package/dist/testing/shared-entities.js +0 -56
- package/dist/testing/utils.d.ts +0 -1
- package/dist/testing/utils.js +0 -1
- package/dist/testing/wait-for.d.ts +0 -20
- package/dist/testing/wait-for.js +0 -47
- package/dist/testing/without-ambient-temporal.d.ts +0 -5
- package/dist/testing/without-ambient-temporal.js +0 -17
- package/dist/testing/zip-fixture.d.ts +0 -1
- package/dist/testing/zip-fixture.js +0 -33
- /package/dist/{stack/test-users.d.ts → seeding/seed-users.d.ts} +0 -0
- /package/dist/{stack/test-users.js → seeding/seed-users.js} +0 -0
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { Hono } from "hono";
|
|
2
|
-
import type { SessionCreator } from "../api/auth-routes.js";
|
|
3
|
-
import type { JwtHelper } from "../api/jwt.js";
|
|
4
|
-
import type { SessionUser } from "../engine/types/index.js";
|
|
5
|
-
export type BatchCommand = {
|
|
6
|
-
type: string;
|
|
7
|
-
payload: unknown;
|
|
8
|
-
};
|
|
9
|
-
export type RequestHelper = {
|
|
10
|
-
write: (type: string, payload: unknown, user: SessionUser, requestId?: string) => Promise<Response>;
|
|
11
|
-
query: (type: string, payload: unknown, user: SessionUser) => Promise<Response>;
|
|
12
|
-
command: (type: string, payload: unknown, user: SessionUser) => Promise<Response>;
|
|
13
|
-
batch: (commands: readonly BatchCommand[], user: SessionUser, requestId?: string) => Promise<Response>;
|
|
14
|
-
raw: (method: string, path: string, body?: unknown, headers?: Record<string, string>) => Promise<Response>;
|
|
15
|
-
/** write + json + assert isSuccess — returns data directly */
|
|
16
|
-
writeOk: <T = Record<string, unknown>>(type: string, payload: unknown, user: SessionUser, requestId?: string) => Promise<T>;
|
|
17
|
-
/** write + json + assert isSuccess === false — returns the structured
|
|
18
|
-
* WriteErrorInfo with `httpStatus` filled in from the HTTP response. */
|
|
19
|
-
writeErr: (type: string, payload: unknown, user: SessionUser) => Promise<import("../errors/index.js").WriteErrorInfo>;
|
|
20
|
-
/** query + json — returns data directly */
|
|
21
|
-
queryOk: <T = unknown>(type: string, payload: unknown, user: SessionUser) => Promise<T>;
|
|
22
|
-
/** query + json + assert the response is an error — returns the structured
|
|
23
|
-
* WriteErrorInfo with `httpStatus` filled in from the HTTP response. */
|
|
24
|
-
queryErr: (type: string, payload: unknown, user: SessionUser) => Promise<import("../errors/index.js").WriteErrorInfo>;
|
|
25
|
-
/** write + additional HTTP headers (e.g. X-Correlation-ID). Returns the
|
|
26
|
-
* raw Response so callers can assert on status + headers + body as needed. */
|
|
27
|
-
writeWithHeaders: (type: string, payload: unknown, user: SessionUser, extraHeaders: Record<string, string>) => Promise<Response>;
|
|
28
|
-
/** query + additional HTTP headers (e.g. X-Forwarded-For). Returns the raw
|
|
29
|
-
* Response so callers can assert on status + headers + body as needed. */
|
|
30
|
-
queryWithHeaders: (type: string, payload: unknown, user: SessionUser, extraHeaders: Record<string, string>) => Promise<Response>;
|
|
31
|
-
};
|
|
32
|
-
export type RequestHelperOptions = {
|
|
33
|
-
readonly sessionCreator?: SessionCreator;
|
|
34
|
-
};
|
|
35
|
-
export declare function createRequestHelper(app: Hono, jwt: JwtHelper, options?: RequestHelperOptions): RequestHelper;
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
function formatFailure(kind, type, body) {
|
|
2
|
-
const parsed = body;
|
|
3
|
-
const code = (typeof parsed.error === "object" ? parsed.error?.code : undefined) ??
|
|
4
|
-
(typeof parsed.error === "string" ? parsed.error : "unknown");
|
|
5
|
-
const details = typeof parsed.error === "object" && parsed.error?.details !== undefined
|
|
6
|
-
? parsed.error.details
|
|
7
|
-
: undefined;
|
|
8
|
-
const causeMessage = details && typeof details === "object" && "causeMessage" in details
|
|
9
|
-
? String(details.causeMessage ?? "")
|
|
10
|
-
: "";
|
|
11
|
-
const causeName = details && typeof details === "object" && "causeName" in details
|
|
12
|
-
? String(details.causeName ?? "")
|
|
13
|
-
: "";
|
|
14
|
-
if (code === "internal_error" && (causeMessage || causeName)) {
|
|
15
|
-
return `Expected ${kind} "${type}" to succeed but got error: ${code} (${causeName}: ${causeMessage})`;
|
|
16
|
-
}
|
|
17
|
-
if (details !== undefined) {
|
|
18
|
-
return `Expected ${kind} "${type}" to succeed but got error: ${code} — ${JSON.stringify(details)}`;
|
|
19
|
-
}
|
|
20
|
-
return `Expected ${kind} "${type}" to succeed but got error: ${code}`;
|
|
21
|
-
}
|
|
22
|
-
export function createRequestHelper(app, jwt, options = {}) {
|
|
23
|
-
// sid per (user.id, tenantId), not one mint per authHeader() call:
|
|
24
|
-
// sessionCreator opens a live session row, so an unmemoized call mints a
|
|
25
|
-
// fresh one on every request a test makes for the same user — tests
|
|
26
|
-
// asserting on session counts / massRevoker / revokeAllOthers behavior
|
|
27
|
-
// then see extra live sids that have nothing to do with what they're
|
|
28
|
-
// testing. Keyed on tenantId too — the same user.id can hold sessions in
|
|
29
|
-
// more than one tenant, and sessionCreator writes the row scoped to
|
|
30
|
-
// `user.tenantId` (session-callbacks.ts), so a user.id-only key would
|
|
31
|
-
// hand a cross-tenant test its wrong tenant's sid.
|
|
32
|
-
// Cache the Promise (not the settled sid) so two concurrent authHeader
|
|
33
|
-
// calls for the same key share one mint instead of racing on a miss.
|
|
34
|
-
const sidByUserKey = new Map();
|
|
35
|
-
async function authHeader(user) {
|
|
36
|
-
let forJwt = user;
|
|
37
|
-
if (options.sessionCreator && !user.sid) {
|
|
38
|
-
const key = `${user.id}:${user.tenantId}`;
|
|
39
|
-
let sidPromise = sidByUserKey.get(key);
|
|
40
|
-
if (sidPromise === undefined) {
|
|
41
|
-
sidPromise = options.sessionCreator(user, { ip: "test", userAgent: "request-helper" });
|
|
42
|
-
sidByUserKey.set(key, sidPromise);
|
|
43
|
-
}
|
|
44
|
-
const sid = await sidPromise;
|
|
45
|
-
forJwt = { ...user, sid };
|
|
46
|
-
}
|
|
47
|
-
const token = await jwt.sign(forJwt);
|
|
48
|
-
return { Authorization: `Bearer ${token}` };
|
|
49
|
-
}
|
|
50
|
-
async function req(method, path, body, headers) {
|
|
51
|
-
const init = {
|
|
52
|
-
method,
|
|
53
|
-
headers: { "Content-Type": "application/json", ...headers },
|
|
54
|
-
};
|
|
55
|
-
if (body)
|
|
56
|
-
init.body = JSON.stringify(body);
|
|
57
|
-
return app.request(path, init);
|
|
58
|
-
}
|
|
59
|
-
async function writeRaw(type, payload, user, requestId) {
|
|
60
|
-
const headers = await authHeader(user);
|
|
61
|
-
return req("POST", "/api/write", { type, payload, requestId }, headers);
|
|
62
|
-
}
|
|
63
|
-
async function queryRaw(type, payload, user) {
|
|
64
|
-
const headers = await authHeader(user);
|
|
65
|
-
return req("POST", "/api/query", { type, payload }, headers);
|
|
66
|
-
}
|
|
67
|
-
return {
|
|
68
|
-
write: writeRaw,
|
|
69
|
-
query: queryRaw,
|
|
70
|
-
async command(type, payload, user) {
|
|
71
|
-
const headers = await authHeader(user);
|
|
72
|
-
return req("POST", "/api/command", { type, payload }, headers);
|
|
73
|
-
},
|
|
74
|
-
async batch(commands, user, requestId) {
|
|
75
|
-
const headers = await authHeader(user);
|
|
76
|
-
return req("POST", "/api/batch", { commands, requestId }, headers);
|
|
77
|
-
},
|
|
78
|
-
raw: req,
|
|
79
|
-
async writeOk(type, payload, user, requestId) {
|
|
80
|
-
const res = await writeRaw(type, payload, user, requestId);
|
|
81
|
-
// wire-body shape direkt nach JSON.parse — Caller-Code prüft danach
|
|
82
|
-
// selber ob isSuccess/error/data tatsächlich da sind.
|
|
83
|
-
const rawBody = await res.json();
|
|
84
|
-
const body = rawBody;
|
|
85
|
-
// Success path still has { isSuccess: true, data }. Error responses now
|
|
86
|
-
// follow the error-contract shape { error: { code, i18nKey, ... } } with
|
|
87
|
-
// a 4xx/5xx status — no isSuccess flag. Detect either.
|
|
88
|
-
if (body.isSuccess !== true) {
|
|
89
|
-
throw new Error(formatFailure("write", type, body));
|
|
90
|
-
}
|
|
91
|
-
return body.data; // @cast-boundary engine-bridge
|
|
92
|
-
},
|
|
93
|
-
async writeErr(type, payload, user) {
|
|
94
|
-
const res = await writeRaw(type, payload, user);
|
|
95
|
-
const rawErrorBody = await res.json();
|
|
96
|
-
const body = rawErrorBody;
|
|
97
|
-
if (body.isSuccess === true) {
|
|
98
|
-
throw new Error(`Expected write "${type}" to fail but it succeeded`);
|
|
99
|
-
}
|
|
100
|
-
const wire = body.error;
|
|
101
|
-
if (!wire || typeof wire !== "object" || typeof wire.code !== "string") {
|
|
102
|
-
throw new Error(`Expected error response for "${type}" but got unexpected shape: ${JSON.stringify(body)}`);
|
|
103
|
-
}
|
|
104
|
-
// The wire body doesn't carry httpStatus (it would be redundant with
|
|
105
|
-
// the HTTP response status). Fill it in from res.status so callers can
|
|
106
|
-
// assert against either code OR status without a second request round.
|
|
107
|
-
return { ...wire, httpStatus: res.status };
|
|
108
|
-
},
|
|
109
|
-
async queryOk(type, payload, user) {
|
|
110
|
-
const res = await queryRaw(type, payload, user);
|
|
111
|
-
const rawBody = await res.json();
|
|
112
|
-
const body = rawBody;
|
|
113
|
-
// res.ok mirrors writeOk's isSuccess assertion — belt-and-suspenders
|
|
114
|
-
// in case a future non-dispatcher rejection skips the error-contract shape.
|
|
115
|
-
if (!res.ok || body.error !== undefined) {
|
|
116
|
-
throw new Error(`${formatFailure("query", type, body)} [HTTP ${res.status}]`);
|
|
117
|
-
}
|
|
118
|
-
return body.data; // @cast-boundary engine-bridge
|
|
119
|
-
},
|
|
120
|
-
async queryErr(type, payload, user) {
|
|
121
|
-
const res = await queryRaw(type, payload, user);
|
|
122
|
-
const rawErrorBody = await res.json();
|
|
123
|
-
const body = rawErrorBody;
|
|
124
|
-
if (res.ok) {
|
|
125
|
-
throw new Error(`Expected query "${type}" to fail but it succeeded`);
|
|
126
|
-
}
|
|
127
|
-
const wire = body.error;
|
|
128
|
-
if (!wire || typeof wire !== "object" || typeof wire.code !== "string") {
|
|
129
|
-
throw new Error(`Expected error response for "${type}" but got unexpected shape: ${JSON.stringify(body)}`);
|
|
130
|
-
}
|
|
131
|
-
// Same rationale as writeErr: the wire body has no httpStatus (it would
|
|
132
|
-
// be redundant with the HTTP response status), so fill it in here.
|
|
133
|
-
return { ...wire, httpStatus: res.status };
|
|
134
|
-
},
|
|
135
|
-
async writeWithHeaders(type, payload, user, extraHeaders) {
|
|
136
|
-
const authHeaders = await authHeader(user);
|
|
137
|
-
return req("POST", "/api/write", { type, payload }, { ...authHeaders, ...extraHeaders });
|
|
138
|
-
},
|
|
139
|
-
async queryWithHeaders(type, payload, user, extraHeaders) {
|
|
140
|
-
const authHeaders = await authHeader(user);
|
|
141
|
-
return req("POST", "/api/query", { type, payload }, { ...authHeaders, ...extraHeaders });
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
}
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import type { Hono } from "hono";
|
|
2
|
-
import type { AuthRoutesConfig } from "../api/auth-routes.js";
|
|
3
|
-
import type { JwtHelper } from "../api/jwt.js";
|
|
4
|
-
import { type SseBroker } from "../api/sse-broker.js";
|
|
5
|
-
import type { AppContext, FeatureDefinition, JobRunIn, Registry, TenantId } from "../engine/types/index.js";
|
|
6
|
-
import type { ErrorDocsConfig } from "../errors/docs-url.js";
|
|
7
|
-
import { type JobRunner, type JobRunnerOptions } from "../jobs/index.js";
|
|
8
|
-
import type { Lifecycle } from "../lifecycle/index.js";
|
|
9
|
-
import { type ObservabilityProvider } from "../observability/index.js";
|
|
10
|
-
import type { Dispatcher, EventDispatcher, SystemHooks } from "../pipeline/index.js";
|
|
11
|
-
import { type ClosableCacheSyncBus } from "../redis/cache-sync-bus.js";
|
|
12
|
-
import type { SearchAdapter } from "../search/types.js";
|
|
13
|
-
import { type EventCollector } from "./event-collector.js";
|
|
14
|
-
import { type TestRedis } from "./redis.js";
|
|
15
|
-
import { type RequestHelper } from "./request-helper.js";
|
|
16
|
-
export type TestStack = {
|
|
17
|
-
app: Hono;
|
|
18
|
-
jwt: JwtHelper;
|
|
19
|
-
registry: Registry;
|
|
20
|
-
db: import("../db/index.js").DbConnection;
|
|
21
|
-
redis: TestRedis;
|
|
22
|
-
cacheSync: ClosableCacheSyncBus;
|
|
23
|
-
search: SearchAdapter;
|
|
24
|
-
events: EventCollector;
|
|
25
|
-
http: RequestHelper;
|
|
26
|
-
observability: ObservabilityProvider;
|
|
27
|
-
sseBroker: SseBroker;
|
|
28
|
-
dispatcher: Dispatcher;
|
|
29
|
-
context: AppContext;
|
|
30
|
-
eventDispatcher?: EventDispatcher;
|
|
31
|
-
lifecycle?: Lifecycle;
|
|
32
|
-
jobRunner?: JobRunner;
|
|
33
|
-
drainJobs: () => Promise<void>;
|
|
34
|
-
cleanup: () => Promise<void>;
|
|
35
|
-
};
|
|
36
|
-
export type TestStackOptions = {
|
|
37
|
-
features: readonly FeatureDefinition[];
|
|
38
|
-
/** System hooks to wire up. Default: all (sse, search) */
|
|
39
|
-
systemHooks?: ("sse" | "search")[];
|
|
40
|
-
/** Pipeline system hooks handed to buildServer, e.g. the cascade-delete preDelete hook. None by default. */
|
|
41
|
-
lifecycleSystemHooks?: SystemHooks;
|
|
42
|
-
/** Search config per tenant — defaults to tenant 1 with all text fields */
|
|
43
|
-
searchConfig?: {
|
|
44
|
-
tenantId: TenantId;
|
|
45
|
-
searchableFields: string[];
|
|
46
|
-
rankingFields: string[];
|
|
47
|
-
};
|
|
48
|
-
jwtSecret?: string;
|
|
49
|
-
/** Extra fields merged into the AppContext (e.g. _notifyFactory, configResolver).
|
|
50
|
-
* Can be a function receiving (registry, db, sseBroker) for late binding. */
|
|
51
|
-
/** Boot default locale (BCP-47) merged into AppContext before extraContext. */
|
|
52
|
-
defaultLocale?: string;
|
|
53
|
-
extraContext?: Record<string, unknown> | ((deps: {
|
|
54
|
-
registry: Registry;
|
|
55
|
-
db: import("../db/index.js").DbConnection;
|
|
56
|
-
sseBroker: import("../api/sse-broker.js").SseBroker;
|
|
57
|
-
redis: import("ioredis").Redis;
|
|
58
|
-
}) => Record<string, unknown>);
|
|
59
|
-
/** Wire up auth routes (login, tenant-switch). Leave undefined to skip. */
|
|
60
|
-
authConfig?: AuthRoutesConfig;
|
|
61
|
-
/** Register a file storage provider so uploads via POST /api/files work and
|
|
62
|
-
* `ctx.files.ref(key)` is available to hooks/MSPs. Omit to skip — tests
|
|
63
|
-
* without file handling don't need it. */
|
|
64
|
-
files?: {
|
|
65
|
-
storageProvider: import("../files/index.js").FileStorageProvider;
|
|
66
|
-
};
|
|
67
|
-
/** Observability provider — omit for NoopProvider (no spans/metrics).
|
|
68
|
-
* Pass a ConsoleProvider to see the span tree in stdout, or a custom
|
|
69
|
-
* provider (e.g. a recording provider for assertions in tests). */
|
|
70
|
-
observability?: ObservabilityProvider;
|
|
71
|
-
/** Inject a process lifecycle so tests can drain() and observe
|
|
72
|
-
* /health/ready flipping to 503. Omit if the suite doesn't care. */
|
|
73
|
-
lifecycle?: Lifecycle;
|
|
74
|
-
/** Wire L1 (global-IP) and/or L2 (auth-endpoint) rate-limit middleware.
|
|
75
|
-
* The resolver is auto-built from the test Redis. Mirrors
|
|
76
|
-
* buildServer's `rateLimit` option 1:1 — see there for shape. */
|
|
77
|
-
rateLimit?: import("../api/server.js").ServerOptions["rateLimit"];
|
|
78
|
-
/** Forwarded to buildServer — Integration-Tests that exercise `extraRoutes`
|
|
79
|
-
* MUST go through here (real HTTP via `stack.http`/`stack.app.fetch`),
|
|
80
|
-
* never `createTestDispatcher`. */
|
|
81
|
-
extraRoutes?: import("../api/server.js").ServerOptions["extraRoutes"];
|
|
82
|
-
/** Forwarded to buildServer like runProdApp. Without a PrometheusMeter-backed
|
|
83
|
-
* `observability` the route answers 503, so spread `resolveObservabilityWiring(token)`
|
|
84
|
-
* rather than setting `metrics` alone. */
|
|
85
|
-
metrics?: import("../api/server.js").ServerOptions["metrics"];
|
|
86
|
-
/** Inject a MasterKeyProvider for secrets-backed tests. Lands typed in
|
|
87
|
-
* AppContext — set/delete/get + rotation job pick it up. Omit for
|
|
88
|
-
* suites that don't touch secrets. */
|
|
89
|
-
masterKeyProvider?: import("../secrets/index.js").MasterKeyProvider;
|
|
90
|
-
/** Feature-toggle resolver. When present the dispatcher's feature-gate,
|
|
91
|
-
* hook-filter, and MSP-filter all consult it; absent = every feature
|
|
92
|
-
* treated as always-on. Pass the callback from
|
|
93
|
-
* GlobalFeatureToggleRuntime.effectiveFeatures for real DB-backed
|
|
94
|
-
* toggles, or a plain `() => new Set<string>(registry.features.keys())`
|
|
95
|
-
* to force a specific snapshot in a unit-style setup. */
|
|
96
|
-
effectiveFeatures?: (tenantId: TenantId) => ReadonlySet<string>;
|
|
97
|
-
/** Pin the underlying Postgres DB name instead of the default
|
|
98
|
-
* `kumiko_test_<8chars>`. Forwarded to createTestDb. Primary use
|
|
99
|
-
* case: dev servers that want persistent storage across restarts —
|
|
100
|
-
* combine with `persistentDb: true`. */
|
|
101
|
-
dbName?: string;
|
|
102
|
-
/** When true, cleanup() keeps the Postgres DB around — the caller
|
|
103
|
-
* owns its lifecycle. Default false (test contract). Used by
|
|
104
|
-
* dev-server wiring to survive hot-reloads. */
|
|
105
|
-
persistentDb?: boolean;
|
|
106
|
-
/** Cap on the main app pool (default: driver default). Lets tests saturate it deliberately. */
|
|
107
|
-
dbPoolMax?: number;
|
|
108
|
-
/** Size of the dedicated pool behind ctx.dbOutsideTransaction / ctx.outsideTransaction. */
|
|
109
|
-
outsideTransactionPoolMax?: number;
|
|
110
|
-
/** Forwarded to buildServer — when set, requests without a JWT pass
|
|
111
|
-
* through as anonymous instead of 401. See AnonymousAccessConfig.
|
|
112
|
-
* Akzeptiert entweder einen statischen Config-Object ODER eine Factory
|
|
113
|
-
* `({registry, db, sseBroker, redis}) => Config` — gleiches Pattern wie
|
|
114
|
-
* `extraContext`. Die Factory wird einmal beim Boot aufgerufen, der
|
|
115
|
-
* TenantResolver darin closure'd typischerweise `db` für Subdomain-
|
|
116
|
-
* Lookups. */
|
|
117
|
-
anonymousAccess?: import("../api/server.js").ServerOptions["anonymousAccess"] | ((deps: {
|
|
118
|
-
registry: Registry;
|
|
119
|
-
db: import("../db/index.js").DbConnection;
|
|
120
|
-
sseBroker: import("../api/sse-broker.js").SseBroker;
|
|
121
|
-
redis: import("ioredis").Redis;
|
|
122
|
-
}) => import("../api/server.js").ServerOptions["anonymousAccess"]);
|
|
123
|
-
/** Optional post-factory enricher (e.g. merge auth-foundation tenant
|
|
124
|
-
* providers). Keeps framework free of a bundled-features dependency. */
|
|
125
|
-
enrichAnonymousAccess?: (base: import("../api/server.js").ServerOptions["anonymousAccess"] | undefined, deps: {
|
|
126
|
-
registry: Registry;
|
|
127
|
-
db: import("../db/index.js").DbConnection;
|
|
128
|
-
}) => Promise<import("../api/server.js").ServerOptions["anonymousAccess"] | undefined>;
|
|
129
|
-
/** Opt-in JobRunner wired into ctx.jobRunner and merged into
|
|
130
|
-
* dispatcherOptions so event-triggered jobs enqueue on commit — mirrors
|
|
131
|
-
* the prod entrypoint's `buildJobRunnerWithHook`. Unlike prod (which
|
|
132
|
-
* always builds one), this only builds a runner when `registry.getAllJobs()`
|
|
133
|
-
* is non-empty — a deliberate test-stack-only shortcut, not parity.
|
|
134
|
-
* Default `undefined`. Pass `consumerLane` only when this test IS the
|
|
135
|
-
* sole consumer (otherwise enqueuer-only, avoiding double-running
|
|
136
|
-
* `runOnBoot`/cron jobs against a caller-owned consumer). */
|
|
137
|
-
jobs?: {
|
|
138
|
-
consumerLane?: JobRunIn;
|
|
139
|
-
/** Default: unique per stack, derived from its test Redis keyPrefix. Pass
|
|
140
|
-
* the same value to every runner that has to share this stack's queues. */
|
|
141
|
-
queueNamePrefix?: string;
|
|
142
|
-
/** Source of active tenant ids for `perTenant: true` jobs. Omit when the
|
|
143
|
-
* tenant feature is among `options.features` — the framework then
|
|
144
|
-
* resolves tenants on its own via that feature's active-tenant-ids
|
|
145
|
-
* query, same as prod. Only needed for suites that fan a job over
|
|
146
|
-
* tenants without mounting the tenant feature. */
|
|
147
|
-
getActiveTenantIds?: JobRunnerOptions["getActiveTenantIds"];
|
|
148
|
-
/** Run-log callbacks (job_runs / tenant job failures), built once registry
|
|
149
|
-
* and db exist. The framework can't import the bundled jobs feature, so the
|
|
150
|
-
* dev-server wrapper supplies prod's `jobRunLoggerCallbacks` here. They are
|
|
151
|
-
* awaited before drainJobs() observes the job's outcome. */
|
|
152
|
-
runLogger?: (deps: {
|
|
153
|
-
registry: Registry;
|
|
154
|
-
db: import("../db/index.js").DbConnection;
|
|
155
|
-
}) => Pick<JobRunnerOptions, "onJobStart" | "onJobComplete" | "onJobFailed" | "onJobQueued" | "onJobDropped"> | undefined;
|
|
156
|
-
};
|
|
157
|
-
/** Override the event dispatcher's polling-timer interval. Default 50ms.
|
|
158
|
-
* Tests that assert LISTEN/NOTIFY wake-up latency need this pushed far
|
|
159
|
-
* out (e.g. 60_000) so the polling timer can't land inside the
|
|
160
|
-
* assertion window and mask a dead subscription — see E.4 (#2042). */
|
|
161
|
-
eventDispatcherPollIntervalMs?: number;
|
|
162
|
-
/** Opt out of auto-created r.entity() tables for callers that create/migrate
|
|
163
|
-
* them themselves. Default true — false pushes only projection/MSP/
|
|
164
|
-
* storeTable sources, same as before fw#3102. */
|
|
165
|
-
entityTables?: boolean;
|
|
166
|
-
/** Time source of the stack's rate-limit resolver, so tests can freeze the
|
|
167
|
-
* clock instead of racing the window. Default: system time. */
|
|
168
|
-
rateLimitNowMs?: () => number;
|
|
169
|
-
/** Forwarded to buildServer's top-level `ServerOptions.trustedProxyHops`
|
|
170
|
-
* — see there. Default 0. */
|
|
171
|
-
trustedProxyHops?: number;
|
|
172
|
-
/** Links the app's own error reasons to its own docs (`docsUrl` in error responses); framework reasons keep the framework docs link. Passed to buildServer's `ServerOptions.errorDocs`. */
|
|
173
|
-
errorDocs?: ErrorDocsConfig;
|
|
174
|
-
/** Second stack on the Redis namespace of `owner`: own connection, same
|
|
175
|
-
* keyPrefix, so rate-limit buckets, locks, idempotency keys and the
|
|
176
|
-
* cache-sync channel are shared across both. The derived
|
|
177
|
-
* queueNamePrefix is identical too, so both stacks share BullMQ queues.
|
|
178
|
-
* Cleanup only disconnects; the owner flushes the namespace and queues, so
|
|
179
|
-
* clean up the borrowing stack first. The DB is NOT shared — pass the same
|
|
180
|
-
* `dbName` + `persistentDb` for that. */
|
|
181
|
-
sharedRedisWith?: TestStack;
|
|
182
|
-
/** Publish/receive cache invalidations (tenant timezone, file providers,
|
|
183
|
-
* tier sets) over Redis Pub/Sub, namespaced by this stack's keyPrefix.
|
|
184
|
-
* Implied by `sharedRedisWith`; set it on the owner stack too, or its writes
|
|
185
|
-
* never reach the borrower. Without it the stack uses a process-local bus. */
|
|
186
|
-
cacheSync?: boolean;
|
|
187
|
-
/** "full" runs the prod-boot validateBoot over `features` (screens and ref
|
|
188
|
-
* entities across features included). Use it with the app's complete feature
|
|
189
|
-
* composition; the default only checks what is safe on a feature subset. */
|
|
190
|
-
validateBoot?: "full";
|
|
191
|
-
};
|
|
192
|
-
export declare function setupTestStack(options: TestStackOptions): Promise<TestStack>;
|