feat(10-02): filter choices and a fully typed admin API proven on the wire
- pact.FilterOptions on the model serves a scope filter's choices; a scope
filter whose model lacks it fails activation (D-27)
- GET /{vendor}/{plugin}/{controller}/filters/{scope}/options answers a
declared scope filter behind the controller permission with localized
{value, label} choices, 404 otherwise
- Every admin route documents a typed success schema, and protected routes
document 401, 403 and 404 (422 on writes); SuccessEnvelope is gone and
logout writes a typed AdminLogoutData
- jsonScalar and fieldContext decode their served shapes
- TestPhase10OpenAPIConformance calls every inventoried route through the
assembled router on PostgreSQL and decodes each body into its documented
type with unknown fields disallowed, checking admin.json's schema ref
- The SPA aliases every new schema type; Tailwind no longer scans the
generated API files, so API changes do not churn boardwalk/dist
This commit is contained in:
315
admin/src/api/schema.d.ts
vendored
315
admin/src/api/schema.d.ts
vendored
@@ -82,7 +82,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.Envelope-cabana_AdminLogoutData"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -94,6 +94,24 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
delete?: never;
|
||||
@@ -137,6 +155,24 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
put?: never;
|
||||
@@ -287,6 +323,15 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
put?: never;
|
||||
@@ -320,7 +365,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.Envelope-array_cabana_SettingsEntry"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -341,6 +386,15 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
put?: never;
|
||||
@@ -377,7 +431,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.Envelope-cabana_SettingsResult"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -428,7 +482,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.Envelope-cabana_SettingsResult"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -449,6 +503,15 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Unprocessable Entity */
|
||||
422: {
|
||||
headers: {
|
||||
@@ -493,7 +556,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.Envelope-cabana_FormView"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -595,6 +658,15 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Unprocessable Entity */
|
||||
422: {
|
||||
headers: {
|
||||
@@ -654,6 +726,15 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Unprocessable Entity */
|
||||
422: {
|
||||
headers: {
|
||||
@@ -703,7 +784,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.Envelope-cabana_BulkResult"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -724,6 +805,24 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Conflict */
|
||||
409: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Unprocessable Entity */
|
||||
422: {
|
||||
headers: {
|
||||
@@ -832,6 +931,81 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/{vendor}/{plugin}/{controller}/filters/{scope}/options": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Filter scope options
|
||||
* @description Choices of a declared scope filter of the controller's list, from the model's FilterOptions. {scope} is the filter name used as filter[<scope>]; labels are localized.
|
||||
*/
|
||||
get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
/** @description Vendor */
|
||||
vendor: string;
|
||||
/** @description Plugin */
|
||||
plugin: string;
|
||||
/** @description Controller */
|
||||
controller: string;
|
||||
/** @description Filter name */
|
||||
scope: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.Envelope-array_cabana_FilterOption"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/{vendor}/{plugin}/{controller}/schema/form": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -1200,7 +1374,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.Envelope-cabana_BulkResult"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -1230,6 +1404,15 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Unprocessable Entity */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
options?: never;
|
||||
@@ -1271,7 +1454,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.ListEnvelope-array_cabana_AdminRecord"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -1292,6 +1475,24 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Unprocessable Entity */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
put?: never;
|
||||
@@ -1336,7 +1537,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.ListEnvelope-array_cabana_AdminRecord"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -1357,6 +1558,24 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Unprocessable Entity */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
put?: never;
|
||||
@@ -1403,7 +1622,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.Envelope-cabana_RelationMutationResult"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -1424,6 +1643,15 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Unprocessable Entity */
|
||||
422: {
|
||||
headers: {
|
||||
@@ -1477,7 +1705,7 @@ export interface paths {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.SuccessEnvelope"];
|
||||
"application/json": components["schemas"]["cabana.Envelope-cabana_RelationMutationResult"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
@@ -1498,6 +1726,15 @@ export interface paths {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Unprocessable Entity */
|
||||
422: {
|
||||
headers: {
|
||||
@@ -1529,6 +1766,9 @@ export interface components {
|
||||
login?: string;
|
||||
password: string;
|
||||
};
|
||||
"cabana.AdminLogoutData": {
|
||||
status: string;
|
||||
};
|
||||
"cabana.AdminProfile": {
|
||||
email: string;
|
||||
first_name: string;
|
||||
@@ -1550,18 +1790,37 @@ export interface components {
|
||||
label?: string;
|
||||
name: string;
|
||||
};
|
||||
"cabana.BulkResult": {
|
||||
deleted: number;
|
||||
};
|
||||
"cabana.Envelope-array_cabana_FilterOption": {
|
||||
data: components["schemas"]["cabana.FilterOption"][];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.Envelope-array_cabana_NavigationEntry": {
|
||||
data: components["schemas"]["cabana.NavigationEntry"][];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.Envelope-array_cabana_SettingsEntry": {
|
||||
data: components["schemas"]["cabana.SettingsEntry"][];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.Envelope-cabana_AdminLoginData": {
|
||||
data: components["schemas"]["cabana.AdminLoginData"];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.Envelope-cabana_AdminLogoutData": {
|
||||
data: components["schemas"]["cabana.AdminLogoutData"];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.Envelope-cabana_AdminProfile": {
|
||||
data: components["schemas"]["cabana.AdminProfile"];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.Envelope-cabana_BulkResult": {
|
||||
data: components["schemas"]["cabana.BulkResult"];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.Envelope-cabana_FormView": {
|
||||
data: components["schemas"]["cabana.FormView"];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
@@ -1574,10 +1833,18 @@ export interface components {
|
||||
data: components["schemas"]["cabana.ListSchema"];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.Envelope-cabana_RelationMutationResult": {
|
||||
data: components["schemas"]["cabana.RelationMutationResult"];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.Envelope-cabana_RelationSchema": {
|
||||
data: components["schemas"]["cabana.RelationSchema"];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.Envelope-cabana_SettingsResult": {
|
||||
data: components["schemas"]["cabana.SettingsResult"];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.ErrorBody": {
|
||||
code: string;
|
||||
details: {
|
||||
@@ -1588,6 +1855,10 @@ export interface components {
|
||||
"cabana.ErrorEnvelope": {
|
||||
error: components["schemas"]["cabana.ErrorBody"];
|
||||
};
|
||||
"cabana.FilterOption": {
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
"cabana.FormField": {
|
||||
attributes?: {
|
||||
[key: string]: components["schemas"]["cabana.jsonScalar"];
|
||||
@@ -1766,6 +2037,10 @@ export interface components {
|
||||
unlinkSelected: components["schemas"]["cabana.MessageForms"];
|
||||
unlinked: components["schemas"]["cabana.MessageForms"];
|
||||
};
|
||||
"cabana.RelationMutationResult": {
|
||||
linked?: number;
|
||||
removed?: number;
|
||||
};
|
||||
"cabana.RelationOption": {
|
||||
label: string;
|
||||
value: number;
|
||||
@@ -1791,9 +2066,21 @@ export interface components {
|
||||
name: string;
|
||||
url?: string;
|
||||
};
|
||||
"cabana.SuccessEnvelope": {
|
||||
data: unknown;
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
"cabana.SettingsEntry": {
|
||||
category: string;
|
||||
code: string;
|
||||
description: string;
|
||||
icon: string;
|
||||
keywords: string[];
|
||||
label: string;
|
||||
model: string;
|
||||
order: number;
|
||||
};
|
||||
"cabana.SettingsResult": {
|
||||
data: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
exists: boolean;
|
||||
};
|
||||
"cabana.SuccessMeta": {
|
||||
last_page?: number;
|
||||
|
||||
@@ -6,11 +6,33 @@ type Schemas = components['schemas']
|
||||
|
||||
export type AdminLoginData = Schemas['cabana.AdminLoginData']
|
||||
export type AdminLoginRequest = Schemas['cabana.AdminLoginRequest']
|
||||
export type AdminLogoutData = Schemas['cabana.AdminLogoutData']
|
||||
export type AdminProfile = Schemas['cabana.AdminProfile']
|
||||
export type NavigationEntry = Schemas['cabana.NavigationEntry']
|
||||
export type SettingsEntry = Schemas['cabana.SettingsEntry']
|
||||
export type SettingsResult = Schemas['cabana.SettingsResult']
|
||||
export type ListSchema = Schemas['cabana.ListSchema']
|
||||
export type ListColumn = Schemas['cabana.ListColumn']
|
||||
export type ListFilter = Schemas['cabana.ListFilter']
|
||||
export type ListMeta = Schemas['cabana.ListMeta']
|
||||
export type ListMessages = Schemas['cabana.ListMessages']
|
||||
export type FormView = Schemas['cabana.FormView']
|
||||
export type FormField = Schemas['cabana.FormField']
|
||||
export type FormOption = Schemas['cabana.FormOption']
|
||||
export type FormMessages = Schemas['cabana.FormMessages']
|
||||
export type FormRedirects = Schemas['cabana.FormRedirects']
|
||||
export type RelationSchema = Schemas['cabana.RelationSchema']
|
||||
export type RelationMessages = Schemas['cabana.RelationMessages']
|
||||
export type RelationMutationResult = Schemas['cabana.RelationMutationResult']
|
||||
export type RelationOption = Schemas['cabana.RelationOption']
|
||||
export type FilterOption = Schemas['cabana.FilterOption']
|
||||
export type RecordMeta = Schemas['cabana.RecordMeta']
|
||||
export type RecordEnvelope = Schemas['cabana.RecordEnvelope']
|
||||
export type BulkResult = Schemas['cabana.BulkResult']
|
||||
/** One message as CLDR plural forms; "other" is always present (D-13). */
|
||||
export type MessageForms = Schemas['cabana.MessageForms']
|
||||
/** The public backend::lang bundle: full key to CLDR forms (D-20). */
|
||||
export type LangBundle = Schemas['cabana.LangBundle']
|
||||
export type ErrorEnvelope = Schemas['cabana.ErrorEnvelope']
|
||||
/** One record: a string-keyed map read through its list or form schema. */
|
||||
export type AdminRecord = Schemas['cabana.ListEnvelope-array_cabana_AdminRecord']['data'][number]
|
||||
export type AdminRecord = Schemas['cabana.AdminRecord']
|
||||
|
||||
Reference in New Issue
Block a user