@c9up/station 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/StationProvider.d.ts +94 -18
- package/dist/StationProvider.d.ts.map +1 -1
- package/dist/StationProvider.js +693 -148
- package/dist/StationProvider.js.map +1 -1
- package/dist/views/form.d.ts +56 -16
- package/dist/views/form.d.ts.map +1 -1
- package/dist/views/form.js +53 -75
- package/dist/views/form.js.map +1 -1
- package/dist/views/list.d.ts +43 -5
- package/dist/views/list.d.ts.map +1 -1
- package/dist/views/list.js +63 -60
- package/dist/views/list.js.map +1 -1
- package/dist/views/login.d.ts +20 -8
- package/dist/views/login.d.ts.map +1 -1
- package/dist/views/login.js +15 -33
- package/dist/views/login.js.map +1 -1
- package/dist/views/show.d.ts +18 -4
- package/dist/views/show.d.ts.map +1 -1
- package/dist/views/show.js +29 -15
- package/dist/views/show.js.map +1 -1
- package/package.json +22 -5
- package/src/StationProvider.ts +941 -155
- package/src/views/form.ts +111 -113
- package/src/views/list.ts +108 -75
- package/src/views/login.ts +31 -44
- package/src/views/show.ts +47 -18
- package/templates/errors/404.inker +4 -0
- package/templates/form.inker +3 -0
- package/{dist/views/layout.js → templates/layout.inker} +10 -35
- package/templates/list.inker +8 -0
- package/templates/login.inker +4 -0
- package/templates/show.inker +4 -0
- package/dist/views/errors/404.d.ts +0 -12
- package/dist/views/errors/404.d.ts.map +0 -1
- package/dist/views/errors/404.js +0 -19
- package/dist/views/errors/404.js.map +0 -1
- package/dist/views/escape.d.ts +0 -30
- package/dist/views/escape.d.ts.map +0 -1
- package/dist/views/escape.js +0 -34
- package/dist/views/escape.js.map +0 -1
- package/dist/views/layout.d.ts +0 -24
- package/dist/views/layout.d.ts.map +0 -1
- package/dist/views/layout.js.map +0 -1
- package/src/views/errors/404.ts +0 -27
- package/src/views/escape.ts +0 -46
- package/src/views/layout.ts +0 -90
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* swallowed.
|
|
19
19
|
*/
|
|
20
20
|
import type { ColumnMetadata } from "@c9up/atlas";
|
|
21
|
+
import type { Resource } from "./types.js";
|
|
21
22
|
/**
|
|
22
23
|
* Duck-typed slice of the host's IoC container — Station MUST stay
|
|
23
24
|
* publishable without importing `@c9up/ream` directly (memory
|
|
@@ -25,7 +26,7 @@ import type { ColumnMetadata } from "@c9up/atlas";
|
|
|
25
26
|
*/
|
|
26
27
|
interface StationContainer {
|
|
27
28
|
singleton<T>(key: unknown, factory: () => T): void;
|
|
28
|
-
resolve<T>(key: unknown): T
|
|
29
|
+
resolve<T>(key: unknown): Promise<T>;
|
|
29
30
|
has(key: unknown): boolean;
|
|
30
31
|
}
|
|
31
32
|
interface StationConfigStore {
|
|
@@ -35,6 +36,54 @@ export interface StationAppContext {
|
|
|
35
36
|
container: StationContainer;
|
|
36
37
|
config: StationConfigStore;
|
|
37
38
|
}
|
|
39
|
+
/** A rune `RuleChain` — only the builders the derivation calls. */
|
|
40
|
+
interface RuneRuleChain {
|
|
41
|
+
optional(): RuneRuleChain;
|
|
42
|
+
nullable(): RuneRuleChain;
|
|
43
|
+
parse(fn: (value: unknown) => unknown): RuneRuleChain;
|
|
44
|
+
}
|
|
45
|
+
/** rune's `rules` factory — the constructors Station maps columns to. */
|
|
46
|
+
interface RuneRules {
|
|
47
|
+
string(): RuneRuleChain;
|
|
48
|
+
number(): RuneRuleChain;
|
|
49
|
+
boolean(): RuneRuleChain;
|
|
50
|
+
/** Type-free chain — a structural (`json`/`jsonb`) column that must accept objects/arrays. */
|
|
51
|
+
any(): RuneRuleChain;
|
|
52
|
+
}
|
|
53
|
+
/** A single rune `ValidationError`. */
|
|
54
|
+
interface RuneValidationError {
|
|
55
|
+
field: string;
|
|
56
|
+
rule: string;
|
|
57
|
+
message: string;
|
|
58
|
+
index?: number;
|
|
59
|
+
meta?: Record<string, unknown>;
|
|
60
|
+
}
|
|
61
|
+
/** Result of `schema.validateResult()` — synchronous, never throws. */
|
|
62
|
+
type RuneValidationResult = {
|
|
63
|
+
valid: true;
|
|
64
|
+
errors: ReadonlyArray<RuneValidationError>;
|
|
65
|
+
data: Record<string, unknown>;
|
|
66
|
+
} | {
|
|
67
|
+
valid: false;
|
|
68
|
+
errors: ReadonlyArray<RuneValidationError>;
|
|
69
|
+
data?: undefined;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* A built rune schema — only the result-based check is consumed.
|
|
73
|
+
*
|
|
74
|
+
* `validateResult`, NOT `validate`: rune reserves `validate()` for the VineJS
|
|
75
|
+
* contract (async, throwing). Reading `.valid` off a Promise gives `undefined`,
|
|
76
|
+
* so keeping the old name would have made every admin write fail closed with an
|
|
77
|
+
* empty error list.
|
|
78
|
+
*/
|
|
79
|
+
interface RuneSchema {
|
|
80
|
+
validateResult(data: unknown): RuneValidationResult;
|
|
81
|
+
}
|
|
82
|
+
/** Lazy-imported `@c9up/rune` value surface (mirror `AtlasModule`). */
|
|
83
|
+
interface RuneModule {
|
|
84
|
+
schema(fields: Record<string, RuneRuleChain>): RuneSchema;
|
|
85
|
+
rules: RuneRules;
|
|
86
|
+
}
|
|
38
87
|
/**
|
|
39
88
|
* Config block read from `app.config.get<StationConfig>('station')`.
|
|
40
89
|
* Every field is optional — the defaults match the 54.2 / 54.3 / 54.4
|
|
@@ -68,26 +117,53 @@ export interface StationConfig {
|
|
|
68
117
|
/** @internal Reset module-level flags between tests. */
|
|
69
118
|
export declare function resetStationProviderFlags(): void;
|
|
70
119
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
*
|
|
81
|
-
*
|
|
120
|
+
* True when at least one resource mounts a write action that maps a request
|
|
121
|
+
* body onto columns (create / edit). `destroy` needs no body validation. This
|
|
122
|
+
* is the AC7 predicate: it decides whether `@c9up/rune` is REQUIRED at boot —
|
|
123
|
+
* exported so `agnostic-peers-missing.test.ts` can pin the decision directly
|
|
124
|
+
* (the dynamic-import-absent path can't be simulated inside vitest, exactly as
|
|
125
|
+
* for atlas — see that file's header).
|
|
126
|
+
*/
|
|
127
|
+
export declare function resourcesNeedValidation(resources: ReadonlyArray<Resource>): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Derive a `@c9up/rune` validation schema (57.7) from an entity's writable
|
|
130
|
+
* column metadata — the structural replacement for the hand-rolled
|
|
131
|
+
* `filterWritableBody`. The mass-assignment guarantee is now INHERENT:
|
|
132
|
+
* `schema.validateResult()` returns only declared-column keys, so unknown body keys
|
|
133
|
+
* (`role`, `passwordHash`, PK, timestamps) are dropped automatically — no
|
|
134
|
+
* explicit filtering pass.
|
|
82
135
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
136
|
+
* Excluded, exactly as the old guard did: the primary key, framework-managed
|
|
137
|
+
* timestamps (both the Lucid-style `autoManaged` flag AND the `created_at /
|
|
138
|
+
* updated_at / deleted_at` name convention) — plus, new in 57.7, relations and
|
|
139
|
+
* the soft-delete column (`excludedProps`). Metadata is read column-by-column,
|
|
140
|
+
* NEVER `in` on an instance (`@Column() declare` makes `in` always false —
|
|
141
|
+
* mirror `BaseRepository.#hydrate`).
|
|
85
142
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
143
|
+
* Per-column rule mapping tolerates the form-post wire shape (values arrive as
|
|
144
|
+
* strings — rune does NOT coerce): booleans `.parse(isCheckedValue)`, numbers
|
|
145
|
+
* `.parse` string→Number (NaN falls through to a type error), everything else
|
|
146
|
+
* `rules.string()`. `.parse`/`.optional`/`.nullable` force rune's TS path, so
|
|
147
|
+
* no native `.node` is touched.
|
|
148
|
+
*
|
|
149
|
+
* Returns the built schema plus the set of boolean columns — the handler
|
|
150
|
+
* default-fills an ABSENT boolean key to `false` before validating (an
|
|
151
|
+
* unchecked checkbox submits nothing; this preserves the old edit-clears-box
|
|
152
|
+
* behaviour).
|
|
153
|
+
*/
|
|
154
|
+
export declare function deriveWritableSchema(columns: ReadonlyArray<ColumnMetadata>, pkColumn: string, autoManaged: ReadonlySet<string>, excludedProps: ReadonlySet<string>, rune: RuneModule): {
|
|
155
|
+
schema: RuneSchema;
|
|
156
|
+
booleanKeys: ReadonlySet<string>;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Validate a request body against a derived schema (57.7). Default-fills any
|
|
160
|
+
* ABSENT boolean column to `false` first (unchecked checkbox = no submission),
|
|
161
|
+
* preserving the old `filterWritableBody` checkbox semantics, then runs rune's
|
|
162
|
+
* synchronous, never-throwing `validateResult()`. On success `result.data` holds only
|
|
163
|
+
* declared-column keys (mass-assignment inherent). Exported for the unit tests
|
|
164
|
+
* that pin the coercion CRUX.
|
|
88
165
|
*/
|
|
89
|
-
|
|
90
|
-
export declare function filterWritableBody(body: Record<string, unknown>, columns: ReadonlyArray<ColumnMetadata>, pkColumn: string, autoManaged: ReadonlySet<string>): Record<string, unknown>;
|
|
166
|
+
export declare function validateWritableBody(schema: RuneSchema, booleanKeys: ReadonlySet<string>, body: Record<string, unknown>): RuneValidationResult;
|
|
91
167
|
export default class StationProvider {
|
|
92
168
|
#private;
|
|
93
169
|
protected app: StationAppContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StationProvider.d.ts","sourceRoot":"","sources":["../src/StationProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"StationProvider.d.ts","sourceRoot":"","sources":["../src/StationProvider.ts"],"names":[],"mappings":"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"}
|