Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore (examples): Add authentication to the examples #2248

Merged
merged 21 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/workflows/deploy_all_examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,14 @@ jobs:
working-directory: ./examples/linearlite-read-only
run: pnpm sst deploy --stage production

- name: Deploy Linearlite
working-directory: ./examples/linearlite
run: pnpm sst deploy --stage production
# - name: Deploy Linearlite
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're keeping this one out because it needs more work.

# working-directory: ./examples/linearlite
# run: pnpm sst deploy --stage production

- name: Deploy NextJs example
working-directory: ./examples/nextjs
run: pnpm sst deploy --stage production

- name: Deploy Yjs example
working-directory: ./examples/yjs
run: pnpm sst deploy --stage production
59 changes: 59 additions & 0 deletions .github/workflows/deploy_examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ jobs:
ELECTRIC_API: ${{ secrets.ELECTRIC_API }}
ELECTRIC_ADMIN_API: ${{ secrets.ELECTRIC_ADMIN_API }}
ELECTRIC_TEAM_ID: ${{ secrets.ELECTRIC_TEAM_ID }}
ELECTRIC_ADMIN_API_TOKEN_ID: ${{ secrets.ELECTRIC_ADMIN_API_TOKEN_ID }}
ELECTRIC_ADMIN_API_TOKEN_SECRET: ${{ secrets.ELECTRIC_ADMIN_API_TOKEN_SECRET }}
# HONEYCOMB_API_KEY: ${{ secrets.HONEYCOMB_API_KEY }} TODO

steps:
Expand All @@ -47,6 +49,18 @@ jobs:
restore-keys: |
sst-cache-main-${{ runner.os }}

- name: Deploy Yjs example
working-directory: ./examples/yjs
run: |
pnpm sst deploy --stage ${{ env.DEPLOY_ENV }}
if [ -f ".sst/outputs.json" ]; then
yjs=$(jq -r '.website' .sst/outputs.json)
echo "yjs=$yjs" >> $GITHUB_ENV
else
echo "sst outputs file not found. Exiting."
exit 123
fi

- name: Deploy Linearlite Read Only
working-directory: ./examples/linearlite-read-only
run: |
Expand All @@ -59,6 +73,19 @@ jobs:
exit 123
fi

- name: Deploy Write Patterns example
working-directory: ./examples/write-patterns
run: |
pnpm --filter @electric-sql/client --filter @electric-sql/experimental --filter @electric-sql/react run build
pnpm sst deploy --stage ${{ env.DEPLOY_ENV }}
if [ -f ".sst/outputs.json" ]; then
writes=$(jq -r '.website' .sst/outputs.json)
echo "writes=$writes" >> $GITHUB_ENV
else
echo "sst outputs file not found. Exiting."
exit 123
fi

- name: Deploy NextJs example
working-directory: ./examples/nextjs
run: |
Expand All @@ -71,6 +98,30 @@ jobs:
exit 123
fi

- name: Deploy TODO App example
working-directory: ./examples/todo-app
run: |
pnpm sst deploy --stage ${{ env.DEPLOY_ENV }}
if [ -f ".sst/outputs.json" ]; then
todoapp=$(jq -r '.website' .sst/outputs.json)
echo "todoapp=$todoapp" >> $GITHUB_ENV
else
echo "sst outputs file not found. Exiting."
exit 123
fi

- name: Deploy proxy-auth example
working-directory: ./examples/proxy-auth
run: |
pnpm sst deploy --stage ${{ env.DEPLOY_ENV }}
if [ -f ".sst/outputs.json" ]; then
auth=$(jq -r '.website' .sst/outputs.json)
echo "auth=$auth" >> $GITHUB_ENV
else
echo "sst outputs file not found. Exiting."
exit 123
fi

- name: Add comment to PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
Expand All @@ -79,11 +130,19 @@ jobs:
script: |
const linearlite_read_only = process.env.linearlite_read_only;
const nextjs = process.env.nextjs;
const todoapp = process.env.todoapp;
const yjs = process.env.yjs;
const writes = process.env.writes;
const auth = process.env.auth;

const prNumber = context.issue.number;
const commentBody = `## Examples
- linearlite-read-only: ${linearlite_read_only}
- nextjs: ${nextjs}
- todoapp: ${todoapp}
- yjs: ${yjs}
- writes: ${writes}
- auth: ${auth}
`;

const { data: comments } = await github.rest.issues.listComments({
Expand Down
4 changes: 2 additions & 2 deletions examples/linearlite-read-only/src/electric.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const baseUrl = import.meta.env.VITE_ELECTRIC_URL
? new URL(import.meta.env.VITE_ELECTRIC_URL).origin
: `http://localhost:3000`
export const token = import.meta.env.VITE_ELECTRIC_TOKEN ?? ``
export const databaseId = import.meta.env.VITE_DATABASE_ID ?? ``
export const source_secret = import.meta.env.VITE_ELECTRIC_SOURCE_SECRET ?? ``
export const source_id = import.meta.env.VITE_ELECTRIC_SOURCE_ID ?? ``
6 changes: 3 additions & 3 deletions examples/linearlite-read-only/src/pages/Issue/Comments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { formatDate } from '../../utils/date'
import { showWarning } from '../../utils/notification'
import { Comment, Issue } from '../../types/types'
import { useShape } from '@electric-sql/react'
import { baseUrl, databaseId, token } from '../../electric'
import { baseUrl, source_id, source_secret } from '../../electric'

export interface CommentsProps {
issue: Issue
Expand All @@ -19,8 +19,8 @@ function Comments(commentProps: CommentsProps) {
const allComments = useShape({
url: `${baseUrl}/v1/shape`,
params: {
token,
source_id: databaseId,
source_secret,
source_id,
table: `comment`,
},
})! as Comment[]
Expand Down
6 changes: 3 additions & 3 deletions examples/linearlite-read-only/src/shapes.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ShapeStreamOptions } from '@electric-sql/client'
import { baseUrl, databaseId, token } from './electric'
import { baseUrl, source_id, source_secret } from './electric'

export const issueShape: ShapeStreamOptions = {
url: `${baseUrl}/v1/shape/`,
params: {
table: `issue`,
token,
source_id: databaseId,
source_secret,
source_id,
},
}
4 changes: 2 additions & 2 deletions examples/linearlite-read-only/src/sst-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_ELECTRIC_URL: string
readonly VITE_ELECTRIC_TOKEN: string
readonly VITE_DATABASE_ID: string
readonly VITE_ELECTRIC_SOURCE_SECRET: string
readonly VITE_ELECTRIC_SOURCE_ID: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
Expand Down
31 changes: 23 additions & 8 deletions examples/linearlite-read-only/sst.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

import { execSync } from 'child_process'

const adminApiTokenId = process.env.ELECTRIC_ADMIN_API_TOKEN_ID
const adminApiTokenSecret = process.env.ELECTRIC_ADMIN_API_TOKEN_SECRET

export default $config({
app(input) {
return {
Expand All @@ -12,7 +15,7 @@ export default $config({
providers: {
cloudflare: `5.42.0`,
aws: {
version: `6.57.0`,
version: `6.66.2`,
profile: process.env.CI ? undefined : `marketing`,
},
neon: `0.6.3`,
Expand All @@ -21,6 +24,14 @@ export default $config({
}
},
async run() {
if (!$dev && !process.env.ELECTRIC_ADMIN_API_TOKEN_ID) {
throw new Error(`ELECTRIC_ADMIN_API_TOKEN_ID is not set`)
}

if (!$dev && !process.env.ELECTRIC_ADMIN_API_TOKEN_SECRET) {
throw new Error(`ELECTRIC_ADMIN_API_TOKEN_ID is not set`)
}

const project = neon.getProjectOutput({ id: process.env.NEON_PROJECT_ID! })

const dbName = `linearlite-read-only-${$app.stage}`
Expand Down Expand Up @@ -53,8 +64,8 @@ export default $config({
const website = deployLinearLite(electricInfo)
return {
databaseUri,
database_id: electricInfo.id,
electric_token: electricInfo.token,
// source_id: electricInfo.id,
// source_secret: electricInfo.source_secret,
website: website.url,
}
} catch (e) {
Expand Down Expand Up @@ -82,13 +93,13 @@ function loadData(uri: string) {
}

function deployLinearLite(
electricInfo: $util.Output<{ id: string; token: string }>
electricInfo: $util.Output<{ id: string; source_secret: string }>
) {
return new sst.aws.StaticSite(`linearlite-read-only`, {
environment: {
VITE_ELECTRIC_URL: process.env.ELECTRIC_API!,
VITE_ELECTRIC_TOKEN: electricInfo.token,
VITE_DATABASE_ID: electricInfo.id,
VITE_ELECTRIC_SOURCE_SECRET: electricInfo.source_secret,
VITE_ELECTRIC_SOURCE_ID: electricInfo.id,
},
build: {
command: `pnpm run --filter @electric-sql/client --filter @electric-sql/react --filter @electric-examples/linearlite-read-only build`,
Expand All @@ -103,13 +114,17 @@ function deployLinearLite(

async function addDatabaseToElectric(
uri: string
): Promise<{ id: string; token: string }> {
): Promise<{ id: string; source_secret: string }> {
const adminApi = process.env.ELECTRIC_ADMIN_API
const teamId = process.env.ELECTRIC_TEAM_ID

const result = await fetch(`${adminApi}/v1/sources`, {
method: `PUT`,
headers: { 'Content-Type': `application/json` },
headers: {
'Content-Type': `application/json`,
'CF-Access-Client-Id': adminApiTokenId ?? ``,
'CF-Access-Client-Secret': adminApiTokenSecret ?? ``,
},
body: JSON.stringify({
database_url: uri,
region: `us-east-1`,
Expand Down
16 changes: 8 additions & 8 deletions examples/linearlite/src/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ const WRITE_SERVER_URL = import.meta.env.VITE_WRITE_SERVER_URL
const ELECTRIC_URL = import.meta.env.VITE_ELECTRIC_URL
? new URL(import.meta.env.VITE_ELECTRIC_URL).origin
: `http://localhost:3000`
const ELECTRIC_DATABASE_ID = import.meta.env.VITE_ELECTRIC_DATABASE_ID
const ELECTRIC_TOKEN = import.meta.env.VITE_ELECTRIC_TOKEN
const ELECTRIC_SOURCE_ID = import.meta.env.VITE_ELECTRIC_SOURCE_ID
const ELECTRIC_SOURCE_SECRET = import.meta.env.VITE_ELECTRIC_SOURCE_SECRET
const APPLY_CHANGES_URL = `${WRITE_SERVER_URL}/apply-changes`

type SyncStatus = 'initial-sync' | 'done'
Expand Down Expand Up @@ -57,8 +57,8 @@ async function startSyncToDatabase(pg: PGliteWithExtensions) {
}

const issueUrl = new URL(`${ELECTRIC_URL}/v1/shape`)
if (ELECTRIC_TOKEN) {
issueUrl.searchParams.set('token', ELECTRIC_TOKEN)
if (ELECTRIC_SOURCE_SECRET) {
issueUrl.searchParams.set('source_secret', ELECTRIC_SOURCE_SECRET)
}

// Issues Sync
Expand All @@ -67,7 +67,7 @@ async function startSyncToDatabase(pg: PGliteWithExtensions) {
url: issueUrl.toString(),
params: {
table: 'issue',
source_id: ELECTRIC_DATABASE_ID,
source_id: ELECTRIC_SOURCE_ID,
},
},
table: 'issue',
Expand All @@ -93,8 +93,8 @@ async function startSyncToDatabase(pg: PGliteWithExtensions) {
)

const commentUrl = new URL(`${ELECTRIC_URL}/v1/shape`)
if (ELECTRIC_TOKEN) {
commentUrl.searchParams.set('token', ELECTRIC_TOKEN)
if (ELECTRIC_SOURCE_SECRET) {
commentUrl.searchParams.set('source_secret', ELECTRIC_SOURCE_SECRET)
}

// Comments Sync
Expand All @@ -103,7 +103,7 @@ async function startSyncToDatabase(pg: PGliteWithExtensions) {
url: commentUrl.toString(),
params: {
table: 'comment',
source_id: ELECTRIC_DATABASE_ID,
source_id: ELECTRIC_SOURCE_ID,
},
},
table: 'comment',
Expand Down
29 changes: 22 additions & 7 deletions examples/linearlite/sst.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { execSync } from 'child_process'
const isProduction = (stage: string) =>
stage.toLocaleLowerCase() === `production`

const adminApiTokenId = process.env.ELECTRIC_ADMIN_API_TOKEN_ID
const adminApiTokenSecret = process.env.ELECTRIC_ADMIN_API_TOKEN_SECRET

export default $config({
app(input) {
return {
Expand All @@ -15,13 +18,21 @@ export default $config({
providers: {
cloudflare: `5.42.0`,
aws: {
version: `6.57.0`,
version: `6.66.2`,
profile: process.env.CI ? undefined : `marketing`,
},
},
}
},
async run() {
if (!$dev && !process.env.ELECTRIC_ADMIN_API_TOKEN_ID) {
throw new Error(`ELECTRIC_ADMIN_API_TOKEN_ID is not set`)
}

if (!$dev && !process.env.ELECTRIC_ADMIN_API_TOKEN_SECRET) {
throw new Error(`ELECTRIC_ADMIN_API_TOKEN_ID is not set`)
}

try {
const databaseUri = $interpolate`postgresql://postgres:${process.env.LINEARLITE_SUPABASE_PROJECT_PASSWORD}@db.${process.env.LINEARLITE_SUPABASE_PROJECT_ID}.supabase.co:5432/postgres`

Expand All @@ -42,8 +53,8 @@ export default $config({
},
environment: {
VITE_ELECTRIC_URL: process.env.ELECTRIC_API,
VITE_ELECTRIC_TOKEN: electricInfo.token,
VITE_ELECTRIC_DATABASE_ID: electricInfo.id,
VITE_ELECTRIC_SOURCE_SECRET: electricInfo.source_secret,
VITE_ELECTRIC_SOURCE_ID: electricInfo.id,
},
domain: {
name: `linearlite${isProduction($app.stage) ? `` : `-stage-${$app.stage}`}.examples.electric-sql.com`,
Expand All @@ -56,8 +67,8 @@ export default $config({

return {
databaseUri,
database_id: electricInfo.id,
electric_token: electricInfo.token,
// source_id: electricInfo.id,
// source_secret: electricInfo.source_secret,
website: website.url,
}
} catch (e) {
Expand All @@ -77,13 +88,17 @@ function applyMigrations(uri: string) {

async function addDatabaseToElectric(
uri: string
): Promise<{ id: string; token: string }> {
): Promise<{ id: string; source_secret: string }> {
const adminApi = process.env.ELECTRIC_ADMIN_API
const teamId = process.env.ELECTRIC_TEAM_ID

const result = await fetch(`${adminApi}/v1/sources`, {
method: `PUT`,
headers: { 'Content-Type': `application/json` },
headers: {
'Content-Type': 'application/json',
'CF-Access-Client-Id': adminApiTokenId ?? ``,
'CF-Access-Client-Secret': adminApiTokenSecret ?? ``,
},
body: JSON.stringify({
database_url: uri,
region: `us-east-1`,
Expand Down
11 changes: 7 additions & 4 deletions examples/nextjs/app/shape-proxy/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ export async function GET(request: Request) {
originUrl.searchParams.set(key, value)
})

if (process.env.DATABASE_ID) {
originUrl.searchParams.set(`source_id`, process.env.DATABASE_ID)
if (process.env.ELECTRIC_SOURCE_ID) {
originUrl.searchParams.set(`source_id`, process.env.ELECTRIC_SOURCE_ID)
}

const headers = new Headers()
if (process.env.ELECTRIC_TOKEN) {
originUrl.searchParams.set(`token`, process.env.ELECTRIC_TOKEN)
if (process.env.ELECTRIC_SOURCE_SECRET) {
originUrl.searchParams.set(
`source_secret`,
process.env.ELECTRIC_SOURCE_SECRET
)
}

const newRequest = new Request(originUrl.toString(), {
Expand Down
Loading
Loading