@payload-onpage/plugin 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +15 -2
- package/dist/access.d.ts +20 -0
- package/dist/access.d.ts.map +1 -0
- package/dist/access.js +51 -0
- package/dist/access.js.map +1 -0
- package/dist/admin/OnPageAdminControls.d.ts +9 -0
- package/dist/admin/OnPageAdminControls.d.ts.map +1 -0
- package/dist/admin/OnPageAdminControls.js +59 -0
- package/dist/admin/OnPageAdminControls.js.map +1 -0
- package/dist/admin/index.d.ts +3 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +2 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/endpoints.d.ts +11 -0
- package/dist/endpoints.d.ts.map +1 -0
- package/dist/endpoints.js +223 -0
- package/dist/endpoints.js.map +1 -0
- package/dist/hooks.d.ts +38 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +42 -0
- package/dist/hooks.js.map +1 -0
- package/dist/http.d.ts +23 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +53 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +148 -0
- package/dist/index.js.map +1 -0
- package/dist/options.d.ts +59 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +4 -0
- package/dist/options.js.map +1 -0
- package/dist/paths.d.ts +11 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +58 -0
- package/dist/paths.js.map +1 -0
- package/dist/schema.d.ts +34 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +209 -0
- package/dist/schema.js.map +1 -0
- package/dist/tokens.d.ts +18 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +24 -0
- package/dist/tokens.js.map +1 -0
- package/dist/translations.d.ts +45 -0
- package/dist/translations.d.ts.map +1 -0
- package/dist/translations.js +44 -0
- package/dist/translations.js.map +1 -0
- package/package.json +65 -4
- package/src/access.ts +65 -0
- package/src/admin/OnPageAdminControls.tsx +99 -0
- package/src/admin/index.ts +2 -0
- package/src/endpoints.ts +269 -0
- package/src/hooks.ts +79 -0
- package/src/http.ts +57 -0
- package/src/index.ts +167 -0
- package/src/options.ts +65 -0
- package/src/paths.ts +59 -0
- package/src/schema.ts +251 -0
- package/src/tokens.ts +46 -0
- package/src/translations.ts +45 -0
package/dist/http.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Request helpers shared by the endpoints. */
|
|
2
|
+
import { parseRefKey, safePath } from '@payload-onpage/core';
|
|
3
|
+
/** The site origin: `serverURL` when configured, else the request's own origin. */
|
|
4
|
+
export function originOf(req) {
|
|
5
|
+
const configured = req.payload.config.serverURL;
|
|
6
|
+
if (configured)
|
|
7
|
+
return configured.replace(/\/$/, '');
|
|
8
|
+
try {
|
|
9
|
+
return new URL(req.url ?? '').origin;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
const host = req.headers.get('x-forwarded-host') ?? req.headers.get('host') ?? 'localhost';
|
|
13
|
+
const proto = req.headers.get('x-forwarded-proto') ?? 'http';
|
|
14
|
+
return `${proto}://${host}`;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export const isSecure = (req) => originOf(req).startsWith('https:');
|
|
18
|
+
export const queryOf = (req) => new URL(req.url ?? '/', 'http://localhost').searchParams;
|
|
19
|
+
export const text = (body, status) => new Response(body, {
|
|
20
|
+
status,
|
|
21
|
+
headers: { 'content-type': 'text/plain; charset=utf-8', 'cache-control': 'no-store' },
|
|
22
|
+
});
|
|
23
|
+
export const json = (body, status = 200) => Response.json(body, { status, headers: { 'cache-control': 'private, no-store' } });
|
|
24
|
+
/** Redirect to a same-origin path (anything unsafe becomes "/"). 303 turns a POST into a GET. */
|
|
25
|
+
export const redirectTo = (req, path, status = 303) => Response.redirect(new URL(safePath(path) ?? '/', originOf(req)), status);
|
|
26
|
+
/**
|
|
27
|
+
* CSRF guard for state-changing endpoints: a POST from this site (Origin, or
|
|
28
|
+
* Sec-Fetch-Site when Origin is absent). Returns an error response or null.
|
|
29
|
+
*/
|
|
30
|
+
export function rejectCrossSite(req) {
|
|
31
|
+
if (req.method?.toUpperCase() !== 'POST')
|
|
32
|
+
return text('Method not allowed', 405);
|
|
33
|
+
const origin = req.headers.get('origin');
|
|
34
|
+
if (origin)
|
|
35
|
+
return origin === originOf(req) ? null : text('Cross-site request refused', 403);
|
|
36
|
+
const site = req.headers.get('sec-fetch-site');
|
|
37
|
+
return site === 'same-origin' || site === 'none' ? null : text('Cross-site request refused', 403);
|
|
38
|
+
}
|
|
39
|
+
/** A document ref from `kind`, `slug`, `id` query/body values. */
|
|
40
|
+
export function readRef(values) {
|
|
41
|
+
const slug = typeof values.slug === 'string' ? values.slug : '';
|
|
42
|
+
if (!slug)
|
|
43
|
+
return null;
|
|
44
|
+
if (values.kind === 'global')
|
|
45
|
+
return { kind: 'global', slug };
|
|
46
|
+
const id = values.id;
|
|
47
|
+
if (typeof id === 'number')
|
|
48
|
+
return { kind: 'collection', slug, id };
|
|
49
|
+
if (typeof id !== 'string' || !id)
|
|
50
|
+
return null;
|
|
51
|
+
return parseRefKey(`c:${slug}:${id}`);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Plugin } from 'payload';
|
|
2
|
+
import { type OnPageOptions } from './options.ts';
|
|
3
|
+
export declare function onpage(options: OnPageOptions): Plugin;
|
|
4
|
+
export type { OnPageDocOptions, OnPageOptions } from './options.ts';
|
|
5
|
+
export { canEditDocument, canUseOnPage } from './access.ts';
|
|
6
|
+
export { createPreviewToken, verifyPreviewToken, type PreviewTokenPayload } from './tokens.ts';
|
|
7
|
+
export { serializeFields, type SerializeContext } from './schema.ts';
|
|
8
|
+
export { wantsMarkers } from './hooks.ts';
|
|
9
|
+
export { translations } from './translations.ts';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAA0C,MAAM,EAAE,MAAM,SAAS,CAAA;AAG7E,OAAO,EAAgC,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAwB/E,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAwHrD;AAED,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACnE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAC9F,OAAO,EAAE,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @payload-onpage/plugin — the Payload side of payload-onpage.
|
|
3
|
+
*
|
|
4
|
+
* plugins: [onpage({ collections: ['pages'], globals: ['header'], session: nextSession() })]
|
|
5
|
+
*
|
|
6
|
+
* Adds the endpoints in ./endpoints, auto-mapping on reads that ask for it,
|
|
7
|
+
* marker stripping and a stale-write guard on every write, and "Edit on page" /
|
|
8
|
+
* "Copy preview link" controls in the admin. Saves from the editor go through
|
|
9
|
+
* Payload's REST API, so access control, hooks, validation, drafts and versions
|
|
10
|
+
* apply unchanged.
|
|
11
|
+
*/
|
|
12
|
+
import { DEFAULTS } from '@payload-onpage/core';
|
|
13
|
+
import { createEndpoints } from "./endpoints.js";
|
|
14
|
+
import { encodeOnRead, guardStaleWrite, stripMarkers } from "./hooks.js";
|
|
15
|
+
import { normalizeEntries } from "./options.js";
|
|
16
|
+
import { serializeFields } from "./schema.js";
|
|
17
|
+
import { translations } from "./translations.js";
|
|
18
|
+
const APPLIED = 'payload-onpage';
|
|
19
|
+
/** Ours first; the site's own translations (any language, any key) win. */
|
|
20
|
+
function mergeTranslations(ours, theirs) {
|
|
21
|
+
const out = { ...ours };
|
|
22
|
+
for (const [lang, table] of Object.entries((theirs ?? {}))) {
|
|
23
|
+
const mine = out[lang] ?? {};
|
|
24
|
+
out[lang] = {
|
|
25
|
+
...mine,
|
|
26
|
+
...table,
|
|
27
|
+
onpage: { ...mine.onpage, ...(table.onpage ?? {}) },
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
export function onpage(options) {
|
|
33
|
+
return (incoming) => {
|
|
34
|
+
if (options.enabled === false || incoming.custom?.[APPLIED])
|
|
35
|
+
return incoming;
|
|
36
|
+
const prefix = options.routePrefix ?? DEFAULTS.routePrefix;
|
|
37
|
+
const apiRoute = incoming.routes?.api ?? DEFAULTS.apiRoute;
|
|
38
|
+
const entries = [
|
|
39
|
+
...normalizeEntries(options.collections, 'collection'),
|
|
40
|
+
...normalizeEntries(options.globals, 'global'),
|
|
41
|
+
];
|
|
42
|
+
const byKey = new Map(entries.map((e) => [`${e.kind}:${e.slug}`, e]));
|
|
43
|
+
const withHooks = (cfg, entry) => {
|
|
44
|
+
let fields;
|
|
45
|
+
// Encoding only needs names, types and editors: serialize once, lazily, without request context.
|
|
46
|
+
const lazyFields = () => (fields ??= serializeFields(cfg.fields, { blocks: incoming.blocks }));
|
|
47
|
+
const hooks = { ...(cfg.hooks ?? {}) };
|
|
48
|
+
hooks.beforeValidate = [...(hooks.beforeValidate ?? []), stripMarkers];
|
|
49
|
+
hooks.beforeChange = [...(hooks.beforeChange ?? []), stripMarkers, guardStaleWrite];
|
|
50
|
+
hooks.afterRead = [
|
|
51
|
+
...(hooks.afterRead ?? []),
|
|
52
|
+
encodeOnRead({
|
|
53
|
+
kind: entry.kind,
|
|
54
|
+
slug: cfg.slug,
|
|
55
|
+
fields: lazyFields,
|
|
56
|
+
only: entry.options.fields,
|
|
57
|
+
filter: options.encode,
|
|
58
|
+
}),
|
|
59
|
+
];
|
|
60
|
+
return { ...cfg, hooks };
|
|
61
|
+
};
|
|
62
|
+
const control = (kind, slug) => ({
|
|
63
|
+
path: '@payload-onpage/plugin/admin#OnPageAdminControls',
|
|
64
|
+
clientProps: { kind, slug, prefix },
|
|
65
|
+
});
|
|
66
|
+
const withCollectionAdmin = (c) => {
|
|
67
|
+
const edit = c.admin?.components?.edit ?? {};
|
|
68
|
+
return {
|
|
69
|
+
...c,
|
|
70
|
+
admin: {
|
|
71
|
+
...c.admin,
|
|
72
|
+
components: {
|
|
73
|
+
...c.admin?.components,
|
|
74
|
+
edit: {
|
|
75
|
+
...edit,
|
|
76
|
+
beforeDocumentControls: [
|
|
77
|
+
...(edit.beforeDocumentControls ?? []),
|
|
78
|
+
control('collection', c.slug),
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
const withGlobalAdmin = (g) => {
|
|
86
|
+
const elements = g.admin?.components?.elements ?? {};
|
|
87
|
+
return {
|
|
88
|
+
...g,
|
|
89
|
+
admin: {
|
|
90
|
+
...g.admin,
|
|
91
|
+
components: {
|
|
92
|
+
...g.admin?.components,
|
|
93
|
+
elements: {
|
|
94
|
+
...elements,
|
|
95
|
+
beforeDocumentControls: [
|
|
96
|
+
...(elements.beforeDocumentControls ?? []),
|
|
97
|
+
control('global', g.slug),
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
const missing = entries.filter((e) => e.kind === 'global'
|
|
105
|
+
? !incoming.globals?.some((g) => g.slug === e.slug)
|
|
106
|
+
: !incoming.collections?.some((c) => c.slug === e.slug));
|
|
107
|
+
if (missing.length) {
|
|
108
|
+
throw new Error(`payload-onpage: unknown ${missing.map((e) => `${e.kind} "${e.slug}"`).join(', ')}`);
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
...incoming,
|
|
112
|
+
custom: { ...incoming.custom, [APPLIED]: true },
|
|
113
|
+
i18n: {
|
|
114
|
+
...incoming.i18n,
|
|
115
|
+
translations: mergeTranslations(translations, incoming.i18n?.translations),
|
|
116
|
+
},
|
|
117
|
+
collections: (incoming.collections ?? []).map((c) => {
|
|
118
|
+
const entry = byKey.get(`collection:${c.slug}`);
|
|
119
|
+
return entry ? withCollectionAdmin(withHooks(c, entry)) : c;
|
|
120
|
+
}),
|
|
121
|
+
globals: (incoming.globals ?? []).map((g) => {
|
|
122
|
+
const entry = byKey.get(`global:${g.slug}`);
|
|
123
|
+
return entry ? withGlobalAdmin(withHooks(g, entry)) : g;
|
|
124
|
+
}),
|
|
125
|
+
endpoints: [
|
|
126
|
+
...(incoming.endpoints ?? []),
|
|
127
|
+
...createEndpoints({
|
|
128
|
+
options,
|
|
129
|
+
prefix,
|
|
130
|
+
apiRoute,
|
|
131
|
+
entry: (kind, slug) => byKey.get(`${kind}:${slug}`),
|
|
132
|
+
}),
|
|
133
|
+
],
|
|
134
|
+
onInit: async (payload) => {
|
|
135
|
+
if (process.env.NODE_ENV === 'production' && !payload.config.serverURL) {
|
|
136
|
+
payload.logger.warn('payload-onpage: set `serverURL` in production so redirects, preview links and Secure cookies use the public origin.');
|
|
137
|
+
}
|
|
138
|
+
await incoming.onInit?.(payload);
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
export { canEditDocument, canUseOnPage } from "./access.js";
|
|
144
|
+
export { createPreviewToken, verifyPreviewToken } from "./tokens.js";
|
|
145
|
+
export { serializeFields } from "./schema.js";
|
|
146
|
+
export { wantsMarkers } from "./hooks.js";
|
|
147
|
+
export { translations } from "./translations.js";
|
|
148
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { DocRef, EncodeFilter, SessionAdapter } from '@payload-onpage/core';
|
|
2
|
+
import type { PayloadRequest } from 'payload';
|
|
3
|
+
export interface OnPageDocOptions {
|
|
4
|
+
/** Top-level fields editable on the page. Default: every top-level field the user may update. */
|
|
5
|
+
fields?: string[];
|
|
6
|
+
/**
|
|
7
|
+
* The site path that shows this document. Default for collections: the
|
|
8
|
+
* collection's `admin.preview` URL, else `/${doc.slug}`. Globals: "/".
|
|
9
|
+
*/
|
|
10
|
+
url?: (args: {
|
|
11
|
+
doc: Record<string, unknown>;
|
|
12
|
+
locale?: string;
|
|
13
|
+
req: PayloadRequest;
|
|
14
|
+
}) => string | null | Promise<string | null>;
|
|
15
|
+
}
|
|
16
|
+
export interface OnPageOptions {
|
|
17
|
+
collections?: string[] | Record<string, OnPageDocOptions | true>;
|
|
18
|
+
globals?: string[] | Record<string, OnPageDocOptions | true>;
|
|
19
|
+
/**
|
|
20
|
+
* Who may use on-page editing (`ref` undefined) and edit a given document.
|
|
21
|
+
* Default: users of the admin user collection, with the document's own
|
|
22
|
+
* `update` access (evaluated by Payload, including row-level rules).
|
|
23
|
+
*/
|
|
24
|
+
access?: (args: {
|
|
25
|
+
req: PayloadRequest;
|
|
26
|
+
ref?: DocRef;
|
|
27
|
+
}) => boolean | Promise<boolean>;
|
|
28
|
+
/** Framework adapter that switches edit/preview mode (e.g. `nextSession()`). Required for the enter/exit/preview endpoints. */
|
|
29
|
+
session?: SessionAdapter;
|
|
30
|
+
/** Narrow which strings get auto-mapping markers. */
|
|
31
|
+
encode?: EncodeFilter;
|
|
32
|
+
/** Lifetime of shareable preview links, in seconds. Default 1 day. */
|
|
33
|
+
previewLinkTTL?: number;
|
|
34
|
+
/** Extra check when a preview link is opened (e.g. a revocation list). Return false to refuse it. */
|
|
35
|
+
validatePreviewLink?: (args: {
|
|
36
|
+
req: PayloadRequest;
|
|
37
|
+
ref: DocRef;
|
|
38
|
+
path: string;
|
|
39
|
+
issuedAt: number;
|
|
40
|
+
id: string;
|
|
41
|
+
}) => boolean | Promise<boolean>;
|
|
42
|
+
/**
|
|
43
|
+
* Secret for preview links and the preview cookie. Default: Payload's `secret`
|
|
44
|
+
* (`PAYLOAD_SECRET`). The Next.js proxy must be given the same value.
|
|
45
|
+
*/
|
|
46
|
+
secret?: string;
|
|
47
|
+
/** Auth cookie an editor's session is bound to. Default `${cookiePrefix}-token` ("payload-token"). */
|
|
48
|
+
authCookie?: string;
|
|
49
|
+
/** Endpoint prefix under the API route. Default "/onpage". */
|
|
50
|
+
routePrefix?: string;
|
|
51
|
+
enabled?: boolean;
|
|
52
|
+
}
|
|
53
|
+
export interface Entry {
|
|
54
|
+
kind: 'collection' | 'global';
|
|
55
|
+
slug: string;
|
|
56
|
+
options: OnPageDocOptions;
|
|
57
|
+
}
|
|
58
|
+
export declare const normalizeEntries: (input: OnPageOptions["collections"], kind: Entry["kind"]) => Entry[];
|
|
59
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C,MAAM,WAAW,gBAAgB;IAC/B,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB;;;OAGG;IACH,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE;QACX,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,GAAG,EAAE,cAAc,CAAA;KACpB,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CAC7C;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAChE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAC5D;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,cAAc,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACpF,+HAA+H;IAC/H,OAAO,CAAC,EAAE,cAAc,CAAA;IACxB,qDAAqD;IACrD,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,sEAAsE;IACtE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qGAAqG;IACrG,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE;QAC3B,GAAG,EAAE,cAAc,CAAA;QACnB,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,MAAM,CAAA;QAChB,EAAE,EAAE,MAAM,CAAA;KACX,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAChC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,sGAAsG;IACtG,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,YAAY,GAAG,QAAQ,CAAA;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,gBAAgB,CAAA;CAC1B;AAED,eAAO,MAAM,gBAAgB,GAC3B,OAAO,aAAa,CAAC,aAAa,CAAC,EACnC,MAAM,KAAK,CAAC,MAAM,CAAC,KAClB,KAAK,EAG4F,CAAA"}
|
package/dist/options.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AA0DA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,KAAmC,EACnC,IAAmB,EACV,EAAE,CACX,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;IAClB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Where a document lives on the site. */
|
|
2
|
+
import { type DocRef } from '@payload-onpage/core';
|
|
3
|
+
import type { PayloadRequest } from 'payload';
|
|
4
|
+
import type { Entry } from './options.ts';
|
|
5
|
+
/**
|
|
6
|
+
* The site path that shows a document: the entry's `url` option, else the
|
|
7
|
+
* collection's `admin.preview` URL, else `/<slug>`; globals default to "/".
|
|
8
|
+
* Absolute URLs must be same-origin. Returns null when there's no page.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolvePath(req: PayloadRequest, ref: DocRef, entry: Entry, locale?: string): Promise<string | null>;
|
|
11
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,OAAO,EAAY,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AAEzC;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,KAAK,EACZ,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0CxB"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** Where a document lives on the site. */
|
|
2
|
+
import { safePath } from '@payload-onpage/core';
|
|
3
|
+
import { originOf } from "./http.js";
|
|
4
|
+
/**
|
|
5
|
+
* The site path that shows a document: the entry's `url` option, else the
|
|
6
|
+
* collection's `admin.preview` URL, else `/<slug>`; globals default to "/".
|
|
7
|
+
* Absolute URLs must be same-origin. Returns null when there's no page.
|
|
8
|
+
*/
|
|
9
|
+
export async function resolvePath(req, ref, entry, locale) {
|
|
10
|
+
const localeArg = locale ? { locale: locale } : {};
|
|
11
|
+
const doc = ref.kind === 'global'
|
|
12
|
+
? await req.payload
|
|
13
|
+
.findGlobal({
|
|
14
|
+
slug: ref.slug,
|
|
15
|
+
draft: true,
|
|
16
|
+
depth: 0,
|
|
17
|
+
overrideAccess: true,
|
|
18
|
+
...localeArg,
|
|
19
|
+
})
|
|
20
|
+
.catch(() => null)
|
|
21
|
+
: await req.payload
|
|
22
|
+
.findByID({
|
|
23
|
+
collection: ref.slug,
|
|
24
|
+
id: ref.id,
|
|
25
|
+
draft: true,
|
|
26
|
+
depth: 0,
|
|
27
|
+
overrideAccess: true,
|
|
28
|
+
...localeArg,
|
|
29
|
+
})
|
|
30
|
+
.catch(() => null);
|
|
31
|
+
if (!doc)
|
|
32
|
+
return null;
|
|
33
|
+
let url;
|
|
34
|
+
if (entry.options.url)
|
|
35
|
+
url = await entry.options.url({ doc, locale, req });
|
|
36
|
+
else if (ref.kind === 'collection') {
|
|
37
|
+
const preview = req.payload.collections[ref.slug]?.config.admin?.preview;
|
|
38
|
+
if (preview)
|
|
39
|
+
url = await preview(doc, { locale: locale ?? '', req, token: null });
|
|
40
|
+
if (!url && typeof doc.slug === 'string')
|
|
41
|
+
url = `/${doc.slug.replace(/^\/+/, '')}`;
|
|
42
|
+
}
|
|
43
|
+
else
|
|
44
|
+
url = '/';
|
|
45
|
+
if (!url)
|
|
46
|
+
return null;
|
|
47
|
+
const origin = originOf(req);
|
|
48
|
+
try {
|
|
49
|
+
const u = new URL(url, origin);
|
|
50
|
+
if (u.origin !== origin)
|
|
51
|
+
return null;
|
|
52
|
+
return safePath(u.pathname + u.search);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,OAAO,EAAE,QAAQ,EAAe,MAAM,sBAAsB,CAAA;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGpC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAmB,EACnB,GAAW,EACX,KAAY,EACZ,MAAe;IAEf,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC3D,MAAM,GAAG,GACP,GAAG,CAAC,IAAI,KAAK,QAAQ;QACnB,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO;aACd,UAAU,CAAC;YACV,IAAI,EAAE,GAAG,CAAC,IAAa;YACvB,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,CAAC;YACR,cAAc,EAAE,IAAI;YACpB,GAAG,SAAS;SACb,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;QACtB,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO;aACd,QAAQ,CAAC;YACR,UAAU,EAAE,GAAG,CAAC,IAAa;YAC7B,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,CAAC;YACR,cAAc,EAAE,IAAI;YACpB,GAAG,SAAS;SACb,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IAC1B,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAA;IAErB,IAAI,GAA8B,CAAA;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG;QAAE,GAAG,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;SACrE,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,CAAA;QACxE,IAAI,OAAO;YAAE,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACjF,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;YAAE,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAA;IACpF,CAAC;;QAAM,GAAG,GAAG,GAAG,CAAA;IAChB,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAA;IAErB,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC5B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QAC9B,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO,IAAI,CAAA;QACpC,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,CAAA;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the editor's JSON schema from Payload field configs, using Payload's
|
|
3
|
+
* own field predicates and translations. Payload's client config can't be used
|
|
4
|
+
* instead: it strips `defaultValue` and `custom`, which the editor needs.
|
|
5
|
+
*/
|
|
6
|
+
import { getTranslation } from '@payloadcms/translations';
|
|
7
|
+
import type { DocumentSchema, SchemaField } from '@payload-onpage/core';
|
|
8
|
+
import type { Block, Field, PayloadRequest, SanitizedFieldsPermissions } from 'payload';
|
|
9
|
+
type I18nLike = Parameters<typeof getTranslation>[1];
|
|
10
|
+
type Permissions = SanitizedFieldsPermissions | undefined;
|
|
11
|
+
export interface SerializeContext {
|
|
12
|
+
/** Translates labels into the admin language. Without it, plain-string labels or the field name are used. */
|
|
13
|
+
i18n?: I18nLike;
|
|
14
|
+
/** Global blocks (`config.blocks`), to resolve `blockReferences`. */
|
|
15
|
+
blocks?: Block[];
|
|
16
|
+
/** Field-level permissions: fields the user can't update are left out. */
|
|
17
|
+
permissions?: Permissions;
|
|
18
|
+
/** Collects function defaults to evaluate for this request. */
|
|
19
|
+
defaults?: {
|
|
20
|
+
req: PayloadRequest;
|
|
21
|
+
pending: Promise<void>[];
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Serialize Payload field configs into the editor schema. Presentational
|
|
26
|
+
* containers (row, collapsible, unnamed group/tab) are flattened into their
|
|
27
|
+
* parent; named tabs become groups; hidden, disabled, virtual, system and
|
|
28
|
+
* join/ui fields are left out.
|
|
29
|
+
*/
|
|
30
|
+
export declare function serializeFields(fields: Field[] | undefined, ctx?: SerializeContext): SchemaField[];
|
|
31
|
+
/** Every collection a relationship or upload field in `fields` points to. */
|
|
32
|
+
export declare function relationTargets(fields: SchemaField[], into?: Set<string>): Set<string>;
|
|
33
|
+
export type { DocumentSchema };
|
|
34
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAe,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACpF,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AAsCvF,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,CAAA;AAEpD,KAAK,WAAW,GAAG,0BAA0B,GAAG,SAAS,CAAA;AAEzD,MAAM,WAAW,gBAAgB;IAC/B,6GAA6G;IAC7G,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,qEAAqE;IACrE,MAAM,CAAC,EAAE,KAAK,EAAE,CAAA;IAChB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,cAAc,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAA;KAAE,CAAA;CAC7D;AAyDD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,EAC3B,GAAG,GAAE,gBAAqB,GACzB,WAAW,EAAE,CAgHf;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,IAAI,cAAoB,GAAG,GAAG,CAAC,MAAM,CAAC,CAS5F;AAED,YAAY,EAAE,cAAc,EAAE,CAAA"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the editor's JSON schema from Payload field configs, using Payload's
|
|
3
|
+
* own field predicates and translations. Payload's client config can't be used
|
|
4
|
+
* instead: it strips `defaultValue` and `custom`, which the editor needs.
|
|
5
|
+
*/
|
|
6
|
+
import { getTranslation } from '@payloadcms/translations';
|
|
7
|
+
import { getDefaultValue } from 'payload';
|
|
8
|
+
import { fieldAffectsData, fieldIsHiddenOrDisabled, fieldIsVirtual, tabHasName, formatLabels, toWords, } from 'payload/shared';
|
|
9
|
+
/** Fields Payload manages itself; never editable on the page. */
|
|
10
|
+
const SYSTEM_FIELDS = new Set(['id', 'createdAt', 'updatedAt', '_status', 'deletedAt']);
|
|
11
|
+
/** Data fields with no meaningful on-page value. */
|
|
12
|
+
const SKIP_TYPES = new Set(['join', 'ui']);
|
|
13
|
+
const label = (value, fallback, ctx) => {
|
|
14
|
+
if (value == null || value === false)
|
|
15
|
+
return fallback;
|
|
16
|
+
if (typeof value === 'string')
|
|
17
|
+
return value || fallback;
|
|
18
|
+
if (!ctx.i18n)
|
|
19
|
+
return fallback;
|
|
20
|
+
try {
|
|
21
|
+
const out = getTranslation(value, ctx.i18n);
|
|
22
|
+
return typeof out === 'string' && out ? out : fallback;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return fallback;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/** Sanitized permissions: `true` = everything; a missing entry = denied. */
|
|
29
|
+
function childPermissions(perms, name) {
|
|
30
|
+
if (perms === undefined || perms === true)
|
|
31
|
+
return perms;
|
|
32
|
+
const entry = perms[name];
|
|
33
|
+
if (!entry)
|
|
34
|
+
return false;
|
|
35
|
+
if (entry === true)
|
|
36
|
+
return true;
|
|
37
|
+
if (entry.update !== true)
|
|
38
|
+
return false;
|
|
39
|
+
return entry.fields ?? true;
|
|
40
|
+
}
|
|
41
|
+
function blockPermissions(perms, name, slug) {
|
|
42
|
+
if (perms === undefined || perms === true)
|
|
43
|
+
return perms;
|
|
44
|
+
const entry = perms[name];
|
|
45
|
+
if (!entry || entry === true)
|
|
46
|
+
return true;
|
|
47
|
+
const block = entry.blocks?.[slug];
|
|
48
|
+
// No block-level rule: the blocks field's own permission (already checked) applies.
|
|
49
|
+
if (!block || block === true)
|
|
50
|
+
return true;
|
|
51
|
+
return block.fields ?? true;
|
|
52
|
+
}
|
|
53
|
+
const isJsonSafe = (v) => {
|
|
54
|
+
if (v === undefined || typeof v === 'function')
|
|
55
|
+
return false;
|
|
56
|
+
try {
|
|
57
|
+
JSON.stringify(v);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
function serializeBlock(block, perms, ctx) {
|
|
65
|
+
return {
|
|
66
|
+
slug: block.slug,
|
|
67
|
+
labels: {
|
|
68
|
+
singular: label(block.labels?.singular, toWords(block.slug), ctx),
|
|
69
|
+
plural: label(block.labels?.plural, toWords(block.slug), ctx),
|
|
70
|
+
},
|
|
71
|
+
fields: serializeFields(block.fields, { ...ctx, permissions: perms }),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Serialize Payload field configs into the editor schema. Presentational
|
|
76
|
+
* containers (row, collapsible, unnamed group/tab) are flattened into their
|
|
77
|
+
* parent; named tabs become groups; hidden, disabled, virtual, system and
|
|
78
|
+
* join/ui fields are left out.
|
|
79
|
+
*/
|
|
80
|
+
export function serializeFields(fields, ctx = {}) {
|
|
81
|
+
const out = [];
|
|
82
|
+
for (const f of fields ?? []) {
|
|
83
|
+
if (!f || typeof f !== 'object' || SKIP_TYPES.has(f.type))
|
|
84
|
+
continue;
|
|
85
|
+
if (f.type === 'tabs') {
|
|
86
|
+
for (const tab of f.tabs ?? []) {
|
|
87
|
+
if (!tabHasName(tab)) {
|
|
88
|
+
out.push(...serializeFields(tab.fields, ctx));
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const perms = childPermissions(ctx.permissions, tab.name);
|
|
92
|
+
if (perms === false)
|
|
93
|
+
continue;
|
|
94
|
+
out.push({
|
|
95
|
+
name: tab.name,
|
|
96
|
+
type: 'group',
|
|
97
|
+
label: label(tab.label, toWords(tab.name), ctx),
|
|
98
|
+
fields: serializeFields(tab.fields, { ...ctx, permissions: perms }),
|
|
99
|
+
...(tab.localized ? { localized: true } : {}),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (!fieldAffectsData(f)) {
|
|
105
|
+
// row, collapsible, unnamed group: their children belong to the parent.
|
|
106
|
+
if ('fields' in f && Array.isArray(f.fields))
|
|
107
|
+
out.push(...serializeFields(f.fields, ctx));
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
// Hidden from the admin (admin.hidden) or the API (hidden), disabled, virtual: not editable here either.
|
|
111
|
+
if (SYSTEM_FIELDS.has(f.name) ||
|
|
112
|
+
fieldIsHiddenOrDisabled(f) ||
|
|
113
|
+
fieldIsVirtual(f) ||
|
|
114
|
+
f.admin?.hidden)
|
|
115
|
+
continue;
|
|
116
|
+
const perms = childPermissions(ctx.permissions, f.name);
|
|
117
|
+
if (perms === false)
|
|
118
|
+
continue;
|
|
119
|
+
// Field is a large union; read the optional, type-specific properties through one loose view.
|
|
120
|
+
const anyField = f;
|
|
121
|
+
const field = {
|
|
122
|
+
name: f.name,
|
|
123
|
+
type: f.type,
|
|
124
|
+
label: label(anyField.label, toWords(f.name), ctx),
|
|
125
|
+
};
|
|
126
|
+
if (anyField.localized)
|
|
127
|
+
field.localized = true;
|
|
128
|
+
if (anyField.required)
|
|
129
|
+
field.required = true;
|
|
130
|
+
if (anyField.hasMany)
|
|
131
|
+
field.hasMany = true;
|
|
132
|
+
if (typeof anyField.defaultValue === 'function') {
|
|
133
|
+
if (ctx.defaults) {
|
|
134
|
+
const { req, pending } = ctx.defaults;
|
|
135
|
+
pending.push(getDefaultValue({
|
|
136
|
+
defaultValue: anyField.defaultValue,
|
|
137
|
+
locale: req.locale ?? undefined,
|
|
138
|
+
req,
|
|
139
|
+
user: req.user,
|
|
140
|
+
})
|
|
141
|
+
.then((v) => {
|
|
142
|
+
if (isJsonSafe(v))
|
|
143
|
+
field.defaultValue = v;
|
|
144
|
+
})
|
|
145
|
+
.catch(() => undefined));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (isJsonSafe(anyField.defaultValue)) {
|
|
149
|
+
field.defaultValue = anyField.defaultValue;
|
|
150
|
+
}
|
|
151
|
+
const description = label(anyField.admin?.description, '', ctx);
|
|
152
|
+
if (description)
|
|
153
|
+
field.description = description;
|
|
154
|
+
if (Array.isArray(anyField.options)) {
|
|
155
|
+
field.options = anyField.options.map((o) => typeof o === 'string'
|
|
156
|
+
? { label: o, value: o }
|
|
157
|
+
: {
|
|
158
|
+
label: label(o.label, String(o.value), ctx),
|
|
159
|
+
value: String(o.value),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (anyField.relationTo)
|
|
163
|
+
field.relationTo = anyField.relationTo;
|
|
164
|
+
for (const k of ['minRows', 'maxRows', 'min', 'max']) {
|
|
165
|
+
const n = anyField[k];
|
|
166
|
+
if (typeof n === 'number')
|
|
167
|
+
field[k] = n;
|
|
168
|
+
}
|
|
169
|
+
const editor = anyField.admin?.custom?.onpage?.editor ?? anyField.custom?.onpage?.editor;
|
|
170
|
+
if (typeof editor === 'string')
|
|
171
|
+
field.editor = editor;
|
|
172
|
+
const picker = anyField.admin?.date?.pickerAppearance;
|
|
173
|
+
if (typeof picker === 'string')
|
|
174
|
+
field.pickerAppearance = picker;
|
|
175
|
+
const childCtx = { ...ctx, permissions: perms };
|
|
176
|
+
if (f.type === 'group' || f.type === 'array')
|
|
177
|
+
field.fields = serializeFields(f.fields, childCtx);
|
|
178
|
+
if (f.type === 'array') {
|
|
179
|
+
const fallback = formatLabels(f.name);
|
|
180
|
+
field.labels = {
|
|
181
|
+
singular: label(anyField.labels?.singular, fallback.singular, ctx),
|
|
182
|
+
plural: label(anyField.labels?.plural, fallback.plural, ctx),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (f.type === 'blocks') {
|
|
186
|
+
const refs = (f.blockReferences ?? [])
|
|
187
|
+
.map((b) => (typeof b === 'string' ? ctx.blocks?.find((x) => x.slug === b) : b))
|
|
188
|
+
.filter((b) => !!b);
|
|
189
|
+
field.blocks = [...(f.blocks ?? []), ...refs].map((b) => serializeBlock(b, blockPermissions(ctx.permissions, f.name, b.slug), ctx));
|
|
190
|
+
}
|
|
191
|
+
out.push(field);
|
|
192
|
+
}
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
195
|
+
/** Every collection a relationship or upload field in `fields` points to. */
|
|
196
|
+
export function relationTargets(fields, into = new Set()) {
|
|
197
|
+
for (const f of fields) {
|
|
198
|
+
if ((f.type === 'relationship' || f.type === 'upload') && f.relationTo) {
|
|
199
|
+
for (const slug of Array.isArray(f.relationTo) ? f.relationTo : [f.relationTo])
|
|
200
|
+
into.add(slug);
|
|
201
|
+
}
|
|
202
|
+
if (f.fields)
|
|
203
|
+
relationTargets(f.fields, into);
|
|
204
|
+
for (const b of f.blocks ?? [])
|
|
205
|
+
relationTargets(b.fields, into);
|
|
206
|
+
}
|
|
207
|
+
return into;
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=schema.js.map
|