@orkestrel/terminal 0.0.20 → 0.0.22

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.
@@ -579,6 +579,9 @@ export declare function isPrintable(character: string): boolean;
579
579
  /**
580
580
  * Narrows an unknown caught value to a {@link TerminalError}, so a caller can branch on its `code`.
581
581
  *
582
+ * @remarks
583
+ * Recognizes branded errors across package copies, including subclasses, and refuses transparent proxies.
584
+ *
582
585
  * @param value - The value to test (typically a `catch` binding or a rejected prompt call)
583
586
  * @returns True if `value` is a {@link TerminalError}; false otherwise
584
587
  *
@@ -579,6 +579,9 @@ export declare function isPrintable(character: string): boolean;
579
579
  /**
580
580
  * Narrows an unknown caught value to a {@link TerminalError}, so a caller can branch on its `code`.
581
581
  *
582
+ * @remarks
583
+ * Recognizes branded errors across package copies, including subclasses, and refuses transparent proxies.
584
+ *
582
585
  * @param value - The value to test (typically a `catch` binding or a rejected prompt call)
583
586
  * @returns True if `value` is a {@link TerminalError}; false otherwise
584
587
  *
@@ -1,10 +1,10 @@
1
1
  import { CSI, ESC, STATUS_ICONS, createStyler, freezeStyle, strip, stripControls } from "@orkestrel/console";
2
- import { arrayOf, attempt, isArray, isBoolean, isError, isInstance, isNonEmptyString, isNumber, isRecord, isString, literalOf, parseJSON, rawShape, recordOf, stringShape } from "@orkestrel/contract";
2
+ import { INTRINSICS, arrayOf, attempt, holds, isArray, isBoolean, isError, isFunction, isNonEmptyString, isNumber, isObject, isRecord, isString, literalOf, parseJSON, rawShape, recordOf, stringShape } from "@orkestrel/contract";
3
3
  import { Emitter } from "@orkestrel/emitter";
4
4
  import { createForm, isFieldError, isFormError, parseForm, serializeForm } from "@orkestrel/form";
5
5
  import { createSSEParser } from "@orkestrel/sse";
6
6
  import { createDatabase, createMemoryDriver } from "@orkestrel/database";
7
- //#region src/core/constants.ts
7
+ // src/core/constants.ts
8
8
  /** Names the carriage return byte (`\r`, U+000D) — Enter on most terminals. */
9
9
  var RETURN = String.fromCharCode(13);
10
10
  /** Names the line feed byte (`\n`, U+000A) — Enter on some terminals / pasted input. */
@@ -259,8 +259,7 @@ var ACCEPT_EVENT_STREAM = "text/event-stream";
259
259
  * or oversized `data:` field cannot grow the buffer without bound (a memory-exhaustion guard).
260
260
  */
261
261
  var SSE_BUFFER_LIMIT = 1048576;
262
- //#endregion
263
- //#region src/core/errors.ts
262
+ // src/core/errors.ts
264
263
  /**
265
264
  * Represents the error the terminal surfaces for its own refusals: parking on a destroyed or full broker, an
266
265
  * unusable driver stream, a manager routing fault, or a ctrl-c cancellation. A parked form's own
@@ -286,6 +285,7 @@ var TerminalError = class extends Error {
286
285
  */
287
286
  constructor(code, message, context) {
288
287
  super(message);
288
+ INTRINSICS.define(this, Symbol.for("@orkestrel/terminal.TerminalError"), { value: this });
289
289
  this.name = "TerminalError";
290
290
  this.code = code;
291
291
  if (context !== void 0) this.context = context;
@@ -294,6 +294,9 @@ var TerminalError = class extends Error {
294
294
  /**
295
295
  * Narrows an unknown caught value to a {@link TerminalError}, so a caller can branch on its `code`.
296
296
  *
297
+ * @remarks
298
+ * Recognizes branded errors across package copies, including subclasses, and refuses transparent proxies.
299
+ *
297
300
  * @param value - The value to test (typically a `catch` binding or a rejected prompt call)
298
301
  * @returns True if `value` is a {@link TerminalError}; false otherwise
299
302
  *
@@ -309,10 +312,17 @@ var TerminalError = class extends Error {
309
312
  * ```
310
313
  */
311
314
  function isTerminalError(value) {
312
- return isInstance(value, TerminalError);
315
+ return holds(() => {
316
+ if (!isError(value) || INTRINSICS.prototype(value) === Error.prototype) return false;
317
+ const brand = INTRINSICS.describe(value, Symbol.for("@orkestrel/terminal.TerminalError"));
318
+ if (brand === void 0 || brand.value !== value) return false;
319
+ const code = INTRINSICS.reflect.read(value, "code");
320
+ if (code !== "EXPIRE" && code !== "CANCEL" && code !== "DRIVER" && code !== "DEADLOCK" && code !== "TARGET" && code !== "LIMIT" && code !== "DESTROYED") return false;
321
+ const context = INTRINSICS.reflect.read(value, "context");
322
+ return context === void 0 || isObject(context) || isFunction(context);
323
+ });
313
324
  }
314
- //#endregion
315
- //#region src/core/validators.ts
325
+ // src/core/validators.ts
316
326
  /**
317
327
  * Narrows an unknown value to a {@link PendingFormStatus}.
318
328
  *
@@ -364,8 +374,7 @@ var isTerminalSnapshot = recordOf({
364
374
  id: isNonEmptyString,
365
375
  timeout: isNumber
366
376
  }, ["timeout"]);
367
- //#endregion
368
- //#region src/core/helpers.ts
377
+ // src/core/helpers.ts
369
378
  /**
370
379
  * Decodes one keypress's bytes into a {@link KeyEvent} — total, never throws. A `Uint8Array` is
371
380
  * read as UTF-8; the resulting string is matched against the known control bytes and the CRLF pair
@@ -843,11 +852,8 @@ function reduceConfirm(state, key) {
843
852
  view: renderConfirmView(state),
844
853
  status: "cancel"
845
854
  };
846
- let answer;
847
855
  const choice = key.name?.toLowerCase();
848
- if (key.name === "return") answer = state.default;
849
- else if (choice === "y") answer = true;
850
- else if (choice === "n") answer = false;
856
+ const answer = key.name === "return" ? state.default : choice === "y" ? true : choice === "n" ? false : void 0;
851
857
  if (answer === void 0) return {
852
858
  state,
853
859
  view: renderConfirmView(state),
@@ -1286,8 +1292,7 @@ function serializeDestroy() {
1286
1292
  data: ""
1287
1293
  };
1288
1294
  }
1289
- //#endregion
1290
- //#region src/core/Prompt.ts
1295
+ // src/core/Prompt.ts
1291
1296
  /**
1292
1297
  * Implements the headless form broker. It parks live forms, exposes their serialized schemas,
1293
1298
  * applies remote answers to the authoritative form, and abandons a parked form on timeout, release,
@@ -1383,11 +1388,10 @@ var Prompt = class {
1383
1388
  return;
1384
1389
  }
1385
1390
  if (isArray(ids)) {
1386
- let stopped = true;
1387
- for (const id of ids) {
1391
+ const stopped = Iterator.from(ids).reduce((result, id) => {
1388
1392
  const parked = this.#parked.get(id);
1389
- if (parked === void 0 || parked.pending.status !== "pending") stopped = false;
1390
- }
1393
+ return parked !== void 0 && parked.pending.status === "pending" && result;
1394
+ }, true);
1391
1395
  for (const id of ids) this.#expire(id);
1392
1396
  return stopped;
1393
1397
  }
@@ -1478,8 +1482,23 @@ var Prompt = class {
1478
1482
  return true;
1479
1483
  }
1480
1484
  };
1481
- //#endregion
1482
- //#region src/core/PromptClient.ts
1485
+ // src/core/PromptAnswers.ts
1486
+ /** Holds the answer and refusal carried between attempts of one remote prompt. */
1487
+ var PromptAnswers = class {
1488
+ #values;
1489
+ #errors = [];
1490
+ get values() {
1491
+ return this.#values;
1492
+ }
1493
+ get errors() {
1494
+ return this.#errors;
1495
+ }
1496
+ replace(values, errors) {
1497
+ this.#values = values;
1498
+ this.#errors = errors;
1499
+ }
1500
+ };
1501
+ // src/core/PromptClient.ts
1483
1502
  /**
1484
1503
  * Implements the SSE form bridge. It ingests serialized forms from a remote broker without waiting
1485
1504
  * on a render, drives one form at a time through a local terminal, posts each answer back, and asks
@@ -1645,11 +1664,7 @@ var PromptClient = class {
1645
1664
  this.#draining = true;
1646
1665
  try {
1647
1666
  while (!this.#destroyed) {
1648
- let queued;
1649
- for (const entry of this.#queue) {
1650
- queued = entry;
1651
- break;
1652
- }
1667
+ const queued = this.#next();
1653
1668
  if (queued === void 0) return;
1654
1669
  const [id, schema] = queued;
1655
1670
  this.#queue.delete(id);
@@ -1672,28 +1687,29 @@ var PromptClient = class {
1672
1687
  }
1673
1688
  }
1674
1689
  async #render(id, schema) {
1675
- let values;
1676
- let errors = [];
1690
+ const answers = new PromptAnswers();
1677
1691
  while (this.#seen.has(id) && !this.#destroyed) {
1678
- const form = this.#createRenderingForm(schema, values);
1692
+ const form = this.#createRenderingForm(schema, answers.values);
1679
1693
  this.#active = {
1680
1694
  id,
1681
1695
  form,
1682
1696
  stopped: false
1683
1697
  };
1684
- for (const error of errors) form.invalidate(error.field, sanitizeDisplayText(error.message));
1698
+ for (const error of answers.errors) form.invalidate(error.field, sanitizeDisplayText(error.message));
1685
1699
  const submitted = await this.#terminal.ask(form);
1686
1700
  const active = this.#active;
1687
1701
  if (active?.id !== id || active.stopped) return;
1688
1702
  const rejected = await this.#post(id, submitted);
1689
1703
  const posted = this.#active;
1690
1704
  if (posted?.id !== id || posted.stopped || rejected === void 0) return;
1691
- values = submitted;
1692
- errors = rejected;
1705
+ answers.replace(submitted, rejected);
1693
1706
  form.destroy();
1694
1707
  this.#active = void 0;
1695
1708
  }
1696
1709
  }
1710
+ #next() {
1711
+ for (const entry of this.#queue) return entry;
1712
+ }
1697
1713
  #createRenderingForm(schema, values) {
1698
1714
  const fields = schema.fields.map((field) => {
1699
1715
  if (field.rule?.pattern === void 0) return field;
@@ -1785,8 +1801,7 @@ var PromptClient = class {
1785
1801
  };
1786
1802
  }
1787
1803
  };
1788
- //#endregion
1789
- //#region src/core/TerminalManager.ts
1804
+ // src/core/TerminalManager.ts
1790
1805
  /**
1791
1806
  * Registers named {@link PromptInterface} brokers, one per endpoint, so several parties can `ask`
1792
1807
  * forms of each other by name with a `from` → `to` attribution edge on every parked form, and
@@ -1952,11 +1967,7 @@ var TerminalManager = class {
1952
1967
  for (const name of [...this.#terminals.keys()]) this.#removeOne(name);
1953
1968
  return;
1954
1969
  }
1955
- if (isArray(names)) {
1956
- let removed = true;
1957
- for (const name of names) if (!this.#removeOne(name)) removed = false;
1958
- return removed;
1959
- }
1970
+ if (isArray(names)) return Iterator.from(names).reduce((result, name) => this.#removeOne(name) && result, true);
1960
1971
  return this.#removeOne(names);
1961
1972
  }
1962
1973
  destroy() {
@@ -2028,8 +2039,7 @@ var TerminalManager = class {
2028
2039
  }
2029
2040
  }
2030
2041
  };
2031
- //#endregion
2032
- //#region src/core/stores/MemoryTerminalStore.ts
2042
+ // src/core/stores/MemoryTerminalStore.ts
2033
2043
  /**
2034
2044
  * Implements the in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of
2035
2045
  * {@link TerminalSnapshot} records keyed by endpoint id, the default store
@@ -2095,8 +2105,7 @@ var MemoryTerminalStore = class {
2095
2105
  return Promise.resolve();
2096
2106
  }
2097
2107
  };
2098
- //#endregion
2099
- //#region src/core/stores/DatabaseTerminalStore.ts
2108
+ // src/core/stores/DatabaseTerminalStore.ts
2100
2109
  /**
2101
2110
  * Implements a {@link TerminalStoreInterface} backed by one table of the `databases` layer — an
2102
2111
  * endpoint's durable config state is a row, so persistence reduces to keyed point-access (`get` /
@@ -2187,8 +2196,7 @@ var DatabaseTerminalStore = class {
2187
2196
  await this.#table.remove(id);
2188
2197
  }
2189
2198
  };
2190
- //#endregion
2191
- //#region src/core/factories.ts
2199
+ // src/core/factories.ts
2192
2200
  /**
2193
2201
  * Creates the headless {@link PromptInterface} broker. It parks live forms and applies remote
2194
2202
  * answers to the authoritative instances.
@@ -2303,7 +2311,6 @@ function createDatabaseTerminalStore(driver = createMemoryDriver()) {
2303
2311
  tables: { terminals: columns }
2304
2312
  }).table("terminals"));
2305
2313
  }
2306
- //#endregion
2307
2314
  export { ACCEPT_EVENT_STREAM, BACKSPACE, CONTROL_NAMES, CTRL_A, CTRL_C, CTRL_D, CTRL_E, CTRL_U, DEFAULT_MASK, DEFAULT_PROMPT_THEME, DEFAULT_PROMPT_TIMEOUT_MS, DEFAULT_RECONNECT_DELAY_MS, DELETE, DatabaseTerminalStore, HEADER_TOKEN, KEY_SS3, MemoryTerminalStore, NEWLINE, PROMPT_ICONS, PROMPT_ROLES, Prompt, PromptClient, RETURN, SEQUENCE_NAMES, SPACE, SSE_BUFFER_LIMIT, SSE_EVENTS, TAB, TerminalError, TerminalManager, createCheckboxState, createConfirmState, createDatabaseTerminalStore, createEditorState, createInputState, createMemoryTerminalStore, createPasswordState, createPrompt, createPromptClient, createPromptTheme, createSelectState, createTerminalManager, defaultTimer, editLine, globalFetch, isAbortError, isInsecureRemote, isPendingForm, isPendingFormStatus, isPrintable, isTerminalError, isTerminalSnapshot, isWireEvent, parseKey, reduceCheckbox, reduceConfirm, reduceEditor, reduceInput, reducePassword, reduceSelect, renderCheckboxView, renderConfirmView, renderEditorView, renderErrorLine, renderHintedHeader, renderInputView, renderPasswordView, renderPromptHeader, renderSelectView, renderSubmitHeader, sanitizeDisplayText, sanitizeSchema, sanitizeThemeIcons, serializeDestroy, serializeExpire, serializePending, toggleIndex };
2308
2315
 
2309
2316
  //# sourceMappingURL=index.js.map