octocms 0.4.16 → 0.4.18
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 +2 -2
- package/dist/admin/actions/agent.d.ts.map +1 -1
- package/dist/admin/actions/agent.js +3 -4
- package/dist/admin/actions/agent.js.map +1 -1
- package/dist/admin/auth/cookies.d.ts +16 -0
- package/dist/admin/auth/cookies.d.ts.map +1 -0
- package/dist/admin/auth/cookies.js +45 -0
- package/dist/admin/auth/cookies.js.map +1 -0
- package/dist/admin/auth/env.d.ts +6 -0
- package/dist/admin/auth/env.d.ts.map +1 -0
- package/dist/admin/auth/env.js +25 -0
- package/dist/admin/auth/env.js.map +1 -0
- package/dist/admin/auth/oauthApp.d.ts +8 -0
- package/dist/admin/auth/oauthApp.d.ts.map +1 -0
- package/dist/admin/auth/oauthApp.js +64 -0
- package/dist/admin/auth/oauthApp.js.map +1 -0
- package/dist/admin/auth/seal.d.ts +6 -0
- package/dist/admin/auth/seal.d.ts.map +1 -0
- package/dist/admin/auth/seal.js +61 -0
- package/dist/admin/auth/seal.js.map +1 -0
- package/dist/admin/auth/session.d.ts +19 -0
- package/dist/admin/auth/session.d.ts.map +1 -0
- package/dist/admin/auth/session.js +89 -0
- package/dist/admin/auth/session.js.map +1 -0
- package/dist/admin/auth/types.d.ts +17 -0
- package/dist/admin/auth/types.d.ts.map +1 -0
- package/dist/admin/auth/types.js +1 -0
- package/dist/admin/auth/types.js.map +1 -0
- package/dist/admin/authRoutes.d.ts +14 -0
- package/dist/admin/authRoutes.d.ts.map +1 -0
- package/dist/admin/authRoutes.js +147 -0
- package/dist/admin/authRoutes.js.map +1 -0
- package/dist/admin/error.d.ts +9 -0
- package/dist/admin/error.d.ts.map +1 -0
- package/dist/admin/error.js +7 -0
- package/dist/admin/error.js.map +1 -0
- package/dist/admin/github.d.ts.map +1 -1
- package/dist/admin/github.js +2 -3
- package/dist/admin/github.js.map +1 -1
- package/dist/admin/index.d.ts +5 -7
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +2 -3
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/pages/AdminErrorView.d.ts +1 -1
- package/dist/admin/pages/AdminErrorView.js.map +1 -1
- package/dist/admin/pages/AdminLayout.d.ts +1 -1
- package/dist/admin/pages/AdminLayout.d.ts.map +1 -1
- package/dist/admin/pages/AdminLayout.js +1 -1
- package/dist/admin/pages/AdminLayout.js.map +1 -1
- package/dist/admin/pages/CollectionPage.d.ts.map +1 -1
- package/dist/admin/pages/CollectionPage.js +2 -3
- package/dist/admin/pages/CollectionPage.js.map +1 -1
- package/dist/admin/pages/ContentModelPage.d.ts.map +1 -1
- package/dist/admin/pages/ContentModelPage.js +2 -3
- package/dist/admin/pages/ContentModelPage.js.map +1 -1
- package/dist/admin/pages/ContentPage.d.ts.map +1 -1
- package/dist/admin/pages/ContentPage.js +2 -3
- package/dist/admin/pages/ContentPage.js.map +1 -1
- package/dist/admin/pages/ContentTypePage.d.ts.map +1 -1
- package/dist/admin/pages/ContentTypePage.js +2 -3
- package/dist/admin/pages/ContentTypePage.js.map +1 -1
- package/dist/admin/pages/EntryPage.d.ts.map +1 -1
- package/dist/admin/pages/EntryPage.js +2 -3
- package/dist/admin/pages/EntryPage.js.map +1 -1
- package/dist/admin/pages/MediaAssetPage.d.ts.map +1 -1
- package/dist/admin/pages/MediaAssetPage.js +2 -3
- package/dist/admin/pages/MediaAssetPage.js.map +1 -1
- package/dist/admin/pages/MediaPage.d.ts.map +1 -1
- package/dist/admin/pages/MediaPage.js +2 -3
- package/dist/admin/pages/MediaPage.js.map +1 -1
- package/dist/admin/provider.d.ts +1 -3
- package/dist/admin/provider.d.ts.map +1 -1
- package/dist/admin/provider.js +2 -7
- package/dist/admin/provider.js.map +1 -1
- package/dist/admin/query/hooks/useEntryList.d.ts +1 -1
- package/dist/admin/query/hooks/useEntryList.d.ts.map +1 -1
- package/dist/admin/theme/toggle.d.ts.map +1 -1
- package/dist/admin/theme/toggle.js +2 -11
- package/dist/admin/theme/toggle.js.map +1 -1
- package/dist/agent/chatApi.d.ts +2 -2
- package/dist/agent/chatApi.d.ts.map +1 -1
- package/dist/agent/chatApi.js +3 -4
- package/dist/agent/chatApi.js.map +1 -1
- package/dist/agent/chatSetup.d.ts +1 -1
- package/dist/agent/chatSetup.d.ts.map +1 -1
- package/dist/agent/chatSetup.js +1 -1
- package/dist/agent/chatSetup.js.map +1 -1
- package/dist/agentDocs-PVLGO5EN.js +54 -0
- package/dist/agentDocs-PVLGO5EN.js.map +1 -0
- package/dist/chunk-M7DLGZNW.js +7 -0
- package/dist/{chunk-TOUAHFDW.js.map → chunk-M7DLGZNW.js.map} +1 -1
- package/dist/{chunk-I7VNI2IG.js → chunk-OJ3KR7WR.js} +67 -15
- package/dist/chunk-OJ3KR7WR.js.map +1 -0
- package/dist/cli/index.js +6 -6
- package/dist/cli/lib/agentDocs.d.ts +5 -4
- package/dist/cli/lib/agentDocs.d.ts.map +1 -1
- package/dist/cli/lib/agentDocs.js +40 -105
- package/dist/cli/lib/agentDocs.js.map +1 -1
- package/dist/cli/lib/codegen.d.ts.map +1 -1
- package/dist/cli/lib/codegen.js +9 -5
- package/dist/cli/lib/codegen.js.map +1 -1
- package/dist/cli/lib/templates.js +57 -13
- package/dist/cli/lib/templates.js.map +1 -1
- package/dist/components/Chat/ChatAgentSetup.js +1 -1
- package/dist/components/Chat/ChatAgentSetup.js.map +1 -1
- package/dist/components/Chat/useChatStream.d.ts.map +1 -1
- package/dist/components/Chat/useChatStream.js +2 -1
- package/dist/components/Chat/useChatStream.js.map +1 -1
- package/dist/components/ContentModel/SchemaOptionFieldInput.js +1 -1
- package/dist/components/ContentModel/SchemaOptionFieldInput.js.map +1 -1
- package/dist/components/Dashboard/DashboardContent.js +1 -1
- package/dist/components/Dashboard/DashboardContent.js.map +1 -1
- package/dist/components/Layout/Layout.d.ts.map +1 -1
- package/dist/components/Layout/Layout.js +24 -21
- package/dist/components/Layout/Layout.js.map +1 -1
- package/dist/components/Layout/LeftNavItem.js +1 -1
- package/dist/components/Layout/LeftNavItem.js.map +1 -1
- package/dist/components/Layout/TopHeader.js +2 -2
- package/dist/components/Layout/TopHeader.js.map +1 -1
- package/dist/components/Layout/UserAccountDialog.d.ts.map +1 -1
- package/dist/components/Layout/UserAccountDialog.js +3 -2
- package/dist/components/Layout/UserAccountDialog.js.map +1 -1
- package/dist/components/MediaAsset/skeletons/MediaMetadataFormSkeleton.js +1 -1
- package/dist/components/MediaAsset/skeletons/MediaMetadataFormSkeleton.js.map +1 -1
- package/dist/components/MediaManager/MediaSelectDialog.d.ts.map +1 -1
- package/dist/components/MediaManager/MediaSelectDialog.js +2 -2
- package/dist/components/MediaManager/MediaSelectDialog.js.map +1 -1
- package/dist/components/OctoCmsSurfaceMarker.d.ts +3 -0
- package/dist/components/OctoCmsSurfaceMarker.d.ts.map +1 -0
- package/dist/components/OctoCmsSurfaceMarker.js +21 -0
- package/dist/components/OctoCmsSurfaceMarker.js.map +1 -0
- package/dist/components/public/RichTextContent.js +3 -3
- package/dist/components/public/RichTextContent.js.map +1 -1
- package/dist/components/public/SearchBox.d.ts.map +1 -1
- package/dist/components/public/SearchBox.js +2 -1
- package/dist/components/public/SearchBox.js.map +1 -1
- package/dist/components/ui/BranchChip/BranchChip.js +1 -1
- package/dist/components/ui/BranchChip/BranchChip.js.map +1 -1
- package/dist/components/ui/FormField/richtext/ConditionEmbedEditor.js +1 -1
- package/dist/components/ui/FormField/richtext/ConditionEmbedEditor.js.map +1 -1
- package/dist/components/ui/FormField/richtext/ImageEmbedEditor.js +5 -5
- package/dist/components/ui/FormField/richtext/ImageEmbedEditor.js.map +1 -1
- package/dist/components/ui/FormField/richtext/ReferenceEmbedEditor.d.ts.map +1 -1
- package/dist/components/ui/FormField/richtext/ReferenceEmbedEditor.js +3 -3
- package/dist/components/ui/FormField/richtext/ReferenceEmbedEditor.js.map +1 -1
- package/dist/components/ui/StatusBadge/StatusBadge.js +3 -3
- package/dist/components/ui/StatusBadge/StatusBadge.js.map +1 -1
- package/dist/{embeddingsGen-FXWCPGB7.js → embeddingsGen-J62LLQUR.js} +2 -2
- package/dist/{github-7HIP6RW3.js → github-WNZOR3LV.js} +66 -26
- package/dist/github-WNZOR3LV.js.map +1 -0
- package/dist/globals.css +1340 -1241
- package/dist/hooks/useCmsSession.d.ts +10 -0
- package/dist/hooks/useCmsSession.d.ts.map +1 -0
- package/dist/hooks/useCmsSession.js +48 -0
- package/dist/hooks/useCmsSession.js.map +1 -0
- package/dist/{init-KNIWQGJL.js → init-Y2IIVIPX.js} +15 -10
- package/dist/init-Y2IIVIPX.js.map +1 -0
- package/dist/lib/cmsSurface.d.ts +3 -0
- package/dist/lib/cmsSurface.d.ts.map +1 -0
- package/dist/lib/cmsSurface.js +6 -0
- package/dist/lib/cmsSurface.js.map +1 -0
- package/dist/lib/octocmsApiRoutes.d.ts +15 -0
- package/dist/lib/octocmsApiRoutes.d.ts.map +1 -0
- package/dist/lib/octocmsApiRoutes.js +15 -0
- package/dist/lib/octocmsApiRoutes.js.map +1 -0
- package/dist/{typesGen-MFAL3B4V.js → typesGen-QWWTC4SZ.js} +6 -2
- package/dist/typesGen-QWWTC4SZ.js.map +1 -0
- package/dist/{update-QALIQG76.js → update-7EDULZ3C.js} +77 -28
- package/dist/update-7EDULZ3C.js.map +1 -0
- package/docs/editing-schema.md +10 -9
- package/docs/index.md +23 -16
- package/docs/overview.md +14 -35
- package/globals.css +1340 -1241
- package/package.json +6 -5
- package/dist/admin/auth.d.ts +0 -3
- package/dist/admin/auth.d.ts.map +0 -1
- package/dist/admin/auth.js +0 -28
- package/dist/admin/auth.js.map +0 -1
- package/dist/agentDocs-QZ4NOQVH.js +0 -38
- package/dist/agentDocs-QZ4NOQVH.js.map +0 -1
- package/dist/chunk-I7VNI2IG.js.map +0 -1
- package/dist/chunk-TOUAHFDW.js +0 -7
- package/dist/github-7HIP6RW3.js.map +0 -1
- package/dist/init-KNIWQGJL.js.map +0 -1
- package/dist/typesGen-MFAL3B4V.js.map +0 -1
- package/dist/update-QALIQG76.js.map +0 -1
- package/docs/schema.md +0 -311
- /package/dist/{embeddingsGen-FXWCPGB7.js.map → embeddingsGen-J62LLQUR.js.map} +0 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A file-based CMS for Next.js. Schema defined in TypeScript, content stored as JSON files, Git-backed, no database.
|
|
4
4
|
|
|
5
|
-
**[octocms.
|
|
5
|
+
**[octocms.gunkin.dev](https://octocms.gunkin.dev)** · [Docs](https://octocms.gunkin.dev/docs)
|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
@@ -47,7 +47,7 @@ Visit `http://localhost:3000/cms` to open the editor.
|
|
|
47
47
|
```bash
|
|
48
48
|
GITHUB_ID= # GitHub App client ID
|
|
49
49
|
GITHUB_SECRET= # GitHub App client secret
|
|
50
|
-
NEXTAUTH_SECRET=
|
|
50
|
+
NEXTAUTH_SECRET= # Random string: openssl rand -base64 32
|
|
51
51
|
NEXTAUTH_URL=http://localhost:3000
|
|
52
52
|
|
|
53
53
|
# Required in production
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../admin/actions/agent.ts"],"names":[],"mappings":"AAEA,OAAO,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../admin/actions/agent.ts"],"names":[],"mappings":"AAEA,OAAO,kBAAkB,CAAC;AAO1B,MAAM,MAAM,iBAAiB,GACzB;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAClB;IACE,OAAO,EAAE,IAAI,CAAC;IACd,QAAQ,EAAE,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN;;;;;;GAMG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAOvE;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC;AAEvE;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAsBjG;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CAYzF"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use server";
|
|
2
2
|
import "../../chunk-B5LE2OEC.js";
|
|
3
3
|
import "./registerConfig";
|
|
4
|
-
import { getServerSession } from "next-auth/next";
|
|
5
4
|
import { getAgentConfig } from "../../agent/configStore";
|
|
6
5
|
import { getAgentStatus, isAgentEnabled } from "../../agent/featureFlag";
|
|
7
6
|
import { acceptProposal, isProposal } from "../../agent/proposals";
|
|
8
|
-
import {
|
|
7
|
+
import { getCmsSession } from "../auth/session";
|
|
9
8
|
async function getAgentClientStatus() {
|
|
10
9
|
const cfg = getAgentConfig();
|
|
11
10
|
if (!cfg || !isAgentEnabled(cfg)) return { enabled: false };
|
|
@@ -18,7 +17,7 @@ async function acceptProposalAction(proposal) {
|
|
|
18
17
|
if (!cfg || !isAgentEnabled(cfg)) {
|
|
19
18
|
throw new Error("Chat agent is disabled.");
|
|
20
19
|
}
|
|
21
|
-
const session = await
|
|
20
|
+
const session = await getCmsSession();
|
|
22
21
|
if (!session) {
|
|
23
22
|
throw new Error("Unauthorized.");
|
|
24
23
|
}
|
|
@@ -36,7 +35,7 @@ async function rejectProposalAction(_reason) {
|
|
|
36
35
|
if (!cfg || !isAgentEnabled(cfg)) {
|
|
37
36
|
throw new Error("Chat agent is disabled.");
|
|
38
37
|
}
|
|
39
|
-
const session = await
|
|
38
|
+
const session = await getCmsSession();
|
|
40
39
|
if (!session) {
|
|
41
40
|
throw new Error("Unauthorized.");
|
|
42
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../admin/actions/agent.ts"],"sourcesContent":["'use server';\n\nimport './registerConfig';\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../admin/actions/agent.ts"],"sourcesContent":["'use server';\n\nimport './registerConfig';\n\nimport { getAgentConfig } from '../../agent/configStore';\nimport { getAgentStatus, isAgentEnabled } from '../../agent/featureFlag';\nimport { acceptProposal, isProposal, type AcceptResult } from '../../agent/proposals';\nimport { getCmsSession } from '../auth/session';\n\nexport type AgentClientStatus =\n | { enabled: false }\n | {\n enabled: true;\n provider: 'anthropic' | 'openai' | 'local';\n model: string;\n };\n\n/**\n * Server-side check exposed to the admin client (Header nav link).\n *\n * Never returns the API key. Returns `{ enabled: false }` when the chat API is\n * disabled (missing config, key, or budget). The `/cms/chat` page still renders\n * a setup guide; this action is for optional client UI that needs a boolean gate.\n */\nexport async function getAgentClientStatus(): Promise<AgentClientStatus> {\n const cfg = getAgentConfig();\n if (!cfg || !isAgentEnabled(cfg)) return { enabled: false };\n // Recompute via getAgentStatus so we exercise the same code path the route uses.\n const status = getAgentStatus(cfg);\n if (!status.enabled) return { enabled: false };\n return { enabled: true, provider: cfg.provider.type, model: cfg.provider.model };\n}\n\nexport type AcceptProposalActionResult =\n | { ok: true; entryPath: string }\n | { ok: false; error: string; fieldErrors?: Record<string, string> };\n\n/**\n * Server action — apply a chat-agent edit/create proposal.\n *\n * Replaces the previous `POST /api/agent/proposals/accept` Route Handler. The\n * client (`useChatStream`) calls this directly via the Server Action transport\n * — no public endpoint, no thin re-export file.\n *\n * Stateless by design: the entire proposal payload arrives over the wire and\n * is re-validated here (and again inside `acceptProposal` via the schema\n * validator + `saveFile`).\n *\n * Returns `{ ok: false, error }` on validation / write failures so the client\n * can render an inline error without try/catch around the action call.\n * Throws only when the agent is disabled or the caller is unauthenticated —\n * those are caller-bug shapes, not user-facing flow.\n */\nexport async function acceptProposalAction(proposal: unknown): Promise<AcceptProposalActionResult> {\n const cfg = getAgentConfig();\n if (!cfg || !isAgentEnabled(cfg)) {\n throw new Error('Chat agent is disabled.');\n }\n\n const session = await getCmsSession();\n if (!session) {\n throw new Error('Unauthorized.');\n }\n\n if (!isProposal(proposal)) {\n return { ok: false, error: 'Invalid proposal payload.' };\n }\n\n const result: AcceptResult = await acceptProposal(proposal);\n if (!result.ok) {\n return result.fieldErrors\n ? { ok: false, error: result.error, fieldErrors: result.fieldErrors }\n : { ok: false, error: result.error };\n }\n return { ok: true, entryPath: result.entryPath };\n}\n\n/**\n * Server action — record that the user dismissed a proposal.\n *\n * Replaces the previous `POST /api/agent/proposals/reject` Route Handler.\n * There's no server-side proposal record to mark rejected; this just\n * acknowledges the click. The client reflects rejection in its own state and\n * feeds the rejection back to the model on the next chat turn as a synthetic\n * system note. The `reason` argument is currently ignored — kept for forward\n * compatibility (e.g. analytics / per-rejection telemetry).\n *\n * Auth-gated to keep the surface consistent with `acceptProposalAction`.\n */\nexport async function rejectProposalAction(_reason?: string | null): Promise<{ ok: true }> {\n const cfg = getAgentConfig();\n if (!cfg || !isAgentEnabled(cfg)) {\n throw new Error('Chat agent is disabled.');\n }\n\n const session = await getCmsSession();\n if (!session) {\n throw new Error('Unauthorized.');\n }\n\n return { ok: true };\n}\n"],"mappings":";;AAEA,OAAO;AAEP,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB,sBAAsB;AAC/C,SAAS,gBAAgB,kBAAqC;AAC9D,SAAS,qBAAqB;AAiB9B,eAAsB,uBAAmD;AACvE,QAAM,MAAM,eAAe;AAC3B,MAAI,CAAC,OAAO,CAAC,eAAe,GAAG,EAAG,QAAO,EAAE,SAAS,MAAM;AAE1D,QAAM,SAAS,eAAe,GAAG;AACjC,MAAI,CAAC,OAAO,QAAS,QAAO,EAAE,SAAS,MAAM;AAC7C,SAAO,EAAE,SAAS,MAAM,UAAU,IAAI,SAAS,MAAM,OAAO,IAAI,SAAS,MAAM;AACjF;AAsBA,eAAsB,qBAAqB,UAAwD;AACjG,QAAM,MAAM,eAAe;AAC3B,MAAI,CAAC,OAAO,CAAC,eAAe,GAAG,GAAG;AAChC,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AAEA,QAAM,UAAU,MAAM,cAAc;AACpC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,eAAe;AAAA,EACjC;AAEA,MAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,WAAO,EAAE,IAAI,OAAO,OAAO,4BAA4B;AAAA,EACzD;AAEA,QAAM,SAAuB,MAAM,eAAe,QAAQ;AAC1D,MAAI,CAAC,OAAO,IAAI;AACd,WAAO,OAAO,cACV,EAAE,IAAI,OAAO,OAAO,OAAO,OAAO,aAAa,OAAO,YAAY,IAClE,EAAE,IAAI,OAAO,OAAO,OAAO,MAAM;AAAA,EACvC;AACA,SAAO,EAAE,IAAI,MAAM,WAAW,OAAO,UAAU;AACjD;AAcA,eAAsB,qBAAqB,SAAgD;AACzF,QAAM,MAAM,eAAe;AAC3B,MAAI,CAAC,OAAO,CAAC,eAAe,GAAG,GAAG;AAChC,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AAEA,QAAM,UAAU,MAAM,cAAc;AACpC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,eAAe;AAAA,EACjC;AAEA,SAAO,EAAE,IAAI,KAAK;AACpB;","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const CMS_SESSION_COOKIE = "octocms-session";
|
|
2
|
+
export declare const CMS_OAUTH_STATE_COOKIE = "octocms-oauth-state";
|
|
3
|
+
export type CookieOptions = {
|
|
4
|
+
httpOnly: boolean;
|
|
5
|
+
secure: boolean;
|
|
6
|
+
sameSite: 'lax' | 'strict' | 'none';
|
|
7
|
+
path: string;
|
|
8
|
+
maxAge?: number;
|
|
9
|
+
};
|
|
10
|
+
export declare function sessionCookieOptions(): CookieOptions;
|
|
11
|
+
export declare function oauthStateCookieOptions(): CookieOptions;
|
|
12
|
+
/** Serialize cookie for `Set-Cookie` header (Route Handler responses). */
|
|
13
|
+
export declare function formatSetCookie(name: string, value: string, options: CookieOptions): string;
|
|
14
|
+
/** Clear cookie via `Set-Cookie` with Max-Age=0. */
|
|
15
|
+
export declare function formatClearCookie(name: string, options: Pick<CookieOptions, 'path' | 'secure' | 'sameSite'>): string;
|
|
16
|
+
//# sourceMappingURL=cookies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../../admin/auth/cookies.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AACpD,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAK5D,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAgB,oBAAoB,IAAI,aAAa,CAQpD;AAED,wBAAgB,uBAAuB,IAAI,aAAa,CAQvD;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAM3F;AAED,oDAAoD;AACpD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC,GAAG,MAAM,CAKpH"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import "../../chunk-B5LE2OEC.js";
|
|
2
|
+
const CMS_SESSION_COOKIE = "octocms-session";
|
|
3
|
+
const CMS_OAUTH_STATE_COOKIE = "octocms-oauth-state";
|
|
4
|
+
const SESSION_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;
|
|
5
|
+
const OAUTH_STATE_MAX_AGE_SECONDS = 5 * 60;
|
|
6
|
+
function sessionCookieOptions() {
|
|
7
|
+
return {
|
|
8
|
+
httpOnly: true,
|
|
9
|
+
secure: process.env.NODE_ENV === "production",
|
|
10
|
+
sameSite: "lax",
|
|
11
|
+
path: "/",
|
|
12
|
+
maxAge: SESSION_MAX_AGE_SECONDS
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function oauthStateCookieOptions() {
|
|
16
|
+
return {
|
|
17
|
+
httpOnly: true,
|
|
18
|
+
secure: process.env.NODE_ENV === "production",
|
|
19
|
+
sameSite: "lax",
|
|
20
|
+
path: "/",
|
|
21
|
+
maxAge: OAUTH_STATE_MAX_AGE_SECONDS
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function formatSetCookie(name, value, options) {
|
|
25
|
+
const parts = [`${name}=${encodeURIComponent(value)}`, `Path=${options.path}`, `SameSite=${options.sameSite}`];
|
|
26
|
+
if (options.httpOnly) parts.push("HttpOnly");
|
|
27
|
+
if (options.secure) parts.push("Secure");
|
|
28
|
+
if (options.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
|
|
29
|
+
return parts.join("; ");
|
|
30
|
+
}
|
|
31
|
+
function formatClearCookie(name, options) {
|
|
32
|
+
const parts = [`${name}=`, `Path=${options.path}`, "Max-Age=0", `SameSite=${options.sameSite}`];
|
|
33
|
+
parts.push("HttpOnly");
|
|
34
|
+
if (options.secure) parts.push("Secure");
|
|
35
|
+
return parts.join("; ");
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
CMS_OAUTH_STATE_COOKIE,
|
|
39
|
+
CMS_SESSION_COOKIE,
|
|
40
|
+
formatClearCookie,
|
|
41
|
+
formatSetCookie,
|
|
42
|
+
oauthStateCookieOptions,
|
|
43
|
+
sessionCookieOptions
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=cookies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../admin/auth/cookies.ts"],"sourcesContent":["export const CMS_SESSION_COOKIE = 'octocms-session';\nexport const CMS_OAUTH_STATE_COOKIE = 'octocms-oauth-state';\n\nconst SESSION_MAX_AGE_SECONDS = 30 * 24 * 60 * 60; // 30 days — parity with typical OAuth sessions\nconst OAUTH_STATE_MAX_AGE_SECONDS = 5 * 60;\n\nexport type CookieOptions = {\n httpOnly: boolean;\n secure: boolean;\n sameSite: 'lax' | 'strict' | 'none';\n path: string;\n maxAge?: number;\n};\n\nexport function sessionCookieOptions(): CookieOptions {\n return {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: SESSION_MAX_AGE_SECONDS,\n };\n}\n\nexport function oauthStateCookieOptions(): CookieOptions {\n return {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: OAUTH_STATE_MAX_AGE_SECONDS,\n };\n}\n\n/** Serialize cookie for `Set-Cookie` header (Route Handler responses). */\nexport function formatSetCookie(name: string, value: string, options: CookieOptions): string {\n const parts = [`${name}=${encodeURIComponent(value)}`, `Path=${options.path}`, `SameSite=${options.sameSite}`];\n if (options.httpOnly) parts.push('HttpOnly');\n if (options.secure) parts.push('Secure');\n if (options.maxAge !== undefined) parts.push(`Max-Age=${options.maxAge}`);\n return parts.join('; ');\n}\n\n/** Clear cookie via `Set-Cookie` with Max-Age=0. */\nexport function formatClearCookie(name: string, options: Pick<CookieOptions, 'path' | 'secure' | 'sameSite'>): string {\n const parts = [`${name}=`, `Path=${options.path}`, 'Max-Age=0', `SameSite=${options.sameSite}`];\n parts.push('HttpOnly');\n if (options.secure) parts.push('Secure');\n return parts.join('; ');\n}\n"],"mappings":";AAAO,MAAM,qBAAqB;AAC3B,MAAM,yBAAyB;AAEtC,MAAM,0BAA0B,KAAK,KAAK,KAAK;AAC/C,MAAM,8BAA8B,IAAI;AAUjC,SAAS,uBAAsC;AACpD,SAAO;AAAA,IACL,UAAU;AAAA,IACV,QAAQ,QAAQ,IAAI,aAAa;AAAA,IACjC,UAAU;AAAA,IACV,MAAM;AAAA,IACN,QAAQ;AAAA,EACV;AACF;AAEO,SAAS,0BAAyC;AACvD,SAAO;AAAA,IACL,UAAU;AAAA,IACV,QAAQ,QAAQ,IAAI,aAAa;AAAA,IACjC,UAAU;AAAA,IACV,MAAM;AAAA,IACN,QAAQ;AAAA,EACV;AACF;AAGO,SAAS,gBAAgB,MAAc,OAAe,SAAgC;AAC3F,QAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,mBAAmB,KAAK,CAAC,IAAI,QAAQ,QAAQ,IAAI,IAAI,YAAY,QAAQ,QAAQ,EAAE;AAC7G,MAAI,QAAQ,SAAU,OAAM,KAAK,UAAU;AAC3C,MAAI,QAAQ,OAAQ,OAAM,KAAK,QAAQ;AACvC,MAAI,QAAQ,WAAW,OAAW,OAAM,KAAK,WAAW,QAAQ,MAAM,EAAE;AACxE,SAAO,MAAM,KAAK,IAAI;AACxB;AAGO,SAAS,kBAAkB,MAAc,SAAsE;AACpH,QAAM,QAAQ,CAAC,GAAG,IAAI,KAAK,QAAQ,QAAQ,IAAI,IAAI,aAAa,YAAY,QAAQ,QAAQ,EAAE;AAC9F,QAAM,KAAK,UAAU;AACrB,MAAI,QAAQ,OAAQ,OAAM,KAAK,QAAQ;AACvC,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Session sealing secret (`NEXTAUTH_SECRET`). */
|
|
2
|
+
export declare function getSessionSecret(): string;
|
|
3
|
+
/** Public app base URL for OAuth callback construction (`NEXTAUTH_URL`). */
|
|
4
|
+
export declare function getAppUrl(): string;
|
|
5
|
+
export declare function getOAuthCallbackUrl(): string;
|
|
6
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../admin/auth/env.ts"],"names":[],"mappings":"AAEA,kDAAkD;AAClD,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAED,4EAA4E;AAC5E,wBAAgB,SAAS,IAAI,MAAM,CASlC;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import "../../chunk-B5LE2OEC.js";
|
|
2
|
+
const trimOrEmpty = (value) => typeof value === "string" ? value.trim() : "";
|
|
3
|
+
function getSessionSecret() {
|
|
4
|
+
const secret = trimOrEmpty(process.env.NEXTAUTH_SECRET);
|
|
5
|
+
if (!secret) {
|
|
6
|
+
throw new Error("Missing NEXTAUTH_SECRET. Generate one with: openssl rand -base64 32");
|
|
7
|
+
}
|
|
8
|
+
return secret;
|
|
9
|
+
}
|
|
10
|
+
function getAppUrl() {
|
|
11
|
+
const url = trimOrEmpty(process.env.NEXTAUTH_URL) || (process.env.NODE_ENV === "development" ? "http://localhost:3000" : "");
|
|
12
|
+
if (!url) {
|
|
13
|
+
throw new Error("Missing NEXTAUTH_URL \u2014 required in production for OAuth callbacks.");
|
|
14
|
+
}
|
|
15
|
+
return url.replace(/\/$/, "");
|
|
16
|
+
}
|
|
17
|
+
function getOAuthCallbackUrl() {
|
|
18
|
+
return `${getAppUrl()}/api/octocms/auth/callback`;
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
getAppUrl,
|
|
22
|
+
getOAuthCallbackUrl,
|
|
23
|
+
getSessionSecret
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../admin/auth/env.ts"],"sourcesContent":["const trimOrEmpty = (value: string | undefined): string => (typeof value === 'string' ? value.trim() : '');\n\n/** Session sealing secret (`NEXTAUTH_SECRET`). */\nexport function getSessionSecret(): string {\n const secret = trimOrEmpty(process.env.NEXTAUTH_SECRET);\n if (!secret) {\n throw new Error('Missing NEXTAUTH_SECRET. Generate one with: openssl rand -base64 32');\n }\n return secret;\n}\n\n/** Public app base URL for OAuth callback construction (`NEXTAUTH_URL`). */\nexport function getAppUrl(): string {\n const url =\n trimOrEmpty(process.env.NEXTAUTH_URL) || (process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : '');\n\n if (!url) {\n throw new Error('Missing NEXTAUTH_URL — required in production for OAuth callbacks.');\n }\n\n return url.replace(/\\/$/, '');\n}\n\nexport function getOAuthCallbackUrl(): string {\n return `${getAppUrl()}/api/octocms/auth/callback`;\n}\n"],"mappings":";AAAA,MAAM,cAAc,CAAC,UAAuC,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;AAGhG,SAAS,mBAA2B;AACzC,QAAM,SAAS,YAAY,QAAQ,IAAI,eAAe;AACtD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,qEAAqE;AAAA,EACvF;AACA,SAAO;AACT;AAGO,SAAS,YAAoB;AAClC,QAAM,MACJ,YAAY,QAAQ,IAAI,YAAY,MAAM,QAAQ,IAAI,aAAa,gBAAgB,0BAA0B;AAE/G,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,yEAAoE;AAAA,EACtF;AAEA,SAAO,IAAI,QAAQ,OAAO,EAAE;AAC9B;AAEO,SAAS,sBAA8B;AAC5C,SAAO,GAAG,UAAU,CAAC;AACvB;","names":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { OAuthApp } from '@octokit/oauth-app';
|
|
2
|
+
import type { CmsSession } from './types';
|
|
3
|
+
export declare function getOAuthApp(): InstanceType<typeof OAuthApp>;
|
|
4
|
+
/** Reset singleton — test seam only. */
|
|
5
|
+
export declare function resetOAuthAppForTests(): void;
|
|
6
|
+
export declare function getAuthorizationUrl(state: string, redirectUrl: string): string;
|
|
7
|
+
export declare function exchangeCodeForSession(code: string): Promise<CmsSession>;
|
|
8
|
+
//# sourceMappingURL=oauthApp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthApp.d.ts","sourceRoot":"","sources":["../../../admin/auth/oauthApp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,OAAO,KAAK,EAAE,UAAU,EAAW,MAAM,SAAS,CAAC;AAgBnD,wBAAgB,WAAW,IAAI,YAAY,CAAC,OAAO,QAAQ,CAAC,CAS3D;AAED,wCAAwC;AACxC,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAS9E;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAoB9E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import "../../chunk-B5LE2OEC.js";
|
|
2
|
+
import { OAuthApp } from "@octokit/oauth-app";
|
|
3
|
+
import { Octokit } from "octokit";
|
|
4
|
+
let oauthAppSingleton = null;
|
|
5
|
+
function getClientId() {
|
|
6
|
+
var _a;
|
|
7
|
+
const id = (_a = process.env.GITHUB_ID) == null ? void 0 : _a.trim();
|
|
8
|
+
if (!id) throw new Error("Missing GITHUB_ID environment variable.");
|
|
9
|
+
return id;
|
|
10
|
+
}
|
|
11
|
+
function getClientSecret() {
|
|
12
|
+
var _a;
|
|
13
|
+
const secret = (_a = process.env.GITHUB_SECRET) == null ? void 0 : _a.trim();
|
|
14
|
+
if (!secret) throw new Error("Missing GITHUB_SECRET environment variable.");
|
|
15
|
+
return secret;
|
|
16
|
+
}
|
|
17
|
+
function getOAuthApp() {
|
|
18
|
+
if (!oauthAppSingleton) {
|
|
19
|
+
oauthAppSingleton = new OAuthApp({
|
|
20
|
+
clientType: "github-app",
|
|
21
|
+
clientId: getClientId(),
|
|
22
|
+
clientSecret: getClientSecret()
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return oauthAppSingleton;
|
|
26
|
+
}
|
|
27
|
+
function resetOAuthAppForTests() {
|
|
28
|
+
oauthAppSingleton = null;
|
|
29
|
+
}
|
|
30
|
+
function getAuthorizationUrl(state, redirectUrl) {
|
|
31
|
+
const app = getOAuthApp();
|
|
32
|
+
const { url } = app.getWebFlowAuthorizationUrl({
|
|
33
|
+
state,
|
|
34
|
+
redirectUrl,
|
|
35
|
+
// GitHub Apps use app permissions — scopes are ignored for github-app client type.
|
|
36
|
+
scopes: ["repo"]
|
|
37
|
+
});
|
|
38
|
+
return url;
|
|
39
|
+
}
|
|
40
|
+
async function exchangeCodeForSession(code) {
|
|
41
|
+
var _a;
|
|
42
|
+
const app = getOAuthApp();
|
|
43
|
+
const { authentication } = await app.createToken({ code });
|
|
44
|
+
const accessToken = authentication.token;
|
|
45
|
+
if (!accessToken) {
|
|
46
|
+
throw new Error("GitHub did not return an access token.");
|
|
47
|
+
}
|
|
48
|
+
const octokit = new Octokit({ auth: accessToken });
|
|
49
|
+
const { data } = await octokit.rest.users.getAuthenticated();
|
|
50
|
+
const user = {
|
|
51
|
+
id: String(data.id),
|
|
52
|
+
name: (_a = data.name) != null ? _a : data.login,
|
|
53
|
+
email: data.email,
|
|
54
|
+
image: data.avatar_url
|
|
55
|
+
};
|
|
56
|
+
return { user, accessToken };
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
exchangeCodeForSession,
|
|
60
|
+
getAuthorizationUrl,
|
|
61
|
+
getOAuthApp,
|
|
62
|
+
resetOAuthAppForTests
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=oauthApp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../admin/auth/oauthApp.ts"],"sourcesContent":["import { OAuthApp } from '@octokit/oauth-app';\nimport { Octokit } from 'octokit';\n\nimport type { CmsSession, CmsUser } from './types';\n\nlet oauthAppSingleton: InstanceType<typeof OAuthApp> | null = null;\n\nfunction getClientId(): string {\n const id = process.env.GITHUB_ID?.trim();\n if (!id) throw new Error('Missing GITHUB_ID environment variable.');\n return id;\n}\n\nfunction getClientSecret(): string {\n const secret = process.env.GITHUB_SECRET?.trim();\n if (!secret) throw new Error('Missing GITHUB_SECRET environment variable.');\n return secret;\n}\n\nexport function getOAuthApp(): InstanceType<typeof OAuthApp> {\n if (!oauthAppSingleton) {\n oauthAppSingleton = new OAuthApp({\n clientType: 'github-app',\n clientId: getClientId(),\n clientSecret: getClientSecret(),\n });\n }\n return oauthAppSingleton;\n}\n\n/** Reset singleton — test seam only. */\nexport function resetOAuthAppForTests(): void {\n oauthAppSingleton = null;\n}\n\nexport function getAuthorizationUrl(state: string, redirectUrl: string): string {\n const app = getOAuthApp();\n const { url } = app.getWebFlowAuthorizationUrl({\n state,\n redirectUrl,\n // GitHub Apps use app permissions — scopes are ignored for github-app client type.\n scopes: ['repo'],\n });\n return url;\n}\n\nexport async function exchangeCodeForSession(code: string): Promise<CmsSession> {\n const app = getOAuthApp();\n const { authentication } = await app.createToken({ code });\n\n const accessToken = authentication.token;\n if (!accessToken) {\n throw new Error('GitHub did not return an access token.');\n }\n\n const octokit = new Octokit({ auth: accessToken });\n const { data } = await octokit.rest.users.getAuthenticated();\n\n const user: CmsUser = {\n id: String(data.id),\n name: data.name ?? data.login,\n email: data.email,\n image: data.avatar_url,\n };\n\n return { user, accessToken };\n}\n"],"mappings":";AAAA,SAAS,gBAAgB;AACzB,SAAS,eAAe;AAIxB,IAAI,oBAA0D;AAE9D,SAAS,cAAsB;AAP/B;AAQE,QAAM,MAAK,aAAQ,IAAI,cAAZ,mBAAuB;AAClC,MAAI,CAAC,GAAI,OAAM,IAAI,MAAM,yCAAyC;AAClE,SAAO;AACT;AAEA,SAAS,kBAA0B;AAbnC;AAcE,QAAM,UAAS,aAAQ,IAAI,kBAAZ,mBAA2B;AAC1C,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,6CAA6C;AAC1E,SAAO;AACT;AAEO,SAAS,cAA6C;AAC3D,MAAI,CAAC,mBAAmB;AACtB,wBAAoB,IAAI,SAAS;AAAA,MAC/B,YAAY;AAAA,MACZ,UAAU,YAAY;AAAA,MACtB,cAAc,gBAAgB;AAAA,IAChC,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAGO,SAAS,wBAA8B;AAC5C,sBAAoB;AACtB;AAEO,SAAS,oBAAoB,OAAe,aAA6B;AAC9E,QAAM,MAAM,YAAY;AACxB,QAAM,EAAE,IAAI,IAAI,IAAI,2BAA2B;AAAA,IAC7C;AAAA,IACA;AAAA;AAAA,IAEA,QAAQ,CAAC,MAAM;AAAA,EACjB,CAAC;AACD,SAAO;AACT;AAEA,eAAsB,uBAAuB,MAAmC;AA9ChF;AA+CE,QAAM,MAAM,YAAY;AACxB,QAAM,EAAE,eAAe,IAAI,MAAM,IAAI,YAAY,EAAE,KAAK,CAAC;AAEzD,QAAM,cAAc,eAAe;AACnC,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,MAAM,wCAAwC;AAAA,EAC1D;AAEA,QAAM,UAAU,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,QAAM,EAAE,KAAK,IAAI,MAAM,QAAQ,KAAK,MAAM,iBAAiB;AAE3D,QAAM,OAAgB;AAAA,IACpB,IAAI,OAAO,KAAK,EAAE;AAAA,IAClB,OAAM,UAAK,SAAL,YAAa,KAAK;AAAA,IACxB,OAAO,KAAK;AAAA,IACZ,OAAO,KAAK;AAAA,EACd;AAEA,SAAO,EAAE,MAAM,YAAY;AAC7B;","names":[]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CmsSession } from './types';
|
|
2
|
+
/** Browser cookie size limit — stay under 4 KB including name and attributes. */
|
|
3
|
+
export declare const MAX_SEALED_SESSION_BYTES = 3800;
|
|
4
|
+
export declare function sealSession(payload: CmsSession, secret: string): Promise<string>;
|
|
5
|
+
export declare function unsealSession(sealed: string, secret: string): Promise<CmsSession | null>;
|
|
6
|
+
//# sourceMappingURL=seal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seal.d.ts","sourceRoot":"","sources":["../../../admin/auth/seal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C,iFAAiF;AACjF,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAiC7C,wBAAsB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAetF;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAgB9F"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import "../../chunk-B5LE2OEC.js";
|
|
2
|
+
const IV_LENGTH = 12;
|
|
3
|
+
const MAX_SEALED_SESSION_BYTES = 3800;
|
|
4
|
+
async function deriveAesKey(secret) {
|
|
5
|
+
const keyMaterial = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(secret));
|
|
6
|
+
return crypto.subtle.importKey("raw", keyMaterial, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
|
|
7
|
+
}
|
|
8
|
+
function base64UrlEncode(bytes) {
|
|
9
|
+
let binary = "";
|
|
10
|
+
for (const byte of bytes) {
|
|
11
|
+
binary += String.fromCharCode(byte);
|
|
12
|
+
}
|
|
13
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
14
|
+
}
|
|
15
|
+
function base64UrlDecode(value) {
|
|
16
|
+
const padded = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
17
|
+
const padLen = (4 - padded.length % 4) % 4;
|
|
18
|
+
const base64 = padded + "=".repeat(padLen);
|
|
19
|
+
const binary = atob(base64);
|
|
20
|
+
const bytes = new Uint8Array(binary.length);
|
|
21
|
+
for (let i = 0; i < binary.length; i++) {
|
|
22
|
+
bytes[i] = binary.charCodeAt(i);
|
|
23
|
+
}
|
|
24
|
+
return bytes;
|
|
25
|
+
}
|
|
26
|
+
async function sealSession(payload, secret) {
|
|
27
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
|
28
|
+
const key = await deriveAesKey(secret);
|
|
29
|
+
const plaintext = new TextEncoder().encode(JSON.stringify(payload));
|
|
30
|
+
const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, plaintext);
|
|
31
|
+
const combined = new Uint8Array(iv.length + ciphertext.byteLength);
|
|
32
|
+
combined.set(iv, 0);
|
|
33
|
+
combined.set(new Uint8Array(ciphertext), iv.length);
|
|
34
|
+
const sealed = base64UrlEncode(combined);
|
|
35
|
+
if (sealed.length > MAX_SEALED_SESSION_BYTES) {
|
|
36
|
+
throw new Error("Session payload exceeds cookie size limit after sealing.");
|
|
37
|
+
}
|
|
38
|
+
return sealed;
|
|
39
|
+
}
|
|
40
|
+
async function unsealSession(sealed, secret) {
|
|
41
|
+
var _a;
|
|
42
|
+
try {
|
|
43
|
+
const combined = base64UrlDecode(sealed);
|
|
44
|
+
if (combined.length <= IV_LENGTH) return null;
|
|
45
|
+
const iv = combined.slice(0, IV_LENGTH);
|
|
46
|
+
const ciphertext = combined.slice(IV_LENGTH);
|
|
47
|
+
const key = await deriveAesKey(secret);
|
|
48
|
+
const plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ciphertext);
|
|
49
|
+
const parsed = JSON.parse(new TextDecoder().decode(plaintext));
|
|
50
|
+
if (!((_a = parsed == null ? void 0 : parsed.user) == null ? void 0 : _a.id)) return null;
|
|
51
|
+
return parsed;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
MAX_SEALED_SESSION_BYTES,
|
|
58
|
+
sealSession,
|
|
59
|
+
unsealSession
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=seal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../admin/auth/seal.ts"],"sourcesContent":["import type { CmsSession } from './types';\n\nconst IV_LENGTH = 12;\n/** Browser cookie size limit — stay under 4 KB including name and attributes. */\nexport const MAX_SEALED_SESSION_BYTES = 3800;\n\n/**\n * AES-256-GCM session seal using the Web Crypto API (Node 18+ / Vercel serverless).\n *\n * Key derivation: SHA-256 digest of the secret string → 256-bit AES key.\n * Wire format: base64url(iv || ciphertext) where ciphertext includes the GCM auth tag.\n */\nasync function deriveAesKey(secret: string): Promise<CryptoKey> {\n const keyMaterial = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(secret));\n return crypto.subtle.importKey('raw', keyMaterial, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']);\n}\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction base64UrlDecode(value: string): Uint8Array {\n const padded = value.replace(/-/g, '+').replace(/_/g, '/');\n const padLen = (4 - (padded.length % 4)) % 4;\n const base64 = padded + '='.repeat(padLen);\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\nexport async function sealSession(payload: CmsSession, secret: string): Promise<string> {\n const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n const key = await deriveAesKey(secret);\n const plaintext = new TextEncoder().encode(JSON.stringify(payload));\n const ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext);\n\n const combined = new Uint8Array(iv.length + ciphertext.byteLength);\n combined.set(iv, 0);\n combined.set(new Uint8Array(ciphertext), iv.length);\n\n const sealed = base64UrlEncode(combined);\n if (sealed.length > MAX_SEALED_SESSION_BYTES) {\n throw new Error('Session payload exceeds cookie size limit after sealing.');\n }\n return sealed;\n}\n\nexport async function unsealSession(sealed: string, secret: string): Promise<CmsSession | null> {\n try {\n const combined = base64UrlDecode(sealed);\n if (combined.length <= IV_LENGTH) return null;\n\n const iv = combined.slice(0, IV_LENGTH);\n const ciphertext = combined.slice(IV_LENGTH);\n const key = await deriveAesKey(secret);\n const plaintext = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext);\n const parsed = JSON.parse(new TextDecoder().decode(plaintext)) as CmsSession;\n\n if (!parsed?.user?.id) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n"],"mappings":";AAEA,MAAM,YAAY;AAEX,MAAM,2BAA2B;AAQxC,eAAe,aAAa,QAAoC;AAC9D,QAAM,cAAc,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI,YAAY,EAAE,OAAO,MAAM,CAAC;AAC1F,SAAO,OAAO,OAAO,UAAU,OAAO,aAAa,EAAE,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,SAAS,CAAC;AACvG;AAEA,SAAS,gBAAgB,OAA2B;AAClD,MAAI,SAAS;AACb,aAAW,QAAQ,OAAO;AACxB,cAAU,OAAO,aAAa,IAAI;AAAA,EACpC;AACA,SAAO,KAAK,MAAM,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,EAAE;AAC/E;AAEA,SAAS,gBAAgB,OAA2B;AAClD,QAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AACzD,QAAM,UAAU,IAAK,OAAO,SAAS,KAAM;AAC3C,QAAM,SAAS,SAAS,IAAI,OAAO,MAAM;AACzC,QAAM,SAAS,KAAK,MAAM;AAC1B,QAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAC1C,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,CAAC,IAAI,OAAO,WAAW,CAAC;AAAA,EAChC;AACA,SAAO;AACT;AAEA,eAAsB,YAAY,SAAqB,QAAiC;AACtF,QAAM,KAAK,OAAO,gBAAgB,IAAI,WAAW,SAAS,CAAC;AAC3D,QAAM,MAAM,MAAM,aAAa,MAAM;AACrC,QAAM,YAAY,IAAI,YAAY,EAAE,OAAO,KAAK,UAAU,OAAO,CAAC;AAClE,QAAM,aAAa,MAAM,OAAO,OAAO,QAAQ,EAAE,MAAM,WAAW,GAAG,GAAG,KAAK,SAAS;AAEtF,QAAM,WAAW,IAAI,WAAW,GAAG,SAAS,WAAW,UAAU;AACjE,WAAS,IAAI,IAAI,CAAC;AAClB,WAAS,IAAI,IAAI,WAAW,UAAU,GAAG,GAAG,MAAM;AAElD,QAAM,SAAS,gBAAgB,QAAQ;AACvC,MAAI,OAAO,SAAS,0BAA0B;AAC5C,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AACA,SAAO;AACT;AAEA,eAAsB,cAAc,QAAgB,QAA4C;AAtDhG;AAuDE,MAAI;AACF,UAAM,WAAW,gBAAgB,MAAM;AACvC,QAAI,SAAS,UAAU,UAAW,QAAO;AAEzC,UAAM,KAAK,SAAS,MAAM,GAAG,SAAS;AACtC,UAAM,aAAa,SAAS,MAAM,SAAS;AAC3C,UAAM,MAAM,MAAM,aAAa,MAAM;AACrC,UAAM,YAAY,MAAM,OAAO,OAAO,QAAQ,EAAE,MAAM,WAAW,GAAG,GAAG,KAAK,UAAU;AACtF,UAAM,SAAS,KAAK,MAAM,IAAI,YAAY,EAAE,OAAO,SAAS,CAAC;AAE7D,QAAI,GAAC,sCAAQ,SAAR,mBAAc,IAAI,QAAO;AAC9B,WAAO;AAAA,EACT,SAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CmsSession, CmsSessionPublic } from './types';
|
|
2
|
+
export type OAuthStatePayload = {
|
|
3
|
+
state: string;
|
|
4
|
+
returnTo: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function toPublicSession(session: CmsSession): CmsSessionPublic;
|
|
7
|
+
/** Read and decrypt the CMS session from the request cookies (Server Components, Actions, Route Handlers). */
|
|
8
|
+
export declare function getCmsSession(): Promise<CmsSession | null>;
|
|
9
|
+
export declare function setCmsSessionCookie(session: CmsSession): Promise<string>;
|
|
10
|
+
export declare function clearCmsSessionCookie(): Promise<void>;
|
|
11
|
+
export declare function setOAuthStateCookie(payload: OAuthStatePayload): Promise<void>;
|
|
12
|
+
export declare function readOAuthStateCookie(): Promise<OAuthStatePayload | null>;
|
|
13
|
+
export declare function clearOAuthStateCookie(): Promise<void>;
|
|
14
|
+
/** Build Set-Cookie headers for Route Handlers that return a raw `Response`. */
|
|
15
|
+
export declare function buildSessionSetCookieHeader(session: CmsSession): Promise<string>;
|
|
16
|
+
export declare function buildSessionClearCookieHeader(): string;
|
|
17
|
+
export declare function buildOAuthStateSetCookieHeader(payload: OAuthStatePayload): string;
|
|
18
|
+
export declare function buildOAuthStateClearCookieHeader(): string;
|
|
19
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../admin/auth/session.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAU5D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,GAAG,gBAAgB,CAErE;AAED,8GAA8G;AAC9G,wBAAsB,aAAa,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAWhE;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9E;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3D;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGnF;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAW9E;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3D;AAED,gFAAgF;AAChF,wBAAsB,2BAA2B,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAItF;AAED,wBAAgB,6BAA6B,IAAI,MAAM,CAGtD;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAEjF;AAED,wBAAgB,gCAAgC,IAAI,MAAM,CAGzD"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import "../../chunk-B5LE2OEC.js";
|
|
2
|
+
import { cookies } from "next/headers";
|
|
3
|
+
import { getSessionSecret } from "./env";
|
|
4
|
+
import { sealSession, unsealSession } from "./seal";
|
|
5
|
+
import {
|
|
6
|
+
CMS_OAUTH_STATE_COOKIE,
|
|
7
|
+
CMS_SESSION_COOKIE,
|
|
8
|
+
formatClearCookie,
|
|
9
|
+
formatSetCookie,
|
|
10
|
+
oauthStateCookieOptions,
|
|
11
|
+
sessionCookieOptions
|
|
12
|
+
} from "./cookies";
|
|
13
|
+
function toPublicSession(session) {
|
|
14
|
+
return { user: session.user };
|
|
15
|
+
}
|
|
16
|
+
async function getCmsSession() {
|
|
17
|
+
var _a;
|
|
18
|
+
const cookieStore = await cookies();
|
|
19
|
+
const sealed = (_a = cookieStore.get(CMS_SESSION_COOKIE)) == null ? void 0 : _a.value;
|
|
20
|
+
if (!sealed) return null;
|
|
21
|
+
try {
|
|
22
|
+
const secret = getSessionSecret();
|
|
23
|
+
return unsealSession(sealed, secret);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function setCmsSessionCookie(session) {
|
|
29
|
+
const secret = getSessionSecret();
|
|
30
|
+
const sealed = await sealSession(session, secret);
|
|
31
|
+
const cookieStore = await cookies();
|
|
32
|
+
cookieStore.set(CMS_SESSION_COOKIE, sealed, sessionCookieOptions());
|
|
33
|
+
return sealed;
|
|
34
|
+
}
|
|
35
|
+
async function clearCmsSessionCookie() {
|
|
36
|
+
const cookieStore = await cookies();
|
|
37
|
+
cookieStore.delete(CMS_SESSION_COOKIE);
|
|
38
|
+
}
|
|
39
|
+
async function setOAuthStateCookie(payload) {
|
|
40
|
+
const cookieStore = await cookies();
|
|
41
|
+
cookieStore.set(CMS_OAUTH_STATE_COOKIE, JSON.stringify(payload), oauthStateCookieOptions());
|
|
42
|
+
}
|
|
43
|
+
async function readOAuthStateCookie() {
|
|
44
|
+
var _a;
|
|
45
|
+
const cookieStore = await cookies();
|
|
46
|
+
const raw = (_a = cookieStore.get(CMS_OAUTH_STATE_COOKIE)) == null ? void 0 : _a.value;
|
|
47
|
+
if (!raw) return null;
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(raw);
|
|
50
|
+
if (!(parsed == null ? void 0 : parsed.state)) return null;
|
|
51
|
+
return parsed;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function clearOAuthStateCookie() {
|
|
57
|
+
const cookieStore = await cookies();
|
|
58
|
+
cookieStore.delete(CMS_OAUTH_STATE_COOKIE);
|
|
59
|
+
}
|
|
60
|
+
async function buildSessionSetCookieHeader(session) {
|
|
61
|
+
const secret = getSessionSecret();
|
|
62
|
+
const sealed = await sealSession(session, secret);
|
|
63
|
+
return formatSetCookie(CMS_SESSION_COOKIE, sealed, sessionCookieOptions());
|
|
64
|
+
}
|
|
65
|
+
function buildSessionClearCookieHeader() {
|
|
66
|
+
const opts = sessionCookieOptions();
|
|
67
|
+
return formatClearCookie(CMS_SESSION_COOKIE, opts);
|
|
68
|
+
}
|
|
69
|
+
function buildOAuthStateSetCookieHeader(payload) {
|
|
70
|
+
return formatSetCookie(CMS_OAUTH_STATE_COOKIE, JSON.stringify(payload), oauthStateCookieOptions());
|
|
71
|
+
}
|
|
72
|
+
function buildOAuthStateClearCookieHeader() {
|
|
73
|
+
const opts = oauthStateCookieOptions();
|
|
74
|
+
return formatClearCookie(CMS_OAUTH_STATE_COOKIE, opts);
|
|
75
|
+
}
|
|
76
|
+
export {
|
|
77
|
+
buildOAuthStateClearCookieHeader,
|
|
78
|
+
buildOAuthStateSetCookieHeader,
|
|
79
|
+
buildSessionClearCookieHeader,
|
|
80
|
+
buildSessionSetCookieHeader,
|
|
81
|
+
clearCmsSessionCookie,
|
|
82
|
+
clearOAuthStateCookie,
|
|
83
|
+
getCmsSession,
|
|
84
|
+
readOAuthStateCookie,
|
|
85
|
+
setCmsSessionCookie,
|
|
86
|
+
setOAuthStateCookie,
|
|
87
|
+
toPublicSession
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../admin/auth/session.ts"],"sourcesContent":["import { cookies } from 'next/headers';\n\nimport { getSessionSecret } from './env';\nimport { sealSession, unsealSession } from './seal';\nimport type { CmsSession, CmsSessionPublic } from './types';\nimport {\n CMS_OAUTH_STATE_COOKIE,\n CMS_SESSION_COOKIE,\n formatClearCookie,\n formatSetCookie,\n oauthStateCookieOptions,\n sessionCookieOptions,\n} from './cookies';\n\nexport type OAuthStatePayload = {\n state: string;\n returnTo: string;\n};\n\nexport function toPublicSession(session: CmsSession): CmsSessionPublic {\n return { user: session.user };\n}\n\n/** Read and decrypt the CMS session from the request cookies (Server Components, Actions, Route Handlers). */\nexport async function getCmsSession(): Promise<CmsSession | null> {\n const cookieStore = await cookies();\n const sealed = cookieStore.get(CMS_SESSION_COOKIE)?.value;\n if (!sealed) return null;\n\n try {\n const secret = getSessionSecret();\n return unsealSession(sealed, secret);\n } catch {\n return null;\n }\n}\n\nexport async function setCmsSessionCookie(session: CmsSession): Promise<string> {\n const secret = getSessionSecret();\n const sealed = await sealSession(session, secret);\n const cookieStore = await cookies();\n cookieStore.set(CMS_SESSION_COOKIE, sealed, sessionCookieOptions());\n return sealed;\n}\n\nexport async function clearCmsSessionCookie(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.delete(CMS_SESSION_COOKIE);\n}\n\nexport async function setOAuthStateCookie(payload: OAuthStatePayload): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(CMS_OAUTH_STATE_COOKIE, JSON.stringify(payload), oauthStateCookieOptions());\n}\n\nexport async function readOAuthStateCookie(): Promise<OAuthStatePayload | null> {\n const cookieStore = await cookies();\n const raw = cookieStore.get(CMS_OAUTH_STATE_COOKIE)?.value;\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as OAuthStatePayload;\n if (!parsed?.state) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport async function clearOAuthStateCookie(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.delete(CMS_OAUTH_STATE_COOKIE);\n}\n\n/** Build Set-Cookie headers for Route Handlers that return a raw `Response`. */\nexport async function buildSessionSetCookieHeader(session: CmsSession): Promise<string> {\n const secret = getSessionSecret();\n const sealed = await sealSession(session, secret);\n return formatSetCookie(CMS_SESSION_COOKIE, sealed, sessionCookieOptions());\n}\n\nexport function buildSessionClearCookieHeader(): string {\n const opts = sessionCookieOptions();\n return formatClearCookie(CMS_SESSION_COOKIE, opts);\n}\n\nexport function buildOAuthStateSetCookieHeader(payload: OAuthStatePayload): string {\n return formatSetCookie(CMS_OAUTH_STATE_COOKIE, JSON.stringify(payload), oauthStateCookieOptions());\n}\n\nexport function buildOAuthStateClearCookieHeader(): string {\n const opts = oauthStateCookieOptions();\n return formatClearCookie(CMS_OAUTH_STATE_COOKIE, opts);\n}\n"],"mappings":";AAAA,SAAS,eAAe;AAExB,SAAS,wBAAwB;AACjC,SAAS,aAAa,qBAAqB;AAE3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAOA,SAAS,gBAAgB,SAAuC;AACrE,SAAO,EAAE,MAAM,QAAQ,KAAK;AAC9B;AAGA,eAAsB,gBAA4C;AAxBlE;AAyBE,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,UAAS,iBAAY,IAAI,kBAAkB,MAAlC,mBAAqC;AACpD,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI;AACF,UAAM,SAAS,iBAAiB;AAChC,WAAO,cAAc,QAAQ,MAAM;AAAA,EACrC,SAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,oBAAoB,SAAsC;AAC9E,QAAM,SAAS,iBAAiB;AAChC,QAAM,SAAS,MAAM,YAAY,SAAS,MAAM;AAChD,QAAM,cAAc,MAAM,QAAQ;AAClC,cAAY,IAAI,oBAAoB,QAAQ,qBAAqB,CAAC;AAClE,SAAO;AACT;AAEA,eAAsB,wBAAuC;AAC3D,QAAM,cAAc,MAAM,QAAQ;AAClC,cAAY,OAAO,kBAAkB;AACvC;AAEA,eAAsB,oBAAoB,SAA2C;AACnF,QAAM,cAAc,MAAM,QAAQ;AAClC,cAAY,IAAI,wBAAwB,KAAK,UAAU,OAAO,GAAG,wBAAwB,CAAC;AAC5F;AAEA,eAAsB,uBAA0D;AAvDhF;AAwDE,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,OAAM,iBAAY,IAAI,sBAAsB,MAAtC,mBAAyC;AACrD,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,EAAC,iCAAQ,OAAO,QAAO;AAC3B,WAAO;AAAA,EACT,SAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,wBAAuC;AAC3D,QAAM,cAAc,MAAM,QAAQ;AAClC,cAAY,OAAO,sBAAsB;AAC3C;AAGA,eAAsB,4BAA4B,SAAsC;AACtF,QAAM,SAAS,iBAAiB;AAChC,QAAM,SAAS,MAAM,YAAY,SAAS,MAAM;AAChD,SAAO,gBAAgB,oBAAoB,QAAQ,qBAAqB,CAAC;AAC3E;AAEO,SAAS,gCAAwC;AACtD,QAAM,OAAO,qBAAqB;AAClC,SAAO,kBAAkB,oBAAoB,IAAI;AACnD;AAEO,SAAS,+BAA+B,SAAoC;AACjF,SAAO,gBAAgB,wBAAwB,KAAK,UAAU,OAAO,GAAG,wBAAwB,CAAC;AACnG;AAEO,SAAS,mCAA2C;AACzD,QAAM,OAAO,wBAAwB;AACrC,SAAO,kBAAkB,wBAAwB,IAAI;AACvD;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type CmsUser = {
|
|
2
|
+
id: string;
|
|
3
|
+
name?: string | null;
|
|
4
|
+
email?: string | null;
|
|
5
|
+
image?: string | null;
|
|
6
|
+
};
|
|
7
|
+
/** Server-side session stored in the sealed `octocms-session` cookie. */
|
|
8
|
+
export type CmsSession = {
|
|
9
|
+
user: CmsUser;
|
|
10
|
+
/** GitHub user access token — used when `CMS_GITHUB_TOKEN` is unset. */
|
|
11
|
+
accessToken?: string;
|
|
12
|
+
};
|
|
13
|
+
/** JSON returned by `GET /api/octocms/auth/session` (no access token). */
|
|
14
|
+
export type CmsSessionPublic = {
|
|
15
|
+
user: CmsUser;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../admin/auth/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,yEAAyE;AACzE,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,0EAA0E;AAC1E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,OAAO,CAAC;CACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CmsUser } from './auth/types';
|
|
2
|
+
export type AuthorizeUserFn = (user: CmsUser) => boolean | Promise<boolean>;
|
|
3
|
+
export type AuthRouteHandlers = {
|
|
4
|
+
authRoute: (request: Request, action: string) => Promise<Response>;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Factory for auth Route Handlers with optional access-control hook.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createAuthRouteHandlers(options?: {
|
|
10
|
+
authorizeUser?: AuthorizeUserFn;
|
|
11
|
+
}): AuthRouteHandlers;
|
|
12
|
+
/** Default auth Route Handler dispatcher (no access-control hook). */
|
|
13
|
+
export declare const authRoute: (request: Request, action: string) => Promise<Response>;
|
|
14
|
+
//# sourceMappingURL=authRoutes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authRoutes.d.ts","sourceRoot":"","sources":["../../admin/authRoutes.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAE5E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACpE,CAAC;AA2HF;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,eAAe,CAAA;CAAE,GAAG,iBAAiB,CAyBxG;AAED,sEAAsE;AACtE,eAAO,MAAQ,SAAS,YA3JD,OAAO,UAAU,MAAM,KAAK,OAAO,CAAC,QAAQ,CA2Jb,CAAC"}
|