@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 +14 -8
- package/dist/auth/password.d.ts +36 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +95 -0
- package/dist/auth/password.js.map +1 -0
- package/dist/auth/session.d.ts +15 -0
- package/dist/auth/session.d.ts.map +1 -0
- package/dist/auth/session.js +91 -0
- package/dist/auth/session.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/pages/client.d.ts +8 -0
- package/dist/pages/client.d.ts.map +1 -1
- package/dist/pages/client.js +18 -0
- package/dist/pages/client.js.map +1 -1
- package/dist/pages/site-handler.d.ts +12 -2
- package/dist/pages/site-handler.d.ts.map +1 -1
- package/dist/pages/site-handler.js +109 -3
- package/dist/pages/site-handler.js.map +1 -1
- package/dist/pages/templates.d.ts +20 -3
- package/dist/pages/templates.d.ts.map +1 -1
- package/dist/pages/templates.js +103 -18
- package/dist/pages/templates.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# `@contentrail/cloudflare`
|
|
2
2
|
|
|
3
|
-
Server-only Cloudflare Worker publishing API with **
|
|
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
|
|
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.
|
|
23
|
+
### From npm (`0.2.5`)
|
|
22
24
|
|
|
23
25
|
```sh
|
|
24
|
-
pnpm add @contentrail/core@0.2.
|
|
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
|
|
29
|
+
## Auth summary (ADR 011b + ADR 030)
|
|
28
30
|
|
|
29
|
-
- Authentication is pluggable; Access JWT
|
|
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`
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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;
|
|
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"}
|
package/dist/pages/client.d.ts
CHANGED
|
@@ -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;;
|
|
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"}
|
package/dist/pages/client.js
CHANGED
|
@@ -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);
|
package/dist/pages/client.js.map
CHANGED
|
@@ -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/*`
|
|
17
|
-
*
|
|
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":"
|
|
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/*`
|
|
15
|
-
*
|
|
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) =>
|
|
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":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EACL,yBAAyB,GAE1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;
|
|
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\
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
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"}
|
package/dist/pages/templates.js
CHANGED
|
@@ -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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
-
${
|
|
52
|
+
import { articles } from "${collectionsModulePath}";
|
|
35
53
|
|
|
36
54
|
interface Env {
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
53
|
-
|
|
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
|
-
*
|
|
87
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
+
"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.
|
|
33
|
-
"@contentrail/publisher": "0.2.
|
|
32
|
+
"@contentrail/core": "0.2.5",
|
|
33
|
+
"@contentrail/publisher": "0.2.5"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^22.20.5",
|