@tetherto/dev-websites-core 0.3.2 → 0.3.4

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 (35) hide show
  1. package/README.md +74 -0
  2. package/dist/cms/google-oauth.d.mts +20 -0
  3. package/dist/cms/google-oauth.d.mts.map +1 -0
  4. package/dist/cms/google-oauth.mjs +130 -0
  5. package/dist/cms/google-oauth.mjs.map +1 -0
  6. package/dist/cms/index.d.mts +2 -2
  7. package/dist/cms/index.mjs +2 -2
  8. package/dist/cms.mjs +436 -7
  9. package/dist/cms.mjs.map +1 -1
  10. package/dist/index.d.mts +24 -3
  11. package/dist/index.d.mts.map +1 -1
  12. package/dist/index.mjs +4 -3
  13. package/dist/index5.d.mts +2 -2
  14. package/dist/seo/index.mjs +2 -1
  15. package/dist/seo.mjs +2 -13
  16. package/dist/seo.mjs.map +1 -1
  17. package/dist/site-url.mjs +16 -0
  18. package/dist/site-url.mjs.map +1 -0
  19. package/dist/ui/components/Badge/Badge.d.mts +1 -1
  20. package/dist/ui/components/GoogleOAuthButton/GoogleOAuthButton.d.mts +5 -0
  21. package/dist/ui/components/GoogleOAuthButton/GoogleOAuthButton.d.mts.map +1 -0
  22. package/dist/ui/components/GoogleOAuthButton/GoogleOAuthButton.mjs +72 -0
  23. package/dist/ui/components/GoogleOAuthButton/GoogleOAuthButton.mjs.map +1 -0
  24. package/dist/ui/components/GoogleOAuthButton/googleOAuthStartPath.d.mts +6 -0
  25. package/dist/ui/components/GoogleOAuthButton/googleOAuthStartPath.d.mts.map +1 -0
  26. package/dist/ui/components/GoogleOAuthButton/googleOAuthStartPath.mjs +7 -0
  27. package/dist/ui/components/GoogleOAuthButton/googleOAuthStartPath.mjs.map +1 -0
  28. package/dist/ui/components/GoogleOAuthButton/index.d.mts +2 -0
  29. package/dist/ui/components/GoogleOAuthButton/index.mjs +2 -0
  30. package/dist/ui/index.d.mts +3 -1
  31. package/dist/ui/index.mjs +1 -0
  32. package/package.json +18 -2
  33. package/src/ui/components/GoogleOAuthButton/GoogleOAuthButton.tsx +69 -0
  34. package/src/ui/components/GoogleOAuthButton/googleOAuthStartPath.ts +2 -0
  35. package/src/ui/components/GoogleOAuthButton/index.ts +1 -0
package/README.md CHANGED
@@ -5,11 +5,13 @@ Shared CMS, SEO, i18n, utils, UI, and analytics primitives for WDK / QVAC / PEAR
5
5
  | Import | Contents |
6
6
  | --- | --- |
7
7
  | `@tetherto/dev-websites-core/cms` | Payload `buildCmsConfig`, stock collections, access, Lexical, media I/O |
8
+ | `@tetherto/dev-websites-core/cms/google-oauth` | Google admin login handlers (`google-auth-library` peer) |
8
9
  | `@tetherto/dev-websites-core/seo` | `createMetadataFactory`, `getSiteUrl`, `getOgBackgroundDataUrl` |
9
10
  | `@tetherto/dev-websites-core/i18n` | `Languages` / `LanguageLabel` |
10
11
  | `@tetherto/dev-websites-core/utils` | `createLogger`, `toPlainValue`, `stripShikiPreBackground` |
11
12
  | `@tetherto/dev-websites-core/analytics` | `GtmLoader`, `createTrackedLink` (optional `@next/third-parties` peer) |
12
13
  | `@tetherto/dev-websites-core/ui` | UI primitives (`Button`, `Dialog`, `Pagination`, `Tooltip`, …) + `cn` |
14
+ | `@tetherto/dev-websites-core/ui/google-oauth` | Payload `GoogleOAuthButton` (Tailwind classes; source `dist` from Payload CSS) |
13
15
  | `@tetherto/dev-websites-core/ui/a11y` | `focusRingClassName`, `VisuallyHidden` |
14
16
  | `@tetherto/dev-websites-core/ui/carousel` | `Carousel` (+ optional `embla-carousel-react` peer) |
15
17
  | `@tetherto/dev-websites-core/ui/theme.css` | One-shot: tokens + Tailwind v4 `@theme` preset |
@@ -51,6 +53,71 @@ rm -rf node_modules/@tetherto/dev-websites-core && npm install @tetherto/dev-web
51
53
  Do **not** import `@tetherto/dev-websites-core/cms` from Client Components — it includes Node-only
52
54
  modules (`fs`, Payload, S3). Prefer domain subpaths over the root barrel.
53
55
 
56
+ ### Google admin login
57
+
58
+ Stock `users` includes `googleId` / `name` / `picture`. Sites add Next.js routes and
59
+ Payload `afterLogin` (optional `google-auth-library` peer):
60
+
61
+ ```ts
62
+ // src/payload.config.ts
63
+ import { GOOGLE_OAUTH_AFTER_LOGIN } from '@tetherto/dev-websites-core/cms/google-oauth'
64
+
65
+ admin: {
66
+ components: { afterLogin: [...GOOGLE_OAUTH_AFTER_LOGIN] },
67
+ }
68
+ ```
69
+
70
+ ```ts
71
+ // src/app/api/auth/google/route.ts
72
+ import { handleGoogleOAuthStart } from '@tetherto/dev-websites-core/cms/google-oauth'
73
+
74
+ export function GET() {
75
+ return handleGoogleOAuthStart({
76
+ clientId: process.env.GOOGLE_OAUTH_CLIENT_ID ?? '',
77
+ clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET ?? '',
78
+ })
79
+ }
80
+ ```
81
+
82
+ ```ts
83
+ // src/app/api/auth/google/callback/route.ts
84
+ import { handleGoogleOAuthCallback } from '@tetherto/dev-websites-core/cms/google-oauth'
85
+ import config from '@payload-config'
86
+
87
+ import type { NextRequest } from 'next/server'
88
+
89
+ export function GET(request: NextRequest) {
90
+ return handleGoogleOAuthCallback(request, {
91
+ config,
92
+ clientId: process.env.GOOGLE_OAUTH_CLIENT_ID ?? '',
93
+ clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET ?? '',
94
+ })
95
+ }
96
+ ```
97
+
98
+ ```css
99
+ /* src/app/(payload)/custom.css — utilities only; do not import Tailwind preflight */
100
+ @import 'tailwindcss/theme.css' layer(theme) source(none);
101
+ @import 'tailwindcss/utilities.css' layer(utilities) source(none);
102
+ @source '../../../node_modules/@tetherto/dev-websites-core/src/ui/components/GoogleOAuthButton';
103
+
104
+ .login__form > .form-submit .btn {
105
+ margin-bottom: 0;
106
+ }
107
+ ```
108
+
109
+ Apps using Next.js should also transpile the package so the Payload button shares the app React instance:
110
+
111
+ ```ts
112
+ // next.config.ts
113
+ transpilePackages: ['@tetherto/dev-websites-core']
114
+ ```
115
+
116
+ The app passes `clientId` and `clientSecret` into both handlers (usually from its own
117
+ `GOOGLE_OAUTH_CLIENT_ID` and `GOOGLE_OAUTH_CLIENT_SECRET`). Redirect URI:
118
+ `{NEXT_PUBLIC_SITE_URL}/api/auth/google/callback`. Existing `users` emails are
119
+ required — Google login does not create accounts.
120
+
54
121
  ### Analytics
55
122
 
56
123
  ```ts
@@ -133,6 +200,8 @@ Registered by `buildCmsConfig` in this order. Disable or extend any of them via
133
200
  | `legal-pages` | collection | Legal/policy content pages (same shape as `pages`). |
134
201
  | `changelog-tags` | collection | Editor-managed tags shown on changelog entries. |
135
202
  | `changelog` | collection | Changelog entries — **shared fields only** (see below). |
203
+ | `event-tags` | collection | Editor-managed event categories (Meetup, Workshop, Hackathon, …). Related from `events`. |
204
+ | `events` | collection | Events — drafts + autosave, start/end, timezone, location, tag, external URL, optional cover/body. |
136
205
  | `site-settings` | global | Site name, default description/OG image, organization + social. |
137
206
 
138
207
  Changelog stock ships shared fields only; site-specific body / GitHub /
@@ -140,6 +209,11 @@ Changelog stock ships shared fields only; site-specific body / GitHub /
140
209
  `overrides.hooks` (site-owned, e.g. `src/lib/cache`) — hook arrays are **appended**
141
210
  to stock hooks, not replaced.
142
211
 
212
+ Draft collections enable Payload `schedulePublish`. `buildCmsConfig` starts
213
+ `jobs.autoRun` every minute so scheduled publishes run in a long-lived Node
214
+ process (`next start` / Docker). Override or disable via `payload.jobs`. This
215
+ is not for serverless hosts.
216
+
143
217
  ### Peer dependencies
144
218
 
145
219
  CMS / Next (required for `/cms` consumers):
@@ -0,0 +1,20 @@
1
+ import { Config, SanitizedConfig } from "payload";
2
+ import { NextRequest, NextResponse } from "next/server.js";
3
+ //#region src/cms/auth/google-oauth.d.ts
4
+ /** Payload `admin.components.afterLogin` path for the shared Google button. */
5
+ declare const GOOGLE_OAUTH_AFTER_LOGIN: readonly ["@tetherto/dev-websites-core/ui/google-oauth#GoogleOAuthButton"];
6
+ type GoogleOAuthClientConfig = {
7
+ clientId: string;
8
+ clientSecret: string;
9
+ };
10
+ type HandleGoogleOAuthCallbackOptions = GoogleOAuthClientConfig & {
11
+ /** Site Payload config default export (`import config from '@payload-config'`). */
12
+ config: Config | SanitizedConfig | Promise<Config | SanitizedConfig>;
13
+ };
14
+ /** GET `/api/auth/google` — start the Google OAuth redirect. */
15
+ declare function handleGoogleOAuthStart(clientConfig: GoogleOAuthClientConfig): Promise<NextResponse<unknown>>;
16
+ /** GET `/api/auth/google/callback` — exchange the code and set the Payload session cookie. */
17
+ declare function handleGoogleOAuthCallback(request: NextRequest, { config, ...clientConfig }: HandleGoogleOAuthCallbackOptions): Promise<NextResponse<unknown>>;
18
+ //#endregion
19
+ export { GOOGLE_OAUTH_AFTER_LOGIN, GoogleOAuthClientConfig, HandleGoogleOAuthCallbackOptions, handleGoogleOAuthCallback, handleGoogleOAuthStart };
20
+ //# sourceMappingURL=google-oauth.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-oauth.d.mts","names":[],"sources":["../../src/cms/auth/google-oauth.ts"],"mappings":";;;;cAiBa;KAMD;EACV;EACA;;KAGU,mCAAmC;;EAE7C,QAAQ,SAAS,kBAAkB,QAAQ,SAAS;;;iBAqBhC,uBAAuB,cAAc,0BAAuB,QAAA;;iBAoB5D,0BACpB,SAAS,eACP,WAAW,gBAAgB,mCAAgC,QAAA"}
@@ -0,0 +1,130 @@
1
+ import { t as createLogger } from "../logger.mjs";
2
+ import { t as getSiteUrl } from "../site-url.mjs";
3
+ import { getFieldsToSign, getPayload, jwtSign } from "payload";
4
+ import { OAuth2Client } from "google-auth-library";
5
+ import { NextResponse } from "next/server.js";
6
+ import { addSessionToUser, generatePayloadCookie } from "payload/shared";
7
+ //#region src/cms/auth/google-oauth.ts
8
+ const log = createLogger("googleOAuth");
9
+ const GOOGLE_OAUTH_CALLBACK_PATH = "/api/auth/google/callback";
10
+ const GOOGLE_OAUTH_LOGIN_PATH = "/admin/login";
11
+ const GOOGLE_OAUTH_ADMIN_PATH = "/admin";
12
+ /** Payload `admin.components.afterLogin` path for the shared Google button. */
13
+ const GOOGLE_OAUTH_AFTER_LOGIN = ["@tetherto/dev-websites-core/ui/google-oauth#GoogleOAuthButton"];
14
+ const GOOGLE_OAUTH_SCOPES = [
15
+ "openid",
16
+ "email",
17
+ "profile"
18
+ ];
19
+ function getGoogleOAuthClient(redirectUri, { clientId, clientSecret }) {
20
+ if (!clientId || !clientSecret) throw new Error("Google OAuth credentials not configured");
21
+ return new OAuth2Client(clientId, clientSecret, redirectUri);
22
+ }
23
+ function loginErrorRedirect(siteUrl, error) {
24
+ return NextResponse.redirect(`${siteUrl}${GOOGLE_OAUTH_LOGIN_PATH}?error=${encodeURIComponent(error)}`);
25
+ }
26
+ /** GET `/api/auth/google` — start the Google OAuth redirect. */
27
+ async function handleGoogleOAuthStart(clientConfig) {
28
+ try {
29
+ const authorizeUrl = getGoogleOAuthClient(`${getSiteUrl()}${GOOGLE_OAUTH_CALLBACK_PATH}`, clientConfig).generateAuthUrl({
30
+ access_type: "offline",
31
+ scope: [...GOOGLE_OAUTH_SCOPES],
32
+ prompt: "select_account"
33
+ });
34
+ return NextResponse.redirect(authorizeUrl);
35
+ } catch (error) {
36
+ log.error(error instanceof Error ? error.message : "OAuth configuration error");
37
+ return NextResponse.json({ error: "OAuth configuration error" }, { status: 500 });
38
+ }
39
+ }
40
+ /** GET `/api/auth/google/callback` — exchange the code and set the Payload session cookie. */
41
+ async function handleGoogleOAuthCallback(request, { config, ...clientConfig }) {
42
+ try {
43
+ const { searchParams } = new URL(request.url);
44
+ const siteUrl = getSiteUrl();
45
+ const code = searchParams.get("code");
46
+ const error = searchParams.get("error");
47
+ if (error) return loginErrorRedirect(siteUrl, error);
48
+ if (!code) return loginErrorRedirect(siteUrl, "no_code");
49
+ const client = getGoogleOAuthClient(`${siteUrl}${GOOGLE_OAUTH_CALLBACK_PATH}`, clientConfig);
50
+ const { tokens } = await client.getToken(code);
51
+ client.setCredentials(tokens);
52
+ if (!tokens.id_token) return loginErrorRedirect(siteUrl, "no_token");
53
+ const googlePayload = (await client.verifyIdToken({
54
+ idToken: tokens.id_token,
55
+ audience: clientConfig.clientId
56
+ })).getPayload();
57
+ if (!googlePayload?.email) return loginErrorRedirect(siteUrl, "no_email");
58
+ const { email, sub: googleId, name, picture } = googlePayload;
59
+ const payload = await getPayload({ config: await config });
60
+ const users = await payload.find({
61
+ collection: "users",
62
+ where: { or: [{ email: { equals: email } }, { googleId: { equals: googleId } }] },
63
+ limit: 1
64
+ });
65
+ let user = users.docs[0];
66
+ if (users.docs.length > 0) {
67
+ user = users.docs[0];
68
+ const googleUser = user;
69
+ const updateData = {};
70
+ if (!googleUser.googleId) {
71
+ updateData.googleId = googleId;
72
+ updateData.name = name || googleUser.name;
73
+ updateData.picture = picture || googleUser.picture;
74
+ }
75
+ if (Object.keys(updateData).length > 0) user = await payload.update({
76
+ collection: "users",
77
+ id: user.id,
78
+ data: updateData
79
+ });
80
+ } else return loginErrorRedirect(siteUrl, "user_not_found");
81
+ const collectionConfig = payload.collections["users"].config;
82
+ const sessionUser = user;
83
+ const { sid } = await addSessionToUser({
84
+ collectionConfig,
85
+ payload,
86
+ req: {
87
+ payload,
88
+ user: sessionUser
89
+ },
90
+ user: sessionUser
91
+ });
92
+ const fieldsToSign = getFieldsToSign({
93
+ collectionConfig,
94
+ email: sessionUser.email,
95
+ sid,
96
+ user: sessionUser
97
+ });
98
+ const tokenExpiration = collectionConfig.auth.tokenExpiration || 7200;
99
+ const secret = payload.secret;
100
+ const { token } = await jwtSign({
101
+ fieldsToSign,
102
+ secret,
103
+ tokenExpiration
104
+ });
105
+ const cookie = generatePayloadCookie({
106
+ collectionAuthConfig: collectionConfig.auth,
107
+ cookiePrefix: payload.config.cookiePrefix || "payload",
108
+ token,
109
+ returnCookieAsObject: true
110
+ });
111
+ const response = NextResponse.redirect(`${siteUrl}${GOOGLE_OAUTH_ADMIN_PATH}`);
112
+ response.cookies.set(cookie.name, cookie.value, {
113
+ httpOnly: cookie.httpOnly,
114
+ sameSite: cookie.sameSite?.toLowerCase(),
115
+ secure: cookie.secure,
116
+ path: cookie.path,
117
+ expires: cookie.expires ? new Date(cookie.expires) : void 0,
118
+ maxAge: cookie.maxAge
119
+ });
120
+ return response;
121
+ } catch (error) {
122
+ const errorMessage = error instanceof Error ? error.message : "Authentication failed";
123
+ log.error(errorMessage);
124
+ return loginErrorRedirect(getSiteUrl(), errorMessage);
125
+ }
126
+ }
127
+ //#endregion
128
+ export { GOOGLE_OAUTH_AFTER_LOGIN, handleGoogleOAuthCallback, handleGoogleOAuthStart };
129
+
130
+ //# sourceMappingURL=google-oauth.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-oauth.mjs","names":[],"sources":["../../src/cms/auth/google-oauth.ts"],"sourcesContent":["import { OAuth2Client } from 'google-auth-library'\nimport { NextRequest, NextResponse } from 'next/server'\nimport { getFieldsToSign, getPayload, jwtSign } from 'payload'\nimport { addSessionToUser, generatePayloadCookie } from 'payload/shared'\n\nimport { getSiteUrl } from '../../seo/site-url.js'\nimport { createLogger } from '../../utils/logger/logger.js'\n\nimport type { Config, SanitizedConfig } from 'payload'\n\nconst log = createLogger('googleOAuth')\n\nconst GOOGLE_OAUTH_CALLBACK_PATH = '/api/auth/google/callback'\nconst GOOGLE_OAUTH_LOGIN_PATH = '/admin/login'\nconst GOOGLE_OAUTH_ADMIN_PATH = '/admin'\n\n/** Payload `admin.components.afterLogin` path for the shared Google button. */\nexport const GOOGLE_OAUTH_AFTER_LOGIN = [\n '@tetherto/dev-websites-core/ui/google-oauth#GoogleOAuthButton',\n] as const\n\nconst GOOGLE_OAUTH_SCOPES = ['openid', 'email', 'profile'] as const\n\nexport type GoogleOAuthClientConfig = {\n clientId: string\n clientSecret: string\n}\n\nexport type HandleGoogleOAuthCallbackOptions = GoogleOAuthClientConfig & {\n /** Site Payload config default export (`import config from '@payload-config'`). */\n config: Config | SanitizedConfig | Promise<Config | SanitizedConfig>\n}\n\nfunction getGoogleOAuthClient(\n redirectUri: string,\n { clientId, clientSecret }: GoogleOAuthClientConfig\n) {\n if (!clientId || !clientSecret) {\n throw new Error('Google OAuth credentials not configured')\n }\n\n return new OAuth2Client(clientId, clientSecret, redirectUri)\n}\n\nfunction loginErrorRedirect(siteUrl: string, error: string) {\n return NextResponse.redirect(\n `${siteUrl}${GOOGLE_OAUTH_LOGIN_PATH}?error=${encodeURIComponent(error)}`\n )\n}\n\n/** GET `/api/auth/google` — start the Google OAuth redirect. */\nexport async function handleGoogleOAuthStart(clientConfig: GoogleOAuthClientConfig) {\n try {\n const siteUrl = getSiteUrl()\n const redirectUri = `${siteUrl}${GOOGLE_OAUTH_CALLBACK_PATH}`\n const client = getGoogleOAuthClient(redirectUri, clientConfig)\n\n const authorizeUrl = client.generateAuthUrl({\n access_type: 'offline',\n scope: [...GOOGLE_OAUTH_SCOPES],\n prompt: 'select_account',\n })\n\n return NextResponse.redirect(authorizeUrl)\n } catch (error) {\n log.error(error instanceof Error ? error.message : 'OAuth configuration error')\n return NextResponse.json({ error: 'OAuth configuration error' }, { status: 500 })\n }\n}\n\n/** GET `/api/auth/google/callback` — exchange the code and set the Payload session cookie. */\nexport async function handleGoogleOAuthCallback(\n request: NextRequest,\n { config, ...clientConfig }: HandleGoogleOAuthCallbackOptions\n) {\n try {\n const { searchParams } = new URL(request.url)\n const siteUrl = getSiteUrl()\n const code = searchParams.get('code')\n const error = searchParams.get('error')\n\n if (error) {\n return loginErrorRedirect(siteUrl, error)\n }\n\n if (!code) {\n return loginErrorRedirect(siteUrl, 'no_code')\n }\n\n const redirectUri = `${siteUrl}${GOOGLE_OAUTH_CALLBACK_PATH}`\n const client = getGoogleOAuthClient(redirectUri, clientConfig)\n\n const { tokens } = await client.getToken(code)\n client.setCredentials(tokens)\n\n if (!tokens.id_token) {\n return loginErrorRedirect(siteUrl, 'no_token')\n }\n\n const ticket = await client.verifyIdToken({\n idToken: tokens.id_token,\n audience: clientConfig.clientId,\n })\n\n const googlePayload = ticket.getPayload()\n if (!googlePayload?.email) {\n return loginErrorRedirect(siteUrl, 'no_email')\n }\n\n const { email, sub: googleId, name, picture } = googlePayload\n const payload = await getPayload({\n config: (await config) as SanitizedConfig,\n })\n\n const users = await payload.find({\n collection: 'users',\n where: {\n or: [{ email: { equals: email } }, { googleId: { equals: googleId } }],\n },\n limit: 1,\n })\n\n let user = users.docs[0]\n if (users.docs.length > 0) {\n user = users.docs[0]\n\n const googleUser = user as typeof user & {\n googleId?: string | null\n name?: string | null\n picture?: string | null\n }\n const updateData: Record<string, unknown> = {}\n\n if (!googleUser.googleId) {\n updateData.googleId = googleId\n updateData.name = name || googleUser.name\n updateData.picture = picture || googleUser.picture\n }\n\n if (Object.keys(updateData).length > 0) {\n user = await payload.update({\n collection: 'users',\n id: user.id,\n data: updateData,\n })\n }\n } else {\n return loginErrorRedirect(siteUrl, 'user_not_found')\n }\n\n const collectionConfig = payload.collections['users'].config\n\n const sessionUser = user as Parameters<typeof addSessionToUser>[0]['user']\n\n const { sid } = await addSessionToUser({\n collectionConfig,\n payload,\n req: {\n payload,\n user: sessionUser,\n } as unknown as Parameters<typeof addSessionToUser>[0]['req'],\n user: sessionUser,\n })\n\n const fieldsToSign = getFieldsToSign({\n collectionConfig,\n email: sessionUser.email as string,\n sid,\n user: sessionUser,\n })\n\n const tokenExpiration = collectionConfig.auth.tokenExpiration || 7200\n const secret = payload.secret\n\n const { token } = await jwtSign({\n fieldsToSign,\n secret,\n tokenExpiration,\n })\n\n const cookie = generatePayloadCookie({\n collectionAuthConfig: collectionConfig.auth,\n cookiePrefix: payload.config.cookiePrefix || 'payload',\n token,\n returnCookieAsObject: true,\n })\n\n const response = NextResponse.redirect(`${siteUrl}${GOOGLE_OAUTH_ADMIN_PATH}`)\n\n response.cookies.set(cookie.name, cookie.value!, {\n httpOnly: cookie.httpOnly,\n sameSite: cookie.sameSite?.toLowerCase() as 'strict' | 'lax' | 'none' | undefined,\n secure: cookie.secure,\n path: cookie.path,\n expires: cookie.expires ? new Date(cookie.expires) : undefined,\n maxAge: cookie.maxAge,\n })\n\n return response\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Authentication failed'\n log.error(errorMessage)\n return loginErrorRedirect(getSiteUrl(), errorMessage)\n }\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { A as codeTabsBlock, B as STOCK_COLLECTION_SLUGS, C as leafBlocks, D as downloadCtaBlock, E as stepsBlock, F as seoFields, G as applyGlobalOverride, H as CollectionOverride, I as draftsWithAutosave, J as createAccessHelpers, K as AccessHelpers, L as BuildCmsConfigOptions, M as richTextBlock, N as setPublishedAt, O as videoBlock, P as slugify, R as buildCmsConfig, S as languageOptions, T as accordionBlock, U as GlobalOverride, V as StockCollectionSlug, W as applyCollectionOverride, _ as blogContentBlocks, a as createPages, b as codeBlockLanguages, c as createAuthors, d as createUsers, f as CreateS3MediaPluginOptions, g as richTextEditor, h as getRichTextEditorConfig, i as createLegalPages, j as codeBlock, k as imageBlock, l as createMedia, m as requireEnvAtRuntime, n as createChangelog, o as createBlogPosts, p as createS3MediaPlugin, q as AccessOptions, r as createChangelogTags, s as createCategories, t as createSiteSettings, u as createApiTokens, v as pageContentBlocks, w as sectionHeadingBlock, x as defaultCodeLanguage, y as showcaseContentBlocks, z as Overrides } from "../index.mjs";
1
+ import { $ as createAccessHelpers, A as downloadCtaBlock, B as seoFields, C as codeBlockLanguages, D as sectionHeadingBlock, E as leafBlocks, F as richTextBlock, G as STOCK_COLLECTION_SLUGS, H as BuildCmsConfigOptions, I as coerceBlogPostCategoriesOnRead, J as GlobalOverride, K as StockCollectionSlug, L as coerceBlogPostCategoriesOnWrite, M as imageBlock, N as codeTabsBlock, O as accordionBlock, P as codeBlock, Q as AccessOptions, R as setPublishedAt, S as showcaseContentBlocks, T as languageOptions, U as buildCmsConfig, V as draftsWithAutosave, W as Overrides, X as applyGlobalOverride, Y as applyCollectionOverride, Z as AccessHelpers, _ as requireEnvAtRuntime, a as createChangelog, b as blogContentBlocks, c as createPages, d as createAuthors, f as createMedia, g as createS3MediaPlugin, h as CreateS3MediaPluginOptions, i as createEventTags, j as videoBlock, k as stepsBlock, l as createBlogPosts, m as createUsers, n as createSiteSettings, o as createChangelogTags, p as createApiTokens, q as CollectionOverride, r as createEvents, s as createLegalPages, t as createAnnouncementBanner, u as createCategories, v as getRichTextEditorConfig, w as defaultCodeLanguage, x as pageContentBlocks, y as richTextEditor, z as slugify } from "../index.mjs";
2
2
  import { n as readPayloadMediaAsDataUrl, r as readPayloadMediaBuffer, t as PayloadMedia } from "../readMediaBuffer.mjs";
3
- export { type AccessHelpers, type AccessOptions, type BuildCmsConfigOptions, type CollectionOverride, type CreateS3MediaPluginOptions, type GlobalOverride, type Overrides, type PayloadMedia, STOCK_COLLECTION_SLUGS, type StockCollectionSlug, accordionBlock, applyCollectionOverride, applyGlobalOverride, blogContentBlocks, buildCmsConfig, codeBlock, codeBlockLanguages, codeTabsBlock, createAccessHelpers, createApiTokens, createAuthors, createBlogPosts, createCategories, createChangelog, createChangelogTags, createLegalPages, createMedia, createPages, createS3MediaPlugin, createSiteSettings, createUsers, defaultCodeLanguage, downloadCtaBlock, draftsWithAutosave, getRichTextEditorConfig, imageBlock, languageOptions, leafBlocks, pageContentBlocks, readPayloadMediaAsDataUrl, readPayloadMediaBuffer, requireEnvAtRuntime, richTextBlock, richTextEditor, sectionHeadingBlock, seoFields, setPublishedAt, showcaseContentBlocks, slugify, stepsBlock, videoBlock };
3
+ export { type AccessHelpers, type AccessOptions, type BuildCmsConfigOptions, type CollectionOverride, type CreateS3MediaPluginOptions, type GlobalOverride, type Overrides, type PayloadMedia, STOCK_COLLECTION_SLUGS, type StockCollectionSlug, accordionBlock, applyCollectionOverride, applyGlobalOverride, blogContentBlocks, buildCmsConfig, codeBlock, codeBlockLanguages, codeTabsBlock, coerceBlogPostCategoriesOnRead, coerceBlogPostCategoriesOnWrite, createAccessHelpers, createAnnouncementBanner, createApiTokens, createAuthors, createBlogPosts, createCategories, createChangelog, createChangelogTags, createEventTags, createEvents, createLegalPages, createMedia, createPages, createS3MediaPlugin, createSiteSettings, createUsers, defaultCodeLanguage, downloadCtaBlock, draftsWithAutosave, getRichTextEditorConfig, imageBlock, languageOptions, leafBlocks, pageContentBlocks, readPayloadMediaAsDataUrl, readPayloadMediaBuffer, requireEnvAtRuntime, richTextBlock, richTextEditor, sectionHeadingBlock, seoFields, setPublishedAt, showcaseContentBlocks, slugify, stepsBlock, videoBlock };
@@ -1,3 +1,3 @@
1
- import { A as downloadCtaBlock, B as createAccessHelpers, C as leafBlocks, D as richTextEditor, E as getRichTextEditorConfig, F as languageOptions, I as createAuthors, L as seoFields, M as codeBlock, N as codeBlockLanguages, O as videoBlock, P as defaultCodeLanguage, R as slugify, S as accordionBlock, T as richTextBlock, _ as setPublishedAt, a as applyCollectionOverride, b as showcaseContentBlocks, c as createUsers, d as createMedia, f as createChangelogTags, g as draftsWithAutosave, h as createBlogPosts, i as STOCK_COLLECTION_SLUGS, j as codeTabsBlock, k as imageBlock, l as createLegalPages, m as createCategories, n as requireEnvAtRuntime, o as applyGlobalOverride, p as createChangelog, r as buildCmsConfig, s as createSiteSettings, t as createS3MediaPlugin, u as createPages, v as blogContentBlocks, w as stepsBlock, x as sectionHeadingBlock, y as pageContentBlocks, z as createApiTokens } from "../cms.mjs";
1
+ import { A as richTextBlock, B as languageOptions, C as blogContentBlocks, D as accordionBlock, E as sectionHeadingBlock, F as downloadCtaBlock, G as createAccessHelpers, H as seoFields, I as codeTabsBlock, L as codeBlock, M as richTextEditor, N as videoBlock, O as leafBlocks, P as imageBlock, R as codeBlockLanguages, S as coerceBlogPostCategoriesOnWrite, T as showcaseContentBlocks, U as slugify, V as createAuthors, W as createApiTokens, _ as createCategories, a as STOCK_COLLECTION_SLUGS, b as setPublishedAt, c as createSiteSettings, d as createPages, f as createMedia, g as createChangelog, h as createChangelogTags, i as buildCmsConfig, j as getRichTextEditorConfig, k as stepsBlock, l as createUsers, m as createEventTags, n as createS3MediaPlugin, o as applyCollectionOverride, p as createEvents, r as requireEnvAtRuntime, s as applyGlobalOverride, t as createAnnouncementBanner, u as createLegalPages, v as createBlogPosts, w as pageContentBlocks, x as coerceBlogPostCategoriesOnRead, y as draftsWithAutosave, z as defaultCodeLanguage } from "../cms.mjs";
2
2
  import { n as readPayloadMediaBuffer, t as readPayloadMediaAsDataUrl } from "../readMediaBuffer.mjs";
3
- export { STOCK_COLLECTION_SLUGS, accordionBlock, applyCollectionOverride, applyGlobalOverride, blogContentBlocks, buildCmsConfig, codeBlock, codeBlockLanguages, codeTabsBlock, createAccessHelpers, createApiTokens, createAuthors, createBlogPosts, createCategories, createChangelog, createChangelogTags, createLegalPages, createMedia, createPages, createS3MediaPlugin, createSiteSettings, createUsers, defaultCodeLanguage, downloadCtaBlock, draftsWithAutosave, getRichTextEditorConfig, imageBlock, languageOptions, leafBlocks, pageContentBlocks, readPayloadMediaAsDataUrl, readPayloadMediaBuffer, requireEnvAtRuntime, richTextBlock, richTextEditor, sectionHeadingBlock, seoFields, setPublishedAt, showcaseContentBlocks, slugify, stepsBlock, videoBlock };
3
+ export { STOCK_COLLECTION_SLUGS, accordionBlock, applyCollectionOverride, applyGlobalOverride, blogContentBlocks, buildCmsConfig, codeBlock, codeBlockLanguages, codeTabsBlock, coerceBlogPostCategoriesOnRead, coerceBlogPostCategoriesOnWrite, createAccessHelpers, createAnnouncementBanner, createApiTokens, createAuthors, createBlogPosts, createCategories, createChangelog, createChangelogTags, createEventTags, createEvents, createLegalPages, createMedia, createPages, createS3MediaPlugin, createSiteSettings, createUsers, defaultCodeLanguage, downloadCtaBlock, draftsWithAutosave, getRichTextEditorConfig, imageBlock, languageOptions, leafBlocks, pageContentBlocks, readPayloadMediaAsDataUrl, readPayloadMediaBuffer, requireEnvAtRuntime, richTextBlock, richTextEditor, sectionHeadingBlock, seoFields, setPublishedAt, showcaseContentBlocks, slugify, stepsBlock, videoBlock };