@graphty/graph-io 0.3.46 → 0.3.48

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.
Files changed (460) hide show
  1. package/dist/chunks/{approximations-wWjCRzKj.js → approximations-C2riR4NT.js} +2 -2
  2. package/dist/chunks/{approximations-wWjCRzKj.js.map → approximations-C2riR4NT.js.map} +1 -1
  3. package/dist/chunks/{block-DiGq58c3.js → block-Cu22ewuS.js} +92 -21
  4. package/dist/chunks/block-Cu22ewuS.js.map +1 -0
  5. package/dist/chunks/{choose--jM0yYCo.js → choose-Cdx6Enl2.js} +3 -3
  6. package/dist/chunks/{choose--jM0yYCo.js.map → choose-Cdx6Enl2.js.map} +1 -1
  7. package/dist/chunks/codes-CV_Bhcyi.js +153 -0
  8. package/dist/chunks/codes-CV_Bhcyi.js.map +1 -0
  9. package/dist/chunks/{constants-BKwqelYD.js → constants-D0LqcsLJ.js} +2 -2
  10. package/dist/chunks/{constants-BKwqelYD.js.map → constants-D0LqcsLJ.js.map} +1 -1
  11. package/dist/chunks/context-cgmmOxZ2.js +663 -0
  12. package/dist/chunks/context-cgmmOxZ2.js.map +1 -0
  13. package/dist/chunks/credentials-BiQsnMTb.js +347 -0
  14. package/dist/chunks/credentials-BiQsnMTb.js.map +1 -0
  15. package/dist/chunks/cx-export-BEeF6ymo.js +259 -0
  16. package/dist/chunks/cx-export-BEeF6ymo.js.map +1 -0
  17. package/dist/chunks/descriptor-BJ-W0Jd-.js +137 -0
  18. package/dist/chunks/descriptor-BJ-W0Jd-.js.map +1 -0
  19. package/dist/chunks/descriptor-C-YDhtsn.js +48 -0
  20. package/dist/chunks/descriptor-C-YDhtsn.js.map +1 -0
  21. package/dist/chunks/{emit-CwU8cUmG.js → emit-CD8xnY8s.js} +70 -10
  22. package/dist/chunks/emit-CD8xnY8s.js.map +1 -0
  23. package/dist/chunks/{escape-CgzxiYPg.js → escape-DH2Egt-l.js} +12 -12
  24. package/dist/chunks/{escape-CgzxiYPg.js.map → escape-DH2Egt-l.js.map} +1 -1
  25. package/dist/chunks/{export-BvqAXCKh.js → export-CZ7VRm4I.js} +53 -1443
  26. package/dist/chunks/export-CZ7VRm4I.js.map +1 -0
  27. package/dist/chunks/{exporter-DndFlGSa.js → exporter-BIdaoIgh.js} +7 -6
  28. package/dist/chunks/{exporter-DndFlGSa.js.map → exporter-BIdaoIgh.js.map} +1 -1
  29. package/dist/chunks/{exporter-CJgfhF-l.js → exporter-ChjL5fmP.js} +8 -7
  30. package/dist/chunks/{exporter-CJgfhF-l.js.map → exporter-ChjL5fmP.js.map} +1 -1
  31. package/dist/chunks/{exporter--Mk9gXCJ.js → exporter-Dcw7Ldtq.js} +6 -4
  32. package/dist/chunks/{exporter--Mk9gXCJ.js.map → exporter-Dcw7Ldtq.js.map} +1 -1
  33. package/dist/chunks/exporter-DtVU80Fa.js +1008 -0
  34. package/dist/chunks/exporter-DtVU80Fa.js.map +1 -0
  35. package/dist/chunks/{exporter-CrDWIyiq.js → exporter-bxxjOrDZ.js} +11 -9
  36. package/dist/chunks/{exporter-CrDWIyiq.js.map → exporter-bxxjOrDZ.js.map} +1 -1
  37. package/dist/chunks/format-BMS-1Nxb.js +64 -0
  38. package/dist/chunks/format-BMS-1Nxb.js.map +1 -0
  39. package/dist/chunks/{generic-Dq1ntt9q.js → generic-CP6YD34u.js} +4 -4
  40. package/dist/chunks/{generic-Dq1ntt9q.js.map → generic-CP6YD34u.js.map} +1 -1
  41. package/dist/chunks/{importer-DiZRmOQG.js → importer-B87_fmVx.js} +13 -17
  42. package/dist/chunks/importer-B87_fmVx.js.map +1 -0
  43. package/dist/chunks/{importer-BSvfrX_h.js → importer-Bji2MeWr.js} +18 -1014
  44. package/dist/chunks/importer-Bji2MeWr.js.map +1 -0
  45. package/dist/chunks/{importer-COTK9Tsl.js → importer-CB_zV5_L.js} +14 -11
  46. package/dist/chunks/importer-CB_zV5_L.js.map +1 -0
  47. package/dist/chunks/{importer-e6LGpqHB.js → importer-CVT-JyDE.js} +12 -9
  48. package/dist/chunks/importer-CVT-JyDE.js.map +1 -0
  49. package/dist/chunks/{importer-yh_aBCU6.js → importer-Cyy6UseH.js} +7 -6
  50. package/dist/chunks/{importer-yh_aBCU6.js.map → importer-Cyy6UseH.js.map} +1 -1
  51. package/dist/chunks/{importer-iFYPEKaJ.js → importer-DPZDN40-.js} +14 -10
  52. package/dist/chunks/{importer-iFYPEKaJ.js.map → importer-DPZDN40-.js.map} +1 -1
  53. package/dist/chunks/{importer-CMmeMWlC.js → importer-e3huMZbm.js} +8 -260
  54. package/dist/chunks/importer-e3huMZbm.js.map +1 -0
  55. package/dist/chunks/input-Ccg9I22A.js +1397 -0
  56. package/dist/chunks/input-Ccg9I22A.js.map +1 -0
  57. package/dist/chunks/{json-elements-DJZRZ6jd.js → json-elements-By172SVq.js} +4 -4
  58. package/dist/chunks/{json-elements-DJZRZ6jd.js.map → json-elements-By172SVq.js.map} +1 -1
  59. package/dist/chunks/{lexicon-CT69Kd87.js → lexicon-u2SI5xcx.js} +19 -5
  60. package/dist/chunks/lexicon-u2SI5xcx.js.map +1 -0
  61. package/dist/chunks/{ontology-export-G4MqRdux.js → ontology-export-BwgMyuF0.js} +4 -3
  62. package/dist/chunks/{ontology-export-G4MqRdux.js.map → ontology-export-BwgMyuF0.js.map} +1 -1
  63. package/dist/chunks/{records-CiaWZrFH.js → records-Cgvxz-Vx.js} +2 -2
  64. package/dist/chunks/{records-CiaWZrFH.js.map → records-Cgvxz-Vx.js.map} +1 -1
  65. package/dist/chunks/{format-BpQBx8MZ.js → report-CgdsL9Hb.js} +72 -129
  66. package/dist/chunks/report-CgdsL9Hb.js.map +1 -0
  67. package/dist/chunks/sigv4-LkAzsLAu.js +247 -0
  68. package/dist/chunks/sigv4-LkAzsLAu.js.map +1 -0
  69. package/dist/chunks/{styles-BQnsga7p.js → styles-CaABMoO1.js} +76 -43
  70. package/dist/chunks/styles-CaABMoO1.js.map +1 -0
  71. package/dist/chunks/{styles-D3fRphrO.js → styles-P_gmFAOi.js} +101 -21
  72. package/dist/chunks/styles-P_gmFAOi.js.map +1 -0
  73. package/dist/chunks/{styles-yed-BF5x3_Y5.js → styles-yed-Cs1nmrjn.js} +60 -20
  74. package/dist/chunks/styles-yed-Cs1nmrjn.js.map +1 -0
  75. package/dist/chunks/{text-CzJNFOS9.js → text-BuKQVMz2.js} +2 -2
  76. package/dist/chunks/{text-CzJNFOS9.js.map → text-BuKQVMz2.js.map} +1 -1
  77. package/dist/chunks/{writer-DMKvthQE.js → writer-DvHTl36J.js} +5 -4
  78. package/dist/chunks/writer-DvHTl36J.js.map +1 -0
  79. package/dist/csv.js +7 -5
  80. package/dist/csv.js.map +1 -1
  81. package/dist/cx.js +5 -4
  82. package/dist/cx.js.map +1 -1
  83. package/dist/cx2.js +2 -2
  84. package/dist/cys.js +1 -1
  85. package/dist/dot.js +2 -2
  86. package/dist/gexf.js +7 -5
  87. package/dist/gexf.js.map +1 -1
  88. package/dist/gml.js +16 -13
  89. package/dist/gml.js.map +1 -1
  90. package/dist/graph-io.js +1181 -224
  91. package/dist/graph-io.js.map +1 -1
  92. package/dist/graphml.js +3 -3
  93. package/dist/json.js +1 -1
  94. package/dist/neo4j.js +6 -4
  95. package/dist/neo4j.js.map +1 -1
  96. package/dist/obo.js +1 -1
  97. package/dist/pajek.js +1 -1
  98. package/dist/sources-cypher.d.ts +1 -0
  99. package/dist/sources-cypher.js +1236 -0
  100. package/dist/sources-cypher.js.map +1 -0
  101. package/dist/sources-ndex.d.ts +1 -0
  102. package/dist/sources-ndex.js +278 -0
  103. package/dist/sources-ndex.js.map +1 -0
  104. package/dist/sources-rest.d.ts +1 -0
  105. package/dist/sources-rest.js +1367 -0
  106. package/dist/sources-rest.js.map +1 -0
  107. package/dist/src/common/report.d.ts +6 -3
  108. package/dist/src/common/report.d.ts.map +1 -1
  109. package/dist/src/common/report.js +15 -9
  110. package/dist/src/common/report.js.map +1 -1
  111. package/dist/src/formats/cx/styles.d.ts.map +1 -1
  112. package/dist/src/formats/cx/styles.js +1 -0
  113. package/dist/src/formats/cx/styles.js.map +1 -1
  114. package/dist/src/formats/dot/styles.d.ts.map +1 -1
  115. package/dist/src/formats/dot/styles.js +3 -1
  116. package/dist/src/formats/dot/styles.js.map +1 -1
  117. package/dist/src/formats/gexf/styles.d.ts +29 -12
  118. package/dist/src/formats/gexf/styles.d.ts.map +1 -1
  119. package/dist/src/formats/gexf/styles.js +160 -31
  120. package/dist/src/formats/gexf/styles.js.map +1 -1
  121. package/dist/src/formats/gml/styles.d.ts.map +1 -1
  122. package/dist/src/formats/gml/styles.js +5 -4
  123. package/dist/src/formats/gml/styles.js.map +1 -1
  124. package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -1
  125. package/dist/src/formats/graphml/styles-plain.js +3 -3
  126. package/dist/src/formats/graphml/styles-plain.js.map +1 -1
  127. package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -1
  128. package/dist/src/formats/graphml/styles-yed.js +89 -19
  129. package/dist/src/formats/graphml/styles-yed.js.map +1 -1
  130. package/dist/src/formats/pajek/styles.d.ts.map +1 -1
  131. package/dist/src/formats/pajek/styles.js +1 -0
  132. package/dist/src/formats/pajek/styles.js.map +1 -1
  133. package/dist/src/formats/xgmml/styles.d.ts.map +1 -1
  134. package/dist/src/formats/xgmml/styles.js +1 -0
  135. package/dist/src/formats/xgmml/styles.js.map +1 -1
  136. package/dist/src/index.d.ts +8 -1
  137. package/dist/src/index.d.ts.map +1 -1
  138. package/dist/src/index.js +9 -1
  139. package/dist/src/index.js.map +1 -1
  140. package/dist/src/registry.d.ts +173 -1
  141. package/dist/src/registry.d.ts.map +1 -1
  142. package/dist/src/registry.js +196 -1
  143. package/dist/src/registry.js.map +1 -1
  144. package/dist/src/sources/builtins.d.ts +11 -0
  145. package/dist/src/sources/builtins.d.ts.map +1 -0
  146. package/dist/src/sources/builtins.js +47 -0
  147. package/dist/src/sources/builtins.js.map +1 -0
  148. package/dist/src/sources/codes.d.ts +230 -0
  149. package/dist/src/sources/codes.d.ts.map +1 -0
  150. package/dist/src/sources/codes.js +58 -0
  151. package/dist/src/sources/codes.js.map +1 -0
  152. package/dist/src/sources/context.d.ts +112 -0
  153. package/dist/src/sources/context.d.ts.map +1 -0
  154. package/dist/src/sources/context.js +739 -0
  155. package/dist/src/sources/context.js.map +1 -0
  156. package/dist/src/sources/credentials.d.ts +179 -0
  157. package/dist/src/sources/credentials.d.ts.map +1 -0
  158. package/dist/src/sources/credentials.js +301 -0
  159. package/dist/src/sources/credentials.js.map +1 -0
  160. package/dist/src/sources/cypher/descriptor.d.ts +21 -0
  161. package/dist/src/sources/cypher/descriptor.d.ts.map +1 -0
  162. package/dist/src/sources/cypher/descriptor.js +119 -0
  163. package/dist/src/sources/cypher/descriptor.js.map +1 -0
  164. package/dist/src/sources/cypher/flatten.d.ts +72 -0
  165. package/dist/src/sources/cypher/flatten.d.ts.map +1 -0
  166. package/dist/src/sources/cypher/flatten.js +279 -0
  167. package/dist/src/sources/cypher/flatten.js.map +1 -0
  168. package/dist/src/sources/cypher/index.d.ts +33 -0
  169. package/dist/src/sources/cypher/index.d.ts.map +1 -0
  170. package/dist/src/sources/cypher/index.js +405 -0
  171. package/dist/src/sources/cypher/index.js.map +1 -0
  172. package/dist/src/sources/cypher/params.d.ts +40 -0
  173. package/dist/src/sources/cypher/params.d.ts.map +1 -0
  174. package/dist/src/sources/cypher/params.js +6 -0
  175. package/dist/src/sources/cypher/params.js.map +1 -0
  176. package/dist/src/sources/cypher/profiles.d.ts +44 -0
  177. package/dist/src/sources/cypher/profiles.d.ts.map +1 -0
  178. package/dist/src/sources/cypher/profiles.js +61 -0
  179. package/dist/src/sources/cypher/profiles.js.map +1 -0
  180. package/dist/src/sources/cypher/query-builder.d.ts +106 -0
  181. package/dist/src/sources/cypher/query-builder.d.ts.map +1 -0
  182. package/dist/src/sources/cypher/query-builder.js +236 -0
  183. package/dist/src/sources/cypher/query-builder.js.map +1 -0
  184. package/dist/src/sources/cypher/transports/bolt.d.ts +21 -0
  185. package/dist/src/sources/cypher/transports/bolt.d.ts.map +1 -0
  186. package/dist/src/sources/cypher/transports/bolt.js +185 -0
  187. package/dist/src/sources/cypher/transports/bolt.js.map +1 -0
  188. package/dist/src/sources/cypher/transports/neptune-analytics.d.ts +15 -0
  189. package/dist/src/sources/cypher/transports/neptune-analytics.d.ts.map +1 -0
  190. package/dist/src/sources/cypher/transports/neptune-analytics.js +38 -0
  191. package/dist/src/sources/cypher/transports/neptune-analytics.js.map +1 -0
  192. package/dist/src/sources/cypher/transports/neptune-https.d.ts +31 -0
  193. package/dist/src/sources/cypher/transports/neptune-https.d.ts.map +1 -0
  194. package/dist/src/sources/cypher/transports/neptune-https.js +104 -0
  195. package/dist/src/sources/cypher/transports/neptune-https.js.map +1 -0
  196. package/dist/src/sources/cypher/transports/query-api.d.ts +14 -0
  197. package/dist/src/sources/cypher/transports/query-api.d.ts.map +1 -0
  198. package/dist/src/sources/cypher/transports/query-api.js +80 -0
  199. package/dist/src/sources/cypher/transports/query-api.js.map +1 -0
  200. package/dist/src/sources/cypher/transports/transport.d.ts +78 -0
  201. package/dist/src/sources/cypher/transports/transport.d.ts.map +1 -0
  202. package/dist/src/sources/cypher/transports/transport.js +77 -0
  203. package/dist/src/sources/cypher/transports/transport.js.map +1 -0
  204. package/dist/src/sources/cypher/types-map.d.ts +91 -0
  205. package/dist/src/sources/cypher/types-map.d.ts.map +1 -0
  206. package/dist/src/sources/cypher/types-map.js +306 -0
  207. package/dist/src/sources/cypher/types-map.js.map +1 -0
  208. package/dist/src/sources/define.d.ts +47 -0
  209. package/dist/src/sources/define.d.ts.map +1 -0
  210. package/dist/src/sources/define.js +173 -0
  211. package/dist/src/sources/define.js.map +1 -0
  212. package/dist/src/sources/fail.d.ts +33 -0
  213. package/dist/src/sources/fail.d.ts.map +1 -0
  214. package/dist/src/sources/fail.js +49 -0
  215. package/dist/src/sources/fail.js.map +1 -0
  216. package/dist/src/sources/ids.d.ts +64 -0
  217. package/dist/src/sources/ids.d.ts.map +1 -0
  218. package/dist/src/sources/ids.js +64 -0
  219. package/dist/src/sources/ids.js.map +1 -0
  220. package/dist/src/sources/ndex/client.d.ts +31 -0
  221. package/dist/src/sources/ndex/client.d.ts.map +1 -0
  222. package/dist/src/sources/ndex/client.js +90 -0
  223. package/dist/src/sources/ndex/client.js.map +1 -0
  224. package/dist/src/sources/ndex/descriptor.d.ts +10 -0
  225. package/dist/src/sources/ndex/descriptor.d.ts.map +1 -0
  226. package/dist/src/sources/ndex/descriptor.js +55 -0
  227. package/dist/src/sources/ndex/descriptor.js.map +1 -0
  228. package/dist/src/sources/ndex/expand.d.ts +20 -0
  229. package/dist/src/sources/ndex/expand.d.ts.map +1 -0
  230. package/dist/src/sources/ndex/expand.js +87 -0
  231. package/dist/src/sources/ndex/expand.js.map +1 -0
  232. package/dist/src/sources/ndex/index.d.ts +25 -0
  233. package/dist/src/sources/ndex/index.d.ts.map +1 -0
  234. package/dist/src/sources/ndex/index.js +191 -0
  235. package/dist/src/sources/ndex/index.js.map +1 -0
  236. package/dist/src/sources/ndex/params.d.ts +17 -0
  237. package/dist/src/sources/ndex/params.d.ts.map +1 -0
  238. package/dist/src/sources/ndex/params.js +6 -0
  239. package/dist/src/sources/ndex/params.js.map +1 -0
  240. package/dist/src/sources/ndex/share-url.d.ts +40 -0
  241. package/dist/src/sources/ndex/share-url.d.ts.map +1 -0
  242. package/dist/src/sources/ndex/share-url.js +64 -0
  243. package/dist/src/sources/ndex/share-url.js.map +1 -0
  244. package/dist/src/sources/params.d.ts +28 -0
  245. package/dist/src/sources/params.d.ts.map +1 -0
  246. package/dist/src/sources/params.js +6 -0
  247. package/dist/src/sources/params.js.map +1 -0
  248. package/dist/src/sources/registry.d.ts +118 -0
  249. package/dist/src/sources/registry.d.ts.map +1 -0
  250. package/dist/src/sources/registry.js +193 -0
  251. package/dist/src/sources/registry.js.map +1 -0
  252. package/dist/src/sources/rest/descriptor.d.ts +16 -0
  253. package/dist/src/sources/rest/descriptor.d.ts.map +1 -0
  254. package/dist/src/sources/rest/descriptor.js +71 -0
  255. package/dist/src/sources/rest/descriptor.js.map +1 -0
  256. package/dist/src/sources/rest/index.d.ts +14 -0
  257. package/dist/src/sources/rest/index.d.ts.map +1 -0
  258. package/dist/src/sources/rest/index.js +13 -0
  259. package/dist/src/sources/rest/index.js.map +1 -0
  260. package/dist/src/sources/rest/mapping.d.ts +30 -0
  261. package/dist/src/sources/rest/mapping.d.ts.map +1 -0
  262. package/dist/src/sources/rest/mapping.js +362 -0
  263. package/dist/src/sources/rest/mapping.js.map +1 -0
  264. package/dist/src/sources/rest/openalex.d.ts +27 -0
  265. package/dist/src/sources/rest/openalex.d.ts.map +1 -0
  266. package/dist/src/sources/rest/openalex.js +269 -0
  267. package/dist/src/sources/rest/openalex.js.map +1 -0
  268. package/dist/src/sources/rest/paging.d.ts +53 -0
  269. package/dist/src/sources/rest/paging.d.ts.map +1 -0
  270. package/dist/src/sources/rest/paging.js +138 -0
  271. package/dist/src/sources/rest/paging.js.map +1 -0
  272. package/dist/src/sources/rest/params.d.ts +216 -0
  273. package/dist/src/sources/rest/params.d.ts.map +1 -0
  274. package/dist/src/sources/rest/params.js +7 -0
  275. package/dist/src/sources/rest/params.js.map +1 -0
  276. package/dist/src/sources/rest/records.d.ts +41 -0
  277. package/dist/src/sources/rest/records.d.ts.map +1 -0
  278. package/dist/src/sources/rest/records.js +240 -0
  279. package/dist/src/sources/rest/records.js.map +1 -0
  280. package/dist/src/sources/rest/samples/deps-dev.d.ts +10 -0
  281. package/dist/src/sources/rest/samples/deps-dev.d.ts.map +1 -0
  282. package/dist/src/sources/rest/samples/deps-dev.js +47 -0
  283. package/dist/src/sources/rest/samples/deps-dev.js.map +1 -0
  284. package/dist/src/sources/rest/samples/string.d.ts +9 -0
  285. package/dist/src/sources/rest/samples/string.d.ts.map +1 -0
  286. package/dist/src/sources/rest/samples/string.js +42 -0
  287. package/dist/src/sources/rest/samples/string.js.map +1 -0
  288. package/dist/src/sources/rest/selectors.d.ts +41 -0
  289. package/dist/src/sources/rest/selectors.d.ts.map +1 -0
  290. package/dist/src/sources/rest/selectors.js +81 -0
  291. package/dist/src/sources/rest/selectors.js.map +1 -0
  292. package/dist/src/sources/rest/source.d.ts +67 -0
  293. package/dist/src/sources/rest/source.d.ts.map +1 -0
  294. package/dist/src/sources/rest/source.js +635 -0
  295. package/dist/src/sources/rest/source.js.map +1 -0
  296. package/dist/src/sources/rest/templates.d.ts +38 -0
  297. package/dist/src/sources/rest/templates.d.ts.map +1 -0
  298. package/dist/src/sources/rest/templates.js +125 -0
  299. package/dist/src/sources/rest/templates.js.map +1 -0
  300. package/dist/src/sources/run.d.ts +93 -0
  301. package/dist/src/sources/run.d.ts.map +1 -0
  302. package/dist/src/sources/run.js +673 -0
  303. package/dist/src/sources/run.js.map +1 -0
  304. package/dist/src/sources/sha256.d.ts +12 -0
  305. package/dist/src/sources/sha256.d.ts.map +1 -0
  306. package/dist/src/sources/sha256.js +95 -0
  307. package/dist/src/sources/sha256.js.map +1 -0
  308. package/dist/src/sources/sigv4.d.ts +24 -0
  309. package/dist/src/sources/sigv4.d.ts.map +1 -0
  310. package/dist/src/sources/sigv4.js +182 -0
  311. package/dist/src/sources/sigv4.js.map +1 -0
  312. package/dist/src/sources/testing.d.ts +96 -0
  313. package/dist/src/sources/testing.d.ts.map +1 -0
  314. package/dist/src/sources/testing.js +138 -0
  315. package/dist/src/sources/testing.js.map +1 -0
  316. package/dist/src/sources/types.d.ts +665 -0
  317. package/dist/src/sources/types.d.ts.map +1 -0
  318. package/dist/src/sources/types.js +10 -0
  319. package/dist/src/sources/types.js.map +1 -0
  320. package/dist/src/styles/canon/enums.d.ts.map +1 -1
  321. package/dist/src/styles/canon/enums.js +1 -0
  322. package/dist/src/styles/canon/enums.js.map +1 -1
  323. package/dist/src/styles/cyjs/cascade.d.ts.map +1 -1
  324. package/dist/src/styles/cyjs/cascade.js +68 -2
  325. package/dist/src/styles/cyjs/cascade.js.map +1 -1
  326. package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -1
  327. package/dist/src/styles/cyjs/defaults-table.js +2 -0
  328. package/dist/src/styles/cyjs/defaults-table.js.map +1 -1
  329. package/dist/src/styles/cyjs/emit.d.ts.map +1 -1
  330. package/dist/src/styles/cyjs/emit.js +18 -7
  331. package/dist/src/styles/cyjs/emit.js.map +1 -1
  332. package/dist/src/styles/cyjs/mappers.d.ts +4 -1
  333. package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
  334. package/dist/src/styles/cyjs/mappers.js +2 -0
  335. package/dist/src/styles/cyjs/mappers.js.map +1 -1
  336. package/dist/src/styles/cytoscape/emit.d.ts.map +1 -1
  337. package/dist/src/styles/cytoscape/emit.js +59 -7
  338. package/dist/src/styles/cytoscape/emit.js.map +1 -1
  339. package/dist/src/styles/cytoscape/lexicon.d.ts +6 -0
  340. package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
  341. package/dist/src/styles/cytoscape/lexicon.js +26 -2
  342. package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
  343. package/dist/src/styles/cytoscape/resolve.d.ts +4 -1
  344. package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
  345. package/dist/src/styles/cytoscape/resolve.js +10 -6
  346. package/dist/src/styles/cytoscape/resolve.js.map +1 -1
  347. package/dist/src/styles/cytoscape/translate.d.ts.map +1 -1
  348. package/dist/src/styles/cytoscape/translate.js +10 -10
  349. package/dist/src/styles/cytoscape/translate.js.map +1 -1
  350. package/dist/src/styles/defaults.d.ts +30 -0
  351. package/dist/src/styles/defaults.d.ts.map +1 -1
  352. package/dist/src/styles/defaults.js +45 -4
  353. package/dist/src/styles/defaults.js.map +1 -1
  354. package/dist/src/styles/io/block.d.ts.map +1 -1
  355. package/dist/src/styles/io/block.js +9 -0
  356. package/dist/src/styles/io/block.js.map +1 -1
  357. package/dist/src/styles/io/writer.d.ts.map +1 -1
  358. package/dist/src/styles/io/writer.js +7 -3
  359. package/dist/src/styles/io/writer.js.map +1 -1
  360. package/dist/src/styles/plan/resolve.d.ts +2 -1
  361. package/dist/src/styles/plan/resolve.d.ts.map +1 -1
  362. package/dist/src/styles/plan/resolve.js +13 -2
  363. package/dist/src/styles/plan/resolve.js.map +1 -1
  364. package/dist/src/styles/types.d.ts +19 -2
  365. package/dist/src/styles/types.d.ts.map +1 -1
  366. package/dist/src/styles/vocabulary.d.ts.map +1 -1
  367. package/dist/src/styles/vocabulary.js +15 -1
  368. package/dist/src/styles/vocabulary.js.map +1 -1
  369. package/dist/src/types.d.ts +19 -5
  370. package/dist/src/types.d.ts.map +1 -1
  371. package/dist/src/types.js.map +1 -1
  372. package/dist/styles.js +11 -11
  373. package/dist/xgmml.js +3 -3
  374. package/docs/samples/people.json +6 -0
  375. package/package.json +29 -4
  376. package/src/common/report.ts +27 -7
  377. package/src/formats/cx/styles.ts +1 -0
  378. package/src/formats/dot/styles.ts +3 -1
  379. package/src/formats/gexf/styles.ts +185 -37
  380. package/src/formats/gml/styles.ts +5 -4
  381. package/src/formats/graphml/styles-plain.ts +3 -9
  382. package/src/formats/graphml/styles-yed.ts +93 -20
  383. package/src/formats/pajek/styles.ts +1 -0
  384. package/src/formats/xgmml/styles.ts +1 -0
  385. package/src/index.ts +90 -0
  386. package/src/registry.ts +326 -1
  387. package/src/sources/builtins.ts +56 -0
  388. package/src/sources/codes.ts +235 -0
  389. package/src/sources/context.ts +893 -0
  390. package/src/sources/credentials.ts +409 -0
  391. package/src/sources/cypher/descriptor.ts +125 -0
  392. package/src/sources/cypher/flatten.ts +323 -0
  393. package/src/sources/cypher/index.ts +498 -0
  394. package/src/sources/cypher/params.ts +41 -0
  395. package/src/sources/cypher/profiles.ts +78 -0
  396. package/src/sources/cypher/query-builder.ts +294 -0
  397. package/src/sources/cypher/transports/bolt.ts +228 -0
  398. package/src/sources/cypher/transports/neptune-analytics.ts +41 -0
  399. package/src/sources/cypher/transports/neptune-https.ts +122 -0
  400. package/src/sources/cypher/transports/query-api.ts +100 -0
  401. package/src/sources/cypher/transports/transport.ts +139 -0
  402. package/src/sources/cypher/types-map.ts +418 -0
  403. package/src/sources/define.ts +195 -0
  404. package/src/sources/fail.ts +70 -0
  405. package/src/sources/ids.ts +74 -0
  406. package/src/sources/ndex/client.ts +102 -0
  407. package/src/sources/ndex/descriptor.ts +64 -0
  408. package/src/sources/ndex/expand.ts +100 -0
  409. package/src/sources/ndex/index.ts +235 -0
  410. package/src/sources/ndex/params.ts +17 -0
  411. package/src/sources/ndex/share-url.ts +84 -0
  412. package/src/sources/params.ts +29 -0
  413. package/src/sources/registry.ts +325 -0
  414. package/src/sources/rest/descriptor.ts +74 -0
  415. package/src/sources/rest/index.ts +22 -0
  416. package/src/sources/rest/mapping.ts +401 -0
  417. package/src/sources/rest/openalex.ts +288 -0
  418. package/src/sources/rest/paging.ts +180 -0
  419. package/src/sources/rest/params.ts +243 -0
  420. package/src/sources/rest/records.ts +289 -0
  421. package/src/sources/rest/samples/deps-dev.ts +49 -0
  422. package/src/sources/rest/samples/string.ts +44 -0
  423. package/src/sources/rest/selectors.ts +91 -0
  424. package/src/sources/rest/source.ts +760 -0
  425. package/src/sources/rest/templates.ts +151 -0
  426. package/src/sources/run.ts +793 -0
  427. package/src/sources/sha256.ts +99 -0
  428. package/src/sources/sigv4.ts +207 -0
  429. package/src/sources/testing.ts +210 -0
  430. package/src/sources/types.ts +741 -0
  431. package/src/styles/canon/enums.ts +1 -0
  432. package/src/styles/cyjs/cascade.ts +81 -2
  433. package/src/styles/cyjs/defaults-table.ts +2 -0
  434. package/src/styles/cyjs/emit.ts +18 -7
  435. package/src/styles/cyjs/mappers.ts +6 -1
  436. package/src/styles/cytoscape/emit.ts +61 -7
  437. package/src/styles/cytoscape/lexicon.ts +28 -2
  438. package/src/styles/cytoscape/resolve.ts +22 -6
  439. package/src/styles/cytoscape/translate.ts +11 -11
  440. package/src/styles/defaults.ts +93 -4
  441. package/src/styles/io/block.ts +10 -0
  442. package/src/styles/io/writer.ts +8 -3
  443. package/src/styles/plan/resolve.ts +14 -2
  444. package/src/styles/types.ts +28 -2
  445. package/src/styles/vocabulary.ts +15 -1
  446. package/src/types.ts +19 -5
  447. package/dist/chunks/block-DiGq58c3.js.map +0 -1
  448. package/dist/chunks/emit-CwU8cUmG.js.map +0 -1
  449. package/dist/chunks/export-BvqAXCKh.js.map +0 -1
  450. package/dist/chunks/format-BpQBx8MZ.js.map +0 -1
  451. package/dist/chunks/importer-BSvfrX_h.js.map +0 -1
  452. package/dist/chunks/importer-CMmeMWlC.js.map +0 -1
  453. package/dist/chunks/importer-COTK9Tsl.js.map +0 -1
  454. package/dist/chunks/importer-DiZRmOQG.js.map +0 -1
  455. package/dist/chunks/importer-e6LGpqHB.js.map +0 -1
  456. package/dist/chunks/lexicon-CT69Kd87.js.map +0 -1
  457. package/dist/chunks/styles-BQnsga7p.js.map +0 -1
  458. package/dist/chunks/styles-D3fRphrO.js.map +0 -1
  459. package/dist/chunks/styles-yed-BF5x3_Y5.js.map +0 -1
  460. package/dist/chunks/writer-DMKvthQE.js.map +0 -1
@@ -0,0 +1,99 @@
1
+ /**
2
+ * SHA-256 in plain JavaScript (FIPS 180-4), for the one place Web Crypto is missing: a browser page
3
+ * that is not a secure context (plain http on a host other than localhost) has no
4
+ * `crypto.subtle`. Only the content hash uses it; signing still needs Web Crypto.
5
+ */
6
+
7
+ const K = new Uint32Array([
8
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98,
9
+ 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
10
+ 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8,
11
+ 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
12
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
13
+ 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
14
+ 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
15
+ 0xc67178f2,
16
+ ]);
17
+
18
+ /**
19
+ * Rotate a 32-bit word right.
20
+ * @param x - the word
21
+ * @param n - the bits
22
+ * @returns the rotated word
23
+ */
24
+ function rotr(x: number, n: number): number {
25
+ return (x >>> n) | (x << (32 - n));
26
+ }
27
+
28
+ /**
29
+ * Pad a message to whole 64-byte blocks, with its bit length at the end.
30
+ * @param data - the message
31
+ * @returns the padded message
32
+ */
33
+ function pad(data: Uint8Array): Uint8Array {
34
+ const blocks = Math.ceil((data.length + 9) / 64);
35
+ const out = new Uint8Array(blocks * 64);
36
+ out.set(data);
37
+ out[data.length] = 0x80;
38
+ const view = new DataView(out.buffer);
39
+ view.setUint32(out.length - 8, Math.floor(data.length / 0x20000000));
40
+ view.setUint32(out.length - 4, (data.length * 8) >>> 0);
41
+ return out;
42
+ }
43
+
44
+ /**
45
+ * Run one 64-byte block through the compression function.
46
+ * @param h - the running hash, updated in place
47
+ * @param w - the 64-word schedule, scratch
48
+ * @param view - the padded message
49
+ * @param offset - where the block starts
50
+ */
51
+ function compress(h: Uint32Array, w: Uint32Array, view: DataView, offset: number): void {
52
+ for (let i = 0; i < 16; i++) {
53
+ w[i] = view.getUint32(offset + i * 4);
54
+ }
55
+ for (let i = 16; i < 64; i++) {
56
+ const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >>> 3);
57
+ const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >>> 10);
58
+ w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
59
+ }
60
+ let [a, b, c, d, e, f, g, hh] = h;
61
+ for (let i = 0; i < 64; i++) {
62
+ const t1 = (hh + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + ((e & f) ^ (~e & g)) + K[i] + w[i]) >>> 0;
63
+ const t2 = ((rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + ((a & b) ^ (a & c) ^ (b & c))) >>> 0;
64
+ hh = g;
65
+ g = f;
66
+ f = e;
67
+ e = (d + t1) >>> 0;
68
+ d = c;
69
+ c = b;
70
+ b = a;
71
+ a = (t1 + t2) >>> 0;
72
+ }
73
+ const next = [a, b, c, d, e, f, g, hh];
74
+ for (let i = 0; i < 8; i++) {
75
+ h[i] = (h[i] + next[i]) >>> 0;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * SHA-256 of bytes.
81
+ * @param data - the bytes
82
+ * @returns the 32-byte digest
83
+ */
84
+ export function sha256Bytes(data: Uint8Array): ArrayBuffer {
85
+ const h = new Uint32Array([
86
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
87
+ ]);
88
+ const padded = pad(data);
89
+ const view = new DataView(padded.buffer);
90
+ const w = new Uint32Array(64);
91
+ for (let offset = 0; offset < padded.length; offset += 64) {
92
+ compress(h, w, view, offset);
93
+ }
94
+ const out = new DataView(new ArrayBuffer(32));
95
+ h.forEach((word, i) => {
96
+ out.setUint32(i * 4, word);
97
+ });
98
+ return out.buffer;
99
+ }
@@ -0,0 +1,207 @@
1
+ /**
2
+ * AWS Signature Version 4 over Web Crypto (design sections 6.3 and 12.4), loaded by
3
+ * `credentials.awsSigV4` on first use. No AWS SDK: it signs the request `ctx.fetch` is about to
4
+ * send, every header that request carries plus `host`, and is checked against AWS's published
5
+ * signature test suite. graph-io never reads `~/.aws` or the environment.
6
+ */
7
+
8
+ import { detectRuntime } from "./context.js";
9
+ import { type AwsSigV4Options } from "./credentials.js";
10
+ import { failAlone } from "./fail.js";
11
+ import { sha256Bytes } from "./sha256.js";
12
+
13
+ /** Headers never signed: proxies and clients may change them in flight. */
14
+ const UNSIGNED = new Set(["user-agent", "expect", "x-amzn-trace-id", "authorization", "content-length"]);
15
+
16
+ /**
17
+ * The UTF-8 bytes of a string.
18
+ * @param text - the text
19
+ * @returns the bytes
20
+ */
21
+ function utf8(text: string): Uint8Array {
22
+ return new TextEncoder().encode(text);
23
+ }
24
+
25
+ /**
26
+ * Code-unit order of two strings.
27
+ * @param a - one string
28
+ * @param b - another
29
+ * @returns negative, zero or positive
30
+ */
31
+ function compareText(a: string, b: string): number {
32
+ if (a === b) {
33
+ return 0;
34
+ }
35
+ return a < b ? -1 : 1;
36
+ }
37
+
38
+ /**
39
+ * Web Crypto: the global one, or Node 18's, which is not global without a flag. A browser page that
40
+ * is not a secure context (plain http on a host other than localhost) has none.
41
+ * @returns the subtle crypto, or null where there is none
42
+ */
43
+ async function subtle(): Promise<SubtleCrypto | null> {
44
+ const global = (globalThis as { crypto?: Crypto }).crypto;
45
+ if (global?.subtle !== undefined) {
46
+ return global.subtle;
47
+ }
48
+ if (detectRuntime() !== "node") {
49
+ return null;
50
+ }
51
+ const name = "node:crypto";
52
+ return ((await import(/* @vite-ignore */ name)) as { webcrypto: Crypto }).webcrypto.subtle;
53
+ }
54
+
55
+ /**
56
+ * Lowercase hex of bytes.
57
+ * @param bytes - the bytes
58
+ * @returns hex
59
+ */
60
+ function hex(bytes: ArrayBuffer): string {
61
+ return Array.from(new Uint8Array(bytes), (b) => b.toString(16).padStart(2, "0")).join("");
62
+ }
63
+
64
+ /**
65
+ * SHA-256 of bytes, as hex.
66
+ * @param data - the bytes
67
+ * @returns the digest
68
+ */
69
+ async function sha256(data: Uint8Array | ArrayBuffer): Promise<string> {
70
+ const s = await subtle();
71
+ if (s === null) {
72
+ return hex(sha256Bytes(data instanceof Uint8Array ? data : new Uint8Array(data)));
73
+ }
74
+ return hex(await s.digest("SHA-256", data as BufferSource));
75
+ }
76
+
77
+ /**
78
+ * SHA-256 of a text's UTF-8 bytes, as lowercase hex (the Cypher source's content hash).
79
+ * @param text - the text
80
+ * @returns the digest
81
+ */
82
+ export function sha256Hex(text: string): Promise<string> {
83
+ return sha256(utf8(text));
84
+ }
85
+
86
+ /**
87
+ * HMAC-SHA-256.
88
+ * @param key - the key
89
+ * @param data - the message
90
+ * @returns the MAC
91
+ */
92
+ async function hmac(key: Uint8Array | ArrayBuffer, data: string): Promise<ArrayBuffer> {
93
+ const s = await subtle();
94
+ if (s === null) {
95
+ failAlone("E_SOURCE_RUNTIME", "AWS signing needs Web Crypto, which a browser has only on a secure page", {
96
+ runtime: detectRuntime(),
97
+ reason: "needs-secure-context",
98
+ });
99
+ }
100
+ const k = await s.importKey("raw", key as BufferSource, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
101
+ return s.sign("HMAC", k, utf8(data) as BufferSource);
102
+ }
103
+
104
+ /**
105
+ * RFC 3986 encoding, as SigV4 asks: every byte but letters, digits and `-_.~`.
106
+ * @param text - the text
107
+ * @returns the encoded text
108
+ */
109
+ function encode(text: string): string {
110
+ return encodeURIComponent(text).replaceAll(
111
+ /[!'()*]/g,
112
+ (c) => `%${(c.codePointAt(0) ?? 0).toString(16).toUpperCase()}`,
113
+ );
114
+ }
115
+
116
+ /**
117
+ * The canonical query string: every pair encoded, sorted by key then value.
118
+ * @param url - the request URL
119
+ * @returns the canonical query
120
+ */
121
+ function canonicalQuery(url: URL): string {
122
+ return [...url.searchParams]
123
+ .map(([k, v]) => [encode(k), encode(v)] as const)
124
+ .sort(([ak, av], [bk, bv]) => compareText(ak, bk) || compareText(av, bv))
125
+ .map(([k, v]) => `${k}=${v}`)
126
+ .join("&");
127
+ }
128
+
129
+ /**
130
+ * The `YYYYMMDDTHHMMSSZ` form of a time.
131
+ * @param date - the time
132
+ * @returns the AWS timestamp
133
+ */
134
+ function amzDate(date: Date): string {
135
+ return date
136
+ .toISOString()
137
+ .replaceAll(/[-:]/g, "")
138
+ .replace(/\.\d{3}/, "");
139
+ }
140
+
141
+ /**
142
+ * Sign a request with AWS SigV4 (`Authorization`, `X-Amz-Date` and, for temporary credentials,
143
+ * `X-Amz-Security-Token`). In a browser, long-term keys (no session token) are refused, since every
144
+ * script on the page could read them: use temporary credentials from an identity pool.
145
+ * @param request - the request
146
+ * @param options - region, service (default "neptune-db") and the credentials or a provider
147
+ * @param now - the signing time; tests fix it. An `X-Amz-Date` already on the request wins.
148
+ * @returns the signed request
149
+ */
150
+ export async function signRequest(
151
+ request: Request,
152
+ options: AwsSigV4Options,
153
+ now: Date = new Date(),
154
+ ): Promise<Request> {
155
+ const creds = typeof options.credentials === "function" ? await options.credentials() : options.credentials;
156
+ const runtime = detectRuntime();
157
+ if ((runtime === "browser" || runtime === "worker") && (creds.sessionToken ?? "") === "") {
158
+ failAlone("E_SOURCE_PARAM", "long-term AWS keys are never used in a browser", {
159
+ name: "credential",
160
+ reason: "long-term-key",
161
+ });
162
+ }
163
+ const service = options.service ?? "neptune-db";
164
+ const url = new URL(request.url);
165
+ const headers = new Headers(request.headers);
166
+ const stamp = headers.get("x-amz-date") ?? amzDate(now);
167
+ headers.set("x-amz-date", stamp);
168
+ if (creds.sessionToken !== undefined && creds.sessionToken !== "") {
169
+ headers.set("x-amz-security-token", creds.sessionToken);
170
+ }
171
+ const method = request.method.toUpperCase();
172
+ const body = method === "GET" || method === "HEAD" ? new Uint8Array(0) : await request.clone().arrayBuffer();
173
+
174
+ const signed = new Map<string, string>([["host", url.host]]);
175
+ headers.forEach((value, name) => {
176
+ if (!UNSIGNED.has(name)) {
177
+ signed.set(name, value.trim().replaceAll(/\s+/g, " "));
178
+ }
179
+ });
180
+ // SigV4 sorts header names by code unit, not by locale
181
+ const names = [...signed.keys()].sort((a, b) => Number(a > b) - Number(a < b));
182
+ const signedHeaders = names.join(";");
183
+ const canonical = [
184
+ method,
185
+ // non-S3 services encode the already-encoded path once more
186
+ url.pathname.split("/").map(encode).join("/"),
187
+ canonicalQuery(url),
188
+ ...names.map((n) => `${n}:${signed.get(n) ?? ""}`),
189
+ "",
190
+ signedHeaders,
191
+ await sha256(body),
192
+ ].join("\n");
193
+
194
+ const day = stamp.slice(0, 8);
195
+ const scope = `${day}/${options.region}/${service}/aws4_request`;
196
+ const toSign = ["AWS4-HMAC-SHA256", stamp, scope, await sha256(utf8(canonical))].join("\n");
197
+ let key: ArrayBuffer = await hmac(utf8(`AWS4${creds.secretAccessKey}`), day);
198
+ for (const part of [options.region, service, "aws4_request"]) {
199
+ key = await hmac(key, part);
200
+ }
201
+ const signature = hex(await hmac(key, toSign));
202
+ headers.set(
203
+ "Authorization",
204
+ `AWS4-HMAC-SHA256 Credential=${creds.accessKeyId}/${scope}, SignedHeaders=${signedHeaders}, Signature=${signature}`,
205
+ );
206
+ return new Request(request, { headers });
207
+ }
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Testing a source without a network: `replayFetch` answers requests from recorded responses and
3
+ * refuses any request it has no recording for. Browser-safe (no file system), so a graphty-element
4
+ * story and a third party's tests use it the same way.
5
+ */
6
+
7
+ /**
8
+ * One recorded exchange. Experimental.
9
+ * @category Network sources
10
+ */
11
+ export interface Recording {
12
+ /** The request method. @defaultValue "GET" */
13
+ readonly method?: string | undefined;
14
+ /** The request URL. Query parameters match in any order. */
15
+ readonly url: string;
16
+ /** The request body, when it must match (JSON bodies compare as JSON). */
17
+ readonly requestBody?: string | undefined;
18
+ /**
19
+ * true: the request must carry a credential; false: it must not. Absent: either. A credential
20
+ * is an Authorization header, or a header or query parameter named in `secretHeaders` /
21
+ * `secretQuery`; its value is never compared.
22
+ */
23
+ readonly credential?: boolean | undefined;
24
+ /** The response status. @defaultValue 200 */
25
+ readonly status?: number | undefined;
26
+ /** The response headers. */
27
+ readonly headers?: Readonly<Record<string, string>> | undefined;
28
+ /** The response body: text, or a value sent as JSON. */
29
+ readonly body?: unknown;
30
+ }
31
+
32
+ /**
33
+ * The options of `replayFetch`. Experimental.
34
+ * @category Network sources
35
+ */
36
+ export interface ReplayOptions {
37
+ /** What an unrecorded request does: "throw" (the only choice; the test fails). @defaultValue "throw" */
38
+ readonly onUnrecorded?: "throw" | undefined;
39
+ /** Query parameters that hold a credential: ignored when matching, counted as a credential. */
40
+ readonly secretQuery?: readonly string[] | undefined;
41
+ /** Request headers that hold a credential, beside Authorization. */
42
+ readonly secretHeaders?: readonly string[] | undefined;
43
+ }
44
+
45
+ /**
46
+ * One request `replayFetch` answered. Experimental.
47
+ * @category Network sources
48
+ */
49
+ export interface ReplayCall {
50
+ /** The method. */
51
+ readonly method: string;
52
+ /** The URL, origin and path only. */
53
+ readonly url: string;
54
+ /** Whether a credential was sent. */
55
+ readonly credential: boolean;
56
+ }
57
+
58
+ /**
59
+ * A fetch that answers from recordings, plus the requests it answered. Experimental.
60
+ * @category Network sources
61
+ */
62
+ export type ReplayFetch = typeof fetch & {
63
+ /** The requests answered, in order. */
64
+ readonly calls: readonly ReplayCall[];
65
+ };
66
+
67
+ /**
68
+ * A fetch that answers every request from recordings: the first unused recording that matches
69
+ * (method, URL with its query in any order, body when recorded, and whether a credential was
70
+ * sent), else the last one that matched, so a recording answers every repeat. A request with no
71
+ * matching recording rejects with an Error naming its method and URL, which a source never
72
+ * retries. Like fetch, a request whose signal is already aborted rejects with the signal's
73
+ * reason. Pass it as the `fetch` option. Experimental.
74
+ * @param recordings - the recorded exchanges
75
+ * @param options - which headers and query parameters hold a credential
76
+ * @returns the fetch
77
+ * @example
78
+ * ```ts
79
+ * const fetch = replayFetch([{ url: "https://example.com/api/people.json?team=core", body: [{ id: "ana", knows: [] }] }]);
80
+ * await loadFromSource("people", { team: "core" }, { endpoint: "https://example.com", fetch });
81
+ * ```
82
+ * @category Network sources
83
+ */
84
+ export function replayFetch(recordings: readonly Recording[], options: ReplayOptions = {}): ReplayFetch {
85
+ const secretQuery = new Set(options.secretQuery ?? []);
86
+ const secretHeaders = ["authorization", ...(options.secretHeaders ?? []).map((h) => h.toLowerCase())];
87
+ const used = new Set<number>();
88
+ const calls: ReplayCall[] = [];
89
+
90
+ const key = (url: URL): string => {
91
+ const params = [...url.searchParams].filter(([k]) => !secretQuery.has(k)).sort(compare);
92
+ return `${url.origin}${url.pathname}?${new URLSearchParams(params).toString()}`;
93
+ };
94
+
95
+ const replay = async (input: string | URL | Request, init?: RequestInit): Promise<Response> => {
96
+ const request = new Request(input, init);
97
+ // like fetch: an aborted signal rejects with its reason before anything is answered
98
+ request.signal.throwIfAborted();
99
+ const url = new URL(request.url);
100
+ const method = request.method.toUpperCase();
101
+ const body = method === "GET" || method === "HEAD" ? "" : await request.clone().text();
102
+ const credential =
103
+ secretHeaders.some((h) => request.headers.has(h)) ||
104
+ [...url.searchParams.keys()].some((k) => secretQuery.has(k));
105
+ const wanted = key(url);
106
+ const matches: number[] = [];
107
+ recordings.forEach((r, i) => {
108
+ if (
109
+ (r.method ?? "GET").toUpperCase() === method &&
110
+ key(new URL(r.url)) === wanted &&
111
+ (r.credential === undefined || r.credential === credential) &&
112
+ (r.requestBody === undefined || sameBody(r.requestBody, body))
113
+ ) {
114
+ matches.push(i);
115
+ }
116
+ });
117
+ const index = matches.find((i) => !used.has(i)) ?? matches.at(-1);
118
+ if (index === undefined) {
119
+ throw new Error(`replayFetch: no recording for ${method} ${url.origin}${url.pathname}`);
120
+ }
121
+ used.add(index);
122
+ calls.push({ method, url: `${url.origin}${url.pathname}`, credential });
123
+ const r = recordings[index];
124
+ const status = r.status ?? 200;
125
+ const text = bodyText(r.body);
126
+ const headers = new Headers(r.headers);
127
+ if (text !== null && typeof r.body !== "string" && !headers.has("content-type")) {
128
+ headers.set("content-type", "application/json");
129
+ }
130
+ const nullBody = status === 204 || status === 304 || (status >= 300 && status < 400 && text === null);
131
+ return new Response(nullBody ? null : text, { status, headers });
132
+ };
133
+ return Object.assign(replay, { calls });
134
+ }
135
+
136
+ /**
137
+ * A recorded body as response text.
138
+ * @param body - the recorded body
139
+ * @returns the text, or null for no body
140
+ */
141
+ function bodyText(body: unknown): string | null {
142
+ if (body === undefined || body === null) {
143
+ return null;
144
+ }
145
+ return typeof body === "string" ? body : JSON.stringify(body);
146
+ }
147
+
148
+ /**
149
+ * Compare two query entries by key, then value.
150
+ * @param a - one entry
151
+ * @param b - another
152
+ * @returns the order
153
+ */
154
+ function compare(a: [string, string], b: [string, string]): number {
155
+ return a[0] === b[0] ? a[1].localeCompare(b[1]) : a[0].localeCompare(b[0]);
156
+ }
157
+
158
+ /**
159
+ * Whether two bodies are the same, as JSON when both parse.
160
+ * @param recorded - the recorded body
161
+ * @param sent - the sent body
162
+ * @returns true when they match
163
+ */
164
+ function sameBody(recorded: string, sent: string): boolean {
165
+ try {
166
+ return JSON.stringify(JSON.parse(recorded)) === JSON.stringify(JSON.parse(sent));
167
+ } catch {
168
+ return recorded === sent;
169
+ }
170
+ }
171
+
172
+ /**
173
+ * A recording made from a real exchange, without its credential: the request's headers are never
174
+ * kept, query parameters named in `secretQuery` are removed from the URL, and of the response only
175
+ * the status, the Content-Type and the headers named in `keepHeaders` are kept. Experimental.
176
+ * @param request - the request sent
177
+ * @param response - its response (read; pass a clone to keep using it)
178
+ * @param options - what to keep and drop
179
+ * @param options.keepHeaders - response headers to keep beside Content-Type
180
+ * @param options.secretQuery - query parameters removed from the URL
181
+ * @returns the recording
182
+ * @category Network sources
183
+ */
184
+ export async function recordingFrom(
185
+ request: Request,
186
+ response: Response,
187
+ options: { readonly keepHeaders?: readonly string[]; readonly secretQuery?: readonly string[] } = {},
188
+ ): Promise<Recording> {
189
+ const headers: Record<string, string> = {};
190
+ for (const name of ["content-type", ...(options.keepHeaders ?? [])]) {
191
+ const value = response.headers.get(name);
192
+ if (value !== null) {
193
+ headers[name.toLowerCase()] = value;
194
+ }
195
+ }
196
+ const url = new URL(request.url);
197
+ for (const name of options.secretQuery ?? []) {
198
+ url.searchParams.delete(name);
199
+ }
200
+ const method = request.method.toUpperCase();
201
+ const requestBody = method === "GET" || method === "HEAD" ? undefined : await request.clone().text();
202
+ return {
203
+ method,
204
+ url: url.toString(),
205
+ ...(requestBody === undefined || requestBody === "" ? {} : { requestBody }),
206
+ status: response.status,
207
+ headers,
208
+ body: await response.text(),
209
+ };
210
+ }