@factoidal/core 0.13.0 → 0.15.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.
@@ -0,0 +1,71 @@
1
+ // A synchronous HTTP GET for Node, for the readers of lib/sbm11.mjs that read
2
+ // over HTTP (lib/sbm11-lws.mjs; https://github.com/danbri/factoidal/issues/1010).
3
+ // The engine is inside WebAssembly and asks for bytes synchronously; Node's
4
+ // fetch is asynchronous. A worker thread makes the fetch; this thread waits
5
+ // on a shared Int32Array (Atomics.wait) and takes the answer with
6
+ // receiveMessageOnPort. Pure I/O: no header is read here, no status judged.
7
+ //
8
+ // The thread that calls the transport is blocked until the answer comes, so
9
+ // the server must not run on that thread (start it in another process or
10
+ // worker).
11
+
12
+ import { Worker, MessageChannel, receiveMessageOnPort } from 'node:worker_threads'
13
+
14
+ const WORKER = `
15
+ const { workerData } = require('node:worker_threads')
16
+ const { port, signal } = workerData
17
+ const flag = new Int32Array(signal)
18
+ port.on('message', async (req) => {
19
+ let out
20
+ try {
21
+ const r = await fetch(req.url, { headers: req.headers, redirect: 'follow' })
22
+ const headers = {}
23
+ r.headers.forEach((v, k) => { headers[k] = v })
24
+ out = { status: r.status, headers, bytes: new Uint8Array(await r.arrayBuffer()) }
25
+ } catch (e) {
26
+ out = { error: String(e && e.message ? e.message : e) }
27
+ }
28
+ port.postMessage(out)
29
+ Atomics.store(flag, 0, 1)
30
+ Atomics.notify(flag, 0)
31
+ })
32
+ `
33
+
34
+ /**
35
+ * A synchronous transport `(url, headers) -> { status, header(name), bytes }`
36
+ * with a `close()` that stops its worker.
37
+ *
38
+ * @param {object} [opts]
39
+ * @param {number} [opts.timeoutMs] the most one request may take (default 60000)
40
+ */
41
+ export function nodeSyncTransport (opts = {}) {
42
+ const timeoutMs = typeof opts.timeoutMs === 'number' ? opts.timeoutMs : 60000
43
+ const signal = new SharedArrayBuffer(4)
44
+ const flag = new Int32Array(signal)
45
+ const { port1, port2 } = new MessageChannel()
46
+ const worker = new Worker(WORKER, { eval: true, workerData: { port: port2, signal }, transferList: [port2] })
47
+ worker.unref()
48
+ port1.unref()
49
+ let closed = false
50
+ function transport (url, headers) {
51
+ if (closed) throw new Error('the transport is closed')
52
+ Atomics.store(flag, 0, 0)
53
+ port1.postMessage({ url: String(url), headers: { ...headers } })
54
+ if (Atomics.wait(flag, 0, 0, timeoutMs) === 'timed-out') {
55
+ throw new Error(`GET ${url}: no answer in ${timeoutMs} ms`)
56
+ }
57
+ const got = receiveMessageOnPort(port1)
58
+ if (!got) throw new Error(`GET ${url}: no answer from the transport worker`)
59
+ const m = got.message
60
+ if (m.error) throw new Error(m.error)
61
+ const h = m.headers
62
+ return { status: m.status, header: (name) => (Object.hasOwn(h, name.toLowerCase()) ? h[name.toLowerCase()] : null), bytes: m.bytes }
63
+ }
64
+ transport.close = () => {
65
+ if (closed) return
66
+ closed = true
67
+ port1.close()
68
+ worker.terminate()
69
+ }
70
+ return transport
71
+ }
package/lib/version.mjs CHANGED
@@ -2,4 +2,4 @@
2
2
  // needs import attributes, which not every runtime this package targets
3
3
  // reads). test/dts-drift.test.js checks that it equals package.json's
4
4
  // `version`.
5
- export const version = '0.13.0';
5
+ export const version = '0.15.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@factoidal/core",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "RDF parsing and writing (Turtle, TriG, N-Triples, N-Quads, RDF/XML, JSON-LD), SPARQL 1.1 and 1.2, RDFS and OWL reasoning, SHACL and ShEx validation, CSVW and RML mapping, RDFC-1.0, and SPARQL, LWS and Solid servers, for Node, Deno and browsers.",
5
5
  "keywords": [
6
6
  "sparql",
package/sample-store.mjs CHANGED
@@ -27,7 +27,7 @@ ex:c3 a skos:Concept ; skos:inScheme ex:scheme ; skos:prefLabel "SECAM"@en ; sko
27
27
  export const sampleStoreFacts = Object.freeze({
28
28
  triples: 15,
29
29
  source: 'SAMPLE_TURTLE in sample-store.mjs (written for this package)',
30
- layout: 'ibk3'
30
+ layout: 'ibk5'
31
31
  })
32
32
 
33
33
  /**