@atproto/bsky 0.0.81 → 0.0.83

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 (77) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/api/app/bsky/graph/getSuggestedFollowsByActor.js +1 -3
  3. package/dist/api/app/bsky/graph/getSuggestedFollowsByActor.js.map +1 -1
  4. package/dist/auth-verifier.d.ts +6 -0
  5. package/dist/auth-verifier.d.ts.map +1 -1
  6. package/dist/auth-verifier.js +80 -1
  7. package/dist/auth-verifier.js.map +1 -1
  8. package/dist/config.d.ts +2 -0
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js +5 -0
  11. package/dist/config.js.map +1 -1
  12. package/dist/data-plane/client.d.ts.map +1 -1
  13. package/dist/data-plane/client.js +2 -1
  14. package/dist/data-plane/client.js.map +1 -1
  15. package/dist/data-plane/server/db/migrations/20240829T211238293Z-simplify-actor-sync.d.ts +4 -0
  16. package/dist/data-plane/server/db/migrations/20240829T211238293Z-simplify-actor-sync.d.ts.map +1 -0
  17. package/dist/data-plane/server/db/migrations/20240829T211238293Z-simplify-actor-sync.js +26 -0
  18. package/dist/data-plane/server/db/migrations/20240829T211238293Z-simplify-actor-sync.js.map +1 -0
  19. package/dist/data-plane/server/db/migrations/index.d.ts +1 -0
  20. package/dist/data-plane/server/db/migrations/index.d.ts.map +1 -1
  21. package/dist/data-plane/server/db/migrations/index.js +2 -1
  22. package/dist/data-plane/server/db/migrations/index.js.map +1 -1
  23. package/dist/data-plane/server/db/tables/actor-sync.d.ts +0 -3
  24. package/dist/data-plane/server/db/tables/actor-sync.d.ts.map +1 -1
  25. package/dist/data-plane/server/db/tables/actor-sync.js.map +1 -1
  26. package/dist/data-plane/server/indexing/index.d.ts +2 -7
  27. package/dist/data-plane/server/indexing/index.d.ts.map +1 -1
  28. package/dist/data-plane/server/indexing/index.js +4 -21
  29. package/dist/data-plane/server/indexing/index.js.map +1 -1
  30. package/dist/data-plane/server/subscription.d.ts +26 -0
  31. package/dist/data-plane/server/subscription.d.ts.map +1 -0
  32. package/dist/data-plane/server/subscription.js +115 -0
  33. package/dist/data-plane/server/subscription.js.map +1 -0
  34. package/dist/feature-gates.d.ts +5 -1
  35. package/dist/feature-gates.d.ts.map +1 -1
  36. package/dist/feature-gates.js +5 -1
  37. package/dist/feature-gates.js.map +1 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +4 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/lexicon/lexicons.d.ts +35 -0
  42. package/dist/lexicon/lexicons.d.ts.map +1 -1
  43. package/dist/lexicon/lexicons.js +35 -0
  44. package/dist/lexicon/lexicons.js.map +1 -1
  45. package/dist/lexicon/types/app/bsky/actor/defs.d.ts +14 -0
  46. package/dist/lexicon/types/app/bsky/actor/defs.d.ts.map +1 -1
  47. package/dist/lexicon/types/app/bsky/actor/defs.js +9 -1
  48. package/dist/lexicon/types/app/bsky/actor/defs.js.map +1 -1
  49. package/package.json +10 -8
  50. package/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts +1 -8
  51. package/src/auth-verifier.ts +77 -0
  52. package/src/config.ts +8 -0
  53. package/src/data-plane/client.ts +4 -1
  54. package/src/data-plane/server/db/migrations/20240829T211238293Z-simplify-actor-sync.ts +23 -0
  55. package/src/data-plane/server/db/migrations/index.ts +1 -0
  56. package/src/data-plane/server/db/tables/actor-sync.ts +0 -3
  57. package/src/data-plane/server/indexing/index.ts +4 -25
  58. package/src/data-plane/server/subscription.ts +104 -0
  59. package/src/feature-gates.ts +5 -1
  60. package/src/index.ts +5 -1
  61. package/src/lexicon/lexicons.ts +37 -0
  62. package/src/lexicon/types/app/bsky/actor/defs.ts +23 -0
  63. package/tests/data-plane/indexing.test.ts +1 -1
  64. package/tests/data-plane/{subscription/repo.test.ts → subscription.test.ts} +4 -9
  65. package/tests/entryway-auth.test.ts +174 -0
  66. package/tests/views/actor-search.test.ts +1 -1
  67. package/dist/data-plane/server/subscription/index.d.ts +0 -33
  68. package/dist/data-plane/server/subscription/index.d.ts.map +0 -1
  69. package/dist/data-plane/server/subscription/index.js +0 -341
  70. package/dist/data-plane/server/subscription/index.js.map +0 -1
  71. package/dist/data-plane/server/subscription/util.d.ts +0 -65
  72. package/dist/data-plane/server/subscription/util.d.ts.map +0 -1
  73. package/dist/data-plane/server/subscription/util.js +0 -215
  74. package/dist/data-plane/server/subscription/util.js.map +0 -1
  75. package/src/data-plane/server/subscription/index.ts +0 -352
  76. package/src/data-plane/server/subscription/util.ts +0 -156
  77. package/tests/data-plane/subscription/util.test.ts +0 -185
@@ -1,156 +0,0 @@
1
- import assert from 'node:assert'
2
- import PQueue from 'p-queue'
3
- import { OutputSchema as RepoMessage } from '../../../lexicon/types/com/atproto/sync/subscribeRepos'
4
- import * as message from '../../../lexicon/types/com/atproto/sync/subscribeRepos'
5
-
6
- // A queue with arbitrarily many partitions, each processing work sequentially.
7
- // Partitions are created lazily and taken out of memory when they go idle.
8
- export class PartitionedQueue {
9
- main: PQueue
10
- partitions = new Map<string, PQueue>()
11
-
12
- constructor(opts: { concurrency: number }) {
13
- this.main = new PQueue({ concurrency: opts.concurrency })
14
- }
15
-
16
- async add(partitionId: string, task: () => Promise<void>) {
17
- if (this.main.isPaused) return
18
- return this.main.add(() => {
19
- return this.getPartition(partitionId).add(task)
20
- })
21
- }
22
-
23
- async destroy() {
24
- this.main.pause()
25
- this.main.clear()
26
- this.partitions.forEach((p) => p.clear())
27
- await this.main.onIdle() // All in-flight work completes
28
- }
29
-
30
- private getPartition(partitionId: string) {
31
- let partition = this.partitions.get(partitionId)
32
- if (!partition) {
33
- partition = new PQueue({ concurrency: 1 })
34
- partition.once('idle', () => this.partitions.delete(partitionId))
35
- this.partitions.set(partitionId, partition)
36
- }
37
- return partition
38
- }
39
- }
40
-
41
- export class LatestQueue {
42
- queue = new PQueue({ concurrency: 1 })
43
-
44
- async add(task: () => Promise<void>) {
45
- if (this.queue.isPaused) return
46
- this.queue.clear() // Only queue the latest task, invalidate any previous ones
47
- return this.queue.add(task)
48
- }
49
-
50
- async destroy() {
51
- this.queue.pause()
52
- this.queue.clear()
53
- await this.queue.onIdle() // All in-flight work completes
54
- }
55
- }
56
-
57
- /**
58
- * Add items to a list, and mark those items as
59
- * completed. Upon item completion, get list of consecutive
60
- * items completed at the head of the list. Example:
61
- *
62
- * const consecutive = new ConsecutiveList<number>()
63
- * const item1 = consecutive.push(1)
64
- * const item2 = consecutive.push(2)
65
- * const item3 = consecutive.push(3)
66
- * item2.complete() // []
67
- * item1.complete() // [1, 2]
68
- * item3.complete() // [3]
69
- *
70
- */
71
- export class ConsecutiveList<T> {
72
- list: ConsecutiveItem<T>[] = []
73
-
74
- push(value: T) {
75
- const item = new ConsecutiveItem<T>(this, value)
76
- this.list.push(item)
77
- return item
78
- }
79
-
80
- complete(): T[] {
81
- let i = 0
82
- while (this.list[i]?.isComplete) {
83
- i += 1
84
- }
85
- return this.list.splice(0, i).map((item) => item.value)
86
- }
87
- }
88
-
89
- export class ConsecutiveItem<T> {
90
- isComplete = false
91
- constructor(
92
- private consecutive: ConsecutiveList<T>,
93
- public value: T,
94
- ) {}
95
-
96
- complete() {
97
- this.isComplete = true
98
- return this.consecutive.complete()
99
- }
100
- }
101
-
102
- export class PerfectMap<K, V> extends Map<K, V> {
103
- get(key: K): V {
104
- const val = super.get(key)
105
- assert(val !== undefined, `Key not found in PerfectMap: ${key}`)
106
- return val
107
- }
108
- }
109
-
110
- // These are the message types that have a sequence number and a repo
111
- export type ProcessableMessage =
112
- | message.Commit
113
- | message.Handle
114
- | message.Identity
115
- | message.Migrate
116
- | message.Tombstone
117
-
118
- export function loggableMessage(msg: RepoMessage) {
119
- if (message.isCommit(msg)) {
120
- const { seq, rebase, prev, repo, commit, time, tooBig, blobs } = msg
121
- return {
122
- $type: msg.$type,
123
- seq,
124
- rebase,
125
- prev: prev?.toString(),
126
- repo,
127
- commit: commit.toString(),
128
- time,
129
- tooBig,
130
- hasBlobs: blobs.length > 0,
131
- }
132
- } else if (message.isHandle(msg)) {
133
- return msg
134
- } else if (message.isIdentity(msg)) {
135
- return msg
136
- } else if (message.isAccount(msg)) {
137
- return msg
138
- } else if (message.isMigrate(msg)) {
139
- return msg
140
- } else if (message.isTombstone(msg)) {
141
- return msg
142
- } else if (message.isInfo(msg)) {
143
- return msg
144
- }
145
- return msg
146
- }
147
-
148
- export function jitter(maxMs) {
149
- return Math.round((Math.random() - 0.5) * maxMs * 2)
150
- }
151
-
152
- export function strToInt(str: string) {
153
- const int = parseInt(str, 10)
154
- assert(!isNaN(int), 'string could not be parsed to an integer')
155
- return int
156
- }
@@ -1,185 +0,0 @@
1
- import { wait } from '@atproto/common'
2
- import { randomStr } from '@atproto/crypto'
3
- import {
4
- ConsecutiveList,
5
- LatestQueue,
6
- PartitionedQueue,
7
- } from '../../../src/data-plane/server/subscription/util'
8
-
9
- describe('subscription utils', () => {
10
- describe('ConsecutiveList', () => {
11
- it('tracks consecutive complete items.', () => {
12
- const consecutive = new ConsecutiveList<number>()
13
- // add items
14
- const item1 = consecutive.push(1)
15
- const item2 = consecutive.push(2)
16
- const item3 = consecutive.push(3)
17
- expect(item1.isComplete).toEqual(false)
18
- expect(item2.isComplete).toEqual(false)
19
- expect(item3.isComplete).toEqual(false)
20
- // complete items out of order
21
- expect(consecutive.list.length).toBe(3)
22
- expect(item2.complete()).toEqual([])
23
- expect(item2.isComplete).toEqual(true)
24
- expect(consecutive.list.length).toBe(3)
25
- expect(item1.complete()).toEqual([1, 2])
26
- expect(item1.isComplete).toEqual(true)
27
- expect(consecutive.list.length).toBe(1)
28
- expect(item3.complete()).toEqual([3])
29
- expect(consecutive.list.length).toBe(0)
30
- expect(item3.isComplete).toEqual(true)
31
- })
32
- })
33
-
34
- describe('LatestQueue', () => {
35
- it('only performs most recently queued item.', async () => {
36
- const latest = new LatestQueue()
37
- const complete: number[] = []
38
- latest.add(async () => {
39
- await wait(1)
40
- complete.push(1)
41
- })
42
- latest.add(async () => {
43
- await wait(1)
44
- complete.push(2)
45
- })
46
- latest.add(async () => {
47
- await wait(1)
48
- complete.push(3)
49
- })
50
- latest.add(async () => {
51
- await wait(1)
52
- complete.push(4)
53
- })
54
- await latest.queue.onIdle()
55
- expect(complete).toEqual([1, 4]) // skip 2, 3
56
- latest.add(async () => {
57
- await wait(1)
58
- complete.push(5)
59
- })
60
- latest.add(async () => {
61
- await wait(1)
62
- complete.push(6)
63
- })
64
- await latest.queue.onIdle()
65
- expect(complete).toEqual([1, 4, 5, 6])
66
- })
67
-
68
- it('stops processing queued messages on destroy.', async () => {
69
- const latest = new LatestQueue()
70
- const complete: number[] = []
71
- latest.add(async () => {
72
- await wait(1)
73
- complete.push(1)
74
- })
75
- latest.add(async () => {
76
- await wait(1)
77
- complete.push(2)
78
- })
79
- const destroyed = latest.destroy()
80
- latest.add(async () => {
81
- await wait(1)
82
- complete.push(3)
83
- })
84
- await destroyed
85
- expect(complete).toEqual([1]) // 2 was cleared, 3 was after destroy
86
- // show that waiting on destroyed above was already enough to reflect all complete items
87
- await latest.queue.onIdle()
88
- expect(complete).toEqual([1])
89
- })
90
- })
91
-
92
- describe('PartitionedQueue', () => {
93
- it('performs work in parallel across partitions, serial within a partition.', async () => {
94
- const partitioned = new PartitionedQueue({ concurrency: Infinity })
95
- const complete: number[] = []
96
- // partition 1 items start slow but get faster: slow should still complete first.
97
- partitioned.add('1', async () => {
98
- await wait(30)
99
- complete.push(11)
100
- })
101
- partitioned.add('1', async () => {
102
- await wait(20)
103
- complete.push(12)
104
- })
105
- partitioned.add('1', async () => {
106
- await wait(1)
107
- complete.push(13)
108
- })
109
- expect(partitioned.partitions.size).toEqual(1)
110
- // partition 2 items complete quickly except the last, which is slowest of all events.
111
- partitioned.add('2', async () => {
112
- await wait(1)
113
- complete.push(21)
114
- })
115
- partitioned.add('2', async () => {
116
- await wait(1)
117
- complete.push(22)
118
- })
119
- partitioned.add('2', async () => {
120
- await wait(1)
121
- complete.push(23)
122
- })
123
- partitioned.add('2', async () => {
124
- await wait(60)
125
- complete.push(24)
126
- })
127
- expect(partitioned.partitions.size).toEqual(2)
128
- await partitioned.main.onIdle()
129
- expect(complete).toEqual([21, 22, 23, 11, 12, 13, 24])
130
- expect(partitioned.partitions.size).toEqual(0)
131
- })
132
-
133
- it('limits overall concurrency.', async () => {
134
- const partitioned = new PartitionedQueue({ concurrency: 1 })
135
- const complete: number[] = []
136
- // if concurrency were not constrained, partition 1 would complete all items
137
- // before any items from partition 2. since it is constrained, the work is complete in the order added.
138
- partitioned.add('1', async () => {
139
- await wait(1)
140
- complete.push(11)
141
- })
142
- partitioned.add('2', async () => {
143
- await wait(10)
144
- complete.push(21)
145
- })
146
- partitioned.add('1', async () => {
147
- await wait(1)
148
- complete.push(12)
149
- })
150
- partitioned.add('2', async () => {
151
- await wait(10)
152
- complete.push(22)
153
- })
154
- // only partition 1 exists so far due to the concurrency
155
- expect(partitioned.partitions.size).toEqual(1)
156
- await partitioned.main.onIdle()
157
- expect(complete).toEqual([11, 21, 12, 22])
158
- expect(partitioned.partitions.size).toEqual(0)
159
- })
160
-
161
- it('settles with many items.', async () => {
162
- const partitioned = new PartitionedQueue({ concurrency: 100 })
163
- const complete: { partition: string; id: number }[] = []
164
- const partitions = new Set<string>()
165
- for (let i = 0; i < 500; ++i) {
166
- const partition = randomStr(1, 'base16').slice(0, 1)
167
- partitions.add(partition)
168
- partitioned.add(partition, async () => {
169
- await wait((i % 2) * 2)
170
- complete.push({ partition, id: i })
171
- })
172
- }
173
- expect(partitioned.partitions.size).toEqual(partitions.size)
174
- await partitioned.main.onIdle()
175
- expect(complete.length).toEqual(500)
176
- for (const partition of partitions) {
177
- const ids = complete
178
- .filter((item) => item.partition === partition)
179
- .map((item) => item.id)
180
- expect(ids).toEqual([...ids].sort((a, b) => a - b))
181
- }
182
- expect(partitioned.partitions.size).toEqual(0)
183
- })
184
- })
185
- })