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