@cosmicdrift/kumiko-framework 0.269.1 → 0.270.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/README.md +5 -1
- package/package.json +3 -3
- package/src/__tests__/anonymous-access.integration.test.ts +1 -1
- package/src/__tests__/error-contract.integration.test.ts +1 -1
- package/src/__tests__/fixtures/migrate-db-raw/global-fetch.expected.ts +9 -0
- package/src/__tests__/fixtures/migrate-db-raw/global-fetch.input.ts +10 -0
- package/src/__tests__/fixtures/migrate-db-raw/global-select.expected.ts +6 -0
- package/src/__tests__/fixtures/migrate-db-raw/global-select.input.ts +12 -0
- package/src/__tests__/fixtures/migrate-db-raw/import-pruning.expected.ts +12 -0
- package/src/__tests__/fixtures/migrate-db-raw/import-pruning.input.ts +12 -0
- package/src/__tests__/fixtures/migrate-db-raw/manual-only.expected.ts +26 -0
- package/src/__tests__/fixtures/migrate-db-raw/manual-only.input.ts +26 -0
- package/src/__tests__/fixtures/migrate-db-raw/own-tenant-const-shorthand.expected.ts +10 -0
- package/src/__tests__/fixtures/migrate-db-raw/own-tenant-const-shorthand.input.ts +11 -0
- package/src/__tests__/fixtures/migrate-db-raw/own-tenant-event.expected.ts +9 -0
- package/src/__tests__/fixtures/migrate-db-raw/own-tenant-event.input.ts +15 -0
- package/src/__tests__/fixtures/migrate-open-to-all/manual-only.expected.ts +16 -0
- package/src/__tests__/fixtures/migrate-open-to-all/manual-only.input.ts +16 -0
- package/src/__tests__/fixtures/migrate-open-to-all/test-nested-shorthand.expected.ts +12 -0
- package/src/__tests__/fixtures/migrate-open-to-all/test-nested-shorthand.input.ts +12 -0
- package/src/__tests__/fixtures/migrate-open-to-all/test-simple.expected.ts +7 -0
- package/src/__tests__/fixtures/migrate-open-to-all/test-simple.input.ts +7 -0
- package/src/__tests__/full-stack.integration.test.ts +2 -2
- package/src/__tests__/migrate-db-raw-codemod.test.ts +132 -0
- package/src/__tests__/migrate-open-to-all-codemod.test.ts +84 -0
- package/src/__tests__/transition-guard.integration.test.ts +7 -7
- package/src/__tests__/upgrade-cli.test.ts +54 -0
- package/src/api/__tests__/api.test.ts +2 -2
- package/src/api/__tests__/body-limit.test.ts +1 -1
- package/src/api/__tests__/pii-leak-guard.integration.test.ts +2 -2
- package/src/api/__tests__/request-locale.integration.test.ts +1 -1
- package/src/api/__tests__/server-error-logging.test.ts +1 -1
- package/src/changes.json +10 -2
- package/src/db/__tests__/list-filter-field-access.integration.test.ts +1 -1
- package/src/derivatives/__tests__/derivatives-context.integration.test.ts +2 -2
- package/src/engine/__tests__/boot-validator-dashboard.test.ts +5 -5
- package/src/engine/__tests__/boot-validator-pii-retention.test.ts +1 -1
- package/src/engine/__tests__/boot-validator-projection-list.test.ts +17 -17
- package/src/engine/__tests__/boot-validator-query-output-schema.test.ts +18 -18
- package/src/engine/__tests__/boot-validator-query-refs.test.ts +3 -3
- package/src/engine/__tests__/boot-validator-s0-integration.test.ts +2 -2
- package/src/engine/__tests__/boot-validator.test.ts +18 -18
- package/src/engine/__tests__/build-app-schema.test.ts +10 -6
- package/src/engine/__tests__/build-config-feature-schema-secrets.test.ts +48 -0
- package/src/engine/__tests__/build-config-feature-schema.test.ts +34 -5
- package/src/engine/__tests__/engine.test.ts +39 -25
- package/src/engine/__tests__/entity-handlers.test.ts +19 -8
- package/src/engine/__tests__/entity-presave-wiring.integration.test.ts +2 -2
- package/src/engine/__tests__/extends-registrar.test.ts +3 -3
- package/src/engine/__tests__/feature-crud-shorthand.test.ts +9 -3
- package/src/engine/__tests__/feature-crud-verb-access.integration.test.ts +1 -1
- package/src/engine/__tests__/hook-phases.test.ts +5 -5
- package/src/engine/__tests__/lifecycle-hooks.test.ts +9 -3
- package/src/engine/__tests__/multiselect-filter.integration.test.ts +1 -1
- package/src/engine/__tests__/post-query-hook.test.ts +6 -2
- package/src/engine/__tests__/projection-detail-actions.test.ts +2 -2
- package/src/engine/__tests__/projection-detail-singleton.test.ts +3 -3
- package/src/engine/__tests__/projection-detail-tabs.test.ts +3 -3
- package/src/engine/__tests__/projection-list-filter.integration.test.ts +1 -1
- package/src/engine/__tests__/registry.test.ts +19 -13
- package/src/engine/__tests__/screen.test.ts +26 -20
- package/src/engine/boot-validator/__tests__/access-declarations.test.ts +5 -4
- package/src/engine/boot-validator/__tests__/parent-ref.test.ts +18 -6
- package/src/engine/boot-validator/access-declarations.ts +3 -5
- package/src/engine/boot-validator/nav.ts +4 -3
- package/src/engine/build-config-feature-schema.ts +9 -2
- package/src/engine/entity-handlers.ts +1 -1
- package/src/engine/feature-ast/__tests__/canonical-form.test.ts +3 -1
- package/src/engine/feature-ast/__tests__/parse-happy-path.test.ts +2 -2
- package/src/engine/feature-ast/__tests__/parse.test.ts +106 -4
- package/src/engine/feature-ast/__tests__/patcher.test.ts +3 -3
- package/src/engine/feature-ast/__tests__/read-optional-access-rule.test.ts +4 -4
- package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +5 -1
- package/src/engine/feature-ast/extractors/handlers.ts +16 -2
- package/src/engine/feature-ast/extractors/hooks.ts +25 -4
- package/src/engine/feature-ast/patcher.ts +15 -3
- package/src/engine/feature-ast/patterns.ts +4 -0
- package/src/engine/feature-ast/render.ts +3 -0
- package/src/engine/pattern-library/shared-fields.ts +7 -3
- package/src/entrypoint/__tests__/entrypoint-attach-dispatcher.integration.test.ts +1 -1
- package/src/entrypoint/__tests__/entrypoint-job-wiring.integration.test.ts +3 -3
- package/src/entrypoint/__tests__/split-deploy.integration.test.ts +1 -1
- package/src/es-ops/__tests__/runner.integration.test.ts +2 -2
- package/src/jobs/__tests__/job-event-trigger.integration.test.ts +2 -2
- package/src/jobs/__tests__/job-multi-trigger.integration.test.ts +2 -2
- package/src/jobs/__tests__/jobs.integration.test.ts +1 -1
- package/src/observability/__tests__/observability.integration.test.ts +7 -7
- package/src/pipeline/__tests__/archive-stream.integration.test.ts +2 -2
- package/src/pipeline/__tests__/dispatcher.test.ts +15 -15
- package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +10 -10
- package/src/pipeline/__tests__/load-aggregate-query.integration.test.ts +1 -1
- package/src/pipeline/__tests__/post-query-hook.integration.test.ts +3 -3
- package/src/pipeline/__tests__/query-projection.integration.test.ts +3 -3
- package/src/scripts/codemod/migrate-db-raw.ts +397 -0
- package/src/scripts/codemod/migrate-open-to-all.ts +248 -0
- package/src/secrets/__tests__/contains-secret.test.ts +5 -5
- package/src/stack/__tests__/request-helper.integration.test.ts +3 -3
- package/src/stack/__tests__/setup-test-stack-jobs.integration.test.ts +1 -1
- package/src/testing/__tests__/e2e-generator.test.ts +19 -5
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
existsSync,
|
|
4
4
|
mkdirSync,
|
|
5
5
|
mkdtempSync,
|
|
6
|
+
readdirSync,
|
|
6
7
|
readFileSync,
|
|
7
8
|
rmSync,
|
|
9
|
+
statSync,
|
|
8
10
|
symlinkSync,
|
|
9
11
|
writeFileSync,
|
|
10
12
|
} from "node:fs";
|
|
@@ -12,6 +14,8 @@ import { tmpdir } from "node:os";
|
|
|
12
14
|
import { join } from "node:path";
|
|
13
15
|
import {
|
|
14
16
|
findCodemodScriptsRoot,
|
|
17
|
+
findCoreChangelogFile,
|
|
18
|
+
findFeaturesDirs,
|
|
15
19
|
resolveCodemodScript,
|
|
16
20
|
runUpgradeCli,
|
|
17
21
|
type UpgradeCliOut,
|
|
@@ -592,3 +596,53 @@ describe("upgrade command — filter baseline is the marker, not the installed v
|
|
|
592
596
|
expect(result.pending.map((e) => e.title)).toEqual(["explicit-from-test-entry"]);
|
|
593
597
|
});
|
|
594
598
|
});
|
|
599
|
+
|
|
600
|
+
describe("changes.json codemod fields resolve to real published scripts", () => {
|
|
601
|
+
function findChangesJsonFiles(dir: string): string[] {
|
|
602
|
+
const found: string[] = [];
|
|
603
|
+
for (const name of readdirSync(dir)) {
|
|
604
|
+
if (name === "node_modules") continue;
|
|
605
|
+
const full = join(dir, name);
|
|
606
|
+
if (statSync(full).isDirectory()) {
|
|
607
|
+
found.push(...findChangesJsonFiles(full));
|
|
608
|
+
} else if (name === "changes.json") {
|
|
609
|
+
found.push(full);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return found;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
test("every codemod field is a scripts/codemod/*.ts path that resolves to an existing published script", () => {
|
|
616
|
+
const coreChangelog = findCoreChangelogFile(REAL_REPO_ROOT);
|
|
617
|
+
const changesJsonFiles = [
|
|
618
|
+
...(coreChangelog ? [coreChangelog] : []),
|
|
619
|
+
...findFeaturesDirs(REAL_REPO_ROOT).flatMap((dir) => findChangesJsonFiles(dir)),
|
|
620
|
+
];
|
|
621
|
+
expect(changesJsonFiles.length).toBeGreaterThan(0);
|
|
622
|
+
|
|
623
|
+
const offenders: string[] = [];
|
|
624
|
+
for (const file of changesJsonFiles) {
|
|
625
|
+
const entries = JSON.parse(readFileSync(file, "utf-8")) as ReadonlyArray<{
|
|
626
|
+
readonly version: string;
|
|
627
|
+
readonly title: string;
|
|
628
|
+
readonly codemod?: string;
|
|
629
|
+
}>;
|
|
630
|
+
for (const entry of entries) {
|
|
631
|
+
if (typeof entry.codemod !== "string") continue;
|
|
632
|
+
if (/\s/.test(entry.codemod)) {
|
|
633
|
+
offenders.push(
|
|
634
|
+
`${file} · ${entry.version} "${entry.title}": codemod is a shell command, not a path: "${entry.codemod}"`,
|
|
635
|
+
);
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
if (resolveCodemodScript(REAL_REPO_ROOT, entry.codemod) === null) {
|
|
639
|
+
offenders.push(
|
|
640
|
+
`${file} · ${entry.version} "${entry.title}": codemod path does not resolve: "${entry.codemod}"`,
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
expect(offenders).toEqual([]);
|
|
647
|
+
});
|
|
648
|
+
});
|
|
@@ -37,7 +37,7 @@ const testFeature = defineFeature("test", (r) => {
|
|
|
37
37
|
"item:list",
|
|
38
38
|
z.object({ search: z.string().optional() }),
|
|
39
39
|
async () => [{ id: 1, name: "Test" }],
|
|
40
|
-
{ access: { openToAll:
|
|
40
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
41
41
|
);
|
|
42
42
|
|
|
43
43
|
r.streamHandler(
|
|
@@ -750,7 +750,7 @@ describe("feature-declared HTTP routes (r.httpRoute)", () => {
|
|
|
750
750
|
}),
|
|
751
751
|
);
|
|
752
752
|
r.queryHandler("item:list", z.object({}), async () => [{ id: 7 }], {
|
|
753
|
-
access: { openToAll:
|
|
753
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
754
754
|
});
|
|
755
755
|
r.httpRoute({
|
|
756
756
|
method: "GET",
|
|
@@ -18,7 +18,7 @@ const testFeature = defineFeature("blob", (r) => {
|
|
|
18
18
|
"note:create",
|
|
19
19
|
z.object({ body: z.string() }),
|
|
20
20
|
async (event) => ({ isSuccess: true, data: { body: event.payload.body } }),
|
|
21
|
-
{ access: { openToAll:
|
|
21
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
22
22
|
);
|
|
23
23
|
});
|
|
24
24
|
|
|
@@ -18,7 +18,7 @@ const leakyFeature = defineFeature("leaky", (r) => {
|
|
|
18
18
|
defineQueryHandler({
|
|
19
19
|
name: "raw",
|
|
20
20
|
schema: z.object({}),
|
|
21
|
-
access: { openToAll:
|
|
21
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
22
22
|
handler: async () => ({ email: CIPHERTEXT, note: "plain" }),
|
|
23
23
|
}),
|
|
24
24
|
);
|
|
@@ -26,7 +26,7 @@ const leakyFeature = defineFeature("leaky", (r) => {
|
|
|
26
26
|
defineQueryHandler({
|
|
27
27
|
name: "clean",
|
|
28
28
|
schema: z.object({}),
|
|
29
|
-
access: { openToAll:
|
|
29
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
30
30
|
handler: async () => ({ email: "marc@example.com" }),
|
|
31
31
|
}),
|
|
32
32
|
);
|
|
@@ -18,7 +18,7 @@ const localeProbe = defineFeature("locale-probe", (r) => {
|
|
|
18
18
|
"read-locale",
|
|
19
19
|
z.object({}),
|
|
20
20
|
async (_event, ctx) => ({ isSuccess: true, data: { locale: ctx.locale } }),
|
|
21
|
-
{ access: { openToAll:
|
|
21
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
22
22
|
);
|
|
23
23
|
});
|
|
24
24
|
|
package/src/changes.json
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.269.0",
|
|
4
|
+
"type": "breaking",
|
|
5
|
+
"title": "`openToAll: true` is removed — every openToAll grant now requires { reason } (fw#2858).",
|
|
6
|
+
"detail": "`OpenToAllAccessRule` (`@cosmicdrift/kumiko-types/handlers`) no longer accepts `true`; only `OpenToAllDeclaration` (`{ reason: string; personalData?: \"tenant-members\" }`) satisfies it, so `{ openToAll: true }` no longer type-checks. `isOpenToAllGranted` denies `true` from untyped sources (pattern JSON, Designer) the same way it already denied a malformed object — a bare `true` reaching it now returns `false` instead of granting access. The boot validator (`engine/boot-validator/access-declarations.ts`) rejects an untyped `openToAll: true` access declaration with an error pointing at `{ reason }` instead of registering the handler. The pattern-library Designer access field (`shared-fields.ts` `accessRuleField`) is now a required text input on `access.openToAll.reason` instead of a boolean toggle, so the Designer can only ever produce the object form. `build-config-feature-schema.ts` synthesizes `{ openToAll: { reason: \"config key declares the \\\"all\\\" role, so every signed-in user of the tenant may read/write it\" } }` for a config key whose roles include `\"all\"`, instead of `{ openToAll: true }`. `boot-validator/nav.ts` and `renderer-web/app/create-app.tsx` switched from `\"openToAll\" in access` to `isOpenToAllGranted(access)`, so a malformed or `true` rule is no longer treated as a visible screen/workspace. The feature-AST extractor now also extracts `escapeHatch: { reason }` on write/query handlers (`extractors/handlers.ts`) and on `r.hook` options (`extractors/hooks.ts`), round-tripped through render/patch the same way `access`/`rateLimit` already were.",
|
|
7
|
+
"migration": "Replace every `openToAll: true` with `openToAll: { reason: \"<who may call it and why that is safe without a role>\" }`, adding `personalData: \"tenant-members\"` where the boot validator requires it for a write handler accepting unbound personal data. Pattern-library or Designer-authored JSON that still has `openToAll: true` must be re-saved with a reason before it type-checks or passes boot. `kumiko-upgrade --apply` runs the migrate-open-to-all codemod automatically, rewriting test files to the default reason and listing every non-test site for manual review; run `bun packages/framework/src/scripts/codemod/migrate-open-to-all.ts --test-reason \"<text>\" <paths>` directly to override the default test reason.",
|
|
8
|
+
"codemod": "scripts/codemod/migrate-open-to-all.ts"
|
|
9
|
+
},
|
|
2
10
|
{
|
|
3
11
|
"version": "0.269.0",
|
|
4
12
|
"type": "breaking",
|
|
@@ -17,8 +25,8 @@
|
|
|
17
25
|
"type": "breaking",
|
|
18
26
|
"title": "ctx.db.unsafeRaw(reason) gated by escapeHatch, tenancy: \"global\" invariants, bundled features migrated off ctx.db.raw (fw#2858).",
|
|
19
27
|
"detail": "`TenantDb.unsafeRaw(reason)` returns the unfiltered `DbRunner` only when the calling write or query handler declares `escapeHatch: { reason }` (lifecycle hooks: `r.hook(..., { escapeHatch })`; a hook no longer inherits the handler's grant, same as the #2859 SYSTEM identity-switch gate). Without a declaration it throws `AccessDeniedError`; an empty reason throws `Error`. `r.systemScope()` features keep using `ctx.systemDb.unsafeRaw(reason)`. `TenantDb.raw` stays deprecated until fw#2860. `createTenantDb`'s 7th parameter changed from an `EscapeHatchDeclaration` to `TenantDbGrants` `{ globalWrites?, unsafeRaw? }`; `withUnsafeRawGrant(tenantDb, grant)` rebinds the unsafeRaw grant. `bindHookIdentitySwitchGrant`/`withHookIdentitySwitchGrant` are renamed to `bindHookEscapeHatchGrant`/`withHookEscapeHatchGrant`. Global tenancy: a `tenancy: \"global\"` entity must declare `systemStream: true` (boot validator + executor) and its create/update payloads may not carry a non-SYSTEM `tenantId`; tenant-mode `insertOne` into a global table with a `tenant_id` column and `db.global(table)` writes with a non-SYSTEM `tenantId` are rejected; `defineUnmanagedTable({ tenancy: \"global\" })` rejects a `tenant_id` column; new `declareGlobalTenancy(table)` declares a plain `table()` store without `tenant_id` as global. Bundled features: `userEntity` is `tenancy: \"global\"`, `store_global_feature_state` is declared global, and every bundled `ctx.db.raw` call site now uses `ctx.db.global(table)`, a filtered `ctx.db` method, or `ctx.db.unsafeRaw(reason)` with an `escapeHatch` on the handler. Handlers that call the auth-mfa `mfaStatusChecker`/MFA code verifier callbacks, handlers wrapped by cap-counter `withStockCap` (declares it automatically) and callers of the custom-fields quota/field-access query helpers now need that declaration.",
|
|
20
|
-
"migration": "Replace each `ctx.db.raw` use: reads of a `tenancy: \"global\"` table → `ctx.db.global(table).selectMany/fetchOne(...)`; reads/inserts whose where/values only use the caller's own tenantId → `ctx.db.selectMany/fetchOne/insertOne(table, ...)` (method form); everything else → `ctx.db.unsafeRaw(\"<what is read/written and why the tenant filter cannot apply>\")` plus `escapeHatch: { reason }` on the write/query handler definition or in the `r.hook` options. Generic reasons (todo, legacy, migration) fail infra#788. `
|
|
21
|
-
"codemod": "
|
|
28
|
+
"migration": "Replace each `ctx.db.raw` use: reads of a `tenancy: \"global\"` table → `ctx.db.global(table).selectMany/fetchOne(...)`; reads/inserts whose where/values only use the caller's own tenantId → `ctx.db.selectMany/fetchOne/insertOne(table, ...)` (method form); everything else → `ctx.db.unsafeRaw(\"<what is read/written and why the tenant filter cannot apply>\")` plus `escapeHatch: { reason }` on the write/query handler definition or in the `r.hook` options. Generic reasons (todo, legacy, migration) fail infra#788. `kumiko-upgrade --apply` runs the migrate-db-raw codemod automatically, rewriting the global-table and own-tenant cases and listing the remaining sites for manual review. Custom handlers calling `mfaStatusChecker`/the MFA code verifier or the custom-fields query helpers must declare `escapeHatch`. Direct `createTenantDb(..., escapeHatch)` calls pass `{ globalWrites: escapeHatch }` (and `unsafeRaw` if needed). Rename imports of `bindHookIdentitySwitchGrant`/`withHookIdentitySwitchGrant`. `defineUnmanagedTable({ tenancy: \"global\" })` definitions must drop their `tenant_id` column; `tenancy: \"global\"` entities must add `systemStream: true`.",
|
|
29
|
+
"codemod": "scripts/codemod/migrate-db-raw.ts"
|
|
22
30
|
},
|
|
23
31
|
{
|
|
24
32
|
"version": "0.267.0",
|
|
@@ -36,7 +36,7 @@ const LIST_QN = "filternotes:query:note:list";
|
|
|
36
36
|
const filterNotesFeature = defineFeature("filternotes", (r) => {
|
|
37
37
|
r.crud("note", filterNoteEntity, {
|
|
38
38
|
write: { access: { roles: ["Admin"] } },
|
|
39
|
-
read: { access: { openToAll:
|
|
39
|
+
read: { access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
40
40
|
});
|
|
41
41
|
});
|
|
42
42
|
|
|
@@ -38,7 +38,7 @@ const derivativesTestFeature = defineFeature("derivativestest", (r) => {
|
|
|
38
38
|
);
|
|
39
39
|
return { isSuccess: true as const, data: result };
|
|
40
40
|
},
|
|
41
|
-
{ access: { openToAll:
|
|
41
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
42
42
|
);
|
|
43
43
|
|
|
44
44
|
// Catches the error INSIDE the handler (not via HTTP serialization) so the
|
|
@@ -69,7 +69,7 @@ const derivativesTestFeature = defineFeature("derivativestest", (r) => {
|
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
|
-
{ access: { openToAll:
|
|
72
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
73
73
|
);
|
|
74
74
|
|
|
75
75
|
r.job("record", { trigger: { manual: true }, runIn: "worker" }, async (payload, ctx) => {
|
|
@@ -19,10 +19,10 @@ function dashboardFeature(
|
|
|
19
19
|
) {
|
|
20
20
|
return defineFeature("demo", (r) => {
|
|
21
21
|
r.queryHandler("incident:open-count", z.object({}), async () => ({ count: 3 }), {
|
|
22
|
-
access: { openToAll:
|
|
22
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
23
23
|
});
|
|
24
24
|
r.queryHandler("incident:latest", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
25
|
-
access: { openToAll:
|
|
25
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
26
26
|
});
|
|
27
27
|
r.screen({
|
|
28
28
|
id: "overview",
|
|
@@ -245,10 +245,10 @@ describe("validateBoot — dashboard screens", () => {
|
|
|
245
245
|
|
|
246
246
|
const catalogFeature = defineFeature("catalog", (r) => {
|
|
247
247
|
r.queryHandler("items:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
248
|
-
access: { openToAll:
|
|
248
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
249
249
|
});
|
|
250
250
|
r.queryHandler("items:status", z.object({}), async () => ({ enabled: true }), {
|
|
251
|
-
access: { openToAll:
|
|
251
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
252
252
|
});
|
|
253
253
|
r.screen({
|
|
254
254
|
id: "items",
|
|
@@ -289,7 +289,7 @@ describe("validateBoot — dashboard screen panels (fw#2841)", () => {
|
|
|
289
289
|
test("accepts a same-feature short id", () => {
|
|
290
290
|
const feature = defineFeature("demo", (r) => {
|
|
291
291
|
r.queryHandler("items:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
292
|
-
access: { openToAll:
|
|
292
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
293
293
|
});
|
|
294
294
|
r.screen({
|
|
295
295
|
id: "items",
|
|
@@ -50,7 +50,7 @@ function stubListHandler(r: any, entityName: string): void {
|
|
|
50
50
|
name: `${entityName}:list`,
|
|
51
51
|
schema: z.object({}),
|
|
52
52
|
handler: async () => ({ rows: [], nextCursor: null }) as never,
|
|
53
|
-
access: { openToAll:
|
|
53
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -7,7 +7,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
7
7
|
test("rejects hand-written searchable:true when the query schema has no search param (3a)", () => {
|
|
8
8
|
const feature = defineFeature("ledger", (r) => {
|
|
9
9
|
r.queryHandler("schedule:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
10
|
-
access: { openToAll:
|
|
10
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
11
11
|
});
|
|
12
12
|
r.screen({
|
|
13
13
|
id: "schedule-list",
|
|
@@ -29,7 +29,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
29
29
|
"schedule:list",
|
|
30
30
|
z.object({ search: z.string().optional() }),
|
|
31
31
|
async () => ({ rows: [], nextCursor: null }),
|
|
32
|
-
{ access: { openToAll:
|
|
32
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
33
33
|
);
|
|
34
34
|
r.screen({
|
|
35
35
|
id: "schedule-list",
|
|
@@ -50,7 +50,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
50
50
|
"schedule:list",
|
|
51
51
|
z.object({ sort: z.string().optional() }),
|
|
52
52
|
async () => ({ rows: [], nextCursor: null }),
|
|
53
|
-
{ access: { openToAll:
|
|
53
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
54
54
|
);
|
|
55
55
|
r.screen({
|
|
56
56
|
id: "schedule-list",
|
|
@@ -71,7 +71,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
71
71
|
"schedule:list",
|
|
72
72
|
z.object({ search: z.string().optional(), sort: z.string().optional() }),
|
|
73
73
|
async () => ({ rows: [], nextCursor: null }),
|
|
74
|
-
{ access: { openToAll:
|
|
74
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
75
75
|
);
|
|
76
76
|
r.screen({
|
|
77
77
|
id: "schedule-list",
|
|
@@ -91,7 +91,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
91
91
|
test("passes when the schema offers neither search nor sort and no defaultSort is set", () => {
|
|
92
92
|
const feature = defineFeature("ledger", (r) => {
|
|
93
93
|
r.queryHandler("schedule:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
94
|
-
access: { openToAll:
|
|
94
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
95
95
|
});
|
|
96
96
|
r.screen({
|
|
97
97
|
id: "schedule-list",
|
|
@@ -112,7 +112,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
112
112
|
"schedule:list",
|
|
113
113
|
z.object({ search: z.string().optional() }),
|
|
114
114
|
async () => ({ rows: [], nextCursor: null }),
|
|
115
|
-
{ access: { openToAll:
|
|
115
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
116
116
|
);
|
|
117
117
|
r.screen({
|
|
118
118
|
id: "schedule-list",
|
|
@@ -135,7 +135,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
135
135
|
"schedule:list",
|
|
136
136
|
z.object({ search: z.string().optional() }),
|
|
137
137
|
async () => ({ rows: [], nextCursor: null }),
|
|
138
|
-
{ access: { openToAll:
|
|
138
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
139
139
|
);
|
|
140
140
|
r.screen({
|
|
141
141
|
id: "download-attempt-list",
|
|
@@ -154,7 +154,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
154
154
|
test("rejects hand-authored sortable on a projectionList screen (fw#2165 review)", () => {
|
|
155
155
|
const feature = defineFeature("ledger", (r) => {
|
|
156
156
|
r.queryHandler("schedule:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
157
|
-
access: { openToAll:
|
|
157
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
158
158
|
});
|
|
159
159
|
r.screen({
|
|
160
160
|
id: "schedule-list",
|
|
@@ -173,7 +173,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
173
173
|
test("rejects hand-authored paginated on a projectionList screen (fw#2165 review)", () => {
|
|
174
174
|
const feature = defineFeature("ledger", (r) => {
|
|
175
175
|
r.queryHandler("schedule:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
176
|
-
access: { openToAll:
|
|
176
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
177
177
|
});
|
|
178
178
|
r.screen({
|
|
179
179
|
id: "schedule-list",
|
|
@@ -202,7 +202,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
202
202
|
z.object({}),
|
|
203
203
|
async () => ({ rows: [], nextCursor: null }),
|
|
204
204
|
{
|
|
205
|
-
access: { openToAll:
|
|
205
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
206
206
|
},
|
|
207
207
|
);
|
|
208
208
|
r.screen({ id: "schedule-detail", type: "custom", renderer: { react: "stub" } });
|
|
@@ -251,7 +251,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
251
251
|
"schedule:list",
|
|
252
252
|
z.object({ filter: z.unknown().optional() }),
|
|
253
253
|
async () => ({ rows: [], nextCursor: null }),
|
|
254
|
-
{ access: { openToAll:
|
|
254
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
255
255
|
);
|
|
256
256
|
r.screen({
|
|
257
257
|
id: "schedule-list",
|
|
@@ -274,7 +274,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
274
274
|
z.object({}),
|
|
275
275
|
async () => ({ rows: [], nextCursor: null }),
|
|
276
276
|
{
|
|
277
|
-
access: { openToAll:
|
|
277
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
278
278
|
},
|
|
279
279
|
);
|
|
280
280
|
r.screen({
|
|
@@ -297,7 +297,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
297
297
|
"schedule:list",
|
|
298
298
|
z.object({ filters: z.unknown().optional() }),
|
|
299
299
|
async () => ({ rows: [], nextCursor: null }),
|
|
300
|
-
{ access: { openToAll:
|
|
300
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
301
301
|
);
|
|
302
302
|
r.screen({
|
|
303
303
|
id: "schedule-list",
|
|
@@ -326,7 +326,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
326
326
|
"schedule:list",
|
|
327
327
|
z.object({ filters: z.unknown().optional() }),
|
|
328
328
|
async () => ({ rows: [], nextCursor: null }),
|
|
329
|
-
{ access: { openToAll:
|
|
329
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
330
330
|
);
|
|
331
331
|
r.screen({
|
|
332
332
|
id: "schedule-list",
|
|
@@ -363,7 +363,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
363
363
|
"schedule:list",
|
|
364
364
|
z.object({ filters: z.unknown().optional() }),
|
|
365
365
|
async () => ({ rows: [], nextCursor: null }),
|
|
366
|
-
{ access: { openToAll:
|
|
366
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
367
367
|
);
|
|
368
368
|
r.screen({
|
|
369
369
|
id: "schedule-list",
|
|
@@ -386,7 +386,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
386
386
|
z.object({}),
|
|
387
387
|
async () => ({ rows: [], nextCursor: null }),
|
|
388
388
|
{
|
|
389
|
-
access: { openToAll:
|
|
389
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
390
390
|
},
|
|
391
391
|
);
|
|
392
392
|
r.screen({
|
|
@@ -417,7 +417,7 @@ describe("validateBoot — projectionList screens", () => {
|
|
|
417
417
|
"schedule:list",
|
|
418
418
|
z.object({ filter: z.unknown().optional(), filters: z.unknown().optional() }),
|
|
419
419
|
async () => ({ rows: [], nextCursor: null }),
|
|
420
|
-
{ access: { openToAll:
|
|
420
|
+
{ access: { openToAll: { reason: "test handler callable by any signed-in test user" } } },
|
|
421
421
|
);
|
|
422
422
|
r.screen({
|
|
423
423
|
id: "schedule-list",
|
|
@@ -20,7 +20,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
20
20
|
test("projectionList column not in the paged query's row shape throws", () => {
|
|
21
21
|
const feature = defineFeature("catalog", (r) => {
|
|
22
22
|
r.queryHandler("items:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
23
|
-
access: { openToAll:
|
|
23
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
24
24
|
outputSchema: pagedSchema,
|
|
25
25
|
});
|
|
26
26
|
r.screen({
|
|
@@ -39,7 +39,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
39
39
|
test("projectionList column present in the row shape does not throw", () => {
|
|
40
40
|
const feature = defineFeature("catalog", (r) => {
|
|
41
41
|
r.queryHandler("items:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
42
|
-
access: { openToAll:
|
|
42
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
43
43
|
outputSchema: pagedSchema,
|
|
44
44
|
});
|
|
45
45
|
r.screen({
|
|
@@ -56,7 +56,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
56
56
|
test("projectionList column with a label is exempt as a virtual/computed column", () => {
|
|
57
57
|
const feature = defineFeature("catalog", (r) => {
|
|
58
58
|
r.queryHandler("items:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
59
|
-
access: { openToAll:
|
|
59
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
60
60
|
outputSchema: pagedSchema,
|
|
61
61
|
});
|
|
62
62
|
r.screen({
|
|
@@ -78,7 +78,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
78
78
|
test("projectionList without a declared outputSchema skips the column check entirely", () => {
|
|
79
79
|
const feature = defineFeature("catalog", (r) => {
|
|
80
80
|
r.queryHandler("items:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
81
|
-
access: { openToAll:
|
|
81
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
82
82
|
});
|
|
83
83
|
r.screen({
|
|
84
84
|
id: "items",
|
|
@@ -94,7 +94,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
94
94
|
test("projectionList outputSchema that isn't a ZodObject (e.g. a union) skips the column check", () => {
|
|
95
95
|
const feature = defineFeature("catalog", (r) => {
|
|
96
96
|
r.queryHandler("items:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
97
|
-
access: { openToAll:
|
|
97
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
98
98
|
outputSchema: z.union([pagedSchema, z.null()]),
|
|
99
99
|
});
|
|
100
100
|
r.screen({
|
|
@@ -111,11 +111,11 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
111
111
|
test("relatedList column not in the query's row shape throws", () => {
|
|
112
112
|
const feature = defineFeature("app", (r) => {
|
|
113
113
|
r.queryHandler("rent:detail", z.object({}), async () => ({ description: "x" }), {
|
|
114
|
-
access: { openToAll:
|
|
114
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
115
115
|
outputSchema: z.object({ description: z.string() }),
|
|
116
116
|
});
|
|
117
117
|
r.queryHandler("rent:payments", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
118
|
-
access: { openToAll:
|
|
118
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
119
119
|
outputSchema: z.object({
|
|
120
120
|
rows: z.array(z.object({ amount: z.number() })),
|
|
121
121
|
nextCursor: z.string().nullable(),
|
|
@@ -145,7 +145,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
145
145
|
test("projectionDetail header.title referencing an unknown field throws", () => {
|
|
146
146
|
const feature = defineFeature("app", (r) => {
|
|
147
147
|
r.queryHandler("tenant:detail", z.object({}), async () => ({ id: "1", name: "x" }), {
|
|
148
|
-
access: { openToAll:
|
|
148
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
149
149
|
outputSchema: z.object({ id: z.string(), name: z.string() }),
|
|
150
150
|
});
|
|
151
151
|
r.screen({
|
|
@@ -164,7 +164,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
164
164
|
test("projectionDetail header.status referencing an unknown field throws", () => {
|
|
165
165
|
const feature = defineFeature("app", (r) => {
|
|
166
166
|
r.queryHandler("tenant:detail", z.object({}), async () => ({ id: "1", name: "x" }), {
|
|
167
|
-
access: { openToAll:
|
|
167
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
168
168
|
outputSchema: z.object({ id: z.string(), name: z.string() }),
|
|
169
169
|
});
|
|
170
170
|
r.screen({
|
|
@@ -181,7 +181,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
181
181
|
test("projectionDetail metrics referencing an unknown field throws", () => {
|
|
182
182
|
const feature = defineFeature("app", (r) => {
|
|
183
183
|
r.queryHandler("tenant:detail", z.object({}), async () => ({ id: "1", balance: 0 }), {
|
|
184
|
-
access: { openToAll:
|
|
184
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
185
185
|
outputSchema: z.object({ id: z.string(), balance: z.number() }),
|
|
186
186
|
});
|
|
187
187
|
r.screen({
|
|
@@ -214,7 +214,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
214
214
|
z.object({}),
|
|
215
215
|
async () => ({ id: "1", name: "x", balance: 0 }),
|
|
216
216
|
{
|
|
217
|
-
access: { openToAll:
|
|
217
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
218
218
|
outputSchema: z.object({
|
|
219
219
|
id: z.string(),
|
|
220
220
|
name: z.string(),
|
|
@@ -241,7 +241,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
241
241
|
test("dashboard stat panel valueField referencing an unknown field throws", () => {
|
|
242
242
|
const feature = defineFeature("demo", (r) => {
|
|
243
243
|
r.queryHandler("open-count", z.object({}), async () => ({ value: "0" }), {
|
|
244
|
-
access: { openToAll:
|
|
244
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
245
245
|
outputSchema: z.object({ value: z.string() }),
|
|
246
246
|
});
|
|
247
247
|
r.screen({
|
|
@@ -269,7 +269,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
269
269
|
test("dashboard stat-group child deltaField referencing an unknown field throws", () => {
|
|
270
270
|
const feature = defineFeature("demo", (r) => {
|
|
271
271
|
r.queryHandler("net-worth", z.object({}), async () => ({ value: "0" }), {
|
|
272
|
-
access: { openToAll:
|
|
272
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
273
273
|
outputSchema: z.object({ value: z.string() }),
|
|
274
274
|
});
|
|
275
275
|
r.screen({
|
|
@@ -308,7 +308,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
308
308
|
test("dashboard list panel column not in the query's row shape throws", () => {
|
|
309
309
|
const feature = defineFeature("demo", (r) => {
|
|
310
310
|
r.queryHandler("next-events", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
311
|
-
access: { openToAll:
|
|
311
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
312
312
|
outputSchema: z.object({
|
|
313
313
|
rows: z.array(z.object({ title: z.string() })),
|
|
314
314
|
nextCursor: z.string().nullable(),
|
|
@@ -342,7 +342,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
342
342
|
defineQueryHandler({
|
|
343
343
|
name: "items:detail",
|
|
344
344
|
schema: z.object({ id: z.string() }),
|
|
345
|
-
access: { openToAll:
|
|
345
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
346
346
|
outputSchema: z.object({ id: z.string(), name: z.string() }),
|
|
347
347
|
handler: async () => ({ id: "1", name: "x" }),
|
|
348
348
|
}),
|
|
@@ -366,7 +366,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
366
366
|
definePagedQueryHandler({
|
|
367
367
|
name: "items:list",
|
|
368
368
|
schema: z.object({}),
|
|
369
|
-
access: { openToAll:
|
|
369
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
370
370
|
outputSchema: pagedSchema,
|
|
371
371
|
handler: async () => ({ rows: [], nextCursor: null }),
|
|
372
372
|
}),
|
|
@@ -390,7 +390,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
390
390
|
definePagedQueryHandler({
|
|
391
391
|
name: "items:list",
|
|
392
392
|
schema: z.object({}),
|
|
393
|
-
access: { openToAll:
|
|
393
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
394
394
|
// Row schema passed directly instead of wrapping it in
|
|
395
395
|
// { rows: [...], nextCursor } — the mistake fw#2493's follow-up
|
|
396
396
|
// check catches instead of silently skipping every column check.
|
|
@@ -417,7 +417,7 @@ describe("validateBoot — query output schema column refs (fw#2493)", () => {
|
|
|
417
417
|
definePagedQueryHandler({
|
|
418
418
|
name: "items:list",
|
|
419
419
|
schema: z.object({}),
|
|
420
|
-
access: { openToAll:
|
|
420
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
421
421
|
outputSchema: pagedSchema,
|
|
422
422
|
handler: async () => ({ rows: [], nextCursor: null }),
|
|
423
423
|
}),
|
|
@@ -36,7 +36,7 @@ describe("validateBoot — query QN refs (fw#2178)", () => {
|
|
|
36
36
|
test("projectionDetail relatedList section with a dead query QN throws (b)", () => {
|
|
37
37
|
const feature = defineFeature("app", (r) => {
|
|
38
38
|
r.queryHandler("rent:detail", z.object({}), async () => ({ description: "x" }), {
|
|
39
|
-
access: { openToAll:
|
|
39
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
40
40
|
});
|
|
41
41
|
r.screen({
|
|
42
42
|
id: "rent-detail",
|
|
@@ -96,7 +96,7 @@ describe("validateBoot — query QN refs (fw#2178)", () => {
|
|
|
96
96
|
test("dashboard filter optionsQuery with a dead query QN throws", () => {
|
|
97
97
|
const feature = defineFeature("demo", (r) => {
|
|
98
98
|
r.queryHandler("open-count", z.object({}), async () => ({ value: "0" }), {
|
|
99
|
-
access: { openToAll:
|
|
99
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
100
100
|
});
|
|
101
101
|
r.screen({
|
|
102
102
|
id: "overview",
|
|
@@ -132,7 +132,7 @@ describe("validateBoot — query QN refs (fw#2178)", () => {
|
|
|
132
132
|
test("a screen referencing a query registered by a different mounted feature does not throw (d)", () => {
|
|
133
133
|
const provider = defineFeature("catalog", (r) => {
|
|
134
134
|
r.queryHandler("items:list", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
135
|
-
access: { openToAll:
|
|
135
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
136
136
|
});
|
|
137
137
|
});
|
|
138
138
|
const consumer = defineFeature("storefront", (r) => {
|
|
@@ -44,7 +44,7 @@ describe("S0 Integration — full surface stack", () => {
|
|
|
44
44
|
name: "compliance:query:for-tenant",
|
|
45
45
|
schema: z.object({}),
|
|
46
46
|
handler: async () => ({ profile: "eu-dsgvo" }) as never,
|
|
47
|
-
access: { openToAll:
|
|
47
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
50
|
|
|
@@ -101,7 +101,7 @@ describe("S0 Integration — full surface stack", () => {
|
|
|
101
101
|
name: "user:list",
|
|
102
102
|
schema: z.object({}),
|
|
103
103
|
handler: async () => ({ rows: [], nextCursor: null }) as never,
|
|
104
|
-
access: { openToAll:
|
|
104
|
+
access: { openToAll: { reason: "test handler callable by any signed-in test user" } },
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
r.useExtension(EXT_USER_DATA, "user", {});
|