Skip to content
Open
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
45 changes: 26 additions & 19 deletions infra/api.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { table, secret } from "./storage";
import { auth } from "./auth";
import { stripeInfo } from "./billing";
import { users, notes, bucket } from "./storage";

// Create the API
export const api = new sst.aws.ApiGatewayV2("Api", {
transform: {
route: {
handler: {
link: [table, secret],
},
args: {
auth: { iam: true }
},
}
}
export const api = new sst.aws.Function("Api", {
url: true,
handler: "packages/functions/src/api/index.handler",
link: [auth, users, notes, bucket, stripeInfo],
});

api.route("GET /notes", "packages/functions/src/list.main");
api.route("POST /notes", "packages/functions/src/create.main");
api.route("GET /notes/{id}", "packages/functions/src/get.main");
api.route("PUT /notes/{id}", "packages/functions/src/update.main");
api.route("DELETE /notes/{id}", "packages/functions/src/delete.main");
api.route("POST /billing", "packages/functions/src/billing.main");
export const stripeWebhook = new stripe.WebhookEndpoint("StripeWebhook", {
url: $interpolate`${api.url}webhook`,
enabledEvents: ["customer.subscription.created"],
description: "Webhook for Stripe subscription created event",
});

api.addEnvironment({
STRIPE_WEBHOOK_SECRET: stripeWebhook.secret,
});

const anthropicKey = new sst.Secret("AnthropicKey");

export const opencontrol = new sst.aws.OpenControl("OpenControl", {
server: {
handler: "packages/opencontrol/src/server.handler",
policies: ["arn:aws:iam::aws:policy/ReadOnlyAccess"],
link: [notes, users, bucket, anthropicKey, stripeInfo],
},
});
49 changes: 10 additions & 39 deletions infra/auth.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,16 @@
import { api } from "./api";
import { bucket } from "./storage";
import { users } from "./storage";
import { domain } from "./constants";

const region = aws.getRegionOutput().name;

export const userPool = new sst.aws.CognitoUserPool("UserPool", {
usernames: ["email"]
export const email = new sst.aws.Email("Email", {
sender: "jay@sst.dev",
});

export const userPoolClient = userPool.addClient("UserPoolClient");

export const identityPool = new sst.aws.CognitoIdentityPool("IdentityPool", {
userPools: [
{
userPool: userPool.id,
client: userPoolClient.id,
export const auth = new sst.aws.Auth("Auth", {
issuer: {
link: [users, email],
handler: "packages/functions/src/auth.handler",
environment: {
FRONTEND_URL: $dev ? "http://localhost:5173" : `https://${domain}`,
},
],
permissions: {
authenticated: [
{
actions: ["s3:*"],
resources: [
$concat(bucket.arn, "/private/${cognito-identity.amazonaws.com:sub}/*"),
],
},
{
actions: [
"execute-api:*",
],
resources: [
$concat(
"arn:aws:execute-api:",
region,
":",
aws.getCallerIdentityOutput({}).accountId,
":",
api.nodes.api.id,
"/*/*/*"
),
],
},
],
},
});
24 changes: 24 additions & 0 deletions infra/billing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export const stripeKey = new sst.Secret("StripeSecretKey");

export const stripeProduct = new stripe.Product("Notes", {
name: "Notes Pro Plan",
description: "A pro plan for the Notes app",
});

export const stripeSubscription = new stripe.Price("NotesSubscription", {
product: stripeProduct.id,
unitAmount: 1000,
currency: "usd",
recurring: {
interval: "month",
intervalCount: 1,
},
});

export const stripeInfo = new sst.Linkable("Stripe", {
properties: {
secretKey: stripeKey.value,
product: stripeProduct.id,
subscription: stripeSubscription.id,
}
});
1 change: 1 addition & 0 deletions infra/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const domain = $app.stage === "production" ? "demo.sst.dev" : undefined;
19 changes: 14 additions & 5 deletions infra/storage.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
// Create an S3 bucket
export const bucket = new sst.aws.Bucket("Uploads");

// Create the DynamoDB table
export const table = new sst.aws.Dynamo("Notes", {
// Create the DynamoDB users table
export const users = new sst.aws.Dynamo("Users", {
fields: {
userId: "string",
email: "string",
},
primaryIndex: { hashKey: "userId" },
globalIndexes: {
emailIndex: { hashKey: "email" },
},
});

// Create the DynamoDB notes table
export const notes = new sst.aws.Dynamo("Notes", {
fields: {
userId: "string",
noteId: "string",
},
primaryIndex: { hashKey: "userId", rangeKey: "noteId" },
});

// Create a secret for Stripe
export const secret = new sst.Secret("StripeSecretKey");
12 changes: 4 additions & 8 deletions infra/web.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import { api } from "./api";
import { auth } from "./auth";
import { bucket } from "./storage";
import { userPool, identityPool, userPoolClient } from "./auth";

const region = aws.getRegionOutput().name;
import { domain } from "./constants";

export const frontend = new sst.aws.StaticSite("Frontend", {
domain,
path: "packages/frontend",
build: {
output: "dist",
command: "npm run build",
},
domain: $app.stage === "production" ? "demo.sst.dev" : undefined,
environment: {
VITE_REGION: region,
VITE_API_URL: api.url,
VITE_AUTH_URL: auth.url,
VITE_BUCKET: bucket.name,
VITE_USER_POOL_ID: userPool.id,
VITE_IDENTITY_POOL_ID: identityPool.id,
VITE_USER_POOL_CLIENT_ID: userPoolClient.id,
},
});
Loading