@setzkasten-cms/astro-admin 1.4.0 → 1.4.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.
- package/dist/api-routes/_auth-guard.d.ts +47 -0
- package/dist/api-routes/_auth-guard.js +18 -0
- package/dist/api-routes/_commit-trailers.d.ts +8 -0
- package/dist/api-routes/_commit-trailers.js +8 -0
- package/dist/api-routes/_feature-gate.d.ts +23 -0
- package/dist/api-routes/_feature-gate.js +7 -0
- package/dist/api-routes/_github-cache.d.ts +4 -0
- package/dist/api-routes/_github-cache.js +8 -0
- package/dist/api-routes/_github-token.d.ts +27 -0
- package/dist/api-routes/_github-token.js +8 -0
- package/dist/api-routes/_license-tier.d.ts +22 -0
- package/dist/api-routes/_license-tier.js +6 -0
- package/dist/api-routes/_pages-meta-store.d.ts +32 -0
- package/dist/api-routes/_pages-meta-store.js +9 -0
- package/dist/api-routes/_role-resolver.d.ts +15 -0
- package/dist/api-routes/_role-resolver.js +13 -0
- package/dist/api-routes/_session-cookie.d.ts +18 -0
- package/dist/api-routes/_session-cookie.js +6 -0
- package/dist/api-routes/_storage-config.d.ts +60 -0
- package/dist/api-routes/_storage-config.js +10 -0
- package/dist/api-routes/_vercel-origin.d.ts +16 -0
- package/dist/api-routes/_vercel-origin.js +6 -0
- package/dist/api-routes/_webhook-dispatcher.d.ts +13 -0
- package/dist/api-routes/_webhook-dispatcher.js +97 -0
- package/dist/api-routes/_webhook-signing.d.ts +11 -0
- package/dist/api-routes/_webhook-signing.js +6 -0
- package/dist/api-routes/_webhook-status-store.d.ts +19 -0
- package/dist/api-routes/_webhook-status-store.js +10 -0
- package/dist/api-routes/_website-resolver.d.ts +49 -0
- package/dist/api-routes/_website-resolver.js +14 -0
- package/dist/api-routes/_websites-store.d.ts +30 -0
- package/dist/api-routes/_websites-store.js +11 -0
- package/dist/api-routes/asset-proxy.d.ts +12 -0
- package/dist/api-routes/asset-proxy.js +67 -0
- package/dist/api-routes/auth-callback.d.ts +9 -0
- package/dist/api-routes/auth-callback.js +68 -0
- package/dist/api-routes/auth-login.d.ts +11 -0
- package/dist/api-routes/auth-login.js +27 -0
- package/dist/api-routes/auth-logout.d.ts +10 -0
- package/dist/api-routes/auth-logout.js +13 -0
- package/dist/api-routes/auth-session.d.ts +9 -0
- package/dist/api-routes/auth-session.js +31 -0
- package/dist/api-routes/auth-setzkasten-login.d.ts +18 -0
- package/dist/api-routes/auth-setzkasten-login.js +74 -0
- package/dist/api-routes/catalog-add.d.ts +14 -0
- package/dist/api-routes/catalog-add.js +153 -0
- package/dist/api-routes/catalog-export.d.ts +13 -0
- package/dist/api-routes/catalog-export.js +71 -0
- package/dist/api-routes/catalog-helpers.d.ts +41 -0
- package/dist/api-routes/catalog-helpers.js +11 -0
- package/dist/api-routes/catalog-list.d.ts +11 -0
- package/dist/api-routes/catalog-list.js +12 -0
- package/dist/api-routes/config.d.ts +12 -0
- package/dist/api-routes/config.js +43 -0
- package/dist/api-routes/deploy-hook.d.ts +14 -0
- package/dist/api-routes/deploy-hook.js +52 -0
- package/dist/api-routes/editors.d.ts +29 -0
- package/dist/api-routes/editors.js +18 -0
- package/dist/api-routes/github-proxy.d.ts +12 -0
- package/dist/api-routes/github-proxy.js +82 -0
- package/dist/api-routes/global-config.d.ts +20 -0
- package/dist/api-routes/global-config.js +19 -0
- package/dist/api-routes/history-rollback.d.ts +22 -0
- package/dist/api-routes/history-rollback.js +111 -0
- package/dist/api-routes/history-version.d.ts +11 -0
- package/dist/api-routes/history-version.js +57 -0
- package/dist/api-routes/history.d.ts +13 -0
- package/dist/api-routes/history.js +85 -0
- package/dist/api-routes/icons-local.d.ts +28 -0
- package/dist/api-routes/icons-local.js +115 -0
- package/dist/api-routes/init-add-section.d.ts +23 -0
- package/dist/api-routes/init-add-section.js +396 -0
- package/dist/api-routes/init-apply.d.ts +11 -0
- package/dist/api-routes/init-apply.js +266 -0
- package/dist/api-routes/init-migrate.d.ts +16 -0
- package/dist/api-routes/init-migrate.js +205 -0
- package/dist/api-routes/init-scan-page.d.ts +39 -0
- package/dist/api-routes/init-scan-page.js +260 -0
- package/dist/api-routes/init-scan.d.ts +11 -0
- package/dist/api-routes/init-scan.js +128 -0
- package/dist/api-routes/migrate-to-multi.d.ts +26 -0
- package/dist/api-routes/migrate-to-multi.js +188 -0
- package/dist/api-routes/pages.d.ts +39 -0
- package/dist/api-routes/pages.js +88 -0
- package/dist/api-routes/section-add.d.ts +18 -0
- package/dist/api-routes/section-add.js +173 -0
- package/dist/api-routes/section-commit-pending.d.ts +18 -0
- package/dist/api-routes/section-commit-pending.js +207 -0
- package/dist/api-routes/section-delete.d.ts +15 -0
- package/dist/api-routes/section-delete.js +149 -0
- package/dist/api-routes/section-duplicate.d.ts +15 -0
- package/dist/api-routes/section-duplicate.js +143 -0
- package/dist/api-routes/section-management.d.ts +41 -0
- package/dist/api-routes/section-management.js +14 -0
- package/dist/api-routes/section-prepare-copy.d.ts +25 -0
- package/dist/api-routes/section-prepare-copy.js +69 -0
- package/dist/api-routes/section-prepare.d.ts +18 -0
- package/dist/api-routes/section-prepare.js +104 -0
- package/dist/api-routes/setup-github-app-bounce.d.ts +13 -0
- package/dist/api-routes/setup-github-app-bounce.js +45 -0
- package/dist/api-routes/setup-github-app-branches.d.ts +14 -0
- package/dist/api-routes/setup-github-app-branches.js +58 -0
- package/dist/api-routes/setup-github-app-callback.d.ts +15 -0
- package/dist/api-routes/setup-github-app-callback.js +45 -0
- package/dist/api-routes/setup-github-app-installed.d.ts +15 -0
- package/dist/api-routes/setup-github-app-installed.js +33 -0
- package/dist/api-routes/setup-github-app-repos.d.ts +17 -0
- package/dist/api-routes/setup-github-app-repos.js +41 -0
- package/dist/api-routes/setup-github-app.d.ts +15 -0
- package/dist/api-routes/setup-github-app.js +41 -0
- package/dist/api-routes/updater-check.d.ts +10 -0
- package/dist/api-routes/updater-check.js +37 -0
- package/dist/api-routes/updater-register.d.ts +14 -0
- package/dist/api-routes/updater-register.js +71 -0
- package/dist/api-routes/updater-transfer.d.ts +11 -0
- package/dist/api-routes/updater-transfer.js +37 -0
- package/dist/api-routes/updater-unbind.d.ts +17 -0
- package/dist/api-routes/updater-unbind.js +35 -0
- package/dist/api-routes/webhooks-status.d.ts +12 -0
- package/dist/api-routes/webhooks-status.js +22 -0
- package/dist/api-routes/webhooks-test.d.ts +13 -0
- package/dist/api-routes/webhooks-test.js +124 -0
- package/dist/api-routes/webhooks.d.ts +6 -0
- package/dist/api-routes/webhooks.js +148 -0
- package/dist/api-routes/websites-add.d.ts +15 -0
- package/dist/api-routes/websites-add.js +92 -0
- package/dist/api-routes/websites-list.d.ts +12 -0
- package/dist/api-routes/websites-list.js +35 -0
- package/dist/api-routes/websites-remove.d.ts +15 -0
- package/dist/api-routes/websites-remove.js +69 -0
- package/dist/chunk-35S35OIV.js +80 -0
- package/dist/chunk-45ARVNT3.js +25 -0
- package/dist/chunk-5PIMDP4N.js +25 -0
- package/dist/chunk-5ZFTG4BW.js +10 -0
- package/dist/chunk-6UIKVKED.js +51 -0
- package/dist/chunk-737TIZRU.js +9 -0
- package/dist/chunk-AM4DZXXM.js +120 -0
- package/dist/chunk-FXNOTESI.js +87 -0
- package/dist/chunk-GHNK2GFE.js +48 -0
- package/dist/chunk-GRG3LNKH.js +37 -0
- package/dist/chunk-INIWFKQ3.js +236 -0
- package/dist/chunk-JHY6XTLL.js +24 -0
- package/dist/chunk-K22A4ZBS.js +1574 -0
- package/dist/chunk-KH22FJO5.js +17 -0
- package/dist/chunk-NKDATSPA.js +43 -0
- package/dist/chunk-RHJONMLK.js +1267 -0
- package/dist/chunk-TJNJKPUL.js +11 -0
- package/dist/chunk-V6IMPVF3.js +120 -0
- package/dist/chunk-W3QHY5GW.js +19 -0
- package/dist/chunk-ZQDGGWJP.js +43 -0
- package/package.json +249 -53
- package/src/api-routes/__tests__/route-registry.test.ts +7 -1
- package/tsconfig.json +0 -9
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getPublicOrigin
|
|
3
|
+
} from "../chunk-5ZFTG4BW.js";
|
|
4
|
+
|
|
5
|
+
// src/api-routes/setup-github-app-installed.ts
|
|
6
|
+
var COOKIE_NAME = "sk_app_setup";
|
|
7
|
+
var COOKIE_MAX_AGE = 600;
|
|
8
|
+
var GET = async ({ url, request, cookies }) => {
|
|
9
|
+
const config = globalThis.__SETZKASTEN_CONFIG__;
|
|
10
|
+
const adminPath = config?.adminPath ?? "/admin";
|
|
11
|
+
const adminUrl = new URL(adminPath, getPublicOrigin(request));
|
|
12
|
+
const installationId = url.searchParams.get("installation_id");
|
|
13
|
+
const existing = cookies.get(COOKIE_NAME)?.value;
|
|
14
|
+
if (!installationId || !existing) {
|
|
15
|
+
adminUrl.searchParams.set("github-app-error", "missing_installation");
|
|
16
|
+
return new Response(null, { status: 302, headers: { Location: adminUrl.toString() } });
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const data = JSON.parse(existing);
|
|
20
|
+
cookies.set(
|
|
21
|
+
COOKIE_NAME,
|
|
22
|
+
JSON.stringify({ ...data, installationId }),
|
|
23
|
+
{ httpOnly: false, sameSite: "lax", maxAge: COOKIE_MAX_AGE, path: "/" }
|
|
24
|
+
);
|
|
25
|
+
} catch {
|
|
26
|
+
adminUrl.searchParams.set("github-app-error", "invalid_session");
|
|
27
|
+
return new Response(null, { status: 302, headers: { Location: adminUrl.toString() } });
|
|
28
|
+
}
|
|
29
|
+
return new Response(null, { status: 302, headers: { Location: adminUrl.toString() } });
|
|
30
|
+
};
|
|
31
|
+
export {
|
|
32
|
+
GET
|
|
33
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { APIRoute } from 'astro';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GET /api/setzkasten/setup/github-app/repos
|
|
5
|
+
*
|
|
6
|
+
* Returns every repository the configured GitHub App can access, flattened
|
|
7
|
+
* across all installations. Each entry includes the installationId so the
|
|
8
|
+
* "Neue Website hinzufügen" form can record which installation owns the
|
|
9
|
+
* repo without a follow-up lookup.
|
|
10
|
+
*
|
|
11
|
+
* Admin-only — editors must not be able to enumerate repos across the
|
|
12
|
+
* organization. The endpoint uses the global App credentials from the env
|
|
13
|
+
* (GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY) so the user never has to type them.
|
|
14
|
+
*/
|
|
15
|
+
declare const GET: APIRoute;
|
|
16
|
+
|
|
17
|
+
export { GET };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
requireAdmin
|
|
3
|
+
} from "../chunk-INIWFKQ3.js";
|
|
4
|
+
import "../chunk-6UIKVKED.js";
|
|
5
|
+
import "../chunk-5PIMDP4N.js";
|
|
6
|
+
import "../chunk-45ARVNT3.js";
|
|
7
|
+
import "../chunk-NKDATSPA.js";
|
|
8
|
+
import "../chunk-TJNJKPUL.js";
|
|
9
|
+
import "../chunk-KH22FJO5.js";
|
|
10
|
+
|
|
11
|
+
// src/api-routes/setup-github-app-repos.ts
|
|
12
|
+
import { listAccessibleRepos } from "@setzkasten-cms/github-adapter";
|
|
13
|
+
var GET = async ({ cookies }) => {
|
|
14
|
+
const denied = requireAdmin(cookies.get("setzkasten_session")?.value);
|
|
15
|
+
if (denied) return denied;
|
|
16
|
+
const appId = process.env.GITHUB_APP_ID;
|
|
17
|
+
const privateKey = process.env.GITHUB_APP_PRIVATE_KEY;
|
|
18
|
+
if (!appId || !privateKey) {
|
|
19
|
+
return new Response(
|
|
20
|
+
JSON.stringify({
|
|
21
|
+
error: "GitHub App not configured. Set GITHUB_APP_ID and GITHUB_APP_PRIVATE_KEY."
|
|
22
|
+
}),
|
|
23
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
const result = await listAccessibleRepos({ appId, privateKey });
|
|
27
|
+
if (!result.ok) {
|
|
28
|
+
const status = result.error.type === "auth" ? 401 : 502;
|
|
29
|
+
return new Response(JSON.stringify({ error: result.error.message }), {
|
|
30
|
+
status,
|
|
31
|
+
headers: { "Content-Type": "application/json" }
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return new Response(JSON.stringify({ repos: result.value }), {
|
|
35
|
+
status: 200,
|
|
36
|
+
headers: { "Content-Type": "application/json" }
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
export {
|
|
40
|
+
GET
|
|
41
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { APIRoute } from 'astro';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Setup-Wizard: GitHub App Integration
|
|
5
|
+
*
|
|
6
|
+
* GET /api/setzkasten/setup/github-app – Status abfragen
|
|
7
|
+
* POST /api/setzkasten/setup/github-app – Verbindung testen
|
|
8
|
+
*
|
|
9
|
+
* Credentials werden NICHT persistiert – der Nutzer setzt die env vars manuell.
|
|
10
|
+
* Der POST-Endpunkt validiert die Verbindung durch einen echten Token-Request.
|
|
11
|
+
*/
|
|
12
|
+
declare const GET: APIRoute;
|
|
13
|
+
declare const POST: APIRoute;
|
|
14
|
+
|
|
15
|
+
export { GET, POST };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/api-routes/setup-github-app.ts
|
|
2
|
+
import { GitHubAppClient } from "@setzkasten-cms/github-adapter";
|
|
3
|
+
var GET = async () => {
|
|
4
|
+
const appId = process.env.GITHUB_APP_ID;
|
|
5
|
+
const privateKey = process.env.GITHUB_APP_PRIVATE_KEY;
|
|
6
|
+
const installationId = process.env.GITHUB_APP_INSTALLATION_ID;
|
|
7
|
+
const configured = Boolean(appId && privateKey && installationId);
|
|
8
|
+
return Response.json({ configured, ...configured ? { appId } : {} });
|
|
9
|
+
};
|
|
10
|
+
var POST = async ({ request }) => {
|
|
11
|
+
let body;
|
|
12
|
+
try {
|
|
13
|
+
body = await request.json();
|
|
14
|
+
} catch {
|
|
15
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
16
|
+
}
|
|
17
|
+
const { appId, privateKey, installationId } = body ?? {};
|
|
18
|
+
if (!appId || !privateKey || !installationId) {
|
|
19
|
+
return Response.json(
|
|
20
|
+
{ error: "appId, privateKey and installationId are required" },
|
|
21
|
+
{ status: 400 }
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
const client = new GitHubAppClient(
|
|
25
|
+
{
|
|
26
|
+
appId: String(appId),
|
|
27
|
+
privateKey: String(privateKey),
|
|
28
|
+
installationId: String(installationId)
|
|
29
|
+
},
|
|
30
|
+
{ owner: "", repo: "", branch: "" }
|
|
31
|
+
);
|
|
32
|
+
const result = await client.getInstallationToken();
|
|
33
|
+
if (!result.ok) {
|
|
34
|
+
return Response.json({ ok: false, error: result.error.message }, { status: 400 });
|
|
35
|
+
}
|
|
36
|
+
return Response.json({ ok: true });
|
|
37
|
+
};
|
|
38
|
+
export {
|
|
39
|
+
GET,
|
|
40
|
+
POST
|
|
41
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// src/api-routes/updater-check.ts
|
|
2
|
+
var GET = async ({ cookies, url }) => {
|
|
3
|
+
const session = cookies.get("setzkasten_session")?.value;
|
|
4
|
+
if (!session) {
|
|
5
|
+
return new Response("Unauthorized", { status: 401 });
|
|
6
|
+
}
|
|
7
|
+
const config = globalThis.__SETZKASTEN_CONFIG__;
|
|
8
|
+
const updaterUrl = config?.updaterUrl;
|
|
9
|
+
if (!updaterUrl) {
|
|
10
|
+
return Response.json({
|
|
11
|
+
updateAvailable: false,
|
|
12
|
+
latestVersion: config?.version ?? "unknown",
|
|
13
|
+
releaseNotesUrl: ""
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
const instanceId = url.searchParams.get("instanceId") ?? "";
|
|
17
|
+
try {
|
|
18
|
+
const response = await fetch(
|
|
19
|
+
`${updaterUrl}/api/check-update?instanceId=${encodeURIComponent(instanceId)}`,
|
|
20
|
+
{ signal: AbortSignal.timeout(5e3) }
|
|
21
|
+
);
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
throw new Error(`HTTP ${response.status}`);
|
|
24
|
+
}
|
|
25
|
+
const data = await response.json();
|
|
26
|
+
return Response.json(data);
|
|
27
|
+
} catch {
|
|
28
|
+
return Response.json({
|
|
29
|
+
updateAvailable: false,
|
|
30
|
+
latestVersion: config?.version ?? "unknown",
|
|
31
|
+
releaseNotesUrl: ""
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
export {
|
|
36
|
+
GET
|
|
37
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { APIRoute } from 'astro';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Registers this Setzkasten instance with the central updater backend.
|
|
5
|
+
* Called on every Dashboard load. Returns update status and license tier.
|
|
6
|
+
*
|
|
7
|
+
* POST /api/setzkasten/updater/register
|
|
8
|
+
*
|
|
9
|
+
* Body (optional — for UI activation flow):
|
|
10
|
+
* { licenseEmail: string, licenseKey: string }
|
|
11
|
+
*/
|
|
12
|
+
declare const POST: APIRoute;
|
|
13
|
+
|
|
14
|
+
export { POST };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// src/api-routes/updater-register.ts
|
|
2
|
+
var POST = async ({ cookies, request }) => {
|
|
3
|
+
const session = cookies.get("setzkasten_session")?.value;
|
|
4
|
+
if (!session) {
|
|
5
|
+
return new Response("Unauthorized", { status: 401 });
|
|
6
|
+
}
|
|
7
|
+
const buildConfig = typeof __SETZKASTEN_BUILD_CONFIG__ !== "undefined" ? __SETZKASTEN_BUILD_CONFIG__ : null;
|
|
8
|
+
const runtimeConfig = globalThis.__SETZKASTEN_CONFIG__;
|
|
9
|
+
const config = runtimeConfig ?? buildConfig;
|
|
10
|
+
const currentVersion = config?.version ?? "0.0.0";
|
|
11
|
+
const updaterUrl = config?.updaterUrl;
|
|
12
|
+
if (!updaterUrl) {
|
|
13
|
+
return Response.json({
|
|
14
|
+
instanceId: null,
|
|
15
|
+
updateAvailable: false,
|
|
16
|
+
currentVersion,
|
|
17
|
+
latestVersion: null,
|
|
18
|
+
releaseNotesUrl: "",
|
|
19
|
+
licenseTier: "free",
|
|
20
|
+
licenseValid: false
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const owner = config?.storage?.owner ?? "";
|
|
24
|
+
const repo = config?.storage?.repo ?? "";
|
|
25
|
+
const repoUrl = owner && repo ? `${owner}/${repo}` : "";
|
|
26
|
+
const websiteUrl = config?.websiteUrl ?? "";
|
|
27
|
+
let licenseEmail;
|
|
28
|
+
let licenseKey;
|
|
29
|
+
try {
|
|
30
|
+
if (request.headers.get("content-type")?.includes("application/json")) {
|
|
31
|
+
const parsed = await request.json();
|
|
32
|
+
licenseEmail = parsed.licenseEmail?.trim() || void 0;
|
|
33
|
+
licenseKey = parsed.licenseKey?.trim() || void 0;
|
|
34
|
+
}
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const response = await fetch(`${updaterUrl}/api/register`, {
|
|
39
|
+
method: "POST",
|
|
40
|
+
headers: { "Content-Type": "application/json" },
|
|
41
|
+
body: JSON.stringify({
|
|
42
|
+
repoUrl,
|
|
43
|
+
websiteUrl,
|
|
44
|
+
currentVersion,
|
|
45
|
+
licenseEmail,
|
|
46
|
+
licenseKey,
|
|
47
|
+
telemetryEnabled: true,
|
|
48
|
+
managedWebsites: []
|
|
49
|
+
}),
|
|
50
|
+
signal: AbortSignal.timeout(5e3)
|
|
51
|
+
});
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
throw new Error(`HTTP ${response.status}`);
|
|
54
|
+
}
|
|
55
|
+
const data = await response.json();
|
|
56
|
+
return Response.json({ ...data, currentVersion, _firebaseConfig: data.firebaseConfig ?? null });
|
|
57
|
+
} catch {
|
|
58
|
+
return Response.json({
|
|
59
|
+
instanceId: null,
|
|
60
|
+
updateAvailable: false,
|
|
61
|
+
currentVersion,
|
|
62
|
+
latestVersion: null,
|
|
63
|
+
releaseNotesUrl: "",
|
|
64
|
+
licenseTier: "free",
|
|
65
|
+
licenseValid: false
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
export {
|
|
70
|
+
POST
|
|
71
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { APIRoute } from 'astro';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Transfer a license to the current Setzkasten instance.
|
|
5
|
+
* The backend identifies the license by instanceId (computed from repoUrl + websiteUrl).
|
|
6
|
+
*
|
|
7
|
+
* POST /api/setzkasten/updater/transfer
|
|
8
|
+
*/
|
|
9
|
+
declare const POST: APIRoute;
|
|
10
|
+
|
|
11
|
+
export { POST };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// src/api-routes/updater-transfer.ts
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
var POST = async ({ cookies }) => {
|
|
4
|
+
const session = cookies.get("setzkasten_session")?.value;
|
|
5
|
+
if (!session) {
|
|
6
|
+
return new Response("Unauthorized", { status: 401 });
|
|
7
|
+
}
|
|
8
|
+
const config = globalThis.__SETZKASTEN_CONFIG__;
|
|
9
|
+
const updaterUrl = config?.updaterUrl;
|
|
10
|
+
if (!updaterUrl) {
|
|
11
|
+
return Response.json({ error: "Updater not configured" }, { status: 400 });
|
|
12
|
+
}
|
|
13
|
+
const owner = config?.storage?.owner ?? "";
|
|
14
|
+
const repo = config?.storage?.repo ?? "";
|
|
15
|
+
const repoUrl = owner && repo ? `${owner}/${repo}` : "";
|
|
16
|
+
const websiteUrl = config?.websiteUrl ?? "";
|
|
17
|
+
const raw = (repoUrl || "unknown") + "|" + (websiteUrl || "unknown");
|
|
18
|
+
const instanceId = createHash("sha256").update(raw).digest("hex").slice(0, 32);
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch(`${updaterUrl}/api/transfer`, {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: { "Content-Type": "application/json" },
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
toInstanceId: instanceId,
|
|
25
|
+
toWebsiteUrl: websiteUrl
|
|
26
|
+
}),
|
|
27
|
+
signal: AbortSignal.timeout(5e3)
|
|
28
|
+
});
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
return Response.json(data, { status: response.status });
|
|
31
|
+
} catch {
|
|
32
|
+
return Response.json({ error: "Transfer failed" }, { status: 500 });
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
export {
|
|
36
|
+
POST
|
|
37
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { APIRoute } from 'astro';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Release the license binding for this Setzkasten instance.
|
|
5
|
+
*
|
|
6
|
+
* POST /api/setzkasten/updater/unbind
|
|
7
|
+
*
|
|
8
|
+
* Reads license credentials from either:
|
|
9
|
+
* 1. `setzkasten.config.ts` → license.{email,key}
|
|
10
|
+
* 2. Request body (UI removal flow): { licenseEmail, licenseKey }
|
|
11
|
+
*
|
|
12
|
+
* On success, Firebase clears `instance.licenseKey` and removes this
|
|
13
|
+
* instance from `license.boundTo` / `license.boundInstances`.
|
|
14
|
+
*/
|
|
15
|
+
declare const POST: APIRoute;
|
|
16
|
+
|
|
17
|
+
export { POST };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// src/api-routes/updater-unbind.ts
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
var POST = async ({ cookies, request }) => {
|
|
4
|
+
const session = cookies.get("setzkasten_session")?.value;
|
|
5
|
+
if (!session) {
|
|
6
|
+
return new Response("Unauthorized", { status: 401 });
|
|
7
|
+
}
|
|
8
|
+
const config = globalThis.__SETZKASTEN_CONFIG__;
|
|
9
|
+
const fullConfig = globalThis.__SETZKASTEN_FULL_CONFIG__;
|
|
10
|
+
const updaterUrl = config?.updaterUrl;
|
|
11
|
+
if (!updaterUrl) {
|
|
12
|
+
return Response.json({ error: "Updater not configured" }, { status: 400 });
|
|
13
|
+
}
|
|
14
|
+
const owner = config?.storage?.owner ?? "";
|
|
15
|
+
const repo = config?.storage?.repo ?? "";
|
|
16
|
+
const repoUrl = owner && repo ? `${owner}/${repo}` : "";
|
|
17
|
+
const websiteUrl = config?.websiteUrl ?? "";
|
|
18
|
+
const raw = (repoUrl || "unknown") + "|" + (websiteUrl || "unknown");
|
|
19
|
+
const instanceId = createHash("sha256").update(raw).digest("hex").slice(0, 32);
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch(`${updaterUrl}/api/unbind`, {
|
|
22
|
+
method: "POST",
|
|
23
|
+
headers: { "Content-Type": "application/json" },
|
|
24
|
+
body: JSON.stringify({ instanceId }),
|
|
25
|
+
signal: AbortSignal.timeout(5e3)
|
|
26
|
+
});
|
|
27
|
+
const data = await response.json();
|
|
28
|
+
return Response.json(data, { status: response.status });
|
|
29
|
+
} catch {
|
|
30
|
+
return Response.json({ error: "Unbind failed" }, { status: 500 });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
export {
|
|
34
|
+
POST
|
|
35
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { APIRoute } from 'astro';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GET /api/setzkasten/webhooks/status
|
|
5
|
+
*
|
|
6
|
+
* Returns the in-memory status map (lastFiredAt + lastStatus per webhook
|
|
7
|
+
* id). Empty for cold-started instances; the UI handles that gracefully
|
|
8
|
+
* with "noch nie gefeuert".
|
|
9
|
+
*/
|
|
10
|
+
declare const GET: APIRoute;
|
|
11
|
+
|
|
12
|
+
export { GET };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getWebhookStatus
|
|
3
|
+
} from "../chunk-W3QHY5GW.js";
|
|
4
|
+
import {
|
|
5
|
+
requireAdmin
|
|
6
|
+
} from "../chunk-INIWFKQ3.js";
|
|
7
|
+
import "../chunk-6UIKVKED.js";
|
|
8
|
+
import "../chunk-5PIMDP4N.js";
|
|
9
|
+
import "../chunk-45ARVNT3.js";
|
|
10
|
+
import "../chunk-NKDATSPA.js";
|
|
11
|
+
import "../chunk-TJNJKPUL.js";
|
|
12
|
+
import "../chunk-KH22FJO5.js";
|
|
13
|
+
|
|
14
|
+
// src/api-routes/webhooks-status.ts
|
|
15
|
+
var GET = async ({ cookies }) => {
|
|
16
|
+
const denied = requireAdmin(cookies.get("setzkasten_session")?.value);
|
|
17
|
+
if (denied) return denied;
|
|
18
|
+
return Response.json({ status: getWebhookStatus() });
|
|
19
|
+
};
|
|
20
|
+
export {
|
|
21
|
+
GET
|
|
22
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { APIRoute } from 'astro';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* POST /api/setzkasten/webhooks/test
|
|
5
|
+
* Body: { id: string }
|
|
6
|
+
*
|
|
7
|
+
* Fires a synthetic test payload at the configured URL and returns
|
|
8
|
+
* { ok, status, latencyMs }. Admin-only, Pro-gated. Used by the UI
|
|
9
|
+
* "Test-Fire"-Button to verify a webhook config end-to-end.
|
|
10
|
+
*/
|
|
11
|
+
declare const POST: APIRoute;
|
|
12
|
+
|
|
13
|
+
export { POST };
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
signPayload
|
|
3
|
+
} from "../chunk-737TIZRU.js";
|
|
4
|
+
import {
|
|
5
|
+
recordWebhookFire
|
|
6
|
+
} from "../chunk-W3QHY5GW.js";
|
|
7
|
+
import {
|
|
8
|
+
parseSession,
|
|
9
|
+
requireAdmin
|
|
10
|
+
} from "../chunk-INIWFKQ3.js";
|
|
11
|
+
import {
|
|
12
|
+
resolveStorageConfigForRequest
|
|
13
|
+
} from "../chunk-6UIKVKED.js";
|
|
14
|
+
import {
|
|
15
|
+
gateFeature
|
|
16
|
+
} from "../chunk-5PIMDP4N.js";
|
|
17
|
+
import "../chunk-45ARVNT3.js";
|
|
18
|
+
import {
|
|
19
|
+
resolveGitHubTokenForRequest
|
|
20
|
+
} from "../chunk-NKDATSPA.js";
|
|
21
|
+
import "../chunk-TJNJKPUL.js";
|
|
22
|
+
import "../chunk-KH22FJO5.js";
|
|
23
|
+
|
|
24
|
+
// src/api-routes/webhooks-test.ts
|
|
25
|
+
import {
|
|
26
|
+
parseWebhooksFile
|
|
27
|
+
} from "@setzkasten-cms/core";
|
|
28
|
+
var WEBHOOKS_FILE = (contentPath) => `${contentPath}/_webhooks.json`;
|
|
29
|
+
var TEST_TIMEOUT_MS = 1e4;
|
|
30
|
+
var POST = async ({ request, cookies }) => {
|
|
31
|
+
const denied = requireAdmin(cookies.get("setzkasten_session")?.value);
|
|
32
|
+
if (denied) return denied;
|
|
33
|
+
const gate = gateFeature("webhooks");
|
|
34
|
+
if (gate) return gate;
|
|
35
|
+
const session = parseSession(cookies.get("setzkasten_session")?.value);
|
|
36
|
+
if (!session) return new Response("Unauthorized", { status: 401 });
|
|
37
|
+
let body;
|
|
38
|
+
try {
|
|
39
|
+
body = await request.json();
|
|
40
|
+
} catch {
|
|
41
|
+
return Response.json({ error: "Invalid JSON" }, { status: 400 });
|
|
42
|
+
}
|
|
43
|
+
if (!body.id) {
|
|
44
|
+
return Response.json({ error: "id is required" }, { status: 400 });
|
|
45
|
+
}
|
|
46
|
+
const tokenResult = await resolveGitHubTokenForRequest(request);
|
|
47
|
+
if (!tokenResult.ok) return new Response(tokenResult.error.message, { status: 500 });
|
|
48
|
+
const storage = await resolveStorageConfigForRequest(request);
|
|
49
|
+
if (!storage) {
|
|
50
|
+
return Response.json({ error: "Could not resolve owner/repo" }, { status: 400 });
|
|
51
|
+
}
|
|
52
|
+
const { owner, repo, branch } = storage;
|
|
53
|
+
const serverConfig = globalThis.__SETZKASTEN_CONFIG__;
|
|
54
|
+
const contentPath = serverConfig?.storage?.contentPath ?? "content";
|
|
55
|
+
const fileRes = await fetch(
|
|
56
|
+
`https://api.github.com/repos/${owner}/${repo}/contents/${WEBHOOKS_FILE(contentPath)}?ref=${branch}`,
|
|
57
|
+
{
|
|
58
|
+
headers: {
|
|
59
|
+
Authorization: `Bearer ${tokenResult.value}`,
|
|
60
|
+
Accept: "application/vnd.github+json",
|
|
61
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
if (fileRes.status === 404) {
|
|
66
|
+
return Response.json({ error: "No webhooks configured" }, { status: 404 });
|
|
67
|
+
}
|
|
68
|
+
if (!fileRes.ok) {
|
|
69
|
+
return Response.json({ error: "Could not read webhooks file" }, { status: 502 });
|
|
70
|
+
}
|
|
71
|
+
const data = await fileRes.json();
|
|
72
|
+
const raw = data.encoding === "base64" ? Buffer.from(data.content, "base64").toString("utf-8") : data.content;
|
|
73
|
+
const parsed = parseWebhooksFile(raw);
|
|
74
|
+
if (!parsed.ok) {
|
|
75
|
+
return Response.json({ error: "Webhooks file is malformed" }, { status: 502 });
|
|
76
|
+
}
|
|
77
|
+
const target = parsed.value.webhooks.find((w) => w.id === body.id);
|
|
78
|
+
if (!target) {
|
|
79
|
+
return Response.json({ error: `Webhook "${body.id}" not found` }, { status: 404 });
|
|
80
|
+
}
|
|
81
|
+
const payload = {
|
|
82
|
+
event: "content.save",
|
|
83
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
84
|
+
website: { id: owner, repo: `${owner}/${repo}`, branch },
|
|
85
|
+
user: { email: session.user.email, name: session.user.name },
|
|
86
|
+
commit: { sha: "0".repeat(40), message: "test webhook fire" },
|
|
87
|
+
files: [],
|
|
88
|
+
test: true
|
|
89
|
+
};
|
|
90
|
+
const payloadBody = JSON.stringify(payload);
|
|
91
|
+
const headers = {
|
|
92
|
+
"Content-Type": "application/json",
|
|
93
|
+
"X-Setzkasten-Event": "content.save",
|
|
94
|
+
"X-Setzkasten-Delivery": crypto.randomUUID(),
|
|
95
|
+
"X-Setzkasten-Test": "true"
|
|
96
|
+
};
|
|
97
|
+
if (target.secret) {
|
|
98
|
+
headers["X-Setzkasten-Signature"] = `sha256=${signPayload(payloadBody, target.secret)}`;
|
|
99
|
+
}
|
|
100
|
+
const startedAt = Date.now();
|
|
101
|
+
try {
|
|
102
|
+
const res = await fetch(target.url, {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers,
|
|
105
|
+
body: payloadBody,
|
|
106
|
+
signal: AbortSignal.timeout(TEST_TIMEOUT_MS)
|
|
107
|
+
});
|
|
108
|
+
const latencyMs = Date.now() - startedAt;
|
|
109
|
+
recordWebhookFire(target.id, res.status);
|
|
110
|
+
return Response.json({ ok: res.ok, status: res.status, latencyMs });
|
|
111
|
+
} catch (err) {
|
|
112
|
+
const latencyMs = Date.now() - startedAt;
|
|
113
|
+
recordWebhookFire(target.id, "error");
|
|
114
|
+
return Response.json({
|
|
115
|
+
ok: false,
|
|
116
|
+
status: "error",
|
|
117
|
+
latencyMs,
|
|
118
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
export {
|
|
123
|
+
POST
|
|
124
|
+
};
|