@cancia/astro 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/chunk-4PYVIIOO.js +25 -0
  2. package/dist/{chunk-DIV2FFYX.js → chunk-5R3I5RLT.js} +15 -8
  3. package/dist/chunk-6GUOGDWO.js +172 -0
  4. package/dist/chunk-DEI3FBNY.js +65 -0
  5. package/dist/{chunk-ONKCUTPU.js → chunk-DOFLZ7KG.js} +6 -7
  6. package/dist/{chunk-GJIX7MWC.js → chunk-ECPYHIAW.js} +9 -1
  7. package/dist/{chunk-YGJ3JHXF.js → chunk-QQEUCOXQ.js} +11 -0
  8. package/dist/{chunk-NVXNJ4YC.js → chunk-R7VA3Z5N.js} +53 -11
  9. package/dist/{chunk-5IPHDIC6.js → chunk-RHFTQW4W.js} +10 -1
  10. package/dist/{chunk-2NVZWZPE.js → chunk-S5YLB6P3.js} +310 -7
  11. package/dist/{chunk-LJSSPOSW.js → chunk-VF3EXXEM.js} +139 -16
  12. package/dist/chunk-XINNLVZP.js +183 -0
  13. package/dist/chunk-XZCXWILA.js +145 -0
  14. package/dist/content.js +3 -3
  15. package/dist/{upload-DwCGjXbz.d.ts → email-BRK4WAO2.d.ts} +9 -1
  16. package/dist/endpoints/auth-callback.d.ts +1 -0
  17. package/dist/endpoints/auth-callback.js +9 -0
  18. package/dist/endpoints/auth-logout.d.ts +1 -0
  19. package/dist/endpoints/auth-logout.js +9 -0
  20. package/dist/endpoints/auth-request.d.ts +18 -0
  21. package/dist/endpoints/auth-request.js +9 -0
  22. package/dist/endpoints/auth-session.d.ts +1 -0
  23. package/dist/endpoints/auth-session.js +9 -0
  24. package/dist/endpoints/auth.js +10 -2
  25. package/dist/endpoints/content.js +12 -12
  26. package/dist/endpoints/lists.js +4 -1
  27. package/dist/endpoints/publish.js +8 -6
  28. package/dist/endpoints/schemas.js +6 -3
  29. package/dist/endpoints/upload.js +11 -10
  30. package/dist/{git-backed-DtiH52EI.d.ts → git-backed-CwTFfUS4.d.ts} +2 -2
  31. package/dist/{github-client-Db0pIrqE.d.ts → github-client-Db5EPcSL.d.ts} +1 -1
  32. package/dist/index.d.ts +32 -6
  33. package/dist/index.js +125 -35
  34. package/dist/loader/index.d.ts +34 -4
  35. package/dist/loader/index.js +3 -3
  36. package/dist/runtime.d.ts +69 -3
  37. package/dist/runtime.js +6 -4
  38. package/dist/schema/index.d.ts +14 -1
  39. package/dist/schema/index.js +1 -1
  40. package/dist/storage/index.d.ts +4 -4
  41. package/dist/storage/index.js +5 -5
  42. package/dist/{types-BMlLS-OS.d.ts → types-CKzfz5iu.d.ts} +1 -1
  43. package/package.json +1 -1
  44. package/dist/chunk-MXVOJRAM.js +0 -504
@@ -0,0 +1,145 @@
1
+ import {
2
+ createRateLimiter,
3
+ getIp,
4
+ isRateLimited,
5
+ recordFailure
6
+ } from "./chunk-ECPYHIAW.js";
7
+ import {
8
+ SESSION_TTL_MS,
9
+ clearSessionCookie,
10
+ isSecureRequest,
11
+ normaliseEmail,
12
+ readSessionCookie,
13
+ redeemLoginToken,
14
+ requestLoginLink,
15
+ revokeSession,
16
+ serialiseSessionCookie
17
+ } from "./chunk-6GUOGDWO.js";
18
+
19
+ // src/auth/email.ts
20
+ var LOOPS_API_URL = "https://app.loops.so/api/v1/transactional";
21
+ var consoleLoginEmail = async ({ to, url }) => {
22
+ console.log(
23
+ `
24
+ \x1B[36m[cancia]\x1B[0m login link for \x1B[1m${to}\x1B[0m:
25
+ ${url}
26
+ `
27
+ );
28
+ };
29
+ var loopsLoginEmail = async ({ to, url }) => {
30
+ const apiKey = process.env.LOOPS_API_KEY;
31
+ const transactionalId = process.env.CANCIA_LOGIN_TID;
32
+ if (!apiKey || !transactionalId) {
33
+ throw new Error(
34
+ "Loops login email needs LOOPS_API_KEY and CANCIA_LOGIN_TID in the server environment."
35
+ );
36
+ }
37
+ const res = await fetch(LOOPS_API_URL, {
38
+ method: "POST",
39
+ headers: {
40
+ "Content-Type": "application/json",
41
+ Authorization: `Bearer ${apiKey}`
42
+ },
43
+ body: JSON.stringify({
44
+ email: to,
45
+ transactionalId,
46
+ dataVariables: { loginUrl: url }
47
+ })
48
+ });
49
+ if (!res.ok) {
50
+ throw new Error(`Loops login email failed (${res.status})`);
51
+ }
52
+ };
53
+ function resolveLoginEmailSender(explicit) {
54
+ if (explicit) return explicit;
55
+ if (process.env.LOOPS_API_KEY && process.env.CANCIA_LOGIN_TID) return loopsLoginEmail;
56
+ return consoleLoginEmail;
57
+ }
58
+
59
+ // src/auth/handlers.ts
60
+ var json = (body, status, headers = {}) => new Response(JSON.stringify(body), {
61
+ status,
62
+ headers: { "Content-Type": "application/json", ...headers }
63
+ });
64
+ var NEUTRAL_ACK = { ok: true, message: "If that address can edit this site, a link is on its way." };
65
+ function looksLikeEmail(value) {
66
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) && value.length <= 254;
67
+ }
68
+ async function handleLoginRequest(request, ctx, origin) {
69
+ const limiter = ctx.limiter ?? createRateLimiter();
70
+ const now = ctx.now ?? Date.now();
71
+ const ip = getIp(request);
72
+ if (isRateLimited(limiter, ip, now)) {
73
+ return json({ error: "Too many attempts. Try again in a minute." }, 429);
74
+ }
75
+ let email;
76
+ try {
77
+ const body = await request.json();
78
+ email = body?.email;
79
+ } catch {
80
+ return json({ error: "Invalid request body" }, 400);
81
+ }
82
+ if (!email || !looksLikeEmail(email.trim())) {
83
+ return json({ error: "Enter a valid email address." }, 400);
84
+ }
85
+ const normalised = normaliseEmail(email);
86
+ if (isRateLimited(limiter, `email:${normalised}`, now)) {
87
+ return json(NEUTRAL_ACK, 200);
88
+ }
89
+ recordFailure(limiter, ip, now);
90
+ recordFailure(limiter, `email:${normalised}`, now);
91
+ const { token } = await requestLoginLink(ctx.store, ctx.site, normalised, now);
92
+ if (token) {
93
+ const url = `${origin}/?cancia_login=${encodeURIComponent(token)}`;
94
+ void ctx.sendEmail({ to: normalised, url, site: ctx.site }).catch((err) => {
95
+ console.error(
96
+ `[cancia] failed to send login email: ${err instanceof Error ? err.message : String(err)}`
97
+ );
98
+ });
99
+ }
100
+ void ctx.store.purgeExpired(ctx.site, new Date(now).toISOString()).catch(() => {
101
+ });
102
+ return json(NEUTRAL_ACK, 200);
103
+ }
104
+ async function handleLoginCallback(request, ctx) {
105
+ const now = ctx.now ?? Date.now();
106
+ let token;
107
+ try {
108
+ const body = await request.json();
109
+ token = body?.token;
110
+ } catch {
111
+ return json({ error: "Invalid request body" }, 400);
112
+ }
113
+ const result = await redeemLoginToken(ctx.store, ctx.site, token ?? "", now);
114
+ if (!result.sessionToken) {
115
+ return json({ error: "That link is invalid or has expired. Request a new one." }, 401);
116
+ }
117
+ return json(
118
+ { ok: true, email: result.email },
119
+ 200,
120
+ {
121
+ "Set-Cookie": serialiseSessionCookie(result.sessionToken, {
122
+ secure: isSecureRequest(request),
123
+ maxAgeSeconds: Math.floor(SESSION_TTL_MS / 1e3)
124
+ })
125
+ }
126
+ );
127
+ }
128
+ async function handleLogout(request, ctx) {
129
+ await revokeSession(ctx.store, ctx.site, readSessionCookie(request));
130
+ return json({ ok: true }, 200, {
131
+ "Set-Cookie": clearSessionCookie({ secure: isSecureRequest(request) })
132
+ });
133
+ }
134
+ async function handleSessionCheck(request, ctx, authorize) {
135
+ const verdict = await authorize();
136
+ return json({ authenticated: verdict.ok, email: verdict.email }, 200);
137
+ }
138
+
139
+ export {
140
+ resolveLoginEmailSender,
141
+ handleLoginRequest,
142
+ handleLoginCallback,
143
+ handleLogout,
144
+ handleSessionCheck
145
+ };
package/dist/content.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import "./chunk-FOSOWSXV.js";
2
2
  import "./chunk-CJDIVWO3.js";
3
+ import "./chunk-XINNLVZP.js";
4
+ import "./chunk-U7V53JX7.js";
3
5
  import {
4
6
  createSqliteAdapterV2
5
- } from "./chunk-MXVOJRAM.js";
6
- import "./chunk-U7V53JX7.js";
7
- import "./chunk-2NVZWZPE.js";
7
+ } from "./chunk-S5YLB6P3.js";
8
8
  import "./chunk-7IA5B5CF.js";
9
9
 
10
10
  // src/content.ts
@@ -10,4 +10,12 @@ declare function makeLocalUploadHandler(opts: {
10
10
  maxMB?: number;
11
11
  }): UploadHandler;
12
12
 
13
- export { type UploadHandler as U, makeLocalUploadHandler as m };
13
+ interface LoginEmailPayload {
14
+ to: string;
15
+ /** The full, ready-to-click URL. */
16
+ url: string;
17
+ site: string;
18
+ }
19
+ type SendLoginEmail = (payload: LoginEmailPayload) => Promise<void>;
20
+
21
+ export { type SendLoginEmail as S, type UploadHandler as U, makeLocalUploadHandler as m };
@@ -0,0 +1 @@
1
+ export { c as POST } from './auth-request.js';
@@ -0,0 +1,9 @@
1
+ import {
2
+ callback
3
+ } from "../chunk-DEI3FBNY.js";
4
+ import "../chunk-XZCXWILA.js";
5
+ import "../chunk-ECPYHIAW.js";
6
+ import "../chunk-6GUOGDWO.js";
7
+ export {
8
+ callback as POST
9
+ };
@@ -0,0 +1 @@
1
+ export { l as POST } from './auth-request.js';
@@ -0,0 +1,9 @@
1
+ import {
2
+ logout
3
+ } from "../chunk-DEI3FBNY.js";
4
+ import "../chunk-XZCXWILA.js";
5
+ import "../chunk-ECPYHIAW.js";
6
+ import "../chunk-6GUOGDWO.js";
7
+ export {
8
+ logout as POST
9
+ };
@@ -0,0 +1,18 @@
1
+ /** POST /api/cancia/auth/request — { email } */
2
+ declare function requestLink({ request }: {
3
+ request: Request;
4
+ }): Promise<Response>;
5
+ /** POST /api/cancia/auth/callback — { token } */
6
+ declare function callback({ request }: {
7
+ request: Request;
8
+ }): Promise<Response>;
9
+ /** POST /api/cancia/auth/logout */
10
+ declare function logout({ request }: {
11
+ request: Request;
12
+ }): Promise<Response>;
13
+ /** GET /api/cancia/auth/session — "am I signed in?" */
14
+ declare function session({ request }: {
15
+ request: Request;
16
+ }): Promise<Response>;
17
+
18
+ export { requestLink as POST, callback as c, logout as l, session as s };
@@ -0,0 +1,9 @@
1
+ import {
2
+ requestLink
3
+ } from "../chunk-DEI3FBNY.js";
4
+ import "../chunk-XZCXWILA.js";
5
+ import "../chunk-ECPYHIAW.js";
6
+ import "../chunk-6GUOGDWO.js";
7
+ export {
8
+ requestLink as POST
9
+ };
@@ -0,0 +1 @@
1
+ export { s as GET } from './auth-request.js';
@@ -0,0 +1,9 @@
1
+ import {
2
+ session
3
+ } from "../chunk-DEI3FBNY.js";
4
+ import "../chunk-XZCXWILA.js";
5
+ import "../chunk-ECPYHIAW.js";
6
+ import "../chunk-6GUOGDWO.js";
7
+ export {
8
+ session as GET
9
+ };
@@ -1,13 +1,21 @@
1
1
  import {
2
2
  createRateLimiter,
3
3
  runAuth
4
- } from "../chunk-GJIX7MWC.js";
4
+ } from "../chunk-ECPYHIAW.js";
5
5
 
6
6
  // src/endpoints/auth.ts
7
7
  import { getCanciaRuntime } from "virtual:cancia/runtime";
8
8
  var limiter = createRateLimiter();
9
9
  async function POST({ request }) {
10
- const { secret } = getCanciaRuntime();
10
+ const { secret, auth } = getCanciaRuntime();
11
+ if (auth) {
12
+ return new Response(
13
+ JSON.stringify({
14
+ error: "This site uses email login. Open the site and request a link instead."
15
+ }),
16
+ { status: 403, headers: { "Content-Type": "application/json" } }
17
+ );
18
+ }
11
19
  return runAuth({ request, secret, limiter });
12
20
  }
13
21
  export {
@@ -2,20 +2,20 @@ import {
2
2
  extractRoute,
3
3
  invalidateOnSave
4
4
  } from "../chunk-VGRG5DN7.js";
5
+ import {
6
+ guardRequest
7
+ } from "../chunk-4PYVIIOO.js";
8
+ import "../chunk-6GUOGDWO.js";
5
9
  import "../chunk-X6ZFFGIA.js";
6
10
 
7
11
  // src/endpoints/content.ts
8
12
  import { getCanciaRuntime } from "virtual:cancia/runtime";
9
- function checkAuth(req, secret) {
10
- if (!secret) return null;
11
- const token = req.headers.get("Authorization")?.replace("Bearer ", "").trim();
12
- if (token !== secret)
13
- return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
14
- return null;
13
+ async function checkAuth(req, secret, auth) {
14
+ return (await guardRequest(req, { secret, auth })).deny;
15
15
  }
16
16
  async function GET({ request }) {
17
- const { storage, secret } = getCanciaRuntime();
18
- const deny = checkAuth(request, secret);
17
+ const { storage, secret, auth } = getCanciaRuntime();
18
+ const deny = await checkAuth(request, secret, auth);
19
19
  if (deny) return deny;
20
20
  const site = new URL(request.url).searchParams.get("site");
21
21
  if (!site)
@@ -27,8 +27,8 @@ async function GET({ request }) {
27
27
  }
28
28
  async function POST(context) {
29
29
  const { request } = context;
30
- const { storage, secret, publishMode } = getCanciaRuntime();
31
- const deny = checkAuth(request, secret);
30
+ const { storage, secret, publishMode, auth } = getCanciaRuntime();
31
+ const deny = await checkAuth(request, secret, auth);
32
32
  if (deny) return deny;
33
33
  const body = await request.json().catch(() => null);
34
34
  if (!body?.site || !body?.key || !body?.lang || body?.value === void 0)
@@ -43,8 +43,8 @@ async function POST(context) {
43
43
  });
44
44
  }
45
45
  async function DELETE({ request }) {
46
- const { storage, secret } = getCanciaRuntime();
47
- const deny = checkAuth(request, secret);
46
+ const { storage, secret, auth } = getCanciaRuntime();
47
+ const deny = await checkAuth(request, secret, auth);
48
48
  if (deny) return deny;
49
49
  const body = await request.json().catch(() => null);
50
50
  if (!body?.site || !body?.key || !body?.lang)
@@ -4,7 +4,9 @@ import {
4
4
  } from "../chunk-VGRG5DN7.js";
5
5
  import {
6
6
  makeListsRoutes
7
- } from "../chunk-DIV2FFYX.js";
7
+ } from "../chunk-5R3I5RLT.js";
8
+ import "../chunk-4PYVIIOO.js";
9
+ import "../chunk-6GUOGDWO.js";
8
10
  import "../chunk-X6ZFFGIA.js";
9
11
  import "../chunk-VL6FO446.js";
10
12
  import "../chunk-7IA5B5CF.js";
@@ -18,6 +20,7 @@ function getRoutes() {
18
20
  projectRoot: rt.projectRoot,
19
21
  schemasPath: rt.schemasPath,
20
22
  secret: rt.secret,
23
+ auth: rt.auth,
21
24
  defaultLocale: rt.defaultLocale
22
25
  });
23
26
  }
@@ -1,6 +1,10 @@
1
1
  import {
2
2
  runPublish
3
3
  } from "../chunk-5RCLBWRH.js";
4
+ import {
5
+ guardRequest
6
+ } from "../chunk-4PYVIIOO.js";
7
+ import "../chunk-6GUOGDWO.js";
4
8
  import "../chunk-U7V53JX7.js";
5
9
 
6
10
  // src/endpoints/publish.ts
@@ -14,13 +18,11 @@ async function POST({ request }) {
14
18
  publishRepo,
15
19
  publishGithubToken,
16
20
  publishMode,
17
- secret
21
+ secret,
22
+ auth
18
23
  } = getCanciaRuntime();
19
- if (secret) {
20
- const token = request.headers.get("Authorization")?.replace("Bearer ", "").trim();
21
- if (token !== secret)
22
- return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
23
- }
24
+ const deny = (await guardRequest(request, { secret, auth })).deny;
25
+ if (deny) return deny;
24
26
  const hook = deployHook ?? process.env.CANCIA_DEPLOY_HOOK;
25
27
  const ghToken = publishGithubToken ?? process.env.CANCIA_GITHUB_TOKEN?.trim();
26
28
  return runPublish({
@@ -1,8 +1,10 @@
1
1
  import {
2
2
  makeSchemasRoute
3
- } from "../chunk-ONKCUTPU.js";
3
+ } from "../chunk-DOFLZ7KG.js";
4
+ import "../chunk-4PYVIIOO.js";
5
+ import "../chunk-6GUOGDWO.js";
4
6
  import "../chunk-VL6FO446.js";
5
- import "../chunk-YGJ3JHXF.js";
7
+ import "../chunk-QQEUCOXQ.js";
6
8
  import "../chunk-KHCFVVYV.js";
7
9
 
8
10
  // src/endpoints/schemas.ts
@@ -12,7 +14,8 @@ async function GET({ request }) {
12
14
  const route = makeSchemasRoute({
13
15
  projectRoot: rt.projectRoot,
14
16
  schemasPath: rt.schemasPath,
15
- secret: rt.secret
17
+ secret: rt.secret,
18
+ auth: rt.auth
16
19
  });
17
20
  return route(request);
18
21
  }
@@ -1,17 +1,18 @@
1
1
  import {
2
- detectImageType,
2
+ detectUploadType,
3
3
  isValidSite
4
- } from "../chunk-5IPHDIC6.js";
4
+ } from "../chunk-RHFTQW4W.js";
5
+ import {
6
+ guardRequest
7
+ } from "../chunk-4PYVIIOO.js";
8
+ import "../chunk-6GUOGDWO.js";
5
9
 
6
10
  // src/endpoints/upload.ts
7
11
  import { getCanciaRuntime } from "virtual:cancia/runtime";
8
12
  async function POST({ request }) {
9
- const { uploadHandler, secret, maxUploadMB } = getCanciaRuntime();
10
- if (secret) {
11
- const token = request.headers.get("Authorization")?.replace("Bearer ", "").trim();
12
- if (token !== secret)
13
- return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
14
- }
13
+ const { uploadHandler, secret, maxUploadMB, auth } = getCanciaRuntime();
14
+ const deny = (await guardRequest(request, { secret, auth })).deny;
15
+ if (deny) return deny;
15
16
  const form = await request.formData().catch(() => null);
16
17
  const file = form?.get("file");
17
18
  const site = form?.get("site");
@@ -28,9 +29,9 @@ async function POST({ request }) {
28
29
  { status: 413 }
29
30
  );
30
31
  const buf = new Uint8Array(await file.arrayBuffer());
31
- const detected = detectImageType(buf);
32
+ const detected = detectUploadType(buf);
32
33
  if (!detected)
33
- return new Response(JSON.stringify({ error: "File type not allowed" }), { status: 415 });
34
+ return new Response(JSON.stringify({ error: "That file type is not supported. Use a JPEG, PNG, GIF, WebP, AVIF or PDF." }), { status: 415 });
34
35
  const url = await uploadHandler(file, site, detected);
35
36
  return new Response(JSON.stringify({ url }), {
36
37
  headers: { "Content-Type": "application/json" }
@@ -1,5 +1,5 @@
1
- import { C as CanciaStorage, a as CanciaStorageV2 } from './types-BMlLS-OS.js';
2
- import { G as GitHubCommitter, a as GitHubClient, F as FetchLike } from './github-client-Db0pIrqE.js';
1
+ import { d as CanciaStorage, C as CanciaStorageV2 } from './types-CKzfz5iu.js';
2
+ import { b as GitHubCommitter, G as GitHubClient, F as FetchLike } from './github-client-Db5EPcSL.js';
3
3
 
4
4
  declare function createJsonFileAdapter(filePath?: string): CanciaStorage;
5
5
 
@@ -54,4 +54,4 @@ interface GitHubClient {
54
54
  }
55
55
  declare function createGitHubClient(opts: GitHubClientOptions): GitHubClient;
56
56
 
57
- export { type CommitFile as C, type FetchLike as F, type GitHubCommitter as G, type GitHubClient as a, type GitHubClientOptions as b, createGitHubClient as c };
57
+ export { type CommitFile as C, type FetchLike as F, type GitHubClient as G, type GitHubClientOptions as a, type GitHubCommitter as b, createGitHubClient as c };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { AstroIntegration } from 'astro';
2
- import { C as CanciaStorage, a as CanciaStorageV2 } from './types-BMlLS-OS.js';
3
- export { b as CanciaKVStore, c as CanciaListStore, d as CanciaPageStore, L as ListEntry, P as PageMeta, e as PageRecord, f as PageSEO, R as Rev, g as RevConflictError } from './types-BMlLS-OS.js';
4
- import { U as UploadHandler } from './upload-DwCGjXbz.js';
5
- export { m as makeLocalUploadHandler } from './upload-DwCGjXbz.js';
6
- import { G as GitHubCommitter } from './github-client-Db0pIrqE.js';
2
+ import { d as CanciaStorage, C as CanciaStorageV2 } from './types-CKzfz5iu.js';
3
+ export { a as CanciaKVStore, b as CanciaListStore, c as CanciaPageStore, L as ListEntry, P as PageMeta, e as PageRecord, f as PageSEO, R as Rev, g as RevConflictError } from './types-CKzfz5iu.js';
4
+ import { U as UploadHandler, S as SendLoginEmail } from './email-BRK4WAO2.js';
5
+ export { m as makeLocalUploadHandler } from './email-BRK4WAO2.js';
6
+ import { b as GitHubCommitter } from './github-client-Db5EPcSL.js';
7
7
  export { CanciaLoaderOptions, canciaLoader } from './loader/index.js';
8
8
  export { FieldDescription, FieldMeta, FieldMetaBase, FieldWidget, ListDescription, ListSchema, SchemasModule, defineField, defineList, describeList } from './schema/index.js';
9
- export { G as GitBackedContentPaths, a as GitBackedControls, b as GitBackedOptions, c as GitBackedStorage, S as SqliteV2Options, d as closeSqliteAdapterV2, e as createGitBackedAdapter, f as createJsonFileAdapter, g as createJsonFileAdapterV2, h as createSQLiteAdapter, i as createSqliteAdapterV2 } from './git-backed-DtiH52EI.js';
9
+ export { G as GitBackedContentPaths, a as GitBackedControls, b as GitBackedOptions, c as GitBackedStorage, S as SqliteV2Options, d as closeSqliteAdapterV2, e as createGitBackedAdapter, f as createJsonFileAdapter, g as createJsonFileAdapterV2, h as createSQLiteAdapter, i as createSqliteAdapterV2 } from './git-backed-CwTFfUS4.js';
10
10
  export { z } from 'zod';
11
11
  import 'astro/loaders';
12
12
  import './portable-text-D74aIuHn.js';
@@ -139,6 +139,32 @@ interface CanciaIntegrationOptions {
139
139
  * Use for public demos only — anyone can edit if this is enabled.
140
140
  */
141
141
  public?: boolean;
142
+ /**
143
+ * Email addresses allowed to sign in (042).
144
+ *
145
+ * Setting this switches the site to magic-link login: the client asks for a
146
+ * link, proves they own the address, and gets a session cookie. It also
147
+ * TURNS OFF the legacy `?cancia=<token>` URL login for humans — that token
148
+ * is a permanent password in a URL, and once a real login exists there is no
149
+ * reason to keep accepting it from a person. `CANCIA_TOKEN` stays valid as a
150
+ * machine credential for the build-time content fetch.
151
+ *
152
+ * Leaving it unset preserves the pre-042 behaviour exactly, so upgrading the
153
+ * package never changes how an existing deployment authenticates.
154
+ *
155
+ * cancia({ editors: ["client@theirsite.com"] })
156
+ *
157
+ * Adding someone is a config change plus a redeploy — the right friction for
158
+ * granting write access to a live site.
159
+ */
160
+ editors?: string[];
161
+ /**
162
+ * Send the login email. Defaults to Loops when LOOPS_API_KEY and
163
+ * CANCIA_LOGIN_TID are set, and otherwise logs the link to the server
164
+ * console (which is also the dev behaviour — no email vendor is needed to
165
+ * work on the CMS locally).
166
+ */
167
+ sendLoginEmail?: SendLoginEmail;
142
168
  /**
143
169
  * v2 storage adapter (KV + pages + lists). When omitted, Cancia builds a
144
170
  * JSON-file v2 adapter automatically at <projectRoot>/.cancia/. List/page