├── .env.example ├── .gitignore ├── .idea ├── .gitignore ├── dataSources.xml ├── modules.xml ├── prettier.xml ├── stripe_to_postgres.iml └── vcs.xml ├── .prettierrc ├── Dockerfile ├── Makefile ├── README.md ├── docker-compose.yml ├── migrations ├── 0000_create_schema.sql └── 0001_add_updated_at.sql ├── package-lock.json ├── package.json ├── src ├── config.ts ├── connection.ts ├── migrate.ts ├── server.ts ├── stripe.ts ├── sync.ts ├── utils.ts └── webhook.ts └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | PORT=3000 3 | SKIP_SYNC=false 4 | SKIP_MIGRATIONS=false 5 | DATABASE_URL=postgres://postgres:postgres@host:5432/postgres?sslmode=disable&search_path=stripe 6 | STRIPE_SECRET_KEY=sk_test_ 7 | STRIPE_WEBHOOK_SECRET= 8 | WEBHOOK_URL= 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node,macos,linux,webstorm,visualstudiocode,sublimetext 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,linux,webstorm,visualstudiocode,sublimetext 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### macOS ### 20 | # General 21 | .DS_Store 22 | .AppleDouble 23 | .LSOverride 24 | 25 | # Icon must end with two \r 26 | Icon 27 | 28 | 29 | # Thumbnails 30 | ._* 31 | 32 | # Files that might appear in the root of a volume 33 | .DocumentRevisions-V100 34 | .fseventsd 35 | .Spotlight-V100 36 | .TemporaryItems 37 | .Trashes 38 | .VolumeIcon.icns 39 | .com.apple.timemachine.donotpresent 40 | 41 | # Directories potentially created on remote AFP share 42 | .AppleDB 43 | .AppleDesktop 44 | Network Trash Folder 45 | Temporary Items 46 | .apdisk 47 | 48 | ### macOS Patch ### 49 | # iCloud generated files 50 | *.icloud 51 | 52 | ### Node ### 53 | # Logs 54 | logs 55 | *.log 56 | npm-debug.log* 57 | yarn-debug.log* 58 | yarn-error.log* 59 | lerna-debug.log* 60 | .pnpm-debug.log* 61 | 62 | # Diagnostic reports (https://nodejs.org/api/report.html) 63 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 64 | 65 | # Runtime data 66 | pids 67 | *.pid 68 | *.seed 69 | *.pid.lock 70 | 71 | # Directory for instrumented libs generated by jscoverage/JSCover 72 | lib-cov 73 | 74 | # Coverage directory used by tools like istanbul 75 | coverage 76 | *.lcov 77 | 78 | # nyc test coverage 79 | .nyc_output 80 | 81 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 82 | .grunt 83 | 84 | # Bower dependency directory (https://bower.io/) 85 | bower_components 86 | 87 | # node-waf configuration 88 | .lock-wscript 89 | 90 | # Compiled binary addons (https://nodejs.org/api/addons.html) 91 | build/Release 92 | 93 | # Dependency directories 94 | node_modules/ 95 | jspm_packages/ 96 | 97 | # Snowpack dependency directory (https://snowpack.dev/) 98 | web_modules/ 99 | 100 | # TypeScript cache 101 | *.tsbuildinfo 102 | 103 | # Optional npm cache directory 104 | .npm 105 | 106 | # Optional eslint cache 107 | .eslintcache 108 | 109 | # Optional stylelint cache 110 | .stylelintcache 111 | 112 | # Microbundle cache 113 | .rpt2_cache/ 114 | .rts2_cache_cjs/ 115 | .rts2_cache_es/ 116 | .rts2_cache_umd/ 117 | 118 | # Optional REPL history 119 | .node_repl_history 120 | 121 | # Output of 'npm pack' 122 | *.tgz 123 | 124 | # Yarn Integrity file 125 | .yarn-integrity 126 | 127 | # dotenv environment variable files 128 | .env 129 | .env.development.local 130 | .env.test.local 131 | .env.production.local 132 | .env.local 133 | 134 | # parcel-bundler cache (https://parceljs.org/) 135 | .cache 136 | .parcel-cache 137 | 138 | # Next.js build output 139 | .next 140 | out 141 | 142 | # Nuxt.js build / generate output 143 | .nuxt 144 | dist 145 | 146 | # Gatsby files 147 | .cache/ 148 | # Comment in the public line in if your project uses Gatsby and not Next.js 149 | # https://nextjs.org/blog/next-9-1#public-directory-support 150 | # public 151 | 152 | # vuepress build output 153 | .vuepress/dist 154 | 155 | # vuepress v2.x temp and cache directory 156 | .temp 157 | 158 | # Docusaurus cache and generated files 159 | .docusaurus 160 | 161 | # Serverless directories 162 | .serverless/ 163 | 164 | # FuseBox cache 165 | .fusebox/ 166 | 167 | # DynamoDB Local files 168 | .dynamodb/ 169 | 170 | # TernJS port file 171 | .tern-port 172 | 173 | # Stores VSCode versions used for testing VSCode extensions 174 | .vscode-test 175 | 176 | # yarn v2 177 | .yarn/cache 178 | .yarn/unplugged 179 | .yarn/build-state.yml 180 | .yarn/install-state.gz 181 | .pnp.* 182 | 183 | ### Node Patch ### 184 | # Serverless Webpack directories 185 | .webpack/ 186 | 187 | # Optional stylelint cache 188 | 189 | # SvelteKit build / generate output 190 | .svelte-kit 191 | 192 | ### SublimeText ### 193 | # Cache files for Sublime Text 194 | *.tmlanguage.cache 195 | *.tmPreferences.cache 196 | *.stTheme.cache 197 | 198 | # Workspace files are user-specific 199 | *.sublime-workspace 200 | 201 | # Project files should be checked into the repository, unless a significant 202 | # proportion of contributors will probably not be using Sublime Text 203 | # *.sublime-project 204 | 205 | # SFTP configuration file 206 | sftp-config.json 207 | sftp-config-alt*.json 208 | 209 | # Package control specific files 210 | Package Control.last-run 211 | Package Control.ca-list 212 | Package Control.ca-bundle 213 | Package Control.system-ca-bundle 214 | Package Control.cache/ 215 | Package Control.ca-certs/ 216 | Package Control.merged-ca-bundle 217 | Package Control.user-ca-bundle 218 | oscrypto-ca-bundle.crt 219 | bh_unicode_properties.cache 220 | 221 | # Sublime-github package stores a github token in this file 222 | # https://packagecontrol.io/packages/sublime-github 223 | GitHub.sublime-settings 224 | 225 | ### VisualStudioCode ### 226 | .vscode/* 227 | !.vscode/settings.json 228 | !.vscode/tasks.json 229 | !.vscode/launch.json 230 | !.vscode/extensions.json 231 | !.vscode/*.code-snippets 232 | 233 | # Local History for Visual Studio Code 234 | .history/ 235 | 236 | # Built Visual Studio Code Extensions 237 | *.vsix 238 | 239 | ### VisualStudioCode Patch ### 240 | # Ignore all local history of files 241 | .history 242 | .ionide 243 | 244 | # Support for Project snippet scope 245 | .vscode/*.code-snippets 246 | 247 | # Ignore code-workspaces 248 | *.code-workspace 249 | 250 | ### WebStorm ### 251 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 252 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 253 | 254 | # User-specific stuff 255 | .idea/**/workspace.xml 256 | .idea/**/tasks.xml 257 | .idea/**/usage.statistics.xml 258 | .idea/**/dictionaries 259 | .idea/**/shelf 260 | 261 | # AWS User-specific 262 | .idea/**/aws.xml 263 | 264 | # Generated files 265 | .idea/**/contentModel.xml 266 | 267 | # Sensitive or high-churn files 268 | .idea/**/dataSources/ 269 | .idea/**/dataSources.ids 270 | .idea/**/dataSources.local.xml 271 | .idea/**/sqlDataSources.xml 272 | .idea/**/dynamic.xml 273 | .idea/**/uiDesigner.xml 274 | .idea/**/dbnavigator.xml 275 | 276 | # Gradle 277 | .idea/**/gradle.xml 278 | .idea/**/libraries 279 | 280 | # Gradle and Maven with auto-import 281 | # When using Gradle or Maven with auto-import, you should exclude module files, 282 | # since they will be recreated, and may cause churn. Uncomment if using 283 | # auto-import. 284 | # .idea/artifacts 285 | # .idea/compiler.xml 286 | # .idea/jarRepositories.xml 287 | # .idea/modules.xml 288 | # .idea/*.iml 289 | # .idea/modules 290 | # *.iml 291 | # *.ipr 292 | 293 | # CMake 294 | cmake-build-*/ 295 | 296 | # Mongo Explorer plugin 297 | .idea/**/mongoSettings.xml 298 | 299 | # File-based project format 300 | *.iws 301 | 302 | # IntelliJ 303 | out/ 304 | 305 | # mpeltonen/sbt-idea plugin 306 | .idea_modules/ 307 | 308 | # JIRA plugin 309 | atlassian-ide-plugin.xml 310 | 311 | # Cursive Clojure plugin 312 | .idea/replstate.xml 313 | 314 | # SonarLint plugin 315 | .idea/sonarlint/ 316 | 317 | # Crashlytics plugin (for Android Studio and IntelliJ) 318 | com_crashlytics_export_strings.xml 319 | crashlytics.properties 320 | crashlytics-build.properties 321 | fabric.properties 322 | 323 | # Editor-based Rest Client 324 | .idea/httpRequests 325 | 326 | # Android studio 3.1+ serialized cache file 327 | .idea/caches/build_file_checksums.ser 328 | 329 | ### WebStorm Patch ### 330 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 331 | 332 | # *.iml 333 | # modules.xml 334 | # .idea/misc.xml 335 | # *.ipr 336 | 337 | # Sonarlint plugin 338 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 339 | .idea/**/sonarlint/ 340 | 341 | # SonarQube Plugin 342 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 343 | .idea/**/sonarIssues.xml 344 | 345 | # Markdown Navigator plugin 346 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 347 | .idea/**/markdown-navigator.xml 348 | .idea/**/markdown-navigator-enh.xml 349 | .idea/**/markdown-navigator/ 350 | 351 | # Cache file creation bug 352 | # See https://youtrack.jetbrains.com/issue/JBR-2257 353 | .idea/$CACHE_FILE$ 354 | 355 | # CodeStream plugin 356 | # https://plugins.jetbrains.com/plugin/12206-codestream 357 | .idea/codestream.xml 358 | 359 | # Azure Toolkit for IntelliJ plugin 360 | # https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij 361 | .idea/**/azureSettings.xml 362 | 363 | # End of https://www.toptal.com/developers/gitignore/api/node,macos,linux,webstorm,visualstudiocode,sublimetext 364 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | postgresql 6 | true 7 | org.postgresql.Driver 8 | jdbc:postgresql://localhost:5432/postgres 9 | $ProjectFileDir$ 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/prettier.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/stripe_to_postgres.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "semi": false, 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine AS builder 2 | 3 | WORKDIR /usr/src/app 4 | 5 | COPY package*.json tsconfig.json ./ 6 | 7 | RUN npm install --only=dev 8 | 9 | COPY src ./src 10 | 11 | RUN npm run build 12 | 13 | FROM node:18-alpine 14 | 15 | ENV NODE_ENV production 16 | 17 | WORKDIR /usr/src/app 18 | 19 | COPY package*.json ./ 20 | 21 | RUN npm install --only=prod 22 | 23 | COPY --from=builder /usr/src/app/dist ./dist 24 | 25 | COPY migrations ./migrations 26 | 27 | CMD npm start 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all buildx 2 | 3 | all: buildx 4 | 5 | buildx: 6 | @docker buildx build --platform linux/amd64,linux/arm64 -t usenoori/stripe_to_postgres:latest -t usenoori/stripe_to_postgres:`npm pkg get version | tr -d '"'` --push . 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stripe_to_postgres 2 | 3 | ## Why we exist 4 | 5 | We built Noori after working on multiple startups, where we had to rewrite the same code each time. We thought there should be an easier solution. After looking around we realized no one was building it..so we build it! 6 | 7 | ## Usage 8 | 9 | `stripe_to_postgres` is packaged as a Docker image you can run directly. 10 | 11 | The image needs the following environment variables. 12 | 13 | - `DATABASE_URL` is your Postgres instance's connection string. 14 | - `STRIPE_SECRET_KEY` can be obtained from the Stripe dashboard https://dashboard.stripe.com/apikeys. 15 | - `WEBHOOK_URL` is your https enabled endpoint where this image is deployed. 16 | 17 | Example: 18 | 19 | - Put the env vars in a .env file then run `docker run --env-file=.env usenoori/stripe_to_postgres` 20 | 21 | ### Update your Postgres search_path 22 | 23 | By default, most database tools only look up database objects in the `public` schema, you might need to update 24 | the `search_path` in your existing tooling to include the `stripe` schema we created for you. 25 | 26 | ## How does it work? 27 | 28 | 1. `stripe_to_postgres` will first create a `stripe` schema then create all the necessary table structures in your database. 29 | 2. Then it will call Stripe and page through your Stripe data to stores them in your database. 30 | 3. After the data sync is done a Stripe webhook will be created that keep your database up to date. 31 | 32 | These are the Stripe resources that are currently handled by us. 33 | 34 | - events 35 | - products 36 | - prices 37 | - customers 38 | - subscriptions 39 | - invoices 40 | - charges 41 | - coupons 42 | - disputes 43 | - plans 44 | 45 | ## Requirements 46 | 47 | At the moment we support Postgres from version 10, as the features evolve this support target could move towards 48 | Postgres 12. 49 | 50 | ## Development 51 | 52 | 1. Start local Postgres instance: `docker compose up` 53 | 2. Run `stripe listen --forward-to localhost:3000` and add the output secret as `STRIPE_WEBHOOK_SECRET` env var 54 | 3. Start development server `npm run dev` 55 | 56 | ## Contact 57 | Questions? Comments? Email us at hello@usenoori.com 58 | 59 | 60 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | db: 5 | image: postgres:14 6 | ports: 7 | - "5432:5432" 8 | environment: 9 | POSTGRES_PASSWORD: postgres 10 | volumes: 11 | - db_data:/var/lib/postgresql/data 12 | 13 | volumes: 14 | db_data: 15 | -------------------------------------------------------------------------------- /migrations/0000_create_schema.sql: -------------------------------------------------------------------------------- 1 | create table if not exists stripe.events 2 | ( 3 | id text primary key, 4 | object text, 5 | api_version text, 6 | created integer, 7 | data jsonb, 8 | livemode boolean, 9 | pending_webhooks integer, 10 | request jsonb, 11 | type text 12 | ); 13 | 14 | create table if not exists stripe.products 15 | ( 16 | id text primary key, 17 | object text, 18 | active boolean, 19 | created integer, 20 | default_price text, 21 | description text, 22 | images jsonb, 23 | livemode boolean, 24 | metadata jsonb, 25 | name text, 26 | package_dimensions jsonb, 27 | shippable boolean, 28 | statement_descriptor text, 29 | tax_code text, 30 | unit_label text, 31 | updated integer, 32 | url text 33 | ); 34 | 35 | create type stripe.pricing_type as enum ( 36 | 'one_time', 37 | 'recurring' 38 | ); 39 | 40 | create type stripe.pricing_tiers as enum ( 41 | 'graduated', 42 | 'volume' 43 | ); 44 | 45 | create table if not exists stripe.prices 46 | ( 47 | id text primary key, 48 | object text, 49 | active boolean, 50 | billing_scheme text, 51 | created integer, 52 | currency text, 53 | custom_unit_amount jsonb, 54 | livemode boolean, 55 | lookup_key text, 56 | metadata jsonb, 57 | nickname text, 58 | product text, 59 | recurring jsonb, 60 | tax_behavior text, 61 | tiers_mode stripe.pricing_tiers, 62 | transform_quantity jsonb, 63 | type stripe.pricing_type, 64 | unit_amount integer, 65 | unit_amount_decimal text 66 | ); 67 | 68 | create table if not exists stripe.customers 69 | ( 70 | id text primary key, 71 | object text, 72 | address jsonb, 73 | balance integer, 74 | created integer, 75 | currency text, 76 | default_source text, 77 | delinquent boolean, 78 | description text, 79 | discount jsonb, 80 | email text, 81 | invoice_prefix text, 82 | invoice_settings jsonb, 83 | livemode boolean, 84 | metadata jsonb, 85 | name text, 86 | phone text, 87 | preferred_locales jsonb, 88 | shipping jsonb, 89 | tax_exempt text 90 | ); 91 | 92 | create type stripe.subscription_status as enum ( 93 | 'trialing', 94 | 'active', 95 | 'canceled', 96 | 'incomplete', 97 | 'incomplete_expired', 98 | 'past_due', 99 | 'unpaid' 100 | ); 101 | 102 | create table if not exists stripe.subscriptions 103 | ( 104 | id text primary key, 105 | object text, 106 | application text, 107 | application_fee_percent double precision, 108 | automatic_tax jsonb, 109 | billing_cycle_anchor integer, 110 | billing_thresholds jsonb, 111 | cancel_at integer, 112 | cancel_at_period_end boolean, 113 | canceled_at integer, 114 | collection_method text, 115 | created integer, 116 | currency text, 117 | current_period_end integer, 118 | current_period_start integer, 119 | customer text, 120 | days_until_due integer, 121 | default_payment_method text, 122 | default_source text, 123 | default_tax_rates jsonb, 124 | description text, 125 | discount jsonb, 126 | ended_at integer, 127 | items jsonb, 128 | latest_invoice text, 129 | livemode boolean, 130 | metadata jsonb, 131 | next_pending_invoice_item_invoice integer, 132 | pause_collection jsonb, 133 | payment_settings jsonb, 134 | pending_invoice_item_interval jsonb, 135 | pending_setup_intent text, 136 | pending_update jsonb, 137 | schedule text, 138 | start_date integer, 139 | status stripe.subscription_status, 140 | test_clock text, 141 | transfer_data jsonb, 142 | trial_end jsonb, 143 | trial_start jsonb 144 | ); 145 | 146 | create type stripe.invoice_status as enum ( 147 | 'draft', 148 | 'open', 149 | 'paid', 150 | 'uncollectible', 151 | 'void' 152 | ); 153 | 154 | create table if not exists stripe.invoices 155 | ( 156 | id text primary key, 157 | object text, 158 | account_country text, 159 | account_name text, 160 | account_tax_ids jsonb, 161 | amount_due integer, 162 | amount_paid integer, 163 | amount_remaining integer, 164 | application text, 165 | application_fee_amount integer, 166 | attempt_count integer, 167 | attempted boolean, 168 | auto_advance boolean, 169 | automatic_tax jsonb, 170 | billing_reason text, 171 | charge text, 172 | collection_method text, 173 | created integer, 174 | currency text, 175 | custom_fields jsonb, 176 | customer text, 177 | customer_address jsonb, 178 | customer_email text, 179 | customer_name text, 180 | customer_phone text, 181 | customer_shipping jsonb, 182 | customer_tax_exempt text, 183 | customer_tax_ids jsonb, 184 | default_payment_method text, 185 | default_source text, 186 | default_tax_rates jsonb, 187 | description text, 188 | discount jsonb, 189 | discounts jsonb, 190 | due_date integer, 191 | ending_balance integer, 192 | footer text, 193 | from_invoice jsonb, 194 | hosted_invoice_url text, 195 | invoice_pdf text, 196 | last_finalization_error jsonb, 197 | latest_revision text, 198 | lines jsonb, 199 | livemode boolean, 200 | metadata jsonb, 201 | next_payment_attempt integer, 202 | number text, 203 | on_behalf_of text, 204 | paid boolean, 205 | paid_out_of_band boolean, 206 | payment_intent text, 207 | payment_settings jsonb, 208 | period_end integer, 209 | period_start integer, 210 | post_payment_credit_notes_amount integer, 211 | pre_payment_credit_notes_amount integer, 212 | quote text, 213 | receipt_number text, 214 | rendering_options jsonb, 215 | starting_balance integer, 216 | statement_descriptor text, 217 | status stripe.invoice_status, 218 | status_transitions jsonb, 219 | subscription text, 220 | subtotal integer, 221 | subtotal_excluding_tax integer, 222 | tax integer, 223 | test_clock text, 224 | total integer, 225 | total_discount_amounts jsonb, 226 | total_excluding_tax integer, 227 | total_tax_amounts jsonb, 228 | transfer_data jsonb, 229 | webhooks_delivered_at integer 230 | ); 231 | 232 | create type stripe.charges_status as enum ( 233 | 'succeeded', 234 | 'pending', 235 | 'failed' 236 | ); 237 | 238 | create table if not exists stripe.charges 239 | ( 240 | id text primary key, 241 | object text, 242 | amount integer, 243 | amount_captured integer, 244 | amount_refunded integer, 245 | application text, 246 | application_fee text, 247 | application_fee_amount integer, 248 | balance_transaction text, 249 | billing_details jsonb, 250 | calculated_statement_descriptor text, 251 | captured boolean, 252 | created integer, 253 | currency text, 254 | customer text, 255 | description text, 256 | disputed boolean, 257 | failure_balance_transaction text, 258 | failure_code text, 259 | failure_message text, 260 | fraud_details jsonb, 261 | invoice text, 262 | livemode boolean, 263 | metadata jsonb, 264 | on_behalf_of text, 265 | outcome jsonb, 266 | paid boolean, 267 | payment_intent text, 268 | payment_method text, 269 | payment_method_details jsonb, 270 | receipt_email text, 271 | receipt_number text, 272 | receipt_url text, 273 | refunded boolean, 274 | refunds jsonb, 275 | review text, 276 | shipping jsonb, 277 | source_transfer text, 278 | statement_descriptor text, 279 | statement_descriptor_suffix text, 280 | status stripe.charges_status, 281 | transfer_data jsonb, 282 | transfer_group text 283 | ); 284 | 285 | create type stripe.coupons_duration as enum ( 286 | 'forever', 287 | 'once', 288 | 'repeating' 289 | ); 290 | 291 | create table if not exists stripe.coupons 292 | ( 293 | id text primary key, 294 | object text, 295 | amount_off integer, 296 | created integer, 297 | currency text, 298 | duration stripe.coupons_duration, 299 | duration_in_months integer, 300 | livemode boolean, 301 | max_redemptions integer, 302 | metadata jsonb, 303 | name text, 304 | percent_off double precision, 305 | redeem_by integer, 306 | times_redeemed integer, 307 | valid boolean 308 | ); 309 | 310 | create type stripe.disputes_status as enum ( 311 | 'warning_needs_response', 312 | 'warning_under_review', 313 | 'warning_closed', 314 | 'needs_response', 315 | 'under_review', 316 | 'charge_refunded', 317 | 'won', 318 | 'lost' 319 | ); 320 | 321 | create table if not exists stripe.disputes 322 | ( 323 | id text primary key, 324 | object text, 325 | amount integer, 326 | balance_transactions jsonb, 327 | created integer, 328 | currency text, 329 | evidence jsonb, 330 | status stripe.disputes_status, 331 | transaction text 332 | ); 333 | 334 | create type stripe.plans_interval as enum ( 335 | 'day', 336 | 'week', 337 | 'month', 338 | 'year' 339 | ); 340 | 341 | create table if not exists stripe.plans 342 | ( 343 | id text primary key, 344 | object text, 345 | active boolean, 346 | aggregate_usage text, 347 | amount integer, 348 | amount_decimal text, 349 | billing_scheme text, 350 | created integer, 351 | currency text, 352 | interval stripe.plans_interval, 353 | interval_count integer, 354 | livemode boolean, 355 | metadata jsonb, 356 | nickname text, 357 | product text, 358 | tiers jsonb, 359 | tiers_mode text, 360 | transform_usage text, 361 | trial_period_days integer, 362 | usage_type text 363 | ); 364 | -------------------------------------------------------------------------------- /migrations/0001_add_updated_at.sql: -------------------------------------------------------------------------------- 1 | create or replace function stripe.set_updated_at() returns trigger 2 | language plpgsql 3 | as 4 | $$ 5 | begin 6 | new.updated_at = now(); 7 | return new; 8 | end; 9 | $$; 10 | 11 | alter function stripe.set_updated_at() owner to postgres; 12 | 13 | alter table stripe.subscriptions 14 | add updated_at timestamptz default timezone('utc'::text, now()) not null; 15 | 16 | create trigger handle_updated_at 17 | before update 18 | on stripe.subscriptions 19 | for each row 20 | execute procedure stripe.set_updated_at(); 21 | 22 | alter table stripe.products 23 | add updated_at timestamptz default timezone('utc'::text, now()) not null; 24 | 25 | create trigger handle_updated_at 26 | before update 27 | on stripe.products 28 | for each row 29 | execute procedure stripe.set_updated_at(); 30 | 31 | alter table stripe.customers 32 | add updated_at timestamptz default timezone('utc'::text, now()) not null; 33 | 34 | create trigger handle_updated_at 35 | before update 36 | on stripe.customers 37 | for each row 38 | execute procedure stripe.set_updated_at(); 39 | 40 | alter table stripe.prices 41 | add updated_at timestamptz default timezone('utc'::text, now()) not null; 42 | 43 | create trigger handle_updated_at 44 | before update 45 | on stripe.prices 46 | for each row 47 | execute procedure stripe.set_updated_at(); 48 | 49 | alter table stripe.invoices 50 | add updated_at timestamptz default timezone('utc'::text, now()) not null; 51 | 52 | create trigger handle_updated_at 53 | before update 54 | on stripe.invoices 55 | for each row 56 | execute procedure stripe.set_updated_at(); 57 | 58 | alter table stripe.charges 59 | add updated_at timestamptz default timezone('utc'::text, now()) not null; 60 | 61 | create trigger handle_updated_at 62 | before update 63 | on stripe.charges 64 | for each row 65 | execute procedure stripe.set_updated_at(); 66 | 67 | alter table stripe.coupons 68 | add updated_at timestamptz default timezone('utc'::text, now()) not null; 69 | 70 | create trigger handle_updated_at 71 | before update 72 | on stripe.coupons 73 | for each row 74 | execute procedure stripe.set_updated_at(); 75 | 76 | alter table stripe.disputes 77 | add updated_at timestamptz default timezone('utc'::text, now()) not null; 78 | 79 | create trigger handle_updated_at 80 | before update 81 | on stripe.disputes 82 | for each row 83 | execute procedure stripe.set_updated_at(); 84 | 85 | alter table stripe.events 86 | add updated_at timestamptz default timezone('utc'::text, now()) not null; 87 | 88 | create trigger handle_updated_at 89 | before update 90 | on stripe.events 91 | for each row 92 | execute procedure stripe.set_updated_at(); 93 | 94 | alter table stripe.plans 95 | add updated_at timestamptz default timezone('utc'::text, now()) not null; 96 | 97 | create trigger handle_updated_at 98 | before update 99 | on stripe.plans 100 | for each row 101 | execute procedure stripe.set_updated_at(); 102 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stripe_to_postgres", 3 | "version": "0.2.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "stripe_to_postgres", 9 | "version": "0.2.0", 10 | "dependencies": { 11 | "@whollacsek/pg-node-migrations": "^0.0.8", 12 | "dotenv": "^16.0.3", 13 | "lodash.chunk": "^4.2.0", 14 | "micro": "9.4.0", 15 | "pg": "^8.8.0", 16 | "stripe": "^10.12.0" 17 | }, 18 | "devDependencies": { 19 | "@types/lodash.chunk": "^4.2.7", 20 | "@types/node": "^18.8.0", 21 | "@types/pg": "^8.6.5", 22 | "@types/yesql": "^4.1.1", 23 | "prettier": "^2.7.1", 24 | "ts-node-dev": "^2.0.0", 25 | "typescript": "^4.8.4" 26 | } 27 | }, 28 | "@whollacsek/pg-node-migrations@0.0.8": { 29 | "extraneous": true 30 | }, 31 | "node_modules/@cspotcode/source-map-support": { 32 | "version": "0.8.1", 33 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 34 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 35 | "dev": true, 36 | "dependencies": { 37 | "@jridgewell/trace-mapping": "0.3.9" 38 | }, 39 | "engines": { 40 | "node": ">=12" 41 | } 42 | }, 43 | "node_modules/@jridgewell/resolve-uri": { 44 | "version": "3.1.0", 45 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 46 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 47 | "dev": true, 48 | "engines": { 49 | "node": ">=6.0.0" 50 | } 51 | }, 52 | "node_modules/@jridgewell/sourcemap-codec": { 53 | "version": "1.4.14", 54 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 55 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 56 | "dev": true 57 | }, 58 | "node_modules/@jridgewell/trace-mapping": { 59 | "version": "0.3.9", 60 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 61 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 62 | "dev": true, 63 | "dependencies": { 64 | "@jridgewell/resolve-uri": "^3.0.3", 65 | "@jridgewell/sourcemap-codec": "^1.4.10" 66 | } 67 | }, 68 | "node_modules/@tsconfig/node10": { 69 | "version": "1.0.9", 70 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 71 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", 72 | "dev": true 73 | }, 74 | "node_modules/@tsconfig/node12": { 75 | "version": "1.0.11", 76 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 77 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 78 | "dev": true 79 | }, 80 | "node_modules/@tsconfig/node14": { 81 | "version": "1.0.3", 82 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 83 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 84 | "dev": true 85 | }, 86 | "node_modules/@tsconfig/node16": { 87 | "version": "1.0.3", 88 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", 89 | "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", 90 | "dev": true 91 | }, 92 | "node_modules/@types/lodash": { 93 | "version": "4.14.186", 94 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.186.tgz", 95 | "integrity": "sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw==", 96 | "dev": true 97 | }, 98 | "node_modules/@types/lodash.chunk": { 99 | "version": "4.2.7", 100 | "resolved": "https://registry.npmjs.org/@types/lodash.chunk/-/lodash.chunk-4.2.7.tgz", 101 | "integrity": "sha512-//tmaWHiANgToom/YYYKKqiCtlNz11fwYtMUUbaemNSbWTI+2zHtYW5nt1PHNCRWHPAJHHhn4UVFD9LKUFvatA==", 102 | "dev": true, 103 | "dependencies": { 104 | "@types/lodash": "*" 105 | } 106 | }, 107 | "node_modules/@types/node": { 108 | "version": "18.8.0", 109 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.0.tgz", 110 | "integrity": "sha512-u+h43R6U8xXDt2vzUaVP3VwjjLyOJk6uEciZS8OSyziUQGOwmk+l+4drxcsDboHXwyTaqS1INebghmWMRxq3LA==" 111 | }, 112 | "node_modules/@types/pg": { 113 | "version": "8.6.5", 114 | "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.5.tgz", 115 | "integrity": "sha512-tOkGtAqRVkHa/PVZicq67zuujI4Oorfglsr2IbKofDwBSysnaqSx7W1mDqFqdkGE6Fbgh+PZAl0r/BWON/mozw==", 116 | "dev": true, 117 | "dependencies": { 118 | "@types/node": "*", 119 | "pg-protocol": "*", 120 | "pg-types": "^2.2.0" 121 | } 122 | }, 123 | "node_modules/@types/strip-bom": { 124 | "version": "3.0.0", 125 | "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", 126 | "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", 127 | "dev": true 128 | }, 129 | "node_modules/@types/strip-json-comments": { 130 | "version": "0.0.30", 131 | "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", 132 | "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", 133 | "dev": true 134 | }, 135 | "node_modules/@types/yesql": { 136 | "version": "4.1.1", 137 | "resolved": "https://registry.npmjs.org/@types/yesql/-/yesql-4.1.1.tgz", 138 | "integrity": "sha512-aLTGG0R/wNCBAzvMNk7pGLFcamZeJMBiKqrObK8BukmcpDEtyvfpR/Hzpta5L9VEtyWgF5w5VIW8HiOUfwhSKw==", 139 | "dev": true 140 | }, 141 | "node_modules/@whollacsek/pg-node-migrations": { 142 | "version": "0.0.8", 143 | "resolved": "https://registry.npmjs.org/@whollacsek/pg-node-migrations/-/pg-node-migrations-0.0.8.tgz", 144 | "integrity": "sha512-1T6a1+N54zWeKJr95/QzNCs35j/d349aW4YCYApd1rcGQirQRfSDlnLQ8Ws6ijba8CRYWkbujP2Yhf+upI6G2A==", 145 | "dependencies": { 146 | "pg": "^8.6.0", 147 | "sql-template-strings": "^2.2.2" 148 | }, 149 | "bin": { 150 | "pg-validate-migrations": "dist/bin/validate.js" 151 | }, 152 | "engines": { 153 | "node": ">10.17.0" 154 | } 155 | }, 156 | "node_modules/acorn": { 157 | "version": "8.8.0", 158 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", 159 | "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", 160 | "dev": true, 161 | "bin": { 162 | "acorn": "bin/acorn" 163 | }, 164 | "engines": { 165 | "node": ">=0.4.0" 166 | } 167 | }, 168 | "node_modules/acorn-walk": { 169 | "version": "8.2.0", 170 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 171 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 172 | "dev": true, 173 | "engines": { 174 | "node": ">=0.4.0" 175 | } 176 | }, 177 | "node_modules/anymatch": { 178 | "version": "3.1.2", 179 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 180 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 181 | "dev": true, 182 | "dependencies": { 183 | "normalize-path": "^3.0.0", 184 | "picomatch": "^2.0.4" 185 | }, 186 | "engines": { 187 | "node": ">= 8" 188 | } 189 | }, 190 | "node_modules/arg": { 191 | "version": "4.1.3", 192 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 193 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 194 | "dev": true 195 | }, 196 | "node_modules/balanced-match": { 197 | "version": "1.0.2", 198 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 199 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 200 | "dev": true 201 | }, 202 | "node_modules/binary-extensions": { 203 | "version": "2.2.0", 204 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 205 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 206 | "dev": true, 207 | "engines": { 208 | "node": ">=8" 209 | } 210 | }, 211 | "node_modules/brace-expansion": { 212 | "version": "1.1.11", 213 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 214 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 215 | "dev": true, 216 | "dependencies": { 217 | "balanced-match": "^1.0.0", 218 | "concat-map": "0.0.1" 219 | } 220 | }, 221 | "node_modules/braces": { 222 | "version": "3.0.2", 223 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 224 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 225 | "dev": true, 226 | "dependencies": { 227 | "fill-range": "^7.0.1" 228 | }, 229 | "engines": { 230 | "node": ">=8" 231 | } 232 | }, 233 | "node_modules/buffer-from": { 234 | "version": "1.1.2", 235 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 236 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 237 | "dev": true 238 | }, 239 | "node_modules/buffer-writer": { 240 | "version": "2.0.0", 241 | "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", 242 | "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", 243 | "engines": { 244 | "node": ">=4" 245 | } 246 | }, 247 | "node_modules/bytes": { 248 | "version": "3.1.0", 249 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 250 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", 251 | "engines": { 252 | "node": ">= 0.8" 253 | } 254 | }, 255 | "node_modules/call-bind": { 256 | "version": "1.0.2", 257 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 258 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 259 | "dependencies": { 260 | "function-bind": "^1.1.1", 261 | "get-intrinsic": "^1.0.2" 262 | }, 263 | "funding": { 264 | "url": "https://github.com/sponsors/ljharb" 265 | } 266 | }, 267 | "node_modules/chokidar": { 268 | "version": "3.5.3", 269 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 270 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 271 | "dev": true, 272 | "funding": [ 273 | { 274 | "type": "individual", 275 | "url": "https://paulmillr.com/funding/" 276 | } 277 | ], 278 | "dependencies": { 279 | "anymatch": "~3.1.2", 280 | "braces": "~3.0.2", 281 | "glob-parent": "~5.1.2", 282 | "is-binary-path": "~2.1.0", 283 | "is-glob": "~4.0.1", 284 | "normalize-path": "~3.0.0", 285 | "readdirp": "~3.6.0" 286 | }, 287 | "engines": { 288 | "node": ">= 8.10.0" 289 | }, 290 | "optionalDependencies": { 291 | "fsevents": "~2.3.2" 292 | } 293 | }, 294 | "node_modules/concat-map": { 295 | "version": "0.0.1", 296 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 297 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 298 | "dev": true 299 | }, 300 | "node_modules/content-type": { 301 | "version": "1.0.4", 302 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 303 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", 304 | "engines": { 305 | "node": ">= 0.6" 306 | } 307 | }, 308 | "node_modules/create-require": { 309 | "version": "1.1.1", 310 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 311 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 312 | "dev": true 313 | }, 314 | "node_modules/depd": { 315 | "version": "1.1.2", 316 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 317 | "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", 318 | "engines": { 319 | "node": ">= 0.6" 320 | } 321 | }, 322 | "node_modules/diff": { 323 | "version": "4.0.2", 324 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 325 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 326 | "dev": true, 327 | "engines": { 328 | "node": ">=0.3.1" 329 | } 330 | }, 331 | "node_modules/dotenv": { 332 | "version": "16.0.3", 333 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", 334 | "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", 335 | "engines": { 336 | "node": ">=12" 337 | } 338 | }, 339 | "node_modules/dynamic-dedupe": { 340 | "version": "0.3.0", 341 | "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", 342 | "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", 343 | "dev": true, 344 | "dependencies": { 345 | "xtend": "^4.0.0" 346 | } 347 | }, 348 | "node_modules/fill-range": { 349 | "version": "7.0.1", 350 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 351 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 352 | "dev": true, 353 | "dependencies": { 354 | "to-regex-range": "^5.0.1" 355 | }, 356 | "engines": { 357 | "node": ">=8" 358 | } 359 | }, 360 | "node_modules/fs.realpath": { 361 | "version": "1.0.0", 362 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 363 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 364 | "dev": true 365 | }, 366 | "node_modules/fsevents": { 367 | "version": "2.3.2", 368 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 369 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 370 | "dev": true, 371 | "hasInstallScript": true, 372 | "optional": true, 373 | "os": [ 374 | "darwin" 375 | ], 376 | "engines": { 377 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 378 | } 379 | }, 380 | "node_modules/function-bind": { 381 | "version": "1.1.1", 382 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 383 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 384 | }, 385 | "node_modules/get-intrinsic": { 386 | "version": "1.1.3", 387 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 388 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 389 | "dependencies": { 390 | "function-bind": "^1.1.1", 391 | "has": "^1.0.3", 392 | "has-symbols": "^1.0.3" 393 | }, 394 | "funding": { 395 | "url": "https://github.com/sponsors/ljharb" 396 | } 397 | }, 398 | "node_modules/glob": { 399 | "version": "7.2.3", 400 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 401 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 402 | "dev": true, 403 | "dependencies": { 404 | "fs.realpath": "^1.0.0", 405 | "inflight": "^1.0.4", 406 | "inherits": "2", 407 | "minimatch": "^3.1.1", 408 | "once": "^1.3.0", 409 | "path-is-absolute": "^1.0.0" 410 | }, 411 | "engines": { 412 | "node": "*" 413 | }, 414 | "funding": { 415 | "url": "https://github.com/sponsors/isaacs" 416 | } 417 | }, 418 | "node_modules/glob-parent": { 419 | "version": "5.1.2", 420 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 421 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 422 | "dev": true, 423 | "dependencies": { 424 | "is-glob": "^4.0.1" 425 | }, 426 | "engines": { 427 | "node": ">= 6" 428 | } 429 | }, 430 | "node_modules/has": { 431 | "version": "1.0.3", 432 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 433 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 434 | "dependencies": { 435 | "function-bind": "^1.1.1" 436 | }, 437 | "engines": { 438 | "node": ">= 0.4.0" 439 | } 440 | }, 441 | "node_modules/has-symbols": { 442 | "version": "1.0.3", 443 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 444 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 445 | "engines": { 446 | "node": ">= 0.4" 447 | }, 448 | "funding": { 449 | "url": "https://github.com/sponsors/ljharb" 450 | } 451 | }, 452 | "node_modules/http-errors": { 453 | "version": "1.7.3", 454 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", 455 | "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", 456 | "dependencies": { 457 | "depd": "~1.1.2", 458 | "inherits": "2.0.4", 459 | "setprototypeof": "1.1.1", 460 | "statuses": ">= 1.5.0 < 2", 461 | "toidentifier": "1.0.0" 462 | }, 463 | "engines": { 464 | "node": ">= 0.6" 465 | } 466 | }, 467 | "node_modules/iconv-lite": { 468 | "version": "0.4.24", 469 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 470 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 471 | "dependencies": { 472 | "safer-buffer": ">= 2.1.2 < 3" 473 | }, 474 | "engines": { 475 | "node": ">=0.10.0" 476 | } 477 | }, 478 | "node_modules/inflight": { 479 | "version": "1.0.6", 480 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 481 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 482 | "dev": true, 483 | "dependencies": { 484 | "once": "^1.3.0", 485 | "wrappy": "1" 486 | } 487 | }, 488 | "node_modules/inherits": { 489 | "version": "2.0.4", 490 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 491 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 492 | }, 493 | "node_modules/is-binary-path": { 494 | "version": "2.1.0", 495 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 496 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 497 | "dev": true, 498 | "dependencies": { 499 | "binary-extensions": "^2.0.0" 500 | }, 501 | "engines": { 502 | "node": ">=8" 503 | } 504 | }, 505 | "node_modules/is-core-module": { 506 | "version": "2.10.0", 507 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", 508 | "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", 509 | "dev": true, 510 | "dependencies": { 511 | "has": "^1.0.3" 512 | }, 513 | "funding": { 514 | "url": "https://github.com/sponsors/ljharb" 515 | } 516 | }, 517 | "node_modules/is-extglob": { 518 | "version": "2.1.1", 519 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 520 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 521 | "dev": true, 522 | "engines": { 523 | "node": ">=0.10.0" 524 | } 525 | }, 526 | "node_modules/is-glob": { 527 | "version": "4.0.3", 528 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 529 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 530 | "dev": true, 531 | "dependencies": { 532 | "is-extglob": "^2.1.1" 533 | }, 534 | "engines": { 535 | "node": ">=0.10.0" 536 | } 537 | }, 538 | "node_modules/is-number": { 539 | "version": "7.0.0", 540 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 541 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 542 | "dev": true, 543 | "engines": { 544 | "node": ">=0.12.0" 545 | } 546 | }, 547 | "node_modules/lodash.chunk": { 548 | "version": "4.2.0", 549 | "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", 550 | "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==" 551 | }, 552 | "node_modules/make-error": { 553 | "version": "1.3.6", 554 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 555 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 556 | "dev": true 557 | }, 558 | "node_modules/micro": { 559 | "version": "9.4.0", 560 | "resolved": "https://registry.npmjs.org/micro/-/micro-9.4.0.tgz", 561 | "integrity": "sha512-F3uh5Ob+0896E1skflRvcY6Cpq6/sA0RB7exMl/IhQ2wbwL79aF+mDAyjDcKNhXKkJVEXhKZrPqOEFLXkJW9og==", 562 | "dependencies": { 563 | "arg": "4.1.0", 564 | "content-type": "1.0.4", 565 | "raw-body": "2.4.1" 566 | }, 567 | "bin": { 568 | "micro": "bin/micro.js" 569 | }, 570 | "engines": { 571 | "node": ">= 8.0.0" 572 | } 573 | }, 574 | "node_modules/micro/node_modules/arg": { 575 | "version": "4.1.0", 576 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", 577 | "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==" 578 | }, 579 | "node_modules/minimatch": { 580 | "version": "3.1.2", 581 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 582 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 583 | "dev": true, 584 | "dependencies": { 585 | "brace-expansion": "^1.1.7" 586 | }, 587 | "engines": { 588 | "node": "*" 589 | } 590 | }, 591 | "node_modules/minimist": { 592 | "version": "1.2.6", 593 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 594 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", 595 | "dev": true 596 | }, 597 | "node_modules/mkdirp": { 598 | "version": "1.0.4", 599 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 600 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", 601 | "dev": true, 602 | "bin": { 603 | "mkdirp": "bin/cmd.js" 604 | }, 605 | "engines": { 606 | "node": ">=10" 607 | } 608 | }, 609 | "node_modules/normalize-path": { 610 | "version": "3.0.0", 611 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 612 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 613 | "dev": true, 614 | "engines": { 615 | "node": ">=0.10.0" 616 | } 617 | }, 618 | "node_modules/object-inspect": { 619 | "version": "1.12.2", 620 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 621 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", 622 | "funding": { 623 | "url": "https://github.com/sponsors/ljharb" 624 | } 625 | }, 626 | "node_modules/once": { 627 | "version": "1.4.0", 628 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 629 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 630 | "dev": true, 631 | "dependencies": { 632 | "wrappy": "1" 633 | } 634 | }, 635 | "node_modules/packet-reader": { 636 | "version": "1.0.0", 637 | "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", 638 | "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" 639 | }, 640 | "node_modules/path-is-absolute": { 641 | "version": "1.0.1", 642 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 643 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 644 | "dev": true, 645 | "engines": { 646 | "node": ">=0.10.0" 647 | } 648 | }, 649 | "node_modules/path-parse": { 650 | "version": "1.0.7", 651 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 652 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 653 | "dev": true 654 | }, 655 | "node_modules/pg": { 656 | "version": "8.8.0", 657 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", 658 | "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", 659 | "dependencies": { 660 | "buffer-writer": "2.0.0", 661 | "packet-reader": "1.0.0", 662 | "pg-connection-string": "^2.5.0", 663 | "pg-pool": "^3.5.2", 664 | "pg-protocol": "^1.5.0", 665 | "pg-types": "^2.1.0", 666 | "pgpass": "1.x" 667 | }, 668 | "engines": { 669 | "node": ">= 8.0.0" 670 | }, 671 | "peerDependencies": { 672 | "pg-native": ">=3.0.1" 673 | }, 674 | "peerDependenciesMeta": { 675 | "pg-native": { 676 | "optional": true 677 | } 678 | } 679 | }, 680 | "node_modules/pg-connection-string": { 681 | "version": "2.5.0", 682 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", 683 | "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" 684 | }, 685 | "node_modules/pg-int8": { 686 | "version": "1.0.1", 687 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", 688 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", 689 | "engines": { 690 | "node": ">=4.0.0" 691 | } 692 | }, 693 | "node_modules/pg-pool": { 694 | "version": "3.5.2", 695 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz", 696 | "integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==", 697 | "peerDependencies": { 698 | "pg": ">=8.0" 699 | } 700 | }, 701 | "node_modules/pg-protocol": { 702 | "version": "1.5.0", 703 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", 704 | "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" 705 | }, 706 | "node_modules/pg-types": { 707 | "version": "2.2.0", 708 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", 709 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", 710 | "dependencies": { 711 | "pg-int8": "1.0.1", 712 | "postgres-array": "~2.0.0", 713 | "postgres-bytea": "~1.0.0", 714 | "postgres-date": "~1.0.4", 715 | "postgres-interval": "^1.1.0" 716 | }, 717 | "engines": { 718 | "node": ">=4" 719 | } 720 | }, 721 | "node_modules/pgpass": { 722 | "version": "1.0.5", 723 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", 724 | "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", 725 | "dependencies": { 726 | "split2": "^4.1.0" 727 | } 728 | }, 729 | "node_modules/picomatch": { 730 | "version": "2.3.1", 731 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 732 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 733 | "dev": true, 734 | "engines": { 735 | "node": ">=8.6" 736 | }, 737 | "funding": { 738 | "url": "https://github.com/sponsors/jonschlinkert" 739 | } 740 | }, 741 | "node_modules/postgres-array": { 742 | "version": "2.0.0", 743 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", 744 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", 745 | "engines": { 746 | "node": ">=4" 747 | } 748 | }, 749 | "node_modules/postgres-bytea": { 750 | "version": "1.0.0", 751 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", 752 | "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", 753 | "engines": { 754 | "node": ">=0.10.0" 755 | } 756 | }, 757 | "node_modules/postgres-date": { 758 | "version": "1.0.7", 759 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", 760 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", 761 | "engines": { 762 | "node": ">=0.10.0" 763 | } 764 | }, 765 | "node_modules/postgres-interval": { 766 | "version": "1.2.0", 767 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", 768 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", 769 | "dependencies": { 770 | "xtend": "^4.0.0" 771 | }, 772 | "engines": { 773 | "node": ">=0.10.0" 774 | } 775 | }, 776 | "node_modules/prettier": { 777 | "version": "2.7.1", 778 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", 779 | "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", 780 | "dev": true, 781 | "bin": { 782 | "prettier": "bin-prettier.js" 783 | }, 784 | "engines": { 785 | "node": ">=10.13.0" 786 | }, 787 | "funding": { 788 | "url": "https://github.com/prettier/prettier?sponsor=1" 789 | } 790 | }, 791 | "node_modules/qs": { 792 | "version": "6.11.0", 793 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 794 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 795 | "dependencies": { 796 | "side-channel": "^1.0.4" 797 | }, 798 | "engines": { 799 | "node": ">=0.6" 800 | }, 801 | "funding": { 802 | "url": "https://github.com/sponsors/ljharb" 803 | } 804 | }, 805 | "node_modules/raw-body": { 806 | "version": "2.4.1", 807 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", 808 | "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", 809 | "dependencies": { 810 | "bytes": "3.1.0", 811 | "http-errors": "1.7.3", 812 | "iconv-lite": "0.4.24", 813 | "unpipe": "1.0.0" 814 | }, 815 | "engines": { 816 | "node": ">= 0.8" 817 | } 818 | }, 819 | "node_modules/readdirp": { 820 | "version": "3.6.0", 821 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 822 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 823 | "dev": true, 824 | "dependencies": { 825 | "picomatch": "^2.2.1" 826 | }, 827 | "engines": { 828 | "node": ">=8.10.0" 829 | } 830 | }, 831 | "node_modules/resolve": { 832 | "version": "1.22.1", 833 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 834 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 835 | "dev": true, 836 | "dependencies": { 837 | "is-core-module": "^2.9.0", 838 | "path-parse": "^1.0.7", 839 | "supports-preserve-symlinks-flag": "^1.0.0" 840 | }, 841 | "bin": { 842 | "resolve": "bin/resolve" 843 | }, 844 | "funding": { 845 | "url": "https://github.com/sponsors/ljharb" 846 | } 847 | }, 848 | "node_modules/rimraf": { 849 | "version": "2.7.1", 850 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 851 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 852 | "dev": true, 853 | "dependencies": { 854 | "glob": "^7.1.3" 855 | }, 856 | "bin": { 857 | "rimraf": "bin.js" 858 | } 859 | }, 860 | "node_modules/safer-buffer": { 861 | "version": "2.1.2", 862 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 863 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 864 | }, 865 | "node_modules/setprototypeof": { 866 | "version": "1.1.1", 867 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 868 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 869 | }, 870 | "node_modules/side-channel": { 871 | "version": "1.0.4", 872 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 873 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 874 | "dependencies": { 875 | "call-bind": "^1.0.0", 876 | "get-intrinsic": "^1.0.2", 877 | "object-inspect": "^1.9.0" 878 | }, 879 | "funding": { 880 | "url": "https://github.com/sponsors/ljharb" 881 | } 882 | }, 883 | "node_modules/source-map": { 884 | "version": "0.6.1", 885 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 886 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 887 | "dev": true, 888 | "engines": { 889 | "node": ">=0.10.0" 890 | } 891 | }, 892 | "node_modules/source-map-support": { 893 | "version": "0.5.21", 894 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 895 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 896 | "dev": true, 897 | "dependencies": { 898 | "buffer-from": "^1.0.0", 899 | "source-map": "^0.6.0" 900 | } 901 | }, 902 | "node_modules/split2": { 903 | "version": "4.1.0", 904 | "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", 905 | "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", 906 | "engines": { 907 | "node": ">= 10.x" 908 | } 909 | }, 910 | "node_modules/sql-template-strings": { 911 | "version": "2.2.2", 912 | "resolved": "https://registry.npmjs.org/sql-template-strings/-/sql-template-strings-2.2.2.tgz", 913 | "integrity": "sha512-UXhXR2869FQaD+GMly8jAMCRZ94nU5KcrFetZfWEMd+LVVG6y0ExgHAhatEcKZ/wk8YcKPdi+hiD2wm75lq3/Q==", 914 | "engines": { 915 | "node": ">=4.0.0" 916 | } 917 | }, 918 | "node_modules/statuses": { 919 | "version": "1.5.0", 920 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 921 | "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", 922 | "engines": { 923 | "node": ">= 0.6" 924 | } 925 | }, 926 | "node_modules/strip-bom": { 927 | "version": "3.0.0", 928 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 929 | "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", 930 | "dev": true, 931 | "engines": { 932 | "node": ">=4" 933 | } 934 | }, 935 | "node_modules/strip-json-comments": { 936 | "version": "2.0.1", 937 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 938 | "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", 939 | "dev": true, 940 | "engines": { 941 | "node": ">=0.10.0" 942 | } 943 | }, 944 | "node_modules/stripe": { 945 | "version": "10.12.0", 946 | "resolved": "https://registry.npmjs.org/stripe/-/stripe-10.12.0.tgz", 947 | "integrity": "sha512-4ijMsbTVSy6rzWIkal+/dFGeTXtjqLeZ/oo/jc2jhICbf3Dby0CBTPxAg6ZhBPXQL96TJxI613C/NhhE7LvrWw==", 948 | "dependencies": { 949 | "@types/node": ">=8.1.0", 950 | "qs": "^6.10.3" 951 | }, 952 | "engines": { 953 | "node": "^8.1 || >=10.*" 954 | } 955 | }, 956 | "node_modules/supports-preserve-symlinks-flag": { 957 | "version": "1.0.0", 958 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 959 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 960 | "dev": true, 961 | "engines": { 962 | "node": ">= 0.4" 963 | }, 964 | "funding": { 965 | "url": "https://github.com/sponsors/ljharb" 966 | } 967 | }, 968 | "node_modules/to-regex-range": { 969 | "version": "5.0.1", 970 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 971 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 972 | "dev": true, 973 | "dependencies": { 974 | "is-number": "^7.0.0" 975 | }, 976 | "engines": { 977 | "node": ">=8.0" 978 | } 979 | }, 980 | "node_modules/toidentifier": { 981 | "version": "1.0.0", 982 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 983 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", 984 | "engines": { 985 | "node": ">=0.6" 986 | } 987 | }, 988 | "node_modules/tree-kill": { 989 | "version": "1.2.2", 990 | "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", 991 | "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", 992 | "dev": true, 993 | "bin": { 994 | "tree-kill": "cli.js" 995 | } 996 | }, 997 | "node_modules/ts-node": { 998 | "version": "10.9.1", 999 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 1000 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 1001 | "dev": true, 1002 | "dependencies": { 1003 | "@cspotcode/source-map-support": "^0.8.0", 1004 | "@tsconfig/node10": "^1.0.7", 1005 | "@tsconfig/node12": "^1.0.7", 1006 | "@tsconfig/node14": "^1.0.0", 1007 | "@tsconfig/node16": "^1.0.2", 1008 | "acorn": "^8.4.1", 1009 | "acorn-walk": "^8.1.1", 1010 | "arg": "^4.1.0", 1011 | "create-require": "^1.1.0", 1012 | "diff": "^4.0.1", 1013 | "make-error": "^1.1.1", 1014 | "v8-compile-cache-lib": "^3.0.1", 1015 | "yn": "3.1.1" 1016 | }, 1017 | "bin": { 1018 | "ts-node": "dist/bin.js", 1019 | "ts-node-cwd": "dist/bin-cwd.js", 1020 | "ts-node-esm": "dist/bin-esm.js", 1021 | "ts-node-script": "dist/bin-script.js", 1022 | "ts-node-transpile-only": "dist/bin-transpile.js", 1023 | "ts-script": "dist/bin-script-deprecated.js" 1024 | }, 1025 | "peerDependencies": { 1026 | "@swc/core": ">=1.2.50", 1027 | "@swc/wasm": ">=1.2.50", 1028 | "@types/node": "*", 1029 | "typescript": ">=2.7" 1030 | }, 1031 | "peerDependenciesMeta": { 1032 | "@swc/core": { 1033 | "optional": true 1034 | }, 1035 | "@swc/wasm": { 1036 | "optional": true 1037 | } 1038 | } 1039 | }, 1040 | "node_modules/ts-node-dev": { 1041 | "version": "2.0.0", 1042 | "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", 1043 | "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", 1044 | "dev": true, 1045 | "dependencies": { 1046 | "chokidar": "^3.5.1", 1047 | "dynamic-dedupe": "^0.3.0", 1048 | "minimist": "^1.2.6", 1049 | "mkdirp": "^1.0.4", 1050 | "resolve": "^1.0.0", 1051 | "rimraf": "^2.6.1", 1052 | "source-map-support": "^0.5.12", 1053 | "tree-kill": "^1.2.2", 1054 | "ts-node": "^10.4.0", 1055 | "tsconfig": "^7.0.0" 1056 | }, 1057 | "bin": { 1058 | "ts-node-dev": "lib/bin.js", 1059 | "tsnd": "lib/bin.js" 1060 | }, 1061 | "engines": { 1062 | "node": ">=0.8.0" 1063 | }, 1064 | "peerDependencies": { 1065 | "node-notifier": "*", 1066 | "typescript": "*" 1067 | }, 1068 | "peerDependenciesMeta": { 1069 | "node-notifier": { 1070 | "optional": true 1071 | } 1072 | } 1073 | }, 1074 | "node_modules/tsconfig": { 1075 | "version": "7.0.0", 1076 | "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", 1077 | "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", 1078 | "dev": true, 1079 | "dependencies": { 1080 | "@types/strip-bom": "^3.0.0", 1081 | "@types/strip-json-comments": "0.0.30", 1082 | "strip-bom": "^3.0.0", 1083 | "strip-json-comments": "^2.0.0" 1084 | } 1085 | }, 1086 | "node_modules/typescript": { 1087 | "version": "4.8.4", 1088 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", 1089 | "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", 1090 | "dev": true, 1091 | "bin": { 1092 | "tsc": "bin/tsc", 1093 | "tsserver": "bin/tsserver" 1094 | }, 1095 | "engines": { 1096 | "node": ">=4.2.0" 1097 | } 1098 | }, 1099 | "node_modules/unpipe": { 1100 | "version": "1.0.0", 1101 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1102 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 1103 | "engines": { 1104 | "node": ">= 0.8" 1105 | } 1106 | }, 1107 | "node_modules/v8-compile-cache-lib": { 1108 | "version": "3.0.1", 1109 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 1110 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 1111 | "dev": true 1112 | }, 1113 | "node_modules/wrappy": { 1114 | "version": "1.0.2", 1115 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1116 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1117 | "dev": true 1118 | }, 1119 | "node_modules/xtend": { 1120 | "version": "4.0.2", 1121 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1122 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 1123 | "engines": { 1124 | "node": ">=0.4" 1125 | } 1126 | }, 1127 | "node_modules/yn": { 1128 | "version": "3.1.1", 1129 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1130 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 1131 | "dev": true, 1132 | "engines": { 1133 | "node": ">=6" 1134 | } 1135 | } 1136 | }, 1137 | "dependencies": { 1138 | "@cspotcode/source-map-support": { 1139 | "version": "0.8.1", 1140 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 1141 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 1142 | "dev": true, 1143 | "requires": { 1144 | "@jridgewell/trace-mapping": "0.3.9" 1145 | } 1146 | }, 1147 | "@jridgewell/resolve-uri": { 1148 | "version": "3.1.0", 1149 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 1150 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 1151 | "dev": true 1152 | }, 1153 | "@jridgewell/sourcemap-codec": { 1154 | "version": "1.4.14", 1155 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 1156 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 1157 | "dev": true 1158 | }, 1159 | "@jridgewell/trace-mapping": { 1160 | "version": "0.3.9", 1161 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 1162 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 1163 | "dev": true, 1164 | "requires": { 1165 | "@jridgewell/resolve-uri": "^3.0.3", 1166 | "@jridgewell/sourcemap-codec": "^1.4.10" 1167 | } 1168 | }, 1169 | "@tsconfig/node10": { 1170 | "version": "1.0.9", 1171 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 1172 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", 1173 | "dev": true 1174 | }, 1175 | "@tsconfig/node12": { 1176 | "version": "1.0.11", 1177 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 1178 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 1179 | "dev": true 1180 | }, 1181 | "@tsconfig/node14": { 1182 | "version": "1.0.3", 1183 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 1184 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 1185 | "dev": true 1186 | }, 1187 | "@tsconfig/node16": { 1188 | "version": "1.0.3", 1189 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", 1190 | "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", 1191 | "dev": true 1192 | }, 1193 | "@types/lodash": { 1194 | "version": "4.14.186", 1195 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.186.tgz", 1196 | "integrity": "sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw==", 1197 | "dev": true 1198 | }, 1199 | "@types/lodash.chunk": { 1200 | "version": "4.2.7", 1201 | "resolved": "https://registry.npmjs.org/@types/lodash.chunk/-/lodash.chunk-4.2.7.tgz", 1202 | "integrity": "sha512-//tmaWHiANgToom/YYYKKqiCtlNz11fwYtMUUbaemNSbWTI+2zHtYW5nt1PHNCRWHPAJHHhn4UVFD9LKUFvatA==", 1203 | "dev": true, 1204 | "requires": { 1205 | "@types/lodash": "*" 1206 | } 1207 | }, 1208 | "@types/node": { 1209 | "version": "18.8.0", 1210 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.0.tgz", 1211 | "integrity": "sha512-u+h43R6U8xXDt2vzUaVP3VwjjLyOJk6uEciZS8OSyziUQGOwmk+l+4drxcsDboHXwyTaqS1INebghmWMRxq3LA==" 1212 | }, 1213 | "@types/pg": { 1214 | "version": "8.6.5", 1215 | "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.5.tgz", 1216 | "integrity": "sha512-tOkGtAqRVkHa/PVZicq67zuujI4Oorfglsr2IbKofDwBSysnaqSx7W1mDqFqdkGE6Fbgh+PZAl0r/BWON/mozw==", 1217 | "dev": true, 1218 | "requires": { 1219 | "@types/node": "*", 1220 | "pg-protocol": "*", 1221 | "pg-types": "^2.2.0" 1222 | } 1223 | }, 1224 | "@types/strip-bom": { 1225 | "version": "3.0.0", 1226 | "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", 1227 | "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", 1228 | "dev": true 1229 | }, 1230 | "@types/strip-json-comments": { 1231 | "version": "0.0.30", 1232 | "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", 1233 | "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", 1234 | "dev": true 1235 | }, 1236 | "@types/yesql": { 1237 | "version": "4.1.1", 1238 | "resolved": "https://registry.npmjs.org/@types/yesql/-/yesql-4.1.1.tgz", 1239 | "integrity": "sha512-aLTGG0R/wNCBAzvMNk7pGLFcamZeJMBiKqrObK8BukmcpDEtyvfpR/Hzpta5L9VEtyWgF5w5VIW8HiOUfwhSKw==", 1240 | "dev": true 1241 | }, 1242 | "@whollacsek/pg-node-migrations": { 1243 | "version": "0.0.8", 1244 | "resolved": "https://registry.npmjs.org/@whollacsek/pg-node-migrations/-/pg-node-migrations-0.0.8.tgz", 1245 | "integrity": "sha512-1T6a1+N54zWeKJr95/QzNCs35j/d349aW4YCYApd1rcGQirQRfSDlnLQ8Ws6ijba8CRYWkbujP2Yhf+upI6G2A==", 1246 | "requires": { 1247 | "pg": "^8.6.0", 1248 | "sql-template-strings": "^2.2.2" 1249 | } 1250 | }, 1251 | "acorn": { 1252 | "version": "8.8.0", 1253 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", 1254 | "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", 1255 | "dev": true 1256 | }, 1257 | "acorn-walk": { 1258 | "version": "8.2.0", 1259 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 1260 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 1261 | "dev": true 1262 | }, 1263 | "anymatch": { 1264 | "version": "3.1.2", 1265 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 1266 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 1267 | "dev": true, 1268 | "requires": { 1269 | "normalize-path": "^3.0.0", 1270 | "picomatch": "^2.0.4" 1271 | } 1272 | }, 1273 | "arg": { 1274 | "version": "4.1.3", 1275 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 1276 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 1277 | "dev": true 1278 | }, 1279 | "balanced-match": { 1280 | "version": "1.0.2", 1281 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1282 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1283 | "dev": true 1284 | }, 1285 | "binary-extensions": { 1286 | "version": "2.2.0", 1287 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 1288 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 1289 | "dev": true 1290 | }, 1291 | "brace-expansion": { 1292 | "version": "1.1.11", 1293 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1294 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1295 | "dev": true, 1296 | "requires": { 1297 | "balanced-match": "^1.0.0", 1298 | "concat-map": "0.0.1" 1299 | } 1300 | }, 1301 | "braces": { 1302 | "version": "3.0.2", 1303 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 1304 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 1305 | "dev": true, 1306 | "requires": { 1307 | "fill-range": "^7.0.1" 1308 | } 1309 | }, 1310 | "buffer-from": { 1311 | "version": "1.1.2", 1312 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 1313 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 1314 | "dev": true 1315 | }, 1316 | "buffer-writer": { 1317 | "version": "2.0.0", 1318 | "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", 1319 | "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" 1320 | }, 1321 | "bytes": { 1322 | "version": "3.1.0", 1323 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 1324 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 1325 | }, 1326 | "call-bind": { 1327 | "version": "1.0.2", 1328 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 1329 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 1330 | "requires": { 1331 | "function-bind": "^1.1.1", 1332 | "get-intrinsic": "^1.0.2" 1333 | } 1334 | }, 1335 | "chokidar": { 1336 | "version": "3.5.3", 1337 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 1338 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 1339 | "dev": true, 1340 | "requires": { 1341 | "anymatch": "~3.1.2", 1342 | "braces": "~3.0.2", 1343 | "fsevents": "~2.3.2", 1344 | "glob-parent": "~5.1.2", 1345 | "is-binary-path": "~2.1.0", 1346 | "is-glob": "~4.0.1", 1347 | "normalize-path": "~3.0.0", 1348 | "readdirp": "~3.6.0" 1349 | } 1350 | }, 1351 | "concat-map": { 1352 | "version": "0.0.1", 1353 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1354 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 1355 | "dev": true 1356 | }, 1357 | "content-type": { 1358 | "version": "1.0.4", 1359 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 1360 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 1361 | }, 1362 | "create-require": { 1363 | "version": "1.1.1", 1364 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 1365 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 1366 | "dev": true 1367 | }, 1368 | "depd": { 1369 | "version": "1.1.2", 1370 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 1371 | "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" 1372 | }, 1373 | "diff": { 1374 | "version": "4.0.2", 1375 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 1376 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 1377 | "dev": true 1378 | }, 1379 | "dotenv": { 1380 | "version": "16.0.3", 1381 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", 1382 | "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" 1383 | }, 1384 | "dynamic-dedupe": { 1385 | "version": "0.3.0", 1386 | "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", 1387 | "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", 1388 | "dev": true, 1389 | "requires": { 1390 | "xtend": "^4.0.0" 1391 | } 1392 | }, 1393 | "fill-range": { 1394 | "version": "7.0.1", 1395 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1396 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1397 | "dev": true, 1398 | "requires": { 1399 | "to-regex-range": "^5.0.1" 1400 | } 1401 | }, 1402 | "fs.realpath": { 1403 | "version": "1.0.0", 1404 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1405 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 1406 | "dev": true 1407 | }, 1408 | "fsevents": { 1409 | "version": "2.3.2", 1410 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1411 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1412 | "dev": true, 1413 | "optional": true 1414 | }, 1415 | "function-bind": { 1416 | "version": "1.1.1", 1417 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1418 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 1419 | }, 1420 | "get-intrinsic": { 1421 | "version": "1.1.3", 1422 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 1423 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 1424 | "requires": { 1425 | "function-bind": "^1.1.1", 1426 | "has": "^1.0.3", 1427 | "has-symbols": "^1.0.3" 1428 | } 1429 | }, 1430 | "glob": { 1431 | "version": "7.2.3", 1432 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 1433 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 1434 | "dev": true, 1435 | "requires": { 1436 | "fs.realpath": "^1.0.0", 1437 | "inflight": "^1.0.4", 1438 | "inherits": "2", 1439 | "minimatch": "^3.1.1", 1440 | "once": "^1.3.0", 1441 | "path-is-absolute": "^1.0.0" 1442 | } 1443 | }, 1444 | "glob-parent": { 1445 | "version": "5.1.2", 1446 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1447 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1448 | "dev": true, 1449 | "requires": { 1450 | "is-glob": "^4.0.1" 1451 | } 1452 | }, 1453 | "has": { 1454 | "version": "1.0.3", 1455 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1456 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1457 | "requires": { 1458 | "function-bind": "^1.1.1" 1459 | } 1460 | }, 1461 | "has-symbols": { 1462 | "version": "1.0.3", 1463 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 1464 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" 1465 | }, 1466 | "http-errors": { 1467 | "version": "1.7.3", 1468 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", 1469 | "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", 1470 | "requires": { 1471 | "depd": "~1.1.2", 1472 | "inherits": "2.0.4", 1473 | "setprototypeof": "1.1.1", 1474 | "statuses": ">= 1.5.0 < 2", 1475 | "toidentifier": "1.0.0" 1476 | } 1477 | }, 1478 | "iconv-lite": { 1479 | "version": "0.4.24", 1480 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1481 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1482 | "requires": { 1483 | "safer-buffer": ">= 2.1.2 < 3" 1484 | } 1485 | }, 1486 | "inflight": { 1487 | "version": "1.0.6", 1488 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1489 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 1490 | "dev": true, 1491 | "requires": { 1492 | "once": "^1.3.0", 1493 | "wrappy": "1" 1494 | } 1495 | }, 1496 | "inherits": { 1497 | "version": "2.0.4", 1498 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1499 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1500 | }, 1501 | "is-binary-path": { 1502 | "version": "2.1.0", 1503 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1504 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1505 | "dev": true, 1506 | "requires": { 1507 | "binary-extensions": "^2.0.0" 1508 | } 1509 | }, 1510 | "is-core-module": { 1511 | "version": "2.10.0", 1512 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", 1513 | "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", 1514 | "dev": true, 1515 | "requires": { 1516 | "has": "^1.0.3" 1517 | } 1518 | }, 1519 | "is-extglob": { 1520 | "version": "2.1.1", 1521 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1522 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1523 | "dev": true 1524 | }, 1525 | "is-glob": { 1526 | "version": "4.0.3", 1527 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1528 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1529 | "dev": true, 1530 | "requires": { 1531 | "is-extglob": "^2.1.1" 1532 | } 1533 | }, 1534 | "is-number": { 1535 | "version": "7.0.0", 1536 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1537 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1538 | "dev": true 1539 | }, 1540 | "lodash.chunk": { 1541 | "version": "4.2.0", 1542 | "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", 1543 | "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==" 1544 | }, 1545 | "make-error": { 1546 | "version": "1.3.6", 1547 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 1548 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 1549 | "dev": true 1550 | }, 1551 | "micro": { 1552 | "version": "9.4.0", 1553 | "resolved": "https://registry.npmjs.org/micro/-/micro-9.4.0.tgz", 1554 | "integrity": "sha512-F3uh5Ob+0896E1skflRvcY6Cpq6/sA0RB7exMl/IhQ2wbwL79aF+mDAyjDcKNhXKkJVEXhKZrPqOEFLXkJW9og==", 1555 | "requires": { 1556 | "arg": "4.1.0", 1557 | "content-type": "1.0.4", 1558 | "raw-body": "2.4.1" 1559 | }, 1560 | "dependencies": { 1561 | "arg": { 1562 | "version": "4.1.0", 1563 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", 1564 | "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==" 1565 | } 1566 | } 1567 | }, 1568 | "minimatch": { 1569 | "version": "3.1.2", 1570 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1571 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1572 | "dev": true, 1573 | "requires": { 1574 | "brace-expansion": "^1.1.7" 1575 | } 1576 | }, 1577 | "minimist": { 1578 | "version": "1.2.6", 1579 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 1580 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", 1581 | "dev": true 1582 | }, 1583 | "mkdirp": { 1584 | "version": "1.0.4", 1585 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 1586 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", 1587 | "dev": true 1588 | }, 1589 | "normalize-path": { 1590 | "version": "3.0.0", 1591 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1592 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1593 | "dev": true 1594 | }, 1595 | "object-inspect": { 1596 | "version": "1.12.2", 1597 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 1598 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" 1599 | }, 1600 | "once": { 1601 | "version": "1.4.0", 1602 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1603 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 1604 | "dev": true, 1605 | "requires": { 1606 | "wrappy": "1" 1607 | } 1608 | }, 1609 | "packet-reader": { 1610 | "version": "1.0.0", 1611 | "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", 1612 | "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" 1613 | }, 1614 | "path-is-absolute": { 1615 | "version": "1.0.1", 1616 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1617 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 1618 | "dev": true 1619 | }, 1620 | "path-parse": { 1621 | "version": "1.0.7", 1622 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1623 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1624 | "dev": true 1625 | }, 1626 | "pg": { 1627 | "version": "8.8.0", 1628 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", 1629 | "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", 1630 | "requires": { 1631 | "buffer-writer": "2.0.0", 1632 | "packet-reader": "1.0.0", 1633 | "pg-connection-string": "^2.5.0", 1634 | "pg-pool": "^3.5.2", 1635 | "pg-protocol": "^1.5.0", 1636 | "pg-types": "^2.1.0", 1637 | "pgpass": "1.x" 1638 | } 1639 | }, 1640 | "pg-connection-string": { 1641 | "version": "2.5.0", 1642 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", 1643 | "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" 1644 | }, 1645 | "pg-int8": { 1646 | "version": "1.0.1", 1647 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", 1648 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" 1649 | }, 1650 | "pg-pool": { 1651 | "version": "3.5.2", 1652 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz", 1653 | "integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==", 1654 | "requires": {} 1655 | }, 1656 | "pg-protocol": { 1657 | "version": "1.5.0", 1658 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", 1659 | "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" 1660 | }, 1661 | "pg-types": { 1662 | "version": "2.2.0", 1663 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", 1664 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", 1665 | "requires": { 1666 | "pg-int8": "1.0.1", 1667 | "postgres-array": "~2.0.0", 1668 | "postgres-bytea": "~1.0.0", 1669 | "postgres-date": "~1.0.4", 1670 | "postgres-interval": "^1.1.0" 1671 | } 1672 | }, 1673 | "pgpass": { 1674 | "version": "1.0.5", 1675 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", 1676 | "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", 1677 | "requires": { 1678 | "split2": "^4.1.0" 1679 | } 1680 | }, 1681 | "picomatch": { 1682 | "version": "2.3.1", 1683 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1684 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1685 | "dev": true 1686 | }, 1687 | "postgres-array": { 1688 | "version": "2.0.0", 1689 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", 1690 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" 1691 | }, 1692 | "postgres-bytea": { 1693 | "version": "1.0.0", 1694 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", 1695 | "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" 1696 | }, 1697 | "postgres-date": { 1698 | "version": "1.0.7", 1699 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", 1700 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" 1701 | }, 1702 | "postgres-interval": { 1703 | "version": "1.2.0", 1704 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", 1705 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", 1706 | "requires": { 1707 | "xtend": "^4.0.0" 1708 | } 1709 | }, 1710 | "prettier": { 1711 | "version": "2.7.1", 1712 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", 1713 | "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", 1714 | "dev": true 1715 | }, 1716 | "qs": { 1717 | "version": "6.11.0", 1718 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 1719 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 1720 | "requires": { 1721 | "side-channel": "^1.0.4" 1722 | } 1723 | }, 1724 | "raw-body": { 1725 | "version": "2.4.1", 1726 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", 1727 | "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", 1728 | "requires": { 1729 | "bytes": "3.1.0", 1730 | "http-errors": "1.7.3", 1731 | "iconv-lite": "0.4.24", 1732 | "unpipe": "1.0.0" 1733 | } 1734 | }, 1735 | "readdirp": { 1736 | "version": "3.6.0", 1737 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1738 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1739 | "dev": true, 1740 | "requires": { 1741 | "picomatch": "^2.2.1" 1742 | } 1743 | }, 1744 | "resolve": { 1745 | "version": "1.22.1", 1746 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 1747 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 1748 | "dev": true, 1749 | "requires": { 1750 | "is-core-module": "^2.9.0", 1751 | "path-parse": "^1.0.7", 1752 | "supports-preserve-symlinks-flag": "^1.0.0" 1753 | } 1754 | }, 1755 | "rimraf": { 1756 | "version": "2.7.1", 1757 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1758 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 1759 | "dev": true, 1760 | "requires": { 1761 | "glob": "^7.1.3" 1762 | } 1763 | }, 1764 | "safer-buffer": { 1765 | "version": "2.1.2", 1766 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1767 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1768 | }, 1769 | "setprototypeof": { 1770 | "version": "1.1.1", 1771 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 1772 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 1773 | }, 1774 | "side-channel": { 1775 | "version": "1.0.4", 1776 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 1777 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 1778 | "requires": { 1779 | "call-bind": "^1.0.0", 1780 | "get-intrinsic": "^1.0.2", 1781 | "object-inspect": "^1.9.0" 1782 | } 1783 | }, 1784 | "source-map": { 1785 | "version": "0.6.1", 1786 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1787 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1788 | "dev": true 1789 | }, 1790 | "source-map-support": { 1791 | "version": "0.5.21", 1792 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 1793 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 1794 | "dev": true, 1795 | "requires": { 1796 | "buffer-from": "^1.0.0", 1797 | "source-map": "^0.6.0" 1798 | } 1799 | }, 1800 | "split2": { 1801 | "version": "4.1.0", 1802 | "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", 1803 | "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==" 1804 | }, 1805 | "sql-template-strings": { 1806 | "version": "2.2.2", 1807 | "resolved": "https://registry.npmjs.org/sql-template-strings/-/sql-template-strings-2.2.2.tgz", 1808 | "integrity": "sha512-UXhXR2869FQaD+GMly8jAMCRZ94nU5KcrFetZfWEMd+LVVG6y0ExgHAhatEcKZ/wk8YcKPdi+hiD2wm75lq3/Q==" 1809 | }, 1810 | "statuses": { 1811 | "version": "1.5.0", 1812 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 1813 | "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" 1814 | }, 1815 | "strip-bom": { 1816 | "version": "3.0.0", 1817 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 1818 | "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", 1819 | "dev": true 1820 | }, 1821 | "strip-json-comments": { 1822 | "version": "2.0.1", 1823 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1824 | "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", 1825 | "dev": true 1826 | }, 1827 | "stripe": { 1828 | "version": "10.12.0", 1829 | "resolved": "https://registry.npmjs.org/stripe/-/stripe-10.12.0.tgz", 1830 | "integrity": "sha512-4ijMsbTVSy6rzWIkal+/dFGeTXtjqLeZ/oo/jc2jhICbf3Dby0CBTPxAg6ZhBPXQL96TJxI613C/NhhE7LvrWw==", 1831 | "requires": { 1832 | "@types/node": ">=8.1.0", 1833 | "qs": "^6.10.3" 1834 | } 1835 | }, 1836 | "supports-preserve-symlinks-flag": { 1837 | "version": "1.0.0", 1838 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1839 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1840 | "dev": true 1841 | }, 1842 | "to-regex-range": { 1843 | "version": "5.0.1", 1844 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1845 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1846 | "dev": true, 1847 | "requires": { 1848 | "is-number": "^7.0.0" 1849 | } 1850 | }, 1851 | "toidentifier": { 1852 | "version": "1.0.0", 1853 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 1854 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 1855 | }, 1856 | "tree-kill": { 1857 | "version": "1.2.2", 1858 | "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", 1859 | "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", 1860 | "dev": true 1861 | }, 1862 | "ts-node": { 1863 | "version": "10.9.1", 1864 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 1865 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 1866 | "dev": true, 1867 | "requires": { 1868 | "@cspotcode/source-map-support": "^0.8.0", 1869 | "@tsconfig/node10": "^1.0.7", 1870 | "@tsconfig/node12": "^1.0.7", 1871 | "@tsconfig/node14": "^1.0.0", 1872 | "@tsconfig/node16": "^1.0.2", 1873 | "acorn": "^8.4.1", 1874 | "acorn-walk": "^8.1.1", 1875 | "arg": "^4.1.0", 1876 | "create-require": "^1.1.0", 1877 | "diff": "^4.0.1", 1878 | "make-error": "^1.1.1", 1879 | "v8-compile-cache-lib": "^3.0.1", 1880 | "yn": "3.1.1" 1881 | } 1882 | }, 1883 | "ts-node-dev": { 1884 | "version": "2.0.0", 1885 | "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", 1886 | "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", 1887 | "dev": true, 1888 | "requires": { 1889 | "chokidar": "^3.5.1", 1890 | "dynamic-dedupe": "^0.3.0", 1891 | "minimist": "^1.2.6", 1892 | "mkdirp": "^1.0.4", 1893 | "resolve": "^1.0.0", 1894 | "rimraf": "^2.6.1", 1895 | "source-map-support": "^0.5.12", 1896 | "tree-kill": "^1.2.2", 1897 | "ts-node": "^10.4.0", 1898 | "tsconfig": "^7.0.0" 1899 | } 1900 | }, 1901 | "tsconfig": { 1902 | "version": "7.0.0", 1903 | "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", 1904 | "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", 1905 | "dev": true, 1906 | "requires": { 1907 | "@types/strip-bom": "^3.0.0", 1908 | "@types/strip-json-comments": "0.0.30", 1909 | "strip-bom": "^3.0.0", 1910 | "strip-json-comments": "^2.0.0" 1911 | } 1912 | }, 1913 | "typescript": { 1914 | "version": "4.8.4", 1915 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", 1916 | "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", 1917 | "dev": true 1918 | }, 1919 | "unpipe": { 1920 | "version": "1.0.0", 1921 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1922 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" 1923 | }, 1924 | "v8-compile-cache-lib": { 1925 | "version": "3.0.1", 1926 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 1927 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 1928 | "dev": true 1929 | }, 1930 | "wrappy": { 1931 | "version": "1.0.2", 1932 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1933 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1934 | "dev": true 1935 | }, 1936 | "xtend": { 1937 | "version": "4.0.2", 1938 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1939 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 1940 | }, 1941 | "yn": { 1942 | "version": "3.1.1", 1943 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1944 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 1945 | "dev": true 1946 | } 1947 | } 1948 | } 1949 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stripe_to_postgres", 3 | "version": "0.2.0", 4 | "description": "Sync Stripe to Postgres", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "ts-node-dev --log-error --files ./src/server.ts", 8 | "build": "tsc -p tsconfig.json", 9 | "start": "node dist/server.js", 10 | "release": "npm version minor && make" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/usenoori/stripe_to_postgres.git" 15 | }, 16 | "keywords": [ 17 | "Stripe", 18 | "Postgres" 19 | ], 20 | "author": "usenoori", 21 | "bugs": { 22 | "url": "https://github.com/usenoori/stripe_to_postgres/issues" 23 | }, 24 | "homepage": "https://github.com/usenoori/stripe_to_postgres#readme", 25 | "dependencies": { 26 | "@whollacsek/pg-node-migrations": "^0.0.8", 27 | "dotenv": "^16.0.3", 28 | "lodash.chunk": "^4.2.0", 29 | "micro": "9.4.0", 30 | "pg": "^8.8.0", 31 | "stripe": "^10.12.0" 32 | }, 33 | "devDependencies": { 34 | "@types/lodash.chunk": "^4.2.7", 35 | "@types/node": "^18.8.0", 36 | "@types/pg": "^8.6.5", 37 | "@types/yesql": "^4.1.1", 38 | "prettier": "^2.7.1", 39 | "ts-node-dev": "^2.0.0", 40 | "typescript": "^4.8.4" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv' 2 | 3 | type configType = { 4 | PORT: string 5 | SKIP_SYNC: string 6 | SKIP_MIGRATIONS: string 7 | DATABASE_URL: string 8 | NODE_ENV: string 9 | STRIPE_SECRET_KEY: string 10 | STRIPE_WEBHOOK_SECRET: string | undefined 11 | WEBHOOK_URL: string | undefined 12 | } 13 | 14 | export function getConfig(): configType { 15 | dotenv.config() 16 | return { 17 | PORT: process.env.PORT ?? '3000', 18 | SKIP_SYNC: process.env.SKIP_SYNC ?? 'false', 19 | SKIP_MIGRATIONS: process.env.SKIP_MIGRATIONS ?? 'false', 20 | NODE_ENV: process.env.NODE_ENV ?? 'development', 21 | DATABASE_URL: process.env.DATABASE_URL as string, 22 | STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY as string, 23 | STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET, 24 | WEBHOOK_URL: process.env.WEBHOOK_URL, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/connection.ts: -------------------------------------------------------------------------------- 1 | import { Pool, QueryResult } from 'pg' 2 | import { getConfig } from './config' 3 | 4 | const config = getConfig() 5 | const pool = new Pool({ connectionString: config.DATABASE_URL }) 6 | 7 | export const query = ( 8 | text: string, 9 | params?: string[] 10 | ): Promise => { 11 | return pool.query(text, params) 12 | } 13 | 14 | export const stringifyArray = (obj: { 15 | [Key: string]: any 16 | }): { 17 | [Key: string]: any 18 | } => { 19 | const cleansed = { ...obj } 20 | Object.keys(cleansed).map((k) => { 21 | const data = cleansed[k] 22 | if (Array.isArray(data)) { 23 | cleansed[k] = JSON.stringify(data) 24 | } 25 | }) 26 | return cleansed 27 | } 28 | 29 | export const constructUpsertSql = ( 30 | schema: string, 31 | table: string, 32 | columns: string[], 33 | rows: Object[], 34 | options?: { 35 | conflict?: string 36 | } 37 | ): { text: string; values: string[] } => { 38 | const { conflict = 'id' } = options || {} 39 | const values: string[] = [] 40 | 41 | // language=txt 42 | const text = ` 43 | insert into "${schema}"."${table}" (${columns 44 | .map((x) => `"${x}"`) 45 | .join(',')}) 46 | values 47 | ${rows 48 | .map((row, i) => { 49 | const sanitized = stringifyArray(row) 50 | return `(${columns 51 | .map((column, j) => { 52 | values.push(sanitized[column]) 53 | return `$${columns.length * (i + 1) - (columns.length - 1 - j)}` 54 | }) 55 | .join(',')})` 56 | }) 57 | .join(',')} 58 | on conflict ( 59 | ${conflict} 60 | ) 61 | do update set ${columns 62 | .map((x) => `"${x}" = excluded.${x}`) 63 | .join(',')};` 64 | 65 | return { text, values } 66 | } 67 | 68 | export const upsert = async ( 69 | table: string, 70 | columns: string[], 71 | rows: T[] 72 | ): Promise => { 73 | const { text, values } = constructUpsertSql('stripe', table, columns, rows) 74 | const result = await query(text, values) 75 | return result.rows 76 | } 77 | 78 | export async function getColumns(table: string) { 79 | const { rows } = await query( 80 | 'SELECT column_name FROM information_schema.columns where table_name = $1', 81 | [table] 82 | ) 83 | const columns: string[] = rows 84 | .map((row) => row.column_name) 85 | .filter((col) => col !== 'updated_at') 86 | return columns 87 | } 88 | -------------------------------------------------------------------------------- /src/migrate.ts: -------------------------------------------------------------------------------- 1 | import { Client } from 'pg' 2 | import { migrate } from '@whollacsek/pg-node-migrations' 3 | import { getConfig } from './config' 4 | 5 | const config = getConfig() 6 | 7 | async function connectAndMigrate( 8 | databaseUrl: string | undefined, 9 | migrationsDirectory: string, 10 | logOnError = false 11 | ) { 12 | const dbConfig = { 13 | connectionString: databaseUrl, 14 | connectionTimeoutMillis: 1000, 15 | } 16 | const optionalConfig = { 17 | schemaName: 'stripe', 18 | tableName: 'migrations', 19 | } 20 | 21 | const client = new Client(dbConfig) 22 | try { 23 | await client.connect() 24 | await migrate({ client }, migrationsDirectory, optionalConfig) 25 | } catch (error) { 26 | if (logOnError && error instanceof Error) { 27 | console.error('Migration error:', error.message) 28 | } else { 29 | throw error 30 | } 31 | } finally { 32 | await client.end() 33 | } 34 | } 35 | 36 | export async function runMigrations(): Promise { 37 | try { 38 | console.log('Running migrations') 39 | await connectAndMigrate(config.DATABASE_URL, './migrations') 40 | } catch (error) { 41 | throw error 42 | } finally { 43 | console.log('Finished migrations') 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | import { runMigrations } from './migrate' 2 | import { runSync } from './sync' 3 | import { getConfig } from './config' 4 | import { startWebhook } from './webhook' 5 | 6 | const config = getConfig() 7 | 8 | const main = async () => { 9 | if (config.SKIP_MIGRATIONS === 'true') { 10 | console.log('Skipping migrations') 11 | } else { 12 | await runMigrations() 13 | } 14 | 15 | if (config.SKIP_SYNC === 'true') { 16 | console.log('Skipping sync') 17 | } else { 18 | await runSync() 19 | } 20 | 21 | startWebhook() 22 | } 23 | 24 | main() 25 | -------------------------------------------------------------------------------- /src/stripe.ts: -------------------------------------------------------------------------------- 1 | import Stripe from 'stripe' 2 | import { getConfig } from './config' 3 | 4 | const config = getConfig() 5 | 6 | export const stripe = new Stripe(config.STRIPE_SECRET_KEY, { 7 | apiVersion: '2022-08-01', 8 | }) 9 | -------------------------------------------------------------------------------- /src/sync.ts: -------------------------------------------------------------------------------- 1 | import chunk from 'lodash.chunk' 2 | import { stripe } from './stripe' 3 | import { getColumns, upsert } from './connection' 4 | import { filterRecord, Record } from './utils' 5 | 6 | async function upsertRecords( 7 | table: string, 8 | resource: AsyncIterableIterator 9 | ) { 10 | const columns = await getColumns(table) 11 | 12 | console.log(`Upserting ${table}`) 13 | const rows = [] 14 | for await (const record of resource) { 15 | const row = filterRecord(record, columns) 16 | rows.push(row) 17 | } 18 | 19 | // TODO: find optimal chunk size 20 | for (const chunkedRows of chunk(rows, 100)) { 21 | await upsert(table, columns, chunkedRows) 22 | } 23 | console.log(`Upserted ${rows.length} ${table}`) 24 | } 25 | 26 | export async function runSync() { 27 | await upsertRecords('products', stripe.products.list({ limit: 100 })) 28 | await upsertRecords('prices', stripe.prices.list({ limit: 100 })) 29 | await upsertRecords('customers', stripe.customers.list({ limit: 100 })) 30 | await upsertRecords( 31 | 'subscriptions', 32 | stripe.subscriptions.list({ limit: 100, status: 'all' }) 33 | ) 34 | await upsertRecords('invoices', stripe.invoices.list({ limit: 100 })) 35 | await upsertRecords('charges', stripe.charges.list({ limit: 100 })) 36 | await upsertRecords('coupons', stripe.coupons.list({ limit: 100 })) 37 | await upsertRecords('disputes', stripe.disputes.list({ limit: 100 })) 38 | await upsertRecords('plans', stripe.plans.list({ limit: 100 })) 39 | await upsertRecords('events', stripe.events.list({ limit: 100 })) 40 | } 41 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | export type Record = { [Key: string]: any } 2 | 3 | export function filterRecord(record: Record, columns: string[]) { 4 | return Object.fromEntries( 5 | columns.reduce((entries, column) => { 6 | entries.push([column, record[column]]) 7 | return entries 8 | }, [] as Array<[string, any]>) 9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /src/webhook.ts: -------------------------------------------------------------------------------- 1 | import { getConfig } from './config' 2 | import http from 'http' 3 | import serve, { buffer, send, sendError } from 'micro' 4 | import Stripe from 'stripe' 5 | import { stripe } from './stripe' 6 | import { filterRecord, Record } from './utils' 7 | import { getColumns, upsert } from './connection' 8 | 9 | const WEBHOOK_API_VERSION = '2022-08-01' 10 | 11 | // https://stripe.com/docs/api/webhook_endpoints/create#create_webhook_endpoint-enabled_events 12 | const enabled_events: Array = [ 13 | 'charge.failed', 14 | 'charge.refunded', 15 | 'charge.succeeded', 16 | 'customer.created', 17 | 'customer.updated', 18 | 'customer.subscription.created', 19 | 'customer.subscription.deleted', 20 | 'customer.subscription.updated', 21 | 'invoice.created', 22 | 'invoice.finalized', 23 | 'invoice.paid', 24 | 'invoice.payment_failed', 25 | 'invoice.payment_succeeded', 26 | 'invoice.updated', 27 | 'product.created', 28 | 'product.updated', 29 | // 'product.deleted', 30 | 'price.created', 31 | 'price.updated', 32 | // 'price.deleted', 33 | ] 34 | 35 | const config = getConfig() 36 | 37 | async function upsertRecord(table: string, record: Record) { 38 | const columns = await getColumns(table) 39 | const row = filterRecord(record, columns) 40 | await upsert(table, columns, [row]) 41 | } 42 | 43 | function makeServer(webhookSecret: string) { 44 | return new http.Server( 45 | serve(async (req, res) => { 46 | const sig = req.headers['stripe-signature'] as string 47 | const body = await buffer(req) 48 | 49 | try { 50 | const event = stripe.webhooks.constructEvent(body, sig, webhookSecret) 51 | await upsertRecord('events', event) 52 | console.log(`Handling event ${event.type} ${event.id}`) 53 | switch (event.type) { 54 | case 'charge.failed': 55 | case 'charge.refunded': 56 | case 'charge.succeeded': { 57 | const charge = event.data.object as Stripe.Charge 58 | await upsertRecord('charges', charge) 59 | break 60 | } 61 | case 'customer.created': 62 | case 'customer.updated': { 63 | const customer = event.data.object as Stripe.Customer 64 | await upsertRecord('customers', customer) 65 | break 66 | } 67 | case 'customer.subscription.created': 68 | case 'customer.subscription.deleted': 69 | case 'customer.subscription.updated': { 70 | const subscription = event.data.object as Stripe.Subscription 71 | await upsertRecord('subscriptions', subscription) 72 | break 73 | } 74 | case 'invoice.created': 75 | case 'invoice.finalized': 76 | case 'invoice.paid': 77 | case 'invoice.payment_failed': 78 | case 'invoice.payment_succeeded': 79 | case 'invoice.updated': { 80 | const invoice = event.data.object as Stripe.Invoice 81 | await upsertRecord('invoices', invoice) 82 | break 83 | } 84 | case 'product.created': 85 | case 'product.updated': { 86 | const product = event.data.object as Stripe.Product 87 | await upsertRecord('products', product) 88 | break 89 | } 90 | case 'price.created': 91 | case 'price.updated': { 92 | const price = event.data.object as Stripe.Price 93 | await upsertRecord('prices', price) 94 | break 95 | } 96 | default: 97 | console.log('Unhandled webhook event') 98 | } 99 | 100 | await send(res, 200) 101 | } catch (err) { 102 | await sendError(req, res, err) 103 | } 104 | }) 105 | ) 106 | } 107 | 108 | async function getOrCreateWebhook() { 109 | const webhookEndpoints = await stripe.webhookEndpoints 110 | .list() 111 | .autoPagingToArray({ limit: 100 }) 112 | const webhookEndpoint = webhookEndpoints.find( 113 | (value) => value.metadata.creator === 'stripe_to_postgres' 114 | ) 115 | 116 | // Create webhook if not exists 117 | if (webhookEndpoint == null) { 118 | console.log(`Creating webhook ${config.WEBHOOK_URL}`) 119 | const { id, secret } = await stripe.webhookEndpoints.create({ 120 | api_version: WEBHOOK_API_VERSION, 121 | url: config.WEBHOOK_URL as string, 122 | metadata: { creator: 'stripe_to_postgres' }, 123 | description: 'stripe_to_postgres webhook', 124 | enabled_events, 125 | }) 126 | 127 | return stripe.webhookEndpoints.update(id, { 128 | metadata: { secret: secret as string }, 129 | }) 130 | } 131 | 132 | console.log( 133 | `Found existing webhook ${webhookEndpoint.api_version} ${webhookEndpoint.url}` 134 | ) 135 | 136 | // Update url 137 | if (webhookEndpoint.url !== config.WEBHOOK_URL) { 138 | console.log('Updating webhook url') 139 | return stripe.webhookEndpoints.update(webhookEndpoint.id, { 140 | url: config.WEBHOOK_URL, 141 | }) 142 | } 143 | 144 | // Update enabled_events 145 | if ( 146 | webhookEndpoint.enabled_events.length !== enabled_events.length || 147 | enabled_events.some( 148 | (value) => !webhookEndpoint.enabled_events.includes(value) 149 | ) 150 | ) { 151 | console.log('Updating webhook enabled_events') 152 | return stripe.webhookEndpoints.update(webhookEndpoint.id, { 153 | enabled_events, 154 | }) 155 | } 156 | 157 | return webhookEndpoint 158 | } 159 | 160 | export async function startWebhook() { 161 | let secret: string 162 | if (config.NODE_ENV === 'production') { 163 | const webhookEndpoint = await getOrCreateWebhook() 164 | const { secret: webhookSecret } = webhookEndpoint.metadata 165 | secret = webhookSecret 166 | } else { 167 | secret = config.STRIPE_WEBHOOK_SECRET as string 168 | } 169 | makeServer(secret).listen(config.PORT, () => { 170 | console.log(`Webhook listening on ${config.PORT}`) 171 | }) 172 | } 173 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDecoratorMetadata": true, 4 | "experimentalDecorators": true, 5 | "esModuleInterop": true, 6 | "preserveConstEnums": true, 7 | "removeComments": true, 8 | "rootDir": "src", 9 | "outDir": "dist", 10 | "sourceMap": true, 11 | "strict": true, 12 | "lib": ["ES6", "DOM"], 13 | "resolveJsonModule": true, 14 | "useUnknownInCatchVariables": false, 15 | }, 16 | "include": [ 17 | "./src/**/*" 18 | ], 19 | "exclude": [ 20 | "node_modules", 21 | "dist" 22 | ] 23 | } 24 | --------------------------------------------------------------------------------