@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.
- package/dist/chunks/{approximations-wWjCRzKj.js → approximations-C2riR4NT.js} +2 -2
- package/dist/chunks/{approximations-wWjCRzKj.js.map → approximations-C2riR4NT.js.map} +1 -1
- package/dist/chunks/{block-DiGq58c3.js → block-Cu22ewuS.js} +92 -21
- package/dist/chunks/block-Cu22ewuS.js.map +1 -0
- package/dist/chunks/{choose--jM0yYCo.js → choose-Cdx6Enl2.js} +3 -3
- package/dist/chunks/{choose--jM0yYCo.js.map → choose-Cdx6Enl2.js.map} +1 -1
- package/dist/chunks/codes-CV_Bhcyi.js +153 -0
- package/dist/chunks/codes-CV_Bhcyi.js.map +1 -0
- package/dist/chunks/{constants-BKwqelYD.js → constants-D0LqcsLJ.js} +2 -2
- package/dist/chunks/{constants-BKwqelYD.js.map → constants-D0LqcsLJ.js.map} +1 -1
- package/dist/chunks/context-cgmmOxZ2.js +663 -0
- package/dist/chunks/context-cgmmOxZ2.js.map +1 -0
- package/dist/chunks/credentials-BiQsnMTb.js +347 -0
- package/dist/chunks/credentials-BiQsnMTb.js.map +1 -0
- package/dist/chunks/cx-export-BEeF6ymo.js +259 -0
- package/dist/chunks/cx-export-BEeF6ymo.js.map +1 -0
- package/dist/chunks/descriptor-BJ-W0Jd-.js +137 -0
- package/dist/chunks/descriptor-BJ-W0Jd-.js.map +1 -0
- package/dist/chunks/descriptor-C-YDhtsn.js +48 -0
- package/dist/chunks/descriptor-C-YDhtsn.js.map +1 -0
- package/dist/chunks/{emit-CwU8cUmG.js → emit-CD8xnY8s.js} +70 -10
- package/dist/chunks/emit-CD8xnY8s.js.map +1 -0
- package/dist/chunks/{escape-CgzxiYPg.js → escape-DH2Egt-l.js} +12 -12
- package/dist/chunks/{escape-CgzxiYPg.js.map → escape-DH2Egt-l.js.map} +1 -1
- package/dist/chunks/{export-BvqAXCKh.js → export-CZ7VRm4I.js} +53 -1443
- package/dist/chunks/export-CZ7VRm4I.js.map +1 -0
- package/dist/chunks/{exporter-DndFlGSa.js → exporter-BIdaoIgh.js} +7 -6
- package/dist/chunks/{exporter-DndFlGSa.js.map → exporter-BIdaoIgh.js.map} +1 -1
- package/dist/chunks/{exporter-CJgfhF-l.js → exporter-ChjL5fmP.js} +8 -7
- package/dist/chunks/{exporter-CJgfhF-l.js.map → exporter-ChjL5fmP.js.map} +1 -1
- package/dist/chunks/{exporter--Mk9gXCJ.js → exporter-Dcw7Ldtq.js} +6 -4
- package/dist/chunks/{exporter--Mk9gXCJ.js.map → exporter-Dcw7Ldtq.js.map} +1 -1
- package/dist/chunks/exporter-DtVU80Fa.js +1008 -0
- package/dist/chunks/exporter-DtVU80Fa.js.map +1 -0
- package/dist/chunks/{exporter-CrDWIyiq.js → exporter-bxxjOrDZ.js} +11 -9
- package/dist/chunks/{exporter-CrDWIyiq.js.map → exporter-bxxjOrDZ.js.map} +1 -1
- package/dist/chunks/format-BMS-1Nxb.js +64 -0
- package/dist/chunks/format-BMS-1Nxb.js.map +1 -0
- package/dist/chunks/{generic-Dq1ntt9q.js → generic-CP6YD34u.js} +4 -4
- package/dist/chunks/{generic-Dq1ntt9q.js.map → generic-CP6YD34u.js.map} +1 -1
- package/dist/chunks/{importer-DiZRmOQG.js → importer-B87_fmVx.js} +13 -17
- package/dist/chunks/importer-B87_fmVx.js.map +1 -0
- package/dist/chunks/{importer-BSvfrX_h.js → importer-Bji2MeWr.js} +18 -1014
- package/dist/chunks/importer-Bji2MeWr.js.map +1 -0
- package/dist/chunks/{importer-COTK9Tsl.js → importer-CB_zV5_L.js} +14 -11
- package/dist/chunks/importer-CB_zV5_L.js.map +1 -0
- package/dist/chunks/{importer-e6LGpqHB.js → importer-CVT-JyDE.js} +12 -9
- package/dist/chunks/importer-CVT-JyDE.js.map +1 -0
- package/dist/chunks/{importer-yh_aBCU6.js → importer-Cyy6UseH.js} +7 -6
- package/dist/chunks/{importer-yh_aBCU6.js.map → importer-Cyy6UseH.js.map} +1 -1
- package/dist/chunks/{importer-iFYPEKaJ.js → importer-DPZDN40-.js} +14 -10
- package/dist/chunks/{importer-iFYPEKaJ.js.map → importer-DPZDN40-.js.map} +1 -1
- package/dist/chunks/{importer-CMmeMWlC.js → importer-e3huMZbm.js} +8 -260
- package/dist/chunks/importer-e3huMZbm.js.map +1 -0
- package/dist/chunks/input-Ccg9I22A.js +1397 -0
- package/dist/chunks/input-Ccg9I22A.js.map +1 -0
- package/dist/chunks/{json-elements-DJZRZ6jd.js → json-elements-By172SVq.js} +4 -4
- package/dist/chunks/{json-elements-DJZRZ6jd.js.map → json-elements-By172SVq.js.map} +1 -1
- package/dist/chunks/{lexicon-CT69Kd87.js → lexicon-u2SI5xcx.js} +19 -5
- package/dist/chunks/lexicon-u2SI5xcx.js.map +1 -0
- package/dist/chunks/{ontology-export-G4MqRdux.js → ontology-export-BwgMyuF0.js} +4 -3
- package/dist/chunks/{ontology-export-G4MqRdux.js.map → ontology-export-BwgMyuF0.js.map} +1 -1
- package/dist/chunks/{records-CiaWZrFH.js → records-Cgvxz-Vx.js} +2 -2
- package/dist/chunks/{records-CiaWZrFH.js.map → records-Cgvxz-Vx.js.map} +1 -1
- package/dist/chunks/{format-BpQBx8MZ.js → report-CgdsL9Hb.js} +72 -129
- package/dist/chunks/report-CgdsL9Hb.js.map +1 -0
- package/dist/chunks/sigv4-LkAzsLAu.js +247 -0
- package/dist/chunks/sigv4-LkAzsLAu.js.map +1 -0
- package/dist/chunks/{styles-BQnsga7p.js → styles-CaABMoO1.js} +76 -43
- package/dist/chunks/styles-CaABMoO1.js.map +1 -0
- package/dist/chunks/{styles-D3fRphrO.js → styles-P_gmFAOi.js} +101 -21
- package/dist/chunks/styles-P_gmFAOi.js.map +1 -0
- package/dist/chunks/{styles-yed-BF5x3_Y5.js → styles-yed-Cs1nmrjn.js} +60 -20
- package/dist/chunks/styles-yed-Cs1nmrjn.js.map +1 -0
- package/dist/chunks/{text-CzJNFOS9.js → text-BuKQVMz2.js} +2 -2
- package/dist/chunks/{text-CzJNFOS9.js.map → text-BuKQVMz2.js.map} +1 -1
- package/dist/chunks/{writer-DMKvthQE.js → writer-DvHTl36J.js} +5 -4
- package/dist/chunks/writer-DvHTl36J.js.map +1 -0
- package/dist/csv.js +7 -5
- package/dist/csv.js.map +1 -1
- package/dist/cx.js +5 -4
- package/dist/cx.js.map +1 -1
- package/dist/cx2.js +2 -2
- package/dist/cys.js +1 -1
- package/dist/dot.js +2 -2
- package/dist/gexf.js +7 -5
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +16 -13
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +1181 -224
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +3 -3
- package/dist/json.js +1 -1
- package/dist/neo4j.js +6 -4
- package/dist/neo4j.js.map +1 -1
- package/dist/obo.js +1 -1
- package/dist/pajek.js +1 -1
- package/dist/sources-cypher.d.ts +1 -0
- package/dist/sources-cypher.js +1236 -0
- package/dist/sources-cypher.js.map +1 -0
- package/dist/sources-ndex.d.ts +1 -0
- package/dist/sources-ndex.js +278 -0
- package/dist/sources-ndex.js.map +1 -0
- package/dist/sources-rest.d.ts +1 -0
- package/dist/sources-rest.js +1367 -0
- package/dist/sources-rest.js.map +1 -0
- package/dist/src/common/report.d.ts +6 -3
- package/dist/src/common/report.d.ts.map +1 -1
- package/dist/src/common/report.js +15 -9
- package/dist/src/common/report.js.map +1 -1
- package/dist/src/formats/cx/styles.d.ts.map +1 -1
- package/dist/src/formats/cx/styles.js +1 -0
- package/dist/src/formats/cx/styles.js.map +1 -1
- package/dist/src/formats/dot/styles.d.ts.map +1 -1
- package/dist/src/formats/dot/styles.js +3 -1
- package/dist/src/formats/dot/styles.js.map +1 -1
- package/dist/src/formats/gexf/styles.d.ts +29 -12
- package/dist/src/formats/gexf/styles.d.ts.map +1 -1
- package/dist/src/formats/gexf/styles.js +160 -31
- package/dist/src/formats/gexf/styles.js.map +1 -1
- package/dist/src/formats/gml/styles.d.ts.map +1 -1
- package/dist/src/formats/gml/styles.js +5 -4
- package/dist/src/formats/gml/styles.js.map +1 -1
- package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-plain.js +3 -3
- package/dist/src/formats/graphml/styles-plain.js.map +1 -1
- package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-yed.js +89 -19
- package/dist/src/formats/graphml/styles-yed.js.map +1 -1
- package/dist/src/formats/pajek/styles.d.ts.map +1 -1
- package/dist/src/formats/pajek/styles.js +1 -0
- package/dist/src/formats/pajek/styles.js.map +1 -1
- package/dist/src/formats/xgmml/styles.d.ts.map +1 -1
- package/dist/src/formats/xgmml/styles.js +1 -0
- package/dist/src/formats/xgmml/styles.js.map +1 -1
- package/dist/src/index.d.ts +8 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/registry.d.ts +173 -1
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +196 -1
- package/dist/src/registry.js.map +1 -1
- package/dist/src/sources/builtins.d.ts +11 -0
- package/dist/src/sources/builtins.d.ts.map +1 -0
- package/dist/src/sources/builtins.js +47 -0
- package/dist/src/sources/builtins.js.map +1 -0
- package/dist/src/sources/codes.d.ts +230 -0
- package/dist/src/sources/codes.d.ts.map +1 -0
- package/dist/src/sources/codes.js +58 -0
- package/dist/src/sources/codes.js.map +1 -0
- package/dist/src/sources/context.d.ts +112 -0
- package/dist/src/sources/context.d.ts.map +1 -0
- package/dist/src/sources/context.js +739 -0
- package/dist/src/sources/context.js.map +1 -0
- package/dist/src/sources/credentials.d.ts +179 -0
- package/dist/src/sources/credentials.d.ts.map +1 -0
- package/dist/src/sources/credentials.js +301 -0
- package/dist/src/sources/credentials.js.map +1 -0
- package/dist/src/sources/cypher/descriptor.d.ts +21 -0
- package/dist/src/sources/cypher/descriptor.d.ts.map +1 -0
- package/dist/src/sources/cypher/descriptor.js +119 -0
- package/dist/src/sources/cypher/descriptor.js.map +1 -0
- package/dist/src/sources/cypher/flatten.d.ts +72 -0
- package/dist/src/sources/cypher/flatten.d.ts.map +1 -0
- package/dist/src/sources/cypher/flatten.js +279 -0
- package/dist/src/sources/cypher/flatten.js.map +1 -0
- package/dist/src/sources/cypher/index.d.ts +33 -0
- package/dist/src/sources/cypher/index.d.ts.map +1 -0
- package/dist/src/sources/cypher/index.js +405 -0
- package/dist/src/sources/cypher/index.js.map +1 -0
- package/dist/src/sources/cypher/params.d.ts +40 -0
- package/dist/src/sources/cypher/params.d.ts.map +1 -0
- package/dist/src/sources/cypher/params.js +6 -0
- package/dist/src/sources/cypher/params.js.map +1 -0
- package/dist/src/sources/cypher/profiles.d.ts +44 -0
- package/dist/src/sources/cypher/profiles.d.ts.map +1 -0
- package/dist/src/sources/cypher/profiles.js +61 -0
- package/dist/src/sources/cypher/profiles.js.map +1 -0
- package/dist/src/sources/cypher/query-builder.d.ts +106 -0
- package/dist/src/sources/cypher/query-builder.d.ts.map +1 -0
- package/dist/src/sources/cypher/query-builder.js +236 -0
- package/dist/src/sources/cypher/query-builder.js.map +1 -0
- package/dist/src/sources/cypher/transports/bolt.d.ts +21 -0
- package/dist/src/sources/cypher/transports/bolt.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/bolt.js +185 -0
- package/dist/src/sources/cypher/transports/bolt.js.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.d.ts +15 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.js +38 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.js.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-https.d.ts +31 -0
- package/dist/src/sources/cypher/transports/neptune-https.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-https.js +104 -0
- package/dist/src/sources/cypher/transports/neptune-https.js.map +1 -0
- package/dist/src/sources/cypher/transports/query-api.d.ts +14 -0
- package/dist/src/sources/cypher/transports/query-api.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/query-api.js +80 -0
- package/dist/src/sources/cypher/transports/query-api.js.map +1 -0
- package/dist/src/sources/cypher/transports/transport.d.ts +78 -0
- package/dist/src/sources/cypher/transports/transport.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/transport.js +77 -0
- package/dist/src/sources/cypher/transports/transport.js.map +1 -0
- package/dist/src/sources/cypher/types-map.d.ts +91 -0
- package/dist/src/sources/cypher/types-map.d.ts.map +1 -0
- package/dist/src/sources/cypher/types-map.js +306 -0
- package/dist/src/sources/cypher/types-map.js.map +1 -0
- package/dist/src/sources/define.d.ts +47 -0
- package/dist/src/sources/define.d.ts.map +1 -0
- package/dist/src/sources/define.js +173 -0
- package/dist/src/sources/define.js.map +1 -0
- package/dist/src/sources/fail.d.ts +33 -0
- package/dist/src/sources/fail.d.ts.map +1 -0
- package/dist/src/sources/fail.js +49 -0
- package/dist/src/sources/fail.js.map +1 -0
- package/dist/src/sources/ids.d.ts +64 -0
- package/dist/src/sources/ids.d.ts.map +1 -0
- package/dist/src/sources/ids.js +64 -0
- package/dist/src/sources/ids.js.map +1 -0
- package/dist/src/sources/ndex/client.d.ts +31 -0
- package/dist/src/sources/ndex/client.d.ts.map +1 -0
- package/dist/src/sources/ndex/client.js +90 -0
- package/dist/src/sources/ndex/client.js.map +1 -0
- package/dist/src/sources/ndex/descriptor.d.ts +10 -0
- package/dist/src/sources/ndex/descriptor.d.ts.map +1 -0
- package/dist/src/sources/ndex/descriptor.js +55 -0
- package/dist/src/sources/ndex/descriptor.js.map +1 -0
- package/dist/src/sources/ndex/expand.d.ts +20 -0
- package/dist/src/sources/ndex/expand.d.ts.map +1 -0
- package/dist/src/sources/ndex/expand.js +87 -0
- package/dist/src/sources/ndex/expand.js.map +1 -0
- package/dist/src/sources/ndex/index.d.ts +25 -0
- package/dist/src/sources/ndex/index.d.ts.map +1 -0
- package/dist/src/sources/ndex/index.js +191 -0
- package/dist/src/sources/ndex/index.js.map +1 -0
- package/dist/src/sources/ndex/params.d.ts +17 -0
- package/dist/src/sources/ndex/params.d.ts.map +1 -0
- package/dist/src/sources/ndex/params.js +6 -0
- package/dist/src/sources/ndex/params.js.map +1 -0
- package/dist/src/sources/ndex/share-url.d.ts +40 -0
- package/dist/src/sources/ndex/share-url.d.ts.map +1 -0
- package/dist/src/sources/ndex/share-url.js +64 -0
- package/dist/src/sources/ndex/share-url.js.map +1 -0
- package/dist/src/sources/params.d.ts +28 -0
- package/dist/src/sources/params.d.ts.map +1 -0
- package/dist/src/sources/params.js +6 -0
- package/dist/src/sources/params.js.map +1 -0
- package/dist/src/sources/registry.d.ts +118 -0
- package/dist/src/sources/registry.d.ts.map +1 -0
- package/dist/src/sources/registry.js +193 -0
- package/dist/src/sources/registry.js.map +1 -0
- package/dist/src/sources/rest/descriptor.d.ts +16 -0
- package/dist/src/sources/rest/descriptor.d.ts.map +1 -0
- package/dist/src/sources/rest/descriptor.js +71 -0
- package/dist/src/sources/rest/descriptor.js.map +1 -0
- package/dist/src/sources/rest/index.d.ts +14 -0
- package/dist/src/sources/rest/index.d.ts.map +1 -0
- package/dist/src/sources/rest/index.js +13 -0
- package/dist/src/sources/rest/index.js.map +1 -0
- package/dist/src/sources/rest/mapping.d.ts +30 -0
- package/dist/src/sources/rest/mapping.d.ts.map +1 -0
- package/dist/src/sources/rest/mapping.js +362 -0
- package/dist/src/sources/rest/mapping.js.map +1 -0
- package/dist/src/sources/rest/openalex.d.ts +27 -0
- package/dist/src/sources/rest/openalex.d.ts.map +1 -0
- package/dist/src/sources/rest/openalex.js +269 -0
- package/dist/src/sources/rest/openalex.js.map +1 -0
- package/dist/src/sources/rest/paging.d.ts +53 -0
- package/dist/src/sources/rest/paging.d.ts.map +1 -0
- package/dist/src/sources/rest/paging.js +138 -0
- package/dist/src/sources/rest/paging.js.map +1 -0
- package/dist/src/sources/rest/params.d.ts +216 -0
- package/dist/src/sources/rest/params.d.ts.map +1 -0
- package/dist/src/sources/rest/params.js +7 -0
- package/dist/src/sources/rest/params.js.map +1 -0
- package/dist/src/sources/rest/records.d.ts +41 -0
- package/dist/src/sources/rest/records.d.ts.map +1 -0
- package/dist/src/sources/rest/records.js +240 -0
- package/dist/src/sources/rest/records.js.map +1 -0
- package/dist/src/sources/rest/samples/deps-dev.d.ts +10 -0
- package/dist/src/sources/rest/samples/deps-dev.d.ts.map +1 -0
- package/dist/src/sources/rest/samples/deps-dev.js +47 -0
- package/dist/src/sources/rest/samples/deps-dev.js.map +1 -0
- package/dist/src/sources/rest/samples/string.d.ts +9 -0
- package/dist/src/sources/rest/samples/string.d.ts.map +1 -0
- package/dist/src/sources/rest/samples/string.js +42 -0
- package/dist/src/sources/rest/samples/string.js.map +1 -0
- package/dist/src/sources/rest/selectors.d.ts +41 -0
- package/dist/src/sources/rest/selectors.d.ts.map +1 -0
- package/dist/src/sources/rest/selectors.js +81 -0
- package/dist/src/sources/rest/selectors.js.map +1 -0
- package/dist/src/sources/rest/source.d.ts +67 -0
- package/dist/src/sources/rest/source.d.ts.map +1 -0
- package/dist/src/sources/rest/source.js +635 -0
- package/dist/src/sources/rest/source.js.map +1 -0
- package/dist/src/sources/rest/templates.d.ts +38 -0
- package/dist/src/sources/rest/templates.d.ts.map +1 -0
- package/dist/src/sources/rest/templates.js +125 -0
- package/dist/src/sources/rest/templates.js.map +1 -0
- package/dist/src/sources/run.d.ts +93 -0
- package/dist/src/sources/run.d.ts.map +1 -0
- package/dist/src/sources/run.js +673 -0
- package/dist/src/sources/run.js.map +1 -0
- package/dist/src/sources/sha256.d.ts +12 -0
- package/dist/src/sources/sha256.d.ts.map +1 -0
- package/dist/src/sources/sha256.js +95 -0
- package/dist/src/sources/sha256.js.map +1 -0
- package/dist/src/sources/sigv4.d.ts +24 -0
- package/dist/src/sources/sigv4.d.ts.map +1 -0
- package/dist/src/sources/sigv4.js +182 -0
- package/dist/src/sources/sigv4.js.map +1 -0
- package/dist/src/sources/testing.d.ts +96 -0
- package/dist/src/sources/testing.d.ts.map +1 -0
- package/dist/src/sources/testing.js +138 -0
- package/dist/src/sources/testing.js.map +1 -0
- package/dist/src/sources/types.d.ts +665 -0
- package/dist/src/sources/types.d.ts.map +1 -0
- package/dist/src/sources/types.js +10 -0
- package/dist/src/sources/types.js.map +1 -0
- package/dist/src/styles/canon/enums.d.ts.map +1 -1
- package/dist/src/styles/canon/enums.js +1 -0
- package/dist/src/styles/canon/enums.js.map +1 -1
- package/dist/src/styles/cyjs/cascade.d.ts.map +1 -1
- package/dist/src/styles/cyjs/cascade.js +68 -2
- package/dist/src/styles/cyjs/cascade.js.map +1 -1
- package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -1
- package/dist/src/styles/cyjs/defaults-table.js +2 -0
- package/dist/src/styles/cyjs/defaults-table.js.map +1 -1
- package/dist/src/styles/cyjs/emit.d.ts.map +1 -1
- package/dist/src/styles/cyjs/emit.js +18 -7
- package/dist/src/styles/cyjs/emit.js.map +1 -1
- package/dist/src/styles/cyjs/mappers.d.ts +4 -1
- package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
- package/dist/src/styles/cyjs/mappers.js +2 -0
- package/dist/src/styles/cyjs/mappers.js.map +1 -1
- package/dist/src/styles/cytoscape/emit.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/emit.js +59 -7
- package/dist/src/styles/cytoscape/emit.js.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.d.ts +6 -0
- package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.js +26 -2
- package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
- package/dist/src/styles/cytoscape/resolve.d.ts +4 -1
- package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/resolve.js +10 -6
- package/dist/src/styles/cytoscape/resolve.js.map +1 -1
- package/dist/src/styles/cytoscape/translate.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/translate.js +10 -10
- package/dist/src/styles/cytoscape/translate.js.map +1 -1
- package/dist/src/styles/defaults.d.ts +30 -0
- package/dist/src/styles/defaults.d.ts.map +1 -1
- package/dist/src/styles/defaults.js +45 -4
- package/dist/src/styles/defaults.js.map +1 -1
- package/dist/src/styles/io/block.d.ts.map +1 -1
- package/dist/src/styles/io/block.js +9 -0
- package/dist/src/styles/io/block.js.map +1 -1
- package/dist/src/styles/io/writer.d.ts.map +1 -1
- package/dist/src/styles/io/writer.js +7 -3
- package/dist/src/styles/io/writer.js.map +1 -1
- package/dist/src/styles/plan/resolve.d.ts +2 -1
- package/dist/src/styles/plan/resolve.d.ts.map +1 -1
- package/dist/src/styles/plan/resolve.js +13 -2
- package/dist/src/styles/plan/resolve.js.map +1 -1
- package/dist/src/styles/types.d.ts +19 -2
- package/dist/src/styles/types.d.ts.map +1 -1
- package/dist/src/styles/vocabulary.d.ts.map +1 -1
- package/dist/src/styles/vocabulary.js +15 -1
- package/dist/src/styles/vocabulary.js.map +1 -1
- package/dist/src/types.d.ts +19 -5
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/styles.js +11 -11
- package/dist/xgmml.js +3 -3
- package/docs/samples/people.json +6 -0
- package/package.json +29 -4
- package/src/common/report.ts +27 -7
- package/src/formats/cx/styles.ts +1 -0
- package/src/formats/dot/styles.ts +3 -1
- package/src/formats/gexf/styles.ts +185 -37
- package/src/formats/gml/styles.ts +5 -4
- package/src/formats/graphml/styles-plain.ts +3 -9
- package/src/formats/graphml/styles-yed.ts +93 -20
- package/src/formats/pajek/styles.ts +1 -0
- package/src/formats/xgmml/styles.ts +1 -0
- package/src/index.ts +90 -0
- package/src/registry.ts +326 -1
- package/src/sources/builtins.ts +56 -0
- package/src/sources/codes.ts +235 -0
- package/src/sources/context.ts +893 -0
- package/src/sources/credentials.ts +409 -0
- package/src/sources/cypher/descriptor.ts +125 -0
- package/src/sources/cypher/flatten.ts +323 -0
- package/src/sources/cypher/index.ts +498 -0
- package/src/sources/cypher/params.ts +41 -0
- package/src/sources/cypher/profiles.ts +78 -0
- package/src/sources/cypher/query-builder.ts +294 -0
- package/src/sources/cypher/transports/bolt.ts +228 -0
- package/src/sources/cypher/transports/neptune-analytics.ts +41 -0
- package/src/sources/cypher/transports/neptune-https.ts +122 -0
- package/src/sources/cypher/transports/query-api.ts +100 -0
- package/src/sources/cypher/transports/transport.ts +139 -0
- package/src/sources/cypher/types-map.ts +418 -0
- package/src/sources/define.ts +195 -0
- package/src/sources/fail.ts +70 -0
- package/src/sources/ids.ts +74 -0
- package/src/sources/ndex/client.ts +102 -0
- package/src/sources/ndex/descriptor.ts +64 -0
- package/src/sources/ndex/expand.ts +100 -0
- package/src/sources/ndex/index.ts +235 -0
- package/src/sources/ndex/params.ts +17 -0
- package/src/sources/ndex/share-url.ts +84 -0
- package/src/sources/params.ts +29 -0
- package/src/sources/registry.ts +325 -0
- package/src/sources/rest/descriptor.ts +74 -0
- package/src/sources/rest/index.ts +22 -0
- package/src/sources/rest/mapping.ts +401 -0
- package/src/sources/rest/openalex.ts +288 -0
- package/src/sources/rest/paging.ts +180 -0
- package/src/sources/rest/params.ts +243 -0
- package/src/sources/rest/records.ts +289 -0
- package/src/sources/rest/samples/deps-dev.ts +49 -0
- package/src/sources/rest/samples/string.ts +44 -0
- package/src/sources/rest/selectors.ts +91 -0
- package/src/sources/rest/source.ts +760 -0
- package/src/sources/rest/templates.ts +151 -0
- package/src/sources/run.ts +793 -0
- package/src/sources/sha256.ts +99 -0
- package/src/sources/sigv4.ts +207 -0
- package/src/sources/testing.ts +210 -0
- package/src/sources/types.ts +741 -0
- package/src/styles/canon/enums.ts +1 -0
- package/src/styles/cyjs/cascade.ts +81 -2
- package/src/styles/cyjs/defaults-table.ts +2 -0
- package/src/styles/cyjs/emit.ts +18 -7
- package/src/styles/cyjs/mappers.ts +6 -1
- package/src/styles/cytoscape/emit.ts +61 -7
- package/src/styles/cytoscape/lexicon.ts +28 -2
- package/src/styles/cytoscape/resolve.ts +22 -6
- package/src/styles/cytoscape/translate.ts +11 -11
- package/src/styles/defaults.ts +93 -4
- package/src/styles/io/block.ts +10 -0
- package/src/styles/io/writer.ts +8 -3
- package/src/styles/plan/resolve.ts +14 -2
- package/src/styles/types.ts +28 -2
- package/src/styles/vocabulary.ts +15 -1
- package/src/types.ts +19 -5
- package/dist/chunks/block-DiGq58c3.js.map +0 -1
- package/dist/chunks/emit-CwU8cUmG.js.map +0 -1
- package/dist/chunks/export-BvqAXCKh.js.map +0 -1
- package/dist/chunks/format-BpQBx8MZ.js.map +0 -1
- package/dist/chunks/importer-BSvfrX_h.js.map +0 -1
- package/dist/chunks/importer-CMmeMWlC.js.map +0 -1
- package/dist/chunks/importer-COTK9Tsl.js.map +0 -1
- package/dist/chunks/importer-DiZRmOQG.js.map +0 -1
- package/dist/chunks/importer-e6LGpqHB.js.map +0 -1
- package/dist/chunks/lexicon-CT69Kd87.js.map +0 -1
- package/dist/chunks/styles-BQnsga7p.js.map +0 -1
- package/dist/chunks/styles-D3fRphrO.js.map +0 -1
- package/dist/chunks/styles-yed-BF5x3_Y5.js.map +0 -1
- package/dist/chunks/writer-DMKvthQE.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sources-cypher.js","sources":["../src/sources/cypher/types-map.ts","../src/sources/cypher/flatten.ts","../src/sources/cypher/profiles.ts","../src/sources/cypher/query-builder.ts","../src/sources/cypher/transports/transport.ts","../src/sources/cypher/transports/bolt.ts","../src/sources/cypher/transports/neptune-https.ts","../src/sources/cypher/transports/neptune-analytics.ts","../src/sources/cypher/transports/query-api.ts","../src/sources/cypher/index.ts"],"sourcesContent":["/**\n * The one type mapper of the Cypher source (design section 10): every transport's wire values --\n * Neo4j's typed JSON, neo4j-driver's objects, Neptune's plain JSON -- become the same plain values,\n * and every node, relationship and path becomes a GraphNode, a GraphRel or an array of them.\n *\n * - Integers: a number while it is exact; past 2^53 the `long` parameter picks a rounded number\n * (W_PRECISION, once per column) or the exact digits as a string.\n * - Floats, booleans, strings: as they are. Dates and instants: epoch milliseconds. Local times,\n * times and durations: their ISO text. Points: `{ srid, x, y, z? }`. Lists and maps: arrays and\n * objects of mapped values. Bytes: dropped (W_SOURCE_VALUE).\n */\n\nimport { PRECISION_CODE } from \"../../common/codes.js\";\nimport { type ImportReportBuilder } from \"../../common/report.js\";\nimport { warnOn } from \"../fail.js\";\n\n/** A node a query returned. */\nexport class GraphNode {\n /**\n * Create one.\n * @param id - the server's element id\n * @param labels - its labels\n * @param properties - its mapped properties\n */\n constructor(\n readonly id: string,\n readonly labels: readonly string[],\n readonly properties: Readonly<Record<string, unknown>>,\n ) {}\n}\n\n/** A relationship a query returned. */\nexport class GraphRel {\n /**\n * Create one.\n * @param id - the server's element id\n * @param start - the start node's element id\n * @param end - the end node's element id\n * @param type - its type\n * @param properties - its mapped properties\n */\n constructor(\n readonly id: string,\n readonly start: string,\n readonly end: string,\n readonly type: string,\n readonly properties: Readonly<Record<string, unknown>>,\n ) {}\n}\n\n/** What the mapper needs: the `long` choice and the report its warnings go to. */\nexport interface MapContext {\n /** Integers past 2^53: \"f64\" (rounded, W_PRECISION) or \"string\". */\n readonly long: \"f64\" | \"string\";\n /** The load's report. */\n readonly report: ImportReportBuilder;\n}\n\n/** Values past this need a 64-bit integer. */\nconst SAFE = BigInt(Number.MAX_SAFE_INTEGER);\n\n/**\n * An integer from its exact decimal digits.\n * @param digits - the digits\n * @param column - the column it belongs to, for the warning\n * @param m - the map context\n * @returns a number, or a string past 2^53 under `long: \"string\"`\n */\nfunction integer(digits: string, column: string, m: MapContext): number | string {\n let big: bigint;\n try {\n big = BigInt(digits);\n } catch {\n return Number(digits);\n }\n if (big <= SAFE && big >= -SAFE) {\n return Number(big);\n }\n if (m.long === \"string\") {\n return big.toString();\n }\n m.report.warnOnce(\n \"precision\",\n PRECISION_CODE,\n `column ${column}: an integer beyond 2^53 was stored as the nearest 64-bit float; pass long: \"string\" to keep every digit`,\n undefined,\n `${PRECISION_CODE}:${column}`,\n );\n return Number(big);\n}\n\n/**\n * Epoch milliseconds of an ISO instant, the zone name in brackets ignored; the text itself when it\n * does not parse.\n * @param text - the ISO text\n * @param type - the server's type name\n * @param column - the column\n * @param m - the map context\n * @returns milliseconds, or the text\n */\nfunction epoch(text: string, type: string, column: string, m: MapContext): number | string {\n const ms = Date.parse(withoutZoneName(text));\n if (Number.isNaN(ms)) {\n warnOn(m.report, \"W_SOURCE_VALUE\", `column ${column}: a ${type} kept as text`, { type, column, as: \"string\" });\n return text;\n }\n return ms;\n}\n\n/**\n * Warn that a value with no dtype was dropped; the caller leaves the property out.\n * @param type - the server's type name\n * @param column - the column\n * @param m - the map context\n */\nfunction dropped(type: string, column: string, m: MapContext): void {\n warnOn(m.report, \"W_SOURCE_VALUE\", `column ${column}: a ${type} value was dropped`, {\n type,\n column,\n as: \"dropped\",\n });\n}\n\n/**\n * Map every property of a map, leaving out dropped values.\n * @param value - the map\n * @param each - maps one value, given its key\n * @returns the mapped map\n */\nfunction mapEntries(\n value: Readonly<Record<string, unknown>>,\n each: (v: unknown, key: string) => unknown,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n const mapped = each(v, k);\n if (mapped !== undefined) {\n out[k] = mapped;\n }\n }\n return out;\n}\n\n/**\n * A WKT point as Neo4j's typed JSON spells it (\"SRID=7203;POINT (1.0 2.0)\").\n * @param text - the text\n * @returns `{ srid, x, y, z? }`, or the text when it does not parse\n */\nfunction wktPoint(text: string): unknown {\n const match = /^SRID=(\\d+);POINT(?: Z)? ?\\(([^)]*)\\)$/i.exec(text.trim());\n if (match === null) {\n return text;\n }\n const [x = 0, y = 0, z] = match[2].trim().split(/\\s+/).map(Number);\n return z === undefined ? { srid: Number(match[1]), x, y } : { srid: Number(match[1]), x, y, z };\n}\n\n/** One typed JSON value: `{ \"$type\": \"Integer\", \"_value\": \"42\" }`. */\ninterface Typed {\n readonly $type: string;\n readonly _value: unknown;\n}\n\n/** The shape of a typed JSON node's value. */\ninterface TypedNode {\n readonly _element_id: string;\n readonly _labels: readonly string[];\n readonly _properties: Readonly<Record<string, unknown>>;\n}\n\n/** The shape of a typed JSON relationship's value. */\ninterface TypedRel {\n readonly _element_id: string;\n readonly _start_node_element_id: string;\n readonly _end_node_element_id: string;\n readonly _type: string;\n readonly _properties: Readonly<Record<string, unknown>>;\n}\n\n/**\n * Map a value of Neo4j's typed JSON (the Query API's `application/vnd.neo4j.query.v1.1`).\n * @param v - the wire value\n * @param column - the result column or property key it belongs to\n * @param m - the map context\n * @returns the plain value, a GraphNode, a GraphRel or an array; undefined when dropped\n */\nexport function fromTypedJson(v: unknown, column: string, m: MapContext): unknown {\n if (v === null || typeof v !== \"object\" || !(\"$type\" in v)) {\n return v ?? null;\n }\n const { $type: type, _value: value } = v as Typed;\n switch (type) {\n case \"Null\":\n return null;\n case \"Boolean\":\n case \"String\":\n return value;\n case \"Integer\":\n return integer(String(value), column, m);\n case \"Float\":\n return Number(value);\n case \"Date\":\n return epoch(`${String(value)}T00:00:00Z`, type, column, m);\n case \"OffsetDateTime\":\n case \"ZonedDateTime\":\n return epoch(String(value), type, column, m);\n case \"LocalDateTime\":\n case \"LocalTime\":\n case \"Time\":\n case \"Duration\":\n return String(value);\n case \"Point\":\n return wktPoint(String(value));\n case \"Base64\":\n dropped(type, column, m);\n return undefined;\n case \"List\":\n return (value as readonly unknown[]).map((x) => fromTypedJson(x, column, m));\n case \"Map\":\n return mapEntries(value as Record<string, unknown>, (x) => fromTypedJson(x, column, m));\n case \"Node\": {\n const n = value as TypedNode;\n return new GraphNode(\n n._element_id,\n n._labels,\n mapEntries(n._properties, (x, k) => fromTypedJson(x, k, m)),\n );\n }\n case \"Relationship\": {\n const r = value as TypedRel;\n return new GraphRel(\n r._element_id,\n r._start_node_element_id,\n r._end_node_element_id,\n r._type,\n mapEntries(r._properties, (x, k) => fromTypedJson(x, k, m)),\n );\n }\n case \"Path\":\n return (value as readonly unknown[]).map((x) => fromTypedJson(x, column, m));\n default:\n warnOn(m.report, \"W_SOURCE_VALUE\", `column ${column}: a ${type} kept as text`, {\n type,\n column,\n as: \"string\",\n });\n return typeof value === \"string\" ? value : JSON.stringify(value);\n }\n}\n\n/** The parts of neo4j-driver the mapper uses: its type checks. */\nexport interface DriverTypes {\n isInt(v: unknown): boolean;\n isNode(v: unknown): boolean;\n isRelationship(v: unknown): boolean;\n isPath(v: unknown): boolean;\n isPoint(v: unknown): boolean;\n isDate(v: unknown): boolean;\n isDateTime(v: unknown): boolean;\n isLocalDateTime(v: unknown): boolean;\n isLocalTime(v: unknown): boolean;\n isTime(v: unknown): boolean;\n isDuration(v: unknown): boolean;\n}\n\n/** A driver node or relationship, as far as the mapper reads it. */\ninterface DriverEntity {\n readonly identity: unknown;\n readonly elementId?: string;\n readonly labels?: readonly string[];\n readonly type?: string;\n readonly start?: unknown;\n readonly end?: unknown;\n readonly startNodeElementId?: string;\n readonly endNodeElementId?: string;\n readonly properties: Readonly<Record<string, unknown>>;\n}\n\n/** A driver path. */\ninterface DriverPath {\n readonly start: unknown;\n readonly segments: readonly { readonly relationship: unknown; readonly end: unknown }[];\n}\n\n/** A driver point. */\ninterface DriverPoint {\n readonly srid: unknown;\n readonly x: number;\n readonly y: number;\n readonly z?: number;\n}\n\n/**\n * The text without a trailing bracketed zone name (`...+01:00[Europe/Paris]`).\n * @param text - the ISO text\n * @returns the text without the zone name\n */\nfunction withoutZoneName(text: string): string {\n const end = text.length - 1;\n if (text[end] !== \"]\") {\n return text;\n }\n const open = text.indexOf(\"[\", text.lastIndexOf(\"]\", end - 1) + 1);\n return open === -1 || open >= end ? text : text.slice(0, open);\n}\n\n/**\n * Map a driver node or relationship.\n * @param e - the driver entity\n * @param node - whether it is a node\n * @param m - the map context\n * @param t - the driver's type checks\n * @returns a GraphNode or a GraphRel\n */\nfunction fromEntity(e: DriverEntity, node: boolean, m: MapContext, t: DriverTypes): GraphNode | GraphRel {\n const props = mapEntries(e.properties, (x, k) => fromDriver(x, k, m, t));\n const id = e.elementId ?? String(e.identity);\n return node\n ? new GraphNode(id, [...(e.labels ?? [])], props)\n : new GraphRel(\n id,\n e.startNodeElementId ?? String(e.start),\n e.endNodeElementId ?? String(e.end),\n e.type ?? \"\",\n props,\n );\n}\n\n/**\n * Map a driver point.\n * @param p - the point\n * @returns srid, x, y and z when it has one\n */\nfunction fromPoint(p: DriverPoint): { srid: number; x: number; y: number; z?: number } {\n const srid = Number(String(p.srid));\n return p.z === undefined ? { srid, x: p.x, y: p.y } : { srid, x: p.x, y: p.y, z: p.z };\n}\n\n/**\n * Map a value neo4j-driver returned. Its lossless Integer keeps every digit, so `long` decides.\n * @param v - the driver value\n * @param column - the result column or property key\n * @param m - the map context\n * @param t - the driver's type checks\n * @returns the plain value, a GraphNode, a GraphRel or an array; undefined when dropped\n */\nexport function fromDriver(v: unknown, column: string, m: MapContext, t: DriverTypes): unknown {\n if (v === null || v === undefined) {\n return null;\n }\n if (typeof v !== \"object\") {\n return typeof v === \"bigint\" ? integer(v.toString(), column, m) : v;\n }\n // driver values (Integer, the temporal types) spell themselves exactly through toString()\n const text = (): string => (v as { toString(): string }).toString();\n if (t.isInt(v)) {\n return integer(text(), column, m);\n }\n if (t.isNode(v) || t.isRelationship(v)) {\n return fromEntity(v as DriverEntity, t.isNode(v), m, t);\n }\n if (t.isPath(v)) {\n const p = v as DriverPath;\n return [p.start, ...p.segments.flatMap((s) => [s.relationship, s.end])].map((x) => fromDriver(x, column, m, t));\n }\n if (t.isDate(v)) {\n return epoch(`${text()}T00:00:00Z`, \"Date\", column, m);\n }\n if (t.isDateTime(v)) {\n return epoch(text(), \"DateTime\", column, m);\n }\n if (t.isLocalDateTime(v) || t.isLocalTime(v) || t.isTime(v) || t.isDuration(v)) {\n return text();\n }\n if (t.isPoint(v)) {\n return fromPoint(v as DriverPoint);\n }\n if (v instanceof Uint8Array || v instanceof ArrayBuffer) {\n dropped(\"ByteArray\", column, m);\n return undefined;\n }\n if (Array.isArray(v)) {\n return v.map((x: unknown) => fromDriver(x, column, m, t));\n }\n return mapEntries(v as Record<string, unknown>, (x) => fromDriver(x, column, m, t));\n}\n\n/**\n * Map a value of Neptune's openCypher JSON: nodes `{ \"~id\", \"~entityType\": \"node\", \"~labels\",\n * \"~properties\" }`, relationships adding `~start`, `~end`, `~type`. Its numbers are plain JSON, so\n * an integer past 2^53 was already rounded on the wire (W_PRECISION).\n * @param v - the wire value\n * @param column - the result column or property key\n * @param m - the map context\n * @returns the plain value, a GraphNode, a GraphRel or an array\n */\nexport function fromNeptune(v: unknown, column: string, m: MapContext): unknown {\n if (typeof v === \"number\" && Number.isInteger(v) && !Number.isSafeInteger(v)) {\n return integer(BigInt(v).toString(), column, m);\n }\n if (v === null || typeof v !== \"object\") {\n return v ?? null;\n }\n if (Array.isArray(v)) {\n return v.map((x: unknown) => fromNeptune(x, column, m));\n }\n const o = v as Record<string, unknown>;\n const props = (): Record<string, unknown> =>\n mapEntries((o[\"~properties\"] ?? {}) as Record<string, unknown>, (x, k) => fromNeptune(x, k, m));\n switch (o[\"~entityType\"]) {\n case \"node\":\n return new GraphNode(String(o[\"~id\"]), (o[\"~labels\"] ?? []) as string[], props());\n case \"relationship\":\n return new GraphRel(String(o[\"~id\"]), String(o[\"~start\"]), String(o[\"~end\"]), String(o[\"~type\"]), props());\n default:\n return mapEntries(o, (x) => fromNeptune(x, column, m));\n }\n}\n","/**\n * The one result flattener of the Cypher source (design section 5): every node and relationship a\n * result holds -- in a column, a path, a list or a map -- is collected once by its element id, and\n * written to the sink as nodes (labels in the `labels` column, as the neo4j CSV importer has them)\n * and directed edges (type in `type`, element id in `id`). A result of scalars only is\n * E_SOURCE_NOT_A_GRAPH.\n */\n\nimport { type ColumnDecl, type GraphSink, INVALID_INDEX, type NodeId } from \"@graphty/graph-format\";\n\nimport { throwIfAborted } from \"../../common/input.js\";\nimport { type ImportReportBuilder } from \"../../common/report.js\";\nimport { failOn } from \"../fail.js\";\nimport { SOURCE_DEGREE_ATTR } from \"../ids.js\";\nimport { GraphNode, GraphRel } from \"./types-map.js\";\n\n/** One query's result, every value already mapped. */\nexport interface QueryResult {\n /** The column names. */\n readonly fields: readonly string[];\n /** The rows, one value per column. */\n readonly rows: readonly (readonly unknown[])[];\n}\n\n/** The column names the neo4j CSV importer gives labels and types; spelled here so the Cypher chunk does not load it. */\nconst LABELS_COLUMN = \"labels\";\nconst TYPE_COLUMN = \"type\";\n\n/** The labels column, as the neo4j CSV importer declares it. */\nconst LABELS_DECL: ColumnDecl = {\n name: LABELS_COLUMN,\n dtype: \"list\",\n itemDtype: \"dict\",\n nullable: true,\n role: \"labels\",\n};\n\n/** The relationship type column. */\nconst TYPE_DECL: ColumnDecl = { name: TYPE_COLUMN, dtype: \"dict\", nullable: true, role: \"kind\" };\n\n/** The edge id column. */\nconst EDGE_ID_DECL: ColumnDecl = { name: \"id\", dtype: \"string\", nullable: true, role: \"id\" };\n\n/** The nodes, relationships and degree hints of one or more results, each once. */\nexport class Collector {\n readonly nodes = new Map<string, GraphNode>();\n readonly rels = new Map<string, GraphRel>();\n /** Degree hints by the id expression's value, as text. */\n readonly degrees = new Map<string, number>();\n\n /**\n * Collect a result.\n * @param result - the result\n * @param hints - whether its `key` / `degree` / `degrees` columns are the generated queries' hints\n */\n add(result: QueryResult, hints: boolean): void {\n const key = hints ? result.fields.indexOf(\"key\") : -1;\n const degree = hints ? result.fields.indexOf(\"degree\") : -1;\n const degrees = hints ? result.fields.indexOf(\"degrees\") : -1;\n for (const row of result.rows) {\n row.forEach((value, i) => {\n if (i === degrees && Array.isArray(value)) {\n for (const pair of value as unknown[]) {\n if (Array.isArray(pair) && typeof pair[1] === \"number\") {\n this.degrees.set(String(pair[0]), pair[1]);\n }\n }\n } else if (i !== key && i !== degree) {\n this.visit(value);\n }\n });\n if (key >= 0 && degree >= 0 && typeof row[degree] === \"number\") {\n this.degrees.set(String(row[key]), row[degree]);\n }\n }\n }\n\n /**\n * Collect every node and relationship inside a value.\n * @param value - the value\n */\n private visit(value: unknown): void {\n if (value instanceof GraphNode) {\n this.nodes.set(value.id, value);\n } else if (value instanceof GraphRel) {\n this.rels.set(value.id, value);\n } else if (Array.isArray(value)) {\n value.forEach((v) => {\n this.visit(v);\n });\n } else if (value !== null && typeof value === \"object\") {\n Object.values(value).forEach((v) => {\n this.visit(v);\n });\n }\n }\n\n /**\n * Whether nothing was collected.\n * @returns true when no node or relationship was found\n */\n get empty(): boolean {\n return this.nodes.size === 0 && this.rels.size === 0;\n }\n}\n\n/**\n * Fail with E_SOURCE_NOT_A_GRAPH when a result has rows but no node, relationship or path.\n * @param result - the result\n * @param collector - what it held\n * @param report - the load's report\n */\nexport function requireGraph(result: QueryResult, collector: Collector, report: ImportReportBuilder): void {\n if (result.rows.length > 0 && collector.empty) {\n failOn(report, \"E_SOURCE_NOT_A_GRAPH\", \"the query returned no node, relationship or path\", {\n columns: result.fields,\n });\n }\n}\n\n/**\n * The id a node gets: its `idProperty` value when it has one, else the server's element id.\n * @param node - the node\n * @param idProperty - the id property, or null\n * @returns the id\n */\nfunction nodeIdOf(node: GraphNode, idProperty: string | null): NodeId {\n const value = idProperty === null ? undefined : node.properties[idProperty];\n return typeof value === \"string\" || typeof value === \"number\" ? value : node.id;\n}\n\n/**\n * A column handle, declared on first use.\n * @param sink - the sink\n * @param decl - the declaration\n * @param domain - node or edge\n * @returns the handle\n */\nfunction column(sink: GraphSink, decl: ColumnDecl, domain: \"node\" | \"edge\"): ReturnType<GraphSink[\"nodeColumn\"]> {\n const existing = domain === \"node\" ? sink.nodeColumn(decl.name) : sink.edgeColumn(decl.name);\n if (existing !== INVALID_INDEX) {\n return existing;\n }\n return domain === \"node\" ? sink.declareNodeColumn(decl) : sink.declareEdgeColumn(decl);\n}\n\n/**\n * Write what was collected into the sink. A node already in the sink is updated, not counted again.\n * @param c - the collector\n * @param sink - the sink\n * @param idProperty - the id property, or null\n * @param report - the load's report\n * @param signal - the load's signal\n */\nexport function writeCollected(\n c: Collector,\n sink: GraphSink,\n idProperty: string | null,\n report: ImportReportBuilder,\n signal: AbortSignal,\n): void {\n if (sink.edgeCount === 0 && !sink.directedLocked && !sink.directed) {\n sink.setDirected(true);\n }\n const ids = writeNodes(c, sink, idProperty, report, signal);\n writeRels(c, sink, ids, report, signal, c.nodes.size);\n}\n\n/**\n * Write the collected nodes into the sink.\n * @param c - the collector\n * @param sink - the sink\n * @param idProperty - the id property, or null\n * @param report - the load's report\n * @param signal - the load's signal\n * @returns each element id's node id\n */\nfunction writeNodes(\n c: Collector,\n sink: GraphSink,\n idProperty: string | null,\n report: ImportReportBuilder,\n signal: AbortSignal,\n): Map<string, NodeId> {\n const ids = new Map<string, NodeId>();\n let n = 0;\n for (const node of c.nodes.values()) {\n if (n++ % 64 === 0) {\n throwIfAborted(signal);\n }\n const id = nodeIdOf(node, idProperty);\n ids.set(node.id, id);\n const degree = c.degrees.get(String(idProperty === null ? node.id : id));\n try {\n const fresh = sink.indexOf(id) === INVALID_INDEX;\n const index = sink.addNodeRecord(\n id,\n degree === undefined ? node.properties : { ...node.properties, [SOURCE_DEGREE_ATTR]: degree },\n );\n sink.setNodeValue(column(sink, LABELS_DECL, \"node\"), index, node.labels);\n if (fresh) {\n report.counts.nodes++;\n }\n } catch (err) {\n report.recordError(err, { element: String(id) });\n report.counts.skippedNodes++;\n }\n }\n return ids;\n}\n\n/**\n * Write the collected relationships into the sink, adding any end the result did not return.\n * @param c - the collector\n * @param sink - the sink\n * @param ids - each element id's node id\n * @param report - the load's report\n * @param signal - the load's signal\n * @param written - how many elements were written before, for the abort check cadence\n */\nfunction writeRels(\n c: Collector,\n sink: GraphSink,\n ids: Map<string, NodeId>,\n report: ImportReportBuilder,\n signal: AbortSignal,\n written: number,\n): void {\n let n = written;\n for (const rel of c.rels.values()) {\n if (n++ % 64 === 0) {\n throwIfAborted(signal);\n }\n // an end the result did not return is known only by its element id\n const s = ids.get(rel.start) ?? rel.start;\n const t = ids.get(rel.end) ?? rel.end;\n try {\n for (const end of [s, t]) {\n if (sink.indexOf(end) === INVALID_INDEX) {\n sink.addNode(end);\n report.counts.nodes++;\n }\n }\n const e = sink.addEdgeRecord(s, t, rel.properties, null);\n sink.setEdgeValue(column(sink, TYPE_DECL, \"edge\"), e, rel.type);\n sink.setEdgeValue(column(sink, EDGE_ID_DECL, \"edge\"), e, rel.id);\n report.counts.edges++;\n } catch (err) {\n report.recordError(err, { element: `${String(s)} -> ${String(t)}` });\n report.counts.skippedEdges++;\n }\n }\n}\n\n/**\n * Code-unit order of two strings, independent of locale.\n * @param a - one string\n * @param b - another\n * @returns negative, zero or positive\n */\nexport function compareText(a: string, b: string): number {\n if (a === b) {\n return 0;\n }\n return a < b ? -1 : 1;\n}\n\n/**\n * One canonical object member.\n * @param key - the key\n * @param value - the value\n * @returns `\"key\":value`\n */\nfunction member(key: string, value: unknown): string {\n return `${JSON.stringify(key)}:${canonical(value)}`;\n}\n\n/**\n * JSON with every object's keys sorted, so equal data spells the same.\n * @param value - the value\n * @returns the canonical text\n */\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) {\n return `[${value.map(canonical).join(\",\")}]`;\n }\n if (value !== null && typeof value === \"object\") {\n const entries = Object.entries(value).sort(([a], [b]) => compareText(a, b));\n const members = entries.map(([k, v]) => member(k, v));\n return `{${members.join(\",\")}}`;\n }\n return JSON.stringify(value) ?? \"null\";\n}\n\n/**\n * The canonical rows of what was collected: one line per node and relationship, sorted, for the\n * content hash `validate` compares.\n * @param c - the collector\n * @param idProperty - the id property, or null\n * @returns the lines\n */\nexport function canonicalRows(c: Collector, idProperty: string | null): string[] {\n const ids = new Map<string, NodeId>();\n const lines: string[] = [];\n for (const node of c.nodes.values()) {\n const id = nodeIdOf(node, idProperty);\n ids.set(node.id, id);\n lines.push(canonical([\"n\", id, [...node.labels].sort(compareText), node.properties]));\n }\n for (const rel of c.rels.values()) {\n lines.push(\n canonical([\n \"r\",\n rel.id,\n ids.get(rel.start) ?? rel.start,\n ids.get(rel.end) ?? rel.end,\n rel.type,\n rel.properties,\n ]),\n );\n }\n return lines;\n}\n","/**\n * What differs between openCypher servers (design section 12.2, \"the profile\"): the id\n * expression, and the server facts `probe` reports. Everything else in the Cypher source is shared.\n */\n\n/** The facts of one server the Cypher source talks to. */\nexport interface CypherProfile {\n /** \"neo4j\" or \"neptune\". */\n readonly name: \"neo4j\" | \"neptune\";\n /** true: ids are `elementId(n)` (Neo4j 5 and later); false: `id(n)` (Neo4j before 5, Neptune's `~id`). */\n readonly elementIds: boolean;\n /** The product, as the server names it. */\n readonly product: string;\n /** The server's version, when known. */\n readonly version: string | null;\n /** \"enforced\": the server refuses writes in this session; \"not-enforced\": nothing in the request does. */\n readonly readOnly: \"enforced\" | \"not-enforced\";\n}\n\n/**\n * The Neo4j profile for a version: `elementId()` from 5.0, `id()` before.\n * @param version - the server's version, or null when not known (assumed 5 or later)\n * @param product - the product name\n * @returns the profile\n */\nexport function neo4jProfile(version: string | null, product = \"Neo4j\"): CypherProfile {\n const major = version === null ? Number.NaN : Number.parseInt(version, 10);\n return {\n name: \"neo4j\",\n elementIds: Number.isNaN(major) || major >= 5,\n product,\n version,\n readOnly: \"enforced\",\n };\n}\n\n/**\n * The profile of a Bolt server from its agent string (\"Neo4j/3.5.12\"). A server that is not Neo4j\n * gets `id()`, which every openCypher server has.\n * @param agent - the server agent\n * @returns the profile\n */\nexport function profileFromAgent(agent: string): CypherProfile {\n const [product = \"\", version = \"\"] = agent.split(\"/\");\n if (product.toLowerCase() === \"neo4j\") {\n return neo4jProfile(version === \"\" ? null : version);\n }\n return {\n name: \"neo4j\",\n elementIds: false,\n product,\n version: version === \"\" ? null : version,\n readOnly: \"enforced\",\n };\n}\n\n/**\n * The Neptune profile: ids are `id(n)`, the `~id` string, never reused.\n * @param version - the engine version, when known\n * @returns the profile\n */\nexport function neptuneProfile(version: string | null = null): CypherProfile {\n return { name: \"neptune\", elementIds: false, product: \"Neptune\", version, readOnly: \"not-enforced\" };\n}\n\n/**\n * The server facts of a profile, as `probe` and `report.source.server` give them.\n * @param profile - the profile\n * @returns the facts\n */\nexport function serverFacts(profile: CypherProfile): Readonly<Record<string, string>> {\n return {\n product: profile.product,\n profile: profile.name,\n readOnly: profile.readOnly,\n ...(profile.version === null ? {} : { version: profile.version }),\n };\n}\n","/**\n * The one query builder of the Cypher source (design sections 11 and 12.2). Caller values travel\n * as query parameters, never spliced. What Cypher cannot parameterize -- labels, relationship\n * types, property keys, variable-length bounds and LIMIT -- is either backtick-quoted (an\n * identifier, a backtick inside doubled) or inlined as a checked integer. The generated queries\n * differ between servers only in the id expression.\n */\n\nimport { type ImportReportBuilder } from \"../../common/report.js\";\nimport { failAlone, failOn } from \"../fail.js\";\nimport { type CypherProfile } from \"./profiles.js\";\n\n/** The deepest neighborhood a generated query asks for. */\nexport const MAX_DEPTH = 10;\n\n/** The largest page of mode \"all\". */\nexport const MAX_PAGE_SIZE = 100_000;\n\n/** The page size of mode \"all\" when the caller gives none. */\nexport const DEFAULT_PAGE_SIZE = 1000;\n\n/**\n * Why an identifier cannot be quoted, or null when it can.\n * @param name - the identifier\n * @returns the reason, or null\n */\nfunction identifierProblem(name: unknown): string | null {\n return typeof name !== \"string\" || name === \"\" || name.includes(\"\\u0000\") ? \"identifier\" : null;\n}\n\n/**\n * Quote one Cypher identifier (a label, relationship type or property key) for a query: wrapped in\n * backticks, with every backtick inside doubled, so no value can end the identifier early. An\n * empty name, or one with a NUL character, is refused (E_SOURCE_PARAM, reason \"identifier\").\n * Experimental.\n * @param name - the identifier\n * @returns the quoted identifier\n * @example\n * ```ts\n * cypherIdentifier(\"Person\"); // \"`Person`\"\n * cypherIdentifier(\"odd`name\"); // \"`odd``name`\"\n * ```\n * @category Network sources\n */\nexport function cypherIdentifier(name: string): string {\n if (identifierProblem(name) !== null) {\n failAlone(\"E_SOURCE_PARAM\", \"a Cypher identifier must be a non-empty string without NUL\", {\n name: \"identifier\",\n reason: \"identifier\",\n });\n }\n return `\\`${name.replaceAll(\"`\", \"``\")}\\``;\n}\n\n/**\n * Quote an identifier a parameter gave, failing the load when it cannot be.\n * @param name - the identifier\n * @param param - the parameter it came from\n * @param report - the load's report\n * @returns the quoted identifier\n */\nexport function quoted(name: unknown, param: string, report: ImportReportBuilder): string {\n if (identifierProblem(name) !== null) {\n failOn(report, \"E_SOURCE_PARAM\", `parameter ${param}: not a Cypher identifier`, {\n name: param,\n reason: \"identifier\",\n });\n }\n return cypherIdentifier(name as string);\n}\n\n/**\n * An integer to inline, checked to lie in its range.\n * @param value - the value\n * @param name - the parameter it came from\n * @param min - the smallest allowed\n * @param max - the largest allowed\n * @param report - the load's report\n * @returns the integer, as query text\n */\nexport function checkedInteger(\n value: unknown,\n name: string,\n min: number,\n max: number,\n report: ImportReportBuilder,\n): string {\n if (typeof value !== \"number\" || !Number.isInteger(value)) {\n failOn(report, \"E_SOURCE_PARAM\", `parameter ${name}: not an integer`, { name, reason: \"type\" });\n }\n if (value < min || value > max) {\n failOn(report, \"E_SOURCE_PARAM\", `parameter ${name}: outside ${String(min)} to ${String(max)}`, {\n name,\n reason: \"range\",\n });\n }\n return String(value);\n}\n\n/** What narrows a generated query: compiled into it, so filtering happens at the source. */\nexport interface QueryFilters {\n /** Quoted labels; a node must have one of them. */\n readonly labels: readonly string[];\n /** Quoted relationship types. */\n readonly relationshipTypes: readonly string[];\n /** The quoted id property, or null for the server's id. */\n readonly idProperty: string | null;\n}\n\n/**\n * The id expression of a node or relationship variable.\n * @param v - the variable\n * @param profile - the server's profile\n * @param filters - the id property, for a node\n * @param node - whether `v` is a node\n * @returns the expression\n */\nfunction idExpression(v: string, profile: CypherProfile, filters: QueryFilters, node = true): string {\n if (node && filters.idProperty !== null) {\n return `${v}.${filters.idProperty}`;\n }\n return profile.elementIds ? `elementId(${v})` : `id(${v})`;\n}\n\n/**\n * The node predicate of the label and id property filters, or null.\n * @param v - the node variable\n * @param filters - the filters\n * @returns the predicate\n */\nfunction nodePredicate(v: string, filters: QueryFilters): string | null {\n const parts: string[] = [];\n if (filters.labels.length > 0) {\n const prefix = `${v}:`;\n parts.push(`(${filters.labels.map((l) => prefix + l).join(\" OR \")})`);\n }\n if (filters.idProperty !== null) {\n parts.push(`${v}.${filters.idProperty} IS NOT NULL`);\n }\n return parts.length === 0 ? null : parts.join(\" AND \");\n}\n\n/**\n * The relationship type part of a pattern: `:`A`|`B``, or \"\".\n * @param filters - the filters\n * @returns the pattern text\n */\nfunction typesPattern(filters: QueryFilters): string {\n return filters.relationshipTypes.length === 0 ? \"\" : `:${filters.relationshipTypes.join(\"|\")}`;\n}\n\n/**\n * The degree hint of a node variable: its relationship count, by pattern comprehension.\n * @param v - the variable\n * @returns the expression\n */\nfunction degreeOf(v: string): string {\n return `size([(${v})--() | 1])`;\n}\n\n/** The arrows of each direction around a relationship pattern. */\nconst ARROWS = { out: [\"-\", \"->\"], in: [\"<-\", \"-\"], both: [\"-\", \"-\"] } as const;\n\n/**\n * One page of the nodes of mode \"all\", ordered by the id expression (keyset paging, never SKIP).\n * @param profile - the server's profile\n * @param filters - the filters\n * @param pageSize - the checked page size, as text\n * @param after - whether the page starts after `$after`\n * @param degree - whether to add the degree hint\n * @returns the statement; it reads `$after`\n */\nexport function nodePage(\n profile: CypherProfile,\n filters: QueryFilters,\n pageSize: string,\n after: boolean,\n degree: boolean,\n): string {\n const where = nodePredicate(\"n\", filters);\n return [\n \"MATCH (n)\",\n where === null ? null : `WHERE ${where}`,\n `WITH n, ${idExpression(\"n\", profile, filters)} AS key`,\n after ? \"WHERE key > $after\" : null,\n degree ? `RETURN n, key, ${degreeOf(\"n\")} AS degree` : \"RETURN n, key\",\n `ORDER BY key LIMIT ${pageSize}`,\n ]\n .filter((l) => l !== null)\n .join(\" \");\n}\n\n/**\n * One page of the relationships of mode \"all\", with their end nodes, ordered by the relationship\n * id expression.\n * @param profile - the server's profile\n * @param filters - the filters\n * @param pageSize - the checked page size, as text\n * @param after - whether the page starts after `$after`\n * @returns the statement; it reads `$after`\n */\nexport function edgePage(profile: CypherProfile, filters: QueryFilters, pageSize: string, after: boolean): string {\n const a = nodePredicate(\"a\", filters);\n const b = nodePredicate(\"b\", filters);\n const where = [a, b].filter((p) => p !== null);\n return [\n `MATCH (a)-[r${typesPattern(filters)}]->(b)`,\n where.length === 0 ? null : `WHERE ${where.join(\" AND \")}`,\n `WITH a, r, b, ${idExpression(\"r\", profile, filters, false)} AS key`,\n after ? \"WHERE key > $after\" : null,\n \"RETURN a, r, b, key\",\n `ORDER BY key LIMIT ${pageSize}`,\n ]\n .filter((l) => l !== null)\n .join(\" \");\n}\n\n/** How far a neighborhood reaches. */\ninterface NeighborhoodShape {\n /** The checked depth, as text. */\n readonly depth: string;\n /** Which way relationships are followed. */\n readonly direction: \"out\" | \"in\" | \"both\";\n /** The checked path limit, as text, or null for none. */\n readonly limit: string | null;\n /** Whether the page starts after the neighbor key `$after` (a capped expansion's next page). */\n readonly after?: boolean;\n}\n\n/**\n * The neighborhood of the seeds `$ids`: every path up to `depth` hops, each seed included even with\n * no neighbor, plus the degree of every node returned.\n * @param profile - the server's profile\n * @param filters - the filters\n * @param shape - depth, direction and limit\n * @param degree - whether to add the degree hint\n * @returns the statement; it reads `$ids`\n */\nexport function neighborhood(\n profile: CypherProfile,\n filters: QueryFilters,\n shape: NeighborhoodShape,\n degree: boolean,\n): string {\n const rel = `[${typesPattern(filters)}*1..${shape.depth}]`;\n const [left, right] = ARROWS[shape.direction];\n const pattern = `${left}${rel}${right}`;\n const x = nodePredicate(\"x\", filters);\n const degrees = degree\n ? `, [m IN CASE WHEN p IS NULL THEN [s] ELSE nodes(p) END | [${idExpression(\"m\", profile, filters)}, ${degreeOf(\"m\")}]] AS degrees`\n : \"\";\n // A capped expansion is ordered by the neighbor's key, so its next page starts after the last\n // key it returned. ponytail: a page boundary falling between two paths to the same neighbor\n // (parallel relationships, or depth > 1) drops the later paths; page on (key, path) if that matters.\n const head = [\n `MATCH (s) WHERE ${idExpression(\"s\", profile, filters)} IN $ids`,\n `OPTIONAL MATCH p = (s)${pattern}(x)${whereClause(x)}`,\n ];\n if (shape.limit === null) {\n return [...head, \"WITH s, p\", `RETURN s, p${degrees}`].join(\" \");\n }\n return [\n ...head,\n `WITH s, p, ${idExpression(\"x\", profile, filters)} AS key`,\n shape.after === true ? \"WHERE key > $after\" : null,\n `WITH s, p, key ORDER BY key LIMIT ${shape.limit}`,\n `RETURN s, p, key${degrees}`,\n ]\n .filter((l) => l !== null)\n .join(\" \");\n}\n\n/**\n * A ` WHERE` clause for a predicate.\n * @param predicate - the predicate, or null\n * @returns the clause with its leading space, or \"\" for no predicate\n */\nfunction whereClause(predicate: string | null): string {\n return predicate === null ? \"\" : ` WHERE ${predicate}`;\n}\n\n/**\n * The counts of mode \"all\", for a progress total.\n * @param filters - the filters\n * @returns two statements: the nodes, then the relationships\n */\nexport function counts(filters: QueryFilters): readonly [string, string] {\n const n = nodePredicate(\"n\", filters);\n const where = [nodePredicate(\"a\", filters), nodePredicate(\"b\", filters)].filter((p) => p !== null);\n return [\n `MATCH (n)${whereClause(n)} RETURN count(n) AS c`,\n `MATCH (a)-[r${typesPattern(filters)}]->(b)${whereClause(where.length === 0 ? null : where.join(\" AND \"))} RETURN count(r) AS c`,\n ];\n}\n","/**\n * What every Cypher transport is (design section 12.2): something that runs one statement with\n * its parameters and returns mapped rows, knows the server's profile, and closes. Also the one\n * place a server's own error code becomes a source issue code.\n */\n\nimport { type ImportReportBuilder } from \"../../../common/report.js\";\nimport { failOn } from \"../../fail.js\";\nimport { type SourceContext } from \"../../types.js\";\nimport { type QueryResult } from \"../flatten.js\";\nimport { type CypherParams } from \"../params.js\";\nimport { type CypherProfile } from \"../profiles.js\";\nimport { type MapContext } from \"../types-map.js\";\n\n/** One way a Cypher statement travels to a server. Internal. */\nexport interface Transport {\n /**\n * Run one read-only statement.\n * @param statement - the statement\n * @param parameters - its parameters, sent separately\n * @returns the mapped result\n */\n run(statement: string, parameters: Readonly<Record<string, unknown>>): Promise<QueryResult>;\n /**\n * The server's profile, detected once.\n * @returns the profile\n */\n profile(): Promise<CypherProfile>;\n /**\n * The server facts `probe` reports, which may cost a request.\n * @returns the profile with its version filled in where the server says it\n */\n probe(): Promise<CypherProfile>;\n /** Release the connection. */\n close(): Promise<void>;\n}\n\n/** What a transport is made from. */\nexport interface TransportInput {\n /** The load's context. */\n readonly ctx: SourceContext;\n /** The params, with defaults. */\n readonly params: CypherParams;\n /** The type mapper's context. */\n readonly m: MapContext;\n}\n\n/** The longest server message a report keeps. */\nconst MAX_SERVER_MESSAGE = 500;\n\n/** What a server said about a failed statement. */\ninterface ServerError {\n /** The service's own code, or null. */\n readonly code: string | null;\n /** Its message, or \"\". */\n readonly message: string;\n /** The HTTP status, or null over Bolt. */\n readonly status: number | null;\n /** Whether the message came from a JSON 4xx body (or a Bolt client error), so a report may keep it. */\n readonly showable: boolean;\n}\n\n/**\n * Raise the source issue a server error is: a login failure, a refusal, a server timeout, a\n * missing database, or E_SOURCE_QUERY with the line and column the message names.\n * @param report - the load's report\n * @param err - what the server said\n * @param origin - the origin that answered\n * @param database - the database asked for, if any\n * @returns never; it throws\n */\nexport function serverError(\n report: ImportReportBuilder,\n err: ServerError,\n origin: string,\n database: string | undefined,\n): never {\n const code = err.code ?? \"\";\n if (/Security\\.Unauthorized|AuthenticationRateLimit|UnauthorizedException/i.test(code)) {\n return failOn(report, \"E_SOURCE_AUTH\", `${origin} refused the login`, {\n origin,\n status: err.status,\n scheme: null,\n serverCode: err.code,\n });\n }\n if (/Security\\.Forbidden|AccessMode|AccessDenied/i.test(code)) {\n return failOn(report, \"E_SOURCE_FORBIDDEN\", `${origin} refused the statement`, {\n status: err.status,\n serverCode: err.code,\n });\n }\n if (/TimedOut|Timeout|TimeLimitExceeded/i.test(code)) {\n return failOn(report, \"E_SOURCE_TIMEOUT\", `${origin} timed the statement out`, {\n timeoutMs: null,\n serverSide: true,\n });\n }\n if (/DatabaseNotFound/i.test(code)) {\n return failOn(report, \"E_SOURCE_NOT_FOUND\", `${origin} has no database ${String(database)}`, {\n what: \"database\",\n value: database ?? null,\n });\n }\n const where = /line (\\d+), column (\\d+)/i.exec(err.message);\n return failOn(report, \"E_SOURCE_QUERY\", `${origin} refused the query: ${code}`, {\n serverCode: err.code,\n line: where === null ? null : Number(where[1]),\n column: where === null ? null : Number(where[2]),\n serverMessage: err.showable && err.message !== \"\" ? err.message.slice(0, MAX_SERVER_MESSAGE) : null,\n });\n}\n\n/**\n * The value of a response body as JSON, or null when it is not JSON.\n * @param text - the body\n * @returns the parsed value, or null\n */\nexport function parseJson(text: string): unknown {\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return null;\n }\n}\n\n/**\n * The fields and rows of a result given as one object per row (Neptune's `results`).\n * @param results - the row objects\n * @param map - maps one value, given its column\n * @returns the result\n */\nexport function objectRows(\n results: readonly Readonly<Record<string, unknown>>[],\n map: (v: unknown, column: string) => unknown,\n): QueryResult {\n const fields = [...new Set(results.flatMap((r) => Object.keys(r)))];\n return { fields, rows: results.map((r) => fields.map((f) => map(r[f], f))) };\n}\n","/**\n * The `bolt` transport (design sections 9 and 12.2): the official neo4j-driver, an optional peer\n * dependency imported only here. Absent, a load fails with E_SOURCE_RUNTIME (`reason:\n * \"needs-peer-dependency\"`). It is the only path to a Neo4j older than 5.26, such as Hetionet's 3.5.\n *\n * - Direct connections only (`bolt:`, `bolt+s:`, `bolt+ssc:`): a routing scheme would send the\n * credential to every host the routing table lists, so `neo4j:` schemes are refused.\n * - `+ssc` accepts any certificate, so it is refused with a credential; plain `bolt:` is refused\n * with one unless the host is this machine or `allowInsecure` is set.\n * - Statements run as auto-commit `session.run` in a READ session, never as managed transactions,\n * which retry a server timeout for 30 s.\n * - Integers stay lossless and are converted by the type mapper; the signal closes the session.\n */\n\nimport { throwIfAborted } from \"../../../common/input.js\";\nimport { isLoopback, transportOptions } from \"../../context.js\";\nimport { originOf, unwrapCredential } from \"../../credentials.js\";\nimport { failOn } from \"../../fail.js\";\nimport { type QueryResult } from \"../flatten.js\";\nimport { type CypherProfile, profileFromAgent } from \"../profiles.js\";\nimport { type DriverTypes, fromDriver } from \"../types-map.js\";\nimport { serverError, type Transport, type TransportInput } from \"./transport.js\";\n\n/** The optional peer dependency. */\nconst DRIVER_PACKAGE = \"neo4j-driver\";\n\n/** The URL schemes of a direct Bolt connection. */\nconst DIRECT_SCHEMES = new Set([\"bolt:\", \"bolt+s:\", \"bolt+ssc:\"]);\n\n/** The parts of a neo4j-driver session this transport uses. */\ninterface DriverSession {\n run(\n statement: string,\n parameters: Readonly<Record<string, unknown>>,\n config?: { readonly timeout?: number },\n ): Promise<{\n readonly records: readonly { readonly keys: readonly PropertyKey[]; get(key: PropertyKey): unknown }[];\n }>;\n close(): Promise<void>;\n}\n\n/** The parts of a neo4j-driver driver this transport uses. */\ninterface Driver {\n session(config: { readonly defaultAccessMode: string; readonly database?: string }): DriverSession;\n getServerInfo(): Promise<{ readonly agent?: string }>;\n close(): Promise<void>;\n}\n\n/** The parts of the neo4j-driver module this transport uses. */\ninterface DriverModule extends DriverTypes {\n driver(url: string, auth?: unknown, config?: Readonly<Record<string, unknown>>): Driver;\n readonly auth: { basic(user: string, password: string): unknown; bearer(token: string): unknown };\n readonly session: { readonly READ: string };\n}\n\n/**\n * Import the optional peer dependency.\n * @param input - the transport input\n * @returns the driver module\n */\nasync function loadDriver(input: TransportInput): Promise<DriverModule> {\n let mod: { default?: DriverModule } & Partial<DriverModule>;\n try {\n mod = (await import(\"neo4j-driver\")) as unknown as typeof mod;\n } catch {\n return failOn(input.ctx.report, \"E_SOURCE_RUNTIME\", `the bolt transport needs ${DRIVER_PACKAGE} installed`, {\n runtime: input.ctx.runtime,\n reason: \"needs-peer-dependency\",\n package: DRIVER_PACKAGE,\n });\n }\n return mod.default ?? (mod as DriverModule);\n}\n\n/**\n * Fail when an https page would open a plain Bolt WebSocket to another machine, which the browser\n * blocks.\n * @param ctx - the context\n * @param url - the endpoint\n */\nfunction refuseMixedContent(ctx: TransportInput[\"ctx\"], url: URL): void {\n const page = (globalThis as { location?: { protocol?: string } }).location;\n if (\n ctx.runtime === \"browser\" &&\n page?.protocol === \"https:\" &&\n url.protocol === \"bolt:\" &&\n !isLoopback(url.hostname)\n ) {\n failOn(ctx.report, \"E_SOURCE_RUNTIME\", \"an https page cannot open a plain Bolt WebSocket\", {\n runtime: ctx.runtime,\n reason: \"insecure-endpoint\",\n });\n }\n}\n\n/**\n * Check the endpoint and the credential before connecting, and turn the credential into the\n * driver's auth token.\n * @param input - the transport input\n * @param neo4j - the driver module\n * @returns the URL and auth token\n */\nasync function connection(input: TransportInput, neo4j: DriverModule): Promise<{ url: URL; auth: unknown }> {\n const { ctx } = input;\n const { report } = ctx;\n const bad = (reason: string, message: string): never =>\n failOn(report, \"E_SOURCE_PARAM\", message, { name: \"endpoint\", reason });\n const url = ctx.endpoint ?? bad(\"missing\", \"the bolt transport needs an endpoint\");\n if (!DIRECT_SCHEMES.has(url.protocol)) {\n bad(url.protocol.startsWith(\"neo4j\") ? \"routing\" : \"scheme\", `${url.protocol} is not a direct Bolt scheme`);\n }\n refuseMixedContent(ctx, url);\n const { credential, allowInsecure } = transportOptions(ctx);\n const origin = originOf(url);\n const bound = credential !== undefined && (credential.origins.length === 0 || credential.origins.includes(origin));\n if (!bound || credential === undefined) {\n return { url, auth: undefined };\n }\n if (url.protocol === \"bolt+ssc:\") {\n bad(\"unverified-tls\", \"bolt+ssc accepts any certificate, so no credential is sent over it\");\n }\n if (url.protocol === \"bolt:\" && !isLoopback(url.hostname) && allowInsecure !== true) {\n bad(\"insecure-endpoint\", \"a credential is never sent without TLS\");\n }\n const secret = unwrapCredential(credential);\n if (secret !== undefined && \"username\" in secret) {\n return { url, auth: neo4j.auth.basic(secret.username, secret.password) };\n }\n if (secret !== undefined && \"token\" in secret) {\n const token = typeof secret.token === \"string\" ? secret.token : await secret.token();\n return { url, auth: neo4j.auth.bearer(token) };\n }\n return failOn(report, \"E_SOURCE_PARAM\", \"the bolt transport takes a basic or bearer credential\", {\n name: \"credential\",\n reason: \"kind\",\n });\n}\n\n/**\n * Make the transport: import the driver, check the endpoint and credential, open a READ session.\n * @param input - the context, params and mapper\n * @returns the transport\n */\nexport async function boltTransport(input: TransportInput): Promise<Transport> {\n const { ctx, params, m } = input;\n throwIfAborted(ctx.signal);\n const neo4j = await loadDriver(input);\n const { url, auth } = await connection(input, neo4j);\n throwIfAborted(ctx.signal);\n const origin = originOf(url);\n const { userAgent } = transportOptions(ctx);\n const driver = neo4j.driver(`${url.protocol}//${url.host}`, auth, userAgent === undefined ? {} : { userAgent });\n const session = driver.session({\n defaultAccessMode: neo4j.session.READ,\n ...(params.database === undefined ? {} : { database: params.database }),\n });\n let closed: Promise<void> | null = null;\n const close = (): Promise<void> => {\n closed ??= session\n .close()\n .catch(() => undefined)\n .then(() => driver.close())\n .catch(() => undefined);\n return closed;\n };\n const onAbort = (): void => {\n void close();\n };\n ctx.signal.addEventListener(\"abort\", onAbort, { once: true });\n\n const fail = (err: unknown): never => {\n throwIfAborted(ctx.signal);\n const e = err as { code?: unknown; message?: unknown };\n const code = typeof e.code === \"string\" ? e.code : null;\n if (code === null || code === \"ServiceUnavailable\" || code === \"SessionExpired\") {\n return ctx.runtime === \"browser\"\n ? failOn(ctx.report, \"E_SOURCE_BLOCKED\", `${origin} could not be reached over Bolt`, {\n url: origin,\n cause: \"unknown\",\n })\n : failOn(ctx.report, \"E_FETCH\", `${origin} could not be reached over Bolt`, {\n url: origin,\n status: null,\n });\n }\n return serverError(\n ctx.report,\n {\n code,\n message: typeof e.message === \"string\" ? e.message : \"\",\n status: null,\n showable: code.startsWith(\"Neo.ClientError.\"),\n },\n origin,\n params.database,\n );\n };\n\n let detected: CypherProfile | null = null;\n const profile = async (): Promise<CypherProfile> => {\n if (detected === null) {\n const info = await driver.getServerInfo().catch(fail);\n detected = profileFromAgent(info.agent ?? \"\");\n }\n return detected;\n };\n const timeout = ctx.limits.timeoutMs;\n\n return {\n async run(statement, parameters): Promise<QueryResult> {\n throwIfAborted(ctx.signal);\n const result = await session\n .run(statement, parameters, timeout === undefined ? undefined : { timeout })\n .catch(fail);\n const fields = (result.records[0]?.keys ?? []).map(String);\n return {\n fields,\n rows: result.records.map((r) => fields.map((k) => fromDriver(r.get(k), k, m, neo4j))),\n };\n },\n profile,\n probe: profile,\n close: async (): Promise<void> => {\n ctx.signal.removeEventListener(\"abort\", onAbort);\n await close();\n },\n };\n}\n","/**\n * The `neptune-https` transport (design section 12.4): Neptune Database's `POST /openCypher`\n * (port 8182, TLS only), form fields `query` and `parameters`, signed with `credentials.awsSigV4`\n * (service \"neptune-db\") or unsigned inside the VPC. Node only: Neptune Database sends no CORS\n * headers, so a browser is refused before any request (E_SOURCE_RUNTIME, reason \"cors\").\n *\n * An error after the first chunk of a 200 answer is appended to the body; the tail is read for it.\n */\n\nimport { originOf } from \"../../credentials.js\";\nimport { failOn } from \"../../fail.js\";\nimport { type SourceContext } from \"../../types.js\";\nimport { type QueryResult } from \"../flatten.js\";\nimport { type CypherProfile, neptuneProfile } from \"../profiles.js\";\nimport { fromNeptune } from \"../types-map.js\";\nimport { objectRows, parseJson, serverError, type Transport, type TransportInput } from \"./transport.js\";\n\n/** Neptune's error body. */\ninterface NeptuneError {\n readonly code?: string;\n readonly detailedMessage?: string;\n readonly message?: string;\n}\n\n/**\n * Refuse a Neptune transport where it cannot run.\n * @param ctx - the context\n * @param transport - the transport name\n */\nexport function nodeOnly(ctx: SourceContext, transport: string): void {\n if (ctx.runtime === \"browser\" || ctx.runtime === \"worker\") {\n failOn(ctx.report, \"E_SOURCE_RUNTIME\", `the ${transport} transport cannot run in a browser`, {\n runtime: ctx.runtime,\n reason: \"cors\",\n });\n }\n}\n\n/**\n * The error a body ends with, when a 200 answer was cut short by one.\n * @param text - the body\n * @returns the error, or null\n */\nfunction trailingError(text: string): NeptuneError | null {\n for (let at = text.lastIndexOf(\"{\"); at > 0; at = text.lastIndexOf(\"{\", at - 1)) {\n const tail = parseJson(text.slice(at)) as NeptuneError | null;\n if (tail !== null && typeof tail.code === \"string\") {\n return tail;\n }\n }\n return null;\n}\n\n/**\n * Turn a Neptune answer into a result, or raise its error.\n * @param input - the transport input\n * @param response - the answer\n * @returns the mapped result\n */\nexport async function neptuneResult(input: TransportInput, response: Response): Promise<QueryResult> {\n const { ctx, m } = input;\n const origin = ctx.endpoint === null ? \"\" : originOf(ctx.endpoint);\n const text = await response.text();\n const body = parseJson(text) as ({ results?: readonly Record<string, unknown>[] } & NeptuneError) | null;\n let error: NeptuneError | null = typeof body?.code === \"string\" ? body : null;\n if (body === null) {\n error = trailingError(text);\n }\n if (error !== null) {\n serverError(\n ctx.report,\n {\n code: error.code ?? null,\n message: error.detailedMessage ?? error.message ?? \"\",\n status: response.status,\n showable: body !== null && response.status >= 400 && response.status < 500,\n },\n origin,\n undefined,\n );\n }\n if (!response.ok) {\n failOn(ctx.report, \"E_FETCH\", `${origin} answered ${String(response.status)}`, {\n url: origin,\n status: response.status,\n });\n }\n if (body === null || !Array.isArray(body.results)) {\n failOn(ctx.report, \"E_SOURCE_RESPONSE\", \"the Neptune answer has no results\", {\n expected: \"json\",\n contentType: response.headers.get(\"content-type\"),\n });\n }\n return objectRows(body.results, (v, column) => fromNeptune(v, column, m));\n}\n\n/**\n * Make the transport.\n * @param input - the context, params and mapper\n * @returns the transport\n */\nexport function neptuneHttpsTransport(input: TransportInput): Transport {\n const { ctx } = input;\n nodeOnly(ctx, \"neptune-https\");\n return {\n async run(statement, parameters): Promise<QueryResult> {\n const response = await ctx.fetch(\"openCypher\", {\n method: \"POST\",\n idempotent: true,\n allowStatus: [400, 500],\n body: new URLSearchParams({ query: statement, parameters: JSON.stringify(parameters) }),\n });\n return neptuneResult(input, response);\n },\n profile: () => Promise.resolve(neptuneProfile()),\n probe: async (): Promise<CypherProfile> => {\n const status = await ctx.fetchJson<{ dbEngineVersion?: string }>(\"status\");\n return neptuneProfile(typeof status.dbEngineVersion === \"string\" ? status.dbEngineVersion : null);\n },\n close: () => Promise.resolve(),\n };\n}\n","/**\n * The `neptune-analytics` transport (design section 12.4): `POST /queries` on the graph's host\n * (`<graph-id>.<region>.neptune-graph.amazonaws.com`), JSON `{ query, language: \"OPEN_CYPHER\",\n * parameters }`, always signed with `credentials.awsSigV4` for the service \"neptune-graph\".\n * Results share Neptune Database's `~id` shape. Node only until CORS on a graph host is shown to\n * work: a browser is refused before any request (E_SOURCE_RUNTIME, reason \"cors\").\n */\n\nimport { type QueryResult } from \"../flatten.js\";\nimport { neptuneProfile } from \"../profiles.js\";\nimport { neptuneResult, nodeOnly } from \"./neptune-https.js\";\nimport { type Transport, type TransportInput } from \"./transport.js\";\n\n/**\n * Make the transport.\n * @param input - the context, params and mapper\n * @returns the transport\n */\nexport function neptuneAnalyticsTransport(input: TransportInput): Transport {\n const { ctx } = input;\n nodeOnly(ctx, \"neptune-analytics\");\n const run = async (statement: string, parameters: Readonly<Record<string, unknown>>): Promise<QueryResult> => {\n const response = await ctx.fetch(\"queries\", {\n method: \"POST\",\n idempotent: true,\n allowStatus: [400, 500],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ query: statement, language: \"OPEN_CYPHER\", parameters }),\n });\n return neptuneResult(input, response);\n };\n return {\n run,\n profile: () => Promise.resolve(neptuneProfile()),\n probe: async () => {\n await run(\"RETURN 1 AS ok\", {});\n return neptuneProfile();\n },\n close: () => Promise.resolve(),\n };\n}\n","/**\n * The `query-api` transport (design section 12.2): Neo4j's `POST /db/{database}/query/v2`, on by\n * default since Neo4j 5.26 and on Aura, with no driver. It asks for typed JSON, so integers keep\n * every digit, and sends `accessMode: \"Read\"`, which the server enforces. CORS is open by default,\n * so it works from a page on https.\n */\n\nimport { originOf } from \"../../credentials.js\";\nimport { failOn } from \"../../fail.js\";\nimport { type QueryResult } from \"../flatten.js\";\nimport { type CypherProfile, neo4jProfile } from \"../profiles.js\";\nimport { fromTypedJson } from \"../types-map.js\";\nimport { parseJson, serverError, type Transport, type TransportInput } from \"./transport.js\";\n\n/** The media type of Neo4j's typed JSON. */\nconst TYPED_JSON = \"application/vnd.neo4j.query.v1.1\";\n\n/** The statuses whose JSON body says what went wrong. */\nconst ERROR_STATUSES = [400, 404, 500];\n\n/** The shape of a Query API answer. */\ninterface QueryApiBody {\n readonly data?: { readonly fields: readonly string[]; readonly values: readonly (readonly unknown[])[] };\n readonly errors?: readonly { readonly code?: string; readonly message?: string }[];\n}\n\n/**\n * Make the transport.\n * @param input - the context, params and mapper\n * @returns the transport\n */\nexport function queryApiTransport(input: TransportInput): Transport {\n const { ctx, params, m } = input;\n const database = params.database ?? \"neo4j\";\n const path = `db/${encodeURIComponent(database)}/query/v2`;\n const origin = ctx.endpoint === null ? \"\" : originOf(ctx.endpoint);\n\n const run = async (statement: string, parameters: Readonly<Record<string, unknown>>): Promise<QueryResult> => {\n const response = await ctx.fetch(path, {\n method: \"POST\",\n idempotent: true,\n allowStatus: ERROR_STATUSES,\n headers: { \"Content-Type\": \"application/json\", Accept: TYPED_JSON },\n body: JSON.stringify({ statement, parameters, accessMode: \"Read\" }),\n });\n const body = parseJson(await response.text()) as QueryApiBody | null;\n const first = body?.errors?.[0];\n if (first !== undefined) {\n serverError(\n ctx.report,\n {\n code: first.code ?? null,\n message: first.message ?? \"\",\n status: response.status,\n showable: response.status >= 400 && response.status < 500,\n },\n origin,\n params.database,\n );\n }\n if (response.status === 404) {\n // no Query API here: a Neo4j before 5.26 answers 404, and speaks only Bolt\n failOn(ctx.report, \"E_SOURCE_NOT_FOUND\", `${origin} has no Query API at ${path}`, {\n what: \"url\",\n value: `${origin}/${path}`,\n });\n }\n if (!response.ok) {\n failOn(ctx.report, \"E_FETCH\", `${origin} answered ${String(response.status)}`, {\n url: `${origin}/${path}`,\n status: response.status,\n });\n }\n if (body?.data === undefined) {\n failOn(ctx.report, \"E_SOURCE_RESPONSE\", \"the Query API answer has no data\", {\n expected: \"json\",\n contentType: response.headers.get(\"content-type\"),\n });\n }\n const { fields, values } = body.data;\n return { fields, rows: values.map((row) => row.map((v, i) => fromTypedJson(v, fields[i] ?? \"\", m))) };\n };\n\n return {\n run,\n // the Query API exists from Neo4j 5.26, so ids are elementId()\n profile: () => Promise.resolve(neo4jProfile(null)),\n probe: async (): Promise<CypherProfile> => {\n const res = await run(\n \"CALL dbms.components() YIELD name, versions, edition RETURN name, versions, edition\",\n {},\n );\n const kernel = res.rows.find((r) => r[0] === \"Neo4j Kernel\") ?? res.rows[0];\n const versions = kernel?.[1];\n const version = Array.isArray(versions) && typeof versions[0] === \"string\" ? versions[0] : null;\n return neo4jProfile(version);\n },\n close: () => Promise.resolve(),\n };\n}\n","/**\n * `@graphty/graph-io/sources/cypher`: the Cypher source and its `neo4j` and `neptune` presets\n * (design sections 10, 11, 12.2 and 12.4). One query builder, one result flattener and one type\n * mapper over four transports: Neo4j's Query API, Bolt (through the optional peer neo4j-driver),\n * Neptune Database over HTTPS and Neptune Analytics. The presets fix the transports and the server\n * profile and hold no query code of their own. Experimental.\n * @module @graphty/graph-io/sources/cypher\n */\n\nimport { type GraphSink, type NodeId } from \"@graphty/graph-format\";\n\nimport { throwIfAborted } from \"../../common/input.js\";\nimport { type ImportReportBuilder } from \"../../common/report.js\";\nimport { ImportError, type ImportReport } from \"../../types.js\";\nimport { SOURCE_ISSUE } from \"../codes.js\";\nimport { defineSource } from \"../define.js\";\nimport { failOn } from \"../fail.js\";\nimport { CYPHER_SOURCE_ID, NEO4J_SOURCE_ID, NEPTUNE_SOURCE_ID } from \"../ids.js\";\nimport { sha256Hex } from \"../sigv4.js\";\nimport {\n type ExpandRequest,\n type GraphSource,\n type SourceContext,\n type SourceCursor,\n type SourceDescriptor,\n type SourceFreshness,\n type SourceProbe,\n type SourceValidators,\n} from \"../types.js\";\nimport { CYPHER_DESCRIPTOR, NEO4J_DESCRIPTOR, NEPTUNE_DESCRIPTOR } from \"./descriptor.js\";\nimport { canonicalRows, Collector, compareText, requireGraph, writeCollected } from \"./flatten.js\";\nimport { type CypherParams } from \"./params.js\";\nimport { type CypherProfile, neo4jProfile, neptuneProfile, serverFacts } from \"./profiles.js\";\nimport {\n checkedInteger,\n counts,\n DEFAULT_PAGE_SIZE,\n edgePage,\n MAX_DEPTH,\n MAX_PAGE_SIZE,\n neighborhood,\n nodePage,\n type QueryFilters,\n quoted,\n} from \"./query-builder.js\";\nimport { boltTransport } from \"./transports/bolt.js\";\nimport { neptuneAnalyticsTransport } from \"./transports/neptune-analytics.js\";\nimport { neptuneHttpsTransport } from \"./transports/neptune-https.js\";\nimport { queryApiTransport } from \"./transports/query-api.js\";\nimport { type Transport, type TransportInput } from \"./transports/transport.js\";\n\nexport { CYPHER_DESCRIPTOR, NEO4J_DESCRIPTOR, NEPTUNE_DESCRIPTOR } from \"./descriptor.js\";\nexport { type CypherParams } from \"./params.js\";\nexport { cypherIdentifier } from \"./query-builder.js\";\n\n/** The transports, by name. */\ntype TransportName = NonNullable<CypherParams[\"transport\"]>;\n\n/** What a preset fixes. */\ninterface Preset {\n /** The source id. */\n readonly id: string;\n /** Its descriptor. */\n readonly descriptor: SourceDescriptor;\n /** The transport used when neither the params nor the endpoint's scheme picks one. */\n readonly transport: TransportName;\n}\n\n/** One page a read produced. */\ninterface Page {\n /** What it held. */\n readonly collected: Collector;\n /** Where the next page starts, or null after the last. */\n readonly next: SourceCursor | null;\n}\n\n/** The directions an expansion may follow. */\nconst DIRECTIONS: ReadonlySet<string> = new Set([\"out\", \"in\", \"both\"]);\n\n/**\n * A list parameter: an array, or one value. A string is one item, never split, since an id or a\n * label may hold any character.\n * @param value - the value\n * @param name - the parameter\n * @param report - the load's report\n * @returns the items\n */\nfunction listParam(value: unknown, name: string, report: ImportReportBuilder): readonly unknown[] {\n if (value === undefined || value === null) {\n return [];\n }\n if (Array.isArray(value)) {\n return value as unknown[];\n }\n if (typeof value === \"string\" || typeof value === \"number\") {\n return [value];\n }\n return failOn(report, \"E_SOURCE_PARAM\", `parameter ${name}: not a list`, { name, reason: \"type\" });\n}\n\n/**\n * The transport a load uses: the params' choice, else the endpoint's scheme, else the preset's.\n * @param params - the params\n * @param ctx - the context\n * @param preset - the preset\n * @returns the transport name\n */\nfunction transportName(params: CypherParams, ctx: SourceContext, preset: Preset): TransportName {\n if (params.transport !== undefined) {\n return params.transport;\n }\n const scheme = ctx.endpoint?.protocol ?? \"\";\n if (scheme.startsWith(\"bolt\") || scheme.startsWith(\"neo4j\")) {\n return \"bolt\";\n }\n if (ctx.endpoint?.hostname.endsWith(\".neptune-graph.amazonaws.com\") === true) {\n return \"neptune-analytics\";\n }\n return preset.transport;\n}\n\n/** One load's connection, filters and profile. */\nclass Reader {\n private known: CypherProfile | null = null;\n private degree = true;\n readonly filters: QueryFilters;\n /** The raw id property, for the node ids. */\n readonly idProperty: string | null;\n\n /**\n * Set up a read.\n * @param transport - the transport\n * @param params - the params\n * @param ctx - the context\n */\n constructor(\n readonly transport: Transport,\n readonly params: CypherParams,\n readonly ctx: SourceContext,\n ) {\n const { report } = ctx;\n this.idProperty = params.idProperty ?? null;\n this.filters = {\n labels: listParam(params.labels, \"labels\", report).map((l) => quoted(l, \"labels\", report)),\n relationshipTypes: listParam(params.relationshipTypes, \"relationshipTypes\", report).map((t) =>\n quoted(t, \"relationshipTypes\", report),\n ),\n idProperty: this.idProperty === null ? null : quoted(this.idProperty, \"idProperty\", report),\n };\n }\n\n /**\n * The server's profile: the params' choice, else the transport's detection.\n * @returns the profile\n */\n async profile(): Promise<CypherProfile> {\n if (this.known === null) {\n const detected = await this.transport.profile();\n this.known = detected;\n if (this.params.profile === \"neptune\") {\n this.known = neptuneProfile(detected.version);\n } else if (this.params.profile === \"neo4j\" && detected.name !== \"neo4j\") {\n this.known = neo4jProfile(detected.version);\n }\n }\n return this.known;\n }\n\n /**\n * Run a generated statement with the degree hint, and without it once if the server refuses it.\n * @param build - builds the statement, with or without the hint\n * @param parameters - its parameters\n * @returns the result, collected\n */\n async generated(\n build: (degree: boolean) => string,\n parameters: Readonly<Record<string, unknown>>,\n ): Promise<{ collected: Collector; rows: readonly (readonly unknown[])[]; fields: readonly string[] }> {\n let result;\n try {\n result = await this.transport.run(build(this.degree), parameters);\n } catch (err) {\n if (!this.degree || !(err instanceof ImportError) || err.issue?.code !== SOURCE_ISSUE.E_SOURCE_QUERY) {\n throw err;\n }\n // the pattern comprehension of the degree hint is not every server's (Neptune, unverified)\n this.degree = false;\n result = await this.transport.run(build(false), parameters);\n }\n const collected = new Collector();\n collected.add(result, true);\n return { collected, rows: result.rows, fields: result.fields };\n }\n\n /**\n * The pages of a read, as `mode` asks.\n * @param cursor - where to resume\n * @yields one page at a time\n */\n async *pages(cursor: SourceCursor | null): AsyncGenerator<Page> {\n const { params, ctx } = this;\n const { report } = ctx;\n const mode = params.mode ?? (typeof params.query === \"string\" && params.query !== \"\" ? \"query\" : \"all\");\n if (mode === \"query\") {\n if (typeof params.query !== \"string\" || params.query.trim() === \"\") {\n failOn(report, \"E_SOURCE_PARAM\", \"mode query needs a query\", { name: \"query\", reason: \"required\" });\n }\n const result = await this.transport.run(params.query, params.parameters ?? {});\n const collected = new Collector();\n collected.add(result, false);\n requireGraph(result, collected, report);\n yield { collected, next: null };\n return;\n }\n const profile = await this.profile();\n if (mode === \"neighborhood\") {\n const ids = listParam(params.ids, \"ids\", report) as readonly NodeId[];\n if (ids.length === 0) {\n failOn(report, \"E_SOURCE_PARAM\", \"mode neighborhood needs ids\", { name: \"ids\", reason: \"required\" });\n }\n const shape = {\n depth: checkedInteger(params.depth ?? 1, \"depth\", 1, MAX_DEPTH, report),\n direction: \"both\" as const,\n limit:\n ctx.limits.maxNodes === undefined\n ? null\n : checkedInteger(ctx.limits.maxNodes, \"maxNodes\", 1, Number.MAX_SAFE_INTEGER, report),\n };\n const { collected } = await this.generated((d) => neighborhood(profile, this.filters, shape, d), { ids });\n yield { collected, next: null };\n return;\n }\n yield* this.everything(profile, cursor);\n }\n\n /**\n * Mode \"all\": the nodes, then the relationships with their ends, each paged by keyset on the\n * id expression (never SKIP), so a page is stable under unrelated writes.\n * @param profile - the server's profile\n * @param cursor - where to resume\n * @yields one page at a time\n */\n private async *everything(profile: CypherProfile, cursor: SourceCursor | null): AsyncGenerator<Page> {\n const { params, ctx } = this;\n const size = checkedInteger(params.pageSize ?? DEFAULT_PAGE_SIZE, \"pageSize\", 1, MAX_PAGE_SIZE, ctx.report);\n let phase: \"nodes\" | \"edges\" = cursor?.phase === \"edges\" ? \"edges\" : \"nodes\";\n let after: string | number | boolean | null = cursor?.after ?? null;\n const total = params.countFirst === true && cursor === null ? await this.total() : undefined;\n for (;;) {\n const nodes = phase === \"nodes\";\n const { collected, rows, fields } = await this.generated(\n (d) =>\n nodes\n ? nodePage(profile, this.filters, size, after !== null, d)\n : edgePage(profile, this.filters, size, after !== null),\n after === null ? {} : { after },\n );\n const next = nextCursor(phase, rows, fields, Number(size));\n yield { collected, next };\n const { counts: done } = ctx.report;\n ctx.progress(done.nodes + done.edges, total, \"items\");\n if (next === null) {\n return;\n }\n phase = next.phase === \"edges\" ? \"edges\" : \"nodes\";\n after = next.after ?? null;\n }\n }\n\n /**\n * How many nodes and relationships the filters match, for progress.\n * @returns the count\n */\n private async total(): Promise<number> {\n const [n, r] = counts(this.filters);\n const [a, b] = await Promise.all([this.transport.run(n, {}), this.transport.run(r, {})]);\n return Number(a.rows[0]?.[0] ?? 0) + Number(b.rows[0]?.[0] ?? 0);\n }\n\n /**\n * The server facts and validators of what was read.\n * @param lines - the canonical rows\n * @returns the server facts and validators\n */\n async facts(lines: string[]): Promise<{ server: Readonly<Record<string, string>>; validators: SourceValidators }> {\n const profile = await this.profile();\n const contentHash = await sha256Hex([...lines].sort(compareText).join(\"\\n\"));\n return {\n server: serverFacts(profile),\n validators: profile.version === null ? { contentHash } : { contentHash, serverVersion: profile.version },\n };\n }\n}\n\n/**\n * Where mode \"all\" resumes after a page: the same phase after the page's last key while pages are\n * full, then the relationships from the start, then nothing.\n * @param phase - the page's phase\n * @param rows - the page's rows\n * @param fields - the page's field names\n * @param size - the page size\n * @returns the next cursor, or null at the end\n */\nfunction nextCursor(\n phase: \"nodes\" | \"edges\",\n rows: readonly (readonly unknown[])[],\n fields: readonly string[],\n size: number,\n): SourceCursor | null {\n const last = rows.at(-1)?.[fields.indexOf(\"key\")];\n const key = typeof last === \"string\" || typeof last === \"number\" ? last : null;\n if (rows.length >= size && key !== null) {\n return { phase, after: key };\n }\n return phase === \"nodes\" ? { phase: \"edges\", after: null } : null;\n}\n\n/**\n * Open a read: pick the transport, check what it needs, connect.\n * @param params - the params\n * @param ctx - the context\n * @param preset - the preset\n * @returns the reader\n */\nasync function open(params: CypherParams, ctx: SourceContext, preset: Preset): Promise<Reader> {\n throwIfAborted(ctx.signal);\n const input: TransportInput = { ctx, params, m: { long: params.long ?? \"f64\", report: ctx.report } };\n const name = transportName(params, ctx, preset);\n let transport: Transport;\n switch (name) {\n case \"bolt\":\n transport = await boltTransport(input);\n break;\n case \"neptune-https\":\n transport = neptuneHttpsTransport(input);\n break;\n case \"neptune-analytics\":\n transport = neptuneAnalyticsTransport(input);\n break;\n default:\n transport = queryApiTransport(input);\n break;\n }\n try {\n return new Reader(transport, params, ctx);\n } catch (err) {\n await transport.close();\n throw err;\n }\n}\n\n/**\n * Run something with a reader, closing it after.\n * @param params - the params\n * @param ctx - the context\n * @param preset - the preset\n * @param body - what to do\n * @returns what the body returned\n */\nasync function withReader<T>(\n params: CypherParams,\n ctx: SourceContext,\n preset: Preset,\n body: (reader: Reader) => Promise<T>,\n): Promise<T> {\n const reader = await open(params, ctx, preset);\n try {\n return await body(reader);\n } finally {\n await reader.transport.close();\n }\n}\n\n/**\n * Make the Cypher source or one of its presets.\n * @param preset - the id, descriptor and default transport\n * @returns the source\n */\nfunction cypher(preset: Preset): GraphSource<CypherParams> {\n return defineSource<CypherParams>({\n id: preset.id,\n descriptor: preset.descriptor,\n import: (params, sink, ctx) =>\n withReader(params, ctx, preset, async (reader): Promise<ImportReport> => {\n const lines: string[] = [];\n let next: SourceCursor | null = null;\n for await (const page of reader.pages(ctx.cursor)) {\n writeCollected(page.collected, sink, reader.idProperty, ctx.report, ctx.signal);\n lines.push(...canonicalRows(page.collected, reader.idProperty));\n ({ next } = page);\n if (next !== null && ctx.limits.reached()) {\n break;\n }\n }\n return ctx.finish({ next, ...(await reader.facts(lines)) });\n }),\n expand: (request, sink, ctx) =>\n withReader(request.params, ctx, preset, (reader) => expand(reader, request, sink)),\n probe: (params, ctx) =>\n withReader(params, ctx, preset, async (reader): Promise<SourceProbe> => {\n const profile = await reader.transport.probe();\n return { ok: true, server: serverFacts(profile) };\n }),\n validate: (params, seen, ctx) =>\n withReader(params, ctx, preset, async (reader): Promise<SourceFreshness> => {\n const lines: string[] = [];\n for await (const page of reader.pages(null)) {\n lines.push(...canonicalRows(page.collected, reader.idProperty));\n }\n const { validators } = await reader.facts(lines);\n let status: SourceFreshness[\"status\"] = \"unverifiable\";\n if (seen.contentHash !== undefined) {\n status = seen.contentHash === validators.contentHash ? \"current\" : \"changed\";\n }\n return { status, via: \"hash\", validators };\n }),\n });\n}\n\n/**\n * Fetch the neighborhood of some nodes into the sink.\n * @param reader - the reader\n * @param request - the seeds and how far to go\n * @param sink - where to write\n * @returns the report\n */\nasync function expand(reader: Reader, request: ExpandRequest<CypherParams>, sink: GraphSink): Promise<ImportReport> {\n const { ctx } = reader;\n const { report } = ctx;\n if (request.ids.length === 0) {\n failOn(report, \"E_SOURCE_PARAM\", \"an expansion needs seed ids\", { name: \"ids\", reason: \"required\" });\n }\n const direction = request.direction ?? \"both\";\n if (!DIRECTIONS.has(direction)) {\n failOn(report, \"E_SOURCE_PARAM\", \"direction must be out, in or both\", { name: \"direction\", reason: \"enum\" });\n }\n const limit = request.limit ?? ctx.limits.maxNodes;\n const after = ctx.cursor?.after ?? null;\n const shape = {\n depth: checkedInteger(request.depth ?? 1, \"depth\", 1, MAX_DEPTH, report),\n direction,\n limit: limit === undefined ? null : checkedInteger(limit, \"limit\", 1, Number.MAX_SAFE_INTEGER, report),\n after: after !== null,\n };\n const filters: QueryFilters =\n request.relationshipTypes === undefined\n ? reader.filters\n : {\n ...reader.filters,\n relationshipTypes: request.relationshipTypes.map((t) => quoted(t, \"relationshipTypes\", report)),\n };\n const profile = await reader.profile();\n const { collected, rows, fields } = await reader.generated((d) => neighborhood(profile, filters, shape, d), {\n ids: request.ids,\n ...(after === null ? {} : { after }),\n });\n writeCollected(collected, sink, reader.idProperty, report, ctx.signal);\n const { server } = await reader.facts([]);\n // A full page may have more behind it: hand back where the next one starts.\n const last = rows.at(-1)?.[fields.indexOf(\"key\")];\n const full = shape.limit !== null && rows.length >= Number(shape.limit);\n const next = full && (typeof last === \"string\" || typeof last === \"number\") ? { after: last } : null;\n return ctx.finish({ server, next });\n}\n\n/**\n * The generic Cypher source, for any openCypher server: Neo4j over its Query API or Bolt, Neptune\n * over HTTPS. The transport comes from `params.transport`, else the endpoint (`bolt+s://` is Bolt,\n * a `neptune-graph` host is Neptune Analytics), else the Query API. Experimental.\n * @category Network sources\n */\nexport const cypherSource: GraphSource<CypherParams> = cypher({\n id: CYPHER_SOURCE_ID,\n descriptor: CYPHER_DESCRIPTOR,\n transport: \"query-api\",\n});\n\n/**\n * The Neo4j preset: the Query API (Neo4j 5.26 and later, Aura), or Bolt for a `bolt:` or\n * `bolt+s:` endpoint (any Neo4j; needs the optional peer neo4j-driver). Experimental.\n * @category Network sources\n */\nexport const neo4jSource: GraphSource<CypherParams> = cypher({\n id: NEO4J_SOURCE_ID,\n descriptor: NEO4J_DESCRIPTOR,\n transport: \"query-api\",\n});\n\n/**\n * The Amazon Neptune preset: Neptune Database over HTTPS, or Neptune Analytics for a\n * `neptune-graph` host. Node only; sign requests with `credentials.awsSigV4`. Experimental.\n * @category Network sources\n */\nexport const neptuneSource: GraphSource<CypherParams> = cypher({\n id: NEPTUNE_SOURCE_ID,\n descriptor: NEPTUNE_DESCRIPTOR,\n transport: \"neptune-https\",\n});\n"],"names":["column","open"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src/sources/ndex/index.js";
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { f as failOn, c as credentials, b as failAlone, N as NDEX_SOURCE_ID, d as defineSource } from "./chunks/credentials-BiQsnMTb.js";
|
|
2
|
+
import { N as NDEX_DESCRIPTOR } from "./chunks/descriptor-C-YDhtsn.js";
|
|
3
|
+
import { c as cxImporter } from "./chunks/importer-Bji2MeWr.js";
|
|
4
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5
|
+
const ACCESS_KEY_QUERY = "accesskey";
|
|
6
|
+
const READ_STATUSES = [401, 403, 404];
|
|
7
|
+
function checkEndpoint(ctx) {
|
|
8
|
+
if (ctx.endpoint?.searchParams.has(ACCESS_KEY_QUERY) === true) {
|
|
9
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "an access key goes in a credential, never in the endpoint", {
|
|
10
|
+
name: "endpoint",
|
|
11
|
+
reason: "credentials-in-url"
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function checkedUuid(uuid, ctx) {
|
|
16
|
+
checkEndpoint(ctx);
|
|
17
|
+
const value = String(uuid);
|
|
18
|
+
if (/accesskey/i.test(value)) {
|
|
19
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "an access key goes in a credential, never in the uuid", {
|
|
20
|
+
name: "uuid",
|
|
21
|
+
reason: "credentials-in-url"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (!UUID.test(value)) {
|
|
25
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "the uuid is not a network UUID", { name: "uuid", reason: "format" });
|
|
26
|
+
}
|
|
27
|
+
return value.toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
async function ndexFetch(ctx, path, uuid, init = {}) {
|
|
30
|
+
const response = await ctx.fetch(path, { ...init, allowStatus: READ_STATUSES });
|
|
31
|
+
if (response.ok) {
|
|
32
|
+
return response;
|
|
33
|
+
}
|
|
34
|
+
const url = new URL(path, ctx.endpoint ?? void 0);
|
|
35
|
+
const serverCode = await errorCode(response);
|
|
36
|
+
const { status } = response;
|
|
37
|
+
if (status === 401) {
|
|
38
|
+
failOn(ctx.report, "E_SOURCE_AUTH", `NDEx answered ${String(status)}`, {
|
|
39
|
+
origin: url.origin,
|
|
40
|
+
status,
|
|
41
|
+
scheme: response.headers.get("www-authenticate")?.split(/\s/)[0] ?? null,
|
|
42
|
+
serverCode
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
if (status === 403) {
|
|
46
|
+
failOn(ctx.report, "E_SOURCE_FORBIDDEN", "NDEx answered 403", { status, serverCode });
|
|
47
|
+
}
|
|
48
|
+
return failOn(ctx.report, "E_SOURCE_NOT_FOUND", "NDEx has no such network", {
|
|
49
|
+
what: uuid === null ? "url" : "network",
|
|
50
|
+
value: uuid ?? `${url.origin}${url.pathname}`
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async function errorCode(response) {
|
|
54
|
+
try {
|
|
55
|
+
const body = await response.json();
|
|
56
|
+
return typeof body.errorCode === "string" ? body.errorCode.slice(0, 100) : null;
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const MAX_DEPTH = 10;
|
|
62
|
+
function term(value) {
|
|
63
|
+
const escaped = value.replaceAll(/["\\]/g, String.raw`\$&`);
|
|
64
|
+
return `"${escaped}"`;
|
|
65
|
+
}
|
|
66
|
+
function queryBody(request, ctx) {
|
|
67
|
+
const { ids } = request;
|
|
68
|
+
const { idAttribute } = request.params;
|
|
69
|
+
const depth = request.depth ?? 1;
|
|
70
|
+
if (!Number.isInteger(depth) || depth < 1 || depth > MAX_DEPTH) {
|
|
71
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "depth is an integer from 1 to 10", { name: "depth", reason: "range" });
|
|
72
|
+
}
|
|
73
|
+
if (ids.length === 0) {
|
|
74
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "an expansion needs at least one id", { name: "ids", reason: "required" });
|
|
75
|
+
}
|
|
76
|
+
const limit = request.limit === void 0 ? {} : { edgeLimit: request.limit, errorWhenLimitIsOver: false };
|
|
77
|
+
if (idAttribute !== void 0) {
|
|
78
|
+
if (!/^[A-Za-z_][\w.]*$/.test(idAttribute)) {
|
|
79
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "idAttribute is not an attribute name", {
|
|
80
|
+
name: "idAttribute",
|
|
81
|
+
reason: "identifier"
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const searchString = ids.map((id) => `${idAttribute}:${term(String(id))}`).join(" ");
|
|
85
|
+
return { searchString, searchDepth: depth, ...limit };
|
|
86
|
+
}
|
|
87
|
+
const nodeIds = ids.map(Number);
|
|
88
|
+
if (nodeIds.some((n) => !Number.isSafeInteger(n))) {
|
|
89
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "NDEx node ids are integers; set idAttribute to seed by name", {
|
|
90
|
+
name: "ids",
|
|
91
|
+
reason: "type"
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return { searchString: "", searchDepth: depth, nodeIds, ...limit };
|
|
95
|
+
}
|
|
96
|
+
async function expandNdex(request, sink, ctx) {
|
|
97
|
+
const uuid = checkedUuid(request.params.uuid, ctx);
|
|
98
|
+
if (request.direction !== void 0 && request.direction !== "both") {
|
|
99
|
+
failOn(ctx.report, "E_SOURCE_UNSUPPORTED", "NDEx expands in both directions only", {
|
|
100
|
+
feature: "direction",
|
|
101
|
+
needs: "both"
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if ((request.relationshipTypes ?? []).length > 0) {
|
|
105
|
+
failOn(ctx.report, "E_SOURCE_UNSUPPORTED", "NDEx cannot filter an expansion by relationship type", {
|
|
106
|
+
feature: "relationshipTypes"
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const response = await ndexFetch(ctx, `v2/search/network/${uuid}/query`, uuid, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
idempotent: true,
|
|
112
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
113
|
+
body: JSON.stringify(queryBody(request, ctx))
|
|
114
|
+
});
|
|
115
|
+
ctx.report.include(await cxImporter.import(response.body ?? "", sink, { signal: ctx.signal }));
|
|
116
|
+
return ctx.finish();
|
|
117
|
+
}
|
|
118
|
+
const UUID_IN_URL = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
|
|
119
|
+
function parseShareUrl(url) {
|
|
120
|
+
let parsed;
|
|
121
|
+
try {
|
|
122
|
+
parsed = new URL(url);
|
|
123
|
+
} catch {
|
|
124
|
+
return refuse("format");
|
|
125
|
+
}
|
|
126
|
+
if (parsed.username !== "" || parsed.password !== "") {
|
|
127
|
+
return refuse("credentials-in-url");
|
|
128
|
+
}
|
|
129
|
+
const hash = new URL(parsed.hash.replace(/^#/, ""), "https://hash.invalid/");
|
|
130
|
+
const uuid = UUID_IN_URL.exec(`${parsed.pathname} ${hash.pathname}`)?.[0];
|
|
131
|
+
if (uuid === void 0 || parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
132
|
+
return refuse("format");
|
|
133
|
+
}
|
|
134
|
+
const host = parsed.host.toLowerCase() === "ndexbio.org" ? "www.ndexbio.org" : parsed.host;
|
|
135
|
+
const endpoint = `${parsed.protocol}//${host}/`;
|
|
136
|
+
const key = parsed.searchParams.get(ACCESS_KEY_QUERY) ?? hash.searchParams.get(ACCESS_KEY_QUERY);
|
|
137
|
+
const params = { uuid: uuid.toLowerCase() };
|
|
138
|
+
if (key === null || key === "") {
|
|
139
|
+
return { params, endpoint };
|
|
140
|
+
}
|
|
141
|
+
const credential = credentials.apiKey({ query: ACCESS_KEY_QUERY }, key, { origins: [new URL(endpoint).origin] });
|
|
142
|
+
return { params, endpoint, credential };
|
|
143
|
+
}
|
|
144
|
+
function refuse(reason) {
|
|
145
|
+
return failAlone("E_SOURCE_PARAM", "not an NDEx share link", { name: "url", reason }, `source:${NDEX_SOURCE_ID}`);
|
|
146
|
+
}
|
|
147
|
+
async function readSummary(uuid, ctx) {
|
|
148
|
+
const response = await ndexFetch(ctx, `v3/networks/${uuid}/summary`, uuid, {
|
|
149
|
+
headers: { Accept: "application/json" }
|
|
150
|
+
});
|
|
151
|
+
const text = await response.text();
|
|
152
|
+
try {
|
|
153
|
+
return { summary: JSON.parse(text), bytes: new TextEncoder().encode(text).byteLength };
|
|
154
|
+
} catch {
|
|
155
|
+
return failOn(ctx.report, "E_SOURCE_RESPONSE", "the NDEx summary is not JSON", {
|
|
156
|
+
expected: "json",
|
|
157
|
+
contentType: response.headers.get("content-type")
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function iso(ms) {
|
|
162
|
+
return typeof ms === "number" && Number.isFinite(ms) ? new Date(ms).toISOString() : void 0;
|
|
163
|
+
}
|
|
164
|
+
function sizeOf(summary, format) {
|
|
165
|
+
return format === "cx" ? summary.cxFileSize : summary.cx2FileSize;
|
|
166
|
+
}
|
|
167
|
+
function checkCaps(summary, format, ctx) {
|
|
168
|
+
const caps = [
|
|
169
|
+
["maxNodes", summary.nodeCount, ctx.limits.maxNodes],
|
|
170
|
+
["maxEdges", summary.edgeCount, ctx.limits.maxEdges],
|
|
171
|
+
["maxBytes", sizeOf(summary, format), ctx.limits.maxBytes]
|
|
172
|
+
];
|
|
173
|
+
for (const [limit, value, cap] of caps) {
|
|
174
|
+
if (value !== void 0 && cap !== void 0 && value > cap) {
|
|
175
|
+
failOn(ctx.report, "E_SOURCE_LIMIT", `the network's ${limit} of ${String(value)} is over the cap`, {
|
|
176
|
+
limit,
|
|
177
|
+
value
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function metaOf(summary) {
|
|
183
|
+
const meta = {};
|
|
184
|
+
const modified = iso(summary.modificationTime);
|
|
185
|
+
if (modified !== void 0) {
|
|
186
|
+
meta.modified = modified;
|
|
187
|
+
}
|
|
188
|
+
if (typeof summary.visibility === "string") {
|
|
189
|
+
meta.visibility = summary.visibility;
|
|
190
|
+
}
|
|
191
|
+
for (const key of ["rights", "rightsHolder"]) {
|
|
192
|
+
const value = summary.properties?.[key]?.v;
|
|
193
|
+
if (typeof value === "string") {
|
|
194
|
+
meta[key] = value;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return meta;
|
|
198
|
+
}
|
|
199
|
+
function validatorsOf(summary) {
|
|
200
|
+
const modified = iso(summary.modificationTime);
|
|
201
|
+
return modified === void 0 ? {} : { modified };
|
|
202
|
+
}
|
|
203
|
+
const ndexSource = defineSource({
|
|
204
|
+
id: NDEX_SOURCE_ID,
|
|
205
|
+
descriptor: NDEX_DESCRIPTOR,
|
|
206
|
+
async file(params, ctx) {
|
|
207
|
+
const uuid = checkedUuid(params.uuid, ctx);
|
|
208
|
+
const format = params.format ?? "cx2";
|
|
209
|
+
const { summary, bytes } = await readSummary(uuid, ctx);
|
|
210
|
+
checkCaps(summary, format, ctx);
|
|
211
|
+
const size = sizeOf(summary, format);
|
|
212
|
+
ctx.progress(bytes, size === void 0 ? void 0 : bytes + size, "bytes");
|
|
213
|
+
ctx.finish({ validators: validatorsOf(summary) });
|
|
214
|
+
const path = format === "cx" ? `v2/network/${uuid}` : `v3/networks/${uuid}`;
|
|
215
|
+
const body = await ndexFetch(ctx, path, uuid);
|
|
216
|
+
return { body, format, meta: metaOf(summary) };
|
|
217
|
+
},
|
|
218
|
+
async probe(params, ctx) {
|
|
219
|
+
const uuid = checkedUuid(params.uuid, ctx);
|
|
220
|
+
const { summary } = await readSummary(uuid, ctx);
|
|
221
|
+
return {
|
|
222
|
+
ok: true,
|
|
223
|
+
counts: {
|
|
224
|
+
nodes: summary.nodeCount,
|
|
225
|
+
edges: summary.edgeCount,
|
|
226
|
+
bytes: sizeOf(summary, params.format ?? "cx2")
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
},
|
|
230
|
+
async list(query, ctx) {
|
|
231
|
+
checkEndpoint(ctx);
|
|
232
|
+
const start = Number(query.cursor?.start ?? 0);
|
|
233
|
+
const size = query.size ?? 25;
|
|
234
|
+
const body = await ctx.fetchJson(
|
|
235
|
+
`v2/search/network?start=${String(start)}&size=${String(size)}`,
|
|
236
|
+
{
|
|
237
|
+
method: "POST",
|
|
238
|
+
idempotent: true,
|
|
239
|
+
headers: { "Content-Type": "application/json" },
|
|
240
|
+
body: JSON.stringify({ searchString: query.search ?? "" })
|
|
241
|
+
}
|
|
242
|
+
);
|
|
243
|
+
const networks = Array.isArray(body.networks) ? body.networks : failOn(ctx.report, "E_SOURCE_RESPONSE", "the NDEx search answer has no networks", {
|
|
244
|
+
expected: "ndex-search",
|
|
245
|
+
contentType: "application/json"
|
|
246
|
+
});
|
|
247
|
+
const { numFound } = body;
|
|
248
|
+
const items = networks.flatMap(
|
|
249
|
+
(n) => typeof n.externalId === "string" ? [
|
|
250
|
+
{
|
|
251
|
+
params: { uuid: n.externalId },
|
|
252
|
+
name: n.name ?? n.externalId,
|
|
253
|
+
nodeCount: n.nodeCount,
|
|
254
|
+
edgeCount: n.edgeCount,
|
|
255
|
+
modified: iso(n.modificationTime)
|
|
256
|
+
}
|
|
257
|
+
] : []
|
|
258
|
+
);
|
|
259
|
+
const total = typeof numFound === "number" ? numFound : void 0;
|
|
260
|
+
const more = total === void 0 ? networks.length === size : start + networks.length < total;
|
|
261
|
+
return { items, next: more && networks.length > 0 ? { start: start + networks.length } : null, total };
|
|
262
|
+
},
|
|
263
|
+
async validate(params, seen, ctx) {
|
|
264
|
+
const uuid = checkedUuid(params.uuid, ctx);
|
|
265
|
+
const validators = validatorsOf((await readSummary(uuid, ctx)).summary);
|
|
266
|
+
if (seen.modified === void 0 || validators.modified === void 0) {
|
|
267
|
+
return { status: "unverifiable", validators };
|
|
268
|
+
}
|
|
269
|
+
return seen.modified === validators.modified ? { status: "current", via: "modified", validators } : { status: "changed", via: "modified", changedAt: validators.modified, validators };
|
|
270
|
+
},
|
|
271
|
+
expand: expandNdex
|
|
272
|
+
});
|
|
273
|
+
export {
|
|
274
|
+
NDEX_DESCRIPTOR,
|
|
275
|
+
ndexSource,
|
|
276
|
+
parseShareUrl
|
|
277
|
+
};
|
|
278
|
+
//# sourceMappingURL=sources-ndex.js.map
|