@webmaster-droid/server 0.1.0-alpha.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.
- package/dist/agent/SOUL.md +36 -0
- package/dist/agent/index.d.ts +5 -0
- package/dist/agent/index.js +2 -2
- package/dist/api-aws/index.js +4 -3
- package/dist/api-supabase/index.d.ts +3 -0
- package/dist/api-supabase/index.js +12 -0
- package/dist/{chunk-5CVLHGGO.js → chunk-6M55DMUE.js} +44 -151
- package/dist/{chunk-2LAI3MY2.js → chunk-EYY23AAK.js} +1 -0
- package/dist/chunk-JIGCFERP.js +509 -0
- package/dist/chunk-OWXROQ4O.js +416 -0
- package/dist/{chunk-X6TU47KZ.js → chunk-PS4GESOZ.js} +850 -793
- package/dist/chunk-SIXK4BMG.js +138 -0
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.js +3 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +14 -3
- package/dist/storage-supabase/index.d.ts +50 -0
- package/dist/storage-supabase/index.js +6 -0
- package/package.json +14 -4
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// src/api-aws/auth.ts
|
|
2
|
+
import { createRemoteJWKSet, decodeProtectedHeader, jwtVerify } from "jose";
|
|
3
|
+
var jwksCache = null;
|
|
4
|
+
function getJwks() {
|
|
5
|
+
const jwksUrl = process.env.SUPABASE_JWKS_URL;
|
|
6
|
+
if (!jwksUrl) {
|
|
7
|
+
throw new Error("SUPABASE_JWKS_URL is not configured");
|
|
8
|
+
}
|
|
9
|
+
if (!jwksCache) {
|
|
10
|
+
jwksCache = createRemoteJWKSet(new URL(jwksUrl));
|
|
11
|
+
}
|
|
12
|
+
return jwksCache;
|
|
13
|
+
}
|
|
14
|
+
function buildSupabaseUserEndpoint() {
|
|
15
|
+
const explicitBaseUrl = process.env.SUPABASE_URL?.trim();
|
|
16
|
+
if (explicitBaseUrl) {
|
|
17
|
+
return `${explicitBaseUrl.replace(/\/$/, "")}/auth/v1/user`;
|
|
18
|
+
}
|
|
19
|
+
const jwksUrl = process.env.SUPABASE_JWKS_URL?.trim();
|
|
20
|
+
if (!jwksUrl) {
|
|
21
|
+
throw new Error("SUPABASE_JWKS_URL is not configured");
|
|
22
|
+
}
|
|
23
|
+
const parsed = new URL(jwksUrl);
|
|
24
|
+
return `${parsed.origin}/auth/v1/user`;
|
|
25
|
+
}
|
|
26
|
+
function getSupabaseAnonKey() {
|
|
27
|
+
const key = process.env.SUPABASE_ANON_KEY?.trim() ?? process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY?.trim();
|
|
28
|
+
if (!key) {
|
|
29
|
+
throw new Error("SUPABASE_ANON_KEY is required for HS256 token verification fallback.");
|
|
30
|
+
}
|
|
31
|
+
return key;
|
|
32
|
+
}
|
|
33
|
+
async function verifyHs256ViaSupabase(token) {
|
|
34
|
+
const response = await fetch(buildSupabaseUserEndpoint(), {
|
|
35
|
+
method: "GET",
|
|
36
|
+
headers: {
|
|
37
|
+
authorization: `Bearer ${token}`,
|
|
38
|
+
apikey: getSupabaseAnonKey()
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
const detail = await response.text();
|
|
43
|
+
throw new Error(`Supabase token verification failed: ${response.status} ${detail}`);
|
|
44
|
+
}
|
|
45
|
+
const user = await response.json();
|
|
46
|
+
const sub = typeof user.id === "string" ? user.id : "";
|
|
47
|
+
if (!sub) {
|
|
48
|
+
throw new Error("Supabase token verification returned no user id.");
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
sub,
|
|
52
|
+
email: typeof user.email === "string" ? user.email : void 0,
|
|
53
|
+
role: typeof user.role === "string" ? user.role : void 0
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function getBearerToken(headers) {
|
|
57
|
+
const value = headers.authorization ?? headers.Authorization;
|
|
58
|
+
if (!value) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const [prefix, token] = value.split(" ");
|
|
62
|
+
if (prefix?.toLowerCase() !== "bearer" || !token) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return token;
|
|
66
|
+
}
|
|
67
|
+
async function verifyAdminToken(token) {
|
|
68
|
+
const header = decodeProtectedHeader(token);
|
|
69
|
+
const algorithm = typeof header.alg === "string" ? header.alg : "";
|
|
70
|
+
if (algorithm === "HS256") {
|
|
71
|
+
const secret = process.env.SUPABASE_JWT_SECRET?.trim();
|
|
72
|
+
if (secret) {
|
|
73
|
+
const result2 = await jwtVerify(token, new TextEncoder().encode(secret), {
|
|
74
|
+
algorithms: ["HS256"]
|
|
75
|
+
});
|
|
76
|
+
const payload2 = result2.payload;
|
|
77
|
+
const identity3 = {
|
|
78
|
+
sub: String(payload2.sub ?? ""),
|
|
79
|
+
email: typeof payload2.email === "string" ? payload2.email : void 0,
|
|
80
|
+
role: typeof payload2.role === "string" ? payload2.role : typeof payload2.user_role === "string" ? payload2.user_role : void 0
|
|
81
|
+
};
|
|
82
|
+
if (!identity3.sub) {
|
|
83
|
+
throw new Error("Invalid token: subject is missing.");
|
|
84
|
+
}
|
|
85
|
+
const enforcedAdminEmail3 = process.env.ADMIN_EMAIL;
|
|
86
|
+
if (enforcedAdminEmail3 && identity3.email?.toLowerCase() !== enforcedAdminEmail3.toLowerCase()) {
|
|
87
|
+
throw new Error("Authenticated user is not allowed for admin access.");
|
|
88
|
+
}
|
|
89
|
+
return identity3;
|
|
90
|
+
}
|
|
91
|
+
const identity2 = await verifyHs256ViaSupabase(token);
|
|
92
|
+
const enforcedAdminEmail2 = process.env.ADMIN_EMAIL;
|
|
93
|
+
if (enforcedAdminEmail2 && identity2.email?.toLowerCase() !== enforcedAdminEmail2.toLowerCase()) {
|
|
94
|
+
throw new Error("Authenticated user is not allowed for admin access.");
|
|
95
|
+
}
|
|
96
|
+
return identity2;
|
|
97
|
+
}
|
|
98
|
+
const result = await jwtVerify(token, getJwks(), {
|
|
99
|
+
algorithms: ["RS256", "ES256"]
|
|
100
|
+
});
|
|
101
|
+
const payload = result.payload;
|
|
102
|
+
const identity = {
|
|
103
|
+
sub: String(payload.sub ?? ""),
|
|
104
|
+
email: typeof payload.email === "string" ? payload.email : void 0,
|
|
105
|
+
role: typeof payload.role === "string" ? payload.role : typeof payload.user_role === "string" ? payload.user_role : void 0
|
|
106
|
+
};
|
|
107
|
+
if (!identity.sub) {
|
|
108
|
+
throw new Error("Invalid token: subject is missing.");
|
|
109
|
+
}
|
|
110
|
+
const enforcedAdminEmail = process.env.ADMIN_EMAIL;
|
|
111
|
+
if (enforcedAdminEmail && identity.email?.toLowerCase() !== enforcedAdminEmail.toLowerCase()) {
|
|
112
|
+
throw new Error("Authenticated user is not allowed for admin access.");
|
|
113
|
+
}
|
|
114
|
+
return identity;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/api-aws/normalize-editable-path.ts
|
|
118
|
+
var EDITABLE_ROOTS = ["pages.", "layout.", "seo.", "themeTokens."];
|
|
119
|
+
var MAX_PATH_LENGTH = 320;
|
|
120
|
+
function normalizeEditablePath(value) {
|
|
121
|
+
if (typeof value !== "string") {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const trimmed = value.trim();
|
|
125
|
+
if (!trimmed || trimmed.length > MAX_PATH_LENGTH) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
if (!EDITABLE_ROOTS.some((prefix) => trimmed.startsWith(prefix))) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
return trimmed;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export {
|
|
135
|
+
getBearerToken,
|
|
136
|
+
verifyAdminToken,
|
|
137
|
+
normalizeEditablePath
|
|
138
|
+
};
|
package/dist/core/index.d.ts
CHANGED
|
@@ -3,8 +3,9 @@ export { A as AgentBatchMutationInput, a as AnyCmsDocument, C as CmsMutationInpu
|
|
|
3
3
|
import { CmsDocument, CmsPatch, ThemeTokenPatch } from '@webmaster-droid/contracts';
|
|
4
4
|
export { C as CmsService, c as createPatchFromAgentOperations, a as createThemePatchFromAgentOperations } from '../service-BYwdlvCI.js';
|
|
5
5
|
|
|
6
|
+
declare function readByPath(input: unknown, path: string): unknown;
|
|
6
7
|
declare function validatePatch(patch: CmsPatch, source: CmsDocument, options: PatchApplicationOptions): PatchValidationResult;
|
|
7
8
|
declare function applyPatch(source: CmsDocument, patch: CmsPatch, options: PatchApplicationOptions): PatchApplyResult;
|
|
8
9
|
declare function applyThemeTokenPatch(source: CmsDocument, patch: ThemeTokenPatch): ThemeApplyResult;
|
|
9
10
|
|
|
10
|
-
export { PatchApplicationOptions, PatchApplyResult, PatchValidationResult, ThemeApplyResult, applyPatch, applyThemeTokenPatch, validatePatch };
|
|
11
|
+
export { PatchApplicationOptions, PatchApplyResult, PatchValidationResult, ThemeApplyResult, applyPatch, applyThemeTokenPatch, readByPath, validatePatch };
|
package/dist/core/index.js
CHANGED
|
@@ -4,13 +4,15 @@ import {
|
|
|
4
4
|
applyThemeTokenPatch,
|
|
5
5
|
createPatchFromAgentOperations,
|
|
6
6
|
createThemePatchFromAgentOperations,
|
|
7
|
+
readByPath,
|
|
7
8
|
validatePatch
|
|
8
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-EYY23AAK.js";
|
|
9
10
|
export {
|
|
10
11
|
CmsService,
|
|
11
12
|
applyPatch,
|
|
12
13
|
applyThemeTokenPatch,
|
|
13
14
|
createPatchFromAgentOperations,
|
|
14
15
|
createThemePatchFromAgentOperations,
|
|
16
|
+
readByPath,
|
|
15
17
|
validatePatch
|
|
16
18
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export { A as AgentBatchMutationInput, a as AnyCmsDocument, C as CmsMutationInput, b as CmsServiceConfig, M as ModelAdapter, c as ModelAdapterInput, d as ModelAdapterOutput, e as MutationResult, P as PatchApplicationOptions, f as PatchApplyResult, g as PatchValidationResult, S as StorageAdapter, T as ThemeApplyResult, h as ThemeMutationInput, i as ThemeMutationResult, j as ToolRegistry } from './types-OKJgq7Oo.js';
|
|
2
|
-
export { applyPatch, applyThemeTokenPatch, validatePatch } from './core/index.js';
|
|
2
|
+
export { applyPatch, applyThemeTokenPatch, readByPath, validatePatch } from './core/index.js';
|
|
3
3
|
export { C as CmsService, c as createPatchFromAgentOperations, a as createThemePatchFromAgentOperations } from './service-BYwdlvCI.js';
|
|
4
4
|
export { S3CmsStorage } from './storage-s3/index.js';
|
|
5
|
+
export { SupabaseCmsStorage } from './storage-supabase/index.js';
|
|
5
6
|
export { AgentRunnerInput, AgentRunnerResult, StaticToolName, listStaticToolNames, runAgentTurn } from './agent/index.js';
|
|
6
7
|
export { handler, streamHandler } from './api-aws/index.js';
|
|
8
|
+
export { default as supabaseHandler } from './api-supabase/index.js';
|
|
7
9
|
import '@webmaster-droid/contracts';
|
|
8
10
|
import '@aws-sdk/client-s3';
|
|
11
|
+
import '@supabase/supabase-js';
|
|
9
12
|
import 'aws-lambda';
|
package/dist/index.js
CHANGED
|
@@ -1,32 +1,43 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handler,
|
|
3
3
|
streamHandler
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6M55DMUE.js";
|
|
5
|
+
import {
|
|
6
|
+
handler as handler2
|
|
7
|
+
} from "./chunk-JIGCFERP.js";
|
|
8
|
+
import "./chunk-SIXK4BMG.js";
|
|
5
9
|
import {
|
|
6
10
|
listStaticToolNames,
|
|
7
11
|
runAgentTurn
|
|
8
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PS4GESOZ.js";
|
|
9
13
|
import {
|
|
10
14
|
CmsService,
|
|
11
15
|
applyPatch,
|
|
12
16
|
applyThemeTokenPatch,
|
|
13
17
|
createPatchFromAgentOperations,
|
|
14
18
|
createThemePatchFromAgentOperations,
|
|
19
|
+
readByPath,
|
|
15
20
|
validatePatch
|
|
16
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-EYY23AAK.js";
|
|
17
22
|
import {
|
|
18
23
|
S3CmsStorage
|
|
19
24
|
} from "./chunk-MLID7STX.js";
|
|
25
|
+
import {
|
|
26
|
+
SupabaseCmsStorage
|
|
27
|
+
} from "./chunk-OWXROQ4O.js";
|
|
20
28
|
export {
|
|
21
29
|
CmsService,
|
|
22
30
|
S3CmsStorage,
|
|
31
|
+
SupabaseCmsStorage,
|
|
23
32
|
applyPatch,
|
|
24
33
|
applyThemeTokenPatch,
|
|
25
34
|
createPatchFromAgentOperations,
|
|
26
35
|
createThemePatchFromAgentOperations,
|
|
27
36
|
handler,
|
|
28
37
|
listStaticToolNames,
|
|
38
|
+
readByPath,
|
|
29
39
|
runAgentTurn,
|
|
30
40
|
streamHandler,
|
|
41
|
+
handler2 as supabaseHandler,
|
|
31
42
|
validatePatch
|
|
32
43
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
import { CmsDocument, CmsStage, CheckpointMeta, PublishedVersionMeta, RollbackRequest, AuditEvent } from '@webmaster-droid/contracts';
|
|
3
|
+
import { S as StorageAdapter } from '../types-OKJgq7Oo.js';
|
|
4
|
+
|
|
5
|
+
interface SupabaseCmsStorageOptions {
|
|
6
|
+
supabaseUrl: string;
|
|
7
|
+
serviceRoleKey: string;
|
|
8
|
+
bucket: string;
|
|
9
|
+
prefix?: string;
|
|
10
|
+
client?: SupabaseClient;
|
|
11
|
+
}
|
|
12
|
+
declare class SupabaseCmsStorage implements StorageAdapter {
|
|
13
|
+
private readonly bucket;
|
|
14
|
+
private readonly client;
|
|
15
|
+
private readonly prefix;
|
|
16
|
+
constructor(options: SupabaseCmsStorageOptions);
|
|
17
|
+
ensureInitialized(seed: CmsDocument): Promise<void>;
|
|
18
|
+
getContent(stage: CmsStage): Promise<CmsDocument>;
|
|
19
|
+
saveDraft(content: CmsDocument): Promise<void>;
|
|
20
|
+
saveLive(content: CmsDocument): Promise<void>;
|
|
21
|
+
putPublicAsset(input: {
|
|
22
|
+
key: string;
|
|
23
|
+
body: Uint8Array;
|
|
24
|
+
contentType: string;
|
|
25
|
+
cacheControl?: string;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
createCheckpoint(content: CmsDocument, input: {
|
|
28
|
+
createdBy?: string;
|
|
29
|
+
reason: string;
|
|
30
|
+
}): Promise<CheckpointMeta>;
|
|
31
|
+
deleteCheckpoint(id: string): Promise<boolean>;
|
|
32
|
+
listCheckpoints(): Promise<CheckpointMeta[]>;
|
|
33
|
+
publishDraft(input: {
|
|
34
|
+
content: CmsDocument;
|
|
35
|
+
createdBy?: string;
|
|
36
|
+
}): Promise<PublishedVersionMeta>;
|
|
37
|
+
listPublishedVersions(): Promise<PublishedVersionMeta[]>;
|
|
38
|
+
getSnapshot(input: RollbackRequest): Promise<CmsDocument | null>;
|
|
39
|
+
appendEvent(event: AuditEvent): Promise<void>;
|
|
40
|
+
private tryGetStage;
|
|
41
|
+
private saveStage;
|
|
42
|
+
private stageKey;
|
|
43
|
+
private putJson;
|
|
44
|
+
private listKeys;
|
|
45
|
+
private tryGetText;
|
|
46
|
+
private getText;
|
|
47
|
+
private isMissingObjectError;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { SupabaseCmsStorage };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webmaster-droid/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"types": "./dist/storage-s3/index.d.ts",
|
|
18
18
|
"import": "./dist/storage-s3/index.js"
|
|
19
19
|
},
|
|
20
|
+
"./storage-supabase": {
|
|
21
|
+
"types": "./dist/storage-supabase/index.d.ts",
|
|
22
|
+
"import": "./dist/storage-supabase/index.js"
|
|
23
|
+
},
|
|
20
24
|
"./agent": {
|
|
21
25
|
"types": "./dist/agent/index.d.ts",
|
|
22
26
|
"import": "./dist/agent/index.js"
|
|
@@ -24,6 +28,10 @@
|
|
|
24
28
|
"./api-aws": {
|
|
25
29
|
"types": "./dist/api-aws/index.d.ts",
|
|
26
30
|
"import": "./dist/api-aws/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./api-supabase": {
|
|
33
|
+
"types": "./dist/api-supabase/index.d.ts",
|
|
34
|
+
"import": "./dist/api-supabase/index.js"
|
|
27
35
|
}
|
|
28
36
|
},
|
|
29
37
|
"files": [
|
|
@@ -36,7 +44,8 @@
|
|
|
36
44
|
"@ai-sdk/google": "^3.0.29",
|
|
37
45
|
"@ai-sdk/openai": "^3.0.29",
|
|
38
46
|
"@aws-sdk/client-s3": "^3.888.0",
|
|
39
|
-
"@
|
|
47
|
+
"@supabase/supabase-js": "^2.57.2",
|
|
48
|
+
"@webmaster-droid/contracts": "^0.1.0",
|
|
40
49
|
"ai": "^6.0.86",
|
|
41
50
|
"aws-lambda": "^1.0.7",
|
|
42
51
|
"jose": "^6.1.0",
|
|
@@ -44,12 +53,13 @@
|
|
|
44
53
|
},
|
|
45
54
|
"scripts": {
|
|
46
55
|
"typecheck": "tsc --noEmit",
|
|
47
|
-
"build": "tsup src/index.ts src/core/index.ts src/storage-s3/index.ts src/agent/index.ts src/api-aws/index.ts --format esm --dts --clean"
|
|
56
|
+
"build": "tsup src/index.ts src/core/index.ts src/storage-s3/index.ts src/storage-supabase/index.ts src/agent/index.ts src/api-aws/index.ts src/api-supabase/index.ts --format esm --dts --clean && node scripts/copy-agent-assets.mjs",
|
|
57
|
+
"test": "node ../../scripts/run-workspace-tests.mjs"
|
|
48
58
|
},
|
|
49
59
|
"devDependencies": {
|
|
50
60
|
"@types/aws-lambda": "^8.10.160"
|
|
51
61
|
},
|
|
52
|
-
"description": "Unified backend runtime: core service,
|
|
62
|
+
"description": "Unified backend runtime: core service, storage adapters, AI agent, and API adapters for AWS and Supabase.",
|
|
53
63
|
"license": "MIT",
|
|
54
64
|
"repository": {
|
|
55
65
|
"type": "git",
|