@contentrail/cloudflare 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # `@contentrail/cloudflare`
2
2
 
3
- Server-only Cloudflare Worker publishing API with **Cloudflare Access** authentication and per-site authorization.
3
+ Server-only Cloudflare Worker / Pages publishing API with **password admin auth**
4
+ (default) or optional **Cloudflare Access**, plus per-site authorization.
4
5
 
5
- **Do not import from browser code.** Git/R2 credentials and Access verification settings stay in Worker secret bindings.
6
+ **Do not import from browser code.** Git/R2 credentials, admin passwords, session
7
+ secrets, and Access verification settings stay in Worker/Pages secret bindings.
6
8
 
7
9
  ## Requirements
8
10
 
@@ -18,17 +20,18 @@ pnpm install
18
20
  pnpm --filter @contentrail/cloudflare build
19
21
  ```
20
22
 
21
- ### From npm (`0.2.3`)
23
+ ### From npm (`0.2.5`)
22
24
 
23
25
  ```sh
24
- pnpm add @contentrail/core@0.2.3 @contentrail/publisher@0.2.3 @contentrail/cloudflare@0.2.3 zod@^4.6.7
26
+ pnpm add @contentrail/core@0.2.5 @contentrail/publisher@0.2.5 @contentrail/cloudflare@0.2.5 zod@^4.6.7
25
27
  ```
26
28
 
27
- ## ADR 011b summary
29
+ ## Auth summary (ADR 011b + ADR 030)
28
30
 
29
- - Authentication is pluggable; Access JWT is the first adapter.
30
- - Authorization is separate and default-deny per `siteId`.
31
+ - Authentication is pluggable. Pages default is username/password session; Access JWT remains optional.
32
+ - Authorization is separate and default-deny per `siteId` (`allowedSubjects` / `allowedEmails`).
31
33
  - Client requests never choose repository/bucket/prefix — only a configured `destinationRef` on the server.
34
+ - Pages scaffolds must mount **both** `/api/*` and `/v1/*` onto `createPagesSiteHandler` (the editor client uses `/v1`).
32
35
 
33
36
  ## Endpoints
34
37
 
@@ -97,7 +100,10 @@ export default {
97
100
  };
98
101
  ```
99
102
 
100
- Pages Functions: `createPagesSiteHandler` (see `docs/CLOUDFLARE_PAGES.md`). Static `/admin` is not protected by Functions middleware.
103
+ Pages Functions: `createPagesSiteHandler` plus `pagesHandlerModuleSource` /
104
+ `PAGES_API_FUNCTION_SOURCE` / `PAGES_V1_FUNCTION_SOURCE` (see
105
+ `docs/CLOUDFLARE_PAGES.md`). Static `/admin` HTML is not protected by Functions
106
+ middleware; API auth still blocks CMS operations.
101
107
 
102
108
  ## Deferred
103
109
 
@@ -0,0 +1,36 @@
1
+ import { type SessionSecrets } from "./session.js";
2
+ import type { Authenticator, Identity } from "./types.js";
3
+ export interface PasswordAuthOptions extends SessionSecrets {
4
+ readonly username: string;
5
+ readonly password: string;
6
+ }
7
+ /**
8
+ * Username/password admin auth. Sessions are HS256 JWTs (Bearer or cookie).
9
+ * Prefer this for small self-hosted sites; Cloudflare Access remains optional.
10
+ */
11
+ export declare function createPasswordAuthenticator(options: PasswordAuthOptions): Authenticator;
12
+ export interface PasswordLoginInput {
13
+ readonly username: string;
14
+ readonly password: string;
15
+ }
16
+ export declare function loginWithPassword(options: PasswordAuthOptions, input: PasswordLoginInput): Promise<{
17
+ ok: true;
18
+ token: string;
19
+ identity: Identity;
20
+ } | {
21
+ ok: false;
22
+ }>;
23
+ /**
24
+ * Prefer password auth when admin credentials are configured.
25
+ * Fall back to Access when Access team+AUD are set and password is not.
26
+ */
27
+ export declare function createPagesAuthenticator(env: {
28
+ readonly CONTENTRAIL_ADMIN_USERNAME?: string;
29
+ readonly CONTENTRAIL_ADMIN_PASSWORD?: string;
30
+ readonly CONTENTRAIL_SESSION_SECRET?: string;
31
+ readonly CONTENTRAIL_ACCESS_TEAM_DOMAIN?: string;
32
+ readonly CONTENTRAIL_ACCESS_AUD?: string;
33
+ readonly accessAuthenticator?: Authenticator;
34
+ readonly passwordAuthenticator?: Authenticator;
35
+ }): Authenticator;
36
+ //# sourceMappingURL=password.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/auth/password.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE1D,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAkBD;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,mBAAmB,GAC3B,aAAa,CA0Bf;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,mBAAmB,EAC5B,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC,CAgB1E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE;IAC5C,QAAQ,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IAC7C,QAAQ,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IAC7C,QAAQ,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IAC7C,QAAQ,CAAC,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACjD,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IACzC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,aAAa,CAAC;IAC7C,QAAQ,CAAC,qBAAqB,CAAC,EAAE,aAAa,CAAC;CAChD,GAAG,aAAa,CA+BhB"}
@@ -0,0 +1,95 @@
1
+ import { createSessionToken, readSessionTokenFromRequest, verifySessionToken, } from "./session.js";
2
+ /** Workers-safe compare (no node:crypto). Length is normalized via SHA-256. */
3
+ async function safeEqualString(left, right) {
4
+ const enc = new TextEncoder();
5
+ const [leftDigest, rightDigest] = await Promise.all([
6
+ crypto.subtle.digest("SHA-256", enc.encode(left)),
7
+ crypto.subtle.digest("SHA-256", enc.encode(right)),
8
+ ]);
9
+ const a = new Uint8Array(leftDigest);
10
+ const b = new Uint8Array(rightDigest);
11
+ let out = 0;
12
+ for (let i = 0; i < a.length; i += 1) {
13
+ out |= a[i] ^ b[i];
14
+ }
15
+ return out === 0;
16
+ }
17
+ /**
18
+ * Username/password admin auth. Sessions are HS256 JWTs (Bearer or cookie).
19
+ * Prefer this for small self-hosted sites; Cloudflare Access remains optional.
20
+ */
21
+ export function createPasswordAuthenticator(options) {
22
+ return {
23
+ async authenticate(request) {
24
+ const token = readSessionTokenFromRequest(request);
25
+ if (token === null) {
26
+ return {
27
+ ok: false,
28
+ status: 401,
29
+ code: "MISSING_CREDENTIAL",
30
+ message: "Missing admin session. Sign in with username and password.",
31
+ };
32
+ }
33
+ const identity = await verifySessionToken(token, {
34
+ sessionSecret: options.sessionSecret,
35
+ });
36
+ if (identity === null) {
37
+ return {
38
+ ok: false,
39
+ status: 401,
40
+ code: "MALFORMED_CREDENTIAL",
41
+ message: "Admin session is invalid or expired.",
42
+ };
43
+ }
44
+ return { ok: true, identity };
45
+ },
46
+ };
47
+ }
48
+ export async function loginWithPassword(options, input) {
49
+ const userOk = await safeEqualString(input.username, options.username);
50
+ const passOk = await safeEqualString(input.password, options.password);
51
+ if (!userOk || !passOk) {
52
+ return { ok: false };
53
+ }
54
+ const identity = {
55
+ subject: `password:${options.username}`,
56
+ issuer: "contentrail:password",
57
+ audience: "contentrail:admin",
58
+ ...(options.username.includes("@") ? { email: options.username } : {}),
59
+ };
60
+ const token = await createSessionToken(identity, {
61
+ sessionSecret: options.sessionSecret,
62
+ });
63
+ return { ok: true, token, identity };
64
+ }
65
+ /**
66
+ * Prefer password auth when admin credentials are configured.
67
+ * Fall back to Access when Access team+AUD are set and password is not.
68
+ */
69
+ export function createPagesAuthenticator(env) {
70
+ const user = env.CONTENTRAIL_ADMIN_USERNAME?.trim() ?? "";
71
+ const password = env.CONTENTRAIL_ADMIN_PASSWORD ?? "";
72
+ const sessionSecret = env.CONTENTRAIL_SESSION_SECRET?.trim() ?? "";
73
+ if (user !== "" && password !== "" && sessionSecret !== "") {
74
+ return (env.passwordAuthenticator ??
75
+ createPasswordAuthenticator({
76
+ username: user,
77
+ password,
78
+ sessionSecret,
79
+ }));
80
+ }
81
+ if (env.accessAuthenticator !== undefined) {
82
+ return env.accessAuthenticator;
83
+ }
84
+ return {
85
+ async authenticate() {
86
+ return {
87
+ ok: false,
88
+ status: 401,
89
+ code: "KEY_UNAVAILABLE",
90
+ message: "Admin auth is not configured. Set CONTENTRAIL_ADMIN_USERNAME, CONTENTRAIL_ADMIN_PASSWORD, and CONTENTRAIL_SESSION_SECRET (or Cloudflare Access).",
91
+ };
92
+ },
93
+ };
94
+ }
95
+ //# sourceMappingURL=password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.js","sourceRoot":"","sources":["../../src/auth/password.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { Identity } from "./types.js";
2
+ export declare const SESSION_COOKIE_NAME = "contentrail_session";
3
+ export declare const SESSION_TTL_SECONDS: number;
4
+ export interface SessionSecrets {
5
+ readonly sessionSecret: string;
6
+ }
7
+ export declare function createSessionToken(identity: Identity, secrets: SessionSecrets, ttlSeconds?: number): Promise<string>;
8
+ export declare function verifySessionToken(token: string, secrets: SessionSecrets): Promise<Identity | null>;
9
+ export declare function readSessionTokenFromRequest(request: Request): string | null;
10
+ export declare function sessionCookieHeader(token: string, options?: {
11
+ readonly maxAgeSeconds?: number;
12
+ readonly secure?: boolean;
13
+ }): string;
14
+ export declare function clearSessionCookieHeader(secure?: boolean): string;
15
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AACzD,eAAO,MAAM,mBAAmB,QAAe,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAMD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,cAAc,EACvB,UAAU,SAAsB,GAC/B,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAyB1B;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAoB3E;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACvE,MAAM,CAcR;AAED,wBAAgB,wBAAwB,CAAC,MAAM,UAAO,GAAG,MAAM,CAY9D"}
@@ -0,0 +1,91 @@
1
+ import * as jose from "jose";
2
+ export const SESSION_COOKIE_NAME = "contentrail_session";
3
+ export const SESSION_TTL_SECONDS = 60 * 60 * 12;
4
+ function secretKey(secret) {
5
+ return new TextEncoder().encode(secret);
6
+ }
7
+ export async function createSessionToken(identity, secrets, ttlSeconds = SESSION_TTL_SECONDS) {
8
+ return new jose.SignJWT({
9
+ email: identity.email,
10
+ })
11
+ .setProtectedHeader({ alg: "HS256" })
12
+ .setSubject(identity.subject)
13
+ .setIssuer("contentrail:password")
14
+ .setAudience("contentrail:admin")
15
+ .setIssuedAt()
16
+ .setExpirationTime(`${ttlSeconds}s`)
17
+ .sign(secretKey(secrets.sessionSecret));
18
+ }
19
+ export async function verifySessionToken(token, secrets) {
20
+ try {
21
+ const { payload } = await jose.jwtVerify(token, secretKey(secrets.sessionSecret), {
22
+ issuer: "contentrail:password",
23
+ audience: "contentrail:admin",
24
+ clockTolerance: 5,
25
+ });
26
+ const subject = payload.sub;
27
+ if (typeof subject !== "string" || subject.trim() === "") {
28
+ return null;
29
+ }
30
+ const email = typeof payload.email === "string" ? payload.email : undefined;
31
+ return {
32
+ subject,
33
+ issuer: "contentrail:password",
34
+ audience: "contentrail:admin",
35
+ ...(email !== undefined ? { email } : {}),
36
+ };
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ export function readSessionTokenFromRequest(request) {
43
+ const authorization = request.headers.get("Authorization");
44
+ if (authorization !== null) {
45
+ const match = /^Bearer\s+(\S+)/i.exec(authorization);
46
+ if (match?.[1]) {
47
+ return match[1];
48
+ }
49
+ }
50
+ const cookie = request.headers.get("Cookie");
51
+ if (cookie === null || cookie.trim() === "") {
52
+ return null;
53
+ }
54
+ for (const part of cookie.split(";")) {
55
+ const trimmed = part.trim();
56
+ if (trimmed.startsWith(`${SESSION_COOKIE_NAME}=`)) {
57
+ const value = trimmed.slice(SESSION_COOKIE_NAME.length + 1);
58
+ return value === "" ? null : decodeURIComponent(value);
59
+ }
60
+ }
61
+ return null;
62
+ }
63
+ export function sessionCookieHeader(token, options) {
64
+ const maxAge = options?.maxAgeSeconds ?? SESSION_TTL_SECONDS;
65
+ const secure = options?.secure !== false;
66
+ const parts = [
67
+ `${SESSION_COOKIE_NAME}=${encodeURIComponent(token)}`,
68
+ "Path=/",
69
+ "HttpOnly",
70
+ "SameSite=Lax",
71
+ `Max-Age=${maxAge}`,
72
+ ];
73
+ if (secure) {
74
+ parts.push("Secure");
75
+ }
76
+ return parts.join("; ");
77
+ }
78
+ export function clearSessionCookieHeader(secure = true) {
79
+ const parts = [
80
+ `${SESSION_COOKIE_NAME}=`,
81
+ "Path=/",
82
+ "HttpOnly",
83
+ "SameSite=Lax",
84
+ "Max-Age=0",
85
+ ];
86
+ if (secure) {
87
+ parts.push("Secure");
88
+ }
89
+ return parts.join("; ");
90
+ }
91
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -3,6 +3,8 @@
3
3
  * Do not import from browser bundles. Secrets stay in Worker bindings.
4
4
  */
5
5
  export { createCloudflareAccessAuthenticator, type CloudflareAccessOptions, } from "./auth/access.js";
6
+ export { createPasswordAuthenticator, createPagesAuthenticator, loginWithPassword, type PasswordAuthOptions, type PasswordLoginInput, } from "./auth/password.js";
7
+ export { SESSION_COOKIE_NAME, clearSessionCookieHeader, createSessionToken, readSessionTokenFromRequest, sessionCookieHeader, verifySessionToken, } from "./auth/session.js";
6
8
  export type { AuthenticationFailure, AuthenticationFailureCode, AuthenticationResult, AuthenticationSuccess, Authenticator, Identity, } from "./auth/types.js";
7
9
  export { createSiteAuthorizer, type AccessibleSiteSummary, type AuthorizationFailure, type AuthorizationResult, type AuthorizationSuccess, type SiteAuthorizer, type SiteAuthorizationConfig, type SiteBinding, type SitePermission, } from "./authz/sites.js";
8
10
  export { createPublishFetchHandler, type PublishApiOptions, } from "./api/handler.js";
@@ -10,6 +12,6 @@ export { createMemoryRateLimiter, type MemoryRateLimiter, } from "./api/rate-lim
10
12
  export { CLOUDFLARE_PAGES_CAPABILITIES } from "./pages/capabilities.js";
11
13
  export { createCloudflarePagesClient, type CloudflarePagesClientOptions, type PagesProjectInput, type PlannedPagesAction, } from "./pages/client.js";
12
14
  export { createPagesSiteHandler, type PagesSiteHandlerOptions, } from "./pages/site-handler.js";
13
- export { PAGES_DEV_VARS_EXAMPLE, PAGES_MIDDLEWARE_SOURCE, pagesApiFunctionSource, } from "./pages/templates.js";
15
+ export { PAGES_API_FUNCTION_SOURCE, PAGES_DEV_VARS_EXAMPLE, PAGES_MIDDLEWARE_SOURCE, PAGES_V1_FUNCTION_SOURCE, pagesApiFunctionSource, pagesHandlerModuleSource, } from "./pages/templates.js";
14
16
  export { checkMutationOrigin } from "./pages/csrf.js";
15
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,mCAAmC,EACnC,KAAK,uBAAuB,GAC7B,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,EACrB,aAAa,EACb,QAAQ,GACT,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,oBAAoB,EACpB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,yBAAyB,EACzB,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,uBAAuB,EACvB,KAAK,iBAAiB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,2BAA2B,EAC3B,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,mCAAmC,EACnC,KAAK,uBAAuB,GAC7B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,EACxB,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,2BAA2B,EAC3B,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,EACrB,aAAa,EACb,QAAQ,GACT,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,oBAAoB,EACpB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,yBAAyB,EACzB,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,uBAAuB,EACvB,KAAK,iBAAiB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,2BAA2B,EAC3B,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -3,12 +3,14 @@
3
3
  * Do not import from browser bundles. Secrets stay in Worker bindings.
4
4
  */
5
5
  export { createCloudflareAccessAuthenticator, } from "./auth/access.js";
6
+ export { createPasswordAuthenticator, createPagesAuthenticator, loginWithPassword, } from "./auth/password.js";
7
+ export { SESSION_COOKIE_NAME, clearSessionCookieHeader, createSessionToken, readSessionTokenFromRequest, sessionCookieHeader, verifySessionToken, } from "./auth/session.js";
6
8
  export { createSiteAuthorizer, } from "./authz/sites.js";
7
9
  export { createPublishFetchHandler, } from "./api/handler.js";
8
10
  export { createMemoryRateLimiter, } from "./api/rate-limit.js";
9
11
  export { CLOUDFLARE_PAGES_CAPABILITIES } from "./pages/capabilities.js";
10
12
  export { createCloudflarePagesClient, } from "./pages/client.js";
11
13
  export { createPagesSiteHandler, } from "./pages/site-handler.js";
12
- export { PAGES_DEV_VARS_EXAMPLE, PAGES_MIDDLEWARE_SOURCE, pagesApiFunctionSource, } from "./pages/templates.js";
14
+ export { PAGES_API_FUNCTION_SOURCE, PAGES_DEV_VARS_EXAMPLE, PAGES_MIDDLEWARE_SOURCE, PAGES_V1_FUNCTION_SOURCE, pagesApiFunctionSource, pagesHandlerModuleSource, } from "./pages/templates.js";
13
15
  export { checkMutationOrigin } from "./pages/csrf.js";
14
16
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,mCAAmC,GAEpC,MAAM,kBAAkB,CAAC;AAS1B,OAAO,EACL,oBAAoB,GASrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,yBAAyB,GAE1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,uBAAuB,GAExB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,2BAA2B,GAI5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,GAEvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,mCAAmC,GAEpC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,EACxB,iBAAiB,GAGlB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,2BAA2B,EAC3B,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAS3B,OAAO,EACL,oBAAoB,GASrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,yBAAyB,GAE1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,uBAAuB,GAExB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,2BAA2B,GAI5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,GAEvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -56,6 +56,14 @@ export declare function createCloudflarePagesClient(options: CloudflarePagesClie
56
56
  };
57
57
  };
58
58
  }[]>;
59
+ /**
60
+ * Upsert production env vars. Secrets use type secret_text.
61
+ * Values are sent to Cloudflare only — never logged by this client.
62
+ */
63
+ upsertEnvironmentVariables(accountId: string, projectName: string, vars: Readonly<Record<string, {
64
+ readonly value: string;
65
+ readonly secret?: boolean;
66
+ }>>): Promise<void>;
59
67
  planProject: (accountId: string, input: PagesProjectInput) => Promise<PlannedPagesAction[]>;
60
68
  applyProjectPlan(accountId: string, input: PagesProjectInput, optionsApply: {
61
69
  confirm: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/pages/client.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,GAAG,CAAC,EAAE;QACb,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;CAM7D;AAmBD;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,4BAA4B;;;;;;;YAwGN,MAAM;cAAQ,MAAM;;4BAGzB,MAAM;cACC,MAAM;YAAM,MAAM;;4BApEd,MAAM,QAAQ,MAAM;+BA4E5B,MAAM,eAAe,MAAM;YAG5C,MAAM;uBACK;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE;6BAC5B;YAAE,QAAQ,CAAC,EAAE;gBAAE,WAAW,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE;;6BAzEvD,MAAM,SACV,iBAAiB,KACvB,OAAO,CAAC,kBAAkB,EAAE,CAAC;gCAkFjB,MAAM,SACV,iBAAiB,gBACV;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAClD,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,kBAAkB,EAAE,CAAA;KAAE,CAAC;EAkDlE"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/pages/client.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,GAAG,CAAC,EAAE;QACb,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;CAM7D;AAmBD;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,4BAA4B;;;;;;;YAwGN,MAAM;cAAQ,MAAM;;4BAGzB,MAAM;cACC,MAAM;YAAM,MAAM;;4BApEd,MAAM,QAAQ,MAAM;+BA4E5B,MAAM,eAAe,MAAM;YAG5C,MAAM;uBACK;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE;6BAC5B;YAAE,QAAQ,CAAC,EAAE;gBAAE,WAAW,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE;;IAQlE;;;OAGG;0CAEU,MAAM,eACJ,MAAM,QACb,QAAQ,CACZ,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CACtE,GACA,OAAO,CAAC,IAAI,CAAC;6BA3FL,MAAM,SACV,iBAAiB,KACvB,OAAO,CAAC,kBAAkB,EAAE,CAAC;gCAiHjB,MAAM,SACV,iBAAiB,gBACV;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAClD,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,kBAAkB,EAAE,CAAA;KAAE,CAAC;EAkDlE"}
@@ -109,6 +109,24 @@ export function createCloudflarePagesClient(options) {
109
109
  listDeployments(accountId, projectName) {
110
110
  return request("GET", `/accounts/${encodeURIComponent(accountId)}/pages/projects/${encodeURIComponent(projectName)}/deployments`);
111
111
  },
112
+ /**
113
+ * Upsert production env vars. Secrets use type secret_text.
114
+ * Values are sent to Cloudflare only — never logged by this client.
115
+ */
116
+ async upsertEnvironmentVariables(accountId, projectName, vars) {
117
+ const env_vars = Object.fromEntries(Object.entries(vars).map(([key, entry]) => [
118
+ key,
119
+ {
120
+ type: entry.secret === true ? "secret_text" : "plain_text",
121
+ value: entry.value,
122
+ },
123
+ ]));
124
+ await request("PATCH", `/accounts/${encodeURIComponent(accountId)}/pages/projects/${encodeURIComponent(projectName)}`, {
125
+ deployment_configs: {
126
+ production: { env_vars },
127
+ },
128
+ });
129
+ },
112
130
  planProject,
113
131
  async applyProjectPlan(accountId, input, optionsApply) {
114
132
  const actions = await planProject(accountId, input);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/pages/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/pages/client.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,30 @@
1
+ import { type PasswordAuthOptions } from "../auth/password.js";
1
2
  import { type PublishApiOptions } from "../api/handler.js";
2
3
  export interface PagesSiteHandlerOptions extends PublishApiOptions {
3
4
  /** Server-bound site id. Never taken from the URL. */
4
5
  readonly siteId: string;
6
+ /**
7
+ * Username/password admin login. When set, POST /api/login issues a session.
8
+ * Prefer this over Cloudflare Access for simple sites.
9
+ */
10
+ readonly passwordAuth?: PasswordAuthOptions;
5
11
  }
6
12
  /**
7
13
  * Pages Functions fetch adapter.
8
14
  *
9
15
  * Maps self-hosted routes onto the existing Worker publisher:
10
16
  * - GET /api/health
17
+ * - POST /api/login | POST /api/logout
11
18
  * - GET /api/content/:collection
12
19
  * - GET /api/content/:collection/:id
13
20
  * - POST /api/publish
14
21
  * - GET /api/publish/status?collection=
15
22
  *
16
- * `/v1/*` continues to work for the Worker-shaped API.
17
- * Static `/admin` HTML is not handled here — protect it with Cloudflare Access.
23
+ * `/v1/*` is the Worker-shaped API the admin editor client calls.
24
+ * Scaffold both `functions/api/[[path]].ts` and `functions/v1/[[path]].ts`
25
+ * so Pages routes those paths to this handler (not static HTML).
26
+ * Static `/admin` HTML is gated by the editor login UI + session auth
27
+ * (Cloudflare Access remains optional).
18
28
  */
19
29
  export declare function createPagesSiteHandler(options: PagesSiteHandlerOptions): (request: Request) => Promise<Response>;
20
30
  //# sourceMappingURL=site-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"site-handler.d.ts","sourceRoot":"","sources":["../../src/pages/site-handler.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAG3B,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAmCzC"}
1
+ {"version":3,"file":"site-handler.d.ts","sourceRoot":"","sources":["../../src/pages/site-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAG3B,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAoEzC"}
@@ -1,3 +1,5 @@
1
+ import { loginWithPassword, } from "../auth/password.js";
2
+ import { clearSessionCookieHeader, sessionCookieHeader, } from "../auth/session.js";
1
3
  import { applyCors, getRequestId, jsonResponse } from "../api/http.js";
2
4
  import { createPublishFetchHandler, } from "../api/handler.js";
3
5
  import { checkMutationOrigin } from "./csrf.js";
@@ -6,20 +8,49 @@ import { checkMutationOrigin } from "./csrf.js";
6
8
  *
7
9
  * Maps self-hosted routes onto the existing Worker publisher:
8
10
  * - GET /api/health
11
+ * - POST /api/login | POST /api/logout
9
12
  * - GET /api/content/:collection
10
13
  * - GET /api/content/:collection/:id
11
14
  * - POST /api/publish
12
15
  * - GET /api/publish/status?collection=
13
16
  *
14
- * `/v1/*` continues to work for the Worker-shaped API.
15
- * Static `/admin` HTML is not handled here — protect it with Cloudflare Access.
17
+ * `/v1/*` is the Worker-shaped API the admin editor client calls.
18
+ * Scaffold both `functions/api/[[path]].ts` and `functions/v1/[[path]].ts`
19
+ * so Pages routes those paths to this handler (not static HTML).
20
+ * Static `/admin` HTML is gated by the editor login UI + session auth
21
+ * (Cloudflare Access remains optional).
16
22
  */
17
23
  export function createPagesSiteHandler(options) {
18
24
  const inner = createPublishFetchHandler(options);
19
25
  const corsAllowedOrigins = options.corsAllowedOrigins ?? [];
20
26
  return async (request) => {
21
27
  const requestId = getRequestId(request);
22
- const respond = (status, body) => applyCors(jsonResponse(status, body, { requestId }), request, corsAllowedOrigins);
28
+ const respond = (status, body, init) => {
29
+ const base = applyCors(jsonResponse(status, body, { requestId }), request, corsAllowedOrigins);
30
+ if (init?.headers === undefined) {
31
+ return base;
32
+ }
33
+ const headers = new Headers(base.headers);
34
+ const extra = new Headers(init.headers);
35
+ extra.forEach((value, key) => {
36
+ headers.append(key, value);
37
+ });
38
+ return new Response(base.body, {
39
+ status: base.status,
40
+ statusText: base.statusText,
41
+ headers,
42
+ });
43
+ };
44
+ const url = new URL(request.url);
45
+ if (url.pathname === "/api/login" &&
46
+ request.method.toUpperCase() === "POST") {
47
+ return handleLogin(request, options, respond, requestId);
48
+ }
49
+ if (url.pathname === "/api/logout" &&
50
+ request.method.toUpperCase() === "POST") {
51
+ const secure = url.protocol === "https:";
52
+ return respond(200, { ok: true }, { headers: { "Set-Cookie": clearSessionCookieHeader(secure) } });
53
+ }
23
54
  const method = request.method.toUpperCase();
24
55
  if (method === "POST" ||
25
56
  method === "PUT" ||
@@ -40,6 +71,81 @@ export function createPagesSiteHandler(options) {
40
71
  return inner(mapped);
41
72
  };
42
73
  }
74
+ async function handleLogin(request, options, respond, requestId) {
75
+ if (options.passwordAuth === undefined) {
76
+ return respond(503, {
77
+ error: {
78
+ code: "PASSWORD_AUTH_DISABLED",
79
+ message: "Password login is not configured. Set CONTENTRAIL_ADMIN_USERNAME, CONTENTRAIL_ADMIN_PASSWORD, and CONTENTRAIL_SESSION_SECRET.",
80
+ },
81
+ requestId,
82
+ });
83
+ }
84
+ const csrf = checkMutationOrigin(request, options.corsAllowedOrigins ?? []);
85
+ if (!csrf.ok) {
86
+ return respond(403, {
87
+ error: { code: "CSRF", message: csrf.message },
88
+ requestId,
89
+ });
90
+ }
91
+ let body;
92
+ try {
93
+ body = await request.json();
94
+ }
95
+ catch {
96
+ return respond(400, {
97
+ error: {
98
+ code: "INVALID_JSON",
99
+ message: "Request body is not valid JSON.",
100
+ },
101
+ requestId,
102
+ });
103
+ }
104
+ if (body === null || typeof body !== "object") {
105
+ return respond(400, {
106
+ error: { code: "INVALID_BODY", message: "JSON object required." },
107
+ requestId,
108
+ });
109
+ }
110
+ const record = body;
111
+ const username = typeof record.username === "string" ? record.username : "";
112
+ const password = typeof record.password === "string" ? record.password : "";
113
+ if (username.trim() === "" || password === "") {
114
+ return respond(400, {
115
+ error: {
116
+ code: "INVALID_BODY",
117
+ message: 'Fields "username" and "password" are required.',
118
+ },
119
+ requestId,
120
+ });
121
+ }
122
+ const result = await loginWithPassword(options.passwordAuth, {
123
+ username,
124
+ password,
125
+ });
126
+ if (!result.ok) {
127
+ return respond(401, {
128
+ error: {
129
+ code: "INVALID_CREDENTIALS",
130
+ message: "Invalid username or password.",
131
+ },
132
+ requestId,
133
+ });
134
+ }
135
+ const secure = new URL(request.url).protocol === "https:";
136
+ return respond(200, {
137
+ ok: true,
138
+ token: result.token,
139
+ identity: {
140
+ subject: result.identity.subject,
141
+ ...(result.identity.email !== undefined
142
+ ? { email: result.identity.email }
143
+ : {}),
144
+ },
145
+ }, {
146
+ headers: { "Set-Cookie": sessionCookieHeader(result.token, { secure }) },
147
+ });
148
+ }
43
149
  async function mapPagesRequest(request, siteId, respond) {
44
150
  const url = new URL(request.url);
45
151
  if (url.pathname === "/api/health") {
@@ -1 +1 @@
1
- {"version":3,"file":"site-handler.js","sourceRoot":"","sources":["../../src/pages/site-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"site-handler.js","sourceRoot":"","sources":["../../src/pages/site-handler.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,25 @@
1
1
  /**
2
2
  * Source templates for Cloudflare Pages Functions.
3
3
  * Secrets are named only — never inlined.
4
+ *
5
+ * The editor API client calls `/v1/*`. Pages must mount the same handler under
6
+ * both `/api/*` (short routes + login) and `/v1/*` (editor Worker-shaped paths).
4
7
  */
5
- export declare const PAGES_DEV_VARS_EXAMPLE = "# Local Pages Functions secrets (gitignored as .dev.vars).\n# Copy to .dev.vars and fill values. Never commit real secrets.\n# Do not prefix secrets with PUBLIC_ or VITE_.\n\nCONTENTRAIL_ACCESS_TEAM_DOMAIN=\nCONTENTRAIL_ACCESS_AUD=\nCONTENTRAIL_SITE_ID=\nCONTENTRAIL_GIT_OWNER=\nCONTENTRAIL_GIT_REPO=\nCONTENTRAIL_GIT_BRANCH=main\nCONTENTRAIL_CONTENT_ROOT=content\nCONTENTRAIL_ADMIN_ORIGIN=http://localhost:4321\nCONTENTRAIL_GITHUB_TOKEN=\n";
6
- export declare function pagesApiFunctionSource(collectionsImport: string): string;
7
- export declare const PAGES_MIDDLEWARE_SOURCE = "/**\n * Rejects unauthenticated API mutations early.\n * Static /admin HTML is NOT covered \u2014 configure Cloudflare Access on /admin* as well.\n */\nexport const onRequest: PagesFunction = async (context) => {\n const url = new URL(context.request.url);\n if (\n url.pathname.startsWith(\"/api/\") &&\n url.pathname !== \"/api/health\" &&\n context.request.method !== \"OPTIONS\"\n ) {\n const access = context.request.headers.get(\"Cf-Access-Jwt-Assertion\");\n const authorization = context.request.headers.get(\"Authorization\");\n const hasBearer =\n authorization !== null && /^Bearer\\s+\\S+/i.test(authorization);\n if ((access === null || access.trim() === \"\") && !hasBearer) {\n return new Response(\n JSON.stringify({\n error: {\n code: \"MISSING_CREDENTIAL\",\n message: \"Missing Access JWT credential.\",\n },\n }),\n { status: 401, headers: { \"content-type\": \"application/json\" } },\n );\n }\n }\n return context.next();\n};\n";
8
+ export declare const PAGES_DEV_VARS_EXAMPLE = "# Local Pages Functions secrets (gitignored as .dev.vars).\n# Copy to .dev.vars and fill values. Never commit real secrets.\n# Do not prefix secrets with PUBLIC_ or VITE_.\n\n# Default: username/password admin (no Zero Trust required)\nCONTENTRAIL_ADMIN_USERNAME=admin\nCONTENTRAIL_ADMIN_PASSWORD=\nCONTENTRAIL_SESSION_SECRET=\n\n# Site + Git publish\nCONTENTRAIL_SITE_ID=site\nCONTENTRAIL_GIT_OWNER=\nCONTENTRAIL_GIT_REPO=\nCONTENTRAIL_GIT_BRANCH=main\nCONTENTRAIL_CONTENT_ROOT=content\nCONTENTRAIL_ADMIN_ORIGIN=http://localhost:8788\nCONTENTRAIL_GITHUB_TOKEN=\n\n# Optional: Cloudflare Access instead of (or in addition to) password auth\n# CONTENTRAIL_ACCESS_TEAM_DOMAIN=\n# CONTENTRAIL_ACCESS_AUD=\n";
9
+ /**
10
+ * Shared handler module at `functions/contentrail.ts`.
11
+ * @param collectionsModulePath - ESM import path to the collections module
12
+ * (for example `"../content/config"` from `functions/`).
13
+ */
14
+ export declare function pagesHandlerModuleSource(collectionsModulePath: string): string;
15
+ /**
16
+ * @deprecated Prefer `pagesHandlerModuleSource` + `PAGES_API_FUNCTION_SOURCE`.
17
+ * `collectionsModulePath` is an ESM path such as `"../content/config"`.
18
+ */
19
+ export declare function pagesApiFunctionSource(collectionsModulePath: string): string;
20
+ /** Thin re-export at `functions/api/[[path]].ts`. */
21
+ export declare const PAGES_API_FUNCTION_SOURCE = "/** ContentRail /api/* \u2014 login, health, short content/publish routes. */\nexport { onRequest } from \"../contentrail\";\n";
22
+ /** Thin re-export at `functions/v1/[[path]].ts` — editor client paths. */
23
+ export declare const PAGES_V1_FUNCTION_SOURCE = "/** ContentRail /v1/* \u2014 Worker-shaped routes used by the admin editor client. */\nexport { onRequest } from \"../contentrail\";\n";
24
+ export declare const PAGES_MIDDLEWARE_SOURCE = "/**\n * Early reject for /api and /v1 without a session cookie, Bearer token, or Access JWT.\n * /api/login and /api/health stay public. Static /admin HTML shows the login UI.\n */\nexport const onRequest: PagesFunction = async (context) => {\n const url = new URL(context.request.url);\n const isApi = url.pathname.startsWith(\"/api/\");\n const isV1 = url.pathname.startsWith(\"/v1/\");\n if (\n (isApi || isV1) &&\n url.pathname !== \"/api/health\" &&\n url.pathname !== \"/api/login\" &&\n context.request.method !== \"OPTIONS\"\n ) {\n const access = context.request.headers.get(\"Cf-Access-Jwt-Assertion\");\n const authorization = context.request.headers.get(\"Authorization\");\n const cookie = context.request.headers.get(\"Cookie\") ?? \"\";\n const hasBearer =\n authorization !== null && /^Bearer\\s+\\S+/i.test(authorization);\n const hasSession = /(?:^|;\\s*)contentrail_session=/.test(cookie);\n if (\n (access === null || access.trim() === \"\") &&\n !hasBearer &&\n !hasSession\n ) {\n return new Response(\n JSON.stringify({\n error: {\n code: \"MISSING_CREDENTIAL\",\n message: \"Missing admin session. Sign in at /admin.\",\n },\n }),\n { status: 401, headers: { \"content-type\": \"application/json\" } },\n );\n }\n }\n return context.next();\n};\n";
8
25
  //# sourceMappingURL=templates.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/pages/templates.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,sBAAsB,6bAalC,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAiExE;AAED,eAAO,MAAM,uBAAuB,miCA6BnC,CAAC"}
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/pages/templates.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,osBAqBlC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,qBAAqB,EAAE,MAAM,GAC5B,MAAM,CA8GR;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,qBAAqB,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,qDAAqD;AACrD,eAAO,MAAM,yBAAyB,mIAErC,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,2IAEpC,CAAC;AAEF,eAAO,MAAM,uBAAuB,i4CAsCnC,CAAC"}
@@ -1,29 +1,47 @@
1
1
  /**
2
2
  * Source templates for Cloudflare Pages Functions.
3
3
  * Secrets are named only — never inlined.
4
+ *
5
+ * The editor API client calls `/v1/*`. Pages must mount the same handler under
6
+ * both `/api/*` (short routes + login) and `/v1/*` (editor Worker-shaped paths).
4
7
  */
5
8
  export const PAGES_DEV_VARS_EXAMPLE = `# Local Pages Functions secrets (gitignored as .dev.vars).
6
9
  # Copy to .dev.vars and fill values. Never commit real secrets.
7
10
  # Do not prefix secrets with PUBLIC_ or VITE_.
8
11
 
9
- CONTENTRAIL_ACCESS_TEAM_DOMAIN=
10
- CONTENTRAIL_ACCESS_AUD=
11
- CONTENTRAIL_SITE_ID=
12
+ # Default: username/password admin (no Zero Trust required)
13
+ CONTENTRAIL_ADMIN_USERNAME=admin
14
+ CONTENTRAIL_ADMIN_PASSWORD=
15
+ CONTENTRAIL_SESSION_SECRET=
16
+
17
+ # Site + Git publish
18
+ CONTENTRAIL_SITE_ID=site
12
19
  CONTENTRAIL_GIT_OWNER=
13
20
  CONTENTRAIL_GIT_REPO=
14
21
  CONTENTRAIL_GIT_BRANCH=main
15
22
  CONTENTRAIL_CONTENT_ROOT=content
16
- CONTENTRAIL_ADMIN_ORIGIN=http://localhost:4321
23
+ CONTENTRAIL_ADMIN_ORIGIN=http://localhost:8788
17
24
  CONTENTRAIL_GITHUB_TOKEN=
25
+
26
+ # Optional: Cloudflare Access instead of (or in addition to) password auth
27
+ # CONTENTRAIL_ACCESS_TEAM_DOMAIN=
28
+ # CONTENTRAIL_ACCESS_AUD=
18
29
  `;
19
- export function pagesApiFunctionSource(collectionsImport) {
30
+ /**
31
+ * Shared handler module at `functions/contentrail.ts`.
32
+ * @param collectionsModulePath - ESM import path to the collections module
33
+ * (for example `"../content/config"` from `functions/`).
34
+ */
35
+ export function pagesHandlerModuleSource(collectionsModulePath) {
20
36
  return `/**
21
- * ContentRail Pages Functions API.
37
+ * ContentRail Pages Functions handler (shared by /api and /v1).
22
38
  * Server-only. Secrets come from Pages bindings / .dev.vars — never PUBLIC_* or VITE_*.
39
+ * Default auth: username/password session. Cloudflare Access is optional.
23
40
  */
24
41
  import {
25
42
  createCloudflareAccessAuthenticator,
26
43
  createPagesSiteHandler,
44
+ createPasswordAuthenticator,
27
45
  createSiteAuthorizer,
28
46
  } from "@contentrail/cloudflare";
29
47
  import {
@@ -31,11 +49,14 @@ import {
31
49
  createGitPublishProvider,
32
50
  createPublisher,
33
51
  } from "@contentrail/publisher";
34
- ${collectionsImport}
52
+ import { articles } from "${collectionsModulePath}";
35
53
 
36
54
  interface Env {
37
- CONTENTRAIL_ACCESS_TEAM_DOMAIN: string;
38
- CONTENTRAIL_ACCESS_AUD: string;
55
+ CONTENTRAIL_ADMIN_USERNAME?: string;
56
+ CONTENTRAIL_ADMIN_PASSWORD?: string;
57
+ CONTENTRAIL_SESSION_SECRET?: string;
58
+ CONTENTRAIL_ACCESS_TEAM_DOMAIN?: string;
59
+ CONTENTRAIL_ACCESS_AUD?: string;
39
60
  CONTENTRAIL_SITE_ID: string;
40
61
  CONTENTRAIL_GIT_OWNER: string;
41
62
  CONTENTRAIL_GIT_REPO: string;
@@ -47,17 +68,57 @@ interface Env {
47
68
 
48
69
  export const onRequest: PagesFunction<Env> = async (context) => {
49
70
  const env = context.env;
71
+ const passwordReady =
72
+ Boolean(env.CONTENTRAIL_ADMIN_USERNAME?.trim()) &&
73
+ Boolean(env.CONTENTRAIL_ADMIN_PASSWORD) &&
74
+ Boolean(env.CONTENTRAIL_SESSION_SECRET?.trim());
75
+ const accessReady =
76
+ Boolean(env.CONTENTRAIL_ACCESS_TEAM_DOMAIN?.trim()) &&
77
+ Boolean(env.CONTENTRAIL_ACCESS_AUD?.trim());
78
+
79
+ const passwordAuth = passwordReady
80
+ ? {
81
+ username: env.CONTENTRAIL_ADMIN_USERNAME!.trim(),
82
+ password: env.CONTENTRAIL_ADMIN_PASSWORD!,
83
+ sessionSecret: env.CONTENTRAIL_SESSION_SECRET!.trim(),
84
+ }
85
+ : undefined;
86
+
87
+ const authenticator = passwordReady
88
+ ? createPasswordAuthenticator(passwordAuth!)
89
+ : accessReady
90
+ ? createCloudflareAccessAuthenticator({
91
+ teamDomain: env.CONTENTRAIL_ACCESS_TEAM_DOMAIN!,
92
+ audience: env.CONTENTRAIL_ACCESS_AUD!,
93
+ })
94
+ : {
95
+ async authenticate() {
96
+ return {
97
+ ok: false as const,
98
+ status: 401 as const,
99
+ code: "KEY_UNAVAILABLE" as const,
100
+ message:
101
+ "Configure CONTENTRAIL_ADMIN_USERNAME/PASSWORD/SESSION_SECRET (recommended) or Cloudflare Access.",
102
+ };
103
+ },
104
+ };
105
+
106
+ // Password auth subjects are password:<username>. Access-only installs must
107
+ // set allowedEmails or allowedSubjects to the Access identity before publish.
108
+ const allowedSubjects = passwordReady
109
+ ? [\`password:\${env.CONTENTRAIL_ADMIN_USERNAME!.trim()}\`]
110
+ : undefined;
111
+
50
112
  const handler = createPagesSiteHandler({
51
113
  siteId: env.CONTENTRAIL_SITE_ID,
52
- authenticator: createCloudflareAccessAuthenticator({
53
- teamDomain: env.CONTENTRAIL_ACCESS_TEAM_DOMAIN,
54
- audience: env.CONTENTRAIL_ACCESS_AUD,
55
- }),
114
+ authenticator,
115
+ ...(passwordAuth !== undefined ? { passwordAuth } : {}),
56
116
  authorizer: createSiteAuthorizer({
57
117
  sites: {
58
118
  [env.CONTENTRAIL_SITE_ID]: {
59
119
  destinationRef: "git:allowlisted",
60
120
  permissions: ["read", "publish", "status", "rollback", "validate"],
121
+ ...(allowedSubjects !== undefined ? { allowedSubjects } : {}),
61
122
  },
62
123
  },
63
124
  }),
@@ -82,27 +143,51 @@ export const onRequest: PagesFunction<Env> = async (context) => {
82
143
  };
83
144
  `;
84
145
  }
146
+ /**
147
+ * @deprecated Prefer `pagesHandlerModuleSource` + `PAGES_API_FUNCTION_SOURCE`.
148
+ * `collectionsModulePath` is an ESM path such as `"../content/config"`.
149
+ */
150
+ export function pagesApiFunctionSource(collectionsModulePath) {
151
+ return pagesHandlerModuleSource(collectionsModulePath);
152
+ }
153
+ /** Thin re-export at `functions/api/[[path]].ts`. */
154
+ export const PAGES_API_FUNCTION_SOURCE = `/** ContentRail /api/* — login, health, short content/publish routes. */
155
+ export { onRequest } from "../contentrail";
156
+ `;
157
+ /** Thin re-export at `functions/v1/[[path]].ts` — editor client paths. */
158
+ export const PAGES_V1_FUNCTION_SOURCE = `/** ContentRail /v1/* — Worker-shaped routes used by the admin editor client. */
159
+ export { onRequest } from "../contentrail";
160
+ `;
85
161
  export const PAGES_MIDDLEWARE_SOURCE = `/**
86
- * Rejects unauthenticated API mutations early.
87
- * Static /admin HTML is NOT covered — configure Cloudflare Access on /admin* as well.
162
+ * Early reject for /api and /v1 without a session cookie, Bearer token, or Access JWT.
163
+ * /api/login and /api/health stay public. Static /admin HTML shows the login UI.
88
164
  */
89
165
  export const onRequest: PagesFunction = async (context) => {
90
166
  const url = new URL(context.request.url);
167
+ const isApi = url.pathname.startsWith("/api/");
168
+ const isV1 = url.pathname.startsWith("/v1/");
91
169
  if (
92
- url.pathname.startsWith("/api/") &&
170
+ (isApi || isV1) &&
93
171
  url.pathname !== "/api/health" &&
172
+ url.pathname !== "/api/login" &&
94
173
  context.request.method !== "OPTIONS"
95
174
  ) {
96
175
  const access = context.request.headers.get("Cf-Access-Jwt-Assertion");
97
176
  const authorization = context.request.headers.get("Authorization");
177
+ const cookie = context.request.headers.get("Cookie") ?? "";
98
178
  const hasBearer =
99
179
  authorization !== null && /^Bearer\\s+\\S+/i.test(authorization);
100
- if ((access === null || access.trim() === "") && !hasBearer) {
180
+ const hasSession = /(?:^|;\\s*)contentrail_session=/.test(cookie);
181
+ if (
182
+ (access === null || access.trim() === "") &&
183
+ !hasBearer &&
184
+ !hasSession
185
+ ) {
101
186
  return new Response(
102
187
  JSON.stringify({
103
188
  error: {
104
189
  code: "MISSING_CREDENTIAL",
105
- message: "Missing Access JWT credential.",
190
+ message: "Missing admin session. Sign in at /admin.",
106
191
  },
107
192
  }),
108
193
  { status: 401, headers: { "content-type": "application/json" } },
@@ -1 +1 @@
1
- {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/pages/templates.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;CAarC,CAAC;AAEF,MAAM,UAAU,sBAAsB,CAAC,iBAAyB;IAC9D,OAAO;;;;;;;;;;;;;;EAcP,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDlB,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BtC,CAAC"}
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/pages/templates.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBrC,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,qBAA6B;IAE7B,OAAO;;;;;;;;;;;;;;;;4BAgBmB,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4FhD,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,qBAA6B;IAClE,OAAO,wBAAwB,CAAC,qBAAqB,CAAC,CAAC;AACzD,CAAC;AAED,qDAAqD;AACrD,MAAM,CAAC,MAAM,yBAAyB,GAAG;;CAExC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,CAAC,MAAM,wBAAwB,GAAG;;CAEvC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCtC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentrail/cloudflare",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Server-only Cloudflare Worker and Pages Functions publishing API with Access auth and Pages setup helpers.",
@@ -29,8 +29,8 @@
29
29
  ],
30
30
  "dependencies": {
31
31
  "jose": "^6.2.14",
32
- "@contentrail/core": "0.2.3",
33
- "@contentrail/publisher": "0.2.3"
32
+ "@contentrail/core": "0.2.5",
33
+ "@contentrail/publisher": "0.2.5"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^22.20.5",