@peisar/peisar-wasm32-wasi 0.2.22 → 0.3.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.
- package/package.json +4 -4
- package/peisar.wasi-browser.js +1 -0
- package/peisar.wasi.cjs +163 -2
- package/peisar.wasi.d.cts +81 -0
- package/peisar.wasm32-wasi.wasm +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peisar/peisar-wasm32-wasi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"main": "peisar.wasi.cjs",
|
|
5
5
|
"files": [
|
|
6
6
|
"peisar.wasm32-wasi.wasm",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"browser": "peisar.wasi-browser.js",
|
|
31
31
|
"type": "module",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@napi-rs/wasm-runtime": "~1.2.
|
|
34
|
-
"@emnapi/core": "2.0.0-alpha.
|
|
35
|
-
"@emnapi/runtime": "2.0.0-alpha.
|
|
33
|
+
"@napi-rs/wasm-runtime": "~1.2.5",
|
|
34
|
+
"@emnapi/core": "2.0.0-alpha.6",
|
|
35
|
+
"@emnapi/runtime": "2.0.0-alpha.6"
|
|
36
36
|
}
|
|
37
37
|
}
|
package/peisar.wasi-browser.js
CHANGED
|
@@ -1441,6 +1441,7 @@ try {
|
|
|
1441
1441
|
}
|
|
1442
1442
|
export default __napiModule.exports
|
|
1443
1443
|
export const Peisar = __napiModule.exports.Peisar
|
|
1444
|
+
export const PeisarCache = __napiModule.exports.PeisarCache
|
|
1444
1445
|
export const EmphasisLevel = __napiModule.exports.EmphasisLevel
|
|
1445
1446
|
export const TableCellAlignment = __napiModule.exports.TableCellAlignment
|
|
1446
1447
|
export const TaskState = __napiModule.exports.TaskState
|
package/peisar.wasi.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// napi-rs-artifact-metadata:{"version":2,"rootEntry":"index.js","exports":["Peisar","EmphasisLevel","TableCellAlignment","TaskState"],"managedRootEntries":["browser.js","index.js","peisar.wasm","peisar.debug.wasm"]}
|
|
1
|
+
// napi-rs-artifact-metadata:{"version":2,"rootEntry":"index.js","exports":["Peisar","PeisarCache","EmphasisLevel","TableCellAlignment","TaskState"],"managedRootEntries":["browser.js","index.js","peisar.wasm","peisar.debug.wasm"]}
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
/* auto-generated by NAPI-RS */
|
|
4
4
|
|
|
@@ -222,6 +222,34 @@ function __hasWasiThreadCrashed() {
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
let __wasiThreadCrashDisposePromise
|
|
225
|
+
// Raised by the crash disposal right before it terminates the workers. See
|
|
226
|
+
// `__wasiSetImmediate`.
|
|
227
|
+
let __wasiReentryClosed = false
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* emnapi's `features.setImmediate` for this binding's context. emnapi defers
|
|
231
|
+
* its calls back into wasm through it: `_emnapi_set_immediate` (libuv handle
|
|
232
|
+
* closes, threadsafe-function finalizers), threadsafe-function dispatch
|
|
233
|
+
* (`async-send`) and the finalizer queue. One queued before a crash disposal
|
|
234
|
+
* terminates the workers still runs after it, and a worker terminated while it
|
|
235
|
+
* held a lock in the wasm heap (napi's heap-sync allocator lock spins and never
|
|
236
|
+
* gives up) leaves that call spinning on this thread for good. The binding is
|
|
237
|
+
* unusable after a crash disposal, so those calls are dropped.
|
|
238
|
+
*
|
|
239
|
+
* Known residual, still able to enter wasm after a crash disposal because emnapi
|
|
240
|
+
* offers no hook for them: the `FinalizationRegistry` callbacks that free
|
|
241
|
+
* external memory when GC collects a value (`_free`, the shared-buffer meta
|
|
242
|
+
* release), threadsafe-function dispatch of `async-send` type 1 and
|
|
243
|
+
* `_emnapi_next_tick` (both `Promise.resolve().then`), and every deferred
|
|
244
|
+
* call under emnapi 1.x, whose `createContext` ignores `features`.
|
|
245
|
+
*/
|
|
246
|
+
function __wasiSetImmediate(callback) {
|
|
247
|
+
return setImmediate(function () {
|
|
248
|
+
if (!__wasiReentryClosed) {
|
|
249
|
+
callback()
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
}
|
|
225
253
|
|
|
226
254
|
/**
|
|
227
255
|
* Stores the first error a pool worker reported, with the worker's id. Called
|
|
@@ -371,6 +399,8 @@ function __disposeWasiBindingAfterThreadCrash() {
|
|
|
371
399
|
return __wasiThreadCrashDisposePromise
|
|
372
400
|
}
|
|
373
401
|
__releaseEmnapiWaitingRequestHandle()
|
|
402
|
+
// No call into wasm after this: see `__wasiSetImmediate`.
|
|
403
|
+
__wasiReentryClosed = true
|
|
374
404
|
let workerResult
|
|
375
405
|
try {
|
|
376
406
|
workerResult = __terminateWasiWorkers()
|
|
@@ -455,6 +485,130 @@ function __rollbackWasiInitializationAfterThreadCrash() {
|
|
|
455
485
|
return [crashError]
|
|
456
486
|
}
|
|
457
487
|
|
|
488
|
+
const __wasiThreadPoolReconcileSymbol = Symbol.for('napi.rs.wasi.reconcileThreadPool')
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Takes a Worker out of emnapi's reuse pool, if it is still there. emnapi
|
|
492
|
+
* terminates a pooled Worker that failed to load but (up to
|
|
493
|
+
* @emnapi/wasi-threads 2.1.0) leaves it in the pool, where the next thread
|
|
494
|
+
* spawn would pop it. A newer emnapi removes it itself, so this is a no-op
|
|
495
|
+
* then.
|
|
496
|
+
*/
|
|
497
|
+
function __removeWasiPoolWorker(manager, worker) {
|
|
498
|
+
const index = manager.unusedWorkers.indexOf(worker)
|
|
499
|
+
if (index !== -1) {
|
|
500
|
+
manager.unusedWorkers.splice(index, 1)
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Takes a Worker the thread manager just terminated out of `__wasiWorkers`
|
|
506
|
+
* once it has exited, not before. `terminateWorker` only starts Node's
|
|
507
|
+
* asynchronous `worker.terminate()` and drops its promise, so a disposal that
|
|
508
|
+
* begins before the exit has to find this Worker in the set and wait for it
|
|
509
|
+
* like any other. A second `terminate()` settles when the Worker has exited,
|
|
510
|
+
* the way `__terminateWasiWorkers` waits.
|
|
511
|
+
*/
|
|
512
|
+
function __untrackWasiWorkerOnExit(worker) {
|
|
513
|
+
const terminated = worker.terminate()
|
|
514
|
+
if (__isThenable(terminated)) {
|
|
515
|
+
Promise.resolve(terminated).then(
|
|
516
|
+
() => {
|
|
517
|
+
__wasiWorkers.delete(worker)
|
|
518
|
+
},
|
|
519
|
+
// Left tracked: disposal terminates it again and reports the error.
|
|
520
|
+
() => {},
|
|
521
|
+
)
|
|
522
|
+
} else {
|
|
523
|
+
__wasiWorkers.delete(worker)
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Matches emnapi's idle reuse pool to the addon's configured MultiThread worker
|
|
529
|
+
* count, which the addon exports as `napi_wasm_runtime_pool_workers`
|
|
530
|
+
* (napi-async-runtime; 0 under CurrentThread). `reuseWorker: true` starts the
|
|
531
|
+
* pool empty, so without this every pool thread the first async call spawns
|
|
532
|
+
* boots a Worker and loads the wasm into it first. Here each missing Worker is
|
|
533
|
+
* created and starts loading now; a spawn later pops one that is already
|
|
534
|
+
* booting. Idle Workers above the count are terminated, last in first out,
|
|
535
|
+
* the way a spawn takes them. A Worker a spawn already took is not in the pool
|
|
536
|
+
* and is left alone.
|
|
537
|
+
*
|
|
538
|
+
* Runs once after a successful load and, when the loader wraps it, after every
|
|
539
|
+
* successful `configureAsyncRuntime`. Also reachable as
|
|
540
|
+
* binding[Symbol.for('napi.rs.wasi.reconcileThreadPool')]().
|
|
541
|
+
* It never throws and never waits on a Worker: a Worker whose load fails is
|
|
542
|
+
* dropped from the pool when its load rejects. Nothing at all happens after a
|
|
543
|
+
* thread crash, once disposal started, or for an addon without the export.
|
|
544
|
+
*/
|
|
545
|
+
function __reconcileWasiThreadPool() {
|
|
546
|
+
try {
|
|
547
|
+
if (__wasiDisposed || __wasiDisposePromise || __hasWasiThreadCrashed()) {
|
|
548
|
+
return
|
|
549
|
+
}
|
|
550
|
+
const read = __napiInstance?.exports?.napi_wasm_runtime_pool_workers
|
|
551
|
+
if (typeof read !== 'function') {
|
|
552
|
+
return
|
|
553
|
+
}
|
|
554
|
+
const count = read() >>> 0
|
|
555
|
+
const manager = __getWasiThreadManager()
|
|
556
|
+
if (
|
|
557
|
+
!manager ||
|
|
558
|
+
!Array.isArray(manager.unusedWorkers) ||
|
|
559
|
+
typeof manager.allocateUnusedWorker !== 'function' ||
|
|
560
|
+
typeof manager.loadWasmModuleToWorker !== 'function'
|
|
561
|
+
) {
|
|
562
|
+
return
|
|
563
|
+
}
|
|
564
|
+
// Both loops are bounded by the difference they start from, so a manager
|
|
565
|
+
// that does not update `unusedWorkers` the way emnapi does cannot spin.
|
|
566
|
+
for (let excess = manager.unusedWorkers.length - count; excess > 0; excess--) {
|
|
567
|
+
const worker = manager.unusedWorkers[manager.unusedWorkers.length - 1]
|
|
568
|
+
manager.terminateWorker(worker)
|
|
569
|
+
__removeWasiPoolWorker(manager, worker)
|
|
570
|
+
__untrackWasiWorkerOnExit(worker)
|
|
571
|
+
// Compatibility with @emnapi/wasi-threads 2.1.0 and older:
|
|
572
|
+
// `terminateWorker` installs a reporter that logs every emnapi message
|
|
573
|
+
// still queued on the port, so a Worker that finished loading just
|
|
574
|
+
// before it was terminated prints 'received "loaded" command from
|
|
575
|
+
// terminated worker'. Nothing listens for that Worker any more, and a
|
|
576
|
+
// newer emnapi ignores the late 'loaded' itself, so this is harmless
|
|
577
|
+
// there. `__terminateWasiWorkers` does the same.
|
|
578
|
+
worker.onmessage = undefined
|
|
579
|
+
}
|
|
580
|
+
for (let missing = count - manager.unusedWorkers.length; missing > 0; missing--) {
|
|
581
|
+
let worker
|
|
582
|
+
try {
|
|
583
|
+
// Through `onCreateWorker`: tracked in `__wasiWorkers`, unref'd, and
|
|
584
|
+
// handed the crash flags like any pool Worker.
|
|
585
|
+
worker = manager.allocateUnusedWorker()
|
|
586
|
+
manager
|
|
587
|
+
.loadWasmModuleToWorker(worker)
|
|
588
|
+
.then(undefined, () => __removeWasiPoolWorker(manager, worker))
|
|
589
|
+
} catch {
|
|
590
|
+
if (worker !== undefined) {
|
|
591
|
+
__removeWasiPoolWorker(manager, worker)
|
|
592
|
+
try {
|
|
593
|
+
manager.terminateWorker(worker)
|
|
594
|
+
__untrackWasiWorkerOnExit(worker)
|
|
595
|
+
} catch {}
|
|
596
|
+
}
|
|
597
|
+
return
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
} catch {}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function __publishWasiThreadPoolReconcile(exports) {
|
|
604
|
+
Object.defineProperty(exports, __wasiThreadPoolReconcileSymbol, {
|
|
605
|
+
configurable: false,
|
|
606
|
+
enumerable: false,
|
|
607
|
+
value: __reconcileWasiThreadPool,
|
|
608
|
+
writable: false,
|
|
609
|
+
})
|
|
610
|
+
}
|
|
611
|
+
|
|
458
612
|
const __cwd = process.cwd()
|
|
459
613
|
const __rootDir = __nodePath.parse(__cwd).root
|
|
460
614
|
const __hostRoot =
|
|
@@ -2011,7 +2165,7 @@ try {
|
|
|
2011
2165
|
const __finishAutoDestroyCapture = __captureEmnapiAutoDestroyListener()
|
|
2012
2166
|
try {
|
|
2013
2167
|
__emnapiContext = __wrapEmnapiContextDestroyForSettlement(
|
|
2014
|
-
__emnapiCreateContext({ autoDestroy: false }),
|
|
2168
|
+
__emnapiCreateContext({ autoDestroy: false, features: { setImmediate: __wasiSetImmediate } }),
|
|
2015
2169
|
__prepareWasmEnvCleanup,
|
|
2016
2170
|
__isPreparingWasmEnvCleanup,
|
|
2017
2171
|
)
|
|
@@ -2108,6 +2262,7 @@ try {
|
|
|
2108
2262
|
},
|
|
2109
2263
|
}))
|
|
2110
2264
|
__publishWasiDispose(__napiModule.exports)
|
|
2265
|
+
__publishWasiThreadPoolReconcile(__napiModule.exports)
|
|
2111
2266
|
// The CommonJS tail below aliases `__napiModule.exports`; a named module
|
|
2112
2267
|
// export does not travel with it, so carry the marker on the binding itself
|
|
2113
2268
|
// too. Three things pin the stamp to exactly this spot:
|
|
@@ -2136,8 +2291,14 @@ try {
|
|
|
2136
2291
|
__runWasiInitializationRollback(rollback)
|
|
2137
2292
|
throw rollback.error
|
|
2138
2293
|
}
|
|
2294
|
+
// Preload the pool for the count the addon configured during registration.
|
|
2295
|
+
// See `__reconcileWasiThreadPool`.
|
|
2296
|
+
try {
|
|
2297
|
+
__reconcileWasiThreadPool()
|
|
2298
|
+
} catch {}
|
|
2139
2299
|
module.exports = __napiModule.exports
|
|
2140
2300
|
module.exports.Peisar = __napiModule.exports.Peisar
|
|
2301
|
+
module.exports.PeisarCache = __napiModule.exports.PeisarCache
|
|
2141
2302
|
module.exports.EmphasisLevel = __napiModule.exports.EmphasisLevel
|
|
2142
2303
|
module.exports.TableCellAlignment = __napiModule.exports.TableCellAlignment
|
|
2143
2304
|
module.exports.TaskState = __napiModule.exports.TaskState
|
package/peisar.wasi.d.cts
CHANGED
|
@@ -65,6 +65,68 @@ export declare class Peisar {
|
|
|
65
65
|
get astJson(): string
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* In-memory cache of markdown files under a given directory.
|
|
70
|
+
* The cache maps absolute PathBuf -> raw file contents.
|
|
71
|
+
*/
|
|
72
|
+
export declare class PeisarCache {
|
|
73
|
+
/**
|
|
74
|
+
* Construct a new PeisarCache using the default discovery behavior.
|
|
75
|
+
*
|
|
76
|
+
* JS: `new PeisarCache(entryDir, assetsDir?)` — both plain strings.
|
|
77
|
+
*/
|
|
78
|
+
constructor(entryDir: string, assetsDir?: string | undefined | null)
|
|
79
|
+
/**
|
|
80
|
+
* JS: same as the constructor, for callers that prefer a factory shape.
|
|
81
|
+
* Kept non-generic so NAPI can export it.
|
|
82
|
+
*/
|
|
83
|
+
static withConfigJs(entryDir: string, assetsDir?: string | undefined | null): PeisarCache
|
|
84
|
+
/**
|
|
85
|
+
* Start watching the entry_dir recursively. The watcher will update the
|
|
86
|
+
* in-memory cache on create/modify/remove events for markdown files and
|
|
87
|
+
* assets, and persist updates to disk.
|
|
88
|
+
*
|
|
89
|
+
* The returned Result is only for watcher setup errors; runtime errors are
|
|
90
|
+
* printed to stderr by the watch callback.
|
|
91
|
+
*
|
|
92
|
+
* JS: `cache.startWatchingJs()` — errors surface as JS exceptions.
|
|
93
|
+
*/
|
|
94
|
+
startWatchingJs(): void
|
|
95
|
+
/**
|
|
96
|
+
* ----------------------------------------------------------------
|
|
97
|
+
* JavaScript (NAPI) surface
|
|
98
|
+
* ----------------------------------------------------------------
|
|
99
|
+
* All JS methods take/return plain strings because `&Path`/`PathBuf`
|
|
100
|
+
* do not cross the NAPI boundary.
|
|
101
|
+
* JS: `cache.getText(absPath)` — cached text of a file, or null.
|
|
102
|
+
*/
|
|
103
|
+
getText(absPath: string): string | null
|
|
104
|
+
/** JS: `cache.getBinary(absPath)` — cached bytes of a binary asset, or null. */
|
|
105
|
+
getBinary(absPath: string): Array<number> | null
|
|
106
|
+
/** JS: `cache.listFiles()` — absolute paths of everything cached. */
|
|
107
|
+
listFiles(): Array<string>
|
|
108
|
+
/** JS: `cache.markdownFiles()` — absolute paths of cached markdown files. */
|
|
109
|
+
markdownFiles(): Array<string>
|
|
110
|
+
/** JS: `cache.assetFiles()` — absolute paths of cached non-markdown files. */
|
|
111
|
+
assetFiles(): Array<string>
|
|
112
|
+
/**
|
|
113
|
+
* JS: `cache.onChange(cb)` — invoke `cb(event)` on every file change the
|
|
114
|
+
* watcher detects while watching is active. Returns a subscription id
|
|
115
|
+
* that can be passed to `offChange(id)`.
|
|
116
|
+
*
|
|
117
|
+
* The callback is wrapped in a `ThreadsafeFunction` because notify
|
|
118
|
+
* events fire on the watcher thread, not the JS main thread.
|
|
119
|
+
*/
|
|
120
|
+
onChange(callback: (event: CacheChangeEvent) => void): number
|
|
121
|
+
/** JS: `cache.offChange(id)` — remove a previously registered callback. */
|
|
122
|
+
offChange(id: number): void
|
|
123
|
+
/**
|
|
124
|
+
* JS: `cache.dispose()` — stop the watcher and drop JS change callbacks.
|
|
125
|
+
* Safe to call more than once.
|
|
126
|
+
*/
|
|
127
|
+
dispose(): void
|
|
128
|
+
}
|
|
129
|
+
|
|
68
130
|
/**
|
|
69
131
|
* Options that control how Markdown is parsed.
|
|
70
132
|
*
|
|
@@ -185,6 +247,25 @@ export interface BlockParseResultJs {
|
|
|
185
247
|
consumed?: number
|
|
186
248
|
}
|
|
187
249
|
|
|
250
|
+
/** A file-change event delivered to JavaScript `onChange` callbacks. */
|
|
251
|
+
export interface CacheChangeEvent {
|
|
252
|
+
/** Absolute path of the changed file. */
|
|
253
|
+
path: string
|
|
254
|
+
/** `"create"`, `"modify"`, `"remove"`, or `"other"`. */
|
|
255
|
+
kind: string
|
|
256
|
+
/** `true` when the file is under the markdown entry directory. */
|
|
257
|
+
isMarkdown: boolean
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* An entry stored in the cache: raw UTF-8 text (markdown) or raw bytes
|
|
262
|
+
* (binary assets). Exposed to JavaScript so JS consumers can branch on
|
|
263
|
+
* the variant.
|
|
264
|
+
*/
|
|
265
|
+
export type CachedContent =
|
|
266
|
+
| { type: 'Text'; field0: string }
|
|
267
|
+
| { type: 'Binary'; field0: Array<number> }
|
|
268
|
+
|
|
188
269
|
/**
|
|
189
270
|
* A Markdown document — the root of the AST.
|
|
190
271
|
*
|
package/peisar.wasm32-wasi.wasm
CHANGED
|
Binary file
|