@lde/pipeline 0.25.3 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,7 +16,8 @@ declare abstract class ProbeResult {
16
16
  readonly statusText: string;
17
17
  readonly lastModified: Date | null;
18
18
  readonly contentType: string | null;
19
- constructor(url: string, response: Response);
19
+ readonly failureReason: string | null;
20
+ constructor(url: string, response: Response, failureReason?: string | null);
20
21
  isSuccess(): boolean;
21
22
  }
22
23
  /**
@@ -31,9 +32,7 @@ export declare class SparqlProbeResult extends ProbeResult {
31
32
  */
32
33
  export declare class DataDumpProbeResult extends ProbeResult {
33
34
  readonly contentSize: number | null;
34
- readonly failureReason: string | null;
35
35
  constructor(url: string, response: Response, failureReason?: string | null);
36
- isSuccess(): boolean;
37
36
  }
38
37
  export type ProbeResultType = SparqlProbeResult | DataDumpProbeResult | NetworkError;
39
38
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../src/distribution/probe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C;;GAEG;AACH,qBAAa,YAAY;aAEL,GAAG,EAAE,MAAM;aACX,OAAO,EAAE,MAAM;gBADf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM;CAElC;AAED;;GAEG;AACH,uBAAe,WAAW;aAON,GAAG,EAAE,MAAM;IAN7B,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,YAAY,EAAE,IAAI,GAAG,IAAI,CAAQ;IACjD,SAAgB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;gBAGzB,GAAG,EAAE,MAAM,EAC3B,QAAQ,EAAE,QAAQ;IAWb,SAAS,IAAI,OAAO;CAG5B;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;IAChD,SAAgB,mBAAmB,qCAAqC;IAE/D,SAAS,IAAI,OAAO;CAM9B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;IAClD,SAAgB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAClD,SAAgB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;gBAG3C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,aAAa,GAAE,MAAM,GAAG,IAAW;IAU5B,SAAS,IAAI,OAAO;CAG9B;AAED,MAAM,MAAM,eAAe,GACvB,iBAAiB,GACjB,mBAAmB,GACnB,YAAY,CAAC;AAEjB;;;;;;;GAOG;AACH,wBAAsB,KAAK,CACzB,YAAY,EAAE,YAAY,EAC1B,OAAO,SAAO,GACb,OAAO,CAAC,eAAe,CAAC,CAY1B"}
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../src/distribution/probe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C;;GAEG;AACH,qBAAa,YAAY;aAEL,GAAG,EAAE,MAAM;aACX,OAAO,EAAE,MAAM;gBADf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM;CAElC;AAED;;GAEG;AACH,uBAAe,WAAW;aAQN,GAAG,EAAE,MAAM;IAP7B,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,YAAY,EAAE,IAAI,GAAG,IAAI,CAAQ;IACjD,SAAgB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,SAAgB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;gBAG3B,GAAG,EAAE,MAAM,EAC3B,QAAQ,EAAE,QAAQ,EAClB,aAAa,GAAE,MAAM,GAAG,IAAW;IAY9B,SAAS,IAAI,OAAO;CAO5B;AAID;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;IAChD,SAAgB,mBAAmB,qCAAuB;IAEjD,SAAS,IAAI,OAAO;CAM9B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;IAClD,SAAgB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;gBAGhD,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,aAAa,GAAE,MAAM,GAAG,IAAW;CAQtC;AAED,MAAM,MAAM,eAAe,GACvB,iBAAiB,GACjB,mBAAmB,GACnB,YAAY,CAAC;AAEjB;;;;;;;GAOG;AACH,wBAAsB,KAAK,CACzB,YAAY,EAAE,YAAY,EAC1B,OAAO,SAAO,GACb,OAAO,CAAC,eAAe,CAAC,CAY1B"}
@@ -19,25 +19,30 @@ class ProbeResult {
19
19
  statusText;
20
20
  lastModified = null;
21
21
  contentType;
22
- constructor(url, response) {
22
+ failureReason;
23
+ constructor(url, response, failureReason = null) {
23
24
  this.url = url;
24
25
  this.statusCode = response.status;
25
26
  this.statusText = response.statusText;
26
27
  this.contentType = response.headers.get('Content-Type');
28
+ this.failureReason = failureReason;
27
29
  const lastModifiedHeader = response.headers.get('Last-Modified');
28
30
  if (lastModifiedHeader) {
29
31
  this.lastModified = new Date(lastModifiedHeader);
30
32
  }
31
33
  }
32
34
  isSuccess() {
33
- return this.statusCode >= 200 && this.statusCode < 400;
35
+ return (this.statusCode >= 200 &&
36
+ this.statusCode < 400 &&
37
+ this.failureReason === null);
34
38
  }
35
39
  }
40
+ const SPARQL_RESULTS_JSON = 'application/sparql-results+json';
36
41
  /**
37
42
  * Result of probing a SPARQL endpoint.
38
43
  */
39
44
  export class SparqlProbeResult extends ProbeResult {
40
- acceptedContentType = 'application/sparql-results+json';
45
+ acceptedContentType = SPARQL_RESULTS_JSON;
41
46
  isSuccess() {
42
47
  return (super.isSuccess() &&
43
48
  (this.contentType?.startsWith(this.acceptedContentType) ?? false));
@@ -48,18 +53,13 @@ export class SparqlProbeResult extends ProbeResult {
48
53
  */
49
54
  export class DataDumpProbeResult extends ProbeResult {
50
55
  contentSize = null;
51
- failureReason;
52
56
  constructor(url, response, failureReason = null) {
53
- super(url, response);
54
- this.failureReason = failureReason;
57
+ super(url, response, failureReason);
55
58
  const contentLengthHeader = response.headers.get('Content-Length');
56
59
  if (contentLengthHeader) {
57
60
  this.contentSize = parseInt(contentLengthHeader);
58
61
  }
59
62
  }
60
- isSuccess() {
61
- return super.isSuccess() && this.failureReason === null;
62
- }
63
63
  }
64
64
  /**
65
65
  * Probe a distribution to check availability and gather metadata.
@@ -87,11 +87,38 @@ async function probeSparqlEndpoint(distribution, timeout) {
87
87
  method: 'POST',
88
88
  headers: {
89
89
  'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
90
- Accept: 'application/sparql-results+json',
90
+ Accept: SPARQL_RESULTS_JSON,
91
91
  },
92
92
  body: `query=${encodeURIComponent('SELECT * { ?s ?p ?o } LIMIT 1')}`,
93
93
  });
94
- return new SparqlProbeResult(url, response);
94
+ const isJsonResponse = response.headers
95
+ .get('Content-Type')
96
+ ?.startsWith(SPARQL_RESULTS_JSON);
97
+ let failureReason = null;
98
+ if (response.ok && isJsonResponse) {
99
+ failureReason = await validateSparqlResponse(response);
100
+ }
101
+ else {
102
+ // Drain unconsumed body to release the underlying connection.
103
+ await response.body?.cancel();
104
+ }
105
+ return new SparqlProbeResult(url, response, failureReason);
106
+ }
107
+ async function validateSparqlResponse(response) {
108
+ const body = await response.text();
109
+ if (body.length === 0) {
110
+ return 'SPARQL endpoint returned an empty response';
111
+ }
112
+ try {
113
+ const json = JSON.parse(body);
114
+ if (!json.results || typeof json.results !== 'object') {
115
+ return 'SPARQL endpoint did not return a valid results object';
116
+ }
117
+ }
118
+ catch {
119
+ return 'SPARQL endpoint returned invalid JSON';
120
+ }
121
+ return null;
95
122
  }
96
123
  async function probeDataDump(distribution, timeout) {
97
124
  const url = distribution.accessUrl.toString();
@@ -1,5 +1,5 @@
1
1
  import { DataFactory } from 'n3';
2
- import { NetworkError, SparqlProbeResult, DataDumpProbeResult, } from './probe.js';
2
+ import { NetworkError, SparqlProbeResult, } from './probe.js';
3
3
  const { quad, namedNode, blankNode, literal } = DataFactory;
4
4
  const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
5
5
  const SCHEMA = 'https://schema.org/';
@@ -30,7 +30,7 @@ export async function* probeResultsToQuads(probeResults, datasetIri, importResul
30
30
  else if (result.isSuccess()) {
31
31
  yield* successQuads(action, result, datasetIri);
32
32
  }
33
- else if (result instanceof DataDumpProbeResult && result.failureReason) {
33
+ else if (result.failureReason) {
34
34
  yield quad(action, namedNode(`${SCHEMA}error`), literal(result.failureReason));
35
35
  }
36
36
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"sparqlUpdateWriter.d.ts","sourceRoot":"","sources":["../../src/writer/sparqlUpdateWriter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAiB,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,QAAQ,EAAE,GAAG,CAAC;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,qBAAa,kBAAmB,YAAW,MAAM;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAM;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;gBAEvC,OAAO,EAAE,mBAAmB;IAOlC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAc1D,UAAU;YAIV,WAAW;YAOX,aAAa;CAsB5B"}
1
+ {"version":3,"file":"sparqlUpdateWriter.d.ts","sourceRoot":"","sources":["../../src/writer/sparqlUpdateWriter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAiB,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,QAAQ,EAAE,GAAG,CAAC;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,qBAAa,kBAAmB,YAAW,MAAM;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAM;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;gBAEvC,OAAO,EAAE,mBAAmB;IAOlC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAc1D,UAAU;YAIV,WAAW;YAOX,aAAa;CAuB5B"}
@@ -55,5 +55,6 @@ export class SparqlUpdateWriter {
55
55
  const body = await response.text();
56
56
  throw new Error(`SPARQL UPDATE failed with status ${response.status}: ${body}`);
57
57
  }
58
+ await response.body?.cancel();
58
59
  }
59
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lde/pipeline",
3
- "version": "0.25.3",
3
+ "version": "0.26.0",
4
4
  "repository": {
5
5
  "url": "git+https://github.com/ldelements/lde.git",
6
6
  "directory": "packages/pipeline"