@orkestrel/terminal 0.0.19 → 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.
- package/dist/src/core/index.cjs +53 -45
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +3 -0
- package/dist/src/core/index.d.ts +3 -0
- package/dist/src/core/index.js +54 -46
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +81 -39
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +10 -6
- package/dist/src/server/index.d.ts +10 -6
- package/dist/src/server/index.js +82 -41
- package/dist/src/server/index.js.map +1 -1
- package/package.json +20 -20
|
@@ -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
|
*
|
package/dist/src/core/index.d.ts
CHANGED
|
@@ -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
|
*
|
package/dist/src/core/index.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
@@ -557,6 +566,7 @@ function sanitizeSchema(schema) {
|
|
|
557
566
|
case "datetime":
|
|
558
567
|
case "color":
|
|
559
568
|
case "confirm":
|
|
569
|
+
case "list":
|
|
560
570
|
fields.push({
|
|
561
571
|
...field,
|
|
562
572
|
...shared
|
|
@@ -842,11 +852,8 @@ function reduceConfirm(state, key) {
|
|
|
842
852
|
view: renderConfirmView(state),
|
|
843
853
|
status: "cancel"
|
|
844
854
|
};
|
|
845
|
-
let answer;
|
|
846
855
|
const choice = key.name?.toLowerCase();
|
|
847
|
-
|
|
848
|
-
else if (choice === "y") answer = true;
|
|
849
|
-
else if (choice === "n") answer = false;
|
|
856
|
+
const answer = key.name === "return" ? state.default : choice === "y" ? true : choice === "n" ? false : void 0;
|
|
850
857
|
if (answer === void 0) return {
|
|
851
858
|
state,
|
|
852
859
|
view: renderConfirmView(state),
|
|
@@ -1285,8 +1292,7 @@ function serializeDestroy() {
|
|
|
1285
1292
|
data: ""
|
|
1286
1293
|
};
|
|
1287
1294
|
}
|
|
1288
|
-
|
|
1289
|
-
//#region src/core/Prompt.ts
|
|
1295
|
+
// src/core/Prompt.ts
|
|
1290
1296
|
/**
|
|
1291
1297
|
* Implements the headless form broker. It parks live forms, exposes their serialized schemas,
|
|
1292
1298
|
* applies remote answers to the authoritative form, and abandons a parked form on timeout, release,
|
|
@@ -1382,11 +1388,10 @@ var Prompt = class {
|
|
|
1382
1388
|
return;
|
|
1383
1389
|
}
|
|
1384
1390
|
if (isArray(ids)) {
|
|
1385
|
-
|
|
1386
|
-
for (const id of ids) {
|
|
1391
|
+
const stopped = Iterator.from(ids).reduce((result, id) => {
|
|
1387
1392
|
const parked = this.#parked.get(id);
|
|
1388
|
-
|
|
1389
|
-
}
|
|
1393
|
+
return parked !== void 0 && parked.pending.status === "pending" && result;
|
|
1394
|
+
}, true);
|
|
1390
1395
|
for (const id of ids) this.#expire(id);
|
|
1391
1396
|
return stopped;
|
|
1392
1397
|
}
|
|
@@ -1477,8 +1482,23 @@ var Prompt = class {
|
|
|
1477
1482
|
return true;
|
|
1478
1483
|
}
|
|
1479
1484
|
};
|
|
1480
|
-
|
|
1481
|
-
|
|
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
|
|
1482
1502
|
/**
|
|
1483
1503
|
* Implements the SSE form bridge. It ingests serialized forms from a remote broker without waiting
|
|
1484
1504
|
* on a render, drives one form at a time through a local terminal, posts each answer back, and asks
|
|
@@ -1644,11 +1664,7 @@ var PromptClient = class {
|
|
|
1644
1664
|
this.#draining = true;
|
|
1645
1665
|
try {
|
|
1646
1666
|
while (!this.#destroyed) {
|
|
1647
|
-
|
|
1648
|
-
for (const entry of this.#queue) {
|
|
1649
|
-
queued = entry;
|
|
1650
|
-
break;
|
|
1651
|
-
}
|
|
1667
|
+
const queued = this.#next();
|
|
1652
1668
|
if (queued === void 0) return;
|
|
1653
1669
|
const [id, schema] = queued;
|
|
1654
1670
|
this.#queue.delete(id);
|
|
@@ -1671,28 +1687,29 @@ var PromptClient = class {
|
|
|
1671
1687
|
}
|
|
1672
1688
|
}
|
|
1673
1689
|
async #render(id, schema) {
|
|
1674
|
-
|
|
1675
|
-
let errors = [];
|
|
1690
|
+
const answers = new PromptAnswers();
|
|
1676
1691
|
while (this.#seen.has(id) && !this.#destroyed) {
|
|
1677
|
-
const form = this.#createRenderingForm(schema, values);
|
|
1692
|
+
const form = this.#createRenderingForm(schema, answers.values);
|
|
1678
1693
|
this.#active = {
|
|
1679
1694
|
id,
|
|
1680
1695
|
form,
|
|
1681
1696
|
stopped: false
|
|
1682
1697
|
};
|
|
1683
|
-
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));
|
|
1684
1699
|
const submitted = await this.#terminal.ask(form);
|
|
1685
1700
|
const active = this.#active;
|
|
1686
1701
|
if (active?.id !== id || active.stopped) return;
|
|
1687
1702
|
const rejected = await this.#post(id, submitted);
|
|
1688
1703
|
const posted = this.#active;
|
|
1689
1704
|
if (posted?.id !== id || posted.stopped || rejected === void 0) return;
|
|
1690
|
-
|
|
1691
|
-
errors = rejected;
|
|
1705
|
+
answers.replace(submitted, rejected);
|
|
1692
1706
|
form.destroy();
|
|
1693
1707
|
this.#active = void 0;
|
|
1694
1708
|
}
|
|
1695
1709
|
}
|
|
1710
|
+
#next() {
|
|
1711
|
+
for (const entry of this.#queue) return entry;
|
|
1712
|
+
}
|
|
1696
1713
|
#createRenderingForm(schema, values) {
|
|
1697
1714
|
const fields = schema.fields.map((field) => {
|
|
1698
1715
|
if (field.rule?.pattern === void 0) return field;
|
|
@@ -1784,8 +1801,7 @@ var PromptClient = class {
|
|
|
1784
1801
|
};
|
|
1785
1802
|
}
|
|
1786
1803
|
};
|
|
1787
|
-
|
|
1788
|
-
//#region src/core/TerminalManager.ts
|
|
1804
|
+
// src/core/TerminalManager.ts
|
|
1789
1805
|
/**
|
|
1790
1806
|
* Registers named {@link PromptInterface} brokers, one per endpoint, so several parties can `ask`
|
|
1791
1807
|
* forms of each other by name with a `from` → `to` attribution edge on every parked form, and
|
|
@@ -1951,11 +1967,7 @@ var TerminalManager = class {
|
|
|
1951
1967
|
for (const name of [...this.#terminals.keys()]) this.#removeOne(name);
|
|
1952
1968
|
return;
|
|
1953
1969
|
}
|
|
1954
|
-
if (isArray(names))
|
|
1955
|
-
let removed = true;
|
|
1956
|
-
for (const name of names) if (!this.#removeOne(name)) removed = false;
|
|
1957
|
-
return removed;
|
|
1958
|
-
}
|
|
1970
|
+
if (isArray(names)) return Iterator.from(names).reduce((result, name) => this.#removeOne(name) && result, true);
|
|
1959
1971
|
return this.#removeOne(names);
|
|
1960
1972
|
}
|
|
1961
1973
|
destroy() {
|
|
@@ -2027,8 +2039,7 @@ var TerminalManager = class {
|
|
|
2027
2039
|
}
|
|
2028
2040
|
}
|
|
2029
2041
|
};
|
|
2030
|
-
|
|
2031
|
-
//#region src/core/stores/MemoryTerminalStore.ts
|
|
2042
|
+
// src/core/stores/MemoryTerminalStore.ts
|
|
2032
2043
|
/**
|
|
2033
2044
|
* Implements the in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of
|
|
2034
2045
|
* {@link TerminalSnapshot} records keyed by endpoint id, the default store
|
|
@@ -2094,8 +2105,7 @@ var MemoryTerminalStore = class {
|
|
|
2094
2105
|
return Promise.resolve();
|
|
2095
2106
|
}
|
|
2096
2107
|
};
|
|
2097
|
-
|
|
2098
|
-
//#region src/core/stores/DatabaseTerminalStore.ts
|
|
2108
|
+
// src/core/stores/DatabaseTerminalStore.ts
|
|
2099
2109
|
/**
|
|
2100
2110
|
* Implements a {@link TerminalStoreInterface} backed by one table of the `databases` layer — an
|
|
2101
2111
|
* endpoint's durable config state is a row, so persistence reduces to keyed point-access (`get` /
|
|
@@ -2186,8 +2196,7 @@ var DatabaseTerminalStore = class {
|
|
|
2186
2196
|
await this.#table.remove(id);
|
|
2187
2197
|
}
|
|
2188
2198
|
};
|
|
2189
|
-
|
|
2190
|
-
//#region src/core/factories.ts
|
|
2199
|
+
// src/core/factories.ts
|
|
2191
2200
|
/**
|
|
2192
2201
|
* Creates the headless {@link PromptInterface} broker. It parks live forms and applies remote
|
|
2193
2202
|
* answers to the authoritative instances.
|
|
@@ -2302,7 +2311,6 @@ function createDatabaseTerminalStore(driver = createMemoryDriver()) {
|
|
|
2302
2311
|
tables: { terminals: columns }
|
|
2303
2312
|
}).table("terminals"));
|
|
2304
2313
|
}
|
|
2305
|
-
//#endregion
|
|
2306
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 };
|
|
2307
2315
|
|
|
2308
2316
|
//# sourceMappingURL=index.js.map
|