@mblaney/holster 2.0.1 → 2.1.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/ts/src/holster.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  */
5
5
 
6
6
  import * as utils from "./utils.ts"
7
- import Wire, { type WireAPI } from "./wire.ts"
8
- import User, { type UserInterface } from "./user.ts"
7
+ import Wire, {type WireAPI} from "./wire.ts"
8
+ import User, {type UserInterface} from "./user.ts"
9
9
  import SEA from "./sea.ts"
10
10
  import type {
11
11
  HolsterOptions,
@@ -25,31 +25,41 @@ import type {
25
25
  */
26
26
  export interface HolsterAPI {
27
27
  get: {
28
- (key: string | null, lex?: LexWithDot, cb?: (data: unknown) => void, _opt?: WireOptions): HolsterAPI
29
28
  (
30
29
  key: string | null,
30
+ lex?: LexWithDot,
31
31
  cb?: (data: unknown) => void,
32
- _opt?: WireOptions
32
+ _opt?: WireOptions,
33
+ ): HolsterAPI
34
+ (
35
+ key: string | null,
36
+ cb?: (data: unknown) => void,
37
+ _opt?: WireOptions,
33
38
  ): HolsterAPI
34
39
  }
35
40
  next: {
36
- (key: string | null, lex?: LexWithDot, cb?: (data: unknown) => void, _opt?: WireOptions): HolsterAPI
37
41
  (
38
42
  key: string | null,
43
+ lex?: LexWithDot,
39
44
  cb?: (data: unknown) => void,
40
- _opt?: WireOptions
45
+ _opt?: WireOptions,
46
+ ): HolsterAPI
47
+ (
48
+ key: string | null,
49
+ cb?: (data: unknown) => void,
50
+ _opt?: WireOptions,
41
51
  ): HolsterAPI
42
52
  }
43
53
  put: (
44
54
  data: GraphValue | Record<string, GraphValue>,
45
55
  set?: boolean | ((data?: string | null) => void),
46
- cb?: (data?: string | null) => void
56
+ cb?: (data?: string | null) => void,
47
57
  ) => HolsterAPI | void
48
58
  on: (
49
59
  lex: LexWithDot | ((data: unknown) => void),
50
60
  cb?: ((data: unknown) => void) | boolean,
51
61
  _get?: boolean,
52
- _opt?: WireOptions
62
+ _opt?: WireOptions,
53
63
  ) => void
54
64
  off: (cb?: (data: unknown) => void) => HolsterAPI | void
55
65
  user: () => UserInterface & HolsterAPI
@@ -59,8 +69,8 @@ export interface HolsterAPI {
59
69
 
60
70
  const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
61
71
  let options: HolsterOptions
62
- if (typeof opt === "string") options = { peers: [opt] }
63
- else if (opt instanceof Array) options = { peers: opt }
72
+ if (typeof opt === "string") options = {peers: [opt]}
73
+ else if (opt instanceof Array) options = {peers: opt}
64
74
  else if (!utils.obj.is(opt)) options = {}
65
75
  else options = opt
66
76
 
@@ -81,7 +91,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
81
91
  }
82
92
 
83
93
  const check = (
84
- data: GraphValue | Record<string, GraphValue>
94
+ data: GraphValue | Record<string, GraphValue>,
85
95
  ): true | string | string[] => {
86
96
  if (ok(data as GraphValue)) return true
87
97
 
@@ -98,7 +108,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
98
108
  if (typeof value === "undefined") {
99
109
  return `error undefined ${key} cannot be converted to a graph`
100
110
  }
101
- const error = JSON.stringify({ [key]: value })
111
+ const error = JSON.stringify({[key]: value})
102
112
  return `error ${error} cannot be converted to a graph`
103
113
  }
104
114
  if (keys.length !== 0) return keys
@@ -113,44 +123,50 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
113
123
  lex: LexFilter,
114
124
  soul: string,
115
125
  ack: (data: unknown) => void,
116
- _opt?: WireOptions
126
+ _opt?: WireOptions,
117
127
  ): void => {
118
128
  wire.get(
119
129
  utils.obj.put(lex as never, "#", soul) as Lex,
120
130
  async msg => {
121
131
  if (msg.err) console.log(msg.err)
122
132
  if (msg.put && msg.put[soul]) {
123
- delete (msg.put[soul] as { _?: unknown })._
124
- delete (msg.put[soul] as Record<string, unknown>)[utils.userPublicKey]
125
- delete (msg.put[soul] as Record<string, unknown>)[utils.userSignature]
133
+ delete (msg.put[soul] as {_?: unknown})._
134
+ delete (msg.put[soul] as Record<string, unknown>)[
135
+ utils.userPublicKey
136
+ ]
137
+ delete (msg.put[soul] as Record<string, unknown>)[
138
+ utils.userSignature
139
+ ]
126
140
  const node = msg.put[soul]!
127
- await Promise.all(Object.keys(node).map(async key => {
128
- const id = utils.rel.is(node[key] as GraphValue)
129
- if (!id) return
130
- const attemptRead = async (retries = 0): Promise<unknown> => {
131
- const data = await new Promise<unknown>(res => {
132
- const _ctxid = utils.text.random()
133
- const ctx = allctx.get(ctxid!)
134
- allctx.set(_ctxid, {
135
- chain: [{ item: null, soul: id }],
136
- user: ctx ? ctx.user : null,
141
+ await Promise.all(
142
+ Object.keys(node).map(async key => {
143
+ const id = utils.rel.is(node[key] as GraphValue)
144
+ if (!id) return
145
+ const attemptRead = async (retries = 0): Promise<unknown> => {
146
+ const data = await new Promise<unknown>(res => {
147
+ const _ctxid = utils.text.random()
148
+ const ctx = allctx.get(ctxid!)
149
+ allctx.set(_ctxid, {
150
+ chain: [{item: null, soul: id}],
151
+ user: ctx ? ctx.user : null,
152
+ })
153
+ api(_ctxid).next(null as never, res as never, _opt)
137
154
  })
138
- api(_ctxid).next(null as never, res as never, _opt)
139
- })
140
- if (data !== null || retries >= 5) {
141
- return data
155
+ if (data !== null || retries >= 5) {
156
+ return data
157
+ }
158
+ await new Promise(resolve => setTimeout(resolve, 50))
159
+ return attemptRead(retries + 1)
142
160
  }
143
- await new Promise(resolve => setTimeout(resolve, 50))
144
- return attemptRead(retries + 1)
145
- }
146
- node[key] = (await attemptRead()) as GraphValue
147
- }))
161
+ node[key] = (await attemptRead()) as GraphValue
162
+ }),
163
+ )
148
164
  ack(msg.put[soul])
149
165
  } else {
150
166
  ack(null)
151
167
  }
152
168
  },
153
- _opt
169
+ _opt,
154
170
  )
155
171
  }
156
172
 
@@ -158,7 +174,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
158
174
  soul: string,
159
175
  data: Record<string, GraphValue>,
160
176
  userctx?: UserIdentity | null,
161
- cb?: (err?: string) => void
177
+ cb?: (err?: string) => void,
162
178
  ): Promise<Graph | null> => {
163
179
  if (userctx) {
164
180
  const timestamp = Date.now()
@@ -192,53 +208,68 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
192
208
  item: string,
193
209
  ctx: ApiContext,
194
210
  i: number,
195
- request: { on?: LexFilter; get?: LexFilter; _get?: boolean; _opt?: WireOptions },
211
+ request: {
212
+ on?: LexFilter
213
+ get?: LexFilter
214
+ _get?: boolean
215
+ _opt?: WireOptions
216
+ },
196
217
  cb: (data: unknown) => void,
197
- on = true
218
+ on = true,
198
219
  ): void => {
199
220
  let timer: ReturnType<typeof setTimeout> | null = null
200
221
  const handler = (): void => {
201
222
  // Bail out if the context was removed by off().
202
223
  if (!allctx.has(ctxid!)) {
203
- wire.off({ "#": soul, ".": item }, handler)
224
+ wire.off({"#": soul, ".": item}, handler)
204
225
  if (timer) clearTimeout(timer)
205
226
  return
206
227
  }
207
228
  wire.get(
208
- { "#": soul, ".": item },
229
+ {"#": soul, ".": item},
209
230
  msg => {
210
231
  const node = msg.put && msg.put[soul]
211
- const id = utils.rel.is(node && node[item] as GraphValue)
232
+ const id = utils.rel.is(node && (node[item] as GraphValue))
212
233
  if (!id) {
213
234
  // If it's a plain value (not a rel) and this is a get, deliver it.
214
235
  // node._ guards against timeout null-acks which lack metadata.
215
236
  if (!on && node && node._ && typeof node[item] !== "undefined") {
216
237
  if (timer) clearTimeout(timer)
217
- wire.off({ "#": soul, ".": item }, handler)
238
+ wire.off({"#": soul, ".": item}, handler)
218
239
  cb(node[item])
219
240
  }
220
241
  return
221
242
  }
222
243
  if (timer) clearTimeout(timer)
223
- wire.off({ "#": soul, ".": item }, handler)
244
+ wire.off({"#": soul, ".": item}, handler)
224
245
  ctx.chain[i]!.soul = id
225
- allctx.set(ctxid!, { ...ctx })
246
+ allctx.set(ctxid!, {...ctx})
226
247
  if (on) {
227
248
  api(ctxid).on(request.on!, cb, request._get, request._opt)
228
249
  } else {
229
- api(ctxid).next(null as never, request.get as never, cb as never, request._opt)
250
+ api(ctxid).next(
251
+ null as never,
252
+ request.get as never,
253
+ cb as never,
254
+ request._opt,
255
+ )
230
256
  }
231
257
  },
232
- { ...request._opt, secure: (typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) || options.secure }
258
+ {
259
+ ...request._opt,
260
+ secure:
261
+ (typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) ||
262
+ options.secure,
263
+ },
233
264
  )
234
265
  }
235
- wire.on({ "#": soul, ".": item }, handler, false, request._opt)
266
+ wire.on({"#": soul, ".": item}, handler, false, request._opt)
236
267
  // Time out after the same total duration as the on() retry loop
237
268
  // (1+2+4+8+16 = 31s) so callers are not blocked forever if the node
238
269
  // genuinely doesn't exist.
239
270
  if (!on) {
240
271
  timer = setTimeout(() => {
241
- wire.off({ "#": soul, ".": item }, handler)
272
+ wire.off({"#": soul, ".": item}, handler)
242
273
  if (cb) cb(null)
243
274
  }, 31000)
244
275
  }
@@ -253,7 +284,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
253
284
  _opt?: WireOptions
254
285
  _get?: boolean
255
286
  },
256
- cb?: (data: unknown) => void
287
+ cb?: (data: unknown) => void,
257
288
  ): ChainItem | false => {
258
289
  if (!request) {
259
290
  console.log("error resolve request parameter required")
@@ -277,9 +308,9 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
277
308
  if (found) {
278
309
  let i = 1
279
310
  while (i < ctx.chain.length && ctx.chain[i]!.soul !== null) i++
280
- const { item, soul } = ctx.chain[i - 1]!
311
+ const {item, soul} = ctx.chain[i - 1]!
281
312
  wire.get(
282
- { "#": soul!, ".": item! },
313
+ {"#": soul!, ".": item!},
283
314
  async msg => {
284
315
  if (msg.err) {
285
316
  console.log(`error getting ${item} on ${soul}: ${msg.err}`)
@@ -292,9 +323,14 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
292
323
  let id = utils.rel.is(node[item!] as GraphValue)
293
324
  if (id) {
294
325
  ctx.chain[i]!.soul = id
295
- allctx.set(ctxid!, { ...ctx })
326
+ allctx.set(ctxid!, {...ctx})
296
327
  if (get) {
297
- api(ctxid).next(null as never, request.get as never, cb as never, request._opt)
328
+ api(ctxid).next(
329
+ null as never,
330
+ request.get as never,
331
+ cb as never,
332
+ request._opt,
333
+ )
298
334
  } else if (put) {
299
335
  api(ctxid).put(request.put!, cb as never)
300
336
  } else if (on) {
@@ -307,12 +343,19 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
307
343
  } else if (put) {
308
344
  id = utils.text.random()
309
345
  node[item!] = utils.rel.ify(id)
310
- const g = await graph(soul!, node as never, ctx.user, cb as never)
346
+ const g = await graph(
347
+ soul!,
348
+ node as never,
349
+ ctx.user,
350
+ cb as never,
351
+ )
311
352
  if (g === null) return
312
353
 
313
354
  wire.put(g, err => {
314
355
  if (err) {
315
- (cb as (err: string) => void)(`error putting ${item} on ${soul}: ${err}`)
356
+ ;(cb as (err: string) => void)(
357
+ `error putting ${item} on ${soul}: ${err}`,
358
+ )
316
359
  return
317
360
  }
318
361
  if (id) {
@@ -337,7 +380,9 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
337
380
 
338
381
  wire.put(g, err => {
339
382
  if (err) {
340
- (cb as (err: string) => void)(`error putting ${item} on ${soul}: ${err}`)
383
+ ;(cb as (err: string) => void)(
384
+ `error putting ${item} on ${soul}: ${err}`,
385
+ )
341
386
  return
342
387
  }
343
388
  ctx.chain[i]!.soul = id
@@ -349,8 +394,16 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
349
394
  watchForRel(soul!, item!, ctx, i, request, cb!)
350
395
  if (request._get) cb!(null)
351
396
  } else if (get && node) {
352
- const sv = (node as Record<string, unknown> & {_?: {">": Record<string, unknown>}})._?.[">"]
353
- if (sv && Object.keys(sv).length > 0 && typeof sv[item!] === "undefined") {
397
+ const sv = (
398
+ node as Record<string, unknown> & {
399
+ _?: {">": Record<string, unknown>}
400
+ }
401
+ )._?.[">"]
402
+ if (
403
+ sv &&
404
+ Object.keys(sv).length > 0 &&
405
+ typeof sv[item!] === "undefined"
406
+ ) {
354
407
  // State vector has other properties but not this one — never written.
355
408
  if (cb) cb(null)
356
409
  } else {
@@ -363,14 +416,24 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
363
416
  }
364
417
  }
365
418
  },
366
- { ...request._opt, secure: (typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) || options.secure }
419
+ {
420
+ ...request._opt,
421
+ secure:
422
+ (typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) ||
423
+ options.secure,
424
+ },
367
425
  )
368
426
  return false
369
427
  }
370
428
 
371
429
  if (get && ctx.chain[ctx.chain.length - 1]!.item !== null) {
372
- ctx.chain.push({ item: null, soul: null })
373
- api(ctxid).next(null as never, request.get as never, cb as never, request._opt)
430
+ ctx.chain.push({item: null, soul: null})
431
+ api(ctxid).next(
432
+ null as never,
433
+ request.get as never,
434
+ cb as never,
435
+ request._opt,
436
+ )
374
437
  return false
375
438
  }
376
439
 
@@ -383,7 +446,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
383
446
  key: string | null,
384
447
  lex?: LexFilter | ((data: unknown) => void),
385
448
  cb?: ((data: unknown) => void) | WireOptions,
386
- _opt?: WireOptions
449
+ _opt?: WireOptions,
387
450
  ): HolsterAPI {
388
451
  let lexFilter: LexFilter | null | undefined
389
452
  let callback: ((data: unknown) => void) | undefined
@@ -412,13 +475,13 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
412
475
 
413
476
  ctxid = utils.text.random()
414
477
  allctx.set(ctxid, {
415
- chain: [{ item: String(key), soul: "root" }],
478
+ chain: [{item: String(key), soul: "root"}],
416
479
  cb: callback,
417
480
  })
418
481
  if (!callback) return api(ctxid)
419
482
 
420
483
  const _done = done(ctxid)
421
- const result = resolve({ get: lexFilter, _opt: opts }, _done)
484
+ const result = resolve({get: lexFilter, _opt: opts}, _done)
422
485
  if (result) get(lexFilter as never, result.soul!, _done, opts)
423
486
  return this
424
487
  } as HolsterAPI["get"],
@@ -428,7 +491,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
428
491
  key: string | null,
429
492
  lex?: LexFilter | ((data: unknown) => void),
430
493
  cb?: ((data: unknown) => void) | WireOptions,
431
- _opt?: WireOptions
494
+ _opt?: WireOptions,
432
495
  ): HolsterAPI {
433
496
  let lexFilter: LexFilter | null | undefined
434
497
  let callback: ((data: unknown) => void) | undefined
@@ -479,10 +542,10 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
479
542
  callback = undefined
480
543
  }
481
544
 
482
- if (key !== null) ctx.chain.push({ item: String(key), soul: null })
545
+ if (key !== null) ctx.chain.push({item: String(key), soul: null})
483
546
  if (!ctx.cb) return api(ctxid)
484
547
 
485
- const result = resolve({ get: lexFilter, _opt: opts }, _ack)
548
+ const result = resolve({get: lexFilter, _opt: opts}, _ack)
486
549
  if (result) get(lexFilter as never, result.soul!, _ack, opts)
487
550
  return this
488
551
  } as HolsterAPI["next"],
@@ -490,7 +553,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
490
553
  put: function (
491
554
  data: GraphValue | Record<string, GraphValue>,
492
555
  set?: boolean | ((data?: string | null) => void),
493
- cb?: (data?: string | null) => void
556
+ cb?: (data?: string | null) => void,
494
557
  ): HolsterAPI | void {
495
558
  let isSet = false
496
559
  let callback: ((data?: string | null) => void) | undefined
@@ -526,7 +589,8 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
526
589
  callback = undefined
527
590
  }
528
591
 
529
- if (isSet) data = { [utils.text.random()]: data } as Record<string, GraphValue>
592
+ if (isSet)
593
+ data = {[utils.text.random()]: data} as Record<string, GraphValue>
530
594
 
531
595
  const _ack = ack(ctxid)
532
596
  const result = check(data)
@@ -535,15 +599,15 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
535
599
  return
536
600
  }
537
601
 
538
- const resolved = resolve({ put: data, _opt: {put: true} }, _ack as never)
602
+ const resolved = resolve({put: data, _opt: {put: true}}, _ack as never)
539
603
  if (!resolved) return
540
604
 
541
- const { item, soul } = resolved
605
+ const {item, soul} = resolved
542
606
  if (!soul) return
543
607
 
544
608
  if (result === true) {
545
609
  wire.get(
546
- { "#": soul, ".": item! },
610
+ {"#": soul, ".": item!},
547
611
  async msg => {
548
612
  if (msg.err) {
549
613
  _ack(`error getting ${soul}: ${msg.err}`)
@@ -556,14 +620,19 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
556
620
  if (!id) {
557
621
  if (!node) node = {} as never
558
622
  node[item!] = (isSet ? data : data) as GraphValue
559
- const g = await graph(soul, node as never, ctx.user, _ack as never)
623
+ const g = await graph(
624
+ soul,
625
+ node as never,
626
+ ctx.user,
627
+ _ack as never,
628
+ )
560
629
  if (g === null) return
561
630
 
562
631
  wire.put(g, _ack as never)
563
632
  return
564
633
  }
565
634
 
566
- wire.get({ "#": id }, async msg => {
635
+ wire.get({"#": id}, async msg => {
567
636
  if (msg.err) {
568
637
  _ack(`error getting ${id}: ${msg.err}`)
569
638
  return
@@ -583,12 +652,14 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
583
652
  continue
584
653
  }
585
654
 
586
- const err = await new Promise<string | null | undefined>(res => {
587
- const _ctxid = utils.text.random()
588
- const chain: ChainItem[] = [{ item: key, soul: id }]
589
- allctx.set(_ctxid, { chain: chain, user: ctx.user })
590
- api(_ctxid).put(null!, res as never)
591
- })
655
+ const err = await new Promise<string | null | undefined>(
656
+ res => {
657
+ const _ctxid = utils.text.random()
658
+ const chain: ChainItem[] = [{item: key, soul: id}]
659
+ allctx.set(_ctxid, {chain: chain, user: ctx.user})
660
+ api(_ctxid).put(null!, res as never)
661
+ },
662
+ )
592
663
  if (err) {
593
664
  _ack(err)
594
665
  return
@@ -596,20 +667,30 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
596
667
  }
597
668
  if (!node) node = {} as never
598
669
  node[item!] = data as GraphValue
599
- const g = await graph(soul, node as never, ctx.user, _ack as never)
670
+ const g = await graph(
671
+ soul,
672
+ node as never,
673
+ ctx.user,
674
+ _ack as never,
675
+ )
600
676
  if (g === null) return
601
677
 
602
678
  wire.put(g, _ack as never)
603
679
  })
604
680
  },
605
- { secure: (typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) || options.secure, put: true }
681
+ {
682
+ secure:
683
+ (typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) ||
684
+ options.secure,
685
+ put: true,
686
+ },
606
687
  )
607
688
  return
608
689
  }
609
690
 
610
691
  const attemptRead = (retries = 0): void => {
611
692
  wire.get(
612
- { "#": soul, ".": item! },
693
+ {"#": soul, ".": item!},
613
694
  async msg => {
614
695
  if (msg.err) {
615
696
  _ack(`error getting ${soul}.${item}: ${msg.err}`)
@@ -628,7 +709,12 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
628
709
  if (!id) {
629
710
  if (!node) node = {} as never
630
711
  node[item!] = utils.rel.ify(utils.text.random())
631
- const g = await graph(soul, node as never, ctx.user, _ack as never)
712
+ const g = await graph(
713
+ soul,
714
+ node as never,
715
+ ctx.user,
716
+ _ack as never,
717
+ )
632
718
  if (g === null) return
633
719
 
634
720
  wire.put(g, err => {
@@ -636,7 +722,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
636
722
  _ack(`error putting ${item} on ${soul}: ${err}`)
637
723
  } else {
638
724
  const _ctxid = utils.text.random()
639
- const chain: ChainItem[] = [{ item: item!, soul: soul }]
725
+ const chain: ChainItem[] = [{item: item!, soul: soul}]
640
726
  allctx.set(_ctxid, {
641
727
  chain: chain,
642
728
  user: ctx.user,
@@ -650,20 +736,25 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
650
736
 
651
737
  const update: string[] = []
652
738
  for (const key of result as string[]) {
653
- const err = await new Promise<string | null | undefined>(res => {
654
- if (
655
- utils.obj.is((data as Record<string, unknown>)[key]) &&
656
- !utils.rel.is((data as Record<string, GraphValue>)[key])
657
- ) {
658
- const _ctxid = utils.text.random()
659
- const chain: ChainItem[] = [{ item: key, soul: id }]
660
- allctx.set(_ctxid, { chain: chain, user: ctx.user })
661
- api(_ctxid).put((data as Record<string, GraphValue>)[key]!, res as never)
662
- } else {
663
- update.push(key)
664
- res(null)
665
- }
666
- })
739
+ const err = await new Promise<string | null | undefined>(
740
+ res => {
741
+ if (
742
+ utils.obj.is((data as Record<string, unknown>)[key]) &&
743
+ !utils.rel.is((data as Record<string, GraphValue>)[key])
744
+ ) {
745
+ const _ctxid = utils.text.random()
746
+ const chain: ChainItem[] = [{item: key, soul: id}]
747
+ allctx.set(_ctxid, {chain: chain, user: ctx.user})
748
+ api(_ctxid).put(
749
+ (data as Record<string, GraphValue>)[key]!,
750
+ res as never,
751
+ )
752
+ } else {
753
+ update.push(key)
754
+ res(null)
755
+ }
756
+ },
757
+ )
667
758
  if (err) {
668
759
  _ack(err)
669
760
  return
@@ -681,12 +772,22 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
681
772
  update.forEach(key => {
682
773
  updateNode[key] = (data as Record<string, GraphValue>)[key]!
683
774
  })
684
- const g = await graph(id, updateNode as never, ctx.user, _ack as never)
775
+ const g = await graph(
776
+ id,
777
+ updateNode as never,
778
+ ctx.user,
779
+ _ack as never,
780
+ )
685
781
  if (g === null) return
686
782
 
687
783
  wire.put(g, _ack as never)
688
784
  },
689
- { secure: (typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) || options.secure, put: true }
785
+ {
786
+ secure:
787
+ (typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) ||
788
+ options.secure,
789
+ put: true,
790
+ },
690
791
  )
691
792
  }
692
793
  attemptRead()
@@ -696,7 +797,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
696
797
  lex: LexWithDot | ((data: unknown) => void),
697
798
  cb?: ((data: unknown) => void) | boolean,
698
799
  _get?: boolean,
699
- _opt?: WireOptions
800
+ _opt?: WireOptions,
700
801
  ): void {
701
802
  let lexFilter: LexFilter | undefined
702
803
  let callback: (data: unknown) => void
@@ -724,16 +825,19 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
724
825
  return
725
826
  }
726
827
 
727
- const resolved = resolve({ on: lexFilter, _get: _get, _opt: opts }, callback)
828
+ const resolved = resolve(
829
+ {on: lexFilter, _get: _get, _opt: opts},
830
+ callback,
831
+ )
728
832
  if (!resolved) return
729
833
 
730
- const { item, soul } = resolved
834
+ const {item, soul} = resolved
731
835
  if (!soul) return
732
836
 
733
837
  const ctx = allctx.get(ctxid)
734
838
 
735
839
  allctx.set(ctxid, {
736
- chain: [{ item: item, soul: soul }],
840
+ chain: [{item: item, soul: soul}],
737
841
  on: true,
738
842
  user: ctx ? ctx.user : null,
739
843
  })
@@ -755,7 +859,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
755
859
  clearTimeout(retryTimer!)
756
860
  retryTimer = null
757
861
  wire.get(
758
- { "#": soul, ".": item! },
862
+ {"#": soul, ".": item!},
759
863
  msg => {
760
864
  const node = msg.put && msg.put[soul]
761
865
  const current = node && node[item!]
@@ -765,10 +869,16 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
765
869
  const data = await new Promise<unknown>(res => {
766
870
  const _ctxid = utils.text.random()
767
871
  allctx.set(_ctxid, {
768
- chain: [{ item: null, soul: id }],
872
+ chain: [{item: null, soul: id}],
769
873
  user: ctx ? ctx.user : null,
770
874
  })
771
- api(_ctxid).next(null as never, res as never, (retries === 0 ? utils.obj.put(opts, "fast", true) : opts) as never)
875
+ api(_ctxid).next(
876
+ null as never,
877
+ res as never,
878
+ (retries === 0
879
+ ? utils.obj.put(opts, "fast", true)
880
+ : opts) as never,
881
+ )
772
882
  })
773
883
  if (data !== null || retries >= 5) {
774
884
  retryCount = 0
@@ -789,20 +899,32 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
789
899
  // exhaust retries. on() with _get can return null on a cache
790
900
  // miss and never fire again if the data doesn't change while
791
901
  // the listener is attached, so we must poll for initial load.
792
- const secureOpt = { ...opts, secure: ctx ? ((typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) || options.secure) : options.secure }
902
+ const secureOpt = {
903
+ ...opts,
904
+ secure: ctx
905
+ ? (typeof ctx.user === "boolean"
906
+ ? ctx.user
907
+ : !!ctx.user) || options.secure
908
+ : options.secure,
909
+ }
793
910
  const retry = (): void => {
794
- const delay = Math.min(retryDelay * Math.pow(2, retryCount), 30000)
911
+ const delay = Math.min(
912
+ retryDelay * Math.pow(2, retryCount),
913
+ 30000,
914
+ )
795
915
  retryCount++
796
916
  retryTimer = setTimeout(() => {
797
917
  wire.get(
798
- { "#": soul, ".": item! },
918
+ {"#": soul, ".": item!},
799
919
  retryMsg => {
800
920
  const retryNode = retryMsg.put && retryMsg.put[soul]
801
921
  if (retryNode) {
802
922
  retryCount = 0
803
923
  retryTimer = null
804
924
  const retryValue = retryNode[item!]
805
- callback(retryValue !== undefined ? retryValue : null)
925
+ callback(
926
+ retryValue !== undefined ? retryValue : null,
927
+ )
806
928
  } else if (retryCount < maxRetries) {
807
929
  retry()
808
930
  } else {
@@ -820,20 +942,29 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
820
942
  }
821
943
  }
822
944
  },
823
- { ...opts, secure: ctx ? ((typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) || options.secure) : options.secure }
945
+ {
946
+ ...opts,
947
+ secure: ctx
948
+ ? (typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) ||
949
+ options.secure
950
+ : options.secure,
951
+ },
824
952
  )
825
953
  })
826
954
 
827
- let initialLex: { "#": string; "."?: string | number } = lexFilter
828
- ? (utils.obj.put(lexFilter as never, "#", soul) as { "#": string; "."?: string | number })
829
- : { "#": soul, ".": item! }
955
+ let initialLex: {"#": string; "."?: string | number} = lexFilter
956
+ ? (utils.obj.put(lexFilter as never, "#", soul) as {
957
+ "#": string
958
+ "."?: string | number
959
+ })
960
+ : {"#": soul, ".": item!}
830
961
  if (initialLex["."] != null && typeof initialLex["."] === "number") {
831
- initialLex = { ...initialLex, ".": String(initialLex["."]) }
962
+ initialLex = {...initialLex, ".": String(initialLex["."])}
832
963
  }
833
964
  wire.on(initialLex as never, map.get(callback)!, false, opts)
834
965
 
835
966
  wire.get(
836
- { "#": soul, ".": item! },
967
+ {"#": soul, ".": item!},
837
968
  msg => {
838
969
  if (msg.err) {
839
970
  console.log(`error getting ${soul}.${item}: ${msg.err}`)
@@ -844,14 +975,25 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
844
975
  const id = utils.rel.is(current as GraphValue)
845
976
  if (id) {
846
977
  wire.off(initialLex as never, map.get(callback)!)
847
- wire.on({ "#": id, ".": null } as never, map.get(callback)!, false, opts)
978
+ wire.on(
979
+ {"#": id, ".": null} as never,
980
+ map.get(callback)!,
981
+ false,
982
+ opts,
983
+ )
848
984
  if (_get) map.get(callback)!()
849
985
  } else if (_get) {
850
986
  // Not a rel, but _get was requested, so trigger callback.
851
987
  map.get(callback)!()
852
988
  }
853
989
  },
854
- { ...opts, secure: ctx ? ((typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) || options.secure) : options.secure }
990
+ {
991
+ ...opts,
992
+ secure: ctx
993
+ ? (typeof ctx.user === "boolean" ? ctx.user : !!ctx.user) ||
994
+ options.secure
995
+ : options.secure,
996
+ },
855
997
  )
856
998
  },
857
999
 
@@ -862,15 +1004,15 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
862
1004
  return
863
1005
  }
864
1006
 
865
- const resolved = resolve({ off: true }, cb)
1007
+ const resolved = resolve({off: true}, cb)
866
1008
  if (!resolved) return
867
1009
 
868
- const { item, soul } = resolved
1010
+ const {item, soul} = resolved
869
1011
  if (!soul) return
870
1012
 
871
- wire.off({ "#": soul } as never, map.get(cb!)!)
1013
+ wire.off({"#": soul} as never, map.get(cb!)!)
872
1014
 
873
- wire.get({ "#": soul, ".": item! }, msg => {
1015
+ wire.get({"#": soul, ".": item!}, msg => {
874
1016
  if (msg.err) {
875
1017
  map.delete(cb!)
876
1018
  allctx.delete(ctxid!)
@@ -879,21 +1021,21 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
879
1021
 
880
1022
  const current = msg.put && msg.put[soul] && msg.put[soul]![item!]
881
1023
  const id = utils.rel.is(current as GraphValue)
882
- if (id) wire.off({ "#": id } as never, map.get(cb!)!)
1024
+ if (id) wire.off({"#": id} as never, map.get(cb!)!)
883
1025
  map.delete(cb!)
884
1026
  allctx.delete(ctxid!)
885
1027
  })
886
1028
  },
887
1029
 
888
1030
  user: () => {
889
- if (!(user as { get?: unknown }).get) {
1031
+ if (!(user as {get?: unknown}).get) {
890
1032
  Object.assign(user, api())
891
1033
  ;(user as UserInterface & HolsterAPI).get = function (
892
1034
  this: HolsterAPI,
893
1035
  keys: string | string[],
894
1036
  lex?: LexFilter | ((data: unknown) => void),
895
1037
  cb?: ((data: unknown) => void) | WireOptions,
896
- _opt?: WireOptions
1038
+ _opt?: WireOptions,
897
1039
  ): HolsterAPI {
898
1040
  let lexFilter: LexFilter | null | undefined
899
1041
  let callback: ((data: unknown) => void) | undefined
@@ -940,12 +1082,16 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
940
1082
  }
941
1083
 
942
1084
  ctxid = utils.text.random()
943
- const chain: ChainItem[] = [{ item: String(key), soul: "~" + pub }]
944
- allctx.set(ctxid, { chain: chain, user: user.is, cb: callback as never })
1085
+ const chain: ChainItem[] = [{item: String(key), soul: "~" + pub}]
1086
+ allctx.set(ctxid, {
1087
+ chain: chain,
1088
+ user: user.is,
1089
+ cb: callback as never,
1090
+ })
945
1091
  if (!callback) return api(ctxid)
946
1092
 
947
1093
  const _done = done(ctxid)
948
- const resolved = resolve({ get: lexFilter, _opt: opts }, _done)
1094
+ const resolved = resolve({get: lexFilter, _opt: opts}, _done)
949
1095
  if (resolved) get(lexFilter as never, resolved.soul!, _done, opts)
950
1096
  return this
951
1097
  } as never
@@ -961,4 +1107,3 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
961
1107
  }
962
1108
 
963
1109
  export default Holster
964
-