@orkestrel/terminal 0.0.20 → 0.0.21

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.
@@ -5,7 +5,7 @@ let _orkestrel_emitter = require("@orkestrel/emitter");
5
5
  let _orkestrel_form = require("@orkestrel/form");
6
6
  let _orkestrel_sse = require("@orkestrel/sse");
7
7
  let _orkestrel_database = require("@orkestrel/database");
8
- //#region src/core/constants.ts
8
+ // src/core/constants.ts
9
9
  /** Names the carriage return byte (`\r`, U+000D) — Enter on most terminals. */
10
10
  var RETURN = String.fromCharCode(13);
11
11
  /** Names the line feed byte (`\n`, U+000A) — Enter on some terminals / pasted input. */
@@ -260,8 +260,7 @@ var ACCEPT_EVENT_STREAM = "text/event-stream";
260
260
  * or oversized `data:` field cannot grow the buffer without bound (a memory-exhaustion guard).
261
261
  */
262
262
  var SSE_BUFFER_LIMIT = 1048576;
263
- //#endregion
264
- //#region src/core/errors.ts
263
+ // src/core/errors.ts
265
264
  /**
266
265
  * Represents the error the terminal surfaces for its own refusals: parking on a destroyed or full broker, an
267
266
  * unusable driver stream, a manager routing fault, or a ctrl-c cancellation. A parked form's own
@@ -287,6 +286,7 @@ var TerminalError = class extends Error {
287
286
  */
288
287
  constructor(code, message, context) {
289
288
  super(message);
289
+ _orkestrel_contract.INTRINSICS.define(this, Symbol.for("@orkestrel/terminal.TerminalError"), { value: this });
290
290
  this.name = "TerminalError";
291
291
  this.code = code;
292
292
  if (context !== void 0) this.context = context;
@@ -295,6 +295,9 @@ var TerminalError = class extends Error {
295
295
  /**
296
296
  * Narrows an unknown caught value to a {@link TerminalError}, so a caller can branch on its `code`.
297
297
  *
298
+ * @remarks
299
+ * Recognizes branded errors across package copies, including subclasses, and refuses transparent proxies.
300
+ *
298
301
  * @param value - The value to test (typically a `catch` binding or a rejected prompt call)
299
302
  * @returns True if `value` is a {@link TerminalError}; false otherwise
300
303
  *
@@ -310,10 +313,17 @@ var TerminalError = class extends Error {
310
313
  * ```
311
314
  */
312
315
  function isTerminalError(value) {
313
- return (0, _orkestrel_contract.isInstance)(value, TerminalError);
316
+ return (0, _orkestrel_contract.holds)(() => {
317
+ if (!(0, _orkestrel_contract.isError)(value) || _orkestrel_contract.INTRINSICS.prototype(value) === Error.prototype) return false;
318
+ const brand = _orkestrel_contract.INTRINSICS.describe(value, Symbol.for("@orkestrel/terminal.TerminalError"));
319
+ if (brand === void 0 || brand.value !== value) return false;
320
+ const code = _orkestrel_contract.INTRINSICS.reflect.read(value, "code");
321
+ if (code !== "EXPIRE" && code !== "CANCEL" && code !== "DRIVER" && code !== "DEADLOCK" && code !== "TARGET" && code !== "LIMIT" && code !== "DESTROYED") return false;
322
+ const context = _orkestrel_contract.INTRINSICS.reflect.read(value, "context");
323
+ return context === void 0 || (0, _orkestrel_contract.isObject)(context) || (0, _orkestrel_contract.isFunction)(context);
324
+ });
314
325
  }
315
- //#endregion
316
- //#region src/core/validators.ts
326
+ // src/core/validators.ts
317
327
  /**
318
328
  * Narrows an unknown value to a {@link PendingFormStatus}.
319
329
  *
@@ -365,8 +375,7 @@ var isTerminalSnapshot = (0, _orkestrel_contract.recordOf)({
365
375
  id: _orkestrel_contract.isNonEmptyString,
366
376
  timeout: _orkestrel_contract.isNumber
367
377
  }, ["timeout"]);
368
- //#endregion
369
- //#region src/core/helpers.ts
378
+ // src/core/helpers.ts
370
379
  /**
371
380
  * Decodes one keypress's bytes into a {@link KeyEvent} — total, never throws. A `Uint8Array` is
372
381
  * read as UTF-8; the resulting string is matched against the known control bytes and the CRLF pair
@@ -844,11 +853,8 @@ function reduceConfirm(state, key) {
844
853
  view: renderConfirmView(state),
845
854
  status: "cancel"
846
855
  };
847
- let answer;
848
856
  const choice = key.name?.toLowerCase();
849
- if (key.name === "return") answer = state.default;
850
- else if (choice === "y") answer = true;
851
- else if (choice === "n") answer = false;
857
+ const answer = key.name === "return" ? state.default : choice === "y" ? true : choice === "n" ? false : void 0;
852
858
  if (answer === void 0) return {
853
859
  state,
854
860
  view: renderConfirmView(state),
@@ -1287,8 +1293,7 @@ function serializeDestroy() {
1287
1293
  data: ""
1288
1294
  };
1289
1295
  }
1290
- //#endregion
1291
- //#region src/core/Prompt.ts
1296
+ // src/core/Prompt.ts
1292
1297
  /**
1293
1298
  * Implements the headless form broker. It parks live forms, exposes their serialized schemas,
1294
1299
  * applies remote answers to the authoritative form, and abandons a parked form on timeout, release,
@@ -1384,11 +1389,10 @@ var Prompt = class {
1384
1389
  return;
1385
1390
  }
1386
1391
  if ((0, _orkestrel_contract.isArray)(ids)) {
1387
- let stopped = true;
1388
- for (const id of ids) {
1392
+ const stopped = Iterator.from(ids).reduce((result, id) => {
1389
1393
  const parked = this.#parked.get(id);
1390
- if (parked === void 0 || parked.pending.status !== "pending") stopped = false;
1391
- }
1394
+ return parked !== void 0 && parked.pending.status === "pending" && result;
1395
+ }, true);
1392
1396
  for (const id of ids) this.#expire(id);
1393
1397
  return stopped;
1394
1398
  }
@@ -1479,8 +1483,23 @@ var Prompt = class {
1479
1483
  return true;
1480
1484
  }
1481
1485
  };
1482
- //#endregion
1483
- //#region src/core/PromptClient.ts
1486
+ // src/core/PromptAnswers.ts
1487
+ /** Holds the answer and refusal carried between attempts of one remote prompt. */
1488
+ var PromptAnswers = class {
1489
+ #values;
1490
+ #errors = [];
1491
+ get values() {
1492
+ return this.#values;
1493
+ }
1494
+ get errors() {
1495
+ return this.#errors;
1496
+ }
1497
+ replace(values, errors) {
1498
+ this.#values = values;
1499
+ this.#errors = errors;
1500
+ }
1501
+ };
1502
+ // src/core/PromptClient.ts
1484
1503
  /**
1485
1504
  * Implements the SSE form bridge. It ingests serialized forms from a remote broker without waiting
1486
1505
  * on a render, drives one form at a time through a local terminal, posts each answer back, and asks
@@ -1646,11 +1665,7 @@ var PromptClient = class {
1646
1665
  this.#draining = true;
1647
1666
  try {
1648
1667
  while (!this.#destroyed) {
1649
- let queued;
1650
- for (const entry of this.#queue) {
1651
- queued = entry;
1652
- break;
1653
- }
1668
+ const queued = this.#next();
1654
1669
  if (queued === void 0) return;
1655
1670
  const [id, schema] = queued;
1656
1671
  this.#queue.delete(id);
@@ -1673,28 +1688,29 @@ var PromptClient = class {
1673
1688
  }
1674
1689
  }
1675
1690
  async #render(id, schema) {
1676
- let values;
1677
- let errors = [];
1691
+ const answers = new PromptAnswers();
1678
1692
  while (this.#seen.has(id) && !this.#destroyed) {
1679
- const form = this.#createRenderingForm(schema, values);
1693
+ const form = this.#createRenderingForm(schema, answers.values);
1680
1694
  this.#active = {
1681
1695
  id,
1682
1696
  form,
1683
1697
  stopped: false
1684
1698
  };
1685
- for (const error of errors) form.invalidate(error.field, sanitizeDisplayText(error.message));
1699
+ for (const error of answers.errors) form.invalidate(error.field, sanitizeDisplayText(error.message));
1686
1700
  const submitted = await this.#terminal.ask(form);
1687
1701
  const active = this.#active;
1688
1702
  if (active?.id !== id || active.stopped) return;
1689
1703
  const rejected = await this.#post(id, submitted);
1690
1704
  const posted = this.#active;
1691
1705
  if (posted?.id !== id || posted.stopped || rejected === void 0) return;
1692
- values = submitted;
1693
- errors = rejected;
1706
+ answers.replace(submitted, rejected);
1694
1707
  form.destroy();
1695
1708
  this.#active = void 0;
1696
1709
  }
1697
1710
  }
1711
+ #next() {
1712
+ for (const entry of this.#queue) return entry;
1713
+ }
1698
1714
  #createRenderingForm(schema, values) {
1699
1715
  const fields = schema.fields.map((field) => {
1700
1716
  if (field.rule?.pattern === void 0) return field;
@@ -1786,8 +1802,7 @@ var PromptClient = class {
1786
1802
  };
1787
1803
  }
1788
1804
  };
1789
- //#endregion
1790
- //#region src/core/TerminalManager.ts
1805
+ // src/core/TerminalManager.ts
1791
1806
  /**
1792
1807
  * Registers named {@link PromptInterface} brokers, one per endpoint, so several parties can `ask`
1793
1808
  * forms of each other by name with a `from` → `to` attribution edge on every parked form, and
@@ -1953,11 +1968,7 @@ var TerminalManager = class {
1953
1968
  for (const name of [...this.#terminals.keys()]) this.#removeOne(name);
1954
1969
  return;
1955
1970
  }
1956
- if ((0, _orkestrel_contract.isArray)(names)) {
1957
- let removed = true;
1958
- for (const name of names) if (!this.#removeOne(name)) removed = false;
1959
- return removed;
1960
- }
1971
+ if ((0, _orkestrel_contract.isArray)(names)) return Iterator.from(names).reduce((result, name) => this.#removeOne(name) && result, true);
1961
1972
  return this.#removeOne(names);
1962
1973
  }
1963
1974
  destroy() {
@@ -2029,8 +2040,7 @@ var TerminalManager = class {
2029
2040
  }
2030
2041
  }
2031
2042
  };
2032
- //#endregion
2033
- //#region src/core/stores/MemoryTerminalStore.ts
2043
+ // src/core/stores/MemoryTerminalStore.ts
2034
2044
  /**
2035
2045
  * Implements the in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of
2036
2046
  * {@link TerminalSnapshot} records keyed by endpoint id, the default store
@@ -2096,8 +2106,7 @@ var MemoryTerminalStore = class {
2096
2106
  return Promise.resolve();
2097
2107
  }
2098
2108
  };
2099
- //#endregion
2100
- //#region src/core/stores/DatabaseTerminalStore.ts
2109
+ // src/core/stores/DatabaseTerminalStore.ts
2101
2110
  /**
2102
2111
  * Implements a {@link TerminalStoreInterface} backed by one table of the `databases` layer — an
2103
2112
  * endpoint's durable config state is a row, so persistence reduces to keyed point-access (`get` /
@@ -2188,8 +2197,7 @@ var DatabaseTerminalStore = class {
2188
2197
  await this.#table.remove(id);
2189
2198
  }
2190
2199
  };
2191
- //#endregion
2192
- //#region src/core/factories.ts
2200
+ // src/core/factories.ts
2193
2201
  /**
2194
2202
  * Creates the headless {@link PromptInterface} broker. It parks live forms and applies remote
2195
2203
  * answers to the authoritative instances.
@@ -2304,7 +2312,6 @@ function createDatabaseTerminalStore(driver = (0, _orkestrel_database.createMemo
2304
2312
  tables: { terminals: columns }
2305
2313
  }).table("terminals"));
2306
2314
  }
2307
- //#endregion
2308
2315
  exports.ACCEPT_EVENT_STREAM = ACCEPT_EVENT_STREAM;
2309
2316
  exports.BACKSPACE = BACKSPACE;
2310
2317
  exports.CONTROL_NAMES = CONTROL_NAMES;