@panneau/protocol 5.0.0-alpha.3 → 5.0.0-alpha.5

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.
Files changed (67) hide show
  1. package/dist/conformance/index.d.ts.map +1 -1
  2. package/dist/conformance/index.js +151 -1
  3. package/dist/conformance/index.js.map +1 -1
  4. package/dist/constants.d.ts +2 -2
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/constants.js +3 -1
  7. package/dist/constants.js.map +1 -1
  8. package/dist/index.js +5 -2
  9. package/dist/libraries.d.ts +16 -0
  10. package/dist/libraries.d.ts.map +1 -0
  11. package/dist/libraries.js +15 -0
  12. package/dist/libraries.js.map +1 -0
  13. package/dist/lint.d.ts +2 -1
  14. package/dist/lint.d.ts.map +1 -1
  15. package/dist/lint.js +34 -2
  16. package/dist/lint.js.map +1 -1
  17. package/dist/mock/example.d.ts +2 -1
  18. package/dist/mock/example.d.ts.map +1 -1
  19. package/dist/mock/example.js +227 -143
  20. package/dist/mock/example.js.map +1 -1
  21. package/dist/mock/index.d.ts +9 -1
  22. package/dist/mock/index.d.ts.map +1 -1
  23. package/dist/mock/index.js +257 -11
  24. package/dist/mock/index.js.map +1 -1
  25. package/dist/openapi.d.ts.map +1 -1
  26. package/dist/openapi.js +55 -101
  27. package/dist/openapi.js.map +1 -1
  28. package/dist/rules.d.ts.map +1 -1
  29. package/dist/rules.js +17 -0
  30. package/dist/rules.js.map +1 -1
  31. package/dist/runtime/index.d.ts +3 -0
  32. package/dist/runtime/index.d.ts.map +1 -1
  33. package/dist/runtime/index.js +4 -1
  34. package/dist/schemas/action.d.ts +17 -1
  35. package/dist/schemas/action.d.ts.map +1 -1
  36. package/dist/schemas/api.d.ts +155 -37
  37. package/dist/schemas/api.d.ts.map +1 -1
  38. package/dist/schemas/api.js +89 -28
  39. package/dist/schemas/api.js.map +1 -1
  40. package/dist/schemas/definition.d.ts +39 -2
  41. package/dist/schemas/definition.d.ts.map +1 -1
  42. package/dist/schemas/definition.js +4 -3
  43. package/dist/schemas/definition.js.map +1 -1
  44. package/dist/schemas/field.d.ts +24 -1
  45. package/dist/schemas/field.d.ts.map +1 -1
  46. package/dist/schemas/field.js +22 -4
  47. package/dist/schemas/field.js.map +1 -1
  48. package/dist/schemas/index.d.ts +262 -40
  49. package/dist/schemas/index.d.ts.map +1 -1
  50. package/dist/schemas/index.js +13 -5
  51. package/dist/schemas/index.js.map +1 -1
  52. package/dist/schemas/resource.d.ts +37 -2
  53. package/dist/schemas/resource.d.ts.map +1 -1
  54. package/dist/schemas/resource.js +4 -1
  55. package/dist/schemas/resource.js.map +1 -1
  56. package/dist/search.d.ts +51 -0
  57. package/dist/search.d.ts.map +1 -0
  58. package/dist/search.js +53 -0
  59. package/dist/search.js.map +1 -0
  60. package/dist/transforms.d.ts +17 -0
  61. package/dist/transforms.d.ts.map +1 -0
  62. package/dist/transforms.js +34 -0
  63. package/dist/transforms.js.map +1 -0
  64. package/package.json +1 -1
  65. package/schema/boot.schema.json +84 -1
  66. package/schema/definition.schema.json +84 -1
  67. package/schema/openapi.json +771 -605
package/dist/openapi.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { PROBLEM_CONTENT_TYPE } from "./version.js";
2
+ import "./search.js";
2
3
  import { Theme } from "./schemas/theme.js";
3
4
  import { Definition } from "./schemas/definition.js";
4
5
  import { BootConfig } from "./schemas/boot.js";
@@ -19,7 +20,8 @@ var PROBLEMS = {
19
20
  404: "Not found.",
20
21
  409: "Conflict with a business rule.",
21
22
  412: "Version conflict: `If-Match` does not match the current version, which is in `current`.",
22
- 422: "Invalid values: messages are in `errors`, keyed by dot path."
23
+ 422: "Invalid values: messages are in `errors`, keyed by dot path.",
24
+ 429: "Too many requests: `Retry-After` gives the seconds to wait."
23
25
  };
24
26
  function problems(...statuses) {
25
27
  return Object.fromEntries(statuses.map((status) => [String(status), {
@@ -225,6 +227,21 @@ function createOpenApiDocument() {
225
227
  }
226
228
  }
227
229
  },
230
+ "/resources/{resource}/fields/{field}/check": {
231
+ parameters: [resource, pathParameter("field", "Name of a field with `check`.")],
232
+ post: {
233
+ operationId: "checkField",
234
+ summary: "Checks a value as it is typed: whether a slug is available, and its URL. With the permission to create, or to update the item `id`.",
235
+ requestBody: {
236
+ required: true,
237
+ content: json(ref("FieldCheckRequest"))
238
+ },
239
+ responses: {
240
+ 200: ok("What the backend says about the value.", ref("FieldCheckResponse")),
241
+ ...problems(401, 403, 404, 422)
242
+ }
243
+ }
244
+ },
228
245
  "/actions/runs": { get: {
229
246
  operationId: "listActionRuns",
230
247
  summary: "The current user's recent runs.",
@@ -257,115 +274,39 @@ function createOpenApiDocument() {
257
274
  }
258
275
  }
259
276
  },
260
- "/media": {
261
- get: {
262
- operationId: "listMedia",
263
- parameters: listParameters,
264
- responses: {
265
- 200: ok("A page of media.", ref("MediaListResponse")),
266
- ...problems(401, 403)
267
- }
277
+ "/uploads/sign": { post: {
278
+ operationId: "signUpload",
279
+ summary: "Signs a request of the browser's S3 client. The first request of a file creates its upload.",
280
+ requestBody: {
281
+ required: true,
282
+ content: json(ref("UploadSignRequest"))
268
283
  },
269
- post: {
270
- operationId: "uploadMedia",
271
- requestBody: {
272
- required: true,
273
- content: { "multipart/form-data": { schema: {
274
- type: "object",
275
- required: ["file"],
276
- properties: {
277
- file: {
278
- type: "string",
279
- contentMediaType: "application/octet-stream"
280
- },
281
- name: { type: "string" },
282
- tags: {
283
- type: "array",
284
- items: { type: "string" }
285
- }
286
- }
287
- } } }
288
- },
289
- responses: {
290
- 201: ok("The created media.", ref("MediaResponse")),
291
- ...problems(401, 403, 422)
292
- }
293
- }
294
- },
295
- "/media/tags": { get: {
296
- operationId: "listMediaTags",
297
284
  responses: {
298
- 200: ok("Tags in use.", {
299
- type: "object",
300
- required: ["data"],
301
- properties: { data: {
302
- type: "array",
303
- items: { type: "string" }
304
- } }
305
- }),
306
- ...problems(401, 403)
285
+ 200: ok("The presigned request.", ref("UploadSignResponse")),
286
+ ...problems(401, 403, 404, 422)
307
287
  }
308
288
  } },
309
- "/media/{id}": {
310
- parameters: [pathParameter("id", "Media id.")],
311
- get: {
312
- operationId: "getMedia",
313
- responses: {
314
- 200: ok("The media.", ref("MediaResponse")),
315
- ...problems(401, 403, 404)
316
- }
317
- },
318
- patch: {
319
- operationId: "updateMedia",
320
- description: "Updates metadata, tags or the image `transform`.",
321
- requestBody: {
322
- required: true,
323
- content: json(values)
324
- },
325
- responses: {
326
- 200: ok("The updated media.", ref("MediaResponse")),
327
- ...problems(401, 403, 404, 422)
328
- }
329
- },
330
- delete: {
331
- operationId: "deleteMedia",
332
- responses: {
333
- 204: ok("Moved to the trash."),
334
- ...problems(401, 403, 404, 409)
335
- }
336
- }
337
- },
338
- "/media/{id}/file": {
339
- parameters: [pathParameter("id", "Media id.")],
289
+ "/uploads/{upload}/complete": {
290
+ parameters: [pathParameter("upload", "Upload id: `upl_…`.")],
340
291
  post: {
341
- operationId: "replaceMediaFile",
292
+ operationId: "completeUpload",
293
+ summary: "Once the browser completed the upload in storage, checks the object and gives the upload, which values reference.",
342
294
  requestBody: {
343
- required: true,
344
- content: { "multipart/form-data": { schema: {
295
+ required: false,
296
+ content: json({
345
297
  type: "object",
346
- required: ["file"],
347
- properties: { file: {
298
+ properties: { name: {
348
299
  type: "string",
349
- contentMediaType: "application/octet-stream"
300
+ description: "The file's name, which the key doesn't keep, since the backend chose it."
350
301
  } }
351
- } } }
302
+ })
352
303
  },
353
304
  responses: {
354
- 200: ok("The media.", ref("MediaResponse")),
305
+ 200: ok("The upload.", ref("UploadResponse")),
355
306
  ...problems(401, 403, 404, 422)
356
307
  }
357
308
  }
358
309
  },
359
- "/media/{id}/restore": {
360
- parameters: [pathParameter("id", "Media id.")],
361
- post: {
362
- operationId: "restoreMedia",
363
- responses: {
364
- 200: ok("The restored media.", ref("MediaResponse")),
365
- ...problems(401, 403, 404)
366
- }
367
- }
368
- },
369
310
  "/auth/session": { get: {
370
311
  operationId: "getSession",
371
312
  responses: {
@@ -520,13 +461,26 @@ function createOpenApiDocument() {
520
461
  },
521
462
  "/search": { get: {
522
463
  operationId: "search",
523
- parameters: [{
524
- ...queryParameter("q", "Search terms.", { type: "string" }),
525
- required: true
526
- }],
464
+ parameters: [
465
+ {
466
+ ...queryParameter("q", "Search terms, trimmed.", {
467
+ type: "string",
468
+ minLength: 2,
469
+ maxLength: 255
470
+ }),
471
+ required: true
472
+ },
473
+ queryParameter("limit", "Items per resource.", {
474
+ type: "integer",
475
+ minimum: 1,
476
+ maximum: 20,
477
+ default: 5
478
+ }),
479
+ queryParameter("resources", "Comma-separated ids of the searchable resources to search. Defaults to every one.", { type: "string" })
480
+ ],
527
481
  responses: {
528
- 200: ok("Results grouped by resource.", ref("SearchResponse")),
529
- ...problems(401)
482
+ 200: ok(`Results grouped by resource, in the order of the definition: at most \`limit\` items per resource, and 20 in all.`, ref("SearchResponse")),
483
+ ...problems(401, 422, 429)
530
484
  }
531
485
  } },
532
486
  "/dashboard/widgets/{widget}": {
@@ -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 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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"}
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 {\n SEARCH_DEFAULT_LIMIT,\n SEARCH_MAX_LENGTH,\n SEARCH_MAX_LIMIT,\n SEARCH_MIN_LENGTH,\n} from './search';\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 429: 'Too many requests: `Retry-After` gives the seconds to wait.',\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 '/resources/{resource}/fields/{field}/check': {\n parameters: [resource, pathParameter('field', 'Name of a field with `check`.')],\n post: {\n operationId: 'checkField',\n summary:\n 'Checks a value as it is typed: whether a slug is available, and its URL. With the permission to create, or to update the item `id`.',\n requestBody: { required: true, content: json(ref('FieldCheckRequest')) },\n responses: {\n 200: ok(\n 'What the backend says about the value.',\n ref('FieldCheckResponse'),\n ),\n ...problems(401, 403, 404, 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 '/uploads/sign': {\n post: {\n operationId: 'signUpload',\n summary:\n \"Signs a request of the browser's S3 client. The first request of a file creates its upload.\",\n requestBody: { required: true, content: json(ref('UploadSignRequest')) },\n responses: {\n 200: ok('The presigned request.', ref('UploadSignResponse')),\n ...problems(401, 403, 404, 422),\n },\n },\n },\n '/uploads/{upload}/complete': {\n parameters: [pathParameter('upload', 'Upload id: `upl_…`.')],\n post: {\n operationId: 'completeUpload',\n summary:\n 'Once the browser completed the upload in storage, checks the object and gives the upload, which values reference.',\n requestBody: {\n required: false,\n content: json({\n type: 'object',\n properties: {\n name: {\n type: 'string',\n description:\n \"The file's name, which the key doesn't keep, since the backend chose it.\",\n },\n },\n }),\n },\n responses: {\n 200: ok('The upload.', ref('UploadResponse')),\n ...problems(401, 403, 404, 422),\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, trimmed.', {\n type: 'string',\n minLength: SEARCH_MIN_LENGTH,\n maxLength: SEARCH_MAX_LENGTH,\n }),\n required: true,\n },\n queryParameter('limit', 'Items per resource.', {\n type: 'integer',\n minimum: 1,\n maximum: SEARCH_MAX_LIMIT,\n default: SEARCH_DEFAULT_LIMIT,\n }),\n queryParameter(\n 'resources',\n 'Comma-separated ids of the searchable resources to search. Defaults to every one.',\n { type: 'string' },\n ),\n ],\n responses: {\n 200: ok(\n `Results grouped by resource, in the order of the definition: at most \\`limit\\` items per resource, and ${SEARCH_MAX_LIMIT} in all.`,\n ref('SearchResponse'),\n ),\n ...problems(401, 422, 429),\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 +1 @@
1
- {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAGnD,2CAA2C;AAC3C,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC3B,qEAAqE;IACrE,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAyDD,6EAA6E;AAC7E,wBAAgB,UAAU,CACtB,KAAK,EAAE,IAAI,EAAE,EACb,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,WAAW,EAAE,CAwEf;AAuFD;;;;GAIG;AACH,wBAAgB,WAAW,CACvB,MAAM,EAAE,KAAK,EAAE,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,GAAE,YAAiB,GAC3B,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAI/B"}
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAInD,2CAA2C;AAC3C,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC3B,qEAAqE;IACrE,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AA6ED,6EAA6E;AAC7E,wBAAgB,UAAU,CACtB,KAAK,EAAE,IAAI,EAAE,EACb,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,WAAW,EAAE,CA2Ef;AAuFD;;;;GAIG;AACH,wBAAgB,WAAW,CACvB,MAAM,EAAE,KAAK,EAAE,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,GAAE,YAAiB,GAC3B,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAI/B"}
package/dist/rules.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { PORTABLE_RULES } from "./constants.js";
2
2
  import { getValue, isFilled, isRecord } from "./values.js";
3
3
  import { evaluateCondition } from "./conditions.js";
4
+ import { matchesRatio, renderedCropSize } from "./transforms.js";
4
5
  //#region src/rules.ts
5
6
  var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
6
7
  function isKnownRule(rule) {
@@ -26,6 +27,19 @@ function matchesMime(mime, patterns) {
26
27
  function mediaList(value) {
27
28
  return (Array.isArray(value) ? value : [value]).filter(isRecord);
28
29
  }
30
+ /**
31
+ * Whether each image of a value has the crop the `crop` rule asks for (decision 0031): a crop when
32
+ * it is required, and one of the ratios once rendered. An id alone has no crop.
33
+ */
34
+ function hasCrop(value, rule) {
35
+ return (Array.isArray(value) ? value : [value]).every((entry) => {
36
+ const transform = isRecord(entry) && isRecord(entry.transform) ? entry.transform : {};
37
+ const size = renderedCropSize(transform);
38
+ if (size === null) return rule.required !== true;
39
+ const ratios = rule.ratios ?? [];
40
+ return ratios.length === 0 || ratios.some((ratio) => matchesRatio(size.width, size.height, ratio));
41
+ });
42
+ }
29
43
  function toTime(value) {
30
44
  if (typeof value !== "string" && typeof value !== "number") return null;
31
45
  const time = new Date(value).getTime();
@@ -70,6 +84,9 @@ function checkRules(rules, value, root = {}) {
70
84
  case "maxSize":
71
85
  valid = mediaList(value).every((media) => typeof media.size !== "number" || media.size <= rule.value);
72
86
  break;
87
+ case "crop":
88
+ valid = !isRecord(rule.value) || hasCrop(value, rule.value);
89
+ break;
73
90
  case "before":
74
91
  case "after": {
75
92
  const bound = rule.value;
package/dist/rules.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"rules.js","names":[],"sources":["../src/rules.ts"],"sourcesContent":["import { evaluateCondition } from './conditions';\nimport { PORTABLE_RULES } from './constants';\nimport type { Field, Rule } from './schemas/field';\nimport { getValue, isFilled, isRecord } from './values';\n\n/** A rule that a value doesn't satisfy. */\nexport interface RuleFailure {\n rule: string;\n /** The rule's parameter (`max: 120` gives `120`). */\n value?: unknown;\n /** The message set on the rule, if any. */\n message?: string;\n}\n\nexport interface CheckOptions {\n /**\n * Locales a `required` localized field must be filled in. Without it, one filled locale is\n * enough.\n */\n locales?: string[];\n /** `create` skips `updateOnly` fields; `update` skips `createOnly` fields. */\n mode?: 'create' | 'update';\n /** Only check the fields present in the values (partial updates). */\n partial?: boolean;\n}\n\ninterface Context extends CheckOptions {\n /** The whole form, for `visibleWhen` and date rules that reference other fields. */\n root: Record<string, unknown>;\n failures: Record<string, RuleFailure[]>;\n}\n\nconst EMAIL = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nfunction isKnownRule(rule: Rule): boolean {\n return (PORTABLE_RULES as readonly string[]).includes(rule.rule);\n}\n\nfunction failure(rule: Rule): RuleFailure {\n const result: RuleFailure = { rule: rule.rule };\n if ('value' in rule && rule.value !== undefined) {\n result.value = rule.value;\n }\n if (rule.message !== undefined) {\n result.message = rule.message;\n }\n return result;\n}\n\nfunction sizeOf(value: unknown): number | null {\n if (typeof value === 'number') {\n return value;\n }\n if (typeof value === 'string' || Array.isArray(value)) {\n return value.length;\n }\n return null;\n}\n\nfunction matchesMime(mime: string, patterns: string[]): boolean {\n return patterns.some((pattern) => {\n if (pattern.endsWith('/*')) {\n return mime.startsWith(pattern.slice(0, -1));\n }\n return mime === pattern;\n });\n}\n\nfunction mediaList(value: unknown): Record<string, unknown>[] {\n const list = Array.isArray(value) ? value : [value];\n return list.filter(isRecord);\n}\n\nfunction toTime(value: unknown): number | null {\n if (typeof value !== 'string' && typeof value !== 'number') {\n return null;\n }\n const time = new Date(value).getTime();\n return Number.isNaN(time) ? null : time;\n}\n\n/** Checks one value against a field's rules. Returns the rules that fail. */\nexport function checkRules(\n rules: Rule[],\n value: unknown,\n root: Record<string, unknown> = {},\n): RuleFailure[] {\n const failures: RuleFailure[] = [];\n const filled = isFilled(value);\n rules.filter(isKnownRule).forEach((rule) => {\n if (rule.rule === 'required') {\n if (!filled) {\n failures.push(failure(rule));\n }\n return;\n }\n if (!filled) {\n return;\n }\n let valid = true;\n switch (rule.rule) {\n case 'min':\n case 'max': {\n const size = sizeOf(value);\n const limit = rule.value as number;\n valid = size === null || (rule.rule === 'min' ? size >= limit : size <= limit);\n break;\n }\n case 'pattern':\n valid =\n typeof value !== 'string' ||\n new RegExp(rule.value as string, (rule as { flags?: string }).flags).test(\n value,\n );\n break;\n case 'email':\n valid = typeof value !== 'string' || EMAIL.test(value);\n break;\n case 'url':\n valid = typeof value !== 'string' || URL.canParse(value);\n break;\n case 'in': {\n const allowed = rule.value as unknown[];\n const values = Array.isArray(value) ? value : [value];\n valid = values.every((item) => allowed.includes(item));\n break;\n }\n case 'accept':\n valid = mediaList(value).every(\n (media) =>\n typeof media.mime !== 'string' ||\n matchesMime(media.mime, rule.value as string[]),\n );\n break;\n case 'maxSize':\n valid = mediaList(value).every(\n (media) =>\n typeof media.size !== 'number' || media.size <= (rule.value as number),\n );\n break;\n case 'before':\n case 'after': {\n const bound = rule.value as string | { field: string };\n const boundTime = toTime(\n typeof bound === 'string' ? bound : getValue(root, bound.field),\n );\n const time = toTime(value);\n if (boundTime !== null && time !== null) {\n valid = rule.rule === 'before' ? time < boundTime : time > boundTime;\n }\n break;\n }\n }\n if (!valid) {\n failures.push(failure(rule));\n }\n });\n return failures;\n}\n\nfunction addFailures(context: Context, path: string, failures: RuleFailure[]) {\n if (failures.length > 0) {\n context.failures[path] = [...(context.failures[path] ?? []), ...failures];\n }\n}\n\nfunction checkFieldValue(field: Field, value: unknown, path: string, context: Context) {\n const rules = field.rules ?? [];\n if (field.localized === true) {\n const localized = isRecord(value) ? value : {};\n const required = rules.filter((rule) => rule.rule === 'required');\n const others = rules.filter((rule) => rule.rule !== 'required');\n if (required.length > 0) {\n const locales = context.locales;\n if (locales === undefined || locales.length === 0) {\n if (!Object.values(localized).some(isFilled)) {\n addFailures(context, path, required.map(failure));\n }\n } else {\n locales.forEach((locale) => {\n addFailures(\n context,\n `${path}.${locale}`,\n checkRules(required, localized[locale], context.root),\n );\n });\n }\n }\n Object.entries(localized).forEach(([locale, localeValue]) => {\n addFailures(\n context,\n `${path}.${locale}`,\n checkRules(others, localeValue, context.root),\n );\n });\n return;\n }\n\n addFailures(context, path, checkRules(rules, value, context.root));\n\n if (field.type === 'group' && field.fields !== undefined && isRecord(value)) {\n checkFields(field.fields, value, `${path}.`, context);\n }\n if (field.type === 'repeater' && Array.isArray(value)) {\n value.forEach((item, index) => {\n if (!isRecord(item)) {\n return;\n }\n const blockFields =\n field.types !== undefined\n ? field.types.find((type) => type.id === item.type)?.fields\n : field.fields;\n if (blockFields !== undefined) {\n checkFields(blockFields, item, `${path}.${index}.`, context);\n }\n });\n }\n}\n\nfunction checkFields(\n fields: Field[],\n values: Record<string, unknown>,\n prefix: string,\n context: Context,\n) {\n fields.forEach((field) => {\n if (field.readOnly === true) {\n return;\n }\n if (context.mode === 'create' && field.updateOnly === true) {\n return;\n }\n if (context.mode === 'update' && field.createOnly === true) {\n return;\n }\n if (field.visibleWhen !== undefined && !evaluateCondition(field.visibleWhen, values)) {\n return;\n }\n if (context.partial === true && prefix === '' && !(field.name in values)) {\n return;\n }\n checkFieldValue(field, values[field.name], `${prefix}${field.name}`, context);\n });\n}\n\n/**\n * Checks form values against the portable rules of their fields. Returns the failures keyed by\n * the dot path of the value (`title.fr`, `blocks.2.image`), the same keys as validation errors.\n * Hidden and read-only fields are skipped. Rules this version doesn't know are ignored.\n */\nexport function checkValues(\n fields: Field[],\n values: Record<string, unknown>,\n options: CheckOptions = {},\n): Record<string, RuleFailure[]> {\n const context: Context = { ...options, root: values, failures: {} };\n checkFields(fields, values, '', context);\n return context.failures;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rules.js","names":[],"sources":["../src/rules.ts"],"sourcesContent":["import { evaluateCondition } from './conditions';\nimport { PORTABLE_RULES } from './constants';\nimport type { Field, Rule } from './schemas/field';\nimport { matchesRatio, renderedCropSize } from './transforms';\nimport { getValue, isFilled, isRecord } from './values';\n\n/** A rule that a value doesn't satisfy. */\nexport interface RuleFailure {\n rule: string;\n /** The rule's parameter (`max: 120` gives `120`). */\n value?: unknown;\n /** The message set on the rule, if any. */\n message?: string;\n}\n\nexport interface CheckOptions {\n /**\n * Locales a `required` localized field must be filled in. Without it, one filled locale is\n * enough.\n */\n locales?: string[];\n /** `create` skips `updateOnly` fields; `update` skips `createOnly` fields. */\n mode?: 'create' | 'update';\n /** Only check the fields present in the values (partial updates). */\n partial?: boolean;\n}\n\ninterface Context extends CheckOptions {\n /** The whole form, for `visibleWhen` and date rules that reference other fields. */\n root: Record<string, unknown>;\n failures: Record<string, RuleFailure[]>;\n}\n\nconst EMAIL = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nfunction isKnownRule(rule: Rule): boolean {\n return (PORTABLE_RULES as readonly string[]).includes(rule.rule);\n}\n\nfunction failure(rule: Rule): RuleFailure {\n const result: RuleFailure = { rule: rule.rule };\n if ('value' in rule && rule.value !== undefined) {\n result.value = rule.value;\n }\n if (rule.message !== undefined) {\n result.message = rule.message;\n }\n return result;\n}\n\nfunction sizeOf(value: unknown): number | null {\n if (typeof value === 'number') {\n return value;\n }\n if (typeof value === 'string' || Array.isArray(value)) {\n return value.length;\n }\n return null;\n}\n\nfunction matchesMime(mime: string, patterns: string[]): boolean {\n return patterns.some((pattern) => {\n if (pattern.endsWith('/*')) {\n return mime.startsWith(pattern.slice(0, -1));\n }\n return mime === pattern;\n });\n}\n\nfunction mediaList(value: unknown): Record<string, unknown>[] {\n const list = Array.isArray(value) ? value : [value];\n return list.filter(isRecord);\n}\n\n/**\n * Whether each image of a value has the crop the `crop` rule asks for (decision 0031): a crop when\n * it is required, and one of the ratios once rendered. An id alone has no crop.\n */\nfunction hasCrop(value: unknown, rule: { ratios?: string[]; required?: boolean }): boolean {\n const entries = Array.isArray(value) ? value : [value];\n return entries.every((entry) => {\n const transform = isRecord(entry) && isRecord(entry.transform) ? entry.transform : {};\n const size = renderedCropSize(transform);\n if (size === null) {\n return rule.required !== true;\n }\n const ratios = rule.ratios ?? [];\n return (\n ratios.length === 0 ||\n ratios.some((ratio) => matchesRatio(size.width, size.height, ratio))\n );\n });\n}\n\nfunction toTime(value: unknown): number | null {\n if (typeof value !== 'string' && typeof value !== 'number') {\n return null;\n }\n const time = new Date(value).getTime();\n return Number.isNaN(time) ? null : time;\n}\n\n/** Checks one value against a field's rules. Returns the rules that fail. */\nexport function checkRules(\n rules: Rule[],\n value: unknown,\n root: Record<string, unknown> = {},\n): RuleFailure[] {\n const failures: RuleFailure[] = [];\n const filled = isFilled(value);\n rules.filter(isKnownRule).forEach((rule) => {\n if (rule.rule === 'required') {\n if (!filled) {\n failures.push(failure(rule));\n }\n return;\n }\n if (!filled) {\n return;\n }\n let valid = true;\n switch (rule.rule) {\n case 'min':\n case 'max': {\n const size = sizeOf(value);\n const limit = rule.value as number;\n valid = size === null || (rule.rule === 'min' ? size >= limit : size <= limit);\n break;\n }\n case 'pattern':\n valid =\n typeof value !== 'string' ||\n new RegExp(rule.value as string, (rule as { flags?: string }).flags).test(\n value,\n );\n break;\n case 'email':\n valid = typeof value !== 'string' || EMAIL.test(value);\n break;\n case 'url':\n valid = typeof value !== 'string' || URL.canParse(value);\n break;\n case 'in': {\n const allowed = rule.value as unknown[];\n const values = Array.isArray(value) ? value : [value];\n valid = values.every((item) => allowed.includes(item));\n break;\n }\n case 'accept':\n valid = mediaList(value).every(\n (media) =>\n typeof media.mime !== 'string' ||\n matchesMime(media.mime, rule.value as string[]),\n );\n break;\n case 'maxSize':\n valid = mediaList(value).every(\n (media) =>\n typeof media.size !== 'number' || media.size <= (rule.value as number),\n );\n break;\n case 'crop':\n valid = !isRecord(rule.value) || hasCrop(value, rule.value);\n break;\n case 'before':\n case 'after': {\n const bound = rule.value as string | { field: string };\n const boundTime = toTime(\n typeof bound === 'string' ? bound : getValue(root, bound.field),\n );\n const time = toTime(value);\n if (boundTime !== null && time !== null) {\n valid = rule.rule === 'before' ? time < boundTime : time > boundTime;\n }\n break;\n }\n }\n if (!valid) {\n failures.push(failure(rule));\n }\n });\n return failures;\n}\n\nfunction addFailures(context: Context, path: string, failures: RuleFailure[]) {\n if (failures.length > 0) {\n context.failures[path] = [...(context.failures[path] ?? []), ...failures];\n }\n}\n\nfunction checkFieldValue(field: Field, value: unknown, path: string, context: Context) {\n const rules = field.rules ?? [];\n if (field.localized === true) {\n const localized = isRecord(value) ? value : {};\n const required = rules.filter((rule) => rule.rule === 'required');\n const others = rules.filter((rule) => rule.rule !== 'required');\n if (required.length > 0) {\n const locales = context.locales;\n if (locales === undefined || locales.length === 0) {\n if (!Object.values(localized).some(isFilled)) {\n addFailures(context, path, required.map(failure));\n }\n } else {\n locales.forEach((locale) => {\n addFailures(\n context,\n `${path}.${locale}`,\n checkRules(required, localized[locale], context.root),\n );\n });\n }\n }\n Object.entries(localized).forEach(([locale, localeValue]) => {\n addFailures(\n context,\n `${path}.${locale}`,\n checkRules(others, localeValue, context.root),\n );\n });\n return;\n }\n\n addFailures(context, path, checkRules(rules, value, context.root));\n\n if (field.type === 'group' && field.fields !== undefined && isRecord(value)) {\n checkFields(field.fields, value, `${path}.`, context);\n }\n if (field.type === 'repeater' && Array.isArray(value)) {\n value.forEach((item, index) => {\n if (!isRecord(item)) {\n return;\n }\n const blockFields =\n field.types !== undefined\n ? field.types.find((type) => type.id === item.type)?.fields\n : field.fields;\n if (blockFields !== undefined) {\n checkFields(blockFields, item, `${path}.${index}.`, context);\n }\n });\n }\n}\n\nfunction checkFields(\n fields: Field[],\n values: Record<string, unknown>,\n prefix: string,\n context: Context,\n) {\n fields.forEach((field) => {\n if (field.readOnly === true) {\n return;\n }\n if (context.mode === 'create' && field.updateOnly === true) {\n return;\n }\n if (context.mode === 'update' && field.createOnly === true) {\n return;\n }\n if (field.visibleWhen !== undefined && !evaluateCondition(field.visibleWhen, values)) {\n return;\n }\n if (context.partial === true && prefix === '' && !(field.name in values)) {\n return;\n }\n checkFieldValue(field, values[field.name], `${prefix}${field.name}`, context);\n });\n}\n\n/**\n * Checks form values against the portable rules of their fields. Returns the failures keyed by\n * the dot path of the value (`title.fr`, `blocks.2.image`), the same keys as validation errors.\n * Hidden and read-only fields are skipped. Rules this version doesn't know are ignored.\n */\nexport function checkValues(\n fields: Field[],\n values: Record<string, unknown>,\n options: CheckOptions = {},\n): Record<string, RuleFailure[]> {\n const context: Context = { ...options, root: values, failures: {} };\n checkFields(fields, values, '', context);\n return context.failures;\n}\n"],"mappings":"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"}
@@ -2,9 +2,12 @@ export { PROBLEM_CONTENT_TYPE, PROTOCOL_VERSION } from '../version';
2
2
  export * from '../constants';
3
3
  export { type CheckOptions, type RuleFailure, checkRules, checkValues } from '../rules';
4
4
  export { evaluateCondition } from '../conditions';
5
+ export { getMediaLibraries, type MediaLibrariesDefinition } from '../libraries';
6
+ export { matchesRatio, parseRatio, renderedCropSize } from '../transforms';
5
7
  export { lintDefinition } from '../lint';
6
8
  export type { ValidationIssue } from '../validate';
7
9
  export { type FilterRange, type FilterValue, type ListQuery, fromSearchParams, isFilterRange, matchesFilterRange, toSearchParams, } from '../query';
10
+ export { type ReadSearchQueryResult, type SearchQuery, type SearchableResource, SEARCH_DEFAULT_LIMIT, SEARCH_MAX_LENGTH, SEARCH_MAX_LIMIT, SEARCH_MIN_LENGTH, isSearchableResource, readSearchQuery, toSearchQueryParams, } from '../search';
8
11
  export { getValue, isFilled } from '../values';
9
12
  export { isProblem } from '../problem';
10
13
  export { type PartialTheme, mergeThemes } from '../themes';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpE,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EACH,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,cAAc,GACjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,KAAK,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpE,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EACH,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,cAAc,GACjB,MAAM,UAAU,CAAC;AAClB,OAAO,EACH,KAAK,qBAAqB,EAC1B,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,mBAAmB,GACtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,KAAK,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -2,9 +2,12 @@ import { PROBLEM_CONTENT_TYPE, PROTOCOL_VERSION } from "../version.js";
2
2
  import { BOOT_CONFIG_ELEMENT_ID, BUILT_IN_ACTIONS, BUILT_IN_FIELD_TYPES, BUILT_IN_LAYOUT_NODE_TYPES, BUILT_IN_LIST_LAYOUTS, PORTABLE_RULES } from "../constants.js";
3
3
  import { getValue, isFilled } from "../values.js";
4
4
  import { evaluateCondition } from "../conditions.js";
5
+ import { matchesRatio, parseRatio, renderedCropSize } from "../transforms.js";
5
6
  import { checkRules, checkValues } from "../rules.js";
7
+ import { getMediaLibraries } from "../libraries.js";
6
8
  import { lintDefinition } from "../lint.js";
7
9
  import { fromSearchParams, isFilterRange, matchesFilterRange, toSearchParams } from "../query.js";
10
+ import { SEARCH_DEFAULT_LIMIT, SEARCH_MAX_LENGTH, SEARCH_MAX_LIMIT, SEARCH_MIN_LENGTH, isSearchableResource, readSearchQuery, toSearchQueryParams } from "../search.js";
8
11
  import { isProblem } from "../problem.js";
9
12
  import { mergeThemes } from "../themes.js";
10
- export { BOOT_CONFIG_ELEMENT_ID, BUILT_IN_ACTIONS, BUILT_IN_FIELD_TYPES, BUILT_IN_LAYOUT_NODE_TYPES, BUILT_IN_LIST_LAYOUTS, PORTABLE_RULES, PROBLEM_CONTENT_TYPE, PROTOCOL_VERSION, checkRules, checkValues, evaluateCondition, fromSearchParams, getValue, isFilled, isFilterRange, isProblem, lintDefinition, matchesFilterRange, mergeThemes, toSearchParams };
13
+ export { BOOT_CONFIG_ELEMENT_ID, BUILT_IN_ACTIONS, BUILT_IN_FIELD_TYPES, BUILT_IN_LAYOUT_NODE_TYPES, BUILT_IN_LIST_LAYOUTS, PORTABLE_RULES, PROBLEM_CONTENT_TYPE, PROTOCOL_VERSION, SEARCH_DEFAULT_LIMIT, SEARCH_MAX_LENGTH, SEARCH_MAX_LIMIT, SEARCH_MIN_LENGTH, checkRules, checkValues, evaluateCondition, fromSearchParams, getMediaLibraries, getValue, isFilled, isFilterRange, isProblem, isSearchableResource, lintDefinition, matchesFilterRange, matchesRatio, mergeThemes, parseRatio, readSearchQuery, renderedCropSize, toSearchParams, toSearchQueryParams };
@@ -98,6 +98,13 @@ export declare const Action: z.ZodObject<{
98
98
  field: z.ZodString;
99
99
  }, z.core.$loose>]>;
100
100
  message: z.ZodOptional<z.ZodString>;
101
+ }, z.core.$loose>, z.ZodObject<{
102
+ rule: z.ZodLiteral<"crop">;
103
+ value: z.ZodObject<{
104
+ ratios: z.ZodOptional<z.ZodArray<z.ZodString>>;
105
+ required: z.ZodOptional<z.ZodBoolean>;
106
+ }, z.core.$loose>;
107
+ message: z.ZodOptional<z.ZodString>;
101
108
  }, z.core.$loose>, z.ZodObject<{
102
109
  rule: z.ZodString;
103
110
  message: z.ZodOptional<z.ZodString>;
@@ -118,9 +125,18 @@ export declare const Action: z.ZodObject<{
118
125
  disabled: z.ZodOptional<z.ZodBoolean>;
119
126
  }, z.core.$loose>>>;
120
127
  multiple: z.ZodOptional<z.ZodBoolean>;
121
- resource: z.ZodOptional<z.ZodString>;
128
+ resource: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
122
129
  accept: z.ZodOptional<z.ZodArray<z.ZodString>>;
130
+ ratios: z.ZodOptional<z.ZodArray<z.ZodString>>;
131
+ rotate: z.ZodOptional<z.ZodBoolean>;
132
+ focalPoint: z.ZodOptional<z.ZodBoolean>;
133
+ transformBase: z.ZodOptional<z.ZodEnum<{
134
+ media: "media";
135
+ original: "original";
136
+ choose: "choose";
137
+ }>>;
123
138
  from: z.ZodOptional<z.ZodString>;
139
+ check: z.ZodOptional<z.ZodBoolean>;
124
140
  display: z.ZodOptional<z.ZodString>;
125
141
  fields: z.ZodOptional<z.ZodArray<typeof Field>>;
126
142
  types: z.ZodOptional<z.ZodArray<typeof import("./field").BlockType>>;
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
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"}