@orkestrel/terminal 0.0.14 → 0.0.16
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/README.md +10 -11
- package/dist/src/core/index.cjs +118 -83
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +265 -150
- package/dist/src/core/index.d.ts +265 -150
- package/dist/src/core/index.js +119 -84
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +111 -86
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +122 -92
- package/dist/src/server/index.d.ts +122 -92
- package/dist/src/server/index.js +111 -86
- package/dist/src/server/index.js.map +1 -1
- package/package.json +18 -19
package/dist/src/core/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CSI, ESC, STATUS_ICONS, createStyler, freezeStyle, strip, stripControls } from "@orkestrel/console";
|
|
2
|
-
import { arrayOf, attempt, isArray, isBoolean, isNonEmptyString, isNumber, isRecord, isString, literalOf, parseJSON, rawShape, recordOf, stringShape } from "@orkestrel/contract";
|
|
2
|
+
import { arrayOf, attempt, isArray, isBoolean, isError, isInstance, isNonEmptyString, isNumber, 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";
|
|
@@ -35,10 +35,11 @@ var CTRL_E = String.fromCharCode(5);
|
|
|
35
35
|
*/
|
|
36
36
|
var KEY_SS3 = `${ESC}O`;
|
|
37
37
|
/**
|
|
38
|
-
* Holds the exact escape
|
|
39
|
-
* consults for the navigation
|
|
40
|
-
* form (`ESCOA`…) of the arrows, plus the `home` / `end` / `delete`
|
|
41
|
-
* their numeric-tilde variants
|
|
38
|
+
* Holds the exact escape sequence to canonical key name table
|
|
39
|
+
* {@link import('./helpers.js').parseKey} consults for the navigation and editing keys. Covers the
|
|
40
|
+
* CSI form (`ESC[A`…) and the SS3 form (`ESCOA`…) of the arrows, plus the `home` / `end` / `delete`
|
|
41
|
+
* CSI sequences with their numeric-tilde variants. The source of truth for the multi-byte key
|
|
42
|
+
* decode; frozen.
|
|
42
43
|
*
|
|
43
44
|
* @remarks
|
|
44
45
|
* Terminals disagree on these: a cursor key is `ESC[A` (normal) or `ESCOA` (application mode),
|
|
@@ -64,10 +65,10 @@ var SEQUENCE_NAMES = Object.freeze({
|
|
|
64
65
|
[`${CSI}8~`]: "end"
|
|
65
66
|
});
|
|
66
67
|
/**
|
|
67
|
-
* Holds the control
|
|
68
|
-
* consults for the one-byte keys and the two-byte CRLF
|
|
69
|
-
* canonical `name` and whether it is a `ctrl` combination. The
|
|
70
|
-
* frozen.
|
|
68
|
+
* Holds the control byte (or CRLF pair) to key descriptor table
|
|
69
|
+
* {@link import('./helpers.js').parseKey} consults for the one-byte keys and the two-byte CRLF
|
|
70
|
+
* Enter chunk. Each entry carries the canonical `name` and whether it is a `ctrl` combination. The
|
|
71
|
+
* source of truth for that decode; frozen.
|
|
71
72
|
*
|
|
72
73
|
* @remarks
|
|
73
74
|
* `return` / `newline` / `return + newline` all map to `return` (one canonical Enter name) — a
|
|
@@ -134,8 +135,9 @@ var CONTROL_NAMES = Object.freeze({
|
|
|
134
135
|
/** Names the default mask glyph {@link import('./helpers.js').createPasswordState} uses — `*`. */
|
|
135
136
|
var DEFAULT_MASK = "*";
|
|
136
137
|
/**
|
|
137
|
-
* Holds the
|
|
138
|
-
* the
|
|
138
|
+
* Holds the terminal-owned glyphs {@link DEFAULT_PROMPT_THEME} assembles its `icons` from, beside
|
|
139
|
+
* the console module's own success and error marks. Read only when the default theme is assembled;
|
|
140
|
+
* a view reads its resolved theme and never this constant. Frozen.
|
|
139
141
|
*
|
|
140
142
|
* @remarks
|
|
141
143
|
* - `question` — the leading mark on a prompt's message line.
|
|
@@ -224,17 +226,18 @@ var DEFAULT_PROMPT_THEME = Object.freeze({
|
|
|
224
226
|
description: freezeStyle({ attributes: ["dim"] })
|
|
225
227
|
})
|
|
226
228
|
});
|
|
227
|
-
/** Holds how long (ms) the {@link import('./types.js').PromptInterface} broker parks an unanswered
|
|
229
|
+
/** Holds how long (ms) the {@link import('./types.js').PromptInterface} broker parks an unanswered form before it expires — 5 minutes. */
|
|
228
230
|
var DEFAULT_PROMPT_TIMEOUT_MS = 3e5;
|
|
229
231
|
/** Holds how long (ms) the {@link import('./types.js').PromptClientInterface} waits before each reconnect attempt — 2 seconds. */
|
|
230
232
|
var DEFAULT_RECONNECT_DELAY_MS = 2e3;
|
|
231
233
|
/**
|
|
232
|
-
* Holds the SSE `event:` names the broker emits and the
|
|
233
|
-
*
|
|
234
|
+
* Holds the SSE `event:` names the broker emits and the
|
|
235
|
+
* {@link import('./types.js').PromptClientInterface} dispatches on — `pending`, `expire`, and
|
|
236
|
+
* `destroy`. Frozen; the source of truth for the wire event vocabulary.
|
|
234
237
|
*
|
|
235
238
|
* @remarks
|
|
236
239
|
* - `pending` — a serialized {@link import('./types.js').PendingForm} to dispatch and answer.
|
|
237
|
-
* - `expire` — an `{ id }` payload: the broker expired or released a parked
|
|
240
|
+
* - `expire` — an `{ id }` payload: the broker expired or released a parked form (the client drops it).
|
|
238
241
|
* - `destroy` — the broker is going away; the client disconnects (no auto-reconnect) but stays reusable.
|
|
239
242
|
*/
|
|
240
243
|
var SSE_EVENTS = Object.freeze({
|
|
@@ -242,9 +245,12 @@ var SSE_EVENTS = Object.freeze({
|
|
|
242
245
|
expire: "expire",
|
|
243
246
|
destroy: "destroy"
|
|
244
247
|
});
|
|
245
|
-
/**
|
|
248
|
+
/**
|
|
249
|
+
* Names the auth-token request header the {@link import('./types.js').PromptClientInterface} sends
|
|
250
|
+
* when a `token` is configured — `x-orkestrel-token`.
|
|
251
|
+
*/
|
|
246
252
|
var HEADER_TOKEN = "x-orkestrel-token";
|
|
247
|
-
/** Names the `Accept` header value that opens the broker's SSE stream
|
|
253
|
+
/** Names the `Accept` header value that opens the broker's SSE stream — `text/event-stream`. */
|
|
248
254
|
var ACCEPT_EVENT_STREAM = "text/event-stream";
|
|
249
255
|
/**
|
|
250
256
|
* Sets the maximum number of characters the {@link import('./types.js').PromptClientInterface} lets its
|
|
@@ -286,7 +292,7 @@ var TerminalError = class extends Error {
|
|
|
286
292
|
}
|
|
287
293
|
};
|
|
288
294
|
/**
|
|
289
|
-
* Narrows an unknown caught value to a {@link TerminalError}
|
|
295
|
+
* Narrows an unknown caught value to a {@link TerminalError}, so a caller can branch on its `code`.
|
|
290
296
|
*
|
|
291
297
|
* @param value - The value to test (typically a `catch` binding or a rejected prompt call)
|
|
292
298
|
* @returns True if `value` is a {@link TerminalError}; false otherwise
|
|
@@ -303,7 +309,7 @@ var TerminalError = class extends Error {
|
|
|
303
309
|
* ```
|
|
304
310
|
*/
|
|
305
311
|
function isTerminalError(value) {
|
|
306
|
-
return value
|
|
312
|
+
return isInstance(value, TerminalError);
|
|
307
313
|
}
|
|
308
314
|
//#endregion
|
|
309
315
|
//#region src/core/validators.ts
|
|
@@ -315,7 +321,8 @@ function isTerminalError(value) {
|
|
|
315
321
|
*/
|
|
316
322
|
var isPendingFormStatus = literalOf("pending", "answered", "expired");
|
|
317
323
|
/**
|
|
318
|
-
* Narrows an unknown wire value to a {@link PendingForm} envelope
|
|
324
|
+
* Narrows an unknown wire value to a {@link PendingForm} envelope — the envelope alone, because the
|
|
325
|
+
* form package's `parseForm` owns the schema payload.
|
|
319
326
|
*
|
|
320
327
|
* @remarks
|
|
321
328
|
* This guard checks the transport record and proves only that `schema` is a record. The Form
|
|
@@ -335,7 +342,8 @@ function isPendingForm(value) {
|
|
|
335
342
|
}, ["from", "to"])(value);
|
|
336
343
|
}
|
|
337
344
|
/**
|
|
338
|
-
* Narrows an unknown value to a transport-neutral {@link WireEvent}
|
|
345
|
+
* Narrows an unknown value to a transport-neutral {@link WireEvent} — the guard a consumer's own
|
|
346
|
+
* transport applies to an inbound frame.
|
|
339
347
|
*
|
|
340
348
|
* @param value - The candidate wire event
|
|
341
349
|
* @returns True if the value carries an event name, serialized data, and an optional id; false otherwise
|
|
@@ -346,8 +354,8 @@ var isWireEvent = recordOf({
|
|
|
346
354
|
id: isString
|
|
347
355
|
}, ["id"]);
|
|
348
356
|
/**
|
|
349
|
-
* Narrows an unknown value to a {@link TerminalSnapshot} —
|
|
350
|
-
* untrusted persisted row.
|
|
357
|
+
* Narrows an unknown value to a {@link TerminalSnapshot} — a non-empty `id` and an optional numeric
|
|
358
|
+
* `timeout`, the read boundary a store applies to an untrusted persisted row.
|
|
351
359
|
*
|
|
352
360
|
* @param value - The candidate snapshot read back from storage
|
|
353
361
|
* @returns True if the value carries a non-empty `id` and an optional numeric `timeout`; false otherwise
|
|
@@ -360,16 +368,16 @@ var isTerminalSnapshot = recordOf({
|
|
|
360
368
|
//#region src/core/helpers.ts
|
|
361
369
|
/**
|
|
362
370
|
* Decodes one keypress's bytes into a {@link KeyEvent} — total, never throws. A `Uint8Array` is
|
|
363
|
-
* read as UTF-8; the resulting string is matched against the known control bytes and the CRLF
|
|
364
|
-
*
|
|
365
|
-
*
|
|
371
|
+
* read as UTF-8; the resulting string is matched against the known control bytes and the CRLF pair
|
|
372
|
+
* ({@link CONTROL_NAMES}) and escape sequences ({@link SEQUENCE_NAMES}), falling back to a single
|
|
373
|
+
* printable character. An unrecognized sequence carries no `name`, with the raw `sequence`
|
|
366
374
|
* preserved.
|
|
367
375
|
*
|
|
368
376
|
* @remarks
|
|
369
377
|
* - **Single control byte.** A one-character control input (`return` / `backspace` / `tab` /
|
|
370
378
|
* `escape` / `space`, or a Ctrl combo `c` / `d` / `u` / `a` / `e`), or the two-byte `\r\n`
|
|
371
379
|
* CRLF pair, is looked up in {@link CONTROL_NAMES}, carrying its `ctrl` flag.
|
|
372
|
-
* - **Escape sequence.** A multi-byte ESC sequence (`up` / `down` / `left` / `right` in
|
|
380
|
+
* - **Escape sequence.** A multi-byte ESC sequence (`up` / `down` / `left` / `right` in both the
|
|
373
381
|
* `ESC[A` and `ESCOA` forms, plus `home` / `end` / `delete`) is looked up in
|
|
374
382
|
* {@link SEQUENCE_NAMES} and flagged `meta`.
|
|
375
383
|
* - **Printable character.** A single printable character becomes `name` = that character, with
|
|
@@ -424,8 +432,8 @@ function parseKey(input) {
|
|
|
424
432
|
};
|
|
425
433
|
}
|
|
426
434
|
/**
|
|
427
|
-
* Checks whether a single character is
|
|
428
|
-
*
|
|
435
|
+
* Checks whether a single character is printable — the fallback test {@link parseKey} applies after
|
|
436
|
+
* the control bytes and the escape sequences, so the C0 controls and DEL are excluded.
|
|
429
437
|
*
|
|
430
438
|
* @param character - The single character to test
|
|
431
439
|
* @returns True if the character is at or above space and is not DEL; false otherwise
|
|
@@ -487,7 +495,8 @@ function sanitizeDisplayText(text) {
|
|
|
487
495
|
return stripControls(strip(text)).replaceAll(" ", "").replaceAll("\n", "").replaceAll("\r", "");
|
|
488
496
|
}
|
|
489
497
|
/**
|
|
490
|
-
* Sanitizes every terminal-readable string in a parsed form schema
|
|
498
|
+
* Sanitizes every terminal-readable string in a parsed form schema, keeping every identity and
|
|
499
|
+
* answer string verbatim and dropping field metadata.
|
|
491
500
|
*
|
|
492
501
|
* @remarks
|
|
493
502
|
* Display strings pass through {@link sanitizeDisplayText}: labels, help, placeholders, masks,
|
|
@@ -638,7 +647,8 @@ function renderSubmitHeader(styler, theme, message) {
|
|
|
638
647
|
return `${styler.render(theme.roles.success, theme.icons.success)} ${styler.render(theme.roles.message, message)}`;
|
|
639
648
|
}
|
|
640
649
|
/**
|
|
641
|
-
* Renders the styled failure line (`✖ message`) a form driver
|
|
650
|
+
* Renders the styled failure line (`✖ message`) a form driver writes for each refused field before
|
|
651
|
+
* it asks that field again.
|
|
642
652
|
*
|
|
643
653
|
* @param styler - The console styler that renders each role
|
|
644
654
|
* @param theme - The resolved prompt theme
|
|
@@ -649,7 +659,8 @@ function renderErrorLine(styler, theme, message) {
|
|
|
649
659
|
return `${styler.render(theme.roles.error, theme.icons.error)} ${styler.render(theme.roles.error, message)}`;
|
|
650
660
|
}
|
|
651
661
|
/**
|
|
652
|
-
* Builds the initial text-field
|
|
662
|
+
* Builds the initial text-field reducer state — the sanitized label, the declared default, the
|
|
663
|
+
* styler, and the resolved theme.
|
|
653
664
|
*
|
|
654
665
|
* @param field - The text field to render
|
|
655
666
|
* @param styler - The styler used to render the view
|
|
@@ -666,7 +677,8 @@ function createInputState(field, styler = createStyler(), theme) {
|
|
|
666
677
|
};
|
|
667
678
|
}
|
|
668
679
|
/**
|
|
669
|
-
* Renders a text-field
|
|
680
|
+
* Renders a text-field reducer state as a styled view — the header, the pointer, and the typed
|
|
681
|
+
* value, or the default shown as a hint while nothing is typed.
|
|
670
682
|
*
|
|
671
683
|
* @param state - The text field's current reducer state
|
|
672
684
|
* @returns The rendered single-line view — header, pointer, and the typed value or the default
|
|
@@ -721,7 +733,8 @@ function reduceInput(state, key) {
|
|
|
721
733
|
};
|
|
722
734
|
}
|
|
723
735
|
/**
|
|
724
|
-
* Builds the initial password-field
|
|
736
|
+
* Builds the initial password-field reducer state — the text-field state, plus the mask glyph each
|
|
737
|
+
* typed character renders as.
|
|
725
738
|
*
|
|
726
739
|
* @param field - The password field to render
|
|
727
740
|
* @param styler - The styler used to render the view
|
|
@@ -738,7 +751,8 @@ function createPasswordState(field, styler = createStyler(), theme) {
|
|
|
738
751
|
};
|
|
739
752
|
}
|
|
740
753
|
/**
|
|
741
|
-
* Renders a password-field
|
|
754
|
+
* Renders a password-field reducer state as a styled view, with the value replaced by the mask
|
|
755
|
+
* repeated so the secret is never echoed.
|
|
742
756
|
*
|
|
743
757
|
* @param state - The password field's current reducer state
|
|
744
758
|
* @returns The rendered view, with the mask repeated in place of the typed value
|
|
@@ -785,7 +799,8 @@ function reducePassword(state, key) {
|
|
|
785
799
|
};
|
|
786
800
|
}
|
|
787
801
|
/**
|
|
788
|
-
* Builds the initial confirm-field
|
|
802
|
+
* Builds the initial confirm-field reducer state — the sanitized label and the declared default
|
|
803
|
+
* answer.
|
|
789
804
|
*
|
|
790
805
|
* @param field - The confirm field to render
|
|
791
806
|
* @param styler - The styler used to render the view
|
|
@@ -801,7 +816,8 @@ function createConfirmState(field, styler = createStyler(), theme) {
|
|
|
801
816
|
};
|
|
802
817
|
}
|
|
803
818
|
/**
|
|
804
|
-
* Renders a confirm-field
|
|
819
|
+
* Renders a confirm-field reducer state as a styled view — the header and the yes/no group, with
|
|
820
|
+
* the default letter capitalized and painted by the `selected` role.
|
|
805
821
|
*
|
|
806
822
|
* @param state - The confirm field's current reducer state
|
|
807
823
|
* @returns The rendered view — the header and the yes/no group with the default capitalized
|
|
@@ -844,7 +860,8 @@ function reduceConfirm(state, key) {
|
|
|
844
860
|
};
|
|
845
861
|
}
|
|
846
862
|
/**
|
|
847
|
-
* Builds the initial select-field
|
|
863
|
+
* Builds the initial select-field reducer state — the offered choices, with the focus pre-placed on
|
|
864
|
+
* the declared default.
|
|
848
865
|
*
|
|
849
866
|
* @param field - The select field to render
|
|
850
867
|
* @param styler - The styler used to render the view
|
|
@@ -863,7 +880,8 @@ function createSelectState(field, styler = createStyler(), theme) {
|
|
|
863
880
|
};
|
|
864
881
|
}
|
|
865
882
|
/**
|
|
866
|
-
* Renders a select-field
|
|
883
|
+
* Renders a select-field reducer state as a multi-line styled view — one row per choice, with the
|
|
884
|
+
* focused row marked and its help shown.
|
|
867
885
|
*
|
|
868
886
|
* @param state - The select field's current reducer state
|
|
869
887
|
* @returns The rendered view — the header, then one row per choice with the focused row marked
|
|
@@ -877,7 +895,7 @@ function renderSelectView(state) {
|
|
|
877
895
|
}
|
|
878
896
|
/**
|
|
879
897
|
* Advances a select prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`
|
|
880
|
-
* reducer. `up` / `down` (and `k` / `j`) move the focus,
|
|
898
|
+
* reducer. `up` / `down` (and `k` / `j`) move the focus, wrapping at the ends; return submits the
|
|
881
899
|
* focused choice's `value`; ctrl-c cancels. An empty choice list can never submit (a higher layer
|
|
882
900
|
* guards against it); any other key is ignored.
|
|
883
901
|
*
|
|
@@ -936,7 +954,8 @@ function reduceSelect(state, key) {
|
|
|
936
954
|
};
|
|
937
955
|
}
|
|
938
956
|
/**
|
|
939
|
-
* Builds the initial checkbox-field
|
|
957
|
+
* Builds the initial checkbox-field reducer state — the offered choices, with every value in the
|
|
958
|
+
* field's `default` list pre-checked.
|
|
940
959
|
*
|
|
941
960
|
* @param field - The checkbox field to render
|
|
942
961
|
* @param styler - The styler used to render the view
|
|
@@ -959,7 +978,8 @@ function createCheckboxState(field, styler = createStyler(), theme) {
|
|
|
959
978
|
};
|
|
960
979
|
}
|
|
961
980
|
/**
|
|
962
|
-
* Renders a checkbox-field
|
|
981
|
+
* Renders a checkbox-field reducer state as a multi-line styled view — one box per choice, and the
|
|
982
|
+
* selected count beneath them.
|
|
963
983
|
*
|
|
964
984
|
* @param state - The checkbox field's current reducer state
|
|
965
985
|
* @returns The rendered view — the header, one box per choice, and the selected count
|
|
@@ -1047,7 +1067,7 @@ function reduceCheckbox(state, key) {
|
|
|
1047
1067
|
}
|
|
1048
1068
|
/**
|
|
1049
1069
|
* Toggles `index` in a readonly index list — copy-on-write, returning the new sorted-by-insertion
|
|
1050
|
-
* list.
|
|
1070
|
+
* list; the primitive {@link reduceCheckbox} calls.
|
|
1051
1071
|
*
|
|
1052
1072
|
* @param indices - The ticked indices, in tick order
|
|
1053
1073
|
* @param index - The index to add when absent, or drop when present
|
|
@@ -1057,7 +1077,8 @@ function toggleIndex(indices, index) {
|
|
|
1057
1077
|
return indices.includes(index) ? indices.filter((i) => i !== index) : [...indices, index];
|
|
1058
1078
|
}
|
|
1059
1079
|
/**
|
|
1060
|
-
* Builds the initial editor-field
|
|
1080
|
+
* Builds the initial editor-field reducer state — the committed lines empty, and the declared
|
|
1081
|
+
* default held for a finish with nothing typed.
|
|
1061
1082
|
*
|
|
1062
1083
|
* @param field - The editor field to render
|
|
1063
1084
|
* @param styler - The styler used to render the view
|
|
@@ -1075,7 +1096,8 @@ function createEditorState(field, styler = createStyler(), theme) {
|
|
|
1075
1096
|
};
|
|
1076
1097
|
}
|
|
1077
1098
|
/**
|
|
1078
|
-
* Renders an editor-field
|
|
1099
|
+
* Renders an editor-field reducer state as a multi-line styled view — the finish hint, the
|
|
1100
|
+
* committed lines, and the line in progress.
|
|
1079
1101
|
*
|
|
1080
1102
|
* @param state - The editor field's current reducer state
|
|
1081
1103
|
* @returns The rendered view — the hinted header, the committed lines, and the line in progress
|
|
@@ -1088,8 +1110,8 @@ function renderEditorView(state) {
|
|
|
1088
1110
|
/**
|
|
1089
1111
|
* Advances an editor prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`
|
|
1090
1112
|
* reducer. Printable characters extend the current line; backspace shrinks it; return commits the
|
|
1091
|
-
* current line and starts a fresh one; ctrl-d
|
|
1092
|
-
* default when empty
|
|
1113
|
+
* current line and starts a fresh one; ctrl-d finishes, joining every line and falling back to the
|
|
1114
|
+
* default when empty; ctrl-c cancels. The form validates the candidate after the driver fills it.
|
|
1093
1115
|
*
|
|
1094
1116
|
* @param state - The editor field's current reducer state
|
|
1095
1117
|
* @param key - The decoded keypress to apply
|
|
@@ -1141,9 +1163,10 @@ function reduceEditor(state, key) {
|
|
|
1141
1163
|
};
|
|
1142
1164
|
}
|
|
1143
1165
|
/**
|
|
1144
|
-
* Applies a single line-editing {@link KeyEvent} to a text buffer — the editing shared by input
|
|
1145
|
-
* password
|
|
1146
|
-
* `space` appends a space; ctrl-u clears the line
|
|
1166
|
+
* Applies a single line-editing {@link KeyEvent} to a text buffer — the editing shared by input,
|
|
1167
|
+
* password, and editor. A printable key appends its character; `backspace` drops the last
|
|
1168
|
+
* character; `space` appends a space; ctrl-u clears the line; a key that edits nothing returns
|
|
1169
|
+
* `undefined`.
|
|
1147
1170
|
*
|
|
1148
1171
|
* @param value - The buffer the field holds so far
|
|
1149
1172
|
* @param key - The decoded keypress to apply
|
|
@@ -1191,11 +1214,13 @@ function globalFetch(input, init) {
|
|
|
1191
1214
|
* @returns True if the value is a host `Error` or `DOMException` named `AbortError`; false otherwise
|
|
1192
1215
|
*/
|
|
1193
1216
|
function isAbortError(error) {
|
|
1194
|
-
return (error
|
|
1217
|
+
return isError(error) && error.name === "AbortError";
|
|
1195
1218
|
}
|
|
1196
1219
|
/**
|
|
1197
|
-
* Checks whether `url` is an
|
|
1198
|
-
* loopback address. Pure string parsing (no `URL` global), so it stays total on malformed input
|
|
1220
|
+
* Checks whether `url` is an insecure remote endpoint — a plain `http://` URL whose host is not a
|
|
1221
|
+
* loopback address. Pure string parsing (no `URL` global), so it stays total on malformed input;
|
|
1222
|
+
* the {@link import('./PromptClient.js').PromptClient} warns once when a `token` would cross such
|
|
1223
|
+
* an endpoint in cleartext.
|
|
1199
1224
|
*
|
|
1200
1225
|
* @remarks
|
|
1201
1226
|
* A loopback host (`localhost`, `127.0.0.1`, `[::1]`) over `http://` is exempt (local
|
|
@@ -1222,7 +1247,8 @@ function isInsecureRemote(url) {
|
|
|
1222
1247
|
return hostname !== "localhost" && hostname !== "127.0.0.1" && hostname !== "[::1]";
|
|
1223
1248
|
}
|
|
1224
1249
|
/**
|
|
1225
|
-
* Serializes a parked {@link PendingForm} into a {@link WireEvent}
|
|
1250
|
+
* Serializes a parked {@link PendingForm} into a `pending` {@link WireEvent}, whose frame `id` is
|
|
1251
|
+
* the form's own id.
|
|
1226
1252
|
*
|
|
1227
1253
|
* @param form - The parked form's wire-safe record
|
|
1228
1254
|
* @returns The `pending` frame — the JSON-stringified record as `data`, and the form's own `id`
|
|
@@ -1235,7 +1261,8 @@ function serializePending(form) {
|
|
|
1235
1261
|
};
|
|
1236
1262
|
}
|
|
1237
1263
|
/**
|
|
1238
|
-
* Serializes a parked
|
|
1264
|
+
* Serializes a parked form's expiry or release into an `expire` {@link WireEvent}, whose `data` is
|
|
1265
|
+
* the JSON `{ id }` payload.
|
|
1239
1266
|
*
|
|
1240
1267
|
* @param id - The id of the parked form that expired or was released
|
|
1241
1268
|
* @returns The `expire` frame, carrying the JSON-stringified `{ id }` payload as `data`
|
|
@@ -1247,7 +1274,8 @@ function serializeExpire(id) {
|
|
|
1247
1274
|
};
|
|
1248
1275
|
}
|
|
1249
1276
|
/**
|
|
1250
|
-
* Serializes the {@link WireEvent} a broker or manager sends when it is going away
|
|
1277
|
+
* Serializes the `destroy` {@link WireEvent} a broker or manager sends when it is going away, which
|
|
1278
|
+
* carries no payload.
|
|
1251
1279
|
*
|
|
1252
1280
|
* @returns The `destroy` frame, whose `data` is empty because the signal carries no payload
|
|
1253
1281
|
*/
|
|
@@ -1260,8 +1288,9 @@ function serializeDestroy() {
|
|
|
1260
1288
|
//#endregion
|
|
1261
1289
|
//#region src/core/Prompt.ts
|
|
1262
1290
|
/**
|
|
1263
|
-
* Implements the headless form broker. It parks live forms, exposes their serialized schemas,
|
|
1264
|
-
* remote answers to the authoritative form
|
|
1291
|
+
* Implements the headless form broker. It parks live forms, exposes their serialized schemas,
|
|
1292
|
+
* applies remote answers to the authoritative form, and abandons a parked form on timeout, release,
|
|
1293
|
+
* or teardown.
|
|
1265
1294
|
*
|
|
1266
1295
|
* @remarks
|
|
1267
1296
|
* A parked record carries one call to `serializeForm`. A failed fill or submit leaves the record
|
|
@@ -1418,7 +1447,7 @@ var Prompt = class {
|
|
|
1418
1447
|
if (isFieldError(error.context)) return [error.context];
|
|
1419
1448
|
const named = error.context?.field;
|
|
1420
1449
|
return [{
|
|
1421
|
-
field:
|
|
1450
|
+
field: isString(named) ? named : this.#field(form, field),
|
|
1422
1451
|
message: error.message
|
|
1423
1452
|
}];
|
|
1424
1453
|
}
|
|
@@ -1451,8 +1480,9 @@ var Prompt = class {
|
|
|
1451
1480
|
//#endregion
|
|
1452
1481
|
//#region src/core/PromptClient.ts
|
|
1453
1482
|
/**
|
|
1454
|
-
* Implements the SSE form bridge. It ingests serialized forms from a remote broker
|
|
1455
|
-
* local terminal,
|
|
1483
|
+
* Implements the SSE form bridge. It ingests serialized forms from a remote broker without waiting
|
|
1484
|
+
* on a render, drives one form at a time through a local terminal, posts each answer back, and asks
|
|
1485
|
+
* again when the authoritative form refuses one.
|
|
1456
1486
|
*
|
|
1457
1487
|
* @remarks
|
|
1458
1488
|
* - **Connect + reconnect.** {@link connect} opens the SSE stream and reconnects after a transport
|
|
@@ -1464,8 +1494,9 @@ var Prompt = class {
|
|
|
1464
1494
|
* - **Safe local form.** The rendering copy omits every wire `pattern`, because Form compiles a
|
|
1465
1495
|
* pattern during local evaluation. The broker's parked form retains it and remains authoritative.
|
|
1466
1496
|
* - **Refusal retry.** A structured `rejected` response seeds a new rendering form with the values
|
|
1467
|
-
*
|
|
1468
|
-
* counter truncates the loop; acceptance, expiry, and the broker's own teardown
|
|
1497
|
+
* the refused attempt submitted, applies every {@link FieldError} through `invalidate`, and asks
|
|
1498
|
+
* again. No retry counter truncates the loop; acceptance, expiry, and the broker's own teardown
|
|
1499
|
+
* are its bounds.
|
|
1469
1500
|
* - **Replay safety.** A replayed id is skipped while it is queued, rendering, or posting. Once an
|
|
1470
1501
|
* attempt ends, a later delivery of that id may be rendered again.
|
|
1471
1502
|
*
|
|
@@ -1756,24 +1787,24 @@ var PromptClient = class {
|
|
|
1756
1787
|
//#endregion
|
|
1757
1788
|
//#region src/core/TerminalManager.ts
|
|
1758
1789
|
/**
|
|
1759
|
-
* Registers named {@link PromptInterface} brokers
|
|
1760
|
-
*
|
|
1761
|
-
*
|
|
1790
|
+
* Registers named {@link PromptInterface} brokers, one per endpoint, so several parties can `ask`
|
|
1791
|
+
* forms of each other by name with a `from` → `to` attribution edge on every parked form, and
|
|
1792
|
+
* refuses `DEADLOCK` on a transitive cycle across every in-flight ask.
|
|
1762
1793
|
*
|
|
1763
1794
|
* @remarks
|
|
1764
1795
|
* - **Registry.** `add(name, options?)` mints (or, if `name` is already mounted, returns the
|
|
1765
|
-
*
|
|
1796
|
+
* existing broker unchanged — idempotent, never clobbers a live/parked endpoint). Every mounted
|
|
1766
1797
|
* broker's `pending` / `answer` / `expire` events are re-emitted on the manager, attributed by
|
|
1767
1798
|
* `name`.
|
|
1768
|
-
* - **`ask`.** The target must already be mounted
|
|
1799
|
+
* - **`ask`.** The target must already be mounted through {@link add} — `ask` never auto-adds it;
|
|
1769
1800
|
* rejects `TARGET` for an unknown `to` (listing the known names). Rejects `DEADLOCK` when parking
|
|
1770
|
-
* `from → to` would close a cycle over the
|
|
1801
|
+
* `from → to` would close a cycle over the current in-flight edge set (walked transitively);
|
|
1771
1802
|
* otherwise parks the caller's live form through the target's broker and returns that form's own
|
|
1772
1803
|
* `answer` promise. Edge cleanup never alters the value or rejection the caller observes.
|
|
1773
1804
|
* - **Durable open / save.** `open(name)` restores an EMPTY broker from the `store` (parked
|
|
1774
1805
|
* Promises are process-bound and never resurrected); `save(name)` persists the endpoint's
|
|
1775
1806
|
* configured `timeout`.
|
|
1776
|
-
* - **Removal.** `remove` drops one endpoint, a batch (the array overload declared
|
|
1807
|
+
* - **Removal.** `remove` drops one endpoint, a batch (the array overload declared first), or every
|
|
1777
1808
|
* endpoint when called without an argument. It destroys each broker, which expires every form
|
|
1778
1809
|
* still parked on it. `destroy` is idempotent.
|
|
1779
1810
|
*
|
|
@@ -2000,9 +2031,10 @@ var TerminalManager = class {
|
|
|
2000
2031
|
//#region src/core/stores/MemoryTerminalStore.ts
|
|
2001
2032
|
/**
|
|
2002
2033
|
* Implements the in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of
|
|
2003
|
-
* {@link TerminalSnapshot}
|
|
2004
|
-
* {@link import('../factories.js').createMemoryTerminalStore} builds
|
|
2005
|
-
* {@link import('./DatabaseTerminalStore.js').DatabaseTerminalStore}.
|
|
2034
|
+
* {@link TerminalSnapshot} records keyed by endpoint id, the default store
|
|
2035
|
+
* {@link import('../factories.js').createMemoryTerminalStore} builds and the exact twin of
|
|
2036
|
+
* {@link import('./DatabaseTerminalStore.js').DatabaseTerminalStore}. It carries no idle expiry and
|
|
2037
|
+
* no eviction.
|
|
2006
2038
|
*
|
|
2007
2039
|
* @remarks
|
|
2008
2040
|
* A plain `Map<string, TerminalSnapshot>` — the snapshot is already pure, self-contained CONFIG-only
|
|
@@ -2065,10 +2097,11 @@ var MemoryTerminalStore = class {
|
|
|
2065
2097
|
//#endregion
|
|
2066
2098
|
//#region src/core/stores/DatabaseTerminalStore.ts
|
|
2067
2099
|
/**
|
|
2068
|
-
* Implements a {@link TerminalStoreInterface} backed by one table of the `databases` layer — an
|
|
2069
|
-
* durable
|
|
2070
|
-
* `delete`) over a {@link TableInterface}, the driver-pluggable twin of the plain-`Map`
|
|
2071
|
-
* {@link import('./MemoryTerminalStore.js').MemoryTerminalStore}.
|
|
2100
|
+
* Implements a {@link TerminalStoreInterface} backed by one table of the `databases` layer — an
|
|
2101
|
+
* endpoint's durable config state is a row, so persistence reduces to keyed point-access (`get` /
|
|
2102
|
+
* `set` / `delete`) over a {@link TableInterface}, the driver-pluggable twin of the plain-`Map`
|
|
2103
|
+
* {@link import('./MemoryTerminalStore.js').MemoryTerminalStore}. A stored `snapshot` is narrowed
|
|
2104
|
+
* with {@link import('../validators.js').isTerminalSnapshot} on read.
|
|
2072
2105
|
*
|
|
2073
2106
|
* @remarks
|
|
2074
2107
|
* The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,
|
|
@@ -2182,9 +2215,10 @@ function createPrompt(options) {
|
|
|
2182
2215
|
return new Prompt(options);
|
|
2183
2216
|
}
|
|
2184
2217
|
/**
|
|
2185
|
-
* Creates the SSE prompt {@link PromptClientInterface}
|
|
2186
|
-
* endpoint, dispatches each received form to a local
|
|
2187
|
-
* and POSTs the answer back. Universal — `fetch`
|
|
2218
|
+
* Creates the SSE prompt {@link PromptClientInterface} bridge — it connects to a remote broker's
|
|
2219
|
+
* SSE endpoint, dispatches each received form to a local
|
|
2220
|
+
* {@link import('./types.js').TerminalInterface}, and POSTs the answer back. Universal — `fetch`
|
|
2221
|
+
* and SSE are web standards.
|
|
2188
2222
|
*
|
|
2189
2223
|
* @param options - See {@link PromptClientOptions} (`url` + `terminal` required)
|
|
2190
2224
|
* @returns A {@link PromptClientInterface}
|
|
@@ -2208,9 +2242,9 @@ function createPromptClient(options) {
|
|
|
2208
2242
|
return new PromptClient(options);
|
|
2209
2243
|
}
|
|
2210
2244
|
/**
|
|
2211
|
-
* Creates the multi-endpoint {@link TerminalManager} — a named registry of
|
|
2212
|
-
*
|
|
2213
|
-
*
|
|
2245
|
+
* Creates the multi-endpoint {@link TerminalManager} — a named registry of {@link PromptInterface}
|
|
2246
|
+
* brokers so several parties can `ask` forms of each other by name, with a transitive cycle check
|
|
2247
|
+
* that refuses `DEADLOCK` across every in-flight ask.
|
|
2214
2248
|
*
|
|
2215
2249
|
* @param options - See {@link TerminalManagerOptions}
|
|
2216
2250
|
* @returns A {@link TerminalManager}
|
|
@@ -2245,7 +2279,8 @@ function createMemoryTerminalStore() {
|
|
|
2245
2279
|
/**
|
|
2246
2280
|
* Creates a {@link TerminalStoreInterface} backed by one table of the `databases` layer — the
|
|
2247
2281
|
* driver-pluggable twin of {@link createMemoryTerminalStore}, storing each endpoint's config
|
|
2248
|
-
* snapshot as one opaque JSON column.
|
|
2282
|
+
* snapshot as one opaque JSON column. The default driver is an in-memory `@orkestrel/database`
|
|
2283
|
+
* driver.
|
|
2249
2284
|
*
|
|
2250
2285
|
* @param driver - The {@link DriverInterface} backing the table (default an in-memory driver)
|
|
2251
2286
|
* @returns A {@link TerminalStoreInterface}
|