@atproto/lex-client 0.1.5 → 0.2.1
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 +25 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js.map +1 -1
- package/dist/client.d.ts +42 -21
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +97 -16
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +6 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -3
- package/dist/errors.js.map +1 -1
- package/dist/response.d.ts +3 -2
- package/dist/response.d.ts.map +1 -1
- package/dist/response.js +2 -1
- package/dist/response.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +6 -2
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +25 -0
- package/dist/util.js.map +1 -1
- package/dist/write-operation-builder.d.ts +3 -2
- package/dist/write-operation-builder.d.ts.map +1 -1
- package/dist/write-operation-builder.js +2 -2
- package/dist/write-operation-builder.js.map +1 -1
- package/dist/xrpc.d.ts +8 -6
- package/dist/xrpc.d.ts.map +1 -1
- package/dist/xrpc.js +1 -1
- package/dist/xrpc.js.map +1 -1
- package/package.json +11 -14
- package/src/agent.test.ts +0 -216
- package/src/agent.ts +0 -186
- package/src/client.ts +0 -1086
- package/src/errors.test.ts +0 -626
- package/src/errors.ts +0 -570
- package/src/index.ts +0 -6
- package/src/lexicons/com/atproto/repo/applyWrites.defs.ts +0 -201
- package/src/lexicons/com/atproto/repo/applyWrites.ts +0 -6
- package/src/lexicons/com/atproto/repo/createRecord.defs.ts +0 -58
- package/src/lexicons/com/atproto/repo/createRecord.ts +0 -6
- package/src/lexicons/com/atproto/repo/defs.defs.ts +0 -28
- package/src/lexicons/com/atproto/repo/defs.ts +0 -5
- package/src/lexicons/com/atproto/repo/deleteRecord.defs.ts +0 -52
- package/src/lexicons/com/atproto/repo/deleteRecord.ts +0 -6
- package/src/lexicons/com/atproto/repo/getRecord.defs.ts +0 -37
- package/src/lexicons/com/atproto/repo/getRecord.ts +0 -6
- package/src/lexicons/com/atproto/repo/listRecords.defs.ts +0 -65
- package/src/lexicons/com/atproto/repo/listRecords.ts +0 -6
- package/src/lexicons/com/atproto/repo/putRecord.defs.ts +0 -59
- package/src/lexicons/com/atproto/repo/putRecord.ts +0 -6
- package/src/lexicons/com/atproto/repo/uploadBlob.defs.ts +0 -35
- package/src/lexicons/com/atproto/repo/uploadBlob.ts +0 -6
- package/src/lexicons/com/atproto/repo.ts +0 -12
- package/src/lexicons/com/atproto/sync/getBlob.defs.ts +0 -37
- package/src/lexicons/com/atproto/sync/getBlob.ts +0 -6
- package/src/lexicons/com/atproto/sync.ts +0 -5
- package/src/lexicons/com/atproto.ts +0 -6
- package/src/lexicons/com.ts +0 -5
- package/src/lexicons/index.ts +0 -5
- package/src/response.bench.ts +0 -113
- package/src/response.ts +0 -366
- package/src/types.ts +0 -71
- package/src/util.test.ts +0 -333
- package/src/util.ts +0 -182
- package/src/write-operation-builder.ts +0 -110
- package/src/www-authenticate.test.ts +0 -227
- package/src/www-authenticate.ts +0 -101
- package/src/xrpc.test.ts +0 -1450
- package/src/xrpc.ts +0 -446
- package/tsconfig.build.json +0 -12
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -8
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { parseWWWAuthenticateHeader } from './www-authenticate.js'
|
|
3
|
-
|
|
4
|
-
describe(parseWWWAuthenticateHeader, () => {
|
|
5
|
-
describe('auth-params', () => {
|
|
6
|
-
it('parses single unquoted auth param', () => {
|
|
7
|
-
expect(parseWWWAuthenticateHeader('Bearer realm=example.com')).toEqual({
|
|
8
|
-
Bearer: { realm: 'example.com' },
|
|
9
|
-
})
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
it('parses single quoted auth param', () => {
|
|
13
|
-
expect(parseWWWAuthenticateHeader('Bearer realm="example.com"')).toEqual({
|
|
14
|
-
Bearer: { realm: 'example.com' },
|
|
15
|
-
})
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
it('parses quoted values with spaces', () => {
|
|
19
|
-
expect(parseWWWAuthenticateHeader('Bearer realm="my realm"')).toEqual({
|
|
20
|
-
Bearer: { realm: 'my realm' },
|
|
21
|
-
})
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('parses quoted values with escaped double quotes', () => {
|
|
25
|
-
expect(
|
|
26
|
-
parseWWWAuthenticateHeader('Bearer realm="example\\"quoted\\""'),
|
|
27
|
-
).toEqual({
|
|
28
|
-
Bearer: { realm: 'example"quoted"' },
|
|
29
|
-
})
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('parses quoted values with escaped backslash', () => {
|
|
33
|
-
expect(
|
|
34
|
-
parseWWWAuthenticateHeader('Bearer realm="path\\\\to\\\\file"'),
|
|
35
|
-
).toEqual({
|
|
36
|
-
Bearer: { realm: 'path\\to\\file' },
|
|
37
|
-
})
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('parses param names with hyphens', () => {
|
|
41
|
-
expect(
|
|
42
|
-
parseWWWAuthenticateHeader('Bearer error-uri="https://example.com"'),
|
|
43
|
-
).toEqual({
|
|
44
|
-
Bearer: { 'error-uri': 'https://example.com' },
|
|
45
|
-
})
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('parses param names with underscores', () => {
|
|
49
|
-
expect(
|
|
50
|
-
parseWWWAuthenticateHeader('Bearer error_description="test"'),
|
|
51
|
-
).toEqual({
|
|
52
|
-
Bearer: { error_description: 'test' },
|
|
53
|
-
})
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('parses param with numeric value', () => {
|
|
57
|
-
expect(parseWWWAuthenticateHeader('Bearer max-age=3600')).toEqual({
|
|
58
|
-
Bearer: { 'max-age': '3600' },
|
|
59
|
-
})
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('parses empty quoted value', () => {
|
|
63
|
-
expect(parseWWWAuthenticateHeader('Bearer realm=""')).toEqual({
|
|
64
|
-
Bearer: { realm: '' },
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('parses Basic auth challenge', () => {
|
|
69
|
-
expect(
|
|
70
|
-
parseWWWAuthenticateHeader('Basic realm="Access to staging site"'),
|
|
71
|
-
).toEqual({
|
|
72
|
-
Basic: { realm: 'Access to staging site' },
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('parses Bearer with realm', () => {
|
|
77
|
-
expect(
|
|
78
|
-
parseWWWAuthenticateHeader('Bearer realm="https://auth.example.com"'),
|
|
79
|
-
).toEqual({
|
|
80
|
-
Bearer: { realm: 'https://auth.example.com' },
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
it('parses DPoP with algs param', () => {
|
|
85
|
-
expect(parseWWWAuthenticateHeader('DPoP algs="ES256 RS256"')).toEqual({
|
|
86
|
-
DPoP: { algs: 'ES256 RS256' },
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('parses Digest auth challenge', () => {
|
|
91
|
-
const result = parseWWWAuthenticateHeader(
|
|
92
|
-
'Digest realm="digest-realm", nonce="abc123"',
|
|
93
|
-
)
|
|
94
|
-
expect(result).toEqual({
|
|
95
|
-
Digest: { realm: 'digest-realm', nonce: 'abc123' },
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('handle empty unquoted params', () => {
|
|
100
|
-
const result = parseWWWAuthenticateHeader('Bearer realm=')
|
|
101
|
-
expect(result).toEqual({ Bearer: { realm: '' } })
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('handle empty params', () => {
|
|
105
|
-
const result = parseWWWAuthenticateHeader('Bearer realm=""')
|
|
106
|
-
expect(result).toEqual({ Bearer: { realm: '' } })
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('treats scheme-only header as scheme with itself as token68', () => {
|
|
110
|
-
const result = parseWWWAuthenticateHeader('Basic')
|
|
111
|
-
expect(result).toEqual({ Basic: {} })
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
it('parses multiple challenges with commas and escaped quotes', () => {
|
|
115
|
-
const result = parseWWWAuthenticateHeader(
|
|
116
|
-
`Newauth realm="apps", type=1,\n\t title="Login to \\"apps\\"", Basic realm="simple"`,
|
|
117
|
-
)
|
|
118
|
-
expect(result).toEqual({
|
|
119
|
-
Newauth: {
|
|
120
|
-
realm: 'apps',
|
|
121
|
-
type: '1',
|
|
122
|
-
title: 'Login to "apps"',
|
|
123
|
-
},
|
|
124
|
-
Basic: { realm: 'simple' },
|
|
125
|
-
})
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('parses first challenge before comma', () => {
|
|
129
|
-
const result = parseWWWAuthenticateHeader(
|
|
130
|
-
'Basic realm="foo", Bearer realm="bar"',
|
|
131
|
-
)
|
|
132
|
-
expect(result).toEqual({
|
|
133
|
-
Basic: { realm: 'foo' },
|
|
134
|
-
Bearer: { realm: 'bar' },
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
describe('edge cases', () => {
|
|
140
|
-
it('handles empty string', () => {
|
|
141
|
-
expect(parseWWWAuthenticateHeader('')).toEqual({})
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
it('handles whitespace-only string', () => {
|
|
145
|
-
expect(parseWWWAuthenticateHeader(' ')).toEqual({})
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
it('trims whitespace from header', () => {
|
|
149
|
-
expect(parseWWWAuthenticateHeader(' Bearer realm="test" ')).toEqual({
|
|
150
|
-
Bearer: { realm: 'test' },
|
|
151
|
-
})
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
it('handles commas as quoted param value', () => {
|
|
155
|
-
expect(
|
|
156
|
-
parseWWWAuthenticateHeader('Bearer realm="example, with, commas"'),
|
|
157
|
-
).toEqual({ Bearer: { realm: 'example, with, commas' } })
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('handles multiple challenges with varying whitespace', () => {
|
|
161
|
-
expect(
|
|
162
|
-
parseWWWAuthenticateHeader(
|
|
163
|
-
' Bearer realm="test" , Basic rr= ',
|
|
164
|
-
),
|
|
165
|
-
).toEqual({
|
|
166
|
-
Bearer: { realm: 'test' },
|
|
167
|
-
Basic: { rr: '' },
|
|
168
|
-
})
|
|
169
|
-
})
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
describe('invalid challenges', () => {
|
|
173
|
-
it('parses single challenge with no comma correctly', () => {
|
|
174
|
-
expect(
|
|
175
|
-
parseWWWAuthenticateHeader('Bearer realm="oauth" error="invalid"'),
|
|
176
|
-
).toEqual(undefined)
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
it('ignores invalid challenges', () => {
|
|
180
|
-
expect(parseWWWAuthenticateHeader('Bearer realm="unclosed')).toEqual(
|
|
181
|
-
undefined,
|
|
182
|
-
)
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
it('handles random text without equals sign as token68', () => {
|
|
186
|
-
expect(parseWWWAuthenticateHeader('Bearer sometoken')).toEqual({
|
|
187
|
-
Bearer: 'sometoken',
|
|
188
|
-
})
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
it('ignores trailing whitespace after scheme', () => {
|
|
192
|
-
expect(parseWWWAuthenticateHeader('Bearer ')).toEqual({ Bearer: {} })
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
it('handles duplicate params (last wins)', () => {
|
|
196
|
-
expect(
|
|
197
|
-
parseWWWAuthenticateHeader('Bearer realm="first", realm="second"'),
|
|
198
|
-
).toEqual({ Bearer: { realm: 'second' } })
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
it('extracts valid param after invalid characters', () => {
|
|
202
|
-
expect(parseWWWAuthenticateHeader('Bearer realm@foo="bar"')).toEqual({
|
|
203
|
-
Bearer: { 'realm@foo': 'bar' },
|
|
204
|
-
})
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
it('ignores param with empty name', () => {
|
|
208
|
-
expect(parseWWWAuthenticateHeader('Bearer ="value"')).toEqual(undefined)
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
it('handles completely malformed input gracefully', () => {
|
|
212
|
-
expect(parseWWWAuthenticateHeader('!@#$%')).toEqual({ '!@#$%': {} })
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it('handles duplicate schemes as invalid', () => {
|
|
216
|
-
expect(
|
|
217
|
-
parseWWWAuthenticateHeader('Basic realm="first", Basic realm="second"'),
|
|
218
|
-
).toEqual(undefined)
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
it('handles params without scheme as invalid', () => {
|
|
222
|
-
expect(parseWWWAuthenticateHeader('Bearer, realm="foo"')).toEqual(
|
|
223
|
-
undefined,
|
|
224
|
-
)
|
|
225
|
-
})
|
|
226
|
-
})
|
|
227
|
-
})
|
package/src/www-authenticate.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
type WWWAuthenticateParams = { [authParam in string]: string }
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Parsed representation of a WWW-Authenticate HTTP header.
|
|
5
|
-
*
|
|
6
|
-
* Maps authentication scheme names to either:
|
|
7
|
-
* - A token68 string (compact authentication data)
|
|
8
|
-
* - A params object with key-value pairs
|
|
9
|
-
*
|
|
10
|
-
* @example Bearer with realm
|
|
11
|
-
* ```typescript
|
|
12
|
-
* // WWW-Authenticate: Bearer realm="example"
|
|
13
|
-
* const parsed: WWWAuthenticate = {
|
|
14
|
-
* Bearer: { realm: 'example' }
|
|
15
|
-
* }
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* @example DPoP with error
|
|
19
|
-
* ```typescript
|
|
20
|
-
* // WWW-Authenticate: DPoP error="use_dpop_nonce", error_description="..."
|
|
21
|
-
* const parsed: WWWAuthenticate = {
|
|
22
|
-
* DPoP: { error: 'use_dpop_nonce', error_description: '...' }
|
|
23
|
-
* }
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
export type WWWAuthenticate = {
|
|
27
|
-
[authScheme in string]:
|
|
28
|
-
| string // token68
|
|
29
|
-
| WWWAuthenticateParams
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Returns `undefined` if the header is malformed.
|
|
34
|
-
*/
|
|
35
|
-
export function parseWWWAuthenticateHeader(
|
|
36
|
-
header?: unknown,
|
|
37
|
-
): undefined | WWWAuthenticate {
|
|
38
|
-
if (typeof header !== 'string') return undefined
|
|
39
|
-
|
|
40
|
-
const wwwAuthenticate: WWWAuthenticate = {}
|
|
41
|
-
|
|
42
|
-
// Split over commas, not within quoted strings
|
|
43
|
-
const trimmedHeader = header.trim()
|
|
44
|
-
if (!trimmedHeader) return wwwAuthenticate
|
|
45
|
-
|
|
46
|
-
const parts = trimmedHeader.split(/,(?=(?:[^"]*"[^"]*")*[^"]*$)/)
|
|
47
|
-
|
|
48
|
-
let currentParams: WWWAuthenticateParams | null = null
|
|
49
|
-
|
|
50
|
-
for (let part of parts) {
|
|
51
|
-
// Check if the part starts with an auth scheme
|
|
52
|
-
const schemeMatch = part.trim().match(/^([^"=\s]+)(\s+.*)?$/)
|
|
53
|
-
if (schemeMatch) {
|
|
54
|
-
const scheme = schemeMatch[1]
|
|
55
|
-
|
|
56
|
-
// Duplicate scheme
|
|
57
|
-
if (Object.hasOwn(wwwAuthenticate, scheme)) return undefined
|
|
58
|
-
|
|
59
|
-
const rest = schemeMatch[2]?.trim()
|
|
60
|
-
if (!rest) {
|
|
61
|
-
// Scheme only (no params or token68)
|
|
62
|
-
currentParams = null
|
|
63
|
-
wwwAuthenticate[scheme] = Object.create(null)
|
|
64
|
-
continue
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (!rest.includes('=')) {
|
|
68
|
-
// Scheme with token68
|
|
69
|
-
currentParams = null
|
|
70
|
-
wwwAuthenticate[scheme] = rest
|
|
71
|
-
continue
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Scheme with params
|
|
75
|
-
|
|
76
|
-
currentParams = Object.create(null) as WWWAuthenticateParams
|
|
77
|
-
wwwAuthenticate[scheme] = currentParams
|
|
78
|
-
|
|
79
|
-
// Fall through to parse params
|
|
80
|
-
part = rest
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Invalid header
|
|
84
|
-
if (!currentParams) return undefined
|
|
85
|
-
|
|
86
|
-
const param = part.match(
|
|
87
|
-
/^\s*([^"\s=]+)=(?:("[^"\\]*(?:\\.[^"\\]*)*")|([^\s,"]*))\s*$/,
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
// invalid param
|
|
91
|
-
if (!param) return undefined
|
|
92
|
-
|
|
93
|
-
const paramName = param[1]
|
|
94
|
-
const paramValue =
|
|
95
|
-
param[3] ?? param[2]!.slice(1, -1).replaceAll(/\\(.)/g, '$1')
|
|
96
|
-
|
|
97
|
-
currentParams[paramName] = paramValue
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return wwwAuthenticate
|
|
101
|
-
}
|