@atproto/bsky 0.0.156 → 0.0.157
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.
- package/CHANGELOG.md +9 -0
- package/dist/api/app/bsky/notification/getPreferences.d.ts +4 -0
- package/dist/api/app/bsky/notification/getPreferences.d.ts.map +1 -0
- package/dist/api/app/bsky/notification/getPreferences.js +39 -0
- package/dist/api/app/bsky/notification/getPreferences.js.map +1 -0
- package/dist/api/app/bsky/notification/putPreferencesV2.d.ts +4 -0
- package/dist/api/app/bsky/notification/putPreferencesV2.d.ts.map +1 -0
- package/dist/api/app/bsky/notification/putPreferencesV2.js +47 -0
- package/dist/api/app/bsky/notification/putPreferencesV2.js.map +1 -0
- package/dist/api/app/bsky/notification/util.d.ts +9 -0
- package/dist/api/app/bsky/notification/util.d.ts.map +1 -0
- package/dist/api/app/bsky/notification/util.js +84 -0
- package/dist/api/app/bsky/notification/util.js.map +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +4 -0
- package/dist/api/index.js.map +1 -1
- package/dist/context.d.ts +3 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +3 -0
- package/dist/context.js.map +1 -1
- package/dist/data-plane/bsync/index.d.ts.map +1 -1
- package/dist/data-plane/bsync/index.js +84 -0
- package/dist/data-plane/bsync/index.js.map +1 -1
- package/dist/data-plane/server/db/database-schema.d.ts +2 -1
- package/dist/data-plane/server/db/database-schema.d.ts.map +1 -1
- package/dist/data-plane/server/db/migrations/20250602T190357447Z-add-private-data.d.ts +4 -0
- package/dist/data-plane/server/db/migrations/20250602T190357447Z-add-private-data.d.ts.map +1 -0
- package/dist/data-plane/server/db/migrations/20250602T190357447Z-add-private-data.js +24 -0
- package/dist/data-plane/server/db/migrations/20250602T190357447Z-add-private-data.js.map +1 -0
- package/dist/data-plane/server/db/migrations/index.d.ts +1 -0
- package/dist/data-plane/server/db/migrations/index.d.ts.map +1 -1
- package/dist/data-plane/server/db/migrations/index.js +2 -1
- package/dist/data-plane/server/db/migrations/index.js.map +1 -1
- package/dist/data-plane/server/db/tables/private-data.d.ts +13 -0
- package/dist/data-plane/server/db/tables/private-data.d.ts.map +1 -0
- package/dist/data-plane/server/db/tables/private-data.js +5 -0
- package/dist/data-plane/server/db/tables/private-data.js.map +1 -0
- package/dist/data-plane/server/routes/index.d.ts.map +1 -1
- package/dist/data-plane/server/routes/index.js +2 -0
- package/dist/data-plane/server/routes/index.js.map +1 -1
- package/dist/data-plane/server/routes/private-data.d.ts +9 -0
- package/dist/data-plane/server/routes/private-data.d.ts.map +1 -0
- package/dist/data-plane/server/routes/private-data.js +63 -0
- package/dist/data-plane/server/routes/private-data.js.map +1 -0
- package/dist/data-plane/server/util.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lexicon/index.d.ts +4 -0
- package/dist/lexicon/index.d.ts.map +1 -1
- package/dist/lexicon/index.js +8 -0
- package/dist/lexicon/index.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +418 -0
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +225 -0
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/app/bsky/notification/defs.d.ts +40 -0
- package/dist/lexicon/types/app/bsky/notification/defs.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/notification/defs.js +36 -0
- package/dist/lexicon/types/app/bsky/notification/defs.js.map +1 -1
- package/dist/lexicon/types/app/bsky/notification/getPreferences.d.ts +35 -0
- package/dist/lexicon/types/app/bsky/notification/getPreferences.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/notification/getPreferences.js +7 -0
- package/dist/lexicon/types/app/bsky/notification/getPreferences.js.map +1 -0
- package/dist/lexicon/types/app/bsky/notification/putPreferencesV2.d.ts +52 -0
- package/dist/lexicon/types/app/bsky/notification/putPreferencesV2.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/notification/putPreferencesV2.js +7 -0
- package/dist/lexicon/types/app/bsky/notification/putPreferencesV2.js.map +1 -0
- package/dist/proto/bsky_connect.d.ts +10 -1
- package/dist/proto/bsky_connect.d.ts.map +1 -1
- package/dist/proto/bsky_connect.js +9 -0
- package/dist/proto/bsky_connect.js.map +1 -1
- package/dist/proto/bsky_pb.d.ts +234 -0
- package/dist/proto/bsky_pb.d.ts.map +1 -1
- package/dist/proto/bsky_pb.js +693 -5
- package/dist/proto/bsky_pb.js.map +1 -1
- package/dist/proto/bsync_pb.d.ts +10 -10
- package/dist/proto/bsync_pb.d.ts.map +1 -1
- package/dist/proto/bsync_pb.js +15 -15
- package/dist/proto/bsync_pb.js.map +1 -1
- package/dist/stash.d.ts +26 -0
- package/dist/stash.d.ts.map +1 -0
- package/dist/stash.js +56 -0
- package/dist/stash.js.map +1 -0
- package/package.json +6 -6
- package/proto/bsky.proto +61 -0
- package/src/api/app/bsky/notification/getPreferences.ts +50 -0
- package/src/api/app/bsky/notification/putPreferencesV2.ts +62 -0
- package/src/api/app/bsky/notification/util.ts +123 -0
- package/src/api/index.ts +4 -0
- package/src/context.ts +6 -0
- package/src/data-plane/bsync/index.ts +109 -1
- package/src/data-plane/server/db/database-schema.ts +3 -1
- package/src/data-plane/server/db/migrations/20250602T190357447Z-add-private-data.ts +22 -0
- package/src/data-plane/server/db/migrations/index.ts +1 -0
- package/src/data-plane/server/db/tables/private-data.ts +13 -0
- package/src/data-plane/server/routes/index.ts +2 -0
- package/src/data-plane/server/routes/private-data.ts +90 -0
- package/src/index.ts +4 -0
- package/src/lexicon/index.ts +24 -0
- package/src/lexicon/lexicons.ts +227 -0
- package/src/lexicon/types/app/bsky/notification/defs.ts +76 -0
- package/src/lexicon/types/app/bsky/notification/getPreferences.ts +52 -0
- package/src/lexicon/types/app/bsky/notification/putPreferencesV2.ts +69 -0
- package/src/proto/bsky_connect.ts +11 -0
- package/src/proto/bsky_pb.ts +669 -0
- package/src/proto/bsync_pb.ts +15 -15
- package/src/stash.ts +75 -0
- package/tests/stash.test.ts +156 -0
- package/tests/views/notifications.test.ts +221 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.tests.tsbuildinfo +1 -1
package/src/proto/bsync_pb.ts
CHANGED
|
@@ -736,14 +736,14 @@ export class Operation extends Message<Operation> {
|
|
|
736
736
|
actorDid = ''
|
|
737
737
|
|
|
738
738
|
/**
|
|
739
|
-
* @generated from field: string
|
|
739
|
+
* @generated from field: string namespace = 3;
|
|
740
740
|
*/
|
|
741
|
-
|
|
741
|
+
namespace = ''
|
|
742
742
|
|
|
743
743
|
/**
|
|
744
|
-
* @generated from field: string
|
|
744
|
+
* @generated from field: string key = 4;
|
|
745
745
|
*/
|
|
746
|
-
|
|
746
|
+
key = ''
|
|
747
747
|
|
|
748
748
|
/**
|
|
749
749
|
* @generated from field: bsync.Method method = 5;
|
|
@@ -765,8 +765,8 @@ export class Operation extends Message<Operation> {
|
|
|
765
765
|
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
|
766
766
|
{ no: 1, name: 'id', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
|
767
767
|
{ no: 2, name: 'actor_did', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
|
768
|
-
{ no: 3, name: '
|
|
769
|
-
{ no: 4, name: '
|
|
768
|
+
{ no: 3, name: 'namespace', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
|
769
|
+
{ no: 4, name: 'key', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
|
770
770
|
{ no: 5, name: 'method', kind: 'enum', T: proto3.getEnumType(Method) },
|
|
771
771
|
{ no: 6, name: 'payload', kind: 'scalar', T: 12 /* ScalarType.BYTES */ },
|
|
772
772
|
])
|
|
@@ -805,19 +805,19 @@ export class Operation extends Message<Operation> {
|
|
|
805
805
|
*/
|
|
806
806
|
export class PutOperationRequest extends Message<PutOperationRequest> {
|
|
807
807
|
/**
|
|
808
|
-
* @generated from field: string
|
|
808
|
+
* @generated from field: string actor_did = 1;
|
|
809
809
|
*/
|
|
810
|
-
|
|
810
|
+
actorDid = ''
|
|
811
811
|
|
|
812
812
|
/**
|
|
813
|
-
* @generated from field: string
|
|
813
|
+
* @generated from field: string namespace = 2;
|
|
814
814
|
*/
|
|
815
|
-
|
|
815
|
+
namespace = ''
|
|
816
816
|
|
|
817
817
|
/**
|
|
818
|
-
* @generated from field: string
|
|
818
|
+
* @generated from field: string key = 3;
|
|
819
819
|
*/
|
|
820
|
-
|
|
820
|
+
key = ''
|
|
821
821
|
|
|
822
822
|
/**
|
|
823
823
|
* @generated from field: bsync.Method method = 4;
|
|
@@ -837,9 +837,9 @@ export class PutOperationRequest extends Message<PutOperationRequest> {
|
|
|
837
837
|
static readonly runtime: typeof proto3 = proto3
|
|
838
838
|
static readonly typeName = 'bsync.PutOperationRequest'
|
|
839
839
|
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
|
840
|
-
{ no: 1, name: '
|
|
841
|
-
{ no: 2, name: '
|
|
842
|
-
{ no: 3, name: '
|
|
840
|
+
{ no: 1, name: 'actor_did', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
|
841
|
+
{ no: 2, name: 'namespace', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
|
842
|
+
{ no: 3, name: 'key', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
|
843
843
|
{ no: 4, name: 'method', kind: 'enum', T: proto3.getEnumType(Method) },
|
|
844
844
|
{ no: 5, name: 'payload', kind: 'scalar', T: 12 /* ScalarType.BYTES */ },
|
|
845
845
|
])
|
package/src/stash.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { LexValue, stringifyLex } from '@atproto/lexicon'
|
|
2
|
+
import { BsyncClient } from './bsync'
|
|
3
|
+
import { lexicons } from './lexicon/lexicons'
|
|
4
|
+
import { Method } from './proto/bsync_pb'
|
|
5
|
+
|
|
6
|
+
export const createStashClient = (bsyncClient: BsyncClient): StashClient => {
|
|
7
|
+
return new StashClient(bsyncClient)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// An abstraction over the BsyncClient, that uses the bsync `PutOperation` RPC
|
|
11
|
+
// to store private data, which can be indexed by the dataplane and queried by the appview.
|
|
12
|
+
export class StashClient {
|
|
13
|
+
constructor(private readonly bsyncClient: BsyncClient) {}
|
|
14
|
+
|
|
15
|
+
create(input: CreateInput) {
|
|
16
|
+
this.validateLexicon(input.namespace, input.payload)
|
|
17
|
+
return this.putOperation(Method.CREATE, input)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
update(input: UpdateInput) {
|
|
21
|
+
this.validateLexicon(input.namespace, input.payload)
|
|
22
|
+
return this.putOperation(Method.UPDATE, input)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
delete(input: DeleteInput) {
|
|
26
|
+
return this.putOperation(Method.DELETE, { ...input, payload: undefined })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private validateLexicon(namespace: string, payload: LexValue) {
|
|
30
|
+
const result = lexicons.validate(namespace, payload)
|
|
31
|
+
if (!result.success) {
|
|
32
|
+
throw result.error
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private async putOperation(method: Method, input: PutOperationInput) {
|
|
37
|
+
const { actorDid, namespace, key, payload } = input
|
|
38
|
+
await this.bsyncClient.putOperation({
|
|
39
|
+
actorDid,
|
|
40
|
+
namespace,
|
|
41
|
+
key,
|
|
42
|
+
method,
|
|
43
|
+
payload: payload
|
|
44
|
+
? Buffer.from(
|
|
45
|
+
stringifyLex({
|
|
46
|
+
$type: namespace,
|
|
47
|
+
...payload,
|
|
48
|
+
}),
|
|
49
|
+
)
|
|
50
|
+
: undefined,
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type PutOperationInput = {
|
|
56
|
+
actorDid: string
|
|
57
|
+
namespace: string
|
|
58
|
+
key: string
|
|
59
|
+
payload: LexValue | undefined
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type CreateInput = {
|
|
63
|
+
actorDid: string
|
|
64
|
+
namespace: string
|
|
65
|
+
key: string
|
|
66
|
+
payload: LexValue
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
type UpdateInput = CreateInput
|
|
70
|
+
|
|
71
|
+
type DeleteInput = {
|
|
72
|
+
actorDid: string
|
|
73
|
+
namespace: string
|
|
74
|
+
key: string
|
|
75
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { TestNetwork } from '@atproto/dev-env'
|
|
2
|
+
import { ProfileAssociatedChat } from '../dist/lexicon/types/app/bsky/actor/defs'
|
|
3
|
+
import { StashClient } from '../dist/stash'
|
|
4
|
+
|
|
5
|
+
type Database = TestNetwork['bsky']['db']
|
|
6
|
+
|
|
7
|
+
describe('private data', () => {
|
|
8
|
+
let network: TestNetwork
|
|
9
|
+
let stashClient: StashClient
|
|
10
|
+
let db: Database
|
|
11
|
+
|
|
12
|
+
const actorDid = 'did:plc:example'
|
|
13
|
+
// This lexicon has nothing special other than being simple, convenient to use in a test.
|
|
14
|
+
const namespace = 'app.bsky.actor.defs#profileAssociatedChat'
|
|
15
|
+
const key = 'self'
|
|
16
|
+
|
|
17
|
+
const validPayload0: ProfileAssociatedChat = { allowIncoming: 'all' }
|
|
18
|
+
const validPayload1: ProfileAssociatedChat = { allowIncoming: 'following' }
|
|
19
|
+
const invalidPayload: ProfileAssociatedChat = {
|
|
20
|
+
invalid: 'all',
|
|
21
|
+
} as unknown as ProfileAssociatedChat
|
|
22
|
+
|
|
23
|
+
beforeAll(async () => {
|
|
24
|
+
network = await TestNetwork.create({
|
|
25
|
+
dbPostgresSchema: 'bsky_private_data',
|
|
26
|
+
})
|
|
27
|
+
db = network.bsky.db
|
|
28
|
+
stashClient = network.bsky.ctx.stashClient
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
afterEach(async () => {
|
|
32
|
+
await clearPrivateData(db)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
afterAll(async () => {
|
|
36
|
+
await network.close()
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
describe('create', () => {
|
|
40
|
+
it('creates entry', async () => {
|
|
41
|
+
await stashClient.create({
|
|
42
|
+
actorDid,
|
|
43
|
+
namespace,
|
|
44
|
+
key,
|
|
45
|
+
payload: validPayload0,
|
|
46
|
+
})
|
|
47
|
+
await network.processAll()
|
|
48
|
+
|
|
49
|
+
const dbResult = await db.db
|
|
50
|
+
.selectFrom('private_data')
|
|
51
|
+
.selectAll()
|
|
52
|
+
.where('actorDid', '=', actorDid)
|
|
53
|
+
.where('namespace', '=', namespace)
|
|
54
|
+
.where('key', '=', key)
|
|
55
|
+
.executeTakeFirstOrThrow()
|
|
56
|
+
expect(dbResult).toStrictEqual({
|
|
57
|
+
actorDid,
|
|
58
|
+
namespace,
|
|
59
|
+
key,
|
|
60
|
+
payload: JSON.stringify({ $type: namespace, ...validPayload0 }),
|
|
61
|
+
indexedAt: expect.any(String),
|
|
62
|
+
updatedAt: expect.any(String),
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('validates lexicon', async () => {
|
|
67
|
+
expect(() =>
|
|
68
|
+
stashClient.create({
|
|
69
|
+
actorDid,
|
|
70
|
+
namespace,
|
|
71
|
+
key,
|
|
72
|
+
payload: invalidPayload,
|
|
73
|
+
}),
|
|
74
|
+
).toThrow('Object must have the property "allowIncoming"')
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
describe('update', () => {
|
|
79
|
+
it('updates entry', async () => {
|
|
80
|
+
await stashClient.create({
|
|
81
|
+
actorDid,
|
|
82
|
+
namespace,
|
|
83
|
+
key,
|
|
84
|
+
payload: validPayload0,
|
|
85
|
+
})
|
|
86
|
+
await network.processAll()
|
|
87
|
+
|
|
88
|
+
await stashClient.update({
|
|
89
|
+
actorDid,
|
|
90
|
+
namespace,
|
|
91
|
+
key,
|
|
92
|
+
payload: validPayload1,
|
|
93
|
+
})
|
|
94
|
+
await network.processAll()
|
|
95
|
+
|
|
96
|
+
const dbResult = await db.db
|
|
97
|
+
.selectFrom('private_data')
|
|
98
|
+
.selectAll()
|
|
99
|
+
.where('actorDid', '=', actorDid)
|
|
100
|
+
.where('namespace', '=', namespace)
|
|
101
|
+
.where('key', '=', key)
|
|
102
|
+
.executeTakeFirstOrThrow()
|
|
103
|
+
expect(dbResult).toStrictEqual({
|
|
104
|
+
actorDid,
|
|
105
|
+
namespace,
|
|
106
|
+
key,
|
|
107
|
+
payload: JSON.stringify({ $type: namespace, ...validPayload1 }),
|
|
108
|
+
indexedAt: expect.any(String),
|
|
109
|
+
updatedAt: expect.any(String),
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it('validates lexicon', async () => {
|
|
114
|
+
expect(() =>
|
|
115
|
+
stashClient.update({
|
|
116
|
+
actorDid,
|
|
117
|
+
namespace,
|
|
118
|
+
key,
|
|
119
|
+
payload: invalidPayload,
|
|
120
|
+
}),
|
|
121
|
+
).toThrow('Object must have the property "allowIncoming"')
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
describe('delete', () => {
|
|
126
|
+
it('deletes entry', async () => {
|
|
127
|
+
await stashClient.create({
|
|
128
|
+
actorDid,
|
|
129
|
+
namespace,
|
|
130
|
+
key,
|
|
131
|
+
payload: validPayload0,
|
|
132
|
+
})
|
|
133
|
+
await network.processAll()
|
|
134
|
+
|
|
135
|
+
await stashClient.delete({
|
|
136
|
+
actorDid,
|
|
137
|
+
namespace,
|
|
138
|
+
key,
|
|
139
|
+
})
|
|
140
|
+
await network.processAll()
|
|
141
|
+
|
|
142
|
+
const dbResult = await db.db
|
|
143
|
+
.selectFrom('private_data')
|
|
144
|
+
.selectAll()
|
|
145
|
+
.where('actorDid', '=', actorDid)
|
|
146
|
+
.where('namespace', '=', namespace)
|
|
147
|
+
.where('key', '=', key)
|
|
148
|
+
.executeTakeFirst()
|
|
149
|
+
expect(dbResult).toBe(undefined)
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const clearPrivateData = async (db: Database) => {
|
|
155
|
+
await db.db.deleteFrom('private_data').execute()
|
|
156
|
+
}
|
|
@@ -2,11 +2,22 @@ import { AtpAgent } from '@atproto/api'
|
|
|
2
2
|
import { SeedClient, TestNetwork, basicSeed } from '@atproto/dev-env'
|
|
3
3
|
import { delayCursor } from '../../src/api/app/bsky/notification/listNotifications'
|
|
4
4
|
import { ids } from '../../src/lexicon/lexicons'
|
|
5
|
+
import {
|
|
6
|
+
ChatPreference,
|
|
7
|
+
FilterablePreference,
|
|
8
|
+
Preference,
|
|
9
|
+
Preferences,
|
|
10
|
+
} from '../../src/lexicon/types/app/bsky/notification/defs'
|
|
5
11
|
import { Notification } from '../../src/lexicon/types/app/bsky/notification/listNotifications'
|
|
12
|
+
import { InputSchema } from '../../src/lexicon/types/app/bsky/notification/putPreferencesV2'
|
|
6
13
|
import { forSnapshot, paginateAll } from '../_util'
|
|
7
14
|
|
|
15
|
+
type Database = TestNetwork['bsky']['db']
|
|
16
|
+
|
|
8
17
|
describe('notification views', () => {
|
|
9
18
|
let network: TestNetwork
|
|
19
|
+
let db: Database
|
|
20
|
+
|
|
10
21
|
let agent: AtpAgent
|
|
11
22
|
let sc: SeedClient
|
|
12
23
|
|
|
@@ -19,6 +30,7 @@ describe('notification views', () => {
|
|
|
19
30
|
network = await TestNetwork.create({
|
|
20
31
|
dbPostgresSchema: 'bsky_views_notifications',
|
|
21
32
|
})
|
|
33
|
+
db = network.bsky.db
|
|
22
34
|
agent = network.bsky.getClient()
|
|
23
35
|
sc = network.getSeedClient()
|
|
24
36
|
await basicSeed(sc)
|
|
@@ -905,4 +917,213 @@ describe('notification views', () => {
|
|
|
905
917
|
})
|
|
906
918
|
})
|
|
907
919
|
})
|
|
920
|
+
|
|
921
|
+
describe('preferences v2', () => {
|
|
922
|
+
beforeEach(async () => {
|
|
923
|
+
await clearPrivateData(db)
|
|
924
|
+
})
|
|
925
|
+
|
|
926
|
+
// Defaults
|
|
927
|
+
const fp: FilterablePreference = {
|
|
928
|
+
filter: 'all',
|
|
929
|
+
list: true,
|
|
930
|
+
push: true,
|
|
931
|
+
}
|
|
932
|
+
const p: Preference = {
|
|
933
|
+
list: true,
|
|
934
|
+
push: true,
|
|
935
|
+
}
|
|
936
|
+
const cp: ChatPreference = {
|
|
937
|
+
filter: 'all',
|
|
938
|
+
push: true,
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
it('gets preferences filling up with the defaults', async () => {
|
|
942
|
+
const actorDid = sc.dids.carol
|
|
943
|
+
|
|
944
|
+
const getAndAssert = async (
|
|
945
|
+
expectedApi: Preferences,
|
|
946
|
+
expectedDb: Preferences | undefined,
|
|
947
|
+
) => {
|
|
948
|
+
const { data } = await agent.app.bsky.notification.getPreferences(
|
|
949
|
+
{},
|
|
950
|
+
{
|
|
951
|
+
headers: await network.serviceHeaders(
|
|
952
|
+
actorDid,
|
|
953
|
+
ids.AppBskyNotificationGetPreferences,
|
|
954
|
+
),
|
|
955
|
+
},
|
|
956
|
+
)
|
|
957
|
+
expect(data.preferences).toStrictEqual(expectedApi)
|
|
958
|
+
|
|
959
|
+
const dbResult = await db.db
|
|
960
|
+
.selectFrom('private_data')
|
|
961
|
+
.selectAll()
|
|
962
|
+
.where('actorDid', '=', actorDid)
|
|
963
|
+
.where('namespace', '=', 'app.bsky.notification.defs#preferences')
|
|
964
|
+
.where('key', '=', 'self')
|
|
965
|
+
.executeTakeFirst()
|
|
966
|
+
if (dbResult === undefined) {
|
|
967
|
+
expect(dbResult).toBe(expectedDb)
|
|
968
|
+
} else {
|
|
969
|
+
expect(dbResult).toStrictEqual({
|
|
970
|
+
actorDid: actorDid,
|
|
971
|
+
namespace: 'app.bsky.notification.defs#preferences',
|
|
972
|
+
key: 'self',
|
|
973
|
+
indexedAt: expect.any(String),
|
|
974
|
+
payload: expect.anything(), // Better to compare payload parsed.
|
|
975
|
+
updatedAt: expect.any(String),
|
|
976
|
+
})
|
|
977
|
+
expect(JSON.parse(dbResult.payload)).toStrictEqual({
|
|
978
|
+
$type: 'app.bsky.notification.defs#preferences',
|
|
979
|
+
...expectedDb,
|
|
980
|
+
})
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
const expectedApi0: Preferences = {
|
|
985
|
+
chat: cp,
|
|
986
|
+
follow: fp,
|
|
987
|
+
like: fp,
|
|
988
|
+
likeViaRepost: fp,
|
|
989
|
+
mention: fp,
|
|
990
|
+
quote: fp,
|
|
991
|
+
reply: fp,
|
|
992
|
+
repost: fp,
|
|
993
|
+
repostViaRepost: fp,
|
|
994
|
+
starterpackJoined: p,
|
|
995
|
+
subscribedPost: p,
|
|
996
|
+
unverified: p,
|
|
997
|
+
verified: p,
|
|
998
|
+
}
|
|
999
|
+
// The user has no preferences set yet, so nothing stored.
|
|
1000
|
+
const expectedDb0 = undefined
|
|
1001
|
+
await getAndAssert(expectedApi0, expectedDb0)
|
|
1002
|
+
|
|
1003
|
+
await agent.app.bsky.notification.putPreferencesV2(
|
|
1004
|
+
{ verified: { list: false, push: false } },
|
|
1005
|
+
{
|
|
1006
|
+
encoding: 'application/json',
|
|
1007
|
+
headers: await network.serviceHeaders(
|
|
1008
|
+
actorDid,
|
|
1009
|
+
ids.AppBskyNotificationPutPreferencesV2,
|
|
1010
|
+
),
|
|
1011
|
+
},
|
|
1012
|
+
)
|
|
1013
|
+
await network.processAll()
|
|
1014
|
+
|
|
1015
|
+
const expectedApi1: Preferences = {
|
|
1016
|
+
chat: cp,
|
|
1017
|
+
follow: fp,
|
|
1018
|
+
like: fp,
|
|
1019
|
+
likeViaRepost: fp,
|
|
1020
|
+
mention: fp,
|
|
1021
|
+
quote: fp,
|
|
1022
|
+
reply: fp,
|
|
1023
|
+
repost: fp,
|
|
1024
|
+
repostViaRepost: fp,
|
|
1025
|
+
starterpackJoined: p,
|
|
1026
|
+
subscribedPost: p,
|
|
1027
|
+
unverified: p,
|
|
1028
|
+
verified: { list: false, push: false },
|
|
1029
|
+
}
|
|
1030
|
+
// Stored all the defaults.
|
|
1031
|
+
const expectedDb1 = expectedApi1
|
|
1032
|
+
await getAndAssert(expectedApi1, expectedDb1)
|
|
1033
|
+
})
|
|
1034
|
+
|
|
1035
|
+
it('stores the preferences setting the defaults', async () => {
|
|
1036
|
+
const actorDid = sc.dids.carol
|
|
1037
|
+
|
|
1038
|
+
const putAndAssert = async (
|
|
1039
|
+
input: InputSchema,
|
|
1040
|
+
expected: Preferences,
|
|
1041
|
+
) => {
|
|
1042
|
+
const { data } = await agent.app.bsky.notification.putPreferencesV2(
|
|
1043
|
+
input,
|
|
1044
|
+
{
|
|
1045
|
+
encoding: 'application/json',
|
|
1046
|
+
headers: await network.serviceHeaders(
|
|
1047
|
+
actorDid,
|
|
1048
|
+
ids.AppBskyNotificationPutPreferencesV2,
|
|
1049
|
+
),
|
|
1050
|
+
},
|
|
1051
|
+
)
|
|
1052
|
+
await network.processAll()
|
|
1053
|
+
expect(data.preferences).toStrictEqual(expected)
|
|
1054
|
+
|
|
1055
|
+
const dbResult = await db.db
|
|
1056
|
+
.selectFrom('private_data')
|
|
1057
|
+
.selectAll()
|
|
1058
|
+
.where('actorDid', '=', actorDid)
|
|
1059
|
+
.where('namespace', '=', 'app.bsky.notification.defs#preferences')
|
|
1060
|
+
.where('key', '=', 'self')
|
|
1061
|
+
.executeTakeFirstOrThrow()
|
|
1062
|
+
expect(dbResult).toStrictEqual({
|
|
1063
|
+
actorDid: actorDid,
|
|
1064
|
+
namespace: 'app.bsky.notification.defs#preferences',
|
|
1065
|
+
key: 'self',
|
|
1066
|
+
indexedAt: expect.any(String),
|
|
1067
|
+
payload: expect.anything(), // Better to compare payload parsed.
|
|
1068
|
+
updatedAt: expect.any(String),
|
|
1069
|
+
})
|
|
1070
|
+
expect(JSON.parse(dbResult.payload)).toStrictEqual({
|
|
1071
|
+
$type: 'app.bsky.notification.defs#preferences',
|
|
1072
|
+
...expected,
|
|
1073
|
+
})
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
const input0 = {
|
|
1077
|
+
chat: {
|
|
1078
|
+
push: false,
|
|
1079
|
+
filter: 'accepted',
|
|
1080
|
+
},
|
|
1081
|
+
}
|
|
1082
|
+
const expected0: Preferences = {
|
|
1083
|
+
chat: input0.chat,
|
|
1084
|
+
follow: fp,
|
|
1085
|
+
like: fp,
|
|
1086
|
+
likeViaRepost: fp,
|
|
1087
|
+
mention: fp,
|
|
1088
|
+
quote: fp,
|
|
1089
|
+
reply: fp,
|
|
1090
|
+
repost: fp,
|
|
1091
|
+
repostViaRepost: fp,
|
|
1092
|
+
starterpackJoined: p,
|
|
1093
|
+
subscribedPost: p,
|
|
1094
|
+
unverified: p,
|
|
1095
|
+
verified: p,
|
|
1096
|
+
}
|
|
1097
|
+
await putAndAssert(input0, expected0)
|
|
1098
|
+
|
|
1099
|
+
const input1 = {
|
|
1100
|
+
mention: {
|
|
1101
|
+
list: false,
|
|
1102
|
+
push: false,
|
|
1103
|
+
filter: 'follows',
|
|
1104
|
+
},
|
|
1105
|
+
}
|
|
1106
|
+
const expected1: Preferences = {
|
|
1107
|
+
// Kept from the previous call.
|
|
1108
|
+
chat: input0.chat,
|
|
1109
|
+
follow: fp,
|
|
1110
|
+
like: fp,
|
|
1111
|
+
likeViaRepost: fp,
|
|
1112
|
+
mention: input1.mention,
|
|
1113
|
+
quote: fp,
|
|
1114
|
+
reply: fp,
|
|
1115
|
+
repost: fp,
|
|
1116
|
+
repostViaRepost: fp,
|
|
1117
|
+
starterpackJoined: p,
|
|
1118
|
+
subscribedPost: p,
|
|
1119
|
+
unverified: p,
|
|
1120
|
+
verified: p,
|
|
1121
|
+
}
|
|
1122
|
+
await putAndAssert(input1, expected1)
|
|
1123
|
+
})
|
|
1124
|
+
})
|
|
908
1125
|
})
|
|
1126
|
+
|
|
1127
|
+
const clearPrivateData = async (db: Database) => {
|
|
1128
|
+
await db.db.deleteFrom('private_data').execute()
|
|
1129
|
+
}
|