@atproto/api 0.20.23 → 0.20.25

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 (57) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/package.json +22 -16
  3. package/definitions/labels.json +0 -170
  4. package/docs/moderation.md +0 -260
  5. package/jest.config.cjs +0 -23
  6. package/jest.d.ts +0 -20
  7. package/jest.setup.ts +0 -97
  8. package/scripts/code/labels.mjs +0 -77
  9. package/scripts/generate-code.mjs +0 -4
  10. package/src/age-assurance.test.ts +0 -218
  11. package/src/age-assurance.ts +0 -137
  12. package/src/agent.ts +0 -1645
  13. package/src/atp-agent.ts +0 -570
  14. package/src/bsky-agent.ts +0 -14
  15. package/src/const.ts +0 -1
  16. package/src/index.ts +0 -44
  17. package/src/mocker.ts +0 -220
  18. package/src/moderation/decision.ts +0 -389
  19. package/src/moderation/index.ts +0 -69
  20. package/src/moderation/mutewords.ts +0 -170
  21. package/src/moderation/subjects/account.ts +0 -44
  22. package/src/moderation/subjects/feed-generator.ts +0 -24
  23. package/src/moderation/subjects/notification.ts +0 -25
  24. package/src/moderation/subjects/post.ts +0 -433
  25. package/src/moderation/subjects/profile.ts +0 -26
  26. package/src/moderation/subjects/status.ts +0 -27
  27. package/src/moderation/subjects/user-list.ts +0 -48
  28. package/src/moderation/types.ts +0 -191
  29. package/src/moderation/ui.ts +0 -21
  30. package/src/moderation/util.ts +0 -111
  31. package/src/predicate.ts +0 -52
  32. package/src/rich-text/detection.ts +0 -146
  33. package/src/rich-text/rich-text.ts +0 -418
  34. package/src/rich-text/sanitization.ts +0 -42
  35. package/src/rich-text/unicode.ts +0 -47
  36. package/src/rich-text/util.ts +0 -15
  37. package/src/session-manager.ts +0 -5
  38. package/src/types.ts +0 -165
  39. package/src/util.ts +0 -96
  40. package/tests/atp-agent.test.ts +0 -3863
  41. package/tests/dispatcher.test.ts +0 -527
  42. package/tests/errors.test.ts +0 -29
  43. package/tests/moderation-behaviors.test.ts +0 -951
  44. package/tests/moderation-custom-labels.test.ts +0 -334
  45. package/tests/moderation-mutewords.test.ts +0 -1299
  46. package/tests/moderation-prefs.test.ts +0 -402
  47. package/tests/moderation-quoteposts.test.ts +0 -277
  48. package/tests/moderation.test.ts +0 -739
  49. package/tests/rich-text-detection.test.ts +0 -456
  50. package/tests/rich-text-sanitization.test.ts +0 -216
  51. package/tests/rich-text.test.ts +0 -705
  52. package/tests/util/echo-server.ts +0 -37
  53. package/tests/util/moderation-behavior.ts +0 -268
  54. package/tsconfig.build.json +0 -9
  55. package/tsconfig.build.tsbuildinfo +0 -1
  56. package/tsconfig.json +0 -7
  57. package/tsconfig.tests.json +0 -10
@@ -1,77 +0,0 @@
1
- import { mkdir, writeFile } from 'node:fs/promises'
2
- import { dirname, join } from 'node:path'
3
- import { fileURLToPath } from 'node:url'
4
- import * as prettier from 'prettier'
5
- import labelsDef from '../../definitions/labels.json' with { type: 'json' }
6
-
7
- const __dirname = dirname(fileURLToPath(import.meta.url))
8
-
9
- export async function labels() {
10
- const content = await gen()
11
-
12
- const path = join(
13
- __dirname,
14
- '..',
15
- '..',
16
- 'src',
17
- 'moderation',
18
- 'const',
19
- 'labels.ts',
20
- )
21
-
22
- await mkdir(dirname(path), { recursive: true })
23
- await writeFile(path, content, 'utf8')
24
- }
25
-
26
- async function gen() {
27
- const knownValues = new Set()
28
- const flattenedLabelDefs = []
29
-
30
- for (const { alias: aliases, ...label } of labelsDef) {
31
- knownValues.add(label.identifier)
32
- flattenedLabelDefs.push([label.identifier, { ...label, locales: [] }])
33
-
34
- if (aliases) {
35
- for (const alias of aliases) {
36
- knownValues.add(alias)
37
- flattenedLabelDefs.push([
38
- alias,
39
- {
40
- ...label,
41
- identifier: alias,
42
- locales: [],
43
- comment: `@deprecated alias for \`${label.identifier}\``,
44
- },
45
- ])
46
- }
47
- }
48
- }
49
-
50
- let labelDefsStr = `{`
51
- for (const [key, { comment, ...value }] of flattenedLabelDefs) {
52
- const commentStr = comment ? `\n/** ${comment} */\n` : ''
53
- labelDefsStr += `${commentStr}'${key}': ${JSON.stringify(value, null, 2)},`
54
- }
55
- labelDefsStr += `}`
56
-
57
- return prettier.format(
58
- `/** this doc is generated by ./scripts/code/labels.mjs **/
59
- import {InterpretedLabelValueDefinition, LabelPreference} from '../types.js'
60
-
61
- export type KnownLabelValue = ${Array.from(knownValues)
62
- .map((value) => `"${value}"`)
63
- .join(' | ')}
64
-
65
- export const DEFAULT_LABEL_SETTINGS: Record<string, LabelPreference> = ${JSON.stringify(
66
- Object.fromEntries(
67
- labelsDef
68
- .filter((label) => label.configurable)
69
- .map((label) => [label.identifier, label.defaultSetting]),
70
- ),
71
- )}
72
-
73
- export const LABELS: Record<KnownLabelValue, InterpretedLabelValueDefinition> = ${labelDefsStr}
74
- `,
75
- { semi: false, parser: 'typescript', singleQuote: true },
76
- )
77
- }
@@ -1,4 +0,0 @@
1
- import { labels } from './code/labels.mjs'
2
- export { labels }
3
-
4
- labels()
@@ -1,218 +0,0 @@
1
- import { describe, expect, it } from '@jest/globals'
2
- import {
3
- ageAssuranceRuleIDs,
4
- computeAgeAssuranceRegionAccess,
5
- getAgeAssuranceRegionConfig,
6
- } from './age-assurance.js'
7
- import { AppBskyAgeassuranceDefs } from './client/index.js'
8
-
9
- describe('age-assurance', () => {
10
- describe('getAgeAssuranceRegionConfig', () => {
11
- const config: AppBskyAgeassuranceDefs.Config = {
12
- regions: [
13
- {
14
- countryCode: 'US',
15
- regionCode: 'CA',
16
- minAccessAge: 13,
17
- rules: [],
18
- },
19
- {
20
- countryCode: 'US',
21
- minAccessAge: 13,
22
- rules: [],
23
- },
24
- ],
25
- }
26
-
27
- it('should find region by country code only', () => {
28
- const result = getAgeAssuranceRegionConfig(config, {
29
- countryCode: 'US',
30
- })
31
-
32
- expect(result).toEqual({
33
- countryCode: 'US',
34
- minAccessAge: 13,
35
- rules: [],
36
- })
37
- })
38
-
39
- it('should find region by country code and region code', () => {
40
- const result = getAgeAssuranceRegionConfig(config, {
41
- countryCode: 'US',
42
- regionCode: 'CA',
43
- })
44
-
45
- expect(result).toEqual({
46
- countryCode: 'US',
47
- regionCode: 'CA',
48
- minAccessAge: 13,
49
- rules: [],
50
- })
51
- })
52
-
53
- it('should return undefined when no matching region found', () => {
54
- const result = getAgeAssuranceRegionConfig(config, {
55
- countryCode: 'GB',
56
- })
57
-
58
- expect(result).toBeUndefined()
59
- })
60
- })
61
-
62
- describe('computeAgeAssuranceRegionAccess', () => {
63
- const region: AppBskyAgeassuranceDefs.ConfigRegion = {
64
- countryCode: 'US',
65
- minAccessAge: 13,
66
- rules: [
67
- {
68
- $type: ageAssuranceRuleIDs.IfAccountNewerThan,
69
- date: '2025-12-10T00:00:00Z',
70
- access: 'none',
71
- },
72
- {
73
- $type: ageAssuranceRuleIDs.IfAssuredOverAge,
74
- age: 18,
75
- access: 'full',
76
- },
77
- {
78
- $type: ageAssuranceRuleIDs.IfAssuredOverAge,
79
- age: 16,
80
- access: 'safe',
81
- },
82
- {
83
- $type: ageAssuranceRuleIDs.IfDeclaredOverAge,
84
- age: 16,
85
- access: 'safe',
86
- },
87
- {
88
- $type: ageAssuranceRuleIDs.Default,
89
- access: 'none',
90
- },
91
- ],
92
- }
93
-
94
- it('should apply default if no data provided', () => {
95
- const result = computeAgeAssuranceRegionAccess(region, {})
96
-
97
- expect(result).toEqual({
98
- access: 'none',
99
- reason: ageAssuranceRuleIDs.Default,
100
- })
101
- })
102
-
103
- describe('IfAccountNewerThan', () => {
104
- it('should block accounts created after threshold', () => {
105
- const result = computeAgeAssuranceRegionAccess(region, {
106
- accountCreatedAt: new Date(2025, 11, 15).toISOString(),
107
- declaredAge: 18,
108
- })
109
- expect(result).toEqual({
110
- access: 'none',
111
- reason: ageAssuranceRuleIDs.IfAccountNewerThan,
112
- })
113
- })
114
-
115
- it('should allow accounts created before threshold', () => {
116
- const result = computeAgeAssuranceRegionAccess(region, {
117
- accountCreatedAt: new Date(2025, 10, 1).toISOString(),
118
- declaredAge: 18,
119
- })
120
- expect(result).toEqual({
121
- access: 'safe',
122
- reason: ageAssuranceRuleIDs.IfDeclaredOverAge,
123
- })
124
- })
125
-
126
- it('should allow accounts created exactly at threshold', () => {
127
- const result = computeAgeAssuranceRegionAccess(region, {
128
- accountCreatedAt: new Date(2025, 11, 1).toISOString(),
129
- declaredAge: 18,
130
- })
131
- expect(result).toEqual({
132
- access: 'safe',
133
- reason: ageAssuranceRuleIDs.IfDeclaredOverAge,
134
- })
135
- })
136
-
137
- it('should not apply rule when accountCreatedAt is not provided', () => {
138
- const result = computeAgeAssuranceRegionAccess(region, {
139
- declaredAge: 15,
140
- })
141
- expect(result).toEqual({
142
- access: 'none',
143
- reason: ageAssuranceRuleIDs.Default,
144
- })
145
- })
146
-
147
- it('should not apply rule when assuredAge is present', () => {
148
- const result = computeAgeAssuranceRegionAccess(region, {
149
- accountCreatedAt: new Date(2025, 11, 15).toISOString(),
150
- assuredAge: 20,
151
- })
152
- expect(result).toEqual({
153
- access: 'full',
154
- reason: ageAssuranceRuleIDs.IfAssuredOverAge,
155
- })
156
- })
157
- })
158
-
159
- describe('IfDeclaredOverAge rule', () => {
160
- it('should allow users at or above age threshold', () => {
161
- const result = computeAgeAssuranceRegionAccess(region, {
162
- declaredAge: 18,
163
- })
164
-
165
- expect(result).toEqual({
166
- access: 'safe',
167
- reason: ageAssuranceRuleIDs.IfDeclaredOverAge,
168
- })
169
- })
170
-
171
- it('should allow users above age threshold', () => {
172
- const result = computeAgeAssuranceRegionAccess(region, {
173
- declaredAge: 25,
174
- })
175
-
176
- expect(result).toEqual({
177
- access: 'safe',
178
- reason: ageAssuranceRuleIDs.IfDeclaredOverAge,
179
- })
180
- })
181
-
182
- it('should not allow users below age threshold', () => {
183
- const result = computeAgeAssuranceRegionAccess(region, {
184
- declaredAge: 17,
185
- })
186
-
187
- expect(result).toEqual({
188
- access: 'safe',
189
- reason: ageAssuranceRuleIDs.IfDeclaredOverAge,
190
- })
191
- })
192
- })
193
-
194
- describe('IfAssuredOverAge rule', () => {
195
- it('should allow users at or above assured age threshold', () => {
196
- const result = computeAgeAssuranceRegionAccess(region, {
197
- assuredAge: 18,
198
- })
199
-
200
- expect(result).toEqual({
201
- access: 'full',
202
- reason: ageAssuranceRuleIDs.IfAssuredOverAge,
203
- })
204
- })
205
-
206
- it('should not allow users below assured age threshold', () => {
207
- const result = computeAgeAssuranceRegionAccess(region, {
208
- assuredAge: 17,
209
- })
210
-
211
- expect(result).toEqual({
212
- access: 'safe',
213
- reason: ageAssuranceRuleIDs.IfAssuredOverAge,
214
- })
215
- })
216
- })
217
- })
218
- })
@@ -1,137 +0,0 @@
1
- import { AppBskyAgeassuranceDefs } from './client/index.js'
2
- import { ids } from './client/lexicons.js'
3
-
4
- export type AgeAssuranceRuleID = Exclude<
5
- | AppBskyAgeassuranceDefs.ConfigRegionRuleDefault['$type']
6
- | AppBskyAgeassuranceDefs.ConfigRegionRuleIfDeclaredOverAge['$type']
7
- | AppBskyAgeassuranceDefs.ConfigRegionRuleIfDeclaredUnderAge['$type']
8
- | AppBskyAgeassuranceDefs.ConfigRegionRuleIfAssuredOverAge['$type']
9
- | AppBskyAgeassuranceDefs.ConfigRegionRuleIfAssuredUnderAge['$type']
10
- | AppBskyAgeassuranceDefs.ConfigRegionRuleIfAccountNewerThan['$type']
11
- | AppBskyAgeassuranceDefs.ConfigRegionRuleIfAccountOlderThan['$type'],
12
- undefined
13
- >
14
-
15
- export const ageAssuranceRuleIDs: Record<string, AgeAssuranceRuleID> = {
16
- Default: `${ids.AppBskyAgeassuranceDefs}#configRegionRuleDefault`,
17
- IfDeclaredOverAge: `${ids.AppBskyAgeassuranceDefs}#configRegionRuleIfDeclaredOverAge`,
18
- IfDeclaredUnderAge: `${ids.AppBskyAgeassuranceDefs}#configRegionRuleIfDeclaredUnderAge`,
19
- IfAssuredOverAge: `${ids.AppBskyAgeassuranceDefs}#configRegionRuleIfAssuredOverAge`,
20
- IfAssuredUnderAge: `${ids.AppBskyAgeassuranceDefs}#configRegionRuleIfAssuredUnderAge`,
21
- IfAccountNewerThan: `${ids.AppBskyAgeassuranceDefs}#configRegionRuleIfAccountNewerThan`,
22
- IfAccountOlderThan: `${ids.AppBskyAgeassuranceDefs}#configRegionRuleIfAccountOlderThan`,
23
- }
24
-
25
- /**
26
- * Returns the first matched region configuration based on the provided geolocation.
27
- */
28
- export function getAgeAssuranceRegionConfig(
29
- config: AppBskyAgeassuranceDefs.Config,
30
- geolocation: {
31
- countryCode: string
32
- regionCode?: string
33
- },
34
- ): AppBskyAgeassuranceDefs.ConfigRegion | undefined {
35
- const { regions } = config
36
- return regions.find(({ countryCode, regionCode }) => {
37
- if (countryCode === geolocation.countryCode) {
38
- return !regionCode || regionCode === geolocation.regionCode
39
- }
40
- })
41
- }
42
-
43
- export function computeAgeAssuranceRegionAccess(
44
- region: AppBskyAgeassuranceDefs.ConfigRegion,
45
- data:
46
- | {
47
- /**
48
- * The account creation date in ISO 8601 format. Only checked if we
49
- * don't have an assured age, such as on the client.
50
- */
51
- accountCreatedAt?: string
52
- /**
53
- * The user's declared age
54
- */
55
- declaredAge?: number
56
- /**
57
- * The user's minimum age as assured by a trusted third party.
58
- */
59
- assuredAge?: number
60
- }
61
- | undefined,
62
- ):
63
- | {
64
- access: AppBskyAgeassuranceDefs.Access
65
- reason: AgeAssuranceRuleID
66
- }
67
- | undefined {
68
- // first match wins
69
- for (const rule of region.rules) {
70
- if (AppBskyAgeassuranceDefs.isConfigRegionRuleIfAccountNewerThan(rule)) {
71
- if (data?.accountCreatedAt && !data?.assuredAge) {
72
- const accountCreatedAt = new Date(data.accountCreatedAt)
73
- const threshold = new Date(rule.date)
74
- if (accountCreatedAt >= threshold) {
75
- return {
76
- access: rule.access,
77
- reason: rule.$type,
78
- }
79
- }
80
- }
81
- } else if (
82
- AppBskyAgeassuranceDefs.isConfigRegionRuleIfAccountOlderThan(rule)
83
- ) {
84
- if (data?.accountCreatedAt && !data?.assuredAge) {
85
- const accountCreatedAt = new Date(data.accountCreatedAt)
86
- const threshold = new Date(rule.date)
87
- if (accountCreatedAt < threshold) {
88
- return {
89
- access: rule.access,
90
- reason: rule.$type,
91
- }
92
- }
93
- }
94
- } else if (
95
- AppBskyAgeassuranceDefs.isConfigRegionRuleIfDeclaredOverAge(rule)
96
- ) {
97
- if (data?.declaredAge !== undefined && data.declaredAge >= rule.age) {
98
- return {
99
- access: rule.access,
100
- reason: rule.$type,
101
- }
102
- }
103
- } else if (
104
- AppBskyAgeassuranceDefs.isConfigRegionRuleIfDeclaredUnderAge(rule)
105
- ) {
106
- if (data?.declaredAge !== undefined && data.declaredAge < rule.age) {
107
- return {
108
- access: rule.access,
109
- reason: rule.$type,
110
- }
111
- }
112
- } else if (
113
- AppBskyAgeassuranceDefs.isConfigRegionRuleIfAssuredOverAge(rule)
114
- ) {
115
- if (data?.assuredAge && data.assuredAge >= rule.age) {
116
- return {
117
- access: rule.access,
118
- reason: rule.$type,
119
- }
120
- }
121
- } else if (
122
- AppBskyAgeassuranceDefs.isConfigRegionRuleIfAssuredUnderAge(rule)
123
- ) {
124
- if (data?.assuredAge && data.assuredAge < rule.age) {
125
- return {
126
- access: rule.access,
127
- reason: rule.$type,
128
- }
129
- }
130
- } else if (AppBskyAgeassuranceDefs.isConfigRegionRuleDefault(rule)) {
131
- return {
132
- access: rule.access,
133
- reason: rule.$type,
134
- }
135
- }
136
- }
137
- }