1
+ /**
2
+ * Implementation of smuggler APIs like @see StorageApi which interact with a
3
+ * cloud-hosted infrastructure to perform their job.
4
+ */
5
+
1
6
import {
2
7
AccountInfo ,
3
8
Ack ,
@@ -7,18 +12,14 @@ import {
7
12
GenerateBlobIndexResponse ,
8
13
GetUserExternalAssociationsResponse ,
9
14
NewNodeResponse ,
10
- Nid ,
11
15
NodeAttrsSearchRequest ,
12
16
NodeAttrsSearchResponse ,
13
17
NodeBatch ,
14
18
NodeCreateRequestBody ,
15
19
NodeCreatedVia ,
16
20
NodeEdges ,
17
- NodeExtattrs ,
18
- NodeIndexText ,
19
21
NodePatchRequest ,
20
22
NodeTextData ,
21
- NodeType ,
22
23
OriginId ,
23
24
TEdge ,
24
25
TNode ,
@@ -29,7 +30,17 @@ import {
29
30
UserExternalPipelineId ,
30
31
UserExternalPipelineIngestionProgress ,
31
32
} from './types'
32
-
33
+ import type {
34
+ UniqueNodeLookupKey ,
35
+ NonUniqueNodeLookupKey ,
36
+ NodeLookupKey ,
37
+ CreateNodeArgs ,
38
+ GetNodeSliceArgs ,
39
+ NodeBatchRequestBody ,
40
+ CreateEdgeArgs ,
41
+ StorageApi ,
42
+ BlobUploadRequestArgs ,
43
+ } from './storage_api'
33
44
import { makeUrl } from './api_url'
34
45
35
46
import { TNodeSliceIterator , GetNodesSliceFn } from './node_slice_iterator'
@@ -43,36 +54,11 @@ import moment from 'moment'
43
54
import { StatusCode } from './status_codes'
44
55
import { authCookie } from './auth/cookie'
45
56
import { makeEmptyNodeTextData , NodeUtil } from './typesutil'
57
+ import { AuthenticationApi } from './authentication_api'
46
58
47
59
const kHeaderCreatedAt = 'x-created-at'
48
60
const kHeaderLastModified = 'last-modified'
49
61
50
- /**
51
- * Unique lookup keys that can match at most 1 node
52
- */
53
- export type UniqueNodeLookupKey =
54
- /** Due to nid's nature there can be at most 1 node with a particular nid */
55
- | { nid : string }
56
- /** Unique because many nodes can refer to the same URL, but only one of them
57
- * can be a bookmark */
58
- | { webBookmark : { url : string } }
59
-
60
- export type NonUniqueNodeLookupKey =
61
- /** Can match more than 1 node because multiple parts of a single web page
62
- * can be quoted */
63
- | { webQuote : { url : string } }
64
- /** Can match more than 1 node because many nodes can refer to
65
- * the same URL:
66
- * - 0 or 1 can be @see NoteType.Url
67
- * - AND at the same time more than 1 can be @see NodeType.WebQuote */
68
- | { url : string }
69
-
70
- /**
71
- * All the different types of keys that can be used to identify (during lookup,
72
- * for example) one or more nodes.
73
- */
74
- export type NodeLookupKey = UniqueNodeLookupKey | NonUniqueNodeLookupKey
75
-
76
62
export function isUniqueLookupKey (
77
63
key : NodeLookupKey
78
64
) : key is UniqueNodeLookupKey {
@@ -82,18 +68,6 @@ export function isUniqueLookupKey(
82
68
return false
83
69
}
84
70
85
- export type CreateNodeArgs = {
86
- text : NodeTextData
87
- from_nid ?: string [ ]
88
- to_nid ?: string [ ]
89
- index_text ?: NodeIndexText
90
- extattrs ?: NodeExtattrs
91
- ntype ?: NodeType
92
- origin ?: OriginId
93
- created_via ?: NodeCreatedVia
94
- created_at ?: Date
95
- }
96
-
97
71
async function createNode (
98
72
{
99
73
text,
@@ -174,19 +148,13 @@ async function createOrUpdateNode(
174
148
)
175
149
}
176
150
177
- const updateArgs : UpdateNodeArgs = {
178
- nid : existingNode . nid ,
151
+ const patch : NodePatchRequest = {
179
152
text : args . text ,
180
153
index_text : args . index_text ,
181
154
}
182
155
183
- const resp = await updateNode ( updateArgs , signal )
184
- if ( ! resp . ok ) {
185
- throw _makeResponseError ( resp , `Failed to update node ${ existingNode . nid } ` )
186
- }
187
- return {
188
- nid : existingNode . nid ,
189
- }
156
+ await updateNode ( { nid : existingNode . nid , ...patch } , signal )
157
+ return { nid : existingNode . nid }
190
158
}
191
159
192
160
/**
@@ -247,10 +215,6 @@ function describeWhatWouldPreventNodeUpdate(args: CreateNodeArgs, node: TNode) {
247
215
return `[what] - [attempted update arg] vs [existing node value]: ${ diff } `
248
216
}
249
217
250
- /**
251
- * Lookup all the nodes that match a given key. For unique lookup keys either
252
- * 0 or 1 nodes will be returned. For non-unique more than 1 node can be returned.
253
- */
254
218
async function lookupNodes (
255
219
key : UniqueNodeLookupKey ,
256
220
signal ?: AbortSignal
@@ -314,10 +278,7 @@ async function lookupNodes(key: NodeLookupKey, signal?: AbortSignal) {
314
278
}
315
279
316
280
async function uploadFiles (
317
- files : File [ ] ,
318
- from_nid : Optional < string > ,
319
- to_nid : Optional < string > ,
320
- createdVia : NodeCreatedVia ,
281
+ { files, from_nid, to_nid, createdVia } : BlobUploadRequestArgs ,
321
282
signal ?: AbortSignal
322
283
) : Promise < UploadMultipartResponse > {
323
284
const query : UploadMultipartQuery = { created_via : createdVia }
@@ -358,7 +319,7 @@ async function buildFilesSearchIndex(
358
319
return await resp . json ( )
359
320
}
360
321
361
- function mimeTypeIsSupportedByBuildIndex ( mimeType : MimeType ) {
322
+ function mimeTypeIsSupportedByBuildIndex ( mimeType : MimeType ) : boolean {
362
323
return Mime . isImage ( mimeType )
363
324
}
364
325
@@ -445,12 +406,8 @@ async function getNode({
445
406
return node
446
407
}
447
408
448
- type NodePatchRequestBody = {
449
- nids : Nid [ ]
450
- }
451
-
452
409
async function getNodeBatch (
453
- req : NodePatchRequestBody ,
410
+ req : NodeBatchRequestBody ,
454
411
signal ?: AbortSignal
455
412
) : Promise < NodeBatch > {
456
413
const res = await fetch ( makeUrl ( `/node-batch-get` ) , {
@@ -468,14 +425,10 @@ async function getNodeBatch(
468
425
}
469
426
}
470
427
471
- type UpdateNodeArgs = {
472
- nid : string
473
- text ?: NodeTextData
474
- index_text ?: NodeIndexText
475
- preserve_update_time ?: boolean
476
- }
477
-
478
- async function updateNode ( args : UpdateNodeArgs , signal ?: AbortSignal ) {
428
+ async function updateNode (
429
+ args : { nid : string } & NodePatchRequest ,
430
+ signal ?: AbortSignal
431
+ ) : Promise < Ack > {
479
432
const { nid, text, index_text, preserve_update_time } = args
480
433
const headers = {
481
434
'Content-type' : MimeType . JSON ,
@@ -485,12 +438,16 @@ async function updateNode(args: UpdateNodeArgs, signal?: AbortSignal) {
485
438
index_text,
486
439
preserve_update_time,
487
440
}
488
- return fetch ( makeUrl ( `/node/${ nid } ` ) , {
441
+ const resp = await fetch ( makeUrl ( `/node/${ nid } ` ) , {
489
442
method : 'PATCH' ,
490
443
body : JSON . stringify ( request ) ,
491
444
headers,
492
445
signal,
493
446
} )
447
+ if ( resp . ok ) {
448
+ return await resp . json ( )
449
+ }
450
+ throw _makeResponseError ( resp )
494
451
}
495
452
496
453
async function getAuth ( {
@@ -508,7 +465,7 @@ async function getAuth({
508
465
return await resp . json ( )
509
466
}
510
467
511
- export const getNodesSlice : GetNodesSliceFn = async ( {
468
+ const getNodesSlice : GetNodesSliceFn = async ( {
512
469
end_time,
513
470
start_time,
514
471
offset,
@@ -575,13 +532,7 @@ function _getNodesSliceIter({
575
532
limit,
576
533
origin,
577
534
bucket_time_size,
578
- } : {
579
- end_time ?: number
580
- start_time ?: number
581
- limit ?: number
582
- origin ?: OriginId
583
- bucket_time_size ?: number
584
- } ) {
535
+ } : GetNodeSliceArgs ) {
585
536
return new TNodeSliceIterator (
586
537
getNodesSlice ,
587
538
start_time ,
@@ -596,11 +547,7 @@ async function createEdge({
596
547
from,
597
548
to,
598
549
signal,
599
- } : {
600
- from ?: string
601
- to ?: string
602
- signal : AbortSignal
603
- } ) : Promise < TEdge > {
550
+ } : CreateEdgeArgs ) : Promise < TEdge > {
604
551
verifyIsNotNull ( from )
605
552
verifyIsNotNull ( to )
606
553
const req = {
@@ -644,14 +591,14 @@ async function getNodeAllEdges(
644
591
645
592
async function switchEdgeStickiness ( {
646
593
eid,
647
- signal,
648
594
on,
649
595
off,
596
+ signal,
650
597
} : {
651
598
eid : string
652
- signal : AbortSignal
653
599
on : Optional < boolean >
654
600
off : Optional < boolean >
601
+ signal : AbortSignal
655
602
} ) : Promise < Ack > {
656
603
verifyIsNotNull ( eid )
657
604
const req = {
@@ -704,7 +651,7 @@ async function createSession(
704
651
password : string ,
705
652
permissions : number | null ,
706
653
signal ?: AbortSignal
707
- ) {
654
+ ) : Promise < { } > {
708
655
verifyIsNotNull ( email )
709
656
verifyIsNotNull ( password )
710
657
verifyIsNotNull ( signal )
@@ -909,7 +856,7 @@ async function passwordChange(
909
856
old_password : string ,
910
857
new_password : string ,
911
858
signal ?: AbortSignal
912
- ) {
859
+ ) : Promise < Ack > {
913
860
const value = { old_password, new_password }
914
861
const resp = await fetch ( makeUrl ( '/auth/password-recover/change' ) , {
915
862
method : 'POST' ,
@@ -1010,7 +957,7 @@ function _makeResponseError(response: Response, message?: string): Error {
1010
957
} )
1011
958
}
1012
959
1013
- export const smuggler = {
960
+ export const smuggler : StorageApi & AuthenticationApi = {
1014
961
getAuth,
1015
962
node : {
1016
963
get : getNode ,
@@ -1035,16 +982,6 @@ export const smuggler = {
1035
982
} ,
1036
983
blob_index : {
1037
984
build : buildFilesSearchIndex ,
1038
- /** 'cfg' section is intended to expose properties of one of smuggler's
1039
- * endpoints *without using network*. This information is unlikely to change
1040
- * during application runtime which makes repeated network usage wasteful.
1041
- *
1042
- * It may be tempting to bake them into respective endpoint methods directly
1043
- * (e.g. into 'blob_index.build'), but that is intentionally avoided to
1044
- * keep a clearer boundary between raw REST endpoints and helper functionality.
1045
- *
1046
- * Similar sections may become useful for other endpoints
1047
- */
1048
985
cfg : {
1049
986
supportsMime : mimeTypeIsSupportedByBuildIndex ,
1050
987
} ,
0 commit comments