beddel 0.2.0 → 0.2.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.2] - 2025-12-19
4
+
5
+ ### Changed
6
+ - Maintenance release (no functional changes)
7
+
3
8
  ## [0.2.0] - 2025-12-18
4
9
 
5
10
  ### Added
package/README.md CHANGED
@@ -215,21 +215,29 @@ output:
215
215
 
216
216
  2. **The agent is automatically registered** when your application starts.
217
217
 
218
- 3. **Execute via GraphQL or directly**:
218
+ 3. **Execute via GraphQL or directly** (GraphQL Yoga, introspection always enabled). GraphiQL is available at `GET /api/graphql`:
219
219
 
220
220
  ```graphql
221
- mutation {
222
- executeMethod(
223
- methodName: "greeting.execute"
224
- params: { name: "Alice" }
225
- props: { gemini_api_key: "your-api-key" }
226
- ) {
221
+ mutation Execute($methodName: String!, $params: JSON!, $props: JSON!) {
222
+ executeMethod(methodName: $methodName, params: $params, props: $props) {
227
223
  success
228
224
  data
225
+ error
226
+ executionTime
229
227
  }
230
228
  }
231
229
  ```
232
230
 
231
+ Example variables:
232
+
233
+ ```json
234
+ {
235
+ "methodName": "greeting.execute",
236
+ "params": { "name": "Alice" },
237
+ "props": { "gemini_api_key": "your-api-key" }
238
+ }
239
+ ```
240
+
233
241
  ### Custom Agents with TypeScript Code-Behind
234
242
 
235
243
  For more complex logic, create custom agents with TypeScript implementations:
@@ -5,5 +5,5 @@ import type { ExecuteMethodInput, ExecuteMethodResult } from "../types";
5
5
  export declare function getGraphQLSchema(): string;
6
6
  export declare function executeRegisteredMethod(input: ExecuteMethodInput, clientId: string): Promise<ExecuteMethodResult>;
7
7
  export declare function handleGraphQLPost(request: Request): Promise<Response>;
8
- export declare function handleGraphQLGet(): Response;
8
+ export declare function handleGraphQLGet(request: Request): Promise<Response>;
9
9
  //# sourceMappingURL=graphql.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../../src/server/api/graphql.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsBH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EAEpB,MAAM,UAAU,CAAC;AASlB,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,kBAAkB,EACzB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,mBAAmB,CAAC,CAwH9B;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,OAAO,qBAyEvD;AAED,wBAAgB,gBAAgB,aAO/B"}
1
+ {"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../../src/server/api/graphql.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwBH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EAEpB,MAAM,UAAU,CAAC;AASlB,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAmCD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,kBAAkB,EACzB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,mBAAmB,CAAC,CAwH9B;AA8ED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,OAAO,qBAEvD;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,qBAEtD"}
@@ -7,6 +7,8 @@ exports.getGraphQLSchema = getGraphQLSchema;
7
7
  exports.executeRegisteredMethod = executeRegisteredMethod;
8
8
  exports.handleGraphQLPost = handleGraphQLPost;
9
9
  exports.handleGraphQLGet = handleGraphQLGet;
10
+ const graphql_1 = require("graphql");
11
+ const graphql_yoga_1 = require("graphql-yoga");
10
12
  const agentRegistry_1 = require("../../agents/agentRegistry");
11
13
  const kvStore_1 = require("../kvStore");
12
14
  const runtimeSecurity_1 = require("../runtimeSecurity");
@@ -20,6 +22,37 @@ const schema = `
20
22
  function getGraphQLSchema() {
21
23
  return schema;
22
24
  }
25
+ const parseJsonLiteral = (ast) => {
26
+ switch (ast.kind) {
27
+ case graphql_1.Kind.STRING:
28
+ case graphql_1.Kind.BOOLEAN:
29
+ return ast.value;
30
+ case graphql_1.Kind.INT:
31
+ return parseInt(ast.value, 10);
32
+ case graphql_1.Kind.FLOAT:
33
+ return parseFloat(ast.value);
34
+ case graphql_1.Kind.OBJECT: {
35
+ const value = {};
36
+ for (const field of ast.fields) {
37
+ value[field.name.value] = parseJsonLiteral(field.value);
38
+ }
39
+ return value;
40
+ }
41
+ case graphql_1.Kind.LIST:
42
+ return ast.values.map(parseJsonLiteral);
43
+ case graphql_1.Kind.NULL:
44
+ return null;
45
+ default:
46
+ return null;
47
+ }
48
+ };
49
+ const jsonScalar = new graphql_1.GraphQLScalarType({
50
+ name: "JSON",
51
+ description: "Arbitrary JSON value",
52
+ serialize: (value) => value,
53
+ parseValue: (value) => value,
54
+ parseLiteral: (ast) => parseJsonLiteral(ast),
55
+ });
23
56
  async function executeRegisteredMethod(input, clientId) {
24
57
  const startTime = Date.now();
25
58
  const context = {
@@ -113,68 +146,77 @@ async function executeRegisteredMethod(input, clientId) {
113
146
  return { success: false, error: errorMessage, executionTime };
114
147
  }
115
148
  }
116
- async function handleGraphQLPost(request) {
117
- try {
118
- let clientId;
119
- const authHeader = request.headers.get("authorization");
120
- if (authHeader && authHeader.startsWith("Bearer ")) {
121
- const apiKey = authHeader.substring(7);
122
- if (!(0, runtimeSecurity_1.isValidApiKey)(apiKey)) {
123
- throw new errors_1.AuthenticationError("Invalid API key format");
124
- }
125
- const client = await (0, kvStore_1.getClientByApiKey)(apiKey);
126
- if (!client)
127
- throw new errors_1.AuthenticationError("Invalid API key");
128
- const rateLimitOk = await (0, kvStore_1.checkRateLimit)(client.id, client.rateLimit);
129
- if (!rateLimitOk)
130
- throw new errors_1.RateLimitError("Rate limit exceeded.");
131
- clientId = client.id;
132
- }
133
- else if (request.headers.get("x-admin-tenant") === "true") {
134
- clientId = "admin_tenant";
135
- }
136
- else {
137
- throw new errors_1.AuthenticationError("Missing or invalid authorization header");
138
- }
139
- const body = await request.json();
140
- if (!body.query) {
141
- throw new errors_1.ValidationError("Missing query in request body");
142
- }
143
- if (body.query && body.query.includes("executeMethod")) {
144
- if (!body.variables || !body.variables.methodName) {
145
- throw new errors_1.ValidationError("Missing 'variables' or 'methodName' in request body");
146
- }
147
- const result = await executeRegisteredMethod({
148
- methodName: body.variables.methodName,
149
- params: body.variables.params || {},
150
- props: body.variables.props || {},
151
- }, clientId);
152
- return Response.json({ data: { executeMethod: result } });
149
+ async function resolveClientId(request) {
150
+ const authHeader = request.headers.get("authorization");
151
+ if (authHeader && authHeader.startsWith("Bearer ")) {
152
+ const apiKey = authHeader.substring(7);
153
+ if (!(0, runtimeSecurity_1.isValidApiKey)(apiKey)) {
154
+ throw new errors_1.AuthenticationError("Invalid API key format");
153
155
  }
154
- return Response.json({ errors: [{ message: "Unsupported operation" }] }, { status: 400 });
156
+ const client = await (0, kvStore_1.getClientByApiKey)(apiKey);
157
+ if (!client)
158
+ throw new errors_1.AuthenticationError("Invalid API key");
159
+ const rateLimitOk = await (0, kvStore_1.checkRateLimit)(client.id, client.rateLimit);
160
+ if (!rateLimitOk)
161
+ throw new errors_1.RateLimitError("Rate limit exceeded.");
162
+ return client.id;
155
163
  }
156
- catch (error) {
157
- const status = error instanceof errors_1.AuthenticationError
158
- ? 401
159
- : error instanceof errors_1.RateLimitError
160
- ? 429
161
- : error instanceof errors_1.ValidationError
162
- ? 400
163
- : error instanceof errors_1.NotFoundError
164
- ? 404
165
- : 500;
166
- return Response.json({
167
- errors: [
168
- {
169
- message: error instanceof Error ? error.message : "Internal server error",
170
- },
171
- ],
172
- }, { status });
164
+ if (request.headers.get("x-admin-tenant") === "true") {
165
+ return "admin_tenant";
166
+ }
167
+ throw new errors_1.AuthenticationError("Missing or invalid authorization header");
168
+ }
169
+ function toGraphQLError(error) {
170
+ const message = error instanceof Error ? error.message : "Internal server error";
171
+ let code = "INTERNAL_SERVER_ERROR";
172
+ if (error instanceof errors_1.AuthenticationError) {
173
+ code = "UNAUTHENTICATED";
174
+ }
175
+ else if (error instanceof errors_1.RateLimitError) {
176
+ code = "RATE_LIMITED";
177
+ }
178
+ else if (error instanceof errors_1.ValidationError) {
179
+ code = "BAD_USER_INPUT";
173
180
  }
181
+ else if (error instanceof errors_1.NotFoundError) {
182
+ code = "NOT_FOUND";
183
+ }
184
+ return new graphql_1.GraphQLError(message, { extensions: { code } });
185
+ }
186
+ const yoga = (0, graphql_yoga_1.createYoga)({
187
+ schema: (0, graphql_yoga_1.createSchema)({
188
+ typeDefs: schema,
189
+ resolvers: {
190
+ JSON: jsonScalar,
191
+ Query: {
192
+ ping: () => "pong",
193
+ },
194
+ Mutation: {
195
+ executeMethod: async (_parent, args, context) => {
196
+ try {
197
+ const clientId = await resolveClientId(context.request);
198
+ return await executeRegisteredMethod({
199
+ methodName: args.methodName,
200
+ params: args.params || {},
201
+ props: args.props || {},
202
+ }, clientId);
203
+ }
204
+ catch (error) {
205
+ throw toGraphQLError(error);
206
+ }
207
+ },
208
+ },
209
+ },
210
+ }),
211
+ context: ({ request }) => ({ request }),
212
+ graphqlEndpoint: "/api/graphql",
213
+ graphiql: true,
214
+ fetchAPI: { Request, Response },
215
+ });
216
+ async function handleGraphQLPost(request) {
217
+ return yoga.handleRequest(request, { request });
174
218
  }
175
- function handleGraphQLGet() {
176
- return new Response(`<!DOCTYPE html>
177
- <html><head><title>Opal Support API - GraphQL</title><style>body{font-family:sans-serif;max-width:800px;margin:50px auto;padding:20px}code,pre{background:#f4f4f4;padding:4px 8px;border-radius:4px}</style></head>
178
- <body><h1>Opal Support API</h1><p>GraphQL endpoint for executing registered methods.</p><h2>Endpoint</h2><code>POST /api/graphql</code><h2>Authentication</h2><p>Use Bearer token in Authorization header.</p><h2>Schema</h2><pre>${schema}</pre></body></html>`, { headers: { "Content-Type": "text/html" } });
219
+ async function handleGraphQLGet(request) {
220
+ return yoga.handleRequest(request, { request });
179
221
  }
180
222
  //# sourceMappingURL=graphql.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../src/server/api/graphql.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../src/server/api/graphql.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beddel",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Beddel - A secure YAML parser and OpenAPI endpoint manager for Node.js applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,6 +23,10 @@
23
23
  "./server/*": {
24
24
  "types": "./dist/server/*.d.ts",
25
25
  "default": "./dist/server/*.js"
26
+ },
27
+ "./server/api/graphql": {
28
+ "types": "./dist/server/api/graphql.d.ts",
29
+ "default": "./dist/server/api/graphql.js"
26
30
  }
27
31
  },
28
32
  "scripts": {
@@ -33,7 +37,10 @@
33
37
  "test:watch": "jest --watch",
34
38
  "test:coverage": "jest --coverage",
35
39
  "lint": "eslint src --ext .ts",
36
- "lint:fix": "eslint src --ext .ts --fix"
40
+ "lint:fix": "eslint src --ext .ts --fix",
41
+ "version:patch": "npm version patch",
42
+ "version:minor": "npm version minor",
43
+ "version:major": "npm version major"
37
44
  },
38
45
  "keywords": [
39
46
  "yaml",
@@ -59,6 +66,8 @@
59
66
  "@upstash/redis": "^1.34.3",
60
67
  "ai": "^5.0.70",
61
68
  "firebase-admin": "12.7.0",
69
+ "graphql": "^16.10.0",
70
+ "graphql-yoga": "^5.13.5",
62
71
  "isolated-vm": "5.0.1",
63
72
  "js-yaml": "^4.1.0",
64
73
  "zod": "^4.1.12"
@@ -77,4 +86,4 @@
77
86
  "engines": {
78
87
  "node": ">=18.0.0"
79
88
  }
80
- }
89
+ }
@@ -2,6 +2,8 @@
2
2
  * GraphQL helpers used by the /api/graphql route.
3
3
  */
4
4
 
5
+ import { GraphQLError, GraphQLScalarType, Kind, type ValueNode } from "graphql";
6
+ import { createSchema, createYoga } from "graphql-yoga";
5
7
  import { agentRegistry } from "../../agents/agentRegistry";
6
8
  import {
7
9
  getClientByApiKey,
@@ -39,6 +41,39 @@ export function getGraphQLSchema(): string {
39
41
  return schema;
40
42
  }
41
43
 
44
+ const parseJsonLiteral = (ast: ValueNode): unknown => {
45
+ switch (ast.kind) {
46
+ case Kind.STRING:
47
+ case Kind.BOOLEAN:
48
+ return ast.value;
49
+ case Kind.INT:
50
+ return parseInt(ast.value, 10);
51
+ case Kind.FLOAT:
52
+ return parseFloat(ast.value);
53
+ case Kind.OBJECT: {
54
+ const value: Record<string, any> = {};
55
+ for (const field of ast.fields) {
56
+ value[field.name.value] = parseJsonLiteral(field.value);
57
+ }
58
+ return value;
59
+ }
60
+ case Kind.LIST:
61
+ return ast.values.map(parseJsonLiteral);
62
+ case Kind.NULL:
63
+ return null;
64
+ default:
65
+ return null;
66
+ }
67
+ };
68
+
69
+ const jsonScalar = new GraphQLScalarType({
70
+ name: "JSON",
71
+ description: "Arbitrary JSON value",
72
+ serialize: (value: unknown) => value,
73
+ parseValue: (value: unknown) => value,
74
+ parseLiteral: (ast: ValueNode) => parseJsonLiteral(ast),
75
+ });
76
+
42
77
  export async function executeRegisteredMethod(
43
78
  input: ExecuteMethodInput,
44
79
  clientId: string
@@ -164,86 +199,86 @@ export async function executeRegisteredMethod(
164
199
  }
165
200
  }
166
201
 
167
- export async function handleGraphQLPost(request: Request) {
168
- try {
169
- let clientId: string;
170
- const authHeader = request.headers.get("authorization");
202
+ async function resolveClientId(request: Request): Promise<string> {
203
+ const authHeader = request.headers.get("authorization");
171
204
 
172
- if (authHeader && authHeader.startsWith("Bearer ")) {
173
- const apiKey = authHeader.substring(7);
174
- if (!isValidApiKey(apiKey)) {
175
- throw new AuthenticationError("Invalid API key format");
176
- }
177
- const client = await getClientByApiKey(apiKey);
178
- if (!client) throw new AuthenticationError("Invalid API key");
179
- const rateLimitOk = await checkRateLimit(client.id, client.rateLimit);
180
- if (!rateLimitOk) throw new RateLimitError("Rate limit exceeded.");
181
- clientId = client.id;
182
- } else if (request.headers.get("x-admin-tenant") === "true") {
183
- clientId = "admin_tenant";
184
- } else {
185
- throw new AuthenticationError(
186
- "Missing or invalid authorization header"
187
- );
205
+ if (authHeader && authHeader.startsWith("Bearer ")) {
206
+ const apiKey = authHeader.substring(7);
207
+ if (!isValidApiKey(apiKey)) {
208
+ throw new AuthenticationError("Invalid API key format");
188
209
  }
210
+ const client = await getClientByApiKey(apiKey);
211
+ if (!client) throw new AuthenticationError("Invalid API key");
212
+ const rateLimitOk = await checkRateLimit(client.id, client.rateLimit);
213
+ if (!rateLimitOk) throw new RateLimitError("Rate limit exceeded.");
214
+ return client.id;
215
+ }
189
216
 
190
- const body = await request.json();
191
- if (!body.query) {
192
- throw new ValidationError("Missing query in request body");
193
- }
217
+ if (request.headers.get("x-admin-tenant") === "true") {
218
+ return "admin_tenant";
219
+ }
194
220
 
195
- if (body.query && body.query.includes("executeMethod")) {
196
- if (!body.variables || !body.variables.methodName) {
197
- throw new ValidationError(
198
- "Missing 'variables' or 'methodName' in request body"
199
- );
200
- }
221
+ throw new AuthenticationError("Missing or invalid authorization header");
222
+ }
201
223
 
202
- const result = await executeRegisteredMethod(
203
- {
204
- methodName: body.variables.methodName,
205
- params: body.variables.params || {},
206
- props: body.variables.props || {},
207
- },
208
- clientId
209
- );
210
- return Response.json({ data: { executeMethod: result } });
211
- }
224
+ function toGraphQLError(error: unknown): GraphQLError {
225
+ const message = error instanceof Error ? error.message : "Internal server error";
226
+ let code = "INTERNAL_SERVER_ERROR";
212
227
 
213
- return Response.json(
214
- { errors: [{ message: "Unsupported operation" }] },
215
- { status: 400 }
216
- );
217
- } catch (error) {
218
- const status =
219
- error instanceof AuthenticationError
220
- ? 401
221
- : error instanceof RateLimitError
222
- ? 429
223
- : error instanceof ValidationError
224
- ? 400
225
- : error instanceof NotFoundError
226
- ? 404
227
- : 500;
228
- return Response.json(
229
- {
230
- errors: [
231
- {
232
- message:
233
- error instanceof Error ? error.message : "Internal server error",
234
- },
235
- ],
236
- },
237
- { status }
238
- );
228
+ if (error instanceof AuthenticationError) {
229
+ code = "UNAUTHENTICATED";
230
+ } else if (error instanceof RateLimitError) {
231
+ code = "RATE_LIMITED";
232
+ } else if (error instanceof ValidationError) {
233
+ code = "BAD_USER_INPUT";
234
+ } else if (error instanceof NotFoundError) {
235
+ code = "NOT_FOUND";
239
236
  }
237
+
238
+ return new GraphQLError(message, { extensions: { code } });
239
+ }
240
+
241
+ const yoga = createYoga({
242
+ schema: createSchema({
243
+ typeDefs: schema,
244
+ resolvers: {
245
+ JSON: jsonScalar,
246
+ Query: {
247
+ ping: () => "pong",
248
+ },
249
+ Mutation: {
250
+ executeMethod: async (
251
+ _parent: unknown,
252
+ args: { methodName: string; params?: Record<string, unknown>; props?: Record<string, string> },
253
+ context: { request: Request }
254
+ ) => {
255
+ try {
256
+ const clientId = await resolveClientId(context.request);
257
+ return await executeRegisteredMethod(
258
+ {
259
+ methodName: args.methodName,
260
+ params: args.params || {},
261
+ props: args.props || {},
262
+ },
263
+ clientId
264
+ );
265
+ } catch (error) {
266
+ throw toGraphQLError(error);
267
+ }
268
+ },
269
+ },
270
+ },
271
+ }),
272
+ context: ({ request }: { request: Request }) => ({ request }),
273
+ graphqlEndpoint: "/api/graphql",
274
+ graphiql: true,
275
+ fetchAPI: { Request, Response },
276
+ });
277
+
278
+ export async function handleGraphQLPost(request: Request) {
279
+ return yoga.handleRequest(request, { request });
240
280
  }
241
281
 
242
- export function handleGraphQLGet() {
243
- return new Response(
244
- `<!DOCTYPE html>
245
- <html><head><title>Opal Support API - GraphQL</title><style>body{font-family:sans-serif;max-width:800px;margin:50px auto;padding:20px}code,pre{background:#f4f4f4;padding:4px 8px;border-radius:4px}</style></head>
246
- <body><h1>Opal Support API</h1><p>GraphQL endpoint for executing registered methods.</p><h2>Endpoint</h2><code>POST /api/graphql</code><h2>Authentication</h2><p>Use Bearer token in Authorization header.</p><h2>Schema</h2><pre>${schema}</pre></body></html>`,
247
- { headers: { "Content-Type": "text/html" } }
248
- );
282
+ export async function handleGraphQLGet(request: Request) {
283
+ return yoga.handleRequest(request, { request });
249
284
  }