import { m as MetadataType, a as MetadataRepository } from './repository-Dl3EudaY.js'; import 'zod'; interface ContractSuiteOptions { /** If the implementation supports `version`-pinned reads, set true. */ supportsVersionedReads?: boolean; /** * The metadata type nearly every clause writes under. Defaults to `'view'`. * * A FIXTURE knob, deliberately not an invariant knob: no clause below is * added, removed or weakened by moving it, because none of the seven * invariants is a statement about a particular type. It exists because an * implementation may sit behind a **write-authorization door** keyed on the * type — `SysMetadataRepository.assertAllowed()` refuses any type whose * registry entry lacks `allowOrgOverride` — so a hard-coded fixture type * decides which implementations can be held to the table at all. Naming the * two types here is what keeps that ONE table, instead of carving a second * one for the engine-backed implementation to be measured against. */ primaryType?: MetadataType; /** * A second, DISTINCT type, used only where a clause must prove a type filter * discriminates (`list`'s `type` filter, `watch`'s). Defaults to `'object'`. * Same fixture-knob argument as {@link primaryType}; it must differ from it * or those two clauses assert nothing. */ secondaryType?: MetadataType; /** * Issue-tracked exceptions to the invariant table above. * * ⚠️ Read the shape before reaching for it. A declaration does NOT skip the * clause it names — a skipped clause is indistinguishable from coverage in a * green run, which is the one failure a shared contract suite must not have. * It swaps the clause for one that **pins the divergent behaviour**, so the * suite reds the day the implementation starts conforming and whoever fixes * it is told, by name, to delete the declaration in the same PR. Same * shrink-only, audited-in-both-directions shape as the repo's other ledgers. * * There is deliberately no free-form escape here: every member is one named * invariant, and its value is the issue that will retire it. */ declaredDivergences?: DeclaredDivergences; } /** @see ContractSuiteOptions.declaredDivergences */ interface DeclaredDivergences { /** * **Invariant 6, first half (a numeric `since` replays).** The * implementation's `watch(filter, since)` never replays from its durable * log, so an event that committed before the subscription cannot be * surfaced however high `since` is set. * * ⚠️ Scoped to the NUMERIC-`since` half on purpose. A `watch(filter)` with * no `since` that surfaces nothing already committed is not a divergence at * all — invariant 6 owes such a subscriber live events only, and replaying * for it is a MAY. That sentence used to be unwritten, and this member's * own doc used to name the no-`since` case as part of the divergence. * * Value is the tracking issue, e.g. `'#10842'`. **No declaration today:** * `SysMetadataRepository`, the only one there has ever been, was fixed and * deleted its line — the pin below is what told it to. An empty ledger is * the mechanism at rest, not dead code; the shrink-only direction is the * only one it travels without a new tracking issue. */ resumableWatch?: string; } declare function runRepositoryContractTests(label: string, factory: () => MetadataRepository | Promise, opts?: ContractSuiteOptions): void; /** * [ADR-0106 / #3682] The metadata-plane FLS contract, as ONE case table every * schema-serving exit is driven through. * * ## Why this is shared rather than per-suite * * ADR-0106 D5 states the invariant negatively — "every schema-serving outlet, * or the mask is decoration" — and the exits it names live in two packages and * six code paths: `@objectstack/rest`'s single cached read, single uncached * read, layered read, compound-name read and list read, plus * `@objectstack/runtime`'s `/metadata` catch-all (protocol-backed, * registry-backed, last-ditch, list, and the legacy one-segment spelling). * A per-suite table would let a new exit ship with no coverage and nothing * would go red; driving them all from this one means a forgotten exit fails * **by name**. * * The invariant itself is one sentence: for a restricted caller, an unreadable * field is COMPLETELY ABSENT from every exit — no third, quieter answer (not a * name with the details stripped, not a `null`, not a 200 with empty `fields`). * * Same shape, and the same reason, as `contract-suite.ts` next door: one * contract, several implementations, one table. */ /** The object schema every exit serves while the contract runs. */ declare const FLS_CONTRACT_OBJECT: { readonly name: "account"; readonly label: "Account"; readonly fields: { readonly id: { readonly type: "text"; readonly label: "Id"; }; readonly name: { readonly type: "text"; readonly label: "Name"; }; readonly salary_grade: { readonly type: "select"; readonly label: "Salary Grade"; readonly options: readonly [{ readonly value: "band_a"; readonly label: "Band A"; }, { readonly value: "band_b"; readonly label: "Band B"; }]; readonly requiredPermissions: readonly ["view_compensation"]; }; readonly bonus_formula: { readonly type: "formula"; readonly label: "Bonus"; readonly formula: "salary_grade == \"band_a\" ? 0.2 : 0.1"; readonly visibleWhen: "record.status == \"active\""; }; }; }; /** Every field name {@link FLS_CONTRACT_OBJECT} declares. */ declare const FLS_CONTRACT_ALL_FIELDS: readonly ["id", "name", "salary_grade", "bonus_formula"]; /** What the exit's `security` double answers, or that it throws. */ type FlsContractReadable = readonly string[] | undefined | 'throw'; /** The one verdict every exit must reach for a case. */ type FlsContractVerdict = /** These field names are present; those are COMPLETELY absent. */ { kind: 'fields'; present: readonly string[]; absent: readonly string[]; } /** Every declared field survives — the passthrough tiers (D4 exemptions, D6 tier 1/2, D8). */ | { kind: 'unmasked'; } /** D6 tier 3 — the exit refuses: 5xx, no body carrying `fields`. */ | { kind: 'fault'; }; interface ObjectSchemaMaskCase { /** Stable id — this is what a forgotten exit fails by. */ readonly id: string; /** Why this row exists, in the ADR's terms. */ readonly why: string; /** The caller's execution context, as the exit resolves it. */ readonly context: Record; /** What `security.getMetadataReadableFields` answers for `account`. */ readonly readable: FlsContractReadable; /** ADR-0106 D8 — masking off for this deployment. */ readonly maskingDisabled?: boolean; readonly expect: FlsContractVerdict; } /** * The ADR-0106 case table. * * Ordered by tier, not by convenience: the projection first, then the three D6 * failure postures, then the D4 exemptions, then the D7 and D8 knobs. */ declare const OBJECT_SCHEMA_MASK_CASES: readonly ObjectSchemaMaskCase[]; /** What an exit answered when the contract drove it. */ type ObjectSchemaMaskOutcome = { kind: 'document'; document: unknown; } | { kind: 'fault'; status: number; }; /** One schema-serving outlet under test. */ interface ObjectSchemaMaskExit { /** Human name — this is what a broken exit is reported as. */ readonly name: string; /** Serve {@link FLS_CONTRACT_OBJECT} through this outlet under `testCase`. */ run(testCase: ObjectSchemaMaskCase): Promise; } /** * Assert one exit's answer against one case. * * Framework-free on purpose (throws plain `Error`s) so the table can be driven * from a vitest suite in either package without this module importing vitest — * `contract-suite.ts` pays that import cost because it *is* a suite; this is a * matcher. */ declare function assertObjectSchemaMaskCase(exitName: string, testCase: ObjectSchemaMaskCase, outcome: ObjectSchemaMaskOutcome): void; /** * The `security` service double a case implies. * * Registers `getMetadataReadableFields` (ADR-0106 D7's entry point) AND * `getReadableFields` at the same answer, so an exit that feature-detects * either one is driven identically — the fallback path is exercised by the * dedicated plugin-security suite, not by making outlets disagree here. * Returns `undefined` for the no-service tier so the caller can register * nothing at all. */ declare function securityDoubleFor(testCase: ObjectSchemaMaskCase): Record | undefined; export { type ContractSuiteOptions, type DeclaredDivergences, FLS_CONTRACT_ALL_FIELDS, FLS_CONTRACT_OBJECT, type FlsContractReadable, type FlsContractVerdict, OBJECT_SCHEMA_MASK_CASES, type ObjectSchemaMaskCase, type ObjectSchemaMaskExit, type ObjectSchemaMaskOutcome, assertObjectSchemaMaskCase, runRepositoryContractTests, securityDoubleFor };