@fougere/app 0.6.0-alpha.0 → 0.8.0-alpha.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/dist/auth.d.ts +1 -7
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js.map +1 -1
- package/dist/boot.d.ts +14 -85
- package/dist/boot.d.ts.map +1 -1
- package/dist/boot.js +25 -79
- package/dist/boot.js.map +1 -1
- package/dist/client.d.ts +5 -24
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +6 -32
- package/dist/client.js.map +1 -1
- package/dist/express.d.ts +2 -12
- package/dist/express.d.ts.map +1 -1
- package/dist/express.js +4 -52
- package/dist/express.js.map +1 -1
- package/dist/form.d.ts +11 -56
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +15 -33
- package/dist/form.js.map +1 -1
- package/dist/graphql.d.ts +2 -28
- package/dist/graphql.d.ts.map +1 -1
- package/dist/graphql.js +1 -6
- package/dist/graphql.js.map +1 -1
- package/dist/index.d.ts +1 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -11
- package/dist/index.js.map +1 -1
- package/dist/rest.d.ts +2 -16
- package/dist/rest.d.ts.map +1 -1
- package/dist/rest.js +4 -34
- package/dist/rest.js.map +1 -1
- package/dist/serve.d.ts +10 -57
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +12 -55
- package/dist/serve.js.map +1 -1
- package/dist/session.d.ts +2 -7
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +2 -7
- package/dist/session.js.map +1 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +1 -11
- package/dist/state.js.map +1 -1
- package/dist/web.d.ts +3 -19
- package/dist/web.d.ts.map +1 -1
- package/dist/web.js +4 -32
- package/dist/web.js.map +1 -1
- package/package.json +11 -11
- package/src/auth.ts +1 -7
- package/src/boot.ts +37 -136
- package/src/client.ts +7 -33
- package/src/express.ts +4 -52
- package/src/form.ts +20 -73
- package/src/graphql.ts +2 -28
- package/src/index.ts +1 -11
- package/src/rest.ts +4 -34
- package/src/serve.ts +13 -60
- package/src/session.ts +2 -7
- package/src/state.ts +1 -11
- package/src/web.ts +4 -32
package/dist/form.d.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import type { SchemaView, ValidationError } from '@fougere/schema';
|
|
2
|
-
/**
|
|
3
|
-
* What an entity class exposes to a form — the schema statics it already has.
|
|
4
|
-
*
|
|
5
|
-
* `SchemaView` and the real `Field`, not a local re-description of the axes: this file
|
|
6
|
-
* used to declare its own `FieldLike` with `shape?` optional, so it kept judging by a
|
|
7
|
-
* looser contract than the schema's own and would never have seen `shape` become
|
|
8
|
-
* required.
|
|
9
|
-
*/
|
|
2
|
+
/** What an entity class exposes to a form — the schema statics it already has. */
|
|
10
3
|
export type FormEntity = SchemaView;
|
|
11
4
|
export interface FormField {
|
|
12
5
|
name: string;
|
|
@@ -20,28 +13,8 @@ export interface FormField {
|
|
|
20
13
|
/** Enum values, when control is 'select'. */
|
|
21
14
|
options?: string[];
|
|
22
15
|
/**
|
|
23
|
-
* What the browser enforces, under the names it already knows — spread this on the
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* The shape holds `minLength`/`maximum`/`pattern`; a browser holds `minlength`/
|
|
27
|
-
* `max`/`pattern` and enforces them with no JavaScript at all. Carrying them here
|
|
28
|
-
* is a projection, not a second rule: the judge reads the same shape, and a form
|
|
29
|
-
* that ignores these still gets the same verdict — it just gets it later, and a
|
|
30
|
-
* screen reader never gets it at all.
|
|
31
|
-
*
|
|
32
|
-
* `type` is part of the contract, not decoration: `email` and `url` are formats the
|
|
33
|
-
* shape states and the browser checks live, per field, as one types. A page writing
|
|
34
|
-
* `type="email"` by hand is spelling a second time what the card already said.
|
|
35
|
-
*
|
|
36
|
-
* Three deliberate absences, each one a place where the attribute would mean
|
|
37
|
-
* something the shape does not say:
|
|
38
|
-
* - a `date` field gets no `type` — neither `date` nor `datetime-local` produces the
|
|
39
|
-
* RFC 3339 string a `date-time` shape judges, so the browser would accept what the
|
|
40
|
-
* judge refuses;
|
|
41
|
-
* - `select` and `boolean` are not inputs — the page picks the widget, `control` says
|
|
42
|
-
* which;
|
|
43
|
-
* - a required `boolean` gets no `required` — on a checkbox that attribute means
|
|
44
|
-
* "must be CHECKED", where the shape only says the value must be supplied.
|
|
16
|
+
* What the browser enforces, under the names it already knows — spread this on the input and the
|
|
17
|
+
* page states no rule of its own.
|
|
45
18
|
*/
|
|
46
19
|
attrs?: {
|
|
47
20
|
type?: 'text' | 'email' | 'url' | 'number';
|
|
@@ -52,18 +25,10 @@ export interface FormField {
|
|
|
52
25
|
max?: number;
|
|
53
26
|
pattern?: string;
|
|
54
27
|
};
|
|
55
|
-
/**
|
|
56
|
-
* The value the field is born with — the literal its `lifecycle.create` rule names.
|
|
57
|
-
* Present so the form can SHOW what is about to be written; the storage realizes it
|
|
58
|
-
* either way, so a form that ignores this still produces the same row.
|
|
59
|
-
*/
|
|
28
|
+
/** The value the field is born with — the literal its `lifecycle.create` rule names. */
|
|
60
29
|
default?: unknown;
|
|
61
30
|
}
|
|
62
|
-
/**
|
|
63
|
-
* The fields a create form is made of: membership from the io projection
|
|
64
|
-
* (`Visibility.input` — what a client may supply), requiredness from the
|
|
65
|
-
* lifecycle axis (any create rule makes absence legal).
|
|
66
|
-
*/
|
|
31
|
+
/** The fields a create form is made of. */
|
|
67
32
|
export declare function formFieldsOf(entity: FormEntity, entityKey: string): FormField[];
|
|
68
33
|
export interface TableColumn {
|
|
69
34
|
name: string;
|
|
@@ -75,27 +40,17 @@ export interface TableColumn {
|
|
|
75
40
|
/** The same key a form uses for the same field — one convention, two projections. */
|
|
76
41
|
labelKey: string;
|
|
77
42
|
label: string;
|
|
78
|
-
/**
|
|
79
|
-
* The entity a `link` points at, under the key its door is named by. Always present on a
|
|
80
|
-
* reference: the card carries the target's name, and a card rebuilt with no sibling to
|
|
81
|
-
* resolve to keeps it as a stand-in rather than losing it.
|
|
82
|
-
*/
|
|
43
|
+
/** The entity a `link` points at, under the key its door is named by. */
|
|
83
44
|
to?: string;
|
|
84
45
|
}
|
|
85
|
-
/**
|
|
86
|
-
* The columns a list is made of: membership from the io projection (`Visibility.output` — what
|
|
87
|
-
* may leave), minus collections, because a cell holds one value and a `many()` is a page.
|
|
88
|
-
*
|
|
89
|
-
* Which column identifies the row is NOT answered here — `FieldSet.primary` answers it for a
|
|
90
|
-
* shape, and its own doc records what five private copies of that loop cost.
|
|
91
|
-
*/
|
|
46
|
+
/** The columns a list is made of. */
|
|
92
47
|
export declare function tableColumnsOf(entity: FormEntity, entityKey: string): TableColumn[];
|
|
93
48
|
/**
|
|
94
|
-
* The wire body of the form's values — an empty control is an absent value
|
|
95
|
-
*
|
|
96
|
-
*
|
|
49
|
+
* The wire body of the form's values — an empty control is an absent value at the create boundary
|
|
50
|
+
* (absence is validated by the lifecycle axis, an empty string would be validated as a present bad
|
|
51
|
+
* value).
|
|
97
52
|
*/
|
|
98
53
|
export declare function payloadOf(values: Record<string, unknown>): Record<string, unknown>;
|
|
99
|
-
/** Index
|
|
54
|
+
/** Index validator errors by field — local validator and remote validator share this shape. */
|
|
100
55
|
export declare function errorsByField(errors: ValidationError[]): Record<string, string>;
|
|
101
56
|
//# sourceMappingURL=form.d.ts.map
|
package/dist/form.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAS,UAAU,EAAE,eAAe,EAAoB,MAAM,iBAAiB,CAAC;AAE5F,kFAAkF;AAClF,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC;AAOpC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7E,QAAQ,EAAE,OAAO,CAAC;IAClB,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;QAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,wFAAwF;IACxF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA6DD,2CAA2C;AAC3C,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,CAkB/E;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjE,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAaD,qCAAqC;AACrC,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CAYnF;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIlF;AAED,+FAA+F;AAC/F,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAO/E"}
|
package/dist/form.js
CHANGED
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
import { Lifecycle } from '@fougere/schema';
|
|
2
2
|
/**
|
|
3
|
-
* Form contract, pure part — derives what a create/edit form is made of
|
|
4
|
-
*
|
|
5
|
-
* usable by any renderer (the page owns the widgets).
|
|
6
|
-
*/
|
|
7
|
-
import { Anatomy, lowerFirst, Role, Visibility } from '@fougere/schema';
|
|
8
|
-
/**
|
|
9
|
-
* The literal a field is born with, when it declares one.
|
|
10
|
-
*
|
|
11
|
-
* `text({ default: 'x' })` and `oneOf('a', 'b', { default: 'a' })` both compile to
|
|
12
|
-
* `lifecycle.create = { value }` — the create rule that answers the field's absence.
|
|
13
|
-
* The other create rules ('now', { generate }, 'optional') name no literal: their value
|
|
14
|
-
* is decided at write time, so a form has nothing to show for them.
|
|
3
|
+
* Form contract, pure part — derives what a create/edit form is made of from the entity's field
|
|
4
|
+
* axes.
|
|
15
5
|
*/
|
|
6
|
+
import { Shapes, lowerFirst, Role, Visibility } from '@fougere/schema';
|
|
7
|
+
/** The literal a field is born with, when it declares one. */
|
|
16
8
|
function defaultOf(field) {
|
|
17
9
|
return Lifecycle.of(field).literal?.value;
|
|
18
10
|
}
|
|
@@ -22,7 +14,7 @@ function baseType(type) {
|
|
|
22
14
|
return type.find((t) => t !== 'null') ?? 'string';
|
|
23
15
|
return type ?? 'string';
|
|
24
16
|
}
|
|
25
|
-
/** The formats a browser has an input type for — the rest stay `text`,
|
|
17
|
+
/** The formats a browser has an input type for — the rest stay `text`, validated later. */
|
|
26
18
|
const CONTROL_BY_FORMAT = {
|
|
27
19
|
'date-time': 'date',
|
|
28
20
|
email: 'email',
|
|
@@ -32,7 +24,7 @@ function controlOf(field) {
|
|
|
32
24
|
// Through `anatomy`, never `shape.type` directly: the nullable form is the `[T,'null']`
|
|
33
25
|
// union, which a direct comparison misses in silence. It is also what narrows the shape
|
|
34
26
|
// union, so `enum` and `format` are only reachable on the branches that carry them.
|
|
35
|
-
const base =
|
|
27
|
+
const base = Shapes.of(field.shape).base;
|
|
36
28
|
if (base?.type === 'string' && base.enum?.length)
|
|
37
29
|
return 'select';
|
|
38
30
|
if (base?.type === 'number' || base?.type === 'integer')
|
|
@@ -45,14 +37,14 @@ function controlOf(field) {
|
|
|
45
37
|
}
|
|
46
38
|
/** A closed set's members, when the shape declares one — `oneOf('draft','live')`. */
|
|
47
39
|
function enumOf(field) {
|
|
48
|
-
const base =
|
|
40
|
+
const base = Shapes.of(field.shape).base;
|
|
49
41
|
return base?.type === 'string' ? base.enum : undefined;
|
|
50
42
|
}
|
|
51
43
|
/** Controls that ARE an `<input type>` — see the two absences on {@link FormField.attrs}. */
|
|
52
44
|
const INPUT_TYPES = new Set(['text', 'email', 'url', 'number']);
|
|
53
45
|
/** The shape's bounds, under the names a browser already enforces. */
|
|
54
46
|
function attrsOf(field, control, required) {
|
|
55
|
-
const base =
|
|
47
|
+
const base = Shapes.of(field.shape).base;
|
|
56
48
|
const text = base?.type === 'string' ? base : undefined;
|
|
57
49
|
const numeric = base?.type === 'number' || base?.type === 'integer' ? base : undefined;
|
|
58
50
|
const attrs = {
|
|
@@ -73,11 +65,7 @@ function attrsOf(field, control, required) {
|
|
|
73
65
|
function labelOf(name, entityKey) {
|
|
74
66
|
return { labelKey: `${entityKey}.${name}`, label: name.charAt(0).toUpperCase() + name.slice(1) };
|
|
75
67
|
}
|
|
76
|
-
/**
|
|
77
|
-
* The fields a create form is made of: membership from the io projection
|
|
78
|
-
* (`Visibility.input` — what a client may supply), requiredness from the
|
|
79
|
-
* lifecycle axis (any create rule makes absence legal).
|
|
80
|
-
*/
|
|
68
|
+
/** The fields a create form is made of. */
|
|
81
69
|
export function formFieldsOf(entity, entityKey) {
|
|
82
70
|
return Object.entries(Visibility.of(entity.getFields()).input).map(([name, field]) => {
|
|
83
71
|
const f = field;
|
|
@@ -101,7 +89,7 @@ export function formFieldsOf(entity, entityKey) {
|
|
|
101
89
|
function renderOf(field) {
|
|
102
90
|
if (Role.of(field).isReference)
|
|
103
91
|
return 'link';
|
|
104
|
-
const base =
|
|
92
|
+
const base = Shapes.of(field.shape).base;
|
|
105
93
|
if (base?.type === 'number' || base?.type === 'integer')
|
|
106
94
|
return 'number';
|
|
107
95
|
if (base?.type === 'boolean')
|
|
@@ -112,13 +100,7 @@ function renderOf(field) {
|
|
|
112
100
|
return 'date';
|
|
113
101
|
return 'text';
|
|
114
102
|
}
|
|
115
|
-
/**
|
|
116
|
-
* The columns a list is made of: membership from the io projection (`Visibility.output` — what
|
|
117
|
-
* may leave), minus collections, because a cell holds one value and a `many()` is a page.
|
|
118
|
-
*
|
|
119
|
-
* Which column identifies the row is NOT answered here — `FieldSet.primary` answers it for a
|
|
120
|
-
* shape, and its own doc records what five private copies of that loop cost.
|
|
121
|
-
*/
|
|
103
|
+
/** The columns a list is made of. */
|
|
122
104
|
export function tableColumnsOf(entity, entityKey) {
|
|
123
105
|
return Object.entries(Visibility.of(entity.getFields()).output)
|
|
124
106
|
.filter(([, field]) => !Role.of(field).isCollection)
|
|
@@ -133,14 +115,14 @@ export function tableColumnsOf(entity, entityKey) {
|
|
|
133
115
|
});
|
|
134
116
|
}
|
|
135
117
|
/**
|
|
136
|
-
* The wire body of the form's values — an empty control is an absent value
|
|
137
|
-
*
|
|
138
|
-
*
|
|
118
|
+
* The wire body of the form's values — an empty control is an absent value at the create boundary
|
|
119
|
+
* (absence is validated by the lifecycle axis, an empty string would be validated as a present bad
|
|
120
|
+
* value).
|
|
139
121
|
*/
|
|
140
122
|
export function payloadOf(values) {
|
|
141
123
|
return Object.fromEntries(Object.entries(values).filter(([, v]) => v !== undefined && v !== ''));
|
|
142
124
|
}
|
|
143
|
-
/** Index
|
|
125
|
+
/** Index validator errors by field — local validator and remote validator share this shape. */
|
|
144
126
|
export function errorsByField(errors) {
|
|
145
127
|
const byField = {};
|
|
146
128
|
for (const err of errors) {
|
package/dist/form.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form.js","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C
|
|
1
|
+
{"version":3,"file":"form.js","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMvE,8DAA8D;AAC9D,SAAS,SAAS,CAAC,KAAY;IAC7B,OAAO,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC;AAC5C,CAAC;AA8BD,sEAAsE;AACtE,SAAS,QAAQ,CAAC,IAAa;IAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAQ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CAAY,IAAI,QAAQ,CAAC;IACvF,OAAQ,IAAe,IAAI,QAAQ,CAAC;AACtC,CAAC;AAED,2FAA2F;AAC3F,MAAM,iBAAiB,GAAyC;IAC9D,WAAW,EAAE,MAAM;IACnB,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,KAAK;CACX,CAAC;AAEF,SAAS,SAAS,CAAC,KAAY;IAC7B,wFAAwF;IACxF,wFAAwF;IACxF,oFAAoF;IACpF,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;IACzC,IAAI,IAAI,EAAE,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM;QAAE,OAAO,QAAQ,CAAC;IAClE,IAAI,IAAI,EAAE,IAAI,KAAK,QAAQ,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IACzE,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC/C,IAAI,IAAI,EAAE,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC;IAC5F,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,qFAAqF;AACrF,SAAS,MAAM,CAAC,KAAY;IAC1B,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;IACzC,OAAO,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACzD,CAAC;AAED,6FAA6F;AAC7F,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEhE,sEAAsE;AACtE,SAAS,OAAO,CAAC,KAAY,EAAE,OAA6B,EAAE,QAAiB;IAC7E,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACxD,MAAM,OAAO,GAAG,IAAI,EAAE,IAAI,KAAK,QAAQ,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACvF,MAAM,KAAK,GAAG;QACZ,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;QACpD,QAAQ,EAAE,CAAC,QAAQ,IAAI,OAAO,KAAK,SAAS,CAAC,IAAI,SAAS;QAC1D,SAAS,EAAE,IAAI,EAAE,SAAS;QAC1B,SAAS,EAAE,IAAI,EAAE,SAAS;QAC1B,GAAG,EAAE,OAAO,EAAE,OAAO;QACrB,GAAG,EAAE,OAAO,EAAE,OAAO;QACrB,OAAO,EAAE,IAAI,EAAE,OAAO;KACvB,CAAC;IACF,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;AACtF,CAAC;AAED;;;GAGG;AACH,SAAS,OAAO,CAAC,IAAY,EAAE,SAAiB;IAC9C,OAAO,EAAE,QAAQ,EAAE,GAAG,SAAS,IAAI,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACnG,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,YAAY,CAAC,MAAkB,EAAE,SAAiB;IAChE,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;QACnF,MAAM,CAAC,GAAG,KAAK,CAAC;QAChB,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,QAAQ,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC5C,OAAO;YACL,IAAI;YACJ,OAAO;YACP,QAAQ;YACR,GAAG,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;YAC3B,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC1B,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,EAAE;gBACvF,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAgBD,wFAAwF;AACxF,SAAS,QAAQ,CAAC,KAAY;IAC5B,IAAI,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,WAAW;QAAE,OAAO,MAAM,CAAC;IAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;IACzC,IAAI,IAAI,EAAE,IAAI,KAAK,QAAQ,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IACzE,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC/C,IAAI,IAAI,EAAE,IAAI,KAAK,QAAQ,IAAI,IAAI,EAAE,IAAI,KAAK,OAAO;QAAE,OAAO,MAAM,CAAC;IACrE,IAAI,IAAI,EAAE,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,MAAM,CAAC;IAC1E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,cAAc,CAAC,MAAkB,EAAE,SAAiB;IAClE,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC;SAC5D,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC;SACnD,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;QACrB,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;QACrC,OAAO;YACL,IAAI;YACJ,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC;YACvB,GAAG,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;YAC3B,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACnD,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,MAA+B;IACvD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC,CACtE,CAAC;AACJ,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,aAAa,CAAC,MAAyB;IACrD,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC;QACjD,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC;IACjC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/graphql.d.ts
CHANGED
|
@@ -1,25 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The GraphQL door — declared like the others, mounted like the others.
|
|
3
|
-
*
|
|
4
|
-
* Until now GraphQL was the odd one out: `adapters: { graphql: true }` was
|
|
5
|
-
* declarable and nothing read it, while an app that wanted a schema wrote fifteen
|
|
6
|
-
* lines of its own (a Pothos builder, a query type, a mutation type, `registerAll`,
|
|
7
|
-
* then `registerGraphQL` on a router). Every one of those lines is convention —
|
|
8
|
-
* there is no decision in them — so the app declaring the adapter is enough.
|
|
9
|
-
*
|
|
10
|
-
* The package is imported LAZILY, the same shape `db: 'sqlite'` uses (`resolveStorage`
|
|
11
|
-
* pulls `@fougere/adapter-sql` only when a database is declared). A schema builder is
|
|
12
|
-
* heavy and most apps serve none, so a host must not carry one to find out. Declaring
|
|
13
|
-
* the adapter without installing it is refused by name, the way an unresolvable dialect is.
|
|
14
|
-
*
|
|
15
|
-
* This file used to BUILD the schema — a Pothos builder, `registerAll`, then `graphql()`
|
|
16
|
-
* — which made it the only schema constructor in the repo, in the package least entitled
|
|
17
|
-
* to be one. Two costs, one cause: the derivation sat away from the adapter whose job it
|
|
18
|
-
* is, and `graphql` guards its types with `instanceOf`, so a schema built on one side of
|
|
19
|
-
* the package boundary was refused on the other as coming *"from another module or
|
|
20
|
-
* realm"*. Both are gone: `@fougere/adapter-graphql` derives and executes, this door
|
|
21
|
-
* translates the result into an `Outcome`.
|
|
22
|
-
*/
|
|
1
|
+
/** The GraphQL door — declared like the others, mounted like the others. */
|
|
23
2
|
import type { App } from '@fougere/core';
|
|
24
3
|
import type { Outcome } from './serve.js';
|
|
25
4
|
/** What a GraphQL request carries, whatever host read it. */
|
|
@@ -31,11 +10,6 @@ export interface GraphQLRequest {
|
|
|
31
10
|
surface?: string;
|
|
32
11
|
state: Record<string, unknown>;
|
|
33
12
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Execute a GraphQL request against the app's own operations.
|
|
36
|
-
*
|
|
37
|
-
* `pass` when the app declares no GraphQL adapter — the same answer `serveRest` gives,
|
|
38
|
-
* so a host that mounted the door takes nothing away from an app that did not ask for it.
|
|
39
|
-
*/
|
|
13
|
+
/** Execute a GraphQL request against the app's own operations. */
|
|
40
14
|
export declare function serveGraphQL(app: App, request: GraphQLRequest): Promise<Outcome>;
|
|
41
15
|
//# sourceMappingURL=graphql.d.ts.map
|
package/dist/graphql.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../src/graphql.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../src/graphql.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAyBD,kEAAkE;AAClE,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAoBtF"}
|
package/dist/graphql.js
CHANGED
|
@@ -10,12 +10,7 @@ async function executor() {
|
|
|
10
10
|
'that out.', { cause });
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
14
|
-
* Execute a GraphQL request against the app's own operations.
|
|
15
|
-
*
|
|
16
|
-
* `pass` when the app declares no GraphQL adapter — the same answer `serveRest` gives,
|
|
17
|
-
* so a host that mounted the door takes nothing away from an app that did not ask for it.
|
|
18
|
-
*/
|
|
13
|
+
/** Execute a GraphQL request against the app's own operations. */
|
|
19
14
|
export async function serveGraphQL(app, request) {
|
|
20
15
|
if (!app.adapters?.graphql)
|
|
21
16
|
return { kind: 'pass' };
|
package/dist/graphql.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../src/graphql.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../src/graphql.ts"],"names":[],"mappings":"AAsBA,KAAK,UAAU,QAAQ;IACrB,IAAI,CAAC;QACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;QAC/D,OAAO,SAAiC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,iFAAiF;YACjF,kFAAkF;YAClF,kFAAkF;YAClF,WAAW,EACX,EAAE,KAAK,EAAE,CACV,CAAC;IACJ,CAAC;AACH,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAQ,EAAE,OAAuB;IAClE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAEpD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACnB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,CAAC;IAC5E,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,QAAQ,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,oFAAoF;QACpF,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC,CAAC;IAEH,qFAAqF;IACrF,2DAA2D;IAC3D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAiC,EAAE,CAAC;AAC9E,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@fougere/app` — what an app host needs and what no host owns.
|
|
3
|
-
*
|
|
4
|
-
* Two adapters read this package: `@fougere/nuxt` and `@fougere/next`. Between
|
|
5
|
-
* them they share the boot, the three doors' decisions, the REST table, the form
|
|
6
|
-
* contract and the session view; what they do NOT share is how a request arrives,
|
|
7
|
-
* how routes are mounted, and how a value becomes reactive.
|
|
8
|
-
*
|
|
9
|
-
* The root entry pulls in the boot, which reads the filesystem — client code wants
|
|
10
|
-
* `@fougere/app/client`.
|
|
11
|
-
*/
|
|
1
|
+
/** `@fougere/app` — what an app host needs and what no host owns. */
|
|
12
2
|
export { configureFougere, extendFougere, useFougereApp, reloadFougere, type FougereServerConfig, } from './boot.js';
|
|
13
3
|
export { useFougereAuth } from './auth.js';
|
|
14
4
|
export { tableOf, matchRoute, type Matchable, type RouteMatch, } from './rest.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,aAAa,EACb,KAAK,mBAAmB,GACzB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,OAAO,EACP,UAAU,EACV,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,SAAS,EACT,SAAS,EACT,QAAQ,EACR,SAAS,EACT,aAAa,EACb,QAAQ,EACR,KAAK,WAAW,EAChB,KAAK,OAAO,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,SAAS,EACT,aAAa,EACb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,WAAW,GACjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAGjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@fougere/app` — what an app host needs and what no host owns.
|
|
3
|
-
*
|
|
4
|
-
* Two adapters read this package: `@fougere/nuxt` and `@fougere/next`. Between
|
|
5
|
-
* them they share the boot, the three doors' decisions, the REST table, the form
|
|
6
|
-
* contract and the session view; what they do NOT share is how a request arrives,
|
|
7
|
-
* how routes are mounted, and how a value becomes reactive.
|
|
8
|
-
*
|
|
9
|
-
* The root entry pulls in the boot, which reads the filesystem — client code wants
|
|
10
|
-
* `@fougere/app/client`.
|
|
11
|
-
*/
|
|
1
|
+
/** `@fougere/app` — what an app host needs and what no host owns. */
|
|
12
2
|
export { configureFougere, extendFougere, useFougereApp, reloadFougere, } from './boot.js';
|
|
13
3
|
export { useFougereAuth } from './auth.js';
|
|
14
4
|
export { tableOf, matchRoute, } from './rest.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,aAAa,GAEd,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,OAAO,EACP,UAAU,GAGX,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,SAAS,EACT,SAAS,EACT,QAAQ,EACR,SAAS,EACT,aAAa,EACb,QAAQ,GAGT,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,SAAS,EACT,aAAa,GAId,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,aAAa,EAAoB,MAAM,cAAc,CAAC;AAE/D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAuB,MAAM,cAAc,CAAC;AAEjE,sFAAsF;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/rest.d.ts
CHANGED
|
@@ -20,22 +20,8 @@ export type RouteMatch = {
|
|
|
20
20
|
}
|
|
21
21
|
/** Not a Fougère path at all: the app's own `/api/*` handlers must still see it. */
|
|
22
22
|
| null;
|
|
23
|
-
/**
|
|
24
|
-
* The table, per frond.
|
|
25
|
-
*
|
|
26
|
-
* `generateRoutes` prefixes every path the same way, while this door addresses a frond by
|
|
27
|
-
* name (`/api/{frond}/{plural}`) — so it runs once per frond, each with its own prefix and
|
|
28
|
-
* a filter naming it. That frond loop is the only thing this file knows that `schema-rest`
|
|
29
|
-
* does not; the verbs, the paths and the membership rule all come from there.
|
|
30
|
-
*/
|
|
23
|
+
/** The table, per frond. */
|
|
31
24
|
export declare function tableOf(app: App): Matchable[];
|
|
32
|
-
/**
|
|
33
|
-
* Path first, method second — a router's order, and what makes a 405 possible at all.
|
|
34
|
-
*
|
|
35
|
-
* The order matters where the two overlap: `/posts/publish` and `/posts/:id` both accept
|
|
36
|
-
* `GET /posts/publish`. Taking the most specific path first means the answer is "that verb
|
|
37
|
-
* is refused here", not `findById('publish')` — and never `publish()`, which is what this
|
|
38
|
-
* door used to do with the caller's session cookie attached.
|
|
39
|
-
*/
|
|
25
|
+
/** Path first, method second — a router's order, and what makes a 405 possible at all. */
|
|
40
26
|
export declare function matchRoute(table: Matchable[], method: string, segments: string[]): RouteMatch;
|
|
41
27
|
//# sourceMappingURL=rest.d.ts.map
|
package/dist/rest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,6EAA6E;AAC7E,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE;AACrE,mFAAmF;GACjF;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE;AACjD,oFAAoF;GAClF,IAAI,CAAC;AAMT,4BAA4B;AAC5B,wBAAgB,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,EAAE,CAmB7C;AAuBD,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,CAkB7F"}
|
package/dist/rest.js
CHANGED
|
@@ -1,24 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The REST table this app serves, and the rule that matches a request against it.
|
|
3
|
-
*
|
|
4
|
-
* Separated from the h3 handler on purpose: this file holds the whole of what the door
|
|
5
|
-
* DECIDES — which operation a verb and a path name — while `api/crud.ts` only translates
|
|
6
|
-
* that decision into h3. The rule was previously inline, untested, and had drifted into a
|
|
7
|
-
* second REST projection that answered differently from `schema-rest` on all three counts
|
|
8
|
-
* (verb, path, exposure).
|
|
9
|
-
*/
|
|
1
|
+
/** The REST table this app serves, and the rule that matches a request against it. */
|
|
10
2
|
import { generateRoutes } from '@fougere/adapter-rest';
|
|
11
3
|
// Keyed on the app, which `useFougereApp` memoizes — the table derives from the boot, so
|
|
12
4
|
// it changes exactly when the app does.
|
|
13
5
|
const tables = new WeakMap();
|
|
14
|
-
/**
|
|
15
|
-
* The table, per frond.
|
|
16
|
-
*
|
|
17
|
-
* `generateRoutes` prefixes every path the same way, while this door addresses a frond by
|
|
18
|
-
* name (`/api/{frond}/{plural}`) — so it runs once per frond, each with its own prefix and
|
|
19
|
-
* a filter naming it. That frond loop is the only thing this file knows that `schema-rest`
|
|
20
|
-
* does not; the verbs, the paths and the membership rule all come from there.
|
|
21
|
-
*/
|
|
6
|
+
/** The table, per frond. */
|
|
22
7
|
export function tableOf(app) {
|
|
23
8
|
const cached = tables.get(app);
|
|
24
9
|
if (cached)
|
|
@@ -54,24 +39,9 @@ function paramsOf(route, segments) {
|
|
|
54
39
|
function openness(route) {
|
|
55
40
|
return route.segments.filter((s) => s.startsWith(':')).length;
|
|
56
41
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Verbs this door accepts in place of the one the table names.
|
|
59
|
-
*
|
|
60
|
-
* `deriveMethod` gives `update` a single verb, PUT, while this door has always served
|
|
61
|
-
* PATCH on it too — and says so (`docs/infra/surfaces`, "PUT · PATCH"). An alias keeps
|
|
62
|
-
* that promise without giving the table a second row: both are mutations on a row, so
|
|
63
|
-
* nothing is widened, and the one thing the table decides — WHICH operation a path names —
|
|
64
|
-
* is still decided there alone.
|
|
65
|
-
*/
|
|
42
|
+
/** Verbs this door accepts in place of the one the table names. */
|
|
66
43
|
const ALIASES = { PATCH: 'PUT' };
|
|
67
|
-
/**
|
|
68
|
-
* Path first, method second — a router's order, and what makes a 405 possible at all.
|
|
69
|
-
*
|
|
70
|
-
* The order matters where the two overlap: `/posts/publish` and `/posts/:id` both accept
|
|
71
|
-
* `GET /posts/publish`. Taking the most specific path first means the answer is "that verb
|
|
72
|
-
* is refused here", not `findById('publish')` — and never `publish()`, which is what this
|
|
73
|
-
* door used to do with the caller's session cookie attached.
|
|
74
|
-
*/
|
|
44
|
+
/** Path first, method second — a router's order, and what makes a 405 possible at all. */
|
|
75
45
|
export function matchRoute(table, method, segments) {
|
|
76
46
|
const matches = table
|
|
77
47
|
.map((route) => ({ route, params: paramsOf(route, segments) }))
|
package/dist/rest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"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"}
|
package/dist/serve.d.ts
CHANGED
|
@@ -1,16 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The three doors, decided — and nothing about how a request arrives.
|
|
3
|
-
*
|
|
4
|
-
* A host (Nuxt, Next) owns exactly two translations: read the request into the
|
|
5
|
-
* plain values below, and write the outcome back out. Everything between — which
|
|
6
|
-
* operation a verb and a path name, which audience a segment selects, what a
|
|
7
|
-
* refusal becomes — is decided here, once, for every host.
|
|
8
|
-
*
|
|
9
|
-
* The split matters because the alternative was measured in this repo: two copies
|
|
10
|
-
* of a REST rule drifted until the Nuxt door answered differently from
|
|
11
|
-
* `schema-rest` on the verb, the path AND the exposure. A second host would have
|
|
12
|
-
* been a third copy.
|
|
13
|
-
*/
|
|
1
|
+
/** The three doors, decided — and nothing about how a request arrives. */
|
|
14
2
|
import { type App, type FrondCall, type InvocationContext } from '@fougere/core';
|
|
15
3
|
/** What a host must read off the request before any decision is possible. */
|
|
16
4
|
export interface DoorRequest {
|
|
@@ -19,11 +7,7 @@ export interface DoorRequest {
|
|
|
19
7
|
path: string;
|
|
20
8
|
query: Record<string, string>;
|
|
21
9
|
body?: unknown;
|
|
22
|
-
/**
|
|
23
|
-
* The server-resolved session. Stamped by the host from what IT resolved —
|
|
24
|
-
* never taken from the wire, which is the whole trust boundary of the browser
|
|
25
|
-
* door (`transport/http/src/server.ts` carries the same warning for the split).
|
|
26
|
-
*/
|
|
10
|
+
/** The server-resolved session. */
|
|
27
11
|
state: Record<string, unknown>;
|
|
28
12
|
}
|
|
29
13
|
/** What a host must write back. `pass` is the one that keeps a door additive. */
|
|
@@ -43,27 +27,12 @@ export type Outcome =
|
|
|
43
27
|
} & Record<string, unknown>;
|
|
44
28
|
headers?: Record<string, string>;
|
|
45
29
|
};
|
|
46
|
-
/**
|
|
47
|
-
* The audience this door serves — the path segment after `/_fougere/call`.
|
|
48
|
-
*
|
|
49
|
-
* The envelope is a surface like REST and GraphQL, so it selects its audience like
|
|
50
|
-
* they do; the difference is only that it takes it from the path instead of an
|
|
51
|
-
* option, because a door is mounted, not called. The same word names the directory
|
|
52
|
-
* (`handlers/public/`), the config key (`surfaces: { public: [...] }`) and this
|
|
53
|
-
* segment — derived, never configured.
|
|
54
|
-
*
|
|
55
|
-
* No escalation to guard: a named surface serves the entities it names and nothing
|
|
56
|
-
* else (closed by naming), so every one of them is a subset of what the bare path
|
|
57
|
-
* already serves.
|
|
58
|
-
*/
|
|
30
|
+
/** The audience this door serves — the path segment after `/_fougere/call`. */
|
|
59
31
|
export declare function surfaceOf(path: string): string | undefined;
|
|
60
32
|
/**
|
|
61
|
-
* Receiving end for the browser — same wire as process-to-process (JSON-RPC),
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* The runner follows the app's topology: local façades and remote doublures alike
|
|
66
|
-
* — the browser never knows where a Frond lives.
|
|
33
|
+
* Receiving end for the browser — same wire as process-to-process (JSON-RPC), different trust
|
|
34
|
+
* boundary: the browser sits outside the topology, so `state` is whatever the host resolved
|
|
35
|
+
* server-side, never what the payload claims.
|
|
67
36
|
*/
|
|
68
37
|
export declare function serveRpc(app: App, request: Pick<DoorRequest, 'path' | 'body' | 'state'>): Promise<unknown>;
|
|
69
38
|
/** The answer a host returns when it could not even parse the payload. */
|
|
@@ -76,34 +45,18 @@ export declare function rpcParseError(): {
|
|
|
76
45
|
};
|
|
77
46
|
};
|
|
78
47
|
/**
|
|
79
|
-
* Match the URL against the canonical table, invoke the call it names, shape the
|
|
80
|
-
* result for HTTP. The decision lives in `rest.ts`; dispatch belongs to the runner.
|
|
81
|
-
*
|
|
82
|
-
* `path` is what follows the REST mount point, so `/api/blog/posts/1` arrives as
|
|
83
|
-
* `blog/posts/1`. A path this door does not serve returns `pass`, and that is what
|
|
84
|
-
* lets an app keep its own `/api/*` handlers.
|
|
48
|
+
* Match the URL against the canonical table, invoke the call it names, shape the result for HTTP.
|
|
85
49
|
*/
|
|
86
50
|
export declare function serveRest(app: App, request: DoorRequest): Promise<Outcome>;
|
|
87
|
-
/**
|
|
88
|
-
* What an operation's return becomes on the wire.
|
|
89
|
-
*
|
|
90
|
-
* Separate from `serveRest` because it is a DECISION and dispatch is not: it can be
|
|
91
|
-
* pinned without a runner, and both hosts get it whether the call ran in memory or
|
|
92
|
-
* came back over JSON-RPC.
|
|
93
|
-
*/
|
|
51
|
+
/** What an operation's return becomes on the wire. */
|
|
94
52
|
export declare function shapeRest(operationName: string, result: unknown): Outcome;
|
|
95
53
|
type EntityClass = {
|
|
96
54
|
name: string;
|
|
97
55
|
};
|
|
98
56
|
type CallInput = Partial<InvocationContext>;
|
|
99
57
|
/**
|
|
100
|
-
* Name a call server-side and let the runner place it — local façade → direct
|
|
101
|
-
*
|
|
102
|
-
* never knows which.
|
|
103
|
-
*
|
|
104
|
-
* `state` is explicit here. Each host wraps this with its own way of finding the
|
|
105
|
-
* current request (Nitro's async context, Next's `headers()` scope), because that
|
|
106
|
-
* is the one part a host actually owns.
|
|
58
|
+
* Name a call server-side and let the runner place it — local façade → direct in-memory execution,
|
|
59
|
+
* a frond in `remotes` → JSON-RPC on the wire.
|
|
107
60
|
*/
|
|
108
61
|
export declare function invokeOn<T = unknown>(app: App, target: EntityClass | FrondCall, opOrInput?: string | CallInput, input?: CallInput, state?: Record<string, unknown>): Promise<T>;
|
|
109
62
|
export {};
|
package/dist/serve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EAIL,KAAK,GAAG,EACR,KAAK,SAAS,EACd,KAAK,iBAAiB,EACvB,MAAM,eAAe,CAAC;AAIvB,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,iFAAiF;AACjF,MAAM,MAAM,OAAO;AACjB,uEAAuE;AACrE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC;AAI7H,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1D;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAGhH;AAED,0EAA0E;AAC1E,wBAAgB,aAAa;aACT,KAAK;;;;;;EACxB;AAID;;GAEG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAyChF;AAED,sDAAsD;AACtD,wBAAgB,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAkBzE;AAID,KAAK,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACpC,KAAK,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE5C;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EACxC,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,EAC9B,KAAK,CAAC,EAAE,SAAS,EACjB,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAClC,OAAO,CAAC,CAAC,CAAC,CAMZ"}
|