@fuzdev/fuz_util 0.48.1 → 0.48.3

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/hash.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Hash utilities for content comparison and cache invalidation.
3
+ *
4
+ * Provides both secure (cryptographic) and insecure (fast) hash functions.
5
+ *
6
+ * @module
7
+ */
8
+ /**
9
+ * Computes a cryptographic hash using Web Crypto API.
10
+ *
11
+ * @param data - String or binary data to hash. Strings are UTF-8 encoded.
12
+ * @param algorithm - Hash algorithm. Defaults to SHA-256.
13
+ * @returns Hexadecimal hash string.
14
+ */
15
+ export declare const hash_secure: (data: BufferSource | string, algorithm?: "SHA-256" | "SHA-384" | "SHA-512") => Promise<string>;
16
+ /**
17
+ * Computes a fast non-cryptographic hash using DJB2 algorithm.
18
+ * Use for content comparison and cache keys, not security.
19
+ *
20
+ * Note: Strings use UTF-16 code units, buffers use raw bytes.
21
+ * For non-ASCII, `hash_insecure(str) !== hash_insecure(encoder.encode(str))`.
22
+ *
23
+ * @param data - String or binary data to hash.
24
+ * @returns 8-character hex-encoded unsigned 32-bit hash.
25
+ */
26
+ export declare const hash_insecure: (data: BufferSource | string) => string;
27
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/hash.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GACvB,MAAM,YAAY,GAAG,MAAM,EAC3B,YAAW,SAAS,GAAG,SAAS,GAAG,SAAqB,KACtD,OAAO,CAAC,MAAM,CAUhB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,YAAY,GAAG,MAAM,KAAG,MAkB3D,CAAC"}
package/dist/hash.js ADDED
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Hash utilities for content comparison and cache invalidation.
3
+ *
4
+ * Provides both secure (cryptographic) and insecure (fast) hash functions.
5
+ *
6
+ * @module
7
+ */
8
+ const encoder = new TextEncoder();
9
+ // Lazily computed lookup table for byte to hex conversion
10
+ let byte_to_hex;
11
+ const get_byte_to_hex = () => {
12
+ if (byte_to_hex === undefined) {
13
+ byte_to_hex = new Array(256); // 256 possible byte values (0x00-0xff)
14
+ for (let i = 0; i < 256; i++) {
15
+ byte_to_hex[i] = i.toString(16).padStart(2, '0');
16
+ }
17
+ }
18
+ return byte_to_hex;
19
+ };
20
+ /**
21
+ * Computes a cryptographic hash using Web Crypto API.
22
+ *
23
+ * @param data - String or binary data to hash. Strings are UTF-8 encoded.
24
+ * @param algorithm - Hash algorithm. Defaults to SHA-256.
25
+ * @returns Hexadecimal hash string.
26
+ */
27
+ export const hash_secure = async (data, algorithm = 'SHA-256') => {
28
+ const buffer = typeof data === 'string' ? encoder.encode(data) : data;
29
+ const digested = await crypto.subtle.digest(algorithm, buffer);
30
+ const bytes = new Uint8Array(digested);
31
+ const lookup = get_byte_to_hex();
32
+ let hex = '';
33
+ for (const byte of bytes) {
34
+ hex += lookup[byte];
35
+ }
36
+ return hex;
37
+ };
38
+ /**
39
+ * Computes a fast non-cryptographic hash using DJB2 algorithm.
40
+ * Use for content comparison and cache keys, not security.
41
+ *
42
+ * Note: Strings use UTF-16 code units, buffers use raw bytes.
43
+ * For non-ASCII, `hash_insecure(str) !== hash_insecure(encoder.encode(str))`.
44
+ *
45
+ * @param data - String or binary data to hash.
46
+ * @returns 8-character hex-encoded unsigned 32-bit hash.
47
+ */
48
+ export const hash_insecure = (data) => {
49
+ let hash = 5381; // DJB2 initial value, chosen empirically for good distribution
50
+ if (typeof data === 'string') {
51
+ for (let i = 0; i < data.length; i++) {
52
+ hash = (hash << 5) - hash + data.charCodeAt(i);
53
+ }
54
+ }
55
+ else {
56
+ const bytes = data instanceof Uint8Array
57
+ ? data
58
+ : data instanceof ArrayBuffer
59
+ ? new Uint8Array(data)
60
+ : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
61
+ for (const byte of bytes) {
62
+ hash = (hash << 5) - hash + byte;
63
+ }
64
+ }
65
+ return (hash >>> 0).toString(16).padStart(8, '0');
66
+ };
package/dist/process.d.ts CHANGED
@@ -84,6 +84,16 @@ export interface DespawnOptions {
84
84
  */
85
85
  timeout_ms?: number;
86
86
  }
87
+ /**
88
+ * Result of spawning a detached process.
89
+ */
90
+ export type SpawnDetachedResult = {
91
+ ok: true;
92
+ child: ChildProcess;
93
+ } | {
94
+ ok: false;
95
+ message: string;
96
+ };
87
97
  /**
88
98
  * Handle for a spawned process with access to the child and completion promise.
89
99
  */
@@ -249,6 +259,33 @@ export declare const despawn_all: (options?: DespawnOptions) => Promise<Array<Sp
249
259
  * @see ProcessRegistry.attach_error_handler
250
260
  */
251
261
  export declare const attach_process_error_handler: (options?: Parameters<ProcessRegistry["attach_error_handler"]>[0]) => (() => void);
262
+ /**
263
+ * Spawns a detached process that continues after parent exits.
264
+ *
265
+ * Unlike other spawn functions, this is NOT tracked in any ProcessRegistry.
266
+ * The spawned process is meant to outlive the parent (e.g., daemon processes).
267
+ *
268
+ * @param command - The command to run
269
+ * @param args - Arguments to pass to the command
270
+ * @param options - Spawn options (use `stdio` to redirect output to file descriptors)
271
+ * @returns Result with pid on success, or error message on failure
272
+ *
273
+ * @example
274
+ * ```ts
275
+ * // Simple detached process
276
+ * const result = spawn_detached('node', ['daemon.js'], {cwd: '/app'});
277
+ *
278
+ * // With log file (caller handles file opening)
279
+ * import {openSync, closeSync} from 'node:fs';
280
+ * const log_fd = openSync('/var/log/daemon.log', 'a');
281
+ * const result = spawn_detached('node', ['daemon.js'], {
282
+ * cwd: '/app',
283
+ * stdio: ['ignore', log_fd, log_fd],
284
+ * });
285
+ * closeSync(log_fd);
286
+ * ```
287
+ */
288
+ export declare const spawn_detached: (command: string, args?: ReadonlyArray<string>, options?: SpawnOptions) => SpawnDetachedResult;
252
289
  /**
253
290
  * Formats a child process for display.
254
291
  *
@@ -1 +1 @@
1
- {"version":3,"file":"process.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/process.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"process.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/process.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,IAAI,wBAAwB,EACjC,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,MAAM,oBAAoB,CAAC;AAa5B;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,IAAI,CAAC;CACb;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IACjC,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,IAAI,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,IAAI,CAAC;IACZ,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AAMrF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAI,QAAQ,WAAW,KAAG,MAAM,IAAI,gBAChD,CAAC;AAEvB;;GAEG;AACH,eAAO,MAAM,wBAAwB,GAAI,QAAQ,WAAW,KAAG,MAAM,IAAI,mBAClD,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,sBAAsB,GAAI,QAAQ,WAAW,KAAG,MAAM,IAAI,iBAClD,CAAC;AAMtB;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACxD;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,mBAAmB,CAAC,EAAE,OAAO,wBAAwB,CAAC;CACtD;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;IACxB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAC,GAAG;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC;AAMjG;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,0CAA0C;IAC1C,KAAK,EAAE,YAAY,CAAC;IACpB,sCAAsC;IACtC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB,qDAAqD;IACrD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,qDAAqD;IACrD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AA2ED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,eAAe;;IAC3B,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,YAAY,CAAC,CAAa;IAIlD;;;;;;;;OAQG;IACH,KAAK,CACJ,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,aAAa,CAAC,MAAM,CAAM,EAChC,OAAO,CAAC,EAAE,mBAAmB,GAC3B,cAAc;IAgCjB;;;;;;;;;;;OAWG;IACG,SAAS,CACd,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,aAAa,CAAC,MAAM,CAAM,EAChC,OAAO,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,UAAU,CAAC;IA2BtB;;;;;;OAMG;IACG,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAsClF;;;;;OAKG;IACG,WAAW,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAIxE;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,oBAAoB,CAAC,OAAO,CAAC,EAAE;QAC9B,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,uBAAuB,KAAK,MAAM,GAAG,IAAI,CAAC;QACvF,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,uBAAuB,KAAK,MAAM,GAAG,IAAI,CAAC;QACvF,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,uBAAuB,KAAK,IAAI,CAAC;QAC5E,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACpC,GAAG,MAAM,IAAI;CAmDd;AAMD;;;GAGG;AACH,eAAO,MAAM,wBAAwB,iBAAwB,CAAC;AAM9D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GACzB,SAAS,MAAM,EACf,OAAM,aAAa,CAAC,MAAM,CAAM,EAChC,UAAU,mBAAmB,KAC3B,cAAwE,CAAC;AAE5E;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,GACjB,SAAS,MAAM,EACf,OAAM,aAAa,CAAC,MAAM,CAAM,EAChC,UAAU,mBAAmB,KAC3B,OAAO,CAAC,WAAW,CAAiD,CAAC;AAExE;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,GACrB,SAAS,MAAM,EACf,OAAM,aAAa,CAAC,MAAM,CAAM,EAChC,UAAU,mBAAmB,KAC3B,OAAO,CAAC,UAAU,CAA+D,CAAC;AAErF;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,OAAO,YAAY,EAAE,UAAU,cAAc,KAAG,OAAO,CAAC,WAAW,CAC1C,CAAC;AAElD;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,UAAU,cAAc,KAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CACnC,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAU,UAAU,CAAC,eAAe,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,KAC9D,CAAC,MAAM,IAAI,CAA2D,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,cAAc,GAC1B,SAAS,MAAM,EACf,OAAM,aAAa,CAAC,MAAM,CAAM,EAChC,UAAU,YAAY,KACpB,mBAmBF,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,YAAY,KAAG,MACkD,CAAC;AAE7G;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,WAAW,KAAG,MAKxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,WAAW,KAAG,MAI7D,CAAC;AAMF;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;;OAIG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,iDAAiD;IACjD,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,yBAAyB,GACrC,SAAS,MAAM,EACf,OAAM,aAAa,CAAC,MAAM,CAAM,EAChC,UAAU,mBAAmB,KAC3B,kBAqFF,CAAC;AAMF;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,GAAI,KAAK,MAAM,KAAG,OAcpD,CAAC"}
package/dist/process.js CHANGED
@@ -351,6 +351,50 @@ export const despawn_all = (options) => process_registry_default.despawn_all(opt
351
351
  * @see ProcessRegistry.attach_error_handler
352
352
  */
353
353
  export const attach_process_error_handler = (options) => process_registry_default.attach_error_handler(options);
354
+ /**
355
+ * Spawns a detached process that continues after parent exits.
356
+ *
357
+ * Unlike other spawn functions, this is NOT tracked in any ProcessRegistry.
358
+ * The spawned process is meant to outlive the parent (e.g., daemon processes).
359
+ *
360
+ * @param command - The command to run
361
+ * @param args - Arguments to pass to the command
362
+ * @param options - Spawn options (use `stdio` to redirect output to file descriptors)
363
+ * @returns Result with pid on success, or error message on failure
364
+ *
365
+ * @example
366
+ * ```ts
367
+ * // Simple detached process
368
+ * const result = spawn_detached('node', ['daemon.js'], {cwd: '/app'});
369
+ *
370
+ * // With log file (caller handles file opening)
371
+ * import {openSync, closeSync} from 'node:fs';
372
+ * const log_fd = openSync('/var/log/daemon.log', 'a');
373
+ * const result = spawn_detached('node', ['daemon.js'], {
374
+ * cwd: '/app',
375
+ * stdio: ['ignore', log_fd, log_fd],
376
+ * });
377
+ * closeSync(log_fd);
378
+ * ```
379
+ */
380
+ export const spawn_detached = (command, args = [], options) => {
381
+ try {
382
+ const child = node_spawn_child_process(command, args, {
383
+ stdio: 'ignore',
384
+ ...options,
385
+ detached: true,
386
+ });
387
+ // Allow parent to exit independently
388
+ child.unref();
389
+ if (child.pid === undefined) {
390
+ return { ok: false, message: 'Failed to get child PID' };
391
+ }
392
+ return { ok: true, child };
393
+ }
394
+ catch (error) {
395
+ return { ok: false, message: error instanceof Error ? error.message : String(error) };
396
+ }
397
+ };
354
398
  //
355
399
  // Formatting Utilities
356
400
  //
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_util",
3
- "version": "0.48.1",
3
+ "version": "0.48.3",
4
4
  "description": "utility belt for JS",
5
5
  "glyph": "🦕",
6
6
  "logo": "logo.svg",
@@ -61,11 +61,11 @@
61
61
  },
62
62
  "devDependencies": {
63
63
  "@changesets/changelog-git": "^0.2.1",
64
- "@fuzdev/fuz_code": "^0.40.0",
65
- "@fuzdev/fuz_css": "^0.44.1",
66
- "@fuzdev/fuz_ui": "^0.179.0",
64
+ "@fuzdev/fuz_code": "^0.41.0",
65
+ "@fuzdev/fuz_css": "^0.45.0",
66
+ "@fuzdev/fuz_ui": "^0.180.0",
67
67
  "@ryanatkn/eslint-config": "^0.9.0",
68
- "@ryanatkn/gro": "^0.189.0",
68
+ "@ryanatkn/gro": "^0.189.3",
69
69
  "@sveltejs/adapter-static": "^3.0.10",
70
70
  "@sveltejs/kit": "^2.50.1",
71
71
  "@sveltejs/package": "^2.5.7",
@@ -79,8 +79,8 @@
79
79
  "fast-deep-equal": "^3.1.3",
80
80
  "prettier": "^3.7.4",
81
81
  "prettier-plugin-svelte": "^3.4.1",
82
- "svelte": "^5.48.2",
83
- "svelte-check": "^4.3.4",
82
+ "svelte": "^5.48.5",
83
+ "svelte-check": "^4.3.5",
84
84
  "tslib": "^2.8.1",
85
85
  "typescript": "^5.9.3",
86
86
  "typescript-eslint": "^8.48.1",
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Hash utilities for content comparison and cache invalidation.
3
+ *
4
+ * Provides both secure (cryptographic) and insecure (fast) hash functions.
5
+ *
6
+ * @module
7
+ */
8
+
9
+ const encoder = new TextEncoder();
10
+
11
+ // Lazily computed lookup table for byte to hex conversion
12
+ let byte_to_hex: Array<string> | undefined;
13
+ const get_byte_to_hex = (): Array<string> => {
14
+ if (byte_to_hex === undefined) {
15
+ byte_to_hex = new Array(256); // 256 possible byte values (0x00-0xff)
16
+ for (let i = 0; i < 256; i++) {
17
+ byte_to_hex[i] = i.toString(16).padStart(2, '0');
18
+ }
19
+ }
20
+ return byte_to_hex;
21
+ };
22
+
23
+ /**
24
+ * Computes a cryptographic hash using Web Crypto API.
25
+ *
26
+ * @param data - String or binary data to hash. Strings are UTF-8 encoded.
27
+ * @param algorithm - Hash algorithm. Defaults to SHA-256.
28
+ * @returns Hexadecimal hash string.
29
+ */
30
+ export const hash_secure = async (
31
+ data: BufferSource | string,
32
+ algorithm: 'SHA-256' | 'SHA-384' | 'SHA-512' = 'SHA-256',
33
+ ): Promise<string> => {
34
+ const buffer = typeof data === 'string' ? encoder.encode(data) : data;
35
+ const digested = await crypto.subtle.digest(algorithm, buffer);
36
+ const bytes = new Uint8Array(digested);
37
+ const lookup = get_byte_to_hex();
38
+ let hex = '';
39
+ for (const byte of bytes) {
40
+ hex += lookup[byte];
41
+ }
42
+ return hex;
43
+ };
44
+
45
+ /**
46
+ * Computes a fast non-cryptographic hash using DJB2 algorithm.
47
+ * Use for content comparison and cache keys, not security.
48
+ *
49
+ * Note: Strings use UTF-16 code units, buffers use raw bytes.
50
+ * For non-ASCII, `hash_insecure(str) !== hash_insecure(encoder.encode(str))`.
51
+ *
52
+ * @param data - String or binary data to hash.
53
+ * @returns 8-character hex-encoded unsigned 32-bit hash.
54
+ */
55
+ export const hash_insecure = (data: BufferSource | string): string => {
56
+ let hash = 5381; // DJB2 initial value, chosen empirically for good distribution
57
+ if (typeof data === 'string') {
58
+ for (let i = 0; i < data.length; i++) {
59
+ hash = (hash << 5) - hash + data.charCodeAt(i);
60
+ }
61
+ } else {
62
+ const bytes: Uint8Array =
63
+ data instanceof Uint8Array
64
+ ? data
65
+ : data instanceof ArrayBuffer
66
+ ? new Uint8Array(data)
67
+ : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
68
+ for (const byte of bytes) {
69
+ hash = (hash << 5) - hash + byte;
70
+ }
71
+ }
72
+ return (hash >>> 0).toString(16).padStart(8, '0');
73
+ };
@@ -120,6 +120,11 @@ export interface DespawnOptions {
120
120
  timeout_ms?: number;
121
121
  }
122
122
 
123
+ /**
124
+ * Result of spawning a detached process.
125
+ */
126
+ export type SpawnDetachedResult = {ok: true; child: ChildProcess} | {ok: false; message: string};
127
+
123
128
  //
124
129
  // Process Handle Types
125
130
  //
@@ -553,6 +558,57 @@ export const attach_process_error_handler = (
553
558
  options?: Parameters<ProcessRegistry['attach_error_handler']>[0],
554
559
  ): (() => void) => process_registry_default.attach_error_handler(options);
555
560
 
561
+ /**
562
+ * Spawns a detached process that continues after parent exits.
563
+ *
564
+ * Unlike other spawn functions, this is NOT tracked in any ProcessRegistry.
565
+ * The spawned process is meant to outlive the parent (e.g., daemon processes).
566
+ *
567
+ * @param command - The command to run
568
+ * @param args - Arguments to pass to the command
569
+ * @param options - Spawn options (use `stdio` to redirect output to file descriptors)
570
+ * @returns Result with pid on success, or error message on failure
571
+ *
572
+ * @example
573
+ * ```ts
574
+ * // Simple detached process
575
+ * const result = spawn_detached('node', ['daemon.js'], {cwd: '/app'});
576
+ *
577
+ * // With log file (caller handles file opening)
578
+ * import {openSync, closeSync} from 'node:fs';
579
+ * const log_fd = openSync('/var/log/daemon.log', 'a');
580
+ * const result = spawn_detached('node', ['daemon.js'], {
581
+ * cwd: '/app',
582
+ * stdio: ['ignore', log_fd, log_fd],
583
+ * });
584
+ * closeSync(log_fd);
585
+ * ```
586
+ */
587
+ export const spawn_detached = (
588
+ command: string,
589
+ args: ReadonlyArray<string> = [],
590
+ options?: SpawnOptions,
591
+ ): SpawnDetachedResult => {
592
+ try {
593
+ const child = node_spawn_child_process(command, args, {
594
+ stdio: 'ignore',
595
+ ...options,
596
+ detached: true,
597
+ });
598
+
599
+ // Allow parent to exit independently
600
+ child.unref();
601
+
602
+ if (child.pid === undefined) {
603
+ return {ok: false, message: 'Failed to get child PID'};
604
+ }
605
+
606
+ return {ok: true, child};
607
+ } catch (error) {
608
+ return {ok: false, message: error instanceof Error ? error.message : String(error)};
609
+ }
610
+ };
611
+
556
612
  //
557
613
  // Formatting Utilities
558
614
  //