set up docker files for OSS self hosting and deving
This commit is contained in:
55
.dockerignore
Normal file
55
.dockerignore
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
**/node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
**/dist/
|
||||||
|
**/build/
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids/
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage/
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
Dockerfile*
|
||||||
|
docker-compose*
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
**/tests/
|
||||||
|
**/*.test.*
|
||||||
|
**/*.spec.*
|
||||||
15
commands.sh
Normal file
15
commands.sh
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
RESTART EVERYTHING
|
||||||
|
docker system prune -a --volumes
|
||||||
|
|
||||||
|
# DB
|
||||||
|
docker compose -f docker-compose.db.yml up --build
|
||||||
|
|
||||||
|
# Dev
|
||||||
|
docker compose -f docker-compose.dev.yml down
|
||||||
|
docker volume rm main-repo_shared-node-modules main-repo_root-node-modules main-repo_vite-node-modules
|
||||||
|
docker compose -f docker-compose.dev.yml build --no-cache
|
||||||
|
docker compose -f docker-compose.dev.yml up
|
||||||
|
|
||||||
|
# Prod
|
||||||
|
docker compose -f docker-compose.prod.yml up --build
|
||||||
|
---
|
||||||
95
docker-compose.dev.yml
Normal file
95
docker-compose.dev.yml
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
services:
|
||||||
|
valkey:
|
||||||
|
image: docker.io/bitnami/valkey:8.0
|
||||||
|
environment:
|
||||||
|
- ALLOW_EMPTY_PASSWORD=yes
|
||||||
|
- VALKEY_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
|
||||||
|
volumes:
|
||||||
|
- valkey-data:/bitnami/valkey/data
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD', 'redis-cli', '-h', 'localhost', '-p', '6379', 'ping']
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
# ports:
|
||||||
|
# - "6379:6379"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
shared:
|
||||||
|
build:
|
||||||
|
dockerfile: docker/dev.dockerfile
|
||||||
|
context: .
|
||||||
|
target: shared
|
||||||
|
volumes:
|
||||||
|
# - ./shared:/app/shared
|
||||||
|
- shared-dist:/app/shared/dist
|
||||||
|
- root-node-modules:/app/node_modules
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# Vite frontend
|
||||||
|
vite:
|
||||||
|
build:
|
||||||
|
dockerfile: docker/dev.dockerfile
|
||||||
|
context: .
|
||||||
|
target: vite
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
# - ./vite:/app/vite
|
||||||
|
- shared-dist:/app/shared/dist
|
||||||
|
- root-node-modules:/app/node_modules
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
depends_on:
|
||||||
|
- shared
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# Main Express server
|
||||||
|
server:
|
||||||
|
build:
|
||||||
|
dockerfile: docker/dev.dockerfile
|
||||||
|
context: .
|
||||||
|
target: server
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- ./server:/app/server
|
||||||
|
- shared-dist:/app/shared/dist
|
||||||
|
- root-node-modules:/app/node_modules
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
- REDIS_URL=redis://valkey:6379
|
||||||
|
depends_on:
|
||||||
|
- shared
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# BullMQ Workers
|
||||||
|
workers:
|
||||||
|
build:
|
||||||
|
dockerfile: docker/dev.dockerfile
|
||||||
|
context: .
|
||||||
|
target: workers
|
||||||
|
volumes:
|
||||||
|
# Mount server source for hot reload (workers use server code)
|
||||||
|
- ./server:/app/server
|
||||||
|
- shared-dist:/app/shared/dist
|
||||||
|
- root-node-modules:/app/node_modules
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
- REDIS_URL=redis://valkey:6379
|
||||||
|
depends_on:
|
||||||
|
- shared
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
# Shared package dist output
|
||||||
|
shared-dist:
|
||||||
|
valkey-data:
|
||||||
|
|
||||||
|
# Node modules volumes to avoid host/container conflicts
|
||||||
|
shared-node-modules:
|
||||||
|
server-node-modules:
|
||||||
|
vite-node-modules:
|
||||||
|
root-node-modules:
|
||||||
46
docker-compose.prod.yml
Normal file
46
docker-compose.prod.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
valkey:
|
||||||
|
image: docker.io/bitnami/valkey:8.0
|
||||||
|
environment:
|
||||||
|
- ALLOW_EMPTY_PASSWORD=yes
|
||||||
|
- VALKEY_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
|
||||||
|
volumes:
|
||||||
|
- valkey-data:/bitnami/valkey/data
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD', 'redis-cli', '-h', 'localhost', '-p', '6379', 'ping']
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
vite:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/prod.dockerfile
|
||||||
|
target: vite-prod
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
server:
|
||||||
|
environment:
|
||||||
|
- REDIS_URL=redis://valkey:6379
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/prod.dockerfile
|
||||||
|
target: server-prod
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
workers:
|
||||||
|
environment:
|
||||||
|
- REDIS_URL=redis://valkey:6379
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/prod.dockerfile
|
||||||
|
target: workers-prod
|
||||||
|
restart: always
|
||||||
35
docker/dev.dockerfile
Normal file
35
docker/dev.dockerfile
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Multi-stage Dockerfile for Autumn development
|
||||||
|
FROM node:18-alpine AS base
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
COPY package*.json pnpm-workspace.yaml pnpm-lock.yaml ./
|
||||||
|
COPY shared/ ./shared/
|
||||||
|
COPY server/ ./server/
|
||||||
|
COPY vite/ ./vite/
|
||||||
|
RUN pnpm install
|
||||||
|
RUN npm install -g nodemon tsx
|
||||||
|
|
||||||
|
# Stage 2: /shared
|
||||||
|
FROM base AS shared
|
||||||
|
WORKDIR /app/shared
|
||||||
|
CMD ["pnpm", "run", "dev"]
|
||||||
|
|
||||||
|
# Stage 3: /vite
|
||||||
|
FROM base AS vite
|
||||||
|
WORKDIR /app/vite
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["pnpm", "run", "dev"]
|
||||||
|
|
||||||
|
# Stage 4: /server
|
||||||
|
FROM base AS server
|
||||||
|
WORKDIR /app/server
|
||||||
|
EXPOSE 8080
|
||||||
|
CMD ["pnpm", "run", "dev"]
|
||||||
|
|
||||||
|
# Stage 5: Workers
|
||||||
|
FROM base AS workers
|
||||||
|
WORKDIR /app/server
|
||||||
|
CMD ["pnpm", "run", "workers"]
|
||||||
42
docker/docker-compose.db.yml
Normal file
42
docker/docker-compose.db.yml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Redis for caching and BullMQ
|
||||||
|
valkey:
|
||||||
|
image: docker.io/bitnami/valkey:8.0
|
||||||
|
environment:
|
||||||
|
- ALLOW_EMPTY_PASSWORD=yes
|
||||||
|
- VALKEY_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
|
||||||
|
volumes:
|
||||||
|
- valkey-data:/bitnami/valkey/data
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD', 'redis-cli', '-h', 'localhost', '-p', '6379', 'ping']
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# PostgreSQL database
|
||||||
|
postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
container_name: autumn-postgres
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: autumn
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: autumn_dev_password
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
valkey-data:
|
||||||
|
postgres-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
autumn-network:
|
||||||
60
docker/prod.dockerfile
Normal file
60
docker/prod.dockerfile
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# ---- Base dependencies ----
|
||||||
|
FROM node:18-alpine AS base
|
||||||
|
WORKDIR /app
|
||||||
|
RUN npm install -g pnpm serve typescript tsc tsc-alias tsx
|
||||||
|
|
||||||
|
COPY package*.json pnpm-workspace.yaml pnpm-lock.yaml ./
|
||||||
|
COPY shared/package*.json ./shared/
|
||||||
|
COPY server/package*.json ./server/
|
||||||
|
COPY vite/package*.json ./vite/
|
||||||
|
|
||||||
|
RUN pnpm install
|
||||||
|
|
||||||
|
|
||||||
|
# # ---- Build shared ----
|
||||||
|
# FROM base AS shared-build
|
||||||
|
# COPY shared/ ./shared/
|
||||||
|
# RUN pnpm -F shared build
|
||||||
|
|
||||||
|
# # ---- Build frontend (vite) ----
|
||||||
|
FROM base AS vite-build
|
||||||
|
COPY . .
|
||||||
|
WORKDIR /app
|
||||||
|
RUN pnpm run vite:build
|
||||||
|
|
||||||
|
# ---- Build backend (server) ----
|
||||||
|
FROM base AS server-build
|
||||||
|
COPY . .
|
||||||
|
WORKDIR /app
|
||||||
|
RUN pnpm run server:build
|
||||||
|
|
||||||
|
# ---- Production frontend image ----
|
||||||
|
FROM vite-build AS vite-prod
|
||||||
|
EXPOSE 3000
|
||||||
|
WORKDIR /app
|
||||||
|
CMD ["pnpm", "run", "vite:start"]
|
||||||
|
|
||||||
|
FROM server-build AS server-prod
|
||||||
|
EXPOSE 8080
|
||||||
|
WORKDIR /app
|
||||||
|
CMD ["pnpm", "run", "server:start"]
|
||||||
|
|
||||||
|
FROM server-build AS workers-prod
|
||||||
|
EXPOSE 8080
|
||||||
|
WORKDIR /app
|
||||||
|
CMD ["pnpm", "run", "server:workers"]
|
||||||
|
|
||||||
|
# # ---- Production backend image ----
|
||||||
|
# FROM node:18-alpine AS server-prod
|
||||||
|
# COPY --from=server-build /app/server/dist ./dist
|
||||||
|
# COPY --from=server-build /app/server/package.json ./
|
||||||
|
# COPY --from=server-build /app/server/node_modules ./node_modules
|
||||||
|
# EXPOSE 8080
|
||||||
|
# CMD ["pnpm", "run", "server:start"]
|
||||||
|
|
||||||
|
# # ---- Production workers image ----
|
||||||
|
# FROM node:18-alpine AS workers-prod
|
||||||
|
# COPY --from=server-build /app/server/dist ./dist
|
||||||
|
# COPY --from=server-build /app/server/package.json ./
|
||||||
|
# COPY --from=server-build /app/server/node_modules ./node_modules
|
||||||
|
# CMD ["pnpm", "run", "server:workers"]
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
https://docs.fontawesome.com/web/use-with/react
|
|
||||||
|
|
||||||
https://docs.fontawesome.com/web/setup/packages#1-configure-access
|
|
||||||
|
|
||||||
In frontend, ran `npm link @useautumn/react`
|
|
||||||
12923
package-lock.json
generated
12923
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@@ -2,20 +2,16 @@
|
|||||||
"name": "autumn",
|
"name": "autumn",
|
||||||
"private": true,
|
"private": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"frontend",
|
|
||||||
"server",
|
"server",
|
||||||
"shared",
|
"shared",
|
||||||
"tests",
|
|
||||||
"vite"
|
"vite"
|
||||||
],
|
],
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"frontend:build": "npm run build -w shared && npm run build -w frontend",
|
"vite:build": "pnpm -F shared build && pnpm -F vite build",
|
||||||
"frontend:start": "npm run start -w frontend",
|
"vite:start": "pnpm -F vite start",
|
||||||
"vite:build": "npm run build -w shared && npm run build -w vite",
|
"server:build": "pnpm -F shared build && pnpm -F server prod:build",
|
||||||
"vite:start": "npm run start -w vite",
|
"server:start": "pnpm -F server prod:start",
|
||||||
"server:build": "npm run build -w shared && npm run prod:build -w server",
|
|
||||||
"server:start": "npm run prod:start -w server",
|
|
||||||
"server:cron": "npm run cron:start -w server",
|
"server:cron": "npm run cron:start -w server",
|
||||||
"server:workers": "npm run workers:start -w server",
|
"server:workers": "npm run workers:start -w server",
|
||||||
"dev": "concurrently \"cd server && npm run dev\" \"cd vite && npm run dev\" \"redis-server\""
|
"dev": "concurrently \"cd server && npm run dev\" \"cd vite && npm run dev\" \"redis-server\""
|
||||||
|
|||||||
10695
pnpm-lock.yaml
generated
Normal file
10695
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
4
pnpm-workspace.yaml
Normal file
4
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
packages:
|
||||||
|
- 'shared'
|
||||||
|
- 'server'
|
||||||
|
- 'vite'
|
||||||
3
run.sh
Executable file
3
run.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
if [[ $1 == *"docker-compose"* ]]; then
|
||||||
|
docker compose -f "$1" up
|
||||||
|
fi
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/anthropic": "^1.2.10",
|
"@ai-sdk/anthropic": "^1.2.10",
|
||||||
"@anthropic-ai/sdk": "^0.32.1",
|
"@anthropic-ai/sdk": "^0.32.1",
|
||||||
"@autumn/shared": "*",
|
"@autumn/shared": "workspace:*",
|
||||||
"@clerk/express": "^1.3.22",
|
"@clerk/express": "^1.3.22",
|
||||||
"@date-fns/tz": "^1.2.0",
|
"@date-fns/tz": "^1.2.0",
|
||||||
"@date-fns/utc": "^2.1.0",
|
"@date-fns/utc": "^2.1.0",
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
"autumn-js": "^0.0.64",
|
"autumn-js": "^0.0.64",
|
||||||
"better-auth": "^1.2.9",
|
"better-auth": "^1.2.9",
|
||||||
"body-parser": "^1.20.3",
|
"body-parser": "^1.20.3",
|
||||||
"bullmq": "^5.31.1",
|
"bullmq": "^5.54.0",
|
||||||
"chai": "^5.1.2",
|
"chai": "^5.1.2",
|
||||||
"chai-http": "^5.1.1",
|
"chai-http": "^5.1.1",
|
||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
@@ -78,12 +78,14 @@
|
|||||||
"pino-pretty": "^13.0.0",
|
"pino-pretty": "^13.0.0",
|
||||||
"postgres": "^3.4.7",
|
"postgres": "^3.4.7",
|
||||||
"posthog-node": "^4.17.2",
|
"posthog-node": "^4.17.2",
|
||||||
|
"react": "^18.2.0",
|
||||||
"recaseai": "^0.0.37",
|
"recaseai": "^0.0.37",
|
||||||
"resend": "^4.1.1",
|
"resend": "^4.1.1",
|
||||||
"stripe": "^17.5.0",
|
"stripe": "^17.5.0",
|
||||||
"svix": "^1.45.1",
|
"svix": "^1.45.1",
|
||||||
"tsc-alias": "^1.8.16",
|
"tsc-alias": "^1.8.16",
|
||||||
"ws": "^8.18.0"
|
"ws": "^8.18.0",
|
||||||
|
"zod": "^3.25.23"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^5.0.1",
|
"@types/chai": "^5.0.1",
|
||||||
@@ -92,6 +94,9 @@
|
|||||||
"@types/mocha": "^10.0.10",
|
"@types/mocha": "^10.0.10",
|
||||||
"@types/node": "^22.13.4",
|
"@types/node": "^22.13.4",
|
||||||
"@types/pg": "^8.11.10",
|
"@types/pg": "^8.11.10",
|
||||||
|
"@types/react": "^18.3.18",
|
||||||
|
"@types/react-dom": "^18.3.5",
|
||||||
|
"@types/ws": "^8.18.1",
|
||||||
"drizzle-kit": "^0.31.1",
|
"drizzle-kit": "^0.31.1",
|
||||||
"mocha": "^11.1.0",
|
"mocha": "^11.1.0",
|
||||||
"puppeteer": "^24.2.0",
|
"puppeteer": "^24.2.0",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import express from "express";
|
import express, { Router } from "express";
|
||||||
import { Webhook } from "svix";
|
import { Webhook } from "svix";
|
||||||
|
|
||||||
export const autumnWebhookRouter = express.Router();
|
export const autumnWebhookRouter: Router = express.Router();
|
||||||
|
|
||||||
const verifyAutumnWebhook = async (req: any, res: any) => {
|
const verifyAutumnWebhook = async (req: any, res: any) => {
|
||||||
const wh = new Webhook(process.env.AUTUMN_WEBHOOK_SECRET!);
|
const wh = new Webhook(process.env.AUTUMN_WEBHOOK_SECRET!);
|
||||||
@@ -54,5 +54,5 @@ autumnWebhookRouter.post(
|
|||||||
success: true,
|
success: true,
|
||||||
message: "Webhook received",
|
message: "Webhook received",
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export const createStripeMeteredPrice = async ({
|
|||||||
const stripePrice = await stripeCli.prices.create({
|
const stripePrice = await stripeCli.prices.create({
|
||||||
...productData,
|
...productData,
|
||||||
...priceAmountData,
|
...priceAmountData,
|
||||||
currency: org.default_currency,
|
currency: org.default_currency || "usd",
|
||||||
nickname: `Autumn Price (${feature!.name}) [Placeholder]`,
|
nickname: `Autumn Price (${feature!.name}) [Placeholder]`,
|
||||||
recurring: {
|
recurring: {
|
||||||
...(billingIntervalToStripe(price.config!.interval!) as any),
|
...(billingIntervalToStripe(price.config!.interval!) as any),
|
||||||
@@ -194,7 +194,7 @@ export const createStripeArrearProrated = async ({
|
|||||||
|
|
||||||
let stripePrice = await stripeCli.prices.create({
|
let stripePrice = await stripeCli.prices.create({
|
||||||
...productData,
|
...productData,
|
||||||
currency: org.default_currency,
|
currency: org.default_currency || "usd",
|
||||||
...priceAmountData,
|
...priceAmountData,
|
||||||
recurring: {
|
recurring: {
|
||||||
...(recurringData as any),
|
...(recurringData as any),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const createStripeFixedPrice = async ({
|
|||||||
const stripePrice = await stripeCli.prices.create({
|
const stripePrice = await stripeCli.prices.create({
|
||||||
product: product.processor!.id,
|
product: product.processor!.id,
|
||||||
unit_amount: amount,
|
unit_amount: amount,
|
||||||
currency: org.default_currency,
|
currency: org.default_currency!,
|
||||||
recurring: {
|
recurring: {
|
||||||
...(billingIntervalToStripe(config.interval!) as any),
|
...(billingIntervalToStripe(config.interval!) as any),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ export const createStripeInArrearPrice = async ({
|
|||||||
const stripePrice = await stripeCli.prices.create({
|
const stripePrice = await stripeCli.prices.create({
|
||||||
...productData,
|
...productData,
|
||||||
...priceAmountData,
|
...priceAmountData,
|
||||||
currency: org.default_currency,
|
currency: org.default_currency!,
|
||||||
recurring: {
|
recurring: {
|
||||||
...(billingIntervalToStripe(price.config!.interval!) as any),
|
...(billingIntervalToStripe(price.config!.interval!) as any),
|
||||||
meter: meter!.id,
|
meter: meter!.id,
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ export const createStripePrepaid = async ({
|
|||||||
...productData,
|
...productData,
|
||||||
// unit_amount_decimal: (amount * 100).toString(),
|
// unit_amount_decimal: (amount * 100).toString(),
|
||||||
unit_amount_decimal: unitAmountDecimalStr,
|
unit_amount_decimal: unitAmountDecimalStr,
|
||||||
currency: org.default_currency,
|
currency: org.default_currency!,
|
||||||
});
|
});
|
||||||
|
|
||||||
config.stripe_product_id = stripePrice.product as string;
|
config.stripe_product_id = stripePrice.product as string;
|
||||||
@@ -133,7 +133,7 @@ export const createStripePrepaid = async ({
|
|||||||
|
|
||||||
stripePrice = await stripeCli.prices.create({
|
stripePrice = await stripeCli.prices.create({
|
||||||
...productData,
|
...productData,
|
||||||
currency: org.default_currency,
|
currency: org.default_currency!,
|
||||||
...priceAmountData,
|
...priceAmountData,
|
||||||
recurring: {
|
recurring: {
|
||||||
...(recurringData as any),
|
...(recurringData as any),
|
||||||
|
|||||||
10
server/src/external/stripe/stripeWebhooks.ts
vendored
10
server/src/external/stripe/stripeWebhooks.ts
vendored
@@ -1,7 +1,10 @@
|
|||||||
|
import express, { Router } from "express";
|
||||||
|
import stripe, { Stripe } from "stripe";
|
||||||
|
import chalk from "chalk";
|
||||||
|
|
||||||
import { OrgService } from "@/internal/orgs/OrgService.js";
|
import { OrgService } from "@/internal/orgs/OrgService.js";
|
||||||
import { AuthType, LoggerAction, Organization } from "@autumn/shared";
|
import { AuthType, LoggerAction, Organization } from "@autumn/shared";
|
||||||
import express from "express";
|
|
||||||
import stripe, { Stripe } from "stripe";
|
|
||||||
import { handleCheckoutSessionCompleted } from "./webhookHandlers/handleCheckoutCompleted.js";
|
import { handleCheckoutSessionCompleted } from "./webhookHandlers/handleCheckoutCompleted.js";
|
||||||
import { handleSubscriptionUpdated } from "./webhookHandlers/handleSubUpdated.js";
|
import { handleSubscriptionUpdated } from "./webhookHandlers/handleSubUpdated.js";
|
||||||
import { handleSubDeleted } from "./webhookHandlers/handleSubDeleted.js";
|
import { handleSubDeleted } from "./webhookHandlers/handleSubDeleted.js";
|
||||||
@@ -10,7 +13,6 @@ import { getStripeWebhookSecret } from "@/internal/orgs/orgUtils.js";
|
|||||||
import { handleInvoicePaid } from "./webhookHandlers/handleInvoicePaid.js";
|
import { handleInvoicePaid } from "./webhookHandlers/handleInvoicePaid.js";
|
||||||
import { handleRequestError } from "@/utils/errorUtils.js";
|
import { handleRequestError } from "@/utils/errorUtils.js";
|
||||||
import { handleInvoiceCreated } from "./webhookHandlers/handleInvoiceCreated/handleInvoiceCreated.js";
|
import { handleInvoiceCreated } from "./webhookHandlers/handleInvoiceCreated/handleInvoiceCreated.js";
|
||||||
import chalk from "chalk";
|
|
||||||
import { handleInvoiceFinalized } from "./webhookHandlers/handleInvoiceFinalized.js";
|
import { handleInvoiceFinalized } from "./webhookHandlers/handleInvoiceFinalized.js";
|
||||||
import { handleSubscriptionScheduleCanceled } from "./webhookHandlers/handleSubScheduleCanceled.js";
|
import { handleSubscriptionScheduleCanceled } from "./webhookHandlers/handleSubScheduleCanceled.js";
|
||||||
import { createLogtailWithContext } from "../logtail/logtailUtils.js";
|
import { createLogtailWithContext } from "../logtail/logtailUtils.js";
|
||||||
@@ -18,7 +20,7 @@ import { handleCusDiscountDeleted } from "./webhookHandlers/handleCusDiscountDel
|
|||||||
import { ExtendedRequest } from "@/utils/models/Request.js";
|
import { ExtendedRequest } from "@/utils/models/Request.js";
|
||||||
import { createStripeCli } from "./utils.js";
|
import { createStripeCli } from "./utils.js";
|
||||||
|
|
||||||
export const stripeWebhookRouter = express.Router();
|
export const stripeWebhookRouter: Router = express.Router();
|
||||||
|
|
||||||
const logStripeWebhook = ({
|
const logStripeWebhook = ({
|
||||||
req,
|
req,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import express from "express";
|
import express, { Router } from "express";
|
||||||
|
|
||||||
import { stripeWebhookRouter } from "../stripe/stripeWebhooks.js";
|
import { stripeWebhookRouter } from "../stripe/stripeWebhooks.js";
|
||||||
import { autumnWebhookRouter } from "../autumn/autumnWebhookRouter.js";
|
import { autumnWebhookRouter } from "../autumn/autumnWebhookRouter.js";
|
||||||
|
|
||||||
const webhooksRouter = express.Router();
|
const webhooksRouter: Router = express.Router();
|
||||||
|
|
||||||
webhooksRouter.use("/stripe", stripeWebhookRouter);
|
webhooksRouter.use("/stripe", stripeWebhookRouter);
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,10 @@
|
|||||||
import { handleFrontendReqError } from "@/utils/errorUtils.js";
|
import { handleFrontendReqError } from "@/utils/errorUtils.js";
|
||||||
import { ExtendedRequest } from "@/utils/models/Request.js";
|
import { ExtendedRequest } from "@/utils/models/Request.js";
|
||||||
import { member, organizations, user } from "@autumn/shared";
|
import { member, organizations, user } from "@autumn/shared";
|
||||||
import {
|
import { and, desc, eq, gt, gte, ilike, inArray, lt, or } from "drizzle-orm";
|
||||||
and,
|
|
||||||
desc,
|
|
||||||
eq,
|
|
||||||
gt,
|
|
||||||
gte,
|
|
||||||
ilike,
|
|
||||||
inArray,
|
|
||||||
lt,
|
|
||||||
lte,
|
|
||||||
or,
|
|
||||||
} from "drizzle-orm";
|
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import { getUserCount } from "./adminUtils/userAnalytics.js";
|
|
||||||
|
|
||||||
export const adminRouter = Router();
|
export const adminRouter: Router = Router();
|
||||||
|
|
||||||
adminRouter.get("/users", async (req: any, res: any) => {
|
adminRouter.get("/users", async (req: any, res: any) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { analyticsMiddleware } from "@/middleware/analyticsMiddleware.js";
|
|||||||
import rewardRouter from "./rewards/rewardRouter.js";
|
import rewardRouter from "./rewards/rewardRouter.js";
|
||||||
import expireRouter from "./customers/products/expireRouter.js";
|
import expireRouter from "./customers/products/expireRouter.js";
|
||||||
|
|
||||||
const apiRouter = Router();
|
const apiRouter: Router = Router();
|
||||||
|
|
||||||
apiRouter.use(apiAuthMiddleware);
|
apiRouter.use(apiAuthMiddleware);
|
||||||
apiRouter.use(pricingMiddleware);
|
apiRouter.use(pricingMiddleware);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { routeHandler } from "@/utils/routerUtils.js";
|
|||||||
import { FullCusProduct, CusProductStatus, ProductV2 } from "@autumn/shared";
|
import { FullCusProduct, CusProductStatus, ProductV2 } from "@autumn/shared";
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
|
||||||
export const componentRouter = Router();
|
export const componentRouter: Router = Router();
|
||||||
|
|
||||||
componentRouter.get("/pricing_table", async (req: any, res) =>
|
componentRouter.get("/pricing_table", async (req: any, res) =>
|
||||||
routeHandler({
|
routeHandler({
|
||||||
|
|||||||
@@ -20,9 +20,8 @@ import { handleUpdateCustomer } from "../customers/handlers/handleUpdateCustomer
|
|||||||
import { handleCreateBillingPortal } from "../customers/handlers/handleCreateBillingPortal.js";
|
import { handleCreateBillingPortal } from "../customers/handlers/handleCreateBillingPortal.js";
|
||||||
import { handleGetCustomer } from "../customers/handlers/handleGetCustomer.js";
|
import { handleGetCustomer } from "../customers/handlers/handleGetCustomer.js";
|
||||||
import { CusSearchService } from "@/internal/customers/CusSearchService.js";
|
import { CusSearchService } from "@/internal/customers/CusSearchService.js";
|
||||||
import assert from "assert";
|
|
||||||
|
|
||||||
export const cusRouter = Router();
|
export const cusRouter: Router = Router();
|
||||||
|
|
||||||
cusRouter.post("/all/search", async (req: any, res: any) => {
|
cusRouter.post("/all/search", async (req: any, res: any) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { CusProductStatus, ErrCode, FullCusProduct } from "@autumn/shared";
|
|||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import { expireCusProduct } from "../../../customers/handlers/handleCusProductExpired.js";
|
import { expireCusProduct } from "../../../customers/handlers/handleCusProductExpired.js";
|
||||||
|
|
||||||
const expireRouter = Router();
|
const expireRouter: Router = Router();
|
||||||
|
|
||||||
expireRouter.post("", async (req, res) =>
|
expireRouter.post("", async (req, res) =>
|
||||||
routeHandler({
|
routeHandler({
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
|
||||||
import { routeHandler } from "@/utils/routerUtils.js";
|
import { routeHandler } from "@/utils/routerUtils.js";
|
||||||
import { EntityService } from "./EntityService.js";
|
|
||||||
import { CusService } from "@/internal/customers/CusService.js";
|
import { CusService } from "@/internal/customers/CusService.js";
|
||||||
import RecaseError from "@/utils/errorUtils.js";
|
|
||||||
import { ErrCode } from "@autumn/shared";
|
|
||||||
import { handleGetEntity } from "./handlers/handleGetEntity.js";
|
import { handleGetEntity } from "./handlers/handleGetEntity.js";
|
||||||
import { handlePostEntityRequest } from "../../entities/handlers/handleCreateEntity/handleCreateEntity.js";
|
import { handlePostEntityRequest } from "../../entities/handlers/handleCreateEntity/handleCreateEntity.js";
|
||||||
import { handleDeleteEntity } from "./handlers/handleDeleteEntity.js";
|
import { handleDeleteEntity } from "./handlers/handleDeleteEntity.js";
|
||||||
|
|
||||||
export const entityRouter = Router({ mergeParams: true });
|
export const entityRouter: Router = Router({ mergeParams: true });
|
||||||
|
|
||||||
// List entityes
|
// List entityes
|
||||||
entityRouter.get("", (req, res) =>
|
entityRouter.get("", (req: any, res: any) =>
|
||||||
routeHandler({
|
routeHandler({
|
||||||
req,
|
req,
|
||||||
res,
|
res,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import { getOrCreateCustomer } from "@/internal/customers/cusUtils/getOrCreateCu
|
|||||||
import { getCheckPreview } from "./getCheckPreview.js";
|
import { getCheckPreview } from "./getCheckPreview.js";
|
||||||
import { orgToVersion } from "@/utils/versionUtils.js";
|
import { orgToVersion } from "@/utils/versionUtils.js";
|
||||||
|
|
||||||
export const entitledRouter = Router();
|
export const entitledRouter: Router = Router();
|
||||||
|
|
||||||
const getRequiredAndActualBalance = ({
|
const getRequiredAndActualBalance = ({
|
||||||
cusEnts,
|
cusEnts,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import { DrizzleCli } from "@/db/initDrizzle.js";
|
|||||||
import { ExtendedRequest } from "@/utils/models/Request.js";
|
import { ExtendedRequest } from "@/utils/models/Request.js";
|
||||||
import { getEventTimestamp } from "./eventUtils.js";
|
import { getEventTimestamp } from "./eventUtils.js";
|
||||||
|
|
||||||
export const eventsRouter = Router();
|
export const eventsRouter: Router = Router();
|
||||||
|
|
||||||
const getEventAndCustomer = async ({
|
const getEventAndCustomer = async ({
|
||||||
req,
|
req,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import {
|
|||||||
CusProductStatus,
|
CusProductStatus,
|
||||||
Customer,
|
Customer,
|
||||||
ErrCode,
|
ErrCode,
|
||||||
Event,
|
|
||||||
EventInsert,
|
EventInsert,
|
||||||
FeatureType,
|
FeatureType,
|
||||||
FeatureUsageType,
|
FeatureUsageType,
|
||||||
@@ -12,22 +11,17 @@ import RecaseError, { handleRequestError } from "@/utils/errorUtils.js";
|
|||||||
import { generateId, nullish } from "@/utils/genUtils.js";
|
import { generateId, nullish } from "@/utils/genUtils.js";
|
||||||
|
|
||||||
import { EventService } from "./EventService.js";
|
import { EventService } from "./EventService.js";
|
||||||
import { OrgService } from "@/internal/orgs/OrgService.js";
|
|
||||||
import { FeatureService } from "@/internal/features/FeatureService.js";
|
|
||||||
import { StatusCodes } from "http-status-codes";
|
import { StatusCodes } from "http-status-codes";
|
||||||
import { QueueManager } from "@/queue/QueueManager.js";
|
|
||||||
|
|
||||||
import { JobName } from "@/queue/JobName.js";
|
import { JobName } from "@/queue/JobName.js";
|
||||||
import { getOrCreateCustomer } from "@/internal/customers/cusUtils/getOrCreateCustomer.js";
|
import { getOrCreateCustomer } from "@/internal/customers/cusUtils/getOrCreateCustomer.js";
|
||||||
import { creditSystemContainsFeature } from "@/internal/features/creditSystemUtils.js";
|
import { creditSystemContainsFeature } from "@/internal/features/creditSystemUtils.js";
|
||||||
import { addTaskToQueue } from "@/queue/queueUtils.js";
|
import { addTaskToQueue } from "@/queue/queueUtils.js";
|
||||||
import { getOrgAndFeatures } from "@/internal/orgs/orgUtils.js";
|
|
||||||
import { getEventTimestamp } from "./eventUtils.js";
|
import { getEventTimestamp } from "./eventUtils.js";
|
||||||
import { ExtendedRequest } from "@/utils/models/Request.js";
|
import { ExtendedRequest } from "@/utils/models/Request.js";
|
||||||
import { runUpdateBalanceTask } from "@/trigger/updateBalanceTask.js";
|
|
||||||
import { runUpdateUsageTask } from "@/trigger/updateUsageTask.js";
|
import { runUpdateUsageTask } from "@/trigger/updateUsageTask.js";
|
||||||
export const eventsRouter = Router();
|
|
||||||
export const usageRouter = Router();
|
export const eventsRouter: Router = Router();
|
||||||
|
export const usageRouter: Router = Router();
|
||||||
|
|
||||||
const getCusFeatureAndOrg = async ({
|
const getCusFeatureAndOrg = async ({
|
||||||
req,
|
req,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import RecaseError, {
|
|||||||
import { handleUpdateFeature } from "./handlers/handleUpdateFeature.js";
|
import { handleUpdateFeature } from "./handlers/handleUpdateFeature.js";
|
||||||
import { Feature, FeatureResponseSchema, FeatureType } from "@autumn/shared";
|
import { Feature, FeatureResponseSchema, FeatureType } from "@autumn/shared";
|
||||||
import { CreateFeatureSchema } from "@autumn/shared";
|
import { CreateFeatureSchema } from "@autumn/shared";
|
||||||
import express from "express";
|
import express, { Router } from "express";
|
||||||
import { generateId } from "@/utils/genUtils.js";
|
import { generateId } from "@/utils/genUtils.js";
|
||||||
import { ErrCode } from "@/errors/errCodes.js";
|
import { ErrCode } from "@/errors/errCodes.js";
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ import { JobName } from "@/queue/JobName.js";
|
|||||||
import { OrgService } from "@/internal/orgs/OrgService.js";
|
import { OrgService } from "@/internal/orgs/OrgService.js";
|
||||||
import { handleDeleteFeature } from "./handlers/handleDeleteFeature.js";
|
import { handleDeleteFeature } from "./handlers/handleDeleteFeature.js";
|
||||||
|
|
||||||
export const featureApiRouter = express.Router();
|
export const featureApiRouter: Router = express.Router();
|
||||||
|
|
||||||
export const validateFeature = (data: any) => {
|
export const validateFeature = (data: any) => {
|
||||||
let featureType = data.type;
|
let featureType = data.type;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { OrgService } from "@/internal/orgs/OrgService.js";
|
|||||||
import { handleRequestError } from "@/utils/errorUtils.js";
|
import { handleRequestError } from "@/utils/errorUtils.js";
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
|
||||||
export const invoiceRouter = Router();
|
export const invoiceRouter: Router = Router();
|
||||||
|
|
||||||
invoiceRouter.get("/:stripe_invoice_id/stripe", async (req: any, res: any) => {
|
invoiceRouter.get("/:stripe_invoice_id/stripe", async (req: any, res: any) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { handleCopyProduct } from "./handlers/handleCopyProduct.js";
|
|||||||
import { handleCreateProduct } from "./handlers/handleCreateProduct.js";
|
import { handleCreateProduct } from "./handlers/handleCreateProduct.js";
|
||||||
import { handleListProducts } from "./handlers/handleListProducts.js";
|
import { handleListProducts } from "./handlers/handleListProducts.js";
|
||||||
|
|
||||||
export const productApiRouter = Router();
|
export const productApiRouter: Router = Router();
|
||||||
|
|
||||||
productApiRouter.get("", handleListProducts);
|
productApiRouter.get("", handleListProducts);
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ import { RewardRedemptionService } from "@/internal/rewards/RewardRedemptionServ
|
|||||||
import RecaseError from "@/utils/errorUtils.js";
|
import RecaseError from "@/utils/errorUtils.js";
|
||||||
import { generateId, notNullish } from "@/utils/genUtils.js";
|
import { generateId, notNullish } from "@/utils/genUtils.js";
|
||||||
import { routeHandler } from "@/utils/routerUtils.js";
|
import { routeHandler } from "@/utils/routerUtils.js";
|
||||||
import { Customer, ErrCode, RewardTriggerEvent } from "@autumn/shared";
|
import { ErrCode, RewardTriggerEvent } from "@autumn/shared";
|
||||||
import express from "express";
|
import express, { Router } from "express";
|
||||||
import { ReferralCode, RewardRedemption } from "@autumn/shared";
|
import { RewardRedemption } from "@autumn/shared";
|
||||||
import { OrgService } from "@/internal/orgs/OrgService.js";
|
import { OrgService } from "@/internal/orgs/OrgService.js";
|
||||||
import { RewardProgramService } from "@/internal/rewards/RewardProgramService.js";
|
import { RewardProgramService } from "@/internal/rewards/RewardProgramService.js";
|
||||||
|
|
||||||
export const referralRouter = express.Router();
|
export const referralRouter: Router = express.Router();
|
||||||
|
|
||||||
// 1. Get referral code
|
// 1. Get referral code
|
||||||
referralRouter.post("/code", (req, res) =>
|
referralRouter.post("/code", (req, res) =>
|
||||||
@@ -238,7 +238,7 @@ referralRouter.post("/redeem", (req, res) =>
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const redemptionRouter = express.Router();
|
export const redemptionRouter: Router = express.Router();
|
||||||
|
|
||||||
redemptionRouter.get("/:redemptionId", (req, res) =>
|
redemptionRouter.get("/:redemptionId", (req, res) =>
|
||||||
routeHandler({
|
routeHandler({
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import {
|
|||||||
ErrCode,
|
ErrCode,
|
||||||
RewardTriggerEvent,
|
RewardTriggerEvent,
|
||||||
} from "@autumn/shared";
|
} from "@autumn/shared";
|
||||||
import express from "express";
|
import express, { Router } from "express";
|
||||||
|
|
||||||
export const rewardProgramRouter = express.Router();
|
export const rewardProgramRouter: Router = express.Router();
|
||||||
|
|
||||||
rewardProgramRouter.post("", (req, res) =>
|
rewardProgramRouter.post("", (req, res) =>
|
||||||
routeHandler({
|
routeHandler({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import express from "express";
|
import express, { Router } from "express";
|
||||||
import {
|
import {
|
||||||
CreateRewardSchema,
|
CreateRewardSchema,
|
||||||
ErrCode,
|
ErrCode,
|
||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
getRewardCat,
|
getRewardCat,
|
||||||
} from "@/internal/rewards/rewardUtils.js";
|
} from "@/internal/rewards/rewardUtils.js";
|
||||||
|
|
||||||
const rewardRouter = express.Router();
|
const rewardRouter: Router = express.Router();
|
||||||
|
|
||||||
rewardRouter.post("", async (req: any, res: any) => {
|
rewardRouter.post("", async (req: any, res: any) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -86,18 +86,18 @@ export const handleOneOffFunction = async ({
|
|||||||
// Create invoice
|
// Create invoice
|
||||||
logger.info("1. Creating invoice");
|
logger.info("1. Creating invoice");
|
||||||
const stripeInvoice = await stripeCli.invoices.create({
|
const stripeInvoice = await stripeCli.invoices.create({
|
||||||
customer: customer.processor.id,
|
customer: customer.processor.id!,
|
||||||
auto_advance: false,
|
auto_advance: false,
|
||||||
currency: org.default_currency,
|
currency: org.default_currency!,
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.info("2. Creating invoice items");
|
logger.info("2. Creating invoice items");
|
||||||
for (const invoiceItem of invoiceItems) {
|
for (const invoiceItem of invoiceItems) {
|
||||||
await stripeCli.invoiceItems.create({
|
await stripeCli.invoiceItems.create({
|
||||||
...invoiceItem,
|
...invoiceItem,
|
||||||
customer: customer.processor.id,
|
customer: customer.processor.id!,
|
||||||
invoice: stripeInvoice.id,
|
invoice: stripeInvoice.id,
|
||||||
});
|
} as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create invoice items
|
// Create invoice items
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import { processAttachBody } from "./attachUtils/attachParams/processAttachBody.
|
|||||||
import { handleAttachPreview } from "./handleAttachPreview/handleAttachPreview.js";
|
import { handleAttachPreview } from "./handleAttachPreview/handleAttachPreview.js";
|
||||||
import { handleAttach } from "./handleAttach.js";
|
import { handleAttach } from "./handleAttach.js";
|
||||||
|
|
||||||
export const attachRouter = Router();
|
export const attachRouter: Router = Router();
|
||||||
|
|
||||||
export const handlePrepaidErrors = async ({
|
export const handlePrepaidErrors = async ({
|
||||||
attachParams,
|
attachParams,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { StatusCodes } from "http-status-codes";
|
|||||||
import { cusProductToProduct } from "./cusProducts/cusProductUtils/convertCusProduct.js";
|
import { cusProductToProduct } from "./cusProducts/cusProductUtils/convertCusProduct.js";
|
||||||
import { createOrgResponse } from "../orgs/orgUtils.js";
|
import { createOrgResponse } from "../orgs/orgUtils.js";
|
||||||
|
|
||||||
export const cusRouter = Router();
|
export const cusRouter: Router = Router();
|
||||||
|
|
||||||
cusRouter.get("/:customer_id/data", async (req: any, res: any) => {
|
cusRouter.get("/:customer_id/data", async (req: any, res: any) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const getProductChargeText = ({
|
|||||||
itemStrs.push(
|
itemStrs.push(
|
||||||
formatCurrency({
|
formatCurrency({
|
||||||
amount: total,
|
amount: total,
|
||||||
defaultCurrency: org.default_currency,
|
defaultCurrency: org.default_currency!,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,17 +26,17 @@ export const formatTiers = ({
|
|||||||
if (tiers.length == 1) {
|
if (tiers.length == 1) {
|
||||||
return formatCurrency({
|
return formatCurrency({
|
||||||
amount: tiers[0].amount,
|
amount: tiers[0].amount,
|
||||||
defaultCurrency: org.default_currency,
|
defaultCurrency: org.default_currency!,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let tiersStart = formatCurrency({
|
let tiersStart = formatCurrency({
|
||||||
amount: tiers[0].amount,
|
amount: tiers[0].amount,
|
||||||
defaultCurrency: org.default_currency,
|
defaultCurrency: org.default_currency!,
|
||||||
});
|
});
|
||||||
let tiersEnd = formatCurrency({
|
let tiersEnd = formatCurrency({
|
||||||
amount: tiers[tiers.length - 1].amount,
|
amount: tiers[tiers.length - 1].amount,
|
||||||
defaultCurrency: org.default_currency,
|
defaultCurrency: org.default_currency!,
|
||||||
});
|
});
|
||||||
|
|
||||||
return `${tiersStart} - ${tiersEnd}`;
|
return `${tiersStart} - ${tiersEnd}`;
|
||||||
@@ -58,13 +58,13 @@ export const getItemsHtml = ({
|
|||||||
if (pricedItems.length == 1) {
|
if (pricedItems.length == 1) {
|
||||||
html += `<br/><p style="font-size: 1.1em;"><strong>${formatCurrency({
|
html += `<br/><p style="font-size: 1.1em;"><strong>${formatCurrency({
|
||||||
amount: totalAmount,
|
amount: totalAmount,
|
||||||
defaultCurrency: org.default_currency,
|
defaultCurrency: org.default_currency!,
|
||||||
})}</strong></p>`;
|
})}</strong></p>`;
|
||||||
} else {
|
} else {
|
||||||
html += `<br/><ul>${itemsToHtml({ items: pricedItems })}</ul>`;
|
html += `<br/><ul>${itemsToHtml({ items: pricedItems })}</ul>`;
|
||||||
html += `<br/><p style="font-size: 1.1em;">Total: ${formatCurrency({
|
html += `<br/><p style="font-size: 1.1em;">Total: ${formatCurrency({
|
||||||
amount: totalAmount,
|
amount: totalAmount,
|
||||||
defaultCurrency: org.default_currency,
|
defaultCurrency: org.default_currency!,
|
||||||
})}</p>`;
|
})}</p>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { CacheManager } from "@/external/caching/CacheManager.js";
|
|||||||
import { CacheType } from "@/external/caching/cacheActions.js";
|
import { CacheType } from "@/external/caching/cacheActions.js";
|
||||||
import { routeHandler } from "@/utils/routerUtils.js";
|
import { routeHandler } from "@/utils/routerUtils.js";
|
||||||
|
|
||||||
export const devRouter = Router();
|
export const devRouter: Router = Router();
|
||||||
|
|
||||||
devRouter.get("/data", withOrgAuth, async (req: any, res) => {
|
devRouter.get("/data", withOrgAuth, async (req: any, res) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import express from "express";
|
import express, { Router } from "express";
|
||||||
|
|
||||||
import { FeatureService } from "./FeatureService.js";
|
import { FeatureService } from "./FeatureService.js";
|
||||||
|
|
||||||
export const featureRouter = express.Router();
|
export const featureRouter: Router = express.Router();
|
||||||
|
|
||||||
featureRouter.get("", async (req: any, res) => {
|
featureRouter.get("", async (req: any, res: any) => {
|
||||||
try {
|
try {
|
||||||
let features = await FeatureService.getFromReq(req);
|
let features = await FeatureService.getFromReq(req);
|
||||||
res.status(200).json({ features });
|
res.status(200).json({ features });
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { autumnHandler } from "autumn-js/express";
|
|||||||
import { withAdminAuth } from "./admin/withAdminAuth.js";
|
import { withAdminAuth } from "./admin/withAdminAuth.js";
|
||||||
import { adminRouter } from "./admin/adminRouter.js";
|
import { adminRouter } from "./admin/adminRouter.js";
|
||||||
|
|
||||||
const mainRouter = Router();
|
const mainRouter: Router = Router();
|
||||||
|
|
||||||
mainRouter.get("", async (req: any, res) => {
|
mainRouter.get("", async (req: any, res) => {
|
||||||
res.status(200).json({ message: "Hello World" });
|
res.status(200).json({ message: "Hello World" });
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
UsagePriceConfig,
|
UsagePriceConfig,
|
||||||
} from "@autumn/shared";
|
} from "@autumn/shared";
|
||||||
import { routeHandler } from "@/utils/routerUtils.js";
|
import { routeHandler } from "@/utils/routerUtils.js";
|
||||||
import express from "express";
|
import express, { Router } from "express";
|
||||||
import { constructMigrationJob } from "@/internal/migrations/migrationUtils.js";
|
import { constructMigrationJob } from "@/internal/migrations/migrationUtils.js";
|
||||||
import { MigrationService } from "@/internal/migrations/MigrationService.js";
|
import { MigrationService } from "@/internal/migrations/MigrationService.js";
|
||||||
import { JobName } from "@/queue/JobName.js";
|
import { JobName } from "@/queue/JobName.js";
|
||||||
@@ -20,7 +20,7 @@ import { isFreeProduct } from "@/internal/products/productUtils.js";
|
|||||||
import { ExtendedRequest, ExtendedResponse } from "@/utils/models/Request.js";
|
import { ExtendedRequest, ExtendedResponse } from "@/utils/models/Request.js";
|
||||||
import { findPrepaidPrice } from "../products/prices/priceUtils/findPriceUtils.js";
|
import { findPrepaidPrice } from "../products/prices/priceUtils/findPriceUtils.js";
|
||||||
|
|
||||||
export const migrationRouter = express.Router();
|
export const migrationRouter: Router = express.Router();
|
||||||
|
|
||||||
migrationRouter.post("", async (req: any, res: any) => {
|
migrationRouter.post("", async (req: any, res: any) => {
|
||||||
return routeHandler({
|
return routeHandler({
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
import { createClerkCli } from "@/external/clerkUtils.js";
|
|
||||||
import { saveOrgToDB } from "@/external/webhooks/clerkWebhooks.js";
|
|
||||||
import { auth } from "@/utils/auth.js";
|
|
||||||
|
|
||||||
import { ExtendedRequest, ExtendedResponse } from "@/utils/models/Request.js";
|
import { ExtendedRequest, ExtendedResponse } from "@/utils/models/Request.js";
|
||||||
import { routeHandler } from "@/utils/routerUtils.js";
|
import { routeHandler } from "@/utils/routerUtils.js";
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { Router } from "express";
|
|||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { routeHandler } from "@/utils/routerUtils.js";
|
import { routeHandler } from "@/utils/routerUtils.js";
|
||||||
import RecaseError from "@/utils/errorUtils.js";
|
import RecaseError from "@/utils/errorUtils.js";
|
||||||
import { createClerkCli } from "@/external/clerkUtils.js";
|
|
||||||
import { AppEnv } from "@autumn/shared";
|
import { AppEnv } from "@autumn/shared";
|
||||||
import { parseChatResultFeatures } from "./parseChatFeatures.js";
|
import { parseChatResultFeatures } from "./parseChatFeatures.js";
|
||||||
import { parseChatProducts } from "./parseChatProducts.js";
|
import { parseChatProducts } from "./parseChatProducts.js";
|
||||||
@@ -14,7 +13,7 @@ import { EntitlementService } from "@/internal/products/entitlements/Entitlement
|
|||||||
import { PriceService } from "@/internal/products/prices/PriceService.js";
|
import { PriceService } from "@/internal/products/prices/PriceService.js";
|
||||||
import { ExtendedRequest, ExtendedResponse } from "@/utils/models/Request.js";
|
import { ExtendedRequest, ExtendedResponse } from "@/utils/models/Request.js";
|
||||||
|
|
||||||
export const onboardingRouter = Router();
|
export const onboardingRouter: Router = Router();
|
||||||
|
|
||||||
onboardingRouter.post("", async (req: Request, res: any) =>
|
onboardingRouter.post("", async (req: Request, res: any) =>
|
||||||
routeHandler({
|
routeHandler({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import express from "express";
|
import express, { Router } from "express";
|
||||||
import Stripe from "stripe";
|
import Stripe from "stripe";
|
||||||
|
|
||||||
import RecaseError, { handleRequestError } from "@/utils/errorUtils.js";
|
import RecaseError, { handleRequestError } from "@/utils/errorUtils.js";
|
||||||
@@ -22,7 +22,7 @@ import { handleInvite } from "./handlers/handleInvite.js";
|
|||||||
import { handleGetUploadUrl } from "./handlers/handleGetUploadUrl.js";
|
import { handleGetUploadUrl } from "./handlers/handleGetUploadUrl.js";
|
||||||
import { handleDeleteOrg } from "./handlers/handleDeleteOrg.js";
|
import { handleDeleteOrg } from "./handlers/handleDeleteOrg.js";
|
||||||
|
|
||||||
export const orgRouter = express.Router();
|
export const orgRouter: Router = express.Router();
|
||||||
orgRouter.get("/members", handleGetOrgMembers);
|
orgRouter.get("/members", handleGetOrgMembers);
|
||||||
orgRouter.get("/upload_url", handleGetUploadUrl);
|
orgRouter.get("/upload_url", handleGetUploadUrl);
|
||||||
orgRouter.post("/invite", handleInvite as any);
|
orgRouter.post("/invite", handleInvite as any);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { isFeaturePriceItem } from "./product-items/productItemUtils/getItemType
|
|||||||
import RecaseError, { handleFrontendReqError } from "@/utils/errorUtils.js";
|
import RecaseError, { handleFrontendReqError } from "@/utils/errorUtils.js";
|
||||||
import { createOrgResponse } from "../orgs/orgUtils.js";
|
import { createOrgResponse } from "../orgs/orgUtils.js";
|
||||||
|
|
||||||
export const productRouter = Router({ mergeParams: true });
|
export const productRouter: Router = Router({ mergeParams: true });
|
||||||
|
|
||||||
productRouter.get("/data", async (req: any, res) => {
|
productRouter.get("/data", async (req: any, res) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import RecaseError from "@/utils/errorUtils.js";
|
import RecaseError from "@/utils/errorUtils.js";
|
||||||
|
|
||||||
import { nullish } from "@/utils/genUtils.js";
|
import { nullish } from "@/utils/genUtils.js";
|
||||||
import { numberWithCommas } from "tests/utils/general/numberUtils.js";
|
|
||||||
import { getFeatureName } from "@/internal/features/utils/displayUtils.js";
|
import { getFeatureName } from "@/internal/features/utils/displayUtils.js";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -13,6 +12,7 @@ import {
|
|||||||
ErrCode,
|
ErrCode,
|
||||||
Infinite,
|
Infinite,
|
||||||
FullCusProduct,
|
FullCusProduct,
|
||||||
|
numberWithCommas,
|
||||||
} from "@autumn/shared";
|
} from "@autumn/shared";
|
||||||
import { isPriceItem } from "../product-items/productItemUtils/getItemType.js";
|
import { isPriceItem } from "../product-items/productItemUtils/getItemType.js";
|
||||||
import { isFeaturePriceItem } from "../product-items/productItemUtils/getItemType.js";
|
import { isFeaturePriceItem } from "../product-items/productItemUtils/getItemType.js";
|
||||||
|
|||||||
@@ -1,23 +1,7 @@
|
|||||||
import { createSupabaseClient } from "@/external/supabaseUtils.js";
|
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
|
||||||
export const userRouter = Router();
|
export const userRouter: Router = Router();
|
||||||
|
|
||||||
userRouter.get("", async (req: any, res) => {
|
userRouter.get("", async (req: any, res) => {
|
||||||
const supabase = createSupabaseClient();
|
|
||||||
|
|
||||||
res.status(200).json({ userId: req.userId });
|
res.status(200).json({ userId: req.userId });
|
||||||
// const { data, error } = await supabase
|
|
||||||
// .from("users")
|
|
||||||
// .select("id, email, initialized")
|
|
||||||
// .eq("id", req.userId)
|
|
||||||
// .single();
|
|
||||||
|
|
||||||
// if (error) {
|
|
||||||
// console.error("Error fetching user data:", error);
|
|
||||||
// res.status(500).json({ error: error.message });
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// res.status(200).json(data);
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
import "dotenv/config";
|
||||||
|
|
||||||
import { Queue } from "bullmq";
|
import { Queue } from "bullmq";
|
||||||
import { Redis } from "ioredis";
|
import { Redis } from "ioredis";
|
||||||
|
|
||||||
|
const BACKUP_REDIS_URL = process.env.REDIS_BACKUP_URL || process.env.REDIS_URL;
|
||||||
|
const MAIN_REDIS_URL = process.env.REDIS_URL;
|
||||||
|
|
||||||
export class QueueManager {
|
export class QueueManager {
|
||||||
private static instance: QueueManager;
|
private static instance: QueueManager;
|
||||||
private queue: Queue | null = null;
|
private queue: Queue | null = null;
|
||||||
@@ -33,9 +38,7 @@ export class QueueManager {
|
|||||||
}) {
|
}) {
|
||||||
// 1. Connect to redis
|
// 1. Connect to redis
|
||||||
|
|
||||||
const redisUrl = useBackup
|
const redisUrl = useBackup ? BACKUP_REDIS_URL : MAIN_REDIS_URL;
|
||||||
? process.env.REDIS_BACKUP_URL
|
|
||||||
: process.env.REDIS_URL;
|
|
||||||
|
|
||||||
const connection = new Redis(redisUrl!, {
|
const connection = new Redis(redisUrl!, {
|
||||||
retryStrategy: (times) => {
|
retryStrategy: (times) => {
|
||||||
@@ -47,7 +50,7 @@ export class QueueManager {
|
|||||||
console.log(
|
console.log(
|
||||||
`Redis connection error (${useBackup ? "backup" : "main"}): ${
|
`Redis connection error (${useBackup ? "backup" : "main"}): ${
|
||||||
error.message
|
error.message
|
||||||
}`
|
}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!keepConnection) {
|
if (!keepConnection) {
|
||||||
@@ -90,7 +93,7 @@ export class QueueManager {
|
|||||||
console.log("2. Initializing main & backup queues");
|
console.log("2. Initializing main & backup queues");
|
||||||
const mainQueue = new Queue("autumn", {
|
const mainQueue = new Queue("autumn", {
|
||||||
connection: {
|
connection: {
|
||||||
url: process.env.REDIS_URL,
|
url: MAIN_REDIS_URL,
|
||||||
enableOfflineQueue: false,
|
enableOfflineQueue: false,
|
||||||
retryStrategy: (times) => {
|
retryStrategy: (times) => {
|
||||||
return 5000;
|
return 5000;
|
||||||
@@ -100,7 +103,7 @@ export class QueueManager {
|
|||||||
|
|
||||||
const backupQueue = new Queue("autumn", {
|
const backupQueue = new Queue("autumn", {
|
||||||
connection: {
|
connection: {
|
||||||
url: process.env.REDIS_BACKUP_URL,
|
url: BACKUP_REDIS_URL,
|
||||||
enableOfflineQueue: false,
|
enableOfflineQueue: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import sendOTPEmail from "@/internal/emails/sendOTPEmail.js";
|
|||||||
import { sendOnboardingEmail } from "@/internal/emails/sendOnboardingEmail.js";
|
import { sendOnboardingEmail } from "@/internal/emails/sendOnboardingEmail.js";
|
||||||
import { ADMIN_USER_IDs } from "./constants.js";
|
import { ADMIN_USER_IDs } from "./constants.js";
|
||||||
import { afterOrgCreated } from "./authUtils/afterOrgCreated.js";
|
import { afterOrgCreated } from "./authUtils/afterOrgCreated.js";
|
||||||
|
|
||||||
export const auth = betterAuth({
|
export const auth = betterAuth({
|
||||||
database: drizzleAdapter(db, {
|
database: drizzleAdapter(db, {
|
||||||
provider: "pg", // or "mysql", "sqlite"
|
provider: "pg", // or "mysql", "sqlite"
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
import { WebSocketServer } from "ws";
|
|
||||||
import http from "http";
|
|
||||||
|
|
||||||
export class WebsocketManager {
|
export class WebsocketManager {
|
||||||
public channels: Map<string, Set<WebSocket>>;
|
public channels: Map<string, Set<WebSocket>>;
|
||||||
public subscriptions: WeakMap<WebSocket, Set<string>>;
|
public subscriptions: WeakMap<WebSocket, Set<string>>;
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import { WebSocketServer } from "ws";
|
|
||||||
import http from "http";
|
import http from "http";
|
||||||
|
|
||||||
import { createSupabaseClient } from "@/external/supabaseUtils.js";
|
|
||||||
import { AppEnv, ErrCode } from "@autumn/shared";
|
import { AppEnv, ErrCode } from "@autumn/shared";
|
||||||
import { OrgService } from "@/internal/orgs/OrgService.js";
|
import { WebSocketServer, WebSocket } from "ws";
|
||||||
|
|
||||||
export enum SbChannelEvent {
|
export enum SbChannelEvent {
|
||||||
BalanceUpdated = "balance_updated",
|
BalanceUpdated = "balance_updated",
|
||||||
@@ -74,7 +71,7 @@ class WebSocketRouter {
|
|||||||
|
|
||||||
constructor(server: http.Server) {
|
constructor(server: http.Server) {
|
||||||
this.wss = new WebSocketServer({ server });
|
this.wss = new WebSocketServer({ server });
|
||||||
this.wss.on("connection", (ws, req) =>
|
this.wss.on("connection", (ws: WebSocket, req: http.IncomingMessage) =>
|
||||||
this.handleConnection(ws as any, req as any),
|
this.handleConnection(ws as any, req as any),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"moduleResolution": "NodeNext",
|
"moduleResolution": "NodeNext",
|
||||||
"module": "NodeNext",
|
"module": "NodeNext",
|
||||||
"declaration": true,
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
@@ -17,9 +18,10 @@
|
|||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"],
|
||||||
|
"@emails/*": ["emails/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src", "emails"],
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
},
|
},
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"moduleResolution": "NodeNext", // or "node16"/"nodenext"
|
"moduleResolution": "NodeNext",
|
||||||
"module": "NodeNext", // or "node16"/"nodenext"
|
"module": "NodeNext",
|
||||||
|
|
||||||
// "declaration": true,
|
// "declaration": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
|
|||||||
@@ -12,15 +12,18 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
|
"dev": "nodemon --watch . --ext ts --ignore dist --exec 'pnpm run build'",
|
||||||
"db:generate": "NODE_OPTIONS='--import tsx' drizzle-kit generate --config drizzle.config.ts",
|
"db:generate": "NODE_OPTIONS='--import tsx' drizzle-kit generate --config drizzle.config.ts",
|
||||||
"db:migrate": "NODE_OPTIONS='--import tsx' drizzle-kit migrate --config drizzle.config.ts"
|
"db:migrate": "NODE_OPTIONS='--import tsx' drizzle-kit migrate --config drizzle.config.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"decimal.js": "^10.5.0",
|
||||||
"drizzle-orm": "^0.43.1",
|
"drizzle-orm": "^0.43.1",
|
||||||
"drizzle-zod": "^0.8.1",
|
"drizzle-zod": "^0.8.2",
|
||||||
"zod": "^3.25.23"
|
"zod": "^3.25.23"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"nodemon": "^3.1.7",
|
||||||
"tsx": "^4.19.4",
|
"tsx": "^4.19.4",
|
||||||
"typescript": "^5.7.2"
|
"typescript": "^5.7.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "@autumn/frontend2",
|
"name": "@autumn/vite",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --port 3000",
|
"dev": "vite --port 3000 --host",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview",
|
||||||
|
"start": "serve -s dist"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@autumn/shared": "*",
|
"@autumn/shared": "workspace:*",
|
||||||
"@clerk/clerk-react": "^5.24.2",
|
"@clerk/clerk-react": "^5.24.2",
|
||||||
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
@@ -32,10 +33,12 @@
|
|||||||
"@wooorm/starry-night": "^3.6.0",
|
"@wooorm/starry-night": "^3.6.0",
|
||||||
"autumn-js": "^0.0.41",
|
"autumn-js": "^0.0.41",
|
||||||
"axios": "^1.8.3",
|
"axios": "^1.8.3",
|
||||||
|
"better-auth": "^1.2.9",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
|
"decimal.js": "^10.5.0",
|
||||||
"hast-util-to-html": "^9.0.5",
|
"hast-util-to-html": "^9.0.5",
|
||||||
"input-otp": "^1.4.2",
|
"input-otp": "^1.4.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
@@ -55,10 +58,12 @@
|
|||||||
"react-router": "^7.3.0",
|
"react-router": "^7.3.0",
|
||||||
"sonner": "^2.0.1",
|
"sonner": "^2.0.1",
|
||||||
"svix-react": "^1.13.3",
|
"svix-react": "^1.13.3",
|
||||||
|
"swr": "^2.3.3",
|
||||||
"tailwind-merge": "^3.0.2",
|
"tailwind-merge": "^3.0.2",
|
||||||
"tailwindcss": "^4.0.13",
|
"tailwindcss": "^4.0.13",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"vaul": "^1.1.2"
|
"vaul": "^1.1.2",
|
||||||
|
"zod": "^3.25.23"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.21.0",
|
"@eslint/js": "^9.21.0",
|
||||||
@@ -75,11 +80,5 @@
|
|||||||
"typescript": "~5.7.2",
|
"typescript": "~5.7.2",
|
||||||
"typescript-eslint": "^8.24.1",
|
"typescript-eslint": "^8.24.1",
|
||||||
"vite": "^6.2.0"
|
"vite": "^6.2.0"
|
||||||
},
|
|
||||||
"resolutions": {
|
|
||||||
"@rollup/rollup-linux-x64-gnu": "npm:@rollup/rollup-linux-x64-musl"
|
|
||||||
},
|
|
||||||
"overrides": {
|
|
||||||
"@rollup/rollup-linux-x64-gnu": "npm:@rollup/rollup-linux-x64-musl"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Reward, CreateReward } from "@autumn/shared";
|
import { Reward, CreateReward } from "@autumn/shared";
|
||||||
|
|
||||||
import { SupabaseClient } from "@supabase/supabase-js";
|
|
||||||
import { AxiosInstance } from "axios";
|
import { AxiosInstance } from "axios";
|
||||||
|
|
||||||
export class RewardService {
|
export class RewardService {
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export const columns: OrgColumnDef[] = [
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
cell: ({ row }: { row: Row<Org> }) => {
|
cell: ({ row }: { row: Row<Org> }) => {
|
||||||
const value = row.getValue("users");
|
const value = row.getValue("users");
|
||||||
return <span className="truncate">{value?.join(", ")}</span>;
|
return <span className="truncate">{(value as string[]).join(", ")}</span>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user