@seshuk/payload-plugin-openapi 1.0.0-beta.1 → 1.0.0-beta.2

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 (148) hide show
  1. package/README.md +8 -4
  2. package/dist/server/spec/buildDocument.js +62 -9
  3. package/dist/server/spec/buildDocument.js.map +1 -1
  4. package/dist/server/spec/components.js.map +1 -1
  5. package/dist/server/spec/entitySchemas.d.ts +5 -6
  6. package/dist/server/spec/entitySchemas.js.map +1 -1
  7. package/dist/server/spec/filters.d.ts +5 -1
  8. package/dist/server/spec/filters.js +21 -10
  9. package/dist/server/spec/filters.js.map +1 -1
  10. package/dist/server/spec/hierarchy.js +9 -4
  11. package/dist/server/spec/hierarchy.js.map +1 -1
  12. package/dist/server/spec/paths/collections.js +111 -7
  13. package/dist/server/spec/paths/collections.js.map +1 -1
  14. package/dist/server/spec/paths/custom.d.ts +4 -2
  15. package/dist/server/spec/paths/custom.js +1 -1
  16. package/dist/server/spec/paths/custom.js.map +1 -1
  17. package/dist/server/spec/paths/system.d.ts +2 -1
  18. package/dist/server/spec/paths/system.js +67 -1
  19. package/dist/server/spec/paths/system.js.map +1 -1
  20. package/dist/server/spec/plugins/ecommerce.d.ts +3 -0
  21. package/dist/server/spec/plugins/ecommerce.js +270 -0
  22. package/dist/server/spec/plugins/ecommerce.js.map +1 -0
  23. package/dist/server/spec/plugins/importExport.d.ts +3 -0
  24. package/dist/server/spec/plugins/importExport.js +202 -0
  25. package/dist/server/spec/plugins/importExport.js.map +1 -0
  26. package/dist/server/spec/plugins/index.d.ts +3 -0
  27. package/dist/server/spec/plugins/index.js +21 -0
  28. package/dist/server/spec/plugins/index.js.map +1 -0
  29. package/dist/server/spec/plugins/mcp.d.ts +3 -0
  30. package/dist/server/spec/plugins/mcp.js +118 -0
  31. package/dist/server/spec/plugins/mcp.js.map +1 -0
  32. package/dist/server/spec/plugins/multiTenant.d.ts +3 -0
  33. package/dist/server/spec/plugins/multiTenant.js +39 -0
  34. package/dist/server/spec/plugins/multiTenant.js.map +1 -0
  35. package/dist/server/spec/plugins/search.d.ts +3 -0
  36. package/dist/server/spec/plugins/search.js +43 -0
  37. package/dist/server/spec/plugins/search.js.map +1 -0
  38. package/dist/server/spec/plugins/seo.d.ts +3 -0
  39. package/dist/server/spec/plugins/seo.js +83 -0
  40. package/dist/server/spec/plugins/seo.js.map +1 -0
  41. package/dist/server/spec/plugins/shared.d.ts +35 -0
  42. package/dist/server/spec/plugins/shared.js +37 -0
  43. package/dist/server/spec/plugins/shared.js.map +1 -0
  44. package/dist/server/spec/plugins/storageR2.d.ts +3 -0
  45. package/dist/server/spec/plugins/storageR2.js +91 -0
  46. package/dist/server/spec/plugins/storageR2.js.map +1 -0
  47. package/dist/server/spec/plugins/stripe.d.ts +10 -0
  48. package/dist/server/spec/plugins/stripe.js +102 -0
  49. package/dist/server/spec/plugins/stripe.js.map +1 -0
  50. package/dist/server/spec/security.d.ts +2 -1
  51. package/dist/server/spec/security.js +5 -2
  52. package/dist/server/spec/security.js.map +1 -1
  53. package/dist/server/spec/tags.d.ts +4 -1
  54. package/dist/server/spec/tags.js +18 -2
  55. package/dist/server/spec/tags.js.map +1 -1
  56. package/dist/server/ui/html.js +2 -2
  57. package/dist/server/ui/html.js.map +1 -1
  58. package/dist/shared/translations/locales/ar.js +74 -0
  59. package/dist/shared/translations/locales/ar.js.map +1 -1
  60. package/dist/shared/translations/locales/az.js +74 -0
  61. package/dist/shared/translations/locales/az.js.map +1 -1
  62. package/dist/shared/translations/locales/bg.js +74 -0
  63. package/dist/shared/translations/locales/bg.js.map +1 -1
  64. package/dist/shared/translations/locales/bnBd.js +74 -0
  65. package/dist/shared/translations/locales/bnBd.js.map +1 -1
  66. package/dist/shared/translations/locales/bnIn.js +74 -0
  67. package/dist/shared/translations/locales/bnIn.js.map +1 -1
  68. package/dist/shared/translations/locales/ca.js +74 -0
  69. package/dist/shared/translations/locales/ca.js.map +1 -1
  70. package/dist/shared/translations/locales/cs.js +74 -0
  71. package/dist/shared/translations/locales/cs.js.map +1 -1
  72. package/dist/shared/translations/locales/da.js +74 -0
  73. package/dist/shared/translations/locales/da.js.map +1 -1
  74. package/dist/shared/translations/locales/de.js +74 -0
  75. package/dist/shared/translations/locales/de.js.map +1 -1
  76. package/dist/shared/translations/locales/en.js +74 -0
  77. package/dist/shared/translations/locales/en.js.map +1 -1
  78. package/dist/shared/translations/locales/es.js +74 -0
  79. package/dist/shared/translations/locales/es.js.map +1 -1
  80. package/dist/shared/translations/locales/et.js +74 -0
  81. package/dist/shared/translations/locales/et.js.map +1 -1
  82. package/dist/shared/translations/locales/fa.js +74 -0
  83. package/dist/shared/translations/locales/fa.js.map +1 -1
  84. package/dist/shared/translations/locales/fr.js +74 -0
  85. package/dist/shared/translations/locales/fr.js.map +1 -1
  86. package/dist/shared/translations/locales/he.js +74 -0
  87. package/dist/shared/translations/locales/he.js.map +1 -1
  88. package/dist/shared/translations/locales/hr.js +74 -0
  89. package/dist/shared/translations/locales/hr.js.map +1 -1
  90. package/dist/shared/translations/locales/hu.js +74 -0
  91. package/dist/shared/translations/locales/hu.js.map +1 -1
  92. package/dist/shared/translations/locales/hy.js +74 -0
  93. package/dist/shared/translations/locales/hy.js.map +1 -1
  94. package/dist/shared/translations/locales/id.js +74 -0
  95. package/dist/shared/translations/locales/id.js.map +1 -1
  96. package/dist/shared/translations/locales/is.js +74 -0
  97. package/dist/shared/translations/locales/is.js.map +1 -1
  98. package/dist/shared/translations/locales/it.js +74 -0
  99. package/dist/shared/translations/locales/it.js.map +1 -1
  100. package/dist/shared/translations/locales/ja.js +74 -0
  101. package/dist/shared/translations/locales/ja.js.map +1 -1
  102. package/dist/shared/translations/locales/ko.js +74 -0
  103. package/dist/shared/translations/locales/ko.js.map +1 -1
  104. package/dist/shared/translations/locales/lt.js +74 -0
  105. package/dist/shared/translations/locales/lt.js.map +1 -1
  106. package/dist/shared/translations/locales/lv.js +74 -0
  107. package/dist/shared/translations/locales/lv.js.map +1 -1
  108. package/dist/shared/translations/locales/my.js +74 -0
  109. package/dist/shared/translations/locales/my.js.map +1 -1
  110. package/dist/shared/translations/locales/nb.js +74 -0
  111. package/dist/shared/translations/locales/nb.js.map +1 -1
  112. package/dist/shared/translations/locales/nl.js +74 -0
  113. package/dist/shared/translations/locales/nl.js.map +1 -1
  114. package/dist/shared/translations/locales/pl.js +74 -0
  115. package/dist/shared/translations/locales/pl.js.map +1 -1
  116. package/dist/shared/translations/locales/pt.js +74 -0
  117. package/dist/shared/translations/locales/pt.js.map +1 -1
  118. package/dist/shared/translations/locales/ro.js +74 -0
  119. package/dist/shared/translations/locales/ro.js.map +1 -1
  120. package/dist/shared/translations/locales/rs.js +74 -0
  121. package/dist/shared/translations/locales/rs.js.map +1 -1
  122. package/dist/shared/translations/locales/rsLatin.js +74 -0
  123. package/dist/shared/translations/locales/rsLatin.js.map +1 -1
  124. package/dist/shared/translations/locales/ru.js +74 -0
  125. package/dist/shared/translations/locales/ru.js.map +1 -1
  126. package/dist/shared/translations/locales/sk.js +74 -0
  127. package/dist/shared/translations/locales/sk.js.map +1 -1
  128. package/dist/shared/translations/locales/sl.js +74 -0
  129. package/dist/shared/translations/locales/sl.js.map +1 -1
  130. package/dist/shared/translations/locales/sv.js +74 -0
  131. package/dist/shared/translations/locales/sv.js.map +1 -1
  132. package/dist/shared/translations/locales/ta.js +74 -0
  133. package/dist/shared/translations/locales/ta.js.map +1 -1
  134. package/dist/shared/translations/locales/th.js +74 -0
  135. package/dist/shared/translations/locales/th.js.map +1 -1
  136. package/dist/shared/translations/locales/tr.js +74 -0
  137. package/dist/shared/translations/locales/tr.js.map +1 -1
  138. package/dist/shared/translations/locales/uk.js +74 -0
  139. package/dist/shared/translations/locales/uk.js.map +1 -1
  140. package/dist/shared/translations/locales/vi.js +74 -0
  141. package/dist/shared/translations/locales/vi.js.map +1 -1
  142. package/dist/shared/translations/locales/zh.js +74 -0
  143. package/dist/shared/translations/locales/zh.js.map +1 -1
  144. package/dist/shared/translations/locales/zhTw.js +74 -0
  145. package/dist/shared/translations/locales/zhTw.js.map +1 -1
  146. package/dist/shared/translations/types.d.ts +74 -0
  147. package/dist/shared/types/index.d.ts +23 -8
  148. package/package.json +23 -15
package/README.md CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
  ## Features
22
22
 
23
- - **Full spec from your config** — collections, globals, auth, versions, uploads, and jobs are documented with zero annotation. See the [endpoint list](https://payload-plugin-openapi.seshuk.im/v1/reference/endpoints).
23
+ - **Full spec from your config** — collections, globals, auth, versions, uploads, jobs, and the endpoints of official Payload plugins are documented with zero annotation. See the [endpoint list](https://payload-plugin-openapi.seshuk.im/v1/reference/endpoints).
24
24
  - **Interactive docs included** — mount Scalar or Swagger UI, or both on different paths.
25
25
  - **Native metadata** — document custom endpoints and refine field schemas through Payload's own `custom.openapi` key. No wrapper, no separate registry.
26
26
  - **Precise filtering** — choose exactly which entities and operations end up in the spec.
@@ -31,7 +31,7 @@
31
31
 
32
32
  ## Quick start
33
33
 
34
- Requires **Payload 4.0.0-canary.38**, **Next.js 16.4 or later** and **Node.js 24.15 or later**. On Payload 3, use `@seshuk/payload-plugin-openapi@0`.
34
+ Requires **Payload 4.0.0-beta.0 or later**, **Next.js 16.4 or later** and **Node.js 24.15 or later**. On Payload 3, use `@seshuk/payload-plugin-openapi@0`.
35
35
 
36
36
  ### Install
37
37
 
@@ -39,15 +39,15 @@ Requires **Payload 4.0.0-canary.38**, **Next.js 16.4 or later** and **Node.js 24
39
39
  npm install @seshuk/payload-plugin-openapi@beta
40
40
  ```
41
41
 
42
- v1 is in beta under the `beta` npm tag, and Payload 4 is published under `canary`.
42
+ v1 is in beta under the `beta` npm tag, and Payload 4 is published under `beta`.
43
43
 
44
44
  ### Configure
45
45
 
46
46
  Add the plugin to your Payload config, plus a docs UI renderer:
47
47
 
48
48
  ```typescript
49
- import { buildConfig } from 'payload'
50
49
  import { openapi, scalar } from '@seshuk/payload-plugin-openapi'
50
+ import { buildConfig } from 'payload'
51
51
 
52
52
  export default buildConfig({
53
53
  plugins: [
@@ -121,6 +121,10 @@ Full docs are at **<https://payload-plugin-openapi.seshuk.im/>**:
121
121
  - [CLI — `openapi:generate`](https://payload-plugin-openapi.seshuk.im/v1/cli/generate)
122
122
  - [Examples](https://payload-plugin-openapi.seshuk.im/v1/guides/examples)
123
123
 
124
+ ## Official plugins
125
+
126
+ When you install an official Payload plugin, the spec documents the REST endpoints it mounts: `@payloadcms/plugin-ecommerce`, `plugin-stripe`, `plugin-mcp`, `plugin-seo`, `plugin-search`, `plugin-multi-tenant`, `plugin-import-export` and `storage-r2`. There is nothing to configure. Filter them with `excludeOperations: [{ plugin: '@payloadcms/plugin-stripe' }]` or `{ kind: 'plugin' }`. See [Official plugins](https://payload-plugin-openapi.seshuk.im/v1/reference/endpoints#official-plugins).
127
+
124
128
  ## For plugin authors
125
129
 
126
130
  If you maintain a Payload plugin, attach a `custom.openapi` Operation Object to the endpoints you add and they show up in the generated spec — no dependency on this package, and nothing for your users to wire up. The same key works on fields. If this plugin isn't installed, the metadata is inert. See [For plugin authors](https://payload-plugin-openapi.seshuk.im/v1/guides/plugin-authors).
@@ -6,17 +6,29 @@ import { PLUGIN_NAME } from "../../shared/constants.js";
6
6
  import { makeT } from "../../shared/translations/index.js";
7
7
  import { buildAuthPaths } from "./paths/auth.js";
8
8
  import { buildParamSchemas, buildQueryOperationsSchema, collectionHasFilters } from "./params.js";
9
+ import { filterOperations, shouldIncludeCollection, shouldIncludeGlobal, stripPluginKeys } from "./filters.js";
10
+ import { applySecurity, evaluateAccess, resolveEntitySecurity, securedRequirement } from "./security.js";
9
11
  import { buildCollectionPaths } from "./paths/collections.js";
10
- import { buildCustomEndpointPaths } from "./paths/custom.js";
12
+ import { buildCustomEndpointPaths, getOpenapiMeta } from "./paths/custom.js";
11
13
  import { buildGlobalPaths } from "./paths/globals.js";
12
14
  import { buildJobsPaths } from "./paths/jobs.js";
13
15
  import { buildSystemPaths } from "./paths/system.js";
14
16
  import { buildVersionPaths, versionComponentSchemas } from "./paths/versions.js";
17
+ import { OFFICIAL_PLUGINS } from "./plugins/index.js";
15
18
  import { buildBlockSchema, buildEntitySchemas } from "./entitySchemas.js";
16
- import { filterOperations, shouldIncludeCollection, shouldIncludeGlobal } from "./filters.js";
17
19
  import { applyHierarchy } from "./hierarchy.js";
18
- import { applySecurity, evaluateAccess, resolveEntitySecurity, securedRequirement } from "./security.js";
19
20
  import { getTranslation } from "@payloadcms/translations";
21
+ const OPERATION_METHODS = /* @__PURE__ */ new Set([
22
+ "get",
23
+ "put",
24
+ "post",
25
+ "delete",
26
+ "options",
27
+ "head",
28
+ "patch",
29
+ "trace",
30
+ "query"
31
+ ]);
20
32
  const resolveDescription = (description, ctx) => {
21
33
  if (description == null) return void 0;
22
34
  const resolved = getTranslation(description, ctx.i18n);
@@ -39,15 +51,17 @@ const buildDocument = async (input) => {
39
51
  const schemas = {};
40
52
  const { filters } = options;
41
53
  const login = options.serve && options.interactiveAuth.enabled;
42
- const finalize = async (group, kind, slug) => applySecurity({
54
+ const finalize = async (group, kind, slug, plugin) => applySecurity({
43
55
  paths: await filterOperations({
44
56
  paths: group,
45
57
  slug,
46
58
  kind,
47
- filters
59
+ filters,
60
+ plugin
48
61
  }),
49
62
  slug,
50
63
  kind,
64
+ plugin,
51
65
  security: options.security,
52
66
  login
53
67
  });
@@ -192,12 +206,12 @@ const buildDocument = async (input) => {
192
206
  logger.warn(`${PLUGIN_NAME}: skipped global "${global.slug}": ${error.message}`);
193
207
  }
194
208
  if (filters.includeCustom) try {
195
- Object.assign(paths, await finalize(buildCustomEndpointPaths({
209
+ Object.assign(paths, stripPluginKeys(await finalize(buildCustomEndpointPaths({
196
210
  config,
197
211
  collections,
198
212
  globals,
199
213
  ctx
200
- }), "custom"));
214
+ }), "custom")));
201
215
  } catch (error) {
202
216
  logger.warn(`${PLUGIN_NAME}: failed to collect custom endpoints: ${error.message}`);
203
217
  }
@@ -215,14 +229,43 @@ const buildDocument = async (input) => {
215
229
  logger.warn(`${PLUGIN_NAME}: failed to add jobs endpoint: ${error.message}`);
216
230
  }
217
231
  const uploadSlugs = collections.filter((c) => c.upload).map((c) => c.slug);
232
+ const reorderMounted = config.endpoints?.some((e) => e.method === "post" && e.path === "/reorder" && !getOpenapiMeta(e));
233
+ const orderableJoinTargets = new Set(input.collections.flatMap((c) => Object.entries(c.joins ?? {}).filter(([, joins]) => joins.some((j) => j.field.orderable)).map(([slug]) => slug)));
234
+ const reorderSlugs = reorderMounted ? collections.filter((c) => c.orderable || orderableJoinTargets.has(c.slug)).map((c) => c.slug) : [];
218
235
  Object.assign(paths, await finalize(buildSystemPaths({
219
236
  ctx,
220
237
  access,
221
- uploadSlugs
238
+ uploadSlugs,
239
+ reorderSlugs
222
240
  }), "system"));
241
+ const pluginTags = [];
242
+ for (const plugin of OFFICIAL_PLUGINS) try {
243
+ const installed = config.plugins?.find((p) => p.slug === plugin.slug);
244
+ if (!(plugin.installed?.(config) ?? installed)) continue;
245
+ const groups = plugin.build({
246
+ config,
247
+ collections,
248
+ ctx,
249
+ options: installed?.options,
250
+ schemas,
251
+ t
252
+ });
253
+ for (const group of groups) {
254
+ const finalized = await finalize(group.paths, "plugin", group.slug, plugin.slug);
255
+ if (Object.keys(finalized).length === 0) continue;
256
+ for (const [path, item] of Object.entries(finalized)) paths[path] = {
257
+ ...paths[path],
258
+ ...item
259
+ };
260
+ if (!pluginTags.includes(plugin.tag)) pluginTags.push(plugin.tag);
261
+ }
262
+ } catch (error) {
263
+ logger.warn(`${PLUGIN_NAME}: skipped plugin "${plugin.slug}": ${error.message}`);
264
+ }
223
265
  const systemTags = [];
224
266
  if (hasJobs) systemTags.push("Jobs");
225
267
  if (uploadSlugs.length > 0) systemTags.push("Uploads");
268
+ if (reorderSlugs.length > 0) systemTags.push("Reorder");
226
269
  if (access) systemTags.push("Access");
227
270
  const supportedTimezones = config.admin?.timezones?.supportedTimezones;
228
271
  if (Array.isArray(supportedTimezones) && supportedTimezones.length > 0) schemas[schemaName("supportedTimezones")] = {
@@ -258,13 +301,23 @@ const buildDocument = async (input) => {
258
301
  collections: collectionTagInfos,
259
302
  globals: globalTagInfos,
260
303
  systemTags,
304
+ pluginTags,
261
305
  t,
262
306
  nested: options.nestedTags
263
307
  }),
264
308
  "x-doc-languages": ctx.docLanguages
265
309
  };
310
+ if (options.extensions.some((ext) => ext.transform)) doc = structuredClone(doc);
266
311
  for (const ext of options.extensions) {
267
- if (ext.paths) doc.paths = deepMerge(doc.paths ?? {}, ext.paths);
312
+ if (ext.paths) {
313
+ const base = { ...doc.paths };
314
+ for (const [path, item] of Object.entries(ext.paths)) {
315
+ const current = base[path];
316
+ if (!current || !item) continue;
317
+ base[path] = Object.fromEntries(Object.entries(current).filter(([key]) => !(OPERATION_METHODS.has(key) && key in item)));
318
+ }
319
+ doc.paths = deepMerge(base, ext.paths);
320
+ }
268
321
  if (ext.components) doc.components = deepMerge(doc.components ?? {}, ext.components);
269
322
  if (ext.tags) {
270
323
  const seen = new Set((doc.tags ?? []).map((tag) => tag.name));
@@ -1 +1 @@
1
- {"version":3,"file":"buildDocument.js","names":[],"sources":["../../../src/server/spec/buildDocument.ts"],"sourcesContent":["import { getTranslation } from '@payloadcms/translations'\nimport type {\n ComponentsObject,\n Document,\n PathsObject,\n SchemaObject,\n SecuritySchemeObject,\n TagObject,\n} from '@scalar/openapi-types/3.2'\nimport type {\n Access,\n BasePayload,\n Field,\n SanitizedCollectionConfig,\n SanitizedConfig,\n SanitizedGlobalConfig,\n} from 'payload'\n\nimport { buildAuthPaths } from '@/server/spec/paths/auth.js'\nimport { buildCollectionPaths } from '@/server/spec/paths/collections.js'\nimport { buildCustomEndpointPaths } from '@/server/spec/paths/custom.js'\nimport { buildGlobalPaths } from '@/server/spec/paths/globals.js'\nimport { buildJobsPaths } from '@/server/spec/paths/jobs.js'\nimport { buildSystemPaths } from '@/server/spec/paths/system.js'\nimport { buildVersionPaths, versionComponentSchemas } from '@/server/spec/paths/versions.js'\nimport { PLUGIN_NAME } from '@/shared/constants.js'\nimport { makeT } from '@/shared/translations/index.js'\nimport type { BuildContext, OperationKind, ResolvedOptions } from '@/shared/types/index.js'\nimport { deepMerge } from '@/shared/utils.js'\n\nimport {\n ERROR_SCHEMA_NAME,\n INTERACTIVE_SCHEME_NAME,\n SECURITY_SCHEME_NAME,\n buildErrorResponseSchema,\n buildListEnvelopeSchema,\n interactiveSecurityScheme,\n securityScheme,\n} from './components.js'\nimport { buildBlockSchema, buildEntitySchemas } from './entitySchemas.js'\nimport { filterOperations, shouldIncludeCollection, shouldIncludeGlobal } from './filters.js'\nimport { applyHierarchy } from './hierarchy.js'\nimport {\n blockSchemaName,\n createSchemaName,\n globalSchemaName,\n joinsSchemaName,\n listSchemaName,\n populateSchemaName,\n querySchemaName,\n schemaName,\n selectSchemaName,\n updateSchemaName,\n} from './names.js'\nimport { buildParamSchemas, buildQueryOperationsSchema, collectionHasFilters } from './params.js'\nimport { applySecurity, evaluateAccess, resolveEntitySecurity, securedRequirement } from './security.js'\nimport { buildTagHierarchy, type CollectionTagInfo, type GlobalTagInfo, type SystemTag } from './tags.js'\n\nconst resolveDescription = (description: unknown, ctx: BuildContext): string | undefined => {\n if (description == null) return undefined\n const resolved: unknown = getTranslation(description as string, ctx.i18n)\n return typeof resolved === 'string' && resolved.length > 0 ? resolved : undefined\n}\n\nconst registerParamSchemas = (\n schemas: Record<string, SchemaObject>,\n base: string,\n fields: Field[],\n ctx: BuildContext,\n): void => {\n const { select, populate, joins } = buildParamSchemas({ fields, ctx })\n schemas[selectSchemaName(base)] = select\n if (populate) schemas[populateSchemaName(base)] = populate\n if (joins) schemas[joinsSchemaName(base)] = joins\n}\n\nexport interface BuildInput {\n options: ResolvedOptions\n servers: { url: string }[]\n collections: SanitizedCollectionConfig[]\n globals: SanitizedGlobalConfig[]\n config: SanitizedConfig\n ctx: BuildContext\n payload: BasePayload\n}\n\nexport const buildDocument = async (input: BuildInput): Promise<Document> => {\n const { options, ctx, config, payload } = input\n const { logger } = payload\n const t = makeT(ctx.i18n)\n const paths: PathsObject = {}\n const schemas: Record<string, SchemaObject> = {}\n\n const { filters } = options\n const login = options.serve && options.interactiveAuth.enabled\n const finalize = async (group: PathsObject, kind: OperationKind, slug?: string): Promise<PathsObject> =>\n applySecurity({\n paths: await filterOperations({ paths: group, slug, kind, filters }),\n slug,\n kind,\n security: options.security,\n login,\n })\n const access = filters.includeAuth && filters.includeAdminAuth\n const collections = input.collections.filter((c) => shouldIncludeCollection(c, filters))\n const globals = input.globals.filter((g) => shouldIncludeGlobal(g, filters))\n\n const collectionTagInfos: CollectionTagInfo[] = []\n const globalTagInfos: GlobalTagInfo[] = []\n\n for (const block of config.blocks ?? []) {\n try {\n schemas[blockSchemaName(block.slug)] = buildBlockSchema(block, config)\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: skipped block \"${block.slug}\": ${(error as Error).message}`)\n }\n }\n\n for (const collection of collections) {\n try {\n const { read, create, update } = await buildEntitySchemas({ entity: collection, config, ctx })\n const base = schemaName(collection.slug)\n collectionTagInfos.push({\n base,\n hasAuth: filters.includeAuth && Boolean(collection.auth),\n hasVersions: Boolean(filters.includeVersions && collection.versions),\n description: resolveDescription(collection.admin?.description, ctx),\n })\n schemas[base] = read\n schemas[createSchemaName(base)] = create\n schemas[updateSchemaName(base)] = update\n schemas[listSchemaName(base)] = buildListEnvelopeSchema(base)\n if (collectionHasFilters(collection.fields)) {\n schemas[querySchemaName(base)] = buildQueryOperationsSchema({ base, fields: collection.fields, ctx })\n }\n registerParamSchemas(schemas, base, collection.fields, ctx)\n\n const security = await resolveEntitySecurity({\n entity: collection,\n operations: ['read', 'create', 'update', 'delete', 'validate', 'readVersions'],\n locale: ctx.locales[0],\n baseAccess: config.baseAccess,\n })\n const collectionPaths: PathsObject = { ...buildCollectionPaths({ collection, ctx, security, access }) }\n\n if (filters.includeAuth) {\n Object.assign(\n collectionPaths,\n buildAuthPaths({\n collection,\n ctx,\n includeAdmin: filters.includeAdminAuth,\n nestedTags: options.nestedTags,\n }),\n )\n }\n\n if (filters.includeVersions && collection.versions) {\n const { version, versionList } = versionComponentSchemas({ docBase: base, base, idType: ctx.defaultIDType })\n schemas[`${base}Version`] = version\n schemas[`${base}VersionList`] = versionList\n Object.assign(\n collectionPaths,\n buildVersionPaths({\n entity: collection,\n pathBase: `${ctx.apiRoute}/${collection.slug}`,\n ctx,\n schemaBase: base,\n nestedTags: options.nestedTags,\n security,\n }),\n )\n }\n\n applyHierarchy({ collection, base, paths: collectionPaths, schemas, ctx })\n Object.assign(paths, await finalize(collectionPaths, 'collection', collection.slug))\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: skipped collection \"${collection.slug}\": ${(error as Error).message}`)\n }\n }\n\n for (const global of globals) {\n try {\n const { read, update } = await buildEntitySchemas({ entity: global, config, ctx })\n const gbase = globalSchemaName(global.slug)\n globalTagInfos.push({\n base: gbase,\n hasVersions: Boolean(filters.includeVersions && global.versions),\n description: resolveDescription(global.admin?.description, ctx),\n })\n schemas[gbase] = read\n schemas[updateSchemaName(gbase)] = update\n registerParamSchemas(schemas, gbase, global.fields, ctx)\n\n const security = await resolveEntitySecurity({\n entity: global,\n operations: ['read', 'update', 'validate', 'readVersions'],\n locale: ctx.locales[0],\n baseAccess: config.baseAccess,\n })\n const globalPaths: PathsObject = { ...buildGlobalPaths({ global, ctx, security, access }) }\n\n if (filters.includeVersions && global.versions) {\n const { version, versionList } = versionComponentSchemas({\n docBase: gbase,\n base: gbase,\n idType: ctx.defaultIDType,\n })\n schemas[`${gbase}Version`] = version\n schemas[`${gbase}VersionList`] = versionList\n Object.assign(\n globalPaths,\n buildVersionPaths({\n entity: global,\n pathBase: `${ctx.apiRoute}/globals/${global.slug}`,\n ctx,\n schemaBase: gbase,\n nestedTags: options.nestedTags,\n security,\n global: true,\n }),\n )\n }\n\n Object.assign(paths, await finalize(globalPaths, 'global', global.slug))\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: skipped global \"${global.slug}\": ${(error as Error).message}`)\n }\n }\n\n if (filters.includeCustom) {\n try {\n Object.assign(paths, await finalize(buildCustomEndpointPaths({ config, collections, globals, ctx }), 'custom'))\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: failed to collect custom endpoints: ${(error as Error).message}`)\n }\n }\n\n const jobsConfig = config.jobs as Record<string, unknown> | undefined\n const hasJobs =\n filters.includeJobs &&\n Boolean((jobsConfig?.tasks as unknown[])?.length || (jobsConfig?.workflows as unknown[])?.length)\n\n if (filters.includeJobs) {\n try {\n const runAccess = (jobsConfig?.access as { run?: Access } | undefined)?.run\n const jobsSecurity = (await evaluateAccess(runAccess, { baseAccess: config.baseAccess }))\n ? undefined\n : securedRequirement()\n Object.assign(paths, await finalize(buildJobsPaths({ config, ctx, security: jobsSecurity }), 'jobs'))\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: failed to add jobs endpoint: ${(error as Error).message}`)\n }\n }\n\n const uploadSlugs = collections.filter((c) => c.upload).map((c) => c.slug)\n Object.assign(paths, await finalize(buildSystemPaths({ ctx, access, uploadSlugs }), 'system'))\n\n const systemTags: SystemTag[] = []\n if (hasJobs) systemTags.push('Jobs')\n if (uploadSlugs.length > 0) systemTags.push('Uploads')\n if (access) systemTags.push('Access')\n\n const supportedTimezones = config.admin?.timezones?.supportedTimezones\n if (Array.isArray(supportedTimezones) && supportedTimezones.length > 0) {\n schemas[schemaName('supportedTimezones')] = {\n type: 'string',\n description: t('schemaSupportedTimezones'),\n enum: supportedTimezones.map((tz) => (typeof tz === 'string' ? tz : tz.value)),\n }\n }\n\n schemas[ERROR_SCHEMA_NAME] = buildErrorResponseSchema()\n\n const cookiePrefix = config.cookiePrefix || 'payload'\n const securitySchemes: Record<string, SecuritySchemeObject> = {\n [SECURITY_SCHEME_NAME]: securityScheme({ cookiePrefix, t }),\n }\n if (login) {\n securitySchemes[INTERACTIVE_SCHEME_NAME] = interactiveSecurityScheme({\n tokenUrl: `${ctx.apiRoute}${options.interactiveAuth.path}`,\n t,\n })\n }\n\n const localeNote =\n ctx.locales.length > 0\n ? `\\n\\n## ${t('localizationHeading')}\\n\\n` +\n t('localizationNote', {\n locales: ctx.locales.map((l) => `\\`${l}\\``).join(', '),\n })\n : ''\n const docLanguagesNote =\n ctx.docLanguages.length > 1\n ? `\\n\\n${t('docLanguagesNote', { languages: ctx.docLanguages.map((l) => `\\`${l}\\``).join(', ') })}`\n : ''\n const info = {\n ...options.info,\n description:\n `${resolveDescription(options.info.description, ctx) ?? ''}${localeNote}${docLanguagesNote}`.trim() || undefined,\n }\n\n let doc = {\n openapi: '3.2.0',\n info,\n servers: input.servers,\n paths,\n components: {\n schemas,\n securitySchemes,\n },\n tags: buildTagHierarchy({\n collections: collectionTagInfos,\n globals: globalTagInfos,\n systemTags,\n t,\n nested: options.nestedTags,\n }),\n 'x-doc-languages': ctx.docLanguages,\n } as Document\n\n for (const ext of options.extensions) {\n if (ext.paths) {\n doc.paths = deepMerge(doc.paths ?? {}, ext.paths) as PathsObject\n }\n if (ext.components) {\n doc.components = deepMerge(\n (doc.components ?? {}) as Record<string, unknown>,\n ext.components as Record<string, unknown>,\n ) as ComponentsObject\n }\n if (ext.tags) {\n const seen = new Set((doc.tags ?? []).map((tag: TagObject) => tag.name))\n doc.tags = [...(doc.tags ?? []), ...ext.tags.filter((tag: TagObject) => !seen.has(tag.name))]\n }\n if (ext.transform) {\n doc = await ext.transform({ ...ctx, doc, payload, options })\n if (typeof doc?.openapi !== 'string' || 'payload' in doc) {\n throw new Error(`[${PLUGIN_NAME}] extensions[].transform must return the document, it gets ({ doc, payload })`)\n }\n }\n }\n\n return doc\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"buildDocument.js","names":[],"sources":["../../../src/server/spec/buildDocument.ts"],"sourcesContent":["import { getTranslation } from '@payloadcms/translations'\nimport type {\n ComponentsObject,\n Document,\n PathsObject,\n SchemaObject,\n SecuritySchemeObject,\n TagObject,\n} from '@scalar/openapi-types/3.2'\nimport type {\n Access,\n BasePayload,\n Field,\n SanitizedCollectionConfig,\n SanitizedConfig,\n SanitizedGlobalConfig,\n} from 'payload'\n\nimport { buildAuthPaths } from '@/server/spec/paths/auth.js'\nimport { buildCollectionPaths } from '@/server/spec/paths/collections.js'\nimport { buildCustomEndpointPaths, getOpenapiMeta } from '@/server/spec/paths/custom.js'\nimport { buildGlobalPaths } from '@/server/spec/paths/globals.js'\nimport { buildJobsPaths } from '@/server/spec/paths/jobs.js'\nimport { buildSystemPaths } from '@/server/spec/paths/system.js'\nimport { buildVersionPaths, versionComponentSchemas } from '@/server/spec/paths/versions.js'\nimport { OFFICIAL_PLUGINS } from '@/server/spec/plugins/index.js'\nimport { PLUGIN_NAME } from '@/shared/constants.js'\nimport { makeT } from '@/shared/translations/index.js'\nimport type { BuildContext, OperationKind, ResolvedOptions } from '@/shared/types/index.js'\nimport { deepMerge } from '@/shared/utils.js'\n\nimport {\n ERROR_SCHEMA_NAME,\n INTERACTIVE_SCHEME_NAME,\n SECURITY_SCHEME_NAME,\n buildErrorResponseSchema,\n buildListEnvelopeSchema,\n interactiveSecurityScheme,\n securityScheme,\n} from './components.js'\nimport { buildBlockSchema, buildEntitySchemas } from './entitySchemas.js'\nimport { filterOperations, shouldIncludeCollection, shouldIncludeGlobal, stripPluginKeys } from './filters.js'\nimport { applyHierarchy } from './hierarchy.js'\nimport {\n blockSchemaName,\n createSchemaName,\n globalSchemaName,\n joinsSchemaName,\n listSchemaName,\n populateSchemaName,\n querySchemaName,\n schemaName,\n selectSchemaName,\n updateSchemaName,\n} from './names.js'\nimport { buildParamSchemas, buildQueryOperationsSchema, collectionHasFilters } from './params.js'\nimport { applySecurity, evaluateAccess, resolveEntitySecurity, securedRequirement } from './security.js'\nimport { buildTagHierarchy, type CollectionTagInfo, type GlobalTagInfo, type SystemTag } from './tags.js'\n\nconst OPERATION_METHODS = new Set(['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace', 'query'])\n\nconst resolveDescription = (description: unknown, ctx: BuildContext): string | undefined => {\n if (description == null) return undefined\n const resolved: unknown = getTranslation(description as string, ctx.i18n)\n return typeof resolved === 'string' && resolved.length > 0 ? resolved : undefined\n}\n\nconst registerParamSchemas = (\n schemas: Record<string, SchemaObject>,\n base: string,\n fields: Field[],\n ctx: BuildContext,\n): void => {\n const { select, populate, joins } = buildParamSchemas({ fields, ctx })\n schemas[selectSchemaName(base)] = select\n if (populate) schemas[populateSchemaName(base)] = populate\n if (joins) schemas[joinsSchemaName(base)] = joins\n}\n\nexport interface BuildInput {\n options: ResolvedOptions\n servers: { url: string }[]\n collections: SanitizedCollectionConfig[]\n globals: SanitizedGlobalConfig[]\n config: SanitizedConfig\n ctx: BuildContext\n payload: BasePayload\n}\n\nexport const buildDocument = async (input: BuildInput): Promise<Document> => {\n const { options, ctx, config, payload } = input\n const { logger } = payload\n const t = makeT(ctx.i18n)\n const paths: PathsObject = {}\n const schemas: Record<string, SchemaObject> = {}\n\n const { filters } = options\n const login = options.serve && options.interactiveAuth.enabled\n const finalize = async (\n group: PathsObject,\n kind: OperationKind,\n slug?: string,\n plugin?: string,\n ): Promise<PathsObject> =>\n applySecurity({\n paths: await filterOperations({ paths: group, slug, kind, filters, plugin }),\n slug,\n kind,\n plugin,\n security: options.security,\n login,\n })\n const access = filters.includeAuth && filters.includeAdminAuth\n const collections = input.collections.filter((c) => shouldIncludeCollection(c, filters))\n const globals = input.globals.filter((g) => shouldIncludeGlobal(g, filters))\n\n const collectionTagInfos: CollectionTagInfo[] = []\n const globalTagInfos: GlobalTagInfo[] = []\n\n for (const block of config.blocks ?? []) {\n try {\n schemas[blockSchemaName(block.slug)] = buildBlockSchema(block, config)\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: skipped block \"${block.slug}\": ${(error as Error).message}`)\n }\n }\n\n for (const collection of collections) {\n try {\n const { read, create, update } = await buildEntitySchemas({ entity: collection, config, ctx })\n const base = schemaName(collection.slug)\n collectionTagInfos.push({\n base,\n hasAuth: filters.includeAuth && Boolean(collection.auth),\n hasVersions: Boolean(filters.includeVersions && collection.versions),\n description: resolveDescription(collection.admin?.description, ctx),\n })\n schemas[base] = read\n schemas[createSchemaName(base)] = create\n schemas[updateSchemaName(base)] = update\n schemas[listSchemaName(base)] = buildListEnvelopeSchema(base)\n if (collectionHasFilters(collection.fields)) {\n schemas[querySchemaName(base)] = buildQueryOperationsSchema({ base, fields: collection.fields, ctx })\n }\n registerParamSchemas(schemas, base, collection.fields, ctx)\n\n const security = await resolveEntitySecurity({\n entity: collection,\n operations: ['read', 'create', 'update', 'delete', 'validate', 'readVersions'],\n locale: ctx.locales[0],\n baseAccess: config.baseAccess,\n })\n const collectionPaths: PathsObject = { ...buildCollectionPaths({ collection, ctx, security, access }) }\n\n if (filters.includeAuth) {\n Object.assign(\n collectionPaths,\n buildAuthPaths({\n collection,\n ctx,\n includeAdmin: filters.includeAdminAuth,\n nestedTags: options.nestedTags,\n }),\n )\n }\n\n if (filters.includeVersions && collection.versions) {\n const { version, versionList } = versionComponentSchemas({ docBase: base, base, idType: ctx.defaultIDType })\n schemas[`${base}Version`] = version\n schemas[`${base}VersionList`] = versionList\n Object.assign(\n collectionPaths,\n buildVersionPaths({\n entity: collection,\n pathBase: `${ctx.apiRoute}/${collection.slug}`,\n ctx,\n schemaBase: base,\n nestedTags: options.nestedTags,\n security,\n }),\n )\n }\n\n applyHierarchy({ collection, base, paths: collectionPaths, schemas, ctx })\n Object.assign(paths, await finalize(collectionPaths, 'collection', collection.slug))\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: skipped collection \"${collection.slug}\": ${(error as Error).message}`)\n }\n }\n\n for (const global of globals) {\n try {\n const { read, update } = await buildEntitySchemas({ entity: global, config, ctx })\n const gbase = globalSchemaName(global.slug)\n globalTagInfos.push({\n base: gbase,\n hasVersions: Boolean(filters.includeVersions && global.versions),\n description: resolveDescription(global.admin?.description, ctx),\n })\n schemas[gbase] = read\n schemas[updateSchemaName(gbase)] = update\n registerParamSchemas(schemas, gbase, global.fields, ctx)\n\n const security = await resolveEntitySecurity({\n entity: global,\n operations: ['read', 'update', 'validate', 'readVersions'],\n locale: ctx.locales[0],\n baseAccess: config.baseAccess,\n })\n const globalPaths: PathsObject = { ...buildGlobalPaths({ global, ctx, security, access }) }\n\n if (filters.includeVersions && global.versions) {\n const { version, versionList } = versionComponentSchemas({\n docBase: gbase,\n base: gbase,\n idType: ctx.defaultIDType,\n })\n schemas[`${gbase}Version`] = version\n schemas[`${gbase}VersionList`] = versionList\n Object.assign(\n globalPaths,\n buildVersionPaths({\n entity: global,\n pathBase: `${ctx.apiRoute}/globals/${global.slug}`,\n ctx,\n schemaBase: gbase,\n nestedTags: options.nestedTags,\n security,\n global: true,\n }),\n )\n }\n\n Object.assign(paths, await finalize(globalPaths, 'global', global.slug))\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: skipped global \"${global.slug}\": ${(error as Error).message}`)\n }\n }\n\n if (filters.includeCustom) {\n try {\n Object.assign(\n paths,\n stripPluginKeys(await finalize(buildCustomEndpointPaths({ config, collections, globals, ctx }), 'custom')),\n )\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: failed to collect custom endpoints: ${(error as Error).message}`)\n }\n }\n\n const jobsConfig = config.jobs as Record<string, unknown> | undefined\n const hasJobs =\n filters.includeJobs &&\n Boolean((jobsConfig?.tasks as unknown[])?.length || (jobsConfig?.workflows as unknown[])?.length)\n\n if (filters.includeJobs) {\n try {\n const runAccess = (jobsConfig?.access as { run?: Access } | undefined)?.run\n const jobsSecurity = (await evaluateAccess(runAccess, { baseAccess: config.baseAccess }))\n ? undefined\n : securedRequirement()\n Object.assign(paths, await finalize(buildJobsPaths({ config, ctx, security: jobsSecurity }), 'jobs'))\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: failed to add jobs endpoint: ${(error as Error).message}`)\n }\n }\n\n const uploadSlugs = collections.filter((c) => c.upload).map((c) => c.slug)\n const reorderMounted = config.endpoints?.some(\n (e) => e.method === 'post' && e.path === '/reorder' && !getOpenapiMeta(e),\n )\n const orderableJoinTargets = new Set(\n input.collections.flatMap((c) =>\n Object.entries(c.joins ?? {})\n .filter(([, joins]) => joins.some((j) => j.field.orderable))\n .map(([slug]) => slug),\n ),\n )\n const reorderSlugs = reorderMounted\n ? collections.filter((c) => c.orderable || orderableJoinTargets.has(c.slug)).map((c) => c.slug)\n : []\n Object.assign(paths, await finalize(buildSystemPaths({ ctx, access, uploadSlugs, reorderSlugs }), 'system'))\n\n const pluginTags: string[] = []\n for (const plugin of OFFICIAL_PLUGINS) {\n try {\n const installed = config.plugins?.find((p) => p.slug === plugin.slug)\n if (!(plugin.installed?.(config) ?? installed)) continue\n const groups = plugin.build({ config, collections, ctx, options: installed?.options, schemas, t })\n for (const group of groups) {\n const finalized = await finalize(group.paths, 'plugin', group.slug, plugin.slug)\n if (Object.keys(finalized).length === 0) continue\n for (const [path, item] of Object.entries(finalized)) paths[path] = { ...paths[path], ...item }\n if (!pluginTags.includes(plugin.tag)) pluginTags.push(plugin.tag)\n }\n } catch (error) {\n logger.warn(`${PLUGIN_NAME}: skipped plugin \"${plugin.slug}\": ${(error as Error).message}`)\n }\n }\n\n const systemTags: SystemTag[] = []\n if (hasJobs) systemTags.push('Jobs')\n if (uploadSlugs.length > 0) systemTags.push('Uploads')\n if (reorderSlugs.length > 0) systemTags.push('Reorder')\n if (access) systemTags.push('Access')\n\n const supportedTimezones = config.admin?.timezones?.supportedTimezones\n if (Array.isArray(supportedTimezones) && supportedTimezones.length > 0) {\n schemas[schemaName('supportedTimezones')] = {\n type: 'string',\n description: t('schemaSupportedTimezones'),\n enum: supportedTimezones.map((tz) => (typeof tz === 'string' ? tz : tz.value)),\n }\n }\n\n schemas[ERROR_SCHEMA_NAME] = buildErrorResponseSchema()\n\n const cookiePrefix = config.cookiePrefix || 'payload'\n const securitySchemes: Record<string, SecuritySchemeObject> = {\n [SECURITY_SCHEME_NAME]: securityScheme({ cookiePrefix, t }),\n }\n if (login) {\n securitySchemes[INTERACTIVE_SCHEME_NAME] = interactiveSecurityScheme({\n tokenUrl: `${ctx.apiRoute}${options.interactiveAuth.path}`,\n t,\n })\n }\n\n const localeNote =\n ctx.locales.length > 0\n ? `\\n\\n## ${t('localizationHeading')}\\n\\n` +\n t('localizationNote', {\n locales: ctx.locales.map((l) => `\\`${l}\\``).join(', '),\n })\n : ''\n const docLanguagesNote =\n ctx.docLanguages.length > 1\n ? `\\n\\n${t('docLanguagesNote', { languages: ctx.docLanguages.map((l) => `\\`${l}\\``).join(', ') })}`\n : ''\n const info = {\n ...options.info,\n description:\n `${resolveDescription(options.info.description, ctx) ?? ''}${localeNote}${docLanguagesNote}`.trim() || undefined,\n }\n\n let doc = {\n openapi: '3.2.0',\n info,\n servers: input.servers,\n paths,\n components: {\n schemas,\n securitySchemes,\n },\n tags: buildTagHierarchy({\n collections: collectionTagInfos,\n globals: globalTagInfos,\n systemTags,\n pluginTags,\n t,\n nested: options.nestedTags,\n }),\n 'x-doc-languages': ctx.docLanguages,\n } as Document\n\n if (options.extensions.some((ext) => ext.transform)) doc = structuredClone(doc)\n\n for (const ext of options.extensions) {\n if (ext.paths) {\n const base: PathsObject = { ...doc.paths }\n for (const [path, item] of Object.entries(ext.paths)) {\n const current = base[path]\n if (!current || !item) continue\n base[path] = Object.fromEntries(\n Object.entries(current).filter(([key]) => !(OPERATION_METHODS.has(key) && key in item)),\n )\n }\n doc.paths = deepMerge(base, ext.paths) as PathsObject\n }\n if (ext.components) {\n doc.components = deepMerge(\n (doc.components ?? {}) as Record<string, unknown>,\n ext.components as Record<string, unknown>,\n ) as ComponentsObject\n }\n if (ext.tags) {\n const seen = new Set((doc.tags ?? []).map((tag: TagObject) => tag.name))\n doc.tags = [...(doc.tags ?? []), ...ext.tags.filter((tag: TagObject) => !seen.has(tag.name))]\n }\n if (ext.transform) {\n doc = await ext.transform({ ...ctx, doc, payload, options })\n if (typeof doc?.openapi !== 'string' || 'payload' in doc) {\n throw new Error(`[${PLUGIN_NAME}] extensions[].transform must return the document, it gets ({ doc, payload })`)\n }\n }\n }\n\n return doc\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"components.js","names":[],"sources":["../../../src/server/spec/components.ts"],"sourcesContent":["import type {\n OperationObject,\n ParameterObject,\n ReferenceObject,\n RequestBodyObject,\n ResponseObject,\n ResponsesObject,\n SchemaObject,\n SecurityRequirementObject,\n SecuritySchemeObject,\n} from '@scalar/openapi-types/3.2'\n\nimport type { Translate } from '@/shared/translations/types.js'\n\nimport { refTo } from './names.js'\n\ntype SchemaOrRef = SchemaObject | ReferenceObject\n\nexport const nullableType = (type: 'integer' | 'string' | 'number' | 'boolean'): SchemaObject => ({\n type: [type, 'null'],\n})\n\nexport const jsonResponse = (description: string, schema: SchemaOrRef): ResponseObject => ({\n description,\n content: { 'application/json': { schema } },\n})\n\nexport const jsonOk = (description: string, schema: SchemaOrRef): ResponsesObject => ({\n '200': jsonResponse(description, schema),\n})\n\nexport const jsonBody = (schema: SchemaOrRef): RequestBodyObject => ({\n required: true,\n content: { 'application/json': { schema } },\n})\n\nexport const messageResponse = (description: string): ResponsesObject =>\n jsonOk(description, { type: 'object', properties: { message: { type: 'string' } } })\n\nexport type ErrorCode = '400' | '401' | '403' | '404' | '500'\n\nconst allowed = (): SchemaObject => ({\n oneOf: [\n { type: 'boolean', enum: [true] },\n {\n type: 'object',\n properties: { permission: { type: 'boolean' }, where: { type: 'object', additionalProperties: true } },\n required: ['permission'],\n },\n ],\n})\n\nexport const docAccessOperation = ({\n tag,\n operationId,\n operations,\n bodyRef,\n errors,\n t,\n}: {\n tag: string\n operationId: string\n operations: string[]\n bodyRef: ReferenceObject\n errors: ErrorCode[]\n t: Translate\n}): OperationObject => ({\n tags: [tag],\n operationId,\n requestBody: { description: t('docAccessBody'), content: { 'application/json': { schema: bodyRef } } },\n responses: {\n ...jsonOk(t('docAccess'), {\n type: 'object',\n properties: {\n ...Object.fromEntries(operations.map((op) => [op, allowed()])),\n fields: {\n oneOf: [\n { type: 'boolean', enum: [true] },\n { type: 'object', additionalProperties: true },\n ],\n },\n },\n }),\n ...errorResponses(errors, t),\n },\n})\n\nexport const validateOperation = ({\n tag,\n operationId,\n parameters,\n requestBody,\n errors,\n security,\n t,\n}: {\n tag: string\n operationId: string\n parameters: ParameterObject[]\n requestBody: RequestBodyObject\n errors: ErrorCode[]\n security?: SecurityRequirementObject[]\n t: Translate\n}): OperationObject => ({\n tags: [tag],\n operationId,\n parameters,\n requestBody: {\n ...requestBody,\n description: [requestBody.description, t('validateBody')].filter(Boolean).join(' '),\n },\n responses: {\n ...jsonOk(t('validateResult'), {\n type: 'object',\n properties: {\n valid: { type: 'boolean' },\n errors: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n message: { type: 'string' },\n path: { type: 'string' },\n label: { oneOf: [{ type: 'string' }, { type: 'object', additionalProperties: { type: 'string' } }] },\n locale: { type: 'string' },\n tableName: { type: 'string' },\n },\n required: ['message', 'path'],\n },\n },\n },\n required: ['valid', 'errors'],\n }),\n ...errorResponses(errors, t),\n },\n security,\n})\n\nexport const ERROR_SCHEMA_NAME = 'ErrorResponse'\n\nconst ERROR_KEYS = {\n '400': 'error400',\n '401': 'error401',\n '403': 'error403',\n '404': 'error404',\n '500': 'error500',\n} as const\n\nexport const ERRORS = {\n list: ['400', '403', '500'] as ErrorCode[],\n read: ['403', '404', '500'] as ErrorCode[],\n create: ['400', '403', '500'] as ErrorCode[],\n update: ['400', '403', '404', '500'] as ErrorCode[],\n delete: ['403', '404', '500'] as ErrorCode[],\n globalRead: ['403', '500'] as ErrorCode[],\n globalUpdate: ['400', '403', '500'] as ErrorCode[],\n login: ['400', '401', '403', '500'] as ErrorCode[],\n session: ['401', '500'] as ErrorCode[],\n authAction: ['400', '403', '500'] as ErrorCode[],\n versionList: ['400', '403', '404', '500'] as ErrorCode[],\n versionRead: ['403', '404', '500'] as ErrorCode[],\n versionRestore: ['403', '404', '500'] as ErrorCode[],\n} as const\n\nexport const buildErrorResponseSchema = (): SchemaObject => ({\n type: 'object',\n properties: {\n errors: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n message: { type: 'string' },\n name: { type: 'string' },\n field: { type: 'string' },\n data: { type: 'object', additionalProperties: true },\n },\n required: ['message'],\n },\n },\n },\n required: ['errors'],\n})\n\nconst errorRef: ReferenceObject = { $ref: refTo(ERROR_SCHEMA_NAME) }\n\nconst errorContent = (description: string): ResponseObject => ({\n description,\n content: { 'application/json': { schema: errorRef } },\n})\n\nexport const errorResponses = (codes: ErrorCode[], t: Translate): ResponsesObject => {\n const responses: ResponsesObject = {}\n for (const code of codes) responses[code] = errorContent(t(ERROR_KEYS[code]))\n return responses\n}\n\nexport const buildListEnvelopeSchema = (base: string): SchemaObject => ({\n type: 'object',\n properties: {\n docs: { type: 'array', items: { $ref: refTo(base) } },\n totalDocs: { type: 'integer' },\n limit: { type: 'integer' },\n totalPages: { type: 'integer' },\n page: { type: 'integer' },\n pagingCounter: { type: 'integer' },\n hasPrevPage: { type: 'boolean' },\n hasNextPage: { type: 'boolean' },\n prevPage: nullableType('integer'),\n nextPage: nullableType('integer'),\n },\n required: ['docs', 'totalDocs', 'limit', 'totalPages', 'page'],\n})\n\nexport const uploadRequestBody = ({\n bodyRef,\n fileRequired,\n t,\n}: {\n bodyRef: ReferenceObject\n fileRequired: boolean\n t: Translate\n}): RequestBodyObject => {\n const fieldsSchemaName = bodyRef.$ref.split('/').pop() ?? 'the document'\n return {\n required: fileRequired,\n description: t('uploadBody'),\n content: {\n 'multipart/form-data': {\n schema: {\n type: 'object',\n properties: {\n file: {\n type: 'string',\n format: 'binary',\n description: t('uploadFile'),\n },\n _payload: {\n allOf: [bodyRef],\n description: t('uploadPayloadField', { schema: fieldsSchemaName }),\n },\n },\n ...(fileRequired ? { required: ['file'] } : {}),\n },\n encoding: {\n file: { contentType: 'application/octet-stream' },\n _payload: { contentType: 'application/json' },\n },\n },\n 'application/json': { schema: bodyRef },\n },\n }\n}\n\nexport const SECURITY_SCHEME_NAME = 'PayloadToken'\nexport const INTERACTIVE_SCHEME_NAME = 'PayloadLogin'\n\nexport const interactiveSecurityScheme = ({\n tokenUrl,\n t,\n}: {\n tokenUrl: string\n t: Translate\n}): SecuritySchemeObject => ({\n type: 'oauth2',\n description: t('securityInteractive'),\n flows: { password: { tokenUrl, scopes: {} } },\n})\n\nexport const securityScheme = ({ cookiePrefix, t }: { cookiePrefix: string; t: Translate }): SecuritySchemeObject => ({\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: t('securityBearer', { cookiePrefix }),\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"components.js","names":[],"sources":["../../../src/server/spec/components.ts"],"sourcesContent":["import type {\n OperationObject,\n ParameterObject,\n ReferenceObject,\n RequestBodyObject,\n ResponseObject,\n ResponsesObject,\n SchemaObject,\n SecurityRequirementObject,\n SecuritySchemeObject,\n} from '@scalar/openapi-types/3.2'\n\nimport type { Translate } from '@/shared/translations/types.js'\n\nimport { refTo } from './names.js'\n\ntype SchemaOrRef = SchemaObject | ReferenceObject\n\nexport const nullableType = (type: 'integer' | 'string' | 'number' | 'boolean'): SchemaObject => ({\n type: [type, 'null'],\n})\n\nexport const jsonResponse = (description: string, schema: SchemaOrRef): ResponseObject => ({\n description,\n content: { 'application/json': { schema } },\n})\n\nexport const jsonOk = (description: string, schema: SchemaOrRef): ResponsesObject => ({\n '200': jsonResponse(description, schema),\n})\n\nexport const jsonBody = (schema: SchemaOrRef): RequestBodyObject => ({\n required: true,\n content: { 'application/json': { schema } },\n})\n\nexport const messageResponse = (description: string): ResponsesObject =>\n jsonOk(description, { type: 'object', properties: { message: { type: 'string' } } })\n\nexport type ErrorCode = '400' | '401' | '403' | '404' | '500'\n\nconst allowed = (): SchemaObject => ({\n oneOf: [\n { type: 'boolean', enum: [true] },\n {\n type: 'object',\n properties: { permission: { type: 'boolean' }, where: { type: 'object', additionalProperties: true } },\n required: ['permission'],\n },\n ],\n})\n\nexport const docAccessOperation = ({\n tag,\n operationId,\n operations,\n bodyRef,\n errors,\n t,\n}: {\n tag: string\n operationId: string\n operations: string[]\n bodyRef: ReferenceObject\n errors: ErrorCode[]\n t: Translate\n}): OperationObject => ({\n tags: [tag],\n operationId,\n requestBody: { description: t('docAccessBody'), content: { 'application/json': { schema: bodyRef } } },\n responses: {\n ...jsonOk(t('docAccess'), {\n type: 'object',\n properties: {\n ...Object.fromEntries(operations.map((op) => [op, allowed()])),\n fields: {\n oneOf: [\n { type: 'boolean', enum: [true] },\n { type: 'object', additionalProperties: true },\n ],\n },\n },\n }),\n ...errorResponses(errors, t),\n },\n})\n\nexport const validateOperation = ({\n tag,\n operationId,\n parameters,\n requestBody,\n errors,\n security,\n t,\n}: {\n tag: string\n operationId: string\n parameters: ParameterObject[]\n requestBody: RequestBodyObject\n errors: ErrorCode[]\n security?: SecurityRequirementObject[]\n t: Translate\n}): OperationObject => ({\n tags: [tag],\n operationId,\n parameters,\n requestBody: {\n ...requestBody,\n description: [requestBody.description, t('validateBody')].filter(Boolean).join(' '),\n },\n responses: {\n ...jsonOk(t('validateResult'), {\n type: 'object',\n properties: {\n valid: { type: 'boolean' },\n errors: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n message: { type: 'string' },\n path: { type: 'string' },\n label: { oneOf: [{ type: 'string' }, { type: 'object', additionalProperties: { type: 'string' } }] },\n locale: { type: 'string' },\n tableName: { type: 'string' },\n },\n required: ['message', 'path'],\n },\n },\n },\n required: ['valid', 'errors'],\n }),\n ...errorResponses(errors, t),\n },\n security,\n})\n\nexport const ERROR_SCHEMA_NAME = 'ErrorResponse'\n\nconst ERROR_KEYS = {\n '400': 'error400',\n '401': 'error401',\n '403': 'error403',\n '404': 'error404',\n '500': 'error500',\n} as const\n\nexport const ERRORS = {\n list: ['400', '403', '500'] as ErrorCode[],\n read: ['403', '404', '500'] as ErrorCode[],\n create: ['400', '403', '500'] as ErrorCode[],\n update: ['400', '403', '404', '500'] as ErrorCode[],\n delete: ['403', '404', '500'] as ErrorCode[],\n globalRead: ['403', '500'] as ErrorCode[],\n globalUpdate: ['400', '403', '500'] as ErrorCode[],\n login: ['400', '401', '403', '500'] as ErrorCode[],\n session: ['401', '500'] as ErrorCode[],\n authAction: ['400', '403', '500'] as ErrorCode[],\n versionList: ['400', '403', '404', '500'] as ErrorCode[],\n versionRead: ['403', '404', '500'] as ErrorCode[],\n versionRestore: ['403', '404', '500'] as ErrorCode[],\n} as const\n\nexport const buildErrorResponseSchema = (): SchemaObject => ({\n type: 'object',\n properties: {\n errors: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n message: { type: 'string' },\n name: { type: 'string' },\n field: { type: 'string' },\n data: { type: 'object', additionalProperties: true },\n },\n required: ['message'],\n },\n },\n },\n required: ['errors'],\n})\n\nconst errorRef: ReferenceObject = { $ref: refTo(ERROR_SCHEMA_NAME) }\n\nconst errorContent = (description: string): ResponseObject => ({\n description,\n content: { 'application/json': { schema: errorRef } },\n})\n\nexport const errorResponses = (codes: ErrorCode[], t: Translate): ResponsesObject => {\n const responses: ResponsesObject = {}\n for (const code of codes) responses[code] = errorContent(t(ERROR_KEYS[code]))\n return responses\n}\n\nexport const buildListEnvelopeSchema = (base: string): SchemaObject => ({\n type: 'object',\n properties: {\n docs: { type: 'array', items: { $ref: refTo(base) } },\n totalDocs: { type: 'integer' },\n limit: { type: 'integer' },\n totalPages: { type: 'integer' },\n page: { type: 'integer' },\n pagingCounter: { type: 'integer' },\n hasPrevPage: { type: 'boolean' },\n hasNextPage: { type: 'boolean' },\n prevPage: nullableType('integer'),\n nextPage: nullableType('integer'),\n },\n required: ['docs', 'totalDocs', 'limit', 'totalPages', 'page'],\n})\n\nexport const uploadRequestBody = ({\n bodyRef,\n fileRequired,\n t,\n}: {\n bodyRef: ReferenceObject\n fileRequired: boolean\n t: Translate\n}): RequestBodyObject => {\n const fieldsSchemaName = bodyRef.$ref.split('/').pop() ?? 'the document'\n return {\n required: fileRequired,\n description: t('uploadBody'),\n content: {\n 'multipart/form-data': {\n schema: {\n type: 'object',\n properties: {\n file: {\n type: 'string',\n format: 'binary',\n description: t('uploadFile'),\n },\n _payload: {\n allOf: [bodyRef],\n description: t('uploadPayloadField', { schema: fieldsSchemaName }),\n },\n },\n ...(fileRequired ? { required: ['file'] } : {}),\n },\n encoding: {\n file: { contentType: 'application/octet-stream' },\n _payload: { contentType: 'application/json' },\n },\n },\n 'application/json': { schema: bodyRef },\n },\n }\n}\n\nexport const SECURITY_SCHEME_NAME = 'PayloadToken'\nexport const INTERACTIVE_SCHEME_NAME = 'PayloadLogin'\n\nexport const interactiveSecurityScheme = ({ tokenUrl, t }: { tokenUrl: string; t: Translate }): SecuritySchemeObject =>\n ({\n type: 'oauth2',\n description: t('securityInteractive'),\n flows: { password: { tokenUrl, scopes: {} } },\n }) as SecuritySchemeObject\n\nexport const securityScheme = ({ cookiePrefix, t }: { cookiePrefix: string; t: Translate }): SecuritySchemeObject => ({\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: t('securityBearer', { cookiePrefix }),\n})\n"],"mappings":";AAkBA,MAAa,gBAAgB,UAAqE,EAChG,MAAM,CAAC,MAAM,MAAM,EACrB;AAEA,MAAa,gBAAgB,aAAqB,YAAyC;CACzF;CACA,SAAS,EAAE,oBAAoB,EAAE,OAAO,EAAE;AAC5C;AAEA,MAAa,UAAU,aAAqB,YAA0C,EACpF,OAAO,aAAa,aAAa,MAAM,EACzC;AAEA,MAAa,YAAY,YAA4C;CACnE,UAAU;CACV,SAAS,EAAE,oBAAoB,EAAE,OAAO,EAAE;AAC5C;AAEA,MAAa,mBAAmB,gBAC9B,OAAO,aAAa;CAAE,MAAM;CAAU,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,EAAE;AAAE,CAAC;AAIrF,MAAM,iBAA+B,EACnC,OAAO,CACL;CAAE,MAAM;CAAW,MAAM,CAAC,IAAI;AAAE,GAChC;CACE,MAAM;CACN,YAAY;EAAE,YAAY,EAAE,MAAM,UAAU;EAAG,OAAO;GAAE,MAAM;GAAU,sBAAsB;EAAK;CAAE;CACrG,UAAU,CAAC,YAAY;AACzB,CACF,EACF;AAEA,MAAa,sBAAsB,EACjC,KACA,aACA,YACA,SACA,QACA,SAQsB;CACtB,MAAM,CAAC,GAAG;CACV;CACA,aAAa;EAAE,aAAa,EAAE,eAAe;EAAG,SAAS,EAAE,oBAAoB,EAAE,QAAQ,QAAQ,EAAE;CAAE;CACrG,WAAW;EACT,GAAG,OAAO,EAAE,WAAW,GAAG;GACxB,MAAM;GACN,YAAY;IACV,GAAG,OAAO,YAAY,WAAW,KAAK,OAAO,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC;IAC7D,QAAQ,EACN,OAAO,CACL;KAAE,MAAM;KAAW,MAAM,CAAC,IAAI;IAAE,GAChC;KAAE,MAAM;KAAU,sBAAsB;IAAK,CAC/C,EACF;GACF;EACF,CAAC;EACD,GAAG,eAAe,QAAQ,CAAC;CAC7B;AACF;AAEA,MAAa,qBAAqB,EAChC,KACA,aACA,YACA,aACA,QACA,UACA,SASsB;CACtB,MAAM,CAAC,GAAG;CACV;CACA;CACA,aAAa;EACX,GAAG;EACH,aAAa,CAAC,YAAY,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CACpF;CACA,WAAW;EACT,GAAG,OAAO,EAAE,gBAAgB,GAAG;GAC7B,MAAM;GACN,YAAY;IACV,OAAO,EAAE,MAAM,UAAU;IACzB,QAAQ;KACN,MAAM;KACN,OAAO;MACL,MAAM;MACN,YAAY;OACV,SAAS,EAAE,MAAM,SAAS;OAC1B,MAAM,EAAE,MAAM,SAAS;OACvB,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,SAAS,GAAG;QAAE,MAAM;QAAU,sBAAsB,EAAE,MAAM,SAAS;OAAE,CAAC,EAAE;OACnG,QAAQ,EAAE,MAAM,SAAS;OACzB,WAAW,EAAE,MAAM,SAAS;MAC9B;MACA,UAAU,CAAC,WAAW,MAAM;KAC9B;IACF;GACF;GACA,UAAU,CAAC,SAAS,QAAQ;EAC9B,CAAC;EACD,GAAG,eAAe,QAAQ,CAAC;CAC7B;CACA;AACF;AAEA,MAAa,oBAAoB;AAEjC,MAAM,aAAa;CACjB,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;AACT;AAEA,MAAa,SAAS;CACpB,MAAM;EAAC;EAAO;EAAO;CAAK;CAC1B,MAAM;EAAC;EAAO;EAAO;CAAK;CAC1B,QAAQ;EAAC;EAAO;EAAO;CAAK;CAC5B,QAAQ;EAAC;EAAO;EAAO;EAAO;CAAK;CACnC,QAAQ;EAAC;EAAO;EAAO;CAAK;CAC5B,YAAY,CAAC,OAAO,KAAK;CACzB,cAAc;EAAC;EAAO;EAAO;CAAK;CAClC,OAAO;EAAC;EAAO;EAAO;EAAO;CAAK;CAClC,SAAS,CAAC,OAAO,KAAK;CACtB,YAAY;EAAC;EAAO;EAAO;CAAK;CAChC,aAAa;EAAC;EAAO;EAAO;EAAO;CAAK;CACxC,aAAa;EAAC;EAAO;EAAO;CAAK;CACjC,gBAAgB;EAAC;EAAO;EAAO;CAAK;AACtC;AAEA,MAAa,kCAAgD;CAC3D,MAAM;CACN,YAAY,EACV,QAAQ;EACN,MAAM;EACN,OAAO;GACL,MAAM;GACN,YAAY;IACV,SAAS,EAAE,MAAM,SAAS;IAC1B,MAAM,EAAE,MAAM,SAAS;IACvB,OAAO,EAAE,MAAM,SAAS;IACxB,MAAM;KAAE,MAAM;KAAU,sBAAsB;IAAK;GACrD;GACA,UAAU,CAAC,SAAS;EACtB;CACF,EACF;CACA,UAAU,CAAC,QAAQ;AACrB;AAEA,MAAM,WAA4B,EAAE,MAAM,MAAM,iBAAiB,EAAE;AAEnE,MAAM,gBAAgB,iBAAyC;CAC7D;CACA,SAAS,EAAE,oBAAoB,EAAE,QAAQ,SAAS,EAAE;AACtD;AAEA,MAAa,kBAAkB,OAAoB,MAAkC;CACnF,MAAM,YAA6B,CAAC;CACpC,KAAK,MAAM,QAAQ,OAAO,UAAU,QAAQ,aAAa,EAAE,WAAW,KAAK,CAAC;CAC5E,OAAO;AACT;AAEA,MAAa,2BAA2B,UAAgC;CACtE,MAAM;CACN,YAAY;EACV,MAAM;GAAE,MAAM;GAAS,OAAO,EAAE,MAAM,MAAM,IAAI,EAAE;EAAE;EACpD,WAAW,EAAE,MAAM,UAAU;EAC7B,OAAO,EAAE,MAAM,UAAU;EACzB,YAAY,EAAE,MAAM,UAAU;EAC9B,MAAM,EAAE,MAAM,UAAU;EACxB,eAAe,EAAE,MAAM,UAAU;EACjC,aAAa,EAAE,MAAM,UAAU;EAC/B,aAAa,EAAE,MAAM,UAAU;EAC/B,UAAU,aAAa,SAAS;EAChC,UAAU,aAAa,SAAS;CAClC;CACA,UAAU;EAAC;EAAQ;EAAa;EAAS;EAAc;CAAM;AAC/D;AAEA,MAAa,qBAAqB,EAChC,SACA,cACA,QAKuB;CACvB,MAAM,mBAAmB,QAAQ,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;CAC1D,OAAO;EACL,UAAU;EACV,aAAa,EAAE,YAAY;EAC3B,SAAS;GACP,uBAAuB;IACrB,QAAQ;KACN,MAAM;KACN,YAAY;MACV,MAAM;OACJ,MAAM;OACN,QAAQ;OACR,aAAa,EAAE,YAAY;MAC7B;MACA,UAAU;OACR,OAAO,CAAC,OAAO;OACf,aAAa,EAAE,sBAAsB,EAAE,QAAQ,iBAAiB,CAAC;MACnE;KACF;KACA,GAAI,eAAe,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC;IAC/C;IACA,UAAU;KACR,MAAM,EAAE,aAAa,2BAA2B;KAChD,UAAU,EAAE,aAAa,mBAAmB;IAC9C;GACF;GACA,oBAAoB,EAAE,QAAQ,QAAQ;EACxC;CACF;AACF;AAEA,MAAa,uBAAuB;AACpC,MAAa,0BAA0B;AAEvC,MAAa,6BAA6B,EAAE,UAAU,SACnD;CACC,MAAM;CACN,aAAa,EAAE,qBAAqB;CACpC,OAAO,EAAE,UAAU;EAAE;EAAU,QAAQ,CAAC;CAAE,EAAE;AAC9C;AAEF,MAAa,kBAAkB,EAAE,cAAc,SAAuE;CACpH,MAAM;CACN,QAAQ;CACR,cAAc;CACd,aAAa,EAAE,kBAAkB,EAAE,aAAa,CAAC;AACnD"}
@@ -1,16 +1,15 @@
1
- import { BuildContext, Entity } from "../../shared/types/index.js";
1
+ import { BuildContext, Entity, Schema } from "../../shared/types/index.js";
2
2
  import { Block, SanitizedConfig } from "payload";
3
- import { SchemaObject } from "@scalar/openapi-types/3.2";
4
3
  export declare const resolveLocalizedStrings: (value: unknown, ctx: BuildContext) => unknown;
5
4
  export interface EntitySchemas {
6
- read: SchemaObject;
7
- create: SchemaObject;
8
- update: SchemaObject;
5
+ read: Schema;
6
+ create: Schema;
7
+ update: Schema;
9
8
  }
10
9
  export declare const buildEntitySchemas: ({ entity, config, ctx }: {
11
10
  entity: Entity;
12
11
  config: SanitizedConfig;
13
12
  ctx: BuildContext;
14
13
  }) => Promise<EntitySchemas>;
15
- export declare const buildBlockSchema: (block: Block, config: SanitizedConfig) => SchemaObject;
14
+ export declare const buildBlockSchema: (block: Block, config: SanitizedConfig) => Schema;
16
15
  //# sourceMappingURL=entitySchemas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entitySchemas.js","names":[],"sources":["../../../src/server/spec/entitySchemas.ts"],"sourcesContent":["import { getTranslation } from '@payloadcms/translations'\nimport type { SchemaObject } from '@scalar/openapi-types/3.2'\nimport { entityToJSONSchema } from 'payload'\nimport type { Block, Field, SanitizedConfig, SchemaVariant } from 'payload'\n\nimport { makeT } from '@/shared/translations/index.js'\nimport type { BuildContext, Entity, IDType } from '@/shared/types/index.js'\nimport { deepMerge, isPlainObject } from '@/shared/utils.js'\n\nimport { AUTH_FIELDS, flattenFields } from './fields.js'\nimport { rewriteRefs } from './names.js'\n\nconst READ_HIDDEN_FIELDS = new Set<string>([...AUTH_FIELDS, 'collection'])\n\nconst stripInterfaceName = <T>(entity: T): T => {\n const { interfaceName: _omit, ...rest } = entity as T & { interfaceName?: string }\n return rest as T\n}\n\nconst toComponentSchema = ({\n config,\n source,\n idType,\n defs = new Map(),\n variant,\n}: {\n config: SanitizedConfig\n source: Entity | Block\n idType: IDType\n defs?: Map<string, unknown>\n variant?: SchemaVariant\n}): SchemaObject => {\n const jsonSchema = entityToJSONSchema(\n config,\n source as never,\n defs as never,\n idType,\n new Set(),\n undefined,\n undefined,\n undefined,\n variant,\n )\n const blockSlugs = new Set((config.blocks ?? []).map((b) => b.slug))\n const schema = rewriteRefs(jsonSchema as never, blockSlugs, defs) as unknown as SchemaObject\n delete schema.title\n return schema\n}\n\nconst fieldOpenapi = (field: Field): Record<string, unknown> | undefined => {\n const meta = (field as { custom?: { openapi?: unknown } }).custom?.openapi\n return isPlainObject(meta) ? meta : undefined\n}\n\nconst isLocaleKeyed = (value: unknown, ctx: BuildContext): value is Record<string, string> => {\n if (!isPlainObject(value)) return false\n const keys = Object.keys(value)\n return (\n keys.length > 0 &&\n keys.every((k) => ctx.locales.includes(k)) &&\n Object.values(value).every((v) => typeof v === 'string')\n )\n}\n\nconst LOCALIZABLE_KEYS = new Set(['description', 'title', 'summary'])\n\nconst resolveTextValue = (value: unknown, ctx: BuildContext): string | undefined => {\n if (typeof value === 'function') {\n try {\n const result = (value as (args: { t: unknown; i18n: unknown }) => unknown)({ t: ctx.i18n.t, i18n: ctx.i18n })\n return typeof result === 'string' && result.length > 0 ? result : undefined\n } catch {\n return undefined\n }\n }\n if (isLocaleKeyed(value, ctx)) return getTranslation(value, ctx.i18n)\n return undefined\n}\n\nexport const resolveLocalizedStrings = (value: unknown, ctx: BuildContext): unknown => {\n if (!isPlainObject(value)) return value\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) {\n if (LOCALIZABLE_KEYS.has(k)) {\n const resolved = resolveTextValue(v, ctx)\n if (resolved !== undefined) out[k] = resolved\n else if (typeof v !== 'function') out[k] = resolveLocalizedStrings(v, ctx)\n continue\n }\n out[k] = resolveLocalizedStrings(v, ctx)\n }\n return out\n}\n\nconst applyFieldOverrides = ({\n schema,\n fields,\n ctx,\n}: {\n schema: SchemaObject\n fields: Field[]\n ctx: BuildContext\n}): void => {\n if (!schema.properties) return\n for (const field of flattenFields(fields)) {\n const name = 'name' in field ? field.name : undefined\n const override = fieldOpenapi(field)\n if (!name || !override) continue\n const current = schema.properties[name]\n if (isPlainObject(current)) {\n const resolved = resolveLocalizedStrings(override, ctx) as Record<string, unknown>\n schema.properties[name] = deepMerge(current, resolved) as SchemaObject\n }\n }\n}\n\nconst isRef = (value: unknown): value is { $ref: string } => isPlainObject(value) && typeof value.$ref === 'string'\n\nconst isBlockBranch = (branch: unknown): boolean => {\n if (isRef(branch)) return branch.$ref.startsWith('#/components/schemas/Block')\n return isPlainObject(branch) && isPlainObject(branch.properties) && 'blockType' in branch.properties\n}\n\nconst addBlockDiscriminators = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const item of node) addBlockDiscriminators(item)\n return\n }\n if (!isPlainObject(node)) return\n const oneOf = node.oneOf\n if (Array.isArray(oneOf) && oneOf.length > 0 && oneOf.every(isBlockBranch)) {\n ;(node as SchemaObject).discriminator = { propertyName: 'blockType' }\n }\n for (const value of Object.values(node)) addBlockDiscriminators(value)\n}\n\nconst fixPolymorphicJoinRequired = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const item of node) fixPolymorphicJoinRequired(item)\n return\n }\n if (!isPlainObject(node)) return\n const { properties, required } = node as SchemaObject\n if (isPlainObject(properties) && 'relationTo' in properties && Array.isArray(required)) {\n ;(node as SchemaObject).required = required.map((r: string) => (r === 'collectionSlug' ? 'relationTo' : r))\n }\n for (const value of Object.values(node)) fixPolymorphicJoinRequired(value)\n}\n\nconst markLocalizedFields = ({\n schema,\n fields,\n ctx,\n}: {\n schema: SchemaObject\n fields: Field[]\n ctx: BuildContext\n}): void => {\n if (!schema.properties || ctx.locales.length === 0) return\n for (const field of flattenFields(fields)) {\n if (!('localized' in field) || !field.localized) continue\n const name = 'name' in field ? field.name : undefined\n if (!name || !(name in schema.properties)) continue\n const single = schema.properties[name] as SchemaObject\n schema.properties[name] = {\n oneOf: [\n single,\n {\n type: 'object',\n description: makeT(ctx.i18n)('schemaPerLocale'),\n properties: Object.fromEntries(ctx.locales.map((l) => [l, single])),\n },\n ],\n }\n }\n}\n\nconst removeProps = (schema: SchemaObject, names: Iterable<string>): void => {\n if (!schema.properties) return\n for (const name of names) delete schema.properties[name]\n if (Array.isArray(schema.required)) {\n const drop = new Set(names)\n schema.required = schema.required.filter((r: string) => !drop.has(r))\n }\n}\n\nconst isConstantDeny = (access: unknown): boolean => {\n if (typeof access !== 'function' || access.length > 0) return false\n try {\n return access() === false\n } catch {\n return false\n }\n}\n\nconst deniedWrites = (fields: Field[], operation: 'create' | 'update'): string[] =>\n flattenFields(fields)\n .filter((field) => 'name' in field && 'access' in field && isConstantDeny(field.access?.[operation]))\n .map((field) => (field as { name: string }).name)\n\nconst cloneSchema = (schema: SchemaObject): SchemaObject => ({\n ...schema,\n properties: { ...schema.properties },\n required: Array.isArray(schema.required) ? [...schema.required] : schema.required,\n})\n\nexport interface EntitySchemas {\n read: SchemaObject\n create: SchemaObject\n update: SchemaObject\n}\n\nexport const buildEntitySchemas = async ({\n entity,\n config,\n ctx,\n}: {\n entity: Entity\n config: SanitizedConfig\n ctx: BuildContext\n}): Promise<EntitySchemas> => {\n const source = stripInterfaceName(entity)\n const defs = new Map<string, unknown>()\n const idType = ctx.defaultIDType\n const read = toComponentSchema({ config, source, idType, defs })\n const write = toComponentSchema({ config, source, idType, defs, variant: 'input' })\n const isAuth = 'auth' in entity && Boolean(entity.auth)\n\n for (const schema of [read, write]) {\n if (isAuth) removeProps(schema, READ_HIDDEN_FIELDS)\n applyFieldOverrides({ schema, fields: entity.fields, ctx })\n addBlockDiscriminators(schema)\n }\n fixPolymorphicJoinRequired(read)\n\n const create = cloneSchema(write)\n if (isAuth && create.properties) {\n create.properties.password = { type: 'string' }\n create.required = [...new Set([...(create.required ?? []), 'password'])]\n }\n\n removeProps(create, deniedWrites(entity.fields, 'create'))\n\n const update = cloneSchema(write)\n removeProps(update, deniedWrites(entity.fields, 'update'))\n delete update.required\n if (update.properties) delete update.properties.id\n if (isAuth && update.properties) {\n update.properties.password = { type: 'string' }\n }\n\n markLocalizedFields({ schema: read, fields: entity.fields, ctx })\n\n return { read, create, update }\n}\n\nexport const buildBlockSchema = (block: Block, config: SanitizedConfig): SchemaObject => {\n const schema = toComponentSchema({ config, source: stripInterfaceName(block), idType: 'text' })\n const blockType: SchemaObject = { type: 'string', enum: [block.slug] }\n const properties = { ...schema.properties, blockType }\n const required = [...new Set(['blockType', ...(schema.required ?? [])])]\n return { ...schema, type: 'object', properties, required }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"entitySchemas.js","names":[],"sources":["../../../src/server/spec/entitySchemas.ts"],"sourcesContent":["import { getTranslation } from '@payloadcms/translations'\nimport { entityToJSONSchema } from 'payload'\nimport type { Block, Field, SanitizedConfig, SchemaVariant } from 'payload'\n\nimport { makeT } from '@/shared/translations/index.js'\nimport type { BuildContext, Entity, IDType, Schema } from '@/shared/types/index.js'\nimport { deepMerge, isPlainObject } from '@/shared/utils.js'\n\nimport { AUTH_FIELDS, flattenFields } from './fields.js'\nimport { rewriteRefs } from './names.js'\n\nconst READ_HIDDEN_FIELDS = new Set<string>([...AUTH_FIELDS, 'collection'])\n\nconst stripInterfaceName = <T>(entity: T): T => {\n const { interfaceName: _omit, ...rest } = entity as T & { interfaceName?: string }\n return rest as T\n}\n\nconst toComponentSchema = ({\n config,\n source,\n idType,\n defs = new Map(),\n variant,\n}: {\n config: SanitizedConfig\n source: Entity | Block\n idType: IDType\n defs?: Map<string, unknown>\n variant?: SchemaVariant\n}): Schema => {\n const jsonSchema = entityToJSONSchema(\n config,\n source as never,\n defs as never,\n idType,\n new Set(),\n undefined,\n undefined,\n undefined,\n variant,\n )\n const blockSlugs = new Set((config.blocks ?? []).map((b) => b.slug))\n const schema = rewriteRefs(jsonSchema as never, blockSlugs, defs) as unknown as Schema\n delete schema.title\n return schema\n}\n\nconst fieldOpenapi = (field: Field): Record<string, unknown> | undefined => {\n const meta = (field as { custom?: { openapi?: unknown } }).custom?.openapi\n return isPlainObject(meta) ? meta : undefined\n}\n\nconst isLocaleKeyed = (value: unknown, ctx: BuildContext): value is Record<string, string> => {\n if (!isPlainObject(value)) return false\n const keys = Object.keys(value)\n return (\n keys.length > 0 &&\n keys.every((k) => ctx.locales.includes(k)) &&\n Object.values(value).every((v) => typeof v === 'string')\n )\n}\n\nconst LOCALIZABLE_KEYS = new Set(['description', 'title', 'summary'])\n\nconst resolveTextValue = (value: unknown, ctx: BuildContext): string | undefined => {\n if (typeof value === 'function') {\n try {\n const result = (value as (args: { t: unknown; i18n: unknown }) => unknown)({ t: ctx.i18n.t, i18n: ctx.i18n })\n return typeof result === 'string' && result.length > 0 ? result : undefined\n } catch {\n return undefined\n }\n }\n if (isLocaleKeyed(value, ctx)) return getTranslation(value, ctx.i18n)\n return undefined\n}\n\nexport const resolveLocalizedStrings = (value: unknown, ctx: BuildContext): unknown => {\n if (!isPlainObject(value)) return value\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) {\n if (LOCALIZABLE_KEYS.has(k)) {\n const resolved = resolveTextValue(v, ctx)\n if (resolved !== undefined) out[k] = resolved\n else if (typeof v !== 'function') out[k] = resolveLocalizedStrings(v, ctx)\n continue\n }\n out[k] = resolveLocalizedStrings(v, ctx)\n }\n return out\n}\n\nconst applyFieldOverrides = ({ schema, fields, ctx }: { schema: Schema; fields: Field[]; ctx: BuildContext }): void => {\n if (!schema.properties) return\n for (const field of flattenFields(fields)) {\n const name = 'name' in field ? field.name : undefined\n const override = fieldOpenapi(field)\n if (!name || !override) continue\n const current = schema.properties[name]\n if (isPlainObject(current)) {\n const resolved = resolveLocalizedStrings(override, ctx) as Record<string, unknown>\n schema.properties[name] = deepMerge(current, resolved) as Schema\n }\n }\n}\n\nconst isRef = (value: unknown): value is { $ref: string } => isPlainObject(value) && typeof value.$ref === 'string'\n\nconst isBlockBranch = (branch: unknown): boolean => {\n if (isRef(branch)) return branch.$ref.startsWith('#/components/schemas/Block')\n return isPlainObject(branch) && isPlainObject(branch.properties) && 'blockType' in branch.properties\n}\n\nconst addBlockDiscriminators = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const item of node) addBlockDiscriminators(item)\n return\n }\n if (!isPlainObject(node)) return\n const oneOf = node.oneOf\n if (Array.isArray(oneOf) && oneOf.length > 0 && oneOf.every(isBlockBranch)) {\n ;(node as Schema).discriminator = { propertyName: 'blockType' }\n }\n for (const value of Object.values(node)) addBlockDiscriminators(value)\n}\n\nconst fixPolymorphicJoinRequired = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const item of node) fixPolymorphicJoinRequired(item)\n return\n }\n if (!isPlainObject(node)) return\n const { properties, required } = node as Schema\n if (isPlainObject(properties) && 'relationTo' in properties && Array.isArray(required)) {\n ;(node as Schema).required = required.map((r: string) => (r === 'collectionSlug' ? 'relationTo' : r))\n }\n for (const value of Object.values(node)) fixPolymorphicJoinRequired(value)\n}\n\nconst markLocalizedFields = ({ schema, fields, ctx }: { schema: Schema; fields: Field[]; ctx: BuildContext }): void => {\n if (!schema.properties || ctx.locales.length === 0) return\n for (const field of flattenFields(fields)) {\n if (!('localized' in field) || !field.localized) continue\n const name = 'name' in field ? field.name : undefined\n if (!name || !(name in schema.properties)) continue\n const single = schema.properties[name] as Schema\n schema.properties[name] = {\n oneOf: [\n single,\n {\n type: 'object',\n description: makeT(ctx.i18n)('schemaPerLocale'),\n properties: Object.fromEntries(ctx.locales.map((l) => [l, single])),\n },\n ],\n }\n }\n}\n\nconst removeProps = (schema: Schema, names: Iterable<string>): void => {\n if (!schema.properties) return\n for (const name of names) delete schema.properties[name]\n if (Array.isArray(schema.required)) {\n const drop = new Set(names)\n schema.required = schema.required.filter((r: string) => !drop.has(r))\n }\n}\n\nconst isConstantDeny = (access: unknown): boolean => {\n if (typeof access !== 'function' || access.length > 0) return false\n try {\n return access() === false\n } catch {\n return false\n }\n}\n\nconst deniedWrites = (fields: Field[], operation: 'create' | 'update'): string[] =>\n flattenFields(fields)\n .filter((field) => 'name' in field && 'access' in field && isConstantDeny(field.access?.[operation]))\n .map((field) => (field as { name: string }).name)\n\nconst cloneSchema = (schema: Schema): Schema => ({\n ...schema,\n properties: { ...schema.properties },\n required: Array.isArray(schema.required) ? [...schema.required] : schema.required,\n})\n\nexport interface EntitySchemas {\n read: Schema\n create: Schema\n update: Schema\n}\n\nexport const buildEntitySchemas = async ({\n entity,\n config,\n ctx,\n}: {\n entity: Entity\n config: SanitizedConfig\n ctx: BuildContext\n}): Promise<EntitySchemas> => {\n const source = stripInterfaceName(entity)\n const defs = new Map<string, unknown>()\n const idType = ctx.defaultIDType\n const read = toComponentSchema({ config, source, idType, defs })\n const write = toComponentSchema({ config, source, idType, defs, variant: 'input' })\n const isAuth = 'auth' in entity && Boolean(entity.auth)\n\n for (const schema of [read, write]) {\n if (isAuth) removeProps(schema, READ_HIDDEN_FIELDS)\n applyFieldOverrides({ schema, fields: entity.fields, ctx })\n addBlockDiscriminators(schema)\n }\n fixPolymorphicJoinRequired(read)\n\n const create = cloneSchema(write)\n if (isAuth && create.properties) {\n create.properties.password = { type: 'string' }\n create.required = [...new Set([...(create.required ?? []), 'password'])]\n }\n\n removeProps(create, deniedWrites(entity.fields, 'create'))\n\n const update = cloneSchema(write)\n removeProps(update, deniedWrites(entity.fields, 'update'))\n delete update.required\n if (update.properties) delete update.properties.id\n if (isAuth && update.properties) {\n update.properties.password = { type: 'string' }\n }\n\n markLocalizedFields({ schema: read, fields: entity.fields, ctx })\n\n return { read, create, update }\n}\n\nexport const buildBlockSchema = (block: Block, config: SanitizedConfig): Schema => {\n const schema = toComponentSchema({ config, source: stripInterfaceName(block), idType: 'text' })\n const blockType: Schema = { type: 'string', enum: [block.slug] }\n const properties = { ...schema.properties, blockType }\n const required = [...new Set(['blockType', ...(schema.required ?? [])])]\n return { ...schema, type: 'object', properties, required }\n}\n"],"mappings":"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"}
@@ -3,10 +3,14 @@ import { SanitizedCollectionConfig, SanitizedGlobalConfig } from "payload";
3
3
  import { PathsObject } from "@scalar/openapi-types/3.2";
4
4
  export declare const shouldIncludeCollection: (collection: SanitizedCollectionConfig, filters: ResolvedFilters) => boolean;
5
5
  export declare const shouldIncludeGlobal: (global: SanitizedGlobalConfig, filters: ResolvedFilters) => boolean;
6
- export declare const filterOperations: ({ paths, slug, kind, filters }: {
6
+ export declare const PLUGIN_KEY = "x-payload-plugin";
7
+ export declare const operationPlugin: (operation: unknown, plugin: string | undefined) => string | undefined;
8
+ export declare const stripPluginKeys: (paths: PathsObject) => PathsObject;
9
+ export declare const filterOperations: ({ paths, slug, kind, plugin, filters }: {
7
10
  paths: PathsObject;
8
11
  slug?: string;
9
12
  kind: OperationKind;
13
+ plugin?: string;
10
14
  filters: ResolvedFilters;
11
15
  }) => Promise<PathsObject>;
12
16
  //# sourceMappingURL=filters.d.ts.map
@@ -56,17 +56,26 @@ const ruleMatchesMethod = (rule, method) => {
56
56
  if (rule.method === void 0) return true;
57
57
  return Array.isArray(rule.method) ? rule.method.includes(method) : rule.method === method;
58
58
  };
59
- const ruleMatchesSlug = (rule, slug) => {
60
- if (rule.slug === void 0) return true;
61
- if (slug === void 0) return false;
62
- return rule.slug instanceof RegExp ? rule.slug.test(slug) : rule.slug === slug;
59
+ const matchesOptional = (matcher, value) => {
60
+ if (matcher === void 0) return true;
61
+ if (value === void 0) return false;
62
+ return matcher instanceof RegExp ? matcher.test(value) : matcher === value;
63
+ };
64
+ const ruleMatches = (rule, { method, slug, kind, path, plugin }) => ruleMatchesMethod(rule, method) && matchesOptional(rule.slug, slug) && matchesOptional(rule.plugin, plugin) && (rule.kind === void 0 || rule.kind === kind) && (rule.path === void 0 || rule.path.test(path));
65
+ const PLUGIN_KEY = "x-payload-plugin";
66
+ const operationPlugin = (operation, plugin) => {
67
+ const marked = operation?.[PLUGIN_KEY];
68
+ return plugin ?? (typeof marked === "string" ? marked : void 0);
69
+ };
70
+ const stripPluginKeys = (paths) => {
71
+ for (const item of Object.values(paths)) for (const method of HTTP_METHODS) delete item[method]?.[PLUGIN_KEY];
72
+ return paths;
63
73
  };
64
- const ruleMatches = (rule, { method, slug, kind, path }) => ruleMatchesMethod(rule, method) && ruleMatchesSlug(rule, slug) && (rule.kind === void 0 || rule.kind === kind) && (rule.path === void 0 || rule.path.test(path));
65
74
  const isOperationExcluded = async (filters, op) => {
66
75
  for (const rule of filters.excludeOperations) if (typeof rule === "function" ? await rule(op) === true : ruleMatches(rule, op)) return true;
67
76
  return false;
68
77
  };
69
- const filterOperations = async ({ paths, slug, kind, filters }) => {
78
+ const filterOperations = async ({ paths, slug, kind, plugin, filters }) => {
70
79
  if (filters.excludeOperations.length === 0) return paths;
71
80
  for (const [path, item] of Object.entries(paths)) {
72
81
  if (!item) continue;
@@ -74,18 +83,20 @@ const filterOperations = async ({ paths, slug, kind, filters }) => {
74
83
  const ops = item;
75
84
  for (const method of HTTP_METHODS) {
76
85
  if (!ops[method]) continue;
77
- if (await isOperationExcluded(filters, {
86
+ const op = {
78
87
  method,
79
88
  path,
80
89
  slug,
81
- kind
82
- })) delete ops[method];
90
+ kind,
91
+ plugin: operationPlugin(ops[method], plugin)
92
+ };
93
+ if (await isOperationExcluded(filters, op)) delete ops[method];
83
94
  else remaining += 1;
84
95
  }
85
96
  if (remaining === 0) delete paths[path];
86
97
  }
87
98
  return paths;
88
99
  };
89
- export { filterOperations, shouldIncludeCollection, shouldIncludeGlobal };
100
+ export { PLUGIN_KEY, filterOperations, operationPlugin, shouldIncludeCollection, shouldIncludeGlobal, stripPluginKeys };
90
101
 
91
102
  //# sourceMappingURL=filters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"filters.js","names":[],"sources":["../../../src/server/spec/filters.ts"],"sourcesContent":["import type { PathsObject } from '@scalar/openapi-types/3.2'\nimport type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload'\n\nimport type {\n EntityKind,\n EntityMatcher,\n HttpMethod,\n OperationContext,\n OperationKind,\n OperationRule,\n ResolvedFilters,\n} from '@/shared/types/index.js'\n\nconst SYSTEM_COLLECTIONS = new Set([\n 'payload-jobs',\n 'payload-locked-documents',\n 'payload-preferences',\n 'payload-migrations',\n 'payload-kv',\n 'payload-llm-instructions',\n 'payload-query-presets',\n])\n\nconst SYSTEM_GLOBALS = new Set(['payload-jobs-stats'])\n\nconst HTTP_METHODS: HttpMethod[] = ['get', 'post', 'patch', 'put', 'delete']\n\ninterface EntityRef {\n slug: string\n kind: EntityKind\n}\n\nconst matchesEntity = (matcher: EntityMatcher, { slug, kind }: EntityRef): boolean => {\n if (typeof matcher === 'string') return matcher === slug\n if (matcher instanceof RegExp) return matcher.test(slug)\n return matcher.kind === kind && matcher.slug === slug\n}\n\nconst anyMatch = (matchers: EntityMatcher[], entity: EntityRef): boolean =>\n matchers.some((m) => matchesEntity(m, entity))\n\nconst isHiddenCollection = (collection: SanitizedCollectionConfig): boolean => {\n if ((collection as { hidden?: unknown }).hidden === true) return true\n const hidden = collection.admin?.hidden\n if (typeof hidden === 'function') {\n try {\n return hidden({ user: null } as never) === true\n } catch {\n return false\n }\n }\n return hidden === true\n}\n\nconst passesIncludeExclude = (entity: EntityRef, filters: ResolvedFilters): boolean => {\n if (filters.include.length > 0 && !anyMatch(filters.include, entity)) return false\n if (anyMatch(filters.exclude, entity)) return false\n return true\n}\n\nexport const shouldIncludeCollection = (collection: SanitizedCollectionConfig, filters: ResolvedFilters): boolean => {\n const { slug } = collection\n if (SYSTEM_COLLECTIONS.has(slug) && !filters.includeSystem) return false\n if (!filters.includeHidden && isHiddenCollection(collection)) return false\n return passesIncludeExclude({ slug, kind: 'collection' }, filters)\n}\n\nexport const shouldIncludeGlobal = (global: SanitizedGlobalConfig, filters: ResolvedFilters): boolean => {\n if (SYSTEM_GLOBALS.has(global.slug) && !filters.includeSystem) return false\n return passesIncludeExclude({ slug: global.slug, kind: 'global' }, filters)\n}\n\nconst ruleMatchesMethod = (rule: OperationRule, method: HttpMethod): boolean => {\n if (rule.method === undefined) return true\n return Array.isArray(rule.method) ? rule.method.includes(method) : rule.method === method\n}\n\nconst ruleMatchesSlug = (rule: OperationRule, slug: string | undefined): boolean => {\n if (rule.slug === undefined) return true\n if (slug === undefined) return false\n return rule.slug instanceof RegExp ? rule.slug.test(slug) : rule.slug === slug\n}\n\nconst ruleMatches = (rule: OperationRule, { method, slug, kind, path }: OperationContext): boolean =>\n ruleMatchesMethod(rule, method) &&\n ruleMatchesSlug(rule, slug) &&\n (rule.kind === undefined || rule.kind === kind) &&\n (rule.path === undefined || rule.path.test(path))\n\nconst isOperationExcluded = async (filters: ResolvedFilters, op: OperationContext): Promise<boolean> => {\n for (const rule of filters.excludeOperations) {\n if (typeof rule === 'function' ? (await rule(op)) === true : ruleMatches(rule, op)) return true\n }\n return false\n}\n\nexport const filterOperations = async ({\n paths,\n slug,\n kind,\n filters,\n}: {\n paths: PathsObject\n slug?: string\n kind: OperationKind\n filters: ResolvedFilters\n}): Promise<PathsObject> => {\n if (filters.excludeOperations.length === 0) return paths\n\n for (const [path, item] of Object.entries(paths)) {\n if (!item) continue\n let remaining = 0\n const ops = item as Record<HttpMethod, unknown>\n for (const method of HTTP_METHODS) {\n if (!ops[method]) continue\n if (await isOperationExcluded(filters, { method, path, slug, kind })) {\n delete ops[method]\n } else {\n remaining += 1\n }\n }\n if (remaining === 0) delete paths[path]\n }\n return paths\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"filters.js","names":[],"sources":["../../../src/server/spec/filters.ts"],"sourcesContent":["import type { PathsObject } from '@scalar/openapi-types/3.2'\nimport type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload'\n\nimport type {\n EntityKind,\n EntityMatcher,\n HttpMethod,\n OperationContext,\n OperationKind,\n OperationRule,\n ResolvedFilters,\n} from '@/shared/types/index.js'\n\nconst SYSTEM_COLLECTIONS = new Set([\n 'payload-jobs',\n 'payload-locked-documents',\n 'payload-preferences',\n 'payload-migrations',\n 'payload-kv',\n 'payload-llm-instructions',\n 'payload-query-presets',\n])\n\nconst SYSTEM_GLOBALS = new Set(['payload-jobs-stats'])\n\nconst HTTP_METHODS: HttpMethod[] = ['get', 'post', 'patch', 'put', 'delete']\n\ninterface EntityRef {\n slug: string\n kind: EntityKind\n}\n\nconst matchesEntity = (matcher: EntityMatcher, { slug, kind }: EntityRef): boolean => {\n if (typeof matcher === 'string') return matcher === slug\n if (matcher instanceof RegExp) return matcher.test(slug)\n return matcher.kind === kind && matcher.slug === slug\n}\n\nconst anyMatch = (matchers: EntityMatcher[], entity: EntityRef): boolean =>\n matchers.some((m) => matchesEntity(m, entity))\n\nconst isHiddenCollection = (collection: SanitizedCollectionConfig): boolean => {\n if ((collection as { hidden?: unknown }).hidden === true) return true\n const hidden = collection.admin?.hidden\n if (typeof hidden === 'function') {\n try {\n return hidden({ user: null } as never) === true\n } catch {\n return false\n }\n }\n return hidden === true\n}\n\nconst passesIncludeExclude = (entity: EntityRef, filters: ResolvedFilters): boolean => {\n if (filters.include.length > 0 && !anyMatch(filters.include, entity)) return false\n if (anyMatch(filters.exclude, entity)) return false\n return true\n}\n\nexport const shouldIncludeCollection = (collection: SanitizedCollectionConfig, filters: ResolvedFilters): boolean => {\n const { slug } = collection\n if (SYSTEM_COLLECTIONS.has(slug) && !filters.includeSystem) return false\n if (!filters.includeHidden && isHiddenCollection(collection)) return false\n return passesIncludeExclude({ slug, kind: 'collection' }, filters)\n}\n\nexport const shouldIncludeGlobal = (global: SanitizedGlobalConfig, filters: ResolvedFilters): boolean => {\n if (SYSTEM_GLOBALS.has(global.slug) && !filters.includeSystem) return false\n return passesIncludeExclude({ slug: global.slug, kind: 'global' }, filters)\n}\n\nconst ruleMatchesMethod = (rule: OperationRule, method: HttpMethod): boolean => {\n if (rule.method === undefined) return true\n return Array.isArray(rule.method) ? rule.method.includes(method) : rule.method === method\n}\n\nconst matchesOptional = (matcher: string | RegExp | undefined, value: string | undefined): boolean => {\n if (matcher === undefined) return true\n if (value === undefined) return false\n return matcher instanceof RegExp ? matcher.test(value) : matcher === value\n}\n\nconst ruleMatches = (rule: OperationRule, { method, slug, kind, path, plugin }: OperationContext): boolean =>\n ruleMatchesMethod(rule, method) &&\n matchesOptional(rule.slug, slug) &&\n matchesOptional(rule.plugin, plugin) &&\n (rule.kind === undefined || rule.kind === kind) &&\n (rule.path === undefined || rule.path.test(path))\n\nexport const PLUGIN_KEY = 'x-payload-plugin'\n\nexport const operationPlugin = (operation: unknown, plugin: string | undefined): string | undefined => {\n const marked = (operation as Record<string, unknown> | undefined)?.[PLUGIN_KEY]\n return plugin ?? (typeof marked === 'string' ? marked : undefined)\n}\n\nexport const stripPluginKeys = (paths: PathsObject): PathsObject => {\n for (const item of Object.values(paths)) {\n for (const method of HTTP_METHODS)\n delete (item as Record<HttpMethod, Record<string, unknown> | undefined>)[method]?.[PLUGIN_KEY]\n }\n return paths\n}\n\nconst isOperationExcluded = async (filters: ResolvedFilters, op: OperationContext): Promise<boolean> => {\n for (const rule of filters.excludeOperations) {\n if (typeof rule === 'function' ? (await rule(op)) === true : ruleMatches(rule, op)) return true\n }\n return false\n}\n\nexport const filterOperations = async ({\n paths,\n slug,\n kind,\n plugin,\n filters,\n}: {\n paths: PathsObject\n slug?: string\n kind: OperationKind\n plugin?: string\n filters: ResolvedFilters\n}): Promise<PathsObject> => {\n if (filters.excludeOperations.length === 0) return paths\n\n for (const [path, item] of Object.entries(paths)) {\n if (!item) continue\n let remaining = 0\n const ops = item as Record<HttpMethod, unknown>\n for (const method of HTTP_METHODS) {\n if (!ops[method]) continue\n const op = { method, path, slug, kind, plugin: operationPlugin(ops[method], plugin) }\n if (await isOperationExcluded(filters, op)) {\n delete ops[method]\n } else {\n remaining += 1\n }\n }\n if (remaining === 0) delete paths[path]\n }\n return paths\n}\n"],"mappings":"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"}
@@ -8,10 +8,15 @@ const applyHierarchy = ({ collection, base, paths, schemas, ctx }) => {
8
8
  [hierarchy.slugPathFieldName]: t("schemaHierarchySlugPath"),
9
9
  [hierarchy.titlePathFieldName]: t("schemaHierarchyTitlePath")
10
10
  };
11
- const read = schemas[base]?.properties;
11
+ const propertiesOf = (name) => {
12
+ const schema = schemas[name];
13
+ return typeof schema === "object" ? schema.properties : void 0;
14
+ };
15
+ const read = propertiesOf(base);
12
16
  for (const [name, description] of Object.entries(pathFields)) {
13
- if (read?.[name]) read[name] = {
14
- ...read[name],
17
+ const current = read?.[name];
18
+ if (read && typeof current === "object") read[name] = {
19
+ ...current,
15
20
  readOnly: true,
16
21
  description
17
22
  };
@@ -19,7 +24,7 @@ const applyHierarchy = ({ collection, base, paths, schemas, ctx }) => {
19
24
  createSchemaName(base),
20
25
  updateSchemaName(base),
21
26
  querySchemaName(base)
22
- ]) delete schemas[other]?.properties?.[name];
27
+ ]) delete propertiesOf(other)?.[name];
23
28
  }
24
29
  const param = {
25
30
  name: "computeHierarchyPaths",
@@ -1 +1 @@
1
- {"version":3,"file":"hierarchy.js","names":[],"sources":["../../../src/server/spec/hierarchy.ts"],"sourcesContent":["import type { OperationObject, ParameterObject, PathsObject, SchemaObject } from '@scalar/openapi-types/3.2'\nimport type { SanitizedCollectionConfig } from 'payload'\n\nimport { createSchemaName, querySchemaName, updateSchemaName } from '@/server/spec/names.js'\nimport { makeT } from '@/shared/translations/index.js'\nimport type { BuildContext } from '@/shared/types/index.js'\n\nexport const applyHierarchy = ({\n collection,\n base,\n paths,\n schemas,\n ctx,\n}: {\n collection: SanitizedCollectionConfig\n base: string\n paths: PathsObject\n schemas: Record<string, SchemaObject>\n ctx: BuildContext\n}): void => {\n const { hierarchy } = collection\n if (!hierarchy) return\n const t = makeT(ctx.i18n)\n const pathFields = {\n [hierarchy.slugPathFieldName]: t('schemaHierarchySlugPath'),\n [hierarchy.titlePathFieldName]: t('schemaHierarchyTitlePath'),\n }\n\n const read = schemas[base]?.properties\n for (const [name, description] of Object.entries(pathFields)) {\n if (read?.[name]) read[name] = { ...read[name], readOnly: true, description }\n for (const other of [createSchemaName(base), updateSchemaName(base), querySchemaName(base)]) {\n delete schemas[other]?.properties?.[name]\n }\n }\n\n const param: ParameterObject = {\n name: 'computeHierarchyPaths',\n in: 'query',\n description: t('paramComputeHierarchyPaths', {\n slugPath: hierarchy.slugPathFieldName,\n titlePath: hierarchy.titlePathFieldName,\n }),\n schema: { type: 'boolean' },\n }\n const route = `${ctx.apiRoute}/${collection.slug}`\n for (const op of [paths[route]?.get, paths[`${route}/{id}`]?.get] as (OperationObject | undefined)[]) {\n op?.parameters?.push(param)\n }\n}\n"],"mappings":";;AAOA,MAAa,kBAAkB,EAC7B,YACA,MACA,OACA,SACA,UAOU;CACV,MAAM,EAAE,cAAc;CACtB,IAAI,CAAC,WAAW;CAChB,MAAM,IAAI,MAAM,IAAI,IAAI;CACxB,MAAM,aAAa;GAChB,UAAU,oBAAoB,EAAE,yBAAyB;GACzD,UAAU,qBAAqB,EAAE,0BAA0B;CAC9D;CAEA,MAAM,OAAO,QAAQ,KAAK,EAAE;CAC5B,KAAK,MAAM,CAAC,MAAM,gBAAgB,OAAO,QAAQ,UAAU,GAAG;EAC5D,IAAI,OAAO,OAAO,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,UAAU;GAAM;EAAY;EAC5E,KAAK,MAAM,SAAS;GAAC,iBAAiB,IAAI;GAAG,iBAAiB,IAAI;GAAG,gBAAgB,IAAI;EAAC,GACxF,OAAO,QAAQ,MAAM,EAAE,aAAa;CAExC;CAEA,MAAM,QAAyB;EAC7B,MAAM;EACN,IAAI;EACJ,aAAa,EAAE,8BAA8B;GAC3C,UAAU,UAAU;GACpB,WAAW,UAAU;EACvB,CAAC;EACD,QAAQ,EAAE,MAAM,UAAU;CAC5B;CACA,MAAM,QAAQ,GAAG,IAAI,SAAS,GAAG,WAAW;CAC5C,KAAK,MAAM,MAAM,CAAC,MAAM,MAAM,EAAE,KAAK,MAAM,GAAG,MAAM,OAAO,EAAE,GAAG,GAC9D,IAAI,YAAY,KAAK,KAAK;AAE9B"}
1
+ {"version":3,"file":"hierarchy.js","names":[],"sources":["../../../src/server/spec/hierarchy.ts"],"sourcesContent":["import type { OperationObject, ParameterObject, PathsObject, SchemaObject } from '@scalar/openapi-types/3.2'\nimport type { SanitizedCollectionConfig } from 'payload'\n\nimport { createSchemaName, querySchemaName, updateSchemaName } from '@/server/spec/names.js'\nimport { makeT } from '@/shared/translations/index.js'\nimport type { BuildContext } from '@/shared/types/index.js'\n\nexport const applyHierarchy = ({\n collection,\n base,\n paths,\n schemas,\n ctx,\n}: {\n collection: SanitizedCollectionConfig\n base: string\n paths: PathsObject\n schemas: Record<string, SchemaObject>\n ctx: BuildContext\n}): void => {\n const { hierarchy } = collection\n if (!hierarchy) return\n const t = makeT(ctx.i18n)\n const pathFields = {\n [hierarchy.slugPathFieldName]: t('schemaHierarchySlugPath'),\n [hierarchy.titlePathFieldName]: t('schemaHierarchyTitlePath'),\n }\n\n const propertiesOf = (name: string) => {\n const schema = schemas[name]\n return typeof schema === 'object' ? schema.properties : undefined\n }\n const read = propertiesOf(base)\n for (const [name, description] of Object.entries(pathFields)) {\n const current = read?.[name]\n if (read && typeof current === 'object') read[name] = { ...current, readOnly: true, description }\n for (const other of [createSchemaName(base), updateSchemaName(base), querySchemaName(base)]) {\n delete propertiesOf(other)?.[name]\n }\n }\n\n const param: ParameterObject = {\n name: 'computeHierarchyPaths',\n in: 'query',\n description: t('paramComputeHierarchyPaths', {\n slugPath: hierarchy.slugPathFieldName,\n titlePath: hierarchy.titlePathFieldName,\n }),\n schema: { type: 'boolean' },\n }\n const route = `${ctx.apiRoute}/${collection.slug}`\n for (const op of [paths[route]?.get, paths[`${route}/{id}`]?.get] as (OperationObject | undefined)[]) {\n op?.parameters?.push(param)\n }\n}\n"],"mappings":";;AAOA,MAAa,kBAAkB,EAC7B,YACA,MACA,OACA,SACA,UAOU;CACV,MAAM,EAAE,cAAc;CACtB,IAAI,CAAC,WAAW;CAChB,MAAM,IAAI,MAAM,IAAI,IAAI;CACxB,MAAM,aAAa;GAChB,UAAU,oBAAoB,EAAE,yBAAyB;GACzD,UAAU,qBAAqB,EAAE,0BAA0B;CAC9D;CAEA,MAAM,gBAAgB,SAAiB;EACrC,MAAM,SAAS,QAAQ;EACvB,OAAO,OAAO,WAAW,WAAW,OAAO,aAAa,KAAA;CAC1D;CACA,MAAM,OAAO,aAAa,IAAI;CAC9B,KAAK,MAAM,CAAC,MAAM,gBAAgB,OAAO,QAAQ,UAAU,GAAG;EAC5D,MAAM,UAAU,OAAO;EACvB,IAAI,QAAQ,OAAO,YAAY,UAAU,KAAK,QAAQ;GAAE,GAAG;GAAS,UAAU;GAAM;EAAY;EAChG,KAAK,MAAM,SAAS;GAAC,iBAAiB,IAAI;GAAG,iBAAiB,IAAI;GAAG,gBAAgB,IAAI;EAAC,GACxF,OAAO,aAAa,KAAK,CAAC,GAAG;CAEjC;CAEA,MAAM,QAAyB;EAC7B,MAAM;EACN,IAAI;EACJ,aAAa,EAAE,8BAA8B;GAC3C,UAAU,UAAU;GACpB,WAAW,UAAU;EACvB,CAAC;EACD,QAAQ,EAAE,MAAM,UAAU;CAC5B;CACA,MAAM,QAAQ,GAAG,IAAI,SAAS,GAAG,WAAW;CAC5C,KAAK,MAAM,MAAM,CAAC,MAAM,MAAM,EAAE,KAAK,MAAM,GAAG,MAAM,OAAO,EAAE,GAAG,GAC9D,IAAI,YAAY,KAAK,KAAK;AAE9B"}