diff --git a/adapters/valtown-adapter/jsr.json b/adapters/valtown-adapter/jsr.json index de7f483f..7d717230 100644 --- a/adapters/valtown-adapter/jsr.json +++ b/adapters/valtown-adapter/jsr.json @@ -1,6 +1,6 @@ { "name": "@inferable/valtown-adapter", - "version": "0.0.5", + "version": "0.0.10", "license": "MIT", "exports": "./mod.ts" } \ No newline at end of file diff --git a/adapters/valtown-adapter/mod.ts b/adapters/valtown-adapter/mod.ts index 6c57a730..6a909bfc 100644 --- a/adapters/valtown-adapter/mod.ts +++ b/adapters/valtown-adapter/mod.ts @@ -1,31 +1,13 @@ -const { - createVerify, -} = await import('node:crypto'); - export class InferableService { private functions: Parameters[0][] = []; constructor( private options: { description: string; - publicKey: string; + token?: string; }, ) { - if (this.options.publicKey) { - const hasPrefix = this.options.publicKey.startsWith("-----BEGIN PUBLIC KEY-----"); - - if (!hasPrefix) { - const base64Content = this.options.publicKey; - const lines = base64Content.match(/.{1,64}/g) || []; - const formatted = [ - "-----BEGIN PUBLIC KEY-----", - ...lines, - "-----END PUBLIC KEY-----", - ].join("\n"); - - this.options.publicKey = formatted; - } - } + // Remove public key formatting logic as it's no longer needed } registerFunction(options: { @@ -43,91 +25,60 @@ export class InferableService { this.functions.push(options); } - private isAuthenticated({ - xTimestamp, - xSignature, - method, - path, - body, - }: { - xTimestamp: string; - xSignature: string; - method: string; - path: string; - body: string; - }): boolean { - const signatureFromHeader = xSignature; - - if (!signatureFromHeader) { - return false; + private isAuthenticated(token: string | null): boolean { + if (!this.options.token) { + return true; // If no token is configured, authentication is disabled } - - console.log("About to verify", { - xTimestamp, - method, - path, - body, - signatureFromHeader, - publicKey: this.options.publicKey, - }); - - const verifier = createVerify("SHA256"); - const message = `${xTimestamp}${method}${path}${body}`; - console.log("Message to verify:", message); - verifier.update(message); - verifier.end(); - const result = verifier.verify(this.options.publicKey, signatureFromHeader, "hex"); - console.log("Verification result:", result); - return result; + return token === this.options.token; } getServer(): (request: Request) => Promise { const server = async (request: Request): Promise => { + console.log(`[Inferable Adapter] Incoming request to: ${request.url}`); + const url = new URL(request.url); const path = url.pathname; - const hasPublicKey = this.options.publicKey !== undefined; + const hasToken = this.options.token !== undefined; + const authHeader = request.headers.get("Authorization"); + const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null; - if (!hasPublicKey) { - console.warn("No public key provided. Authentication is disabled. See https://docs.inferable.ai/valtown to learn how to enable it."); + console.log(`[Inferable Adapter] Authentication status: hasToken=${hasToken}, token=${token ? 'provided' : 'not provided'}`); + + if (!hasToken) { + console.warn("[Inferable Adapter] No token provided. Authentication is disabled. See https://docs.inferable.ai/valtown to learn how to enable it."); } // Metadata route if (path === "/meta") { - return new Response( - JSON.stringify({ - description: this.options.description, - functions: Object.values(this.functions).map(func => ({ - name: func.name, - description: func.description, - input: func.input, - })), - }), - { + console.log("[Inferable Adapter] Handling /meta request"); + if (hasToken && !this.isAuthenticated(token)) { + console.log("[Inferable Adapter] /meta request unauthorized"); + return new Response(JSON.stringify({ error: "Unauthorized" }), { + status: 401, headers: { "content-type": "application/json" }, - }, - ); + }); + } + + const metadata = { + description: this.options.description, + functions: Object.values(this.functions).map(func => ({ + name: func.name, + description: func.description, + input: func.input, + })), + }; + console.log("[Inferable Adapter] Returning metadata:", metadata); + return new Response(JSON.stringify(metadata), { + headers: { "content-type": "application/json" }, + }); } // Execution route if (path.startsWith("/exec/functions/")) { - const body = await request.body?.getReader().read(); - const bodyText = body ? new TextDecoder().decode(body.value) : ""; - - if (!bodyText) { - return new Response(JSON.stringify({ error: "No body" }), { - status: 400, - headers: { "content-type": "application/json" }, - }); - } - - if (hasPublicKey && !this.isAuthenticated({ - xTimestamp: request.headers.get("X-Timestamp") || "", - xSignature: request.headers.get("X-Signature") || "", - method: request.method, - path, - body: bodyText, - })) { + console.log("[Inferable Adapter] Handling function execution request"); + if (hasToken && !this.isAuthenticated(token)) { + console.log("[Inferable Adapter] Function execution unauthorized"); return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" }, @@ -135,8 +86,10 @@ export class InferableService { } const functionName = path.split("/")[3]; + console.log(`[Inferable Adapter] Attempting to execute function: ${functionName}`); if (request.method !== "POST") { + console.log(`[Inferable Adapter] Invalid method ${request.method} for function execution`); return new Response(JSON.stringify({ error: "Method not allowed" }), { status: 405, headers: { "content-type": "application/json" }, @@ -145,18 +98,25 @@ export class InferableService { try { const input = await request.json(); + console.log(`[Inferable Adapter] Function input:`, input); const handler = this.functions.find(func => func.name === functionName); if (!handler) { + console.log(`[Inferable Adapter] Function ${functionName} not found`); return new Response(JSON.stringify({ error: `Function ${functionName} not found` }), { status: 404, headers: { "content-type": "application/json" }, }); } - return new Response(JSON.stringify({ result: await handler.handler(input) })); + console.log(`[Inferable Adapter] Executing function ${functionName}`); + const result = await handler.handler(input); + console.log(`[Inferable Adapter] Function ${functionName} result:`, result); + + return new Response(JSON.stringify({ result })); } catch (error) { + console.error(`[Inferable Adapter] Error executing function:`, error); return new Response(JSON.stringify({ error: `Error occurred during execution: ${error}` }), { status: 400, headers: { "content-type": "application/json" }, @@ -165,6 +125,7 @@ export class InferableService { } // Default route + console.log(`[Inferable Adapter] Route not found: ${path}`); return new Response( JSON.stringify({ error: `Route not found: ${path}`,