@cancia/astro 0.2.1 → 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-5AUIPW2I.js +518 -0
- package/dist/chunk-BMCI2F2Y.js +45 -0
- package/dist/{chunk-ST44VULL.js → chunk-L2VKQJPY.js} +9 -4
- package/dist/{chunk-7MPOERVU.js → chunk-U46HCJN3.js} +20 -3
- package/dist/chunk-U7V53JX7.js +83 -0
- package/dist/{chunk-337LJIKX.js → chunk-UR5WC3RA.js} +1 -1
- package/dist/endpoints/publish.js +47 -17
- package/dist/git-backed-DtiH52EI.d.ts +98 -0
- package/dist/{github-client-BAZ1pW24.d.ts → github-client-Db0pIrqE.d.ts} +9 -0
- package/dist/index.d.ts +54 -2
- package/dist/index.js +83 -23
- package/dist/loader/index.js +2 -2
- package/dist/runtime.d.ts +36 -1
- package/dist/runtime.js +4 -3
- package/dist/storage/index.d.ts +13 -84
- package/dist/storage/index.js +14 -4
- package/package.json +1 -1
- package/dist/chunk-5ELSN6LI.js +0 -244
|
@@ -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,33 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fireDispatch,
|
|
3
|
+
firePublish
|
|
4
|
+
} from "../chunk-BMCI2F2Y.js";
|
|
5
|
+
import "../chunk-U7V53JX7.js";
|
|
6
|
+
|
|
1
7
|
// src/endpoints/publish.ts
|
|
2
8
|
import { getCanciaRuntime } from "virtual:cancia/runtime";
|
|
3
9
|
async function POST({ request }) {
|
|
4
|
-
const {
|
|
10
|
+
const {
|
|
11
|
+
deployHook,
|
|
12
|
+
deployHookToken,
|
|
13
|
+
deployHookMethod,
|
|
14
|
+
deployHookHeaders,
|
|
15
|
+
publishRepo,
|
|
16
|
+
publishGithubToken,
|
|
17
|
+
secret
|
|
18
|
+
} = getCanciaRuntime();
|
|
5
19
|
if (secret) {
|
|
6
20
|
const token = request.headers.get("Authorization")?.replace("Bearer ", "").trim();
|
|
7
21
|
if (token !== secret)
|
|
8
22
|
return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
|
|
9
23
|
}
|
|
10
|
-
const
|
|
11
|
-
if (
|
|
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
|
+
});
|
|
12
31
|
return new Response(
|
|
13
|
-
JSON.stringify({ error: "
|
|
14
|
-
{ status:
|
|
32
|
+
JSON.stringify({ error: "GitHub repository_dispatch failed" }),
|
|
33
|
+
{ status: 502 }
|
|
15
34
|
);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
35
|
+
}
|
|
36
|
+
const hook = deployHook ?? process.env.CANCIA_DEPLOY_HOOK;
|
|
37
|
+
const result = await firePublish(hook, {
|
|
38
|
+
token: deployHookToken,
|
|
39
|
+
method: deployHookMethod,
|
|
40
|
+
headers: deployHookHeaders
|
|
41
|
+
});
|
|
42
|
+
if (result.ok)
|
|
23
43
|
return new Response(JSON.stringify({ ok: true }), {
|
|
24
44
|
headers: { "Content-Type": "application/json" }
|
|
25
45
|
});
|
|
26
|
-
|
|
27
|
-
return new Response(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
46
|
+
if (result.kind === "no-hook")
|
|
47
|
+
return new Response(
|
|
48
|
+
JSON.stringify({
|
|
49
|
+
error: "No publish mechanism configured. Set a publish repo + CANCIA_GITHUB_TOKEN, or CANCIA_DEPLOY_HOOK."
|
|
50
|
+
}),
|
|
51
|
+
{ status: 503 }
|
|
52
|
+
);
|
|
53
|
+
if (result.kind === "bad-response")
|
|
54
|
+
return new Response(
|
|
55
|
+
JSON.stringify({ error: `Deploy hook responded with ${result.status}` }),
|
|
56
|
+
{ status: 502 }
|
|
57
|
+
);
|
|
58
|
+
return new Response(JSON.stringify({ error: "Failed to reach deploy hook" }), {
|
|
59
|
+
status: 502
|
|
60
|
+
});
|
|
31
61
|
}
|
|
32
62
|
export {
|
|
33
63
|
POST
|
|
@@ -0,0 +1,98 @@
|
|
|
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';
|
|
3
|
+
|
|
4
|
+
declare function createJsonFileAdapter(filePath?: string): CanciaStorage;
|
|
5
|
+
|
|
6
|
+
interface JsonFileV2Options {
|
|
7
|
+
/** Project root. Defaults to process.cwd(). */
|
|
8
|
+
projectRoot?: string;
|
|
9
|
+
/** Override the KV file path. Defaults to <root>/cancia-content.json. */
|
|
10
|
+
kvPath?: string;
|
|
11
|
+
/** Override the pages file path. Defaults to <root>/.cancia/pages.json. */
|
|
12
|
+
pagesPath?: string;
|
|
13
|
+
/** Override the lists directory. Defaults to <root>/.cancia/lists. */
|
|
14
|
+
listsDir?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function createJsonFileAdapterV2(opts?: JsonFileV2Options): CanciaStorageV2;
|
|
17
|
+
|
|
18
|
+
declare function createSQLiteAdapter(dbPath?: string): CanciaStorage;
|
|
19
|
+
|
|
20
|
+
interface SqliteV2Options {
|
|
21
|
+
/** Absolute path to the .db file. Defaults to <projectRoot>/cancia.db. */
|
|
22
|
+
dbPath?: string;
|
|
23
|
+
/** Project root. Defaults to process.cwd(). Used to derive dbPath. */
|
|
24
|
+
projectRoot?: string;
|
|
25
|
+
}
|
|
26
|
+
declare function createSqliteAdapterV2(opts?: SqliteV2Options): CanciaStorageV2;
|
|
27
|
+
/**
|
|
28
|
+
* Close and forget the cached connection for a db path (or all connections
|
|
29
|
+
* when no path is given). The store interface has no lifecycle hook, so this
|
|
30
|
+
* is the seam for graceful shutdown and for tests that need to release the
|
|
31
|
+
* file handle before deleting the .db (Windows keeps WAL files locked while
|
|
32
|
+
* the connection is open). No-op if the path was never opened.
|
|
33
|
+
*/
|
|
34
|
+
declare function closeSqliteAdapterV2(dbPath?: string): void;
|
|
35
|
+
|
|
36
|
+
interface GitBackedContentPaths {
|
|
37
|
+
/** KV file path. Default <projectRoot>/cancia-content.json. */
|
|
38
|
+
kvPath?: string;
|
|
39
|
+
/** Pages file path. Default <projectRoot>/.cancia/pages.json. */
|
|
40
|
+
pagesPath?: string;
|
|
41
|
+
/** Lists directory. Default <projectRoot>/.cancia/lists. */
|
|
42
|
+
listsDir?: string;
|
|
43
|
+
}
|
|
44
|
+
interface GitBackedOptions {
|
|
45
|
+
/** The wrapped local adapter — the on-disk source of truth. */
|
|
46
|
+
local: CanciaStorageV2;
|
|
47
|
+
/** "owner/name" of the GitHub repo whose builds carry the content. */
|
|
48
|
+
repo: string;
|
|
49
|
+
/** Branch to commit onto. Default "main". */
|
|
50
|
+
branch?: string;
|
|
51
|
+
/**
|
|
52
|
+
* GitHub PAT. Reads CANCIA_GITHUB_TOKEN if omitted. When absent entirely the
|
|
53
|
+
* adapter runs in local-only mode (disk writes only; no commits) + warns once.
|
|
54
|
+
*/
|
|
55
|
+
token?: string;
|
|
56
|
+
/** Optional committer identity for commits. */
|
|
57
|
+
committer?: GitHubCommitter;
|
|
58
|
+
/**
|
|
59
|
+
* Project root the local adapter writes under — needed to turn absolute
|
|
60
|
+
* on-disk paths into repo-relative commit paths. Default process.cwd().
|
|
61
|
+
*/
|
|
62
|
+
projectRoot?: string;
|
|
63
|
+
/** Override where the local adapter's content lives (must match `local`). */
|
|
64
|
+
contentPaths?: GitBackedContentPaths;
|
|
65
|
+
/** Quiet window (ms) before a flush fires. Default 3000. */
|
|
66
|
+
debounceMs?: number;
|
|
67
|
+
/** Commit message for content updates. */
|
|
68
|
+
commitMessage?: string;
|
|
69
|
+
/** Injected GitHub client (tests pass a mock). Overrides token/fetch. */
|
|
70
|
+
client?: GitHubClient;
|
|
71
|
+
/** Injected fetch, forwarded to the default GitHub client. */
|
|
72
|
+
fetch?: FetchLike;
|
|
73
|
+
/** API base override, forwarded to the default GitHub client (tests). */
|
|
74
|
+
apiBase?: string;
|
|
75
|
+
/** Warn sink (tests capture). Default console.warn. */
|
|
76
|
+
warn?: (msg: string) => void;
|
|
77
|
+
/** Error sink for push failures (tests capture). Default console.error. */
|
|
78
|
+
onError?: (msg: string, err: unknown) => void;
|
|
79
|
+
}
|
|
80
|
+
/** The extra control surface the git adapter adds on top of CanciaStorageV2. */
|
|
81
|
+
interface GitBackedControls {
|
|
82
|
+
/**
|
|
83
|
+
* Force any pending dirty files to commit now, bypassing the debounce.
|
|
84
|
+
* Resolves once the flush completes (or rejects if the push failed — the
|
|
85
|
+
* files stay dirty for the next flush). For tests + graceful shutdown.
|
|
86
|
+
*/
|
|
87
|
+
flush(): Promise<void>;
|
|
88
|
+
/** True if git commits are active (token present). */
|
|
89
|
+
readonly gitEnabled: boolean;
|
|
90
|
+
/** Snapshot of currently-dirty repo-relative paths (for tests/inspection). */
|
|
91
|
+
pendingPaths(): string[];
|
|
92
|
+
}
|
|
93
|
+
type GitBackedStorage = CanciaStorageV2 & {
|
|
94
|
+
git: GitBackedControls;
|
|
95
|
+
};
|
|
96
|
+
declare function createGitBackedAdapter(opts: GitBackedOptions): GitBackedStorage;
|
|
97
|
+
|
|
98
|
+
export { type GitBackedContentPaths as G, type SqliteV2Options as S, type GitBackedControls as a, type GitBackedOptions as b, type GitBackedStorage as c, closeSqliteAdapterV2 as d, createGitBackedAdapter as e, createJsonFileAdapter as f, createJsonFileAdapterV2 as g, createSQLiteAdapter as h, createSqliteAdapterV2 as i };
|
|
@@ -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 { GitBackedContentPaths, GitBackedControls, GitBackedOptions, GitBackedStorage, createGitBackedAdapter, createJsonFileAdapter, createJsonFileAdapterV2, createSQLiteAdapter } from './
|
|
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';
|
|
@@ -48,6 +48,37 @@ interface CanciaIntegrationOptions {
|
|
|
48
48
|
accentColor?: string;
|
|
49
49
|
/** Deploy hook URL. Reads CANCIA_DEPLOY_HOOK env var if not set. */
|
|
50
50
|
deployHook?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Auth token for the deploy hook (e.g. Coolify's "auth required" hook).
|
|
53
|
+
* When set, the publish POST sends `Authorization: Bearer <token>`.
|
|
54
|
+
* SECRET — prefer the CANCIA_DEPLOY_HOOK_TOKEN env var (read at runtime,
|
|
55
|
+
* never baked into the build). This option is a dev/testing convenience.
|
|
56
|
+
*/
|
|
57
|
+
deployHookToken?: string;
|
|
58
|
+
/** Optional HTTP method for the deploy hook. Default: "POST". */
|
|
59
|
+
deployHookMethod?: string;
|
|
60
|
+
/** Optional extra headers merged into the deploy-hook request. */
|
|
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
|
+
};
|
|
51
82
|
/**
|
|
52
83
|
* Custom storage adapter.
|
|
53
84
|
* Default: SQLite (cancia.db in project root) — works anywhere with Node.
|
|
@@ -90,6 +121,27 @@ interface CanciaIntegrationOptions {
|
|
|
90
121
|
* (named or default) — a record of list name → defineList() output.
|
|
91
122
|
*/
|
|
92
123
|
schemasPath?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Declarative v2 storage backend — bakes SERIALISABLY into the runtime
|
|
126
|
+
* descriptor so a fresh production SSR server reconstructs the same adapter
|
|
127
|
+
* from config + `process.cwd()` (no live object crosses the build→deploy
|
|
128
|
+
* boundary). Prefer this over a live `storageV2` object for production.
|
|
129
|
+
*
|
|
130
|
+
* - `{ kind: "sqlite" }` (recommended) — the everything-store: KV + pages +
|
|
131
|
+
* lists in ONE `.db` per site (default `<root>/cancia.db`; override with
|
|
132
|
+
* `path`, relative paths resolve against the project root). Gitignore the
|
|
133
|
+
* `.db` for webhook-publish sites — it is NOT committed (contrast the
|
|
134
|
+
* git-backed model).
|
|
135
|
+
* - `{ kind: "json-file" }` — the JSON-file v2 default (files under
|
|
136
|
+
* `<root>/.cancia/`).
|
|
137
|
+
*
|
|
138
|
+
* Ignored when `git` is set (git-backed wins) or `storageV2` is passed as a
|
|
139
|
+
* live object (dev uses that eagerly).
|
|
140
|
+
*/
|
|
141
|
+
db?: {
|
|
142
|
+
kind: "sqlite" | "json-file";
|
|
143
|
+
path?: string;
|
|
144
|
+
};
|
|
93
145
|
/**
|
|
94
146
|
* Git-backed storage, described SERIALISABLY so a production SSR server can
|
|
95
147
|
* reconstruct the adapter in its own (fresh) process from this config + the
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fireDispatch,
|
|
3
|
+
firePublish
|
|
4
|
+
} from "./chunk-BMCI2F2Y.js";
|
|
1
5
|
import {
|
|
2
6
|
makeListsRoutes
|
|
3
7
|
} from "./chunk-22DJVJBR.js";
|
|
@@ -10,7 +14,7 @@ import {
|
|
|
10
14
|
makeR2UploadHandler,
|
|
11
15
|
makeUploadRoute,
|
|
12
16
|
setCanciaRuntime
|
|
13
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-U46HCJN3.js";
|
|
14
18
|
import {
|
|
15
19
|
defineField,
|
|
16
20
|
defineList,
|
|
@@ -19,17 +23,20 @@ import {
|
|
|
19
23
|
} from "./chunk-MCHQV6Y7.js";
|
|
20
24
|
import {
|
|
21
25
|
canciaLoader
|
|
22
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-UR5WC3RA.js";
|
|
23
27
|
import {
|
|
24
28
|
createSQLiteAdapter
|
|
25
29
|
} from "./chunk-AE4SIY24.js";
|
|
26
30
|
import {
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
closeSqliteAdapterV2,
|
|
32
|
+
createGitBackedAdapter,
|
|
33
|
+
createSqliteAdapterV2
|
|
34
|
+
} from "./chunk-5AUIPW2I.js";
|
|
35
|
+
import "./chunk-U7V53JX7.js";
|
|
29
36
|
import {
|
|
30
37
|
createJsonFileAdapter,
|
|
31
38
|
createJsonFileAdapterV2
|
|
32
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-L2VKQJPY.js";
|
|
33
40
|
import {
|
|
34
41
|
RevConflictError
|
|
35
42
|
} from "./chunk-7IA5B5CF.js";
|
|
@@ -39,6 +46,7 @@ import "./chunk-5IPHDIC6.js";
|
|
|
39
46
|
// src/integration.ts
|
|
40
47
|
import { loadEnv } from "vite";
|
|
41
48
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
49
|
+
import { isAbsolute, join as join2 } from "path";
|
|
42
50
|
|
|
43
51
|
// src/routes/content.ts
|
|
44
52
|
function makeContentRoute(storage, secret) {
|
|
@@ -87,7 +95,7 @@ function makeContentRoute(storage, secret) {
|
|
|
87
95
|
}
|
|
88
96
|
|
|
89
97
|
// src/routes/publish.ts
|
|
90
|
-
function makePublishRoute(deployHook, secret) {
|
|
98
|
+
function makePublishRoute(deployHook, secret, hookOptions, dispatch) {
|
|
91
99
|
return async ({ request }) => {
|
|
92
100
|
if (secret) {
|
|
93
101
|
const token = request.headers.get("Authorization")?.replace("Bearer ", "").trim();
|
|
@@ -95,27 +103,40 @@ function makePublishRoute(deployHook, secret) {
|
|
|
95
103
|
return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
|
-
|
|
99
|
-
|
|
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
|
+
}
|
|
100
113
|
return new Response(
|
|
101
|
-
JSON.stringify({ error: "
|
|
102
|
-
{ status:
|
|
114
|
+
JSON.stringify({ error: "GitHub repository_dispatch failed" }),
|
|
115
|
+
{ status: 502 }
|
|
103
116
|
);
|
|
104
117
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return new Response(
|
|
109
|
-
JSON.stringify({ error: `Deploy hook responded with ${res.status}` }),
|
|
110
|
-
{ status: 502 }
|
|
111
|
-
);
|
|
112
|
-
}
|
|
118
|
+
const hook = deployHook ?? process.env.CANCIA_DEPLOY_HOOK;
|
|
119
|
+
const result = await firePublish(hook, hookOptions);
|
|
120
|
+
if (result.ok) {
|
|
113
121
|
return new Response(JSON.stringify({ ok: true }), {
|
|
114
122
|
headers: { "Content-Type": "application/json" }
|
|
115
123
|
});
|
|
116
|
-
} catch {
|
|
117
|
-
return new Response(JSON.stringify({ error: "Failed to reach deploy hook" }), { status: 502 });
|
|
118
124
|
}
|
|
125
|
+
if (result.kind === "no-hook") {
|
|
126
|
+
return new Response(
|
|
127
|
+
JSON.stringify({
|
|
128
|
+
error: "No publish mechanism configured. Set a publish repo + CANCIA_GITHUB_TOKEN, or CANCIA_DEPLOY_HOOK."
|
|
129
|
+
}),
|
|
130
|
+
{ status: 503 }
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
if (result.kind === "bad-response") {
|
|
134
|
+
return new Response(
|
|
135
|
+
JSON.stringify({ error: `Deploy hook responded with ${result.status}` }),
|
|
136
|
+
{ status: 502 }
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
return new Response(JSON.stringify({ error: "Failed to reach deploy hook" }), { status: 502 });
|
|
119
140
|
};
|
|
120
141
|
}
|
|
121
142
|
|
|
@@ -205,6 +226,13 @@ CANCIA_TOKEN=${token}
|
|
|
205
226
|
}
|
|
206
227
|
|
|
207
228
|
// src/integration.ts
|
|
229
|
+
function buildDefaultV2Store(opts, projectRoot) {
|
|
230
|
+
if (opts.db?.kind === "sqlite") {
|
|
231
|
+
const path = opts.db.path ? isAbsolute(opts.db.path) ? opts.db.path : join2(projectRoot, opts.db.path) : join2(projectRoot, "cancia.db");
|
|
232
|
+
return createSqliteAdapterV2({ dbPath: path });
|
|
233
|
+
}
|
|
234
|
+
return createJsonFileAdapterV2({ projectRoot });
|
|
235
|
+
}
|
|
208
236
|
function canciaIntegration(opts = {}) {
|
|
209
237
|
let storage;
|
|
210
238
|
let resolvedToken = "";
|
|
@@ -212,6 +240,7 @@ function canciaIntegration(opts = {}) {
|
|
|
212
240
|
let resolvedRootPath = "";
|
|
213
241
|
let resolvedUploadHandler;
|
|
214
242
|
let resolvedDeployHook;
|
|
243
|
+
let resolvedPublishRepo;
|
|
215
244
|
let resolvedLocales = ["en"];
|
|
216
245
|
let bakedConfig = null;
|
|
217
246
|
return {
|
|
@@ -243,6 +272,7 @@ function canciaIntegration(opts = {}) {
|
|
|
243
272
|
\x1B[32mcancia\x1B[0m No CANCIA_TOKEN found \u2014 generated one for you.`);
|
|
244
273
|
}
|
|
245
274
|
const hasDeployHook = !!(opts.deployHook ?? env.CANCIA_DEPLOY_HOOK ?? process.env.CANCIA_DEPLOY_HOOK);
|
|
275
|
+
resolvedPublishRepo = opts.publish?.github?.repo ?? opts.git?.repo;
|
|
246
276
|
let storageDescriptor;
|
|
247
277
|
if (opts.git) {
|
|
248
278
|
storageDescriptor = {
|
|
@@ -255,6 +285,8 @@ function canciaIntegration(opts = {}) {
|
|
|
255
285
|
};
|
|
256
286
|
} else if (opts.storageV2 === null) {
|
|
257
287
|
storageDescriptor = void 0;
|
|
288
|
+
} else if (opts.db?.kind === "sqlite") {
|
|
289
|
+
storageDescriptor = { kind: "sqlite-v2", dbPath: opts.db.path };
|
|
258
290
|
} else {
|
|
259
291
|
storageDescriptor = { kind: "json-file", dbPath: opts.dbPath };
|
|
260
292
|
}
|
|
@@ -276,6 +308,9 @@ function canciaIntegration(opts = {}) {
|
|
|
276
308
|
maxUploadMB: opts.maxUploadMB ?? 10,
|
|
277
309
|
public: opts.public ?? false,
|
|
278
310
|
hasDeployHook,
|
|
311
|
+
deployHookMethod: opts.deployHookMethod,
|
|
312
|
+
deployHookHeaders: opts.deployHookHeaders,
|
|
313
|
+
publishRepo: resolvedPublishRepo,
|
|
279
314
|
storage: storageDescriptor,
|
|
280
315
|
r2: r2Baked
|
|
281
316
|
};
|
|
@@ -335,6 +370,8 @@ function canciaIntegration(opts = {}) {
|
|
|
335
370
|
storage = opts.storage ?? createJsonFileAdapter(opts.dbPath);
|
|
336
371
|
const secret = resolvedToken;
|
|
337
372
|
const deployHook = opts.deployHook ?? process.env.CANCIA_DEPLOY_HOOK;
|
|
373
|
+
const deployHookToken = process.env.CANCIA_DEPLOY_HOOK_TOKEN || opts.deployHookToken;
|
|
374
|
+
const publishGithubToken = process.env.CANCIA_GITHUB_TOKEN?.trim() || void 0;
|
|
338
375
|
let uploadHandler;
|
|
339
376
|
if (opts.r2) {
|
|
340
377
|
const serverEnv = loadEnv(process.env.NODE_ENV ?? "development", resolvedRootPath, "");
|
|
@@ -354,7 +391,7 @@ function canciaIntegration(opts = {}) {
|
|
|
354
391
|
const routeSecret = opts.public ? void 0 : secret || void 0;
|
|
355
392
|
resolvedUploadHandler = uploadHandler;
|
|
356
393
|
resolvedDeployHook = deployHook;
|
|
357
|
-
const storageV2 = opts.storageV2 === null ? void 0 : opts.storageV2 ??
|
|
394
|
+
const storageV2 = opts.storageV2 === null ? void 0 : opts.storageV2 ?? buildDefaultV2Store(opts, resolvedRootPath);
|
|
358
395
|
setCanciaRuntime({
|
|
359
396
|
storage,
|
|
360
397
|
storageV2,
|
|
@@ -365,11 +402,25 @@ function canciaIntegration(opts = {}) {
|
|
|
365
402
|
secret: routeSecret,
|
|
366
403
|
uploadHandler,
|
|
367
404
|
deployHook,
|
|
405
|
+
deployHookToken,
|
|
406
|
+
deployHookMethod: opts.deployHookMethod,
|
|
407
|
+
deployHookHeaders: opts.deployHookHeaders,
|
|
408
|
+
publishRepo: resolvedPublishRepo,
|
|
409
|
+
publishGithubToken,
|
|
368
410
|
maxUploadMB: opts.maxUploadMB ?? 10
|
|
369
411
|
});
|
|
370
412
|
const contentRoutes = makeContentRoute(storage, routeSecret);
|
|
371
413
|
const uploadRoute = makeUploadRoute(uploadHandler, routeSecret, opts.maxUploadMB);
|
|
372
|
-
const publishRoute = makePublishRoute(
|
|
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
|
+
);
|
|
373
424
|
const authRoute = makeAuthRoute(secret);
|
|
374
425
|
const listsRoutes = makeListsRoutes({
|
|
375
426
|
storageV2,
|
|
@@ -501,7 +552,9 @@ function canciaIntegration(opts = {}) {
|
|
|
501
552
|
uploadHandler = opts.uploadHandler ?? makeLocalUploadHandler({ maxMB: opts.maxUploadMB });
|
|
502
553
|
}
|
|
503
554
|
const deployHook = opts.deployHook ?? process.env.CANCIA_DEPLOY_HOOK;
|
|
504
|
-
const
|
|
555
|
+
const deployHookToken = process.env.CANCIA_DEPLOY_HOOK_TOKEN || opts.deployHookToken;
|
|
556
|
+
const publishGithubToken = process.env.CANCIA_GITHUB_TOKEN?.trim() || void 0;
|
|
557
|
+
const storageV2 = opts.storageV2 === null ? void 0 : opts.storageV2 ?? buildDefaultV2Store(opts, resolvedRootPath);
|
|
505
558
|
setCanciaRuntime({
|
|
506
559
|
storage,
|
|
507
560
|
storageV2,
|
|
@@ -512,6 +565,11 @@ function canciaIntegration(opts = {}) {
|
|
|
512
565
|
secret: routeSecret,
|
|
513
566
|
uploadHandler,
|
|
514
567
|
deployHook,
|
|
568
|
+
deployHookToken,
|
|
569
|
+
deployHookMethod: opts.deployHookMethod,
|
|
570
|
+
deployHookHeaders: opts.deployHookHeaders,
|
|
571
|
+
publishRepo: resolvedPublishRepo,
|
|
572
|
+
publishGithubToken,
|
|
515
573
|
maxUploadMB: opts.maxUploadMB ?? 10
|
|
516
574
|
});
|
|
517
575
|
}
|
|
@@ -552,10 +610,12 @@ export {
|
|
|
552
610
|
RevConflictError,
|
|
553
611
|
canciaIntegration,
|
|
554
612
|
canciaLoader,
|
|
613
|
+
closeSqliteAdapterV2,
|
|
555
614
|
createGitBackedAdapter,
|
|
556
615
|
createJsonFileAdapter,
|
|
557
616
|
createJsonFileAdapterV2,
|
|
558
617
|
createSQLiteAdapter,
|
|
618
|
+
createSqliteAdapterV2,
|
|
559
619
|
canciaIntegration as default,
|
|
560
620
|
defineField,
|
|
561
621
|
defineList,
|