@webmaster-droid/server 0.1.0 → 0.2.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.
@@ -28,6 +28,11 @@ interface AgentRunnerResult {
28
28
  }>;
29
29
  updatedDraft: CmsDocument;
30
30
  mutationsApplied: boolean;
31
+ mutationSummary?: {
32
+ contentOperations: number;
33
+ themeTokenChanges: number;
34
+ imageOperations: number;
35
+ };
31
36
  }
32
37
  declare const STATIC_TOOL_NAMES: readonly ["patch_content", "patch_theme_tokens", "get_page", "get_section", "search_content", "generate_image"];
33
38
  type StaticToolName = (typeof STATIC_TOOL_NAMES)[number];
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  listStaticToolNames,
3
3
  runAgentTurn
4
- } from "../chunk-IK36OUJQ.js";
4
+ } from "../chunk-PS4GESOZ.js";
5
5
  import "../chunk-EYY23AAK.js";
6
6
  export {
7
7
  listStaticToolNames,
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  handler,
3
3
  streamHandler
4
- } from "../chunk-6RB7H6PA.js";
5
- import "../chunk-IK36OUJQ.js";
4
+ } from "../chunk-6M55DMUE.js";
5
+ import "../chunk-SIXK4BMG.js";
6
+ import "../chunk-PS4GESOZ.js";
6
7
  import "../chunk-EYY23AAK.js";
7
8
  import "../chunk-MLID7STX.js";
8
9
  export {
@@ -0,0 +1,3 @@
1
+ declare function handler(request: Request): Promise<Response>;
2
+
3
+ export { handler as default, handler };
@@ -0,0 +1,12 @@
1
+ import {
2
+ api_supabase_default,
3
+ handler
4
+ } from "../chunk-JIGCFERP.js";
5
+ import "../chunk-SIXK4BMG.js";
6
+ import "../chunk-PS4GESOZ.js";
7
+ import "../chunk-EYY23AAK.js";
8
+ import "../chunk-OWXROQ4O.js";
9
+ export {
10
+ api_supabase_default as default,
11
+ handler
12
+ };
@@ -1,6 +1,11 @@
1
+ import {
2
+ getBearerToken,
3
+ normalizeEditablePath,
4
+ verifyAdminToken
5
+ } from "./chunk-SIXK4BMG.js";
1
6
  import {
2
7
  runAgentTurn
3
- } from "./chunk-IK36OUJQ.js";
8
+ } from "./chunk-PS4GESOZ.js";
4
9
  import {
5
10
  CmsService
6
11
  } from "./chunk-EYY23AAK.js";
@@ -8,122 +13,6 @@ import {
8
13
  S3CmsStorage
9
14
  } from "./chunk-MLID7STX.js";
10
15
 
11
- // src/api-aws/auth.ts
12
- import { createRemoteJWKSet, decodeProtectedHeader, jwtVerify } from "jose";
13
- var jwksCache = null;
14
- function getJwks() {
15
- const jwksUrl = process.env.SUPABASE_JWKS_URL;
16
- if (!jwksUrl) {
17
- throw new Error("SUPABASE_JWKS_URL is not configured");
18
- }
19
- if (!jwksCache) {
20
- jwksCache = createRemoteJWKSet(new URL(jwksUrl));
21
- }
22
- return jwksCache;
23
- }
24
- function buildSupabaseUserEndpoint() {
25
- const explicitBaseUrl = process.env.SUPABASE_URL?.trim();
26
- if (explicitBaseUrl) {
27
- return `${explicitBaseUrl.replace(/\/$/, "")}/auth/v1/user`;
28
- }
29
- const jwksUrl = process.env.SUPABASE_JWKS_URL?.trim();
30
- if (!jwksUrl) {
31
- throw new Error("SUPABASE_JWKS_URL is not configured");
32
- }
33
- const parsed = new URL(jwksUrl);
34
- return `${parsed.origin}/auth/v1/user`;
35
- }
36
- function getSupabaseAnonKey() {
37
- const key = process.env.SUPABASE_ANON_KEY?.trim() ?? process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY?.trim();
38
- if (!key) {
39
- throw new Error("SUPABASE_ANON_KEY is required for HS256 token verification fallback.");
40
- }
41
- return key;
42
- }
43
- async function verifyHs256ViaSupabase(token) {
44
- const response = await fetch(buildSupabaseUserEndpoint(), {
45
- method: "GET",
46
- headers: {
47
- authorization: `Bearer ${token}`,
48
- apikey: getSupabaseAnonKey()
49
- }
50
- });
51
- if (!response.ok) {
52
- const detail = await response.text();
53
- throw new Error(`Supabase token verification failed: ${response.status} ${detail}`);
54
- }
55
- const user = await response.json();
56
- const sub = typeof user.id === "string" ? user.id : "";
57
- if (!sub) {
58
- throw new Error("Supabase token verification returned no user id.");
59
- }
60
- return {
61
- sub,
62
- email: typeof user.email === "string" ? user.email : void 0,
63
- role: typeof user.role === "string" ? user.role : void 0
64
- };
65
- }
66
- function getBearerToken(headers) {
67
- const value = headers.authorization ?? headers.Authorization;
68
- if (!value) {
69
- return null;
70
- }
71
- const [prefix, token] = value.split(" ");
72
- if (prefix?.toLowerCase() !== "bearer" || !token) {
73
- return null;
74
- }
75
- return token;
76
- }
77
- async function verifyAdminToken(token) {
78
- const header = decodeProtectedHeader(token);
79
- const algorithm = typeof header.alg === "string" ? header.alg : "";
80
- if (algorithm === "HS256") {
81
- const secret = process.env.SUPABASE_JWT_SECRET?.trim();
82
- if (secret) {
83
- const result2 = await jwtVerify(token, new TextEncoder().encode(secret), {
84
- algorithms: ["HS256"]
85
- });
86
- const payload2 = result2.payload;
87
- const identity3 = {
88
- sub: String(payload2.sub ?? ""),
89
- email: typeof payload2.email === "string" ? payload2.email : void 0,
90
- role: typeof payload2.role === "string" ? payload2.role : typeof payload2.user_role === "string" ? payload2.user_role : void 0
91
- };
92
- if (!identity3.sub) {
93
- throw new Error("Invalid token: subject is missing.");
94
- }
95
- const enforcedAdminEmail3 = process.env.ADMIN_EMAIL;
96
- if (enforcedAdminEmail3 && identity3.email?.toLowerCase() !== enforcedAdminEmail3.toLowerCase()) {
97
- throw new Error("Authenticated user is not allowed for admin access.");
98
- }
99
- return identity3;
100
- }
101
- const identity2 = await verifyHs256ViaSupabase(token);
102
- const enforcedAdminEmail2 = process.env.ADMIN_EMAIL;
103
- if (enforcedAdminEmail2 && identity2.email?.toLowerCase() !== enforcedAdminEmail2.toLowerCase()) {
104
- throw new Error("Authenticated user is not allowed for admin access.");
105
- }
106
- return identity2;
107
- }
108
- const result = await jwtVerify(token, getJwks(), {
109
- algorithms: ["RS256", "ES256"]
110
- });
111
- const payload = result.payload;
112
- const identity = {
113
- sub: String(payload.sub ?? ""),
114
- email: typeof payload.email === "string" ? payload.email : void 0,
115
- role: typeof payload.role === "string" ? payload.role : typeof payload.user_role === "string" ? payload.user_role : void 0
116
- };
117
- if (!identity.sub) {
118
- throw new Error("Invalid token: subject is missing.");
119
- }
120
- const enforcedAdminEmail = process.env.ADMIN_EMAIL;
121
- if (enforcedAdminEmail && identity.email?.toLowerCase() !== enforcedAdminEmail.toLowerCase()) {
122
- throw new Error("Authenticated user is not allowed for admin access.");
123
- }
124
- return identity;
125
- }
126
-
127
16
  // src/api-aws/http.ts
128
17
  function jsonResponse(statusCode, body) {
129
18
  return {
@@ -168,23 +57,6 @@ function normalizePath(path) {
168
57
  return path.replace(/\/+$/, "") || "/";
169
58
  }
170
59
 
171
- // src/api-aws/normalize-editable-path.ts
172
- var EDITABLE_ROOTS = ["pages.", "layout.", "seo.", "themeTokens."];
173
- var MAX_PATH_LENGTH = 320;
174
- function normalizeEditablePath(value) {
175
- if (typeof value !== "string") {
176
- return null;
177
- }
178
- const trimmed = value.trim();
179
- if (!trimmed || trimmed.length > MAX_PATH_LENGTH) {
180
- return null;
181
- }
182
- if (!EDITABLE_ROOTS.some((prefix) => trimmed.startsWith(prefix))) {
183
- return null;
184
- }
185
- return trimmed;
186
- }
187
-
188
60
  // src/api-aws/service-factory.ts
189
61
  import {
190
62
  createDefaultCmsDocument
@@ -314,6 +186,17 @@ function buildAvailableModels(config) {
314
186
  }
315
187
  return Array.from(options.values());
316
188
  }
189
+ function buildModelCapabilities(input) {
190
+ const hasReadableModel = input.availableModels.length > 0;
191
+ const hasImagePipeline = input.config.geminiEnabled && input.hasPublicAssetBaseUrl;
192
+ return {
193
+ contentEdit: hasReadableModel,
194
+ themeTokenEdit: hasReadableModel,
195
+ imageGenerate: hasImagePipeline,
196
+ imageEdit: hasImagePipeline,
197
+ visionAssist: hasReadableModel
198
+ };
199
+ }
317
200
  function resolveDefaultModelId(config, availableModels) {
318
201
  const requestedDefault = config.defaultModelId.trim();
319
202
  if (availableModels.some((model) => model.id === requestedDefault)) {
@@ -472,11 +355,17 @@ async function handler(event) {
472
355
  const config = service.getModelConfig();
473
356
  const availableModels = buildAvailableModels(config);
474
357
  const defaultModelId = resolveDefaultModelId(config, availableModels);
358
+ const capabilities = buildModelCapabilities({
359
+ config,
360
+ availableModels,
361
+ hasPublicAssetBaseUrl: Boolean(service.getPublicAssetBaseUrl())
362
+ });
475
363
  return jsonResponse(200, {
476
364
  providers: {
477
365
  openai: config.openaiEnabled,
478
366
  gemini: config.geminiEnabled
479
367
  },
368
+ capabilities,
480
369
  defaultModelId,
481
370
  showModelPicker: availableModels.length > 1,
482
371
  availableModels
@@ -564,7 +453,12 @@ async function handler(event) {
564
453
  event: "draft-updated",
565
454
  data: {
566
455
  contentVersion: result.updatedDraft.meta.contentVersion,
567
- updatedAt: result.updatedDraft.meta.updatedAt
456
+ updatedAt: result.updatedDraft.meta.updatedAt,
457
+ summary: result.mutationSummary ?? {
458
+ contentOperations: 0,
459
+ themeTokenChanges: 0,
460
+ imageOperations: 0
461
+ }
568
462
  }
569
463
  });
570
464
  }
@@ -641,7 +535,12 @@ var streamHandler = awslambda.streamifyResponse(
641
535
  if (result.mutationsApplied) {
642
536
  write("draft-updated", {
643
537
  contentVersion: result.updatedDraft.meta.contentVersion,
644
- updatedAt: result.updatedDraft.meta.updatedAt
538
+ updatedAt: result.updatedDraft.meta.updatedAt,
539
+ summary: result.mutationSummary ?? {
540
+ contentOperations: 0,
541
+ themeTokenChanges: 0,
542
+ imageOperations: 0
543
+ }
645
544
  });
646
545
  }
647
546
  write("done", { ok: true });