@cancia/astro 0.3.0 → 0.4.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.
- package/dist/{chunk-52URFK5Y.js → chunk-5AUIPW2I.js} +3 -65
- package/dist/chunk-BMCI2F2Y.js +45 -0
- package/dist/{chunk-AIPRCBJM.js → chunk-U46HCJN3.js} +5 -1
- package/dist/chunk-U7V53JX7.js +83 -0
- package/dist/endpoints/publish.js +27 -3
- package/dist/{git-backed-DFAB0tzf.d.ts → git-backed-DtiH52EI.d.ts} +1 -1
- package/dist/{github-client-BAZ1pW24.d.ts → github-client-Db0pIrqE.d.ts} +9 -0
- package/dist/index.d.ts +22 -2
- package/dist/index.js +40 -10
- package/dist/runtime.d.ts +19 -1
- package/dist/runtime.js +3 -2
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +4 -2
- package/package.json +1 -1
- package/dist/chunk-PIDFNJME.js +0 -19
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createGitHubClient
|
|
3
|
+
} from "./chunk-U7V53JX7.js";
|
|
1
4
|
import {
|
|
2
5
|
hashRev
|
|
3
6
|
} from "./chunk-L2VKQJPY.js";
|
|
@@ -332,70 +335,6 @@ function closeSqliteAdapterV2(dbPath) {
|
|
|
332
335
|
}
|
|
333
336
|
}
|
|
334
337
|
|
|
335
|
-
// src/storage/github-client.ts
|
|
336
|
-
function toBase64(text) {
|
|
337
|
-
if (typeof Buffer !== "undefined") {
|
|
338
|
-
return Buffer.from(text, "utf-8").toString("base64");
|
|
339
|
-
}
|
|
340
|
-
const bytes = new TextEncoder().encode(text);
|
|
341
|
-
let binary = "";
|
|
342
|
-
for (const b of bytes) binary += String.fromCharCode(b);
|
|
343
|
-
return btoa(binary);
|
|
344
|
-
}
|
|
345
|
-
function createGitHubClient(opts) {
|
|
346
|
-
const { repo, branch, token, committer } = opts;
|
|
347
|
-
const doFetch = opts.fetch ?? globalThis.fetch;
|
|
348
|
-
const apiBase = (opts.apiBase ?? "https://api.github.com").replace(/\/$/, "");
|
|
349
|
-
if (!doFetch) {
|
|
350
|
-
throw new Error("createGitHubClient: no fetch available (pass opts.fetch)");
|
|
351
|
-
}
|
|
352
|
-
const headers = () => ({
|
|
353
|
-
Authorization: `Bearer ${token}`,
|
|
354
|
-
Accept: "application/vnd.github+json",
|
|
355
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
356
|
-
});
|
|
357
|
-
const contentsUrl = (path) => {
|
|
358
|
-
const encoded = path.split("/").map((seg) => encodeURIComponent(seg)).join("/");
|
|
359
|
-
return `${apiBase}/repos/${repo}/contents/${encoded}`;
|
|
360
|
-
};
|
|
361
|
-
async function getFileSha(path) {
|
|
362
|
-
const url = `${contentsUrl(path)}?ref=${encodeURIComponent(branch)}`;
|
|
363
|
-
const res = await doFetch(url, { method: "GET", headers: headers() });
|
|
364
|
-
if (res.status === 404) return null;
|
|
365
|
-
if (!res.ok) {
|
|
366
|
-
const detail = await res.text().catch(() => "");
|
|
367
|
-
throw new Error(`GitHub getFileSha ${path} failed: ${res.status} ${detail}`);
|
|
368
|
-
}
|
|
369
|
-
const body = await res.json();
|
|
370
|
-
return body.sha ?? null;
|
|
371
|
-
}
|
|
372
|
-
async function putFile(file, message) {
|
|
373
|
-
const sha = await getFileSha(file.path);
|
|
374
|
-
const payload = {
|
|
375
|
-
message,
|
|
376
|
-
content: toBase64(file.content),
|
|
377
|
-
branch
|
|
378
|
-
};
|
|
379
|
-
if (sha) payload.sha = sha;
|
|
380
|
-
if (committer) payload.committer = committer;
|
|
381
|
-
const res = await doFetch(contentsUrl(file.path), {
|
|
382
|
-
method: "PUT",
|
|
383
|
-
headers: headers(),
|
|
384
|
-
body: JSON.stringify(payload)
|
|
385
|
-
});
|
|
386
|
-
if (!res.ok) {
|
|
387
|
-
const detail = await res.text().catch(() => "");
|
|
388
|
-
throw new Error(`GitHub commit ${file.path} failed: ${res.status} ${detail}`);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
async function commitFiles(files, message) {
|
|
392
|
-
for (const file of files) {
|
|
393
|
-
await putFile(file, message);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
return { getFileSha, commitFiles };
|
|
397
|
-
}
|
|
398
|
-
|
|
399
338
|
// src/storage/git-backed.ts
|
|
400
339
|
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
401
340
|
import { join, relative } from "path";
|
|
@@ -575,6 +514,5 @@ function createGitBackedAdapter(opts) {
|
|
|
575
514
|
export {
|
|
576
515
|
createSqliteAdapterV2,
|
|
577
516
|
closeSqliteAdapterV2,
|
|
578
|
-
createGitHubClient,
|
|
579
517
|
createGitBackedAdapter
|
|
580
518
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createGitHubClient
|
|
3
|
+
} from "./chunk-U7V53JX7.js";
|
|
4
|
+
|
|
5
|
+
// src/publish-hook.ts
|
|
6
|
+
async function firePublish(hook, opts = {}) {
|
|
7
|
+
if (!hook) return { ok: false, kind: "no-hook" };
|
|
8
|
+
const headers = { ...opts.headers ?? {} };
|
|
9
|
+
if (opts.token) headers.Authorization = `Bearer ${opts.token}`;
|
|
10
|
+
const init = { method: opts.method ?? "POST" };
|
|
11
|
+
if (Object.keys(headers).length > 0) init.headers = headers;
|
|
12
|
+
try {
|
|
13
|
+
const res = await fetch(hook, init);
|
|
14
|
+
if (!res.ok) return { ok: false, kind: "bad-response", status: res.status };
|
|
15
|
+
return { ok: true };
|
|
16
|
+
} catch {
|
|
17
|
+
return { ok: false, kind: "unreachable" };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/publish-dispatch.ts
|
|
22
|
+
var CANCIA_PUBLISH_EVENT = "cancia-publish";
|
|
23
|
+
async function fireDispatch(opts) {
|
|
24
|
+
if (!opts.repo || !opts.token) return { ok: false, kind: "not-configured" };
|
|
25
|
+
const client = createGitHubClient({
|
|
26
|
+
repo: opts.repo,
|
|
27
|
+
// branch is irrelevant for dispatch (repo-level event) but required by the
|
|
28
|
+
// client's options — a harmless placeholder.
|
|
29
|
+
branch: "main",
|
|
30
|
+
token: opts.token,
|
|
31
|
+
fetch: opts.fetch,
|
|
32
|
+
apiBase: opts.apiBase
|
|
33
|
+
});
|
|
34
|
+
try {
|
|
35
|
+
await client.dispatch(opts.eventType ?? CANCIA_PUBLISH_EVENT, opts.clientPayload);
|
|
36
|
+
return { ok: true };
|
|
37
|
+
} catch {
|
|
38
|
+
return { ok: false, kind: "failed" };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
firePublish,
|
|
44
|
+
fireDispatch
|
|
45
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createGitBackedAdapter,
|
|
3
3
|
createSqliteAdapterV2
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5AUIPW2I.js";
|
|
5
5
|
import {
|
|
6
6
|
createJsonFileAdapter,
|
|
7
7
|
createJsonFileAdapterV2
|
|
@@ -172,6 +172,8 @@ function buildRuntimeFromBaked(baked) {
|
|
|
172
172
|
const secret = baked.public ? void 0 : token || void 0;
|
|
173
173
|
const deployHook = process.env.CANCIA_DEPLOY_HOOK || void 0;
|
|
174
174
|
const deployHookToken = process.env.CANCIA_DEPLOY_HOOK_TOKEN || void 0;
|
|
175
|
+
const publishRepo = baked.publishRepo || void 0;
|
|
176
|
+
const publishGithubToken = process.env.CANCIA_GITHUB_TOKEN?.trim() || void 0;
|
|
175
177
|
const storageV2 = buildStorageV2(baked, projectRoot);
|
|
176
178
|
const storage = storageV2 ? storageV2.kv : lazyJsonFileAdapter(projectRoot);
|
|
177
179
|
const uploadHandler = buildUploadHandler(baked, projectRoot);
|
|
@@ -188,6 +190,8 @@ function buildRuntimeFromBaked(baked) {
|
|
|
188
190
|
deployHookToken,
|
|
189
191
|
deployHookMethod: baked.deployHookMethod,
|
|
190
192
|
deployHookHeaders: baked.deployHookHeaders,
|
|
193
|
+
publishRepo,
|
|
194
|
+
publishGithubToken,
|
|
191
195
|
maxUploadMB: baked.maxUploadMB
|
|
192
196
|
};
|
|
193
197
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// src/storage/github-client.ts
|
|
2
|
+
function toBase64(text) {
|
|
3
|
+
if (typeof Buffer !== "undefined") {
|
|
4
|
+
return Buffer.from(text, "utf-8").toString("base64");
|
|
5
|
+
}
|
|
6
|
+
const bytes = new TextEncoder().encode(text);
|
|
7
|
+
let binary = "";
|
|
8
|
+
for (const b of bytes) binary += String.fromCharCode(b);
|
|
9
|
+
return btoa(binary);
|
|
10
|
+
}
|
|
11
|
+
function createGitHubClient(opts) {
|
|
12
|
+
const { repo, branch, token, committer } = opts;
|
|
13
|
+
const doFetch = opts.fetch ?? globalThis.fetch;
|
|
14
|
+
const apiBase = (opts.apiBase ?? "https://api.github.com").replace(/\/$/, "");
|
|
15
|
+
if (!doFetch) {
|
|
16
|
+
throw new Error("createGitHubClient: no fetch available (pass opts.fetch)");
|
|
17
|
+
}
|
|
18
|
+
const headers = () => ({
|
|
19
|
+
Authorization: `Bearer ${token}`,
|
|
20
|
+
Accept: "application/vnd.github+json",
|
|
21
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
22
|
+
});
|
|
23
|
+
const contentsUrl = (path) => {
|
|
24
|
+
const encoded = path.split("/").map((seg) => encodeURIComponent(seg)).join("/");
|
|
25
|
+
return `${apiBase}/repos/${repo}/contents/${encoded}`;
|
|
26
|
+
};
|
|
27
|
+
async function getFileSha(path) {
|
|
28
|
+
const url = `${contentsUrl(path)}?ref=${encodeURIComponent(branch)}`;
|
|
29
|
+
const res = await doFetch(url, { method: "GET", headers: headers() });
|
|
30
|
+
if (res.status === 404) return null;
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
const detail = await res.text().catch(() => "");
|
|
33
|
+
throw new Error(`GitHub getFileSha ${path} failed: ${res.status} ${detail}`);
|
|
34
|
+
}
|
|
35
|
+
const body = await res.json();
|
|
36
|
+
return body.sha ?? null;
|
|
37
|
+
}
|
|
38
|
+
async function putFile(file, message) {
|
|
39
|
+
const sha = await getFileSha(file.path);
|
|
40
|
+
const payload = {
|
|
41
|
+
message,
|
|
42
|
+
content: toBase64(file.content),
|
|
43
|
+
branch
|
|
44
|
+
};
|
|
45
|
+
if (sha) payload.sha = sha;
|
|
46
|
+
if (committer) payload.committer = committer;
|
|
47
|
+
const res = await doFetch(contentsUrl(file.path), {
|
|
48
|
+
method: "PUT",
|
|
49
|
+
headers: headers(),
|
|
50
|
+
body: JSON.stringify(payload)
|
|
51
|
+
});
|
|
52
|
+
if (!res.ok) {
|
|
53
|
+
const detail = await res.text().catch(() => "");
|
|
54
|
+
throw new Error(`GitHub commit ${file.path} failed: ${res.status} ${detail}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function commitFiles(files, message) {
|
|
58
|
+
for (const file of files) {
|
|
59
|
+
await putFile(file, message);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function dispatch(eventType, clientPayload) {
|
|
63
|
+
const url = `${apiBase}/repos/${repo}/dispatches`;
|
|
64
|
+
const payload = { event_type: eventType };
|
|
65
|
+
if (clientPayload !== void 0) payload.client_payload = clientPayload;
|
|
66
|
+
const res = await doFetch(url, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
headers: headers(),
|
|
69
|
+
body: JSON.stringify(payload)
|
|
70
|
+
});
|
|
71
|
+
if (!res.ok) {
|
|
72
|
+
const detail = await res.text().catch(() => "");
|
|
73
|
+
throw new Error(
|
|
74
|
+
`GitHub repository_dispatch ${eventType} failed: ${res.status} ${detail}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { getFileSha, commitFiles, dispatch };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
createGitHubClient
|
|
83
|
+
};
|
|
@@ -1,16 +1,38 @@
|
|
|
1
1
|
import {
|
|
2
|
+
fireDispatch,
|
|
2
3
|
firePublish
|
|
3
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-BMCI2F2Y.js";
|
|
5
|
+
import "../chunk-U7V53JX7.js";
|
|
4
6
|
|
|
5
7
|
// src/endpoints/publish.ts
|
|
6
8
|
import { getCanciaRuntime } from "virtual:cancia/runtime";
|
|
7
9
|
async function POST({ request }) {
|
|
8
|
-
const {
|
|
10
|
+
const {
|
|
11
|
+
deployHook,
|
|
12
|
+
deployHookToken,
|
|
13
|
+
deployHookMethod,
|
|
14
|
+
deployHookHeaders,
|
|
15
|
+
publishRepo,
|
|
16
|
+
publishGithubToken,
|
|
17
|
+
secret
|
|
18
|
+
} = getCanciaRuntime();
|
|
9
19
|
if (secret) {
|
|
10
20
|
const token = request.headers.get("Authorization")?.replace("Bearer ", "").trim();
|
|
11
21
|
if (token !== secret)
|
|
12
22
|
return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
|
|
13
23
|
}
|
|
24
|
+
const ghToken = publishGithubToken ?? process.env.CANCIA_GITHUB_TOKEN?.trim();
|
|
25
|
+
if (publishRepo && ghToken) {
|
|
26
|
+
const dispatched = await fireDispatch({ repo: publishRepo, token: ghToken });
|
|
27
|
+
if (dispatched.ok)
|
|
28
|
+
return new Response(JSON.stringify({ ok: true }), {
|
|
29
|
+
headers: { "Content-Type": "application/json" }
|
|
30
|
+
});
|
|
31
|
+
return new Response(
|
|
32
|
+
JSON.stringify({ error: "GitHub repository_dispatch failed" }),
|
|
33
|
+
{ status: 502 }
|
|
34
|
+
);
|
|
35
|
+
}
|
|
14
36
|
const hook = deployHook ?? process.env.CANCIA_DEPLOY_HOOK;
|
|
15
37
|
const result = await firePublish(hook, {
|
|
16
38
|
token: deployHookToken,
|
|
@@ -23,7 +45,9 @@ async function POST({ request }) {
|
|
|
23
45
|
});
|
|
24
46
|
if (result.kind === "no-hook")
|
|
25
47
|
return new Response(
|
|
26
|
-
JSON.stringify({
|
|
48
|
+
JSON.stringify({
|
|
49
|
+
error: "No publish mechanism configured. Set a publish repo + CANCIA_GITHUB_TOKEN, or CANCIA_DEPLOY_HOOK."
|
|
50
|
+
}),
|
|
27
51
|
{ status: 503 }
|
|
28
52
|
);
|
|
29
53
|
if (result.kind === "bad-response")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
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-
|
|
2
|
+
import { G as GitHubCommitter, a as GitHubClient, F as FetchLike } from './github-client-Db0pIrqE.js';
|
|
3
3
|
|
|
4
4
|
declare function createJsonFileAdapter(filePath?: string): CanciaStorage;
|
|
5
5
|
|
|
@@ -42,6 +42,15 @@ interface GitHubClient {
|
|
|
42
42
|
* any PUT fails so the caller can keep the batch dirty and retry.
|
|
43
43
|
*/
|
|
44
44
|
commitFiles(files: CommitFile[], message: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Fire a `repository_dispatch` event on the repo. POSTs
|
|
47
|
+
* `/repos/{owner}/{repo}/dispatches` with `{ event_type, client_payload }`
|
|
48
|
+
* and the Bearer token. GitHub returns 204 on success — throws on anything
|
|
49
|
+
* else. This is the host-independent publish trigger (031): a workflow in the
|
|
50
|
+
* client repo listens for the event and makes an empty commit, so the host's
|
|
51
|
+
* normal git integration rebuilds. Same repo-write PAT the Contents API uses.
|
|
52
|
+
*/
|
|
53
|
+
dispatch(eventType: string, clientPayload?: object): Promise<void>;
|
|
45
54
|
}
|
|
46
55
|
declare function createGitHubClient(opts: GitHubClientOptions): GitHubClient;
|
|
47
56
|
|
package/dist/index.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ import { C as CanciaStorage, a as CanciaStorageV2 } from './types-BMlLS-OS.js';
|
|
|
3
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
4
|
import { U as UploadHandler } from './upload-DwCGjXbz.js';
|
|
5
5
|
export { m as makeLocalUploadHandler } from './upload-DwCGjXbz.js';
|
|
6
|
-
import { G as GitHubCommitter } from './github-client-
|
|
6
|
+
import { G as GitHubCommitter } from './github-client-Db0pIrqE.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-
|
|
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';
|
|
10
10
|
export { z } from 'zod';
|
|
11
11
|
import 'astro/loaders';
|
|
12
12
|
import './portable-text-BikSqS9T.js';
|
|
@@ -59,6 +59,26 @@ interface CanciaIntegrationOptions {
|
|
|
59
59
|
deployHookMethod?: string;
|
|
60
60
|
/** Optional extra headers merged into the deploy-hook request. */
|
|
61
61
|
deployHookHeaders?: Record<string, string>;
|
|
62
|
+
/**
|
|
63
|
+
* The host-independent standard publish path (031). When set, the Publish
|
|
64
|
+
* button fires a GitHub `repository_dispatch` (event `cancia-publish`) on
|
|
65
|
+
* this repo instead of the raw deploy hook — a workflow in the repo
|
|
66
|
+
* (templates/cancia-publish.yml) makes an empty commit → the host's normal
|
|
67
|
+
* git integration rebuilds. Identical for every host; no host API / IP
|
|
68
|
+
* allowlist. The token is NEVER baked — it is read from
|
|
69
|
+
* `process.env.CANCIA_GITHUB_TOKEN` at runtime (a fine-grained PAT with
|
|
70
|
+
* `contents:write`, which covers repository_dispatch). Precedence:
|
|
71
|
+
* publish-dispatch (if repo + token) → deploy hook (030) → 503.
|
|
72
|
+
*
|
|
73
|
+
* If a git-backed `git.repo` is already declared, that repo is reused as the
|
|
74
|
+
* publish target unless overridden here.
|
|
75
|
+
*/
|
|
76
|
+
publish?: {
|
|
77
|
+
github?: {
|
|
78
|
+
/** "owner/name" of the repo whose `cancia-publish` workflow rebuilds. */
|
|
79
|
+
repo: string;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
62
82
|
/**
|
|
63
83
|
* Custom storage adapter.
|
|
64
84
|
* Default: SQLite (cancia.db in project root) — works anywhere with Node.
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
fireDispatch,
|
|
2
3
|
firePublish
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BMCI2F2Y.js";
|
|
4
5
|
import {
|
|
5
6
|
makeListsRoutes
|
|
6
7
|
} from "./chunk-22DJVJBR.js";
|
|
@@ -13,7 +14,7 @@ import {
|
|
|
13
14
|
makeR2UploadHandler,
|
|
14
15
|
makeUploadRoute,
|
|
15
16
|
setCanciaRuntime
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-U46HCJN3.js";
|
|
17
18
|
import {
|
|
18
19
|
defineField,
|
|
19
20
|
defineList,
|
|
@@ -30,7 +31,8 @@ import {
|
|
|
30
31
|
closeSqliteAdapterV2,
|
|
31
32
|
createGitBackedAdapter,
|
|
32
33
|
createSqliteAdapterV2
|
|
33
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-5AUIPW2I.js";
|
|
35
|
+
import "./chunk-U7V53JX7.js";
|
|
34
36
|
import {
|
|
35
37
|
createJsonFileAdapter,
|
|
36
38
|
createJsonFileAdapterV2
|
|
@@ -93,7 +95,7 @@ function makeContentRoute(storage, secret) {
|
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
// src/routes/publish.ts
|
|
96
|
-
function makePublishRoute(deployHook, secret, hookOptions) {
|
|
98
|
+
function makePublishRoute(deployHook, secret, hookOptions, dispatch) {
|
|
97
99
|
return async ({ request }) => {
|
|
98
100
|
if (secret) {
|
|
99
101
|
const token = request.headers.get("Authorization")?.replace("Bearer ", "").trim();
|
|
@@ -101,6 +103,18 @@ function makePublishRoute(deployHook, secret, hookOptions) {
|
|
|
101
103
|
return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
|
|
102
104
|
}
|
|
103
105
|
}
|
|
106
|
+
if (dispatch?.repo && dispatch?.token) {
|
|
107
|
+
const dispatched = await fireDispatch({ repo: dispatch.repo, token: dispatch.token });
|
|
108
|
+
if (dispatched.ok) {
|
|
109
|
+
return new Response(JSON.stringify({ ok: true }), {
|
|
110
|
+
headers: { "Content-Type": "application/json" }
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return new Response(
|
|
114
|
+
JSON.stringify({ error: "GitHub repository_dispatch failed" }),
|
|
115
|
+
{ status: 502 }
|
|
116
|
+
);
|
|
117
|
+
}
|
|
104
118
|
const hook = deployHook ?? process.env.CANCIA_DEPLOY_HOOK;
|
|
105
119
|
const result = await firePublish(hook, hookOptions);
|
|
106
120
|
if (result.ok) {
|
|
@@ -110,7 +124,9 @@ function makePublishRoute(deployHook, secret, hookOptions) {
|
|
|
110
124
|
}
|
|
111
125
|
if (result.kind === "no-hook") {
|
|
112
126
|
return new Response(
|
|
113
|
-
JSON.stringify({
|
|
127
|
+
JSON.stringify({
|
|
128
|
+
error: "No publish mechanism configured. Set a publish repo + CANCIA_GITHUB_TOKEN, or CANCIA_DEPLOY_HOOK."
|
|
129
|
+
}),
|
|
114
130
|
{ status: 503 }
|
|
115
131
|
);
|
|
116
132
|
}
|
|
@@ -224,6 +240,7 @@ function canciaIntegration(opts = {}) {
|
|
|
224
240
|
let resolvedRootPath = "";
|
|
225
241
|
let resolvedUploadHandler;
|
|
226
242
|
let resolvedDeployHook;
|
|
243
|
+
let resolvedPublishRepo;
|
|
227
244
|
let resolvedLocales = ["en"];
|
|
228
245
|
let bakedConfig = null;
|
|
229
246
|
return {
|
|
@@ -255,6 +272,7 @@ function canciaIntegration(opts = {}) {
|
|
|
255
272
|
\x1B[32mcancia\x1B[0m No CANCIA_TOKEN found \u2014 generated one for you.`);
|
|
256
273
|
}
|
|
257
274
|
const hasDeployHook = !!(opts.deployHook ?? env.CANCIA_DEPLOY_HOOK ?? process.env.CANCIA_DEPLOY_HOOK);
|
|
275
|
+
resolvedPublishRepo = opts.publish?.github?.repo ?? opts.git?.repo;
|
|
258
276
|
let storageDescriptor;
|
|
259
277
|
if (opts.git) {
|
|
260
278
|
storageDescriptor = {
|
|
@@ -292,6 +310,7 @@ function canciaIntegration(opts = {}) {
|
|
|
292
310
|
hasDeployHook,
|
|
293
311
|
deployHookMethod: opts.deployHookMethod,
|
|
294
312
|
deployHookHeaders: opts.deployHookHeaders,
|
|
313
|
+
publishRepo: resolvedPublishRepo,
|
|
295
314
|
storage: storageDescriptor,
|
|
296
315
|
r2: r2Baked
|
|
297
316
|
};
|
|
@@ -352,6 +371,7 @@ function canciaIntegration(opts = {}) {
|
|
|
352
371
|
const secret = resolvedToken;
|
|
353
372
|
const deployHook = opts.deployHook ?? process.env.CANCIA_DEPLOY_HOOK;
|
|
354
373
|
const deployHookToken = process.env.CANCIA_DEPLOY_HOOK_TOKEN || opts.deployHookToken;
|
|
374
|
+
const publishGithubToken = process.env.CANCIA_GITHUB_TOKEN?.trim() || void 0;
|
|
355
375
|
let uploadHandler;
|
|
356
376
|
if (opts.r2) {
|
|
357
377
|
const serverEnv = loadEnv(process.env.NODE_ENV ?? "development", resolvedRootPath, "");
|
|
@@ -385,15 +405,22 @@ function canciaIntegration(opts = {}) {
|
|
|
385
405
|
deployHookToken,
|
|
386
406
|
deployHookMethod: opts.deployHookMethod,
|
|
387
407
|
deployHookHeaders: opts.deployHookHeaders,
|
|
408
|
+
publishRepo: resolvedPublishRepo,
|
|
409
|
+
publishGithubToken,
|
|
388
410
|
maxUploadMB: opts.maxUploadMB ?? 10
|
|
389
411
|
});
|
|
390
412
|
const contentRoutes = makeContentRoute(storage, routeSecret);
|
|
391
413
|
const uploadRoute = makeUploadRoute(uploadHandler, routeSecret, opts.maxUploadMB);
|
|
392
|
-
const publishRoute = makePublishRoute(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
414
|
+
const publishRoute = makePublishRoute(
|
|
415
|
+
deployHook,
|
|
416
|
+
routeSecret,
|
|
417
|
+
{
|
|
418
|
+
token: deployHookToken,
|
|
419
|
+
method: opts.deployHookMethod,
|
|
420
|
+
headers: opts.deployHookHeaders
|
|
421
|
+
},
|
|
422
|
+
{ repo: resolvedPublishRepo, token: publishGithubToken }
|
|
423
|
+
);
|
|
397
424
|
const authRoute = makeAuthRoute(secret);
|
|
398
425
|
const listsRoutes = makeListsRoutes({
|
|
399
426
|
storageV2,
|
|
@@ -526,6 +553,7 @@ function canciaIntegration(opts = {}) {
|
|
|
526
553
|
}
|
|
527
554
|
const deployHook = opts.deployHook ?? process.env.CANCIA_DEPLOY_HOOK;
|
|
528
555
|
const deployHookToken = process.env.CANCIA_DEPLOY_HOOK_TOKEN || opts.deployHookToken;
|
|
556
|
+
const publishGithubToken = process.env.CANCIA_GITHUB_TOKEN?.trim() || void 0;
|
|
529
557
|
const storageV2 = opts.storageV2 === null ? void 0 : opts.storageV2 ?? buildDefaultV2Store(opts, resolvedRootPath);
|
|
530
558
|
setCanciaRuntime({
|
|
531
559
|
storage,
|
|
@@ -540,6 +568,8 @@ function canciaIntegration(opts = {}) {
|
|
|
540
568
|
deployHookToken,
|
|
541
569
|
deployHookMethod: opts.deployHookMethod,
|
|
542
570
|
deployHookHeaders: opts.deployHookHeaders,
|
|
571
|
+
publishRepo: resolvedPublishRepo,
|
|
572
|
+
publishGithubToken,
|
|
543
573
|
maxUploadMB: opts.maxUploadMB ?? 10
|
|
544
574
|
});
|
|
545
575
|
}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { C as CanciaStorage, a as CanciaStorageV2 } from './types-BMlLS-OS.js';
|
|
2
2
|
import { U as UploadHandler } from './upload-DwCGjXbz.js';
|
|
3
|
-
import { G as GitHubCommitter } from './github-client-
|
|
3
|
+
import { G as GitHubCommitter } from './github-client-Db0pIrqE.js';
|
|
4
4
|
|
|
5
5
|
interface CanciaRuntime {
|
|
6
6
|
/** v1 KV-only storage. Kept for the existing /content endpoint. */
|
|
@@ -37,6 +37,18 @@ interface CanciaRuntime {
|
|
|
37
37
|
deployHookMethod: string | undefined;
|
|
38
38
|
/** Optional extra headers merged into the hook request. Non-secret, baked. */
|
|
39
39
|
deployHookHeaders: Record<string, string> | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* "owner/name" of the GitHub repo whose `cancia-publish` workflow rebuilds
|
|
42
|
+
* the site (031). Non-secret, baked. When set (with CANCIA_GITHUB_TOKEN in
|
|
43
|
+
* env) the publish route fires a repository_dispatch instead of the raw
|
|
44
|
+
* deploy hook — the host-independent standard publish path.
|
|
45
|
+
*/
|
|
46
|
+
publishRepo?: string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* GitHub PAT (contents:write) used to fire the repository_dispatch. SECRET —
|
|
49
|
+
* read from CANCIA_GITHUB_TOKEN at runtime, never baked into dist/.
|
|
50
|
+
*/
|
|
51
|
+
publishGithubToken?: string | undefined;
|
|
40
52
|
maxUploadMB: number;
|
|
41
53
|
}
|
|
42
54
|
/** Describes which storage adapter to build lazily in the server process. */
|
|
@@ -75,6 +87,12 @@ interface BakedConfig {
|
|
|
75
87
|
deployHookMethod: string | undefined;
|
|
76
88
|
/** Optional deploy-hook extra headers. Non-secret (the token stays in env). */
|
|
77
89
|
deployHookHeaders: Record<string, string> | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* "owner/name" of the GitHub repo for repository_dispatch publish (031).
|
|
92
|
+
* Non-secret, baked. The token (CANCIA_GITHUB_TOKEN) is read from env at
|
|
93
|
+
* runtime. Absent = no dispatch path (falls through to the deploy hook).
|
|
94
|
+
*/
|
|
95
|
+
publishRepo?: string | undefined;
|
|
78
96
|
/** How to build the v2 storage adapter at runtime. Absent = no v2 storage. */
|
|
79
97
|
storage: BakedStorageDescriptor | undefined;
|
|
80
98
|
/** When set, build an R2 upload handler; secrets come from env at runtime. */
|
package/dist/runtime.js
CHANGED
|
@@ -2,8 +2,9 @@ import {
|
|
|
2
2
|
getCanciaRuntime,
|
|
3
3
|
setBakedConfig,
|
|
4
4
|
setCanciaRuntime
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-U46HCJN3.js";
|
|
6
|
+
import "./chunk-5AUIPW2I.js";
|
|
7
|
+
import "./chunk-U7V53JX7.js";
|
|
7
8
|
import "./chunk-L2VKQJPY.js";
|
|
8
9
|
import "./chunk-7IA5B5CF.js";
|
|
9
10
|
import "./chunk-5IPHDIC6.js";
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { R as Rev } from '../types-BMlLS-OS.js';
|
|
2
2
|
export { b as CanciaKVStore, c as CanciaListStore, d as CanciaPageStore, C as CanciaStorage, a as CanciaStorageV2, L as ListEntry, P as PageMeta, e as PageRecord, f as PageSEO, g as RevConflictError } from '../types-BMlLS-OS.js';
|
|
3
|
-
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-
|
|
4
|
-
export { C as CommitFile, a as GitHubClient, b as GitHubClientOptions, G as GitHubCommitter, c as createGitHubClient } from '../github-client-
|
|
3
|
+
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';
|
|
4
|
+
export { C as CommitFile, a as GitHubClient, b as GitHubClientOptions, G as GitHubCommitter, c as createGitHubClient } from '../github-client-Db0pIrqE.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Canonical JSON: keys sorted alphabetically at every level. Two values that
|
package/dist/storage/index.js
CHANGED
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
closeSqliteAdapterV2,
|
|
6
6
|
createGitBackedAdapter,
|
|
7
|
-
createGitHubClient,
|
|
8
7
|
createSqliteAdapterV2
|
|
9
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-5AUIPW2I.js";
|
|
9
|
+
import {
|
|
10
|
+
createGitHubClient
|
|
11
|
+
} from "../chunk-U7V53JX7.js";
|
|
10
12
|
import {
|
|
11
13
|
canonicalize,
|
|
12
14
|
createJsonFileAdapter,
|
package/package.json
CHANGED
package/dist/chunk-PIDFNJME.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// src/publish-hook.ts
|
|
2
|
-
async function firePublish(hook, opts = {}) {
|
|
3
|
-
if (!hook) return { ok: false, kind: "no-hook" };
|
|
4
|
-
const headers = { ...opts.headers ?? {} };
|
|
5
|
-
if (opts.token) headers.Authorization = `Bearer ${opts.token}`;
|
|
6
|
-
const init = { method: opts.method ?? "POST" };
|
|
7
|
-
if (Object.keys(headers).length > 0) init.headers = headers;
|
|
8
|
-
try {
|
|
9
|
-
const res = await fetch(hook, init);
|
|
10
|
-
if (!res.ok) return { ok: false, kind: "bad-response", status: res.status };
|
|
11
|
-
return { ok: true };
|
|
12
|
-
} catch {
|
|
13
|
-
return { ok: false, kind: "unreachable" };
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export {
|
|
18
|
-
firePublish
|
|
19
|
-
};
|