@gjsify/utils 0.36.0 → 0.37.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.
@@ -1,29 +1,21 @@
1
1
  /**
2
- * Wrap an ES6 class so it supports both the modern `new Cls(...)` pattern and
3
- * the legacy `Cls.call(thisArg, ...)` / `Cls(...)` (no-`new`) patterns.
2
+ * Wrap an ES6 class so it supports `new Cls(...)`, `Cls.call(thisArg, ...)` and
3
+ * `Cls(...)` (no-`new`) alike.
4
4
  *
5
5
  * The `apply` trap has two modes:
6
6
  *
7
- * 1. **`Cls.call(thisArg, ...)`** — a real consumer instance is provided.
8
- * We materialise a temporary instance via `Reflect.construct` (so field
9
- * initializers and constructor bodies run normally) and transplant its
10
- * own property descriptors onto `thisArg`. This is how Node-era CJS
11
- * consumers + `util.inherits(Sub, Cls)` chains expect to subclass our
12
- * ES6 classes.
7
+ * 1. **`Cls.call(thisArg, ...)`** — materialise a temporary instance via
8
+ * `Reflect.construct` (so field initializers and constructor bodies run) and
9
+ * transplant its own property descriptors onto `thisArg`.
13
10
  *
14
- * 2. **`Cls(...)`** (called as a plain function — `thisArg` is `undefined`
15
- * in strict mode or `globalThis` in sloppy mode) — we treat the call as
16
- * a constructor call and return a fresh `new Cls(...)`. Node's stream
17
- * constructors implement this guard explicitly:
18
- * `if (!(this instanceof PassThrough)) return new PassThrough(...)`
19
- * so consumers like `merge2` invoke `Stream.PassThrough(opts)` without
20
- * `new` and rely on the result being a real instance. Without this
21
- * branch the apply trap would crash with "undefined is not a non-null
22
- * object" when it tried to `Object.defineProperty(thisArg, …)`.
11
+ * 2. **`Cls(...)`** — `thisArg` is `undefined` (strict) or `globalThis`
12
+ * (sloppy); construct instead. Node's stream constructors guard this
13
+ * explicitly (`if (!(this instanceof PassThrough)) return new PassThrough(…)`)
14
+ * and consumers like `merge2` rely on it. Without this branch the trap
15
+ * crashes on `Object.defineProperty(thisArg, …)`.
23
16
  *
24
- * The default Proxy traps pass `construct`, `get` and `getPrototypeOf`
25
- * straight through, so `new Wrapped()`, `Wrapped.prototype` (consulted by
26
- * `util.inherits`) and `instance instanceof Wrapped` all behave identically
27
- * to the underlying class.
17
+ * `construct`, `get` and `getPrototypeOf` pass straight through, so
18
+ * `Wrapped.prototype` (consulted by `util.inherits`) and `instanceof` behave
19
+ * exactly as on the underlying class.
28
20
  */
29
21
  export declare function makeCallable<T extends new (...args: unknown[]) => unknown>(Cls: T): T;
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Defines the static Error.captureStackTrace method,
3
- * this is not present in SpiderMonkey because it comes from V8
2
+ * Installs the V8-only static `Error.captureStackTrace` on engines that lack it.
4
3
  * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#static_methods
5
4
  * @see https://nodejs.org/dist/latest-v18.x/docs/api/errors.html#errorcapturestacktracetargetobject-constructoropt
6
5
  */
package/lib/types/fs.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- /** Check if a file descriptor exists */
1
+ /** Is `fd` open? Probed by wrapping it, as GLib has no file-descriptor test. */
2
2
  export declare const existsFD: (fd: number) => boolean;
3
3
  export declare function existsSync(path: string): boolean;
@@ -1,4 +1,13 @@
1
- /** Map from Gio.IOErrorEnum numeric values to Node.js error code strings. */
1
+ /**
2
+ * Gio.IOErrorEnum numeric value → Node error code.
3
+ *
4
+ * The trailing name on each row is the member that number ACTUALLY has, checked
5
+ * against `Gio.IOErrorEnum` on gjs 1.88.1; GLib's numbering is append-only, so it
6
+ * does not drift with the GIR version. Several rows pair a member with an errno that
7
+ * does not follow from it (12 is NO_SPACE yet maps to ELOOP, 24 is TIMED_OUT yet maps
8
+ * to EROFS, 31 is TOO_MANY_OPEN_FILES yet maps to ENETUNREACH): those are wrong
9
+ * mappings to repair, not aliases — do not "correct" the name back.
10
+ */
2
11
  export declare const GIO_ERROR_TO_NODE: Record<number, string>;
3
12
  export interface NodeErrorDetails {
4
13
  path?: string;
@@ -8,16 +8,9 @@ import Gio from '@girs/gio-2.0';
8
8
  export declare function gioAsync<T>(obj: any, asyncMethod: string, finishMethod: string, ...args: any[]): Promise<T>;
9
9
  /**
10
10
  * Promise wrapper around `Gio.InputStream.read_bytes_async` / `read_bytes_finish`.
11
- * Returns a `Uint8Array` or `null` if the end of the stream is reached.
12
- *
13
- * Treats `G_IO_ERROR_PARTIAL_INPUT` as EOF: Soup3's chunked-decoding input
14
- * stream surfaces this when the upstream closes the connection cleanly at a
15
- * non-chunk boundary (common on the npm registry CDN). Without this, the
16
- * fetch `Body.text()` path raises "Invalid response body" mid-read even
17
- * though the full payload has already arrived. Bubble all other errors.
11
+ * `null` means end of stream; a clean-stream-end error counts as EOF (see the catch),
12
+ * everything else is bubbled.
18
13
  */
19
14
  export declare function readBytesAsync(inputStream: Gio.InputStream, count?: number, ioPriority?: number, cancellable?: Gio.Cancellable | null): Promise<Uint8Array | null>;
20
- /**
21
- * Async generator that yields `Uint8Array` chunks from a `Gio.InputStream`.
22
- */
15
+ /** Yields `Uint8Array` chunks from a `Gio.InputStream` until EOF. */
23
16
  export declare function inputStreamAsyncIterator(inputStream: Gio.InputStream, count?: number, ioPriority?: number, cancellable?: Gio.Cancellable | null): AsyncGenerator<Uint8Array>;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Register a value as a global property if it doesn't already exist.
3
- * This is a no-op in environments where the global is already defined (e.g. Node.js).
2
+ * Register `value` as a global only where that name is still free, so a web polyfill
3
+ * never displaces a host implementation that is already there.
4
4
  */
5
5
  export declare function registerGlobal(name: string, value: unknown): void;
@@ -2,26 +2,22 @@ import type { ProcessPlatform } from './platform-names.js';
2
2
  /**
3
3
  * The three operating systems ADR 0018 declares as the project's target set.
4
4
  *
5
- * Deliberately NARROWER than {@link ProcessPlatform}, which is Node's full
6
- * vocabulary. `gjsify.os` keys are exactly these three: a package may not
7
- * declare support for an OS the project does not claim, and `os-axis` fails on
8
- * a key outside this set. The emulated `linux-{ppc64,s390x,riscv64}` targets
9
- * are build-verified only and are an ARCH question, not an OS one — they live
10
- * on the `gjsify.platforms` axis, which stays separate by design.
5
+ * Deliberately narrower than {@link ProcessPlatform} (Node's full vocabulary):
6
+ * `gjsify.os` keys are exactly these three and `os-axis` fails on any other key.
7
+ * The emulated `linux-{ppc64,s390x,riscv64}` targets are an ARCH question and
8
+ * live on the separate `gjsify.platforms` axis.
11
9
  */
12
10
  export type TargetOs = 'linux' | 'darwin' | 'win32';
13
- /** The target set as data, so a check iterates it instead of restating it. */
11
+ /** The target set as data, for checks that iterate it. */
14
12
  export declare const TARGET_OSES: readonly TargetOs[];
15
13
  /** Is `value` one of the three declared target operating systems? */
16
14
  export declare function isTargetOs(value: unknown): value is TargetOs;
17
15
  /**
18
16
  * The host's `process.platform`, or `undefined` where nothing answers.
19
17
  *
20
- * `undefined` is the honest result on a runtime with no process object (the
21
- * browser), and callers must treat it as "unknown", never as "not Windows" —
22
- * which is why this returns an optional rather than defaulting to `'linux'`.
23
- * The defaulting belongs to `@gjsify/process`'s `detectPlatform()`, which has a
24
- * uname probe to fall back ON; this module has none and must not pretend.
18
+ * Callers must treat `undefined` as "unknown", never as "not Windows". Nothing is
19
+ * defaulted here because this module has no uname probe to fall back on; that
20
+ * defaulting belongs to `@gjsify/process`'s `detectPlatform()`.
25
21
  */
26
22
  export declare function hostPlatform(): ProcessPlatform | undefined;
27
23
  /**
@@ -32,9 +28,9 @@ export declare function hostOs(): TargetOs | undefined;
32
28
  /**
33
29
  * Running on Windows?
34
30
  *
35
- * The predicate `it.failing(name, fn, reason, { when: isWin32() })` takes — the
36
- * sanctioned way to carry a POSIX-only assertion through a win32 run without
37
- * weakening it, and without an `if (platform)` guard that would hide it forever.
31
+ * The predicate for `it.failing(name, fn, reason, { when: isWin32() })` — the
32
+ * sanctioned way to park a POSIX-only assertion on a win32 run, instead of an
33
+ * `if (platform)` guard that would hide it forever.
38
34
  */
39
35
  export declare function isWin32(): boolean;
40
36
  /** Running on macOS? */
@@ -1,7 +1,9 @@
1
1
  /** Does this host have a readable procfs for the current process? */
2
2
  export declare function hasProcfs(): boolean;
3
3
  /**
4
- * This process's own pid, or `undefined` where nothing can answer.
4
+ * This process's own pid, or `undefined` where nothing can answer. Never `0` —
5
+ * that is a real pid, and returning it as "unknown" hands the caller a number
6
+ * that looks answered.
5
7
  *
6
8
  * Two readers, capability-selected:
7
9
  *
@@ -9,12 +11,8 @@ export declare function hasProcfs(): boolean;
9
11
  * subprocess.
10
12
  * 2. `sh -c 'echo $PPID'` — the shell's PARENT is us, because
11
13
  * `g_spawn_command_line_sync()` forks this process and execs the shell in
12
- * the child. This is the same trick `@gjsify/v8`'s darwin heap reader has
13
- * used since it was written, and it is portable to every POSIX host that
14
- * has no procfs.
15
- *
16
- * Never `0`. `0` is a real pid, so returning it as "unknown" would hand every
17
- * caller a number that looks answered.
14
+ * the child (same trick as `@gjsify/v8`'s darwin heap reader; portable to
15
+ * every POSIX host without procfs).
18
16
  */
19
17
  export declare function hostPid(): number | undefined;
20
18
  /**
@@ -30,20 +28,17 @@ export declare function hostPpid(): number | undefined;
30
28
  * The absolute path of the INTERPRETER running this process — what Node calls
31
29
  * `process.execPath` — or `undefined` where nothing can answer.
32
30
  *
33
- * NOT `imports.system.programInvocationName`. That is the SCRIPT, and reporting
34
- * it as `execPath` is a defect with teeth: `spawn(process.execPath, […])` is the
35
- * documented portable way to start a second copy of the current runtime, and
36
- * against a script path it fails `ENOENT` — or worse, `g_spawn` retries a
37
- * non-executable text file through `/bin/sh` and the shell begins interpreting
38
- * a bundle.
31
+ * NOT `imports.system.programInvocationName`: that is the SCRIPT, and reporting it
32
+ * as `execPath` breaks `spawn(process.execPath, […])` — the portable way to start
33
+ * a second copy of the runtime — with `ENOENT`, or worse, `g_spawn` retries the
34
+ * non-executable text file through `/bin/sh` and the shell interprets a bundle.
39
35
  *
40
36
  * 1. `/proc/self/exe` — a symlink to the running binary, exact by
41
37
  * construction.
42
- * 2. `g_find_program_in_path(g_get_prgname())` — the PATH lookup for the name
43
- * this process was invoked under (`gjs`). Honest but not exact: a host with
44
- * two gjs installations can resolve the other one. That is why it is the
45
- * fallback and not the primary, and why nothing here defaults to a
46
- * hardcoded `/usr/bin/gjs` — a path that does not exist on macOS at all.
38
+ * 2. `g_find_program_in_path(g_get_prgname())` — honest but not exact, since a
39
+ * host with two gjs installations can resolve the other one; hence the
40
+ * fallback position. Nothing defaults to a hardcoded `/usr/bin/gjs`, a path
41
+ * that does not exist on macOS at all.
47
42
  */
48
43
  export declare function hostExecPath(): string | undefined;
49
44
  /** The OS's view of a process's memory, in bytes. */
@@ -60,11 +55,9 @@ export interface ProcessMemory {
60
55
  /**
61
56
  * This process's memory figures, or `null` when no reader applies.
62
57
  *
63
- * DEGRADED CONTRACT off procfs: `ps(1)` reports only `rss` and `vsz`, so `data`
64
- * and `peak` stay `0` there. That is the same shape the Linux reader already
65
- * produced for a procfs it could not parse, so no consumer meets a new one —
66
- * but it is a real difference and `@gjsify/v8` documents it in
67
- * `getHeapStatistics()`'s own contract.
58
+ * Degraded off procfs: `ps(1)` reports only `rss` and `vsz`, so `data` and `peak`
59
+ * stay `0` — the same shape the Linux reader already produced for a procfs it
60
+ * could not parse.
68
61
  *
69
62
  * Both `ps` columns are in KiB on Linux and on macOS (POSIX mandates KiB for
70
63
  * `rss`; BSD `vsz` follows), so one multiply serves both.
@@ -1,4 +1,21 @@
1
1
  import type GLib from '@girs/glib-2.0';
2
+ /**
3
+ * Ensure a GLib MainLoop is running for async I/O dispatch (Soup.Server,
4
+ * Gio.SocketService, …). No-op on Node.js. Idempotent.
5
+ *
6
+ * Called automatically by `http.Server.listen()`, `net.Server.listen()`,
7
+ * `dgram.Socket.bind()`. GTK apps must NOT call it — they use
8
+ * `Gtk.Application.runAsync()` instead.
9
+ *
10
+ * Teardown hazard: with a main-loop hook set, GJS's `eval_module` drives the
11
+ * hook's *blocking* `loop.run()`, so terminating from an async continuation with
12
+ * a bare `imports.system.exit()` DEADLOCKS — it only sets GJS's internal exit
13
+ * flag, never calls `loop.quit()`, so the parked `loop.run()` never returns.
14
+ * Microtask draining is unaffected; only the exit hangs
15
+ * (`docs/poc/tla-microtask-draining.md`). Exit through `process.exit()` (which
16
+ * idle-schedules `quitMainLoop()` + `system.exit()`) or call {@link quitMainLoop}
17
+ * yourself first.
18
+ */
2
19
  export declare function ensureMainLoop(): GLib.MainLoop | undefined;
3
20
  /**
4
21
  * Quit the MainLoop created by `ensureMainLoop()`. Idempotent, no-op on Node.js.
@@ -1,8 +1,7 @@
1
1
  /** @internal Test helper: reset burst state. */
2
2
  export declare function __resetBurstStateForTests(): void;
3
3
  /**
4
- * Schedule a function on the next turn of the event loop.
5
- * On GJS: uses GLib.timeout_add(PRIORITY_DEFAULT, delay=0).
6
- * On Node.js: uses process.nextTick → queueMicrotask → Promise.resolve().then().
4
+ * Schedule a function on the next turn of the event loop: the burst-yield drainer on
5
+ * GJS, otherwise `process.nextTick` → `queueMicrotask` → `Promise.resolve().then()`.
7
6
  */
8
7
  export declare const nextTick: (fn: (...args: unknown[]) => void, ...args: unknown[]) => void;
@@ -1,22 +1,15 @@
1
1
  /**
2
2
  * structuredClone polyfill implementing the HTML structured clone algorithm.
3
3
  *
4
- * Supports: primitives (incl. -0, NaN, Infinity, BigInt), wrapper objects,
5
- * Date, RegExp, Error types, ArrayBuffer (with transfer), TypedArrays,
6
- * DataView, Map, Set, Blob, File, circular/shared references, plain objects
7
- * and arrays.
4
+ * Throws DataCloneError for functions, symbols, WeakMap, WeakSet, WeakRef and
5
+ * Promise; everything else the spec covers is cloned, circular and shared
6
+ * references included.
8
7
  *
9
- * Throws DataCloneError for: functions, symbols, WeakMap, WeakSet, WeakRef, Promise.
10
- *
11
- * Transfer semantics: any `ArrayBuffer` listed in `options.transfer` is
12
- * transferred to the clone via SM140's `ArrayBuffer.prototype.transfer()`
13
- * (zero-copy, sender becomes detached). Non-`ArrayBuffer` entries are
14
- * accepted but ignored — the caller (e.g. `MessagePort.postMessage`) is
15
- * responsible for handling transferable objects that aren't structured-clone
16
- * primitives (`MessagePort`, `ReadableStream`, …).
17
- *
18
- * @param value The value to clone
19
- * @param options Optional transfer list
8
+ * An `ArrayBuffer` in `options.transfer` is moved zero-copy via
9
+ * `ArrayBuffer.prototype.transfer()` and the sender's buffer becomes detached.
10
+ * Non-`ArrayBuffer` entries are accepted but IGNORED: transferables that are not
11
+ * structured-clone primitives (`MessagePort`, `ReadableStream`, …) are the caller's
12
+ * responsibility, e.g. `MessagePort.postMessage`.
20
13
  */
21
14
  export declare function structuredClone<T>(value: T, options?: {
22
15
  transfer?: unknown[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/utils",
3
- "version": "0.36.0",
3
+ "version": "0.37.0",
4
4
  "description": "Utils module for gjsify",
5
5
  "module": "lib/esm/index.js",
6
6
  "types": "lib/types/index.d.ts",
@@ -40,7 +40,7 @@
40
40
  "fs"
41
41
  ],
42
42
  "devDependencies": {
43
- "@gjsify/cli": "^0.36.0",
43
+ "@gjsify/cli": "^0.37.0",
44
44
  "typescript": "^6.0.3"
45
45
  },
46
46
  "dependencies": {