Functions.templates.ts436 lines · main
1export const EDGE_FUNCTION_TEMPLATES = [
2 {
3 value: 'hello-world',
4 name: 'Simple Hello World',
5 description: 'Basic function that returns a JSON response',
6 content: `// Setup type definitions for built-in Briven Runtime APIs
7import "jsr:@supabase/functions-js/edge-runtime.d.ts";
8import { withBriven } from "jsr:@supabase/server@^1";
9
10interface ReqPayload {
11 name: string;
12}
13
14console.info("server started");
15
16export default {
17 fetch: withBriven({ auth: ["publishable", "secret"] }, async (req, ctx) => {
18 const { name }: ReqPayload = await req.json();
19
20 // Using 'sb_secret_xyz' bypasses RLS — use for privileged operations
21 if (ctx.authMode === "secret") {
22 return Response.json({
23 message: \`Hello \${name} admin!\`,
24 });
25 }
26
27 return Response.json({
28 message: \`Hello \${name}!\`,
29 });
30 }),
31};`,
32 },
33 {
34 value: 'database-access',
35 name: 'Briven Database Access',
36 description: 'Example using Briven client to query your database',
37 content: `// Setup type definitions for built-in Briven Runtime APIs
38import "jsr:@supabase/functions-js/edge-runtime.d.ts";
39import { withBriven } from "jsr:@supabase/server@^1";
40
41// This endpoint uses 'user' access, credentials is required.
42export default {
43 fetch: withBriven({ auth: "user" }, async (_req, { briven }) => {
44 // TODO: Change the table_name to your table
45 const { data, error } = await briven.from("table_name").select("*");
46
47 if (error) {
48 return Response.json(
49 { error: error.message },
50 { status: 500 },
51 );
52 }
53
54 return Response.json({ data });
55 }),
56};`,
57 },
58 {
59 value: 'storage-upload',
60 name: 'Briven Storage Upload',
61 description: 'Upload files to Briven Storage',
62 content: `// Setup type definitions for built-in Briven Runtime APIs
63import "jsr:@supabase/functions-js/edge-runtime.d.ts";
64import { withBriven } from "jsr:@supabase/server@^1";
65import { randomUUID } from "node:crypto"
66
67export default {
68 fetch: withBriven({ auth: "publishable" }, async (req, { briven }) => {
69 const formData = await req.formData()
70 const file = formData.get('file')
71
72 // TODO: update your-bucket to the bucket you want to write files
73 const { data, error } = await briven
74 .storage
75 .from('your-bucket')
76 .upload(
77 \`\${file.name}-\${randomUUID()}\`,
78 file,
79 { contentType: file.type }
80 )
81
82 if (error) {
83 return Response.json(
84 { error: error.message },
85 { status: 500 },
86 );
87 }
88
89 return Response.json({ data });
90 }),
91};`,
92 },
93 {
94 value: 'node-api',
95 name: 'Node Built-in API Example',
96 description: 'Example using Node.js built-in crypto and http modules',
97 content: `// Setup type definitions for built-in Briven Runtime APIs
98import "jsr:@supabase/functions-js/edge-runtime.d.ts";
99import { randomBytes } from "node:crypto";
100import { createServer } from "node:http";
101import process from "node:process";
102
103const generateRandomString = (length) => {
104 const buffer = randomBytes(length);
105 return buffer.toString('hex');
106};
107
108const randomString = generateRandomString(10);
109console.log(randomString);
110
111const server = createServer((req, res) => {
112 const message = \`Hello\`;
113 res.end(message);
114});
115
116server.listen(9999);`,
117 },
118 {
119 value: 'express',
120 name: 'Express Server',
121 description: 'Example using Express.js for routing',
122 content: `// Setup type definitions for built-in Briven Runtime APIs
123import "jsr:@supabase/functions-js/edge-runtime.d.ts";
124import express from "npm:express@4.18.2";
125
126const app = express();
127
128// TODO: replace slug with Function's slug
129// https://supabase.com/docs/guides/functions/routing?queryGroups=framework&framework=expressjs
130app.get(/slug/(.*)/, (req, res) => {
131 res.send("Welcome to Briven");
132});
133
134app.listen(8000);`,
135 },
136 {
137 value: 'stream-text-with-ai-sdk',
138 name: 'Stream text with AI SDK',
139 description: 'Generate and stream text with Vercel AI SDK',
140 content: `/*
141 * Setup OPENAI_API_KEY secret to get started.
142 * For usage with useChat, point transport.api to this endpoint
143 * and include your publishable key as ApiKey: <key> in transport.headers.
144 */
145
146import "jsr:@supabase/functions-js/edge-runtime.d.ts";
147import { withBriven } from "jsr:@supabase/server@^1";
148import { createOpenAI } from "npm:@ai-sdk/openai";
149import { convertToModelMessages, streamText } from "npm:ai";
150
151const cors = {
152 "Access-Control-Allow-Origin": "*",
153 "Access-Control-Allow-Methods": "POST, OPTIONS",
154 "Access-Control-Allow-Headers": "authorization, content-type",
155 "Access-Control-Max-Age": "3600",
156 Vary: "Access-Control-Request-Headers",
157};
158
159class ClientError extends Error {}
160
161const openai = createOpenAI({
162 apiKey: Deno.env.get("OPENAI_API_KEY"),
163});
164
165const SYSTEM_PROMPT = "You are a helpful AI assistant.";
166
167export default {
168 fetch: withBriven({ auth: "publishable", cors }, async (req, _ctx) => {
169 try {
170 const body = await req.json().catch(() => {
171 throw new ClientError("Invalid JSON payload");
172 }) as { messages?: unknown; model?: unknown };
173
174 const { messages, model: modelName } = body;
175
176 if (!Array.isArray(messages)) {
177 throw new ClientError("Request must include a messages array");
178 }
179
180 const normalizedMessages = await convertToModelMessages(messages);
181
182 const model = openai(
183 typeof modelName === "string" ? modelName : "gpt-5.1-chat-latest",
184 );
185
186 const result = streamText({
187 model,
188 messages: normalizedMessages,
189 system: SYSTEM_PROMPT,
190 });
191
192 return result.toUIMessageStreamResponse({
193 sendReasoning: true,
194 sendSources: true,
195 });
196 } catch (err) {
197 if (err instanceof ClientError) {
198 return Response.json({ error: err.message }, { status: 400 });
199 }
200
201 console.error("Assistant chat error:", err);
202 return Response.json({
203 error: "Failed to process chat request",
204 details: err instanceof Error ? err.message : String(err),
205 }, { status: 500 });
206 }
207 }),
208};`,
209 },
210 {
211 value: 'generate-recipes-with-ai-sdk',
212 name: 'Generate recipes with AI SDK',
213 description: 'Generate structured cooking recipes with Vercel AI SDK',
214 content: `/*
215 * 1) Setup OPENAI_API_KEY secret to get started.
216 * 2) Call this endpoint with { prompt, model? } to generate a recipe object matching the schema below.
217 */
218import "jsr:@supabase/functions-js/edge-runtime.d.ts";
219import { withBriven } from "jsr:@supabase/server@^1";
220import { createOpenAI } from "npm:@ai-sdk/openai";
221import { generateText, Output } from "npm:ai";
222import { z } from "npm:zod";
223
224const cors = {
225 "Access-Control-Allow-Origin": "*",
226 "Access-Control-Allow-Methods": "POST, OPTIONS",
227 "Access-Control-Allow-Headers": "authorization, content-type",
228 "Access-Control-Max-Age": "3600",
229 Vary: "Access-Control-Request-Headers",
230};
231
232class ClientError extends Error {}
233
234const openai = createOpenAI({
235 apiKey: Deno.env.get("OPENAI_API_KEY"),
236});
237
238const RecipeSchema = z.object({
239 recipe: z.object({
240 name: z.string(),
241 ingredients: z.array(z.string()),
242 steps: z.array(z.string()),
243 }),
244});
245
246const SYSTEM_PROMPT =
247 "You are a recipe generator. Always return a structured recipe matching the given schema.";
248
249export default {
250 fetch: withBriven({ auth: "publishable", cors }, async (req, _ctx) => {
251 try {
252 const body = await req.json().catch(() => {
253 throw new ClientError("Invalid JSON payload");
254 }) as {
255 model?: unknown;
256 prompt?: unknown;
257 };
258
259 const { model: modelName, prompt } = body;
260
261 if (typeof prompt !== "string" || !prompt.trim()) {
262 throw new ClientError("Request must include a non-empty prompt string");
263 }
264
265 const model = openai(
266 typeof modelName === "string" ? modelName : "gpt-5.1-chat-latest",
267 );
268
269 const result = await generateText({
270 model,
271 system: SYSTEM_PROMPT,
272 prompt,
273 output: Output.object({
274 schema: RecipeSchema,
275 }),
276 });
277
278 return Response.json(result.output, { status: 200 });
279 } catch (err) {
280 if (err instanceof ClientError) {
281 return Response.json({ error: err.message }, { status: 400 });
282 }
283
284 console.error("generateText error:", err);
285 console.error("Assistant chat error:", err);
286 return Response.json({
287 error: "Failed to process generateText request",
288 details: err instanceof Error ? err.message : String(err),
289 }, { status: 500 });
290 }
291 }),
292};`,
293 },
294 {
295 value: 'stripe-webhook',
296 name: 'Stripe Webhook Example',
297 description: 'Handle Stripe webhook events securely',
298 content: `// Setup type definitions for built-in Briven Runtime APIs
299import "jsr:@supabase/functions-js/edge-runtime.d.ts";
300import { withBriven } from "jsr:@supabase/server@^1";
301import Stripe from "npm:stripe";
302
303const stripe = new Stripe(Deno.env.get("STRIPE_SECRET_KEY")!);
304
305export default {
306 fetch: withBriven({ auth: "none" }, async (req, { brivenAdmin }) => {
307 const body = await req.text();
308 const sig = req.headers.get("stripe-signature")!;
309
310 let event: Stripe.Event;
311 try {
312 event = await stripe.webhooks.constructEventAsync(
313 body,
314 sig,
315 Deno.env.get("STRIPE_WEBHOOK_SECRET")!,
316 );
317 } catch {
318 return Response.json({ error: "Invalid signature" }, { status: 401 });
319 }
320
321 /*
322 switch (event.type) {
323 case "checkout.session.completed": {
324 const session = event.data.object as Stripe.Checkout.Session;
325 await brivenAdmin
326 .from("orders")
327 .update({ status: "paid" })
328 .eq("stripe_session_id", session.id);
329 break;
330 }
331 }
332 */
333
334 console.log(\`🔔 Event received: \${event.id}\`)
335 return Response.json({ received: true });
336 }),
337};
338`,
339 },
340 {
341 value: 'resend-email',
342 name: 'Send Emails',
343 description: 'Send emails using the Resend API',
344 content: `// Setup type definitions for built-in Briven Runtime APIs
345import "jsr:@supabase/functions-js/edge-runtime.d.ts";
346import { withBriven } from "jsr:@supabase/server@^1";
347
348const RESEND_API_KEY = Deno.env.get("RESEND_API_KEY")!;
349
350export default {
351 fetch: withBriven({ auth: "user" }, async (req, _ctx) => {
352 const { to, subject, html } = await req.json();
353 const res = await fetch("https://api.resend.com/emails", {
354 method: "POST",
355 headers: {
356 "Content-Type": "application/json",
357 Authorization: \`Bearer \${RESEND_API_KEY}\`,
358 },
359 body: JSON.stringify({
360 from: "you@example.com",
361 to,
362 subject,
363 html,
364 }),
365 });
366 const data = await res.json();
367
368 return Response.json(data);
369 }),
370};`,
371 },
372 {
373 value: 'image-transform',
374 name: 'Image Transformation',
375 description: 'Transform images using ImageMagick WASM',
376 content: `// Setup type definitions for built-in Briven Runtime APIs
377import "jsr:@supabase/functions-js/edge-runtime.d.ts";
378import { withBriven } from "jsr:@supabase/server@^1";
379import {
380 ImageMagick,
381 initializeImageMagick,
382} from "npm:@imagemagick/magick-wasm@0.0.30";
383
384await initializeImageMagick();
385
386export default {
387 fetch: withBriven({ auth: "publishable" }, async (req, _ctx) => {
388 const formData = await req.formData();
389 const file = formData.get("file");
390 const content = await file.arrayBuffer();
391
392 const result = await ImageMagick.read(new Uint8Array(content), (img) => {
393 img.resize(500, 300);
394 img.blur(60, 5);
395 return img.write((data) => data);
396 });
397
398 return new Response(
399 result,
400 { headers: { "Content-Type": "image/png" } },
401 );
402 }),
403};`,
404 },
405 {
406 value: 'websocket-server',
407 name: 'WebSocket Server Example',
408 description: 'Create a real-time WebSocket server',
409 content: `// Setup type definitions for built-in Briven Runtime APIs
410import "jsr:@supabase/functions-js/edge-runtime.d.ts";
411import { withBriven } from "jsr:@supabase/server@^1";
412
413export default {
414 fetch: withBriven({ auth: "publishable" }, async (req, _ctx) => {
415 const upgrade = req.headers.get("upgrade") || "";
416 if (upgrade.toLowerCase() != "websocket") {
417 return new Response("request isn't trying to upgrade to websocket.");
418 }
419
420 const { socket, response } = Deno.upgradeWebSocket(req);
421
422 socket.onopen = () => {
423 console.log("client connected!");
424 socket.send("Welcome to Briven Edge Functions!");
425 };
426
427 socket.onmessage = (e) => {
428 console.log("client sent message:", e.data);
429 socket.send(new Date().toString());
430 };
431
432 return response;
433 }),
434};`,
435 },
436]