@atproto/bsync 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/client.d.ts +1 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +17 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/config.d.ts +1 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +53 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/context.d.ts +5 -1
  11. package/dist/context.d.ts.map +1 -0
  12. package/dist/context.js +54 -0
  13. package/dist/context.js.map +1 -0
  14. package/dist/db/index.d.ts +1 -0
  15. package/dist/db/index.d.ts.map +1 -0
  16. package/dist/db/index.js +216 -0
  17. package/dist/db/index.js.map +1 -0
  18. package/dist/db/migrations/20240108T220751294Z-init.d.ts +1 -0
  19. package/dist/db/migrations/20240108T220751294Z-init.d.ts.map +1 -0
  20. package/dist/db/migrations/20240108T220751294Z-init.js +28 -0
  21. package/dist/db/migrations/20240108T220751294Z-init.js.map +1 -0
  22. package/dist/db/migrations/index.d.ts +1 -0
  23. package/dist/db/migrations/index.d.ts.map +1 -0
  24. package/dist/db/migrations/index.js +31 -0
  25. package/dist/db/migrations/index.js.map +1 -0
  26. package/dist/db/migrations/provider.d.ts +1 -0
  27. package/dist/db/migrations/provider.d.ts.map +1 -0
  28. package/dist/db/migrations/provider.js +18 -0
  29. package/dist/db/migrations/provider.js.map +1 -0
  30. package/dist/db/schema/index.d.ts +1 -0
  31. package/dist/db/schema/index.d.ts.map +1 -0
  32. package/dist/db/schema/index.js +3 -0
  33. package/dist/db/schema/index.js.map +1 -0
  34. package/dist/db/schema/mute_item.d.ts +1 -0
  35. package/dist/db/schema/mute_item.d.ts.map +1 -0
  36. package/dist/db/schema/mute_item.js +5 -0
  37. package/dist/db/schema/mute_item.js.map +1 -0
  38. package/dist/db/schema/mute_op.d.ts +1 -0
  39. package/dist/db/schema/mute_op.d.ts.map +1 -0
  40. package/dist/db/schema/mute_op.js +6 -0
  41. package/dist/db/schema/mute_op.js.map +1 -0
  42. package/dist/db/types.d.ts +1 -0
  43. package/dist/db/types.d.ts.map +1 -0
  44. package/dist/db/types.js +3 -0
  45. package/dist/db/types.js.map +1 -0
  46. package/dist/index.d.ts +3 -1
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +130 -76724
  49. package/dist/index.js.map +1 -7
  50. package/dist/logger.d.ts +1 -0
  51. package/dist/logger.d.ts.map +1 -0
  52. package/dist/logger.js +25 -0
  53. package/dist/logger.js.map +1 -0
  54. package/dist/proto/bsync_connect.d.ts +18 -1
  55. package/dist/proto/bsync_connect.d.ts.map +1 -0
  56. package/dist/proto/bsync_connect.js +49 -0
  57. package/dist/proto/bsync_connect.js.map +1 -0
  58. package/dist/proto/bsync_pb.d.ts +75 -0
  59. package/dist/proto/bsync_pb.d.ts.map +1 -0
  60. package/dist/proto/bsync_pb.js +461 -0
  61. package/dist/proto/bsync_pb.js.map +1 -0
  62. package/dist/routes/add-mute-operation.d.ts +1 -0
  63. package/dist/routes/add-mute-operation.d.ts.map +1 -0
  64. package/dist/routes/add-mute-operation.js +136 -0
  65. package/dist/routes/add-mute-operation.js.map +1 -0
  66. package/dist/routes/auth.d.ts +1 -0
  67. package/dist/routes/auth.d.ts.map +1 -0
  68. package/dist/routes/auth.js +17 -0
  69. package/dist/routes/auth.js.map +1 -0
  70. package/dist/routes/index.d.ts +1 -0
  71. package/dist/routes/index.d.ts.map +1 -0
  72. package/dist/routes/index.js +21 -0
  73. package/dist/routes/index.js.map +1 -0
  74. package/dist/routes/scan-mute-operations.d.ts +1 -0
  75. package/dist/routes/scan-mute-operations.d.ts.map +1 -0
  76. package/dist/routes/scan-mute-operations.js +80 -0
  77. package/dist/routes/scan-mute-operations.js.map +1 -0
  78. package/jest.config.js +3 -3
  79. package/package.json +9 -11
  80. package/src/context.ts +5 -1
  81. package/src/db/index.ts +33 -31
  82. package/src/index.ts +6 -2
  83. package/src/proto/bsync_connect.ts +1 -1
  84. package/src/routes/scan-mute-operations.ts +20 -1
  85. package/tsconfig.build.json +6 -2
  86. package/tsconfig.json +3 -10
  87. package/tsconfig.tests.json +7 -0
  88. package/babel.config.js +0 -3
  89. package/build.js +0 -18
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const kysely_1 = require("kysely");
7
+ const bsync_connect_1 = require("../proto/bsync_connect");
8
+ const add_mute_operation_1 = __importDefault(require("./add-mute-operation"));
9
+ const scan_mute_operations_1 = __importDefault(require("./scan-mute-operations"));
10
+ exports.default = (ctx) => (router) => {
11
+ return router.service(bsync_connect_1.Service, {
12
+ ...(0, add_mute_operation_1.default)(ctx),
13
+ ...(0, scan_mute_operations_1.default)(ctx),
14
+ async ping() {
15
+ const { db } = ctx;
16
+ await (0, kysely_1.sql) `select 1`.execute(db.db);
17
+ return {};
18
+ },
19
+ });
20
+ };
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":";;;;;AAAA,mCAA4B;AAE5B,0DAAgD;AAEhD,8EAAmD;AACnD,kFAAuD;AAEvD,kBAAe,CAAC,GAAe,EAAE,EAAE,CAAC,CAAC,MAAqB,EAAE,EAAE;IAC5D,OAAO,MAAM,CAAC,OAAO,CAAC,uBAAO,EAAE;QAC7B,GAAG,IAAA,4BAAgB,EAAC,GAAG,CAAC;QACxB,GAAG,IAAA,8BAAkB,EAAC,GAAG,CAAC;QAC1B,KAAK,CAAC,IAAI;YACR,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAA;YAClB,MAAM,IAAA,YAAG,EAAA,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;YAClC,OAAO,EAAE,CAAA;QACX,CAAC;KACF,CAAC,CAAA;AACJ,CAAC,CAAA"}
@@ -3,3 +3,4 @@ import { Service } from '../proto/bsync_connect';
3
3
  import AppContext from '../context';
4
4
  declare const _default: (ctx: AppContext) => Partial<ServiceImpl<typeof Service>>;
5
5
  export default _default;
6
+ //# sourceMappingURL=scan-mute-operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-mute-operations.d.ts","sourceRoot":"","sources":["../../src/routes/scan-mute-operations.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAEhD,OAAO,UAAU,MAAM,YAAY,CAAA;8BAId,UAAU,KAAG,QAAQ,YAAY,cAAc,CAAC,CAAC;AAAtE,wBAuDE"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_events_1 = require("node:events");
4
+ const connect_1 = require("@connectrpc/connect");
5
+ const bsync_pb_1 = require("../proto/bsync_pb");
6
+ const mute_op_1 = require("../db/schema/mute_op");
7
+ const auth_1 = require("./auth");
8
+ exports.default = (ctx) => ({
9
+ async scanMuteOperations(req, handlerCtx) {
10
+ (0, auth_1.authWithApiKey)(ctx, handlerCtx);
11
+ const { db, events } = ctx;
12
+ const limit = req.limit || 1000;
13
+ const cursor = validCursor(req.cursor);
14
+ const nextMuteOpPromise = (0, node_events_1.once)(events, mute_op_1.createMuteOpChannel, {
15
+ signal: combineSignals(ctx.shutdown, AbortSignal.timeout(ctx.cfg.service.longPollTimeoutMs)),
16
+ });
17
+ nextMuteOpPromise.catch(() => null); // ensure timeout is always handled
18
+ const nextMuteOpPageQb = db.db
19
+ .selectFrom('mute_op')
20
+ .selectAll()
21
+ .where('id', '>', cursor ?? -1)
22
+ .orderBy('id', 'asc')
23
+ .limit(limit);
24
+ let ops = await nextMuteOpPageQb.execute();
25
+ if (!ops.length) {
26
+ // if there were no ops on the page, wait for an event then try again.
27
+ try {
28
+ await nextMuteOpPromise;
29
+ }
30
+ catch (err) {
31
+ ctx.shutdown.throwIfAborted();
32
+ return new bsync_pb_1.ScanMuteOperationsResponse({
33
+ operations: [],
34
+ cursor: req.cursor,
35
+ });
36
+ }
37
+ ops = await nextMuteOpPageQb.execute();
38
+ if (!ops.length) {
39
+ return new bsync_pb_1.ScanMuteOperationsResponse({
40
+ operations: [],
41
+ cursor: req.cursor,
42
+ });
43
+ }
44
+ }
45
+ const lastOp = ops[ops.length - 1];
46
+ return new bsync_pb_1.ScanMuteOperationsResponse({
47
+ operations: ops.map((op) => ({
48
+ id: op.id.toString(),
49
+ type: op.type,
50
+ actorDid: op.actorDid,
51
+ subject: op.subject,
52
+ })),
53
+ cursor: lastOp.id.toString(),
54
+ });
55
+ },
56
+ });
57
+ const validCursor = (cursor) => {
58
+ if (cursor === '')
59
+ return null;
60
+ const int = parseInt(cursor, 10);
61
+ if (isNaN(int) || int < 0) {
62
+ throw new connect_1.ConnectError('invalid cursor', connect_1.Code.InvalidArgument);
63
+ }
64
+ return int;
65
+ };
66
+ const combineSignals = (a, b) => {
67
+ const controller = new AbortController();
68
+ for (const signal of [a, b]) {
69
+ if (signal.aborted) {
70
+ controller.abort();
71
+ return signal;
72
+ }
73
+ signal.addEventListener('abort', () => controller.abort(signal.reason), {
74
+ // @ts-ignore https://github.com/DefinitelyTyped/DefinitelyTyped/pull/68625
75
+ signal: controller.signal,
76
+ });
77
+ }
78
+ return controller.signal;
79
+ };
80
+ //# sourceMappingURL=scan-mute-operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-mute-operations.js","sourceRoot":"","sources":["../../src/routes/scan-mute-operations.ts"],"names":[],"mappings":"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"}
package/jest.config.js CHANGED
@@ -1,6 +1,6 @@
1
- const base = require('../../jest.config.base.js')
2
-
1
+ /** @type {import('jest').Config} */
3
2
  module.exports = {
4
- ...base,
5
3
  displayName: 'Bsync',
4
+ transform: { '^.+\\.(t|j)s$': '@swc/jest' },
5
+ setupFiles: ['<rootDir>/../../jest.setup.ts'],
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/bsync",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "license": "MIT",
5
5
  "description": "Sychronizing service for app.bsky App View (Bluesky API)",
6
6
  "keywords": [
@@ -14,36 +14,34 @@
14
14
  "directory": "packages/bsync"
15
15
  },
16
16
  "main": "dist/index.js",
17
+ "types": "dist/index.d.ts",
17
18
  "dependencies": {
18
19
  "@bufbuild/protobuf": "^1.5.0",
19
20
  "@connectrpc/connect": "^1.1.4",
20
- "@connectrpc/connect-express": "^1.1.4",
21
21
  "@connectrpc/connect-node": "^1.1.4",
22
22
  "http-terminator": "^3.2.0",
23
23
  "kysely": "^0.22.0",
24
24
  "pg": "^8.10.0",
25
- "pino": "^8.15.0",
26
25
  "pino-http": "^8.2.1",
27
26
  "typed-emitter": "^2.1.0",
28
- "@atproto/common": "^0.3.4",
29
- "@atproto/syntax": "^0.2.1"
27
+ "@atproto/common": "^0.4.0",
28
+ "@atproto/syntax": "^0.3.0"
30
29
  },
31
30
  "devDependencies": {
32
31
  "@bufbuild/buf": "^1.28.1",
33
32
  "@bufbuild/protoc-gen-es": "^1.5.0",
34
33
  "@connectrpc/protoc-gen-connect-es": "^1.1.4",
35
- "@types/pg": "^8.6.6"
34
+ "@types/pg": "^8.6.6",
35
+ "jest": "^28.1.2",
36
+ "ts-node": "^10.8.2"
36
37
  },
37
38
  "scripts": {
38
- "build": "node ./build.js",
39
- "postbuild": "tsc --build tsconfig.build.json",
40
- "update-main-to-dist": "node ../../update-main-to-dist.js packages/bsync",
39
+ "build": "tsc --build tsconfig.build.json",
41
40
  "start": "node --enable-source-maps dist/bin.js",
42
41
  "test": "../dev-infra/with-test-db.sh jest",
43
42
  "test:log": "tail -50 test.log | pino-pretty",
44
43
  "test:updateSnapshot": "jest --updateSnapshot",
45
44
  "migration:create": "ts-node ./bin/migration-create.ts",
46
45
  "buf:gen": "buf generate proto"
47
- },
48
- "types": "dist/index.d.ts"
46
+ }
49
47
  }
package/src/context.ts CHANGED
@@ -7,21 +7,25 @@ import { EventEmitter } from 'stream'
7
7
  export type AppContextOptions = {
8
8
  db: Database
9
9
  cfg: ServerConfig
10
+ shutdown: AbortSignal
10
11
  }
11
12
 
12
13
  export class AppContext {
13
14
  db: Database
14
15
  cfg: ServerConfig
16
+ shutdown: AbortSignal
15
17
  events: TypedEventEmitter<AppEvents>
16
18
 
17
19
  constructor(opts: AppContextOptions) {
18
20
  this.db = opts.db
19
21
  this.cfg = opts.cfg
22
+ this.shutdown = opts.shutdown
20
23
  this.events = new EventEmitter() as TypedEventEmitter<AppEvents>
21
24
  }
22
25
 
23
26
  static async fromConfig(
24
27
  cfg: ServerConfig,
28
+ shutdown: AbortSignal,
25
29
  overrides?: Partial<AppContextOptions>,
26
30
  ): Promise<AppContext> {
27
31
  const db = new Database({
@@ -31,7 +35,7 @@ export class AppContext {
31
35
  poolMaxUses: cfg.db.poolMaxUses,
32
36
  poolIdleTimeoutMs: cfg.db.poolIdleTimeoutMs,
33
37
  })
34
- return new AppContext({ db, cfg, ...overrides })
38
+ return new AppContext({ db, cfg, shutdown, ...overrides })
35
39
  }
36
40
  }
37
41
 
package/src/db/index.ts CHANGED
@@ -34,41 +34,43 @@ export class Database {
34
34
  if (instances) {
35
35
  this.db = instances.db
36
36
  this.pool = instances.pool
37
- return
38
- }
37
+ } else {
38
+ // else create a pool & connect
39
+ const { schema, url } = opts
40
+ const pool =
41
+ opts.pool ??
42
+ new PgPool({
43
+ connectionString: url,
44
+ max: opts.poolSize,
45
+ maxUses: opts.poolMaxUses,
46
+ idleTimeoutMillis: opts.poolIdleTimeoutMs,
47
+ })
39
48
 
40
- // else create a pool & connect
41
- const { schema, url } = opts
42
- const pool =
43
- opts.pool ??
44
- new PgPool({
45
- connectionString: url,
46
- max: opts.poolSize,
47
- maxUses: opts.poolMaxUses,
48
- idleTimeoutMillis: opts.poolIdleTimeoutMs,
49
- })
49
+ // Select count(*) and other pg bigints as js integer
50
+ pgTypes.setTypeParser(pgTypes.builtins.INT8, (n) => parseInt(n, 10))
50
51
 
51
- // Select count(*) and other pg bigints as js integer
52
- pgTypes.setTypeParser(pgTypes.builtins.INT8, (n) => parseInt(n, 10))
52
+ // Setup schema usage, primarily for test parallelism (each test suite runs in its own pg schema)
53
+ if (schema && !/^[a-z_]+$/i.test(schema)) {
54
+ throw new Error(
55
+ `Postgres schema must only contain [A-Za-z_]: ${schema}`,
56
+ )
57
+ }
53
58
 
54
- // Setup schema usage, primarily for test parallelism (each test suite runs in its own pg schema)
55
- if (schema && !/^[a-z_]+$/i.test(schema)) {
56
- throw new Error(`Postgres schema must only contain [A-Za-z_]: ${schema}`)
57
- }
59
+ pool.on('error', onPoolError)
60
+ pool.on('connect', (client) => {
61
+ client.on('error', onClientError)
62
+ if (schema) {
63
+ // Shared objects such as extensions will go in the public schema
64
+ client.query(`SET search_path TO "${schema}",public;`)
65
+ }
66
+ })
58
67
 
59
- pool.on('error', onPoolError)
60
- pool.on('connect', (client) => {
61
- client.on('error', onClientError)
62
- if (schema) {
63
- // Shared objects such as extensions will go in the public schema
64
- client.query(`SET search_path TO "${schema}",public;`)
65
- }
66
- })
68
+ this.pool = pool
69
+ this.db = new Kysely<DatabaseSchemaType>({
70
+ dialect: new PostgresDialect({ pool }),
71
+ })
72
+ }
67
73
 
68
- this.pool = pool
69
- this.db = new Kysely<DatabaseSchemaType>({
70
- dialect: new PostgresDialect({ pool }),
71
- })
72
74
  this.migrator = new Migrator({
73
75
  db: this.db,
74
76
  migrationTableSchema: opts.schema,
@@ -165,7 +167,7 @@ const onClientError = (err: Error) => dbLogger.error({ err }, 'db client error')
165
167
  // -------
166
168
 
167
169
  class LeakyTxPlugin implements KyselyPlugin {
168
- private txOver: boolean
170
+ private txOver = false
169
171
 
170
172
  endTx() {
171
173
  this.txOver = true
package/src/index.ts CHANGED
@@ -19,7 +19,7 @@ export class BsyncService {
19
19
  public server: http.Server
20
20
  private ac: AbortController
21
21
  private terminator: HttpTerminator
22
- private dbStatsInterval: NodeJS.Timer
22
+ private dbStatsInterval?: NodeJS.Timeout
23
23
 
24
24
  constructor(opts: {
25
25
  ctx: AppContext
@@ -36,8 +36,8 @@ export class BsyncService {
36
36
  cfg: ServerConfig,
37
37
  overrides?: Partial<AppContextOptions>,
38
38
  ): Promise<BsyncService> {
39
- const ctx = await AppContext.fromConfig(cfg, overrides)
40
39
  const ac = new AbortController()
40
+ const ctx = await AppContext.fromConfig(cfg, ac.signal, overrides)
41
41
  const handler = connectNodeAdapter({
42
42
  routes: routes(ctx),
43
43
  shutdownSignal: ac.signal,
@@ -55,6 +55,9 @@ export class BsyncService {
55
55
  }
56
56
 
57
57
  async start(): Promise<http.Server> {
58
+ if (this.dbStatsInterval) {
59
+ throw new Error(`${this.constructor.name} already started`)
60
+ }
58
61
  this.dbStatsInterval = setInterval(() => {
59
62
  dbLogger.info(
60
63
  {
@@ -77,6 +80,7 @@ export class BsyncService {
77
80
  await this.terminator.terminate()
78
81
  await this.ctx.db.close()
79
82
  clearInterval(this.dbStatsInterval)
83
+ this.dbStatsInterval = undefined
80
84
  }
81
85
 
82
86
  async setupAppEvents() {
@@ -10,7 +10,7 @@ import {
10
10
  PingResponse,
11
11
  ScanMuteOperationsRequest,
12
12
  ScanMuteOperationsResponse,
13
- } from './bsync_pb.ts'
13
+ } from './bsync_pb'
14
14
  import { MethodKind } from '@bufbuild/protobuf'
15
15
 
16
16
  /**
@@ -13,7 +13,10 @@ export default (ctx: AppContext): Partial<ServiceImpl<typeof Service>> => ({
13
13
  const limit = req.limit || 1000
14
14
  const cursor = validCursor(req.cursor)
15
15
  const nextMuteOpPromise = once(events, createMuteOpChannel, {
16
- signal: AbortSignal.timeout(ctx.cfg.service.longPollTimeoutMs),
16
+ signal: combineSignals(
17
+ ctx.shutdown,
18
+ AbortSignal.timeout(ctx.cfg.service.longPollTimeoutMs),
19
+ ),
17
20
  })
18
21
  nextMuteOpPromise.catch(() => null) // ensure timeout is always handled
19
22
 
@@ -31,6 +34,7 @@ export default (ctx: AppContext): Partial<ServiceImpl<typeof Service>> => ({
31
34
  try {
32
35
  await nextMuteOpPromise
33
36
  } catch (err) {
37
+ ctx.shutdown.throwIfAborted()
34
38
  return new ScanMuteOperationsResponse({
35
39
  operations: [],
36
40
  cursor: req.cursor,
@@ -67,3 +71,18 @@ const validCursor = (cursor: string): number | null => {
67
71
  }
68
72
  return int
69
73
  }
74
+
75
+ const combineSignals = (a: AbortSignal, b: AbortSignal) => {
76
+ const controller = new AbortController()
77
+ for (const signal of [a, b]) {
78
+ if (signal.aborted) {
79
+ controller.abort()
80
+ return signal
81
+ }
82
+ signal.addEventListener('abort', () => controller.abort(signal.reason), {
83
+ // @ts-ignore https://github.com/DefinitelyTyped/DefinitelyTyped/pull/68625
84
+ signal: controller.signal,
85
+ })
86
+ }
87
+ return controller.signal
88
+ }
@@ -1,4 +1,8 @@
1
1
  {
2
- "extends": "./tsconfig.json",
3
- "exclude": ["**/*.spec.ts", "**/*.test.ts"]
2
+ "extends": "../../tsconfig/node.json",
3
+ "compilerOptions": {
4
+ "rootDir": "./src",
5
+ "outDir": "./dist"
6
+ },
7
+ "include": ["./src"]
4
8
  }
package/tsconfig.json CHANGED
@@ -1,14 +1,7 @@
1
1
  {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./dist",
6
- "emitDeclarationOnly": true
7
- },
8
- "module": "nodenext",
9
- "include": ["./src", "__tests__/**/**.ts"],
2
+ "include": [],
10
3
  "references": [
11
- { "path": "../common/tsconfig.build.json" },
12
- { "path": "../common-web/tsconfig.build.json" }
4
+ { "path": "./tsconfig.build.json" },
5
+ { "path": "./tsconfig.tests.json" }
13
6
  ]
14
7
  }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig/tests.json",
3
+ "compilerOptions": {
4
+ "rootDir": "."
5
+ },
6
+ "include": ["./tests"]
7
+ }
package/babel.config.js DELETED
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- presets: [['@babel/preset-env']],
3
- }
package/build.js DELETED
@@ -1,18 +0,0 @@
1
- const { nodeExternalsPlugin } = require('esbuild-node-externals')
2
-
3
- const buildShallow =
4
- process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true'
5
-
6
- require('esbuild').build({
7
- logLevel: 'info',
8
- entryPoints: ['src/index.ts'],
9
- bundle: true,
10
- sourcemap: true,
11
- outdir: 'dist',
12
- platform: 'node',
13
- external: [
14
- // Referenced in pg driver, but optional and we don't use it
15
- 'pg-native',
16
- ],
17
- plugins: buildShallow ? [nodeExternalsPlugin()] : [],
18
- })