惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
N
News and Events Feed by Topic
D
DataBreaches.Net
MongoDB | Blog
MongoDB | Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Engineering at Meta
Engineering at Meta
T
Tailwind CSS Blog
博客园_首页
Microsoft Azure Blog
Microsoft Azure Blog
Y
Y Combinator Blog
博客园 - Franky
Hugging Face - Blog
Hugging Face - Blog
月光博客
月光博客
A
About on SuperTechFans
I
InfoQ
S
Securelist
Last Week in AI
Last Week in AI
S
Schneier on Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
Hacker News: Ask HN
Hacker News: Ask HN
Schneier on Security
Schneier on Security
Know Your Adversary
Know Your Adversary
腾讯CDC
大猫的无限游戏
大猫的无限游戏
S
Security @ Cisco Blogs
博客园 - 三生石上(FineUI控件)
Simon Willison's Weblog
Simon Willison's Weblog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tor Project blog
美团技术团队
aimingoo的专栏
aimingoo的专栏
G
Google Developers Blog
罗磊的独立博客
Vercel News
Vercel News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
The Cloudflare Blog
S
Secure Thoughts
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Latest news
Latest news
Recent Announcements
Recent Announcements
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
L
LINUX DO - 热门话题
Security Latest
Security Latest
TaoSecurity Blog
TaoSecurity Blog
Cyberwarzone
Cyberwarzone
有赞技术团队
有赞技术团队

Supabase Blog

AI Agents Know About Supabase. They Don't Always Use It Right. Custom OIDC Providers for Supabase Auth 100,000 GitHub stars Supabase docs over SSH Navigating Regional Network Blocks Supabase Joins the Stripe Projects Developer Preview Log Drains: Now available on Pro Supabase Storage: major performance, security, and reliability updates Supabase incident on February 12, 2026 Hydra joins Supabase X / Twitter OAuth 2.0 is now available for Supabase Auth BKND joins Supabase Supabase is now an official Claude connector Supabase PrivateLink is now available Introducing: Postgres Best Practices When to use Read Replicas vs. bigger compute Introducing TRAE SOLO integration with Supabase Supabase Security Retro: 2025 Sync Stripe Data to Your Supabase Database in One Click Building ChatGPT Apps with Supabase Edge Functions and mcp-use Own Your Observability: Supabase Metrics API Introducing iceberg-js: A JavaScript Client for Apache Iceberg Introducing Supabase for Platforms Adding Async Streaming to Postgres Foreign Data Wrappers Build "Sign in with Your App" using Supabase Auth Introducing Seven New Email Templates for Supabase Auth The new Supabase power for Kiro Introducing Supabase ETL Introducing Analytics Buckets Introducing Vector Buckets Snap, Inc. Launches Snap Cloud, Powered by Supabase Triplit joins Supabase Supabase Series E 1000 Y Combinator Founders Choose Supabase gm 👋 web3, welcome aboard to Sign in with Web3 (Solana, Ethereum) Announcing the Supabase Remote MCP Server Enterprise speed, enterprise standards with Bolt Cloud + Supabase PostgREST 13 Lovable Cloud + Supabase: The Default Platform for AI Builders Processing large jobs with Edge Functions, Cron, and Queues Defense in Depth for MCP Servers OrioleDB Patent: now freely available to the Postgres community Supabase Launch Week 15 Hackathon Winner Announcement The Vibe Coder's Guide to Supabase Environments Testing for Vibe Coders: From Zero to Production Confidence The Vibe Coding Master Checklist Vibe Coding: Best Practices for Prompting Supabase Auth: Build vs. Buy Top 10 Launches of Launch Week 15 Supabase Launch Week 15 Hackathon Storage: 10x Larger Uploads, 3x Cheaper Cached Egress, and 2x Egress Quota Persistent Storage and 97% Faster Cold Starts for Edge Functions Algolia Connector for Supabase New Observability Features in Supabase Improved Security Controls and A New Home for Security Introducing Branching 2.0 Stripe-To-Postgres Sync Engine as standalone Library Supabase Analytics Buckets with Iceberg Support Create a Supabase backend using Figma Make Introducing JWT Signing Keys Supabase UI: Platform Kit Build a Personalized AI Assistant with Postgres Announcing Multigres: Vitess for Postgres Building on open table formats Open Data Standards: Postgres, OTel, and Iceberg Simplifying back-end complexity with Supabase Data APIs PostgreSQL Event Triggers without superuser access Top 10 Launches of Launch Week 14 Supabase MCP Server Data API Routes to Nearest Read Replica Declarative Schemas for Simpler Database Management Realtime: Broadcast from Database Keeping Tabs on What's New in Supabase Studio Edge Functions: Deploy from the Dashboard + Deno 2.1 Automatic Embeddings in Postgres Introducing the Supabase UI Library Supabase Auth: Bring Your Own Clerk Postgres Language Server: Initial Release Migrating from Fauna to Supabase Migrating from the MongoDB Data API to Supabase Dedicated Poolers Postgres as a Graph Database: (Ab)using pgRouting AI Hackathon at Y Combinator Calendars in Postgres using Foreign Data Wrappers Supabase Launch Week 13 Hackathon Winners How to Hack the Base! Running Durable Workflows in Postgres using DBOS database.build v2: Bring-your-own-LLM Restore to a New Project Hack the Base! with Supabase Top 10 Launches of Launch Week 13 Supabase Queues High Performance Disk Supabase Cron Supabase CLI v2: Config as Code Supabase Edge Functions: Introducing Background Tasks, Ephemeral Storage, and WebSockets Supabase AI Assistant v2 OrioleDB Public Alpha Executing Dynamic JavaScript Code on Supabase with Edge Functions ClickHouse Partnership, improved Postgres Replication, and Disk Management
Building ChatGPT Plugins with Supabase Edge Runtime
Thor Schaeff · 2023-05-15 · via Supabase Blog

Building ChatGPT Plugins with Supabase Edge Runtime

ChatGPT Plugins support is rolling out in beta this week! To help you get up and running quickly, we're releasing a plugin template written in TypeScript and running on Supabase Edge Runtime!

Want to get started right away? Fork the template on GitHub!

The ai-plugin.json manifest file is required for ChatGPT to identify our plugin, know what kind of authentication mechanism is used, understand where to find the OpenAPI definition, and some other details about our plugin. You can find the full list of supported parameters in the OpenAI docs.

Supabase Edge Runtime does currently not support hosting/serving of static files, however, we can import JSON files in our function and serve them as a JSON response. As this needs to be at the root of our domain, we add this to our main function handler:


_11

// functions/main/index.ts

_11

import aiPlugins from './ai-plugins.json' with { type: 'json' }

_11

_11

// [...]

_11

_11

// Serve /.well-known/ai-plugin.json

_11

if (service_name === '.well-known') {

_11

return new Response(JSON.stringify(aiPlugins), {

_11

headers: { ...corsHeaders, 'Content-Type': 'application/json' },

_11

})

_11

}


Now, when running Edge Runtime locally via Docker, our plugin manifest will be available at http://localhost:8000/.well-known/ai-plugin.json

The OpenAPI definition is required for ChatGPT to know how to underact with our API. Only endpoints included in there will be exposed to ChatGPT, which allows you to selectively make our endpoints available, or add specific endpoints for ChatGPT.

The OpenAPI definition can be either in YAML or JSON format. We’ll be using JSON and the same approach as above to serve it. Writing an OpenAPI definition is not something we will want to do by hand, luckily there is an open source tool called swagger-jsdoc which we can use to annotate our endpoints with JSDoc comments and generate the OpenAPI definition with a little script.


_22

// /scripts/generate-openapi-spec.ts

_22

import swaggerJsdoc from 'npm:swagger-jsdoc@6.2.8'

_22

_22

const options = {

_22

definition: {

_22

openapi: '3.0.1',

_22

info: {

_22

title: 'TODO Plugin',

_22

description: `A plugin that allows the user to create and manage a TODO list using ChatGPT. If you do not know the user's username, ask them first before making queries to the plugin. Otherwise, use the username "global".`,

_22

version: '1.0.0',

_22

},

_22

servers: [{ url: 'http://localhost:8000' }],

_22

},

_22

apis: ['./functions/chatgpt-plugin/index.ts'], // files containing annotations as above

_22

}

_22

_22

const openapiSpecification = swaggerJsdoc(options)

_22

const openapiString = JSON.stringify(openapiSpecification, null, 2)

_22

const encoder = new TextEncoder()

_22

const data = encoder.encode(openapiString)

_22

await Deno.writeFile('./functions/chatgpt-plugin/openapi.json', data)

_22

console.log(openapiString)


Since this script is run outside of the function execution, e.g. as a GitHub Action, we can use npm specifiers to import swagger-jsdoc.

Next, we create our /functions/chatgpt-plugin/index.ts file where we use the Deno oak router to build our API and annotate it with JSDOC comments.


_64

// /functions/chatgpt-plugin/index.ts

_64

import { Application, Router } from 'https://deno.land/x/oak@v11.1.0/mod.ts'

_64

import openapi from './openapi.json' with { type: 'json' }

_64

_64

console.log('Hello from `chatgpt-plugin` Function!')

_64

_64

const _TODOS: { [key: string]: Array<string> } = {

_64

user: ['Build your own ChatGPT Plugin!'],

_64

}

_64

_64

/**

_64

* @openapi

_64

* components:

_64

* schemas:

_64

* getTodosResponse:

_64

* type: object

_64

* properties:

_64

* todos:

_64

* type: array

_64

* items:

_64

* type: string

_64

* description: The list of todos.

_64

*/

_64

_64

const router = new Router()

_64

router

_64

.get('/chatgpt-plugin', (ctx) => {

_64

ctx.response.body = 'Building ChatGPT plugins with Deno!'

_64

})

_64

/**

_64

* @openapi

_64

* /chatgpt-plugin/todos/{username}:

_64

* get:

_64

* operationId: getTodos

_64

* summary: Get the list of todos

_64

* parameters:

_64

* - in: path

_64

* name: username

_64

* schema:

_64

* type: string

_64

* required: true

_64

* description: The name of the user.

_64

* responses:

_64

* 200:

_64

* description: OK

_64

* content:

_64

* application/json:

_64

* schema:

_64

* $ref: '#/components/schemas/getTodosResponse'

_64

*/

_64

.get('/chatgpt-plugin/todos/:username', (ctx) => {

_64

const username = ctx.params.username.toLowerCase()

_64

ctx.response.body = _TODOS[username] ?? []

_64

})

_64

.get('/chatgpt-plugin/openapi.json', (ctx) => {

_64

ctx.response.body = JSON.stringify(openapi)

_64

ctx.response.headers.set('Content-Type', 'application/json')

_64

})

_64

_64

const app = new Application()

_64

app.use(router.routes())

_64

app.use(router.allowedMethods())

_64

_64

await app.listen({ port: 8000 })


With our JSDoc annotation in place, we can now run the generation script in the terminal:


_10

deno run --allow-read --allow-write scripts/generate-openapi-spec.ts


Lastly, we need to add some CORS headers to make the browser happy. We define them in a /functions/_shared/cors.ts file so we can easily reuse them across our main and chatgpt-plugins function.


_10

// /functions/_shared/cors.ts

_10

export const corsHeaders = {

_10

'Access-Control-Allow-Origin': 'https://chat.openai.com',

_10

'Access-Control-Allow-Credentials': 'true',

_10

'Access-Control-Allow-Private-Network': 'true',

_10

'Access-Control-Allow-Headers': '*',

_10

}


Now we can easily add them to all our chatgpt-plugin routes a middleware for our oak application.


_18

// /functions/chatgpt-plugin/index.ts

_18

import { Application, Router } from 'https://deno.land/x/oak@v11.1.0/mod.ts'

_18

import { corsHeaders } from '../_shared/cors.ts'

_18

_18

// [...]

_18

const app = new Application()

_18

// ChatGPT specific CORS headers

_18

app.use(async (ctx, next) => {

_18

await next()

_18

let key: keyof typeof corsHeaders

_18

for (key in corsHeaders) {

_18

ctx.response.headers.set(key, corsHeaders[key])

_18

}

_18

})

_18

app.use(router.routes())

_18

app.use(router.allowedMethods())

_18

_18

await app.listen({ port: 8000 })


Now that we’ve got all the pieces in place, let’s spin up Edge Runtime locally and test things out. For this, we need a Dockerfile and for convenience, we can add a docker-compose file also.


_10

// Dockerfile

_10

FROM ghcr.io/supabase/edge-runtime:v1.2.18

_10

_10

COPY ./functions /home/deno/functions

_10

CMD [ "start", "--main-service", "/home/deno/functions/main" ]


This will pull down Edge Runtime v1.2.18 (you can check the latest release here) and start up the main service (our /functions/main/index.ts function).


_11

// docker-compose.yml

_11

version: "3.9"

_11

services:

_11

web:

_11

build: .

_11

volumes:

_11

- type: bind

_11

source: ./functions

_11

target: /home/deno/functions

_11

ports:

_11

- "8000:9000"


Edge Runtime will serve requests on port 9000, so we’re creating a mapping from [localhost:8000](http://localhost:8000) where we want to serve our requests locally (of course you can adapt this to your needs) to port 9000 of our Docker container.

Furthermore, we’re using bind mounts to mount our functions directory into the container. This allows us to make modifications to our functions without needing to rebuild the container after, making for a great local developer experience.

That’s it, now we can build and spin up our container from the terminal:


_10

docker compose up --build


Go ahead and try it out by visiting:

You can conveniently test your plugin while running it on localhost using the ChatGPT UI:

  1. Select the plugin model from the top drop down, then select “Plugins”, “Plugin Store”, and finally “Develop your own plugin”.
  2. Enter localhost:8000 and click "Find manifest file".
  3. Confirm with “Install localhost plugin”.

That’s it, now go ahead and ask some questions, e.g. you can start with “Do I have any todos?”

There you are, now go ahead and build your own plugin as it says on your todo list ;)

Once you’re happy with the functionality of your plugin, go ahead and deploy it to Fly.io. After installing the flyctl cli, it only takes a couple of steps:

  • Change http://localhost:8000 to your Fly domain in the /main/ai-plugins.json file
  • Open fly.toml and update the app name and optionally the region etc.
  • In your terminal, run fly apps create and specify the app name you just set in your fly.toml file.
  • Finally, run fly deploy.

There you go, now you’re ready to release your plugin to the world \o/

ChatGPT is a powerful new interface and its usage is growing rapidly. With ChatGPT Plugins you can allow your users to access your service directly from ChatGPT, using cutting edge technologies like TypeScript and Deno.

In a next step you can add authentication to your plugin, let us know on Twitter if you’d be interested in a tutorial for that. We can’t wait to see what you will build!