From f689bd51a2f4e02d4eca40eb2568a1fcb95494e9 Mon Sep 17 00:00:00 2001 From: Matthieu Sieben Date: Mon, 18 Mar 2024 22:10:58 +0100 Subject: [PATCH] Build system rework (#2169) * refactor(crypto): remove circular dependency * refactor(crypto): expose compress/decompress as part of the DidKeyPlugin interface * fix(crypto): remove import from private file * refactor: isolate tsconfig * fix: remove unused bench file * chore(repo): remove unused deps * fix(ozone): properly list dependencies * fix(services): do lint js files * fix(services/pds): remove unused deps * chore(pds): remove bench * chore(dev-env): remove unused deps * chore(api): remove bench * remove unused babel.config.js files * fix: remove .ts extension from import * fix(pds): remove imports of src files * fix(tsconfig): properly list all projects * fix(dev-env): remove imports of src files * fix(bsky): remove direct import to crypto src * fix(api): remove imports to api internals * chore(build): prevent bundling of built output * chore(dev): add "dev" script to build in watch mode * chore(deps): move ts-node dependency where it is actually used * fix(deps): add dev-env as project dependency * fix(xrpc-server): properly type kexicon * fix(bsky): improve typings * fix(pds): fully type formatRecordEmbedInternal return value * fix(repo): remove imports from @ipld/car/api * feat(dev-env): re-export BskyIngester * fix: properly lint & type jest config & test files * fix(ci): test after build * fix(types): use NodeJS.Timeout instead of NodeJS.Timer * fix(bsky): make types exportable * fix(ozone): make types exportable * fix(xrpc-server): make types exportable * fix(xprc-server): make code compliant with "node" types * fix(xrpc-server): avoid accessing properties of unknown * chore(deps): update @types/node * feat(tsconfig): narrow down available types depending on the package's target environment * fix(pds): remove unused prop * fix(bsync): Database's migrator not always initialized * fix(dev-env): remove unreachable code * fix(xrpc-server): remove unused import * fix(xrpc-server): mark header property as abstract * fix(pds): initialize LeakyTxPlugin's txOver property * fix(bsky): initialize LeakyTxPlugin's txOver property * fix(bsky): remove unused migrator from DatabaseCoordinator * fix(bsky): Properly initialize LabelService's cache property * fix(ozone): Database's migrator not initialized * fix(ozone): initialize LeakyTxPlugin's txOver property * fix(crypto): ignore unused variable error * feat(tsconfig): use stricter rules * feat(tsconfig): enable useDefineForClassFields * feat(xrpc-server): add support for brotli incoming payload * fix(xrpc-server): properly parse & process content-encoding * fix(common:stream): always call cb in _transform * tidy/fix tests and service entrypoints * Revert "fix(xrpc-server): properly parse & process content-encoding" This reverts commit 2b1c66e153820d3e128fc839fcc1834d52a66686. * Revert "feat(xrpc-server): add support for brotli incoming payload" This reverts commit e710c21e6118214ddf215b0515e68cb87299a952. * remove special node env for tests (defaults to jest val of "test") * kill mute sync handler on disconnect * work around connect-es bug w/ request aborts * style(crypto): rename imports from uint8arrays * fix update package-lock * fix lint * force hbs files to be bundled as cjs * fix: use concurrently instead of npm-run-all npm-run-all seems not to be maintained anymore. Additionally, concurrently better forwards signals to child processes. * remove concurrently alltogether * ignore sqlite files in services/pds * fix verify * fix verify * tidy, fix verify * fix blob diversion test * build rework changeset --------- Co-authored-by: Devin Ivy --- .changeset/long-planes-bathe.md | 21 + .eslintrc | 29 +- .github/workflows/publish.yaml | 1 + .github/workflows/repo.yaml | 15 + babel.config.js | 3 - jest.config.base.js | 20 - jest.config.js | 5 +- test-setup.ts => jest.setup.ts | 0 package.json | 30 +- packages/api/babel.config.js | 3 - packages/api/build.js | 15 - packages/api/jest.bench.config.js | 8 - packages/api/jest.config.js | 9 +- packages/api/jest.d.ts | 20 + packages/api/jest.setup.ts | 97 +++ packages/api/package.json | 19 +- packages/api/tests/moderation.test.ts | 53 +- .../api/tests/util/moderation-behavior.ts | 2 +- packages/api/tsconfig.build.json | 9 +- packages/api/tsconfig.json | 12 +- packages/api/tsconfig.tests.json | 10 + packages/aws/build.js | 14 - packages/aws/package.json | 11 +- packages/aws/tsconfig.build.json | 8 +- packages/aws/tsconfig.json | 8 +- packages/bsky/babel.config.js | 3 - packages/bsky/buf.gen.yaml | 4 +- packages/bsky/build.js | 19 - packages/bsky/jest.config.js | 8 +- packages/bsky/package.json | 15 +- packages/bsky/src/data-plane/server/db/db.ts | 2 +- packages/bsky/src/image/server.ts | 16 +- packages/bsky/src/index.ts | 1 + packages/bsky/src/proto/bsky_connect.ts | 4 +- packages/bsky/src/proto/bsky_pb.ts | 2 +- packages/bsky/src/proto/bsync_connect.ts | 4 +- packages/bsky/src/proto/bsync_pb.ts | 2 +- packages/bsky/src/proto/courier_connect.ts | 4 +- packages/bsky/src/proto/courier_pb.ts | 2 +- packages/bsky/tests/_util.ts | 14 + .../data-plane/duplicate-records.test.ts | 3 +- .../bsky/tests/data-plane/indexing.test.ts | 6 +- .../data-plane/subscription/repo.test.ts | 10 +- .../data-plane/subscription/util.test.ts | 2 +- packages/bsky/tests/feed-generation.test.ts | 8 +- packages/bsky/tests/image/server.test.ts | 6 +- packages/bsky/tests/views/block-lists.test.ts | 10 +- packages/bsky/tests/views/blocks.test.ts | 67 +- packages/bsky/tests/views/thread.test.ts | 19 +- packages/bsky/tsconfig.build.json | 9 +- packages/bsky/tsconfig.json | 19 +- packages/bsky/tsconfig.tests.json | 8 + packages/bsync/babel.config.js | 3 - packages/bsync/build.js | 18 - packages/bsync/jest.config.js | 6 +- packages/bsync/package.json | 15 +- packages/bsync/src/context.ts | 6 +- packages/bsync/src/db/index.ts | 64 +- packages/bsync/src/index.ts | 8 +- packages/bsync/src/proto/bsync_connect.ts | 2 +- .../bsync/src/routes/scan-mute-operations.ts | 21 +- packages/bsync/tsconfig.build.json | 8 +- packages/bsync/tsconfig.json | 13 +- packages/bsync/tsconfig.tests.json | 7 + packages/common-web/babel.config.js | 1 - packages/common-web/build.js | 15 - packages/common-web/jest.config.js | 6 +- packages/common-web/package.json | 14 +- packages/common-web/tsconfig.build.json | 8 +- packages/common-web/tsconfig.json | 12 +- packages/common-web/tsconfig.tests.json | 7 + packages/common/babel.config.js | 1 - packages/common/build.js | 14 - packages/common/jest.config.js | 6 +- packages/common/package.json | 16 +- packages/common/src/streams.ts | 5 +- packages/common/tsconfig.build.json | 8 +- packages/common/tsconfig.json | 13 +- packages/common/tsconfig.tests.json | 7 + packages/crypto/build.js | 14 - packages/crypto/jest.config.js | 6 +- packages/crypto/package.json | 14 +- packages/crypto/src/did.ts | 48 +- packages/crypto/src/p256/keypair.ts | 14 +- packages/crypto/src/p256/operations.ts | 14 +- packages/crypto/src/p256/plugin.ts | 9 +- packages/crypto/src/secp256k1/keypair.ts | 16 +- packages/crypto/src/secp256k1/operations.ts | 10 +- packages/crypto/src/secp256k1/plugin.ts | 9 +- packages/crypto/src/types.ts | 3 + packages/crypto/src/utils.ts | 23 + packages/crypto/tests/signatures.test.ts | 1 + packages/crypto/tsconfig.build.json | 8 +- packages/crypto/tsconfig.json | 12 +- packages/crypto/tsconfig.tests.json | 7 + packages/dev-env/build.js | 27 - packages/dev-env/package.json | 16 +- packages/dev-env/src/bsky.ts | 4 +- packages/dev-env/src/feed-gen.ts | 13 +- packages/dev-env/src/index.ts | 1 + packages/dev-env/src/mock/index.ts | 19 +- packages/dev-env/src/moderator-client.ts | 12 +- packages/dev-env/src/network-no-appview.ts | 2 +- packages/dev-env/src/pds.ts | 2 +- packages/dev-env/src/seed/client.ts | 41 +- packages/dev-env/tsconfig.build.json | 8 +- packages/dev-env/tsconfig.json | 18 +- packages/identity/babel.config.js | 3 - packages/identity/build.js | 15 - packages/identity/jest.config.js | 7 +- packages/identity/package.json | 14 +- packages/identity/tsconfig.build.json | 8 +- packages/identity/tsconfig.json | 12 +- packages/identity/tsconfig.tests.json | 7 + packages/lex-cli/babel.config.js | 1 - packages/lex-cli/build.js | 14 - packages/lex-cli/package.json | 13 +- packages/lex-cli/tsconfig.build.json | 8 +- packages/lex-cli/tsconfig.json | 12 +- packages/lexicon/build.js | 14 - packages/lexicon/jest.config.js | 7 +- packages/lexicon/package.json | 14 +- packages/lexicon/tsconfig.build.json | 8 +- packages/lexicon/tsconfig.json | 13 +- packages/lexicon/tsconfig.tests.json | 7 + packages/ozone/babel.config.js | 3 - packages/ozone/build.js | 18 - packages/ozone/jest.config.js | 8 +- packages/ozone/package.json | 19 +- packages/ozone/src/daemon/event-pusher.ts | 2 +- packages/ozone/src/daemon/event-reverser.ts | 3 +- packages/ozone/src/db/index.ts | 68 +- packages/ozone/src/index.ts | 6 +- packages/ozone/tests/blob-divert.test.ts | 6 +- .../ozone/tests/moderation-appeals.test.ts | 40 +- .../ozone/tests/moderation-events.test.ts | 5 +- packages/ozone/tests/moderation.test.ts | 1 + packages/ozone/tests/query-labels.test.ts | 2 + packages/ozone/tests/sequencer.test.ts | 1 + packages/ozone/tests/server.test.ts | 3 +- packages/ozone/tsconfig.build.json | 9 +- packages/ozone/tsconfig.json | 20 +- packages/ozone/tsconfig.tests.json | 8 + packages/pds/babel.config.js | 3 - packages/pds/build.js | 27 - packages/pds/build.templates.js | 21 + packages/pds/jest.bench.config.js | 8 - packages/pds/jest.config.js | 8 +- packages/pds/package.json | 20 +- .../src/actor-store/repo/sql-repo-reader.ts | 1 - packages/pds/src/db/db.ts | 2 +- packages/pds/src/index.ts | 10 +- packages/pds/src/mailer/index.ts | 12 +- packages/pds/src/mailer/templates.ts | 13 +- .../src/mailer/templates/confirm-email.d.ts | 4 + .../src/mailer/templates/delete-account.d.ts | 4 + .../src/mailer/templates/plc-operation.d.ts | 4 + .../src/mailer/templates/reset-password.d.ts | 4 + .../src/mailer/templates/update-email.d.ts | 4 + packages/pds/src/read-after-write/viewer.ts | 12 +- packages/pds/src/types.d.ts | 5 - packages/pds/tests/account-deletion.test.ts | 1 + packages/pds/tests/account.test.ts | 2 + packages/pds/tests/auth.test.ts | 12 +- packages/pds/tests/blob-deletes.test.ts | 1 + packages/pds/tests/crud.test.ts | 29 +- packages/pds/tests/email-confirmation.test.ts | 1 + packages/pds/tests/file-uploads.test.ts | 9 +- packages/pds/tests/handles.test.ts | 1 + packages/pds/tests/invite-codes.test.ts | 1 + packages/pds/tests/plc-operations.test.ts | 1 + packages/pds/tests/proxied/admin.test.ts | 8 +- packages/pds/tests/races.test.ts | 1 + packages/pds/tests/sequencer.test.ts | 1 + .../pds/tests/sync/subscribe-repos.test.ts | 1 + packages/pds/tsconfig.build.json | 9 +- packages/pds/tsconfig.json | 22 +- packages/pds/tsconfig.tests.json | 8 + packages/repo/babel.config.js | 1 - packages/repo/build.js | 14 - packages/repo/jest.bench.config.js | 8 - packages/repo/jest.config.js | 6 +- packages/repo/package.json | 18 +- packages/repo/src/mst/mst.ts | 2 +- packages/repo/src/types.ts | 6 +- packages/repo/src/util.ts | 2 +- packages/repo/tests/_util.ts | 4 + packages/repo/tsconfig.build.json | 8 +- packages/repo/tsconfig.json | 14 +- packages/repo/tsconfig.tests.json | 7 + packages/syntax/babel.config.js | 1 - packages/syntax/build.js | 22 - packages/syntax/jest.config.js | 6 +- packages/syntax/package.json | 15 +- packages/syntax/tsconfig.build.json | 8 +- packages/syntax/tsconfig.json | 13 +- packages/syntax/tsconfig.tests.json | 7 + packages/xrpc-server/babel.config.js | 1 - packages/xrpc-server/build.js | 14 - packages/xrpc-server/jest.config.js | 7 +- packages/xrpc-server/package.json | 12 +- packages/xrpc-server/src/server.ts | 22 +- packages/xrpc-server/src/stream/frames.ts | 2 +- .../src/stream/websocket-keepalive.ts | 3 +- packages/xrpc-server/tests/bodies.test.ts | 8 +- packages/xrpc-server/tests/errors.test.ts | 2 +- packages/xrpc-server/tsconfig.build.json | 8 +- packages/xrpc-server/tsconfig.json | 14 +- packages/xrpc-server/tsconfig.tests.json | 7 + packages/xrpc/babel.config.js | 1 - packages/xrpc/build.js | 14 - packages/xrpc/package.json | 14 +- packages/xrpc/tsconfig.build.json | 8 +- packages/xrpc/tsconfig.json | 13 +- pnpm-lock.yaml | 603 +++++++++--------- services/bsky/Dockerfile | 4 +- services/bsky/api.js | 4 +- services/bsync/Dockerfile | 4 +- services/bsync/index.js | 4 +- services/ozone/Dockerfile | 4 +- services/ozone/api.js | 4 +- services/ozone/daemon.js | 4 +- services/pds/.gitignore | 1 + services/pds/Dockerfile | 4 +- services/pds/index.js | 9 +- services/pds/package.json | 2 - tsconfig.json | 58 +- tsconfig/base.json | 39 ++ tsconfig/isomorphic.json | 14 + tsconfig/node.json | 8 + tsconfig/tests.json | 8 + update-main-to-dist.js | 9 - 232 files changed, 1571 insertions(+), 1557 deletions(-) create mode 100644 .changeset/long-planes-bathe.md delete mode 100644 babel.config.js delete mode 100644 jest.config.base.js rename test-setup.ts => jest.setup.ts (100%) delete mode 100644 packages/api/babel.config.js delete mode 100644 packages/api/build.js delete mode 100644 packages/api/jest.bench.config.js create mode 100644 packages/api/jest.d.ts create mode 100644 packages/api/jest.setup.ts create mode 100644 packages/api/tsconfig.tests.json delete mode 100644 packages/aws/build.js delete mode 100644 packages/bsky/babel.config.js delete mode 100644 packages/bsky/build.js create mode 100644 packages/bsky/tsconfig.tests.json delete mode 100644 packages/bsync/babel.config.js delete mode 100644 packages/bsync/build.js create mode 100644 packages/bsync/tsconfig.tests.json delete mode 100644 packages/common-web/babel.config.js delete mode 100644 packages/common-web/build.js create mode 100644 packages/common-web/tsconfig.tests.json delete mode 100644 packages/common/babel.config.js delete mode 100644 packages/common/build.js create mode 100644 packages/common/tsconfig.tests.json delete mode 100644 packages/crypto/build.js create mode 100644 packages/crypto/src/utils.ts create mode 100644 packages/crypto/tsconfig.tests.json delete mode 100644 packages/dev-env/build.js delete mode 100644 packages/identity/babel.config.js delete mode 100644 packages/identity/build.js create mode 100644 packages/identity/tsconfig.tests.json delete mode 100644 packages/lex-cli/babel.config.js delete mode 100644 packages/lex-cli/build.js delete mode 100644 packages/lexicon/build.js create mode 100644 packages/lexicon/tsconfig.tests.json delete mode 100644 packages/ozone/babel.config.js delete mode 100644 packages/ozone/build.js create mode 100644 packages/ozone/tsconfig.tests.json delete mode 100644 packages/pds/babel.config.js delete mode 100644 packages/pds/build.js create mode 100644 packages/pds/build.templates.js delete mode 100644 packages/pds/jest.bench.config.js create mode 100644 packages/pds/src/mailer/templates/confirm-email.d.ts create mode 100644 packages/pds/src/mailer/templates/delete-account.d.ts create mode 100644 packages/pds/src/mailer/templates/plc-operation.d.ts create mode 100644 packages/pds/src/mailer/templates/reset-password.d.ts create mode 100644 packages/pds/src/mailer/templates/update-email.d.ts delete mode 100644 packages/pds/src/types.d.ts create mode 100644 packages/pds/tsconfig.tests.json delete mode 100644 packages/repo/babel.config.js delete mode 100644 packages/repo/build.js delete mode 100644 packages/repo/jest.bench.config.js create mode 100644 packages/repo/tsconfig.tests.json delete mode 100644 packages/syntax/babel.config.js delete mode 100644 packages/syntax/build.js create mode 100644 packages/syntax/tsconfig.tests.json delete mode 100644 packages/xrpc-server/babel.config.js delete mode 100644 packages/xrpc-server/build.js create mode 100644 packages/xrpc-server/tsconfig.tests.json delete mode 100644 packages/xrpc/babel.config.js delete mode 100644 packages/xrpc/build.js create mode 100644 services/pds/.gitignore create mode 100644 tsconfig/base.json create mode 100644 tsconfig/isomorphic.json create mode 100644 tsconfig/node.json create mode 100644 tsconfig/tests.json delete mode 100644 update-main-to-dist.js diff --git a/.changeset/long-planes-bathe.md b/.changeset/long-planes-bathe.md new file mode 100644 index 00000000000..b78736d2ce0 --- /dev/null +++ b/.changeset/long-planes-bathe.md @@ -0,0 +1,21 @@ +--- +'@atproto/xrpc-server': minor +'@atproto/common-web': minor +'@atproto/identity': minor +'@atproto/dev-env': minor +'@atproto/lex-cli': minor +'@atproto/lexicon': minor +'@atproto/common': minor +'@atproto/crypto': minor +'@atproto/syntax': minor +'@atproto/repo': minor +'@atproto/xrpc': minor +'@atproto/api': minor +'@atproto/aws': minor +'@atproto/bsync': patch +'@atproto/ozone': patch +'@atproto/bsky': patch +'@atproto/pds': patch +--- + +Build system rework, stop bundling dependencies. diff --git a/.eslintrc b/.eslintrc index 11c6e76318a..650df576b78 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,16 +13,7 @@ "plugin:prettier/recommended", "prettier" ], - "ignorePatterns": [ - "dist", - "node_modules", - "jest.config.base.js", - "jest.bench.config.js", - "jest.config.js", - "babel.config.js", - "build.js", - "update-pkg.js" - ], + "ignorePatterns": ["dist", "node_modules"], "rules": { "no-var": "error", "prefer-const": "warn", @@ -36,5 +27,21 @@ "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-explicit-any": "off" - } + }, + "overrides": [ + { + "files": ["jest.config.js"], + "env": { "commonjs": true } + }, + { + "files": ["jest.setup.js"], + "env": { "jest": true } + }, + { + "files": "*.js", + "rules": { + "@typescript-eslint/no-var-requires": "off" + } + } + ] } diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index c84ab0d94cb..48581feaa63 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -27,6 +27,7 @@ jobs: node-version: 18 cache: 'pnpm' - run: pnpm i --frozen-lockfile + - run: pnpm build - run: pnpm verify - name: Publish id: changesets diff --git a/.github/workflows/repo.yaml b/.github/workflows/repo.yaml index 8380fff8a63..3b46597f514 100644 --- a/.github/workflows/repo.yaml +++ b/.github/workflows/repo.yaml @@ -24,8 +24,14 @@ jobs: cache: 'pnpm' - run: pnpm i --frozen-lockfile - run: pnpm build + - uses: actions/upload-artifact@v4 + with: + name: dist + path: packages/*/dist + retention-days: 1 test: name: Test + needs: build strategy: matrix: shard: [1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8, 8/8] @@ -40,9 +46,14 @@ jobs: node-version: 18 cache: 'pnpm' - run: pnpm i --frozen-lockfile + - uses: actions/download-artifact@v4 + with: + name: dist + path: packages - run: pnpm test:withFlags --maxWorkers=1 --shard=${{ matrix.shard }} --passWithNoTests verify: name: Verify + needs: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -54,4 +65,8 @@ jobs: node-version: 18 cache: 'pnpm' - run: pnpm install --frozen-lockfile + - uses: actions/download-artifact@v4 + with: + name: dist + path: packages - run: pnpm verify diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index ee58f35df11..00000000000 --- a/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [['@babel/preset-env']], -} diff --git a/jest.config.base.js b/jest.config.base.js deleted file mode 100644 index ee4e2799057..00000000000 --- a/jest.config.base.js +++ /dev/null @@ -1,20 +0,0 @@ -// Jest doesn't like ES modules, so we need to transpile them -// For each one, add them to this list, add them to -// "workspaces.nohoist" in the root package.json, and -// make sure that a babel.config.js is in the package root -const esModules = ['get-port', 'node-fetch'].join('|') - -// jestconfig.base.js -module.exports = { - roots: ['/src', '/tests'], - transform: { - '^.+\\.(t|j)s?$': '@swc/jest', - '^.+\\.hbs$': require.resolve('handlebars-jest'), - }, - transformIgnorePatterns: [`/node_modules/(?!${esModules})`], - testRegex: '(/tests/.*.(test|spec)).(jsx?|tsx?)$', - moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], - setupFiles: ['/../../test-setup.ts'], - verbose: true, - testTimeout: 60000, -} diff --git a/jest.config.js b/jest.config.js index 2366503d1d3..d0126bea35b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,4 @@ -// jest.config.js -const base = require('./jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, projects: ['/packages/*/jest.config.js'], } diff --git a/test-setup.ts b/jest.setup.ts similarity index 100% rename from test-setup.ts rename to jest.setup.ts diff --git a/package.json b/package.json index 7fe531a530f..0c03df2affd 100644 --- a/package.json +++ b/package.json @@ -10,44 +10,46 @@ }, "scripts": { "lint:fix": "pnpm lint --fix", - "lint": "eslint . --ext .ts,.tsx", - "verify": "prettier --check . && pnpm lint", - "format": "prettier --write .", - "build": "pnpm -r --stream build", - "update-main-to-dist": "pnpm -r --stream update-main-to-dist", - "test": "LOG_ENABLED=false NODE_ENV=development ./packages/dev-infra/with-test-redis-and-db.sh pnpm --stream -r test", - "test:withFlags": "LOG_ENABLED=false NODE_ENV=development ./packages/dev-infra/with-test-redis-and-db.sh pnpm --stream -r test --", + "lint": "eslint . --ext .ts,.js", + "style:fix": "prettier --write .", + "style": "prettier --check .", + "verify": "pnpm --stream '/^verify:.+$/'", + "verify:style": "pnpm run style", + "verify:lint": "pnpm lint", + "verify:types": "tsc --build tsconfig.json", + "format": "pnpm lint:fix && pnpm style:fix", + "build": "pnpm --recursive --stream build", + "dev": "pnpm --stream '/^dev:.+$/'", + "dev:tsc": "tsc --build tsconfig.json --watch", + "dev:pkg": "pnpm --recursive --parallel --stream dev", + "test": "LOG_ENABLED=false ./packages/dev-infra/with-test-redis-and-db.sh pnpm --stream -r test", + "test:withFlags": "LOG_ENABLED=false ./packages/dev-infra/with-test-redis-and-db.sh pnpm --stream -r test --", "changeset": "changeset", "release": "pnpm build && changeset publish", "version-packages": "changeset version && git add ." }, "devDependencies": { + "@atproto/dev-env": "workspace:^", "@babel/core": "^7.18.6", "@babel/preset-env": "^7.18.6", "@changesets/changelog-github": "^0.4.8", "@changesets/cli": "^2.26.2", - "@npmcli/package-json": "^3.0.0", "@swc/core": "^1.3.42", "@swc/jest": "^0.2.24", "@types/jest": "^28.1.4", - "@types/node": "^18.0.0", + "@types/node": "^18.19.24", "@typescript-eslint/eslint-plugin": "^6.14.0", "@typescript-eslint/parser": "^6.14.0", "babel-eslint": "^10.1.0", "dotenv": "^16.0.3", - "esbuild": "^0.14.48", - "esbuild-node-externals": "^1.5.0", - "esbuild-plugin-handlebars": "^1.0.2", "eslint": "^8.24.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.2.1", - "handlebars-jest": "^1.0.0", "jest": "^28.1.2", "node-gyp": "^9.3.1", "pino-pretty": "^9.1.0", "prettier": "^2.7.1", "prettier-config-standard": "^5.0.0", - "ts-node": "^10.8.2", "typescript": "^5.3.3" }, "workspaces": { diff --git a/packages/api/babel.config.js b/packages/api/babel.config.js deleted file mode 100644 index ee58f35df11..00000000000 --- a/packages/api/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [['@babel/preset-env']], -} diff --git a/packages/api/build.js b/packages/api/build.js deleted file mode 100644 index 30fbe7cea56..00000000000 --- a/packages/api/build.js +++ /dev/null @@ -1,15 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'browser', - format: 'cjs', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/api/jest.bench.config.js b/packages/api/jest.bench.config.js deleted file mode 100644 index b3bb54fca4d..00000000000 --- a/packages/api/jest.bench.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const base = require('./jest.config') - -module.exports = { - ...base, - roots: ['/bench'], - testRegex: '(.*.bench.ts)', - testTimeout: 3000000, -} diff --git a/packages/api/jest.config.js b/packages/api/jest.config.js index d8abff65a6f..23994feaf41 100644 --- a/packages/api/jest.config.js +++ b/packages/api/jest.config.js @@ -1,6 +1,9 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'API', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + transformIgnorePatterns: [`/node_modules/(?!get-port)`], + testTimeout: 60000, + setupFiles: ['/../../jest.setup.ts'], + setupFilesAfterEnv: ['/jest.setup.ts'], } diff --git a/packages/api/jest.d.ts b/packages/api/jest.d.ts new file mode 100644 index 00000000000..68ace0e840d --- /dev/null +++ b/packages/api/jest.d.ts @@ -0,0 +1,20 @@ +declare namespace jest { + // eslint-disable-next-line + interface Matchers { + toBeModerationResult( + expected: ModerationTestSuiteResultFlag[] | undefined, + context?: string, + stringifiedResult?: string, + ignoreCause?: boolean, + ): R + } + + interface Expect { + toBeModerationResult( + expected: ModerationTestSuiteResultFlag[] | undefined, + context?: string, + stringifiedResult?: string, + ignoreCause?: boolean, + ): void + } +} diff --git a/packages/api/jest.setup.ts b/packages/api/jest.setup.ts new file mode 100644 index 00000000000..f0e4aaaf36f --- /dev/null +++ b/packages/api/jest.setup.ts @@ -0,0 +1,97 @@ +import { ModerationUI } from './src' +import { ModerationTestSuiteResultFlag } from './tests/util/moderation-behavior' + +expect.extend({ + toBeModerationResult( + actual: ModerationUI, + expected: ModerationTestSuiteResultFlag[] | undefined, + context: string = '', + stringifiedResult: string | undefined = undefined, + _ignoreCause = false, + ) { + const fail = (msg: string) => ({ + pass: false, + message: () => + `${msg}.${ + stringifiedResult ? ` Full result: ${stringifiedResult}` : '' + }`, + }) + // let cause = actual.causes?.type as string + // if (actual.cause?.type === 'label') { + // cause = `label:${actual.cause.labelDef.id}` + // } else if (actual.cause?.type === 'muted') { + // if (actual.cause.source.type === 'list') { + // cause = 'muted-by-list' + // } + // } else if (actual.cause?.type === 'blocking') { + // if (actual.cause.source.type === 'list') { + // cause = 'blocking-by-list' + // } + // } + if (!expected) { + // if (!ignoreCause && actual.cause) { + // return fail(`${context} expected to be a no-op, got ${cause}`) + // } + if (actual.inform) { + return fail(`${context} expected to be a no-op, got inform=true`) + } + if (actual.alert) { + return fail(`${context} expected to be a no-op, got alert=true`) + } + if (actual.blur) { + return fail(`${context} expected to be a no-op, got blur=true`) + } + if (actual.filter) { + return fail(`${context} expected to be a no-op, got filter=true`) + } + if (actual.noOverride) { + return fail(`${context} expected to be a no-op, got noOverride=true`) + } + } else { + // if (!ignoreCause && cause !== expected.cause) { + // return fail(`${context} expected to be ${expected.cause}, got ${cause}`) + // } + const expectedInform = expected.includes('inform') + if (!!actual.inform !== expectedInform) { + return fail( + `${context} expected to be inform=${expectedInform}, got ${ + actual.inform || false + }`, + ) + } + const expectedAlert = expected.includes('alert') + if (!!actual.alert !== expectedAlert) { + return fail( + `${context} expected to be alert=${expectedAlert}, got ${ + actual.alert || false + }`, + ) + } + const expectedBlur = expected.includes('blur') + if (!!actual.blur !== expectedBlur) { + return fail( + `${context} expected to be blur=${expectedBlur}, got ${ + actual.blur || false + }`, + ) + } + const expectedFilter = expected.includes('filter') + if (!!actual.filter !== expectedFilter) { + return fail( + `${context} expected to be filter=${expectedFilter}, got ${ + actual.filter || false + }`, + ) + } + const expectedNoOverride = expected.includes('noOverride') + if (!!actual.noOverride !== expectedNoOverride) { + return fail( + `${context} expected to be noOverride=${expectedNoOverride}, got ${ + actual.noOverride || false + }`, + ) + } + } + return { pass: true, message: () => '' } + }, +}) diff --git a/packages/api/package.json b/packages/api/package.json index 37c26f4c670..ae401b02e70 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -14,19 +14,12 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/api" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "codegen": "node ./scripts/generate-code.mjs && lex gen-api ./src/client ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/* ../../lexicons/tools/ozone/*/*", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/api", - "test": "jest", - "bench": "jest --config jest.bench.config.js", - "bench:profile": "node --inspect-brk ../../node_modules/.bin/jest --config jest.bench.config.js" + "build": "tsc --build tsconfig.build.json", + "test": "jest" }, "dependencies": { "@atproto/common-web": "workspace:^", @@ -38,7 +31,7 @@ }, "devDependencies": { "@atproto/lex-cli": "workspace:^", - "@atproto/dev-env": "workspace:^", - "get-port": "^6.1.2" + "get-port": "^6.1.2", + "jest": "^28.1.2" } } diff --git a/packages/api/tests/moderation.test.ts b/packages/api/tests/moderation.test.ts index 320e1b105d0..d7d3f9d47bc 100644 --- a/packages/api/tests/moderation.test.ts +++ b/packages/api/tests/moderation.test.ts @@ -5,6 +5,7 @@ import { interpretLabelValueDefinition, } from '../src' import './util/moderation-behavior' +import { ModerationOpts } from '../dist' describe('Moderation', () => { it('Applies self-labels on profiles according to the global preferences', () => { @@ -30,6 +31,8 @@ describe('Moderation', () => { porn: 'hide', }, labelers: [], + hiddenPosts: [], + mutedWords: [], }, }, ) @@ -62,6 +65,8 @@ describe('Moderation', () => { porn: 'ignore', }, labelers: [], + hiddenPosts: [], + mutedWords: [], }, }, ) @@ -96,6 +101,8 @@ describe('Moderation', () => { porn: 'hide', }, labelers: [], + hiddenPosts: [], + mutedWords: [], }, }, ) @@ -108,7 +115,7 @@ describe('Moderation', () => { 'contentList', 'contentView', 'contentMedia', - ]) { + ] as const) { expect(res1.ui(k)).toBeModerationResult( [], k, @@ -143,6 +150,8 @@ describe('Moderation', () => { labels: { porn: 'ignore' }, }, ], + hiddenPosts: [], + mutedWords: [], }, }, ) @@ -155,7 +164,7 @@ describe('Moderation', () => { 'contentList', 'contentView', 'contentMedia', - ]) { + ] as const) { expect(res2.ui(k)).toBeModerationResult( [], k, @@ -188,6 +197,8 @@ describe('Moderation', () => { labels: {}, }, ], + hiddenPosts: [], + mutedWords: [], }, }, ) @@ -238,17 +249,19 @@ describe('Moderation', () => { labels: {}, }, ], + hiddenPosts: [], + mutedWords: [], }, }, ) - expect(res1.ui('contentList').filters[0].label.val).toBe('!hide') - expect(res1.ui('contentList').filters[1].label.val).toBe('porn') - expect(res1.ui('contentList').blurs[0].label.val).toBe('!hide') - expect(res1.ui('contentMedia').blurs[0].label.val).toBe('porn') + expect((res1.ui('contentList').filters[0] as any).label.val).toBe('!hide') + expect((res1.ui('contentList').filters[1] as any).label.val).toBe('porn') + expect((res1.ui('contentList').blurs[0] as any).label.val).toBe('!hide') + expect((res1.ui('contentMedia').blurs[0] as any).label.val).toBe('porn') }) it('Prioritizes custom label definitions', () => { - const modOpts = { + const modOpts: ModerationOpts = { userDid: 'did:web:alice.test', prefs: { adultContentEnabled: true, @@ -259,6 +272,8 @@ describe('Moderation', () => { labels: { porn: 'warn' }, }, ], + hiddenPosts: [], + mutedWords: [], }, labelDefs: { 'did:web:labeler.test': [ @@ -268,6 +283,7 @@ describe('Moderation', () => { blurs: 'none', severity: 'inform', locales: [], + defaultSetting: 'warn', }, 'did:web:labeler.test', ), @@ -306,7 +322,7 @@ describe('Moderation', () => { }) it('Doesnt allow custom behaviors to override imperative labels', () => { - const modOpts = { + const modOpts: ModerationOpts = { userDid: 'did:web:alice.test', prefs: { adultContentEnabled: true, @@ -317,6 +333,8 @@ describe('Moderation', () => { labels: {}, }, ], + hiddenPosts: [], + mutedWords: [], }, labelDefs: { 'did:web:labeler.test': [ @@ -326,6 +344,7 @@ describe('Moderation', () => { blurs: 'none', severity: 'inform', locales: [], + defaultSetting: 'warn', }, 'did:web:labeler.test', ), @@ -369,7 +388,7 @@ describe('Moderation', () => { }) it('Ignores invalid label value names', () => { - const modOpts = { + const modOpts: ModerationOpts = { userDid: 'did:web:alice.test', prefs: { adultContentEnabled: true, @@ -380,6 +399,8 @@ describe('Moderation', () => { labels: { BadLabel: 'hide', 'bad/label': 'hide' }, }, ], + hiddenPosts: [], + mutedWords: [], }, labelDefs: { 'did:web:labeler.test': [ @@ -389,6 +410,7 @@ describe('Moderation', () => { blurs: 'content', severity: 'inform', locales: [], + defaultSetting: 'warn', }, 'did:web:labeler.test', ), @@ -398,6 +420,7 @@ describe('Moderation', () => { blurs: 'content', severity: 'inform', locales: [], + defaultSetting: 'warn', }, 'did:web:labeler.test', ), @@ -443,7 +466,7 @@ describe('Moderation', () => { }) it('Custom labels can set the default setting', () => { - const modOpts = { + const modOpts: ModerationOpts = { userDid: 'did:web:alice.test', prefs: { adultContentEnabled: true, @@ -454,6 +477,8 @@ describe('Moderation', () => { labels: {}, }, ], + hiddenPosts: [], + mutedWords: [], }, labelDefs: { 'did:web:labeler.test': [ @@ -585,7 +610,7 @@ describe('Moderation', () => { }) it('Custom labels can require adult content to be enabled', () => { - const modOpts = { + const modOpts: ModerationOpts = { userDid: 'did:web:alice.test', prefs: { adultContentEnabled: false, @@ -598,6 +623,8 @@ describe('Moderation', () => { }, }, ], + hiddenPosts: [], + mutedWords: [], }, labelDefs: { 'did:web:labeler.test': [ @@ -652,7 +679,7 @@ describe('Moderation', () => { }) it('Adult content disabled forces the preference to hide', () => { - const modOpts = { + const modOpts: ModerationOpts = { userDid: 'did:web:alice.test', prefs: { adultContentEnabled: false, @@ -663,6 +690,8 @@ describe('Moderation', () => { labels: {}, }, ], + hiddenPosts: [], + mutedWords: [], }, labelDefs: {}, } diff --git a/packages/api/tests/util/moderation-behavior.ts b/packages/api/tests/util/moderation-behavior.ts index 0f33ec65b7e..260753b0ab0 100644 --- a/packages/api/tests/util/moderation-behavior.ts +++ b/packages/api/tests/util/moderation-behavior.ts @@ -65,7 +65,7 @@ expect.extend({ expected: ModerationTestSuiteResultFlag[] | undefined, context: string = '', stringifiedResult: string | undefined = undefined, - ignoreCause = false, + _ignoreCause = false, ) { const fail = (msg: string) => ({ pass: false, diff --git a/packages/api/tsconfig.build.json b/packages/api/tsconfig.build.json index 02a84823b65..2a319212737 100644 --- a/packages/api/tsconfig.build.json +++ b/packages/api/tsconfig.build.json @@ -1,4 +1,9 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/isomorphic.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "noUnusedLocals": false + }, + "include": ["./src"] } diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 22ed93bd63f..1f3ab3c0ec4 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -1,13 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src"], + "include": [], "references": [ - { "path": "../xrpc/tsconfig.build.json" }, - { "path": "../lex-cli/tsconfig.build.json" } + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } ] } diff --git a/packages/api/tsconfig.tests.json b/packages/api/tsconfig.tests.json new file mode 100644 index 00000000000..bd21d2eeb5c --- /dev/null +++ b/packages/api/tsconfig.tests.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": ".", + "types": ["jest", "./jest.d.ts"], + "noEmit": true, + "noUnusedLocals": false + }, + "include": ["./tests"] +} diff --git a/packages/aws/build.js b/packages/aws/build.js deleted file mode 100644 index e880ae9930b..00000000000 --- a/packages/aws/build.js +++ /dev/null @@ -1,14 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/aws/package.json b/packages/aws/package.json index 9b95ceb395b..0aa03638dfa 100644 --- a/packages/aws/package.json +++ b/packages/aws/package.json @@ -13,15 +13,10 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/aws" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/src/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/aws" + "build": "tsc --build tsconfig.build.json" }, "dependencies": { "@atproto/common": "workspace:^", diff --git a/packages/aws/tsconfig.build.json b/packages/aws/tsconfig.build.json index 02a84823b65..436d8ecb628 100644 --- a/packages/aws/tsconfig.build.json +++ b/packages/aws/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/isomorphic.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/aws/tsconfig.json b/packages/aws/tsconfig.json index fee83b7f23b..e84b8178b47 100644 --- a/packages/aws/tsconfig.json +++ b/packages/aws/tsconfig.json @@ -1,8 +1,4 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src", "__tests__/**/**.ts"] + "include": [], + "references": [{ "path": "./tsconfig.build.json" }] } diff --git a/packages/bsky/babel.config.js b/packages/bsky/babel.config.js deleted file mode 100644 index ee58f35df11..00000000000 --- a/packages/bsky/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [['@babel/preset-env']], -} diff --git a/packages/bsky/buf.gen.yaml b/packages/bsky/buf.gen.yaml index a81e4248719..a7ecaa0a540 100644 --- a/packages/bsky/buf.gen.yaml +++ b/packages/bsky/buf.gen.yaml @@ -3,10 +3,10 @@ plugins: - plugin: es opt: - target=ts - - import_extension=.ts + - import_extension= out: src/proto - plugin: connect-es opt: - target=ts - - import_extension=.ts + - import_extension= out: src/proto diff --git a/packages/bsky/build.js b/packages/bsky/build.js deleted file mode 100644 index 85c4a88243b..00000000000 --- a/packages/bsky/build.js +++ /dev/null @@ -1,19 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - external: [ - // Referenced in pg driver, but optional and we don't use it - 'pg-native', - 'sharp', - ], - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/bsky/jest.config.js b/packages/bsky/jest.config.js index 14720ce82eb..ee315e79d22 100644 --- a/packages/bsky/jest.config.js +++ b/packages/bsky/jest.config.js @@ -1,6 +1,8 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'Bsky App View', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + transformIgnorePatterns: [`/node_modules/(?!get-port)`], + testTimeout: 60000, + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/bsky/package.json b/packages/bsky/package.json index e1e9b8040d4..028e431a88a 100644 --- a/packages/bsky/package.json +++ b/packages/bsky/package.json @@ -13,17 +13,12 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/bsky" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "bin": "dist/bin.js", "scripts": { "codegen": "lex gen-server ./src/lexicon ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/*", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/bsky", + "build": "tsc --build tsconfig.build.json", "start": "node --enable-source-maps dist/bin.js", "test": "../dev-infra/with-test-redis-and-db.sh jest", "test:log": "tail -50 test.log | pino-pretty", @@ -65,7 +60,6 @@ }, "devDependencies": { "@atproto/api": "workspace:^", - "@atproto/dev-env": "workspace:^", "@atproto/lex-cli": "workspace:^", "@atproto/pds": "workspace:^", "@atproto/xrpc": "workspace:^", @@ -79,6 +73,7 @@ "@types/pg": "^8.6.6", "@types/qs": "^6.9.7", "axios": "^0.27.2", - "http2-express-bridge": "^1.0.7" + "jest": "^28.1.2", + "ts-node": "^10.8.2" } } diff --git a/packages/bsky/src/data-plane/server/db/db.ts b/packages/bsky/src/data-plane/server/db/db.ts index 6411938d69d..9b1cc645d62 100644 --- a/packages/bsky/src/data-plane/server/db/db.ts +++ b/packages/bsky/src/data-plane/server/db/db.ts @@ -169,7 +169,7 @@ const onClientError = (err: Error) => dbLogger.error({ err }, 'db client error') // ------- class LeakyTxPlugin implements KyselyPlugin { - private txOver: boolean + private txOver = false endTx() { this.txOver = true diff --git a/packages/bsky/src/image/server.ts b/packages/bsky/src/image/server.ts index 563d9b5bf4b..caadc0e68c7 100644 --- a/packages/bsky/src/image/server.ts +++ b/packages/bsky/src/image/server.ts @@ -4,7 +4,13 @@ import os from 'os' import path from 'path' import { Readable } from 'stream' import axios, { AxiosError } from 'axios' -import express, { ErrorRequestHandler, NextFunction } from 'express' +import express, { + Request, + Response, + Express, + ErrorRequestHandler, + NextFunction, +} from 'express' import createError, { isHttpError } from 'http-errors' import { BlobNotFoundError } from '@atproto/repo' import { @@ -20,7 +26,7 @@ import { retryHttp } from '../util/retry' import { ServerConfig } from '../config' export class ImageProcessingServer { - app = express() + app: Express = express() uriBuilder: ImageUriBuilder constructor(public cfg: ServerConfig, public cache: BlobCache) { @@ -29,11 +35,7 @@ export class ImageProcessingServer { this.app.use(errorMiddleware) } - async handler( - req: express.Request, - res: express.Response, - next: NextFunction, - ) { + async handler(req: Request, res: Response, next: NextFunction) { try { const path = req.path const options = ImageUriBuilder.getOptions(path) diff --git a/packages/bsky/src/index.ts b/packages/bsky/src/index.ts index 4c78b1e973c..b91ff91922c 100644 --- a/packages/bsky/src/index.ts +++ b/packages/bsky/src/index.ts @@ -29,6 +29,7 @@ export { ServerConfig } from './config' export { Database } from './data-plane/server/db' export { Redis } from './redis' export { AppContext } from './context' +export { BackgroundQueue } from './data-plane/server/background' export class BskyAppView { public ctx: AppContext diff --git a/packages/bsky/src/proto/bsky_connect.ts b/packages/bsky/src/proto/bsky_connect.ts index db3e318ef01..60e71b28e62 100644 --- a/packages/bsky/src/proto/bsky_connect.ts +++ b/packages/bsky/src/proto/bsky_connect.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-connect-es v1.3.0 with parameter "target=ts,import_extension=.ts" +// @generated by protoc-gen-connect-es v1.3.0 with parameter "target=ts,import_extension=" // @generated from file bsky.proto (package bsky, syntax proto3) /* eslint-disable */ // @ts-nocheck @@ -160,7 +160,7 @@ import { UntakedownRecordResponse, UpdateNotificationSeenRequest, UpdateNotificationSeenResponse, -} from './bsky_pb.ts' +} from './bsky_pb' import { MethodKind } from '@bufbuild/protobuf' /** diff --git a/packages/bsky/src/proto/bsky_pb.ts b/packages/bsky/src/proto/bsky_pb.ts index 354b3ccdbaf..51b71d418fe 100644 --- a/packages/bsky/src/proto/bsky_pb.ts +++ b/packages/bsky/src/proto/bsky_pb.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-es v1.6.0 with parameter "target=ts,import_extension=.ts" +// @generated by protoc-gen-es v1.6.0 with parameter "target=ts,import_extension=" // @generated from file bsky.proto (package bsky, syntax proto3) /* eslint-disable */ // @ts-nocheck diff --git a/packages/bsky/src/proto/bsync_connect.ts b/packages/bsky/src/proto/bsync_connect.ts index 94a37266bfd..c8bdbd778c2 100644 --- a/packages/bsky/src/proto/bsync_connect.ts +++ b/packages/bsky/src/proto/bsync_connect.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-connect-es v1.3.0 with parameter "target=ts,import_extension=.ts" +// @generated by protoc-gen-connect-es v1.3.0 with parameter "target=ts,import_extension=" // @generated from file bsync.proto (package bsync, syntax proto3) /* eslint-disable */ // @ts-nocheck @@ -10,7 +10,7 @@ import { PingResponse, ScanMuteOperationsRequest, ScanMuteOperationsResponse, -} from './bsync_pb.ts' +} from './bsync_pb' import { MethodKind } from '@bufbuild/protobuf' /** diff --git a/packages/bsky/src/proto/bsync_pb.ts b/packages/bsky/src/proto/bsync_pb.ts index aafd4012b25..980e0360421 100644 --- a/packages/bsky/src/proto/bsync_pb.ts +++ b/packages/bsky/src/proto/bsync_pb.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-es v1.6.0 with parameter "target=ts,import_extension=.ts" +// @generated by protoc-gen-es v1.6.0 with parameter "target=ts,import_extension=" // @generated from file bsync.proto (package bsync, syntax proto3) /* eslint-disable */ // @ts-nocheck diff --git a/packages/bsky/src/proto/courier_connect.ts b/packages/bsky/src/proto/courier_connect.ts index 04d482e0788..ccf818df6e2 100644 --- a/packages/bsky/src/proto/courier_connect.ts +++ b/packages/bsky/src/proto/courier_connect.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-connect-es v1.3.0 with parameter "target=ts,import_extension=.ts" +// @generated by protoc-gen-connect-es v1.3.0 with parameter "target=ts,import_extension=" // @generated from file courier.proto (package courier, syntax proto3) /* eslint-disable */ // @ts-nocheck @@ -10,7 +10,7 @@ import { PushNotificationsResponse, RegisterDeviceTokenRequest, RegisterDeviceTokenResponse, -} from './courier_pb.ts' +} from './courier_pb' import { MethodKind } from '@bufbuild/protobuf' /** diff --git a/packages/bsky/src/proto/courier_pb.ts b/packages/bsky/src/proto/courier_pb.ts index 447b47211d9..c566944aae4 100644 --- a/packages/bsky/src/proto/courier_pb.ts +++ b/packages/bsky/src/proto/courier_pb.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-es v1.6.0 with parameter "target=ts,import_extension=.ts" +// @generated by protoc-gen-es v1.6.0 with parameter "target=ts,import_extension=" // @generated from file courier.proto (package courier, syntax proto3) /* eslint-disable */ // @ts-nocheck diff --git a/packages/bsky/tests/_util.ts b/packages/bsky/tests/_util.ts index 48011be9b25..fc93fce6d91 100644 --- a/packages/bsky/tests/_util.ts +++ b/packages/bsky/tests/_util.ts @@ -8,12 +8,26 @@ import { isThreadViewPost, } from '../src/lexicon/types/app/bsky/feed/defs' import { isViewRecord } from '../src/lexicon/types/app/bsky/embed/record' +import { AppBskyFeedGetPostThread } from '@atproto/api' import { LabelerView, isLabelerView, isLabelerViewDetailed, } from '../src/lexicon/types/app/bsky/labeler/defs' +type ThreadViewPost = Extract< + AppBskyFeedGetPostThread.OutputSchema['thread'], + { post: { uri: string } } +> + +export function assertIsThreadViewPost( + value: unknown, +): asserts value is ThreadViewPost { + expect(value).toMatchObject({ + $type: 'app.bsky.feed.defs#threadViewPost', + }) +} + // Swap out identifiers and dates with stable // values for the purpose of snapshot testing export const forSnapshot = (obj: unknown) => { diff --git a/packages/bsky/tests/data-plane/duplicate-records.test.ts b/packages/bsky/tests/data-plane/duplicate-records.test.ts index da7287893ba..e09980751d7 100644 --- a/packages/bsky/tests/data-plane/duplicate-records.test.ts +++ b/packages/bsky/tests/data-plane/duplicate-records.test.ts @@ -3,7 +3,8 @@ import { cidForCbor, TID } from '@atproto/common' import { WriteOpAction } from '@atproto/repo' import { TestNetwork } from '@atproto/dev-env' import * as lex from '../../src/lexicon/lexicons' -import { Database } from '../../src' + +type Database = TestNetwork['bsky']['db'] describe('duplicate record', () => { let network: TestNetwork diff --git a/packages/bsky/tests/data-plane/indexing.test.ts b/packages/bsky/tests/data-plane/indexing.test.ts index f97495c6b32..6703290cd3b 100644 --- a/packages/bsky/tests/data-plane/indexing.test.ts +++ b/packages/bsky/tests/data-plane/indexing.test.ts @@ -1,7 +1,7 @@ import { sql } from 'kysely' import { CID } from 'multiformats/cid' import { cidForCbor, TID } from '@atproto/common' -import * as pdsRepo from '@atproto/pds/src/repo/prepare' +import { repoPrepare } from '@atproto/pds' import { WriteOpAction } from '@atproto/repo' import { AtUri } from '@atproto/syntax' import AtpAgent, { @@ -489,12 +489,12 @@ describe('indexing', () => { // const { db: pdsDb, services: pdsServices } = network.pds.ctx // Create a good and a bad post record const writes = await Promise.all([ - pdsRepo.prepareCreate({ + repoPrepare.prepareCreate({ did: sc.dids.alice, collection: ids.AppBskyFeedPost, record: { text: 'valid', createdAt: new Date().toISOString() }, }), - pdsRepo.prepareCreate({ + repoPrepare.prepareCreate({ did: sc.dids.alice, collection: ids.AppBskyFeedPost, record: { text: 0 }, diff --git a/packages/bsky/tests/data-plane/subscription/repo.test.ts b/packages/bsky/tests/data-plane/subscription/repo.test.ts index 3a02b2fa61c..61f505e61d9 100644 --- a/packages/bsky/tests/data-plane/subscription/repo.test.ts +++ b/packages/bsky/tests/data-plane/subscription/repo.test.ts @@ -1,13 +1,13 @@ import AtpAgent from '@atproto/api' -import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env' -import { CommitData } from '@atproto/repo' -import { PreparedWrite } from '@atproto/pds/src/repo' -import * as sequencer from '@atproto/pds/src/sequencer' import { cborDecode, cborEncode } from '@atproto/common' import { DatabaseSchemaType } from '../../../src/data-plane/server/db/database-schema' +import { SeedClient, TestNetwork, basicSeed } from '@atproto/dev-env' +import { PreparedWrite, sequencer } from '@atproto/pds' +import { CommitData } from '@atproto/repo' import { ids } from '../../../src/lexicon/lexicons' import { forSnapshot } from '../../_util' -import { Database } from '../../../src' + +type Database = TestNetwork['bsky']['db'] describe('sync', () => { let network: TestNetwork diff --git a/packages/bsky/tests/data-plane/subscription/util.test.ts b/packages/bsky/tests/data-plane/subscription/util.test.ts index 0aba097c334..9c2bbf92bfb 100644 --- a/packages/bsky/tests/data-plane/subscription/util.test.ts +++ b/packages/bsky/tests/data-plane/subscription/util.test.ts @@ -1,10 +1,10 @@ import { wait } from '@atproto/common' +import { randomStr } from '@atproto/crypto' import { ConsecutiveList, LatestQueue, PartitionedQueue, } from '../../../src/data-plane/server/subscription/util' -import { randomStr } from '../../../../crypto/src' describe('subscription utils', () => { describe('ConsecutiveList', () => { diff --git a/packages/bsky/tests/feed-generation.test.ts b/packages/bsky/tests/feed-generation.test.ts index 44f3760808b..3120f45669c 100644 --- a/packages/bsky/tests/feed-generation.test.ts +++ b/packages/bsky/tests/feed-generation.test.ts @@ -11,8 +11,6 @@ import { basicSeed, } from '@atproto/dev-env' import { Handler as SkeletonHandler } from '../src/lexicon/types/app/bsky/feed/getFeedSkeleton' -import { GeneratorView } from '@atproto/api/src/client/types/app/bsky/feed/defs' -import { UnknownFeedError } from '@atproto/api/src/client/types/app/bsky/feed/getFeed' import { ids } from '../src/lexicon/lexicons' import { FeedViewPost, @@ -197,7 +195,7 @@ describe('feed generation', () => { return res.data } - const paginatedAll: GeneratorView[] = results(await paginateAll(paginator)) + const paginatedAll = results(await paginateAll(paginator)) expect(paginatedAll.length).toEqual(5) expect(paginatedAll[0].uri).toEqual(feedUriOdd) @@ -453,7 +451,9 @@ describe('feed generation', () => { { feed: feedUriOdd }, { headers: await network.serviceHeaders(alice, gen.did) }, ) - await expect(tryGetFeed).rejects.toThrow(UnknownFeedError) + await expect(tryGetFeed).rejects.toMatchObject({ + error: 'UnknownFeed', + }) }) it('resolves contents of taken-down feed.', async () => { diff --git a/packages/bsky/tests/image/server.test.ts b/packages/bsky/tests/image/server.test.ts index 5ccd3dbd70a..4d879c30c03 100644 --- a/packages/bsky/tests/image/server.test.ts +++ b/packages/bsky/tests/image/server.test.ts @@ -35,7 +35,7 @@ describe('image processing server', () => { ImageUriBuilder.getPath({ preset: 'feed_fullsize', did: fileDid, - cid: fileCid, + cid: fileCid.toString(), }), { responseType: 'stream' }, ) @@ -61,7 +61,7 @@ describe('image processing server', () => { const path = ImageUriBuilder.getPath({ preset: 'avatar', did: fileDid, - cid: fileCid, + cid: fileCid.toString(), }) const res1 = await client.get(path, { responseType: 'arraybuffer' }) expect(res1.headers['x-cache']).toEqual('miss') @@ -79,7 +79,7 @@ describe('image processing server', () => { ImageUriBuilder.getPath({ preset: 'feed_fullsize', did: fileDid, - cid: missingCid, + cid: missingCid.toString(), }), ) expect(res.status).toEqual(404) diff --git a/packages/bsky/tests/views/block-lists.test.ts b/packages/bsky/tests/views/block-lists.test.ts index 85339e74cd6..8d23b680fa9 100644 --- a/packages/bsky/tests/views/block-lists.test.ts +++ b/packages/bsky/tests/views/block-lists.test.ts @@ -1,8 +1,6 @@ import AtpAgent, { AtUri } from '@atproto/api' import { TestNetwork, SeedClient, RecordRef, basicSeed } from '@atproto/dev-env' import { forSnapshot } from '../_util' -import { BlockedActorError } from '@atproto/api/src/client/types/app/bsky/feed/getAuthorFeed' -import { BlockedByActorError } from '@atproto/api/src/client/types/app/bsky/feed/getAuthorFeed' describe('pds views with blocking from block lists', () => { let network: TestNetwork @@ -165,13 +163,17 @@ describe('pds views with blocking from block lists', () => { { actor: carol }, { headers: await network.serviceHeaders(dan) }, ) - await expect(attempt1).rejects.toThrow(BlockedActorError) + await expect(attempt1).rejects.toMatchObject({ + error: 'BlockedActor', + }) const attempt2 = agent.api.app.bsky.feed.getAuthorFeed( { actor: dan }, { headers: await network.serviceHeaders(carol) }, ) - await expect(attempt2).rejects.toThrow(BlockedByActorError) + await expect(attempt2).rejects.toMatchObject({ + error: 'BlockedByActor', + }) }) it('strips blocked users out of getTimeline', async () => { diff --git a/packages/bsky/tests/views/blocks.test.ts b/packages/bsky/tests/views/blocks.test.ts index ceff6f57392..8ff5d00a54a 100644 --- a/packages/bsky/tests/views/blocks.test.ts +++ b/packages/bsky/tests/views/blocks.test.ts @@ -1,14 +1,7 @@ import assert from 'assert' import { TestNetwork, RecordRef, SeedClient, basicSeed } from '@atproto/dev-env' import AtpAgent, { AtUri } from '@atproto/api' -import { BlockedActorError } from '@atproto/api/src/client/types/app/bsky/feed/getAuthorFeed' -import { BlockedByActorError } from '@atproto/api/src/client/types/app/bsky/feed/getAuthorFeed' -import { isThreadViewPost } from '@atproto/api/src/client/types/app/bsky/feed/defs' -import { - isViewRecord as isEmbedViewRecord, - isViewBlocked as isEmbedViewBlocked, -} from '@atproto/api/src/client/types/app/bsky/embed/record' -import { forSnapshot } from '../_util' +import { assertIsThreadViewPost, forSnapshot } from '../_util' describe('pds views with blocking', () => { let network: TestNetwork @@ -116,9 +109,9 @@ describe('pds views with blocking', () => { { depth: 1, uri: carolReplyToDan.ref.uriStr }, { headers: await network.serviceHeaders(alice) }, ) - if (!isThreadViewPost(thread.thread)) { - throw new Error('Expected thread view post') - } + + assertIsThreadViewPost(thread.thread) + expect(thread.thread.post.uri).toEqual(carolReplyToDan.ref.uriStr) expect(thread.thread.parent).toMatchObject({ $type: 'app.bsky.feed.defs#blockedPost', @@ -149,13 +142,17 @@ describe('pds views with blocking', () => { { actor: carol }, { headers: await network.serviceHeaders(dan) }, ) - await expect(attempt1).rejects.toThrow(BlockedActorError) + await expect(attempt1).rejects.toMatchObject({ + error: 'BlockedActor', + }) const attempt2 = agent.api.app.bsky.feed.getAuthorFeed( { actor: dan }, { headers: await network.serviceHeaders(carol) }, ) - await expect(attempt2).rejects.toThrow(BlockedByActorError) + await expect(attempt2).rejects.toMatchObject({ + error: 'BlockedByActor', + }) }) it('strips blocked users out of getTimeline', async () => { @@ -396,7 +393,8 @@ describe('pds views with blocking', () => { { depth: 1, uri: sc.posts[dan][0].ref.uriStr }, { headers: await network.serviceHeaders(alice) }, ) - assert(isThreadViewPost(replyThenBlock.thread)) + assertIsThreadViewPost(replyThenBlock.thread) + expect(replyThenBlock.thread.replies?.map(getThreadPostUri)).toEqual([ aliceReplyToDan.ref.uriStr, ]) @@ -411,10 +409,12 @@ describe('pds views with blocking', () => { { depth: 1, uri: sc.posts[dan][0].ref.uriStr }, { headers: await network.serviceHeaders(alice) }, ) - assert(isThreadViewPost(unblock.thread)) - expect(unblock.thread.replies?.map(getThreadPostUri).sort()).toEqual( - [aliceReplyToDan.ref.uriStr, carolReplyToDan.ref.uriStr].sort(), - ) + + assertIsThreadViewPost(unblock.thread) + expect(unblock.thread.replies?.map(getThreadPostUri)).toEqual([ + carolReplyToDan.ref.uriStr, + aliceReplyToDan.ref.uriStr, + ]) // block then reply danBlockCarol = await pdsAgent.api.app.bsky.graph.block.create( @@ -434,7 +434,9 @@ describe('pds views with blocking', () => { { depth: 1, uri: sc.posts[dan][0].ref.uriStr }, { headers: await network.serviceHeaders(alice) }, ) - assert(isThreadViewPost(blockThenReply.thread)) + + assertIsThreadViewPost(blockThenReply.thread) + expect(replyThenBlock.thread.replies?.map(getThreadPostUri)).toEqual([ aliceReplyToDan.ref.uriStr, ]) @@ -454,8 +456,12 @@ describe('pds views with blocking', () => { { depth: 0, uri: sc.posts[dan][1].ref.uriStr }, { headers: await network.serviceHeaders(alice) }, ) - assert(isThreadViewPost(embedThenBlock.thread)) - assert(isEmbedViewBlocked(embedThenBlock.thread.post.embed?.record)) + + assertIsThreadViewPost(embedThenBlock.thread) + + expect(embedThenBlock.thread.post.embed?.record).toMatchObject({ + $type: 'app.bsky.embed.record#viewBlocked', + }) // unblock await pdsAgent.api.app.bsky.graph.block.delete( @@ -467,8 +473,12 @@ describe('pds views with blocking', () => { { depth: 0, uri: sc.posts[dan][1].ref.uriStr }, { headers: await network.serviceHeaders(alice) }, ) - assert(isThreadViewPost(unblock.thread)) - assert(isEmbedViewRecord(unblock.thread.post.embed?.record)) + + assertIsThreadViewPost(unblock.thread) + + expect(unblock.thread.post?.embed?.record).toMatchObject({ + $type: 'app.bsky.embed.record#viewRecord', + }) // block then embed danBlockCarol = await pdsAgent.api.app.bsky.graph.block.create( @@ -489,8 +499,11 @@ describe('pds views with blocking', () => { { depth: 0, uri: carolEmbedsDan.ref.uriStr }, { headers: await network.serviceHeaders(alice) }, ) - assert(isThreadViewPost(blockThenEmbed.thread)) - assert(isEmbedViewBlocked(blockThenEmbed.thread.post.embed?.record)) + assertIsThreadViewPost(blockThenEmbed.thread) + + expect(blockThenEmbed.thread.post.embed?.record).toMatchObject({ + $type: 'app.bsky.embed.record#viewBlocked', + }) // cleanup await pdsAgent.api.app.bsky.feed.post.delete( @@ -517,7 +530,9 @@ describe('pds views with blocking', () => { (item) => item.post.uri === embedBlockedUri, ) assert(embedBlockedPost) - assert(isEmbedViewBlocked(embedBlockedPost.post.embed?.record)) + expect(embedBlockedPost.post.embed?.record).toMatchObject({ + $type: 'app.bsky.embed.record#viewBlocked', + }) }) it('returns a list of blocks', async () => { diff --git a/packages/bsky/tests/views/thread.test.ts b/packages/bsky/tests/views/thread.test.ts index c3496f7cf50..9dd63239893 100644 --- a/packages/bsky/tests/views/thread.test.ts +++ b/packages/bsky/tests/views/thread.test.ts @@ -1,8 +1,10 @@ import AtpAgent, { AppBskyFeedGetPostThread } from '@atproto/api' import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env' -import { forSnapshot, stripViewerFromThread } from '../_util' -import assert from 'assert' -import { isThreadViewPost } from '@atproto/api/src/client/types/app/bsky/feed/defs' +import { + assertIsThreadViewPost, + forSnapshot, + stripViewerFromThread, +} from '../_util' describe('pds thread views', () => { let network: TestNetwork @@ -164,12 +166,12 @@ describe('pds thread views', () => { { uri: goodReply1.ref.uriStr }, { headers: await network.serviceHeaders(alice) }, ) - assert(isThreadViewPost(goodReply1Thread.thread)) - assert(isThreadViewPost(goodReply1Thread.thread.parent)) + assertIsThreadViewPost(goodReply1Thread.thread) + assertIsThreadViewPost(goodReply1Thread.thread.parent) expect(goodReply1Thread.thread.parent.post.uri).toEqual(goodRoot.ref.uriStr) expect( goodReply1Thread.thread.replies?.map((r) => { - assert(isThreadViewPost(r)) + assertIsThreadViewPost(r) return r.post.uri }), ).toEqual([ @@ -182,7 +184,7 @@ describe('pds thread views', () => { { uri: badReply.ref.uriStr }, { headers: await network.serviceHeaders(alice) }, ) - assert(isThreadViewPost(badReplyThread.thread)) + assertIsThreadViewPost(badReplyThread.thread) expect(badReplyThread.thread.parent).toBeUndefined() // is not goodReply1 }) @@ -192,7 +194,8 @@ describe('pds thread views', () => { { headers: await network.serviceHeaders(bob) }, ) - assert(isThreadViewPost(thread.thread), 'post does not exist') + assertIsThreadViewPost(thread.thread) + const post = thread.thread.post const postSelfLabels = post.labels diff --git a/packages/bsky/tsconfig.build.json b/packages/bsky/tsconfig.build.json index 02a84823b65..944827a6f62 100644 --- a/packages/bsky/tsconfig.build.json +++ b/packages/bsky/tsconfig.build.json @@ -1,4 +1,9 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/node.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "noUnusedLocals": false + }, + "include": ["./src"] } diff --git a/packages/bsky/tsconfig.json b/packages/bsky/tsconfig.json index 45283e8f73b..1f3ab3c0ec4 100644 --- a/packages/bsky/tsconfig.json +++ b/packages/bsky/tsconfig.json @@ -1,20 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", - "emitDeclarationOnly": true - }, - "module": "nodenext", - "include": ["./src", "__tests__/**/**.ts"], + "include": [], "references": [ - { "path": "../api/tsconfig.build.json" }, - { "path": "../common/tsconfig.build.json" }, - { "path": "../crypto/tsconfig.build.json" }, - { "path": "../lexicon/tsconfig.build.json" }, - { "path": "../lex-cli/tsconfig.build.json" }, - { "path": "../repo/tsconfig.build.json" }, - { "path": "../syntax/tsconfig.build.json" }, - { "path": "../xrpc-server/tsconfig.build.json" } + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } ] } diff --git a/packages/bsky/tsconfig.tests.json b/packages/bsky/tsconfig.tests.json new file mode 100644 index 00000000000..7fac0ed90d5 --- /dev/null +++ b/packages/bsky/tsconfig.tests.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": ".", + "noUnusedLocals": false + }, + "include": ["./tests"] +} diff --git a/packages/bsync/babel.config.js b/packages/bsync/babel.config.js deleted file mode 100644 index ee58f35df11..00000000000 --- a/packages/bsync/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [['@babel/preset-env']], -} diff --git a/packages/bsync/build.js b/packages/bsync/build.js deleted file mode 100644 index 25452318508..00000000000 --- a/packages/bsync/build.js +++ /dev/null @@ -1,18 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - external: [ - // Referenced in pg driver, but optional and we don't use it - 'pg-native', - ], - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/bsync/jest.config.js b/packages/bsync/jest.config.js index 9abb11c632d..4ac7794c9ed 100644 --- a/packages/bsync/jest.config.js +++ b/packages/bsync/jest.config.js @@ -1,6 +1,6 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'Bsync', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/bsync/package.json b/packages/bsync/package.json index 9c963b97682..354ec32e2b2 100644 --- a/packages/bsync/package.json +++ b/packages/bsync/package.json @@ -13,15 +13,10 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/bsync" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/bsync", + "build": "tsc --build tsconfig.build.json", "start": "node --enable-source-maps dist/bin.js", "test": "../dev-infra/with-test-db.sh jest", "test:log": "tail -50 test.log | pino-pretty", @@ -45,6 +40,8 @@ "@bufbuild/buf": "^1.28.1", "@bufbuild/protoc-gen-es": "^1.5.0", "@connectrpc/protoc-gen-connect-es": "^1.1.4", - "@types/pg": "^8.6.6" + "@types/pg": "^8.6.6", + "jest": "^28.1.2", + "ts-node": "^10.8.2" } } diff --git a/packages/bsync/src/context.ts b/packages/bsync/src/context.ts index ff6e25bd08b..daabe2b046c 100644 --- a/packages/bsync/src/context.ts +++ b/packages/bsync/src/context.ts @@ -7,21 +7,25 @@ import { EventEmitter } from 'stream' export type AppContextOptions = { db: Database cfg: ServerConfig + shutdown: AbortSignal } export class AppContext { db: Database cfg: ServerConfig + shutdown: AbortSignal events: TypedEventEmitter constructor(opts: AppContextOptions) { this.db = opts.db this.cfg = opts.cfg + this.shutdown = opts.shutdown this.events = new EventEmitter() as TypedEventEmitter } static async fromConfig( cfg: ServerConfig, + shutdown: AbortSignal, overrides?: Partial, ): Promise { const db = new Database({ @@ -31,7 +35,7 @@ export class AppContext { poolMaxUses: cfg.db.poolMaxUses, poolIdleTimeoutMs: cfg.db.poolIdleTimeoutMs, }) - return new AppContext({ db, cfg, ...overrides }) + return new AppContext({ db, cfg, shutdown, ...overrides }) } } diff --git a/packages/bsync/src/db/index.ts b/packages/bsync/src/db/index.ts index 7922c421bf5..6fa14f365dd 100644 --- a/packages/bsync/src/db/index.ts +++ b/packages/bsync/src/db/index.ts @@ -34,41 +34,43 @@ export class Database { if (instances) { this.db = instances.db this.pool = instances.pool - return - } + } else { + // else create a pool & connect + const { schema, url } = opts + const pool = + opts.pool ?? + new PgPool({ + connectionString: url, + max: opts.poolSize, + maxUses: opts.poolMaxUses, + idleTimeoutMillis: opts.poolIdleTimeoutMs, + }) - // else create a pool & connect - const { schema, url } = opts - const pool = - opts.pool ?? - new PgPool({ - connectionString: url, - max: opts.poolSize, - maxUses: opts.poolMaxUses, - idleTimeoutMillis: opts.poolIdleTimeoutMs, - }) + // Select count(*) and other pg bigints as js integer + pgTypes.setTypeParser(pgTypes.builtins.INT8, (n) => parseInt(n, 10)) - // Select count(*) and other pg bigints as js integer - pgTypes.setTypeParser(pgTypes.builtins.INT8, (n) => parseInt(n, 10)) + // Setup schema usage, primarily for test parallelism (each test suite runs in its own pg schema) + if (schema && !/^[a-z_]+$/i.test(schema)) { + throw new Error( + `Postgres schema must only contain [A-Za-z_]: ${schema}`, + ) + } - // Setup schema usage, primarily for test parallelism (each test suite runs in its own pg schema) - if (schema && !/^[a-z_]+$/i.test(schema)) { - throw new Error(`Postgres schema must only contain [A-Za-z_]: ${schema}`) - } + pool.on('error', onPoolError) + pool.on('connect', (client) => { + client.on('error', onClientError) + if (schema) { + // Shared objects such as extensions will go in the public schema + client.query(`SET search_path TO "${schema}",public;`) + } + }) - pool.on('error', onPoolError) - pool.on('connect', (client) => { - client.on('error', onClientError) - if (schema) { - // Shared objects such as extensions will go in the public schema - client.query(`SET search_path TO "${schema}",public;`) - } - }) + this.pool = pool + this.db = new Kysely({ + dialect: new PostgresDialect({ pool }), + }) + } - this.pool = pool - this.db = new Kysely({ - dialect: new PostgresDialect({ pool }), - }) this.migrator = new Migrator({ db: this.db, migrationTableSchema: opts.schema, @@ -165,7 +167,7 @@ const onClientError = (err: Error) => dbLogger.error({ err }, 'db client error') // ------- class LeakyTxPlugin implements KyselyPlugin { - private txOver: boolean + private txOver = false endTx() { this.txOver = true diff --git a/packages/bsync/src/index.ts b/packages/bsync/src/index.ts index cc984d9b35e..9dc5b0c084d 100644 --- a/packages/bsync/src/index.ts +++ b/packages/bsync/src/index.ts @@ -19,7 +19,7 @@ export class BsyncService { public server: http.Server private ac: AbortController private terminator: HttpTerminator - private dbStatsInterval: NodeJS.Timer + private dbStatsInterval?: NodeJS.Timeout constructor(opts: { ctx: AppContext @@ -36,8 +36,8 @@ export class BsyncService { cfg: ServerConfig, overrides?: Partial, ): Promise { - const ctx = await AppContext.fromConfig(cfg, overrides) const ac = new AbortController() + const ctx = await AppContext.fromConfig(cfg, ac.signal, overrides) const handler = connectNodeAdapter({ routes: routes(ctx), shutdownSignal: ac.signal, @@ -55,6 +55,9 @@ export class BsyncService { } async start(): Promise { + if (this.dbStatsInterval) { + throw new Error(`${this.constructor.name} already started`) + } this.dbStatsInterval = setInterval(() => { dbLogger.info( { @@ -77,6 +80,7 @@ export class BsyncService { await this.terminator.terminate() await this.ctx.db.close() clearInterval(this.dbStatsInterval) + this.dbStatsInterval = undefined } async setupAppEvents() { diff --git a/packages/bsync/src/proto/bsync_connect.ts b/packages/bsync/src/proto/bsync_connect.ts index 94a37266bfd..908f68f7dd5 100644 --- a/packages/bsync/src/proto/bsync_connect.ts +++ b/packages/bsync/src/proto/bsync_connect.ts @@ -10,7 +10,7 @@ import { PingResponse, ScanMuteOperationsRequest, ScanMuteOperationsResponse, -} from './bsync_pb.ts' +} from './bsync_pb' import { MethodKind } from '@bufbuild/protobuf' /** diff --git a/packages/bsync/src/routes/scan-mute-operations.ts b/packages/bsync/src/routes/scan-mute-operations.ts index 671632531b0..ef9e2f5510a 100644 --- a/packages/bsync/src/routes/scan-mute-operations.ts +++ b/packages/bsync/src/routes/scan-mute-operations.ts @@ -13,7 +13,10 @@ export default (ctx: AppContext): Partial> => ({ const limit = req.limit || 1000 const cursor = validCursor(req.cursor) const nextMuteOpPromise = once(events, createMuteOpChannel, { - signal: AbortSignal.timeout(ctx.cfg.service.longPollTimeoutMs), + signal: combineSignals( + ctx.shutdown, + AbortSignal.timeout(ctx.cfg.service.longPollTimeoutMs), + ), }) nextMuteOpPromise.catch(() => null) // ensure timeout is always handled @@ -31,6 +34,7 @@ export default (ctx: AppContext): Partial> => ({ try { await nextMuteOpPromise } catch (err) { + ctx.shutdown.throwIfAborted() return new ScanMuteOperationsResponse({ operations: [], cursor: req.cursor, @@ -67,3 +71,18 @@ const validCursor = (cursor: string): number | null => { } return int } + +const combineSignals = (a: AbortSignal, b: AbortSignal) => { + const controller = new AbortController() + for (const signal of [a, b]) { + if (signal.aborted) { + controller.abort() + return signal + } + signal.addEventListener('abort', () => controller.abort(signal.reason), { + // @ts-ignore https://github.com/DefinitelyTyped/DefinitelyTyped/pull/68625 + signal: controller.signal, + }) + } + return controller.signal +} diff --git a/packages/bsync/tsconfig.build.json b/packages/bsync/tsconfig.build.json index 02a84823b65..fafdab3d6f7 100644 --- a/packages/bsync/tsconfig.build.json +++ b/packages/bsync/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/node.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/bsync/tsconfig.json b/packages/bsync/tsconfig.json index 7e6792f9590..1f3ab3c0ec4 100644 --- a/packages/bsync/tsconfig.json +++ b/packages/bsync/tsconfig.json @@ -1,14 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", - "emitDeclarationOnly": true - }, - "module": "nodenext", - "include": ["./src", "__tests__/**/**.ts"], + "include": [], "references": [ - { "path": "../common/tsconfig.build.json" }, - { "path": "../common-web/tsconfig.build.json" } + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } ] } diff --git a/packages/bsync/tsconfig.tests.json b/packages/bsync/tsconfig.tests.json new file mode 100644 index 00000000000..c192c436e23 --- /dev/null +++ b/packages/bsync/tsconfig.tests.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./tests"] +} diff --git a/packages/common-web/babel.config.js b/packages/common-web/babel.config.js deleted file mode 100644 index 0126e9dbaa6..00000000000 --- a/packages/common-web/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config.js') diff --git a/packages/common-web/build.js b/packages/common-web/build.js deleted file mode 100644 index 30fbe7cea56..00000000000 --- a/packages/common-web/build.js +++ /dev/null @@ -1,15 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'browser', - format: 'cjs', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/common-web/jest.config.js b/packages/common-web/jest.config.js index 6beabf62b60..85f61f37aac 100644 --- a/packages/common-web/jest.config.js +++ b/packages/common-web/jest.config.js @@ -1,6 +1,6 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'Common Web', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/common-web/package.json b/packages/common-web/package.json index 94d0372e1d8..9fc50fa67cd 100644 --- a/packages/common-web/package.json +++ b/packages/common-web/package.json @@ -12,21 +12,19 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/common-web" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "test": "jest", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/common-web" + "build": "tsc --build tsconfig.build.json" }, "dependencies": { "graphemer": "^1.4.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.21.4" + }, + "devDependencies": { + "jest": "^28.1.2" } } diff --git a/packages/common-web/tsconfig.build.json b/packages/common-web/tsconfig.build.json index 02a84823b65..436d8ecb628 100644 --- a/packages/common-web/tsconfig.build.json +++ b/packages/common-web/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/isomorphic.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/common-web/tsconfig.json b/packages/common-web/tsconfig.json index 5c5ec40ce03..1f3ab3c0ec4 100644 --- a/packages/common-web/tsconfig.json +++ b/packages/common-web/tsconfig.json @@ -1,9 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src", "__tests__/**/**.ts"] + "include": [], + "references": [ + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } + ] } diff --git a/packages/common-web/tsconfig.tests.json b/packages/common-web/tsconfig.tests.json new file mode 100644 index 00000000000..c192c436e23 --- /dev/null +++ b/packages/common-web/tsconfig.tests.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./tests"] +} diff --git a/packages/common/babel.config.js b/packages/common/babel.config.js deleted file mode 100644 index 0126e9dbaa6..00000000000 --- a/packages/common/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config.js') diff --git a/packages/common/build.js b/packages/common/build.js deleted file mode 100644 index e880ae9930b..00000000000 --- a/packages/common/build.js +++ /dev/null @@ -1,14 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/common/jest.config.js b/packages/common/jest.config.js index 33f1da33d80..18e79db079e 100644 --- a/packages/common/jest.config.js +++ b/packages/common/jest.config.js @@ -1,6 +1,6 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'Common', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/common/package.json b/packages/common/package.json index c979cae8f18..0626d40f6fe 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -12,16 +12,11 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/common" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "test": "jest", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/common" + "build": "tsc --build tsconfig.build.json" }, "dependencies": { "@atproto/common-web": "workspace:^", @@ -30,5 +25,10 @@ "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.15.0" + }, + "devDependencies": { + "jest": "^28.1.2", + "typescript": "^5.3.3", + "uint8arrays": "3.0.0" } } diff --git a/packages/common/src/streams.ts b/packages/common/src/streams.ts index 2d18c3e2400..691ad3ff08c 100644 --- a/packages/common/src/streams.ts +++ b/packages/common/src/streams.ts @@ -59,8 +59,9 @@ export class MaxSizeChecker extends Transform { _transform(chunk: Uint8Array, _enc: BufferEncoding, cb: TransformCallback) { this.totalSize += chunk.length if (this.totalSize > this.maxSize) { - return this.destroy(this.createError()) + cb(this.createError()) + } else { + cb(null, chunk) } - return cb(null, chunk) } } diff --git a/packages/common/tsconfig.build.json b/packages/common/tsconfig.build.json index 02a84823b65..fafdab3d6f7 100644 --- a/packages/common/tsconfig.build.json +++ b/packages/common/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/node.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/common/tsconfig.json b/packages/common/tsconfig.json index 81714d5ec97..1f3ab3c0ec4 100644 --- a/packages/common/tsconfig.json +++ b/packages/common/tsconfig.json @@ -1,10 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src", "__tests__/**/**.ts"], - "references": [{ "path": "../common-web/tsconfig.build.json" }] + "include": [], + "references": [ + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } + ] } diff --git a/packages/common/tsconfig.tests.json b/packages/common/tsconfig.tests.json new file mode 100644 index 00000000000..c192c436e23 --- /dev/null +++ b/packages/common/tsconfig.tests.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./tests"] +} diff --git a/packages/crypto/build.js b/packages/crypto/build.js deleted file mode 100644 index e880ae9930b..00000000000 --- a/packages/crypto/build.js +++ /dev/null @@ -1,14 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/crypto/jest.config.js b/packages/crypto/jest.config.js index 365131c9293..d5f37b722f9 100644 --- a/packages/crypto/jest.config.js +++ b/packages/crypto/jest.config.js @@ -1,6 +1,6 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'Crypto', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/crypto/package.json b/packages/crypto/package.json index bb359c5f36f..16db0cc1046 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -13,16 +13,11 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/crypto" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "test": "jest ", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/crypto" + "build": "tsc --build tsconfig.build.json" }, "dependencies": { "@noble/curves": "^1.1.0", @@ -30,6 +25,7 @@ "uint8arrays": "3.0.0" }, "devDependencies": { - "@atproto/common": "workspace:^" + "@atproto/common": "workspace:^", + "jest": "^28.1.2" } } diff --git a/packages/crypto/src/did.ts b/packages/crypto/src/did.ts index 7ced78a394d..a8e4f03a7c1 100644 --- a/packages/crypto/src/did.ts +++ b/packages/crypto/src/did.ts @@ -1,13 +1,8 @@ import * as uint8arrays from 'uint8arrays' -import * as p256 from './p256/encoding' -import * as secp from './secp256k1/encoding' + +import { BASE58_MULTIBASE_PREFIX, DID_KEY_PREFIX } from './const' import plugins from './plugins' -import { - BASE58_MULTIBASE_PREFIX, - DID_KEY_PREFIX, - P256_JWT_ALG, - SECP256K1_JWT_ALG, -} from './const' +import { extractMultikey, extractPrefixedBytes, hasPrefix } from './utils' export type ParsedMultikey = { jwtAlg: string @@ -15,23 +10,14 @@ export type ParsedMultikey = { } export const parseMultikey = (multikey: string): ParsedMultikey => { - if (!multikey.startsWith(BASE58_MULTIBASE_PREFIX)) { - throw new Error(`Incorrect prefix for multikey: ${multikey}`) - } - const prefixedBytes = uint8arrays.fromString( - multikey.slice(BASE58_MULTIBASE_PREFIX.length), - 'base58btc', - ) + const prefixedBytes = extractPrefixedBytes(multikey) const plugin = plugins.find((p) => hasPrefix(prefixedBytes, p.prefix)) if (!plugin) { throw new Error('Unsupported key type') } - let keyBytes = prefixedBytes.slice(plugin.prefix.length) - if (plugin.jwtAlg === P256_JWT_ALG) { - keyBytes = p256.decompressPubkey(keyBytes) - } else if (plugin.jwtAlg === SECP256K1_JWT_ALG) { - keyBytes = secp.decompressPubkey(keyBytes) - } + const keyBytes = plugin.decompressPubkey( + prefixedBytes.slice(plugin.prefix.length), + ) return { jwtAlg: plugin.jwtAlg, keyBytes, @@ -46,28 +32,20 @@ export const formatMultikey = ( if (!plugin) { throw new Error('Unsupported key type') } - if (jwtAlg === P256_JWT_ALG) { - keyBytes = p256.compressPubkey(keyBytes) - } else if (jwtAlg === SECP256K1_JWT_ALG) { - keyBytes = secp.compressPubkey(keyBytes) - } - const prefixedBytes = uint8arrays.concat([plugin.prefix, keyBytes]) + const prefixedBytes = uint8arrays.concat([ + plugin.prefix, + plugin.compressPubkey(keyBytes), + ]) return ( BASE58_MULTIBASE_PREFIX + uint8arrays.toString(prefixedBytes, 'base58btc') ) } export const parseDidKey = (did: string): ParsedMultikey => { - if (!did.startsWith(DID_KEY_PREFIX)) { - throw new Error(`Incorrect prefix for did:key: ${did}`) - } - return parseMultikey(did.slice(DID_KEY_PREFIX.length)) + const multikey = extractMultikey(did) + return parseMultikey(multikey) } export const formatDidKey = (jwtAlg: string, keyBytes: Uint8Array): string => { return DID_KEY_PREFIX + formatMultikey(jwtAlg, keyBytes) } - -const hasPrefix = (bytes: Uint8Array, prefix: Uint8Array): boolean => { - return uint8arrays.equals(prefix, bytes.subarray(0, prefix.byteLength)) -} diff --git a/packages/crypto/src/p256/keypair.ts b/packages/crypto/src/p256/keypair.ts index 515d9a89ed7..a858fd77093 100644 --- a/packages/crypto/src/p256/keypair.ts +++ b/packages/crypto/src/p256/keypair.ts @@ -1,7 +1,11 @@ import { p256 } from '@noble/curves/p256' import { sha256 } from '@noble/hashes/sha256' -import * as uint8arrays from 'uint8arrays' -import { SupportedEncodings } from 'uint8arrays/util/bases' +import { SupportedEncodings } from 'uint8arrays/to-string' +import { + fromString as ui8FromString, + toString as ui8ToString, +} from 'uint8arrays' + import * as did from '../did' import { P256_JWT_ALG } from '../const' import { Keypair } from '../types' @@ -32,9 +36,7 @@ export class P256Keypair implements Keypair { ): Promise { const { exportable = false } = opts || {} const privKeyBytes = - typeof privKey === 'string' - ? uint8arrays.fromString(privKey, 'hex') - : privKey + typeof privKey === 'string' ? ui8FromString(privKey, 'hex') : privKey return new P256Keypair(privKeyBytes, exportable) } @@ -43,7 +45,7 @@ export class P256Keypair implements Keypair { } publicKeyStr(encoding: SupportedEncodings = 'base64pad'): string { - return uint8arrays.toString(this.publicKey, encoding) + return ui8ToString(this.publicKey, encoding) } did(): string { diff --git a/packages/crypto/src/p256/operations.ts b/packages/crypto/src/p256/operations.ts index e41c494ae55..7422c282281 100644 --- a/packages/crypto/src/p256/operations.ts +++ b/packages/crypto/src/p256/operations.ts @@ -1,9 +1,10 @@ import { p256 } from '@noble/curves/p256' import { sha256 } from '@noble/hashes/sha256' -import * as ui8 from 'uint8arrays' -import { P256_JWT_ALG } from '../const' -import { parseDidKey } from '../did' +import { equals as ui8equals } from 'uint8arrays' + +import { P256_DID_PREFIX } from '../const' import { VerifyOptions } from '../types' +import { extractMultikey, extractPrefixedBytes, hasPrefix } from '../utils' export const verifyDidSig = async ( did: string, @@ -11,10 +12,11 @@ export const verifyDidSig = async ( sig: Uint8Array, opts?: VerifyOptions, ): Promise => { - const { jwtAlg, keyBytes } = parseDidKey(did) - if (jwtAlg !== P256_JWT_ALG) { + const prefixedBytes = extractPrefixedBytes(extractMultikey(did)) + if (!hasPrefix(prefixedBytes, P256_DID_PREFIX)) { throw new Error(`Not a P-256 did:key: ${did}`) } + const keyBytes = prefixedBytes.slice(P256_DID_PREFIX.length) return verifySig(keyBytes, data, sig, opts) } @@ -39,7 +41,7 @@ export const verifySig = async ( export const isCompactFormat = (sig: Uint8Array) => { try { const parsed = p256.Signature.fromCompact(sig) - return ui8.equals(parsed.toCompactRawBytes(), sig) + return ui8equals(parsed.toCompactRawBytes(), sig) } catch { return false } diff --git a/packages/crypto/src/p256/plugin.ts b/packages/crypto/src/p256/plugin.ts index d2c304d0fde..4fcbafc00ca 100644 --- a/packages/crypto/src/p256/plugin.ts +++ b/packages/crypto/src/p256/plugin.ts @@ -1,11 +1,16 @@ -import * as operations from './operations' +import { verifyDidSig } from './operations' +import { compressPubkey, decompressPubkey } from './encoding' + import { DidKeyPlugin } from '../types' import { P256_DID_PREFIX, P256_JWT_ALG } from '../const' export const p256Plugin: DidKeyPlugin = { prefix: P256_DID_PREFIX, jwtAlg: P256_JWT_ALG, - verifySignature: operations.verifyDidSig, + verifySignature: verifyDidSig, + + compressPubkey, + decompressPubkey, } export default p256Plugin diff --git a/packages/crypto/src/secp256k1/keypair.ts b/packages/crypto/src/secp256k1/keypair.ts index e5d4ad0dcc6..4391e01add9 100644 --- a/packages/crypto/src/secp256k1/keypair.ts +++ b/packages/crypto/src/secp256k1/keypair.ts @@ -1,9 +1,13 @@ import { secp256k1 as k256 } from '@noble/curves/secp256k1' import { sha256 } from '@noble/hashes/sha256' -import * as uint8arrays from 'uint8arrays' -import { SupportedEncodings } from 'uint8arrays/util/bases' -import * as did from '../did' +import { + fromString as ui8FromString, + toString as ui8ToString, +} from 'uint8arrays' +import { SupportedEncodings } from 'uint8arrays/to-string' + import { SECP256K1_JWT_ALG } from '../const' +import * as did from '../did' import { Keypair } from '../types' export type Secp256k1KeypairOptions = { @@ -32,9 +36,7 @@ export class Secp256k1Keypair implements Keypair { ): Promise { const { exportable = false } = opts || {} const privKeyBytes = - typeof privKey === 'string' - ? uint8arrays.fromString(privKey, 'hex') - : privKey + typeof privKey === 'string' ? ui8FromString(privKey, 'hex') : privKey return new Secp256k1Keypair(privKeyBytes, exportable) } @@ -43,7 +45,7 @@ export class Secp256k1Keypair implements Keypair { } publicKeyStr(encoding: SupportedEncodings = 'base64pad'): string { - return uint8arrays.toString(this.publicKey, encoding) + return ui8ToString(this.publicKey, encoding) } did(): string { diff --git a/packages/crypto/src/secp256k1/operations.ts b/packages/crypto/src/secp256k1/operations.ts index bc2415feb47..9214f63014a 100644 --- a/packages/crypto/src/secp256k1/operations.ts +++ b/packages/crypto/src/secp256k1/operations.ts @@ -1,9 +1,10 @@ import { secp256k1 as k256 } from '@noble/curves/secp256k1' import { sha256 } from '@noble/hashes/sha256' import * as ui8 from 'uint8arrays' -import { SECP256K1_JWT_ALG } from '../const' -import { parseDidKey } from '../did' + +import { SECP256K1_DID_PREFIX } from '../const' import { VerifyOptions } from '../types' +import { extractMultikey, extractPrefixedBytes, hasPrefix } from '../utils' export const verifyDidSig = async ( did: string, @@ -11,10 +12,11 @@ export const verifyDidSig = async ( sig: Uint8Array, opts?: VerifyOptions, ): Promise => { - const { jwtAlg, keyBytes } = parseDidKey(did) - if (jwtAlg !== SECP256K1_JWT_ALG) { + const prefixedBytes = extractPrefixedBytes(extractMultikey(did)) + if (!hasPrefix(prefixedBytes, SECP256K1_DID_PREFIX)) { throw new Error(`Not a secp256k1 did:key: ${did}`) } + const keyBytes = prefixedBytes.slice(SECP256K1_DID_PREFIX.length) return verifySig(keyBytes, data, sig, opts) } diff --git a/packages/crypto/src/secp256k1/plugin.ts b/packages/crypto/src/secp256k1/plugin.ts index 5184a3778fa..1e8c622b752 100644 --- a/packages/crypto/src/secp256k1/plugin.ts +++ b/packages/crypto/src/secp256k1/plugin.ts @@ -1,11 +1,16 @@ -import * as operations from './operations' +import { verifyDidSig } from './operations' +import { compressPubkey, decompressPubkey } from './encoding' + import { DidKeyPlugin } from '../types' import { SECP256K1_DID_PREFIX, SECP256K1_JWT_ALG } from '../const' export const secp256k1Plugin: DidKeyPlugin = { prefix: SECP256K1_DID_PREFIX, jwtAlg: SECP256K1_JWT_ALG, - verifySignature: operations.verifyDidSig, + verifySignature: verifyDidSig, + + compressPubkey, + decompressPubkey, } export default secp256k1Plugin diff --git a/packages/crypto/src/types.ts b/packages/crypto/src/types.ts index b664b6d4d30..c6f87b99bd3 100644 --- a/packages/crypto/src/types.ts +++ b/packages/crypto/src/types.ts @@ -22,6 +22,9 @@ export type DidKeyPlugin = { data: Uint8Array, opts?: VerifyOptions, ) => Promise + + compressPubkey: (uncompressed: Uint8Array) => Uint8Array + decompressPubkey: (compressed: Uint8Array) => Uint8Array } export type VerifyOptions = { diff --git a/packages/crypto/src/utils.ts b/packages/crypto/src/utils.ts new file mode 100644 index 00000000000..a2875758039 --- /dev/null +++ b/packages/crypto/src/utils.ts @@ -0,0 +1,23 @@ +import * as uint8arrays from 'uint8arrays' +import { BASE58_MULTIBASE_PREFIX, DID_KEY_PREFIX } from './const' + +export const extractMultikey = (did: string): string => { + if (!did.startsWith(DID_KEY_PREFIX)) { + throw new Error(`Incorrect prefix for did:key: ${did}`) + } + return did.slice(DID_KEY_PREFIX.length) +} + +export const extractPrefixedBytes = (multikey: string): Uint8Array => { + if (!multikey.startsWith(BASE58_MULTIBASE_PREFIX)) { + throw new Error(`Incorrect prefix for multikey: ${multikey}`) + } + return uint8arrays.fromString( + multikey.slice(BASE58_MULTIBASE_PREFIX.length), + 'base58btc', + ) +} + +export const hasPrefix = (bytes: Uint8Array, prefix: Uint8Array): boolean => { + return uint8arrays.equals(prefix, bytes.subarray(0, prefix.byteLength)) +} diff --git a/packages/crypto/tests/signatures.test.ts b/packages/crypto/tests/signatures.test.ts index f495e304696..a849e1c5ec0 100644 --- a/packages/crypto/tests/signatures.test.ts +++ b/packages/crypto/tests/signatures.test.ts @@ -137,6 +137,7 @@ describe('signatures', () => { }) }) +// @ts-expect-error // eslint-disable-next-line @typescript-eslint/no-unused-vars async function generateTestVectors(): Promise { const p256Key = await EcdsaKeypair.create({ exportable: true }) diff --git a/packages/crypto/tsconfig.build.json b/packages/crypto/tsconfig.build.json index 02a84823b65..436d8ecb628 100644 --- a/packages/crypto/tsconfig.build.json +++ b/packages/crypto/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/isomorphic.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/crypto/tsconfig.json b/packages/crypto/tsconfig.json index 5c5ec40ce03..1f3ab3c0ec4 100644 --- a/packages/crypto/tsconfig.json +++ b/packages/crypto/tsconfig.json @@ -1,9 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src", "__tests__/**/**.ts"] + "include": [], + "references": [ + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } + ] } diff --git a/packages/crypto/tsconfig.tests.json b/packages/crypto/tsconfig.tests.json new file mode 100644 index 00000000000..c192c436e23 --- /dev/null +++ b/packages/crypto/tsconfig.tests.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./tests"] +} diff --git a/packages/dev-env/build.js b/packages/dev-env/build.js deleted file mode 100644 index 65ca7679909..00000000000 --- a/packages/dev-env/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') -const hbsPlugin = require('esbuild-plugin-handlebars') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts', 'src/bin.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - external: [ - 'better-sqlite3', - // Referenced in pg driver, but optional and we don't use it - 'pg-native', - 'sharp', - ], - plugins: [].concat(buildShallow ? [nodeExternalsPlugin()] : []).concat([ - hbsPlugin({ - filter: /\.(hbs)$/, - additionalHelpers: {}, - precompileOptions: {}, - }), - ]), -}) diff --git a/packages/dev-env/package.json b/packages/dev-env/package.json index 8db1f828795..22515f07874 100644 --- a/packages/dev-env/package.json +++ b/packages/dev-env/package.json @@ -12,16 +12,11 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/dev-env" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "bin": "dist/bin.js", "scripts": { - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/dev-env", + "build": "tsc --build tsconfig.build.json", "start": "../dev-infra/with-test-redis-and-db.sh node dist/bin.js" }, "dependencies": { @@ -39,15 +34,10 @@ "@did-plc/lib": "^0.0.1", "@did-plc/server": "^0.0.1", "axios": "^0.27.2", - "better-sqlite3": "^9.4.0", "dotenv": "^16.0.3", "express": "^4.18.2", "get-port": "^6.1.2", "multiformats": "^9.9.0", - "sharp": "^0.32.6", "uint8arrays": "3.0.0" - }, - "devDependencies": { - "ts-node": "^10.8.1" } } diff --git a/packages/dev-env/src/bsky.ts b/packages/dev-env/src/bsky.ts index d0019865e77..2425d9b1efe 100644 --- a/packages/dev-env/src/bsky.ts +++ b/packages/dev-env/src/bsky.ts @@ -3,10 +3,12 @@ import * as ui8 from 'uint8arrays' import * as bsky from '@atproto/bsky' import { AtpAgent } from '@atproto/api' import { Secp256k1Keypair } from '@atproto/crypto' +import { BackgroundQueue } from '@atproto/bsky' import { Client as PlcClient } from '@did-plc/lib' import { BskyConfig } from './types' import { ADMIN_PASSWORD, EXAMPLE_LABELER } from './const' -import { BackgroundQueue } from '@atproto/bsky/src/data-plane/server/background' + +export * from '@atproto/bsky' export class TestBsky { constructor( diff --git a/packages/dev-env/src/feed-gen.ts b/packages/dev-env/src/feed-gen.ts index e8e58d742ce..cd2ffd93c07 100644 --- a/packages/dev-env/src/feed-gen.ts +++ b/packages/dev-env/src/feed-gen.ts @@ -1,12 +1,11 @@ -import http from 'http' +import { Secp256k1Keypair } from '@atproto/crypto' +import { SkeletonHandler, createLexiconServer } from '@atproto/pds' +import { InvalidRequestError } from '@atproto/xrpc-server' +import * as plc from '@did-plc/lib' import events from 'events' import express from 'express' import getPort from 'get-port' -import * as plc from '@did-plc/lib' -import { Secp256k1Keypair } from '@atproto/crypto' -import { Handler as SkeletonHandler } from '@atproto/pds/src/lexicon/types/app/bsky/feed/getFeedSkeleton' -import { createServer } from '@atproto/pds/src/lexicon' -import { InvalidRequestError } from '@atproto/xrpc-server' +import http from 'http' export class TestFeedGen { destroyed = false @@ -24,7 +23,7 @@ export class TestFeedGen { const port = await getPort() const did = await createFgDid(plcUrl, port) const app = express() - const lexServer = createServer() + const lexServer = createLexiconServer() lexServer.app.bsky.feed.getFeedSkeleton(async (args) => { const handler = feeds[args.params.feed] diff --git a/packages/dev-env/src/index.ts b/packages/dev-env/src/index.ts index 4f81340a5d3..5ddb61711e0 100644 --- a/packages/dev-env/src/index.ts +++ b/packages/dev-env/src/index.ts @@ -2,6 +2,7 @@ export * from './bsky' export * from './bsync' export * from './network' export * from './network-no-appview' +export * from './ozone' export * from './pds' export * from './plc' export * from './ozone' diff --git a/packages/dev-env/src/mock/index.ts b/packages/dev-env/src/mock/index.ts index be0efc138f9..dbbd9915339 100644 --- a/packages/dev-env/src/mock/index.ts +++ b/packages/dev-env/src/mock/index.ts @@ -1,10 +1,6 @@ import { AtUri } from '@atproto/syntax' -import AtpAgent from '@atproto/api' +import AtpAgent, { COM_ATPROTO_MODERATION } from '@atproto/api' import { Database } from '@atproto/bsky' -import { - REASONSPAM, - REASONOTHER, -} from '@atproto/api/src/client/types/com/atproto/moderation/defs' import { EXAMPLE_LABELER, TestNetwork } from '../index' import { postTexts, replyTexts } from './data' import labeledImgB64 from './img/labeled-img-b64' @@ -15,13 +11,12 @@ import blurHashB64 from './img/blur-hash-avatar-b64' // we use this to ensure the mock dataset is always the same // which is very useful when testing // (not everything is currently deterministic but it could be) -function* dateGen() { +function* dateGen(): Generator { let start = 1657846031914 while (true) { yield new Date(start).toISOString() start += 1e3 } - return '' } export async function generateMockSetup(env: TestNetwork) { @@ -119,7 +114,10 @@ export async function generateMockSetup(env: TestNetwork) { // Report one user const reporter = picka(users) await reporter.agent.api.com.atproto.moderation.createReport({ - reasonType: picka([REASONSPAM, REASONOTHER]), + reasonType: picka([ + COM_ATPROTO_MODERATION.DefsReasonSpam, + COM_ATPROTO_MODERATION.DefsReasonOther, + ]), reason: picka(["Didn't look right to me", undefined, undefined]), subject: { $type: 'com.atproto.admin.defs#repoRef', @@ -169,7 +167,10 @@ export async function generateMockSetup(env: TestNetwork) { if (rand(6) === 0) { const reporter = picka(users) await reporter.agent.api.com.atproto.moderation.createReport({ - reasonType: picka([REASONSPAM, REASONOTHER]), + reasonType: picka([ + COM_ATPROTO_MODERATION.DefsReasonSpam, + COM_ATPROTO_MODERATION.DefsReasonOther, + ]), reason: picka(["Didn't look right to me", undefined, undefined]), subject: { $type: 'com.atproto.repo.strongRef', diff --git a/packages/dev-env/src/moderator-client.ts b/packages/dev-env/src/moderator-client.ts index fc537b2d2a5..5687371c5de 100644 --- a/packages/dev-env/src/moderator-client.ts +++ b/packages/dev-env/src/moderator-client.ts @@ -1,9 +1,13 @@ -import AtpAgent from '@atproto/api' -import { InputSchema as TakeActionInput } from '@atproto/api/src/client/types/tools/ozone/moderation/emitEvent' -import { QueryParams as QueryStatusesParams } from '@atproto/api/src/client/types/tools/ozone/moderation/queryStatuses' -import { QueryParams as QueryEventsParams } from '@atproto/api/src/client/types/tools/ozone/moderation/queryEvents' +import AtpAgent, { + ToolsOzoneModerationEmitEvent as EmitModerationEvent, + ToolsOzoneModerationQueryStatuses as QueryModerationStatuses, + ToolsOzoneModerationQueryEvents as QueryModerationEvents, +} from '@atproto/api' import { TestOzone } from './ozone' +type TakeActionInput = EmitModerationEvent.InputSchema +type QueryStatusesParams = QueryModerationStatuses.QueryParams +type QueryEventsParams = QueryModerationEvents.QueryParams type ModLevel = 'admin' | 'moderator' | 'triage' export class ModeratorClient { diff --git a/packages/dev-env/src/network-no-appview.ts b/packages/dev-env/src/network-no-appview.ts index 3272245280c..c47713c4443 100644 --- a/packages/dev-env/src/network-no-appview.ts +++ b/packages/dev-env/src/network-no-appview.ts @@ -1,4 +1,4 @@ -import { Handler as SkeletonHandler } from '@atproto/pds/src/lexicon/types/app/bsky/feed/getFeedSkeleton' +import { SkeletonHandler } from '@atproto/pds' import { TestServerParams } from './types' import { TestPlc } from './plc' import { TestPds } from './pds' diff --git a/packages/dev-env/src/pds.ts b/packages/dev-env/src/pds.ts index 0eb47c3f625..0828f2f3f03 100644 --- a/packages/dev-env/src/pds.ts +++ b/packages/dev-env/src/pds.ts @@ -4,7 +4,7 @@ import fs from 'node:fs/promises' import getPort from 'get-port' import * as ui8 from 'uint8arrays' import * as pds from '@atproto/pds' -import { createSecretKeyObject } from '@atproto/pds/src/auth-verifier' +import { createSecretKeyObject } from '@atproto/pds' import { Secp256k1Keypair, randomStr } from '@atproto/crypto' import { AtpAgent } from '@atproto/api' import { PdsConfig } from './types' diff --git a/packages/dev-env/src/seed/client.ts b/packages/dev-env/src/seed/client.ts index f4c2283543d..41ba25e551e 100644 --- a/packages/dev-env/src/seed/client.ts +++ b/packages/dev-env/src/seed/client.ts @@ -1,11 +1,12 @@ import fs from 'fs/promises' import { CID } from 'multiformats/cid' -import AtpAgent from '@atproto/api' -import { Main as Facet } from '@atproto/api/src/client/types/app/bsky/richtext/facet' -import { InputSchema as CreateReportInput } from '@atproto/api/src/client/types/com/atproto/moderation/createReport' -import { Record as PostRecord } from '@atproto/api/src/client/types/app/bsky/feed/post' -import { Record as LikeRecord } from '@atproto/api/src/client/types/app/bsky/feed/like' -import { Record as FollowRecord } from '@atproto/api/src/client/types/app/bsky/graph/follow' +import AtpAgent, { + ComAtprotoModerationCreateReport, + AppBskyFeedPost, + AppBskyRichtextFacet, + AppBskyFeedLike, + AppBskyGraphFollow, +} from '@atproto/api' import { AtUri } from '@atproto/syntax' import { BlobRef } from '@atproto/lexicon' import { TestNetworkNoAppView } from '../network-no-appview' @@ -191,7 +192,11 @@ export class SeedClient< return this.profiles[by] } - async follow(from: string, to: string, overrides?: Partial) { + async follow( + from: string, + to: string, + overrides?: Partial, + ) { const res = await this.agent.api.app.bsky.graph.follow.create( { repo: from }, { @@ -218,7 +223,11 @@ export class SeedClient< delete this.follows[from][to] } - async block(from: string, to: string, overrides?: Partial) { + async block( + from: string, + to: string, + overrides?: Partial, + ) { const res = await this.agent.api.app.bsky.graph.block.create( { repo: from }, { @@ -248,10 +257,10 @@ export class SeedClient< async post( by: string, text: string, - facets?: Facet[], + facets?: AppBskyRichtextFacet.Main[], images?: ImageRef[], quote?: RecordRef, - overrides?: Partial, + overrides?: Partial, ) { const imageEmbed = images && { $type: 'app.bsky.embed.images', @@ -315,7 +324,11 @@ export class SeedClient< return { image: res.data.blob, alt: filePath } } - async like(by: string, subject: RecordRef, overrides?: Partial) { + async like( + by: string, + subject: RecordRef, + overrides?: Partial, + ) { const res = await this.agent.api.app.bsky.feed.like.create( { repo: by }, { @@ -335,7 +348,7 @@ export class SeedClient< root: RecordRef, parent: RecordRef, text: string, - facets?: Facet[], + facets?: AppBskyRichtextFacet.Main[], images?: ImageRef[], ) { const embed = images @@ -447,8 +460,8 @@ export class SeedClient< } async createReport(opts: { - reasonType: CreateReportInput['reasonType'] - subject: CreateReportInput['subject'] + reasonType: ComAtprotoModerationCreateReport.InputSchema['reasonType'] + subject: ComAtprotoModerationCreateReport.InputSchema['subject'] reason?: string reportedBy: string }) { diff --git a/packages/dev-env/tsconfig.build.json b/packages/dev-env/tsconfig.build.json index 02a84823b65..fafdab3d6f7 100644 --- a/packages/dev-env/tsconfig.build.json +++ b/packages/dev-env/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/node.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/dev-env/tsconfig.json b/packages/dev-env/tsconfig.json index 6e341637305..e84b8178b47 100644 --- a/packages/dev-env/tsconfig.json +++ b/packages/dev-env/tsconfig.json @@ -1,18 +1,4 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "module": "esnext", - "include": ["./src", "__tests__/**/**.ts"], - "references": [ - { "path": "../api/tsconfig.build.json" }, - { "path": "../bsky/tsconfig.build.json" }, - { "path": "../crypto/tsconfig.build.json" }, - { "path": "../identity/tsconfig.build.json" }, - { "path": "../pds/tsconfig.json" }, - { "path": "../uri/tsconfig.build.json" } - ] + "include": [], + "references": [{ "path": "./tsconfig.build.json" }] } diff --git a/packages/identity/babel.config.js b/packages/identity/babel.config.js deleted file mode 100644 index ee58f35df11..00000000000 --- a/packages/identity/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [['@babel/preset-env']], -} diff --git a/packages/identity/build.js b/packages/identity/build.js deleted file mode 100644 index 709647b64ff..00000000000 --- a/packages/identity/build.js +++ /dev/null @@ -1,15 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - sourcemap: true, - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/identity/jest.config.js b/packages/identity/jest.config.js index 4eb023d6fcc..768288c07bf 100644 --- a/packages/identity/jest.config.js +++ b/packages/identity/jest.config.js @@ -1,6 +1,7 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'Identity', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + transformIgnorePatterns: [`/node_modules/(?!get-port)`], + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/identity/package.json b/packages/identity/package.json index 5505eb3d397..6b04ce48a91 100644 --- a/packages/identity/package.json +++ b/packages/identity/package.json @@ -14,17 +14,12 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/identity" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "test": "jest", "test:log": "cat test.log | pino-pretty", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/identity" + "build": "tsc --build tsconfig.build.json" }, "dependencies": { "@atproto/common-web": "workspace:^", @@ -36,6 +31,7 @@ "@did-plc/server": "^0.0.1", "cors": "^2.8.5", "express": "^4.18.2", - "get-port": "^6.1.2" + "get-port": "^6.1.2", + "jest": "^28.1.2" } } diff --git a/packages/identity/tsconfig.build.json b/packages/identity/tsconfig.build.json index 02a84823b65..436d8ecb628 100644 --- a/packages/identity/tsconfig.build.json +++ b/packages/identity/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/isomorphic.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/identity/tsconfig.json b/packages/identity/tsconfig.json index 9d6fd378666..1f3ab3c0ec4 100644 --- a/packages/identity/tsconfig.json +++ b/packages/identity/tsconfig.json @@ -1,13 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src", "__tests__/**/**.ts"], + "include": [], "references": [ - { "path": "../common/tsconfig.build.json" }, - { "path": "../crypto/tsconfig.build.json" } + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } ] } diff --git a/packages/identity/tsconfig.tests.json b/packages/identity/tsconfig.tests.json new file mode 100644 index 00000000000..c192c436e23 --- /dev/null +++ b/packages/identity/tsconfig.tests.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./tests"] +} diff --git a/packages/lex-cli/babel.config.js b/packages/lex-cli/babel.config.js deleted file mode 100644 index 0126e9dbaa6..00000000000 --- a/packages/lex-cli/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config.js') diff --git a/packages/lex-cli/build.js b/packages/lex-cli/build.js deleted file mode 100644 index e880ae9930b..00000000000 --- a/packages/lex-cli/build.js +++ /dev/null @@ -1,14 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/lex-cli/package.json b/packages/lex-cli/package.json index a9bc6944866..55c8b84beb7 100644 --- a/packages/lex-cli/package.json +++ b/packages/lex-cli/package.json @@ -16,20 +16,15 @@ "bin": { "lex": "dist/index.js" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/src/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/lex-cli" + "build": "tsc --build tsconfig.build.json" }, "dependencies": { "@atproto/lexicon": "workspace:^", "@atproto/syntax": "workspace:^", - "chalk": "^5.1.1", + "chalk": "^4.1.2", "commander": "^9.4.0", "ts-morph": "^16.0.0", "yesno": "^0.4.0", diff --git a/packages/lex-cli/tsconfig.build.json b/packages/lex-cli/tsconfig.build.json index 02a84823b65..fafdab3d6f7 100644 --- a/packages/lex-cli/tsconfig.build.json +++ b/packages/lex-cli/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/node.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/lex-cli/tsconfig.json b/packages/lex-cli/tsconfig.json index bdf4c2a099a..e84b8178b47 100644 --- a/packages/lex-cli/tsconfig.json +++ b/packages/lex-cli/tsconfig.json @@ -1,12 +1,4 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src", "__tests__/**/**.ts"], - "references": [ - { "path": "../nsid/tsconfig.build.json" }, - { "path": "../lexicon/tsconfig.build.json" } - ] + "include": [], + "references": [{ "path": "./tsconfig.build.json" }] } diff --git a/packages/lexicon/build.js b/packages/lexicon/build.js deleted file mode 100644 index e880ae9930b..00000000000 --- a/packages/lexicon/build.js +++ /dev/null @@ -1,14 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/lexicon/jest.config.js b/packages/lexicon/jest.config.js index ecdb2ae4b7c..cb439bdfb43 100644 --- a/packages/lexicon/jest.config.js +++ b/packages/lexicon/jest.config.js @@ -1,6 +1,7 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'Lexicon', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + transformIgnorePatterns: [`/node_modules/(?!get-port)`], + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/lexicon/package.json b/packages/lexicon/package.json index 388fba2531d..48949907c7a 100644 --- a/packages/lexicon/package.json +++ b/packages/lexicon/package.json @@ -13,16 +13,11 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/lexicon" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "test": "jest", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/lexicon" + "build": "tsc --build tsconfig.build.json" }, "dependencies": { "@atproto/common-web": "workspace:^", @@ -30,5 +25,8 @@ "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.21.4" + }, + "devDependencies": { + "jest": "^28.1.2" } } diff --git a/packages/lexicon/tsconfig.build.json b/packages/lexicon/tsconfig.build.json index 02a84823b65..436d8ecb628 100644 --- a/packages/lexicon/tsconfig.build.json +++ b/packages/lexicon/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/isomorphic.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/lexicon/tsconfig.json b/packages/lexicon/tsconfig.json index 5e60cf9920e..1f3ab3c0ec4 100644 --- a/packages/lexicon/tsconfig.json +++ b/packages/lexicon/tsconfig.json @@ -1,14 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src"], + "include": [], "references": [ - { "path": "../common/tsconfig.build.json" }, - { "path": "../nsid/tsconfig.build.json" }, - { "path": "../uri/tsconfig.build.json" } + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } ] } diff --git a/packages/lexicon/tsconfig.tests.json b/packages/lexicon/tsconfig.tests.json new file mode 100644 index 00000000000..c192c436e23 --- /dev/null +++ b/packages/lexicon/tsconfig.tests.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./tests"] +} diff --git a/packages/ozone/babel.config.js b/packages/ozone/babel.config.js deleted file mode 100644 index ee58f35df11..00000000000 --- a/packages/ozone/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [['@babel/preset-env']], -} diff --git a/packages/ozone/build.js b/packages/ozone/build.js deleted file mode 100644 index 45d59b50f8e..00000000000 --- a/packages/ozone/build.js +++ /dev/null @@ -1,18 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts', 'src/db/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - external: [ - // Referenced in pg driver, but optional and we don't use it - 'pg-native', - ], - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/ozone/jest.config.js b/packages/ozone/jest.config.js index 14720ce82eb..ee315e79d22 100644 --- a/packages/ozone/jest.config.js +++ b/packages/ozone/jest.config.js @@ -1,6 +1,8 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'Bsky App View', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + transformIgnorePatterns: [`/node_modules/(?!get-port)`], + testTimeout: 60000, + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/ozone/package.json b/packages/ozone/package.json index 767759ea113..7b19cf81af4 100644 --- a/packages/ozone/package.json +++ b/packages/ozone/package.json @@ -13,17 +13,12 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/ozone" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "bin": "dist/bin.js", "scripts": { "codegen": "lex gen-server ./src/lexicon ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/* ../../lexicons/tools/ozone/*/*", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/ozone", + "build": "tsc --build tsconfig.build.json", "start": "node --enable-source-maps dist/bin.js", "test": "../dev-infra/with-test-redis-and-db.sh jest", "test:log": "tail -50 test.log | pino-pretty", @@ -37,8 +32,10 @@ "@atproto/identity": "workspace:^", "@atproto/lexicon": "workspace:^", "@atproto/syntax": "workspace:^", + "@atproto/xrpc": "workspace:^", "@atproto/xrpc-server": "workspace:^", "@did-plc/lib": "^0.0.1", + "axios": "^1.6.7", "compression": "^1.7.4", "cors": "^2.8.5", "express": "^4.17.2", @@ -52,11 +49,8 @@ "uint8arrays": "3.0.0" }, "devDependencies": { - "@atproto/api": "workspace:^", - "@atproto/dev-env": "workspace:^", "@atproto/lex-cli": "workspace:^", "@atproto/pds": "workspace:^", - "@atproto/xrpc": "workspace:^", "@did-plc/server": "^0.0.1", "@types/cors": "^2.8.12", "@types/express": "^4.17.13", @@ -64,6 +58,7 @@ "@types/pg": "^8.6.6", "@types/qs": "^6.9.7", "axios": "^0.27.2", - "nodemailer": "^6.8.0" + "jest": "^28.1.2", + "ts-node": "^10.8.2" } } diff --git a/packages/ozone/src/daemon/event-pusher.ts b/packages/ozone/src/daemon/event-pusher.ts index ea4b5ecd35d..908b1e875d4 100644 --- a/packages/ozone/src/daemon/event-pusher.ts +++ b/packages/ozone/src/daemon/event-pusher.ts @@ -12,7 +12,7 @@ import { Insertable, Selectable } from 'kysely' type EventSubject = InputSchema['subject'] type PollState = { - timer?: NodeJS.Timer + timer?: NodeJS.Timeout promise: Promise } diff --git a/packages/ozone/src/daemon/event-reverser.ts b/packages/ozone/src/daemon/event-reverser.ts index ba3f3cb40f7..3146843acd7 100644 --- a/packages/ozone/src/daemon/event-reverser.ts +++ b/packages/ozone/src/daemon/event-reverser.ts @@ -6,7 +6,7 @@ import Database from '../db' export class EventReverser { destroyed = false reversalPromise: Promise = Promise.resolve() - timer: NodeJS.Timer | undefined + timer?: NodeJS.Timeout constructor( private db: Database, @@ -32,6 +32,7 @@ export class EventReverser { this.destroyed = true if (this.timer) { clearTimeout(this.timer) + this.timer = undefined } await this.reversalPromise } diff --git a/packages/ozone/src/db/index.ts b/packages/ozone/src/db/index.ts index 85702af2b79..b5b66542583 100644 --- a/packages/ozone/src/db/index.ts +++ b/packages/ozone/src/db/index.ts @@ -35,43 +35,45 @@ export class Database { if (instances) { this.db = instances.db this.pool = instances.pool - return - } + } else { + // else create a pool & connect + const { schema, url } = opts + const pool = + opts.pool ?? + new PgPool({ + connectionString: url, + max: opts.poolSize, + maxUses: opts.poolMaxUses, + idleTimeoutMillis: opts.poolIdleTimeoutMs, + }) - // else create a pool & connect - const { schema, url } = opts - const pool = - opts.pool ?? - new PgPool({ - connectionString: url, - max: opts.poolSize, - maxUses: opts.poolMaxUses, - idleTimeoutMillis: opts.poolIdleTimeoutMs, - }) + // Select count(*) and other pg bigints as js integer + pgTypes.setTypeParser(pgTypes.builtins.INT8, (n) => parseInt(n, 10)) - // Select count(*) and other pg bigints as js integer - pgTypes.setTypeParser(pgTypes.builtins.INT8, (n) => parseInt(n, 10)) + // Setup schema usage, primarily for test parallelism (each test suite runs in its own pg schema) + if (schema && !/^[a-z_]+$/i.test(schema)) { + throw new Error( + `Postgres schema must only contain [A-Za-z_]: ${schema}`, + ) + } - // Setup schema usage, primarily for test parallelism (each test suite runs in its own pg schema) - if (schema && !/^[a-z_]+$/i.test(schema)) { - throw new Error(`Postgres schema must only contain [A-Za-z_]: ${schema}`) - } + pool.on('error', onPoolError) + pool.on('connect', (client) => { + client.on('error', onClientError) + // Used for trigram indexes, e.g. on actor search + client.query('SET pg_trgm.word_similarity_threshold TO .4;') + if (schema) { + // Shared objects such as extensions will go in the public schema + client.query(`SET search_path TO "${schema}",public;`) + } + }) - pool.on('error', onPoolError) - pool.on('connect', (client) => { - client.on('error', onClientError) - // Used for trigram indexes, e.g. on actor search - client.query('SET pg_trgm.word_similarity_threshold TO .4;') - if (schema) { - // Shared objects such as extensions will go in the public schema - client.query(`SET search_path TO "${schema}",public;`) - } - }) + this.pool = pool + this.db = new Kysely({ + dialect: new PostgresDialect({ pool }), + }) + } - this.pool = pool - this.db = new Kysely({ - dialect: new PostgresDialect({ pool }), - }) this.migrator = new Migrator({ db: this.db, migrationTableSchema: opts.schema, @@ -168,7 +170,7 @@ const onClientError = (err: Error) => dbLogger.error({ err }, 'db client error') // ------- class LeakyTxPlugin implements KyselyPlugin { - private txOver: boolean + private txOver = false endTx() { this.txOver = true diff --git a/packages/ozone/src/index.ts b/packages/ozone/src/index.ts index c1879745a78..59ce09e614b 100644 --- a/packages/ozone/src/index.ts +++ b/packages/ozone/src/index.ts @@ -24,7 +24,7 @@ export class OzoneService { public app: express.Application public server?: http.Server private terminator?: HttpTerminator - private dbStatsInterval: NodeJS.Timer + private dbStatsInterval?: NodeJS.Timeout constructor(opts: { ctx: AppContext; app: express.Application }) { this.ctx = opts.ctx @@ -64,6 +64,9 @@ export class OzoneService { } async start(): Promise { + if (this.dbStatsInterval) { + throw new Error(`${this.constructor.name} already started`) + } const { db, backgroundQueue } = this.ctx this.dbStatsInterval = setInterval(() => { dbLogger.info( @@ -99,6 +102,7 @@ export class OzoneService { await this.ctx.sequencer.destroy() await this.ctx.db.close() clearInterval(this.dbStatsInterval) + this.dbStatsInterval = undefined } } diff --git a/packages/ozone/tests/blob-divert.test.ts b/packages/ozone/tests/blob-divert.test.ts index a07cbf62b73..9c335f20ec3 100644 --- a/packages/ozone/tests/blob-divert.test.ts +++ b/packages/ozone/tests/blob-divert.test.ts @@ -1,10 +1,10 @@ +import assert from 'node:assert' import { ModeratorClient, SeedClient, TestNetwork, basicSeed, } from '@atproto/dev-env' -import { BlobDiverter } from '../src/daemon' import { forSnapshot } from './_util' describe('blob divert', () => { @@ -31,8 +31,10 @@ describe('blob divert', () => { }) const mockReportServiceResponse = (result: boolean) => { + const blobDiverter = network.ozone.ctx.blobDiverter + assert(blobDiverter) return jest - .spyOn(BlobDiverter.prototype, 'sendImage') + .spyOn(blobDiverter, 'sendImage') .mockImplementation(async () => { return result }) diff --git a/packages/ozone/tests/moderation-appeals.test.ts b/packages/ozone/tests/moderation-appeals.test.ts index 05328065ad0..0c95ead78ca 100644 --- a/packages/ozone/tests/moderation-appeals.test.ts +++ b/packages/ozone/tests/moderation-appeals.test.ts @@ -4,17 +4,15 @@ import { basicSeed, ModeratorClient, } from '@atproto/dev-env' -import { ToolsOzoneModerationDefs } from '@atproto/api' +import { + ComAtprotoModerationDefs, + ToolsOzoneModerationDefs, +} from '@atproto/api' import { REASONMISLEADING, REASONSPAM, - REASONAPPEAL, } from '../src/lexicon/types/com/atproto/moderation/defs' -import { - REVIEWCLOSED, - REVIEWOPEN, - REVIEWESCALATED, -} from '@atproto/api/src/client/types/tools/ozone/moderation/defs' +import { REVIEWESCALATED } from '../src/lexicon/types/tools/ozone/moderation/defs' describe('moderation-appeals', () => { let network: TestNetwork @@ -74,26 +72,26 @@ describe('moderation-appeals', () => { subject: getBobsPostSubject(), }) - await assertBobsPostStatus(REVIEWOPEN, undefined) + await assertBobsPostStatus(ToolsOzoneModerationDefs.REVIEWOPEN, undefined) // Create a report as normal user with appeal type expect( sc.createReport({ reportedBy: sc.dids.carol, - reasonType: REASONAPPEAL, + reasonType: ComAtprotoModerationDefs.REASONAPPEAL, reason: 'appealing', subject: getBobsPostSubject(), }), ).rejects.toThrow('You cannot appeal this report') // Verify that the appeal status did not change - await assertBobsPostStatus(REVIEWOPEN, undefined) + await assertBobsPostStatus(ToolsOzoneModerationDefs.REVIEWOPEN, undefined) // Emit report event as moderator await modClient.emitEvent({ event: { $type: 'tools.ozone.moderation.defs#modEventReport', - reportType: REASONAPPEAL, + reportType: ComAtprotoModerationDefs.REASONAPPEAL, }, subject: getBobsPostSubject(), }) @@ -113,13 +111,13 @@ describe('moderation-appeals', () => { // Verify that the appeal status on carol's post is undefined await assertSubjectStatus( getCarolPostSubject().uri, - REVIEWOPEN, + ToolsOzoneModerationDefs.REVIEWOPEN, undefined, ) await sc.createReport({ reportedBy: sc.dids.carol, - reasonType: REASONAPPEAL, + reasonType: ComAtprotoModerationDefs.REASONAPPEAL, reason: 'appealing', subject: getCarolPostSubject(), }) @@ -144,7 +142,7 @@ describe('moderation-appeals', () => { await modClient.emitEvent({ event: { $type: 'tools.ozone.moderation.defs#modEventReport', - reportType: REASONAPPEAL, + reportType: ComAtprotoModerationDefs.REASONAPPEAL, }, subject: getBobsPostSubject(), }) @@ -185,7 +183,7 @@ describe('moderation-appeals', () => { await modClient.emitEvent({ event: { $type: 'tools.ozone.moderation.defs#modEventReport', - reportType: REASONAPPEAL, + reportType: ComAtprotoModerationDefs.REASONAPPEAL, }, subject: getAlicesPostSubject(), }) @@ -235,7 +233,11 @@ describe('moderation-appeals', () => { }) // Assert that status moved on to reviewClosed while appealed status is still true - await assertSubjectStatus(getAlicesPostSubject().uri, REVIEWCLOSED, true) + await assertSubjectStatus( + getAlicesPostSubject().uri, + ToolsOzoneModerationDefs.REVIEWCLOSED, + true, + ) // Emit a resolveAppeal event await modClient.emitEvent({ @@ -247,7 +249,11 @@ describe('moderation-appeals', () => { }) // Assert that status stayed the same while appealed status is still true - await assertSubjectStatus(getAlicesPostSubject().uri, REVIEWCLOSED, false) + await assertSubjectStatus( + getAlicesPostSubject().uri, + ToolsOzoneModerationDefs.REVIEWCLOSED, + false, + ) }) }) }) diff --git a/packages/ozone/tests/moderation-events.test.ts b/packages/ozone/tests/moderation-events.test.ts index 101687d502d..30d41967b98 100644 --- a/packages/ozone/tests/moderation-events.test.ts +++ b/packages/ozone/tests/moderation-events.test.ts @@ -7,7 +7,6 @@ import { ModeratorClient, } from '@atproto/dev-env' import { ToolsOzoneModerationDefs } from '@atproto/api' -import Mail from 'nodemailer/lib/mailer' import { forSnapshot } from './_util' import { REASONAPPEAL, @@ -386,7 +385,9 @@ describe('moderation-events', () => { describe('email event', () => { let sendMailOriginal const mailCatcher = new EventEmitter() - const getMailFrom = async (promise): Promise => { + const getMailFrom = async ( + promise, + ): Promise<{ to: string; subject: string; from: string }> => { const result = await Promise.all([once(mailCatcher, 'mail'), promise]) return result[0][0] } diff --git a/packages/ozone/tests/moderation.test.ts b/packages/ozone/tests/moderation.test.ts index 211b22fa4d9..c11dd5e0293 100644 --- a/packages/ozone/tests/moderation.test.ts +++ b/packages/ozone/tests/moderation.test.ts @@ -636,6 +636,7 @@ describe('moderation', () => { // In the actual app, this will be instantiated and run on server startup const reverser = new EventReverser( network.ozone.ctx.db, + // @ts-expect-error Error due to circular dependency with the dev-env package network.ozone.ctx.modService, ) await reverser.findAndRevertDueActions() diff --git a/packages/ozone/tests/query-labels.test.ts b/packages/ozone/tests/query-labels.test.ts index 1e958269cd0..33ae952cf51 100644 --- a/packages/ozone/tests/query-labels.test.ts +++ b/packages/ozone/tests/query-labels.test.ts @@ -151,12 +151,14 @@ describe('ozone query labels', () => { const newSigningKey = await Secp256k1Keypair.create() const newSigningKeyId = await getSigningKeyId(ctx.db, newSigningKey.did()) ctx.devOverride({ + // @ts-ignore modService: ModerationService.creator( newSigningKey, newSigningKeyId, ctx.cfg, modSrvc.backgroundQueue, ctx.idResolver, + // @ts-ignore modSrvc.eventPusher, modSrvc.appviewAgent, ctx.serviceAuthHeaders, diff --git a/packages/ozone/tests/sequencer.test.ts b/packages/ozone/tests/sequencer.test.ts index cc7003c64c7..840e78ff243 100644 --- a/packages/ozone/tests/sequencer.test.ts +++ b/packages/ozone/tests/sequencer.test.ts @@ -16,6 +16,7 @@ describe('sequencer', () => { network = await TestNetwork.create({ dbPostgresSchema: 'ozone_sequencer', }) + // @ts-expect-error sequencer = network.ozone.ctx.sequencer }) diff --git a/packages/ozone/tests/server.test.ts b/packages/ozone/tests/server.test.ts index 3b40299d4c7..955a6cafa88 100644 --- a/packages/ozone/tests/server.test.ts +++ b/packages/ozone/tests/server.test.ts @@ -1,9 +1,8 @@ import { AddressInfo } from 'net' import express from 'express' import axios, { AxiosError } from 'axios' -import { TestNetwork } from '@atproto/dev-env' +import { TestOzone, TestNetwork } from '@atproto/dev-env' import { handler as errorHandler } from '../src/error' -import { TestOzone } from '@atproto/dev-env/src/ozone' describe('server', () => { let network: TestNetwork diff --git a/packages/ozone/tsconfig.build.json b/packages/ozone/tsconfig.build.json index 02a84823b65..944827a6f62 100644 --- a/packages/ozone/tsconfig.build.json +++ b/packages/ozone/tsconfig.build.json @@ -1,4 +1,9 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/node.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "noUnusedLocals": false + }, + "include": ["./src"] } diff --git a/packages/ozone/tsconfig.json b/packages/ozone/tsconfig.json index 3f6ca1c27ec..1f3ab3c0ec4 100644 --- a/packages/ozone/tsconfig.json +++ b/packages/ozone/tsconfig.json @@ -1,21 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", - "emitDeclarationOnly": true - }, - "module": "nodenext", - "include": ["./src", "__tests__/**/**.ts"], + "include": [], "references": [ - { "path": "../api/tsconfig.build.json" }, - { "path": "../common/tsconfig.build.json" }, - { "path": "../crypto/tsconfig.build.json" }, - { "path": "../identifier/tsconfig.build.json" }, - { "path": "../lexicon/tsconfig.build.json" }, - { "path": "../lex-cli/tsconfig.build.json" }, - { "path": "../repo/tsconfig.build.json" }, - { "path": "../uri/tsconfig.build.json" }, - { "path": "../xrpc-server/tsconfig.build.json" } + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } ] } diff --git a/packages/ozone/tsconfig.tests.json b/packages/ozone/tsconfig.tests.json new file mode 100644 index 00000000000..7fac0ed90d5 --- /dev/null +++ b/packages/ozone/tsconfig.tests.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": ".", + "noUnusedLocals": false + }, + "include": ["./tests"] +} diff --git a/packages/pds/babel.config.js b/packages/pds/babel.config.js deleted file mode 100644 index ee58f35df11..00000000000 --- a/packages/pds/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [['@babel/preset-env']], -} diff --git a/packages/pds/build.js b/packages/pds/build.js deleted file mode 100644 index f78cfc153c5..00000000000 --- a/packages/pds/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') -const hbsPlugin = require('esbuild-plugin-handlebars') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts', 'src/db/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - external: [ - 'better-sqlite3', - // Referenced in pg driver, but optional and we don't use it - 'pg-native', - 'sharp', - ], - plugins: [].concat(buildShallow ? [nodeExternalsPlugin()] : []).concat([ - hbsPlugin({ - filter: /\.(hbs)$/, - additionalHelpers: {}, - precompileOptions: {}, - }), - ]), -}) diff --git a/packages/pds/build.templates.js b/packages/pds/build.templates.js new file mode 100644 index 00000000000..fd42af400a4 --- /dev/null +++ b/packages/pds/build.templates.js @@ -0,0 +1,21 @@ +/* eslint-env node */ + +const hbsPlugin = require('esbuild-plugin-handlebars') +const { globSync } = require('glob') + +require('esbuild').build({ + logLevel: 'info', + watch: process.argv.includes('--watch'), + entryPoints: globSync('src/**/*.hbs'), + sourcemap: true, + outdir: 'dist/mailer/templates', + platform: 'node', + format: 'cjs', + plugins: [ + hbsPlugin({ + filter: /\.(hbs)$/, + additionalHelpers: {}, + precompileOptions: {}, + }), + ], +}) diff --git a/packages/pds/jest.bench.config.js b/packages/pds/jest.bench.config.js deleted file mode 100644 index 3207cdd8b97..00000000000 --- a/packages/pds/jest.bench.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const base = require('./jest.config') - -module.exports = { - ...base, - roots: ['/bench'], - testRegex: '(.*.bench)', - testTimeout: 3000000, -} diff --git a/packages/pds/jest.config.js b/packages/pds/jest.config.js index e98e672e050..e66657f9546 100644 --- a/packages/pds/jest.config.js +++ b/packages/pds/jest.config.js @@ -1,6 +1,8 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'PDS', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + transformIgnorePatterns: [`/node_modules/(?!get-port)`], + testTimeout: 60000, + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/pds/package.json b/packages/pds/package.json index 5068ef2f350..e7cf0fe4a6e 100644 --- a/packages/pds/package.json +++ b/packages/pds/package.json @@ -13,22 +13,18 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/pds" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "bin": "dist/bin.js", "scripts": { "codegen": "lex gen-server ./src/lexicon ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/* ../../lexicons/tools/ozone/*/*", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", + "build": "tsc --build tsconfig.build.json", + "postbuild": "node ./build.templates.js", + "dev": "node ./build.templates.js --watch", "test": "../dev-infra/with-test-redis-and-db.sh jest", "test:sqlite": "jest", "test:sqlite-only": "jest --testPathIgnorePatterns /tests/proxied/*", "test:log": "tail -50 test.log | pino-pretty", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/pds", - "bench": "../dev-infra/with-test-redis-and-db.sh jest --config jest.bench.config.js", "test:updateSnapshot": "jest --updateSnapshot", "migration:create": "ts-node ./bin/migration-create.ts" }, @@ -52,6 +48,7 @@ "express": "^4.17.2", "express-async-errors": "^3.1.1", "file-type": "^16.5.4", + "glob": "^10.3.10", "handlebars": "^4.7.7", "http-terminator": "^3.2.0", "ioredis": "^5.3.2", @@ -72,7 +69,6 @@ "devDependencies": { "@atproto/api": "workspace:^", "@atproto/bsky": "workspace:^", - "@atproto/dev-env": "workspace:^", "@atproto/lex-cli": "workspace:^", "@atproto/pds-entryway": "npm:@atproto/pds@0.3.0-entryway.3", "@did-plc/server": "^0.0.1", @@ -83,7 +79,11 @@ "@types/nodemailer": "^6.4.6", "@types/qs": "^6.9.7", "axios": "^0.27.2", + "esbuild": "^0.14.48", + "esbuild-plugin-handlebars": "^1.0.3", "get-port": "^6.1.2", + "jest": "^28.1.2", + "ts-node": "^10.8.2", "ws": "^8.12.0" } } diff --git a/packages/pds/src/actor-store/repo/sql-repo-reader.ts b/packages/pds/src/actor-store/repo/sql-repo-reader.ts index 30f994031c4..8fd12d22923 100644 --- a/packages/pds/src/actor-store/repo/sql-repo-reader.ts +++ b/packages/pds/src/actor-store/repo/sql-repo-reader.ts @@ -12,7 +12,6 @@ import { countAll } from '../../db' export class SqlRepoReader extends ReadableBlockstore { cache: BlockMap = new BlockMap() - now: string constructor(public db: ActorDb) { super() diff --git a/packages/pds/src/db/db.ts b/packages/pds/src/db/db.ts index 1850e07f2d5..b911c960e87 100644 --- a/packages/pds/src/db/db.ts +++ b/packages/pds/src/db/db.ts @@ -116,7 +116,7 @@ export class Database { type CommitHook = () => void class LeakyTxPlugin implements KyselyPlugin { - private txOver: boolean + private txOver = false endTx() { this.txOver = true diff --git a/packages/pds/src/index.ts b/packages/pds/src/index.ts index ea7c7aa53ee..3471f288070 100644 --- a/packages/pds/src/index.ts +++ b/packages/pds/src/index.ts @@ -31,14 +31,20 @@ export { Database } from './db' export { DiskBlobStore } from './disk-blobstore' export { AppContext } from './context' export { httpLogger } from './logger' +export { createSecretKeyObject } from './auth-verifier' +export { type Handler as SkeletonHandler } from './lexicon/types/app/bsky/feed/getFeedSkeleton' +export { createServer as createLexiconServer } from './lexicon' +export * as sequencer from './sequencer' +export { type PreparedWrite } from './repo' +export * as repoPrepare from './repo/prepare' export class PDS { public ctx: AppContext public app: express.Application public server?: http.Server private terminator?: HttpTerminator - private dbStatsInterval?: NodeJS.Timer - private sequencerStatsInterval?: NodeJS.Timer + private dbStatsInterval?: NodeJS.Timeout + private sequencerStatsInterval?: NodeJS.Timeout constructor(opts: { ctx: AppContext; app: express.Application }) { this.ctx = opts.ctx diff --git a/packages/pds/src/mailer/index.ts b/packages/pds/src/mailer/index.ts index f6c57cec40e..3a4633da1c2 100644 --- a/packages/pds/src/mailer/index.ts +++ b/packages/pds/src/mailer/index.ts @@ -8,8 +8,6 @@ import { mailerLogger } from '../logger' import * as templates from './templates' export class ServerMailer { - private readonly templates = templates - constructor( public readonly transporter: Transporter, private readonly config: ServerConfig, @@ -60,11 +58,15 @@ export class ServerMailer { }) } - private async sendTemplate(templateName, params, mailOpts: Mail.Options) { - const html = this.templates[templateName]({ + private async sendTemplate( + templateName: K, + params: Parameters[0], + mailOpts: Mail.Options, + ) { + const html = templates[templateName]({ ...params, config: ServerMailer.getEmailConfig(this.config), - }) + } as any) const res = await this.transporter.sendMail({ ...mailOpts, from: mailOpts.from ?? this.config.email?.fromAddress, diff --git a/packages/pds/src/mailer/templates.ts b/packages/pds/src/mailer/templates.ts index 86a683053f9..2a1e31c55db 100644 --- a/packages/pds/src/mailer/templates.ts +++ b/packages/pds/src/mailer/templates.ts @@ -1,8 +1,5 @@ -// eslint-disable-next-line @typescript-eslint/triple-slash-reference -/// - -export { default as resetPassword } from './templates/reset-password.hbs' -export { default as deleteAccount } from './templates/delete-account.hbs' -export { default as confirmEmail } from './templates/confirm-email.hbs' -export { default as updateEmail } from './templates/update-email.hbs' -export { default as plcOperation } from './templates/plc-operation.hbs' +export { default as resetPassword } from './templates/reset-password' +export { default as deleteAccount } from './templates/delete-account' +export { default as confirmEmail } from './templates/confirm-email' +export { default as updateEmail } from './templates/update-email' +export { default as plcOperation } from './templates/plc-operation' diff --git a/packages/pds/src/mailer/templates/confirm-email.d.ts b/packages/pds/src/mailer/templates/confirm-email.d.ts new file mode 100644 index 00000000000..3e2726d64ac --- /dev/null +++ b/packages/pds/src/mailer/templates/confirm-email.d.ts @@ -0,0 +1,4 @@ +import { TemplateDelegate } from "handlebars"; + +declare const template: TemplateDelegate<{ token: string }> +export default template diff --git a/packages/pds/src/mailer/templates/delete-account.d.ts b/packages/pds/src/mailer/templates/delete-account.d.ts new file mode 100644 index 00000000000..3e2726d64ac --- /dev/null +++ b/packages/pds/src/mailer/templates/delete-account.d.ts @@ -0,0 +1,4 @@ +import { TemplateDelegate } from "handlebars"; + +declare const template: TemplateDelegate<{ token: string }> +export default template diff --git a/packages/pds/src/mailer/templates/plc-operation.d.ts b/packages/pds/src/mailer/templates/plc-operation.d.ts new file mode 100644 index 00000000000..3e2726d64ac --- /dev/null +++ b/packages/pds/src/mailer/templates/plc-operation.d.ts @@ -0,0 +1,4 @@ +import { TemplateDelegate } from "handlebars"; + +declare const template: TemplateDelegate<{ token: string }> +export default template diff --git a/packages/pds/src/mailer/templates/reset-password.d.ts b/packages/pds/src/mailer/templates/reset-password.d.ts new file mode 100644 index 00000000000..47d9c9e5fc6 --- /dev/null +++ b/packages/pds/src/mailer/templates/reset-password.d.ts @@ -0,0 +1,4 @@ +import { TemplateDelegate } from "handlebars"; + +declare const template: TemplateDelegate<{ token: string; identifier: string }> +export default template diff --git a/packages/pds/src/mailer/templates/update-email.d.ts b/packages/pds/src/mailer/templates/update-email.d.ts new file mode 100644 index 00000000000..3e2726d64ac --- /dev/null +++ b/packages/pds/src/mailer/templates/update-email.d.ts @@ -0,0 +1,4 @@ +import { TemplateDelegate } from "handlebars"; + +declare const template: TemplateDelegate<{ token: string }> +export default template diff --git a/packages/pds/src/read-after-write/viewer.ts b/packages/pds/src/read-after-write/viewer.ts index 6777b951cdf..3a4dd8f5381 100644 --- a/packages/pds/src/read-after-write/viewer.ts +++ b/packages/pds/src/read-after-write/viewer.ts @@ -13,7 +13,12 @@ import { ProfileView, ProfileViewDetailed, } from '../lexicon/types/app/bsky/actor/defs' -import { FeedViewPost, PostView } from '../lexicon/types/app/bsky/feed/defs' +import { + FeedViewPost, + GeneratorView, + PostView, +} from '../lexicon/types/app/bsky/feed/defs' +import { ListView } from '../lexicon/types/app/bsky/graph/defs' import { Main as EmbedImages, isMain as isEmbedImages, @@ -26,6 +31,7 @@ import { Main as EmbedRecord, isMain as isEmbedRecord, View as EmbedRecordView, + ViewRecord, } from '../lexicon/types/app/bsky/embed/record' import { Main as EmbedRecordWithMedia, @@ -225,7 +231,9 @@ export class LocalViewer { } } - async formatRecordEmbedInternal(embed: EmbedRecord) { + private async formatRecordEmbedInternal( + embed: EmbedRecord, + ): Promise { if (!this.appViewAgent || !this.appviewDid) { return null } diff --git a/packages/pds/src/types.d.ts b/packages/pds/src/types.d.ts deleted file mode 100644 index e5ad25b72c7..00000000000 --- a/packages/pds/src/types.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module "*.hbs" { - import { TemplateDelegate } from "handlebars"; - const template: TemplateDelegate; - export default template; -} diff --git a/packages/pds/tests/account-deletion.test.ts b/packages/pds/tests/account-deletion.test.ts index 2365e935c69..1fc9c8388ca 100644 --- a/packages/pds/tests/account-deletion.test.ts +++ b/packages/pds/tests/account-deletion.test.ts @@ -36,6 +36,7 @@ describe('account deletion', () => { network = await TestNetworkNoAppView.create({ dbPostgresSchema: 'account_deletion', }) + // @ts-expect-error Error due to circular dependency with the dev-env package ctx = network.pds.ctx mailer = ctx.mailer agent = new AtpAgent({ service: network.pds.url }) diff --git a/packages/pds/tests/account.test.ts b/packages/pds/tests/account.test.ts index 20a5c7cce14..a0cddde4d4b 100644 --- a/packages/pds/tests/account.test.ts +++ b/packages/pds/tests/account.test.ts @@ -31,7 +31,9 @@ describe('account', () => { privacyPolicyUrl: 'https://example.com/privacy-policy', }, }) + // @ts-expect-error Error due to circular dependency with the dev-env package mailer = network.pds.ctx.mailer + // @ts-expect-error Error due to circular dependency with the dev-env package ctx = network.pds.ctx idResolver = network.pds.ctx.idResolver agent = network.pds.getClient() diff --git a/packages/pds/tests/auth.test.ts b/packages/pds/tests/auth.test.ts index d8d29942ccd..e4d58a84537 100644 --- a/packages/pds/tests/auth.test.ts +++ b/packages/pds/tests/auth.test.ts @@ -1,8 +1,6 @@ import * as jose from 'jose' import AtpAgent from '@atproto/api' import { TestNetworkNoAppView, SeedClient } from '@atproto/dev-env' -import * as CreateSession from '@atproto/api/src/client/types/com/atproto/server/createSession' -import * as RefreshSession from '@atproto/api/src/client/types/com/atproto/server/refreshSession' import { createRefreshToken } from '../src/account-manager/helpers/auth' describe('auth', () => { @@ -283,7 +281,9 @@ describe('auth', () => { ) await expect( createSession({ identifier: 'iris.test', password: 'password' }), - ).rejects.toThrow(CreateSession.AccountTakedownError) + ).rejects.toMatchObject({ + error: 'AccountTakedown', + }) }) it('actor takedown disallows refresh session.', async () => { @@ -305,8 +305,8 @@ describe('auth', () => { headers: { authorization: network.pds.adminAuth() }, }, ) - await expect(refreshSession(account.refreshJwt)).rejects.toThrow( - RefreshSession.AccountTakedownError, - ) + await expect(refreshSession(account.refreshJwt)).rejects.toMatchObject({ + error: 'AccountTakedown', + }) }) }) diff --git a/packages/pds/tests/blob-deletes.test.ts b/packages/pds/tests/blob-deletes.test.ts index e40883afc95..73b466c8727 100644 --- a/packages/pds/tests/blob-deletes.test.ts +++ b/packages/pds/tests/blob-deletes.test.ts @@ -17,6 +17,7 @@ describe('blob deletes', () => { network = await TestNetworkNoAppView.create({ dbPostgresSchema: 'blob_deletes', }) + // @ts-expect-error Error due to circular dependency with the dev-env package ctx = network.pds.ctx agent = network.pds.getClient() sc = network.getSeedClient() diff --git a/packages/pds/tests/crud.test.ts b/packages/pds/tests/crud.test.ts index dd3f3f3b11f..fce1ce85638 100644 --- a/packages/pds/tests/crud.test.ts +++ b/packages/pds/tests/crud.test.ts @@ -3,10 +3,6 @@ import { AtUri } from '@atproto/syntax' import AtpAgent from '@atproto/api' import { BlobRef } from '@atproto/lexicon' import { TestNetworkNoAppView } from '@atproto/dev-env' -import * as createRecord from '@atproto/api/src/client/types/com/atproto/repo/createRecord' -import * as putRecord from '@atproto/api/src/client/types/com/atproto/repo/putRecord' -import * as deleteRecord from '@atproto/api/src/client/types/com/atproto/repo/deleteRecord' -import * as applyWrites from '@atproto/api/src/client/types/com/atproto/repo/applyWrites' import { cidForCbor, TID, ui8ToArrayBuffer } from '@atproto/common' import { BlobNotFoundError } from '@atproto/repo' import { defaultFetchHandler } from '@atproto/xrpc' @@ -39,6 +35,7 @@ describe('crud operations', () => { network = await TestNetworkNoAppView.create({ dbPostgresSchema: 'crud', }) + // @ts-expect-error Error due to circular dependency with the dev-env package ctx = network.pds.ctx agent = network.pds.getClient() aliceAgent = network.pds.getClient() @@ -797,7 +794,9 @@ describe('crud operations', () => { swapCommit: staleCommit.cid, record: postRecord(), }) - await expect(attemptCreate).rejects.toThrow(createRecord.InvalidSwapError) + await expect(attemptCreate).rejects.toMatchObject({ + error: 'InvalidSwap', + }) }) it('deleteRecord succeeds on proper commit cas', async () => { @@ -840,7 +839,9 @@ describe('crud operations', () => { rkey: uri.rkey, swapCommit: staleCommit.cid, }) - await expect(attemptDelete).rejects.toThrow(deleteRecord.InvalidSwapError) + await expect(attemptDelete).rejects.toMatchObject({ + error: 'InvalidSwap', + }) const checkPost = repo.getRecord({ repo: uri.host, collection: uri.collection, @@ -885,7 +886,9 @@ describe('crud operations', () => { rkey: uri.rkey, swapRecord: (await cidForCbor({})).toString(), }) - await expect(attemptDelete).rejects.toThrow(deleteRecord.InvalidSwapError) + await expect(attemptDelete).rejects.toMatchObject({ + error: 'InvalidSwap', + }) const checkPost = repo.getRecord({ repo: uri.host, collection: uri.collection, @@ -930,7 +933,7 @@ describe('crud operations', () => { swapCommit: staleCommit.cid, record: profileRecord(), }) - await expect(attemptPut).rejects.toThrow(putRecord.InvalidSwapError) + await expect(attemptPut).rejects.toMatchObject({ error: 'InvalidSwap' }) }) it('putRecord succeeds on proper record cas', async () => { @@ -981,7 +984,7 @@ describe('crud operations', () => { swapRecord: null, record: profileRecord(), }) - await expect(attemptPut1).rejects.toThrow(putRecord.InvalidSwapError) + await expect(attemptPut1).rejects.toMatchObject({ error: 'InvalidSwap' }) // Test swapRecord w/ cid (ensures update) const attemptPut2 = repo.putRecord({ repo: alice.did, @@ -990,7 +993,7 @@ describe('crud operations', () => { swapRecord: (await cidForCbor({})).toString(), record: profileRecord(), }) - await expect(attemptPut2).rejects.toThrow(putRecord.InvalidSwapError) + await expect(attemptPut2).rejects.toMatchObject({ error: 'InvalidSwap' }) }) it('applyWrites succeeds on proper commit cas', async () => { @@ -1033,9 +1036,9 @@ describe('crud operations', () => { }, ], }) - await expect(attemptApplyWrite).rejects.toThrow( - applyWrites.InvalidSwapError, - ) + await expect(attemptApplyWrite).rejects.toMatchObject({ + error: 'InvalidSwap', + }) }) it("writes fail on values that can't reliably transform between cbor to lex", async () => { diff --git a/packages/pds/tests/email-confirmation.test.ts b/packages/pds/tests/email-confirmation.test.ts index 2f66b1939d2..d41ed587476 100644 --- a/packages/pds/tests/email-confirmation.test.ts +++ b/packages/pds/tests/email-confirmation.test.ts @@ -24,6 +24,7 @@ describe('email confirmation', () => { network = await TestNetworkNoAppView.create({ dbPostgresSchema: 'email_confirmation', }) + // @ts-expect-error Error due to circular dependency with the dev-env package mailer = network.pds.ctx.mailer agent = network.pds.getClient() sc = network.getSeedClient() diff --git a/packages/pds/tests/file-uploads.test.ts b/packages/pds/tests/file-uploads.test.ts index 7cde753bfb0..0ce419a7209 100644 --- a/packages/pds/tests/file-uploads.test.ts +++ b/packages/pds/tests/file-uploads.test.ts @@ -23,6 +23,7 @@ describe('file uploads', () => { network = await TestNetworkNoAppView.create({ dbPostgresSchema: 'file_uploads', }) + // @ts-expect-error Error due to circular dependency with the dev-env package ctx = network.pds.ctx agent = network.pds.getClient() sc = network.getSeedClient() @@ -43,8 +44,10 @@ describe('file uploads', () => { it('handles client abort', async () => { const abortController = new AbortController() - const _putTemp = DiskBlobStore.prototype.putTemp - DiskBlobStore.prototype.putTemp = function (...args) { + const BlobStore = ctx.blobstore('did:invalid') + .constructor as typeof DiskBlobStore + const _putTemp = BlobStore.prototype.putTemp + BlobStore.prototype.putTemp = function (...args) { // Abort just as processing blob in packages/pds/src/services/repo/blobs.ts process.nextTick(() => abortController.abort()) return _putTemp.call(this, ...args) @@ -63,7 +66,7 @@ describe('file uploads', () => { ) await expect(response).rejects.toThrow('operation was aborted') // Cleanup - DiskBlobStore.prototype.putTemp = _putTemp + BlobStore.prototype.putTemp = _putTemp // This test would fail from an uncaught exception: this grace period gives time for that to surface await new Promise((res) => setTimeout(res, 10)) }) diff --git a/packages/pds/tests/handles.test.ts b/packages/pds/tests/handles.test.ts index aaac2daa3df..ee7ec7716f4 100644 --- a/packages/pds/tests/handles.test.ts +++ b/packages/pds/tests/handles.test.ts @@ -35,6 +35,7 @@ describe('handles', () => { network = await TestNetworkNoAppView.create({ dbPostgresSchema: 'handles', }) + // @ts-expect-error Error due to circular dependency with the dev-env package ctx = network.pds.ctx idResolver = new IdResolver({ plcUrl: ctx.cfg.identity.plcUrl }) agent = network.pds.getClient() diff --git a/packages/pds/tests/invite-codes.test.ts b/packages/pds/tests/invite-codes.test.ts index 90d16aad00b..f1066feb7d2 100644 --- a/packages/pds/tests/invite-codes.test.ts +++ b/packages/pds/tests/invite-codes.test.ts @@ -19,6 +19,7 @@ describe('account', () => { inviteEpoch: Date.now() - 3 * DAY, }, }) + // @ts-expect-error Error due to circular dependency with the dev-env package ctx = network.pds.ctx agent = network.pds.getClient() }) diff --git a/packages/pds/tests/plc-operations.test.ts b/packages/pds/tests/plc-operations.test.ts index 9c90b3482ff..20a149d4d94 100644 --- a/packages/pds/tests/plc-operations.test.ts +++ b/packages/pds/tests/plc-operations.test.ts @@ -26,6 +26,7 @@ describe('plc operations', () => { network = await TestNetworkNoAppView.create({ dbPostgresSchema: 'plc_operations', }) + // @ts-expect-error Error due to circular dependency with the dev-env package ctx = network.pds.ctx const mailer = ctx.mailer diff --git a/packages/pds/tests/proxied/admin.test.ts b/packages/pds/tests/proxied/admin.test.ts index 4f54a6ce9b4..05a9fed80f5 100644 --- a/packages/pds/tests/proxied/admin.test.ts +++ b/packages/pds/tests/proxied/admin.test.ts @@ -1,10 +1,6 @@ import AtpAgent from '@atproto/api' import { TestNetwork, SeedClient } from '@atproto/dev-env' import basicSeed from '../seeds/basic' -import { - REASONOTHER, - REASONSPAM, -} from '@atproto/api/src/client/types/com/atproto/moderation/defs' import { forSnapshot } from '../_util' describe('proxies admin requests', () => { @@ -77,7 +73,7 @@ describe('proxies admin requests', () => { const { data: reportA } = await agent.api.com.atproto.moderation.createReport( { - reasonType: REASONSPAM, + reasonType: 'com.atproto.moderation.defs#reasonSpam', subject: { $type: 'com.atproto.admin.defs#repoRef', did: sc.dids.bob, @@ -91,7 +87,7 @@ describe('proxies admin requests', () => { const { data: reportB } = await agent.api.com.atproto.moderation.createReport( { - reasonType: REASONOTHER, + reasonType: 'com.atproto.moderation.defs#reasonOther', reason: 'impersonation', subject: { $type: 'com.atproto.admin.defs#repoRef', diff --git a/packages/pds/tests/races.test.ts b/packages/pds/tests/races.test.ts index fc65dab664c..d595b2ef397 100644 --- a/packages/pds/tests/races.test.ts +++ b/packages/pds/tests/races.test.ts @@ -17,6 +17,7 @@ describe('races', () => { network = await TestNetworkNoAppView.create({ dbPostgresSchema: 'races', }) + // @ts-expect-error Error due to circular dependency with the dev-env package ctx = network.pds.ctx agent = network.pds.getClient() await agent.createAccount({ diff --git a/packages/pds/tests/sequencer.test.ts b/packages/pds/tests/sequencer.test.ts index 82308b4db35..cec8481baac 100644 --- a/packages/pds/tests/sequencer.test.ts +++ b/packages/pds/tests/sequencer.test.ts @@ -19,6 +19,7 @@ describe('sequencer', () => { network = await TestNetworkNoAppView.create({ dbPostgresSchema: 'sequencer', }) + // @ts-expect-error Error due to circular dependency with the dev-env package sequencer = network.pds.ctx.sequencer sc = network.getSeedClient() await userSeed(sc) diff --git a/packages/pds/tests/sync/subscribe-repos.test.ts b/packages/pds/tests/sync/subscribe-repos.test.ts index d6f11cc4121..00cd15753fa 100644 --- a/packages/pds/tests/sync/subscribe-repos.test.ts +++ b/packages/pds/tests/sync/subscribe-repos.test.ts @@ -42,6 +42,7 @@ describe('repo subscribe repos', () => { }, }) serverHost = network.pds.url.replace('http://', '') + // @ts-expect-error Error due to circular dependency with the dev-env package ctx = network.pds.ctx agent = network.pds.getClient() sc = network.getSeedClient() diff --git a/packages/pds/tsconfig.build.json b/packages/pds/tsconfig.build.json index 02a84823b65..944827a6f62 100644 --- a/packages/pds/tsconfig.build.json +++ b/packages/pds/tsconfig.build.json @@ -1,4 +1,9 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/node.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "noUnusedLocals": false + }, + "include": ["./src"] } diff --git a/packages/pds/tsconfig.json b/packages/pds/tsconfig.json index daf8ee1a04a..1f3ab3c0ec4 100644 --- a/packages/pds/tsconfig.json +++ b/packages/pds/tsconfig.json @@ -1,23 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "module": "nodenext", - "include": ["./src", "__tests__/**/**.ts"], + "include": [], "references": [ - { "path": "../api/tsconfig.build.json" }, - { "path": "../aws/tsconfig.build.json" }, - { "path": "../common/tsconfig.build.json" }, - { "path": "../crypto/tsconfig.build.json" }, - { "path": "../identity/tsconfig.build.json" }, - { "path": "../identifier/tsconfig.build.json" }, - { "path": "../lexicon/tsconfig.build.json" }, - { "path": "../lex-cli/tsconfig.build.json" }, - { "path": "../repo/tsconfig.build.json" }, - { "path": "../uri/tsconfig.build.json" }, - { "path": "../xrpc-server/tsconfig.build.json" } + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } ] } diff --git a/packages/pds/tsconfig.tests.json b/packages/pds/tsconfig.tests.json new file mode 100644 index 00000000000..7fac0ed90d5 --- /dev/null +++ b/packages/pds/tsconfig.tests.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": ".", + "noUnusedLocals": false + }, + "include": ["./tests"] +} diff --git a/packages/repo/babel.config.js b/packages/repo/babel.config.js deleted file mode 100644 index 0126e9dbaa6..00000000000 --- a/packages/repo/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config.js') diff --git a/packages/repo/build.js b/packages/repo/build.js deleted file mode 100644 index e880ae9930b..00000000000 --- a/packages/repo/build.js +++ /dev/null @@ -1,14 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/repo/jest.bench.config.js b/packages/repo/jest.bench.config.js deleted file mode 100644 index 3207cdd8b97..00000000000 --- a/packages/repo/jest.bench.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const base = require('./jest.config') - -module.exports = { - ...base, - roots: ['/bench'], - testRegex: '(.*.bench)', - testTimeout: 3000000, -} diff --git a/packages/repo/jest.config.js b/packages/repo/jest.config.js index 57136979d86..3c34b5882cf 100644 --- a/packages/repo/jest.config.js +++ b/packages/repo/jest.config.js @@ -1,6 +1,6 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'Repo', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/repo/package.json b/packages/repo/package.json index 593739f5c05..069187fb4e9 100644 --- a/packages/repo/package.json +++ b/packages/repo/package.json @@ -13,31 +13,25 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/repo" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "test": "jest", "test:profile": "node --inspect ../../node_modules/.bin/jest", - "bench": "jest --config jest.bench.config.js", - "bench:profile": "node --inspect-brk ../../node_modules/.bin/jest --config jest.bench.config.js", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/repo" + "build": "tsc --build tsconfig.build.json" }, "dependencies": { "@atproto/common": "workspace:^", "@atproto/common-web": "workspace:^", "@atproto/crypto": "workspace:^", - "@atproto/identity": "workspace:^", "@atproto/lexicon": "workspace:^", - "@atproto/syntax": "workspace:^", "@ipld/car": "^3.2.3", "@ipld/dag-cbor": "^7.0.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.21.4" + }, + "devDependencies": { + "jest": "^28.1.2" } } diff --git a/packages/repo/src/mst/mst.ts b/packages/repo/src/mst/mst.ts index 80458d9dc61..1a44aafdc65 100644 --- a/packages/repo/src/mst/mst.ts +++ b/packages/repo/src/mst/mst.ts @@ -3,7 +3,7 @@ import { CID } from 'multiformats' import { ReadableBlockstore } from '../storage' import { schema as common, cidForCbor, dataToCborBlock } from '@atproto/common' -import { BlockWriter } from '@ipld/car/api' +import { BlockWriter } from '@ipld/car/writer' import * as util from './util' import BlockMap from '../block-map' import CidSet from '../cid-set' diff --git a/packages/repo/src/types.ts b/packages/repo/src/types.ts index e9debe013ed..228300dd37f 100644 --- a/packages/repo/src/types.ts +++ b/packages/repo/src/types.ts @@ -2,7 +2,6 @@ import { z } from 'zod' import { def as commonDef } from '@atproto/common-web' import { schema as common } from '@atproto/common' import { CID } from 'multiformats' -import * as car from '@ipld/car/api' import BlockMap from './block-map' import { RepoRecord } from '@atproto/lexicon' import CidSet from './cid-set' @@ -174,4 +173,7 @@ export type VerifiedRepo = { commit: CommitData } -export type CarBlock = car.Block +export type CarBlock = { + cid: CID + bytes: Uint8Array +} diff --git a/packages/repo/src/util.ts b/packages/repo/src/util.ts index 5d52eb565a5..d6ef28f75e1 100644 --- a/packages/repo/src/util.ts +++ b/packages/repo/src/util.ts @@ -1,7 +1,7 @@ import { setImmediate } from 'node:timers/promises' import { CID } from 'multiformats/cid' import * as cbor from '@ipld/dag-cbor' -import { CarBlockIterator } from '@ipld/car' +import { CarBlockIterator } from '@ipld/car/iterator' import { BlockWriter, CarWriter } from '@ipld/car/writer' import { streamToBuffer, diff --git a/packages/repo/tests/_util.ts b/packages/repo/tests/_util.ts index 9942cff7568..206f2bad541 100644 --- a/packages/repo/tests/_util.ts +++ b/packages/repo/tests/_util.ts @@ -24,6 +24,7 @@ type IdMapping = Record export const randomCid = async (storage?: RepoStorage): Promise => { const block = await dataToCborBlock({ test: randomStr(50) }) if (storage) { + // @ts-expect-error FIXME remove this comment (and fix the TS error) await storage.putBlock(block.cid, block.bytes) } return block.cid @@ -189,6 +190,7 @@ export const pathsForOps = (ops: RecordWriteOp[]): RecordPath[] => export const saveMst = async (storage: RepoStorage, mst: MST): Promise => { const diff = await mst.getUnstoredBlocks() + // @ts-expect-error FIXME remove this comment (and fix the TS error) await storage.putMany(diff.blocks) return diff.root } @@ -215,6 +217,8 @@ export const addBadCommit = async ( sig: await keypair.sign(randomBytes(256)), } const commitCid = await newBlocks.add(commit) + + // @ts-expect-error FIXME remove this comment (and fix the TS error) await repo.storage.applyCommit({ cid: commitCid, rev, diff --git a/packages/repo/tsconfig.build.json b/packages/repo/tsconfig.build.json index 02a84823b65..fafdab3d6f7 100644 --- a/packages/repo/tsconfig.build.json +++ b/packages/repo/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/node.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/repo/tsconfig.json b/packages/repo/tsconfig.json index 07c54d2c4d7..1f3ab3c0ec4 100644 --- a/packages/repo/tsconfig.json +++ b/packages/repo/tsconfig.json @@ -1,15 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src", "__tests__/**/**.ts"], + "include": [], "references": [ - { "path": "../common/tsconfig.build.json" }, - { "path": "../crypto/tsconfig.build.json" }, - { "path": "../identity/tsconfig.build.json" }, - { "path": "../nsid/tsconfig.build.json" } + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } ] } diff --git a/packages/repo/tsconfig.tests.json b/packages/repo/tsconfig.tests.json new file mode 100644 index 00000000000..c192c436e23 --- /dev/null +++ b/packages/repo/tsconfig.tests.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./tests"] +} diff --git a/packages/syntax/babel.config.js b/packages/syntax/babel.config.js deleted file mode 100644 index 0126e9dbaa6..00000000000 --- a/packages/syntax/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config.js') diff --git a/packages/syntax/build.js b/packages/syntax/build.js deleted file mode 100644 index 5628aa4f4eb..00000000000 --- a/packages/syntax/build.js +++ /dev/null @@ -1,22 +0,0 @@ -const pkgJson = require('@npmcli/package-json') -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -if (process.argv.includes('--update-main-to-dist')) { - return pkgJson - .load(__dirname) - .then((pkg) => pkg.update({ main: 'dist/index.js' })) - .then((pkg) => pkg.save()) -} - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/syntax/jest.config.js b/packages/syntax/jest.config.js index 08a81143eda..90d955c21ab 100644 --- a/packages/syntax/jest.config.js +++ b/packages/syntax/jest.config.js @@ -1,6 +1,6 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'Syntax', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/syntax/package.json b/packages/syntax/package.json index 5bb951aa313..1d93da7c5b5 100644 --- a/packages/syntax/package.json +++ b/packages/syntax/package.json @@ -15,16 +15,15 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/syntax" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "test": "jest", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/syntax" + "build": "tsc --build tsconfig.build.json" + }, + "dependencies": {}, + "devDependencies": { + "jest": "^28.1.2" }, "browser": { "dns/promises": false diff --git a/packages/syntax/tsconfig.build.json b/packages/syntax/tsconfig.build.json index 02a84823b65..436d8ecb628 100644 --- a/packages/syntax/tsconfig.build.json +++ b/packages/syntax/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/isomorphic.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/syntax/tsconfig.json b/packages/syntax/tsconfig.json index db7a7c4ad35..1f3ab3c0ec4 100644 --- a/packages/syntax/tsconfig.json +++ b/packages/syntax/tsconfig.json @@ -1,10 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src", "__tests__/**/**.ts"], - "references": [{ "path": "../common/tsconfig.build.json" }] + "include": [], + "references": [ + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } + ] } diff --git a/packages/syntax/tsconfig.tests.json b/packages/syntax/tsconfig.tests.json new file mode 100644 index 00000000000..c192c436e23 --- /dev/null +++ b/packages/syntax/tsconfig.tests.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./tests"] +} diff --git a/packages/xrpc-server/babel.config.js b/packages/xrpc-server/babel.config.js deleted file mode 100644 index 0126e9dbaa6..00000000000 --- a/packages/xrpc-server/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config.js') diff --git a/packages/xrpc-server/build.js b/packages/xrpc-server/build.js deleted file mode 100644 index e880ae9930b..00000000000 --- a/packages/xrpc-server/build.js +++ /dev/null @@ -1,14 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/xrpc-server/jest.config.js b/packages/xrpc-server/jest.config.js index 81ec7cce52f..1ecdecded6d 100644 --- a/packages/xrpc-server/jest.config.js +++ b/packages/xrpc-server/jest.config.js @@ -1,6 +1,7 @@ -const base = require('../../jest.config.base.js') - +/** @type {import('jest').Config} */ module.exports = { - ...base, displayName: 'XRPC Server', + transform: { '^.+\\.(t|j)s$': '@swc/jest' }, + transformIgnorePatterns: [`/node_modules/(?!get-port)`], + setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/xrpc-server/package.json b/packages/xrpc-server/package.json index a5e7e3ca37d..3e65ea9e4d8 100644 --- a/packages/xrpc-server/package.json +++ b/packages/xrpc-server/package.json @@ -13,16 +13,11 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/xrpc-server" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "test": "jest", - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/xrpc-server" + "build": "tsc --build tsconfig.build.json" }, "dependencies": { "@atproto/common": "workspace:^", @@ -46,6 +41,7 @@ "@types/ws": "^8.5.4", "get-port": "^6.1.2", "jose": "^4.15.4", + "jest": "^28.1.2", "key-encoder": "^2.0.3", "multiformats": "^9.9.0" } diff --git a/packages/xrpc-server/src/server.ts b/packages/xrpc-server/src/server.ts index 75621136995..6510429c1e5 100644 --- a/packages/xrpc-server/src/server.ts +++ b/packages/xrpc-server/src/server.ts @@ -1,5 +1,10 @@ import { Readable } from 'stream' import express, { + Application, + Express, + Router, + Request, + Response, ErrorRequestHandler, NextFunction, RequestHandler, @@ -37,7 +42,6 @@ import { isShared, RateLimitExceededError, HandlerPipeThrough, - handlerPipeThrough, } from './types' import { decodeQueryParams, @@ -53,8 +57,8 @@ export function createServer(lexicons?: LexiconDoc[], options?: Options) { } export class Server { - router = express() - routes = express.Router() + router: Express = express() + routes: Router = express.Router() subscriptions = new Map() lex = new Lexicons() options: Options @@ -70,7 +74,7 @@ export class Server { this.router.use(this.routes) this.router.use('/xrpc/:methodId', this.catchall.bind(this)) this.router.use(errorMiddleware) - this.router.once('mount', (app: express.Application) => { + this.router.once('mount', (app: Application) => { this.enableStreamingOnListen(app) }) this.options = opts ?? {} @@ -179,11 +183,7 @@ export class Server { ) } - async catchall( - req: express.Request, - _res: express.Response, - next: NextFunction, - ) { + async catchall(req: Request, _res: Response, next: NextFunction) { const def = this.lex.getDef(req.params.methodId) if (!def) { return next(new MethodNotImplementedError()) @@ -213,7 +213,7 @@ export class Server { const routeOpts = { blobLimit: routeCfg.opts?.blobLimit ?? this.options.payload?.blobLimit, } - const validateReqInput = (req: express.Request) => + const validateReqInput = (req: Request) => validateInput(nsid, def, req, routeOpts, this.lex) const validateResOutput = this.options.validateResponse === false @@ -390,7 +390,7 @@ export class Server { ) } - private enableStreamingOnListen(app: express.Application) { + private enableStreamingOnListen(app: Application) { const _listen = app.listen app.listen = (...args) => { // @ts-ignore the args spread diff --git a/packages/xrpc-server/src/stream/frames.ts b/packages/xrpc-server/src/stream/frames.ts index cb171c7172e..866277d3f5a 100644 --- a/packages/xrpc-server/src/stream/frames.ts +++ b/packages/xrpc-server/src/stream/frames.ts @@ -11,7 +11,7 @@ import { } from './types' export abstract class Frame { - header: FrameHeader + abstract header: FrameHeader body: unknown get op(): FrameType { return this.header.op diff --git a/packages/xrpc-server/src/stream/websocket-keepalive.ts b/packages/xrpc-server/src/stream/websocket-keepalive.ts index 696a058df5c..8efeee4e6f3 100644 --- a/packages/xrpc-server/src/stream/websocket-keepalive.ts +++ b/packages/xrpc-server/src/stream/websocket-keepalive.ts @@ -80,7 +80,7 @@ export class WebSocketKeepAlive { startHeartbeat(ws: WebSocket) { let isAlive = true - let heartbeatInterval: NodeJS.Timer | null = null + let heartbeatInterval: NodeJS.Timeout | null = null const checkAlive = () => { if (!isAlive) { @@ -145,6 +145,7 @@ function forwardSignal(signal: AbortSignal, ac: AbortController) { return ac.abort(signal.reason) } else { signal.addEventListener('abort', () => ac.abort(signal.reason), { + // @ts-ignore https://github.com/DefinitelyTyped/DefinitelyTyped/pull/68625 signal: ac.signal, }) } diff --git a/packages/xrpc-server/tests/bodies.test.ts b/packages/xrpc-server/tests/bodies.test.ts index 072299cdcd7..6ff0f8ed980 100644 --- a/packages/xrpc-server/tests/bodies.test.ts +++ b/packages/xrpc-server/tests/bodies.test.ts @@ -274,9 +274,9 @@ describe('Bodies', () => { const resBody = await res.json() const status = res.status expect(status).toBe(400) - expect(resBody.error).toBe('InvalidRequest') - expect(resBody.message).toBe( - 'Request encoding (Content-Type) required but not provided', - ) + expect(resBody).toMatchObject({ + error: 'InvalidRequest', + message: 'Request encoding (Content-Type) required but not provided', + }) }) }) diff --git a/packages/xrpc-server/tests/errors.test.ts b/packages/xrpc-server/tests/errors.test.ts index c7781e71907..05da883a771 100644 --- a/packages/xrpc-server/tests/errors.test.ts +++ b/packages/xrpc-server/tests/errors.test.ts @@ -75,7 +75,7 @@ const LEXICONS: LexiconDoc[] = [ }, ] -const MISMATCHED_LEXICONS = [ +const MISMATCHED_LEXICONS: LexiconDoc[] = [ { lexicon: 1, id: 'io.example.query', diff --git a/packages/xrpc-server/tsconfig.build.json b/packages/xrpc-server/tsconfig.build.json index 02a84823b65..fafdab3d6f7 100644 --- a/packages/xrpc-server/tsconfig.build.json +++ b/packages/xrpc-server/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/node.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/xrpc-server/tsconfig.json b/packages/xrpc-server/tsconfig.json index 6a9622be37f..1f3ab3c0ec4 100644 --- a/packages/xrpc-server/tsconfig.json +++ b/packages/xrpc-server/tsconfig.json @@ -1,15 +1,7 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src", "__tests__/**/**.ts"], + "include": [], "references": [ - { "path": "../common/tsconfig.build.json" }, - { "path": "../crypto/tsconfig.build.json" }, - { "path": "../lexicon/tsconfig.build.json" }, - { "path": "../xrpc/tsconfig.build.json" } + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.tests.json" } ] } diff --git a/packages/xrpc-server/tsconfig.tests.json b/packages/xrpc-server/tsconfig.tests.json new file mode 100644 index 00000000000..c192c436e23 --- /dev/null +++ b/packages/xrpc-server/tsconfig.tests.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig/tests.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./tests"] +} diff --git a/packages/xrpc/babel.config.js b/packages/xrpc/babel.config.js deleted file mode 100644 index 0126e9dbaa6..00000000000 --- a/packages/xrpc/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config.js') diff --git a/packages/xrpc/build.js b/packages/xrpc/build.js deleted file mode 100644 index e880ae9930b..00000000000 --- a/packages/xrpc/build.js +++ /dev/null @@ -1,14 +0,0 @@ -const { nodeExternalsPlugin } = require('esbuild-node-externals') - -const buildShallow = - process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true' - -require('esbuild').build({ - logLevel: 'info', - entryPoints: ['src/index.ts'], - bundle: true, - sourcemap: true, - outdir: 'dist', - platform: 'node', - plugins: buildShallow ? [nodeExternalsPlugin()] : [], -}) diff --git a/packages/xrpc/package.json b/packages/xrpc/package.json index 387fa06c2b9..d24b889478a 100644 --- a/packages/xrpc/package.json +++ b/packages/xrpc/package.json @@ -13,18 +13,16 @@ "url": "https://github.com/bluesky-social/atproto", "directory": "packages/xrpc" }, - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "types": "dist/index.d.ts" - }, + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { - "build": "node ./build.js", - "postbuild": "tsc --build tsconfig.build.json", - "update-main-to-dist": "node ../../update-main-to-dist.js packages/xrpc" + "build": "tsc --build tsconfig.build.json" }, "dependencies": { "@atproto/lexicon": "workspace:^", "zod": "^3.21.4" + }, + "devDependencies": { + "typescript": "^5.3.3" } } diff --git a/packages/xrpc/tsconfig.build.json b/packages/xrpc/tsconfig.build.json index 02a84823b65..436d8ecb628 100644 --- a/packages/xrpc/tsconfig.build.json +++ b/packages/xrpc/tsconfig.build.json @@ -1,4 +1,8 @@ { - "extends": "./tsconfig.json", - "exclude": ["**/*.spec.ts", "**/*.test.ts"] + "extends": "../../tsconfig/isomorphic.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src"] } diff --git a/packages/xrpc/tsconfig.json b/packages/xrpc/tsconfig.json index 72f1ae0e0f3..e84b8178b47 100644 --- a/packages/xrpc/tsconfig.json +++ b/packages/xrpc/tsconfig.json @@ -1,13 +1,4 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", // Your outDir, - "emitDeclarationOnly": true - }, - "include": ["./src", "__tests__/**/**.ts"], - "references": [ - { "path": "../common/tsconfig.build.json" }, - { "path": "../lexicon/tsconfig.build.json" } - ] + "include": [], + "references": [{ "path": "./tsconfig.build.json" }] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b59be273d6c..b5e35aefa41 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: devDependencies: + '@atproto/dev-env': + specifier: workspace:^ + version: link:packages/dev-env '@babel/core': specifier: ^7.18.6 version: 7.18.6 @@ -20,9 +23,6 @@ importers: '@changesets/cli': specifier: ^2.26.2 version: 2.26.2 - '@npmcli/package-json': - specifier: ^3.0.0 - version: 3.0.0 '@swc/core': specifier: ^1.3.42 version: 1.3.42 @@ -33,8 +33,8 @@ importers: specifier: ^28.1.4 version: 28.1.4 '@types/node': - specifier: ^18.0.0 - version: 18.0.0 + specifier: ^18.19.24 + version: 18.19.24 '@typescript-eslint/eslint-plugin': specifier: ^6.14.0 version: 6.18.1(@typescript-eslint/parser@6.18.1)(eslint@8.24.0)(typescript@5.3.3) @@ -47,15 +47,6 @@ importers: dotenv: specifier: ^16.0.3 version: 16.0.3 - esbuild: - specifier: ^0.14.48 - version: 0.14.48 - esbuild-node-externals: - specifier: ^1.5.0 - version: 1.5.0(esbuild@0.14.48) - esbuild-plugin-handlebars: - specifier: ^1.0.2 - version: 1.0.2 eslint: specifier: ^8.24.0 version: 8.24.0 @@ -65,12 +56,9 @@ importers: eslint-plugin-prettier: specifier: ^4.2.1 version: 4.2.1(eslint-config-prettier@8.5.0)(eslint@8.24.0)(prettier@2.7.1) - handlebars-jest: - specifier: ^1.0.0 - version: 1.0.0 jest: specifier: ^28.1.2 - version: 28.1.2(@types/node@18.0.0)(ts-node@10.8.2) + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) node-gyp: specifier: ^9.3.1 version: 9.3.1 @@ -83,9 +71,6 @@ importers: prettier-config-standard: specifier: ^5.0.0 version: 5.0.0(prettier@2.7.1) - ts-node: - specifier: ^10.8.2 - version: 10.8.2(@swc/core@1.3.42)(@types/node@18.0.0)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -111,15 +96,15 @@ importers: specifier: ^1.234.0 version: 1.234.0 devDependencies: - '@atproto/dev-env': - specifier: workspace:^ - version: link:../dev-env '@atproto/lex-cli': specifier: workspace:^ version: link:../lex-cli get-port: specifier: ^6.1.2 version: 6.1.2 + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) packages/aws: dependencies: @@ -250,9 +235,6 @@ importers: specifier: 3.0.0 version: 3.0.0 devDependencies: - '@atproto/dev-env': - specifier: workspace:^ - version: link:../dev-env '@atproto/lex-cli': specifier: workspace:^ version: link:../lex-cli @@ -292,9 +274,12 @@ importers: axios: specifier: ^0.27.2 version: 0.27.2 - http2-express-bridge: - specifier: ^1.0.7 - version: 1.0.7 + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) + ts-node: + specifier: ^10.8.2 + version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.24)(typescript@5.3.3) packages/bsync: dependencies: @@ -341,6 +326,12 @@ importers: '@types/pg': specifier: ^8.6.6 version: 8.6.6 + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) + ts-node: + specifier: ^10.8.2 + version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.24)(typescript@5.3.3) packages/common: dependencies: @@ -362,6 +353,16 @@ importers: pino: specifier: ^8.15.0 version: 8.15.0 + devDependencies: + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) + typescript: + specifier: ^5.3.3 + version: 5.3.3 + uint8arrays: + specifier: 3.0.0 + version: 3.0.0 packages/common-web: dependencies: @@ -377,6 +378,10 @@ importers: zod: specifier: ^3.21.4 version: 3.21.4 + devDependencies: + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) packages/crypto: dependencies: @@ -393,6 +398,9 @@ importers: '@atproto/common': specifier: workspace:^ version: link:../common + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) packages/dev-env: dependencies: @@ -438,9 +446,6 @@ importers: axios: specifier: ^0.27.2 version: 0.27.2 - better-sqlite3: - specifier: ^9.4.0 - version: 9.4.0 dotenv: specifier: ^16.0.3 version: 16.0.3 @@ -453,16 +458,9 @@ importers: multiformats: specifier: ^9.9.0 version: 9.9.0 - sharp: - specifier: ^0.32.6 - version: 0.32.6 uint8arrays: specifier: 3.0.0 version: 3.0.0 - devDependencies: - ts-node: - specifier: ^10.8.1 - version: 10.8.2(@swc/core@1.3.42)(@types/node@18.17.8)(typescript@5.3.3) packages/identity: dependencies: @@ -491,6 +489,9 @@ importers: get-port: specifier: ^6.1.2 version: 6.1.2 + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) packages/lex-cli: dependencies: @@ -501,8 +502,8 @@ importers: specifier: workspace:^ version: link:../syntax chalk: - specifier: ^5.1.1 - version: 5.1.1 + specifier: ^4.1.2 + version: 4.1.2 commander: specifier: ^9.4.0 version: 9.4.0 @@ -533,6 +534,10 @@ importers: zod: specifier: ^3.21.4 version: 3.21.4 + devDependencies: + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) packages/ozone: dependencies: @@ -554,12 +559,18 @@ importers: '@atproto/syntax': specifier: workspace:^ version: link:../syntax + '@atproto/xrpc': + specifier: workspace:^ + version: link:../xrpc '@atproto/xrpc-server': specifier: workspace:^ version: link:../xrpc-server '@did-plc/lib': specifier: ^0.0.1 version: 0.0.1 + axios: + specifier: ^1.6.7 + version: 1.6.7 compression: specifier: ^1.7.4 version: 1.7.4 @@ -594,18 +605,12 @@ importers: specifier: 3.0.0 version: 3.0.0 devDependencies: - '@atproto/dev-env': - specifier: workspace:^ - version: link:../dev-env '@atproto/lex-cli': specifier: workspace:^ version: link:../lex-cli '@atproto/pds': specifier: workspace:^ version: link:../pds - '@atproto/xrpc': - specifier: workspace:^ - version: link:../xrpc '@did-plc/server': specifier: ^0.0.1 version: 0.0.1 @@ -624,12 +629,12 @@ importers: '@types/qs': specifier: ^6.9.7 version: 6.9.7 - axios: - specifier: ^0.27.2 - version: 0.27.2 - nodemailer: - specifier: ^6.8.0 - version: 6.8.0 + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) + ts-node: + specifier: ^10.8.2 + version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.24)(typescript@5.3.3) packages/pds: dependencies: @@ -690,6 +695,9 @@ importers: file-type: specifier: ^16.5.4 version: 16.5.4 + glob: + specifier: ^10.3.10 + version: 10.3.10 handlebars: specifier: ^4.7.7 version: 4.7.7 @@ -742,9 +750,6 @@ importers: '@atproto/bsky': specifier: workspace:^ version: link:../bsky - '@atproto/dev-env': - specifier: workspace:^ - version: link:../dev-env '@atproto/lex-cli': specifier: workspace:^ version: link:../lex-cli @@ -775,9 +780,21 @@ importers: axios: specifier: ^0.27.2 version: 0.27.2 + esbuild: + specifier: ^0.14.48 + version: 0.14.48 + esbuild-plugin-handlebars: + specifier: ^1.0.3 + version: 1.0.3 get-port: specifier: ^6.1.2 version: 6.1.2 + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) + ts-node: + specifier: ^10.8.2 + version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.24)(typescript@5.3.3) ws: specifier: ^8.12.0 version: 8.12.0 @@ -793,15 +810,9 @@ importers: '@atproto/crypto': specifier: workspace:^ version: link:../crypto - '@atproto/identity': - specifier: workspace:^ - version: link:../identity '@atproto/lexicon': specifier: workspace:^ version: link:../lexicon - '@atproto/syntax': - specifier: workspace:^ - version: link:../syntax '@ipld/car': specifier: ^3.2.3 version: 3.2.3 @@ -817,8 +828,16 @@ importers: zod: specifier: ^3.21.4 version: 3.21.4 + devDependencies: + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) - packages/syntax: {} + packages/syntax: + devDependencies: + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) packages/xrpc: dependencies: @@ -828,6 +847,10 @@ importers: zod: specifier: ^3.21.4 version: 3.21.4 + devDependencies: + typescript: + specifier: ^5.3.3 + version: 5.3.3 packages/xrpc-server: dependencies: @@ -883,6 +906,9 @@ importers: get-port: specifier: ^6.1.2 version: 6.1.2 + jest: + specifier: ^28.1.2 + version: 28.1.2(@types/node@18.19.24)(ts-node@10.8.2) jose: specifier: ^4.15.4 version: 4.15.4 @@ -928,12 +954,6 @@ importers: services/pds: dependencies: - '@atproto/aws': - specifier: workspace:^ - version: link:../../packages/aws - '@atproto/crypto': - specifier: workspace:^ - version: link:../../packages/crypto '@atproto/pds': specifier: workspace:^ version: link:../../packages/pds @@ -945,7 +965,7 @@ importers: version: 4.20.0 opentelemetry-plugin-better-sqlite3: specifier: ^1.1.0 - version: 1.1.0(better-sqlite3@9.4.0) + version: 1.1.0(better-sqlite3@9.4.1) packages: @@ -5024,7 +5044,7 @@ packages: '@atproto/common': 0.1.1 '@atproto/crypto': 0.1.0 '@ipld/dag-cbor': 7.0.3 - axios: 1.6.2 + axios: 1.6.7 multiformats: 9.9.0 uint8arrays: 3.0.0 zod: 3.21.4 @@ -5136,6 +5156,18 @@ packages: cborg: 1.10.2 multiformats: 9.9.0 + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: false + /@istanbuljs/load-nyc-config@1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -5157,7 +5189,7 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: '@jest/types': 28.1.3 - '@types/node': 18.17.8 + '@types/node': 18.19.24 chalk: 4.1.2 jest-message-util: 28.1.3 jest-util: 28.1.3 @@ -5178,14 +5210,14 @@ packages: '@jest/test-result': 28.1.3 '@jest/transform': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 18.17.8 + '@types/node': 18.19.24 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.8.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 28.1.3 - jest-config: 28.1.3(@types/node@18.17.8)(ts-node@10.8.2) + jest-config: 28.1.3(@types/node@18.19.24)(ts-node@10.8.2) jest-haste-map: 28.1.3 jest-message-util: 28.1.3 jest-regex-util: 28.0.2 @@ -5220,7 +5252,7 @@ packages: dependencies: '@jest/fake-timers': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 18.17.8 + '@types/node': 18.19.24 jest-mock: 28.1.3 dev: true @@ -5247,7 +5279,7 @@ packages: dependencies: '@jest/types': 28.1.3 '@sinonjs/fake-timers': 9.1.2 - '@types/node': 18.17.8 + '@types/node': 18.19.24 jest-message-util: 28.1.3 jest-mock: 28.1.3 jest-util: 28.1.3 @@ -5279,7 +5311,7 @@ packages: '@jest/transform': 28.1.3 '@jest/types': 28.1.3 '@jridgewell/trace-mapping': 0.3.19 - '@types/node': 18.17.8 + '@types/node': 18.19.24 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -5367,7 +5399,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.17.8 + '@types/node': 18.19.24 '@types/yargs': 16.0.5 chalk: 4.1.2 dev: true @@ -5379,7 +5411,7 @@ packages: '@jest/schemas': 28.1.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.17.8 + '@types/node': 18.19.24 '@types/yargs': 17.0.24 chalk: 4.1.2 dev: true @@ -5490,13 +5522,6 @@ packages: rimraf: 3.0.2 dev: true - /@npmcli/package-json@3.0.0: - resolution: {integrity: sha512-NnuPuM97xfiCpbTEJYtEuKz6CFbpUHtaT0+5via5pQeI25omvQDFbp1GcGJ/c4zvL/WX0qbde6YiLgfZbWFgvg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - dependencies: - json-parse-even-better-errors: 3.0.0 - dev: true - /@opentelemetry/api@1.7.0: resolution: {integrity: sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==} engines: {node: '>=8.0.0'} @@ -5549,6 +5574,13 @@ packages: engines: {node: '>=14'} dev: false + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: false + optional: true + /@protobufjs/aspromise@1.1.2: resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} dev: false @@ -5806,18 +5838,18 @@ packages: /@types/bn.js@5.1.1: resolution: {integrity: sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==} dependencies: - '@types/node': 18.17.8 + '@types/node': 18.19.24 /@types/body-parser@1.19.2: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: '@types/connect': 3.4.35 - '@types/node': 18.17.8 + '@types/node': 18.19.24 /@types/connect@3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 18.17.8 + '@types/node': 18.19.24 /@types/cors@2.8.12: resolution: {integrity: sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==} @@ -5861,7 +5893,7 @@ packages: /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: - '@types/node': 18.17.8 + '@types/node': 18.19.24 dev: true /@types/http-errors@2.0.1: @@ -5914,13 +5946,14 @@ packages: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} dev: true - /@types/node@18.0.0: - resolution: {integrity: sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==} - dev: true - /@types/node@18.17.8: resolution: {integrity: sha512-Av/7MqX/iNKwT9Tr60V85NqMnsmh8ilfJoBlIVibkXfitk9Q22D9Y5mSpm+FvG5DET7EbVfB40bOiLzKgYFgPw==} + /@types/node@18.19.24: + resolution: {integrity: sha512-eghAz3gnbQbvnHqB+mgB2ZR3aH6RhdEmHGS48BnV75KceQPHqabkxKI0BbUSsqhqy2Ddhc2xD/VAR9ySZd57Lw==} + dependencies: + undici-types: 5.26.5 + /@types/nodemailer@6.4.6: resolution: {integrity: sha512-pD6fL5GQtUKvD2WnPmg5bC2e8kWCAPDwMPmHe/ohQbW+Dy0EcHgZ2oCSuPlWNqk74LS5BVMig1SymQbFMPPK3w==} dependencies: @@ -5957,14 +5990,14 @@ packages: resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} dependencies: '@types/mime': 1.3.2 - '@types/node': 18.17.8 + '@types/node': 18.19.24 /@types/serve-static@1.15.2: resolution: {integrity: sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==} dependencies: '@types/http-errors': 2.0.1 '@types/mime': 3.0.1 - '@types/node': 18.17.8 + '@types/node': 18.19.24 /@types/shimmer@1.0.5: resolution: {integrity: sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==} @@ -6245,7 +6278,11 @@ packages: /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: true + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: false /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} @@ -6259,13 +6296,17 @@ packages: engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: true /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} dev: true + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: false + /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -6388,6 +6429,15 @@ packages: transitivePeerDependencies: - debug + /axios@1.6.7: + resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} + dependencies: + follow-redirects: 1.15.5 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + /b4a@1.6.4: resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==} @@ -6537,6 +6587,14 @@ packages: bindings: 1.5.0 prebuild-install: 7.1.1 + /better-sqlite3@9.4.1: + resolution: {integrity: sha512-QpqiQeMI4WkE+dQ68zTMX5OzlPGc7lXIDP1iKUt4Omt9PdaVgzKYxHIJRIzt1E+RUBQoFmkip/IbvzyrxehAIg==} + requiresBuild: true + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.1 + dev: false + /big-integer@1.6.51: resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} engines: {node: '>=0.6'} @@ -6766,12 +6824,6 @@ packages: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true - - /chalk@5.1.1: - resolution: {integrity: sha512-OItMegkSDU3P7OJRWBbNRsQsL8SzgwlIGXSZRVfHCLBYrDgzYDuozwDMwvEDpiZdjr50tdOTbTzuubirtEozsg==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: false /char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} @@ -6825,11 +6877,6 @@ packages: engines: {node: '>=0.8'} dev: true - /clone@2.1.2: - resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} - engines: {node: '>=0.8'} - dev: true - /cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} @@ -6980,7 +7027,6 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true /crypto-randomuuid@1.0.0: resolution: {integrity: sha512-/RC5F4l1SCqD/jazwUF6+t34Cd8zTSAGZ7rvvZu1whZUhD2a5MOGKjSGowoGcpj/cbVZk1ZODIooJEQQq3nNAA==} @@ -7184,19 +7230,10 @@ packages: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} - /depd@1.1.2: - resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} - engines: {node: '>= 0.6'} - dev: true - /depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - /destroy@1.0.4: - resolution: {integrity: sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==} - dev: true - /destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -7278,6 +7315,10 @@ packages: engines: {node: '>=10'} dev: true + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: false + /ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} dependencies: @@ -7309,7 +7350,10 @@ packages: /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: false /encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} @@ -7558,16 +7602,6 @@ packages: dev: true optional: true - /esbuild-node-externals@1.5.0(esbuild@0.14.48): - resolution: {integrity: sha512-9394Ne2t2Z243BWeNBRkXEYVMOVbQuzp7XSkASZTOQs0GSXDuno5aH5OmzEXc6GMuln5zJjpkZpgwUPW0uRKgw==} - peerDependencies: - esbuild: 0.12 - 0.15 - dependencies: - esbuild: 0.14.48 - find-up: 5.0.0 - tslib: 2.3.1 - dev: true - /esbuild-openbsd-64@0.14.48: resolution: {integrity: sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==} engines: {node: '>=12'} @@ -7577,10 +7611,10 @@ packages: dev: true optional: true - /esbuild-plugin-handlebars@1.0.2: - resolution: {integrity: sha512-2U45b8AZV0UdLrdlB5q0siV7J2FfJUeoMb+8qxTpeOmrOna09aox+YRfxUlFWS+OzK3ZDiPdvYnFzuE+YQ2hmw==} + /esbuild-plugin-handlebars@1.0.3: + resolution: {integrity: sha512-vOqurrqU7s4f9xgwDiUG0I+9auJPf21GFf6xYxObRrQdi088N81P4ztCs0xVg0uSmWkIPcZuCLIwP+ttzKpezQ==} dependencies: - handlebars: 4.7.7 + handlebars: 4.7.8 dev: true /esbuild-sunos-64@0.14.48: @@ -8107,12 +8141,29 @@ packages: debug: optional: true + /follow-redirects@1.15.5: + resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 dev: true + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: false + /form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} @@ -8255,6 +8306,18 @@ packages: is-glob: 4.0.3 dev: true + /glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.3 + minipass: 5.0.0 + path-scurry: 1.10.1 + dev: false + /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: @@ -8324,12 +8387,6 @@ packages: /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - /handlebars-jest@1.0.0: - resolution: {integrity: sha512-giA9RSHNLKOqFU2dJ3QapELUJmXb4wmQWIEPc5cYp3Sx4Nwo01PBsTWrwo28cGWC8gRg+seMVMBi7wQtcaqw3g==} - dependencies: - node-cache: 5.1.2 - dev: true - /handlebars@4.7.7: resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} engines: {node: '>=0.4.7'} @@ -8342,6 +8399,19 @@ packages: optionalDependencies: uglify-js: 3.17.4 + /handlebars@4.7.8: + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} + hasBin: true + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.17.4 + dev: true + /hard-rejection@2.1.0: resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} engines: {node: '>=6'} @@ -8359,7 +8429,6 @@ packages: /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dev: true /has-property-descriptors@1.0.0: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} @@ -8445,17 +8514,6 @@ packages: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} dev: true - /http-errors@1.8.1: - resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} - engines: {node: '>= 0.6'} - dependencies: - depd: 1.1.2 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 1.5.0 - toidentifier: 1.0.1 - dev: true - /http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -8486,17 +8544,6 @@ packages: roarr: 7.15.1 type-fest: 2.19.0 - /http2-express-bridge@1.0.7: - resolution: {integrity: sha512-bmzZSyn3nuzXRqs/+WgH7IGOQYMCIZNJeqTJ/1AoDgMPTSP5wXQCxPGsdUbGzzxwiHrMwyT4Z7t8ccbsKqiHrw==} - engines: {node: '>= 10.0.0'} - dependencies: - merge-descriptors: 1.0.1 - send: 0.17.2 - setprototypeof: 1.2.0 - transitivePeerDependencies: - - supports-color - dev: true - /https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} @@ -8699,7 +8746,6 @@ packages: /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: true /is-generator-fn@2.1.0: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} @@ -8805,7 +8851,6 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true /iso-datestring-validator@2.2.2: resolution: {integrity: sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==} @@ -8856,6 +8901,15 @@ packages: istanbul-lib-report: 3.0.1 dev: true + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: false + /jest-changed-files@28.1.3: resolution: {integrity: sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -8872,7 +8926,7 @@ packages: '@jest/expect': 28.1.3 '@jest/test-result': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 18.17.8 + '@types/node': 18.19.24 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -8891,7 +8945,7 @@ packages: - supports-color dev: true - /jest-cli@28.1.3(@types/node@18.0.0)(ts-node@10.8.2): + /jest-cli@28.1.3(@types/node@18.19.24)(ts-node@10.8.2): resolution: {integrity: sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} hasBin: true @@ -8908,7 +8962,7 @@ packages: exit: 0.1.2 graceful-fs: 4.2.11 import-local: 3.1.0 - jest-config: 28.1.3(@types/node@18.0.0)(ts-node@10.8.2) + jest-config: 28.1.3(@types/node@18.19.24)(ts-node@10.8.2) jest-util: 28.1.3 jest-validate: 28.1.3 prompts: 2.4.2 @@ -8919,47 +8973,7 @@ packages: - ts-node dev: true - /jest-config@28.1.3(@types/node@18.0.0)(ts-node@10.8.2): - resolution: {integrity: sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - dependencies: - '@babel/core': 7.18.6 - '@jest/test-sequencer': 28.1.3 - '@jest/types': 28.1.3 - '@types/node': 18.0.0 - babel-jest: 28.1.3(@babel/core@7.18.6) - chalk: 4.1.2 - ci-info: 3.8.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 28.1.3 - jest-environment-node: 28.1.3 - jest-get-type: 28.0.2 - jest-regex-util: 28.0.2 - jest-resolve: 28.1.3 - jest-runner: 28.1.3 - jest-util: 28.1.3 - jest-validate: 28.1.3 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 28.1.3 - slash: 3.0.0 - strip-json-comments: 3.1.1 - ts-node: 10.8.2(@swc/core@1.3.42)(@types/node@18.0.0)(typescript@5.3.3) - transitivePeerDependencies: - - supports-color - dev: true - - /jest-config@28.1.3(@types/node@18.17.8)(ts-node@10.8.2): + /jest-config@28.1.3(@types/node@18.19.24)(ts-node@10.8.2): resolution: {integrity: sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} peerDependencies: @@ -8974,7 +8988,7 @@ packages: '@babel/core': 7.18.6 '@jest/test-sequencer': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 18.17.8 + '@types/node': 18.19.24 babel-jest: 28.1.3(@babel/core@7.18.6) chalk: 4.1.2 ci-info: 3.8.0 @@ -8994,7 +9008,7 @@ packages: pretty-format: 28.1.3 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.8.2(@swc/core@1.3.42)(@types/node@18.0.0)(typescript@5.3.3) + ts-node: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.24)(typescript@5.3.3) transitivePeerDependencies: - supports-color dev: true @@ -9041,7 +9055,7 @@ packages: '@jest/environment': 28.1.3 '@jest/fake-timers': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 18.17.8 + '@types/node': 18.19.24 jest-mock: 28.1.3 jest-util: 28.1.3 dev: true @@ -9057,7 +9071,7 @@ packages: dependencies: '@jest/types': 28.1.3 '@types/graceful-fs': 4.1.6 - '@types/node': 18.17.8 + '@types/node': 18.19.24 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -9108,7 +9122,7 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: '@jest/types': 28.1.3 - '@types/node': 18.17.8 + '@types/node': 18.19.24 dev: true /jest-pnp-resolver@1.2.3(jest-resolve@28.1.3): @@ -9162,7 +9176,7 @@ packages: '@jest/test-result': 28.1.3 '@jest/transform': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 18.17.8 + '@types/node': 18.19.24 chalk: 4.1.2 emittery: 0.10.2 graceful-fs: 4.2.11 @@ -9248,7 +9262,7 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: '@jest/types': 28.1.3 - '@types/node': 18.17.8 + '@types/node': 18.19.24 chalk: 4.1.2 ci-info: 3.8.0 graceful-fs: 4.2.11 @@ -9273,7 +9287,7 @@ packages: dependencies: '@jest/test-result': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 18.17.8 + '@types/node': 18.19.24 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.10.2 @@ -9285,12 +9299,12 @@ packages: resolution: {integrity: sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@types/node': 18.17.8 + '@types/node': 18.19.24 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest@28.1.2(@types/node@18.0.0)(ts-node@10.8.2): + /jest@28.1.2(@types/node@18.19.24)(ts-node@10.8.2): resolution: {integrity: sha512-Tuf05DwLeCh2cfWCQbcz9UxldoDyiR1E9Igaei5khjonKncYdc6LDfynKCEWozK0oLE3GD+xKAo2u8x/0s6GOg==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} hasBin: true @@ -9303,7 +9317,7 @@ packages: '@jest/core': 28.1.3(ts-node@10.8.2) '@jest/types': 28.1.3 import-local: 3.1.0 - jest-cli: 28.1.3(@types/node@18.0.0)(ts-node@10.8.2) + jest-cli: 28.1.3(@types/node@18.19.24)(ts-node@10.8.2) transitivePeerDependencies: - '@types/node' - supports-color @@ -9361,11 +9375,6 @@ packages: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} dev: true - /json-parse-even-better-errors@3.0.0: - resolution: {integrity: sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - dev: true - /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true @@ -9571,6 +9580,11 @@ packages: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} dev: false + /lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} + dev: false + /lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} dependencies: @@ -9741,7 +9755,6 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 - dev: true /minimist-options@4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} @@ -9804,7 +9817,6 @@ packages: /minipass@5.0.0: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} - dev: true /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} @@ -9880,13 +9892,6 @@ packages: /node-addon-api@6.1.0: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} - /node-cache@5.1.2: - resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==} - engines: {node: '>= 8.0.0'} - dependencies: - clone: 2.1.2 - dev: true - /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -10019,13 +10024,6 @@ packages: /on-exit-leak-free@2.1.0: resolution: {integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==} - /on-finished@2.3.0: - resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} - engines: {node: '>= 0.8'} - dependencies: - ee-first: 1.1.1 - dev: true - /on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -10051,7 +10049,7 @@ packages: mimic-fn: 2.1.0 dev: true - /opentelemetry-plugin-better-sqlite3@1.1.0(better-sqlite3@9.4.0): + /opentelemetry-plugin-better-sqlite3@1.1.0(better-sqlite3@9.4.1): resolution: {integrity: sha512-yd+mgaB5W5JxzcQt9TvX1VIrusqtbbeuxSoZ6KQe4Ra0J/Kqkp6kz7dg0VQUU5+cenOWkza6xtvsT0KGXI03HA==} peerDependencies: better-sqlite3: ^7.1.1 || ^8.0.0 || ^9.0.0 @@ -10060,7 +10058,7 @@ packages: '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) '@opentelemetry/instrumentation': 0.44.0(@opentelemetry/api@1.7.0) '@opentelemetry/semantic-conventions': 1.18.1 - better-sqlite3: 9.4.0 + better-sqlite3: 9.4.1 transitivePeerDependencies: - supports-color dev: false @@ -10206,11 +10204,18 @@ packages: /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - dev: true /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + /path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.2.0 + minipass: 5.0.0 + dev: false + /path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} @@ -10498,7 +10503,7 @@ packages: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 18.17.8 + '@types/node': 18.19.24 long: 5.2.3 dev: false @@ -10880,27 +10885,6 @@ packages: dependencies: lru-cache: 6.0.0 - /send@0.17.2: - resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==} - engines: {node: '>= 0.8.0'} - dependencies: - debug: 2.6.9 - depd: 1.1.2 - destroy: 1.0.4 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 1.8.1 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.3.0 - range-parser: 1.2.1 - statuses: 1.5.0 - transitivePeerDependencies: - - supports-color - dev: true - /send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -10965,7 +10949,6 @@ packages: engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 - dev: true /shebang-regex@1.0.0: resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} @@ -10975,7 +10958,6 @@ packages: /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - dev: true /shimmer@1.2.1: resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} @@ -10992,6 +10974,11 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: false + /simple-concat@1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} @@ -11134,11 +11121,6 @@ packages: /standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} - /statuses@1.5.0: - resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} - engines: {node: '>= 0.6'} - dev: true - /statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -11177,7 +11159,15 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: false /string.prototype.trim@1.2.7: resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} @@ -11214,7 +11204,13 @@ packages: engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 - dev: true + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: false /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -11275,7 +11271,6 @@ packages: engines: {node: '>=8'} dependencies: has-flag: 4.0.0 - dev: true /supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} @@ -11438,7 +11433,7 @@ packages: code-block-writer: 11.0.3 dev: false - /ts-node@10.8.2(@swc/core@1.3.42)(@types/node@18.0.0)(typescript@5.3.3): + /ts-node@10.8.2(@swc/core@1.3.42)(@types/node@18.19.24)(typescript@5.3.3): resolution: {integrity: sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==} hasBin: true peerDependencies: @@ -11458,39 +11453,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 18.0.0 - acorn: 8.10.0 - acorn-walk: 8.2.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.3.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - - /ts-node@10.8.2(@swc/core@1.3.42)(@types/node@18.17.8)(typescript@5.3.3): - resolution: {integrity: sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@swc/core': 1.3.42 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 18.17.8 + '@types/node': 18.19.24 acorn: 8.10.0 acorn-walk: 8.2.0 arg: 4.1.3 @@ -11506,10 +11469,6 @@ packages: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: false - /tslib@2.3.1: - resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} - dev: true - /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} requiresBuild: true @@ -11537,7 +11496,7 @@ packages: resolution: {integrity: sha512-+meDbJPOxs6vEysJ7xX7XMn6FLKmZFSeVzMKjzN9NWgDXssp713Kf1ukteZlXhnhd7/NtNiUv5OU17qVgBb/BQ==} engines: {node: '>=14.0'} dependencies: - axios: 1.6.2 + axios: 1.6.7 dayjs: 1.11.10 https-proxy-agent: 5.0.1 jsonwebtoken: 9.0.2 @@ -11674,6 +11633,9 @@ packages: which-boxed-primitive: 1.0.2 dev: true + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + /undici@5.28.2: resolution: {integrity: sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==} engines: {node: '>=14.0'} @@ -11858,7 +11820,6 @@ packages: hasBin: true dependencies: isexe: 2.0.0 - dev: true /wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} @@ -11885,7 +11846,15 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: false /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} diff --git a/services/bsky/Dockerfile b/services/bsky/Dockerfile index a15e6aa2ee7..c8d8a2e8a46 100644 --- a/services/bsky/Dockerfile +++ b/services/bsky/Dockerfile @@ -22,9 +22,7 @@ COPY ./services/bsky ./services/bsky # install all deps RUN pnpm install --frozen-lockfile > /dev/null # build all packages with external node_modules -RUN ATP_BUILD_SHALLOW=true pnpm build > /dev/null -# update main with publishConfig -RUN pnpm update-main-to-dist > /dev/null +RUN pnpm build > /dev/null # clean up RUN rm -rf node_modules # install only prod deps, hoisted to root node_modules dir diff --git a/services/bsky/api.js b/services/bsky/api.js index 44d8f96b37d..e14b43f2d32 100644 --- a/services/bsky/api.js +++ b/services/bsky/api.js @@ -1,4 +1,6 @@ -'use strict' /* eslint-disable */ +/* eslint-env node */ + +'use strict' const dd = require('dd-trace') diff --git a/services/bsync/Dockerfile b/services/bsync/Dockerfile index 515bcfa02c3..b55cc864a79 100644 --- a/services/bsync/Dockerfile +++ b/services/bsync/Dockerfile @@ -16,9 +16,7 @@ COPY ./services/bsync ./services/bsync # install all deps RUN pnpm install --frozen-lockfile > /dev/null # build all packages with external node_modules -RUN ATP_BUILD_SHALLOW=true pnpm build > /dev/null -# update main with publishConfig -RUN pnpm update-main-to-dist > /dev/null +RUN pnpm build > /dev/null # clean up RUN rm -rf node_modules # install only prod deps, hoisted to root node_modules dir diff --git a/services/bsync/index.js b/services/bsync/index.js index c58cf839a3c..93aa1a10fc8 100644 --- a/services/bsync/index.js +++ b/services/bsync/index.js @@ -1,4 +1,6 @@ -'use strict' /* eslint-disable */ +/* eslint-env node */ + +'use strict' require('dd-trace') // Only works with commonjs .init({ logInjection: true }) diff --git a/services/ozone/Dockerfile b/services/ozone/Dockerfile index 5ecfb06f746..df6a8c04290 100644 --- a/services/ozone/Dockerfile +++ b/services/ozone/Dockerfile @@ -23,9 +23,7 @@ COPY ./services/ozone ./services/ozone # install all deps RUN pnpm install --frozen-lockfile > /dev/null # build all packages with external node_modules -RUN ATP_BUILD_SHALLOW=true pnpm build > /dev/null -# update main with publishConfig -RUN pnpm update-main-to-dist > /dev/null +RUN pnpm build > /dev/null # clean up RUN rm -rf node_modules # install only prod deps, hoisted to root node_modules dir diff --git a/services/ozone/api.js b/services/ozone/api.js index a58e8e53cab..08d2ad02ac2 100644 --- a/services/ozone/api.js +++ b/services/ozone/api.js @@ -1,4 +1,6 @@ -'use strict' /* eslint-disable */ +/* eslint-env node */ + +'use strict' require('dd-trace') // Only works with commonjs .init({ logInjection: true }) diff --git a/services/ozone/daemon.js b/services/ozone/daemon.js index a36df00d87f..faba5f29521 100644 --- a/services/ozone/daemon.js +++ b/services/ozone/daemon.js @@ -1,4 +1,6 @@ -'use strict' /* eslint-disable */ +/* eslint-env node */ + +'use strict' require('dd-trace/init') // Only works with commonjs diff --git a/services/pds/.gitignore b/services/pds/.gitignore new file mode 100644 index 00000000000..9b19b93c9f1 --- /dev/null +++ b/services/pds/.gitignore @@ -0,0 +1 @@ +*.sqlite* diff --git a/services/pds/Dockerfile b/services/pds/Dockerfile index e5f7b057184..3b74ae192b5 100644 --- a/services/pds/Dockerfile +++ b/services/pds/Dockerfile @@ -26,9 +26,7 @@ COPY ./services/pds ./services/pds # install all deps RUN pnpm install --frozen-lockfile > /dev/null # build all packages with external node_modules -RUN ATP_BUILD_SHALLOW=true pnpm build > /dev/null -# update main with publishConfig -RUN pnpm update-main-to-dist > /dev/null +RUN pnpm build > /dev/null # clean up RUN rm -rf node_modules # install only prod deps, hoisted to root node_modules dir diff --git a/services/pds/index.js b/services/pds/index.js index 54742f7865e..214350bcdc8 100644 --- a/services/pds/index.js +++ b/services/pds/index.js @@ -1,4 +1,6 @@ -'use strict' /* eslint-disable */ +/* eslint-env node */ + +'use strict' const { registerInstrumentations } = require('@opentelemetry/instrumentation') @@ -48,12 +50,7 @@ const main = async () => { // Graceful shutdown (see also https://aws.amazon.com/blogs/containers/graceful-shutdowns-with-ecs/) process.on('SIGTERM', async () => { httpLogger.info('pds is stopping') - - periodicModerationActionReversal?.destroy() - await periodicModerationActionReversalRunning - await pds.destroy() - httpLogger.info('pds is stopped') }) } diff --git a/services/pds/package.json b/services/pds/package.json index 1490e2419da..398b2038047 100644 --- a/services/pds/package.json +++ b/services/pds/package.json @@ -2,8 +2,6 @@ "name": "plc-service", "private": true, "dependencies": { - "@atproto/aws": "workspace:^", - "@atproto/crypto": "workspace:^", "@atproto/pds": "workspace:^", "@opentelemetry/instrumentation": "^0.45.0", "dd-trace": "^4.18.0", diff --git a/tsconfig.json b/tsconfig.json index 75a29d07106..73a52e54516 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,46 +1,22 @@ { - "compilerOptions": { - "declaration": true, - "noImplicitAny": false, - "removeComments": true, - "noLib": false, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "target": "es2020", - "sourceMap": true, - "module": "commonjs", - "jsx": "preserve", - "strict": true, - "strictPropertyInitialization": false, - "moduleResolution": "node", - "resolveJsonModule": true, - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "lib": ["dom", "dom.iterable", "esnext", "webworker"], - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "isolatedModules": true - }, - "exclude": ["node_modules", "**/*/dist"], + "include": [], "references": [ - { "path": "./packages/pds/tsconfig.build.json" }, - { "path": "./packages/bsky/tsconfig.build.json" }, - { "path": "./packages/bsync/tsconfig.build.json" }, - { "path": "./packages/ozone/tsconfig.build.json" }, - { "path": "./packages/api/tsconfig.build.json" }, - { "path": "./packages/aws/tsconfig.build.json" }, - { "path": "./packages/common/tsconfig.build.json" }, - { "path": "./packages/common-web/tsconfig.build.json" }, - { "path": "./packages/crypto/tsconfig.build.json" }, + { "path": "./packages/api" }, + { "path": "./packages/aws" }, + { "path": "./packages/bsky" }, + { "path": "./packages/bsync" }, + { "path": "./packages/common" }, + { "path": "./packages/common-web" }, + { "path": "./packages/crypto" }, { "path": "./packages/dev-env" }, - { "path": "./packages/identity/tsconfig.build.json" }, - { "path": "./packages/identifier/tsconfig.build.json" }, - { "path": "./packages/syntax/tsconfig.build.json" }, - { "path": "./packages/lexicon/tsconfig.build.json" }, - { "path": "./packages/lex-cli/tsconfig.build.json" }, - { "path": "./packages/nsid/tsconfig.build.json" }, - { "path": "./packages/uri/tsconfig.build.json" }, - { "path": "./packages/xrpc/tsconfig.build.json" }, - { "path": "./packages/xrpc-server/tsconfig.build.json" } + { "path": "./packages/identity" }, + { "path": "./packages/lex-cli" }, + { "path": "./packages/lexicon" }, + { "path": "./packages/ozone" }, + { "path": "./packages/pds" }, + { "path": "./packages/repo" }, + { "path": "./packages/syntax" }, + { "path": "./packages/xrpc" }, + { "path": "./packages/xrpc-server" } ] } diff --git a/tsconfig/base.json b/tsconfig/base.json new file mode 100644 index 00000000000..0434e9fe5cf --- /dev/null +++ b/tsconfig/base.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "checkJs": true, + + "strict": true, + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "exactOptionalPropertyTypes": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": false, + "noImplicitReturns": false, + "noUnusedLocals": true, + "noUnusedParameters": false, + + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "isolatedModules": true, + "preserveSymlinks": false, + "useDefineForClassFields": true, + + "lib": [], + "moduleResolution": "node", + "resolveJsonModule": true, + "types": [], + + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "jsx": "preserve", + "module": "CommonJS", + "target": "ES2020" + }, + "typeAcquisition": { + "enable": false + } +} diff --git a/tsconfig/isomorphic.json b/tsconfig/isomorphic.json new file mode 100644 index 00000000000..43bff8bf979 --- /dev/null +++ b/tsconfig/isomorphic.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./base.json", + "compilerOptions": { + // Currently, there is not ideal way of developing a lib that is compatible + // with both node and the browser. + // + // https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/1685 + // https://github.com/microsoft/TypeScript/issues/31535 + // https://github.com/microsoft/TypeScript/issues/41727 + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["node"] + } +} diff --git a/tsconfig/node.json b/tsconfig/node.json new file mode 100644 index 00000000000..f69da239387 --- /dev/null +++ b/tsconfig/node.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./base.json", + "compilerOptions": { + "lib": ["ES2022", "ScriptHost"], + "types": ["node"] + } +} diff --git a/tsconfig/tests.json b/tsconfig/tests.json new file mode 100644 index 00000000000..321864788ee --- /dev/null +++ b/tsconfig/tests.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./node.json", + "compilerOptions": { + "types": ["node", "jest"], + "noEmit": true + } +} diff --git a/update-main-to-dist.js b/update-main-to-dist.js deleted file mode 100644 index fe625caa4d6..00000000000 --- a/update-main-to-dist.js +++ /dev/null @@ -1,9 +0,0 @@ -const path = require('path') -const pkgJson = require('@npmcli/package-json') - -const [dir] = process.argv.slice(2) - -pkgJson - .load(path.resolve(__dirname, dir)) - .then((pkg) => pkg.update({ main: pkg.content.publishConfig.main })) - .then((pkg) => pkg.save())