UNPKG

11.4 kBMarkdownView Raw
1# reactotron-core-client
2
3This provides the core functionality of the clients allowing it talk to talk to the server.
4
5It is used by `reactotron-react-dom` and `reactotron-react-native`.
6
7# Usage
8
9```js
10import { createClient } from "reactotron-core-client"
11
12// setup a reactotron client
13const client = createClient({
14 // injected in for compatibility
15 createSocket: (path) => new WebSocket(path),
16
17 host: "localhost",
18 port: 9090,
19 name: "I am a client!",
20
21 // fires when we get connected to a server
22 onConnect: () => console.log("hi"),
23
24 // fires when we get disconnected from the server
25 onDisconnect: () => console.log("bye"),
26
27 // fires when the server is telling us something
28 onCommand: ({ type, payload }) => {
29 switch (type) {
30 case "server.intro":
31 const { name, version } = payload
32 break
33
34 case "state.values.request":
35 const { path } = payload // the path to the state
36 break
37
38 case "state.keys.request":
39 const { path } = payload // the path to the state
40 break
41
42 case "state.values.subscribe":
43 const { paths } = payload // string array of state paths
44 break
45
46 case "state.action.dispatch":
47 const { action } = payload // an object to be dispatch through the state plugin
48 break
49 }
50 console.log(`I just received a ${type} command`)
51 console.log(payload)
52 },
53})
54
55// connect to the server
56client.connect()
57
58// send a log message as a string
59client.send("log", { level: "debug", message: "hello!" })
60
61// send a log message as a string that's important
62client.send("log", { level: "debug", message: "hello!" }, true)
63
64// sending an object log message
65client.send("log", {
66 level: "debug",
67 message: {
68 nested: [1, 2, { hello: "there" }],
69 fun: true,
70 },
71})
72
73// send a warning
74client.send("log", { level: "warn", message: "oops" })
75
76// send an error with an optional stack trace
77client.send("log", {
78 level: "error",
79 message: "crap",
80 stackTrace: [],
81})
82
83// report that an action is complete
84client.send("state.action.complete", {
85 name: "LOGIN_REQUEST",
86 action: {
87 type: "LOGIN_REQUEST",
88 email: "steve@kellock.ca",
89 password: "secret...shhh....",
90 },
91})
92
93// report that values have changed
94client.send("state.values.response", {
95 path: "user.givenName",
96 value: "Steve",
97 valid: true,
98})
99
100// list the keys at a given path in state
101client.send("state.keys.response", {
102 path: "user",
103 keys: ["givenName", "familyName"],
104 valid: true,
105})
106
107// let the server know the state values they're subscribed to have changed
108client.send("state.values.change", {
109 changes: [
110 { path: "user.givenName", value: "Steve" },
111 {
112 path: "user",
113 value: { givenName: "Steve", familyName: "Kellock" },
114 },
115 ],
116})
117
118// report any API activity
119client.send("api.response", {
120 request: {
121 url: "https://api.example.com/v1/people",
122 method: "POST",
123 data: {
124 user: { givenName: "Steve", familyName: "Kellock" },
125 },
126 headers: {
127 Accept: "application/json",
128 Cookie: "__ispy=mylittleye; __something=blue",
129 },
130 },
131 response: {
132 body: { result: "ok" },
133 status: 200,
134 headers: {
135 Connection: "keep-alive",
136 Server: "cloudflare-nginx",
137 },
138 },
139 duration: 150.0,
140})
141
142// send a benchmark report up to the server
143client.send("bench.report", {
144 title: "My Fast Algorithmz",
145 steps: [
146 { title: "Step 1", time: 0 },
147 { title: "Step 2", time: 123 },
148 { title: "Step 3", time: 1024 },
149 ],
150})
151
152// a utility to time things
153const elapsed = client.startTimer()
154// do something you want to time
155const ms = elapsed() // the number of ms it took. ish.
156
157// display a custom event
158client.display({
159 name: "MY EVENT",
160 value: { color: "green", vegetable: "spinach", variant: "baby", salad: true },
161 important: true,
162 preview: "What's in my appetizer?",
163})
164```
165
166# Why are we passing createSocket down?
167
168# Messages
169
170### client.intro
171
172The client sends this message to the server when it first connects. It contains
173all the configuration information used to configure the client.
174
175For example:
176
177```js
178{
179 "host": "localhost", // the server we're connecting to
180 "port": 9090, // the server's port
181 "name": "My Fantastic App", // the name of our app
182 "userAgent": "Internet Explorer 3.0", // the user agent
183 "reactotronVersion": "0.99.1", // the version of reactotron
184 "environment": "development" // our environment
185}
186```
187
188### server.intro
189
190The client receives this message from the server once connected. It contains
191configuration information used by the server.
192
193Right now the payload is empty because I haven't even created the server!
194
195It'll probably have things like directory, version... I really don't know yet.
196
197```json
198{
199 "name": "I Am Server. Roar.",
200 "version": "0.99.1"
201}
202```
203
204### log
205
206The client sends this to the server to log a message, warning or error. For
207warnings and errors, we pass through an optional stackTrace array.
208
209Log:
210
211```json
212{
213 "value": "hello!",
214 "level": "debug"
215}
216```
217
218Warn:
219
220```json
221{
222 "value": "hello!",
223 "level": "warn",
224 "stackTrace": null
225}
226```
227
228Error:
229
230```json
231{
232 "value": "hello!",
233 "level": "error",
234 "stackTrace": [{ "lineNo": 1, "file": "foo.js" }]
235}
236```
237
238TBD: The actual stack trace format. I've seen a couple of formats unfortunately
239and I need to research what these will look like.
240
241Also, how is source maps going to factor in?
242
243### image
244
245Send from the client to the server to pass an image. The uri field is required
246and is a `data-uri`. This means, an ordinary http link will work, but as will embedding the image inline.
247
248```json
249{
250 "uri": "http://placekitten.com/g/400/400",
251 "preview": "placekitten.com!",
252 "filename": "cat.jpg",
253 "width": 400,
254 "height": 400,
255 "caption": "D'awwwwwww"
256}
257```
258
259### clear
260
261An instruction sent from the client to the server to clear the history on the server.
262
263### state.action.complete
264
265Sent from the client to the server when an action is complete. It's up to you
266to decide what an action is. For Redux, these are actions dispatched. For MobX,
267these are the results of `spy`.
268
269```json
270{
271 "name": "MY_ACTION",
272 "value": {}
273}
274```
275
276### state.action.dispatch
277
278Sent from the client to the server in order to dispatch this action through the
279state system.
280
281```json
282{
283 "action": { "type": "LOGIN_REQUEST", "password": "s3cr3t@g3ntm@n" }
284}
285```
286
287### state.values.request
288
289Sent from the server to the client to ask for the values of state.
290
291```json
292{
293 "path": "account"
294}
295```
296
297### state.values.response
298
299Sent from the client to the server in response to `state.values.request`.
300
301```json
302{
303 "path": "account",
304 "valid": true,
305 "value": {
306 "givenName": "Steve",
307 "familyName": "Kellock"
308 }
309}
310```
311
312### state.values.subscribe
313
314Sent from the server to the client to ask for notification when something
315in the state changes.
316
317```json
318{
319 "paths": ["account", "cart.total"]
320}
321```
322
323### state.values.change
324
325Sent from the client to the server when one of the subscriptions found in
326`state.values.subscribe` has changed.
327
328```json
329{
330 "changes": [
331 {
332 "path": "account",
333 "value": {
334 "email": "steve@kellock.ca"
335 }
336 },
337 {
338 "path": "cart.total",
339 "value": 100.01
340 }
341 ]
342}
343```
344
345### state.keys.request
346
347Sent from the server to the client to enumerate the keys inside state.
348
349```json
350{
351 "path": "account"
352}
353```
354
355### state.keys.response
356
357Sent from the client to server in response to `state.keys.request`.
358
359```json
360{
361 "path": "account",
362 "valid": true,
363 "keys": ["givenName", "familyName"]
364}
365```
366
367### api.response
368
369Sent from the client to server when an API has finished a request.
370
371```json
372{
373 "request": {
374 "url": "https://api.example.com/people/1",
375 "method": "PUT",
376 "data": {
377 "firstName": "Steve",
378 "lastName": "Kellock"
379 },
380 "headers": {
381 "Accept": "application/json",
382 "Cookie": "__ispy=mylittleye; __something=blue"
383 }
384 },
385 "response": {
386 "body": {},
387 "status": 200,
388 "headers": {
389 "Connection": "keep-alive",
390 "Server": "cloudflare-nginx"
391 }
392 },
393 "duration": 120.0
394}
395```
396
397### bench.report
398
399Sent from the client to server when it's time to report some performance details.
400
401```json
402{
403 "title": "My Sorting Algorithm",
404 "steps": [
405 { "title": "start", "time": 0 },
406 { "title": "lookup tables", "time": 123 },
407 { "title": "randomize", "time": 422 }
408 ]
409}
410```
411
412### display
413
414Sent from the client to the server to provide a way to show "custom" commands.
415
416```json
417{
418 "name": "MY EVENT",
419 "value": {
420 "color": "green",
421 "vegetable": "spinach",
422 "variant": "baby",
423 "salad": true
424 },
425 "image": {
426 "uri": "http://placekitten.com/g/400/400"
427 },
428 "important": true,
429 "preview": "What's in my appetizer?"
430}
431```
432
433# Plugins
434
435Reactotron is extensible via plugins. You add plugins by calling the `use`
436function on the the client.
437
438A plugin looks like this:
439
440```js
441export default () => (reactotron) => {}
442```
443
444- A function that:
445 - returns a function with 1 parameter (reactotron) that:
446 - returns an object
447
448### The 1st Function
449
450You use the first function to configure your plugin. If you don't have any
451configuration required for your plugin, just leave it empty like above.
452
453### The 2nd function
454
455The 2nd function gets called with the reactotron object. Among other things,
456it contains (most importantly) a function called `send()`.
457
458### The return object
459
460This contains hooks into reactotron. By naming the keys certain things, you're
461able to hook into guts to do stuff. Most importantly `onCommand` to receive
462events from the server and `features` to define extra functions on reactotron.
463
464```js
465// counter-plugin.js
466export default () => (reactotron) => {
467 let commandCounter = 0
468 return {
469 onCommand: (command) => {
470 commandCounter++
471 if (commandCounter === 69) console.log("tee hee")
472 },
473 }
474}
475```
476
477Here's what a plugin can do.
478
479```js
480{
481 // Fires whenever a command is received from the server.
482 //
483 // command is an object with:
484 // .type - String - the name of the command
485 // .payload - anything - maybe null, maybe a string, maybe an object, not a function
486 // its whatever the server sent.
487 onCommand: command => {
488 const { type, payload } = command
489 },
490
491 // Fires when we connect to the server. Will only be called if the plugin
492 // is setup before connecting to the server.
493 onConnect: () => {},
494
495 // Fires when we disconnect from the server.
496 onDisconnect: () => {},
497
498 // fires when the plugin is attached (this only happens once at initialization)
499 onPlugin: reactotron => console.log('I have been attached to ', reactotron),
500
501 // This is an object (not a function). The keys are strings. The values are functions.
502 // Every entry in here will become a method on the Reactotron client object.
503 // Collisions are handled on a first-come first-serve basis.
504 //
505 // These names are reserved:
506 // connect, configure, send, use, options, connected, plugins, and socket.
507 //
508 // Sorry.
509 //
510 // I went with this mixin approach because the interface feels nice from the
511 // calling code point-of-view.
512 features: {
513 // Reactotron.log('hello!')
514 log: (message) => send('log', { level: 'debug', message } ),
515
516 // Reactotron.warn('look out! falling rocks!')
517 warn: (message) => send('log', { level: 'warn', message } ),
518 }
519
520}
521```