@kottera/tera-web 0.0.0-stage → 0.1.0-rc.10

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.
Files changed (42) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +28 -0
  3. package/README.md +56 -2
  4. package/dist/client.d.ts +223 -0
  5. package/dist/client.js +500 -0
  6. package/dist/feed/connection.d.ts +179 -0
  7. package/dist/feed/connection.js +457 -0
  8. package/dist/feed/sse.d.ts +51 -0
  9. package/dist/feed/sse.js +134 -0
  10. package/dist/generated/feed.d.ts +199 -0
  11. package/dist/generated/feed.js +16 -0
  12. package/dist/generated/kit.d.ts +374 -0
  13. package/dist/generated/kit.js +258 -0
  14. package/dist/generated/shares.d.ts +214 -0
  15. package/dist/generated/shares.js +17 -0
  16. package/dist/generated/workorder-events.d.ts +47 -0
  17. package/dist/generated/workorder-events.js +10 -0
  18. package/dist/generated/workorder.d.ts +3775 -0
  19. package/dist/generated/workorder.js +74 -0
  20. package/dist/generated/wsstream.d.ts +34 -0
  21. package/dist/generated/wsstream.js +28 -0
  22. package/dist/index.d.ts +23 -0
  23. package/dist/index.js +24 -0
  24. package/dist/phone.d.ts +11 -0
  25. package/dist/phone.js +24 -0
  26. package/dist/routes.d.ts +32 -0
  27. package/dist/routes.js +69 -0
  28. package/dist/signin.d.ts +48 -0
  29. package/dist/signin.js +74 -0
  30. package/dist/stepup.d.ts +87 -0
  31. package/dist/stepup.js +66 -0
  32. package/dist/stream/connection.d.ts +145 -0
  33. package/dist/stream/connection.js +377 -0
  34. package/dist/terminal/view.d.ts +168 -0
  35. package/dist/terminal/view.js +546 -0
  36. package/dist/terminalwire/codec.d.ts +182 -0
  37. package/dist/terminalwire/codec.js +556 -0
  38. package/dist/terminalwire/collapse.d.ts +4 -0
  39. package/dist/terminalwire/collapse.js +7 -0
  40. package/dist/unreached.d.ts +26 -0
  41. package/dist/unreached.js +30 -0
  42. package/package.json +32 -4
@@ -0,0 +1,199 @@
1
+ /**
2
+ * feed connect-time parameters.
3
+ *
4
+ * The query parameters of a feed URL (`GET /feeds/<name>?…`), each a repeatable query key. The query is a closed vocabulary: an unknown parameter is refused at connect.
5
+ *
6
+ * Schema: sdk/feed/schema/v1/connect.params.json
7
+ */
8
+ export type FeedConnectParams = {
9
+ /** Precedes the live stream with the stored history of the selected run. */
10
+ backfill?: "all";
11
+ /** Overrides the delivery window: a duration such as `2s`, or `0` for no batching. */
12
+ batch_window?: string;
13
+ /** Selects a subset of the topics the connection would otherwise receive; each occurrence may be a comma-separated list. */
14
+ topics?: string[];
15
+ /** Adds or tightens one predicate, `<field>=<value>[,<value>…]`, once per field. */
16
+ where?: string[];
17
+ };
18
+ /**
19
+ * The vocabulary of the feed drop reason (sdk/feed.DropReason).
20
+ *
21
+ * Every member the daemon writes. A later level adds members and removes none (ADR-143 D3); how a consumer reads an unknown member is ADR-143 D13's.
22
+ *
23
+ * Schema: sdk/feed/schema/v1/drop-reason.json
24
+ */
25
+ export type FeedDropReason = "slow_consumer" | "rate_limit" | "connection_closed";
26
+ /**
27
+ * The vocabulary of the feed frame `type` (sdk/feed.FrameType).
28
+ *
29
+ * Every member the daemon writes. A later level adds members and removes none (ADR-143 D3); how a consumer reads an unknown member is ADR-143 D13's.
30
+ *
31
+ * Schema: sdk/feed/schema/v1/frame-type.json
32
+ */
33
+ export type FeedFrameType = "record" | "status" | "heartbeat" | "batch";
34
+ /**
35
+ * `batch` frame (tera.feed.v1).
36
+ *
37
+ * A `batch` frame, generated from feed.BatchFrame.
38
+ *
39
+ * Schema: sdk/feed/schema/v1/frame.batch.json
40
+ */
41
+ export type FeedFrameBatch = {
42
+ /** The frame's type; a consumer skips a frame whose type it does not know (ADR-143 D13). */
43
+ type: string;
44
+ /** The feed's name. */
45
+ feed: string;
46
+ /** This frame's own place in the connection's sequence; the records inside precede it. */
47
+ seq: number;
48
+ /** When the daemon wrote the frame, RFC 3339. */
49
+ at: string;
50
+ /** The delivery window in force, in seconds. */
51
+ window_seconds: number;
52
+ /** The number of records in the batch. */
53
+ count: number;
54
+ /** The window's records, in order; each element is a record frame. */
55
+ records: unknown[] | null;
56
+ /** Records dropped during this window. */
57
+ dropped?: number;
58
+ /** The connection's running total of dropped records. */
59
+ dropped_total?: number;
60
+ /** Why records were dropped; a member of the drop-reason vocabulary. */
61
+ drop_reason?: string;
62
+ };
63
+ /**
64
+ * `heartbeat` frame (tera.feed.v1).
65
+ *
66
+ * A `heartbeat` frame, generated from feed.HeartbeatFrame.
67
+ *
68
+ * Schema: sdk/feed/schema/v1/frame.heartbeat.json
69
+ */
70
+ export type FeedFrameHeartbeat = {
71
+ /** The frame's type; a consumer skips a frame whose type it does not know (ADR-143 D13). */
72
+ type: string;
73
+ /** The feed's name. */
74
+ feed: string;
75
+ /** This frame's place in the connection's single sequence, which has no gaps. */
76
+ seq: number;
77
+ /** When the daemon wrote the frame, RFC 3339. */
78
+ at: string;
79
+ /** How long the connection has been idle, in seconds. */
80
+ idle_seconds: number;
81
+ /** The connection's running total of dropped records. */
82
+ dropped_total?: number;
83
+ };
84
+ /**
85
+ * `record` frame (tera.feed.v1).
86
+ *
87
+ * A `record` frame, generated from feed.RecordFrame.
88
+ *
89
+ * Schema: sdk/feed/schema/v1/frame.record.json
90
+ */
91
+ export type FeedFrameRecord = {
92
+ /** The frame's type; a consumer skips a frame whose type it does not know (ADR-143 D13). */
93
+ type: string;
94
+ /** The feed's name. */
95
+ feed: string;
96
+ /** This record's place in the connection's single sequence, which has no gaps. */
97
+ seq: number;
98
+ /** The broker topic the record was published on. */
99
+ topic: string;
100
+ /** When the daemon observed the record, RFC 3339. */
101
+ observed_at: string;
102
+ /** The publishing principal, when one is known (ADR-083 D11). */
103
+ publisher?: string;
104
+ /** Whether the publisher was verified rather than claimed (ADR-011 Amendment 1); always present. */
105
+ publisher_verified: boolean;
106
+ /** The content type the publishing adapter declared: raw, json, text, protobuf, jsonrpc, formdata, or unknown/<n>. A label, not the arbiter of which payload key is set. */
107
+ content_type: string;
108
+ /** The record's payload as JSON, when its content type is JSON; its shape is the publishing family's. */
109
+ payload?: unknown;
110
+ /** The record's payload, when it is valid UTF-8 that is not JSON. */
111
+ payload_text?: string;
112
+ /** The record's payload, base64-encoded, when it is neither JSON nor UTF-8 text. */
113
+ payload_base64?: string;
114
+ };
115
+ /**
116
+ * `status` frame (tera.feed.v1).
117
+ *
118
+ * A `status` frame, generated from feed.StatusFrame.
119
+ *
120
+ * Schema: sdk/feed/schema/v1/frame.status.json
121
+ */
122
+ export type FeedFrameStatus = {
123
+ /** The frame's type; a consumer skips a frame whose type it does not know (ADR-143 D13). */
124
+ type: string;
125
+ /** The status value; a consumer reads one it does not know as possible loss and reconciles (ADR-143 D13). */
126
+ status: string;
127
+ /** The feed's name. */
128
+ feed: string;
129
+ /** This frame's place in the connection's single sequence, which has no gaps. */
130
+ seq: number;
131
+ /** When the daemon wrote the frame, RFC 3339. */
132
+ at: string;
133
+ /** A human-readable explanation. Never the machine-readable answer: that is status. */
134
+ message?: string;
135
+ /** Accompanies open and partial_authorization. On open, the effective filter set this connection delivers, after any connect-time narrowing. */
136
+ filters?: string[];
137
+ /** Accompanies open and partial_authorization: the feed's filters the principal is not granted. */
138
+ denied?: string[];
139
+ /** On narrowed, the authorized filter set the connection was narrowed from. */
140
+ narrowed_from?: string[];
141
+ /** On narrowed, the effective predicates after the client's request was folded into the feed's own. */
142
+ where?: string[];
143
+ /** On open, the heartbeat interval in seconds: the consumer's silence budget. */
144
+ heartbeat_interval_seconds?: number;
145
+ /** On open, on a batching connection, the effective delivery window in seconds. */
146
+ batch_window_seconds?: number;
147
+ /** On open, on a batching connection, the ceiling on one batch's record count. */
148
+ batch_max_records?: number;
149
+ /** On records_dropped, the records dropped since the last report. */
150
+ dropped?: number;
151
+ /** The connection's running total of dropped records; also carried on every terminal frame. */
152
+ dropped_total?: number;
153
+ /** Why records were dropped; a member of the drop-reason vocabulary. */
154
+ drop_reason?: string;
155
+ /** On a terminal frame, the WebSocket close code that follows it. */
156
+ close_code?: number;
157
+ /** On backfill_gap and backfill_unavailable, the run the statement is about. */
158
+ run?: string;
159
+ /** On backfill_gap, the first day of the inclusive range the store no longer reaches. */
160
+ missing_from?: string;
161
+ /** On backfill_gap, the last day of the inclusive range the store no longer reaches. */
162
+ missing_to?: string;
163
+ /** On backfill_gap, the number of days in the missing range. */
164
+ missing_days?: number;
165
+ /** On backfill_gap, records lost inside days that were read. */
166
+ missing_records?: number;
167
+ /** On backfill_gap and backfill_unavailable, the machine-readable cause. Its vocabulary is not yet part of this contract. */
168
+ reason?: string;
169
+ /** On backfill_unavailable, the partition's admission sampling rate: one session in N is kept (ADR-114 D8). */
170
+ sampling_rate?: number;
171
+ /** On backfill_complete, how many records came from the store. */
172
+ records?: number;
173
+ /** On backfill_complete, how many sessions those records came from. */
174
+ sessions?: number;
175
+ /** On backfill_degraded, the stored record schema versions the daemon met and does not understand. */
176
+ schema_versions?: number[];
177
+ };
178
+ /**
179
+ * The vocabulary of the feed `status` value (sdk/feed.Status).
180
+ *
181
+ * Every member the daemon writes. A later level adds members and removes none (ADR-143 D3); how a consumer reads an unknown member is ADR-143 D13's.
182
+ *
183
+ * Schema: sdk/feed/schema/v1/status.json
184
+ */
185
+ export type FeedStatus = "open" | "partial_authorization" | "narrowed" | "records_dropped" | "upstream_lost" | "shutting_down" | "selection_changed" | "credential_expired" | "backfill_complete" | "backfill_gap" | "backfill_unavailable" | "backfill_degraded";
186
+ /**
187
+ * Every type this module declares, mapped to the repository path of the schema
188
+ * it was generated from.
189
+ */
190
+ export declare const FEED_SCHEMAS: {
191
+ readonly FeedConnectParams: "sdk/feed/schema/v1/connect.params.json";
192
+ readonly FeedDropReason: "sdk/feed/schema/v1/drop-reason.json";
193
+ readonly FeedFrameType: "sdk/feed/schema/v1/frame-type.json";
194
+ readonly FeedFrameBatch: "sdk/feed/schema/v1/frame.batch.json";
195
+ readonly FeedFrameHeartbeat: "sdk/feed/schema/v1/frame.heartbeat.json";
196
+ readonly FeedFrameRecord: "sdk/feed/schema/v1/frame.record.json";
197
+ readonly FeedFrameStatus: "sdk/feed/schema/v1/frame.status.json";
198
+ readonly FeedStatus: "sdk/feed/schema/v1/status.json";
199
+ };
@@ -0,0 +1,16 @@
1
+ // Code generated by cmd/internal/genwebtypes from sdk/feed/schema/v1/; DO NOT EDIT.
2
+ // Regenerate with `make web-types` (ADR-162 D4 item 1).
3
+ /**
4
+ * Every type this module declares, mapped to the repository path of the schema
5
+ * it was generated from.
6
+ */
7
+ export const FEED_SCHEMAS = {
8
+ FeedConnectParams: "sdk/feed/schema/v1/connect.params.json",
9
+ FeedDropReason: "sdk/feed/schema/v1/drop-reason.json",
10
+ FeedFrameType: "sdk/feed/schema/v1/frame-type.json",
11
+ FeedFrameBatch: "sdk/feed/schema/v1/frame.batch.json",
12
+ FeedFrameHeartbeat: "sdk/feed/schema/v1/frame.heartbeat.json",
13
+ FeedFrameRecord: "sdk/feed/schema/v1/frame.record.json",
14
+ FeedFrameStatus: "sdk/feed/schema/v1/frame.status.json",
15
+ FeedStatus: "sdk/feed/schema/v1/status.json",
16
+ };
@@ -0,0 +1,374 @@
1
+ import type { FeedFrameRecord, FeedFrameStatus } from "./feed.ts";
2
+ /**
3
+ * The vocabulary of the kit's own error codes (sdk/plugin/webui.KitCodes).
4
+ *
5
+ * Every code the kit answers with when no verb gave a verdict, and sign_in_required, which tera's UI proxy answers in front of the kit when a request that is not a page load reaches the plugin's origin with no live session: load the page again to sign in; and the codes the proxy answers such a request with when it did not reach the plugin: plugin_busy (503, the plugin is at its runner link's stream cap, with Retry-After), plugin_starting (503, tera has not yet settled where the plugin runs, with Retry-After), plugin_runner_unreachable (502, the plugin's runner has no live link) and plugin_not_answering (502, the plugin's UI did not answer on its socket). Only tera_unavailable and those four are retryable. A failure envelope may also carry a verb's own code, or tera's own code for a call it refused, verbatim, which is not a member: a reader keeps a code it does not know as it arrived and branches on retryable.
6
+ *
7
+ * Schema: sdk/plugin/webui/schema/v1/error-code.json
8
+ */
9
+ export type KitErrorCode = "unauthenticated" | "cross_origin" | "route_not_found" | "method_not_allowed" | "route_not_served" | "invalid_request" | "exchange_refused" | "tera_unavailable" | "step_up_required" | "sign_in_required" | "plugin_busy" | "plugin_starting" | "plugin_runner_unreachable" | "plugin_not_answering";
10
+ /**
11
+ * Kit error envelope.
12
+ *
13
+ * Every kit route's failure (ADR-162 D2 item 8). The outer form is ADR-035's management-API envelope.
14
+ *
15
+ * Schema: sdk/plugin/webui/schema/v1/error.json
16
+ */
17
+ export type KitError = {
18
+ /** The failure. */
19
+ error: {
20
+ /** What failed: one of the kit's own codes (the error-code vocabulary) when the kit refused before any verb ran, tera's own code, verbatim, when tera refused a call the kit relayed, or a verb's own code, verbatim, when a verb refused. A code a reader does not know is kept as it arrived. */
21
+ code: string;
22
+ /** A sentence for a person saying what failed. Never carries a secret. */
23
+ message: string;
24
+ /** Whether the identical request may succeed if it is sent again later with nothing changed. A reader branches on this, never on a list of codes. */
25
+ retryable: boolean;
26
+ /** How long to wait before retrying, in milliseconds, when the refusing verb said. */
27
+ retry_after_ms?: number;
28
+ /** Structured detail the refusing verb attached, whose shape the verb decides. The kit's own refusals attach none. */
29
+ data?: unknown;
30
+ /** The step-up a step_up_required, step_up_pending or step_up_mismatch refusal of the kit's is about. On a step-up just begun it carries the id, the page (url) the person confirms it on, its expiry and the methods the act accepts: open the page, poll the step-up route until it is satisfied, declined or expired, and send the identical request again with the Tera-Step-Up header set to the id. */
31
+ step_up?: {
32
+ id: string;
33
+ url?: string;
34
+ methods?: string[];
35
+ expires_at?: string;
36
+ label?: string;
37
+ state?: string;
38
+ };
39
+ };
40
+ };
41
+ /**
42
+ * The feed's reauthenticate event.
43
+ *
44
+ * The data of the last event of a feed stream closed because the person's token expired.
45
+ *
46
+ * Schema: sdk/plugin/webui/schema/v1/feed.event.reauthenticate.json
47
+ */
48
+ export type KitFeedEventReauthenticate = {
49
+ /** Why the stream closed. token_expired is the reason this version sends; a reader reconnects at once whatever the reason. */
50
+ reason: string;
51
+ };
52
+ /**
53
+ * POST /tera/v1/invoke/{capability} response.
54
+ *
55
+ * The verb's reply envelope, HTTP 200 whenever the verb ran: workorder.HTTPInvoker's reading of the management invoke route.
56
+ *
57
+ * Schema: sdk/plugin/webui/schema/v1/invoke.response.json
58
+ */
59
+ export type KitInvokeResponse = {
60
+ /** success when the verb answered; error when it refused. */
61
+ status: "success" | "error";
62
+ /** The verb's answer, present when status is success. */
63
+ result?: {
64
+ /** The verb's result. For a work_order.* verb, valid against sdk/workorder/schema/v1/<verb>.result.json. */
65
+ structured: unknown;
66
+ };
67
+ /** The verb's refusal, present when status is error. */
68
+ error?: {
69
+ code: string;
70
+ message: string;
71
+ retryable: boolean;
72
+ retry_after_ms?: number;
73
+ /** Structured detail the refusing tool attached, whose shape the tool and its code decide. */
74
+ data?: unknown;
75
+ };
76
+ };
77
+ /**
78
+ * GET /tera/v1/me response.
79
+ *
80
+ * The signed-in person.
81
+ *
82
+ * Schema: sdk/plugin/webui/schema/v1/me.response.json
83
+ */
84
+ export type KitMeResponse = {
85
+ /** The signed-in person, as tera's caller assertion names them: spelled as a Work Order that person filed would name them. */
86
+ subject: string;
87
+ /** Where to send the person to sign out: tera's own sign-out, as a path relative to the app's base, which a page resolves against that base (/ on the plugin's own origin, /plugins/<name>/ on a path-based installation). It is never root-absolute. */
88
+ signout_path: string;
89
+ /** Where to send the person to open a page on their phone: tera's proxy's redirect to tera's phone page, given the page's own URL as the next query parameter. A path relative to the app's base, resolved as signout_path is. It is never root-absolute. */
90
+ phone_path: string;
91
+ /** What to call the signed-in person, as tera's record of them holds it; absent when it holds none. Presentation only: subject is the identity, and nothing is decided by this. */
92
+ display_name?: string;
93
+ /** The address tera's record of the signed-in person holds; absent when it holds none. Presentation only: subject is the identity, and nothing is decided by this. */
94
+ email?: string;
95
+ };
96
+ /**
97
+ * GET /tera/v1/step-ups/{id} response.
98
+ *
99
+ * Where one of the person's own step-ups is in its life (ADR-173 D11).
100
+ *
101
+ * Schema: sdk/plugin/webui/schema/v1/step-up.response.json
102
+ */
103
+ export type KitStepUpResponse = {
104
+ /** The step-up's id. */
105
+ id: string;
106
+ /** Where the step-up is in its life: pending until the person confirms or declines it, satisfied once confirmed, spent once the act used it, declined, or expired. A reader polls until it is satisfied, declined or expired. */
107
+ state: "pending" | "satisfied" | "spent" | "declined" | "expired";
108
+ /** tera's own text for the act the step-up confirms. */
109
+ display: string;
110
+ /** The methods the act accepts: passkey, and email_code when the act accepts it. */
111
+ methods: string[] | null;
112
+ /** When the step-up stops waiting, in RFC 3339. */
113
+ expires_at: string;
114
+ /** What satisfied it, passkey or email_code; absent until it is satisfied. */
115
+ method?: string;
116
+ /** For a passkey, the kind of sign-in that registered it; a passkey anchored on email_code is worth an email code. Absent otherwise. */
117
+ anchor?: string;
118
+ /** When the person confirmed it, in RFC 3339; absent until then. */
119
+ satisfied_at?: string;
120
+ };
121
+ /**
122
+ * POST /tera/v1/uploads response.
123
+ *
124
+ * The staged artifact an upload made (ADR-123).
125
+ *
126
+ * Schema: sdk/plugin/webui/schema/v1/upload.response.json
127
+ */
128
+ export type KitUploadResponse = {
129
+ /** The artifact handle, which a Work Order's attachments name. */
130
+ handle: string;
131
+ /** The file's name, as the upload gave it. */
132
+ filename: string;
133
+ /** The file's media type, as the upload gave it. */
134
+ mime_type: string;
135
+ /** The file's length in bytes. */
136
+ size_bytes: number;
137
+ /** The sha256 of the bytes tera stored, as sha256:<hex>. */
138
+ digest: string;
139
+ /** The file's description, when the upload gave one. */
140
+ description?: string;
141
+ /** When the staged artifact is discarded if no Work Order has attached it, in RFC 3339. */
142
+ staged_expires_at: string;
143
+ };
144
+ /**
145
+ * Every type this module declares, mapped to the repository path of the schema
146
+ * it was generated from.
147
+ */
148
+ export declare const KIT_SCHEMAS: {
149
+ readonly KitErrorCode: "sdk/plugin/webui/schema/v1/error-code.json";
150
+ readonly KitError: "sdk/plugin/webui/schema/v1/error.json";
151
+ readonly KitFeedEventReauthenticate: "sdk/plugin/webui/schema/v1/feed.event.reauthenticate.json";
152
+ readonly KitInvokeResponse: "sdk/plugin/webui/schema/v1/invoke.response.json";
153
+ readonly KitMeResponse: "sdk/plugin/webui/schema/v1/me.response.json";
154
+ readonly KitStepUpResponse: "sdk/plugin/webui/schema/v1/step-up.response.json";
155
+ readonly KitUploadResponse: "sdk/plugin/webui/schema/v1/upload.response.json";
156
+ };
157
+ /** The prefix every kit route is served under (ADR-162 D3), below the app's base. */
158
+ export declare const KIT_ROUTE_PREFIX = "/tera/v1/";
159
+ /** tera's own sign-out path, which `GET /tera/v1/me` answers as signout_path: relative, resolved against the app's base. */
160
+ export declare const KIT_SIGNOUT_PATH = "_tera/signout";
161
+ /** tera's proxy's phone path, which `GET /tera/v1/me` answers as phone_path: relative, resolved against the app's base. */
162
+ export declare const KIT_PHONE_PATH = "_tera/phone";
163
+ /** The kit's route table (ADR-162 D3), as sdk/plugin/webui declares it. */
164
+ export declare const KIT_ROUTE_TABLE: {
165
+ readonly prefix: "/tera/v1/";
166
+ readonly signout_path: "_tera/signout";
167
+ readonly phone_path: "_tera/phone";
168
+ readonly same_origin: "A route marked same_origin refuses a request unless it is same-origin: when the request carries Sec-Fetch-Site, that header must be same-origin; when it does not, its Origin must equal the request's own (scheme http or https, and the Host the request was sent to). The refusal is 403 cross_origin.";
169
+ readonly public: "None. Every route under the prefix refuses a request with no verified caller, 401 unauthenticated, before anything else is decided. Only the app's assets, outside the prefix, are served to an anonymous request.";
170
+ readonly error: {
171
+ readonly media_type: "application/json";
172
+ readonly schema: "https://kottera.dev/schemas/plugin/webui/error/v1";
173
+ readonly description: "Every failure of every route: the kit's own refusal, under one of the error-code vocabulary, or a verb's refusal passed through as the verb gave it.";
174
+ };
175
+ readonly routes: readonly [{
176
+ readonly name: "me";
177
+ readonly method: "GET";
178
+ readonly path: "/tera/v1/me";
179
+ readonly summary: "Who is signed in, where to send them to sign out, and where to send them to open a page on their phone.";
180
+ readonly same_origin: false;
181
+ readonly response: {
182
+ readonly media_type: "application/json";
183
+ readonly schema: "https://kottera.dev/schemas/plugin/webui/me.response/v1";
184
+ readonly description: "The signed-in person.";
185
+ };
186
+ }, {
187
+ readonly name: "invoke";
188
+ readonly method: "POST";
189
+ readonly path: "/tera/v1/invoke/{capability}";
190
+ readonly summary: "Invoke one capability as the person, with the request body as its params. tera decides it on the person's token; the kit vets nothing.";
191
+ readonly same_origin: true;
192
+ readonly path_params: readonly [{
193
+ readonly name: "capability";
194
+ readonly description: "The capability to invoke, e.g. work_order.get.";
195
+ readonly required: true;
196
+ }];
197
+ readonly request: {
198
+ readonly media_type: "application/json";
199
+ readonly description: "The capability's params. For a work_order.* verb, valid against sdk/workorder/schema/v1/<verb>.params.json.";
200
+ };
201
+ readonly response: {
202
+ readonly media_type: "application/json";
203
+ readonly schema: "https://kottera.dev/schemas/plugin/webui/invoke.response/v1";
204
+ readonly description: "The verb's reply envelope, HTTP 200 whenever the verb ran, refusals included.";
205
+ };
206
+ }, {
207
+ readonly name: "feed";
208
+ readonly method: "GET";
209
+ readonly path: "/tera/v1/feeds/{feed}";
210
+ readonly summary: "Open a feed as the person: server-sent events carrying feed records and status frames verbatim.";
211
+ readonly same_origin: false;
212
+ readonly path_params: readonly [{
213
+ readonly name: "feed";
214
+ readonly description: "The feed's name.";
215
+ readonly required: true;
216
+ }];
217
+ readonly query: readonly [{
218
+ readonly name: "topics";
219
+ readonly description: "Selects a subset of the topics the person may subscribe to; each occurrence may be a comma-separated list. Widening is refused.";
220
+ readonly repeated: true;
221
+ }, {
222
+ readonly name: "backfill";
223
+ readonly description: "Precede the live stream with the stored history of the run the connection selected.";
224
+ readonly values: readonly ["all"];
225
+ }];
226
+ readonly response: {
227
+ readonly media_type: "text/event-stream";
228
+ readonly description: "A stream of the events below, until the person's token expires or either side closes it. Any other feed frame (a heartbeat, a batch, a type this kit does not know) is relayed verbatim as an unnamed event, read by its own type.";
229
+ };
230
+ readonly events: readonly [{
231
+ readonly name: "record";
232
+ readonly schema: "https://kottera.dev/schemas/feed/frame.record/v1";
233
+ readonly description: "A feed record frame, verbatim.";
234
+ }, {
235
+ readonly name: "status";
236
+ readonly schema: "https://kottera.dev/schemas/feed/frame.status/v1";
237
+ readonly description: "A feed status frame, verbatim; loss is reported here and nowhere else.";
238
+ }, {
239
+ readonly name: "reauthenticate";
240
+ readonly schema: "https://kottera.dev/schemas/plugin/webui/feed.event.reauthenticate/v1";
241
+ readonly description: "The last event of a stream closed because the person's token expired. Reconnect at once.";
242
+ }];
243
+ }, {
244
+ readonly name: "upload";
245
+ readonly method: "POST";
246
+ readonly path: "/tera/v1/uploads";
247
+ readonly summary: "Upload one file as the person (ADR-123): the kit streams the body once, digesting it, then authorizes and stores it.";
248
+ readonly same_origin: true;
249
+ readonly headers: readonly [{
250
+ readonly name: "Content-Type";
251
+ readonly description: "The file's media type.";
252
+ readonly required: true;
253
+ }, {
254
+ readonly name: "Tera-Upload-Filename";
255
+ readonly description: "The file's name, percent-encoded UTF-8.";
256
+ readonly required: true;
257
+ }, {
258
+ readonly name: "Tera-Upload-Description";
259
+ readonly description: "A description of the file, percent-encoded UTF-8.";
260
+ }];
261
+ readonly request: {
262
+ readonly media_type: "application/octet-stream";
263
+ readonly description: "The file's bytes, any media type. The body is read against its declared Content-Length, capped by the 33554432-byte (32 MiB) bound on an input artifact; a body with no declared length is held to the cap. A declaration over the cap is refused before the body is read, and a body is refused at the first byte past its bound, never after it is read whole.";
264
+ };
265
+ readonly response: {
266
+ readonly media_type: "application/json";
267
+ readonly schema: "https://kottera.dev/schemas/plugin/webui/upload.response/v1";
268
+ readonly description: "The staged artifact.";
269
+ };
270
+ }, {
271
+ readonly name: "step_up";
272
+ readonly method: "GET";
273
+ readonly path: "/tera/v1/step-ups/{id}";
274
+ readonly summary: "Read one of the person's own step-ups as the person (ADR-173 D11): what a page polls, after opening the step-up's url, until it is satisfied, declined or expired. A step-up that is not the person's is tera's 404, the same as an id no step-up carries.";
275
+ readonly same_origin: false;
276
+ readonly path_params: readonly [{
277
+ readonly name: "id";
278
+ readonly description: "The step-up's id, as a step_up_required refusal's step_up names it.";
279
+ readonly required: true;
280
+ }];
281
+ readonly response: {
282
+ readonly media_type: "application/json";
283
+ readonly schema: "https://kottera.dev/schemas/plugin/webui/step-up.response/v1";
284
+ readonly description: "The step-up's state.";
285
+ };
286
+ }, {
287
+ readonly name: "terminal";
288
+ readonly method: "GET";
289
+ readonly path: "/tera/v1/workorders/{id}/terminal";
290
+ readonly summary: "Open one view of an attended session's terminal as the person (ADR-181 D8): a WebSocket the kit splices to tera's terminal door, opened with the person's token. Which Work Order it is, and whether the person may see it, is tera's to decide; the kit keeps no list of sessions. Every refusal after the upgrade is a close: a query of the wrong shape is refused invalid_request; tera's 401 is reconnect, reason reauthenticate, and a second within the minute refused; its 400, 403 and 404 are refused with tera's code (not_attendee, attend_view_not_granted, not_found); its 410 is refused, reason ended, a session with no process and none coming without the person's act; its 409 (not_running, a session whose process is coming), 408, 429 and 5xx, and no answer, are retry_later with tera's code or tera_unavailable. A text message is refused binary_only.";
291
+ readonly same_origin: true;
292
+ readonly path_params: readonly [{
293
+ readonly name: "id";
294
+ readonly description: "The attended Work Order's id.";
295
+ readonly required: true;
296
+ }];
297
+ readonly query: readonly [{
298
+ readonly name: "view";
299
+ readonly description: "The view's id: a canonical, lower-case UUIDv7 the page mints per pane and keeps across reconnects.";
300
+ readonly required: true;
301
+ }, {
302
+ readonly name: "want";
303
+ readonly description: "Whether the view asks to type (control), only to watch (view), or to watch without being counted as attached (peek).";
304
+ readonly required: true;
305
+ readonly values: readonly ["control", "view", "peek"];
306
+ }, {
307
+ readonly name: "resume";
308
+ readonly description: "The output offset the page has handed to its renderer so far, a decimal integer from 0 to 9007199254740991; absent on a fresh view, which replays.";
309
+ }, {
310
+ readonly name: "cols";
311
+ readonly description: "The view's width in cells, a decimal integer from 1 to 65535.";
312
+ readonly required: true;
313
+ }, {
314
+ readonly name: "rows";
315
+ readonly description: "The view's height in cells, a decimal integer from 1 to 65535.";
316
+ readonly required: true;
317
+ }];
318
+ readonly response: {
319
+ readonly media_type: "application/octet-stream";
320
+ readonly description: "A WebSocket upgrade (101), then messages both ways until either side closes, with the close vocabulary.";
321
+ };
322
+ readonly upgrade: "websocket";
323
+ readonly subprotocol: "tera.terminalwire.v1";
324
+ readonly messages: {
325
+ readonly media_type: "application/octet-stream";
326
+ readonly description: "One sdk/terminalwire frame per binary message, each way, at most 16388 bytes. The kit relays each as it arrived, reading no payload and redacting nothing.";
327
+ };
328
+ }];
329
+ readonly close_codes: readonly [{
330
+ readonly code: 1000;
331
+ readonly name: "ended";
332
+ readonly does: "what the protocol above said last; otherwise nothing";
333
+ }, {
334
+ readonly code: 1001;
335
+ readonly name: "going_away";
336
+ readonly does: "reconnects after backoff: the peer is stopping or stopped answering pings";
337
+ }, {
338
+ readonly code: 1009;
339
+ readonly name: "too_big";
340
+ readonly does: "nothing: a message broke the route's bound, a client defect";
341
+ }, {
342
+ readonly code: 4000;
343
+ readonly name: "reconnect";
344
+ readonly does: "reconnects at once with the same identity: a token renewal";
345
+ }, {
346
+ readonly code: 4001;
347
+ readonly name: "retry_later";
348
+ readonly does: "reconnects after backoff: the far side is unreachable or not ready";
349
+ }, {
350
+ readonly code: 4003;
351
+ readonly name: "refused";
352
+ readonly does: "nothing until something changes; the reason is the error code";
353
+ }];
354
+ };
355
+ /** The name of a route in KIT_ROUTE_TABLE. */
356
+ export type KitRouteName = (typeof KIT_ROUTE_TABLE)["routes"][number]["name"];
357
+ /**
358
+ * The JSON body each route answers on success, by route name. A route not
359
+ * here answers a body that is not JSON.
360
+ */
361
+ export type KitRouteResponses = {
362
+ me: KitMeResponse;
363
+ invoke: KitInvokeResponse;
364
+ upload: KitUploadResponse;
365
+ step_up: KitStepUpResponse;
366
+ };
367
+ /** The data of each server-sent event a feed stream carries, by event name. */
368
+ export type KitFeedEvents = {
369
+ record: FeedFrameRecord;
370
+ status: FeedFrameStatus;
371
+ reauthenticate: KitFeedEventReauthenticate;
372
+ };
373
+ /** Every route's failure body. */
374
+ export type KitRouteError = KitError;