@atproto/pds 0.5.36 → 0.5.37

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 (64) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/account-manager/account-manager.d.ts +1 -1
  3. package/dist/account-manager/account-manager.d.ts.map +1 -1
  4. package/dist/account-manager/account-manager.js +2 -2
  5. package/dist/account-manager/account-manager.js.map +1 -1
  6. package/dist/actor-store/actor-store-reader.d.ts +3 -1
  7. package/dist/actor-store/actor-store-reader.d.ts.map +1 -1
  8. package/dist/actor-store/actor-store-reader.js +72 -5
  9. package/dist/actor-store/actor-store-reader.js.map +1 -1
  10. package/dist/actor-store/actor-store-transactor.d.ts +3 -1
  11. package/dist/actor-store/actor-store-transactor.d.ts.map +1 -1
  12. package/dist/actor-store/actor-store-transactor.js +6 -3
  13. package/dist/actor-store/actor-store-transactor.js.map +1 -1
  14. package/dist/actor-store/actor-store-writer.js +67 -3
  15. package/dist/actor-store/actor-store-writer.js.map +1 -1
  16. package/dist/actor-store/actor-store.d.ts +2 -2
  17. package/dist/actor-store/actor-store.d.ts.map +1 -1
  18. package/dist/actor-store/actor-store.js +125 -25
  19. package/dist/actor-store/actor-store.js.map +1 -1
  20. package/dist/api/com/atproto/repo/importRepo.d.ts.map +1 -1
  21. package/dist/api/com/atproto/repo/importRepo.js +7 -2
  22. package/dist/api/com/atproto/repo/importRepo.js.map +1 -1
  23. package/dist/api/com/atproto/sync/getRecord.d.ts.map +1 -1
  24. package/dist/api/com/atproto/sync/getRecord.js +4 -2
  25. package/dist/api/com/atproto/sync/getRecord.js.map +1 -1
  26. package/dist/api/com/atproto/sync/getRepo.d.ts.map +1 -1
  27. package/dist/api/com/atproto/sync/getRepo.js +3 -1
  28. package/dist/api/com/atproto/sync/getRepo.js.map +1 -1
  29. package/dist/context.d.ts +3 -3
  30. package/dist/context.d.ts.map +1 -1
  31. package/dist/context.js +20 -12
  32. package/dist/context.js.map +1 -1
  33. package/dist/db/db.d.ts +5 -3
  34. package/dist/db/db.d.ts.map +1 -1
  35. package/dist/db/db.js +13 -7
  36. package/dist/db/db.js.map +1 -1
  37. package/dist/disk-blobstore.d.ts +3 -2
  38. package/dist/disk-blobstore.d.ts.map +1 -1
  39. package/dist/disk-blobstore.js +13 -4
  40. package/dist/disk-blobstore.js.map +1 -1
  41. package/dist/lexicons/app/bsky/authManageNotifications.defs.d.ts.map +1 -1
  42. package/dist/lexicons/app/bsky/authManageNotifications.defs.js +1 -0
  43. package/dist/lexicons/app/bsky/authManageNotifications.defs.js.map +1 -1
  44. package/dist/lexicons/app/bsky/feed/getListFeed.defs.d.ts +4 -0
  45. package/dist/lexicons/app/bsky/feed/getListFeed.defs.d.ts.map +1 -1
  46. package/dist/lexicons/app/bsky/feed/getListFeed.defs.js +2 -0
  47. package/dist/lexicons/app/bsky/feed/getListFeed.defs.js.map +1 -1
  48. package/dist/lexicons/app/bsky/feed/getTimeline.defs.d.ts +4 -0
  49. package/dist/lexicons/app/bsky/feed/getTimeline.defs.d.ts.map +1 -1
  50. package/dist/lexicons/app/bsky/feed/getTimeline.defs.js +2 -0
  51. package/dist/lexicons/app/bsky/feed/getTimeline.defs.js.map +1 -1
  52. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.d.ts +3 -0
  53. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.d.ts.map +1 -0
  54. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.d.ts +299 -0
  55. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.d.ts.map +1 -0
  56. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.js +231 -0
  57. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.js.map +1 -0
  58. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.js +6 -0
  59. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.js.map +1 -0
  60. package/dist/lexicons/app/bsky/notification.d.ts +1 -0
  61. package/dist/lexicons/app/bsky/notification.d.ts.map +1 -1
  62. package/dist/lexicons/app/bsky/notification.js +1 -0
  63. package/dist/lexicons/app/bsky/notification.js.map +1 -1
  64. package/package.json +19 -19
@@ -1,9 +1,73 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
1
53
  import { ActorStoreTransactor } from './actor-store-transactor.js';
2
54
  export class ActorStoreWriter extends ActorStoreTransactor {
3
55
  async transact(fn) {
4
- return this.db.transaction((dbTxn) => {
5
- const transactor = new ActorStoreTransactor(this.did, dbTxn, this.keypair, this.resources);
6
- return fn(transactor);
56
+ return this.db.transaction(async (dbTxn) => {
57
+ const env_1 = { stack: [], error: void 0, hasError: false };
58
+ try {
59
+ const transactor = __addDisposableResource(env_1, new ActorStoreTransactor(this.did, dbTxn, this.keypair, this.resources), true);
60
+ return await fn(transactor);
61
+ }
62
+ catch (e_1) {
63
+ env_1.error = e_1;
64
+ env_1.hasError = true;
65
+ }
66
+ finally {
67
+ const result_1 = __disposeResources(env_1);
68
+ if (result_1)
69
+ await result_1;
70
+ }
7
71
  });
8
72
  }
9
73
  }
@@ -1 +1 @@
1
- {"version":3,"file":"actor-store-writer.js","sourceRoot":"","sources":["../../src/actor-store/actor-store-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAElE,MAAM,OAAO,gBAAiB,SAAQ,oBAAoB;IACxD,KAAK,CAAC,QAAQ,CACZ,EAAoD;QAEpD,OAAO,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,EAAE;YACnC,MAAM,UAAU,GAAG,IAAI,oBAAoB,CACzC,IAAI,CAAC,GAAG,EACR,KAAK,EACL,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,SAAS,CACf,CAAA;YACD,OAAO,EAAE,CAAC,UAAU,CAAC,CAAA;QACvB,CAAC,CAAC,CAAA;IACJ,CAAC;CACF","sourcesContent":["import { ActorStoreTransactor } from './actor-store-transactor.js'\n\nexport class ActorStoreWriter extends ActorStoreTransactor {\n async transact<T>(\n fn: (fn: ActorStoreTransactor) => T | PromiseLike<T>,\n ): Promise<T> {\n return this.db.transaction((dbTxn) => {\n const transactor = new ActorStoreTransactor(\n this.did,\n dbTxn,\n this.keypair,\n this.resources,\n )\n return fn(transactor)\n })\n }\n}\n"]}
1
+ {"version":3,"file":"actor-store-writer.js","sourceRoot":"","sources":["../../src/actor-store/actor-store-writer.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAElE,MAAM,OAAO,gBAAiB,SAAQ,oBAAoB;IACxD,KAAK,CAAC,QAAQ,CACZ,EAAoD;QAEpD,OAAO,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;;;gBACzC,MAAY,UAAU,kCAAG,IAAI,oBAAoB,CAC/C,IAAI,CAAC,GAAG,EACR,KAAK,EACL,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,SAAS,CACf,OAAA,CAAA;gBACD,OAAO,MAAM,EAAE,CAAC,UAAU,CAAC,CAAA;;;;;;;;;;;QAC7B,CAAC,CAAC,CAAA;IACJ,CAAC;CACF","sourcesContent":["import { ActorStoreTransactor } from './actor-store-transactor.js'\n\nexport class ActorStoreWriter extends ActorStoreTransactor {\n async transact<T>(\n fn: (fn: ActorStoreTransactor) => T | PromiseLike<T>,\n ): Promise<T> {\n return this.db.transaction(async (dbTxn) => {\n await using transactor = new ActorStoreTransactor(\n this.did,\n dbTxn,\n this.keypair,\n this.resources,\n )\n return await fn(transactor)\n })\n }\n}\n"]}
@@ -20,8 +20,8 @@ export declare class ActorStore {
20
20
  keypair(did: string): Promise<Keypair>;
21
21
  openDb(did: string): Promise<ActorDb>;
22
22
  read<T>(did: DidString, fn: (fn: ActorStoreReader) => T | PromiseLike<T>): Promise<T>;
23
- transact<T>(did: DidString, fn: (fn: ActorStoreTransactor) => T | PromiseLike<T>): Promise<T>;
24
- writeNoTransaction<T>(did: DidString, fn: (fn: ActorStoreWriter) => T | PromiseLike<T>): Promise<T>;
23
+ transact<T>(did: DidString, fn: (transactor: ActorStoreTransactor) => T | PromiseLike<T>): Promise<T>;
24
+ writeNoTransaction<T>(did: DidString, fn: (writer: ActorStoreWriter) => T | PromiseLike<T>): Promise<T>;
25
25
  create(did: string, keypair: ExportableKeypair): Promise<void>;
26
26
  destroy(did: DidString): Promise<void>;
27
27
  reserveKeypair(did?: string): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"actor-store.d.ts","sourceRoot":"","sources":["../../src/actor-store/actor-store.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAI1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,KAAK,OAAO,EAAsB,MAAM,eAAe,CAAA;AAEhE,qBAAa,UAAU;IAIZ,GAAG,EAAE,gBAAgB;IACrB,SAAS,EAAE,mBAAmB;IAJvC,cAAc,EAAE,MAAM,CAAA;IAEtB,YACS,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,mBAAmB,EAGtC;IAEK,WAAW,CAAC,GAAG,EAAE,MAAM;;;;OAM5B;IAEK,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG1C;IAEK,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAI3C;IAEK,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAoB1C;IAEK,IAAI,CAAC,CAAC,EACV,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,CAAC,EAAE,EAAE,gBAAgB,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,cASjD;IAEK,QAAQ,CAAC,CAAC,EACd,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,CAAC,EAAE,EAAE,oBAAoB,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,cAWrD;IAEK,kBAAkB,CAAC,CAAC,EACxB,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,CAAC,EAAE,EAAE,gBAAgB,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,cASjD;IAEK,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,iBAmBnD;IAEK,OAAO,CAAC,GAAG,EAAE,SAAS,iBAe3B;IAEK,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBlD;IAEK,kBAAkB,CACtB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAExC;IAEK,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,iBAKtD;IAEK,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,iBAI3C;IAEK,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAI/C;IAEK,UAAU,CAAC,GAAG,EAAE,MAAM,iBAI3B;CACF"}
1
+ {"version":3,"file":"actor-store.d.ts","sourceRoot":"","sources":["../../src/actor-store/actor-store.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAI1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,KAAK,OAAO,EAAsB,MAAM,eAAe,CAAA;AAEhE,qBAAa,UAAU;IAIZ,GAAG,EAAE,gBAAgB;IACrB,SAAS,EAAE,mBAAmB;IAJvC,cAAc,EAAE,MAAM,CAAA;IAEtB,YACS,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,mBAAmB,EAGtC;IAEK,WAAW,CAAC,GAAG,EAAE,MAAM;;;;OAM5B;IAEK,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG1C;IAEK,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAI3C;IAEK,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAoB1C;IAEK,IAAI,CAAC,CAAC,EACV,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,CAAC,EAAE,EAAE,gBAAgB,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,cAWjD;IAEK,QAAQ,CAAC,CAAC,EACd,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,CAAC,UAAU,EAAE,oBAAoB,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,cAa7D;IAEK,kBAAkB,CAAC,CAAC,EACxB,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,cAMrD;IAEK,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,iBAmBnD;IAEK,OAAO,CAAC,GAAG,EAAE,SAAS,iBAe3B;IAEK,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBlD;IAEK,kBAAkB,CACtB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAExC;IAEK,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,iBAKtD;IAEK,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,iBAI3C;IAEK,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAI/C;IAEK,UAAU,CAAC,GAAG,EAAE,MAAM,iBAI3B;CACF"}
@@ -1,3 +1,55 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
1
53
  import assert from 'node:assert';
2
54
  import fs, { mkdir } from 'node:fs/promises';
3
55
  import path from 'node:path';
@@ -45,41 +97,77 @@ export class ActorStore {
45
97
  await retrySqlite(() => db.db.selectFrom('repo_root').selectAll().execute());
46
98
  }
47
99
  catch (err) {
48
- db.close();
100
+ await db.close();
49
101
  throw err;
50
102
  }
51
103
  return db;
52
104
  }
53
105
  async read(did, fn) {
54
- const db = await this.openDb(did);
106
+ const env_1 = { stack: [], error: void 0, hasError: false };
55
107
  try {
108
+ const db = __addDisposableResource(env_1, await this.openDb(did), true);
56
109
  const getKeypair = () => this.keypair(did);
57
- return await fn(new ActorStoreReader(did, db, this.resources, getKeypair));
110
+ const reader = __addDisposableResource(env_1, new ActorStoreReader(did, db, this.resources, getKeypair), true);
111
+ return await fn(reader);
112
+ }
113
+ catch (e_1) {
114
+ env_1.error = e_1;
115
+ env_1.hasError = true;
58
116
  }
59
117
  finally {
60
- db.close();
118
+ const result_1 = __disposeResources(env_1);
119
+ if (result_1)
120
+ await result_1;
61
121
  }
62
122
  }
63
123
  async transact(did, fn) {
64
- const keypair = await this.keypair(did);
65
- const db = await this.openDb(did);
124
+ const env_2 = { stack: [], error: void 0, hasError: false };
66
125
  try {
67
- return await db.transaction((dbTxn) => {
68
- return fn(new ActorStoreTransactor(did, dbTxn, keypair, this.resources));
126
+ const keypair = await this.keypair(did);
127
+ const db = __addDisposableResource(env_2, await this.openDb(did), true);
128
+ return await db.transaction(async (dbTxn) => {
129
+ const env_3 = { stack: [], error: void 0, hasError: false };
130
+ try {
131
+ const transactor = __addDisposableResource(env_3, new ActorStoreTransactor(did, dbTxn, keypair, this.resources), true);
132
+ return await fn(transactor);
133
+ }
134
+ catch (e_3) {
135
+ env_3.error = e_3;
136
+ env_3.hasError = true;
137
+ }
138
+ finally {
139
+ const result_3 = __disposeResources(env_3);
140
+ if (result_3)
141
+ await result_3;
142
+ }
69
143
  });
70
144
  }
145
+ catch (e_2) {
146
+ env_2.error = e_2;
147
+ env_2.hasError = true;
148
+ }
71
149
  finally {
72
- db.close();
150
+ const result_2 = __disposeResources(env_2);
151
+ if (result_2)
152
+ await result_2;
73
153
  }
74
154
  }
75
155
  async writeNoTransaction(did, fn) {
76
- const keypair = await this.keypair(did);
77
- const db = await this.openDb(did);
156
+ const env_4 = { stack: [], error: void 0, hasError: false };
78
157
  try {
79
- return await fn(new ActorStoreWriter(did, db, keypair, this.resources));
158
+ const keypair = await this.keypair(did);
159
+ const db = __addDisposableResource(env_4, await this.openDb(did), true);
160
+ const writer = __addDisposableResource(env_4, new ActorStoreWriter(did, db, keypair, this.resources), true);
161
+ return await fn(writer);
162
+ }
163
+ catch (e_4) {
164
+ env_4.error = e_4;
165
+ env_4.hasError = true;
80
166
  }
81
167
  finally {
82
- db.close();
168
+ const result_4 = __disposeResources(env_4);
169
+ if (result_4)
170
+ await result_4;
83
171
  }
84
172
  }
85
173
  async create(did, keypair) {
@@ -99,22 +187,34 @@ export class ActorStore {
99
187
  await migrator.migrateToLatestOrThrow();
100
188
  }
101
189
  finally {
102
- db.close();
190
+ await db.close();
103
191
  }
104
192
  }
105
193
  async destroy(did) {
106
- const blobstore = this.resources.blobstore(did);
107
- if (blobstore instanceof DiskBlobStore) {
108
- await blobstore.deleteAll();
109
- }
110
- else {
111
- const cids = await this.read(did, async (store) => store.repo.blob.getBlobCids());
112
- await blobstore.deleteMany(cids).catch((err) => {
113
- blobStoreLogger.error({ did, cids, err }, 'Failed to delete blobs');
114
- });
194
+ const env_5 = { stack: [], error: void 0, hasError: false };
195
+ try {
196
+ const blobstore = __addDisposableResource(env_5, this.resources.blobstore(did), true);
197
+ if (blobstore instanceof DiskBlobStore) {
198
+ await blobstore.deleteAll();
199
+ }
200
+ else {
201
+ const cids = await this.read(did, async (store) => store.repo.blob.getBlobCids());
202
+ await blobstore.deleteMany(cids).catch((err) => {
203
+ blobStoreLogger.error({ did, cids, err }, 'Failed to delete blobs');
204
+ });
205
+ }
206
+ const { directory } = await this.getLocation(did);
207
+ await rmIfExists(directory, true);
208
+ }
209
+ catch (e_5) {
210
+ env_5.error = e_5;
211
+ env_5.hasError = true;
212
+ }
213
+ finally {
214
+ const result_5 = __disposeResources(env_5);
215
+ if (result_5)
216
+ await result_5;
115
217
  }
116
- const { directory } = await this.getLocation(did);
117
- await rmIfExists(directory, true);
118
218
  }
119
219
  async reserveKeypair(did) {
120
220
  let keyLoc;
@@ -1 +1 @@
1
- {"version":3,"file":"actor-store.js","sourceRoot":"","sources":["../../src/actor-store/actor-store.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from 'node:assert'\nimport fs, { mkdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport { fileExists, readIfExists, rmIfExists } from '@atproto/common'\nimport * as crypto from '@atproto/crypto'\nimport type { ExportableKeypair, Keypair } from '@atproto/crypto'\nimport type { DidString } from '@atproto/lex'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport type { ActorStoreConfig } from '../config/index.js'\nimport { retrySqlite } from '../db/index.js'\nimport { DiskBlobStore } from '../disk-blobstore.js'\nimport { blobStoreLogger } from '../logger.js'\nimport { ActorStoreReader } from './actor-store-reader.js'\nimport type { ActorStoreResources } from './actor-store-resources.js'\nimport { ActorStoreTransactor } from './actor-store-transactor.js'\nimport { ActorStoreWriter } from './actor-store-writer.js'\nimport { type ActorDb, getDb, getMigrator } from './db/index.js'\n\nexport class ActorStore {\n reservedKeyDir: string\n\n constructor(\n public cfg: ActorStoreConfig,\n public resources: ActorStoreResources,\n ) {\n this.reservedKeyDir = path.join(cfg.directory, 'reserved_keys')\n }\n\n async getLocation(did: string) {\n const didHash = await crypto.sha256Hex(did)\n const directory = path.join(this.cfg.directory, didHash.slice(0, 2), did)\n const dbLocation = path.join(directory, `store.sqlite`)\n const keyLocation = path.join(directory, `key`)\n return { directory, dbLocation, keyLocation }\n }\n\n async exists(did: string): Promise<boolean> {\n const location = await this.getLocation(did)\n return await fileExists(location.dbLocation)\n }\n\n async keypair(did: string): Promise<Keypair> {\n const { keyLocation } = await this.getLocation(did)\n const privKey = await fs.readFile(keyLocation)\n return crypto.Secp256k1Keypair.import(privKey)\n }\n\n async openDb(did: string): Promise<ActorDb> {\n const { dbLocation } = await this.getLocation(did)\n const exists = await fileExists(dbLocation)\n if (!exists) {\n throw new InvalidRequestError('Repo not found', 'NotFound')\n }\n\n const db = getDb(dbLocation, this.cfg.disableWalAutoCheckpoint)\n\n // run a simple select with retry logic to ensure the db is ready (not in wal recovery mode)\n try {\n await retrySqlite(() =>\n db.db.selectFrom('repo_root').selectAll().execute(),\n )\n } catch (err) {\n db.close()\n throw err\n }\n\n return db\n }\n\n async read<T>(\n did: DidString,\n fn: (fn: ActorStoreReader) => T | PromiseLike<T>,\n ) {\n const db = await this.openDb(did)\n try {\n const getKeypair = () => this.keypair(did)\n return await fn(new ActorStoreReader(did, db, this.resources, getKeypair))\n } finally {\n db.close()\n }\n }\n\n async transact<T>(\n did: DidString,\n fn: (fn: ActorStoreTransactor) => T | PromiseLike<T>,\n ) {\n const keypair = await this.keypair(did)\n const db = await this.openDb(did)\n try {\n return await db.transaction((dbTxn) => {\n return fn(new ActorStoreTransactor(did, dbTxn, keypair, this.resources))\n })\n } finally {\n db.close()\n }\n }\n\n async writeNoTransaction<T>(\n did: DidString,\n fn: (fn: ActorStoreWriter) => T | PromiseLike<T>,\n ) {\n const keypair = await this.keypair(did)\n const db = await this.openDb(did)\n try {\n return await fn(new ActorStoreWriter(did, db, keypair, this.resources))\n } finally {\n db.close()\n }\n }\n\n async create(did: string, keypair: ExportableKeypair) {\n const { directory, dbLocation, keyLocation } = await this.getLocation(did)\n // ensure subdir exists\n await mkdir(directory, { recursive: true })\n const exists = await fileExists(dbLocation)\n if (exists) {\n throw new InvalidRequestError('Repo already exists', 'AlreadyExists')\n }\n const privKey = await keypair.export()\n await fs.writeFile(keyLocation, privKey)\n\n const db: ActorDb = getDb(dbLocation, this.cfg.disableWalAutoCheckpoint)\n try {\n await db.ensureWal()\n const migrator = getMigrator(db)\n await migrator.migrateToLatestOrThrow()\n } finally {\n db.close()\n }\n }\n\n async destroy(did: DidString) {\n const blobstore = this.resources.blobstore(did)\n if (blobstore instanceof DiskBlobStore) {\n await blobstore.deleteAll()\n } else {\n const cids = await this.read(did, async (store) =>\n store.repo.blob.getBlobCids(),\n )\n await blobstore.deleteMany(cids).catch((err) => {\n blobStoreLogger.error({ did, cids, err }, 'Failed to delete blobs')\n })\n }\n\n const { directory } = await this.getLocation(did)\n await rmIfExists(directory, true)\n }\n\n async reserveKeypair(did?: string): Promise<string> {\n let keyLoc: string | undefined\n if (did) {\n assertSafePathPart(did)\n keyLoc = path.join(this.reservedKeyDir, did)\n const maybeKey = await loadKey(keyLoc)\n if (maybeKey) {\n return maybeKey.did()\n }\n }\n const keypair = await crypto.Secp256k1Keypair.create({ exportable: true })\n const keyDid = keypair.did()\n keyLoc = keyLoc ?? path.join(this.reservedKeyDir, keyDid)\n await mkdir(this.reservedKeyDir, { recursive: true })\n await fs.writeFile(keyLoc, await keypair.export())\n return keyDid\n }\n\n async getReservedKeypair(\n signingKeyOrDid: string,\n ): Promise<ExportableKeypair | undefined> {\n return loadKey(path.join(this.reservedKeyDir, signingKeyOrDid))\n }\n\n async clearReservedKeypair(keyDid: string, did?: string) {\n await rmIfExists(path.join(this.reservedKeyDir, keyDid))\n if (did) {\n await rmIfExists(path.join(this.reservedKeyDir, did))\n }\n }\n\n async storePlcOp(did: string, op: Uint8Array) {\n const { directory } = await this.getLocation(did)\n const opLoc = path.join(directory, `did-op`)\n await fs.writeFile(opLoc, op)\n }\n\n async getPlcOp(did: string): Promise<Uint8Array> {\n const { directory } = await this.getLocation(did)\n const opLoc = path.join(directory, `did-op`)\n return await fs.readFile(opLoc)\n }\n\n async clearPlcOp(did: string) {\n const { directory } = await this.getLocation(did)\n const opLoc = path.join(directory, `did-op`)\n await rmIfExists(opLoc)\n }\n}\n\nconst loadKey = async (loc: string): Promise<ExportableKeypair | undefined> => {\n const privKey = await readIfExists(loc)\n if (!privKey) return undefined\n return crypto.Secp256k1Keypair.import(privKey, { exportable: true })\n}\n\nfunction assertSafePathPart(part: string) {\n const normalized = path.normalize(part)\n assert(\n part === normalized &&\n !part.startsWith('.') &&\n !part.includes('/') &&\n !part.includes('\\\\'),\n `unsafe path part: ${part}`,\n )\n}\n"]}
1
+ {"version":3,"file":"actor-store.js","sourceRoot":"","sources":["../../src/actor-store/actor-store.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from 'node:assert'\nimport fs, { mkdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport { fileExists, readIfExists, rmIfExists } from '@atproto/common'\nimport * as crypto from '@atproto/crypto'\nimport type { ExportableKeypair, Keypair } from '@atproto/crypto'\nimport type { DidString } from '@atproto/lex'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport type { ActorStoreConfig } from '../config/index.js'\nimport { retrySqlite } from '../db/index.js'\nimport { DiskBlobStore } from '../disk-blobstore.js'\nimport { blobStoreLogger } from '../logger.js'\nimport { ActorStoreReader } from './actor-store-reader.js'\nimport type { ActorStoreResources } from './actor-store-resources.js'\nimport { ActorStoreTransactor } from './actor-store-transactor.js'\nimport { ActorStoreWriter } from './actor-store-writer.js'\nimport { type ActorDb, getDb, getMigrator } from './db/index.js'\n\nexport class ActorStore {\n reservedKeyDir: string\n\n constructor(\n public cfg: ActorStoreConfig,\n public resources: ActorStoreResources,\n ) {\n this.reservedKeyDir = path.join(cfg.directory, 'reserved_keys')\n }\n\n async getLocation(did: string) {\n const didHash = await crypto.sha256Hex(did)\n const directory = path.join(this.cfg.directory, didHash.slice(0, 2), did)\n const dbLocation = path.join(directory, `store.sqlite`)\n const keyLocation = path.join(directory, `key`)\n return { directory, dbLocation, keyLocation }\n }\n\n async exists(did: string): Promise<boolean> {\n const location = await this.getLocation(did)\n return await fileExists(location.dbLocation)\n }\n\n async keypair(did: string): Promise<Keypair> {\n const { keyLocation } = await this.getLocation(did)\n const privKey = await fs.readFile(keyLocation)\n return crypto.Secp256k1Keypair.import(privKey)\n }\n\n async openDb(did: string): Promise<ActorDb> {\n const { dbLocation } = await this.getLocation(did)\n const exists = await fileExists(dbLocation)\n if (!exists) {\n throw new InvalidRequestError('Repo not found', 'NotFound')\n }\n\n const db = getDb(dbLocation, this.cfg.disableWalAutoCheckpoint)\n\n // run a simple select with retry logic to ensure the db is ready (not in wal recovery mode)\n try {\n await retrySqlite(() =>\n db.db.selectFrom('repo_root').selectAll().execute(),\n )\n } catch (err) {\n await db.close()\n throw err\n }\n\n return db\n }\n\n async read<T>(\n did: DidString,\n fn: (fn: ActorStoreReader) => T | PromiseLike<T>,\n ) {\n await using db = await this.openDb(did)\n const getKeypair = () => this.keypair(did)\n await using reader = new ActorStoreReader(\n did,\n db,\n this.resources,\n getKeypair,\n )\n return await fn(reader)\n }\n\n async transact<T>(\n did: DidString,\n fn: (transactor: ActorStoreTransactor) => T | PromiseLike<T>,\n ) {\n const keypair = await this.keypair(did)\n await using db = await this.openDb(did)\n return await db.transaction(async (dbTxn) => {\n await using transactor = new ActorStoreTransactor(\n did,\n dbTxn,\n keypair,\n this.resources,\n )\n return await fn(transactor)\n })\n }\n\n async writeNoTransaction<T>(\n did: DidString,\n fn: (writer: ActorStoreWriter) => T | PromiseLike<T>,\n ) {\n const keypair = await this.keypair(did)\n await using db = await this.openDb(did)\n await using writer = new ActorStoreWriter(did, db, keypair, this.resources)\n return await fn(writer)\n }\n\n async create(did: string, keypair: ExportableKeypair) {\n const { directory, dbLocation, keyLocation } = await this.getLocation(did)\n // ensure subdir exists\n await mkdir(directory, { recursive: true })\n const exists = await fileExists(dbLocation)\n if (exists) {\n throw new InvalidRequestError('Repo already exists', 'AlreadyExists')\n }\n const privKey = await keypair.export()\n await fs.writeFile(keyLocation, privKey)\n\n const db: ActorDb = getDb(dbLocation, this.cfg.disableWalAutoCheckpoint)\n try {\n await db.ensureWal()\n const migrator = getMigrator(db)\n await migrator.migrateToLatestOrThrow()\n } finally {\n await db.close()\n }\n }\n\n async destroy(did: DidString) {\n await using blobstore = this.resources.blobstore(did)\n if (blobstore instanceof DiskBlobStore) {\n await blobstore.deleteAll()\n } else {\n const cids = await this.read(did, async (store) =>\n store.repo.blob.getBlobCids(),\n )\n await blobstore.deleteMany(cids).catch((err) => {\n blobStoreLogger.error({ did, cids, err }, 'Failed to delete blobs')\n })\n }\n\n const { directory } = await this.getLocation(did)\n await rmIfExists(directory, true)\n }\n\n async reserveKeypair(did?: string): Promise<string> {\n let keyLoc: string | undefined\n if (did) {\n assertSafePathPart(did)\n keyLoc = path.join(this.reservedKeyDir, did)\n const maybeKey = await loadKey(keyLoc)\n if (maybeKey) {\n return maybeKey.did()\n }\n }\n const keypair = await crypto.Secp256k1Keypair.create({ exportable: true })\n const keyDid = keypair.did()\n keyLoc = keyLoc ?? path.join(this.reservedKeyDir, keyDid)\n await mkdir(this.reservedKeyDir, { recursive: true })\n await fs.writeFile(keyLoc, await keypair.export())\n return keyDid\n }\n\n async getReservedKeypair(\n signingKeyOrDid: string,\n ): Promise<ExportableKeypair | undefined> {\n return loadKey(path.join(this.reservedKeyDir, signingKeyOrDid))\n }\n\n async clearReservedKeypair(keyDid: string, did?: string) {\n await rmIfExists(path.join(this.reservedKeyDir, keyDid))\n if (did) {\n await rmIfExists(path.join(this.reservedKeyDir, did))\n }\n }\n\n async storePlcOp(did: string, op: Uint8Array) {\n const { directory } = await this.getLocation(did)\n const opLoc = path.join(directory, `did-op`)\n await fs.writeFile(opLoc, op)\n }\n\n async getPlcOp(did: string): Promise<Uint8Array> {\n const { directory } = await this.getLocation(did)\n const opLoc = path.join(directory, `did-op`)\n return await fs.readFile(opLoc)\n }\n\n async clearPlcOp(did: string) {\n const { directory } = await this.getLocation(did)\n const opLoc = path.join(directory, `did-op`)\n await rmIfExists(opLoc)\n }\n}\n\nconst loadKey = async (loc: string): Promise<ExportableKeypair | undefined> => {\n const privKey = await readIfExists(loc)\n if (!privKey) return undefined\n return crypto.Secp256k1Keypair.import(privKey, { exportable: true })\n}\n\nfunction assertSafePathPart(part: string) {\n const normalized = path.normalize(part)\n assert(\n part === normalized &&\n !part.startsWith('.') &&\n !part.includes('/') &&\n !part.includes('\\\\'),\n `unsafe path part: ${part}`,\n )\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"importRepo.d.ts","sourceRoot":"","sources":["../../../../../src/api/com/atproto/repo/importRepo.ts"],"names":[],"mappings":"AAUA,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAEvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAGxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAqFvD"}
1
+ {"version":3,"file":"importRepo.d.ts","sourceRoot":"","sources":["../../../../../src/api/com/atproto/repo/importRepo.ts"],"names":[],"mappings":"AAWA,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAEvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAGxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QA8FvD"}
@@ -1,6 +1,6 @@
1
1
  import { TID } from '@atproto/common';
2
2
  import { enumBlobRefs } from '@atproto/lex-data';
3
- import { BlockMap, WriteOpAction, getAndParseRecord, readCarStream, verifyDiff, } from '@atproto/repo';
3
+ import { BlockMap, VisitedCidError, WriteOpAction, getAndParseRecord, readCarStream, verifyDiff, } from '@atproto/repo';
4
4
  import { AtUri } from '@atproto/syntax';
5
5
  import { InvalidRequestError } from '@atproto/xrpc-server';
6
6
  import { ACCESS_FULL } from '../../../../auth-scope.js';
@@ -38,7 +38,12 @@ export default function (server, ctx) {
38
38
  const rev = TID.nextStr();
39
39
  const did = store.repo.did;
40
40
  const currRepo = await store.repo.maybeLoadRepo();
41
- const diff = await verifyDiff(currRepo, blockMap, roots[0], undefined, undefined, { ensureLeaves: false });
41
+ const diff = await verifyDiff(currRepo, blockMap, roots[0], undefined, undefined, { ensureLeaves: false }).catch((cause) => {
42
+ if (cause instanceof VisitedCidError) {
43
+ throw new InvalidRequestError(`invalid MST: node referenced more than once: ${cause.cid}`, undefined, { cause });
44
+ }
45
+ throw cause;
46
+ });
42
47
  diff.commit.rev = rev;
43
48
  await store.repo.storage.applyCommit(diff.commit, currRepo === null);
44
49
  // @NOTE There is no point in performing the following concurrently
@@ -1 +1 @@
1
- {"version":3,"file":"importRepo.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/repo/importRepo.ts"],"names":[],"mappings":"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","sourcesContent":["import { TID } from '@atproto/common'\nimport { type LexMap, enumBlobRefs } from '@atproto/lex-data'\nimport {\n BlockMap,\n WriteOpAction,\n getAndParseRecord,\n readCarStream,\n verifyDiff,\n} from '@atproto/repo'\nimport { AtUri } from '@atproto/syntax'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport { ACCESS_FULL } from '../../../../auth-scope.js'\nimport type { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(com.atproto.repo.importRepo, {\n opts: {\n blobLimit: ctx.cfg.service.maxImportSize,\n },\n auth: ctx.authVerifier.authorization({\n checkTakedown: true,\n scopes: ACCESS_FULL,\n authorize: (permissions) => {\n permissions.assertAccount({ attr: 'repo', action: 'manage' })\n },\n }),\n handler: async ({ input, auth }) => {\n if (!ctx.cfg.service.acceptingImports) {\n throw new InvalidRequestError('Service is not accepting repo imports')\n }\n\n const { did } = auth.credentials\n\n // @NOTE process as much as we can before the transaction, in particular\n // the reading of the body stream.\n const { roots, blocks } = await readCarStream(input.body)\n if (roots.length !== 1) {\n await blocks.dump()\n throw new InvalidRequestError('expected one root')\n }\n\n const blockMap = new BlockMap()\n for await (const block of blocks) {\n blockMap.set(block.cid, block.bytes)\n }\n\n await ctx.actorStore.transact(did, async (store) => {\n const now = new Date().toISOString()\n const rev = TID.nextStr()\n const did = store.repo.did\n\n const currRepo = await store.repo.maybeLoadRepo()\n const diff = await verifyDiff(\n currRepo,\n blockMap,\n roots[0],\n undefined,\n undefined,\n { ensureLeaves: false },\n )\n diff.commit.rev = rev\n await store.repo.storage.applyCommit(diff.commit, currRepo === null)\n\n // @NOTE There is no point in performing the following concurrently\n // since better-sqlite3 is synchronous.\n for (const write of diff.writes) {\n const uri = AtUri.make(did, write.collection, write.rkey)\n if (write.action === WriteOpAction.Delete) {\n await store.record.deleteRecord(uri)\n } else {\n let parsedRecord: LexMap\n try {\n // @NOTE getAndParseRecord returns a promise for historical\n // reasons but it's internal processing is actually synchronous.\n const parsed = await getAndParseRecord(blockMap, write.cid)\n parsedRecord = parsed.record\n } catch {\n throw new InvalidRequestError(\n `Could not parse record at '${write.collection}/${write.rkey}'`,\n )\n }\n\n await store.record.indexRecord(\n uri,\n write.cid,\n parsedRecord,\n write.action,\n rev,\n now,\n )\n const recordBlobs = Array.from(\n enumBlobRefs(parsedRecord, { allowLegacy: true, strict: false }),\n )\n await store.repo.blob.insertBlobs(uri.toString(), recordBlobs)\n }\n }\n })\n },\n })\n}\n"]}
1
+ {"version":3,"file":"importRepo.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/repo/importRepo.ts"],"names":[],"mappings":"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","sourcesContent":["import { TID } from '@atproto/common'\nimport { type LexMap, enumBlobRefs } from '@atproto/lex-data'\nimport {\n BlockMap,\n VisitedCidError,\n WriteOpAction,\n getAndParseRecord,\n readCarStream,\n verifyDiff,\n} from '@atproto/repo'\nimport { AtUri } from '@atproto/syntax'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport { ACCESS_FULL } from '../../../../auth-scope.js'\nimport type { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(com.atproto.repo.importRepo, {\n opts: {\n blobLimit: ctx.cfg.service.maxImportSize,\n },\n auth: ctx.authVerifier.authorization({\n checkTakedown: true,\n scopes: ACCESS_FULL,\n authorize: (permissions) => {\n permissions.assertAccount({ attr: 'repo', action: 'manage' })\n },\n }),\n handler: async ({ input, auth }) => {\n if (!ctx.cfg.service.acceptingImports) {\n throw new InvalidRequestError('Service is not accepting repo imports')\n }\n\n const { did } = auth.credentials\n\n // @NOTE process as much as we can before the transaction, in particular\n // the reading of the body stream.\n const { roots, blocks } = await readCarStream(input.body)\n if (roots.length !== 1) {\n await blocks.dump()\n throw new InvalidRequestError('expected one root')\n }\n\n const blockMap = new BlockMap()\n for await (const block of blocks) {\n blockMap.set(block.cid, block.bytes)\n }\n\n await ctx.actorStore.transact(did, async (store) => {\n const now = new Date().toISOString()\n const rev = TID.nextStr()\n const did = store.repo.did\n\n const currRepo = await store.repo.maybeLoadRepo()\n const diff = await verifyDiff(\n currRepo,\n blockMap,\n roots[0],\n undefined,\n undefined,\n { ensureLeaves: false },\n ).catch((cause) => {\n if (cause instanceof VisitedCidError) {\n throw new InvalidRequestError(\n `invalid MST: node referenced more than once: ${cause.cid}`,\n undefined,\n { cause },\n )\n }\n throw cause\n })\n diff.commit.rev = rev\n await store.repo.storage.applyCommit(diff.commit, currRepo === null)\n\n // @NOTE There is no point in performing the following concurrently\n // since better-sqlite3 is synchronous.\n for (const write of diff.writes) {\n const uri = AtUri.make(did, write.collection, write.rkey)\n if (write.action === WriteOpAction.Delete) {\n await store.record.deleteRecord(uri)\n } else {\n let parsedRecord: LexMap\n try {\n // @NOTE getAndParseRecord returns a promise for historical\n // reasons but it's internal processing is actually synchronous.\n const parsed = await getAndParseRecord(blockMap, write.cid)\n parsedRecord = parsed.record\n } catch {\n throw new InvalidRequestError(\n `Could not parse record at '${write.collection}/${write.rkey}'`,\n )\n }\n\n await store.record.indexRecord(\n uri,\n write.cid,\n parsedRecord,\n write.action,\n rev,\n now,\n )\n const recordBlobs = Array.from(\n enumBlobRefs(parsedRecord, { allowLegacy: true, strict: false }),\n )\n await store.repo.blob.insertBlobs(uri.toString(), recordBlobs)\n }\n }\n })\n },\n })\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"getRecord.d.ts","sourceRoot":"","sources":["../../../../../src/api/com/atproto/sync/getRecord.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAGvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAIxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAsCvD"}
1
+ {"version":3,"file":"getRecord.d.ts","sourceRoot":"","sources":["../../../../../src/api/com/atproto/sync/getRecord.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAGvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAIxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAwCvD"}
@@ -16,6 +16,8 @@ export default function (server, ctx) {
16
16
  const { did, collection, rkey } = params;
17
17
  await assertRepoAvailability(ctx, did, isUserOrAdmin(auth, did));
18
18
  // must open up the db outside of store interface so that we can close the file handle after finished streaming
19
+ // @TODO *not* using "await using" so that we can manually control when the DB
20
+ // is closed. This should be implemented using an AsyncDisposableStack.
19
21
  const actorDb = await ctx.actorStore.openDb(did);
20
22
  let carStream;
21
23
  try {
@@ -28,10 +30,10 @@ export default function (server, ctx) {
28
30
  carStream = byteIterableToStream(carIter);
29
31
  }
30
32
  catch (err) {
31
- actorDb.close();
33
+ await actorDb.close();
32
34
  throw err;
33
35
  }
34
- const closeDb = () => actorDb.close();
36
+ const closeDb = () => void actorDb.close();
35
37
  carStream.on('error', closeDb);
36
38
  carStream.on('close', closeDb);
37
39
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"getRecord.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/sync/getRecord.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AACtD,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,mBAAmB,EAAe,MAAM,sBAAsB,CAAA;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAE5D,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAElD,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE;QACrC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,iCAAiC,CAAC;YACvD,SAAS,EAAE,GAAG,EAAE;gBACd,eAAe;YACjB,CAAC;SACF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;YAClC,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,MAAM,CAAA;YACxC,MAAM,sBAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;YAEhE,+GAA+G;YAC/G,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAEhD,IAAI,SAA0B,CAAA;YAC9B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC,CAAA;gBAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;gBAEtC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM,IAAI,mBAAmB,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAA;gBACtE,CAAC;gBACD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;gBACxE,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAC3C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,EAAE,CAAA;gBACf,MAAM,GAAG,CAAA;YACX,CAAC;YACD,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;YACrC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YAC9B,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YAE9B,OAAO;gBACL,QAAQ,EAAE,0BAAmC;gBAC7C,IAAI,EAAE,SAAS;aAChB,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import type stream from 'node:stream'\nimport { byteIterableToStream } from '@atproto/common'\nimport * as repo from '@atproto/repo'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport { SqlRepoReader } from '../../../../actor-store/repo/sql-repo-reader.js'\nimport { isUserOrAdmin } from '../../../../auth-verifier.js'\nimport type { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\nimport { assertRepoAvailability } from './util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(com.atproto.sync.getRecord, {\n auth: ctx.authVerifier.authorizationOrAdminTokenOptional({\n authorize: () => {\n // always allow\n },\n }),\n handler: async ({ params, auth }) => {\n const { did, collection, rkey } = params\n await assertRepoAvailability(ctx, did, isUserOrAdmin(auth, did))\n\n // must open up the db outside of store interface so that we can close the file handle after finished streaming\n const actorDb = await ctx.actorStore.openDb(did)\n\n let carStream: stream.Readable\n try {\n const storage = new SqlRepoReader(actorDb)\n const commit = await storage.getRoot()\n\n if (!commit) {\n throw new InvalidRequestError(`Could not find repo for DID: ${did}`)\n }\n const carIter = repo.getRecords(storage, commit, [{ collection, rkey }])\n carStream = byteIterableToStream(carIter)\n } catch (err) {\n actorDb.close()\n throw err\n }\n const closeDb = () => actorDb.close()\n carStream.on('error', closeDb)\n carStream.on('close', closeDb)\n\n return {\n encoding: 'application/vnd.ipld.car' as const,\n body: carStream,\n }\n },\n })\n}\n"]}
1
+ {"version":3,"file":"getRecord.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/sync/getRecord.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AACtD,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,mBAAmB,EAAe,MAAM,sBAAsB,CAAA;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAE5D,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAElD,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE;QACrC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,iCAAiC,CAAC;YACvD,SAAS,EAAE,GAAG,EAAE;gBACd,eAAe;YACjB,CAAC;SACF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;YAClC,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,MAAM,CAAA;YACxC,MAAM,sBAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;YAEhE,+GAA+G;YAC/G,8EAA8E;YAC9E,uEAAuE;YACvE,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAEhD,IAAI,SAA0B,CAAA;YAC9B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC,CAAA;gBAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;gBAEtC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM,IAAI,mBAAmB,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAA;gBACtE,CAAC;gBACD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;gBACxE,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAC3C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,OAAO,CAAC,KAAK,EAAE,CAAA;gBACrB,MAAM,GAAG,CAAA;YACX,CAAC;YACD,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,KAAK,EAAE,CAAA;YAC1C,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YAC9B,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YAE9B,OAAO;gBACL,QAAQ,EAAE,0BAAmC;gBAC7C,IAAI,EAAE,SAAS;aAChB,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import type stream from 'node:stream'\nimport { byteIterableToStream } from '@atproto/common'\nimport * as repo from '@atproto/repo'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport { SqlRepoReader } from '../../../../actor-store/repo/sql-repo-reader.js'\nimport { isUserOrAdmin } from '../../../../auth-verifier.js'\nimport type { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\nimport { assertRepoAvailability } from './util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(com.atproto.sync.getRecord, {\n auth: ctx.authVerifier.authorizationOrAdminTokenOptional({\n authorize: () => {\n // always allow\n },\n }),\n handler: async ({ params, auth }) => {\n const { did, collection, rkey } = params\n await assertRepoAvailability(ctx, did, isUserOrAdmin(auth, did))\n\n // must open up the db outside of store interface so that we can close the file handle after finished streaming\n // @TODO *not* using \"await using\" so that we can manually control when the DB\n // is closed. This should be implemented using an AsyncDisposableStack.\n const actorDb = await ctx.actorStore.openDb(did)\n\n let carStream: stream.Readable\n try {\n const storage = new SqlRepoReader(actorDb)\n const commit = await storage.getRoot()\n\n if (!commit) {\n throw new InvalidRequestError(`Could not find repo for DID: ${did}`)\n }\n const carIter = repo.getRecords(storage, commit, [{ collection, rkey }])\n carStream = byteIterableToStream(carIter)\n } catch (err) {\n await actorDb.close()\n throw err\n }\n const closeDb = () => void actorDb.close()\n carStream.on('error', closeDb)\n carStream.on('close', closeDb)\n\n return {\n encoding: 'application/vnd.ipld.car' as const,\n body: carStream,\n }\n },\n })\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"getRepo.d.ts","sourceRoot":"","sources":["../../../../../src/api/com/atproto/sync/getRepo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAMrC,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAOvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAMxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAgCvD;AAED,eAAO,MAAM,YAAY,QAClB,UAAU,OACV,MAAM,UACH,MAAM,KACb,OAAO,CAAC,MAAM,CAAC,QAAQ,CAiBzB,CAAA"}
1
+ {"version":3,"file":"getRepo.d.ts","sourceRoot":"","sources":["../../../../../src/api/com/atproto/sync/getRepo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAMrC,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAOvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAMxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAgCvD;AAED,eAAO,MAAM,YAAY,QAClB,UAAU,OACV,MAAM,UACH,MAAM,KACb,OAAO,CAAC,MAAM,CAAC,QAAQ,CAmBzB,CAAA"}
@@ -38,12 +38,14 @@ export default function (server, ctx) {
38
38
  });
39
39
  }
40
40
  export const getCarStream = async (ctx, did, since) => {
41
+ // @TODO *not* using "await using" so that we can manually control when the DB
42
+ // is closed. This should be implemented using an AsyncDisposableStack.
41
43
  const actorDb = await ctx.actorStore.openDb(did);
42
44
  try {
43
45
  const storage = new SqlRepoReader(actorDb);
44
46
  const carIter = await storage.getCarStream(since);
45
47
  const carStream = byteIterableToStream(carIter);
46
- const closeDb = () => actorDb.close();
48
+ const closeDb = () => void actorDb.close();
47
49
  carStream.on('error', closeDb);
48
50
  carStream.on('close', closeDb);
49
51
  return carStream;
@@ -1 +1 @@
1
- {"version":3,"file":"getRepo.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/sync/getRepo.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EACN,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,mBAAmB,EAAe,MAAM,sBAAsB,CAAA;AACvE,OAAO,EACL,qBAAqB,EACrB,aAAa,GACd,MAAM,iDAAiD,CAAA;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAE5D,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAElD,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,CAAA;AAEvC,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE;QACnC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,iCAAiC,CAAC;YACvD,UAAU,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC;YACjC,SAAS,EAAE,GAAG,EAAE;gBACd,eAAe;YACjB,CAAC;SACF,CAAC;QACF,SAAS,EAAE;YACT,UAAU,EAAE,CAAC,GAAG,MAAM;YACtB,MAAM,EAAE,IAAI;SACb;QACD,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;YACvC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,MAAM,CAAA;YAC7B,MAAM,sBAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;YAEhE,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;YAErD,OAAO;gBACL,QAAQ,EAAE,0BAAmC;gBAC7C,wEAAwE;gBACxE,oEAAoE;gBACpE,sEAAsE;gBACtE,EAAE;gBACF,+DAA+D;gBAC/D,oEAAoE;gBACpE,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC;oBAClC,CAAC,CAAC,kBAAkB,CAAC,SAAS,EAAE,qBAAqB,CAAC;oBACtD,CAAC,CAAC,SAAS;aACd,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAC/B,GAAe,EACf,GAAW,EACX,KAAc,EACY,EAAE;IAC5B,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAChD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC,CAAA;QAC1C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QACjD,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;QAC/C,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;QACrC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAC9B,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAC9B,OAAO,SAAS,CAAA;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,CAAC,KAAK,EAAE,CAAA;QACrB,IAAI,GAAG,YAAY,qBAAqB,EAAE,CAAC;YACzC,MAAM,IAAI,mBAAmB,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAA;QACtE,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC,CAAA","sourcesContent":["import type stream from 'node:stream'\nimport {\n MINUTE,\n byteIterableToStream,\n coalesceByteStream,\n} from '@atproto/common'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport {\n RepoRootNotFoundError,\n SqlRepoReader,\n} from '../../../../actor-store/repo/sql-repo-reader.js'\nimport { AuthScope } from '../../../../auth-scope.js'\nimport { isUserOrAdmin } from '../../../../auth-verifier.js'\nimport type { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\nimport { assertRepoAvailability } from './util.js'\n\nconst CAR_STREAM_CHUNK_SIZE = 64 * 1024\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(com.atproto.sync.getRepo, {\n auth: ctx.authVerifier.authorizationOrAdminTokenOptional({\n additional: [AuthScope.Takendown],\n authorize: () => {\n // always allow\n },\n }),\n rateLimit: {\n durationMs: 5 * MINUTE,\n points: 6000,\n },\n handler: async ({ req, params, auth }) => {\n const { did, since } = params\n await assertRepoAvailability(ctx, did, isUserOrAdmin(auth, did))\n\n const carStream = await getCarStream(ctx, did, since)\n\n return {\n encoding: 'application/vnd.ipld.car' as const,\n // @NOTE If the client asked for compression (via \"accept-encoding\"), we\n // coalesce the CAR stream into larger chunks to improve compression\n // efficiency. See https://github.com/bluesky-social/atproto/pull/5078\n //\n // @TODO This would be better handled by xrpc-server and/or the\n // compression middleware instead of manually coalescing the stream.\n body: req.headers['accept-encoding']\n ? coalesceByteStream(carStream, CAR_STREAM_CHUNK_SIZE)\n : carStream,\n }\n },\n })\n}\n\nexport const getCarStream = async (\n ctx: AppContext,\n did: string,\n since?: string,\n): Promise<stream.Readable> => {\n const actorDb = await ctx.actorStore.openDb(did)\n try {\n const storage = new SqlRepoReader(actorDb)\n const carIter = await storage.getCarStream(since)\n const carStream = byteIterableToStream(carIter)\n const closeDb = () => actorDb.close()\n carStream.on('error', closeDb)\n carStream.on('close', closeDb)\n return carStream\n } catch (err) {\n await actorDb.close()\n if (err instanceof RepoRootNotFoundError) {\n throw new InvalidRequestError(`Could not find repo for DID: ${did}`)\n }\n throw err\n }\n}\n"]}
1
+ {"version":3,"file":"getRepo.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/sync/getRepo.ts"],"names":[],"mappings":"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","sourcesContent":["import type stream from 'node:stream'\nimport {\n MINUTE,\n byteIterableToStream,\n coalesceByteStream,\n} from '@atproto/common'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport {\n RepoRootNotFoundError,\n SqlRepoReader,\n} from '../../../../actor-store/repo/sql-repo-reader.js'\nimport { AuthScope } from '../../../../auth-scope.js'\nimport { isUserOrAdmin } from '../../../../auth-verifier.js'\nimport type { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\nimport { assertRepoAvailability } from './util.js'\n\nconst CAR_STREAM_CHUNK_SIZE = 64 * 1024\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(com.atproto.sync.getRepo, {\n auth: ctx.authVerifier.authorizationOrAdminTokenOptional({\n additional: [AuthScope.Takendown],\n authorize: () => {\n // always allow\n },\n }),\n rateLimit: {\n durationMs: 5 * MINUTE,\n points: 6000,\n },\n handler: async ({ req, params, auth }) => {\n const { did, since } = params\n await assertRepoAvailability(ctx, did, isUserOrAdmin(auth, did))\n\n const carStream = await getCarStream(ctx, did, since)\n\n return {\n encoding: 'application/vnd.ipld.car' as const,\n // @NOTE If the client asked for compression (via \"accept-encoding\"), we\n // coalesce the CAR stream into larger chunks to improve compression\n // efficiency. See https://github.com/bluesky-social/atproto/pull/5078\n //\n // @TODO This would be better handled by xrpc-server and/or the\n // compression middleware instead of manually coalescing the stream.\n body: req.headers['accept-encoding']\n ? coalesceByteStream(carStream, CAR_STREAM_CHUNK_SIZE)\n : carStream,\n }\n },\n })\n}\n\nexport const getCarStream = async (\n ctx: AppContext,\n did: string,\n since?: string,\n): Promise<stream.Readable> => {\n // @TODO *not* using \"await using\" so that we can manually control when the DB\n // is closed. This should be implemented using an AsyncDisposableStack.\n const actorDb = await ctx.actorStore.openDb(did)\n try {\n const storage = new SqlRepoReader(actorDb)\n const carIter = await storage.getCarStream(since)\n const carStream = byteIterableToStream(carIter)\n const closeDb = () => void actorDb.close()\n carStream.on('error', closeDb)\n carStream.on('close', closeDb)\n return carStream\n } catch (err) {\n await actorDb.close()\n if (err instanceof RepoRootNotFoundError) {\n throw new InvalidRequestError(`Could not find repo for DID: ${did}`)\n }\n throw err\n }\n}\n"]}
package/dist/context.d.ts CHANGED
@@ -6,7 +6,7 @@ import * as crypto from '@atproto/crypto';
6
6
  import { IdResolver } from '@atproto/identity';
7
7
  import { Client } from '@atproto/lex';
8
8
  import { OAuthProvider } from '@atproto/oauth-provider/provider';
9
- import type { BlobStore } from '@atproto/repo';
9
+ import type { BlobStoreCreator } from '@atproto/repo';
10
10
  import { type Fetch } from '@atproto-labs/fetch-node';
11
11
  import { AccountManager } from './account-manager/account-manager.js';
12
12
  import { ActorStore } from './actor-store/actor-store.js';
@@ -22,7 +22,7 @@ import { type LocalViewerCreator } from './read-after-write/viewer.js';
22
22
  import { Sequencer } from './sequencer/index.js';
23
23
  export type AppContextOptions = {
24
24
  actorStore: ActorStore;
25
- blobstore: (did: string) => BlobStore;
25
+ blobstore: BlobStoreCreator;
26
26
  localViewer: LocalViewerCreator;
27
27
  mailer: ServerMailer;
28
28
  moderationMailer: ModerationMailer;
@@ -48,7 +48,7 @@ export type AppContextOptions = {
48
48
  };
49
49
  export declare class AppContext implements AsyncDisposable {
50
50
  actorStore: ActorStore;
51
- blobstore: (did: string) => BlobStore;
51
+ blobstore: BlobStoreCreator;
52
52
  localViewer: LocalViewerCreator;
53
53
  mailer: ServerMailer;
54
54
  moderationMailer: ModerationMailer;
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}