@panneau/protocol 5.0.0-alpha.2 → 5.0.0-alpha.3
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/conformance/index.d.ts.map +1 -1
- package/dist/conformance/index.js +34 -1
- package/dist/conformance/index.js.map +1 -1
- package/dist/mock/example.d.ts.map +1 -1
- package/dist/mock/example.js +2 -1
- package/dist/mock/example.js.map +1 -1
- package/dist/mock/index.d.ts.map +1 -1
- package/dist/mock/index.js +20 -1
- package/dist/mock/index.js.map +1 -1
- package/dist/openapi.d.ts.map +1 -1
- package/dist/openapi.js +2 -1
- package/dist/openapi.js.map +1 -1
- package/dist/schemas/action.d.ts +1 -0
- package/dist/schemas/action.d.ts.map +1 -1
- package/dist/schemas/action.js +1 -0
- package/dist/schemas/action.js.map +1 -1
- package/dist/schemas/api.d.ts +1 -0
- package/dist/schemas/api.d.ts.map +1 -1
- package/dist/schemas/api.js +2 -1
- package/dist/schemas/api.js.map +1 -1
- package/dist/schemas/definition.d.ts +1 -0
- package/dist/schemas/definition.d.ts.map +1 -1
- package/dist/schemas/index.d.ts +4 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/resource.d.ts +1 -0
- package/dist/schemas/resource.d.ts.map +1 -1
- package/package.json +1 -1
- package/schema/boot.schema.json +3 -0
- package/schema/definition.schema.json +3 -0
- package/schema/openapi.json +18 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conformance/index.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,kBAAkB;IAC/B,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjE,wEAAwE;IACxE,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE;QACL,mCAAmC;QACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,kCAAkC;QAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,2FAA2F;QAC3F,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;CACL;AAED,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEhE,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,CAAC;IAC1B,qDAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAoED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conformance/index.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,kBAAkB;IAC/B,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjE,wEAAwE;IACxE,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE;QACL,mCAAmC;QACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,kCAAkC;QAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,2FAA2F;QAC3F,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;CACL;AAED,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEhE,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,CAAC;IAC1B,qDAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAoED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA2X5F;AAED,oDAAoD;AACpD,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAU9D"}
|
|
@@ -2,7 +2,7 @@ import { PROBLEM_CONTENT_TYPE } from "../version.js";
|
|
|
2
2
|
import { isFilled } from "../values.js";
|
|
3
3
|
import { toSearchParams } from "../query.js";
|
|
4
4
|
import { Definition } from "../schemas/definition.js";
|
|
5
|
-
import { ItemResponse, ListResponse, Problem } from "../schemas/api.js";
|
|
5
|
+
import { ActionResult, ItemResponse, ListResponse, Problem } from "../schemas/api.js";
|
|
6
6
|
//#region src/conformance/index.ts
|
|
7
7
|
var UNKNOWN = "__panneau_conformance_unknown__";
|
|
8
8
|
function describeIssues(error) {
|
|
@@ -154,6 +154,39 @@ async function runConformance(options) {
|
|
|
154
154
|
const future = await list({ from: "9999-12-31" }, "The list filtered from 9999-12-31");
|
|
155
155
|
if (future !== null) check.expect(future.meta.total === 0, `Filtered from 9999-12-31, the list has ${future.meta.total} items, expected 0.`);
|
|
156
156
|
});
|
|
157
|
+
await run("action.dry-run", "A dry run of an action counts what it would do, and changes nothing", async (check) => {
|
|
158
|
+
const action = resource?.actions?.find((candidate) => candidate.dryRun === true && candidate.kind === "server" && candidate.scope.includes("selection"));
|
|
159
|
+
if (action === void 0) {
|
|
160
|
+
check.skip("The resource declares no selection action with dryRun.");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const page = async (label) => {
|
|
164
|
+
const reply = await request(`${resourcePath()}?page=1&perPage=20`);
|
|
165
|
+
return check.expectStatus(reply, 200) ? check.expectSchema(ListResponse, reply.body, label) : null;
|
|
166
|
+
};
|
|
167
|
+
const before = await page("The list before the dry run");
|
|
168
|
+
const reply = await request(`${resourcePath()}/actions/${encodeURIComponent(action.id)}`, {
|
|
169
|
+
method: "POST",
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
selection: { query: {} },
|
|
172
|
+
dryRun: true
|
|
173
|
+
})
|
|
174
|
+
});
|
|
175
|
+
if (!check.expectStatus(reply, 200)) return;
|
|
176
|
+
const result = check.expectSchema(ActionResult, reply.body, "The dry run result");
|
|
177
|
+
if (result !== null && before !== null) {
|
|
178
|
+
check.expect(result.summary !== void 0, "A dry run result must have a summary of the items that would succeed and be skipped.");
|
|
179
|
+
if (result.summary !== void 0) {
|
|
180
|
+
const counted = result.summary.succeeded + result.summary.failed + result.summary.skipped;
|
|
181
|
+
check.expect(counted === before.meta.total, `The dry run counts ${counted} items; the list has ${before.meta.total}.`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const after = await page("The list after the dry run");
|
|
185
|
+
if (before !== null && after !== null) {
|
|
186
|
+
const versions = (list) => JSON.stringify(list.data.map((item) => [item.id, item.version ?? null]));
|
|
187
|
+
check.expect(after.meta.total === before.meta.total && versions(after) === versions(before), "A dry run must not change the items.");
|
|
188
|
+
}
|
|
189
|
+
});
|
|
157
190
|
await run("list.unknown-resource", "An unknown resource is a 404 problem", async (check) => {
|
|
158
191
|
check.expectProblem(await request(`/resources/${UNKNOWN}`), 404);
|
|
159
192
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/conformance/index.ts"],"sourcesContent":["import type { z } from 'zod';\n\nimport { type FilterRange, toSearchParams } from '../query';\nimport { Definition, type Resource } from '../schemas';\nimport { ItemResponse, ListResponse, Problem } from '../schemas/api';\nimport { isFilled } from '../values';\nimport { PROBLEM_CONTENT_TYPE } from '../version';\n\nexport interface ConformanceOptions {\n /** Base URL of the API, the same as `api.baseUrl` of the definition, but absolute. */\n baseUrl: string;\n /** The `fetch` to use. Defaults to the global one. */\n fetch?: (input: string, init?: RequestInit) => Promise<Response>;\n /** Merged into every request, for authentication headers or cookies. */\n init?: RequestInit;\n /** Resource to test. Defaults to the first resource of the definition. */\n resource?: string;\n /**\n * Enables the checks that write data, on the tested resource. Use a test database: these\n * checks create, update and delete an item.\n */\n writes?: {\n /** Valid values for a new item. */\n create: Record<string, unknown>;\n /** Valid values for an update. */\n update: Record<string, unknown>;\n /** Values that must be refused with a `422`. Defaults to `{}` when a field is required. */\n invalid?: Record<string, unknown>;\n };\n}\n\nexport type ConformanceStatus = 'passed' | 'failed' | 'skipped';\n\nexport interface ConformanceCheck {\n id: string;\n title: string;\n status: ConformanceStatus;\n /** What went wrong, or why the check was skipped. */\n issues: string[];\n}\n\nexport interface ConformanceReport {\n passed: boolean;\n checks: ConformanceCheck[];\n}\n\ninterface Reply {\n status: number;\n contentType: string;\n etag: string | null;\n body: unknown;\n}\n\nconst UNKNOWN = '__panneau_conformance_unknown__';\n\nfunction describeIssues(error: z.ZodError): string[] {\n return error.issues.slice(0, 10).map((issue) => {\n const path = issue.path.map(String).join('.');\n return path === '' ? issue.message : `${path}: ${issue.message}`;\n });\n}\n\nfunction normalizeEtag(value: string): string {\n return value.replace(/^W\\//, '');\n}\n\nclass Check {\n issues: string[] = [];\n skippedBecause: string | null = null;\n\n expect(condition: boolean, issue: string): boolean {\n if (!condition) {\n this.issues.push(issue);\n }\n return condition;\n }\n\n expectStatus(reply: Reply, status: number): boolean {\n return this.expect(\n reply.status === status,\n `Expected status ${status}, got ${reply.status}.`,\n );\n }\n\n expectSchema<T extends z.ZodType>(schema: T, value: unknown, label: string): z.infer<T> | null {\n const result = schema.safeParse(value);\n if (result.success) {\n return result.data;\n }\n this.issues.push(\n `${label} does not match the schema:`,\n ...describeIssues(result.error).map((issue) => ` ${issue}`),\n );\n return null;\n }\n\n expectProblem(reply: Reply, status: number): Problem | null {\n if (!this.expectStatus(reply, status)) {\n return null;\n }\n this.expect(\n reply.contentType.startsWith(PROBLEM_CONTENT_TYPE),\n `Expected content type ${PROBLEM_CONTENT_TYPE}, got \"${reply.contentType}\".`,\n );\n return this.expectSchema(Problem, reply.body, 'The error');\n }\n\n skip(reason: string) {\n this.skippedBecause = reason;\n }\n}\n\n/**\n * Runs the protocol's conformance checks against a live backend. Read-only checks always run;\n * checks that write data run only with `writes`.\n */\nexport async function runConformance(options: ConformanceOptions): Promise<ConformanceReport> {\n const fetcher = options.fetch ?? ((input: string, init?: RequestInit) => fetch(input, init));\n const baseUrl = options.baseUrl.replace(/\\/$/, '');\n const checks: ConformanceCheck[] = [];\n\n const request = async (path: string, init: RequestInit = {}): Promise<Reply> => {\n const headers = new Headers(options.init?.headers);\n headers.set('Accept', 'application/json');\n new Headers(init.headers).forEach((value, key) => headers.set(key, value));\n if (init.body !== undefined) {\n headers.set('Content-Type', 'application/json');\n }\n const response = await fetcher(`${baseUrl}${path}`, { ...options.init, ...init, headers });\n const text = await response.text();\n const parse = (): unknown => {\n if (text === '') {\n return null;\n }\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n };\n const body = parse();\n return {\n status: response.status,\n contentType: response.headers.get('Content-Type') ?? '',\n etag: response.headers.get('ETag'),\n body,\n };\n };\n\n const run = async (id: string, title: string, body: (check: Check) => Promise<void>) => {\n const check = new Check();\n try {\n await body(check);\n } catch (error) {\n check.issues.push(\n `Request failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n const status: ConformanceStatus =\n check.issues.length > 0\n ? 'failed'\n : check.skippedBecause !== null\n ? 'skipped'\n : 'passed';\n checks.push({\n id,\n title,\n status,\n issues:\n status === 'skipped' && check.skippedBecause !== null\n ? [check.skippedBecause]\n : check.issues,\n });\n };\n\n let definition: Definition | null = null;\n let resource: Resource | null = null;\n let firstItemId: string | null = null;\n\n await run('definition', 'GET /definition returns a valid definition', async (check) => {\n const reply = await request('/definition');\n if (check.expectStatus(reply, 200)) {\n definition = check.expectSchema(Definition, reply.body, 'The definition');\n }\n });\n\n await run('definition.resource', 'The definition has the resource to test', async (check) => {\n const current = definition as Definition | null;\n if (current === null) {\n check.skip('No valid definition.');\n return;\n }\n resource =\n (options.resource !== undefined\n ? current.resources.find((candidate) => candidate.id === options.resource)\n : current.resources[0]) ?? null;\n check.expect(\n resource !== null,\n options.resource !== undefined\n ? `The definition has no resource \"${options.resource}\".`\n : 'The definition has no resources.',\n );\n });\n\n const resourcePath = () =>\n `/resources/${encodeURIComponent((resource as Resource | null)?.id ?? '')}`;\n\n await run('list', 'GET /resources/{resource} returns a page of items', async (check) => {\n if (resource === null) {\n check.skip('No resource to test.');\n return;\n }\n const reply = await request(`${resourcePath()}?page=1&perPage=2`);\n if (!check.expectStatus(reply, 200)) {\n return;\n }\n const list = check.expectSchema(ListResponse, reply.body, 'The list');\n if (list === null) {\n return;\n }\n check.expect(list.data.length <= 2, `perPage=2 returned ${list.data.length} items.`);\n check.expect(list.meta.page === 1, `meta.page is ${list.meta.page}, expected 1.`);\n check.expect(list.meta.perPage === 2, `meta.perPage is ${list.meta.perPage}, expected 2.`);\n firstItemId = list.data[0]?.id ?? null;\n });\n\n await run('list.sort', 'GET /resources/{resource} accepts a sort', async (check) => {\n const sort = (resource as Resource | null)?.list?.sorts?.[0];\n if (sort === undefined) {\n check.skip('The resource declares no sorts.');\n return;\n }\n const reply = await request(`${resourcePath()}?sort=${encodeURIComponent(`-${sort}`)}`);\n if (check.expectStatus(reply, 200)) {\n check.expectSchema(ListResponse, reply.body, 'The sorted list');\n }\n });\n\n await run(\n 'list.filter-range',\n 'GET /resources/{resource} reads the bounds of a range filter',\n async (check) => {\n const filter = (resource as Resource | null)?.list?.filters?.find(\n (candidate) => candidate.type === 'date-range',\n );\n if (filter === undefined) {\n check.skip('The resource declares no date-range filter.');\n return;\n }\n const list = async (range: FilterRange | null, label: string) => {\n const query =\n range !== null ? `?${toSearchParams({ filter: { [filter.id]: range } })}` : '';\n const reply = await request(`${resourcePath()}${query}`);\n if (!check.expectStatus(reply, 200)) {\n return null;\n }\n return check.expectSchema(ListResponse, reply.body, label);\n };\n const all = await list(null, 'The list');\n if (all === null) {\n return;\n }\n // Items of the first page with a value: a range that covers every day includes them.\n const dated = all.data.filter((item) => isFilled(item[filter.id])).length;\n const ranges: [FilterRange, string][] = [\n [{ from: '0001-01-01', to: '9999-12-31' }, 'from 0001-01-01 to 9999-12-31'],\n [{ to: '9999-12-31' }, 'up to 9999-12-31 (an open start)'],\n ];\n for (const [range, label] of ranges) {\n const reply = await list(range, `The list filtered ${label}`);\n if (reply !== null) {\n check.expect(\n reply.meta.total >= dated,\n `Filtered ${label}, the list has ${reply.meta.total} items; the first page alone has ${dated} with a ${filter.id}.`,\n );\n }\n }\n const future = await list({ from: '9999-12-31' }, 'The list filtered from 9999-12-31');\n if (future !== null) {\n check.expect(\n future.meta.total === 0,\n `Filtered from 9999-12-31, the list has ${future.meta.total} items, expected 0.`,\n );\n }\n },\n );\n\n await run('list.unknown-resource', 'An unknown resource is a 404 problem', async (check) => {\n check.expectProblem(await request(`/resources/${UNKNOWN}`), 404);\n });\n\n await run(\n 'item',\n 'GET /resources/{resource}/{id} returns the item with its ETag',\n async (check) => {\n if (firstItemId === null) {\n check.skip('The list has no items.');\n return;\n }\n const reply = await request(`${resourcePath()}/${encodeURIComponent(firstItemId)}`);\n if (!check.expectStatus(reply, 200)) {\n return;\n }\n const item = check.expectSchema(ItemResponse, reply.body, 'The item');\n if (item === null) {\n return;\n }\n check.expect(\n item.data.id === firstItemId,\n `Asked for item \"${firstItemId}\", got \"${item.data.id}\".`,\n );\n if (item.data.version !== null) {\n check.expect(\n reply.etag !== null && normalizeEtag(reply.etag) === `\"${item.data.version}\"`,\n `Expected ETag \"${item.data.version}\" (quoted), got ${reply.etag ?? 'none'}.`,\n );\n }\n },\n );\n\n await run('item.missing', 'A missing item is a 404 problem', async (check) => {\n if (resource === null) {\n check.skip('No resource to test.');\n return;\n }\n check.expectProblem(await request(`${resourcePath()}/${UNKNOWN}`), 404);\n });\n\n const writes = options.writes;\n let createdId: string | null = null;\n let createdVersion: string | null = null;\n\n await run('create.invalid', 'Invalid values are refused with a 422 problem', async (check) => {\n if (writes === undefined || resource === null) {\n check.skip('Write checks are disabled.');\n return;\n }\n const hasRequired = resource.fields.some((field) =>\n (field.rules ?? []).some((rule) => rule.rule === 'required'),\n );\n if (writes.invalid === undefined && !hasRequired) {\n check.skip('No invalid values given, and the resource has no required field.');\n return;\n }\n const reply = await request(resourcePath(), {\n method: 'POST',\n body: JSON.stringify(writes.invalid ?? {}),\n });\n const failure = check.expectProblem(reply, 422);\n if (failure !== null) {\n check.expect(\n failure.errors !== undefined && Object.keys(failure.errors).length > 0,\n 'A 422 problem must list the invalid values in `errors`.',\n );\n }\n });\n\n await run('create', 'POST /resources/{resource} creates an item', async (check) => {\n if (writes === undefined || resource === null) {\n check.skip('Write checks are disabled.');\n return;\n }\n const reply = await request(resourcePath(), {\n method: 'POST',\n body: JSON.stringify(writes.create),\n });\n if (!check.expectStatus(reply, 201)) {\n return;\n }\n const item = check.expectSchema(ItemResponse, reply.body, 'The created item');\n createdId = item?.data.id ?? null;\n createdVersion = item?.data.version ?? null;\n });\n\n const itemPath = () => `${resourcePath()}/${encodeURIComponent(createdId ?? '')}`;\n\n await run('update', 'PATCH /resources/{resource}/{id} updates the item', async (check) => {\n if (createdId === null || writes === undefined) {\n check.skip('No item was created.');\n return;\n }\n const reply = await request(itemPath(), {\n method: 'PATCH',\n body: JSON.stringify(writes.update),\n headers: createdVersion !== null ? { 'If-Match': `\"${createdVersion}\"` } : {},\n });\n if (!check.expectStatus(reply, 200)) {\n return;\n }\n const item = check.expectSchema(ItemResponse, reply.body, 'The updated item');\n if (item !== null && createdVersion !== null) {\n check.expect(\n item.data.version !== createdVersion,\n 'The version did not change after an update.',\n );\n }\n });\n\n await run(\n 'update.conflict',\n 'A stale If-Match is a 412 problem with the current item',\n async (check) => {\n if (createdId === null || writes === undefined) {\n check.skip('No item was created.');\n return;\n }\n if (createdVersion === null) {\n check.skip('The backend has no versions.');\n return;\n }\n const reply = await request(itemPath(), {\n method: 'PATCH',\n body: JSON.stringify(writes.update),\n headers: { 'If-Match': '\"__panneau_conformance_stale__\"' },\n });\n const failure = check.expectProblem(reply, 412);\n if (failure !== null) {\n check.expect(\n failure.current !== undefined,\n 'A 412 problem must include the current item.',\n );\n }\n },\n );\n\n await run('delete', 'DELETE /resources/{resource}/{id} deletes the item', async (check) => {\n if (createdId === null) {\n check.skip('No item was created.');\n return;\n }\n if (!check.expectStatus(await request(itemPath(), { method: 'DELETE' }), 204)) {\n return;\n }\n check.expectProblem(await request(itemPath()), 404);\n });\n\n return { passed: checks.every((check) => check.status !== 'failed'), checks };\n}\n\n/** Formats a report as text, one line per check. */\nexport function formatReport(report: ConformanceReport): string {\n const symbols: Record<ConformanceStatus, string> = { passed: '✓', failed: '✗', skipped: '-' };\n return report.checks\n .map((check) =>\n [\n `${symbols[check.status]} ${check.title}`,\n ...check.issues.map((issue) => ` ${issue}`),\n ].join('\\n'),\n )\n .join('\\n');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/conformance/index.ts"],"sourcesContent":["import type { z } from 'zod';\n\nimport { type FilterRange, toSearchParams } from '../query';\nimport { Definition, type Resource } from '../schemas';\nimport { ActionResult, ItemResponse, ListResponse, Problem } from '../schemas/api';\nimport { isFilled } from '../values';\nimport { PROBLEM_CONTENT_TYPE } from '../version';\n\nexport interface ConformanceOptions {\n /** Base URL of the API, the same as `api.baseUrl` of the definition, but absolute. */\n baseUrl: string;\n /** The `fetch` to use. Defaults to the global one. */\n fetch?: (input: string, init?: RequestInit) => Promise<Response>;\n /** Merged into every request, for authentication headers or cookies. */\n init?: RequestInit;\n /** Resource to test. Defaults to the first resource of the definition. */\n resource?: string;\n /**\n * Enables the checks that write data, on the tested resource. Use a test database: these\n * checks create, update and delete an item.\n */\n writes?: {\n /** Valid values for a new item. */\n create: Record<string, unknown>;\n /** Valid values for an update. */\n update: Record<string, unknown>;\n /** Values that must be refused with a `422`. Defaults to `{}` when a field is required. */\n invalid?: Record<string, unknown>;\n };\n}\n\nexport type ConformanceStatus = 'passed' | 'failed' | 'skipped';\n\nexport interface ConformanceCheck {\n id: string;\n title: string;\n status: ConformanceStatus;\n /** What went wrong, or why the check was skipped. */\n issues: string[];\n}\n\nexport interface ConformanceReport {\n passed: boolean;\n checks: ConformanceCheck[];\n}\n\ninterface Reply {\n status: number;\n contentType: string;\n etag: string | null;\n body: unknown;\n}\n\nconst UNKNOWN = '__panneau_conformance_unknown__';\n\nfunction describeIssues(error: z.ZodError): string[] {\n return error.issues.slice(0, 10).map((issue) => {\n const path = issue.path.map(String).join('.');\n return path === '' ? issue.message : `${path}: ${issue.message}`;\n });\n}\n\nfunction normalizeEtag(value: string): string {\n return value.replace(/^W\\//, '');\n}\n\nclass Check {\n issues: string[] = [];\n skippedBecause: string | null = null;\n\n expect(condition: boolean, issue: string): boolean {\n if (!condition) {\n this.issues.push(issue);\n }\n return condition;\n }\n\n expectStatus(reply: Reply, status: number): boolean {\n return this.expect(\n reply.status === status,\n `Expected status ${status}, got ${reply.status}.`,\n );\n }\n\n expectSchema<T extends z.ZodType>(schema: T, value: unknown, label: string): z.infer<T> | null {\n const result = schema.safeParse(value);\n if (result.success) {\n return result.data;\n }\n this.issues.push(\n `${label} does not match the schema:`,\n ...describeIssues(result.error).map((issue) => ` ${issue}`),\n );\n return null;\n }\n\n expectProblem(reply: Reply, status: number): Problem | null {\n if (!this.expectStatus(reply, status)) {\n return null;\n }\n this.expect(\n reply.contentType.startsWith(PROBLEM_CONTENT_TYPE),\n `Expected content type ${PROBLEM_CONTENT_TYPE}, got \"${reply.contentType}\".`,\n );\n return this.expectSchema(Problem, reply.body, 'The error');\n }\n\n skip(reason: string) {\n this.skippedBecause = reason;\n }\n}\n\n/**\n * Runs the protocol's conformance checks against a live backend. Read-only checks always run;\n * checks that write data run only with `writes`.\n */\nexport async function runConformance(options: ConformanceOptions): Promise<ConformanceReport> {\n const fetcher = options.fetch ?? ((input: string, init?: RequestInit) => fetch(input, init));\n const baseUrl = options.baseUrl.replace(/\\/$/, '');\n const checks: ConformanceCheck[] = [];\n\n const request = async (path: string, init: RequestInit = {}): Promise<Reply> => {\n const headers = new Headers(options.init?.headers);\n headers.set('Accept', 'application/json');\n new Headers(init.headers).forEach((value, key) => headers.set(key, value));\n if (init.body !== undefined) {\n headers.set('Content-Type', 'application/json');\n }\n const response = await fetcher(`${baseUrl}${path}`, { ...options.init, ...init, headers });\n const text = await response.text();\n const parse = (): unknown => {\n if (text === '') {\n return null;\n }\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n };\n const body = parse();\n return {\n status: response.status,\n contentType: response.headers.get('Content-Type') ?? '',\n etag: response.headers.get('ETag'),\n body,\n };\n };\n\n const run = async (id: string, title: string, body: (check: Check) => Promise<void>) => {\n const check = new Check();\n try {\n await body(check);\n } catch (error) {\n check.issues.push(\n `Request failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n const status: ConformanceStatus =\n check.issues.length > 0\n ? 'failed'\n : check.skippedBecause !== null\n ? 'skipped'\n : 'passed';\n checks.push({\n id,\n title,\n status,\n issues:\n status === 'skipped' && check.skippedBecause !== null\n ? [check.skippedBecause]\n : check.issues,\n });\n };\n\n let definition: Definition | null = null;\n let resource: Resource | null = null;\n let firstItemId: string | null = null;\n\n await run('definition', 'GET /definition returns a valid definition', async (check) => {\n const reply = await request('/definition');\n if (check.expectStatus(reply, 200)) {\n definition = check.expectSchema(Definition, reply.body, 'The definition');\n }\n });\n\n await run('definition.resource', 'The definition has the resource to test', async (check) => {\n const current = definition as Definition | null;\n if (current === null) {\n check.skip('No valid definition.');\n return;\n }\n resource =\n (options.resource !== undefined\n ? current.resources.find((candidate) => candidate.id === options.resource)\n : current.resources[0]) ?? null;\n check.expect(\n resource !== null,\n options.resource !== undefined\n ? `The definition has no resource \"${options.resource}\".`\n : 'The definition has no resources.',\n );\n });\n\n const resourcePath = () =>\n `/resources/${encodeURIComponent((resource as Resource | null)?.id ?? '')}`;\n\n await run('list', 'GET /resources/{resource} returns a page of items', async (check) => {\n if (resource === null) {\n check.skip('No resource to test.');\n return;\n }\n const reply = await request(`${resourcePath()}?page=1&perPage=2`);\n if (!check.expectStatus(reply, 200)) {\n return;\n }\n const list = check.expectSchema(ListResponse, reply.body, 'The list');\n if (list === null) {\n return;\n }\n check.expect(list.data.length <= 2, `perPage=2 returned ${list.data.length} items.`);\n check.expect(list.meta.page === 1, `meta.page is ${list.meta.page}, expected 1.`);\n check.expect(list.meta.perPage === 2, `meta.perPage is ${list.meta.perPage}, expected 2.`);\n firstItemId = list.data[0]?.id ?? null;\n });\n\n await run('list.sort', 'GET /resources/{resource} accepts a sort', async (check) => {\n const sort = (resource as Resource | null)?.list?.sorts?.[0];\n if (sort === undefined) {\n check.skip('The resource declares no sorts.');\n return;\n }\n const reply = await request(`${resourcePath()}?sort=${encodeURIComponent(`-${sort}`)}`);\n if (check.expectStatus(reply, 200)) {\n check.expectSchema(ListResponse, reply.body, 'The sorted list');\n }\n });\n\n await run(\n 'list.filter-range',\n 'GET /resources/{resource} reads the bounds of a range filter',\n async (check) => {\n const filter = (resource as Resource | null)?.list?.filters?.find(\n (candidate) => candidate.type === 'date-range',\n );\n if (filter === undefined) {\n check.skip('The resource declares no date-range filter.');\n return;\n }\n const list = async (range: FilterRange | null, label: string) => {\n const query =\n range !== null ? `?${toSearchParams({ filter: { [filter.id]: range } })}` : '';\n const reply = await request(`${resourcePath()}${query}`);\n if (!check.expectStatus(reply, 200)) {\n return null;\n }\n return check.expectSchema(ListResponse, reply.body, label);\n };\n const all = await list(null, 'The list');\n if (all === null) {\n return;\n }\n // Items of the first page with a value: a range that covers every day includes them.\n const dated = all.data.filter((item) => isFilled(item[filter.id])).length;\n const ranges: [FilterRange, string][] = [\n [{ from: '0001-01-01', to: '9999-12-31' }, 'from 0001-01-01 to 9999-12-31'],\n [{ to: '9999-12-31' }, 'up to 9999-12-31 (an open start)'],\n ];\n for (const [range, label] of ranges) {\n const reply = await list(range, `The list filtered ${label}`);\n if (reply !== null) {\n check.expect(\n reply.meta.total >= dated,\n `Filtered ${label}, the list has ${reply.meta.total} items; the first page alone has ${dated} with a ${filter.id}.`,\n );\n }\n }\n const future = await list({ from: '9999-12-31' }, 'The list filtered from 9999-12-31');\n if (future !== null) {\n check.expect(\n future.meta.total === 0,\n `Filtered from 9999-12-31, the list has ${future.meta.total} items, expected 0.`,\n );\n }\n },\n );\n\n await run(\n 'action.dry-run',\n 'A dry run of an action counts what it would do, and changes nothing',\n async (check) => {\n const action = (resource as Resource | null)?.actions?.find(\n (candidate) =>\n candidate.dryRun === true &&\n candidate.kind === 'server' &&\n candidate.scope.includes('selection'),\n );\n if (action === undefined) {\n check.skip('The resource declares no selection action with dryRun.');\n return;\n }\n const page = async (label: string) => {\n const reply = await request(`${resourcePath()}?page=1&perPage=20`);\n return check.expectStatus(reply, 200)\n ? check.expectSchema(ListResponse, reply.body, label)\n : null;\n };\n const before = await page('The list before the dry run');\n const reply = await request(\n `${resourcePath()}/actions/${encodeURIComponent(action.id)}`,\n {\n method: 'POST',\n body: JSON.stringify({ selection: { query: {} }, dryRun: true }),\n },\n );\n if (!check.expectStatus(reply, 200)) {\n return;\n }\n const result = check.expectSchema(ActionResult, reply.body, 'The dry run result');\n if (result !== null && before !== null) {\n check.expect(\n result.summary !== undefined,\n 'A dry run result must have a summary of the items that would succeed and be skipped.',\n );\n if (result.summary !== undefined) {\n const counted =\n result.summary.succeeded + result.summary.failed + result.summary.skipped;\n check.expect(\n counted === before.meta.total,\n `The dry run counts ${counted} items; the list has ${before.meta.total}.`,\n );\n }\n }\n const after = await page('The list after the dry run');\n if (before !== null && after !== null) {\n const versions = (list: typeof before) =>\n JSON.stringify(list.data.map((item) => [item.id, item.version ?? null]));\n check.expect(\n after.meta.total === before.meta.total && versions(after) === versions(before),\n 'A dry run must not change the items.',\n );\n }\n },\n );\n\n await run('list.unknown-resource', 'An unknown resource is a 404 problem', async (check) => {\n check.expectProblem(await request(`/resources/${UNKNOWN}`), 404);\n });\n\n await run(\n 'item',\n 'GET /resources/{resource}/{id} returns the item with its ETag',\n async (check) => {\n if (firstItemId === null) {\n check.skip('The list has no items.');\n return;\n }\n const reply = await request(`${resourcePath()}/${encodeURIComponent(firstItemId)}`);\n if (!check.expectStatus(reply, 200)) {\n return;\n }\n const item = check.expectSchema(ItemResponse, reply.body, 'The item');\n if (item === null) {\n return;\n }\n check.expect(\n item.data.id === firstItemId,\n `Asked for item \"${firstItemId}\", got \"${item.data.id}\".`,\n );\n if (item.data.version !== null) {\n check.expect(\n reply.etag !== null && normalizeEtag(reply.etag) === `\"${item.data.version}\"`,\n `Expected ETag \"${item.data.version}\" (quoted), got ${reply.etag ?? 'none'}.`,\n );\n }\n },\n );\n\n await run('item.missing', 'A missing item is a 404 problem', async (check) => {\n if (resource === null) {\n check.skip('No resource to test.');\n return;\n }\n check.expectProblem(await request(`${resourcePath()}/${UNKNOWN}`), 404);\n });\n\n const writes = options.writes;\n let createdId: string | null = null;\n let createdVersion: string | null = null;\n\n await run('create.invalid', 'Invalid values are refused with a 422 problem', async (check) => {\n if (writes === undefined || resource === null) {\n check.skip('Write checks are disabled.');\n return;\n }\n const hasRequired = resource.fields.some((field) =>\n (field.rules ?? []).some((rule) => rule.rule === 'required'),\n );\n if (writes.invalid === undefined && !hasRequired) {\n check.skip('No invalid values given, and the resource has no required field.');\n return;\n }\n const reply = await request(resourcePath(), {\n method: 'POST',\n body: JSON.stringify(writes.invalid ?? {}),\n });\n const failure = check.expectProblem(reply, 422);\n if (failure !== null) {\n check.expect(\n failure.errors !== undefined && Object.keys(failure.errors).length > 0,\n 'A 422 problem must list the invalid values in `errors`.',\n );\n }\n });\n\n await run('create', 'POST /resources/{resource} creates an item', async (check) => {\n if (writes === undefined || resource === null) {\n check.skip('Write checks are disabled.');\n return;\n }\n const reply = await request(resourcePath(), {\n method: 'POST',\n body: JSON.stringify(writes.create),\n });\n if (!check.expectStatus(reply, 201)) {\n return;\n }\n const item = check.expectSchema(ItemResponse, reply.body, 'The created item');\n createdId = item?.data.id ?? null;\n createdVersion = item?.data.version ?? null;\n });\n\n const itemPath = () => `${resourcePath()}/${encodeURIComponent(createdId ?? '')}`;\n\n await run('update', 'PATCH /resources/{resource}/{id} updates the item', async (check) => {\n if (createdId === null || writes === undefined) {\n check.skip('No item was created.');\n return;\n }\n const reply = await request(itemPath(), {\n method: 'PATCH',\n body: JSON.stringify(writes.update),\n headers: createdVersion !== null ? { 'If-Match': `\"${createdVersion}\"` } : {},\n });\n if (!check.expectStatus(reply, 200)) {\n return;\n }\n const item = check.expectSchema(ItemResponse, reply.body, 'The updated item');\n if (item !== null && createdVersion !== null) {\n check.expect(\n item.data.version !== createdVersion,\n 'The version did not change after an update.',\n );\n }\n });\n\n await run(\n 'update.conflict',\n 'A stale If-Match is a 412 problem with the current item',\n async (check) => {\n if (createdId === null || writes === undefined) {\n check.skip('No item was created.');\n return;\n }\n if (createdVersion === null) {\n check.skip('The backend has no versions.');\n return;\n }\n const reply = await request(itemPath(), {\n method: 'PATCH',\n body: JSON.stringify(writes.update),\n headers: { 'If-Match': '\"__panneau_conformance_stale__\"' },\n });\n const failure = check.expectProblem(reply, 412);\n if (failure !== null) {\n check.expect(\n failure.current !== undefined,\n 'A 412 problem must include the current item.',\n );\n }\n },\n );\n\n await run('delete', 'DELETE /resources/{resource}/{id} deletes the item', async (check) => {\n if (createdId === null) {\n check.skip('No item was created.');\n return;\n }\n if (!check.expectStatus(await request(itemPath(), { method: 'DELETE' }), 204)) {\n return;\n }\n check.expectProblem(await request(itemPath()), 404);\n });\n\n return { passed: checks.every((check) => check.status !== 'failed'), checks };\n}\n\n/** Formats a report as text, one line per check. */\nexport function formatReport(report: ConformanceReport): string {\n const symbols: Record<ConformanceStatus, string> = { passed: '✓', failed: '✗', skipped: '-' };\n return report.checks\n .map((check) =>\n [\n `${symbols[check.status]} ${check.title}`,\n ...check.issues.map((issue) => ` ${issue}`),\n ].join('\\n'),\n )\n .join('\\n');\n}\n"],"mappings":";;;;;;AAqDA,IAAM,UAAU;AAEhB,SAAS,eAAe,OAA6B;CACjD,OAAO,MAAM,OAAO,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,UAAU;EAC5C,MAAM,OAAO,MAAM,KAAK,IAAI,MAAM,CAAC,CAAC,KAAK,GAAG;EAC5C,OAAO,SAAS,KAAK,MAAM,UAAU,GAAG,KAAK,IAAI,MAAM;CAC3D,CAAC;AACL;AAEA,SAAS,cAAc,OAAuB;CAC1C,OAAO,MAAM,QAAQ,QAAQ,EAAE;AACnC;AAEA,IAAM,QAAN,MAAY;CACR,SAAmB,CAAC;CACpB,iBAAgC;CAEhC,OAAO,WAAoB,OAAwB;EAC/C,IAAI,CAAC,WACD,KAAK,OAAO,KAAK,KAAK;EAE1B,OAAO;CACX;CAEA,aAAa,OAAc,QAAyB;EAChD,OAAO,KAAK,OACR,MAAM,WAAW,QACjB,mBAAmB,OAAO,QAAQ,MAAM,OAAO,EACnD;CACJ;CAEA,aAAkC,QAAW,OAAgB,OAAkC;EAC3F,MAAM,SAAS,OAAO,UAAU,KAAK;EACrC,IAAI,OAAO,SACP,OAAO,OAAO;EAElB,KAAK,OAAO,KACR,GAAG,MAAM,8BACT,GAAG,eAAe,OAAO,KAAK,CAAC,CAAC,KAAK,UAAU,KAAK,OAAO,CAC/D;EACA,OAAO;CACX;CAEA,cAAc,OAAc,QAAgC;EACxD,IAAI,CAAC,KAAK,aAAa,OAAO,MAAM,GAChC,OAAO;EAEX,KAAK,OACD,MAAM,YAAY,WAAW,oBAAoB,GACjD,yBAAyB,qBAAqB,SAAS,MAAM,YAAY,GAC7E;EACA,OAAO,KAAK,aAAa,SAAS,MAAM,MAAM,WAAW;CAC7D;CAEA,KAAK,QAAgB;EACjB,KAAK,iBAAiB;CAC1B;AACJ;;;;;AAMA,eAAsB,eAAe,SAAyD;CAC1F,MAAM,UAAU,QAAQ,WAAW,OAAe,SAAuB,MAAM,OAAO,IAAI;CAC1F,MAAM,UAAU,QAAQ,QAAQ,QAAQ,OAAO,EAAE;CACjD,MAAM,SAA6B,CAAC;CAEpC,MAAM,UAAU,OAAO,MAAc,OAAoB,CAAC,MAAsB;EAC5E,MAAM,UAAU,IAAI,QAAQ,QAAQ,MAAM,OAAO;EACjD,QAAQ,IAAI,UAAU,kBAAkB;EACxC,IAAI,QAAQ,KAAK,OAAO,CAAC,CAAC,SAAS,OAAO,QAAQ,QAAQ,IAAI,KAAK,KAAK,CAAC;EACzE,IAAI,KAAK,SAAS,KAAA,GACd,QAAQ,IAAI,gBAAgB,kBAAkB;EAElD,MAAM,WAAW,MAAM,QAAQ,GAAG,UAAU,QAAQ;GAAE,GAAG,QAAQ;GAAM,GAAG;GAAM;EAAQ,CAAC;EACzF,MAAM,OAAO,MAAM,SAAS,KAAK;EACjC,MAAM,cAAuB;GACzB,IAAI,SAAS,IACT,OAAO;GAEX,IAAI;IACA,OAAO,KAAK,MAAM,IAAI;GAC1B,QAAQ;IACJ,OAAO;GACX;EACJ;EACA,MAAM,OAAO,MAAM;EACnB,OAAO;GACH,QAAQ,SAAS;GACjB,aAAa,SAAS,QAAQ,IAAI,cAAc,KAAK;GACrD,MAAM,SAAS,QAAQ,IAAI,MAAM;GACjC;EACJ;CACJ;CAEA,MAAM,MAAM,OAAO,IAAY,OAAe,SAA0C;EACpF,MAAM,QAAQ,IAAI,MAAM;EACxB,IAAI;GACA,MAAM,KAAK,KAAK;EACpB,SAAS,OAAO;GACZ,MAAM,OAAO,KACT,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAC5E;EACJ;EACA,MAAM,SACF,MAAM,OAAO,SAAS,IAChB,WACA,MAAM,mBAAmB,OACvB,YACA;EACZ,OAAO,KAAK;GACR;GACA;GACA;GACA,QACI,WAAW,aAAa,MAAM,mBAAmB,OAC3C,CAAC,MAAM,cAAc,IACrB,MAAM;EACpB,CAAC;CACL;CAEA,IAAI,aAAgC;CACpC,IAAI,WAA4B;CAChC,IAAI,cAA6B;CAEjC,MAAM,IAAI,cAAc,8CAA8C,OAAO,UAAU;EACnF,MAAM,QAAQ,MAAM,QAAQ,aAAa;EACzC,IAAI,MAAM,aAAa,OAAO,GAAG,GAC7B,aAAa,MAAM,aAAa,YAAY,MAAM,MAAM,gBAAgB;CAEhF,CAAC;CAED,MAAM,IAAI,uBAAuB,2CAA2C,OAAO,UAAU;EACzF,MAAM,UAAU;EAChB,IAAI,YAAY,MAAM;GAClB,MAAM,KAAK,sBAAsB;GACjC;EACJ;EACA,YACK,QAAQ,aAAa,KAAA,IAChB,QAAQ,UAAU,MAAM,cAAc,UAAU,OAAO,QAAQ,QAAQ,IACvE,QAAQ,UAAU,OAAO;EACnC,MAAM,OACF,aAAa,MACb,QAAQ,aAAa,KAAA,IACf,mCAAmC,QAAQ,SAAS,MACpD,kCACV;CACJ,CAAC;CAED,MAAM,qBACF,cAAc,mBAAoB,UAA8B,MAAM,EAAE;CAE5E,MAAM,IAAI,QAAQ,qDAAqD,OAAO,UAAU;EACpF,IAAI,aAAa,MAAM;GACnB,MAAM,KAAK,sBAAsB;GACjC;EACJ;EACA,MAAM,QAAQ,MAAM,QAAQ,GAAG,aAAa,EAAE,kBAAkB;EAChE,IAAI,CAAC,MAAM,aAAa,OAAO,GAAG,GAC9B;EAEJ,MAAM,OAAO,MAAM,aAAa,cAAc,MAAM,MAAM,UAAU;EACpE,IAAI,SAAS,MACT;EAEJ,MAAM,OAAO,KAAK,KAAK,UAAU,GAAG,sBAAsB,KAAK,KAAK,OAAO,QAAQ;EACnF,MAAM,OAAO,KAAK,KAAK,SAAS,GAAG,gBAAgB,KAAK,KAAK,KAAK,cAAc;EAChF,MAAM,OAAO,KAAK,KAAK,YAAY,GAAG,mBAAmB,KAAK,KAAK,QAAQ,cAAc;EACzF,cAAc,KAAK,KAAK,EAAE,EAAE,MAAM;CACtC,CAAC;CAED,MAAM,IAAI,aAAa,4CAA4C,OAAO,UAAU;EAChF,MAAM,OAAQ,UAA8B,MAAM,QAAQ;EAC1D,IAAI,SAAS,KAAA,GAAW;GACpB,MAAM,KAAK,iCAAiC;GAC5C;EACJ;EACA,MAAM,QAAQ,MAAM,QAAQ,GAAG,aAAa,EAAE,QAAQ,mBAAmB,IAAI,MAAM,GAAG;EACtF,IAAI,MAAM,aAAa,OAAO,GAAG,GAC7B,MAAM,aAAa,cAAc,MAAM,MAAM,iBAAiB;CAEtE,CAAC;CAED,MAAM,IACF,qBACA,gEACA,OAAO,UAAU;EACb,MAAM,SAAU,UAA8B,MAAM,SAAS,MACxD,cAAc,UAAU,SAAS,YACtC;EACA,IAAI,WAAW,KAAA,GAAW;GACtB,MAAM,KAAK,6CAA6C;GACxD;EACJ;EACA,MAAM,OAAO,OAAO,OAA2B,UAAkB;GAC7D,MAAM,QACF,UAAU,OAAO,IAAI,eAAe,EAAE,QAAQ,GAAG,OAAO,KAAK,MAAM,EAAE,CAAC,MAAM;GAChF,MAAM,QAAQ,MAAM,QAAQ,GAAG,aAAa,IAAI,OAAO;GACvD,IAAI,CAAC,MAAM,aAAa,OAAO,GAAG,GAC9B,OAAO;GAEX,OAAO,MAAM,aAAa,cAAc,MAAM,MAAM,KAAK;EAC7D;EACA,MAAM,MAAM,MAAM,KAAK,MAAM,UAAU;EACvC,IAAI,QAAQ,MACR;EAGJ,MAAM,QAAQ,IAAI,KAAK,QAAQ,SAAS,SAAS,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC;EAKnE,KAAK,MAAM,CAAC,OAAO,UAAU,CAHzB,CAAC;GAAE,MAAM;GAAc,IAAI;EAAa,GAAG,+BAA+B,GAC1E,CAAC,EAAE,IAAI,aAAa,GAAG,kCAAkC,CAEhC,GAAQ;GACjC,MAAM,QAAQ,MAAM,KAAK,OAAO,qBAAqB,OAAO;GAC5D,IAAI,UAAU,MACV,MAAM,OACF,MAAM,KAAK,SAAS,OACpB,YAAY,MAAM,iBAAiB,MAAM,KAAK,MAAM,mCAAmC,MAAM,UAAU,OAAO,GAAG,EACrH;EAER;EACA,MAAM,SAAS,MAAM,KAAK,EAAE,MAAM,aAAa,GAAG,mCAAmC;EACrF,IAAI,WAAW,MACX,MAAM,OACF,OAAO,KAAK,UAAU,GACtB,0CAA0C,OAAO,KAAK,MAAM,oBAChE;CAER,CACJ;CAEA,MAAM,IACF,kBACA,uEACA,OAAO,UAAU;EACb,MAAM,SAAU,UAA8B,SAAS,MAClD,cACG,UAAU,WAAW,QACrB,UAAU,SAAS,YACnB,UAAU,MAAM,SAAS,WAAW,CAC5C;EACA,IAAI,WAAW,KAAA,GAAW;GACtB,MAAM,KAAK,wDAAwD;GACnE;EACJ;EACA,MAAM,OAAO,OAAO,UAAkB;GAClC,MAAM,QAAQ,MAAM,QAAQ,GAAG,aAAa,EAAE,mBAAmB;GACjE,OAAO,MAAM,aAAa,OAAO,GAAG,IAC9B,MAAM,aAAa,cAAc,MAAM,MAAM,KAAK,IAClD;EACV;EACA,MAAM,SAAS,MAAM,KAAK,6BAA6B;EACvD,MAAM,QAAQ,MAAM,QAChB,GAAG,aAAa,EAAE,WAAW,mBAAmB,OAAO,EAAE,KACzD;GACI,QAAQ;GACR,MAAM,KAAK,UAAU;IAAE,WAAW,EAAE,OAAO,CAAC,EAAE;IAAG,QAAQ;GAAK,CAAC;EACnE,CACJ;EACA,IAAI,CAAC,MAAM,aAAa,OAAO,GAAG,GAC9B;EAEJ,MAAM,SAAS,MAAM,aAAa,cAAc,MAAM,MAAM,oBAAoB;EAChF,IAAI,WAAW,QAAQ,WAAW,MAAM;GACpC,MAAM,OACF,OAAO,YAAY,KAAA,GACnB,sFACJ;GACA,IAAI,OAAO,YAAY,KAAA,GAAW;IAC9B,MAAM,UACF,OAAO,QAAQ,YAAY,OAAO,QAAQ,SAAS,OAAO,QAAQ;IACtE,MAAM,OACF,YAAY,OAAO,KAAK,OACxB,sBAAsB,QAAQ,uBAAuB,OAAO,KAAK,MAAM,EAC3E;GACJ;EACJ;EACA,MAAM,QAAQ,MAAM,KAAK,4BAA4B;EACrD,IAAI,WAAW,QAAQ,UAAU,MAAM;GACnC,MAAM,YAAY,SACd,KAAK,UAAU,KAAK,KAAK,KAAK,SAAS,CAAC,KAAK,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC;GAC3E,MAAM,OACF,MAAM,KAAK,UAAU,OAAO,KAAK,SAAS,SAAS,KAAK,MAAM,SAAS,MAAM,GAC7E,sCACJ;EACJ;CACJ,CACJ;CAEA,MAAM,IAAI,yBAAyB,wCAAwC,OAAO,UAAU;EACxF,MAAM,cAAc,MAAM,QAAQ,cAAc,SAAS,GAAG,GAAG;CACnE,CAAC;CAED,MAAM,IACF,QACA,iEACA,OAAO,UAAU;EACb,IAAI,gBAAgB,MAAM;GACtB,MAAM,KAAK,wBAAwB;GACnC;EACJ;EACA,MAAM,QAAQ,MAAM,QAAQ,GAAG,aAAa,EAAE,GAAG,mBAAmB,WAAW,GAAG;EAClF,IAAI,CAAC,MAAM,aAAa,OAAO,GAAG,GAC9B;EAEJ,MAAM,OAAO,MAAM,aAAa,cAAc,MAAM,MAAM,UAAU;EACpE,IAAI,SAAS,MACT;EAEJ,MAAM,OACF,KAAK,KAAK,OAAO,aACjB,mBAAmB,YAAY,UAAU,KAAK,KAAK,GAAG,GAC1D;EACA,IAAI,KAAK,KAAK,YAAY,MACtB,MAAM,OACF,MAAM,SAAS,QAAQ,cAAc,MAAM,IAAI,MAAM,IAAI,KAAK,KAAK,QAAQ,IAC3E,kBAAkB,KAAK,KAAK,QAAQ,kBAAkB,MAAM,QAAQ,OAAO,EAC/E;CAER,CACJ;CAEA,MAAM,IAAI,gBAAgB,mCAAmC,OAAO,UAAU;EAC1E,IAAI,aAAa,MAAM;GACnB,MAAM,KAAK,sBAAsB;GACjC;EACJ;EACA,MAAM,cAAc,MAAM,QAAQ,GAAG,aAAa,EAAE,GAAG,SAAS,GAAG,GAAG;CAC1E,CAAC;CAED,MAAM,SAAS,QAAQ;CACvB,IAAI,YAA2B;CAC/B,IAAI,iBAAgC;CAEpC,MAAM,IAAI,kBAAkB,iDAAiD,OAAO,UAAU;EAC1F,IAAI,WAAW,KAAA,KAAa,aAAa,MAAM;GAC3C,MAAM,KAAK,4BAA4B;GACvC;EACJ;EACA,MAAM,cAAc,SAAS,OAAO,MAAM,WACrC,MAAM,SAAS,CAAC,EAAA,CAAG,MAAM,SAAS,KAAK,SAAS,UAAU,CAC/D;EACA,IAAI,OAAO,YAAY,KAAA,KAAa,CAAC,aAAa;GAC9C,MAAM,KAAK,kEAAkE;GAC7E;EACJ;EACA,MAAM,QAAQ,MAAM,QAAQ,aAAa,GAAG;GACxC,QAAQ;GACR,MAAM,KAAK,UAAU,OAAO,WAAW,CAAC,CAAC;EAC7C,CAAC;EACD,MAAM,UAAU,MAAM,cAAc,OAAO,GAAG;EAC9C,IAAI,YAAY,MACZ,MAAM,OACF,QAAQ,WAAW,KAAA,KAAa,OAAO,KAAK,QAAQ,MAAM,CAAC,CAAC,SAAS,GACrE,yDACJ;CAER,CAAC;CAED,MAAM,IAAI,UAAU,8CAA8C,OAAO,UAAU;EAC/E,IAAI,WAAW,KAAA,KAAa,aAAa,MAAM;GAC3C,MAAM,KAAK,4BAA4B;GACvC;EACJ;EACA,MAAM,QAAQ,MAAM,QAAQ,aAAa,GAAG;GACxC,QAAQ;GACR,MAAM,KAAK,UAAU,OAAO,MAAM;EACtC,CAAC;EACD,IAAI,CAAC,MAAM,aAAa,OAAO,GAAG,GAC9B;EAEJ,MAAM,OAAO,MAAM,aAAa,cAAc,MAAM,MAAM,kBAAkB;EAC5E,YAAY,MAAM,KAAK,MAAM;EAC7B,iBAAiB,MAAM,KAAK,WAAW;CAC3C,CAAC;CAED,MAAM,iBAAiB,GAAG,aAAa,EAAE,GAAG,mBAAmB,aAAa,EAAE;CAE9E,MAAM,IAAI,UAAU,qDAAqD,OAAO,UAAU;EACtF,IAAI,cAAc,QAAQ,WAAW,KAAA,GAAW;GAC5C,MAAM,KAAK,sBAAsB;GACjC;EACJ;EACA,MAAM,QAAQ,MAAM,QAAQ,SAAS,GAAG;GACpC,QAAQ;GACR,MAAM,KAAK,UAAU,OAAO,MAAM;GAClC,SAAS,mBAAmB,OAAO,EAAE,YAAY,IAAI,eAAe,GAAG,IAAI,CAAC;EAChF,CAAC;EACD,IAAI,CAAC,MAAM,aAAa,OAAO,GAAG,GAC9B;EAEJ,MAAM,OAAO,MAAM,aAAa,cAAc,MAAM,MAAM,kBAAkB;EAC5E,IAAI,SAAS,QAAQ,mBAAmB,MACpC,MAAM,OACF,KAAK,KAAK,YAAY,gBACtB,6CACJ;CAER,CAAC;CAED,MAAM,IACF,mBACA,2DACA,OAAO,UAAU;EACb,IAAI,cAAc,QAAQ,WAAW,KAAA,GAAW;GAC5C,MAAM,KAAK,sBAAsB;GACjC;EACJ;EACA,IAAI,mBAAmB,MAAM;GACzB,MAAM,KAAK,8BAA8B;GACzC;EACJ;EACA,MAAM,QAAQ,MAAM,QAAQ,SAAS,GAAG;GACpC,QAAQ;GACR,MAAM,KAAK,UAAU,OAAO,MAAM;GAClC,SAAS,EAAE,YAAY,oCAAkC;EAC7D,CAAC;EACD,MAAM,UAAU,MAAM,cAAc,OAAO,GAAG;EAC9C,IAAI,YAAY,MACZ,MAAM,OACF,QAAQ,YAAY,KAAA,GACpB,8CACJ;CAER,CACJ;CAEA,MAAM,IAAI,UAAU,sDAAsD,OAAO,UAAU;EACvF,IAAI,cAAc,MAAM;GACpB,MAAM,KAAK,sBAAsB;GACjC;EACJ;EACA,IAAI,CAAC,MAAM,aAAa,MAAM,QAAQ,SAAS,GAAG,EAAE,QAAQ,SAAS,CAAC,GAAG,GAAG,GACxE;EAEJ,MAAM,cAAc,MAAM,QAAQ,SAAS,CAAC,GAAG,GAAG;CACtD,CAAC;CAED,OAAO;EAAE,QAAQ,OAAO,OAAO,UAAU,MAAM,WAAW,QAAQ;EAAG;CAAO;AAChF;;AAGA,SAAgB,aAAa,QAAmC;CAC5D,MAAM,UAA6C;EAAE,QAAQ;EAAK,QAAQ;EAAK,SAAS;CAAI;CAC5F,OAAO,OAAO,OACT,KAAK,UACF,CACI,GAAG,QAAQ,MAAM,QAAQ,GAAG,MAAM,SAClC,GAAG,MAAM,OAAO,KAAK,UAAU,OAAO,OAAO,CACjD,CAAC,CAAC,KAAK,IAAI,CACf,CAAC,CACA,KAAK,IAAI;AAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"example.d.ts","sourceRoot":"","sources":["../../src/mock/example.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,eAAe,
|
|
1
|
+
{"version":3,"file":"example.d.ts","sourceRoot":"","sources":["../../src/mock/example.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,eAAe,CA2IzD"}
|
package/dist/mock/example.js
CHANGED
package/dist/mock/example.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"example.js","names":[],"sources":["../../src/mock/example.ts"],"sourcesContent":["import type { DefinitionInput } from '../schemas';\n\n/**\n * A small but complete definition: pages with localized titles, a status, a publication date shown\n * for published pages, an author and typed blocks, in tabs and a sidebar, plus authors. For tests\n * and stories, with `createMockBackend()`.\n */\nexport function createExampleDefinition(): DefinitionInput {\n return {\n protocol: 1,\n name: 'Test site',\n locale: 'fr',\n locales: ['fr', 'en'],\n api: { baseUrl: '/panneau/api' },\n resources: [\n {\n id: 'pages',\n label: { singular: 'page', plural: 'pages' },\n itemTitle: 'title',\n fields: [\n {\n name: 'title',\n type: 'text',\n label: 'Titre',\n localized: true,\n rules: [{ rule: 'required' }, { rule: 'max', value: 120 }],\n },\n {\n name: 'status',\n type: 'select',\n options: [\n { value: 'draft', label: 'Brouillon' },\n { value: 'published', label: 'Publiée' },\n ],\n rules: [\n { rule: 'required' },\n { rule: 'in', value: ['draft', 'published'] },\n ],\n },\n {\n name: 'published_at',\n type: 'datetime',\n visibleWhen: { field: 'status', equals: 'published' },\n rules: [{ rule: 'required' }],\n },\n { name: 'author', type: 'relation', resource: 'authors' },\n {\n name: 'blocks',\n type: 'repeater',\n types: [\n {\n id: 'text',\n label: 'Texte',\n fields: [\n {\n name: 'body',\n type: 'richtext',\n rules: [{ rule: 'required' }],\n },\n ],\n },\n {\n id: 'image',\n label: 'Image',\n fields: [\n {\n name: 'image',\n type: 'media',\n rules: [\n { rule: 'accept', value: ['image/*'] },\n { rule: 'maxSize', value: 1000 },\n ],\n },\n ],\n },\n ],\n },\n ],\n form: {\n layout: [\n {\n type: 'tabs',\n children: [\n {\n type: 'tab',\n label: 'Contenu',\n children: [\n {\n type: 'row',\n children: [\n { type: 'field', name: 'title', width: 8 },\n { type: 'field', name: 'status', width: 4 },\n ],\n },\n { type: 'field', name: 'blocks' },\n ],\n },\n ],\n },\n { type: 'sidebar', children: [{ type: 'field', name: 'published_at' }] },\n ],\n },\n list: {\n columns: [\n { field: 'title', sortable: true },\n { field: 'status' },\n { id: 'updated' },\n ],\n filters: [\n { id: 'status', type: 'select' },\n { id: 'published_at', type: 'date-range', label: 'Publication' },\n ],\n sorts: ['title', 'published_at'],\n defaultSort: 'title',\n perPage: 20,\n search: true,\n },\n actions: [\n {\n id: 'publish',\n label: 'Publier',\n scope: ['item', 'selection'],\n placement: ['row', 'toolbar'],\n confirm: { message: 'Publier {count} pages ?' },\n fields: [{ name: 'notify', type: 'boolean' }],\n },\n {\n id: 'edit',\n label: 'Modifier',\n kind: 'link',\n url: '/pages/{id}/edit',\n scope: ['item'],\n },\n ],\n abilities: { viewAny: true, create: true },\n },\n {\n id: 'authors',\n label: { singular: 'auteur', plural: 'auteurs' },\n fields: [{ name: 'name', type: 'text', rules: [{ rule: 'required' }] }],\n },\n ],\n menus: { main: [{ type: 'resources' }, { type: 'link', label: 'Site', url: '/' }] },\n auth: { mode: 'panneau', password: true, providers: [{ id: 'google', label: 'Google' }] },\n };\n}\n"],"mappings":";;;;;;AAOA,SAAgB,0BAA2C;CACvD,OAAO;EACH,UAAU;EACV,MAAM;EACN,QAAQ;EACR,SAAS,CAAC,MAAM,IAAI;EACpB,KAAK,EAAE,SAAS,eAAe;EAC/B,WAAW,CACP;GACI,IAAI;GACJ,OAAO;IAAE,UAAU;IAAQ,QAAQ;GAAQ;GAC3C,WAAW;GACX,QAAQ;IACJ;KACI,MAAM;KACN,MAAM;KACN,OAAO;KACP,WAAW;KACX,OAAO,CAAC,EAAE,MAAM,WAAW,GAAG;MAAE,MAAM;MAAO,OAAO;KAAI,CAAC;IAC7D;IACA;KACI,MAAM;KACN,MAAM;KACN,SAAS,CACL;MAAE,OAAO;MAAS,OAAO;KAAY,GACrC;MAAE,OAAO;MAAa,OAAO;KAAU,CAC3C;KACA,OAAO,CACH,EAAE,MAAM,WAAW,GACnB;MAAE,MAAM;MAAM,OAAO,CAAC,SAAS,WAAW;KAAE,CAChD;IACJ;IACA;KACI,MAAM;KACN,MAAM;KACN,aAAa;MAAE,OAAO;MAAU,QAAQ;KAAY;KACpD,OAAO,CAAC,EAAE,MAAM,WAAW,CAAC;IAChC;IACA;KAAE,MAAM;KAAU,MAAM;KAAY,UAAU;IAAU;IACxD;KACI,MAAM;KACN,MAAM;KACN,OAAO,CACH;MACI,IAAI;MACJ,OAAO;MACP,QAAQ,CACJ;OACI,MAAM;OACN,MAAM;OACN,OAAO,CAAC,EAAE,MAAM,WAAW,CAAC;MAChC,CACJ;KACJ,GACA;MACI,IAAI;MACJ,OAAO;MACP,QAAQ,CACJ;OACI,MAAM;OACN,MAAM;OACN,OAAO,CACH;QAAE,MAAM;QAAU,OAAO,CAAC,SAAS;OAAE,GACrC;QAAE,MAAM;QAAW,OAAO;OAAK,CACnC;MACJ,CACJ;KACJ,CACJ;IACJ;GACJ;GACA,MAAM,EACF,QAAQ,CACJ;IACI,MAAM;IACN,UAAU,CACN;KACI,MAAM;KACN,OAAO;KACP,UAAU,CACN;MACI,MAAM;MACN,UAAU,CACN;OAAE,MAAM;OAAS,MAAM;OAAS,OAAO;MAAE,GACzC;OAAE,MAAM;OAAS,MAAM;OAAU,OAAO;MAAE,CAC9C;KACJ,GACA;MAAE,MAAM;MAAS,MAAM;KAAS,CACpC;IACJ,CACJ;GACJ,GACA;IAAE,MAAM;IAAW,UAAU,CAAC;KAAE,MAAM;KAAS,MAAM;IAAe,CAAC;GAAE,CAC3E,EACJ;GACA,MAAM;IACF,SAAS;KACL;MAAE,OAAO;MAAS,UAAU;KAAK;KACjC,EAAE,OAAO,SAAS;KAClB,EAAE,IAAI,UAAU;IACpB;IACA,SAAS,CACL;KAAE,IAAI;KAAU,MAAM;IAAS,GAC/B;KAAE,IAAI;KAAgB,MAAM;KAAc,OAAO;IAAc,CACnE;IACA,OAAO,CAAC,SAAS,cAAc;IAC/B,aAAa;IACb,SAAS;IACT,QAAQ;GACZ;GACA,SAAS,CACL;IACI,IAAI;IACJ,OAAO;IACP,OAAO,CAAC,QAAQ,WAAW;IAC3B,WAAW,CAAC,OAAO,SAAS;IAC5B,SAAS,EAAE,SAAS,0BAA0B;IAC9C,QAAQ,CAAC;KAAE,MAAM;KAAU,MAAM;IAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"example.js","names":[],"sources":["../../src/mock/example.ts"],"sourcesContent":["import type { DefinitionInput } from '../schemas';\n\n/**\n * A small but complete definition: pages with localized titles, a status, a publication date shown\n * for published pages, an author and typed blocks, in tabs and a sidebar, plus authors. For tests\n * and stories, with `createMockBackend()`.\n */\nexport function createExampleDefinition(): DefinitionInput {\n return {\n protocol: 1,\n name: 'Test site',\n locale: 'fr',\n locales: ['fr', 'en'],\n api: { baseUrl: '/panneau/api' },\n resources: [\n {\n id: 'pages',\n label: { singular: 'page', plural: 'pages' },\n itemTitle: 'title',\n fields: [\n {\n name: 'title',\n type: 'text',\n label: 'Titre',\n localized: true,\n rules: [{ rule: 'required' }, { rule: 'max', value: 120 }],\n },\n {\n name: 'status',\n type: 'select',\n options: [\n { value: 'draft', label: 'Brouillon' },\n { value: 'published', label: 'Publiée' },\n ],\n rules: [\n { rule: 'required' },\n { rule: 'in', value: ['draft', 'published'] },\n ],\n },\n {\n name: 'published_at',\n type: 'datetime',\n visibleWhen: { field: 'status', equals: 'published' },\n rules: [{ rule: 'required' }],\n },\n { name: 'author', type: 'relation', resource: 'authors' },\n {\n name: 'blocks',\n type: 'repeater',\n types: [\n {\n id: 'text',\n label: 'Texte',\n fields: [\n {\n name: 'body',\n type: 'richtext',\n rules: [{ rule: 'required' }],\n },\n ],\n },\n {\n id: 'image',\n label: 'Image',\n fields: [\n {\n name: 'image',\n type: 'media',\n rules: [\n { rule: 'accept', value: ['image/*'] },\n { rule: 'maxSize', value: 1000 },\n ],\n },\n ],\n },\n ],\n },\n ],\n form: {\n layout: [\n {\n type: 'tabs',\n children: [\n {\n type: 'tab',\n label: 'Contenu',\n children: [\n {\n type: 'row',\n children: [\n { type: 'field', name: 'title', width: 8 },\n { type: 'field', name: 'status', width: 4 },\n ],\n },\n { type: 'field', name: 'blocks' },\n ],\n },\n ],\n },\n { type: 'sidebar', children: [{ type: 'field', name: 'published_at' }] },\n ],\n },\n list: {\n columns: [\n { field: 'title', sortable: true },\n { field: 'status' },\n { id: 'updated' },\n ],\n filters: [\n { id: 'status', type: 'select' },\n { id: 'published_at', type: 'date-range', label: 'Publication' },\n ],\n sorts: ['title', 'published_at'],\n defaultSort: 'title',\n perPage: 20,\n search: true,\n },\n actions: [\n {\n id: 'publish',\n label: 'Publier',\n scope: ['item', 'selection'],\n placement: ['row', 'toolbar'],\n confirm: { message: 'Publier {count} pages ?' },\n fields: [{ name: 'notify', type: 'boolean' }],\n dryRun: true,\n },\n {\n id: 'edit',\n label: 'Modifier',\n kind: 'link',\n url: '/pages/{id}/edit',\n scope: ['item'],\n },\n ],\n abilities: { viewAny: true, create: true },\n },\n {\n id: 'authors',\n label: { singular: 'auteur', plural: 'auteurs' },\n fields: [{ name: 'name', type: 'text', rules: [{ rule: 'required' }] }],\n },\n ],\n menus: { main: [{ type: 'resources' }, { type: 'link', label: 'Site', url: '/' }] },\n auth: { mode: 'panneau', password: true, providers: [{ id: 'google', label: 'Google' }] },\n };\n}\n"],"mappings":"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"}
|
package/dist/mock/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mock/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,YAAY,CAAC;AACjE,OAAO,KAAK,EAAgB,IAAI,EAAsB,MAAM,gBAAgB,CAAC;AAI7E,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtC,MAAM,WAAW,kBAAkB;IAC/B,kGAAkG;IAClG,UAAU,EAAE,eAAe,CAAC;IAC5B,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IACxB,oEAAoE;IACpE,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChF,uCAAuC;IACvC,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,EAAE,CAAC;CACvC;AA6GD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,KAAU,EAAE,EAAE,kBAAkB,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mock/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,YAAY,CAAC;AACjE,OAAO,KAAK,EAAgB,IAAI,EAAsB,MAAM,gBAAgB,CAAC;AAI7E,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtC,MAAM,WAAW,kBAAkB;IAC/B,kGAAkG;IAClG,UAAU,EAAE,eAAe,CAAC;IAC5B,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IACxB,oEAAoE;IACpE,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChF,uCAAuC;IACvC,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,EAAE,CAAC;CACvC;AA6GD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,KAAU,EAAE,EAAE,kBAAkB,GAAG,WAAW,CA+O7F;AAED,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/mock/index.js
CHANGED
|
@@ -196,8 +196,27 @@ function createMockBackend({ definition, items = {} }) {
|
|
|
196
196
|
}
|
|
197
197
|
if (segments[2] === "actions" && segments[3] !== void 0 && segments.length === 4) {
|
|
198
198
|
if (method !== "POST") return problem(405, "Method not allowed.");
|
|
199
|
-
|
|
199
|
+
const actionId = segments[3];
|
|
200
|
+
const action = (resource.actions ?? []).find((candidate) => candidate.id === actionId);
|
|
200
201
|
const body = await readBody();
|
|
202
|
+
if (body.dryRun === true) {
|
|
203
|
+
if (action?.dryRun !== true) return problem(400, "This action does not support dry runs.");
|
|
204
|
+
const selected = selectItems(list, body.selection);
|
|
205
|
+
const allowed = selected.filter((item) => item.abilities?.[actionId] !== false);
|
|
206
|
+
return json(200, {
|
|
207
|
+
summary: {
|
|
208
|
+
succeeded: allowed.length,
|
|
209
|
+
failed: 0,
|
|
210
|
+
skipped: selected.length - allowed.length
|
|
211
|
+
},
|
|
212
|
+
results: selected.filter((item) => !allowed.includes(item)).slice(0, 20).map((item) => ({
|
|
213
|
+
id: item.id,
|
|
214
|
+
status: "skipped",
|
|
215
|
+
reason: "forbidden"
|
|
216
|
+
}))
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
if (actionId !== "delete") return problem(404, "Action not found.");
|
|
201
220
|
const selected = selectItems(list, body.selection);
|
|
202
221
|
store.set(resource.id, list.filter((item) => !selected.includes(item)));
|
|
203
222
|
return json(200, {
|
package/dist/mock/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/mock/index.ts"],"sourcesContent":["import { type ListQuery, fromSearchParams, isFilterRange, matchesFilterRange } from '../query';\nimport { type RuleFailure, checkValues } from '../rules';\nimport type { DefinitionInput, ResourceInput } from '../schemas';\nimport type { ActionResult, Item, Problem, Selection } from '../schemas/api';\nimport { isRecord } from '../values';\nimport { PROBLEM_CONTENT_TYPE } from '../version';\n\ntype Values = Record<string, unknown>;\n\nexport interface MockBackendOptions {\n /** The definition served by `GET /definition`. Its `api.baseUrl` is the prefix of every route. */\n definition: DefinitionInput;\n /** Initial values of the items, per resource id. Items without an `id` get one. */\n items?: Record<string, Values[]>;\n}\n\nexport interface MockBackend {\n /** A `fetch`-compatible function that answers protocol requests. */\n fetch: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;\n /** The current items of a resource. */\n items: (resource: string) => Item[];\n}\n\nconst RESERVED_KEYS = new Set(['id', 'version', 'abilities']);\n\nconst DEFAULT_MESSAGES: Record<string, (failure: RuleFailure) => string> = {\n required: () => 'This field is required.',\n min: (failure) => `This value must be at least ${String(failure.value)}.`,\n max: (failure) => `This value must be at most ${String(failure.value)}.`,\n pattern: () => 'This value has an invalid format.',\n email: () => 'This value must be an email address.',\n url: () => 'This value must be a URL.',\n in: () => 'This value is not one of the choices.',\n accept: () => 'This file type is not accepted.',\n maxSize: () => 'This file is too large.',\n before: () => 'This date is too late.',\n after: () => 'This date is too early.',\n};\n\nfunction message(failure: RuleFailure): string {\n return failure.message ?? DEFAULT_MESSAGES[failure.rule]?.(failure) ?? 'This value is invalid.';\n}\n\nfunction json(status: number, body: unknown, headers: Record<string, string> = {}): Response {\n return new Response(status === 204 ? null : JSON.stringify(body), {\n status,\n headers: status === 204 ? headers : { 'Content-Type': 'application/json', ...headers },\n });\n}\n\nfunction problem(status: number, title: string, extra: Partial<Problem> = {}): Response {\n const body: Problem = { type: 'about:blank', title, status, ...extra };\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'Content-Type': PROBLEM_CONTENT_TYPE },\n });\n}\n\nfunction etag(item: Item): Record<string, string> {\n return item.version === null ? {} : { ETag: `\"${item.version}\"` };\n}\n\nfunction parseEtag(value: string): string {\n return value.replace(/^W\\//, '').replace(/^\"(.*)\"$/, '$1');\n}\n\nfunction searchableText(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n if (isRecord(value)) {\n return Object.values(value).map(searchableText).join(' ');\n }\n return '';\n}\n\nfunction compare(a: unknown, b: unknown): number {\n const left = isRecord(a) ? searchableText(a) : a;\n const right = isRecord(b) ? searchableText(b) : b;\n if (left === right) {\n return 0;\n }\n if (left === undefined || left === null) {\n return 1;\n }\n if (right === undefined || right === null) {\n return -1;\n }\n return String(left).localeCompare(String(right), undefined, { numeric: true });\n}\n\nfunction applyQuery(items: Item[], query: Pick<ListQuery, 'filter' | 'q' | 'sort'>): Item[] {\n let result = items;\n Object.entries(query.filter ?? {}).forEach(([key, expected]) => {\n if (isFilterRange(expected)) {\n result = result.filter((item) => matchesFilterRange(item[key], expected));\n return;\n }\n const accepted = (Array.isArray(expected) ? expected : [expected]).map(String);\n result = result.filter((item) => {\n const value = item[key];\n const values = Array.isArray(value) ? value : [value];\n return values.some((candidate) => accepted.includes(String(candidate)));\n });\n });\n if (query.q !== undefined && query.q !== '') {\n const terms = query.q.toLowerCase();\n result = result.filter((item) =>\n Object.entries(item)\n .filter(([key]) => !RESERVED_KEYS.has(key))\n .some(([, value]) => searchableText(value).toLowerCase().includes(terms)),\n );\n }\n const sort = query.sort ?? [];\n if (sort.length > 0) {\n result = [...result].sort((a, b) => {\n for (const part of sort) {\n const descending = part.startsWith('-');\n const key = descending ? part.slice(1) : part;\n const order = compare(a[key], b[key]);\n if (order !== 0) {\n return descending ? -order : order;\n }\n }\n return 0;\n });\n }\n return result;\n}\n\n/**\n * An in-memory backend that implements the protocol's resource routes: definition, list, show,\n * create, update (with `If-Match`), delete and the built-in `delete` action. Values are checked\n * with the portable rules. Used to test the conformance kit, and to develop frontends without a\n * real backend.\n */\nexport function createMockBackend({ definition, items = {} }: MockBackendOptions): MockBackend {\n const store = new Map<string, Item[]>();\n let nextId = 1;\n\n const abilitiesFor = (resource: ResourceInput) =>\n Object.fromEntries([\n ['update', true],\n ['delete', true],\n ...(resource.actions ?? []).map((action) => [action.id, true]),\n ]);\n\n const makeItem = (resource: ResourceInput, values: Values): Item => {\n const id =\n typeof values.id === 'string' || typeof values.id === 'number'\n ? String(values.id)\n : String(nextId++);\n const rest = Object.fromEntries(\n Object.entries(values).filter(([key]) => !RESERVED_KEYS.has(key)),\n );\n return { ...rest, id, version: '1', abilities: abilitiesFor(resource) };\n };\n\n definition.resources.forEach((resource) => {\n store.set(\n resource.id,\n (items[resource.id] ?? []).map((values) => makeItem(resource, values)),\n );\n });\n\n const basePath = new URL(definition.api.baseUrl, 'http://panneau.test').pathname.replace(\n /\\/$/,\n '',\n );\n\n const validationProblem = (\n resource: ResourceInput,\n values: Values,\n mode: 'create' | 'update',\n ) => {\n const failures = checkValues(resource.fields, values, {\n mode,\n partial: mode === 'update',\n locales: definition.locales,\n });\n const paths = Object.keys(failures);\n if (paths.length === 0) {\n return null;\n }\n return problem(422, 'The given data was invalid.', {\n type: 'urn:panneau:problem:validation',\n errors: Object.fromEntries(\n paths.map((path) => [path, (failures[path] ?? []).map(message)]),\n ),\n });\n };\n\n const selectItems = (list: Item[], selection: Selection | undefined): Item[] => {\n if (selection === undefined) {\n return [];\n }\n if ('ids' in selection) {\n const ids = selection.ids as string[];\n return list.filter((item) => ids.includes(item.id));\n }\n const except = selection.except ?? [];\n const { filter, q } = selection.query;\n const query: Pick<ListQuery, 'filter' | 'q'> = {};\n if (filter !== undefined) {\n query.filter = filter as NonNullable<ListQuery['filter']>;\n }\n if (q !== undefined) {\n query.q = q;\n }\n return applyQuery(list, query).filter((item) => !except.includes(item.id));\n };\n\n const handle = async (request: Request): Promise<Response> => {\n const url = new URL(request.url, 'http://panneau.test');\n if (!url.pathname.startsWith(basePath)) {\n return problem(404, 'Not found.');\n }\n const segments = url.pathname\n .slice(basePath.length)\n .split('/')\n .filter((segment) => segment !== '')\n .map(decodeURIComponent);\n const method = request.method.toUpperCase();\n const readBody = async (): Promise<Values> => {\n const body: unknown = await request.json().catch(() => null);\n return isRecord(body) ? body : {};\n };\n\n if (segments.length === 1 && segments[0] === 'definition' && method === 'GET') {\n return json(200, definition);\n }\n if (segments[0] !== 'resources' || segments[1] === undefined) {\n return problem(404, 'Not found.');\n }\n\n const resource = definition.resources.find((candidate) => candidate.id === segments[1]);\n const list = resource !== undefined ? store.get(resource.id) : undefined;\n if (resource === undefined || list === undefined) {\n return problem(404, 'Resource not found.');\n }\n\n if (segments.length === 2) {\n if (method === 'GET') {\n const query = fromSearchParams(url.searchParams);\n const perPage = query.perPage ?? resource.list?.perPage ?? 20;\n const page = query.page ?? 1;\n const sort = query.sort ?? resource.list?.defaultSort?.split(',');\n const matching = applyQuery(list, {\n ...query,\n ...(sort !== undefined ? { sort } : {}),\n });\n return json(200, {\n data: matching.slice((page - 1) * perPage, page * perPage),\n meta: {\n page,\n perPage,\n total: matching.length,\n lastPage: Math.max(1, Math.ceil(matching.length / perPage)),\n },\n });\n }\n if (method === 'POST') {\n const values = await readBody();\n const invalid = validationProblem(resource, values, 'create');\n if (invalid !== null) {\n return invalid;\n }\n const item = makeItem(resource, { ...values, id: undefined });\n list.push(item);\n return json(201, { data: item }, etag(item));\n }\n return problem(405, 'Method not allowed.');\n }\n\n if (segments[2] === 'actions' && segments[3] !== undefined && segments.length === 4) {\n if (method !== 'POST') {\n return problem(405, 'Method not allowed.');\n }\n if (segments[3] !== 'delete') {\n return problem(404, 'Action not found.');\n }\n const body = await readBody();\n const selected = selectItems(list, body.selection as Selection | undefined);\n store.set(\n resource.id,\n list.filter((item) => !selected.includes(item)),\n );\n const result: ActionResult = {\n message: `${selected.length} deleted.`,\n summary: { succeeded: selected.length, failed: 0, skipped: 0 },\n refresh: 'list',\n };\n return json(200, result);\n }\n\n if (segments.length !== 3 || segments[2] === undefined) {\n return problem(404, 'Not found.');\n }\n const id = segments[2];\n const index = list.findIndex((item) => item.id === id);\n const current = list[index];\n if (current === undefined) {\n return problem(404, 'Item not found.');\n }\n\n if (method === 'GET') {\n return json(200, { data: current }, etag(current));\n }\n if (method === 'PATCH') {\n const ifMatch = request.headers.get('If-Match');\n if (\n ifMatch !== null &&\n current.version !== null &&\n parseEtag(ifMatch) !== current.version\n ) {\n return problem(412, 'The item was changed by someone else.', {\n type: 'urn:panneau:problem:version-conflict',\n current,\n });\n }\n const values = await readBody();\n const invalid = validationProblem(resource, values, 'update');\n if (invalid !== null) {\n return invalid;\n }\n const updates = Object.fromEntries(\n Object.entries(values).filter(([key]) => !RESERVED_KEYS.has(key)),\n );\n const updated: Item = {\n ...current,\n ...updates,\n version: current.version === null ? null : String(Number(current.version) + 1),\n };\n list[index] = updated;\n return json(200, { data: updated }, etag(updated));\n }\n if (method === 'DELETE') {\n list.splice(index, 1);\n return json(204, null);\n }\n return problem(405, 'Method not allowed.');\n };\n\n return {\n fetch: (input, init) => {\n if (input instanceof Request) {\n return handle(input);\n }\n // Relative URLs are accepted, as a browser would resolve them.\n return handle(new Request(new URL(input, 'http://panneau.test'), init));\n },\n items: (resource) => [...(store.get(resource) ?? [])],\n };\n}\n\nexport { createExampleDefinition } from './example';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/mock/index.ts"],"sourcesContent":["import { type ListQuery, fromSearchParams, isFilterRange, matchesFilterRange } from '../query';\nimport { type RuleFailure, checkValues } from '../rules';\nimport type { DefinitionInput, ResourceInput } from '../schemas';\nimport type { ActionResult, Item, Problem, Selection } from '../schemas/api';\nimport { isRecord } from '../values';\nimport { PROBLEM_CONTENT_TYPE } from '../version';\n\ntype Values = Record<string, unknown>;\n\nexport interface MockBackendOptions {\n /** The definition served by `GET /definition`. Its `api.baseUrl` is the prefix of every route. */\n definition: DefinitionInput;\n /** Initial values of the items, per resource id. Items without an `id` get one. */\n items?: Record<string, Values[]>;\n}\n\nexport interface MockBackend {\n /** A `fetch`-compatible function that answers protocol requests. */\n fetch: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;\n /** The current items of a resource. */\n items: (resource: string) => Item[];\n}\n\nconst RESERVED_KEYS = new Set(['id', 'version', 'abilities']);\n\nconst DEFAULT_MESSAGES: Record<string, (failure: RuleFailure) => string> = {\n required: () => 'This field is required.',\n min: (failure) => `This value must be at least ${String(failure.value)}.`,\n max: (failure) => `This value must be at most ${String(failure.value)}.`,\n pattern: () => 'This value has an invalid format.',\n email: () => 'This value must be an email address.',\n url: () => 'This value must be a URL.',\n in: () => 'This value is not one of the choices.',\n accept: () => 'This file type is not accepted.',\n maxSize: () => 'This file is too large.',\n before: () => 'This date is too late.',\n after: () => 'This date is too early.',\n};\n\nfunction message(failure: RuleFailure): string {\n return failure.message ?? DEFAULT_MESSAGES[failure.rule]?.(failure) ?? 'This value is invalid.';\n}\n\nfunction json(status: number, body: unknown, headers: Record<string, string> = {}): Response {\n return new Response(status === 204 ? null : JSON.stringify(body), {\n status,\n headers: status === 204 ? headers : { 'Content-Type': 'application/json', ...headers },\n });\n}\n\nfunction problem(status: number, title: string, extra: Partial<Problem> = {}): Response {\n const body: Problem = { type: 'about:blank', title, status, ...extra };\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'Content-Type': PROBLEM_CONTENT_TYPE },\n });\n}\n\nfunction etag(item: Item): Record<string, string> {\n return item.version === null ? {} : { ETag: `\"${item.version}\"` };\n}\n\nfunction parseEtag(value: string): string {\n return value.replace(/^W\\//, '').replace(/^\"(.*)\"$/, '$1');\n}\n\nfunction searchableText(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n if (isRecord(value)) {\n return Object.values(value).map(searchableText).join(' ');\n }\n return '';\n}\n\nfunction compare(a: unknown, b: unknown): number {\n const left = isRecord(a) ? searchableText(a) : a;\n const right = isRecord(b) ? searchableText(b) : b;\n if (left === right) {\n return 0;\n }\n if (left === undefined || left === null) {\n return 1;\n }\n if (right === undefined || right === null) {\n return -1;\n }\n return String(left).localeCompare(String(right), undefined, { numeric: true });\n}\n\nfunction applyQuery(items: Item[], query: Pick<ListQuery, 'filter' | 'q' | 'sort'>): Item[] {\n let result = items;\n Object.entries(query.filter ?? {}).forEach(([key, expected]) => {\n if (isFilterRange(expected)) {\n result = result.filter((item) => matchesFilterRange(item[key], expected));\n return;\n }\n const accepted = (Array.isArray(expected) ? expected : [expected]).map(String);\n result = result.filter((item) => {\n const value = item[key];\n const values = Array.isArray(value) ? value : [value];\n return values.some((candidate) => accepted.includes(String(candidate)));\n });\n });\n if (query.q !== undefined && query.q !== '') {\n const terms = query.q.toLowerCase();\n result = result.filter((item) =>\n Object.entries(item)\n .filter(([key]) => !RESERVED_KEYS.has(key))\n .some(([, value]) => searchableText(value).toLowerCase().includes(terms)),\n );\n }\n const sort = query.sort ?? [];\n if (sort.length > 0) {\n result = [...result].sort((a, b) => {\n for (const part of sort) {\n const descending = part.startsWith('-');\n const key = descending ? part.slice(1) : part;\n const order = compare(a[key], b[key]);\n if (order !== 0) {\n return descending ? -order : order;\n }\n }\n return 0;\n });\n }\n return result;\n}\n\n/**\n * An in-memory backend that implements the protocol's resource routes: definition, list, show,\n * create, update (with `If-Match`), delete and the built-in `delete` action. Values are checked\n * with the portable rules. Used to test the conformance kit, and to develop frontends without a\n * real backend.\n */\nexport function createMockBackend({ definition, items = {} }: MockBackendOptions): MockBackend {\n const store = new Map<string, Item[]>();\n let nextId = 1;\n\n const abilitiesFor = (resource: ResourceInput) =>\n Object.fromEntries([\n ['update', true],\n ['delete', true],\n ...(resource.actions ?? []).map((action) => [action.id, true]),\n ]);\n\n const makeItem = (resource: ResourceInput, values: Values): Item => {\n const id =\n typeof values.id === 'string' || typeof values.id === 'number'\n ? String(values.id)\n : String(nextId++);\n const rest = Object.fromEntries(\n Object.entries(values).filter(([key]) => !RESERVED_KEYS.has(key)),\n );\n return { ...rest, id, version: '1', abilities: abilitiesFor(resource) };\n };\n\n definition.resources.forEach((resource) => {\n store.set(\n resource.id,\n (items[resource.id] ?? []).map((values) => makeItem(resource, values)),\n );\n });\n\n const basePath = new URL(definition.api.baseUrl, 'http://panneau.test').pathname.replace(\n /\\/$/,\n '',\n );\n\n const validationProblem = (\n resource: ResourceInput,\n values: Values,\n mode: 'create' | 'update',\n ) => {\n const failures = checkValues(resource.fields, values, {\n mode,\n partial: mode === 'update',\n locales: definition.locales,\n });\n const paths = Object.keys(failures);\n if (paths.length === 0) {\n return null;\n }\n return problem(422, 'The given data was invalid.', {\n type: 'urn:panneau:problem:validation',\n errors: Object.fromEntries(\n paths.map((path) => [path, (failures[path] ?? []).map(message)]),\n ),\n });\n };\n\n const selectItems = (list: Item[], selection: Selection | undefined): Item[] => {\n if (selection === undefined) {\n return [];\n }\n if ('ids' in selection) {\n const ids = selection.ids as string[];\n return list.filter((item) => ids.includes(item.id));\n }\n const except = selection.except ?? [];\n const { filter, q } = selection.query;\n const query: Pick<ListQuery, 'filter' | 'q'> = {};\n if (filter !== undefined) {\n query.filter = filter as NonNullable<ListQuery['filter']>;\n }\n if (q !== undefined) {\n query.q = q;\n }\n return applyQuery(list, query).filter((item) => !except.includes(item.id));\n };\n\n const handle = async (request: Request): Promise<Response> => {\n const url = new URL(request.url, 'http://panneau.test');\n if (!url.pathname.startsWith(basePath)) {\n return problem(404, 'Not found.');\n }\n const segments = url.pathname\n .slice(basePath.length)\n .split('/')\n .filter((segment) => segment !== '')\n .map(decodeURIComponent);\n const method = request.method.toUpperCase();\n const readBody = async (): Promise<Values> => {\n const body: unknown = await request.json().catch(() => null);\n return isRecord(body) ? body : {};\n };\n\n if (segments.length === 1 && segments[0] === 'definition' && method === 'GET') {\n return json(200, definition);\n }\n if (segments[0] !== 'resources' || segments[1] === undefined) {\n return problem(404, 'Not found.');\n }\n\n const resource = definition.resources.find((candidate) => candidate.id === segments[1]);\n const list = resource !== undefined ? store.get(resource.id) : undefined;\n if (resource === undefined || list === undefined) {\n return problem(404, 'Resource not found.');\n }\n\n if (segments.length === 2) {\n if (method === 'GET') {\n const query = fromSearchParams(url.searchParams);\n const perPage = query.perPage ?? resource.list?.perPage ?? 20;\n const page = query.page ?? 1;\n const sort = query.sort ?? resource.list?.defaultSort?.split(',');\n const matching = applyQuery(list, {\n ...query,\n ...(sort !== undefined ? { sort } : {}),\n });\n return json(200, {\n data: matching.slice((page - 1) * perPage, page * perPage),\n meta: {\n page,\n perPage,\n total: matching.length,\n lastPage: Math.max(1, Math.ceil(matching.length / perPage)),\n },\n });\n }\n if (method === 'POST') {\n const values = await readBody();\n const invalid = validationProblem(resource, values, 'create');\n if (invalid !== null) {\n return invalid;\n }\n const item = makeItem(resource, { ...values, id: undefined });\n list.push(item);\n return json(201, { data: item }, etag(item));\n }\n return problem(405, 'Method not allowed.');\n }\n\n if (segments[2] === 'actions' && segments[3] !== undefined && segments.length === 4) {\n if (method !== 'POST') {\n return problem(405, 'Method not allowed.');\n }\n const actionId = segments[3];\n const action = (resource.actions ?? []).find((candidate) => candidate.id === actionId);\n const body = await readBody();\n if (body.dryRun === true) {\n // A dry run counts what the action would do, and changes nothing.\n if (action?.dryRun !== true) {\n return problem(400, 'This action does not support dry runs.');\n }\n const selected = selectItems(list, body.selection as Selection | undefined);\n const allowed = selected.filter((item) => item.abilities?.[actionId] !== false);\n const result: ActionResult = {\n summary: {\n succeeded: allowed.length,\n failed: 0,\n skipped: selected.length - allowed.length,\n },\n results: selected\n .filter((item) => !allowed.includes(item))\n .slice(0, 20)\n .map((item) => ({ id: item.id, status: 'skipped', reason: 'forbidden' })),\n };\n return json(200, result);\n }\n if (actionId !== 'delete') {\n return problem(404, 'Action not found.');\n }\n const selected = selectItems(list, body.selection as Selection | undefined);\n store.set(\n resource.id,\n list.filter((item) => !selected.includes(item)),\n );\n const result: ActionResult = {\n message: `${selected.length} deleted.`,\n summary: { succeeded: selected.length, failed: 0, skipped: 0 },\n refresh: 'list',\n };\n return json(200, result);\n }\n\n if (segments.length !== 3 || segments[2] === undefined) {\n return problem(404, 'Not found.');\n }\n const id = segments[2];\n const index = list.findIndex((item) => item.id === id);\n const current = list[index];\n if (current === undefined) {\n return problem(404, 'Item not found.');\n }\n\n if (method === 'GET') {\n return json(200, { data: current }, etag(current));\n }\n if (method === 'PATCH') {\n const ifMatch = request.headers.get('If-Match');\n if (\n ifMatch !== null &&\n current.version !== null &&\n parseEtag(ifMatch) !== current.version\n ) {\n return problem(412, 'The item was changed by someone else.', {\n type: 'urn:panneau:problem:version-conflict',\n current,\n });\n }\n const values = await readBody();\n const invalid = validationProblem(resource, values, 'update');\n if (invalid !== null) {\n return invalid;\n }\n const updates = Object.fromEntries(\n Object.entries(values).filter(([key]) => !RESERVED_KEYS.has(key)),\n );\n const updated: Item = {\n ...current,\n ...updates,\n version: current.version === null ? null : String(Number(current.version) + 1),\n };\n list[index] = updated;\n return json(200, { data: updated }, etag(updated));\n }\n if (method === 'DELETE') {\n list.splice(index, 1);\n return json(204, null);\n }\n return problem(405, 'Method not allowed.');\n };\n\n return {\n fetch: (input, init) => {\n if (input instanceof Request) {\n return handle(input);\n }\n // Relative URLs are accepted, as a browser would resolve them.\n return handle(new Request(new URL(input, 'http://panneau.test'), init));\n },\n items: (resource) => [...(store.get(resource) ?? [])],\n };\n}\n\nexport { createExampleDefinition } from './example';\n"],"mappings":";;;;;;AAuBA,IAAM,gCAAgB,IAAI,IAAI;CAAC;CAAM;CAAW;AAAW,CAAC;AAE5D,IAAM,mBAAqE;CACvE,gBAAgB;CAChB,MAAM,YAAY,+BAA+B,OAAO,QAAQ,KAAK,EAAE;CACvE,MAAM,YAAY,8BAA8B,OAAO,QAAQ,KAAK,EAAE;CACtE,eAAe;CACf,aAAa;CACb,WAAW;CACX,UAAU;CACV,cAAc;CACd,eAAe;CACf,cAAc;CACd,aAAa;AACjB;AAEA,SAAS,QAAQ,SAA8B;CAC3C,OAAO,QAAQ,WAAW,iBAAiB,QAAQ,KAAK,GAAG,OAAO,KAAK;AAC3E;AAEA,SAAS,KAAK,QAAgB,MAAe,UAAkC,CAAC,GAAa;CACzF,OAAO,IAAI,SAAS,WAAW,MAAM,OAAO,KAAK,UAAU,IAAI,GAAG;EAC9D;EACA,SAAS,WAAW,MAAM,UAAU;GAAE,gBAAgB;GAAoB,GAAG;EAAQ;CACzF,CAAC;AACL;AAEA,SAAS,QAAQ,QAAgB,OAAe,QAA0B,CAAC,GAAa;CACpF,MAAM,OAAgB;EAAE,MAAM;EAAe;EAAO;EAAQ,GAAG;CAAM;CACrE,OAAO,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;EACtC;EACA,SAAS,EAAE,gBAAgB,qBAAqB;CACpD,CAAC;AACL;AAEA,SAAS,KAAK,MAAoC;CAC9C,OAAO,KAAK,YAAY,OAAO,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK,QAAQ,GAAG;AACpE;AAEA,SAAS,UAAU,OAAuB;CACtC,OAAO,MAAM,QAAQ,QAAQ,EAAE,CAAC,CAAC,QAAQ,YAAY,IAAI;AAC7D;AAEA,SAAS,eAAe,OAAwB;CAC5C,IAAI,OAAO,UAAU,UACjB,OAAO;CAEX,IAAI,SAAS,KAAK,GACd,OAAO,OAAO,OAAO,KAAK,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,KAAK,GAAG;CAE5D,OAAO;AACX;AAEA,SAAS,QAAQ,GAAY,GAAoB;CAC7C,MAAM,OAAO,SAAS,CAAC,IAAI,eAAe,CAAC,IAAI;CAC/C,MAAM,QAAQ,SAAS,CAAC,IAAI,eAAe,CAAC,IAAI;CAChD,IAAI,SAAS,OACT,OAAO;CAEX,IAAI,SAAS,KAAA,KAAa,SAAS,MAC/B,OAAO;CAEX,IAAI,UAAU,KAAA,KAAa,UAAU,MACjC,OAAO;CAEX,OAAO,OAAO,IAAI,CAAC,CAAC,cAAc,OAAO,KAAK,GAAG,KAAA,GAAW,EAAE,SAAS,KAAK,CAAC;AACjF;AAEA,SAAS,WAAW,OAAe,OAAyD;CACxF,IAAI,SAAS;CACb,OAAO,QAAQ,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,cAAc;EAC5D,IAAI,cAAc,QAAQ,GAAG;GACzB,SAAS,OAAO,QAAQ,SAAS,mBAAmB,KAAK,MAAM,QAAQ,CAAC;GACxE;EACJ;EACA,MAAM,YAAY,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ,EAAA,CAAG,IAAI,MAAM;EAC7E,SAAS,OAAO,QAAQ,SAAS;GAC7B,MAAM,QAAQ,KAAK;GAEnB,QADe,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK,EAAA,CACtC,MAAM,cAAc,SAAS,SAAS,OAAO,SAAS,CAAC,CAAC;EAC1E,CAAC;CACL,CAAC;CACD,IAAI,MAAM,MAAM,KAAA,KAAa,MAAM,MAAM,IAAI;EACzC,MAAM,QAAQ,MAAM,EAAE,YAAY;EAClC,SAAS,OAAO,QAAQ,SACpB,OAAO,QAAQ,IAAI,CAAC,CACf,QAAQ,CAAC,SAAS,CAAC,cAAc,IAAI,GAAG,CAAC,CAAC,CAC1C,MAAM,GAAG,WAAW,eAAe,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,KAAK,CAAC,CAChF;CACJ;CACA,MAAM,OAAO,MAAM,QAAQ,CAAC;CAC5B,IAAI,KAAK,SAAS,GACd,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM;EAChC,KAAK,MAAM,QAAQ,MAAM;GACrB,MAAM,aAAa,KAAK,WAAW,GAAG;GACtC,MAAM,MAAM,aAAa,KAAK,MAAM,CAAC,IAAI;GACzC,MAAM,QAAQ,QAAQ,EAAE,MAAM,EAAE,IAAI;GACpC,IAAI,UAAU,GACV,OAAO,aAAa,CAAC,QAAQ;EAErC;EACA,OAAO;CACX,CAAC;CAEL,OAAO;AACX;;;;;;;AAQA,SAAgB,kBAAkB,EAAE,YAAY,QAAQ,CAAC,KAAsC;CAC3F,MAAM,wBAAQ,IAAI,IAAoB;CACtC,IAAI,SAAS;CAEb,MAAM,gBAAgB,aAClB,OAAO,YAAY;EACf,CAAC,UAAU,IAAI;EACf,CAAC,UAAU,IAAI;EACf,IAAI,SAAS,WAAW,CAAC,EAAA,CAAG,KAAK,WAAW,CAAC,OAAO,IAAI,IAAI,CAAC;CACjE,CAAC;CAEL,MAAM,YAAY,UAAyB,WAAyB;EAChE,MAAM,KACF,OAAO,OAAO,OAAO,YAAY,OAAO,OAAO,OAAO,WAChD,OAAO,OAAO,EAAE,IAChB,OAAO,QAAQ;EAIzB,OAAO;GAAE,GAHI,OAAO,YAChB,OAAO,QAAQ,MAAM,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,cAAc,IAAI,GAAG,CAAC,CAExD;GAAM;GAAI,SAAS;GAAK,WAAW,aAAa,QAAQ;EAAE;CAC1E;CAEA,WAAW,UAAU,SAAS,aAAa;EACvC,MAAM,IACF,SAAS,KACR,MAAM,SAAS,OAAO,CAAC,EAAA,CAAG,KAAK,WAAW,SAAS,UAAU,MAAM,CAAC,CACzE;CACJ,CAAC;CAED,MAAM,WAAW,IAAI,IAAI,WAAW,IAAI,SAAS,qBAAqB,CAAC,CAAC,SAAS,QAC7E,OACA,EACJ;CAEA,MAAM,qBACF,UACA,QACA,SACC;EACD,MAAM,WAAW,YAAY,SAAS,QAAQ,QAAQ;GAClD;GACA,SAAS,SAAS;GAClB,SAAS,WAAW;EACxB,CAAC;EACD,MAAM,QAAQ,OAAO,KAAK,QAAQ;EAClC,IAAI,MAAM,WAAW,GACjB,OAAO;EAEX,OAAO,QAAQ,KAAK,+BAA+B;GAC/C,MAAM;GACN,QAAQ,OAAO,YACX,MAAM,KAAK,SAAS,CAAC,OAAO,SAAS,SAAS,CAAC,EAAA,CAAG,IAAI,OAAO,CAAC,CAAC,CACnE;EACJ,CAAC;CACL;CAEA,MAAM,eAAe,MAAc,cAA6C;EAC5E,IAAI,cAAc,KAAA,GACd,OAAO,CAAC;EAEZ,IAAI,SAAS,WAAW;GACpB,MAAM,MAAM,UAAU;GACtB,OAAO,KAAK,QAAQ,SAAS,IAAI,SAAS,KAAK,EAAE,CAAC;EACtD;EACA,MAAM,SAAS,UAAU,UAAU,CAAC;EACpC,MAAM,EAAE,QAAQ,MAAM,UAAU;EAChC,MAAM,QAAyC,CAAC;EAChD,IAAI,WAAW,KAAA,GACX,MAAM,SAAS;EAEnB,IAAI,MAAM,KAAA,GACN,MAAM,IAAI;EAEd,OAAO,WAAW,MAAM,KAAK,CAAC,CAAC,QAAQ,SAAS,CAAC,OAAO,SAAS,KAAK,EAAE,CAAC;CAC7E;CAEA,MAAM,SAAS,OAAO,YAAwC;EAC1D,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,qBAAqB;EACtD,IAAI,CAAC,IAAI,SAAS,WAAW,QAAQ,GACjC,OAAO,QAAQ,KAAK,YAAY;EAEpC,MAAM,WAAW,IAAI,SAChB,MAAM,SAAS,MAAM,CAAC,CACtB,MAAM,GAAG,CAAC,CACV,QAAQ,YAAY,YAAY,EAAE,CAAC,CACnC,IAAI,kBAAkB;EAC3B,MAAM,SAAS,QAAQ,OAAO,YAAY;EAC1C,MAAM,WAAW,YAA6B;GAC1C,MAAM,OAAgB,MAAM,QAAQ,KAAK,CAAC,CAAC,YAAY,IAAI;GAC3D,OAAO,SAAS,IAAI,IAAI,OAAO,CAAC;EACpC;EAEA,IAAI,SAAS,WAAW,KAAK,SAAS,OAAO,gBAAgB,WAAW,OACpE,OAAO,KAAK,KAAK,UAAU;EAE/B,IAAI,SAAS,OAAO,eAAe,SAAS,OAAO,KAAA,GAC/C,OAAO,QAAQ,KAAK,YAAY;EAGpC,MAAM,WAAW,WAAW,UAAU,MAAM,cAAc,UAAU,OAAO,SAAS,EAAE;EACtF,MAAM,OAAO,aAAa,KAAA,IAAY,MAAM,IAAI,SAAS,EAAE,IAAI,KAAA;EAC/D,IAAI,aAAa,KAAA,KAAa,SAAS,KAAA,GACnC,OAAO,QAAQ,KAAK,qBAAqB;EAG7C,IAAI,SAAS,WAAW,GAAG;GACvB,IAAI,WAAW,OAAO;IAClB,MAAM,QAAQ,iBAAiB,IAAI,YAAY;IAC/C,MAAM,UAAU,MAAM,WAAW,SAAS,MAAM,WAAW;IAC3D,MAAM,OAAO,MAAM,QAAQ;IAC3B,MAAM,OAAO,MAAM,QAAQ,SAAS,MAAM,aAAa,MAAM,GAAG;IAChE,MAAM,WAAW,WAAW,MAAM;KAC9B,GAAG;KACH,GAAI,SAAS,KAAA,IAAY,EAAE,KAAK,IAAI,CAAC;IACzC,CAAC;IACD,OAAO,KAAK,KAAK;KACb,MAAM,SAAS,OAAO,OAAO,KAAK,SAAS,OAAO,OAAO;KACzD,MAAM;MACF;MACA;MACA,OAAO,SAAS;MAChB,UAAU,KAAK,IAAI,GAAG,KAAK,KAAK,SAAS,SAAS,OAAO,CAAC;KAC9D;IACJ,CAAC;GACL;GACA,IAAI,WAAW,QAAQ;IACnB,MAAM,SAAS,MAAM,SAAS;IAC9B,MAAM,UAAU,kBAAkB,UAAU,QAAQ,QAAQ;IAC5D,IAAI,YAAY,MACZ,OAAO;IAEX,MAAM,OAAO,SAAS,UAAU;KAAE,GAAG;KAAQ,IAAI,KAAA;IAAU,CAAC;IAC5D,KAAK,KAAK,IAAI;IACd,OAAO,KAAK,KAAK,EAAE,MAAM,KAAK,GAAG,KAAK,IAAI,CAAC;GAC/C;GACA,OAAO,QAAQ,KAAK,qBAAqB;EAC7C;EAEA,IAAI,SAAS,OAAO,aAAa,SAAS,OAAO,KAAA,KAAa,SAAS,WAAW,GAAG;GACjF,IAAI,WAAW,QACX,OAAO,QAAQ,KAAK,qBAAqB;GAE7C,MAAM,WAAW,SAAS;GAC1B,MAAM,UAAU,SAAS,WAAW,CAAC,EAAA,CAAG,MAAM,cAAc,UAAU,OAAO,QAAQ;GACrF,MAAM,OAAO,MAAM,SAAS;GAC5B,IAAI,KAAK,WAAW,MAAM;IAEtB,IAAI,QAAQ,WAAW,MACnB,OAAO,QAAQ,KAAK,wCAAwC;IAEhE,MAAM,WAAW,YAAY,MAAM,KAAK,SAAkC;IAC1E,MAAM,UAAU,SAAS,QAAQ,SAAS,KAAK,YAAY,cAAc,KAAK;IAY9E,OAAO,KAAK,KAAK;KAVb,SAAS;MACL,WAAW,QAAQ;MACnB,QAAQ;MACR,SAAS,SAAS,SAAS,QAAQ;KACvC;KACA,SAAS,SACJ,QAAQ,SAAS,CAAC,QAAQ,SAAS,IAAI,CAAC,CAAC,CACzC,MAAM,GAAG,EAAE,CAAC,CACZ,KAAK,UAAU;MAAE,IAAI,KAAK;MAAI,QAAQ;MAAW,QAAQ;KAAY,EAAE;IAE/D,CAAM;GAC3B;GACA,IAAI,aAAa,UACb,OAAO,QAAQ,KAAK,mBAAmB;GAE3C,MAAM,WAAW,YAAY,MAAM,KAAK,SAAkC;GAC1E,MAAM,IACF,SAAS,IACT,KAAK,QAAQ,SAAS,CAAC,SAAS,SAAS,IAAI,CAAC,CAClD;GAMA,OAAO,KAAK,KAAK;IAJb,SAAS,GAAG,SAAS,OAAO;IAC5B,SAAS;KAAE,WAAW,SAAS;KAAQ,QAAQ;KAAG,SAAS;IAAE;IAC7D,SAAS;GAEI,CAAM;EAC3B;EAEA,IAAI,SAAS,WAAW,KAAK,SAAS,OAAO,KAAA,GACzC,OAAO,QAAQ,KAAK,YAAY;EAEpC,MAAM,KAAK,SAAS;EACpB,MAAM,QAAQ,KAAK,WAAW,SAAS,KAAK,OAAO,EAAE;EACrD,MAAM,UAAU,KAAK;EACrB,IAAI,YAAY,KAAA,GACZ,OAAO,QAAQ,KAAK,iBAAiB;EAGzC,IAAI,WAAW,OACX,OAAO,KAAK,KAAK,EAAE,MAAM,QAAQ,GAAG,KAAK,OAAO,CAAC;EAErD,IAAI,WAAW,SAAS;GACpB,MAAM,UAAU,QAAQ,QAAQ,IAAI,UAAU;GAC9C,IACI,YAAY,QACZ,QAAQ,YAAY,QACpB,UAAU,OAAO,MAAM,QAAQ,SAE/B,OAAO,QAAQ,KAAK,yCAAyC;IACzD,MAAM;IACN;GACJ,CAAC;GAEL,MAAM,SAAS,MAAM,SAAS;GAC9B,MAAM,UAAU,kBAAkB,UAAU,QAAQ,QAAQ;GAC5D,IAAI,YAAY,MACZ,OAAO;GAEX,MAAM,UAAU,OAAO,YACnB,OAAO,QAAQ,MAAM,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,cAAc,IAAI,GAAG,CAAC,CACpE;GACA,MAAM,UAAgB;IAClB,GAAG;IACH,GAAG;IACH,SAAS,QAAQ,YAAY,OAAO,OAAO,OAAO,OAAO,QAAQ,OAAO,IAAI,CAAC;GACjF;GACA,KAAK,SAAS;GACd,OAAO,KAAK,KAAK,EAAE,MAAM,QAAQ,GAAG,KAAK,OAAO,CAAC;EACrD;EACA,IAAI,WAAW,UAAU;GACrB,KAAK,OAAO,OAAO,CAAC;GACpB,OAAO,KAAK,KAAK,IAAI;EACzB;EACA,OAAO,QAAQ,KAAK,qBAAqB;CAC7C;CAEA,OAAO;EACH,QAAQ,OAAO,SAAS;GACpB,IAAI,iBAAiB,SACjB,OAAO,OAAO,KAAK;GAGvB,OAAO,OAAO,IAAI,QAAQ,IAAI,IAAI,OAAO,qBAAqB,GAAG,IAAI,CAAC;EAC1E;EACA,QAAQ,aAAa,CAAC,GAAI,MAAM,IAAI,QAAQ,KAAK,CAAC,CAAE;CACxD;AACJ"}
|
package/dist/openapi.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAQA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAQA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA4E1C,oEAAoE;AACpE,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAWnE;AAED,6DAA6D;AAC7D,wBAAgB,0BAA0B,IAAI,UAAU,CAQvD;AAED,oEAAoE;AACpE,wBAAgB,qBAAqB,IAAI,UAAU,CAQlD;AAED,wFAAwF;AACxF,wBAAgB,0BAA0B,IAAI,UAAU,CAQvD;AAED,wDAAwD;AACxD,wBAAgB,qBAAqB,IAAI,UAAU,CAialD"}
|
package/dist/openapi.js
CHANGED
|
@@ -13,6 +13,7 @@ var ok = (description, schema, headers) => ({
|
|
|
13
13
|
...headers !== void 0 ? { headers } : {}
|
|
14
14
|
});
|
|
15
15
|
var PROBLEMS = {
|
|
16
|
+
400: "Bad request, such as a dry run of an action that does not declare `dryRun`.",
|
|
16
17
|
401: "Not authenticated.",
|
|
17
18
|
403: "Not allowed.",
|
|
18
19
|
404: "Not found.",
|
|
@@ -220,7 +221,7 @@ function createOpenApiDocument() {
|
|
|
220
221
|
responses: {
|
|
221
222
|
200: ok("The result.", ref("ActionResult")),
|
|
222
223
|
202: ok("The action runs in the background.", ref("ActionRunResponse")),
|
|
223
|
-
...problems(401, 403, 404, 409, 422)
|
|
224
|
+
...problems(400, 401, 403, 404, 409, 422)
|
|
224
225
|
}
|
|
225
226
|
}
|
|
226
227
|
},
|
package/dist/openapi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.js","names":[],"sources":["../src/openapi.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport { createSchemaRegistry } from './schemas';\nimport { BootConfig } from './schemas/boot';\nimport { Definition } from './schemas/definition';\nimport { Theme } from './schemas/theme';\nimport { PROBLEM_CONTENT_TYPE, PROTOCOL_VERSION } from './version';\n\ntype JsonObject = Record<string, unknown>;\n\nconst ref = (id: string): JsonObject => ({ $ref: `#/components/schemas/${id}` });\n\nconst json = (schema: JsonObject): JsonObject => ({ 'application/json': { schema } });\n\nconst ok = (description: string, schema?: JsonObject, headers?: JsonObject): JsonObject => ({\n description,\n ...(schema !== undefined ? { content: json(schema) } : {}),\n ...(headers !== undefined ? { headers } : {}),\n});\n\nconst PROBLEMS: Record<number, string> = {\n 401: 'Not authenticated.',\n 403: 'Not allowed.',\n 404: 'Not found.',\n 409: 'Conflict with a business rule.',\n 412: 'Version conflict: `If-Match` does not match the current version, which is in `current`.',\n 422: 'Invalid values: messages are in `errors`, keyed by dot path.',\n};\n\nfunction problems(...statuses: number[]): JsonObject {\n return Object.fromEntries(\n statuses.map((status) => [\n String(status),\n {\n description: PROBLEMS[status],\n content: { [PROBLEM_CONTENT_TYPE]: { schema: ref('Problem') } },\n },\n ]),\n );\n}\n\nconst etag = { ETag: { description: 'The version of the item.', schema: { type: 'string' } } };\n\nconst pathParameter = (name: string, description: string): JsonObject => ({\n name,\n in: 'path',\n required: true,\n description,\n schema: { type: 'string' },\n});\n\nconst queryParameter = (name: string, description: string, schema: JsonObject): JsonObject => ({\n name,\n in: 'query',\n required: false,\n description,\n schema,\n});\n\nconst listParameters = [\n queryParameter('page', 'Page number, from 1.', { type: 'integer', minimum: 1 }),\n queryParameter('perPage', 'Items per page.', { type: 'integer', minimum: 1 }),\n queryParameter('sort', 'Comma-separated fields; a `-` prefix sorts descending.', {\n type: 'string',\n }),\n {\n name: 'filter',\n in: 'query',\n required: false,\n style: 'deepObject',\n explode: true,\n description:\n '`filter[status]=published`; `filter[tags][]=a&filter[tags][]=b` for any of several values; `filter[published_at][from]=2026-01-01&filter[published_at][to]=2026-01-31` for the inclusive bounds of a range filter (`date-range`), without the open end.',\n schema: { type: 'object', additionalProperties: true },\n },\n queryParameter('q', 'Search.', { type: 'string' }),\n queryParameter('fields', 'Comma-separated fields to include in each item.', { type: 'string' }),\n];\n\nconst resource = pathParameter('resource', 'Resource id.');\nconst id = pathParameter('id', 'Item id.');\nconst values = { type: 'object', additionalProperties: true };\n\n/** Component schemas, generated from the protocol's Zod schemas. */\nexport function createComponentSchemas(): Record<string, JsonObject> {\n const { schemas } = z.toJSONSchema(createSchemaRegistry(), {\n io: 'input',\n uri: (schemaId) => `#/components/schemas/${schemaId}`,\n });\n return Object.fromEntries(\n Object.entries(schemas).map(([schemaId, schema]) => {\n const { $schema: _schema, $id: _id, ...rest } = schema as JsonObject;\n return [schemaId, rest];\n }),\n );\n}\n\n/** The JSON Schema of the definition (`GET /definition`). */\nexport function createDefinitionJsonSchema(): JsonObject {\n return {\n $id: 'https://github.com/folkloreinc/panneau-js/blob/v5.x/packages/protocol/schema/definition.schema.json',\n ...(z.toJSONSchema(Definition, {\n io: 'input',\n metadata: createSchemaRegistry(),\n }) as JsonObject),\n };\n}\n\n/** The JSON Schema of a theme, for themes written as JSON files. */\nexport function createThemeJsonSchema(): JsonObject {\n return {\n $id: 'https://github.com/folkloreinc/panneau-js/blob/v5.x/packages/protocol/schema/theme.schema.json',\n ...(z.toJSONSchema(Theme, {\n io: 'input',\n metadata: createSchemaRegistry(),\n }) as JsonObject),\n };\n}\n\n/** The JSON Schema of the boot config, which a server writes in the page of the app. */\nexport function createBootConfigJsonSchema(): JsonObject {\n return {\n $id: 'https://github.com/folkloreinc/panneau-js/blob/v5.x/packages/protocol/schema/boot.schema.json',\n ...(z.toJSONSchema(BootConfig, {\n io: 'input',\n metadata: createSchemaRegistry(),\n }) as JsonObject),\n };\n}\n\n/** The OpenAPI 3.1 document of the Panneau HTTP API. */\nexport function createOpenApiDocument(): JsonObject {\n return {\n openapi: '3.1.0',\n info: {\n title: 'Panneau protocol',\n version: String(PROTOCOL_VERSION),\n description:\n 'The HTTP API between a Panneau frontend and its backend. Paths are relative to `api.baseUrl` of the definition. Authentication is up to the backend (session cookie or bearer token). Errors use `application/problem+json`.',\n },\n paths: {\n '/definition': {\n get: {\n operationId: 'getDefinition',\n summary: 'The definition for the current user, in the current locale.',\n responses: {\n 200: ok('The definition.', ref('Definition')),\n ...problems(401, 403),\n },\n },\n },\n '/resources/{resource}': {\n parameters: [resource],\n get: {\n operationId: 'listItems',\n parameters: listParameters,\n responses: {\n 200: ok('A page of items.', ref('ListResponse')),\n ...problems(401, 403, 404),\n },\n },\n post: {\n operationId: 'createItem',\n requestBody: { required: true, content: json(values) },\n responses: {\n 201: ok('The created item.', ref('ItemResponse'), etag),\n ...problems(401, 403, 404, 409, 422),\n },\n },\n },\n '/resources/{resource}/{id}': {\n parameters: [resource, id],\n get: {\n operationId: 'getItem',\n responses: {\n 200: ok('The item.', ref('ItemResponse'), etag),\n ...problems(401, 403, 404),\n },\n },\n patch: {\n operationId: 'updateItem',\n description: 'Partial update: only the values sent are changed.',\n parameters: [\n {\n name: 'If-Match',\n in: 'header',\n required: false,\n description: 'The version the client edited.',\n schema: { type: 'string' },\n },\n ],\n requestBody: { required: true, content: json(values) },\n responses: {\n 200: ok('The updated item.', ref('ItemResponse'), etag),\n ...problems(401, 403, 404, 409, 412, 422),\n },\n },\n delete: {\n operationId: 'deleteItem',\n responses: { 204: ok('Deleted.'), ...problems(401, 403, 404, 409) },\n },\n },\n '/resources/{resource}/{id}/preview': {\n parameters: [resource, id],\n post: {\n operationId: 'previewItem',\n requestBody: { required: true, content: json(values) },\n responses: {\n 200: ok('A short-lived preview URL.', ref('PreviewResponse')),\n ...problems(401, 403, 404, 422),\n },\n },\n },\n '/resources/{resource}/actions/{action}': {\n parameters: [resource, pathParameter('action', 'Action id.')],\n post: {\n operationId: 'runAction',\n requestBody: {\n required: true,\n content: {\n ...json(ref('ActionRequest')),\n 'multipart/form-data': { schema: ref('ActionRequest') },\n },\n },\n responses: {\n 200: ok('The result.', ref('ActionResult')),\n 202: ok('The action runs in the background.', ref('ActionRunResponse')),\n ...problems(401, 403, 404, 409, 422),\n },\n },\n },\n '/actions/runs': {\n get: {\n operationId: 'listActionRuns',\n summary: \"The current user's recent runs.\",\n responses: {\n 200: ok('Runs, newest first.', {\n type: 'object',\n required: ['data'],\n properties: { data: { type: 'array', items: ref('ActionRun') } },\n }),\n ...problems(401),\n },\n },\n },\n '/actions/runs/{run}': {\n parameters: [pathParameter('run', 'Run id.')],\n get: {\n operationId: 'getActionRun',\n responses: {\n 200: ok('The run.', ref('ActionRunResponse')),\n ...problems(401, 403, 404),\n },\n },\n delete: {\n operationId: 'cancelActionRun',\n responses: { 204: ok('Cancelled.'), ...problems(401, 403, 404, 409) },\n },\n },\n '/media': {\n get: {\n operationId: 'listMedia',\n parameters: listParameters,\n responses: {\n 200: ok('A page of media.', ref('MediaListResponse')),\n ...problems(401, 403),\n },\n },\n post: {\n operationId: 'uploadMedia',\n requestBody: {\n required: true,\n content: {\n 'multipart/form-data': {\n schema: {\n type: 'object',\n required: ['file'],\n properties: {\n file: {\n type: 'string',\n contentMediaType: 'application/octet-stream',\n },\n name: { type: 'string' },\n tags: { type: 'array', items: { type: 'string' } },\n },\n },\n },\n },\n },\n responses: {\n 201: ok('The created media.', ref('MediaResponse')),\n ...problems(401, 403, 422),\n },\n },\n },\n '/media/tags': {\n get: {\n operationId: 'listMediaTags',\n responses: {\n 200: ok('Tags in use.', {\n type: 'object',\n required: ['data'],\n properties: { data: { type: 'array', items: { type: 'string' } } },\n }),\n ...problems(401, 403),\n },\n },\n },\n '/media/{id}': {\n parameters: [pathParameter('id', 'Media id.')],\n get: {\n operationId: 'getMedia',\n responses: {\n 200: ok('The media.', ref('MediaResponse')),\n ...problems(401, 403, 404),\n },\n },\n patch: {\n operationId: 'updateMedia',\n description: 'Updates metadata, tags or the image `transform`.',\n requestBody: { required: true, content: json(values) },\n responses: {\n 200: ok('The updated media.', ref('MediaResponse')),\n ...problems(401, 403, 404, 422),\n },\n },\n delete: {\n operationId: 'deleteMedia',\n responses: { 204: ok('Moved to the trash.'), ...problems(401, 403, 404, 409) },\n },\n },\n '/media/{id}/file': {\n parameters: [pathParameter('id', 'Media id.')],\n post: {\n operationId: 'replaceMediaFile',\n requestBody: {\n required: true,\n content: {\n 'multipart/form-data': {\n schema: {\n type: 'object',\n required: ['file'],\n properties: {\n file: {\n type: 'string',\n contentMediaType: 'application/octet-stream',\n },\n },\n },\n },\n },\n },\n responses: {\n 200: ok('The media.', ref('MediaResponse')),\n ...problems(401, 403, 404, 422),\n },\n },\n },\n '/media/{id}/restore': {\n parameters: [pathParameter('id', 'Media id.')],\n post: {\n operationId: 'restoreMedia',\n responses: {\n 200: ok('The restored media.', ref('MediaResponse')),\n ...problems(401, 403, 404),\n },\n },\n },\n '/auth/session': {\n get: {\n operationId: 'getSession',\n responses: { 200: ok('The current user.', ref('Session')), ...problems(401) },\n },\n },\n '/auth/login': {\n post: {\n operationId: 'login',\n requestBody: {\n required: true,\n content: json({\n type: 'object',\n required: ['email', 'password'],\n properties: {\n email: { type: 'string' },\n password: { type: 'string' },\n remember: { type: 'boolean' },\n },\n }),\n },\n responses: {\n 200: ok('Logged in.', ref('Session')),\n 202: ok(\n 'A second factor is required: answer `/auth/two-factor/challenge`.',\n {\n type: 'object',\n properties: { twoFactor: { type: 'boolean', const: true } },\n },\n ),\n ...problems(422),\n },\n },\n },\n '/auth/logout': {\n post: { operationId: 'logout', responses: { 204: ok('Logged out.') } },\n },\n '/auth/providers/{provider}/redirect': {\n parameters: [pathParameter('provider', 'Provider id.')],\n get: {\n operationId: 'redirectToProvider',\n parameters: [\n queryParameter('next', 'Local path to go to after login.', {\n type: 'string',\n }),\n ],\n responses: {\n 302: { description: 'Redirect to the provider.' },\n ...problems(404),\n },\n },\n },\n '/auth/password/forgot': {\n post: {\n operationId: 'forgotPassword',\n requestBody: {\n required: true,\n content: json({\n type: 'object',\n required: ['email'],\n properties: { email: { type: 'string' } },\n }),\n },\n responses: {\n 204: ok('A reset link was sent, if the account exists.'),\n ...problems(422),\n },\n },\n },\n '/auth/password/reset': {\n post: {\n operationId: 'resetPassword',\n requestBody: {\n required: true,\n content: json({\n type: 'object',\n required: ['token', 'email', 'password'],\n properties: {\n token: { type: 'string' },\n email: { type: 'string' },\n password: { type: 'string' },\n },\n }),\n },\n responses: { 204: ok('The password was reset.'), ...problems(422) },\n },\n },\n '/auth/two-factor/challenge': {\n post: {\n operationId: 'twoFactorChallenge',\n requestBody: {\n required: true,\n content: json({\n type: 'object',\n properties: {\n code: { type: 'string' },\n recoveryCode: { type: 'string' },\n },\n }),\n },\n responses: { 200: ok('Logged in.', ref('Session')), ...problems(422) },\n },\n },\n '/auth/passkeys/options': {\n post: {\n operationId: 'passkeyOptions',\n responses: {\n 200: ok('WebAuthn request options.', {\n type: 'object',\n additionalProperties: true,\n }),\n },\n },\n },\n '/auth/passkeys/login': {\n post: {\n operationId: 'passkeyLogin',\n requestBody: {\n required: true,\n content: json({ type: 'object', additionalProperties: true }),\n },\n responses: { 200: ok('Logged in.', ref('Session')), ...problems(422) },\n },\n },\n '/account': {\n get: {\n operationId: 'getAccount',\n responses: {\n 200: ok('The current user.', {\n type: 'object',\n required: ['data'],\n properties: { data: ref('User') },\n }),\n ...problems(401),\n },\n },\n patch: {\n operationId: 'updateAccount',\n requestBody: { required: true, content: json(values) },\n responses: {\n 200: ok('The updated user.', {\n type: 'object',\n required: ['data'],\n properties: { data: ref('User') },\n }),\n ...problems(401, 422),\n },\n },\n },\n '/search': {\n get: {\n operationId: 'search',\n parameters: [\n {\n ...queryParameter('q', 'Search terms.', { type: 'string' }),\n required: true,\n },\n ],\n responses: {\n 200: ok('Results grouped by resource.', ref('SearchResponse')),\n ...problems(401),\n },\n },\n },\n '/dashboard/widgets/{widget}': {\n parameters: [pathParameter('widget', 'Widget id.')],\n get: {\n operationId: 'getWidgetData',\n responses: {\n 200: ok(\"The widget's data. Its shape depends on the widget type.\", {\n type: 'object',\n additionalProperties: true,\n }),\n ...problems(401, 403, 404),\n },\n },\n },\n },\n components: { schemas: createComponentSchemas() },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"openapi.js","names":[],"sources":["../src/openapi.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport { createSchemaRegistry } from './schemas';\nimport { BootConfig } from './schemas/boot';\nimport { Definition } from './schemas/definition';\nimport { Theme } from './schemas/theme';\nimport { PROBLEM_CONTENT_TYPE, PROTOCOL_VERSION } from './version';\n\ntype JsonObject = Record<string, unknown>;\n\nconst ref = (id: string): JsonObject => ({ $ref: `#/components/schemas/${id}` });\n\nconst json = (schema: JsonObject): JsonObject => ({ 'application/json': { schema } });\n\nconst ok = (description: string, schema?: JsonObject, headers?: JsonObject): JsonObject => ({\n description,\n ...(schema !== undefined ? { content: json(schema) } : {}),\n ...(headers !== undefined ? { headers } : {}),\n});\n\nconst PROBLEMS: Record<number, string> = {\n 400: 'Bad request, such as a dry run of an action that does not declare `dryRun`.',\n 401: 'Not authenticated.',\n 403: 'Not allowed.',\n 404: 'Not found.',\n 409: 'Conflict with a business rule.',\n 412: 'Version conflict: `If-Match` does not match the current version, which is in `current`.',\n 422: 'Invalid values: messages are in `errors`, keyed by dot path.',\n};\n\nfunction problems(...statuses: number[]): JsonObject {\n return Object.fromEntries(\n statuses.map((status) => [\n String(status),\n {\n description: PROBLEMS[status],\n content: { [PROBLEM_CONTENT_TYPE]: { schema: ref('Problem') } },\n },\n ]),\n );\n}\n\nconst etag = { ETag: { description: 'The version of the item.', schema: { type: 'string' } } };\n\nconst pathParameter = (name: string, description: string): JsonObject => ({\n name,\n in: 'path',\n required: true,\n description,\n schema: { type: 'string' },\n});\n\nconst queryParameter = (name: string, description: string, schema: JsonObject): JsonObject => ({\n name,\n in: 'query',\n required: false,\n description,\n schema,\n});\n\nconst listParameters = [\n queryParameter('page', 'Page number, from 1.', { type: 'integer', minimum: 1 }),\n queryParameter('perPage', 'Items per page.', { type: 'integer', minimum: 1 }),\n queryParameter('sort', 'Comma-separated fields; a `-` prefix sorts descending.', {\n type: 'string',\n }),\n {\n name: 'filter',\n in: 'query',\n required: false,\n style: 'deepObject',\n explode: true,\n description:\n '`filter[status]=published`; `filter[tags][]=a&filter[tags][]=b` for any of several values; `filter[published_at][from]=2026-01-01&filter[published_at][to]=2026-01-31` for the inclusive bounds of a range filter (`date-range`), without the open end.',\n schema: { type: 'object', additionalProperties: true },\n },\n queryParameter('q', 'Search.', { type: 'string' }),\n queryParameter('fields', 'Comma-separated fields to include in each item.', { type: 'string' }),\n];\n\nconst resource = pathParameter('resource', 'Resource id.');\nconst id = pathParameter('id', 'Item id.');\nconst values = { type: 'object', additionalProperties: true };\n\n/** Component schemas, generated from the protocol's Zod schemas. */\nexport function createComponentSchemas(): Record<string, JsonObject> {\n const { schemas } = z.toJSONSchema(createSchemaRegistry(), {\n io: 'input',\n uri: (schemaId) => `#/components/schemas/${schemaId}`,\n });\n return Object.fromEntries(\n Object.entries(schemas).map(([schemaId, schema]) => {\n const { $schema: _schema, $id: _id, ...rest } = schema as JsonObject;\n return [schemaId, rest];\n }),\n );\n}\n\n/** The JSON Schema of the definition (`GET /definition`). */\nexport function createDefinitionJsonSchema(): JsonObject {\n return {\n $id: 'https://github.com/folkloreinc/panneau-js/blob/v5.x/packages/protocol/schema/definition.schema.json',\n ...(z.toJSONSchema(Definition, {\n io: 'input',\n metadata: createSchemaRegistry(),\n }) as JsonObject),\n };\n}\n\n/** The JSON Schema of a theme, for themes written as JSON files. */\nexport function createThemeJsonSchema(): JsonObject {\n return {\n $id: 'https://github.com/folkloreinc/panneau-js/blob/v5.x/packages/protocol/schema/theme.schema.json',\n ...(z.toJSONSchema(Theme, {\n io: 'input',\n metadata: createSchemaRegistry(),\n }) as JsonObject),\n };\n}\n\n/** The JSON Schema of the boot config, which a server writes in the page of the app. */\nexport function createBootConfigJsonSchema(): JsonObject {\n return {\n $id: 'https://github.com/folkloreinc/panneau-js/blob/v5.x/packages/protocol/schema/boot.schema.json',\n ...(z.toJSONSchema(BootConfig, {\n io: 'input',\n metadata: createSchemaRegistry(),\n }) as JsonObject),\n };\n}\n\n/** The OpenAPI 3.1 document of the Panneau HTTP API. */\nexport function createOpenApiDocument(): JsonObject {\n return {\n openapi: '3.1.0',\n info: {\n title: 'Panneau protocol',\n version: String(PROTOCOL_VERSION),\n description:\n 'The HTTP API between a Panneau frontend and its backend. Paths are relative to `api.baseUrl` of the definition. Authentication is up to the backend (session cookie or bearer token). Errors use `application/problem+json`.',\n },\n paths: {\n '/definition': {\n get: {\n operationId: 'getDefinition',\n summary: 'The definition for the current user, in the current locale.',\n responses: {\n 200: ok('The definition.', ref('Definition')),\n ...problems(401, 403),\n },\n },\n },\n '/resources/{resource}': {\n parameters: [resource],\n get: {\n operationId: 'listItems',\n parameters: listParameters,\n responses: {\n 200: ok('A page of items.', ref('ListResponse')),\n ...problems(401, 403, 404),\n },\n },\n post: {\n operationId: 'createItem',\n requestBody: { required: true, content: json(values) },\n responses: {\n 201: ok('The created item.', ref('ItemResponse'), etag),\n ...problems(401, 403, 404, 409, 422),\n },\n },\n },\n '/resources/{resource}/{id}': {\n parameters: [resource, id],\n get: {\n operationId: 'getItem',\n responses: {\n 200: ok('The item.', ref('ItemResponse'), etag),\n ...problems(401, 403, 404),\n },\n },\n patch: {\n operationId: 'updateItem',\n description: 'Partial update: only the values sent are changed.',\n parameters: [\n {\n name: 'If-Match',\n in: 'header',\n required: false,\n description: 'The version the client edited.',\n schema: { type: 'string' },\n },\n ],\n requestBody: { required: true, content: json(values) },\n responses: {\n 200: ok('The updated item.', ref('ItemResponse'), etag),\n ...problems(401, 403, 404, 409, 412, 422),\n },\n },\n delete: {\n operationId: 'deleteItem',\n responses: { 204: ok('Deleted.'), ...problems(401, 403, 404, 409) },\n },\n },\n '/resources/{resource}/{id}/preview': {\n parameters: [resource, id],\n post: {\n operationId: 'previewItem',\n requestBody: { required: true, content: json(values) },\n responses: {\n 200: ok('A short-lived preview URL.', ref('PreviewResponse')),\n ...problems(401, 403, 404, 422),\n },\n },\n },\n '/resources/{resource}/actions/{action}': {\n parameters: [resource, pathParameter('action', 'Action id.')],\n post: {\n operationId: 'runAction',\n requestBody: {\n required: true,\n content: {\n ...json(ref('ActionRequest')),\n 'multipart/form-data': { schema: ref('ActionRequest') },\n },\n },\n responses: {\n 200: ok('The result.', ref('ActionResult')),\n 202: ok('The action runs in the background.', ref('ActionRunResponse')),\n ...problems(400, 401, 403, 404, 409, 422),\n },\n },\n },\n '/actions/runs': {\n get: {\n operationId: 'listActionRuns',\n summary: \"The current user's recent runs.\",\n responses: {\n 200: ok('Runs, newest first.', {\n type: 'object',\n required: ['data'],\n properties: { data: { type: 'array', items: ref('ActionRun') } },\n }),\n ...problems(401),\n },\n },\n },\n '/actions/runs/{run}': {\n parameters: [pathParameter('run', 'Run id.')],\n get: {\n operationId: 'getActionRun',\n responses: {\n 200: ok('The run.', ref('ActionRunResponse')),\n ...problems(401, 403, 404),\n },\n },\n delete: {\n operationId: 'cancelActionRun',\n responses: { 204: ok('Cancelled.'), ...problems(401, 403, 404, 409) },\n },\n },\n '/media': {\n get: {\n operationId: 'listMedia',\n parameters: listParameters,\n responses: {\n 200: ok('A page of media.', ref('MediaListResponse')),\n ...problems(401, 403),\n },\n },\n post: {\n operationId: 'uploadMedia',\n requestBody: {\n required: true,\n content: {\n 'multipart/form-data': {\n schema: {\n type: 'object',\n required: ['file'],\n properties: {\n file: {\n type: 'string',\n contentMediaType: 'application/octet-stream',\n },\n name: { type: 'string' },\n tags: { type: 'array', items: { type: 'string' } },\n },\n },\n },\n },\n },\n responses: {\n 201: ok('The created media.', ref('MediaResponse')),\n ...problems(401, 403, 422),\n },\n },\n },\n '/media/tags': {\n get: {\n operationId: 'listMediaTags',\n responses: {\n 200: ok('Tags in use.', {\n type: 'object',\n required: ['data'],\n properties: { data: { type: 'array', items: { type: 'string' } } },\n }),\n ...problems(401, 403),\n },\n },\n },\n '/media/{id}': {\n parameters: [pathParameter('id', 'Media id.')],\n get: {\n operationId: 'getMedia',\n responses: {\n 200: ok('The media.', ref('MediaResponse')),\n ...problems(401, 403, 404),\n },\n },\n patch: {\n operationId: 'updateMedia',\n description: 'Updates metadata, tags or the image `transform`.',\n requestBody: { required: true, content: json(values) },\n responses: {\n 200: ok('The updated media.', ref('MediaResponse')),\n ...problems(401, 403, 404, 422),\n },\n },\n delete: {\n operationId: 'deleteMedia',\n responses: { 204: ok('Moved to the trash.'), ...problems(401, 403, 404, 409) },\n },\n },\n '/media/{id}/file': {\n parameters: [pathParameter('id', 'Media id.')],\n post: {\n operationId: 'replaceMediaFile',\n requestBody: {\n required: true,\n content: {\n 'multipart/form-data': {\n schema: {\n type: 'object',\n required: ['file'],\n properties: {\n file: {\n type: 'string',\n contentMediaType: 'application/octet-stream',\n },\n },\n },\n },\n },\n },\n responses: {\n 200: ok('The media.', ref('MediaResponse')),\n ...problems(401, 403, 404, 422),\n },\n },\n },\n '/media/{id}/restore': {\n parameters: [pathParameter('id', 'Media id.')],\n post: {\n operationId: 'restoreMedia',\n responses: {\n 200: ok('The restored media.', ref('MediaResponse')),\n ...problems(401, 403, 404),\n },\n },\n },\n '/auth/session': {\n get: {\n operationId: 'getSession',\n responses: { 200: ok('The current user.', ref('Session')), ...problems(401) },\n },\n },\n '/auth/login': {\n post: {\n operationId: 'login',\n requestBody: {\n required: true,\n content: json({\n type: 'object',\n required: ['email', 'password'],\n properties: {\n email: { type: 'string' },\n password: { type: 'string' },\n remember: { type: 'boolean' },\n },\n }),\n },\n responses: {\n 200: ok('Logged in.', ref('Session')),\n 202: ok(\n 'A second factor is required: answer `/auth/two-factor/challenge`.',\n {\n type: 'object',\n properties: { twoFactor: { type: 'boolean', const: true } },\n },\n ),\n ...problems(422),\n },\n },\n },\n '/auth/logout': {\n post: { operationId: 'logout', responses: { 204: ok('Logged out.') } },\n },\n '/auth/providers/{provider}/redirect': {\n parameters: [pathParameter('provider', 'Provider id.')],\n get: {\n operationId: 'redirectToProvider',\n parameters: [\n queryParameter('next', 'Local path to go to after login.', {\n type: 'string',\n }),\n ],\n responses: {\n 302: { description: 'Redirect to the provider.' },\n ...problems(404),\n },\n },\n },\n '/auth/password/forgot': {\n post: {\n operationId: 'forgotPassword',\n requestBody: {\n required: true,\n content: json({\n type: 'object',\n required: ['email'],\n properties: { email: { type: 'string' } },\n }),\n },\n responses: {\n 204: ok('A reset link was sent, if the account exists.'),\n ...problems(422),\n },\n },\n },\n '/auth/password/reset': {\n post: {\n operationId: 'resetPassword',\n requestBody: {\n required: true,\n content: json({\n type: 'object',\n required: ['token', 'email', 'password'],\n properties: {\n token: { type: 'string' },\n email: { type: 'string' },\n password: { type: 'string' },\n },\n }),\n },\n responses: { 204: ok('The password was reset.'), ...problems(422) },\n },\n },\n '/auth/two-factor/challenge': {\n post: {\n operationId: 'twoFactorChallenge',\n requestBody: {\n required: true,\n content: json({\n type: 'object',\n properties: {\n code: { type: 'string' },\n recoveryCode: { type: 'string' },\n },\n }),\n },\n responses: { 200: ok('Logged in.', ref('Session')), ...problems(422) },\n },\n },\n '/auth/passkeys/options': {\n post: {\n operationId: 'passkeyOptions',\n responses: {\n 200: ok('WebAuthn request options.', {\n type: 'object',\n additionalProperties: true,\n }),\n },\n },\n },\n '/auth/passkeys/login': {\n post: {\n operationId: 'passkeyLogin',\n requestBody: {\n required: true,\n content: json({ type: 'object', additionalProperties: true }),\n },\n responses: { 200: ok('Logged in.', ref('Session')), ...problems(422) },\n },\n },\n '/account': {\n get: {\n operationId: 'getAccount',\n responses: {\n 200: ok('The current user.', {\n type: 'object',\n required: ['data'],\n properties: { data: ref('User') },\n }),\n ...problems(401),\n },\n },\n patch: {\n operationId: 'updateAccount',\n requestBody: { required: true, content: json(values) },\n responses: {\n 200: ok('The updated user.', {\n type: 'object',\n required: ['data'],\n properties: { data: ref('User') },\n }),\n ...problems(401, 422),\n },\n },\n },\n '/search': {\n get: {\n operationId: 'search',\n parameters: [\n {\n ...queryParameter('q', 'Search terms.', { type: 'string' }),\n required: true,\n },\n ],\n responses: {\n 200: ok('Results grouped by resource.', ref('SearchResponse')),\n ...problems(401),\n },\n },\n },\n '/dashboard/widgets/{widget}': {\n parameters: [pathParameter('widget', 'Widget id.')],\n get: {\n operationId: 'getWidgetData',\n responses: {\n 200: ok(\"The widget's data. Its shape depends on the widget type.\", {\n type: 'object',\n additionalProperties: true,\n }),\n ...problems(401, 403, 404),\n },\n },\n },\n },\n components: { schemas: createComponentSchemas() },\n };\n}\n"],"mappings":"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"}
|
package/dist/schemas/action.d.ts
CHANGED
|
@@ -149,6 +149,7 @@ export declare const Action: z.ZodObject<{
|
|
|
149
149
|
children: z.ZodOptional<z.ZodArray<typeof LayoutNode>>;
|
|
150
150
|
}, z.core.$loose>>>;
|
|
151
151
|
queued: z.ZodOptional<z.ZodBoolean>;
|
|
152
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
152
153
|
url: z.ZodOptional<z.ZodString>;
|
|
153
154
|
route: z.ZodOptional<z.ZodString>;
|
|
154
155
|
component: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/schemas/action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,eAAO,MAAM,WAAW;;;;EAA4C,CAAC;AAErE,eAAO,MAAM,eAAe;;;;;EAA6C,CAAC;AAE1E,eAAO,MAAM,aAAa;;;;;mBAWxB,CAAC;AAEH,eAAO,MAAM,MAAM
|
|
1
|
+
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/schemas/action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,eAAO,MAAM,WAAW;;;;EAA4C,CAAC;AAErE,eAAO,MAAM,eAAe;;;;;EAA6C,CAAC;AAE1E,eAAO,MAAM,aAAa;;;;;mBAWxB,CAAC;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+CwE,CAAC;AAE5F,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AACtD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC9D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAC1D,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAC5C,qEAAqE;AACrE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC"}
|
package/dist/schemas/action.js
CHANGED
|
@@ -36,6 +36,7 @@ var Action = z.looseObject({
|
|
|
36
36
|
fields: z.array(Field).optional().meta({ description: "Parameters, shown in a modal." }),
|
|
37
37
|
layout: z.array(LayoutNode).optional(),
|
|
38
38
|
queued: z.boolean().optional().meta({ description: "The action always answers `202` with a run." }),
|
|
39
|
+
dryRun: z.boolean().optional().meta({ description: "The backend answers dry runs of this action (`dryRun` in the request): lists ask it how many items of a query selection will be skipped. Without it, the UI never sends `dryRun`, since a backend that ignores it would run the action." }),
|
|
39
40
|
url: z.string().optional().meta({ description: "`link`: URL template, with `{id}` for the item." }),
|
|
40
41
|
route: z.string().optional().meta({ description: "`link`: name of a route in the definition." }),
|
|
41
42
|
component: z.string().optional().meta({ description: "`client`: the plugin handler." }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action.js","names":[],"sources":["../../src/schemas/action.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport { Abilities } from './common';\nimport { Field } from './field';\nimport { LayoutNode } from './layout';\n\nexport const ActionScope = z.enum(['item', 'selection', 'resource']);\n\nexport const ActionPlacement = z.enum(['row', 'toolbar', 'form', 'menu']);\n\nexport const ActionConfirm = z.union([\n z.boolean(),\n z.looseObject({\n title: z.string().optional(),\n message: z\n .string()\n .optional()\n .meta({ description: 'ICU message. `{count}` is the number of items.' }),\n confirmLabel: z.string().optional(),\n cancelLabel: z.string().optional(),\n }),\n]);\n\nexport const Action = z\n .looseObject({\n id: z.string().min(1),\n label: z.string(),\n icon: z.string().optional(),\n kind: z.enum(['server', 'link', 'client']).default('server').meta({\n description:\n '`server` calls the action endpoint; `link` navigates; `client` runs a plugin handler.',\n }),\n scope: z.array(ActionScope).min(1),\n placement: z.array(ActionPlacement).optional(),\n destructive: z.boolean().optional(),\n confirm: ActionConfirm.optional(),\n fields: z.array(Field).optional().meta({ description: 'Parameters, shown in a modal.' }),\n layout: z.array(LayoutNode).optional(),\n queued: z\n .boolean()\n .optional()\n .meta({ description: 'The action always answers `202` with a run.' }),\n url: z\n .string()\n .optional()\n .meta({ description: '`link`: URL template, with `{id}` for the item.' }),\n route: z\n .string()\n .optional()\n .meta({ description: '`link`: name of a route in the definition.' }),\n component: z.string().optional().meta({ description: '`client`: the plugin handler.' }),\n abilities: Abilities.optional().meta({\n description: '`run`: whether the current user can run the action on the resource.',\n }),\n })\n .superRefine((action, context) => {\n if (action.kind === 'link' && action.url === undefined && action.route === undefined) {\n context.addIssue({\n code: 'custom',\n message: 'A `link` action needs a `url` or a `route`.',\n });\n }\n if (action.kind === 'client' && action.component === undefined) {\n context.addIssue({ code: 'custom', message: 'A `client` action needs a `component`.' });\n }\n })\n .meta({ description: 'An operation on one item, a selection, or the whole resource.' });\n\nexport type ActionScope = z.infer<typeof ActionScope>;\nexport type ActionPlacement = z.infer<typeof ActionPlacement>;\nexport type ActionConfirm = z.infer<typeof ActionConfirm>;\nexport type Action = z.infer<typeof Action>;\n/** An action as a backend writes it: `kind` defaults to `server`. */\nexport type ActionInput = z.input<typeof Action>;\n"],"mappings":";;;;;AAMA,IAAa,cAAc,EAAE,KAAK;CAAC;CAAQ;CAAa;AAAU,CAAC;AAEnE,IAAa,kBAAkB,EAAE,KAAK;CAAC;CAAO;CAAW;CAAQ;AAAM,CAAC;AAExE,IAAa,gBAAgB,EAAE,MAAM,CACjC,EAAE,QAAQ,GACV,EAAE,YAAY;CACV,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;CAC3B,SAAS,EACJ,OAAO,CAAC,CACR,SAAS,CAAC,CACV,KAAK,EAAE,aAAa,iDAAiD,CAAC;CAC3E,cAAc,EAAE,OAAO,CAAC,CAAC,SAAS;CAClC,aAAa,EAAE,OAAO,CAAC,CAAC,SAAS;AACrC,CAAC,CACL,CAAC;AAED,IAAa,SAAS,EACjB,YAAY;CACT,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACpB,OAAO,EAAE,OAAO;CAChB,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS;CAC1B,MAAM,EAAE,KAAK;EAAC;EAAU;EAAQ;CAAQ,CAAC,CAAC,CAAC,QAAQ,QAAQ,CAAC,CAAC,KAAK,EAC9D,aACI,wFACR,CAAC;CACD,OAAO,EAAE,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC;CACjC,WAAW,EAAE,MAAM,eAAe,CAAC,CAAC,SAAS;CAC7C,aAAa,EAAE,QAAQ,CAAC,CAAC,SAAS;CAClC,SAAS,cAAc,SAAS;CAChC,QAAQ,EAAE,MAAM,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,aAAa,gCAAgC,CAAC;CACvF,QAAQ,EAAE,MAAM,UAAU,CAAC,CAAC,SAAS;CACrC,QAAQ,EACH,QAAQ,CAAC,CACT,SAAS,CAAC,CACV,KAAK,EAAE,aAAa,8CAA8C,CAAC;CACxE,KAAK,EACA,OAAO,CAAC,CACR,SAAS,CAAC,CACV,KAAK,EAAE,aAAa,kDAAkD,CAAC;CAC5E,OAAO,EACF,OAAO,CAAC,CACR,SAAS,CAAC,CACV,KAAK,EAAE,aAAa,6CAA6C,CAAC;CACvE,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,aAAa,gCAAgC,CAAC;CACtF,WAAW,UAAU,SAAS,CAAC,CAAC,KAAK,EACjC,aAAa,sEACjB,CAAC;AACL,CAAC,CAAC,CACD,aAAa,QAAQ,YAAY;CAC9B,IAAI,OAAO,SAAS,UAAU,OAAO,QAAQ,KAAA,KAAa,OAAO,UAAU,KAAA,GACvE,QAAQ,SAAS;EACb,MAAM;EACN,SAAS;CACb,CAAC;CAEL,IAAI,OAAO,SAAS,YAAY,OAAO,cAAc,KAAA,GACjD,QAAQ,SAAS;EAAE,MAAM;EAAU,SAAS;CAAyC,CAAC;AAE9F,CAAC,CAAC,CACD,KAAK,EAAE,aAAa,gEAAgE,CAAC"}
|
|
1
|
+
{"version":3,"file":"action.js","names":[],"sources":["../../src/schemas/action.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport { Abilities } from './common';\nimport { Field } from './field';\nimport { LayoutNode } from './layout';\n\nexport const ActionScope = z.enum(['item', 'selection', 'resource']);\n\nexport const ActionPlacement = z.enum(['row', 'toolbar', 'form', 'menu']);\n\nexport const ActionConfirm = z.union([\n z.boolean(),\n z.looseObject({\n title: z.string().optional(),\n message: z\n .string()\n .optional()\n .meta({ description: 'ICU message. `{count}` is the number of items.' }),\n confirmLabel: z.string().optional(),\n cancelLabel: z.string().optional(),\n }),\n]);\n\nexport const Action = z\n .looseObject({\n id: z.string().min(1),\n label: z.string(),\n icon: z.string().optional(),\n kind: z.enum(['server', 'link', 'client']).default('server').meta({\n description:\n '`server` calls the action endpoint; `link` navigates; `client` runs a plugin handler.',\n }),\n scope: z.array(ActionScope).min(1),\n placement: z.array(ActionPlacement).optional(),\n destructive: z.boolean().optional(),\n confirm: ActionConfirm.optional(),\n fields: z.array(Field).optional().meta({ description: 'Parameters, shown in a modal.' }),\n layout: z.array(LayoutNode).optional(),\n queued: z\n .boolean()\n .optional()\n .meta({ description: 'The action always answers `202` with a run.' }),\n dryRun: z.boolean().optional().meta({\n description:\n 'The backend answers dry runs of this action (`dryRun` in the request): lists ask it how many items of a query selection will be skipped. Without it, the UI never sends `dryRun`, since a backend that ignores it would run the action.',\n }),\n url: z\n .string()\n .optional()\n .meta({ description: '`link`: URL template, with `{id}` for the item.' }),\n route: z\n .string()\n .optional()\n .meta({ description: '`link`: name of a route in the definition.' }),\n component: z.string().optional().meta({ description: '`client`: the plugin handler.' }),\n abilities: Abilities.optional().meta({\n description: '`run`: whether the current user can run the action on the resource.',\n }),\n })\n .superRefine((action, context) => {\n if (action.kind === 'link' && action.url === undefined && action.route === undefined) {\n context.addIssue({\n code: 'custom',\n message: 'A `link` action needs a `url` or a `route`.',\n });\n }\n if (action.kind === 'client' && action.component === undefined) {\n context.addIssue({ code: 'custom', message: 'A `client` action needs a `component`.' });\n }\n })\n .meta({ description: 'An operation on one item, a selection, or the whole resource.' });\n\nexport type ActionScope = z.infer<typeof ActionScope>;\nexport type ActionPlacement = z.infer<typeof ActionPlacement>;\nexport type ActionConfirm = z.infer<typeof ActionConfirm>;\nexport type Action = z.infer<typeof Action>;\n/** An action as a backend writes it: `kind` defaults to `server`. */\nexport type ActionInput = z.input<typeof Action>;\n"],"mappings":";;;;;AAMA,IAAa,cAAc,EAAE,KAAK;CAAC;CAAQ;CAAa;AAAU,CAAC;AAEnE,IAAa,kBAAkB,EAAE,KAAK;CAAC;CAAO;CAAW;CAAQ;AAAM,CAAC;AAExE,IAAa,gBAAgB,EAAE,MAAM,CACjC,EAAE,QAAQ,GACV,EAAE,YAAY;CACV,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;CAC3B,SAAS,EACJ,OAAO,CAAC,CACR,SAAS,CAAC,CACV,KAAK,EAAE,aAAa,iDAAiD,CAAC;CAC3E,cAAc,EAAE,OAAO,CAAC,CAAC,SAAS;CAClC,aAAa,EAAE,OAAO,CAAC,CAAC,SAAS;AACrC,CAAC,CACL,CAAC;AAED,IAAa,SAAS,EACjB,YAAY;CACT,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACpB,OAAO,EAAE,OAAO;CAChB,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS;CAC1B,MAAM,EAAE,KAAK;EAAC;EAAU;EAAQ;CAAQ,CAAC,CAAC,CAAC,QAAQ,QAAQ,CAAC,CAAC,KAAK,EAC9D,aACI,wFACR,CAAC;CACD,OAAO,EAAE,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC;CACjC,WAAW,EAAE,MAAM,eAAe,CAAC,CAAC,SAAS;CAC7C,aAAa,EAAE,QAAQ,CAAC,CAAC,SAAS;CAClC,SAAS,cAAc,SAAS;CAChC,QAAQ,EAAE,MAAM,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,aAAa,gCAAgC,CAAC;CACvF,QAAQ,EAAE,MAAM,UAAU,CAAC,CAAC,SAAS;CACrC,QAAQ,EACH,QAAQ,CAAC,CACT,SAAS,CAAC,CACV,KAAK,EAAE,aAAa,8CAA8C,CAAC;CACxE,QAAQ,EAAE,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAChC,aACI,0OACR,CAAC;CACD,KAAK,EACA,OAAO,CAAC,CACR,SAAS,CAAC,CACV,KAAK,EAAE,aAAa,kDAAkD,CAAC;CAC5E,OAAO,EACF,OAAO,CAAC,CACR,SAAS,CAAC,CACV,KAAK,EAAE,aAAa,6CAA6C,CAAC;CACvE,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,aAAa,gCAAgC,CAAC;CACtF,WAAW,UAAU,SAAS,CAAC,CAAC,KAAK,EACjC,aAAa,sEACjB,CAAC;AACL,CAAC,CAAC,CACD,aAAa,QAAQ,YAAY;CAC9B,IAAI,OAAO,SAAS,UAAU,OAAO,QAAQ,KAAA,KAAa,OAAO,UAAU,KAAA,GACvE,QAAQ,SAAS;EACb,MAAM;EACN,SAAS;CACb,CAAC;CAEL,IAAI,OAAO,SAAS,YAAY,OAAO,cAAc,KAAA,GACjD,QAAQ,SAAS;EAAE,MAAM;EAAU,SAAS;CAAyC,CAAC;AAE9F,CAAC,CAAC,CACD,KAAK,EAAE,aAAa,gEAAgE,CAAC"}
|
package/dist/schemas/api.d.ts
CHANGED
|
@@ -63,6 +63,7 @@ export declare const ActionRequest: z.ZodObject<{
|
|
|
63
63
|
except: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
64
64
|
}, z.core.$loose>]>>;
|
|
65
65
|
values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
66
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
66
67
|
}, z.core.$loose>;
|
|
67
68
|
export declare const ActionItemResult: z.ZodObject<{
|
|
68
69
|
id: z.ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/schemas/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,IAAI;;;;iBAUX,CAAC;AAEP,eAAO,MAAM,UAAU;;;;;iBAKrB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;iBAAgC,CAAC;AAE1D,eAAO,MAAM,YAAY;;;;;;;;;;;;iBAA2D,CAAC;AAErF,eAAO,MAAM,OAAO;;;;;;;;;;;;iBAa6E,CAAC;AAElG,eAAO,MAAM,SAAS;;;;;;;;mBAYpB,CAAC;AAEH,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/schemas/api.ts"],"names":[],"mappings":"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"}
|
package/dist/schemas/api.js
CHANGED
|
@@ -36,7 +36,8 @@ var Selection = z.union([z.looseObject({ ids: z.array(Id).min(1) }), z.looseObje
|
|
|
36
36
|
})]);
|
|
37
37
|
var ActionRequest = z.looseObject({
|
|
38
38
|
selection: Selection.optional().meta({ description: "Omitted for actions on the whole resource." }),
|
|
39
|
-
values: z.record(z.string(), z.unknown()).optional()
|
|
39
|
+
values: z.record(z.string(), z.unknown()).optional(),
|
|
40
|
+
dryRun: z.boolean().optional().meta({ description: "Answer what the action would do without running it: a `200` action result whose `summary` counts the items that would succeed and those that would be skipped. Only for actions with `dryRun: true`." })
|
|
40
41
|
});
|
|
41
42
|
var ActionItemResult = z.looseObject({
|
|
42
43
|
id: Id,
|
package/dist/schemas/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","names":[],"sources":["../../src/schemas/api.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport { Abilities, Id, RouteReference } from './common';\nimport { User } from './definition';\n\nexport const Item = z\n .looseObject({\n id: Id,\n version: z.string().nullable().meta({\n description: 'Changes on every update. `null` when the backend has no versions.',\n }),\n abilities: Abilities,\n })\n .meta({\n description: 'An item of a resource. Its other properties are the values of its fields.',\n });\n\nexport const Pagination = z.looseObject({\n page: z.number().int().positive(),\n perPage: z.number().int().positive(),\n total: z.number().int().nonnegative(),\n lastPage: z.number().int().positive(),\n});\n\nexport const ItemResponse = z.looseObject({ data: Item });\n\nexport const ListResponse = z.looseObject({ data: z.array(Item), meta: Pagination });\n\nexport const Problem = z\n .looseObject({\n type: z.string().meta({ description: 'A URI reference that identifies the problem type.' }),\n title: z.string(),\n status: z.number().int().min(400).max(599),\n detail: z.string().optional(),\n instance: z.string().optional(),\n errors: z\n .record(z.string(), z.array(z.string()))\n .optional()\n .meta({ description: '`422`: messages keyed by the dot path of the invalid value.' }),\n current: Item.optional().meta({ description: '`412`: the current version of the item.' }),\n })\n .meta({ description: 'An error, as RFC 9457 problem details (`application/problem+json`).' });\n\nexport const Selection = z.union([\n z.looseObject({ ids: z.array(Id).min(1) }),\n z.looseObject({\n query: z.looseObject({\n filter: z.record(z.string(), z.unknown()).optional().meta({\n description:\n 'The `filter` of the list query, by filter id: a value, a list of values, or the bounds of a range (`{ \"from\": \"2026-01-01\", \"to\": \"2026-01-31\" }`).',\n }),\n q: z.string().optional(),\n }),\n except: z.array(Id).optional(),\n }),\n]);\n\nexport const ActionRequest = z.looseObject({\n selection: Selection.optional().meta({\n description: 'Omitted for actions on the whole resource.',\n }),\n values: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport const ActionItemResult = z.looseObject({\n id: Id,\n status: z.enum(['failed', 'skipped']),\n message: z.string().optional(),\n reason: z\n .string()\n .optional()\n .meta({ description: '`skipped`: `forbidden`, `not_found` or `unchanged`.' }),\n});\n\nexport const ActionResult = z.looseObject({\n message: z.string().optional(),\n summary: z\n .looseObject({\n succeeded: z.number().int().nonnegative(),\n failed: z.number().int().nonnegative(),\n skipped: z.number().int().nonnegative(),\n })\n .optional(),\n results: z\n .array(ActionItemResult)\n .optional()\n .meta({ description: 'The items that did not succeed.' }),\n refresh: z.enum(['none', 'items', 'list']).optional(),\n redirect: z.union([z.string(), RouteReference]).nullable().optional(),\n download: z\n .looseObject({\n url: z.string(),\n filename: z.string().optional(),\n expiresAt: z.string().optional(),\n })\n .nullable()\n .optional(),\n});\n\nexport const ActionRun = z.looseObject({\n id: Id,\n action: z.string(),\n resource: z.string(),\n status: z.enum(['queued', 'running', 'succeeded', 'partial', 'failed', 'cancelled']),\n progress: z.number().int().nonnegative(),\n total: z.number().int().nonnegative().nullable(),\n result: ActionResult.optional().meta({ description: 'Set once the run has finished.' }),\n createdAt: z.string().optional(),\n finishedAt: z.string().nullable().optional(),\n});\n\nexport const ActionRunResponse = z.looseObject({ run: ActionRun });\n\nexport const MediaTransform = z.looseObject({\n crop: z\n .looseObject({ x: z.number(), y: z.number(), width: z.number(), height: z.number() })\n .optional()\n .meta({ description: 'In pixels of the original image.' }),\n rotate: z.union([z.literal(0), z.literal(90), z.literal(180), z.literal(270)]).optional(),\n flipX: z.boolean().optional(),\n flipY: z.boolean().optional(),\n focalPoint: z\n .looseObject({ x: z.number().min(0).max(1), y: z.number().min(0).max(1) })\n .optional()\n .meta({ description: 'Relative to the width and height, from 0 to 1.' }),\n});\n\nexport const Media = Item.extend({\n type: z\n .string()\n .meta({ description: '`image`, `video`, `audio`, `document`, `font`, or another type.' }),\n name: z.string(),\n mime: z.string(),\n size: z.number().int().nonnegative(),\n url: z.string(),\n thumbnailUrl: z.string().nullable().optional(),\n variants: z\n .record(\n z.string(),\n z.looseObject({\n url: z.string(),\n width: z.number().optional(),\n height: z.number().optional(),\n }),\n )\n .optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n transform: MediaTransform.nullable().optional(),\n tags: z.array(z.string()).optional(),\n});\n\nexport const MediaResponse = z.looseObject({ data: Media });\n\nexport const MediaListResponse = z.looseObject({ data: z.array(Media), meta: Pagination });\n\nexport const Session = z.looseObject({ user: User });\n\nexport const SearchResponse = z.looseObject({\n data: z.array(\n z.looseObject({\n resource: z.string(),\n items: z.array(Item),\n total: z.number().int().nonnegative().optional(),\n }),\n ),\n});\n\nexport const PreviewResponse = z.looseObject({ url: z.string(), expiresAt: z.string().optional() });\n\nexport type Item = z.infer<typeof Item>;\nexport type Pagination = z.infer<typeof Pagination>;\nexport type ItemResponse = z.infer<typeof ItemResponse>;\nexport type ListResponse = z.infer<typeof ListResponse>;\nexport type Problem = z.infer<typeof Problem>;\nexport type Selection = z.infer<typeof Selection>;\nexport type ActionRequest = z.infer<typeof ActionRequest>;\nexport type ActionItemResult = z.infer<typeof ActionItemResult>;\nexport type ActionResult = z.infer<typeof ActionResult>;\nexport type ActionRun = z.infer<typeof ActionRun>;\nexport type ActionRunResponse = z.infer<typeof ActionRunResponse>;\nexport type MediaTransform = z.infer<typeof MediaTransform>;\nexport type Media = z.infer<typeof Media>;\nexport type MediaResponse = z.infer<typeof MediaResponse>;\nexport type MediaListResponse = z.infer<typeof MediaListResponse>;\nexport type Session = z.infer<typeof Session>;\nexport type SearchResponse = z.infer<typeof SearchResponse>;\nexport type PreviewResponse = z.infer<typeof PreviewResponse>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.js","names":[],"sources":["../../src/schemas/api.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport { Abilities, Id, RouteReference } from './common';\nimport { User } from './definition';\n\nexport const Item = z\n .looseObject({\n id: Id,\n version: z.string().nullable().meta({\n description: 'Changes on every update. `null` when the backend has no versions.',\n }),\n abilities: Abilities,\n })\n .meta({\n description: 'An item of a resource. Its other properties are the values of its fields.',\n });\n\nexport const Pagination = z.looseObject({\n page: z.number().int().positive(),\n perPage: z.number().int().positive(),\n total: z.number().int().nonnegative(),\n lastPage: z.number().int().positive(),\n});\n\nexport const ItemResponse = z.looseObject({ data: Item });\n\nexport const ListResponse = z.looseObject({ data: z.array(Item), meta: Pagination });\n\nexport const Problem = z\n .looseObject({\n type: z.string().meta({ description: 'A URI reference that identifies the problem type.' }),\n title: z.string(),\n status: z.number().int().min(400).max(599),\n detail: z.string().optional(),\n instance: z.string().optional(),\n errors: z\n .record(z.string(), z.array(z.string()))\n .optional()\n .meta({ description: '`422`: messages keyed by the dot path of the invalid value.' }),\n current: Item.optional().meta({ description: '`412`: the current version of the item.' }),\n })\n .meta({ description: 'An error, as RFC 9457 problem details (`application/problem+json`).' });\n\nexport const Selection = z.union([\n z.looseObject({ ids: z.array(Id).min(1) }),\n z.looseObject({\n query: z.looseObject({\n filter: z.record(z.string(), z.unknown()).optional().meta({\n description:\n 'The `filter` of the list query, by filter id: a value, a list of values, or the bounds of a range (`{ \"from\": \"2026-01-01\", \"to\": \"2026-01-31\" }`).',\n }),\n q: z.string().optional(),\n }),\n except: z.array(Id).optional(),\n }),\n]);\n\nexport const ActionRequest = z.looseObject({\n selection: Selection.optional().meta({\n description: 'Omitted for actions on the whole resource.',\n }),\n values: z.record(z.string(), z.unknown()).optional(),\n dryRun: z.boolean().optional().meta({\n description:\n 'Answer what the action would do without running it: a `200` action result whose `summary` counts the items that would succeed and those that would be skipped. Only for actions with `dryRun: true`.',\n }),\n});\n\nexport const ActionItemResult = z.looseObject({\n id: Id,\n status: z.enum(['failed', 'skipped']),\n message: z.string().optional(),\n reason: z\n .string()\n .optional()\n .meta({ description: '`skipped`: `forbidden`, `not_found` or `unchanged`.' }),\n});\n\nexport const ActionResult = z.looseObject({\n message: z.string().optional(),\n summary: z\n .looseObject({\n succeeded: z.number().int().nonnegative(),\n failed: z.number().int().nonnegative(),\n skipped: z.number().int().nonnegative(),\n })\n .optional(),\n results: z\n .array(ActionItemResult)\n .optional()\n .meta({ description: 'The items that did not succeed.' }),\n refresh: z.enum(['none', 'items', 'list']).optional(),\n redirect: z.union([z.string(), RouteReference]).nullable().optional(),\n download: z\n .looseObject({\n url: z.string(),\n filename: z.string().optional(),\n expiresAt: z.string().optional(),\n })\n .nullable()\n .optional(),\n});\n\nexport const ActionRun = z.looseObject({\n id: Id,\n action: z.string(),\n resource: z.string(),\n status: z.enum(['queued', 'running', 'succeeded', 'partial', 'failed', 'cancelled']),\n progress: z.number().int().nonnegative(),\n total: z.number().int().nonnegative().nullable(),\n result: ActionResult.optional().meta({ description: 'Set once the run has finished.' }),\n createdAt: z.string().optional(),\n finishedAt: z.string().nullable().optional(),\n});\n\nexport const ActionRunResponse = z.looseObject({ run: ActionRun });\n\nexport const MediaTransform = z.looseObject({\n crop: z\n .looseObject({ x: z.number(), y: z.number(), width: z.number(), height: z.number() })\n .optional()\n .meta({ description: 'In pixels of the original image.' }),\n rotate: z.union([z.literal(0), z.literal(90), z.literal(180), z.literal(270)]).optional(),\n flipX: z.boolean().optional(),\n flipY: z.boolean().optional(),\n focalPoint: z\n .looseObject({ x: z.number().min(0).max(1), y: z.number().min(0).max(1) })\n .optional()\n .meta({ description: 'Relative to the width and height, from 0 to 1.' }),\n});\n\nexport const Media = Item.extend({\n type: z\n .string()\n .meta({ description: '`image`, `video`, `audio`, `document`, `font`, or another type.' }),\n name: z.string(),\n mime: z.string(),\n size: z.number().int().nonnegative(),\n url: z.string(),\n thumbnailUrl: z.string().nullable().optional(),\n variants: z\n .record(\n z.string(),\n z.looseObject({\n url: z.string(),\n width: z.number().optional(),\n height: z.number().optional(),\n }),\n )\n .optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n transform: MediaTransform.nullable().optional(),\n tags: z.array(z.string()).optional(),\n});\n\nexport const MediaResponse = z.looseObject({ data: Media });\n\nexport const MediaListResponse = z.looseObject({ data: z.array(Media), meta: Pagination });\n\nexport const Session = z.looseObject({ user: User });\n\nexport const SearchResponse = z.looseObject({\n data: z.array(\n z.looseObject({\n resource: z.string(),\n items: z.array(Item),\n total: z.number().int().nonnegative().optional(),\n }),\n ),\n});\n\nexport const PreviewResponse = z.looseObject({ url: z.string(), expiresAt: z.string().optional() });\n\nexport type Item = z.infer<typeof Item>;\nexport type Pagination = z.infer<typeof Pagination>;\nexport type ItemResponse = z.infer<typeof ItemResponse>;\nexport type ListResponse = z.infer<typeof ListResponse>;\nexport type Problem = z.infer<typeof Problem>;\nexport type Selection = z.infer<typeof Selection>;\nexport type ActionRequest = z.infer<typeof ActionRequest>;\nexport type ActionItemResult = z.infer<typeof ActionItemResult>;\nexport type ActionResult = z.infer<typeof ActionResult>;\nexport type ActionRun = z.infer<typeof ActionRun>;\nexport type ActionRunResponse = z.infer<typeof ActionRunResponse>;\nexport type MediaTransform = z.infer<typeof MediaTransform>;\nexport type Media = z.infer<typeof Media>;\nexport type MediaResponse = z.infer<typeof MediaResponse>;\nexport type MediaListResponse = z.infer<typeof MediaListResponse>;\nexport type Session = z.infer<typeof Session>;\nexport type SearchResponse = z.infer<typeof SearchResponse>;\nexport type PreviewResponse = z.infer<typeof PreviewResponse>;\n"],"mappings":"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"}
|
|
@@ -352,6 +352,7 @@ export declare const Definition: z.ZodObject<{
|
|
|
352
352
|
children: z.ZodOptional<z.ZodArray<typeof import("./layout").LayoutNode>>;
|
|
353
353
|
}, z.core.$loose>>>;
|
|
354
354
|
queued: z.ZodOptional<z.ZodBoolean>;
|
|
355
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
355
356
|
url: z.ZodOptional<z.ZodString>;
|
|
356
357
|
route: z.ZodOptional<z.ZodString>;
|
|
357
358
|
component: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/schemas/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,IAAI;;;;;;iBAMf,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;iBAKvB,CAAC;AAEH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;iBAef,CAAC;AAEH,eAAO,MAAM,QAAQ;;;;;;;;cAYG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,QAAQ,CAAC,CAAC;iBAIjB,CAAC;AAElD,eAAO,MAAM,IAAI;;;;;iBAQf,CAAC;AAEH,eAAO,MAAM,MAAM;;;;;;iBAQjB,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;iBAIlB,CAAC;AAEH,eAAO,MAAM,UAAU
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/schemas/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,IAAI;;;;;;iBAMf,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;iBAKvB,CAAC;AAEH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;iBAef,CAAC;AAEH,eAAO,MAAM,QAAQ;;;;;;;;cAYG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,QAAQ,CAAC,CAAC;iBAIjB,CAAC;AAElD,eAAO,MAAM,IAAI;;;;;iBAQf,CAAC;AAEH,eAAO,MAAM,MAAM;;;;;;iBAQjB,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;iBAIlB,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAhCC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,QAAQ,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuEiC,CAAC;AAEpG,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AACxC,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AACxD,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AACxC,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAChD,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AACxC,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAC5C,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC;AAC9C,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AACpD,wEAAwE;AACxE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
|
package/dist/schemas/index.d.ts
CHANGED
|
@@ -403,6 +403,7 @@ export declare const namedSchemas: {
|
|
|
403
403
|
children: z.ZodOptional<z.ZodArray<typeof LayoutNode>>;
|
|
404
404
|
}, z.core.$loose>>>;
|
|
405
405
|
queued: z.ZodOptional<z.ZodBoolean>;
|
|
406
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
406
407
|
url: z.ZodOptional<z.ZodString>;
|
|
407
408
|
route: z.ZodOptional<z.ZodString>;
|
|
408
409
|
component: z.ZodOptional<z.ZodString>;
|
|
@@ -702,6 +703,7 @@ export declare const namedSchemas: {
|
|
|
702
703
|
children: z.ZodOptional<z.ZodArray<typeof LayoutNode>>;
|
|
703
704
|
}, z.core.$loose>>>;
|
|
704
705
|
queued: z.ZodOptional<z.ZodBoolean>;
|
|
706
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
705
707
|
url: z.ZodOptional<z.ZodString>;
|
|
706
708
|
route: z.ZodOptional<z.ZodString>;
|
|
707
709
|
component: z.ZodOptional<z.ZodString>;
|
|
@@ -1250,6 +1252,7 @@ export declare const namedSchemas: {
|
|
|
1250
1252
|
children: z.ZodOptional<z.ZodArray<typeof LayoutNode>>;
|
|
1251
1253
|
}, z.core.$loose>>>;
|
|
1252
1254
|
queued: z.ZodOptional<z.ZodBoolean>;
|
|
1255
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
1253
1256
|
url: z.ZodOptional<z.ZodString>;
|
|
1254
1257
|
route: z.ZodOptional<z.ZodString>;
|
|
1255
1258
|
component: z.ZodOptional<z.ZodString>;
|
|
@@ -1464,6 +1467,7 @@ export declare const namedSchemas: {
|
|
|
1464
1467
|
except: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1465
1468
|
}, z.core.$loose>]>>;
|
|
1466
1469
|
values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1470
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
1467
1471
|
}, z.core.$loose>;
|
|
1468
1472
|
ActionItemResult: z.ZodObject<{
|
|
1469
1473
|
id: z.ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuBxB,OAAO,EAAa,SAAS,EAA8B,MAAM,UAAU,CAAC;AAC5E,OAAO,EAIH,QAAQ,EAKX,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAQ,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AActC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AAEvB,wGAAwG;AACxG,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -295,6 +295,7 @@ export declare const Resource: z.ZodObject<{
|
|
|
295
295
|
children: z.ZodOptional<z.ZodArray<typeof LayoutNode>>;
|
|
296
296
|
}, z.core.$loose>>>;
|
|
297
297
|
queued: z.ZodOptional<z.ZodBoolean>;
|
|
298
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
298
299
|
url: z.ZodOptional<z.ZodString>;
|
|
299
300
|
route: z.ZodOptional<z.ZodString>;
|
|
300
301
|
component: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/schemas/resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC,eAAO,MAAM,gBAAgB;;;;;;;;;;;iBAmB3B,CAAC;AAEH,eAAO,MAAM,QAAQ
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/schemas/resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC,eAAO,MAAM,gBAAgB;;;;;;;;;;;iBAmB3B,CAAC;AAEH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsB6C,CAAC;AAEnE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAChE,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAChD,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC"}
|
package/package.json
CHANGED
package/schema/boot.schema.json
CHANGED
package/schema/openapi.json
CHANGED
|
@@ -623,6 +623,16 @@
|
|
|
623
623
|
}
|
|
624
624
|
}
|
|
625
625
|
},
|
|
626
|
+
"400": {
|
|
627
|
+
"description": "Bad request, such as a dry run of an action that does not declare `dryRun`.",
|
|
628
|
+
"content": {
|
|
629
|
+
"application/problem+json": {
|
|
630
|
+
"schema": {
|
|
631
|
+
"$ref": "#/components/schemas/Problem"
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
},
|
|
626
636
|
"401": {
|
|
627
637
|
"description": "Not authenticated.",
|
|
628
638
|
"content": {
|
|
@@ -2644,6 +2654,10 @@
|
|
|
2644
2654
|
"description": "The action always answers `202` with a run.",
|
|
2645
2655
|
"type": "boolean"
|
|
2646
2656
|
},
|
|
2657
|
+
"dryRun": {
|
|
2658
|
+
"description": "The backend answers dry runs of this action (`dryRun` in the request): lists ask it how many items of a query selection will be skipped. Without it, the UI never sends `dryRun`, since a backend that ignores it would run the action.",
|
|
2659
|
+
"type": "boolean"
|
|
2660
|
+
},
|
|
2647
2661
|
"url": {
|
|
2648
2662
|
"description": "`link`: URL template, with `{id}` for the item.",
|
|
2649
2663
|
"type": "string"
|
|
@@ -3769,6 +3783,10 @@
|
|
|
3769
3783
|
"type": "string"
|
|
3770
3784
|
},
|
|
3771
3785
|
"additionalProperties": {}
|
|
3786
|
+
},
|
|
3787
|
+
"dryRun": {
|
|
3788
|
+
"description": "Answer what the action would do without running it: a `200` action result whose `summary` counts the items that would succeed and those that would be skipped. Only for actions with `dryRun: true`.",
|
|
3789
|
+
"type": "boolean"
|
|
3772
3790
|
}
|
|
3773
3791
|
},
|
|
3774
3792
|
"additionalProperties": {}
|