Skip to content

Commit 593625c

Browse files
SaxonFjoshenlim
andauthored
Edge functions empty state (supabase#33802)
* page components * page component changes * settings but broken saving * rvert * use sheet for provider * styling * remove things * Some refactoring and fixing, added JSDocs to layouts * Smol refactor * Fix * Update JSDocs * updated scaffolding * update edge functions layout * remove params * Clean up * Spelling * Clean up FormFieldWrappers * One last clean up * create edge functon * use component * flag * fix merge errors * fix imports * fix merge issues * fix import * fix flag * remove unused * simple empty * empty state improvements * move templates * re-add flag * use templates * flag * copy functions * feature flag it * Fix issues and clean up * Smol fix * Add comment --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
1 parent a3fee4e commit 593625c

File tree

13 files changed

+422
-107
lines changed

13 files changed

+422
-107
lines changed

apps/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const FormSchema = z.object({
5252
verify_jwt: z.boolean(),
5353
})
5454

55-
const EdgeFunctionDetails = () => {
55+
export const EdgeFunctionDetails = () => {
5656
const router = useRouter()
5757
const { ref: projectRef, functionSlug } = useParams()
5858
const [showDeleteModal, setShowDeleteModal] = useState(false)
@@ -365,5 +365,3 @@ const EdgeFunctionDetails = () => {
365365
</div>
366366
)
367367
}
368-
369-
export default EdgeFunctionDetails

apps/studio/components/interfaces/Functions/EdgeFunctionsListItem.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ interface EdgeFunctionsListItemProps {
1414
function: EdgeFunctionsResponse
1515
}
1616

17-
const EdgeFunctionsListItem = ({ function: item }: EdgeFunctionsListItemProps) => {
17+
export const EdgeFunctionsListItem = ({ function: item }: EdgeFunctionsListItemProps) => {
1818
const router = useRouter()
1919
const { ref } = useParams()
2020
const { project } = useProjectContext()
@@ -46,7 +46,9 @@ const EdgeFunctionsListItem = ({ function: item }: EdgeFunctionsListItemProps) =
4646
</Table.td>
4747
<Table.td>
4848
<div className="text-xs text-foreground-light flex gap-2 items-center truncate">
49-
<p className="font-mono truncate hidden md:inline">{endpoint}</p>
49+
<p title={endpoint} className="font-mono truncate hidden md:inline max-w-[30rem]">
50+
{endpoint}
51+
</p>
5052
<button
5153
type="button"
5254
className="text-foreground-lighter hover:text-foreground transition"
@@ -99,5 +101,3 @@ const EdgeFunctionsListItem = ({ function: item }: EdgeFunctionsListItemProps) =
99101
</Table.tr>
100102
)
101103
}
102-
103-
export default EdgeFunctionsListItem

apps/studio/components/interfaces/Functions/Functions.templates.ts

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,37 @@ Deno.serve(async (req) => {
5252
} catch (err) {
5353
return new Response(String(err?.message ?? err), { status: 500 })
5454
}
55+
})`,
56+
},
57+
{
58+
value: 'storage-upload',
59+
name: 'Supabase Storage Upload',
60+
description: 'Upload files to Supabase Storage',
61+
content: `// Setup type definitions for built-in Supabase Runtime APIs
62+
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
63+
import { createClient } from 'jsr:@supabase/supabase-js@2'
64+
65+
const supabase = createClient(
66+
Deno.env.get('SUPABASE_URL') ?? '',
67+
Deno.env.get('SUPABASE_ANON_KEY') ?? ''
68+
)
69+
70+
Deno.serve(async (req) => {
71+
const formData = await req.formData()
72+
const file = formData.get('file')
73+
const { data, error } = await supabase
74+
.storage
75+
.from('your-bucket')
76+
.upload(
77+
\`files/\${crypto.randomUUID()}\`,
78+
file,
79+
{ contentType: file.type }
80+
)
81+
if (error) throw error
82+
return new Response(
83+
JSON.stringify({ data }),
84+
{ headers: { 'Content-Type': 'application/json' }}
85+
)
5586
})`,
5687
},
5788
{
@@ -95,4 +126,177 @@ app.get(/(.*)/, (req, res) => {
95126
96127
app.listen(8000);`,
97128
},
129+
{
130+
value: 'openai-completion',
131+
name: 'OpenAI Text Completion',
132+
description: 'Generate text completions using OpenAI GPT-3',
133+
content: `// Setup type definitions for built-in Supabase Runtime APIs
134+
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
135+
import { Configuration, OpenAIApi } from 'npm:openai@3.3.0'
136+
137+
const openAi = new OpenAIApi(
138+
new Configuration({
139+
apiKey: Deno.env.get('OPENAI_API_KEY')
140+
})
141+
)
142+
143+
Deno.serve(async (req) => {
144+
const { prompt } = await req.json()
145+
const completion = await openAi.createCompletion({
146+
model: 'text-davinci-003',
147+
prompt,
148+
max_tokens: 200
149+
})
150+
return new Response(
151+
JSON.stringify({ text: completion.data.choices[0].text }),
152+
{ headers: { 'Content-Type': 'application/json' }}
153+
)
154+
})`,
155+
},
156+
{
157+
value: 'stripe-webhook',
158+
name: 'Stripe Webhook Example',
159+
description: 'Handle Stripe webhook events securely',
160+
content: `// Setup type definitions for built-in Supabase Runtime APIs
161+
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
162+
import Stripe from 'npm:stripe@12.0.0'
163+
164+
const stripe = new Stripe(Deno.env.get('STRIPE_API_KEY')!)
165+
const endpointSecret = Deno.env.get('STRIPE_WEBHOOK_SIGNING_SECRET')!
166+
167+
Deno.serve(async (req) => {
168+
const signature = req.headers.get('stripe-signature')
169+
try {
170+
const event = stripe.webhooks.constructEvent(
171+
await req.text(),
172+
signature!,
173+
endpointSecret
174+
)
175+
switch (event.type) {
176+
case 'payment_intent.succeeded':
177+
// Handle successful payment
178+
break
179+
}
180+
return new Response(JSON.stringify({ received: true }), {
181+
headers: { 'Content-Type': 'application/json' },
182+
})
183+
} catch (err) {
184+
return new Response(
185+
JSON.stringify({ error: err.message }),
186+
{ status: 400 }
187+
)
188+
}
189+
})`,
190+
},
191+
{
192+
value: 'resend-email',
193+
name: 'Send Emails',
194+
description: 'Send emails using the Resend API',
195+
content: `// Setup type definitions for built-in Supabase Runtime APIs
196+
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
197+
198+
const RESEND_API_KEY = Deno.env.get('RESEND_API_KEY')!
199+
200+
Deno.serve(async (req) => {
201+
const { to, subject, html } = await req.json()
202+
const res = await fetch('https://api.resend.com/emails', {
203+
method: 'POST',
204+
headers: {
205+
'Content-Type': 'application/json',
206+
Authorization: \`Bearer \${RESEND_API_KEY}\`,
207+
},
208+
body: JSON.stringify({
209+
from: 'you@example.com',
210+
to,
211+
subject,
212+
html,
213+
}),
214+
})
215+
const data = await res.json()
216+
return new Response(JSON.stringify(data), {
217+
headers: { 'Content-Type': 'application/json' },
218+
})
219+
})`,
220+
},
221+
{
222+
value: 'image-transform',
223+
name: 'Image Transformation',
224+
description: 'Transform images using ImageMagick WASM',
225+
content: `// Setup type definitions for built-in Supabase Runtime APIs
226+
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
227+
import {
228+
ImageMagick,
229+
initializeImageMagick,
230+
} from "npm:@imagemagick/magick-wasm@0.0.30"
231+
232+
await initializeImageMagick()
233+
234+
Deno.serve(async (req) => {
235+
const formData = await req.formData()
236+
const file = formData.get('file')
237+
const content = await file.arrayBuffer()
238+
const result = await ImageMagick.read(new Uint8Array(content), (img) => {
239+
img.resize(500, 300)
240+
img.blur(60, 5)
241+
return img.write(data => data)
242+
})
243+
return new Response(
244+
result,
245+
{ headers: { 'Content-Type': 'image/png' }}
246+
)
247+
})`,
248+
},
249+
{
250+
value: 'discord-bot',
251+
name: 'Discord Bot Example',
252+
description: 'Build a Slash Command Discord Bot',
253+
content: `// Setup type definitions for built-in Supabase Runtime APIs
254+
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
255+
import { verifyDiscordRequest } from './_shared/discord.ts'
256+
257+
Deno.serve(async (req) => {
258+
const { valid } = await verifyDiscordRequest(req)
259+
if (!valid) {
260+
return new Response('Invalid request', { status: 401 })
261+
}
262+
const message = await req.json()
263+
if (message.type === 1) {
264+
return new Response(
265+
JSON.stringify({ type: 1 }),
266+
{ headers: { 'Content-Type': 'application/json' }}
267+
)
268+
}
269+
return new Response(
270+
JSON.stringify({
271+
type: 4,
272+
data: { content: 'Hello from Supabase Edge Functions!' }
273+
}),
274+
{ headers: { 'Content-Type': 'application/json' }}
275+
)
276+
})`,
277+
},
278+
{
279+
value: 'websocket-server',
280+
name: 'Websocket Server Example',
281+
description: 'Create a real-time WebSocket server',
282+
content: `// Setup type definitions for built-in Supabase Runtime APIs
283+
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
284+
285+
Deno.serve((req) => {
286+
const upgrade = req.headers.get("upgrade") || ""
287+
if (upgrade.toLowerCase() != "websocket") {
288+
return new Response("request isn't trying to upgrade to websocket.")
289+
}
290+
const { socket, response } = Deno.upgradeWebSocket(req)
291+
socket.onopen = () => {
292+
console.log("client connected!")
293+
socket.send('Welcome to Supabase Edge Functions!')
294+
}
295+
socket.onmessage = (e) => {
296+
console.log("client sent message:", e.data)
297+
socket.send(new Date().toString())
298+
}
299+
return response
300+
})`,
301+
},
98302
]

0 commit comments

Comments
 (0)