Skip to content

Commit 96423fc

Browse files
committed
refactoring: rewrite sync to class (#137)
Refactor to having a single class for syncing Stripe entities - while the class itself is a bit large, it avoids having to do parameter drilling through many methods and actually reduces overall code by quite a bit. Additionally - Reduced boilerplate for backfills (generic function) - Reduced boilerplate for deletions - Reduced boilerplate for auto-expanding lists - Migrated from jest to vitest - Sped up CI - Config option to enable/disable automatic backfills - Configurable max connections - Migrate to pnpm
1 parent 012a2d5 commit 96423fc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+4506
-9332
lines changed

.env.sample

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,12 @@ STRIPE_API_VERSION="2020-08-27"
2323
## - charges.refunds
2424
## - subscription.items
2525
AUTO_EXPAND_LISTS=false
26+
27+
# optional
28+
# If true, the sync engine will backfill related entities, i.e. when a invoice webhook comes in, it ensures that the customer is present and synced.
29+
# This ensures foreign key integrity, but comes at the cost of additional queries to the database (and added latency for Stripe calls if the entity is actually missing).
30+
BACKFILL_RELATED_ENTITIES=true
31+
32+
# optional, default 10
33+
# Max number of connections for the Postgres connection pool, higher value lead to more concurrent queries, but also more load on the database (connections are expensive)
34+
MAX_POSTGRES_CONNECTIONS=20

.github/workflows/ci.yml

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,35 @@ on:
99

1010
jobs:
1111
test:
12-
name: Test / OS ${{ matrix.platform }} / Node ${{ matrix.node }}
13-
strategy:
14-
fail-fast: false
15-
matrix:
16-
platform: [ubuntu-24.04]
17-
node: ['22']
12+
name: Test
13+
runs-on: ubuntu-24.04
1814

19-
runs-on: ${{ matrix.platform }}
15+
services:
16+
postgres:
17+
image: postgres:15
18+
ports:
19+
- 55432:5432
20+
env:
21+
POSTGRES_DB: postgres
22+
POSTGRES_USER: postgres
23+
POSTGRES_PASSWORD: postgres
2024

2125
steps:
2226
- uses: actions/checkout@v4
23-
- uses: actions/cache@v4
24-
with:
25-
path: ~/.npm
26-
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
27-
restore-keys: |
28-
${{ runner.os }}-node-
27+
28+
- name: Install pnpm
29+
uses: pnpm/action-setup@v4
30+
2931
- name: Set up Node
3032
uses: actions/setup-node@v4
3133
with:
32-
node-version: ${{ matrix.node }}
34+
node-version-file: ./.nvmrc
35+
cache: pnpm
3336

3437
- name: Set up .env file
3538
run: |
3639
touch .env
37-
echo DATABASE_URL='postgres://postgres:postgres@127.0.0.1:55432/postgres?sslmode=disable&search_path=stripe' >> .env
40+
echo DATABASE_URL='postgres://postgres:postgres@localhost:55432/postgres?sslmode=disable&search_path=stripe' >> .env
3841
echo NODE_ENV=dev >> .env
3942
echo STRIPE_SECRET_KEY=sk_test_ >> .env
4043
echo STRIPE_WEBHOOK_SECRET=whsec_ >> .env
@@ -44,21 +47,29 @@ jobs:
4447
4548
- name: Install dependencies
4649
run: |
47-
npm ci
50+
pnpm install --frozen-lockfile
4851
4952
- name: Formatting checks
5053
run: |
51-
npm run format:check
54+
pnpm format:check
5255
5356
- name: Lint
5457
run: |
55-
npm run lint
58+
pnpm lint
5659
5760
- name: Builds successfully
5861
run: |
59-
npm run build
62+
pnpm typecheck
63+
64+
65+
- name: Initialize DB schema
66+
run: |
67+
docker run --rm \
68+
--network="host" \
69+
-e PGPASSWORD=postgres \
70+
postgres:15 \
71+
psql -h localhost -p 55432 -U postgres -d postgres -c 'create schema if not exists "stripe";'
6072
6173
- name: Tests
6274
run: |
63-
docker compose -f ./docker/compose.yml up -d
6475
npm run test

.github/workflows/release.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
name: release
22

33
on:
4-
push:
5-
branches:
6-
- 'main'
4+
#push:
5+
# branches:
6+
# - 'main'
77
workflow_dispatch:
88

99
jobs:
@@ -29,8 +29,7 @@ jobs:
2929
node-version: ${{ matrix.node }}
3030

3131
- run: |
32-
npm clean-install
33-
npm run build
32+
pnpm install --frozen-lockfile
3433
3534
- name: Run semantic-release
3635
id: semantic-release

.prettierignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.expo
22
.next
33
node_modules
4-
package-lock.json
4+
pnpm-lock.yaml
55
docker*
66
Pulumi.*.yaml

.tours/implement-a-webhook.tour

Lines changed: 0 additions & 57 deletions
This file was deleted.

Dockerfile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
# Build step
22
FROM node:22-alpine
3+
4+
RUN npm install -g [email protected]
5+
36
WORKDIR /app
4-
COPY package.json package-lock.json ./
5-
RUN npm ci
7+
COPY package.json pnpm-lock.yaml ./
8+
RUN pnpm install --frozen-lockfile
69
COPY . /app
7-
RUN npm run build
8-
RUN npm prune --production
10+
RUN pnpm build
11+
RUN pnpm prune --production
912

1013
## Build step complete, copy to working image
1114
FROM node:22-alpine

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ The entity type is recognized automatically, based on the prefix.
175175

176176
**Develop**
177177

178-
- `npm run dev` to start the local server
179-
- `npm run test` to run tests
178+
- `pnpm dev` to start the local server
179+
- `pnpm t` to run tests
180180

181181
**Building Docker**
182182

eslint.config.mjs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
import tsParser from "@typescript-eslint/parser";
2-
import path from "node:path";
3-
import { fileURLToPath } from "node:url";
4-
import js from "@eslint/js";
5-
import { FlatCompat } from "@eslint/eslintrc";
1+
import tsParser from '@typescript-eslint/parser'
2+
import path from 'node:path'
3+
import { fileURLToPath } from 'node:url'
4+
import js from '@eslint/js'
5+
import { FlatCompat } from '@eslint/eslintrc'
66

7-
const __filename = fileURLToPath(import.meta.url);
8-
const __dirname = path.dirname(__filename);
7+
const __filename = fileURLToPath(import.meta.url)
8+
const __dirname = path.dirname(__filename)
99
const compat = new FlatCompat({
10-
baseDirectory: __dirname,
11-
recommendedConfig: js.configs.recommended,
12-
allConfig: js.configs.all
13-
});
10+
baseDirectory: __dirname,
11+
recommendedConfig: js.configs.recommended,
12+
allConfig: js.configs.all,
13+
})
1414

1515
export default [
16-
...compat.extends("plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"),
17-
{
18-
languageOptions: {
19-
parser: tsParser,
20-
ecmaVersion: 2022,
21-
sourceType: "module",
22-
},
16+
...compat.extends('plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'),
17+
{
18+
languageOptions: {
19+
parser: tsParser,
20+
ecmaVersion: 2022,
21+
sourceType: 'module',
2322
},
24-
];
23+
},
24+
]

jest.config.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)