@webstir-io/module-contract 0.8.0 → 0.9.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/client-nav.d.ts +4 -1
- package/dist/client-nav.js +4 -1
- package/dist/index.d.ts +136 -22
- package/dist/index.js +46 -5
- package/dist/render-execute.d.ts +10 -0
- package/dist/render-execute.js +20 -0
- package/package.json +1 -1
- package/schema/module-manifest.schema.json +23 -7
- package/schema/route-definition.schema.json +22 -3
- package/schema/view-definition.schema.json +18 -3
package/dist/client-nav.d.ts
CHANGED
|
@@ -15,5 +15,8 @@ export declare const CLIENT_NAV_HEADERS: {
|
|
|
15
15
|
/** Identifies one form submission, so the same post sent again gets the first answer. */
|
|
16
16
|
readonly submission: 'x-webstir-submission';
|
|
17
17
|
};
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* The form field carrying a submission id: rendered into every POST form a view renders, and set by
|
|
20
|
+
* client-nav when it falls back to a normal post.
|
|
21
|
+
*/
|
|
19
22
|
export declare const CLIENT_NAV_SUBMISSION_FIELD = "_webstir_submission";
|
package/dist/client-nav.js
CHANGED
|
@@ -15,5 +15,8 @@ export const CLIENT_NAV_HEADERS = {
|
|
|
15
15
|
/** Identifies one form submission, so the same post sent again gets the first answer. */
|
|
16
16
|
submission: 'x-webstir-submission',
|
|
17
17
|
};
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* The form field carrying a submission id: rendered into every POST form a view renders, and set by
|
|
20
|
+
* client-nav when it falls back to a normal post.
|
|
21
|
+
*/
|
|
19
22
|
export const CLIENT_NAV_SUBMISSION_FIELD = '_webstir_submission';
|
package/dist/index.d.ts
CHANGED
|
@@ -98,6 +98,29 @@ export interface FormState {
|
|
|
98
98
|
export interface FormStateReader {
|
|
99
99
|
read(formId: string): FormState;
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* What a page binds for one form: whether it came back from a failed submission, what was typed in
|
|
103
|
+
* each field, and the first error per field (and `form`, for errors about the whole form).
|
|
104
|
+
*/
|
|
105
|
+
export declare function formStateSchema<const TFields extends readonly string[]>(fields: TFields): z.ZodObject<{
|
|
106
|
+
submitted: z.ZodBoolean;
|
|
107
|
+
values: z.ZodObject<Record<TFields[number], z.ZodOptional<z.ZodString>>, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<Record<TFields[number], z.ZodOptional<z.ZodString>>>, any> extends infer T ? { [k in keyof T]: T[k]; } : never, z.baseObjectInputType<Record<TFields[number], z.ZodOptional<z.ZodString>>> extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never>;
|
|
108
|
+
errors: z.ZodObject<Record<(readonly [...TFields, "form"])[number], z.ZodOptional<z.ZodString>>, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<Record<(readonly [...TFields, "form"])[number], z.ZodOptional<z.ZodString>>>, any> extends infer T_2 ? { [k in keyof T_2]: T_2[k]; } : never, z.baseObjectInputType<Record<(readonly [...TFields, "form"])[number], z.ZodOptional<z.ZodString>>> extends infer T_3 ? { [k in keyof T_3]: T_3[k]; } : never>;
|
|
109
|
+
}, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<{
|
|
110
|
+
submitted: z.ZodBoolean;
|
|
111
|
+
values: z.ZodObject<Record<TFields[number], z.ZodOptional<z.ZodString>>, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<Record<TFields[number], z.ZodOptional<z.ZodString>>>, any> extends infer T ? { [k in keyof T]: T[k]; } : never, z.baseObjectInputType<Record<TFields[number], z.ZodOptional<z.ZodString>>> extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never>;
|
|
112
|
+
errors: z.ZodObject<Record<(readonly [...TFields, "form"])[number], z.ZodOptional<z.ZodString>>, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<Record<(readonly [...TFields, "form"])[number], z.ZodOptional<z.ZodString>>>, any> extends infer T_2 ? { [k in keyof T_2]: T_2[k]; } : never, z.baseObjectInputType<Record<(readonly [...TFields, "form"])[number], z.ZodOptional<z.ZodString>>> extends infer T_3 ? { [k in keyof T_3]: T_3[k]; } : never>;
|
|
113
|
+
}>, any> extends infer T_4 ? { [k in keyof T_4]: T_4[k]; } : never, z.baseObjectInputType<{
|
|
114
|
+
submitted: z.ZodBoolean;
|
|
115
|
+
values: z.ZodObject<Record<TFields[number], z.ZodOptional<z.ZodString>>, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<Record<TFields[number], z.ZodOptional<z.ZodString>>>, any> extends infer T ? { [k in keyof T]: T[k]; } : never, z.baseObjectInputType<Record<TFields[number], z.ZodOptional<z.ZodString>>> extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never>;
|
|
116
|
+
errors: z.ZodObject<Record<(readonly [...TFields, "form"])[number], z.ZodOptional<z.ZodString>>, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<Record<(readonly [...TFields, "form"])[number], z.ZodOptional<z.ZodString>>>, any> extends infer T_2 ? { [k in keyof T_2]: T_2[k]; } : never, z.baseObjectInputType<Record<(readonly [...TFields, "form"])[number], z.ZodOptional<z.ZodString>>> extends infer T_3 ? { [k in keyof T_3]: T_3[k]; } : never>;
|
|
117
|
+
}> extends infer T_5 ? { [k in keyof T_5]: T_5[k]; } : never>;
|
|
118
|
+
/** A form's state as `formStateSchema(fields)` binds it, with `defaults` for a fresh form. */
|
|
119
|
+
export declare function formView<const TFields extends readonly string[]>(state: FormState, fields: TFields, defaults?: Partial<Record<TFields[number], string>>): {
|
|
120
|
+
submitted: boolean;
|
|
121
|
+
values: Partial<Record<TFields[number], string>>;
|
|
122
|
+
errors: Partial<Record<TFields[number] | 'form', string>>;
|
|
123
|
+
};
|
|
101
124
|
export interface SSRContext<TParams = Record<string, string>, TAuth = unknown, TSession = unknown, TEnv extends EnvAccessor = EnvAccessor, TLogger extends Logger = Logger> {
|
|
102
125
|
readonly url: URL;
|
|
103
126
|
readonly params: TParams;
|
|
@@ -196,6 +219,18 @@ export declare const moduleErrorSchema: z.ZodObject<{
|
|
|
196
219
|
correlationId?: string | undefined;
|
|
197
220
|
}>;
|
|
198
221
|
export type ModuleError = z.infer<typeof moduleErrorSchema>;
|
|
222
|
+
/**
|
|
223
|
+
* Who reaches a route or view: `'required'` is anyone signed in; `{ role }` is someone signed in
|
|
224
|
+
* whose user has that role. Others are sent to sign in; signed in without the role is a 404.
|
|
225
|
+
*/
|
|
226
|
+
export declare const accessRequirementSchema: z.ZodUnion<[z.ZodLiteral<"required">, z.ZodObject<{
|
|
227
|
+
role: z.ZodString;
|
|
228
|
+
}, "strict", z.ZodTypeAny, {
|
|
229
|
+
role: string;
|
|
230
|
+
}, {
|
|
231
|
+
role: string;
|
|
232
|
+
}>]>;
|
|
233
|
+
export type AccessRequirement = z.infer<typeof accessRequirementSchema>;
|
|
199
234
|
export declare const httpMethodSchema: z.ZodEnum<["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]>;
|
|
200
235
|
export type HttpMethod = z.infer<typeof httpMethodSchema>;
|
|
201
236
|
export declare const routeInteractionKindSchema: z.ZodEnum<["navigation", "mutation"]>;
|
|
@@ -362,6 +397,17 @@ export declare const routeSessionSchema: z.ZodObject<{
|
|
|
362
397
|
export type RouteSessionDefinition = z.infer<typeof routeSessionSchema>;
|
|
363
398
|
export declare const flashLevelSchema: z.ZodEnum<["info", "success", "warning", "error"]>;
|
|
364
399
|
export type FlashLevel = z.infer<typeof flashLevelSchema>;
|
|
400
|
+
/** What a page binds as `flash`: the messages an action left for it. The framework supplies it. */
|
|
401
|
+
export declare const flashSchema: z.ZodArray<z.ZodObject<{
|
|
402
|
+
level: z.ZodEnum<["info", "success", "warning", "error"]>;
|
|
403
|
+
message: z.ZodString;
|
|
404
|
+
}, "strip", z.ZodTypeAny, {
|
|
405
|
+
level: "error" | "info" | "success" | "warning";
|
|
406
|
+
message: string;
|
|
407
|
+
}, {
|
|
408
|
+
level: "error" | "info" | "success" | "warning";
|
|
409
|
+
message: string;
|
|
410
|
+
}>, "many">;
|
|
365
411
|
export declare const flashPublishConditionSchema: z.ZodEnum<["always", "success", "error"]>;
|
|
366
412
|
export type FlashPublishCondition = z.infer<typeof flashPublishConditionSchema>;
|
|
367
413
|
export declare const routeFlashMessageSchema: z.ZodObject<{
|
|
@@ -418,6 +464,8 @@ export declare const routeFlashSchema: z.ZodObject<{
|
|
|
418
464
|
}>;
|
|
419
465
|
export type RouteFlashDefinition = z.infer<typeof routeFlashSchema>;
|
|
420
466
|
export declare const routeFormSchema: z.ZodObject<{
|
|
467
|
+
/** The form's id, which the page's loader reads its state by; the route's name by default. */
|
|
468
|
+
id: z.ZodOptional<z.ZodString>;
|
|
421
469
|
contentType: z.ZodOptional<z.ZodEnum<["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]>>;
|
|
422
470
|
csrf: z.ZodOptional<z.ZodBoolean>;
|
|
423
471
|
session: z.ZodOptional<z.ZodObject<{
|
|
@@ -466,6 +514,7 @@ export declare const routeFormSchema: z.ZodObject<{
|
|
|
466
514
|
}[] | undefined;
|
|
467
515
|
}>>;
|
|
468
516
|
}, "strict", z.ZodTypeAny, {
|
|
517
|
+
id?: string | undefined;
|
|
469
518
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
470
519
|
csrf?: boolean | undefined;
|
|
471
520
|
session?: {
|
|
@@ -482,6 +531,7 @@ export declare const routeFormSchema: z.ZodObject<{
|
|
|
482
531
|
}[] | undefined;
|
|
483
532
|
} | undefined;
|
|
484
533
|
}, {
|
|
534
|
+
id?: string | undefined;
|
|
485
535
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
486
536
|
csrf?: boolean | undefined;
|
|
487
537
|
session?: {
|
|
@@ -1603,8 +1653,14 @@ export declare const routeDefinitionSchema: z.ZodObject<{
|
|
|
1603
1653
|
mode?: "optional" | "required" | undefined;
|
|
1604
1654
|
write?: boolean | undefined;
|
|
1605
1655
|
}>>;
|
|
1606
|
-
/**
|
|
1607
|
-
auth: z.ZodOptional<z.
|
|
1656
|
+
/** Who reaches the route: see `accessRequirementSchema`. */
|
|
1657
|
+
auth: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"required">, z.ZodObject<{
|
|
1658
|
+
role: z.ZodString;
|
|
1659
|
+
}, "strict", z.ZodTypeAny, {
|
|
1660
|
+
role: string;
|
|
1661
|
+
}, {
|
|
1662
|
+
role: string;
|
|
1663
|
+
}>]>>;
|
|
1608
1664
|
flash: z.ZodOptional<z.ZodObject<{
|
|
1609
1665
|
consume: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1610
1666
|
publish: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -1641,6 +1697,8 @@ export declare const routeDefinitionSchema: z.ZodObject<{
|
|
|
1641
1697
|
}[] | undefined;
|
|
1642
1698
|
}>>;
|
|
1643
1699
|
form: z.ZodOptional<z.ZodObject<{
|
|
1700
|
+
/** The form's id, which the page's loader reads its state by; the route's name by default. */
|
|
1701
|
+
id: z.ZodOptional<z.ZodString>;
|
|
1644
1702
|
contentType: z.ZodOptional<z.ZodEnum<["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]>>;
|
|
1645
1703
|
csrf: z.ZodOptional<z.ZodBoolean>;
|
|
1646
1704
|
session: z.ZodOptional<z.ZodObject<{
|
|
@@ -1689,6 +1747,7 @@ export declare const routeDefinitionSchema: z.ZodObject<{
|
|
|
1689
1747
|
}[] | undefined;
|
|
1690
1748
|
}>>;
|
|
1691
1749
|
}, "strict", z.ZodTypeAny, {
|
|
1750
|
+
id?: string | undefined;
|
|
1692
1751
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
1693
1752
|
csrf?: boolean | undefined;
|
|
1694
1753
|
session?: {
|
|
@@ -1705,6 +1764,7 @@ export declare const routeDefinitionSchema: z.ZodObject<{
|
|
|
1705
1764
|
}[] | undefined;
|
|
1706
1765
|
} | undefined;
|
|
1707
1766
|
}, {
|
|
1767
|
+
id?: string | undefined;
|
|
1708
1768
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
1709
1769
|
csrf?: boolean | undefined;
|
|
1710
1770
|
session?: {
|
|
@@ -2308,7 +2368,9 @@ export declare const routeDefinitionSchema: z.ZodObject<{
|
|
|
2308
2368
|
mode?: "optional" | "required" | undefined;
|
|
2309
2369
|
write?: boolean | undefined;
|
|
2310
2370
|
} | undefined;
|
|
2311
|
-
auth?: "required" |
|
|
2371
|
+
auth?: "required" | {
|
|
2372
|
+
role: string;
|
|
2373
|
+
} | undefined;
|
|
2312
2374
|
flash?: {
|
|
2313
2375
|
consume?: string[] | undefined;
|
|
2314
2376
|
publish?: {
|
|
@@ -2319,6 +2381,7 @@ export declare const routeDefinitionSchema: z.ZodObject<{
|
|
|
2319
2381
|
}[] | undefined;
|
|
2320
2382
|
} | undefined;
|
|
2321
2383
|
form?: {
|
|
2384
|
+
id?: string | undefined;
|
|
2322
2385
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
2323
2386
|
csrf?: boolean | undefined;
|
|
2324
2387
|
session?: {
|
|
@@ -2472,7 +2535,9 @@ export declare const routeDefinitionSchema: z.ZodObject<{
|
|
|
2472
2535
|
mode?: "optional" | "required" | undefined;
|
|
2473
2536
|
write?: boolean | undefined;
|
|
2474
2537
|
} | undefined;
|
|
2475
|
-
auth?: "required" |
|
|
2538
|
+
auth?: "required" | {
|
|
2539
|
+
role: string;
|
|
2540
|
+
} | undefined;
|
|
2476
2541
|
flash?: {
|
|
2477
2542
|
consume?: string[] | undefined;
|
|
2478
2543
|
publish?: {
|
|
@@ -2483,6 +2548,7 @@ export declare const routeDefinitionSchema: z.ZodObject<{
|
|
|
2483
2548
|
}[] | undefined;
|
|
2484
2549
|
} | undefined;
|
|
2485
2550
|
form?: {
|
|
2551
|
+
id?: string | undefined;
|
|
2486
2552
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
2487
2553
|
csrf?: boolean | undefined;
|
|
2488
2554
|
session?: {
|
|
@@ -2703,8 +2769,14 @@ export declare const viewDefinitionSchema: z.ZodObject<{
|
|
|
2703
2769
|
summary: z.ZodOptional<z.ZodString>;
|
|
2704
2770
|
description: z.ZodOptional<z.ZodString>;
|
|
2705
2771
|
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
2706
|
-
/**
|
|
2707
|
-
auth: z.ZodOptional<z.
|
|
2772
|
+
/** Who sees the page: see `accessRequirementSchema`. */
|
|
2773
|
+
auth: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"required">, z.ZodObject<{
|
|
2774
|
+
role: z.ZodString;
|
|
2775
|
+
}, "strict", z.ZodTypeAny, {
|
|
2776
|
+
role: string;
|
|
2777
|
+
}, {
|
|
2778
|
+
role: string;
|
|
2779
|
+
}>]>>;
|
|
2708
2780
|
params: z.ZodOptional<z.ZodObject<{
|
|
2709
2781
|
kind: z.ZodDefault<z.ZodEnum<["zod", "json-schema", "ts-rest"]>>;
|
|
2710
2782
|
name: z.ZodString;
|
|
@@ -2747,7 +2819,9 @@ export declare const viewDefinitionSchema: z.ZodObject<{
|
|
|
2747
2819
|
summary?: string | undefined;
|
|
2748
2820
|
description?: string | undefined;
|
|
2749
2821
|
tags?: string[] | undefined;
|
|
2750
|
-
auth?: "required" |
|
|
2822
|
+
auth?: "required" | {
|
|
2823
|
+
role: string;
|
|
2824
|
+
} | undefined;
|
|
2751
2825
|
params?: {
|
|
2752
2826
|
kind: "json-schema" | "ts-rest" | "zod";
|
|
2753
2827
|
name: string;
|
|
@@ -2770,7 +2844,9 @@ export declare const viewDefinitionSchema: z.ZodObject<{
|
|
|
2770
2844
|
summary?: string | undefined;
|
|
2771
2845
|
description?: string | undefined;
|
|
2772
2846
|
tags?: string[] | undefined;
|
|
2773
|
-
auth?: "required" |
|
|
2847
|
+
auth?: "required" | {
|
|
2848
|
+
role: string;
|
|
2849
|
+
} | undefined;
|
|
2774
2850
|
params?: {
|
|
2775
2851
|
kind?: "json-schema" | "ts-rest" | "zod" | undefined;
|
|
2776
2852
|
name: string;
|
|
@@ -2791,7 +2867,9 @@ export type ViewDefinition = z.infer<typeof viewDefinitionSchema>;
|
|
|
2791
2867
|
export type ViewLoaderContext<TContext extends SSRContext, TParams extends z.ZodTypeAny | undefined> = TContext & {
|
|
2792
2868
|
readonly params: InferOrNever<TParams>;
|
|
2793
2869
|
};
|
|
2794
|
-
|
|
2870
|
+
/** What a loader returns: the page's data, less the `flash` the framework adds. */
|
|
2871
|
+
export type ViewLoaderData<TData extends z.ZodTypeAny> = z.input<TData> extends Record<string, unknown> ? Omit<z.input<TData>, 'flash'> : z.input<TData>;
|
|
2872
|
+
export type ViewLoader<TContext extends SSRContext, TParams extends z.ZodTypeAny | undefined, TData extends z.ZodTypeAny> = (context: ViewLoaderContext<TContext, TParams>) => Promise<ViewLoaderData<TData>> | ViewLoaderData<TData>;
|
|
2795
2873
|
export interface ViewSpec<TContext extends SSRContext = SSRContext, TParams extends z.ZodTypeAny | undefined = undefined, TData extends z.ZodTypeAny = z.ZodTypeAny> {
|
|
2796
2874
|
readonly definition: ViewDefinition;
|
|
2797
2875
|
readonly params?: TParams;
|
|
@@ -2912,8 +2990,14 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
2912
2990
|
mode?: "optional" | "required" | undefined;
|
|
2913
2991
|
write?: boolean | undefined;
|
|
2914
2992
|
}>>;
|
|
2915
|
-
/**
|
|
2916
|
-
auth: z.ZodOptional<z.
|
|
2993
|
+
/** Who reaches the route: see `accessRequirementSchema`. */
|
|
2994
|
+
auth: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"required">, z.ZodObject<{
|
|
2995
|
+
role: z.ZodString;
|
|
2996
|
+
}, "strict", z.ZodTypeAny, {
|
|
2997
|
+
role: string;
|
|
2998
|
+
}, {
|
|
2999
|
+
role: string;
|
|
3000
|
+
}>]>>;
|
|
2917
3001
|
flash: z.ZodOptional<z.ZodObject<{
|
|
2918
3002
|
consume: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
2919
3003
|
publish: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -2950,6 +3034,8 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
2950
3034
|
}[] | undefined;
|
|
2951
3035
|
}>>;
|
|
2952
3036
|
form: z.ZodOptional<z.ZodObject<{
|
|
3037
|
+
/** The form's id, which the page's loader reads its state by; the route's name by default. */
|
|
3038
|
+
id: z.ZodOptional<z.ZodString>;
|
|
2953
3039
|
contentType: z.ZodOptional<z.ZodEnum<["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]>>;
|
|
2954
3040
|
csrf: z.ZodOptional<z.ZodBoolean>;
|
|
2955
3041
|
session: z.ZodOptional<z.ZodObject<{
|
|
@@ -2998,6 +3084,7 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
2998
3084
|
}[] | undefined;
|
|
2999
3085
|
}>>;
|
|
3000
3086
|
}, "strict", z.ZodTypeAny, {
|
|
3087
|
+
id?: string | undefined;
|
|
3001
3088
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
3002
3089
|
csrf?: boolean | undefined;
|
|
3003
3090
|
session?: {
|
|
@@ -3014,6 +3101,7 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
3014
3101
|
}[] | undefined;
|
|
3015
3102
|
} | undefined;
|
|
3016
3103
|
}, {
|
|
3104
|
+
id?: string | undefined;
|
|
3017
3105
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
3018
3106
|
csrf?: boolean | undefined;
|
|
3019
3107
|
session?: {
|
|
@@ -3617,7 +3705,9 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
3617
3705
|
mode?: "optional" | "required" | undefined;
|
|
3618
3706
|
write?: boolean | undefined;
|
|
3619
3707
|
} | undefined;
|
|
3620
|
-
auth?: "required" |
|
|
3708
|
+
auth?: "required" | {
|
|
3709
|
+
role: string;
|
|
3710
|
+
} | undefined;
|
|
3621
3711
|
flash?: {
|
|
3622
3712
|
consume?: string[] | undefined;
|
|
3623
3713
|
publish?: {
|
|
@@ -3628,6 +3718,7 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
3628
3718
|
}[] | undefined;
|
|
3629
3719
|
} | undefined;
|
|
3630
3720
|
form?: {
|
|
3721
|
+
id?: string | undefined;
|
|
3631
3722
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
3632
3723
|
csrf?: boolean | undefined;
|
|
3633
3724
|
session?: {
|
|
@@ -3781,7 +3872,9 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
3781
3872
|
mode?: "optional" | "required" | undefined;
|
|
3782
3873
|
write?: boolean | undefined;
|
|
3783
3874
|
} | undefined;
|
|
3784
|
-
auth?: "required" |
|
|
3875
|
+
auth?: "required" | {
|
|
3876
|
+
role: string;
|
|
3877
|
+
} | undefined;
|
|
3785
3878
|
flash?: {
|
|
3786
3879
|
consume?: string[] | undefined;
|
|
3787
3880
|
publish?: {
|
|
@@ -3792,6 +3885,7 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
3792
3885
|
}[] | undefined;
|
|
3793
3886
|
} | undefined;
|
|
3794
3887
|
form?: {
|
|
3888
|
+
id?: string | undefined;
|
|
3795
3889
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
3796
3890
|
csrf?: boolean | undefined;
|
|
3797
3891
|
session?: {
|
|
@@ -3938,8 +4032,14 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
3938
4032
|
summary: z.ZodOptional<z.ZodString>;
|
|
3939
4033
|
description: z.ZodOptional<z.ZodString>;
|
|
3940
4034
|
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
3941
|
-
/**
|
|
3942
|
-
auth: z.ZodOptional<z.
|
|
4035
|
+
/** Who sees the page: see `accessRequirementSchema`. */
|
|
4036
|
+
auth: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"required">, z.ZodObject<{
|
|
4037
|
+
role: z.ZodString;
|
|
4038
|
+
}, "strict", z.ZodTypeAny, {
|
|
4039
|
+
role: string;
|
|
4040
|
+
}, {
|
|
4041
|
+
role: string;
|
|
4042
|
+
}>]>>;
|
|
3943
4043
|
params: z.ZodOptional<z.ZodObject<{
|
|
3944
4044
|
kind: z.ZodDefault<z.ZodEnum<["zod", "json-schema", "ts-rest"]>>;
|
|
3945
4045
|
name: z.ZodString;
|
|
@@ -3982,7 +4082,9 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
3982
4082
|
summary?: string | undefined;
|
|
3983
4083
|
description?: string | undefined;
|
|
3984
4084
|
tags?: string[] | undefined;
|
|
3985
|
-
auth?: "required" |
|
|
4085
|
+
auth?: "required" | {
|
|
4086
|
+
role: string;
|
|
4087
|
+
} | undefined;
|
|
3986
4088
|
params?: {
|
|
3987
4089
|
kind: "json-schema" | "ts-rest" | "zod";
|
|
3988
4090
|
name: string;
|
|
@@ -4005,7 +4107,9 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
4005
4107
|
summary?: string | undefined;
|
|
4006
4108
|
description?: string | undefined;
|
|
4007
4109
|
tags?: string[] | undefined;
|
|
4008
|
-
auth?: "required" |
|
|
4110
|
+
auth?: "required" | {
|
|
4111
|
+
role: string;
|
|
4112
|
+
} | undefined;
|
|
4009
4113
|
params?: {
|
|
4010
4114
|
kind?: "json-schema" | "ts-rest" | "zod" | undefined;
|
|
4011
4115
|
name: string;
|
|
@@ -4112,7 +4216,9 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
4112
4216
|
mode?: "optional" | "required" | undefined;
|
|
4113
4217
|
write?: boolean | undefined;
|
|
4114
4218
|
} | undefined;
|
|
4115
|
-
auth?: "required" |
|
|
4219
|
+
auth?: "required" | {
|
|
4220
|
+
role: string;
|
|
4221
|
+
} | undefined;
|
|
4116
4222
|
flash?: {
|
|
4117
4223
|
consume?: string[] | undefined;
|
|
4118
4224
|
publish?: {
|
|
@@ -4123,6 +4229,7 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
4123
4229
|
}[] | undefined;
|
|
4124
4230
|
} | undefined;
|
|
4125
4231
|
form?: {
|
|
4232
|
+
id?: string | undefined;
|
|
4126
4233
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
4127
4234
|
csrf?: boolean | undefined;
|
|
4128
4235
|
session?: {
|
|
@@ -4269,7 +4376,9 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
4269
4376
|
summary?: string | undefined;
|
|
4270
4377
|
description?: string | undefined;
|
|
4271
4378
|
tags?: string[] | undefined;
|
|
4272
|
-
auth?: "required" |
|
|
4379
|
+
auth?: "required" | {
|
|
4380
|
+
role: string;
|
|
4381
|
+
} | undefined;
|
|
4273
4382
|
params?: {
|
|
4274
4383
|
kind: "json-schema" | "ts-rest" | "zod";
|
|
4275
4384
|
name: string;
|
|
@@ -4336,7 +4445,9 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
4336
4445
|
mode?: "optional" | "required" | undefined;
|
|
4337
4446
|
write?: boolean | undefined;
|
|
4338
4447
|
} | undefined;
|
|
4339
|
-
auth?: "required" |
|
|
4448
|
+
auth?: "required" | {
|
|
4449
|
+
role: string;
|
|
4450
|
+
} | undefined;
|
|
4340
4451
|
flash?: {
|
|
4341
4452
|
consume?: string[] | undefined;
|
|
4342
4453
|
publish?: {
|
|
@@ -4347,6 +4458,7 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
4347
4458
|
}[] | undefined;
|
|
4348
4459
|
} | undefined;
|
|
4349
4460
|
form?: {
|
|
4461
|
+
id?: string | undefined;
|
|
4350
4462
|
contentType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined;
|
|
4351
4463
|
csrf?: boolean | undefined;
|
|
4352
4464
|
session?: {
|
|
@@ -4493,7 +4605,9 @@ export declare const moduleManifestSchema: z.ZodObject<{
|
|
|
4493
4605
|
summary?: string | undefined;
|
|
4494
4606
|
description?: string | undefined;
|
|
4495
4607
|
tags?: string[] | undefined;
|
|
4496
|
-
auth?: "required" |
|
|
4608
|
+
auth?: "required" | {
|
|
4609
|
+
role: string;
|
|
4610
|
+
} | undefined;
|
|
4497
4611
|
params?: {
|
|
4498
4612
|
kind?: "json-schema" | "ts-rest" | "zod" | undefined;
|
|
4499
4613
|
name: string;
|
|
@@ -4567,6 +4681,6 @@ export { fromTsRestRoute, fromTsRestRouter } from './adapters/ts-rest.js';
|
|
|
4567
4681
|
export type { FromTsRestRouteOptions, FromTsRestRouterOptions, RouterRouteConfig, } from './adapters/ts-rest.js';
|
|
4568
4682
|
export { RENDER_PROGRAM_FILE, RENDER_PROGRAM_VERSION, renderFlashMessageSchema, renderFlashSchema, renderNodeSchema, renderPathSchema, renderProgramSchema, renderSourceLocationSchema, } from './render-program.js';
|
|
4569
4683
|
export type { RenderFlashMessage, RenderNode, RenderPath, RenderProgram, RenderSourceLocation, } from './render-program.js';
|
|
4570
|
-
export { executeRenderProgram, programUsesCsrf, readRenderProgram, RENDER_CSRF_FIELD, RenderProgramError, prepareViewData, schemaDeclaresField, } from './render-execute.js';
|
|
4684
|
+
export { executeRenderProgram, programUsesCsrf, readRenderProgram, RENDER_CSRF_FIELD, RenderProgramError, prepareViewData, schemaDeclaresField, withShellData, } from './render-execute.js';
|
|
4571
4685
|
export type { ExecuteRenderProgramOptions, PreparedViewData } from './render-execute.js';
|
|
4572
4686
|
export { CLIENT_NAV_HEADERS, CLIENT_NAV_SUBMISSION_FIELD } from './client-nav.js';
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,35 @@ export const CONTRACT_VERSION = '1.0.0';
|
|
|
4
4
|
export const contractVersionLiteral = z.literal(CONTRACT_VERSION);
|
|
5
5
|
export const moduleKindSchema = z.enum(['frontend', 'backend']);
|
|
6
6
|
export const logLevelSchema = z.enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal']);
|
|
7
|
+
/**
|
|
8
|
+
* What a page binds for one form: whether it came back from a failed submission, what was typed in
|
|
9
|
+
* each field, and the first error per field (and `form`, for errors about the whole form).
|
|
10
|
+
*/
|
|
11
|
+
export function formStateSchema(fields) {
|
|
12
|
+
const strings = (names) => z.object(Object.fromEntries(names.map((name) => [name, z.string().optional()])));
|
|
13
|
+
return z.object({
|
|
14
|
+
submitted: z.boolean(),
|
|
15
|
+
values: strings(fields),
|
|
16
|
+
errors: strings([...fields, 'form']),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/** A form's state as `formStateSchema(fields)` binds it, with `defaults` for a fresh form. */
|
|
20
|
+
export function formView(state, fields, defaults = {}) {
|
|
21
|
+
const values = {};
|
|
22
|
+
const errors = {};
|
|
23
|
+
for (const field of fields) {
|
|
24
|
+
const value = state.values[field];
|
|
25
|
+
const typed = typeof value === 'string' ? value : Array.isArray(value) ? value[0] : undefined;
|
|
26
|
+
const shown = state.submitted ? typed : defaults[field];
|
|
27
|
+
if (shown !== undefined)
|
|
28
|
+
values[field] = shown;
|
|
29
|
+
if (state.errors[field])
|
|
30
|
+
errors[field] = state.errors[field];
|
|
31
|
+
}
|
|
32
|
+
if (state.errors.form)
|
|
33
|
+
errors.form = state.errors.form;
|
|
34
|
+
return { submitted: state.submitted, values, errors };
|
|
35
|
+
}
|
|
7
36
|
export const moduleErrorCodeSchema = z.enum([
|
|
8
37
|
'validation',
|
|
9
38
|
'auth',
|
|
@@ -19,6 +48,14 @@ export const moduleErrorSchema = z.object({
|
|
|
19
48
|
cause: z.unknown().optional(),
|
|
20
49
|
correlationId: z.string().optional(),
|
|
21
50
|
});
|
|
51
|
+
/**
|
|
52
|
+
* Who reaches a route or view: `'required'` is anyone signed in; `{ role }` is someone signed in
|
|
53
|
+
* whose user has that role. Others are sent to sign in; signed in without the role is a 404.
|
|
54
|
+
*/
|
|
55
|
+
export const accessRequirementSchema = z.union([
|
|
56
|
+
z.literal('required'),
|
|
57
|
+
z.object({ role: z.string().min(1) }).strict(),
|
|
58
|
+
]);
|
|
22
59
|
export const httpMethodSchema = z.enum([
|
|
23
60
|
'GET',
|
|
24
61
|
'HEAD',
|
|
@@ -79,6 +116,8 @@ export const routeSessionSchema = z
|
|
|
79
116
|
})
|
|
80
117
|
.strict();
|
|
81
118
|
export const flashLevelSchema = z.enum(['info', 'success', 'warning', 'error']);
|
|
119
|
+
/** What a page binds as `flash`: the messages an action left for it. The framework supplies it. */
|
|
120
|
+
export const flashSchema = z.array(z.object({ level: flashLevelSchema, message: z.string() }));
|
|
82
121
|
export const flashPublishConditionSchema = z.enum(['always', 'success', 'error']);
|
|
83
122
|
export const routeFlashMessageSchema = z
|
|
84
123
|
.object({
|
|
@@ -96,6 +135,8 @@ export const routeFlashSchema = z
|
|
|
96
135
|
.strict();
|
|
97
136
|
export const routeFormSchema = z
|
|
98
137
|
.object({
|
|
138
|
+
/** The form's id, which the page's loader reads its state by; the route's name by default. */
|
|
139
|
+
id: z.string().min(1).optional(),
|
|
99
140
|
contentType: formEncodingSchema.optional(),
|
|
100
141
|
csrf: z.boolean().optional(),
|
|
101
142
|
session: routeSessionSchema.optional(),
|
|
@@ -159,8 +200,8 @@ export const routeDefinitionSchema = z.object({
|
|
|
159
200
|
interaction: routeInteractionKindSchema.optional(),
|
|
160
201
|
requestHooks: z.array(requestHookReferenceSchema).optional(),
|
|
161
202
|
session: routeSessionSchema.optional(),
|
|
162
|
-
/**
|
|
163
|
-
auth:
|
|
203
|
+
/** Who reaches the route: see `accessRequirementSchema`. */
|
|
204
|
+
auth: accessRequirementSchema.optional(),
|
|
164
205
|
flash: routeFlashSchema.optional(),
|
|
165
206
|
form: routeFormSchema.optional(),
|
|
166
207
|
fragment: routeFragmentSchema.optional(),
|
|
@@ -182,8 +223,8 @@ export const viewDefinitionSchema = z.object({
|
|
|
182
223
|
summary: z.string().optional(),
|
|
183
224
|
description: z.string().optional(),
|
|
184
225
|
tags: z.array(z.string()).optional(),
|
|
185
|
-
/**
|
|
186
|
-
auth:
|
|
226
|
+
/** Who sees the page: see `accessRequirementSchema`. */
|
|
227
|
+
auth: accessRequirementSchema.optional(),
|
|
187
228
|
params: schemaReferenceSchema.optional(),
|
|
188
229
|
data: schemaReferenceSchema.optional(),
|
|
189
230
|
renderMode: z.enum(['ssg', 'ssr', 'spa']).optional(),
|
|
@@ -237,5 +278,5 @@ export function createModule(definition) {
|
|
|
237
278
|
}
|
|
238
279
|
export { fromTsRestRoute, fromTsRestRouter } from './adapters/ts-rest.js';
|
|
239
280
|
export { RENDER_PROGRAM_FILE, RENDER_PROGRAM_VERSION, renderFlashMessageSchema, renderFlashSchema, renderNodeSchema, renderPathSchema, renderProgramSchema, renderSourceLocationSchema, } from './render-program.js';
|
|
240
|
-
export { executeRenderProgram, programUsesCsrf, readRenderProgram, RENDER_CSRF_FIELD, RenderProgramError, prepareViewData, schemaDeclaresField, } from './render-execute.js';
|
|
281
|
+
export { executeRenderProgram, programUsesCsrf, readRenderProgram, RENDER_CSRF_FIELD, RenderProgramError, prepareViewData, schemaDeclaresField, withShellData, } from './render-execute.js';
|
|
241
282
|
export { CLIENT_NAV_HEADERS, CLIENT_NAV_SUBMISSION_FIELD } from './client-nav.js';
|
package/dist/render-execute.d.ts
CHANGED
|
@@ -10,6 +10,11 @@ export interface ExecuteRenderProgramOptions {
|
|
|
10
10
|
* POST forms render without a token field.
|
|
11
11
|
*/
|
|
12
12
|
readonly csrfToken?: string | false;
|
|
13
|
+
/**
|
|
14
|
+
* A new id for each POST form rendered, so the same submission sent again (a resent post, a
|
|
15
|
+
* double click) is answered once. Left out, forms render without one.
|
|
16
|
+
*/
|
|
17
|
+
readonly submissionId?: () => string;
|
|
13
18
|
}
|
|
14
19
|
export declare function readRenderProgram(value: unknown, source: string): RenderProgram;
|
|
15
20
|
export declare function programUsesCsrf(program: RenderProgram): boolean;
|
|
@@ -28,6 +33,11 @@ export type PreparedViewData = {
|
|
|
28
33
|
* failing that, without it, starting with what the schema declares.
|
|
29
34
|
*/
|
|
30
35
|
export declare function prepareViewData(schema: unknown, loaded: unknown, flash: readonly unknown[]): PreparedViewData;
|
|
36
|
+
/**
|
|
37
|
+
* A page's data with the app's shell data beside it as `shell`, checked against the shell's schema
|
|
38
|
+
* when it has one.
|
|
39
|
+
*/
|
|
40
|
+
export declare function withShellData(data: unknown, shellSchema: unknown, loaded: unknown): PreparedViewData;
|
|
31
41
|
/**
|
|
32
42
|
* Whether a zod-style schema's underlying object declares `field`, looking through wrappers
|
|
33
43
|
* such as optional, default, refine and transform, and into unions and intersections. A schema
|
package/dist/render-execute.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CLIENT_NAV_SUBMISSION_FIELD } from './client-nav.js';
|
|
1
2
|
import { RENDER_PROGRAM_VERSION } from './render-version.js';
|
|
2
3
|
export const RENDER_CSRF_FIELD = '_csrf';
|
|
3
4
|
const SAFE_URL_SCHEMES = new Set(['http', 'https', 'mailto', 'tel']);
|
|
@@ -63,6 +64,9 @@ function run(nodes, data, scopes, options, out) {
|
|
|
63
64
|
throw new Error('A POST form needs a CSRF token, but none was supplied.');
|
|
64
65
|
}
|
|
65
66
|
out.push(`<input type="hidden" name="${RENDER_CSRF_FIELD}" value="${escapeAttribute(options.csrfToken)}">`);
|
|
67
|
+
if (options.submissionId) {
|
|
68
|
+
out.push(`<input type="hidden" name="${CLIENT_NAV_SUBMISSION_FIELD}" value="${escapeAttribute(options.submissionId())}">`);
|
|
69
|
+
}
|
|
66
70
|
break;
|
|
67
71
|
case 'text': {
|
|
68
72
|
const value = read(node.path, data, scopes);
|
|
@@ -194,6 +198,22 @@ export function prepareViewData(schema, loaded, flash) {
|
|
|
194
198
|
}
|
|
195
199
|
return { ok: false, error: describeSchemaError(firstError) };
|
|
196
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* A page's data with the app's shell data beside it as `shell`, checked against the shell's schema
|
|
203
|
+
* when it has one.
|
|
204
|
+
*/
|
|
205
|
+
export function withShellData(data, shellSchema, loaded) {
|
|
206
|
+
if (!isPlainObject(data)) {
|
|
207
|
+
return { ok: true, data };
|
|
208
|
+
}
|
|
209
|
+
if (!shellSchema || typeof shellSchema.safeParse !== 'function') {
|
|
210
|
+
return { ok: true, data: { ...data, shell: loaded } };
|
|
211
|
+
}
|
|
212
|
+
const parsed = shellSchema.safeParse(loaded);
|
|
213
|
+
return parsed.success
|
|
214
|
+
? { ok: true, data: { ...data, shell: parsed.data } }
|
|
215
|
+
: { ok: false, error: describeSchemaError(parsed.error) };
|
|
216
|
+
}
|
|
197
217
|
function mergeFlash(value, flash) {
|
|
198
218
|
if (!isPlainObject(value)) {
|
|
199
219
|
return value;
|
package/package.json
CHANGED
|
@@ -147,9 +147,24 @@
|
|
|
147
147
|
"additionalProperties": false
|
|
148
148
|
},
|
|
149
149
|
"auth": {
|
|
150
|
-
"
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
"anyOf": [
|
|
151
|
+
{
|
|
152
|
+
"type": "string",
|
|
153
|
+
"const": "required"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"type": "object",
|
|
157
|
+
"properties": {
|
|
158
|
+
"role": {
|
|
159
|
+
"type": "string",
|
|
160
|
+
"minLength": 1
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"required": [
|
|
164
|
+
"role"
|
|
165
|
+
],
|
|
166
|
+
"additionalProperties": false
|
|
167
|
+
}
|
|
153
168
|
]
|
|
154
169
|
},
|
|
155
170
|
"flash": {
|
|
@@ -205,6 +220,10 @@
|
|
|
205
220
|
"form": {
|
|
206
221
|
"type": "object",
|
|
207
222
|
"properties": {
|
|
223
|
+
"id": {
|
|
224
|
+
"type": "string",
|
|
225
|
+
"minLength": 1
|
|
226
|
+
},
|
|
208
227
|
"contentType": {
|
|
209
228
|
"type": "string",
|
|
210
229
|
"enum": [
|
|
@@ -486,10 +505,7 @@
|
|
|
486
505
|
}
|
|
487
506
|
},
|
|
488
507
|
"auth": {
|
|
489
|
-
"
|
|
490
|
-
"enum": [
|
|
491
|
-
"required"
|
|
492
|
-
]
|
|
508
|
+
"$ref": "#/definitions/module-manifest/properties/routes/items/properties/auth"
|
|
493
509
|
},
|
|
494
510
|
"params": {
|
|
495
511
|
"$ref": "#/definitions/module-manifest/properties/routes/items/properties/input/properties/params"
|
|
@@ -76,9 +76,24 @@
|
|
|
76
76
|
"additionalProperties": false
|
|
77
77
|
},
|
|
78
78
|
"auth": {
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
"anyOf": [
|
|
80
|
+
{
|
|
81
|
+
"type": "string",
|
|
82
|
+
"const": "required"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"type": "object",
|
|
86
|
+
"properties": {
|
|
87
|
+
"role": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"minLength": 1
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"required": [
|
|
93
|
+
"role"
|
|
94
|
+
],
|
|
95
|
+
"additionalProperties": false
|
|
96
|
+
}
|
|
82
97
|
]
|
|
83
98
|
},
|
|
84
99
|
"flash": {
|
|
@@ -134,6 +149,10 @@
|
|
|
134
149
|
"form": {
|
|
135
150
|
"type": "object",
|
|
136
151
|
"properties": {
|
|
152
|
+
"id": {
|
|
153
|
+
"type": "string",
|
|
154
|
+
"minLength": 1
|
|
155
|
+
},
|
|
137
156
|
"contentType": {
|
|
138
157
|
"type": "string",
|
|
139
158
|
"enum": [
|
|
@@ -29,9 +29,24 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"auth": {
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
"anyOf": [
|
|
33
|
+
{
|
|
34
|
+
"type": "string",
|
|
35
|
+
"const": "required"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"type": "object",
|
|
39
|
+
"properties": {
|
|
40
|
+
"role": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"minLength": 1
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"required": [
|
|
46
|
+
"role"
|
|
47
|
+
],
|
|
48
|
+
"additionalProperties": false
|
|
49
|
+
}
|
|
35
50
|
]
|
|
36
51
|
},
|
|
37
52
|
"params": {
|