@gjsify/terminal-native 0.53.0 → 0.54.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/lib/esm/index.js CHANGED
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{loadOptionalNativeModule as e}from"@gjsify/utils/core";const t=e(`GjsifyTerminal`,[`Terminal`,`ResizeWatcher`]),n=t.module,r=n;function hasNativeTerminal(){return n!==null}function getNativeTerminalLoadError(){return t.error}export{getNativeTerminalLoadError,hasNativeTerminal,r as nativeTerminal};
1
+ import"./_virtual/_rolldown/runtime.js";import{claimRawMode as e,isRawModeClaimed as t,noteRawMode as n,releaseRawMode as r,restoreClaimedRawModes as i}from"./raw-mode.js";import{loadOptionalNativeModule as a}from"@gjsify/utils/core";const o=a(`GjsifyTerminal`,[`Terminal`,`ResizeWatcher`]),s=o.module,c=s;function hasNativeTerminal(){return s!==null}function getNativeTerminalLoadError(){return o.error}function callableModule(){if(!s)return null;try{return s.Terminal.is_tty(2),s}catch{return null}}function nativeIsTty(e){try{return callableModule()?.Terminal.is_tty(e)??null}catch{return null}}function nativeTerminalSize(e){try{let[t,n,r]=callableModule()?.Terminal.get_size(e)??[!1,0,0];return!t||r<=0?null:{rows:n,columns:r}}catch{return null}}function nativeSetRawMode(e,t){try{return callableModule()?.Terminal.set_raw_mode(e,t)??null}catch{return null}}export{e as claimRawMode,getNativeTerminalLoadError,hasNativeTerminal,t as isRawModeClaimed,nativeIsTty,nativeSetRawMode,c as nativeTerminal,nativeTerminalSize,n as noteRawMode,r as releaseRawMode,i as restoreClaimedRawModes};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";const e=Symbol.for(`@gjsify/terminal-native:raw-mode-claims`),t=globalThis,n=t[e]??=new Map;function claimRawMode(e,t){n.set(e,t)}function releaseRawMode(e){n.delete(e)}function isRawModeClaimed(e){return n.has(e)}function noteRawMode(e,t,n){let r=n(t);return t?r&&claimRawMode(e,()=>{n(!1)}):releaseRawMode(e),r}function restoreClaimedRawModes(){let e=[...n.entries()];n.clear();let t=0,r;for(let[,n]of e)try{n(),t+=1}catch(e){r??=e}if(r!==void 0)throw r;return t}export{claimRawMode,isRawModeClaimed,noteRawMode,releaseRawMode,restoreClaimedRawModes};
@@ -1,3 +1,4 @@
1
+ export * from './raw-mode.js';
1
2
  export interface NativeTerminal {
2
3
  /** Check whether fd is an interactive terminal (Posix.isatty). */
3
4
  is_tty(fd: number): boolean;
@@ -22,7 +23,16 @@ export interface GjsifyTerminalModule {
22
23
  Terminal: NativeTerminal;
23
24
  ResizeWatcher: NativeResizeWatcherClass;
24
25
  }
25
- /** The native GjsifyTerminal module, or null if not installed. */
26
+ /**
27
+ * The native GjsifyTerminal module, or null if not installed.
28
+ *
29
+ * READING this namespace proves less than it looks: girepository opens the
30
+ * shared library at the first member CALL, not at the load, so a namespace
31
+ * that resolved can still raise on every call (see {@link callableModule}).
32
+ * Prefer the `native*` accessors below — they carry that one step and return
33
+ * `null` instead of throwing, which is what an optional prebuild owes a caller
34
+ * that already has a fallback.
35
+ */
26
36
  export declare const nativeTerminal: GjsifyTerminalModule | null;
27
37
  /** Returns true when the GjsifyTerminal native library is available. */
28
38
  export declare function hasNativeTerminal(): boolean;
@@ -32,3 +42,27 @@ export declare function hasNativeTerminal(): boolean;
32
42
  * dependency when it is installed but its library will not open.
33
43
  */
34
44
  export declare function getNativeTerminalLoadError(): Error | null;
45
+ /**
46
+ * `Terminal.is_tty(fd)`, or `null` when the native module is absent or its
47
+ * calls throw. `null` is distinct from `false`: a caller that owns a fallback
48
+ * (`process.stdout.isTTY` → GLib's `log_writer_supports_color`) must take it
49
+ * on `null` and answer `false` itself on a real answer.
50
+ */
51
+ export declare function nativeIsTty(fd: number): boolean | null;
52
+ /**
53
+ * `Terminal.get_size(fd)` as `[rows, columns]`, or `null` when the native
54
+ * module is absent, its calls throw, or the ioctl reports no size. The last
55
+ * collapse is deliberate: every consumer asks the same question — "how wide is
56
+ * this fd, if I can really tell?" — and answered `ok && cols > 0` itself.
57
+ * Returns columns second, matching the bridge's own tuple order.
58
+ */
59
+ export declare function nativeTerminalSize(fd: number): {
60
+ rows: number;
61
+ columns: number;
62
+ } | null;
63
+ /**
64
+ * `Terminal.set_raw_mode(fd, enable)`, or `null` when the native module is
65
+ * absent or its calls throw. The caller keeps its own `isRaw` bookkeeping, so
66
+ * the return value is only ever read as "did the native call happen".
67
+ */
68
+ export declare function nativeSetRawMode(fd: number, enable: boolean): boolean | null;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Record that this process put `fd` into raw mode, and how to undo it.
3
+ *
4
+ * Called by whoever performs the transition, on EVERY path — a path that forgets
5
+ * to claim is a terminal nobody will restore, which is the bug this exists for.
6
+ */
7
+ export declare function claimRawMode(fd: number, restore: () => void): void;
8
+ /**
9
+ * Record that the owner turned `fd` back itself, in the normal close() path.
10
+ *
11
+ * A paid debt: nothing is owed at exit, so the exit hook must not run a restore
12
+ * that could fight whoever claimed the descriptor afterwards.
13
+ */
14
+ export declare function releaseRawMode(fd: number): void;
15
+ /** Whether this process still owes `fd` a restore. */
16
+ export declare function isRawModeClaimed(fd: number): boolean;
17
+ /**
18
+ * Make the raw-mode transition on `fd` and record what it now owes — or that it
19
+ * owes nothing. The rule in one place, because getting it wrong is the whole
20
+ * failure: one call used to take two branches and only one of them remembered,
21
+ * so the terminal was restored where the native module was absent and stranded
22
+ * everywhere else.
23
+ *
24
+ * `setRawMode` performs the change and reports whether it HAPPENED; that verdict
25
+ * is the return value, so a caller with a further fallback (the `stty` spawn in
26
+ * `@gjsify/process`) can take it without asking the terminal twice. It is the
27
+ * same function for both directions, so the undo cannot drift from the change: a
28
+ * claim taken on a transition that did not happen would restore a terminal this
29
+ * process never broke, and turning raw mode off through here PAYS the debt rather
30
+ * than recording it, so no stale undo can outlive the owner that made it — and it
31
+ * pays it whatever the verdict, because an owner that asked to let go has let go
32
+ * whether or not the terminal heard it, and a claim the exit hook would then run
33
+ * is a restore of a state this process may never have reached.
34
+ */
35
+ export declare function noteRawMode(fd: number, mode: boolean, setRawMode: (enable: boolean) => boolean): boolean;
36
+ /**
37
+ * Pay every outstanding debt, and report how many were paid.
38
+ *
39
+ * The map is emptied BEFORE anything runs, so a restore that claims again — or
40
+ * throws — cannot be undone by this same pass. One descriptor failing does not
41
+ * strand the others: every restore is attempted, and the first failure is
42
+ * rethrown afterwards so the caller can see it. A silently empty restore is the
43
+ * exact failure this module exists to remove, so the error is never swallowed.
44
+ */
45
+ export declare function restoreClaimedRawModes(): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/terminal-native",
3
- "version": "0.53.0",
3
+ "version": "0.54.0",
4
4
  "description": "Optional Vala/GObject bridge providing Posix.isatty(), ioctl(TIOCGWINSZ), termios raw-mode and SIGWINCH for GJS. Enhances @gjsify/tty and @gjsify/process with correct terminal behaviour when installed.",
5
5
  "type": "module",
6
6
  "main": "lib/esm/index.js",
@@ -62,10 +62,10 @@
62
62
  "dependencies": {
63
63
  "@girs/glib-2.0": "5.4.0",
64
64
  "@girs/gobject-2.0": "5.4.0",
65
- "@gjsify/utils": "^0.53.0"
65
+ "@gjsify/utils": "^0.54.0"
66
66
  },
67
67
  "devDependencies": {
68
- "@gjsify/cli": "^0.53.0",
68
+ "@gjsify/cli": "^0.54.0",
69
69
  "@ts-for-gir/cli": "^4.1.0",
70
70
  "@types/node": "^25.9.2",
71
71
  "typescript": "^6.0.3"
@@ -81,12 +81,12 @@
81
81
  },
82
82
  "homepage": "https://github.com/gjsify/gjsify/tree/main/packages/node/terminal-native#readme",
83
83
  "optionalDependencies": {
84
- "@gjsify/terminal-native-darwin-arm64": "0.53.0",
85
- "@gjsify/terminal-native-darwin-x64": "0.53.0",
86
- "@gjsify/terminal-native-linux-arm64": "0.53.0",
87
- "@gjsify/terminal-native-linux-ppc64": "0.53.0",
88
- "@gjsify/terminal-native-linux-riscv64": "0.53.0",
89
- "@gjsify/terminal-native-linux-s390x": "0.53.0",
90
- "@gjsify/terminal-native-linux-x64": "0.53.0"
84
+ "@gjsify/terminal-native-darwin-arm64": "0.54.0",
85
+ "@gjsify/terminal-native-darwin-x64": "0.54.0",
86
+ "@gjsify/terminal-native-linux-arm64": "0.54.0",
87
+ "@gjsify/terminal-native-linux-ppc64": "0.54.0",
88
+ "@gjsify/terminal-native-linux-riscv64": "0.54.0",
89
+ "@gjsify/terminal-native-linux-s390x": "0.54.0",
90
+ "@gjsify/terminal-native-linux-x64": "0.54.0"
91
91
  }
92
92
  }