@atproto/xrpc-server 0.0.1 → 0.2.0
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/dist/auth.d.ts +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +40116 -29848
- package/dist/index.js.map +4 -4
- package/dist/server.d.ts +9 -3
- package/dist/src/index.d.ts +2 -0
- package/dist/src/logger.d.ts +2 -0
- package/dist/src/server.d.ts +19 -0
- package/dist/src/types.d.ts +115 -0
- package/dist/src/util.d.ts +10 -0
- package/dist/stream/frames.d.ts +25 -0
- package/dist/stream/index.d.ts +5 -0
- package/dist/stream/logger.d.ts +2 -0
- package/dist/stream/server.d.ts +11 -0
- package/dist/stream/stream.d.ts +5 -0
- package/dist/stream/subscription.d.ts +24 -0
- package/dist/stream/types.d.ts +64 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/util.d.ts +3 -2
- package/package.json +14 -2
- package/src/auth.ts +111 -0
- package/src/index.ts +2 -0
- package/src/server.ts +148 -10
- package/src/stream/frames.ts +95 -0
- package/src/stream/index.ts +5 -0
- package/src/stream/logger.ts +5 -0
- package/src/stream/server.ts +65 -0
- package/src/stream/stream.ts +26 -0
- package/src/stream/subscription.ts +175 -0
- package/src/stream/types.ts +43 -0
- package/src/types.ts +27 -2
- package/src/util.ts +38 -7
- package/tests/_util.ts +36 -1
- package/tests/auth.test.ts +15 -36
- package/tests/bodies.test.ts +50 -9
- package/tests/errors.test.ts +38 -11
- package/tests/frames.test.ts +137 -0
- package/tests/ipld.test.ts +96 -0
- package/tests/parameters.test.ts +13 -45
- package/tests/procedures.test.ts +7 -3
- package/tests/queries.test.ts +7 -3
- package/tests/stream.test.ts +169 -0
- package/tests/subscriptions.test.ts +347 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.json +1 -0
package/tests/errors.test.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as http from 'http'
|
|
2
|
+
import getPort from 'get-port'
|
|
2
3
|
import { createServer, closeServer } from './_util'
|
|
3
4
|
import * as xrpcServer from '../src'
|
|
4
5
|
import xrpc, {
|
|
5
6
|
Client,
|
|
7
|
+
ServiceClient,
|
|
6
8
|
XRPCError,
|
|
7
9
|
XRPCInvalidResponseError,
|
|
8
10
|
} from '@atproto/xrpc'
|
|
@@ -24,6 +26,15 @@ const LEXICONS = [
|
|
|
24
26
|
},
|
|
25
27
|
},
|
|
26
28
|
},
|
|
29
|
+
{
|
|
30
|
+
lexicon: 1,
|
|
31
|
+
id: 'io.example.throwFalsyValue',
|
|
32
|
+
defs: {
|
|
33
|
+
main: {
|
|
34
|
+
type: 'query',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
27
38
|
{
|
|
28
39
|
lexicon: 1,
|
|
29
40
|
id: 'io.example.query',
|
|
@@ -105,6 +116,9 @@ describe('Errors', () => {
|
|
|
105
116
|
return { status: 400 }
|
|
106
117
|
}
|
|
107
118
|
})
|
|
119
|
+
server.method('io.example.throwFalsyValue', () => {
|
|
120
|
+
throw ''
|
|
121
|
+
})
|
|
108
122
|
server.method('io.example.query', () => {
|
|
109
123
|
return undefined
|
|
110
124
|
})
|
|
@@ -115,13 +129,17 @@ describe('Errors', () => {
|
|
|
115
129
|
server.method('io.example.procedure', () => {
|
|
116
130
|
return undefined
|
|
117
131
|
})
|
|
118
|
-
const client = xrpc.service(`http://localhost:8893`)
|
|
119
132
|
xrpc.addLexicons(LEXICONS)
|
|
120
133
|
const badXrpc = new Client()
|
|
121
|
-
const badClient = badXrpc.service(`http://localhost:8893`)
|
|
122
134
|
badXrpc.addLexicons(MISMATCHED_LEXICONS)
|
|
135
|
+
|
|
136
|
+
let client: ServiceClient
|
|
137
|
+
let badClient: ServiceClient
|
|
123
138
|
beforeAll(async () => {
|
|
124
|
-
|
|
139
|
+
const port = await getPort()
|
|
140
|
+
s = await createServer(port, server)
|
|
141
|
+
client = xrpc.service(`http://localhost:${port}`)
|
|
142
|
+
badClient = badXrpc.service(`http://localhost:${port}`)
|
|
125
143
|
})
|
|
126
144
|
afterAll(async () => {
|
|
127
145
|
await closeServer(s)
|
|
@@ -134,7 +152,7 @@ describe('Errors', () => {
|
|
|
134
152
|
})
|
|
135
153
|
throw new Error('Didnt throw')
|
|
136
154
|
} catch (e) {
|
|
137
|
-
expect(e
|
|
155
|
+
expect(e).toBeInstanceOf(XRPCError)
|
|
138
156
|
expect((e as XRPCError).success).toBeFalsy()
|
|
139
157
|
expect((e as XRPCError).error).toBe('Foo')
|
|
140
158
|
expect((e as XRPCError).message).toBe('It was this one!')
|
|
@@ -145,18 +163,27 @@ describe('Errors', () => {
|
|
|
145
163
|
})
|
|
146
164
|
throw new Error('Didnt throw')
|
|
147
165
|
} catch (e) {
|
|
148
|
-
expect(e
|
|
166
|
+
expect(e).toBeInstanceOf(XRPCError)
|
|
149
167
|
expect((e as XRPCError).success).toBeFalsy()
|
|
150
168
|
expect((e as XRPCError).error).toBe('Bar')
|
|
151
169
|
expect((e as XRPCError).message).toBe('It was that one!')
|
|
152
170
|
}
|
|
171
|
+
try {
|
|
172
|
+
await client.call('io.example.throwFalsyValue')
|
|
173
|
+
throw new Error('Didnt throw')
|
|
174
|
+
} catch (e) {
|
|
175
|
+
expect(e instanceof XRPCError).toBeTruthy()
|
|
176
|
+
expect((e as XRPCError).success).toBeFalsy()
|
|
177
|
+
expect((e as XRPCError).error).toBe('InternalServerError')
|
|
178
|
+
expect((e as XRPCError).message).toBe('Internal Server Error')
|
|
179
|
+
}
|
|
153
180
|
try {
|
|
154
181
|
await client.call('io.example.error', {
|
|
155
182
|
which: 'other',
|
|
156
183
|
})
|
|
157
184
|
throw new Error('Didnt throw')
|
|
158
185
|
} catch (e) {
|
|
159
|
-
expect(e
|
|
186
|
+
expect(e).toBeInstanceOf(XRPCError)
|
|
160
187
|
expect((e as XRPCError).success).toBeFalsy()
|
|
161
188
|
expect((e as XRPCError).error).toBe('InvalidRequest')
|
|
162
189
|
expect((e as XRPCError).message).toBe('Invalid Request')
|
|
@@ -165,8 +192,8 @@ describe('Errors', () => {
|
|
|
165
192
|
await client.call('io.example.invalidResponse')
|
|
166
193
|
throw new Error('Didnt throw')
|
|
167
194
|
} catch (e: any) {
|
|
168
|
-
expect(e
|
|
169
|
-
expect(e
|
|
195
|
+
expect(e).toBeInstanceOf(XRPCError)
|
|
196
|
+
expect(e).toBeInstanceOf(XRPCInvalidResponseError)
|
|
170
197
|
expect(e.success).toBeFalsy()
|
|
171
198
|
expect(e.error).toBe('Invalid Response')
|
|
172
199
|
expect(e.message).toBe(
|
|
@@ -187,7 +214,7 @@ describe('Errors', () => {
|
|
|
187
214
|
await badClient.call('io.example.query')
|
|
188
215
|
throw new Error('Didnt throw')
|
|
189
216
|
} catch (e: any) {
|
|
190
|
-
expect(e
|
|
217
|
+
expect(e).toBeInstanceOf(XRPCError)
|
|
191
218
|
expect(e.success).toBeFalsy()
|
|
192
219
|
expect(e.error).toBe('InvalidRequest')
|
|
193
220
|
expect(e.message).toBe('Incorrect HTTP method (POST) expected GET')
|
|
@@ -196,7 +223,7 @@ describe('Errors', () => {
|
|
|
196
223
|
await badClient.call('io.example.procedure')
|
|
197
224
|
throw new Error('Didnt throw')
|
|
198
225
|
} catch (e: any) {
|
|
199
|
-
expect(e
|
|
226
|
+
expect(e).toBeInstanceOf(XRPCError)
|
|
200
227
|
expect(e.success).toBeFalsy()
|
|
201
228
|
expect(e.error).toBe('InvalidRequest')
|
|
202
229
|
expect(e.message).toBe('Incorrect HTTP method (GET) expected POST')
|
|
@@ -205,7 +232,7 @@ describe('Errors', () => {
|
|
|
205
232
|
await badClient.call('io.example.doesNotExist')
|
|
206
233
|
throw new Error('Didnt throw')
|
|
207
234
|
} catch (e: any) {
|
|
208
|
-
expect(e
|
|
235
|
+
expect(e).toBeInstanceOf(XRPCError)
|
|
209
236
|
expect(e.success).toBeFalsy()
|
|
210
237
|
expect(e.error).toBe('MethodNotImplemented')
|
|
211
238
|
expect(e.message).toBe('Method Not Implemented')
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import * as cborx from 'cbor-x'
|
|
2
|
+
import * as uint8arrays from 'uint8arrays'
|
|
3
|
+
import { MessageFrame, ErrorFrame, Frame, FrameType } from '../src'
|
|
4
|
+
|
|
5
|
+
describe('Frames', () => {
|
|
6
|
+
it('creates and parses message frame.', async () => {
|
|
7
|
+
const messageFrame = new MessageFrame(
|
|
8
|
+
{ a: 'b', c: [1, 2, 3] },
|
|
9
|
+
{ type: '#d' },
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
expect(messageFrame.header).toEqual({
|
|
13
|
+
op: FrameType.Message,
|
|
14
|
+
t: '#d',
|
|
15
|
+
})
|
|
16
|
+
expect(messageFrame.op).toEqual(FrameType.Message)
|
|
17
|
+
expect(messageFrame.type).toEqual('#d')
|
|
18
|
+
expect(messageFrame.body).toEqual({ a: 'b', c: [1, 2, 3] })
|
|
19
|
+
|
|
20
|
+
const bytes = messageFrame.toBytes()
|
|
21
|
+
expect(
|
|
22
|
+
uint8arrays.equals(
|
|
23
|
+
bytes,
|
|
24
|
+
new Uint8Array([
|
|
25
|
+
/*header*/ 162, 97, 116, 98, 35, 100, 98, 111, 112, 1, /*body*/ 162,
|
|
26
|
+
97, 97, 97, 98, 97, 99, 131, 1, 2, 3,
|
|
27
|
+
]),
|
|
28
|
+
),
|
|
29
|
+
).toEqual(true)
|
|
30
|
+
|
|
31
|
+
const parsedFrame = Frame.fromBytes(bytes)
|
|
32
|
+
if (!(parsedFrame instanceof MessageFrame)) {
|
|
33
|
+
throw new Error('Did not parse as message frame')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
expect(parsedFrame.header).toEqual(messageFrame.header)
|
|
37
|
+
expect(parsedFrame.op).toEqual(messageFrame.op)
|
|
38
|
+
expect(parsedFrame.type).toEqual(messageFrame.type)
|
|
39
|
+
expect(parsedFrame.body).toEqual(messageFrame.body)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('creates and parses error frame.', async () => {
|
|
43
|
+
const errorFrame = new ErrorFrame({
|
|
44
|
+
error: 'BigOops',
|
|
45
|
+
message: 'Something went awry',
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
expect(errorFrame.header).toEqual({ op: FrameType.Error })
|
|
49
|
+
expect(errorFrame.op).toEqual(FrameType.Error)
|
|
50
|
+
expect(errorFrame.code).toEqual('BigOops')
|
|
51
|
+
expect(errorFrame.message).toEqual('Something went awry')
|
|
52
|
+
expect(errorFrame.body).toEqual({
|
|
53
|
+
error: 'BigOops',
|
|
54
|
+
message: 'Something went awry',
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const bytes = errorFrame.toBytes()
|
|
58
|
+
expect(
|
|
59
|
+
uint8arrays.equals(
|
|
60
|
+
bytes,
|
|
61
|
+
new Uint8Array([
|
|
62
|
+
/*header*/ 161, 98, 111, 112, 32, /*body*/ 162, 101, 101, 114, 114,
|
|
63
|
+
111, 114, 103, 66, 105, 103, 79, 111, 112, 115, 103, 109, 101, 115,
|
|
64
|
+
115, 97, 103, 101, 115, 83, 111, 109, 101, 116, 104, 105, 110, 103,
|
|
65
|
+
32, 119, 101, 110, 116, 32, 97, 119, 114, 121,
|
|
66
|
+
]),
|
|
67
|
+
),
|
|
68
|
+
).toEqual(true)
|
|
69
|
+
|
|
70
|
+
const parsedFrame = Frame.fromBytes(bytes)
|
|
71
|
+
if (!(parsedFrame instanceof ErrorFrame)) {
|
|
72
|
+
throw new Error('Did not parse as error frame')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
expect(parsedFrame.header).toEqual(errorFrame.header)
|
|
76
|
+
expect(parsedFrame.op).toEqual(errorFrame.op)
|
|
77
|
+
expect(parsedFrame.code).toEqual(errorFrame.code)
|
|
78
|
+
expect(parsedFrame.message).toEqual(errorFrame.message)
|
|
79
|
+
expect(parsedFrame.body).toEqual(errorFrame.body)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('parsing fails when frame is not CBOR.', async () => {
|
|
83
|
+
const bytes = Buffer.from('some utf8 bytes')
|
|
84
|
+
const emptyBytes = Buffer.from('')
|
|
85
|
+
expect(() => Frame.fromBytes(bytes)).toThrow('Unexpected end of CBOR data')
|
|
86
|
+
expect(() => Frame.fromBytes(emptyBytes)).toThrow(
|
|
87
|
+
'Unexpected end of CBOR data',
|
|
88
|
+
)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('parsing fails when frame header is malformed.', async () => {
|
|
92
|
+
const bytes = uint8arrays.concat([
|
|
93
|
+
cborx.encode({ op: -2 }), // Unknown op
|
|
94
|
+
cborx.encode({ a: 'b', c: [1, 2, 3] }),
|
|
95
|
+
])
|
|
96
|
+
|
|
97
|
+
expect(() => Frame.fromBytes(bytes)).toThrow('Invalid frame header:')
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('parsing fails when frame is missing body.', async () => {
|
|
101
|
+
const messageFrame = new MessageFrame(
|
|
102
|
+
{ a: 'b', c: [1, 2, 3] },
|
|
103
|
+
{ type: '#d' },
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
const headerBytes = cborx.encode(messageFrame.header)
|
|
107
|
+
|
|
108
|
+
expect(() => Frame.fromBytes(headerBytes)).toThrow('Missing frame body')
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('parsing fails when frame has too many data items.', async () => {
|
|
112
|
+
const messageFrame = new MessageFrame(
|
|
113
|
+
{ a: 'b', c: [1, 2, 3] },
|
|
114
|
+
{ type: '#d' },
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
const bytes = uint8arrays.concat([
|
|
118
|
+
messageFrame.toBytes(),
|
|
119
|
+
cborx.encode({ d: 'e', f: [4, 5, 6] }),
|
|
120
|
+
])
|
|
121
|
+
|
|
122
|
+
expect(() => Frame.fromBytes(bytes)).toThrow(
|
|
123
|
+
'Too many CBOR data items in frame',
|
|
124
|
+
)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('parsing fails when error frame has invalid body.', async () => {
|
|
128
|
+
const errorFrame = new ErrorFrame({ error: 'BadOops' })
|
|
129
|
+
|
|
130
|
+
const bytes = uint8arrays.concat([
|
|
131
|
+
cborx.encode(errorFrame.header),
|
|
132
|
+
cborx.encode({ blah: 1 }),
|
|
133
|
+
])
|
|
134
|
+
|
|
135
|
+
expect(() => Frame.fromBytes(bytes)).toThrow('Invalid error frame body:')
|
|
136
|
+
})
|
|
137
|
+
})
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as http from 'http'
|
|
2
|
+
import xrpc, { ServiceClient } from '@atproto/xrpc'
|
|
3
|
+
import { CID } from 'multiformats/cid'
|
|
4
|
+
import getPort from 'get-port'
|
|
5
|
+
import { createServer, closeServer } from './_util'
|
|
6
|
+
import * as xrpcServer from '../src'
|
|
7
|
+
|
|
8
|
+
const LEXICONS = [
|
|
9
|
+
{
|
|
10
|
+
lexicon: 1,
|
|
11
|
+
id: 'io.example.ipld',
|
|
12
|
+
defs: {
|
|
13
|
+
main: {
|
|
14
|
+
type: 'procedure',
|
|
15
|
+
input: {
|
|
16
|
+
encoding: 'application/json',
|
|
17
|
+
schema: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
cid: {
|
|
21
|
+
type: 'cid-link',
|
|
22
|
+
},
|
|
23
|
+
bytes: {
|
|
24
|
+
type: 'bytes',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
output: {
|
|
30
|
+
encoding: 'application/json',
|
|
31
|
+
schema: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
cid: {
|
|
35
|
+
type: 'cid-link',
|
|
36
|
+
},
|
|
37
|
+
bytes: {
|
|
38
|
+
type: 'bytes',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
describe('Ipld vals', () => {
|
|
49
|
+
let s: http.Server
|
|
50
|
+
const server = xrpcServer.createServer(LEXICONS)
|
|
51
|
+
server.method(
|
|
52
|
+
'io.example.ipld',
|
|
53
|
+
(ctx: { input?: xrpcServer.HandlerInput }) => {
|
|
54
|
+
const asCid = CID.asCID(ctx.input?.body.cid)
|
|
55
|
+
if (!(asCid instanceof CID)) {
|
|
56
|
+
throw new Error('expected cid')
|
|
57
|
+
}
|
|
58
|
+
const bytes = ctx.input?.body.bytes
|
|
59
|
+
if (!(bytes instanceof Uint8Array)) {
|
|
60
|
+
throw new Error('expected bytes')
|
|
61
|
+
}
|
|
62
|
+
return { encoding: 'application/json', body: ctx.input?.body }
|
|
63
|
+
},
|
|
64
|
+
)
|
|
65
|
+
xrpc.addLexicons(LEXICONS)
|
|
66
|
+
|
|
67
|
+
let client: ServiceClient
|
|
68
|
+
beforeAll(async () => {
|
|
69
|
+
const port = await getPort()
|
|
70
|
+
s = await createServer(port, server)
|
|
71
|
+
client = xrpc.service(`http://localhost:${port}`)
|
|
72
|
+
})
|
|
73
|
+
afterAll(async () => {
|
|
74
|
+
await closeServer(s)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('can send and receive ipld vals', async () => {
|
|
78
|
+
const cid = CID.parse(
|
|
79
|
+
'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
|
|
80
|
+
)
|
|
81
|
+
const bytes = new Uint8Array([0, 1, 2, 3])
|
|
82
|
+
const res = await client.call(
|
|
83
|
+
'io.example.ipld',
|
|
84
|
+
{},
|
|
85
|
+
{
|
|
86
|
+
cid,
|
|
87
|
+
bytes,
|
|
88
|
+
},
|
|
89
|
+
{ encoding: 'application/json' },
|
|
90
|
+
)
|
|
91
|
+
expect(res.success).toBeTruthy()
|
|
92
|
+
expect(res.headers['content-type']).toBe('application/json; charset=utf-8')
|
|
93
|
+
expect(cid.equals(res.data.cid)).toBeTruthy()
|
|
94
|
+
expect(bytes).toEqual(res.data.bytes)
|
|
95
|
+
})
|
|
96
|
+
})
|
package/tests/parameters.test.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as http from 'http'
|
|
2
|
+
import getPort from 'get-port'
|
|
3
|
+
import xrpc, { ServiceClient } from '@atproto/xrpc'
|
|
2
4
|
import { createServer, closeServer } from './_util'
|
|
3
5
|
import * as xrpcServer from '../src'
|
|
4
|
-
import xrpc from '@atproto/xrpc'
|
|
5
6
|
|
|
6
7
|
const LEXICONS = [
|
|
7
8
|
{
|
|
@@ -12,13 +13,13 @@ const LEXICONS = [
|
|
|
12
13
|
type: 'query',
|
|
13
14
|
parameters: {
|
|
14
15
|
type: 'params',
|
|
15
|
-
required: ['str', 'int', '
|
|
16
|
+
required: ['str', 'int', 'bool', 'arr'],
|
|
16
17
|
properties: {
|
|
17
18
|
str: { type: 'string', minLength: 2, maxLength: 10 },
|
|
18
19
|
int: { type: 'integer', minimum: 2, maximum: 10 },
|
|
19
|
-
num: { type: 'number', minimum: 2, maximum: 10 },
|
|
20
20
|
bool: { type: 'boolean' },
|
|
21
21
|
arr: { type: 'array', items: { type: 'integer' }, maxLength: 2 },
|
|
22
|
+
def: { type: 'integer', default: 0 },
|
|
22
23
|
},
|
|
23
24
|
},
|
|
24
25
|
output: {
|
|
@@ -39,10 +40,13 @@ describe('Parameters', () => {
|
|
|
39
40
|
body: ctx.params,
|
|
40
41
|
}),
|
|
41
42
|
)
|
|
42
|
-
const client = xrpc.service(`http://localhost:8889`)
|
|
43
43
|
xrpc.addLexicons(LEXICONS)
|
|
44
|
+
|
|
45
|
+
let client: ServiceClient
|
|
44
46
|
beforeAll(async () => {
|
|
45
|
-
|
|
47
|
+
const port = await getPort()
|
|
48
|
+
s = await createServer(port, server)
|
|
49
|
+
client = xrpc.service(`http://localhost:${port}`)
|
|
46
50
|
})
|
|
47
51
|
afterAll(async () => {
|
|
48
52
|
await closeServer(s)
|
|
@@ -52,36 +56,35 @@ describe('Parameters', () => {
|
|
|
52
56
|
const res1 = await client.call('io.example.paramTest', {
|
|
53
57
|
str: 'valid',
|
|
54
58
|
int: 5,
|
|
55
|
-
num: 5.5,
|
|
56
59
|
bool: true,
|
|
57
60
|
arr: [1, 2],
|
|
61
|
+
def: 5,
|
|
58
62
|
})
|
|
59
63
|
expect(res1.success).toBeTruthy()
|
|
60
64
|
expect(res1.data.str).toBe('valid')
|
|
61
65
|
expect(res1.data.int).toBe(5)
|
|
62
|
-
expect(res1.data.num).toBe(5.5)
|
|
63
66
|
expect(res1.data.bool).toBe(true)
|
|
64
67
|
expect(res1.data.arr).toEqual([1, 2])
|
|
68
|
+
expect(res1.data.def).toEqual(5)
|
|
65
69
|
|
|
66
70
|
const res2 = await client.call('io.example.paramTest', {
|
|
67
71
|
str: 10,
|
|
68
72
|
int: '5',
|
|
69
|
-
num: '5.5',
|
|
70
73
|
bool: 'foo',
|
|
71
74
|
arr: '3',
|
|
72
75
|
})
|
|
73
76
|
expect(res2.success).toBeTruthy()
|
|
74
77
|
expect(res2.data.str).toBe('10')
|
|
75
78
|
expect(res2.data.int).toBe(5)
|
|
76
|
-
expect(res2.data.num).toBe(5.5)
|
|
77
79
|
expect(res2.data.bool).toBe(true)
|
|
78
80
|
expect(res2.data.arr).toEqual([3])
|
|
81
|
+
expect(res2.data.def).toEqual(0)
|
|
79
82
|
|
|
83
|
+
// @TODO test sending blatantly bad types
|
|
80
84
|
await expect(
|
|
81
85
|
client.call('io.example.paramTest', {
|
|
82
86
|
str: 'n',
|
|
83
87
|
int: 5,
|
|
84
|
-
num: 5.5,
|
|
85
88
|
bool: true,
|
|
86
89
|
arr: [1],
|
|
87
90
|
}),
|
|
@@ -90,7 +93,6 @@ describe('Parameters', () => {
|
|
|
90
93
|
client.call('io.example.paramTest', {
|
|
91
94
|
str: 'loooooooooooooong',
|
|
92
95
|
int: 5,
|
|
93
|
-
num: 5.5,
|
|
94
96
|
bool: true,
|
|
95
97
|
arr: [1],
|
|
96
98
|
}),
|
|
@@ -98,7 +100,6 @@ describe('Parameters', () => {
|
|
|
98
100
|
await expect(
|
|
99
101
|
client.call('io.example.paramTest', {
|
|
100
102
|
int: 5,
|
|
101
|
-
num: 5.5,
|
|
102
103
|
bool: true,
|
|
103
104
|
arr: [1],
|
|
104
105
|
}),
|
|
@@ -108,7 +109,6 @@ describe('Parameters', () => {
|
|
|
108
109
|
client.call('io.example.paramTest', {
|
|
109
110
|
str: 'valid',
|
|
110
111
|
int: -1,
|
|
111
|
-
num: 5.5,
|
|
112
112
|
bool: true,
|
|
113
113
|
arr: [1],
|
|
114
114
|
}),
|
|
@@ -117,7 +117,6 @@ describe('Parameters', () => {
|
|
|
117
117
|
client.call('io.example.paramTest', {
|
|
118
118
|
str: 'valid',
|
|
119
119
|
int: 11,
|
|
120
|
-
num: 5.5,
|
|
121
120
|
bool: true,
|
|
122
121
|
arr: [1],
|
|
123
122
|
}),
|
|
@@ -125,7 +124,6 @@ describe('Parameters', () => {
|
|
|
125
124
|
await expect(
|
|
126
125
|
client.call('io.example.paramTest', {
|
|
127
126
|
str: 'valid',
|
|
128
|
-
num: 5.5,
|
|
129
127
|
bool: true,
|
|
130
128
|
arr: [1],
|
|
131
129
|
}),
|
|
@@ -135,34 +133,6 @@ describe('Parameters', () => {
|
|
|
135
133
|
client.call('io.example.paramTest', {
|
|
136
134
|
str: 'valid',
|
|
137
135
|
int: 5,
|
|
138
|
-
num: -5.5,
|
|
139
|
-
bool: true,
|
|
140
|
-
arr: [1],
|
|
141
|
-
}),
|
|
142
|
-
).rejects.toThrow('num can not be less than 2')
|
|
143
|
-
await expect(
|
|
144
|
-
client.call('io.example.paramTest', {
|
|
145
|
-
str: 'valid',
|
|
146
|
-
int: 5,
|
|
147
|
-
num: 50.5,
|
|
148
|
-
bool: true,
|
|
149
|
-
arr: [1],
|
|
150
|
-
}),
|
|
151
|
-
).rejects.toThrow('num can not be greater than 10')
|
|
152
|
-
await expect(
|
|
153
|
-
client.call('io.example.paramTest', {
|
|
154
|
-
str: 'valid',
|
|
155
|
-
int: 5,
|
|
156
|
-
bool: true,
|
|
157
|
-
arr: [1],
|
|
158
|
-
}),
|
|
159
|
-
).rejects.toThrow(`Params must have the property "num"`)
|
|
160
|
-
|
|
161
|
-
await expect(
|
|
162
|
-
client.call('io.example.paramTest', {
|
|
163
|
-
str: 'valid',
|
|
164
|
-
int: 5,
|
|
165
|
-
num: 5.5,
|
|
166
136
|
arr: [1],
|
|
167
137
|
}),
|
|
168
138
|
).rejects.toThrow(`Params must have the property "bool"`)
|
|
@@ -171,7 +141,6 @@ describe('Parameters', () => {
|
|
|
171
141
|
client.call('io.example.paramTest', {
|
|
172
142
|
str: 'valid',
|
|
173
143
|
int: 5,
|
|
174
|
-
num: 5.5,
|
|
175
144
|
bool: true,
|
|
176
145
|
arr: [],
|
|
177
146
|
}),
|
|
@@ -180,7 +149,6 @@ describe('Parameters', () => {
|
|
|
180
149
|
client.call('io.example.paramTest', {
|
|
181
150
|
str: 'valid',
|
|
182
151
|
int: 5,
|
|
183
|
-
num: 5.5,
|
|
184
152
|
bool: true,
|
|
185
153
|
arr: [1, 2, 3],
|
|
186
154
|
}),
|
package/tests/procedures.test.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as http from 'http'
|
|
2
2
|
import { Readable } from 'stream'
|
|
3
|
-
import xrpc from '@atproto/xrpc'
|
|
3
|
+
import xrpc, { ServiceClient } from '@atproto/xrpc'
|
|
4
|
+
import getPort from 'get-port'
|
|
4
5
|
import { createServer, closeServer } from './_util'
|
|
5
6
|
import * as xrpcServer from '../src'
|
|
6
7
|
|
|
@@ -119,10 +120,13 @@ describe('Procedures', () => {
|
|
|
119
120
|
}
|
|
120
121
|
},
|
|
121
122
|
)
|
|
122
|
-
const client = xrpc.service(`http://localhost:8891`)
|
|
123
123
|
xrpc.addLexicons(LEXICONS)
|
|
124
|
+
|
|
125
|
+
let client: ServiceClient
|
|
124
126
|
beforeAll(async () => {
|
|
125
|
-
|
|
127
|
+
const port = await getPort()
|
|
128
|
+
s = await createServer(port, server)
|
|
129
|
+
client = xrpc.service(`http://localhost:${port}`)
|
|
126
130
|
})
|
|
127
131
|
afterAll(async () => {
|
|
128
132
|
await closeServer(s)
|
package/tests/queries.test.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as http from 'http'
|
|
2
|
+
import getPort from 'get-port'
|
|
3
|
+
import xrpc, { ServiceClient } from '@atproto/xrpc'
|
|
2
4
|
import { createServer, closeServer } from './_util'
|
|
3
5
|
import * as xrpcServer from '../src'
|
|
4
|
-
import xrpc from '@atproto/xrpc'
|
|
5
6
|
|
|
6
7
|
const LEXICONS = [
|
|
7
8
|
{
|
|
@@ -83,10 +84,13 @@ describe('Queries', () => {
|
|
|
83
84
|
body: { message: ctx.params.message },
|
|
84
85
|
}
|
|
85
86
|
})
|
|
86
|
-
const client = xrpc.service(`http://localhost:8890`)
|
|
87
87
|
xrpc.addLexicons(LEXICONS)
|
|
88
|
+
|
|
89
|
+
let client: ServiceClient
|
|
88
90
|
beforeAll(async () => {
|
|
89
|
-
|
|
91
|
+
const port = await getPort()
|
|
92
|
+
s = await createServer(port, server)
|
|
93
|
+
client = xrpc.service(`http://localhost:${port}`)
|
|
90
94
|
})
|
|
91
95
|
afterAll(async () => {
|
|
92
96
|
await closeServer(s)
|