mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Merge pull request #9925 from supabase/thor/caching-examples
Thor/caching examples
This commit is contained in:
24 files changed
+8606
No files matched your search
@@ -0,0 +1,171 @@
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
\*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
\*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
\*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
\*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
.cache/
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.\*
|
||||
|
||||
# wrangler project
|
||||
|
||||
.dev.vars
|
||||
@@ -0,0 +1,62 @@
|
||||
# Use waitUntil to perform work after Cloudflare Worker returns response
|
||||
|
||||
**[📹 Video](https://egghead.io/lessons/supabase-use-waituntil-to-perform-work-after-cloudflare-worker-returns-response?af=9qsk0a)**
|
||||
|
||||
The `waitUntil` function allows us to continue performing work in our Cloudflare Worker, after a response has been sent back to the client.
|
||||
|
||||
In this lesson, we modify the `revalidate` route to send a response immediately, and then continue on to fetch new data and refresh our KV store.
|
||||
|
||||
Finally, we use the Thunder Client extension to simulate a POST request to the `revalidate` route, and confirm that this receives a response before the cache is updated.
|
||||
|
||||
## Code Snippets
|
||||
|
||||
**Update Revalidate route to respond immediately**
|
||||
|
||||
```javascript
|
||||
router.post(
|
||||
"/revalidate",
|
||||
withContent,
|
||||
async (request, { SUPABASE_URL, SUPABASE_ANON_KEY, ARTICLES }, context) => {
|
||||
const updateCache = async () => {
|
||||
const { type, record, old_record } = request.content;
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
|
||||
|
||||
if (type === "INSERT" || type === "UPDATE") {
|
||||
await writeTo(ARTICLES, `/articles/${record.id}`, record);
|
||||
}
|
||||
|
||||
if (type === "DELETE") {
|
||||
await ARTICLES.delete(`/articles/${old_record.id}`);
|
||||
}
|
||||
|
||||
const { data: articles } = await supabase.from("articles").select("*");
|
||||
await writeTo(ARTICLES, "/articles", articles);
|
||||
console.log("updated cache");
|
||||
};
|
||||
|
||||
context.waitUntil(updateCache());
|
||||
|
||||
console.log("sending response");
|
||||
|
||||
return json({ received: true });
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
**Run wrangler development server**
|
||||
|
||||
```bash
|
||||
npx wrangler dev
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [Cloudflare waitUntil docs](https://developers.cloudflare.com/workers/runtime-apis/scheduled-event/)
|
||||
- [Supabase.js docs](https://github.com/supabase/supabase-js)
|
||||
- [Wrangler CLI docs](https://developers.cloudflare.com/workers/wrangler/commands/)
|
||||
- [KV Storage docs](https://developers.cloudflare.com/workers/runtime-apis/kv/)
|
||||
- [Thunder Client VS Code extension](https://marketplace.visualstudio.com/items?itemName=rangav.vscode-thunder-client)
|
||||
|
||||
---
|
||||
|
||||
Enjoying the course? Follow Jon Meyers on [Twitter](https://twitter.com/jonmeyers_io) and subscribe to the [YouTube channel](https://www.youtube.com/c/jonmeyers).
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "supabase-at-the-edge",
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"wrangler": "2.0.16"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "wrangler dev",
|
||||
"deploy": "wrangler publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^1.35.4",
|
||||
"itty-router": "^2.6.1",
|
||||
"itty-router-extras": "^0.4.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import { Router } from "itty-router";
|
||||
import { json, status, withContent } from "itty-router-extras";
|
||||
import { readFrom, writeTo } from "./utils/cache";
|
||||
|
||||
const router = new Router();
|
||||
|
||||
router.get("/read-kv", async (request, { ARTICLES }) => {
|
||||
const articles = await readFrom(ARTICLES, "/articles");
|
||||
return json(articles);
|
||||
});
|
||||
|
||||
router.get("/write-kv", async (request, { ARTICLES }) => {
|
||||
const articles = [{ title: "test3" }, { title: "test4" }];
|
||||
await writeTo(ARTICLES, "/articles", articles);
|
||||
|
||||
return json(articles);
|
||||
});
|
||||
|
||||
router.get(
|
||||
"/articles",
|
||||
async (request, { SUPABASE_URL, SUPABASE_ANON_KEY, ARTICLES }) => {
|
||||
const cachedArticles = await readFrom(ARTICLES, "/articles");
|
||||
|
||||
if (cachedArticles) {
|
||||
console.log("sending the cache");
|
||||
return json(cachedArticles);
|
||||
}
|
||||
|
||||
console.log("fetching fresh articles");
|
||||
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
|
||||
|
||||
const { data } = await supabase.from("articles").select("*");
|
||||
await writeTo(ARTICLES, "/articles", data);
|
||||
return json(data);
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/articles/:id",
|
||||
async (request, { SUPABASE_URL, SUPABASE_ANON_KEY, ARTICLES }) => {
|
||||
const { id } = request.params;
|
||||
const cachedArticle = await readFrom(ARTICLES, `/articles/${id}`);
|
||||
|
||||
if (cachedArticle) {
|
||||
console.log("sending the cache");
|
||||
return json(cachedArticle);
|
||||
}
|
||||
|
||||
console.log("fetching fresh article");
|
||||
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
|
||||
|
||||
const { data } = await supabase
|
||||
.from("articles")
|
||||
.select("*")
|
||||
.match({ id })
|
||||
.single();
|
||||
|
||||
await writeTo(ARTICLES, `/articles/${id}`, data);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/revalidate",
|
||||
withContent,
|
||||
async (request, { SUPABASE_URL, SUPABASE_ANON_KEY, ARTICLES }, context) => {
|
||||
const updateCache = async () => {
|
||||
const { type, record, old_record } = request.content;
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
|
||||
|
||||
if (type === "INSERT" || type === "UPDATE") {
|
||||
await writeTo(ARTICLES, `/articles/${record.id}`, record);
|
||||
}
|
||||
|
||||
if (type === "DELETE") {
|
||||
await ARTICLES.delete(`/articles/${old_record.id}`);
|
||||
}
|
||||
|
||||
const { data: articles } = await supabase.from("articles").select("*");
|
||||
await writeTo(ARTICLES, "/articles", articles);
|
||||
console.log("updated cache");
|
||||
};
|
||||
|
||||
context.waitUntil(updateCache());
|
||||
|
||||
console.log("sending response");
|
||||
|
||||
return json({ received: true });
|
||||
}
|
||||
);
|
||||
|
||||
router.all("*", () => status(404, "Not found"));
|
||||
|
||||
export default {
|
||||
fetch: router.handle,
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
export const readFrom = async (cache, path) => {
|
||||
const data = await cache.get(path);
|
||||
return JSON.parse(data);
|
||||
};
|
||||
|
||||
export const writeTo = async (cache, path, data) => {
|
||||
await cache.put(path, JSON.stringify(data));
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
name = "supabase-at-the-edge"
|
||||
main = "src/index.js"
|
||||
compatibility_date = "2022-07-07"
|
||||
|
||||
kv_namespaces = [
|
||||
{ binding = "replace-with-your-kv-name", id = "replace-with-your-kv-production-id", preview_id = "replace-with-your-kv-preview-id" }
|
||||
]
|
||||
@@ -0,0 +1,2 @@
|
||||
NEXT_PUBLIC_SUPABASE_URL=
|
||||
SUPABASE_SERVICE_ROLE_KEY=
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
.vscode
|
||||
@@ -0,0 +1,44 @@
|
||||
# Caching data at the edge with Next.js 13 and Supabase
|
||||
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
It showcases how to [fetch and cache data](// See the docs: https://beta.nextjs.org/docs/data-fetching/caching) at the Edge with Next.js and Supabase.
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, start Supabase locally and seed your local development database with the [Supabase CLI](https://supabase.com/docs/reference/cli):
|
||||
|
||||
```bash
|
||||
supabase start
|
||||
```
|
||||
|
||||
Next, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
|
||||
|
||||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||
@@ -0,0 +1,26 @@
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
||||
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
color-scheme: dark;
|
||||
}
|
||||
body {
|
||||
color: white;
|
||||
background: black;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import './globals.css'
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Create Next App</title>
|
||||
<meta name="description" content="Generated by create next app" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Caching data at the edge with Next.js 13 and Supabase
|
||||
// See the docs: https://beta.nextjs.org/docs/data-fetching/caching
|
||||
import 'server-only'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL ?? 'http://localhost:54321',
|
||||
process.env.SUPABASE_SERVICE_ROLE_KEY ??
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSJ9.vI9obAHOGyVVKa3pD--kJlyxp-Z2zV9UUMAhKpNLAcU'
|
||||
)
|
||||
|
||||
export const config = {
|
||||
runtime: 'experimental-edge',
|
||||
}
|
||||
export const revalidate = 60 // revalidate this page at most every 60 seconds
|
||||
|
||||
export default async function PostList() {
|
||||
const { data, error } = await supabase.from('articles').select('*')
|
||||
|
||||
return <pre>{JSON.stringify({ data, error }, null, 2)}</pre>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
experimental: {
|
||||
appDir: true,
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
+5751
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "with-nextjs-13",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^2.0.4",
|
||||
"next": "13.0.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"server-only": "^0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.11.7",
|
||||
"@types/react": "18.0.24",
|
||||
"@types/react-dom": "18.0.8",
|
||||
"eslint": "8.26.0",
|
||||
"eslint-config-next": "13.0.0",
|
||||
"typescript": "4.8.4"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,3 @@
|
||||
# Supabase
|
||||
.branches
|
||||
.temp
|
||||
@@ -0,0 +1,71 @@
|
||||
# A string used to distinguish different Supabase projects on the same host. Defaults to the working
|
||||
# directory name when running `supabase init`.
|
||||
project_id = "with-nextjs-13"
|
||||
|
||||
[api]
|
||||
# Port to use for the API URL.
|
||||
port = 54321
|
||||
# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
|
||||
# endpoints. public and storage are always included.
|
||||
schemas = []
|
||||
# Extra schemas to add to the search_path of every request.
|
||||
extra_search_path = ["extensions"]
|
||||
# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
|
||||
# for accidental or malicious requests.
|
||||
max_rows = 1000
|
||||
|
||||
[db]
|
||||
# Port to use for the local database URL.
|
||||
port = 54322
|
||||
# The database major version to use. This has to be the same as your remote database's. Run `SHOW
|
||||
# server_version;` on the remote database to check.
|
||||
major_version = 14
|
||||
|
||||
[studio]
|
||||
# Port to use for Supabase Studio.
|
||||
port = 54323
|
||||
|
||||
# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they
|
||||
# are monitored, and you can view the emails that would have been sent from the web interface.
|
||||
[inbucket]
|
||||
# Port to use for the email testing server web interface.
|
||||
port = 54324
|
||||
smtp_port = 54325
|
||||
pop3_port = 54326
|
||||
|
||||
[storage]
|
||||
# The maximum file size allowed (e.g. "5MB", "500KB").
|
||||
file_size_limit = "50MiB"
|
||||
|
||||
[auth]
|
||||
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
|
||||
# in emails.
|
||||
site_url = "http://localhost:3000"
|
||||
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
|
||||
additional_redirect_urls = ["https://localhost:3000"]
|
||||
# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one
|
||||
# week).
|
||||
jwt_expiry = 3600
|
||||
# Allow/disallow new user signups to your project.
|
||||
enable_signup = true
|
||||
|
||||
[auth.email]
|
||||
# Allow/disallow new user signups via email to your project.
|
||||
enable_signup = true
|
||||
# If enabled, a user will be required to confirm any email change on both the old, and new email
|
||||
# addresses. If disabled, only the new email is required to confirm.
|
||||
double_confirm_changes = true
|
||||
# If enabled, users need to confirm their email address before signing in.
|
||||
enable_confirmations = false
|
||||
|
||||
# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
|
||||
# `discord`, `facebook`, `github`, `gitlab`, `google`, `twitch`, `twitter`, `slack`, `spotify`.
|
||||
[auth.external.apple]
|
||||
enabled = false
|
||||
client_id = ""
|
||||
secret = ""
|
||||
# Overrides the default auth redirectUrl.
|
||||
redirect_uri = ""
|
||||
# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure,
|
||||
# or any other third-party OIDC providers.
|
||||
url = ""
|
||||
@@ -0,0 +1,7 @@
|
||||
create table if not exists articles (
|
||||
id uuid default uuid_generate_v4() primary key,
|
||||
created_at timestamp with time zone default timezone('utc'::text, now()) not null,
|
||||
title text not null,
|
||||
content text not null,
|
||||
is_published bool default false not null
|
||||
);
|
||||
@@ -0,0 +1,5 @@
|
||||
insert into articles(title, content)
|
||||
values
|
||||
('First blog', 'This is my very first blog'),
|
||||
('Second blog', 'I am really enjoying writing blogs'),
|
||||
('Third blog', 'Okay, this is getting hard to maintain');
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in new issue
Block a user