payload-plugin-urls 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,6 +57,16 @@ export default buildConfig({
57
57
  },
58
58
  },
59
59
  },
60
+ overrides: {
61
+ label: "Site structure",
62
+ hooks: {
63
+ afterChange: [
64
+ async () => {
65
+ /* runs after the plugin's root-pages URL hook */
66
+ },
67
+ ],
68
+ },
69
+ },
60
70
  }),
61
71
  ],
62
72
  })
@@ -68,9 +78,21 @@ default locale and `/<locale>` for other locales. Each field can set `relationTo
68
78
  which are merged into the generated relationship field. Collection `rootPage` values such as
69
79
  `recipesPage` define URL prefixes for documents in that collection.
70
80
 
71
- Locales are read from the Payload `localization` config when the plugin is installed. You can still
72
- pass `locales` to the plugin options to override that inferred value or when using exported helpers
73
- outside the plugin lifecycle.
81
+ ### Root-pages global (`overrides`)
82
+
83
+ `overrides` is an optional `Partial<GlobalConfig>` merged into the generated `root-pages` global
84
+ after the plugin's defaults. Use it for **`label`**, **`access`**, extra **`hooks`**, **`admin`**,
85
+ and other global options. Hook arrays are **concatenated**: the plugin's hooks run first, then
86
+ yours. The **`fields`** key in `overrides` is ignored so the plugin keeps control of the
87
+ relationship fields; customize those per field with `rootPages.fields[fieldName].overrides` instead.
88
+
89
+ ### Other options
90
+
91
+ - **`field`** — Rename the hidden `populatedUrl` field or pass field-level `overrides` (for example
92
+ `admin` UI tweaks).
93
+ - **`locales`** — Optional. When omitted, locales are taken from Payload `localization`. Set
94
+ `defaultLocale` and `locales` explicitly to override that, or when using exported helpers outside
95
+ the normal plugin lifecycle.
74
96
 
75
97
  Categorized collections can choose how their prefix is built:
76
98
 
@@ -83,11 +105,367 @@ when page, category, or root page relationships change.
83
105
 
84
106
  ## Exports
85
107
 
86
- - `payloadPluginUrls`
87
- - `populatedUrlField`
88
- - `resolvePopulatedUrl`
89
- - `getDocumentLink`
90
- - `getDocumentLinkBySlugs`
91
- - `getRootPageChangeSources`
92
- - `withLocalePrefix`
93
- - `withoutTrailingSlash`
108
+ The package default export is the same function as `payloadPluginUrls`. Import runtime helpers and
109
+ TypeScript types from `payload-plugin-urls`. Import the Next.js App Router client `CmsLink` from the
110
+ [`payload-plugin-urls/next`](#nextjs-exports-payload-plugin-urlsnext) submodule (optional peer dependency on `next`
111
+ and React).
112
+
113
+ ### `payloadPluginUrls`
114
+
115
+ Registers the `root-pages` global, URL hooks and fields on configured collections, and the
116
+ `update-urls` job workflow.
117
+
118
+ ```ts
119
+ interface PayloadPluginUrls {
120
+ (options?: PayloadPluginUrlsOptions): PayloadPlugin
121
+ }
122
+ ```
123
+
124
+ - **`options`** — Plugin configuration; see [`PayloadPluginUrlsOptions`](#payloadpluginurlsoptions).
125
+ When omitted, the plugin is a no-op and returns the Payload config unchanged.
126
+
127
+ ### `populatedUrlField`
128
+
129
+ Builds the hidden, localized `populatedUrl` text field definition (same shape the plugin injects
130
+ into collections). Use it if you register the field manually.
131
+
132
+ ```ts
133
+ interface PopulatedUrlField {
134
+ (options?: PayloadPluginUrlsOptions): Field
135
+ }
136
+ ```
137
+
138
+ - **`options`** — Same plugin options object used for `name` / `overrides` under `field`; defaults
139
+ to `{ collections: {} }` if omitted.
140
+
141
+ ### `resolvePopulatedUrl`
142
+
143
+ Async helper that computes the public URL path for a document using your plugin `options`, locale,
144
+ merged document data, and the `root-pages` global snapshot.
145
+
146
+ ```ts
147
+ interface ResolvePopulatedUrl {
148
+ (args: ResolvePopulatedUrlArgs): Promise<string | undefined>
149
+ }
150
+ ```
151
+
152
+ `ResolvePopulatedUrlArgs`:
153
+
154
+ ```ts
155
+ interface ResolvePopulatedUrlArgs {
156
+ /** Collection slug configured under `options.collections`. */
157
+ collection: string
158
+ /** Incoming payload data for the document (merged with `originalDoc` internally). */
159
+ data: Partial<UrlDoc>
160
+ /** Locale code to resolve for. */
161
+ locale: Locale
162
+ /** Full plugin options including `collections` and `locales`. */
163
+ options: PayloadPluginUrlsOptions
164
+ /** Prior revision used to fill missing fields when resolving. */
165
+ originalDoc?: Partial<UrlDoc>
166
+ /** Optional Payload instance for loading related docs when needed. */
167
+ payload?: PayloadLike
168
+ /** Loaded `root-pages` global document for this locale. */
169
+ rootPages: RootPagesDoc
170
+ }
171
+ ```
172
+
173
+ ### `getDocumentLink`
174
+
175
+ Builds a site path from a populated relationship. Reads `populatedUrl` from the related document
176
+ when present; otherwise derives segments from plugin options and document shape. Throws if
177
+ `reference.value` is a plain id string instead of an expanded doc.
178
+
179
+ ```ts
180
+ interface GetDocumentLink {
181
+ (reference: GetDocumentLinkArgs, context: GetDocumentLinkContext): string
182
+ }
183
+ ```
184
+
185
+ - **`reference`** — Which collection the relationship targets and the related `UrlDoc` (expanded).
186
+
187
+ `GetDocumentLinkArgs`:
188
+
189
+ ```ts
190
+ interface GetDocumentLinkArgs {
191
+ relationTo: string
192
+ value: string | UrlDoc
193
+ }
194
+ ```
195
+
196
+ - **`relationTo`** — Target collection slug.
197
+ - **`value`** — Related document; must be an object with `populatedUrl` / category / slug data,
198
+ not an unresolved id string.
199
+
200
+ - **`context`** — Locale, plugin options, optional public `baseUrl`, and optional
201
+ `urlPrefixStrategy` override when building category paths.
202
+
203
+ `GetDocumentLinkContext`:
204
+
205
+ ```ts
206
+ interface GetDocumentLinkContext {
207
+ baseUrl?: string
208
+ locale: Locale
209
+ options: PayloadPluginUrlsOptions
210
+ urlPrefixStrategy?: UrlPrefixStrategy
211
+ }
212
+ ```
213
+
214
+ ### Next.js exports (`payload-plugin-urls/next`)
215
+
216
+ Client `CmsLink` for Payload-style link fields: resolves internal paths with
217
+ [`getDocumentLink`](#getdocumentlink), highlights the active destination with `usePathname`, handles
218
+ same-document `#hash` targets with configurable scroll offset (`hashScrollYOffset`), resets scroll near the viewport top on
219
+ client navigations (unless opening a new tab or modifier-click), and renders **`disabled`** links as
220
+ plain `span` elements instead of anchors.
221
+
222
+ Requires optional peer dependencies `next`, `react`, and `react-dom`.
223
+
224
+ ```tsx
225
+ "use client"
226
+
227
+ import type { ReactNode } from "react"
228
+ import type { PayloadPluginUrlsOptions, UrlDoc } from "payload-plugin-urls"
229
+ import { CmsLink } from "payload-plugin-urls/next"
230
+
231
+ const urlPluginOptions = {} satisfies PayloadPluginUrlsOptions
232
+
233
+ interface CmsRelationship {
234
+ relationTo: string
235
+ value: UrlDoc | string
236
+ }
237
+
238
+ export function NavLinkDemo(props: {
239
+ locale: string
240
+ siteUrl: string
241
+ type?: string | null
242
+ url?: string | null
243
+ reference?: CmsRelationship | null
244
+ newTab?: boolean | null
245
+ /** Resolve localized labels yourself; pass the result as children. */
246
+ children: ReactNode
247
+ }) {
248
+ const { locale, siteUrl, type, url, reference, newTab, children } = props
249
+
250
+ return (
251
+ <CmsLink
252
+ siteUrl={siteUrl}
253
+ urls={{ locale, options: urlPluginOptions }}
254
+ className="text-primary underline"
255
+ type={type ?? undefined}
256
+ url={url ?? undefined}
257
+ reference={reference && typeof reference.value === "object" ? reference : undefined}
258
+ newTab={newTab ?? undefined}
259
+ >
260
+ {children}
261
+ </CmsLink>
262
+ )
263
+ }
264
+ ```
265
+
266
+ - **`siteUrl`** — Public site base (`https://example.com`-style origin is enough); used with `URL`
267
+ and `usePathname` for same-origin and active-route checks.
268
+ - **`urls`** — `locale`, `options` (your plugin config), optional `baseUrl`, optional
269
+ `urlPrefixStrategy` (same meanings as [`getDocumentLink`](#getdocumentlink)).
270
+
271
+ ### `getDocumentLinkBySlugs`
272
+
273
+ Joins URL segments with an optional locale or `baseUrl` prefix. Lower-level helper used when you
274
+ already know slug segments.
275
+
276
+ ```ts
277
+ interface GetDocumentLinkBySlugs {
278
+ (slugs: string[], context: GetDocumentLinkBySlugsContext): string
279
+ }
280
+ ```
281
+
282
+ `GetDocumentLinkBySlugsContext`:
283
+
284
+ ```ts
285
+ interface GetDocumentLinkBySlugsContext {
286
+ /** When set, prefixed before segments (can include origin or path prefix). */
287
+ baseUrl?: string
288
+ /** Declares which collection the path belongs to (for consistency with call sites). */
289
+ collection: string
290
+ locale: Locale
291
+ options: PayloadPluginUrlsOptions
292
+ }
293
+ ```
294
+
295
+ - **`slugs`** — Path segments in order (for example category path + page slug).
296
+ - **`context`** — Locale and options for default-locale handling; `collection` is part of the public
297
+ signature for naming consistency with internal routing.
298
+
299
+ ### `withLocalePrefix`
300
+
301
+ Prefixes `path` with `/<locale>` when `locale` is not the configured default locale.
302
+
303
+ ```ts
304
+ interface WithLocalePrefix {
305
+ (path: string, locale: Locale, options: PayloadPluginUrlsOptions): string
306
+ }
307
+ ```
308
+
309
+ - **`path`** — Path starting with `/` (trailing slash normalized away in the result).
310
+ - **`locale`** — Active locale.
311
+ - **`options`** — Plugin options (uses normalized `locales.defaultLocale`).
312
+
313
+ ### `withoutTrailingSlash`
314
+
315
+ Normalizes a path to start with `/` and removes a trailing slash.
316
+
317
+ ```ts
318
+ interface WithoutTrailingSlash {
319
+ (path: string): string
320
+ }
321
+ ```
322
+
323
+ - **`path`** — Raw path string.
324
+
325
+ ### `getRootPageChangeSources`
326
+
327
+ Returns job input sources describing which collections and homepage pages need URL refreshes after
328
+ the root-pages global changes. Used internally and available for custom workflows.
329
+
330
+ ```ts
331
+ interface GetRootPageChangeSources {
332
+ (
333
+ current: RootPagesDoc,
334
+ previous: RootPagesDoc | undefined,
335
+ options: PayloadPluginUrlsOptions,
336
+ ): UrlUpdateSource[]
337
+ }
338
+ ```
339
+
340
+ - **`current`** — New root-pages field values (ids or embedded docs).
341
+ - **`previous`** — Previous root-pages snapshot, or `undefined` on first save.
342
+ - **`options`** — Plugin options determining homepage field and `rootPage` mappings.
343
+
344
+ ### `hasUrlPathChanged`
345
+
346
+ Compares `populatedUrl` on two document-like values when both exist; otherwise compares `slug`.
347
+ Handy in hooks to detect URL-relevant edits.
348
+
349
+ ```ts
350
+ interface HasUrlPathChanged {
351
+ (doc: unknown, previousDoc: unknown): boolean
352
+ }
353
+ ```
354
+
355
+ - **`doc`** — Current document or partial.
356
+ - **`previousDoc`** — Prior revision for comparison.
357
+
358
+ ---
359
+
360
+ ### Exported types
361
+
362
+ References to `GlobalConfig`, `Field`, `LabelFunction`, `StaticLabel`, and `PayloadPlugin` use the
363
+ same names as in [`payload`](https://payloadcms.com/docs/configuration/overview). The following
364
+ interfaces are exported from `payload-plugin-urls` for use in your codebase.
365
+
366
+ #### `PayloadPluginUrlsOptions`
367
+
368
+ ```ts
369
+ interface PayloadPluginUrlsOptions {
370
+ /** Collections that participate in URL generation and how each behaves. */
371
+ collections: Record<string, UrlCollectionOptions>
372
+ /** Applied to the generated `root-pages` global only; see [Root-pages global](#root-pages-global-overrides). */
373
+ overrides?: Partial<GlobalConfig>
374
+ /** Customize the hidden URL field name or field config. */
375
+ field?: {
376
+ name?: string
377
+ overrides?: Record<string, unknown>
378
+ }
379
+ /** Override inferred localization or use helpers outside Payload. */
380
+ locales?: {
381
+ defaultLocale?: Locale
382
+ locales?: Locale[]
383
+ }
384
+ /** Root global slug, label, and relationship fields. */
385
+ rootPages?: {
386
+ slug?: string
387
+ label?: LabelFunction | StaticLabel
388
+ fields?: Record<string, RootPageFieldOptions>
389
+ }
390
+ }
391
+ ```
392
+
393
+ #### `UrlCollectionOptions`
394
+
395
+ ```ts
396
+ interface UrlCollectionOptions {
397
+ /** Use breadcrumb trail for path (typical for page trees). */
398
+ breadcrumbs?: boolean
399
+ /** How category segments appear in the path. */
400
+ prefixStrategy?: UrlPrefixStrategy
401
+ /** Key in `rootPages.fields` whose page defines this collection's URL prefix. */
402
+ rootPage?: string
403
+ category?: {
404
+ collection: string
405
+ field?: string
406
+ }
407
+ routeCollection?: string
408
+ }
409
+ ```
410
+
411
+ #### `RootPageFieldOptions`
412
+
413
+ ```ts
414
+ interface RootPageFieldOptions {
415
+ /** Marks the field whose target is the locale root `/`. */
416
+ isHomepage?: boolean
417
+ relationTo?: string
418
+ overrides?: Partial<Field>
419
+ }
420
+ ```
421
+
422
+ #### `UrlDoc`, `RootPagesDoc`, `Breadcrumb`
423
+
424
+ ```ts
425
+ interface Breadcrumb {
426
+ url?: string | null
427
+ }
428
+
429
+ interface UrlDoc {
430
+ id?: string | number | null
431
+ slug?: string | null
432
+ populatedUrl?: string | null
433
+ breadcrumbs?: Breadcrumb[] | null
434
+ categories?: unknown
435
+ _status?: "draft" | "published" | null
436
+ [key: string]: unknown
437
+ }
438
+
439
+ interface RootPagesDoc {
440
+ id?: string | null
441
+ [field: string]: string | UrlDoc | null | undefined
442
+ }
443
+ ```
444
+
445
+ #### `UrlPrefixStrategy`
446
+
447
+ ```ts
448
+ type UrlPrefixStrategy = "category" | "rootPage"
449
+ ```
450
+
451
+ #### `UrlUpdateSource`
452
+
453
+ ```ts
454
+ type UrlUpdateSource =
455
+ | {
456
+ collection: string
457
+ id?: string | null
458
+ type: "category" | "collection" | "page"
459
+ }
460
+ | {
461
+ current: RootPagesDoc
462
+ previous?: RootPagesDoc
463
+ type: "rootPages"
464
+ }
465
+ ```
466
+
467
+ #### Aliases from Payload
468
+
469
+ `PayloadPlugin`, `PayloadPluginConfig`, `CollectionConfigLike`, `GlobalConfigLike`, `FieldLike`,
470
+ `WorkflowLike`, `PayloadLike`, `Hook`, and `HookArgs` match the names exported from this package and
471
+ follow Payload’s definitions. `Locale` is `string`.
@@ -0,0 +1,2 @@
1
+ var l=e=>e.replace(/\/$/,"").replace(/^\/?/,"/");function c(e){return(e?.at(-1)?.url??"").replace(/(^\/)|(\/$)/g,"")}function b(e,t){return{...t||{},...p(e)}}function x(e){let{populatedUrl:t,...n}=e;return n}function L(e){if(!(!e||typeof e!="object"||!("id"in e)))return typeof e.id=="string"?e.id:void 0}function C(e){if(typeof e=="string")return e;if(!(!e||typeof e!="object"||!("id"in e)))return typeof e.id=="string"?e.id:void 0}function k(e){return l(`/${e??""}`.replace(/\/+/g,"/"))}function w(e,t){if(!e||typeof e!="object"||!(t in e))return;let n=e;return typeof n[t]=="string"?n[t]:void 0}function D(e){return e._status==="draft"}function T(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function h(e){let t=new Set;return e.filter(n=>{let o=f(n);return t.has(o)?!1:(t.add(o),!0)})}function f(e){switch(e.type){case"category":case"collection":case"page":return`${e.type}:${e.collection}:${e.id??""}`;case"rootPages":return`rootPages:${JSON.stringify(e.current)}:${JSON.stringify(e.previous)}`}}function p(e){return Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0))}function i(e,t){let r={...y(t)??{defaultLocale:"en",locales:["en"]},...e.locales};return{...e,field:{name:"populatedUrl",...e.field},locales:{defaultLocale:r.defaultLocale??r.locales[0]??"en",locales:r.locales.length?r.locales:[r.defaultLocale??"en"]},rootPages:{slug:"root-pages",...e.rootPages,fields:e.rootPages?.fields??{indexPage:{isHomepage:!0,relationTo:"pages"}}}}}function u(e,t){return e.collections[t]}function P(e){return Object.entries(e.collections)}function S(e,t){return P(e).filter(([,n])=>n.category?.collection===t).map(([n])=>n)}function R(e){let t=i(e);return Object.keys(t.rootPages.fields)}function $(e){let t=i(e).rootPages.fields;return(Object.entries(t).find(([,o])=>o.isHomepage)??Object.entries(t).find(([o])=>o==="indexPage"))?.[0]??Object.keys(t)[0]??"indexPage"}function z(e,t){return i(e).rootPages.fields[t]}function y(e){let t=e?.localization||void 0,n=t?.locales?.map(o=>typeof o=="string"?o:o.code).filter(o=>!!o);if(n?.length)return{defaultLocale:t?.defaultLocale??n[0]??"en",locales:n}}function I(e,{baseUrl:t,locale:n,options:o,urlPrefixStrategy:r}){if(typeof e.value=="string")throw new Error("Reference value is a string");if(e.value.populatedUrl)return l(e.value.populatedUrl);let a=i(o),s=u(a,e.relationTo),g=s?.routeCollection??e.relationTo,d=U(s,e.value,r??s?.prefixStrategy);return m(d,{baseUrl:t,collection:g,locale:n,options:a})}function m(e,{baseUrl:t,locale:n,options:o}){let r=i(o),s=[...(t||(n===r.locales?.defaultLocale?"":n)).split("/"),...e].filter(Boolean);return l(`/${s.join("/")}`)}function E(e,t,n){let o=i(n).locales?.defaultLocale;return t===o?l(e):l(`/${t}${e}`)}function U(e,t,n){return e?.category?n==="rootPage"?[t.slug??""]:[O(t),t.slug??""]:e?.breadcrumbs?[c(t.breadcrumbs)||t.slug||""]:[t.slug??""]}function O(e){let t=e.categories;if(!Array.isArray(t)||t.length===0)return"";let o=t[0];if(!o||typeof o!="object"||typeof o=="string")return"";let r=o;return c(r.breadcrumbs)||(r.slug??"").replace(/(^\/)|(\/$)/g,"")}export{l as a,c as b,b as c,x as d,L as e,C as f,k as g,w as h,D as i,T as j,h as k,i as l,u as m,P as n,S as o,R as p,$ as q,z as r,I as s,m as t,E as u};
2
+ //# sourceMappingURL=chunk-OKNQKSNQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts","../src/options.ts","../src/link.ts"],"sourcesContent":["import type { Breadcrumb, UrlDoc, UrlUpdateSource } from \"./types\"\n\nconst withoutTrailingSlash = (path: string) => path.replace(/\\/$/, \"\").replace(/^\\/?/, \"/\")\n\nfunction getBreadcrumbsUrl(breadcrumbs: Breadcrumb[] | null | undefined) {\n const lastItem = breadcrumbs?.at(-1)\n const url = lastItem?.url ?? \"\"\n return url.replace(/(^\\/)|(\\/$)/g, \"\")\n}\n\nfunction mergeDoc<T extends object>(data: Partial<T>, originalDoc?: Partial<T>) {\n return {\n ...(originalDoc || {}),\n ...withoutUndefinedValues(data),\n } as T\n}\n\nfunction withoutPopulatedUrl<T extends object>(doc: T) {\n const { populatedUrl: _populatedUrl, ...rest } = doc as T & { populatedUrl?: unknown }\n return rest\n}\n\nfunction getDocumentId(doc: unknown) {\n if (!doc || typeof doc !== \"object\" || !(\"id\" in doc)) {\n return undefined\n }\n\n return typeof doc.id === \"string\" ? doc.id : undefined\n}\n\nfunction getRelationId(value: unknown) {\n if (typeof value === \"string\") {\n return value\n }\n\n if (!value || typeof value !== \"object\" || !(\"id\" in value)) {\n return undefined\n }\n\n return typeof value.id === \"string\" ? value.id : undefined\n}\n\nfunction normalizePath(path: string | undefined) {\n return withoutTrailingSlash(`/${path ?? \"\"}`.replace(/\\/+/g, \"/\"))\n}\n\nfunction getStringValue(value: unknown, key: \"populatedUrl\" | \"slug\") {\n if (!value || typeof value !== \"object\" || !(key in value)) {\n return undefined\n }\n\n const record = value as Record<\"populatedUrl\" | \"slug\", unknown>\n return typeof record[key] === \"string\" ? record[key] : undefined\n}\n\nfunction isDraftDoc(doc: UrlDoc) {\n return doc._status === \"draft\"\n}\n\nfunction getRecord(value: unknown) {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {}\n}\n\nfunction dedupeSources<T extends UrlUpdateSource>(sources: T[]) {\n const seen = new Set<string>()\n\n return sources.filter((source) => {\n const key = sourceKey(source)\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n}\n\nfunction sourceKey(source: UrlUpdateSource) {\n switch (source.type) {\n case \"category\":\n case \"collection\":\n case \"page\":\n return `${source.type}:${source.collection}:${source.id ?? \"\"}`\n case \"rootPages\":\n return `rootPages:${JSON.stringify(source.current)}:${JSON.stringify(source.previous)}`\n }\n}\n\nfunction withoutUndefinedValues<T extends object>(value: Partial<T>) {\n return Object.fromEntries(\n Object.entries(value).filter(([, entry]) => entry !== undefined),\n ) as Partial<T>\n}\n\nexport {\n getBreadcrumbsUrl,\n getRecord,\n dedupeSources,\n isDraftDoc,\n getStringValue,\n normalizePath,\n getRelationId,\n getDocumentId,\n withoutPopulatedUrl,\n mergeDoc,\n withoutTrailingSlash,\n}\n","import type {\n PayloadPluginConfig,\n PayloadPluginUrlsOptions,\n RootPageFieldOptions,\n UrlCollectionOptions,\n} from \"./types\"\n\nexport type NormalizedPayloadPluginUrlsOptions = PayloadPluginUrlsOptions & {\n collections: Record<string, UrlCollectionOptions>\n locales: {\n defaultLocale: string\n locales: string[]\n }\n rootPages: {\n slug: string\n label?: unknown\n fields: Record<string, RootPageFieldOptions>\n }\n}\n\nexport function normalizeOptions(\n options: PayloadPluginUrlsOptions,\n config?: PayloadPluginConfig,\n): NormalizedPayloadPluginUrlsOptions {\n const configLocales = getConfigLocales(config)\n const fallbackLocales = configLocales ?? { defaultLocale: \"en\", locales: [\"en\"] }\n const locales = {\n ...fallbackLocales,\n ...options.locales,\n }\n\n return {\n ...options,\n field: {\n name: \"populatedUrl\",\n ...options.field,\n },\n locales: {\n defaultLocale: locales.defaultLocale ?? locales.locales[0] ?? \"en\",\n locales: locales.locales.length ? locales.locales : [locales.defaultLocale ?? \"en\"],\n },\n rootPages: {\n slug: \"root-pages\",\n ...options.rootPages,\n fields: options.rootPages?.fields ?? {\n indexPage: {\n isHomepage: true,\n relationTo: \"pages\",\n },\n },\n },\n }\n}\n\nexport function getCollectionOptions(options: PayloadPluginUrlsOptions, collection: string) {\n return options.collections[collection]\n}\n\nexport function getCollectionEntries(options: PayloadPluginUrlsOptions) {\n return Object.entries(options.collections)\n}\n\nexport function getCollectionsForCategory(\n options: PayloadPluginUrlsOptions,\n categoryCollection: string,\n) {\n return getCollectionEntries(options)\n .filter(\n ([, collectionOptions]) => collectionOptions.category?.collection === categoryCollection,\n )\n .map(([collection]) => collection)\n}\n\nexport function getRootPageFieldNames(options: PayloadPluginUrlsOptions) {\n const normalizedOptions = normalizeOptions(options)\n return Object.keys(normalizedOptions.rootPages.fields)\n}\n\nexport function getHomepageRootPageField(options: PayloadPluginUrlsOptions) {\n const fields = normalizeOptions(options).rootPages.fields\n const homepageEntry =\n Object.entries(fields).find(([, field]) => field.isHomepage) ??\n Object.entries(fields).find(([fieldName]) => fieldName === \"indexPage\")\n\n return homepageEntry?.[0] ?? Object.keys(fields)[0] ?? \"indexPage\"\n}\n\nexport function getRootPageFieldOptions(options: PayloadPluginUrlsOptions, fieldName: string) {\n return normalizeOptions(options).rootPages.fields[fieldName]\n}\n\nfunction getConfigLocales(config: PayloadPluginConfig | undefined) {\n const localization = config?.localization || undefined\n const locales = localization?.locales\n ?.map((locale) => (typeof locale === \"string\" ? locale : locale.code))\n .filter((locale): locale is string => Boolean(locale))\n\n if (!locales?.length) {\n return undefined\n }\n\n return {\n defaultLocale: localization?.defaultLocale ?? locales[0] ?? \"en\",\n locales,\n }\n}\n","import { getCollectionOptions, normalizeOptions } from \"./options\"\nimport { getBreadcrumbsUrl, withoutTrailingSlash } from \"./utils\"\n\nimport type {\n GetDocumentLinkArgs,\n GetDocumentLinkContext,\n Locale,\n PayloadPluginUrlsOptions,\n UrlCollectionOptions,\n UrlDoc,\n UrlPrefixStrategy,\n} from \"./types\"\n\nexport function getDocumentLink(\n reference: GetDocumentLinkArgs,\n { baseUrl, locale, options, urlPrefixStrategy }: GetDocumentLinkContext,\n) {\n if (typeof reference.value === \"string\") {\n throw new Error(\"Reference value is a string\")\n }\n\n if (reference.value.populatedUrl) {\n return withoutTrailingSlash(reference.value.populatedUrl)\n }\n\n const normalizedOptions = normalizeOptions(options)\n const collectionOptions = getCollectionOptions(normalizedOptions, reference.relationTo)\n const routeCollection = collectionOptions?.routeCollection ?? reference.relationTo\n const slugs = getSlugsForCollection(\n collectionOptions,\n reference.value,\n urlPrefixStrategy ?? collectionOptions?.prefixStrategy,\n )\n\n return getDocumentLinkBySlugs(slugs, {\n baseUrl,\n collection: routeCollection,\n locale,\n options: normalizedOptions,\n })\n}\n\nexport function getDocumentLinkBySlugs(\n slugs: string[],\n {\n baseUrl,\n locale,\n options,\n }: {\n baseUrl?: string\n collection: string\n locale: Locale\n options: PayloadPluginUrlsOptions\n },\n) {\n const normalizedOptions = normalizeOptions(options)\n const prefix = baseUrl || (locale === normalizedOptions.locales?.defaultLocale ? \"\" : locale)\n const segments = [...prefix.split(\"/\"), ...slugs].filter(Boolean)\n return withoutTrailingSlash(`/${segments.join(\"/\")}`)\n}\n\nexport function withLocalePrefix(path: string, locale: Locale, options: PayloadPluginUrlsOptions) {\n const defaultLocale = normalizeOptions(options).locales?.defaultLocale\n if (locale === defaultLocale) {\n return withoutTrailingSlash(path)\n }\n return withoutTrailingSlash(`/${locale}${path}`)\n}\n\nfunction getSlugsForCollection(\n collectionOptions: UrlCollectionOptions | undefined,\n doc: UrlDoc,\n strategy?: UrlPrefixStrategy,\n) {\n if (collectionOptions?.category) {\n return strategy === \"rootPage\"\n ? [doc.slug ?? \"\"]\n : [firstRelatedCategoryPath(doc), doc.slug ?? \"\"]\n }\n\n if (collectionOptions?.breadcrumbs) {\n return [getBreadcrumbsUrl(doc.breadcrumbs) || doc.slug || \"\"]\n }\n\n return [doc.slug ?? \"\"]\n}\n\nfunction firstRelatedCategoryPath(doc: UrlDoc) {\n const categories = doc.categories\n if (!Array.isArray(categories) || categories.length === 0) {\n return \"\"\n }\n\n const categoryItems = categories as unknown[]\n const first = categoryItems[0]\n if (!first || typeof first !== \"object\" || typeof first === \"string\") {\n return \"\"\n }\n\n const categoryDoc = first as UrlDoc\n return (\n getBreadcrumbsUrl(categoryDoc.breadcrumbs) ||\n (categoryDoc.slug ?? \"\").replace(/(^\\/)|(\\/$)/g, \"\")\n )\n}\n"],"mappings":"AAEA,IAAMA,EAAwBC,GAAiBA,EAAK,QAAQ,MAAO,EAAE,EAAE,QAAQ,OAAQ,GAAG,EAE1F,SAASC,EAAkBC,EAA8C,CAGvE,OAFiBA,GAAa,GAAG,EAAE,GACb,KAAO,IAClB,QAAQ,eAAgB,EAAE,CACvC,CAEA,SAASC,EAA2BC,EAAkBC,EAA0B,CAC9E,MAAO,CACL,GAAIA,GAAe,CAAC,EACpB,GAAGC,EAAuBF,CAAI,CAChC,CACF,CAEA,SAASG,EAAsCC,EAAQ,CACrD,GAAM,CAAE,aAAcC,EAAe,GAAGC,CAAK,EAAIF,EACjD,OAAOE,CACT,CAEA,SAASC,EAAcH,EAAc,CACnC,GAAI,GAACA,GAAO,OAAOA,GAAQ,UAAY,EAAE,OAAQA,IAIjD,OAAO,OAAOA,EAAI,IAAO,SAAWA,EAAI,GAAK,MAC/C,CAEA,SAASI,EAAcC,EAAgB,CACrC,GAAI,OAAOA,GAAU,SACnB,OAAOA,EAGT,GAAI,GAACA,GAAS,OAAOA,GAAU,UAAY,EAAE,OAAQA,IAIrD,OAAO,OAAOA,EAAM,IAAO,SAAWA,EAAM,GAAK,MACnD,CAEA,SAASC,EAAcd,EAA0B,CAC/C,OAAOD,EAAqB,IAAIC,GAAQ,EAAE,GAAG,QAAQ,OAAQ,GAAG,CAAC,CACnE,CAEA,SAASe,EAAeF,EAAgBG,EAA8B,CACpE,GAAI,CAACH,GAAS,OAAOA,GAAU,UAAY,EAAEG,KAAOH,GAClD,OAGF,IAAMI,EAASJ,EACf,OAAO,OAAOI,EAAOD,CAAG,GAAM,SAAWC,EAAOD,CAAG,EAAI,MACzD,CAEA,SAASE,EAAWV,EAAa,CAC/B,OAAOA,EAAI,UAAY,OACzB,CAEA,SAASW,EAAUN,EAAgB,CACjC,OAAOA,GAAS,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,EAC5DA,EACD,CAAC,CACP,CAEA,SAASO,EAAyCC,EAAc,CAC9D,IAAMC,EAAO,IAAI,IAEjB,OAAOD,EAAQ,OAAQE,GAAW,CAChC,IAAMP,EAAMQ,EAAUD,CAAM,EAC5B,OAAID,EAAK,IAAIN,CAAG,EACP,IAETM,EAAK,IAAIN,CAAG,EACL,GACT,CAAC,CACH,CAEA,SAASQ,EAAUD,EAAyB,CAC1C,OAAQA,EAAO,KAAM,CACnB,IAAK,WACL,IAAK,aACL,IAAK,OACH,MAAO,GAAGA,EAAO,IAAI,IAAIA,EAAO,UAAU,IAAIA,EAAO,IAAM,EAAE,GAC/D,IAAK,YACH,MAAO,aAAa,KAAK,UAAUA,EAAO,OAAO,CAAC,IAAI,KAAK,UAAUA,EAAO,QAAQ,CAAC,EACzF,CACF,CAEA,SAASjB,EAAyCO,EAAmB,CACnE,OAAO,OAAO,YACZ,OAAO,QAAQA,CAAK,EAAE,OAAO,CAAC,CAAC,CAAEY,CAAK,IAAMA,IAAU,MAAS,CACjE,CACF,CCzEO,SAASC,EACdC,EACAC,EACoC,CAGpC,IAAMC,EAAU,CACd,GAHoBC,EAAiBF,CAAM,GACJ,CAAE,cAAe,KAAM,QAAS,CAAC,IAAI,CAAE,EAG9E,GAAGD,EAAQ,OACb,EAEA,MAAO,CACL,GAAGA,EACH,MAAO,CACL,KAAM,eACN,GAAGA,EAAQ,KACb,EACA,QAAS,CACP,cAAeE,EAAQ,eAAiBA,EAAQ,QAAQ,CAAC,GAAK,KAC9D,QAASA,EAAQ,QAAQ,OAASA,EAAQ,QAAU,CAACA,EAAQ,eAAiB,IAAI,CACpF,EACA,UAAW,CACT,KAAM,aACN,GAAGF,EAAQ,UACX,OAAQA,EAAQ,WAAW,QAAU,CACnC,UAAW,CACT,WAAY,GACZ,WAAY,OACd,CACF,CACF,CACF,CACF,CAEO,SAASI,EAAqBJ,EAAmCK,EAAoB,CAC1F,OAAOL,EAAQ,YAAYK,CAAU,CACvC,CAEO,SAASC,EAAqBN,EAAmC,CACtE,OAAO,OAAO,QAAQA,EAAQ,WAAW,CAC3C,CAEO,SAASO,EACdP,EACAQ,EACA,CACA,OAAOF,EAAqBN,CAAO,EAChC,OACC,CAAC,CAAC,CAAES,CAAiB,IAAMA,EAAkB,UAAU,aAAeD,CACxE,EACC,IAAI,CAAC,CAACH,CAAU,IAAMA,CAAU,CACrC,CAEO,SAASK,EAAsBV,EAAmC,CACvE,IAAMW,EAAoBZ,EAAiBC,CAAO,EAClD,OAAO,OAAO,KAAKW,EAAkB,UAAU,MAAM,CACvD,CAEO,SAASC,EAAyBZ,EAAmC,CAC1E,IAAMa,EAASd,EAAiBC,CAAO,EAAE,UAAU,OAKnD,OAHE,OAAO,QAAQa,CAAM,EAAE,KAAK,CAAC,CAAC,CAAEC,CAAK,IAAMA,EAAM,UAAU,GAC3D,OAAO,QAAQD,CAAM,EAAE,KAAK,CAAC,CAACE,CAAS,IAAMA,IAAc,WAAW,KAEjD,CAAC,GAAK,OAAO,KAAKF,CAAM,EAAE,CAAC,GAAK,WACzD,CAEO,SAASG,EAAwBhB,EAAmCe,EAAmB,CAC5F,OAAOhB,EAAiBC,CAAO,EAAE,UAAU,OAAOe,CAAS,CAC7D,CAEA,SAASZ,EAAiBF,EAAyC,CACjE,IAAMgB,EAAehB,GAAQ,cAAgB,OACvCC,EAAUe,GAAc,SAC1B,IAAKC,GAAY,OAAOA,GAAW,SAAWA,EAASA,EAAO,IAAK,EACpE,OAAQA,GAA6B,EAAQA,CAAO,EAEvD,GAAKhB,GAAS,OAId,MAAO,CACL,cAAee,GAAc,eAAiBf,EAAQ,CAAC,GAAK,KAC5D,QAAAA,CACF,CACF,CC5FO,SAASiB,EACdC,EACA,CAAE,QAAAC,EAAS,OAAAC,EAAQ,QAAAC,EAAS,kBAAAC,CAAkB,EAC9C,CACA,GAAI,OAAOJ,EAAU,OAAU,SAC7B,MAAM,IAAI,MAAM,6BAA6B,EAG/C,GAAIA,EAAU,MAAM,aAClB,OAAOK,EAAqBL,EAAU,MAAM,YAAY,EAG1D,IAAMM,EAAoBC,EAAiBJ,CAAO,EAC5CK,EAAoBC,EAAqBH,EAAmBN,EAAU,UAAU,EAChFU,EAAkBF,GAAmB,iBAAmBR,EAAU,WAClEW,EAAQC,EACZJ,EACAR,EAAU,MACVI,GAAqBI,GAAmB,cAC1C,EAEA,OAAOK,EAAuBF,EAAO,CACnC,QAAAV,EACA,WAAYS,EACZ,OAAAR,EACA,QAASI,CACX,CAAC,CACH,CAEO,SAASO,EACdF,EACA,CACE,QAAAV,EACA,OAAAC,EACA,QAAAC,CACF,EAMA,CACA,IAAMG,EAAoBC,EAAiBJ,CAAO,EAE5CW,EAAW,CAAC,IADHb,IAAYC,IAAWI,EAAkB,SAAS,cAAgB,GAAKJ,IAC1D,MAAM,GAAG,EAAG,GAAGS,CAAK,EAAE,OAAO,OAAO,EAChE,OAAON,EAAqB,IAAIS,EAAS,KAAK,GAAG,CAAC,EAAE,CACtD,CAEO,SAASC,EAAiBC,EAAcd,EAAgBC,EAAmC,CAChG,IAAMc,EAAgBV,EAAiBJ,CAAO,EAAE,SAAS,cACzD,OAAID,IAAWe,EACNZ,EAAqBW,CAAI,EAE3BX,EAAqB,IAAIH,CAAM,GAAGc,CAAI,EAAE,CACjD,CAEA,SAASJ,EACPJ,EACAU,EACAC,EACA,CACA,OAAIX,GAAmB,SACdW,IAAa,WAChB,CAACD,EAAI,MAAQ,EAAE,EACf,CAACE,EAAyBF,CAAG,EAAGA,EAAI,MAAQ,EAAE,EAGhDV,GAAmB,YACd,CAACa,EAAkBH,EAAI,WAAW,GAAKA,EAAI,MAAQ,EAAE,EAGvD,CAACA,EAAI,MAAQ,EAAE,CACxB,CAEA,SAASE,EAAyBF,EAAa,CAC7C,IAAMI,EAAaJ,EAAI,WACvB,GAAI,CAAC,MAAM,QAAQI,CAAU,GAAKA,EAAW,SAAW,EACtD,MAAO,GAIT,IAAMC,EADgBD,EACM,CAAC,EAC7B,GAAI,CAACC,GAAS,OAAOA,GAAU,UAAY,OAAOA,GAAU,SAC1D,MAAO,GAGT,IAAMC,EAAcD,EACpB,OACEF,EAAkBG,EAAY,WAAW,IACxCA,EAAY,MAAQ,IAAI,QAAQ,eAAgB,EAAE,CAEvD","names":["withoutTrailingSlash","path","getBreadcrumbsUrl","breadcrumbs","mergeDoc","data","originalDoc","withoutUndefinedValues","withoutPopulatedUrl","doc","_populatedUrl","rest","getDocumentId","getRelationId","value","normalizePath","getStringValue","key","record","isDraftDoc","getRecord","dedupeSources","sources","seen","source","sourceKey","entry","normalizeOptions","options","config","locales","getConfigLocales","getCollectionOptions","collection","getCollectionEntries","getCollectionsForCategory","categoryCollection","collectionOptions","getRootPageFieldNames","normalizedOptions","getHomepageRootPageField","fields","field","fieldName","getRootPageFieldOptions","localization","locale","getDocumentLink","reference","baseUrl","locale","options","urlPrefixStrategy","withoutTrailingSlash","normalizedOptions","normalizeOptions","collectionOptions","getCollectionOptions","routeCollection","slugs","getSlugsForCollection","getDocumentLinkBySlugs","segments","withLocalePrefix","path","defaultLocale","doc","strategy","firstRelatedCategoryPath","getBreadcrumbsUrl","categories","first","categoryDoc"]}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var j=Object.defineProperty;var Z=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var oo=Object.prototype.hasOwnProperty;var eo=(o,e)=>{for(var t in e)j(o,t,{get:e[t],enumerable:!0})},to=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of q(e))!oo.call(o,r)&&r!==t&&j(o,r,{get:()=>e[r],enumerable:!(n=Z(e,r))||n.enumerable});return o};var no=o=>to(j({},"__esModule",{value:!0}),o);var yo={};eo(yo,{default:()=>B,getBreadcrumbsUrl:()=>g,getDocumentLink:()=>U,getDocumentLinkBySlugs:()=>v,getRootPageChangeSources:()=>I,hasUrlPathChanged:()=>F,payloadPluginUrls:()=>B,populatedUrlField:()=>L,resolvePopulatedUrl:()=>y,withLocalePrefix:()=>O,withoutTrailingSlash:()=>d});module.exports=no(yo);var d=o=>o.replace(/\/$/,"").replace(/^\/?/,"/");function g(o){return(o?.at(-1)?.url??"").replace(/(^\/)|(\/$)/g,"")}function G(o,e){return{...e||{},...lo(o)}}function z(o){let{populatedUrl:e,...t}=o;return t}function N(o){if(!(!o||typeof o!="object"||!("id"in o)))return typeof o.id=="string"?o.id:void 0}function k(o){if(typeof o=="string")return o;if(!(!o||typeof o!="object"||!("id"in o)))return typeof o.id=="string"?o.id:void 0}function C(o){return d(`/${o??""}`.replace(/\/+/g,"/"))}function b(o,e){if(!o||typeof o!="object"||!(e in o))return;let t=o;return typeof t[e]=="string"?t[e]:void 0}function D(o){return o._status==="draft"}function E(o){return o&&typeof o=="object"&&!Array.isArray(o)?o:{}}function _(o){let e=new Set;return o.filter(t=>{let n=ro(t);return e.has(n)?!1:(e.add(n),!0)})}function ro(o){switch(o.type){case"category":case"collection":case"page":return`${o.type}:${o.collection}:${o.id??""}`;case"rootPages":return`rootPages:${JSON.stringify(o.current)}:${JSON.stringify(o.previous)}`}}function lo(o){return Object.fromEntries(Object.entries(o).filter(([,e])=>e!==void 0))}function L(o={collections:{}}){return{name:o.field?.name??"populatedUrl",type:"text",label:!1,localized:!0,...o.field?.overrides??{},admin:{hidden:!0,...E(o.field?.overrides?.admin)}}}function c(o,e){let r={...ao(e)??{defaultLocale:"en",locales:["en"]},...o.locales};return{...o,field:{name:"populatedUrl",...o.field},locales:{defaultLocale:r.defaultLocale??r.locales[0]??"en",locales:r.locales.length?r.locales:[r.defaultLocale??"en"]},rootPages:{slug:"root-pages",...o.rootPages,fields:o.rootPages?.fields??{indexPage:{isHomepage:!0,relationTo:"pages"}}}}}function p(o,e){return o.collections[e]}function H(o){return Object.entries(o.collections)}function x(o,e){return H(o).filter(([,t])=>t.category?.collection===e).map(([t])=>t)}function w(o){let e=c(o);return Object.keys(e.rootPages.fields)}function R(o){let e=c(o).rootPages.fields;return(Object.entries(e).find(([,n])=>n.isHomepage)??Object.entries(e).find(([n])=>n==="indexPage"))?.[0]??Object.keys(e)[0]??"indexPage"}function m(o,e){return c(o).rootPages.fields[e]}function ao(o){let e=o?.localization||void 0,t=e?.locales?.map(n=>typeof n=="string"?n:n.code).filter(n=>!!n);if(t?.length)return{defaultLocale:e?.defaultLocale??t[0]??"en",locales:t}}function U(o,{baseUrl:e,locale:t,options:n,urlPrefixStrategy:r}){if(typeof o.value=="string")throw new Error("Reference value is a string");if(o.value.populatedUrl)return d(o.value.populatedUrl);let l=c(n),i=p(l,o.relationTo),s=i?.routeCollection??o.relationTo,a=io(i,o.value,r??i?.prefixStrategy);return v(a,{baseUrl:e,collection:s,locale:t,options:l})}function v(o,{baseUrl:e,locale:t,options:n}){let r=c(n),i=[...(e||(t===r.locales?.defaultLocale?"":t)).split("/"),...o].filter(Boolean);return d(`/${i.join("/")}`)}function O(o,e,t){let n=c(t).locales?.defaultLocale;return e===n?d(o):d(`/${e}${o}`)}function io(o,e,t){return o?.category?t==="rootPage"?[e.slug??""]:[so(e),e.slug??""]:o?.breadcrumbs?[g(e.breadcrumbs)||e.slug||""]:[e.slug??""]}function so(o){let e=o.categories;if(!Array.isArray(e)||e.length===0)return"";let n=e[0];if(!n||typeof n!="object"||typeof n=="string")return"";let r=n;return g(r.breadcrumbs)||(r.slug??"").replace(/(^\/)|(\/$)/g,"")}async function y({collection:o,data:e,locale:t,options:n,originalDoc:r,payload:l,rootPages:i}){let s=c(n),a=p(s,o);if(!a)return;let u=G(e,r),f=R(s);if(a.breadcrumbs&&!a.rootPage){let P=await W({field:f,locale:t,payload:l,rootPages:i}),X=N(P);if(u.id&&X===u.id)return O("/",t,s);let S=C(g(u.breadcrumbs)),T=C(g(P?.breadcrumbs)),Y=T&&S.startsWith(`${T}/`)?C(S.slice(T.length)):S;return O(Y||`/${u.slug??""}`,t,s)}let h=await co({collectionOptions:a,locale:t,options:s,payload:l,rootPages:i});if(a.category){let P=await uo({categories:u[a.category.field??"categories"],collection:a.category.collection,locale:t,payload:l});return U({relationTo:o,value:{...z(u),[a.category.field??"categories"]:P,categories:P}},{baseUrl:h,locale:t,options:s})}return U({relationTo:o,value:z(u)},{baseUrl:h,locale:t,options:s})}async function co({collectionOptions:o,locale:e,options:t,payload:n,rootPages:r}){if(!o.rootPage)return;let l=o.rootPage,s=m(t,l)?.relationTo??"pages",a=await W({collection:s,field:l,locale:e,payload:n,rootPages:r});if(a)return typeof a.populatedUrl=="string"&&a.populatedUrl?V(a.populatedUrl,e,t):s!=="pages"?V(U({relationTo:s,value:a},{locale:e,options:t}),e,t):y({collection:s,data:{},locale:e,options:t,originalDoc:a,payload:n,rootPages:r})}function V(o,e,t){let n=c(t);return e===n.locales.defaultLocale||o===`/${e}`||o.startsWith(`/${e}/`)?o:O(o,e,n)}async function W({collection:o="pages",field:e,locale:t,payload:n,rootPages:r}){let l=r[e];return l?typeof l!="string"?l:await n?.findByID?.({collection:o,id:l,depth:0,locale:t,select:{id:!0,slug:!0,populatedUrl:!0,breadcrumbs:!0}}):void 0}async function uo({categories:o,collection:e,locale:t,payload:n}){return Array.isArray(o)?Promise.all(o.map(r=>typeof r!="string"?Promise.resolve(r):n?.findByID?.({collection:e,id:r,depth:2,locale:t})??Promise.resolve(r))):[]}function M(o){return async({job:e,req:t})=>{let n=c(o),r=e.input?.sources??[];for(let l of n.locales?.locales??[]){let i=await t.payload.findGlobal?.({slug:n.rootPages?.slug??"root-pages",depth:2,locale:l});if(i)for(let s of go(r,n))switch(s.type){case"category":await A({collection:s.collection,locale:l,options:n,payload:t.payload,rootPages:i});for(let a of x(n,s.collection))await A({collection:a,locale:l,options:n,payload:t.payload,rootPages:i});break;case"collection":case"page":await A({collection:s.collection,locale:l,options:n,payload:t.payload,rootPages:i});break;case"rootPages":break}}}}function F(o,e){let t=b(o,"populatedUrl"),n=b(e,"populatedUrl");return t&&n?t!==n:b(o,"slug")!==b(e,"slug")}function I(o,e,t){let n=c(t),r=[],l=R(n),i=m(n,l)?.relationTo??"pages",s=k(o[l]),a=k(e?.[l]);s!==a&&(s&&r.push({type:"page",collection:i,id:s}),a&&r.push({type:"page",collection:i,id:a}));for(let[u,f]of H(n)){if(!f.rootPage)continue;let h=k(o[f.rootPage]),P=k(e?.[f.rootPage]);h!==P&&r.push({type:"collection",collection:u})}return _(r)}function $(o,e){let t={};for(let n of w(e))t[n]=o?.[n];return t}function go(o,e){return o.flatMap(t=>t.type!=="rootPages"?[t]:I(t.current,t.previous,e))}async function A({collection:o,locale:e,options:t,payload:n,rootPages:r}){let l=1;for(;;){let i=await n.find?.({collection:o,depth:2,draft:!1,limit:100,locale:e,overrideAccess:!0,page:l,pagination:!0});if(!i)return;for(let s of i.docs){let a=s;if(!a.id||D(a))continue;let u=await y({collection:o,data:{},locale:e,options:t,originalDoc:a,payload:n,rootPages:r});!u||a.populatedUrl===u||await n.update?.({collection:o,id:a.id,locale:e,overrideAccess:!0,data:{[t.field?.name??"populatedUrl"]:u},context:{disablePopulateUrl:!0,disableUrlUpdates:!0}})}if(!i.nextPage)return;l=i.nextPage}}function J(o){return async({collection:e,context:t,data:n={},originalDoc:r,req:l})=>{let i=l.locale;if(!i||i==="all"||t?.disablePopulateUrl||l.context?.disablePopulateUrl)return n;let s=await l.payload.findGlobal?.({slug:c(o).rootPages?.slug??"root-pages",depth:2,locale:i});if(!s)return n;let a=await y({collection:e?.slug??"",data:n,locale:i,options:o,originalDoc:r,payload:l.payload,rootPages:s});return a&&(n[o.field?.name??"populatedUrl"]=a),n}}function K(o){return async({collection:e,doc:t,previousDoc:n,req:r})=>{let l=t,i=n;if(r.context?.disableUrlUpdates||!l||D(l)||!F(l,i))return l;let s=p(o,e?.slug??"");if(!s)return l;let a=e?.slug??"",f=x(o,a).length>0?{type:"category",collection:a,id:l.id}:{type:s.breadcrumbs&&!s.rootPage?"page":"collection",collection:a,id:l.id};return await r.payload.jobs?.queue?.({workflow:"update-urls",input:{sources:[f]}}),l}}function Q(o){return async({doc:e,previousDoc:t,req:n})=>{let r=e,l=t;return n.context?.disableUrlUpdates||await n.payload.jobs?.queue?.({workflow:"update-urls",input:{sources:[{type:"rootPages",current:$(r,o),previous:$(l,o)}]}}),r}}var B=o=>o?e=>{let t=c(o,e),n=(e.collections??[]).map(r=>po(r,t));return{...e,collections:n,globals:[...e.globals??[],fo(t)],jobs:{...e.jobs??{},workflows:[...e.jobs?.workflows??[],{slug:"update-urls",handler:M(t)}]}}}:e=>e;function po(o,e){if(!p(e,o.slug))return o;let n=e.field?.name??"populatedUrl",r=o.fields.some(i=>"name"in i&&i.name===n)?o.fields:[...o.fields,L(e)],l=o.hooks??{};return{...o,defaultPopulate:{...o.defaultPopulate??{},[n]:!0},fields:r,hooks:{...l,beforeChange:[...l.beforeChange??[],J(e)],afterChange:[...l.afterChange??[],K(e)]}}}function fo(o){let e=c(o).rootPages;return{slug:e?.slug??"root-pages",label:e?.label??"Root pages",fields:w(o).map(t=>Po(t,o)),hooks:{afterChange:[Q(o)]}}}function Po(o,e){let t=m(e,o),n=t?.overrides??{},{name:r,type:l,hasMany:i,relationTo:s,...a}=n;return{name:o,type:"relationship",relationTo:t?.relationTo??"pages",hasMany:!1,admin:{width:"50%"},...a}}0&&(module.exports={getBreadcrumbsUrl,getDocumentLink,getDocumentLinkBySlugs,getRootPageChangeSources,hasUrlPathChanged,payloadPluginUrls,populatedUrlField,resolvePopulatedUrl,withLocalePrefix,withoutTrailingSlash});
1
+ "use strict";var H=Object.defineProperty;var oo=Object.getOwnPropertyDescriptor;var eo=Object.getOwnPropertyNames;var to=Object.prototype.hasOwnProperty;var no=(o,e)=>{for(var t in e)H(o,t,{get:e[t],enumerable:!0})},ro=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of eo(e))!to.call(o,r)&&r!==t&&H(o,r,{get:()=>e[r],enumerable:!(n=oo(e,r))||n.enumerable});return o};var lo=o=>ro(H({},"__esModule",{value:!0}),o);var Oo={};no(Oo,{default:()=>$,getBreadcrumbsUrl:()=>g,getDocumentLink:()=>U,getDocumentLinkBySlugs:()=>G,getRootPageChangeSources:()=>z,hasUrlPathChanged:()=>F,payloadPluginUrls:()=>$,populatedUrlField:()=>L,resolvePopulatedUrl:()=>y,withLocalePrefix:()=>k,withoutTrailingSlash:()=>d});module.exports=lo(Oo);var d=o=>o.replace(/\/$/,"").replace(/^\/?/,"/");function g(o){return(o?.at(-1)?.url??"").replace(/(^\/)|(\/$)/g,"")}function B(o,e){return{...e||{},...ao(o)}}function T(o){let{populatedUrl:e,...t}=o;return t}function N(o){if(!(!o||typeof o!="object"||!("id"in o)))return typeof o.id=="string"?o.id:void 0}function O(o){if(typeof o=="string")return o;if(!(!o||typeof o!="object"||!("id"in o)))return typeof o.id=="string"?o.id:void 0}function h(o){return d(`/${o??""}`.replace(/\/+/g,"/"))}function C(o,e){if(!o||typeof o!="object"||!(e in o))return;let t=o;return typeof t[e]=="string"?t[e]:void 0}function w(o){return o._status==="draft"}function _(o){return o&&typeof o=="object"&&!Array.isArray(o)?o:{}}function E(o){let e=new Set;return o.filter(t=>{let n=io(t);return e.has(n)?!1:(e.add(n),!0)})}function io(o){switch(o.type){case"category":case"collection":case"page":return`${o.type}:${o.collection}:${o.id??""}`;case"rootPages":return`rootPages:${JSON.stringify(o.current)}:${JSON.stringify(o.previous)}`}}function ao(o){return Object.fromEntries(Object.entries(o).filter(([,e])=>e!==void 0))}function L(o={collections:{}}){return{name:o.field?.name??"populatedUrl",type:"text",label:!1,localized:!0,...o.field?.overrides??{},admin:{hidden:!0,..._(o.field?.overrides?.admin)}}}function c(o,e){let r={...so(e)??{defaultLocale:"en",locales:["en"]},...o.locales};return{...o,field:{name:"populatedUrl",...o.field},locales:{defaultLocale:r.defaultLocale??r.locales[0]??"en",locales:r.locales.length?r.locales:[r.defaultLocale??"en"]},rootPages:{slug:"root-pages",...o.rootPages,fields:o.rootPages?.fields??{indexPage:{isHomepage:!0,relationTo:"pages"}}}}}function p(o,e){return o.collections[e]}function j(o){return Object.entries(o.collections)}function R(o,e){return j(o).filter(([,t])=>t.category?.collection===e).map(([t])=>t)}function D(o){let e=c(o);return Object.keys(e.rootPages.fields)}function x(o){let e=c(o).rootPages.fields;return(Object.entries(e).find(([,n])=>n.isHomepage)??Object.entries(e).find(([n])=>n==="indexPage"))?.[0]??Object.keys(e)[0]??"indexPage"}function m(o,e){return c(o).rootPages.fields[e]}function so(o){let e=o?.localization||void 0,t=e?.locales?.map(n=>typeof n=="string"?n:n.code).filter(n=>!!n);if(t?.length)return{defaultLocale:e?.defaultLocale??t[0]??"en",locales:t}}function U(o,{baseUrl:e,locale:t,options:n,urlPrefixStrategy:r}){if(typeof o.value=="string")throw new Error("Reference value is a string");if(o.value.populatedUrl)return d(o.value.populatedUrl);let l=c(n),a=p(l,o.relationTo),i=a?.routeCollection??o.relationTo,s=co(a,o.value,r??a?.prefixStrategy);return G(s,{baseUrl:e,collection:i,locale:t,options:l})}function G(o,{baseUrl:e,locale:t,options:n}){let r=c(n),a=[...(e||(t===r.locales?.defaultLocale?"":t)).split("/"),...o].filter(Boolean);return d(`/${a.join("/")}`)}function k(o,e,t){let n=c(t).locales?.defaultLocale;return e===n?d(o):d(`/${e}${o}`)}function co(o,e,t){return o?.category?t==="rootPage"?[e.slug??""]:[uo(e),e.slug??""]:o?.breadcrumbs?[g(e.breadcrumbs)||e.slug||""]:[e.slug??""]}function uo(o){let e=o.categories;if(!Array.isArray(e)||e.length===0)return"";let n=e[0];if(!n||typeof n!="object"||typeof n=="string")return"";let r=n;return g(r.breadcrumbs)||(r.slug??"").replace(/(^\/)|(\/$)/g,"")}async function y({collection:o,data:e,locale:t,options:n,originalDoc:r,payload:l,rootPages:a}){let i=c(n),s=p(i,o);if(!s)return;let u=B(e,r),f=x(i);if(s.breadcrumbs&&!s.rootPage){let P=await W({field:f,locale:t,payload:l,rootPages:a}),Z=N(P);if(u.id&&Z===u.id)return k("/",t,i);let S=h(g(u.breadcrumbs)),A=h(g(P?.breadcrumbs)),q=A&&S.startsWith(`${A}/`)?h(S.slice(A.length)):S;return k(q||`/${u.slug??""}`,t,i)}let b=await go({collectionOptions:s,locale:t,options:i,payload:l,rootPages:a});if(s.category){let P=await po({categories:u[s.category.field??"categories"],collection:s.category.collection,locale:t,payload:l});return U({relationTo:o,value:{...T(u),[s.category.field??"categories"]:P,categories:P}},{baseUrl:b,locale:t,options:i})}return U({relationTo:o,value:T(u)},{baseUrl:b,locale:t,options:i})}async function go({collectionOptions:o,locale:e,options:t,payload:n,rootPages:r}){if(!o.rootPage)return;let l=o.rootPage,i=m(t,l)?.relationTo??"pages",s=await W({collection:i,field:l,locale:e,payload:n,rootPages:r});if(s)return typeof s.populatedUrl=="string"&&s.populatedUrl?V(s.populatedUrl,e,t):i!=="pages"?V(U({relationTo:i,value:s},{locale:e,options:t}),e,t):y({collection:i,data:{},locale:e,options:t,originalDoc:s,payload:n,rootPages:r})}function V(o,e,t){let n=c(t);return e===n.locales.defaultLocale||o===`/${e}`||o.startsWith(`/${e}/`)?o:k(o,e,n)}async function W({collection:o="pages",field:e,locale:t,payload:n,rootPages:r}){let l=r[e];return l?typeof l!="string"?l:await n?.findByID?.({collection:o,id:l,depth:0,locale:t,select:{id:!0,slug:!0,populatedUrl:!0,breadcrumbs:!0}}):void 0}async function po({categories:o,collection:e,locale:t,payload:n}){return Array.isArray(o)?Promise.all(o.map(r=>typeof r!="string"?Promise.resolve(r):n?.findByID?.({collection:e,id:r,depth:2,locale:t})??Promise.resolve(r))):[]}function M(o){return async({job:e,req:t})=>{let n=c(o),r=e.input?.sources??[];for(let l of n.locales?.locales??[]){let a=await t.payload.findGlobal?.({slug:n.rootPages?.slug??"root-pages",depth:2,locale:l});if(a)for(let i of fo(r,n))switch(i.type){case"category":await v({collection:i.collection,locale:l,options:n,payload:t.payload,rootPages:a});for(let s of R(n,i.collection))await v({collection:s,locale:l,options:n,payload:t.payload,rootPages:a});break;case"collection":case"page":await v({collection:i.collection,locale:l,options:n,payload:t.payload,rootPages:a});break;case"rootPages":break}}}}function F(o,e){let t=C(o,"populatedUrl"),n=C(e,"populatedUrl");return t&&n?t!==n:C(o,"slug")!==C(e,"slug")}function z(o,e,t){let n=c(t),r=[],l=x(n),a=m(n,l)?.relationTo??"pages",i=O(o[l]),s=O(e?.[l]);i!==s&&(i&&r.push({type:"page",collection:a,id:i}),s&&r.push({type:"page",collection:a,id:s}));for(let[u,f]of j(n)){if(!f.rootPage)continue;let b=O(o[f.rootPage]),P=O(e?.[f.rootPage]);b!==P&&r.push({type:"collection",collection:u})}return E(r)}function I(o,e){let t={};for(let n of D(e))t[n]=o?.[n];return t}function fo(o,e){return o.flatMap(t=>t.type!=="rootPages"?[t]:z(t.current,t.previous,e))}async function v({collection:o,locale:e,options:t,payload:n,rootPages:r}){let l=1;for(;;){let a=await n.find?.({collection:o,depth:2,draft:!1,limit:100,locale:e,overrideAccess:!0,page:l,pagination:!0});if(!a)return;for(let i of a.docs){let s=i;if(!s.id||w(s))continue;let u=await y({collection:o,data:{},locale:e,options:t,originalDoc:s,payload:n,rootPages:r});!u||s.populatedUrl===u||await n.update?.({collection:o,id:s.id,locale:e,overrideAccess:!0,data:{[t.field?.name??"populatedUrl"]:u},context:{disablePopulateUrl:!0,disableUrlUpdates:!0}})}if(!a.nextPage)return;l=a.nextPage}}function J(o){return async({collection:e,context:t,data:n={},originalDoc:r,req:l})=>{let a=l.locale;if(!a||a==="all"||t?.disablePopulateUrl||l.context?.disablePopulateUrl)return n;let i=await l.payload.findGlobal?.({slug:c(o).rootPages?.slug??"root-pages",depth:2,locale:a});if(!i)return n;let s=await y({collection:e?.slug??"",data:n,locale:a,options:o,originalDoc:r,payload:l.payload,rootPages:i});return s&&(n[o.field?.name??"populatedUrl"]=s),n}}function K(o){return async({collection:e,doc:t,previousDoc:n,req:r})=>{let l=t,a=n;if(r.context?.disableUrlUpdates||!l||w(l)||!F(l,a))return l;let i=p(o,e?.slug??"");if(!i)return l;let s=e?.slug??"",f=R(o,s).length>0?{type:"category",collection:s,id:l.id}:{type:i.breadcrumbs&&!i.rootPage?"page":"collection",collection:s,id:l.id};return await r.payload.jobs?.queue?.({workflow:"update-urls",input:{sources:[f]}}),l}}function Q(o){return async({doc:e,previousDoc:t,req:n})=>{let r=e,l=t;return n.context?.disableUrlUpdates||await n.payload.jobs?.queue?.({workflow:"update-urls",input:{sources:[{type:"rootPages",current:I(r,o),previous:I(l,o)}]}}),r}}var $=o=>o?e=>{let t=c(o,e),n=(e.collections??[]).map(r=>Po(r,t));return{...e,collections:n,globals:[...e.globals??[],yo(t)],jobs:{...e.jobs??{},workflows:[...e.jobs?.workflows??[],{slug:"update-urls",handler:M(t)}]}}}:e=>e;function Po(o,e){if(!p(e,o.slug))return o;let n=e.field?.name??"populatedUrl",r=o.fields.some(a=>"name"in a&&a.name===n)?o.fields:[...o.fields,L(e)],l=o.hooks??{};return{...o,defaultPopulate:{...o.defaultPopulate??{},[n]:!0},fields:r,hooks:{...l,beforeChange:[...l.beforeChange??[],J(e)],afterChange:[...l.afterChange??[],K(e)]}}}function yo(o){let e=c(o).rootPages,t={slug:e?.slug??"root-pages",label:e?.label??"Root pages",fields:D(o).map(r=>mo(r,o)),hooks:{afterChange:[Q(o)]}},n=o.overrides;return n?ko(t,n):t}function mo(o,e){let t=m(e,o),n=t?.overrides??{},{name:r,type:l,hasMany:a,relationTo:i,...s}=n;return{name:o,type:"relationship",relationTo:t?.relationTo??"pages",hasMany:!1,admin:{width:"50%"},...s}}function X(o){if(!Array.isArray(o))return[];let e=[];for(let t of o)e.push(t);return e}function Uo(o,e){if(!e)return o;if(!o)return e;let t=o,n=e,r={...t};for(let l of Object.keys(n)){let a=t[l],i=n[l];Array.isArray(a)||Array.isArray(i)?r[l]=[...X(a),...X(i)]:i!==void 0&&(r[l]=i)}return r}function Y(o,e){return e?o?{...o,...e}:e:o}function ko(o,e){let{hooks:t,access:n,admin:r,fields:l,...a}=e,i={...o,...a};return n&&(i.access=Y(o.access,n)),r&&(i.admin=Y(o.admin,r)),(t||o.hooks)&&(i.hooks=Uo(o.hooks,t)),i}0&&(module.exports={getBreadcrumbsUrl,getDocumentLink,getDocumentLinkBySlugs,getRootPageChangeSources,hasUrlPathChanged,payloadPluginUrls,populatedUrlField,resolvePopulatedUrl,withLocalePrefix,withoutTrailingSlash});
2
2
  //# sourceMappingURL=index.cjs.map