@cancia/astro 0.0.1

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.
@@ -0,0 +1,393 @@
1
+ import {
2
+ RevConflictError
3
+ } from "./chunk-7IA5B5CF.js";
4
+
5
+ // src/loader/index.ts
6
+ import { join as join2 } from "path";
7
+
8
+ // src/storage/json-file-v2.ts
9
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, rmSync } from "fs";
10
+ import { dirname as dirname2, join } from "path";
11
+ import { createHash, randomUUID } from "crypto";
12
+
13
+ // src/storage/json-file.ts
14
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
15
+ import { dirname } from "path";
16
+ function readStore(filePath) {
17
+ if (!existsSync(filePath)) return {};
18
+ try {
19
+ return JSON.parse(readFileSync(filePath, "utf-8"));
20
+ } catch {
21
+ return {};
22
+ }
23
+ }
24
+ function writeStore(filePath, data) {
25
+ mkdirSync(dirname(filePath), { recursive: true });
26
+ writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
27
+ }
28
+ function createJsonFileAdapter(filePath) {
29
+ const path = filePath ?? process.cwd() + "/cancia-content.json";
30
+ return {
31
+ async get(site, key, lang) {
32
+ const store = readStore(path);
33
+ return store[`${site}::${key}.${lang}`] ?? null;
34
+ },
35
+ async set(site, key, lang, value) {
36
+ const store = readStore(path);
37
+ store[`${site}::${key}.${lang}`] = value;
38
+ writeStore(path, store);
39
+ },
40
+ async getAll(site) {
41
+ const store = readStore(path);
42
+ const prefix = `${site}::`;
43
+ const result = {};
44
+ for (const [k, v] of Object.entries(store)) {
45
+ if (k.startsWith(prefix)) {
46
+ result[k.slice(prefix.length)] = v;
47
+ }
48
+ }
49
+ return result;
50
+ },
51
+ async delete(site, key, lang) {
52
+ const store = readStore(path);
53
+ delete store[`${site}::${key}.${lang}`];
54
+ writeStore(path, store);
55
+ }
56
+ };
57
+ }
58
+
59
+ // src/storage/json-file-v2.ts
60
+ function canonicalize(value) {
61
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
62
+ if (Array.isArray(value)) {
63
+ return `[${value.map(canonicalize).join(",")}]`;
64
+ }
65
+ const obj = value;
66
+ const keys = Object.keys(obj).sort();
67
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalize(obj[k])}`).join(",")}}`;
68
+ }
69
+ function hashRev(value) {
70
+ return createHash("sha256").update(canonicalize(value)).digest("hex").slice(0, 16);
71
+ }
72
+ function readJsonFile(filePath, fallback) {
73
+ if (!existsSync2(filePath)) return fallback;
74
+ try {
75
+ return JSON.parse(readFileSync2(filePath, "utf-8"));
76
+ } catch {
77
+ return fallback;
78
+ }
79
+ }
80
+ function writeJsonFile(filePath, data) {
81
+ mkdirSync2(dirname2(filePath), { recursive: true });
82
+ writeFileSync2(filePath, JSON.stringify(data, null, 2), "utf-8");
83
+ }
84
+ function pageKey(site, route) {
85
+ return `${site}::${route}`;
86
+ }
87
+ function makePageStore(pagesPath) {
88
+ return {
89
+ async get(site, route) {
90
+ const all = readJsonFile(pagesPath, {});
91
+ const meta = all[pageKey(site, route)];
92
+ if (!meta) return null;
93
+ return { route, meta, _rev: hashRev(meta) };
94
+ },
95
+ async list(site) {
96
+ const all = readJsonFile(pagesPath, {});
97
+ const prefix = `${site}::`;
98
+ const records = [];
99
+ for (const [k, meta] of Object.entries(all)) {
100
+ if (!k.startsWith(prefix)) continue;
101
+ records.push({
102
+ route: k.slice(prefix.length),
103
+ meta,
104
+ _rev: hashRev(meta)
105
+ });
106
+ }
107
+ return records;
108
+ },
109
+ async set(site, route, meta, rev) {
110
+ const all = readJsonFile(pagesPath, {});
111
+ const key = pageKey(site, route);
112
+ const existing = all[key];
113
+ if (existing) {
114
+ const currentRev = hashRev(existing);
115
+ if (rev !== currentRev) throw new RevConflictError();
116
+ }
117
+ all[key] = meta;
118
+ writeJsonFile(pagesPath, all);
119
+ return { route, meta, _rev: hashRev(meta) };
120
+ },
121
+ async delete(site, route) {
122
+ const all = readJsonFile(pagesPath, {});
123
+ delete all[pageKey(site, route)];
124
+ writeJsonFile(pagesPath, all);
125
+ }
126
+ };
127
+ }
128
+ var RESERVED_DIRS = /* @__PURE__ */ new Set(["_order.json"]);
129
+ function listSiteDir(listsDir, listName, site) {
130
+ return join(listsDir, listName, site);
131
+ }
132
+ function localeDir(listsDir, listName, site, locale) {
133
+ return join(listSiteDir(listsDir, listName, site), locale);
134
+ }
135
+ function entryPath(listsDir, listName, site, locale, id) {
136
+ return join(localeDir(listsDir, listName, site, locale), `${id}.json`);
137
+ }
138
+ function orderPath(listsDir, listName, site) {
139
+ return join(listSiteDir(listsDir, listName, site), "_order.json");
140
+ }
141
+ function toEntry(raw) {
142
+ return { ...raw, _rev: hashRev(raw.data) };
143
+ }
144
+ function readOrder(listsDir, listName, site) {
145
+ return readJsonFile(orderPath(listsDir, listName, site), { ids: [] }).ids;
146
+ }
147
+ function writeOrder(listsDir, listName, site, ids) {
148
+ writeJsonFile(orderPath(listsDir, listName, site), { ids });
149
+ }
150
+ function listLocales(listsDir, listName, site) {
151
+ const siteDir = listSiteDir(listsDir, listName, site);
152
+ if (!existsSync2(siteDir)) return [];
153
+ return readdirSync(siteDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !RESERVED_DIRS.has(d.name)).map((d) => d.name);
154
+ }
155
+ function listEntryIdsInLocale(listsDir, listName, site, locale) {
156
+ const dir = localeDir(listsDir, listName, site, locale);
157
+ if (!existsSync2(dir)) return [];
158
+ return readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
159
+ }
160
+ function makeListStore(listsDir) {
161
+ function readEntry(site, listName, id, locale) {
162
+ const path = entryPath(listsDir, listName, site, locale, id);
163
+ if (!existsSync2(path)) return null;
164
+ try {
165
+ return JSON.parse(readFileSync2(path, "utf-8"));
166
+ } catch {
167
+ return null;
168
+ }
169
+ }
170
+ function writeEntry(site, listName, locale, entry) {
171
+ writeJsonFile(entryPath(listsDir, listName, site, locale, entry.id), entry);
172
+ }
173
+ function applyOrder(order, ids) {
174
+ const result = [];
175
+ const seen = /* @__PURE__ */ new Set();
176
+ for (const id of order) {
177
+ if (ids.has(id)) {
178
+ result.push(id);
179
+ seen.add(id);
180
+ }
181
+ }
182
+ const extras = [...ids].filter((id) => !seen.has(id)).sort();
183
+ return [...result, ...extras];
184
+ }
185
+ return {
186
+ async list(site, listName, locale) {
187
+ const order = readOrder(listsDir, listName, site);
188
+ if (locale !== void 0) {
189
+ const ids = new Set(listEntryIdsInLocale(listsDir, listName, site, locale));
190
+ const sorted = applyOrder(order, ids);
191
+ const entries2 = [];
192
+ for (const id of sorted) {
193
+ const raw = readEntry(site, listName, id, locale);
194
+ if (raw) entries2.push(toEntry(raw));
195
+ }
196
+ return entries2;
197
+ }
198
+ const locales = listLocales(listsDir, listName, site);
199
+ const allIds = /* @__PURE__ */ new Set();
200
+ for (const loc of locales) {
201
+ for (const id of listEntryIdsInLocale(listsDir, listName, site, loc)) {
202
+ allIds.add(id);
203
+ }
204
+ }
205
+ const sortedIds = applyOrder(order, allIds);
206
+ const entries = [];
207
+ for (const id of sortedIds) {
208
+ for (const loc of locales) {
209
+ const raw = readEntry(site, listName, id, loc);
210
+ if (raw) entries.push(toEntry(raw));
211
+ }
212
+ }
213
+ return entries;
214
+ },
215
+ async get(site, listName, id, locale) {
216
+ const raw = readEntry(site, listName, id, locale);
217
+ return raw ? toEntry(raw) : null;
218
+ },
219
+ async create(site, listName, data, locale, id) {
220
+ const finalId = id ?? randomUUID();
221
+ const existing = readEntry(site, listName, finalId, locale);
222
+ if (existing) {
223
+ throw new Error(`List entry "${finalId}" already exists in "${listName}" (${locale})`);
224
+ }
225
+ const now = (/* @__PURE__ */ new Date()).toISOString();
226
+ const entry = {
227
+ id: finalId,
228
+ locale,
229
+ data,
230
+ createdAt: now,
231
+ updatedAt: now
232
+ };
233
+ writeEntry(site, listName, locale, entry);
234
+ const order = readOrder(listsDir, listName, site);
235
+ if (!order.includes(finalId)) {
236
+ writeOrder(listsDir, listName, site, [...order, finalId]);
237
+ }
238
+ return toEntry(entry);
239
+ },
240
+ async update(site, listName, id, locale, data, rev) {
241
+ const existing = readEntry(site, listName, id, locale);
242
+ if (!existing) {
243
+ throw new Error(`List entry "${id}" not found in "${listName}" (${locale})`);
244
+ }
245
+ if (hashRev(existing.data) !== rev) throw new RevConflictError();
246
+ const updated = {
247
+ ...existing,
248
+ data,
249
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
250
+ };
251
+ writeEntry(site, listName, locale, updated);
252
+ return toEntry(updated);
253
+ },
254
+ async delete(site, listName, id, locale) {
255
+ const path = entryPath(listsDir, listName, site, locale, id);
256
+ if (!existsSync2(path)) return;
257
+ rmSync(path);
258
+ const stillExists = listLocales(listsDir, listName, site).some((loc) => existsSync2(entryPath(listsDir, listName, site, loc, id)));
259
+ if (!stillExists) {
260
+ const order = readOrder(listsDir, listName, site);
261
+ const next = order.filter((existingId) => existingId !== id);
262
+ if (next.length !== order.length) {
263
+ writeOrder(listsDir, listName, site, next);
264
+ }
265
+ }
266
+ },
267
+ async reorder(site, listName, ids) {
268
+ const locales = listLocales(listsDir, listName, site);
269
+ const allIds = /* @__PURE__ */ new Set();
270
+ for (const loc of locales) {
271
+ for (const id of listEntryIdsInLocale(listsDir, listName, site, loc)) {
272
+ allIds.add(id);
273
+ }
274
+ }
275
+ for (const id of ids) {
276
+ if (!allIds.has(id)) {
277
+ throw new Error(`Cannot reorder: entry "${id}" not found in "${listName}"`);
278
+ }
279
+ }
280
+ const supplied = new Set(ids);
281
+ for (const id of allIds) {
282
+ if (supplied.has(id)) continue;
283
+ for (const loc of locales) {
284
+ const path = entryPath(listsDir, listName, site, loc, id);
285
+ if (existsSync2(path)) rmSync(path);
286
+ }
287
+ }
288
+ writeOrder(listsDir, listName, site, ids);
289
+ },
290
+ async translations(site, listName) {
291
+ const locales = listLocales(listsDir, listName, site);
292
+ const idToLocales = /* @__PURE__ */ new Map();
293
+ for (const loc of locales) {
294
+ for (const id of listEntryIdsInLocale(listsDir, listName, site, loc)) {
295
+ const existing = idToLocales.get(id) ?? [];
296
+ existing.push(loc);
297
+ idToLocales.set(id, existing);
298
+ }
299
+ }
300
+ const order = readOrder(listsDir, listName, site);
301
+ const orderedIds = applyOrder(order, new Set(idToLocales.keys()));
302
+ return orderedIds.map((id) => ({
303
+ id,
304
+ locales: idToLocales.get(id) ?? []
305
+ }));
306
+ }
307
+ };
308
+ }
309
+ function createJsonFileAdapterV2(opts = {}) {
310
+ const root = opts.projectRoot ?? process.cwd();
311
+ const kvPath = opts.kvPath ?? join(root, "cancia-content.json");
312
+ const pagesPath = opts.pagesPath ?? join(root, ".cancia", "pages.json");
313
+ const listsDir = opts.listsDir ?? join(root, ".cancia", "lists");
314
+ return {
315
+ kv: createJsonFileAdapter(kvPath),
316
+ pages: makePageStore(pagesPath),
317
+ lists: makeListStore(listsDir)
318
+ };
319
+ }
320
+
321
+ // src/loader/index.ts
322
+ function makeId(locale, entryId) {
323
+ return `${locale}/${entryId}`;
324
+ }
325
+ async function syncOnce(ctx, lists, list, site) {
326
+ ctx.store.clear();
327
+ const entries = await lists.list(site, list);
328
+ for (const entry of entries) {
329
+ const id = makeId(entry.locale, entry.id);
330
+ const data = {
331
+ ...entry.data,
332
+ locale: entry.locale,
333
+ createdAt: entry.createdAt,
334
+ updatedAt: entry.updatedAt
335
+ };
336
+ ctx.store.set({
337
+ id,
338
+ data,
339
+ digest: entry._rev
340
+ });
341
+ }
342
+ ctx.logger.info(
343
+ `cancia: loaded ${entries.length} entr${entries.length === 1 ? "y" : "ies"} from list "${list}"`
344
+ );
345
+ }
346
+ function canciaLoader(opts) {
347
+ let watcherAttached = false;
348
+ let latestCtx = null;
349
+ let pendingTimer = null;
350
+ let inflight = Promise.resolve();
351
+ return {
352
+ name: `@cancia/astro/loader[${opts.list}]`,
353
+ async load(ctx) {
354
+ latestCtx = ctx;
355
+ const storage = opts.storage ?? createJsonFileAdapterV2({
356
+ projectRoot: opts.projectRoot ?? process.cwd()
357
+ });
358
+ const { lists } = storage;
359
+ await syncOnce(ctx, lists, opts.list, opts.site);
360
+ if (ctx.watcher && !watcherAttached) {
361
+ watcherAttached = true;
362
+ const root = opts.projectRoot ?? process.cwd();
363
+ const watchDir = join2(root, ".cancia", "lists", opts.list, opts.site);
364
+ ctx.watcher.add(watchDir);
365
+ const scheduleSync = () => {
366
+ if (pendingTimer) clearTimeout(pendingTimer);
367
+ pendingTimer = setTimeout(() => {
368
+ pendingTimer = null;
369
+ inflight = inflight.catch(() => {
370
+ }).then(
371
+ () => syncOnce(latestCtx, lists, opts.list, opts.site).catch((err) => {
372
+ latestCtx.logger.error(`cancia: resync failed \u2014 ${err.message}`);
373
+ })
374
+ );
375
+ }, 50);
376
+ };
377
+ const onEvent = (path) => {
378
+ if (!path.startsWith(watchDir)) return;
379
+ scheduleSync();
380
+ };
381
+ ctx.watcher.on("change", onEvent);
382
+ ctx.watcher.on("add", onEvent);
383
+ ctx.watcher.on("unlink", onEvent);
384
+ }
385
+ }
386
+ };
387
+ }
388
+
389
+ export {
390
+ createJsonFileAdapter,
391
+ createJsonFileAdapterV2,
392
+ canciaLoader
393
+ };
@@ -0,0 +1,5 @@
1
+ declare function POST({ request }: {
2
+ request: Request;
3
+ }): Promise<Response>;
4
+
5
+ export { POST };
@@ -0,0 +1,56 @@
1
+ // src/endpoints/auth.ts
2
+ import { getCanciaRuntime } from "virtual:cancia/runtime";
3
+ var buckets = /* @__PURE__ */ new Map();
4
+ var MAX_FAILURES = 5;
5
+ var WINDOW_MS = 6e4;
6
+ function getIp(req) {
7
+ return req.headers.get("x-forwarded-for")?.split(",")[0].trim() ?? req.headers.get("x-real-ip") ?? "unknown";
8
+ }
9
+ function isRateLimited(ip) {
10
+ const bucket = buckets.get(ip);
11
+ if (!bucket || Date.now() > bucket.resetAt) return false;
12
+ return bucket.failures >= MAX_FAILURES;
13
+ }
14
+ function recordFailure(ip) {
15
+ const now = Date.now();
16
+ const bucket = buckets.get(ip);
17
+ if (!bucket || now > bucket.resetAt) {
18
+ buckets.set(ip, { failures: 1, resetAt: now + WINDOW_MS });
19
+ } else {
20
+ bucket.failures += 1;
21
+ }
22
+ }
23
+ async function POST({ request }) {
24
+ const { secret } = getCanciaRuntime();
25
+ const ip = getIp(request);
26
+ if (isRateLimited(ip))
27
+ return new Response(
28
+ JSON.stringify({ error: "Too many attempts. Try again in a minute." }),
29
+ { status: 429, headers: { "Content-Type": "application/json" } }
30
+ );
31
+ let token;
32
+ try {
33
+ const body = await request.json();
34
+ token = body?.token;
35
+ } catch {
36
+ return new Response(
37
+ JSON.stringify({ error: "Invalid request body" }),
38
+ { status: 400, headers: { "Content-Type": "application/json" } }
39
+ );
40
+ }
41
+ if (!token || token !== secret) {
42
+ recordFailure(ip);
43
+ return new Response(
44
+ JSON.stringify({ error: "Invalid token" }),
45
+ { status: 401, headers: { "Content-Type": "application/json" } }
46
+ );
47
+ }
48
+ buckets.delete(ip);
49
+ return new Response(
50
+ JSON.stringify({ ok: true }),
51
+ { status: 200, headers: { "Content-Type": "application/json" } }
52
+ );
53
+ }
54
+ export {
55
+ POST
56
+ };
@@ -0,0 +1,11 @@
1
+ declare function GET({ request }: {
2
+ request: Request;
3
+ }): Promise<Response>;
4
+ declare function POST({ request }: {
5
+ request: Request;
6
+ }): Promise<Response>;
7
+ declare function DELETE({ request }: {
8
+ request: Request;
9
+ }): Promise<Response>;
10
+
11
+ export { DELETE, GET, POST };
@@ -0,0 +1,56 @@
1
+ // src/endpoints/content.ts
2
+ import { getCanciaRuntime } from "virtual:cancia/runtime";
3
+ function checkAuth(req, secret) {
4
+ if (!secret) return null;
5
+ const token = req.headers.get("Authorization")?.replace("Bearer ", "").trim();
6
+ if (token !== secret)
7
+ return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
8
+ return null;
9
+ }
10
+ async function GET({ request }) {
11
+ const { storage, secret } = getCanciaRuntime();
12
+ const deny = checkAuth(request, secret);
13
+ if (deny) return deny;
14
+ const site = new URL(request.url).searchParams.get("site");
15
+ if (!site)
16
+ return new Response(JSON.stringify({ error: "Missing ?site=" }), { status: 400 });
17
+ const data = await storage.getAll(site);
18
+ return new Response(JSON.stringify(data), {
19
+ headers: { "Content-Type": "application/json" }
20
+ });
21
+ }
22
+ async function POST({ request }) {
23
+ const { storage, secret } = getCanciaRuntime();
24
+ const deny = checkAuth(request, secret);
25
+ if (deny) return deny;
26
+ const body = await request.json().catch(() => null);
27
+ if (!body?.site || !body?.key || !body?.lang || body?.value === void 0)
28
+ return new Response(
29
+ JSON.stringify({ error: "Missing fields: site, key, lang, value" }),
30
+ { status: 400 }
31
+ );
32
+ await storage.set(body.site, body.key, body.lang, body.value);
33
+ return new Response(JSON.stringify({ ok: true }), {
34
+ headers: { "Content-Type": "application/json" }
35
+ });
36
+ }
37
+ async function DELETE({ request }) {
38
+ const { storage, secret } = getCanciaRuntime();
39
+ const deny = checkAuth(request, secret);
40
+ if (deny) return deny;
41
+ const body = await request.json().catch(() => null);
42
+ if (!body?.site || !body?.key || !body?.lang)
43
+ return new Response(
44
+ JSON.stringify({ error: "Missing fields: site, key, lang" }),
45
+ { status: 400 }
46
+ );
47
+ await storage.delete(body.site, body.key, body.lang);
48
+ return new Response(JSON.stringify({ ok: true }), {
49
+ headers: { "Content-Type": "application/json" }
50
+ });
51
+ }
52
+ export {
53
+ DELETE,
54
+ GET,
55
+ POST
56
+ };
@@ -0,0 +1,3 @@
1
+ declare function GET(): Response;
2
+
3
+ export { GET };
@@ -0,0 +1,9 @@
1
+ // src/endpoints/health.ts
2
+ function GET() {
3
+ return new Response(JSON.stringify({ ok: true }), {
4
+ headers: { "Content-Type": "application/json" }
5
+ });
6
+ }
7
+ export {
8
+ GET
9
+ };
@@ -0,0 +1,14 @@
1
+ declare function GET({ request }: {
2
+ request: Request;
3
+ }): Promise<Response>;
4
+ declare function POST({ request }: {
5
+ request: Request;
6
+ }): Promise<Response>;
7
+ declare function PATCH({ request }: {
8
+ request: Request;
9
+ }): Promise<Response>;
10
+ declare function DELETE({ request }: {
11
+ request: Request;
12
+ }): Promise<Response>;
13
+
14
+ export { DELETE, GET, PATCH, POST };
@@ -0,0 +1,36 @@
1
+ import {
2
+ makeListsRoutes
3
+ } from "../chunk-22DJVJBR.js";
4
+ import "../chunk-NG5GJME5.js";
5
+ import "../chunk-7IA5B5CF.js";
6
+
7
+ // src/endpoints/lists.ts
8
+ import { getCanciaRuntime } from "virtual:cancia/runtime";
9
+ function getRoutes() {
10
+ const rt = getCanciaRuntime();
11
+ return makeListsRoutes({
12
+ storageV2: rt.storageV2,
13
+ projectRoot: rt.projectRoot,
14
+ schemasPath: rt.schemasPath,
15
+ secret: rt.secret,
16
+ defaultLocale: rt.defaultLocale
17
+ });
18
+ }
19
+ async function GET({ request }) {
20
+ return getRoutes().handle(request, "GET");
21
+ }
22
+ async function POST({ request }) {
23
+ return getRoutes().handle(request, "POST");
24
+ }
25
+ async function PATCH({ request }) {
26
+ return getRoutes().handle(request, "PATCH");
27
+ }
28
+ async function DELETE({ request }) {
29
+ return getRoutes().handle(request, "DELETE");
30
+ }
31
+ export {
32
+ DELETE,
33
+ GET,
34
+ PATCH,
35
+ POST
36
+ };
@@ -0,0 +1,5 @@
1
+ declare function POST({ request }: {
2
+ request: Request;
3
+ }): Promise<Response>;
4
+
5
+ export { POST };
@@ -0,0 +1,34 @@
1
+ // src/endpoints/publish.ts
2
+ import { getCanciaRuntime } from "virtual:cancia/runtime";
3
+ async function POST({ request }) {
4
+ const { deployHook, secret } = getCanciaRuntime();
5
+ if (secret) {
6
+ const token = request.headers.get("Authorization")?.replace("Bearer ", "").trim();
7
+ if (token !== secret)
8
+ return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
9
+ }
10
+ const hook = deployHook ?? process.env.CANCIA_DEPLOY_HOOK;
11
+ if (!hook)
12
+ return new Response(
13
+ JSON.stringify({ error: "No deploy hook configured. Set CANCIA_DEPLOY_HOOK." }),
14
+ { status: 503 }
15
+ );
16
+ try {
17
+ const res = await fetch(hook, { method: "POST" });
18
+ if (!res.ok)
19
+ return new Response(
20
+ JSON.stringify({ error: `Deploy hook responded with ${res.status}` }),
21
+ { status: 502 }
22
+ );
23
+ return new Response(JSON.stringify({ ok: true }), {
24
+ headers: { "Content-Type": "application/json" }
25
+ });
26
+ } catch {
27
+ return new Response(JSON.stringify({ error: "Failed to reach deploy hook" }), {
28
+ status: 502
29
+ });
30
+ }
31
+ }
32
+ export {
33
+ POST
34
+ };
@@ -0,0 +1,5 @@
1
+ declare function GET({ request }: {
2
+ request: Request;
3
+ }): Promise<Response>;
4
+
5
+ export { GET };
@@ -0,0 +1,20 @@
1
+ import {
2
+ makeSchemasRoute
3
+ } from "../chunk-YPVZDWTW.js";
4
+ import "../chunk-NG5GJME5.js";
5
+ import "../chunk-QAM5VKAF.js";
6
+
7
+ // src/endpoints/schemas.ts
8
+ import { getCanciaRuntime } from "virtual:cancia/runtime";
9
+ async function GET({ request }) {
10
+ const rt = getCanciaRuntime();
11
+ const route = makeSchemasRoute({
12
+ projectRoot: rt.projectRoot,
13
+ schemasPath: rt.schemasPath,
14
+ secret: rt.secret
15
+ });
16
+ return route(request);
17
+ }
18
+ export {
19
+ GET
20
+ };
@@ -0,0 +1,5 @@
1
+ declare function POST({ request }: {
2
+ request: Request;
3
+ }): Promise<Response>;
4
+
5
+ export { POST };