@jigs.design/protocol 0.1.2 → 0.3.0

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.
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * - `error`: what the model wrote is wrong there. The program still runs,
11
11
  * with that part dropped or replaced, but the turn is not valid: the server
12
- * asks the model for a repair, and a strict compile (a stored spec, a
12
+ * asks the model for a repair, and a strict compile (a page, a
13
13
  * situation's example, `jigs.compile`) fails.
14
14
  * - `warning`: the source itself may be fine, but it was written for a
15
15
  * language or catalog newer than this server's, so it may not mean what it
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * - `error`: what the model wrote is wrong there. The program still runs,
11
11
  * with that part dropped or replaced, but the turn is not valid: the server
12
- * asks the model for a repair, and a strict compile (a stored spec, a
12
+ * asks the model for a repair, and a strict compile (a page, a
13
13
  * situation's example, `jigs.compile`) fails.
14
14
  * - `warning`: the source itself may be fine, but it was written for a
15
15
  * language or catalog newer than this server's, so it may not mean what it
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Diagnostic, DiagnosticFix, Severity, Span, severities } from "./diagnostics.js";
2
- import { ChatBlock, ChatBlockStatus, ChildrenKind, ComponentSchema, Invalidation, JigsErrorCode, JigsErrorData, JsonValue, Message, NumberPropSchema, PROGRAM_FORMAT, ProcedureEntry, ProcedureKind, Program, PropSchema, SessionBody, SessionEvent, SessionOptions, jigsErrorCodes } from "./types.js";
2
+ import { ChatBlock, ChatBlockStatus, ChildrenKind, ComponentSchema, Invalidation, JigsErrorCode, JigsErrorData, JsonValue, Message, NumberPropSchema, PROGRAM_FORMAT, PageInvalidation, PageProps, PageRef, PageReply, ProcedureEntry, ProcedureKind, Program, PropSchema, PushEvent, SessionBody, SessionDocument, SessionEvent, SessionOptions, jigsErrorCodes } from "./types.js";
3
3
  import { FrameMessage, HostMessage, MutationCall, MutationResult, Op, QueryRead, QueryResult, ROOT_ID, Row, RuntimeError, WireArg, WireProps, WireValue, WorkerMessage } from "./protocol.js";
4
- import { parseErrorData, parseInvalidations, parseProgram, parseSessionEvent } from "./parse.js";
4
+ import { parseErrorData, parseInvalidations, parsePageReply, parseProgram, parsePushEvent, parseSessionEvent } from "./parse.js";
5
5
  import { isAllowedImage, isAllowedLink, isImageHostEntry, normalizeImageHost } from "./urls.js";
6
- export { type ChatBlock, type ChatBlockStatus, type ChildrenKind, type ComponentSchema, type Diagnostic, type DiagnosticFix, type FrameMessage, type HostMessage, type Invalidation, type JigsErrorCode, type JigsErrorData, type JsonValue, type Message, type MutationCall, type MutationResult, type NumberPropSchema, type Op, PROGRAM_FORMAT, type ProcedureEntry, type ProcedureKind, type Program, type PropSchema, type QueryRead, type QueryResult, ROOT_ID, type Row, type RuntimeError, type SessionBody, type SessionEvent, type SessionOptions, type Severity, type Span, type WireArg, type WireProps, type WireValue, type WorkerMessage, isAllowedImage, isAllowedLink, isImageHostEntry, jigsErrorCodes, normalizeImageHost, parseErrorData, parseInvalidations, parseProgram, parseSessionEvent, severities };
6
+ export { type ChatBlock, type ChatBlockStatus, type ChildrenKind, type ComponentSchema, type Diagnostic, type DiagnosticFix, type FrameMessage, type HostMessage, type Invalidation, type JigsErrorCode, type JigsErrorData, type JsonValue, type Message, type MutationCall, type MutationResult, type NumberPropSchema, type Op, PROGRAM_FORMAT, type PageInvalidation, type PageProps, type PageRef, type PageReply, type ProcedureEntry, type ProcedureKind, type Program, type PropSchema, type PushEvent, type QueryRead, type QueryResult, ROOT_ID, type Row, type RuntimeError, type SessionBody, type SessionDocument, type SessionEvent, type SessionOptions, type Severity, type Span, type WireArg, type WireProps, type WireValue, type WorkerMessage, isAllowedImage, isAllowedLink, isImageHostEntry, jigsErrorCodes, normalizeImageHost, parseErrorData, parseInvalidations, parsePageReply, parseProgram, parsePushEvent, parseSessionEvent, severities };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { PROGRAM_FORMAT, jigsErrorCodes } from "./types.js";
2
2
  import { severities } from "./diagnostics.js";
3
3
  import { ROOT_ID } from "./protocol.js";
4
- import { parseErrorData, parseInvalidations, parseProgram, parseSessionEvent } from "./parse.js";
4
+ import { parseErrorData, parseInvalidations, parsePageReply, parseProgram, parsePushEvent, parseSessionEvent } from "./parse.js";
5
5
  import { isAllowedImage, isAllowedLink, isImageHostEntry, normalizeImageHost } from "./urls.js";
6
- export { PROGRAM_FORMAT, ROOT_ID, isAllowedImage, isAllowedLink, isImageHostEntry, jigsErrorCodes, normalizeImageHost, parseErrorData, parseInvalidations, parseProgram, parseSessionEvent, severities };
6
+ export { PROGRAM_FORMAT, ROOT_ID, isAllowedImage, isAllowedLink, isImageHostEntry, jigsErrorCodes, normalizeImageHost, parseErrorData, parseInvalidations, parsePageReply, parseProgram, parsePushEvent, parseSessionEvent, severities };
package/dist/parse.d.ts CHANGED
@@ -1,9 +1,17 @@
1
- import { Invalidation, JigsErrorData, Program, SessionEvent } from "./types.js";
1
+ import { Invalidation, JigsErrorData, PageReply, Program, PushEvent, SessionEvent } from "./types.js";
2
2
  //#region src/parse.d.ts
3
3
  export declare function parseErrorData(value: unknown): JigsErrorData | null;
4
4
  /** The `invalidate` list of a mutation's reply. */
5
5
  export declare function parseInvalidations(value: unknown): ReadonlyArray<Invalidation> | null;
6
6
  export declare function parseProgram(value: unknown): Program | null;
7
+ /** A page request's reply body, or null when it is not one. */
8
+ export declare function parsePageReply(value: unknown): PageReply | null;
7
9
  /** One session event from its JSON text, or null when it is not one. */
8
10
  export declare function parseSessionEvent(text: string): SessionEvent | null;
11
+ /**
12
+ * One event of the push stream from its JSON text, or null when it is not
13
+ * one the server may send. `open` and `version` come from the transport,
14
+ * never the wire, so they are null here.
15
+ */
16
+ export declare function parsePushEvent(text: string): PushEvent | null;
9
17
  //#endregion
package/dist/parse.js CHANGED
@@ -41,6 +41,27 @@ function parseInvalidations(value) {
41
41
  }
42
42
  return out;
43
43
  }
44
+ const isScalar = (value) => typeof value === "boolean" || typeof value === "number" || typeof value === "string";
45
+ function parsePageInvalidation(value) {
46
+ if (!isRecord(value) || !isString(value.name)) return null;
47
+ if (!("props" in value)) return { name: value.name };
48
+ const props = recordOf(value.props, (entry) => isScalar(entry) ? entry : null);
49
+ return props === null ? null : {
50
+ name: value.name,
51
+ props
52
+ };
53
+ }
54
+ /** The `pages` list of an `invalidate-pages` event. */
55
+ function parsePageInvalidations(value) {
56
+ if (!Array.isArray(value)) return null;
57
+ const out = [];
58
+ for (const entry of value) {
59
+ const parsed = parsePageInvalidation(entry);
60
+ if (parsed === null) return null;
61
+ out.push(parsed);
62
+ }
63
+ return out;
64
+ }
44
65
  function parsePropSchema(value) {
45
66
  if (!isRecord(value)) return null;
46
67
  switch (value.kind) {
@@ -111,6 +132,17 @@ function parseDiagnostics(value) {
111
132
  return parsed === null ? [] : [parsed];
112
133
  });
113
134
  }
135
+ /** A page request's reply body, or null when it is not one. */
136
+ function parsePageReply(value) {
137
+ if (!isRecord(value) || !isString(value.version)) return null;
138
+ const program = parseProgram(value.program);
139
+ const diagnostics = parseDiagnostics(value.diagnostics);
140
+ return program === null || diagnostics === null ? null : {
141
+ diagnostics,
142
+ program,
143
+ version: value.version
144
+ };
145
+ }
114
146
  /** One session event from its JSON text, or null when it is not one. */
115
147
  function parseSessionEvent(text) {
116
148
  let value;
@@ -139,7 +171,13 @@ function parseSessionEvent(text) {
139
171
  type: "program"
140
172
  };
141
173
  }
142
- if (value.type === "done" && isString(value.source)) return {
174
+ if (value.type === "done" && isString(value.source)) return isString(value.reply) ? {
175
+ diagnostics,
176
+ reply: value.reply,
177
+ revision: value.revision,
178
+ source: value.source,
179
+ type: "done"
180
+ } : {
143
181
  diagnostics,
144
182
  revision: value.revision,
145
183
  source: value.source,
@@ -147,5 +185,35 @@ function parseSessionEvent(text) {
147
185
  };
148
186
  return null;
149
187
  }
188
+ /**
189
+ * One event of the push stream from its JSON text, or null when it is not
190
+ * one the server may send. `open` and `version` come from the transport,
191
+ * never the wire, so they are null here.
192
+ */
193
+ function parsePushEvent(text) {
194
+ let value;
195
+ try {
196
+ value = JSON.parse(text);
197
+ } catch {
198
+ return null;
199
+ }
200
+ if (!isRecord(value)) return null;
201
+ if (value.type === "close") return { type: "close" };
202
+ if (value.type === "invalidate") {
203
+ const invalidate = parseInvalidations(value.invalidate);
204
+ return invalidate === null ? null : {
205
+ invalidate,
206
+ type: "invalidate"
207
+ };
208
+ }
209
+ if (value.type === "invalidate-pages") {
210
+ const pages = parsePageInvalidations(value.pages);
211
+ return pages === null ? null : {
212
+ pages,
213
+ type: "invalidate-pages"
214
+ };
215
+ }
216
+ return null;
217
+ }
150
218
  //#endregion
151
- export { parseErrorData, parseInvalidations, parseProgram, parseSessionEvent };
219
+ export { parseErrorData, parseInvalidations, parsePageReply, parseProgram, parsePushEvent, parseSessionEvent };
package/dist/types.d.ts CHANGED
@@ -51,10 +51,35 @@ export interface ProcedureEntry {
51
51
  * data. Without `input`, every input of the query refetches. With it, only
52
52
  * the queries whose input contains those values.
53
53
  */
54
- export interface Invalidation {
54
+ export interface Invalidation<TName extends string = string> {
55
55
  input?: JsonValue;
56
- name: string;
56
+ name: TName;
57
57
  }
58
+ /**
59
+ * What the push channel carries. The server sends `invalidate` (the queries
60
+ * to refetch, by name), `invalidate-pages` (the pages to refetch, by name)
61
+ * and `close` (it is ending the stream on purpose, so the next connection is
62
+ * no gap). The transport adds `open` on every connection it makes, with
63
+ * `replayed` true when it asked the server to resume from the last event
64
+ * id, and `version`, the server's `jigs-version` on that connection. A
65
+ * server cannot send `open` or `version`. No event carries a program: a
66
+ * page refetches its own.
67
+ */
68
+ export type PushEvent = {
69
+ invalidate: ReadonlyArray<Invalidation>;
70
+ type: "invalidate";
71
+ } | {
72
+ pages: ReadonlyArray<PageInvalidation>;
73
+ type: "invalidate-pages";
74
+ } | {
75
+ replayed: boolean;
76
+ type: "open";
77
+ } | {
78
+ type: "close";
79
+ } | {
80
+ type: "version";
81
+ version: string;
82
+ };
58
83
  /**
59
84
  * A compiled spec. Opaque to apps: pass it from the server to the view and
60
85
  * nowhere else. The view trusts its schemas and image hosts.
@@ -70,6 +95,10 @@ export interface Program {
70
95
  /** Text nodes pulled out of the code, so a prose edit swaps a table. */
71
96
  prose: Readonly<Record<string, string>>;
72
97
  }
98
+ /**
99
+ * One message of a session's conversation: the user's ask, or the model's
100
+ * reply as it wrote it. The current UI travels beside it, as `document`.
101
+ */
73
102
  export interface Message {
74
103
  content: string;
75
104
  role: "assistant" | "user";
@@ -87,13 +116,52 @@ export type SessionEvent = {
87
116
  type: "program";
88
117
  } | {
89
118
  diagnostics: ReadonlyArray<Diagnostic>;
119
+ /**
120
+ * The assistant's message for the conversation, absent when no model
121
+ * ran: the reply as written when the turn took one round and the
122
+ * server did not reorder it, otherwise the checked source.
123
+ */
124
+ reply?: string;
90
125
  revision: number;
126
+ /** The new document: the checked source, with its pragma. */
91
127
  source: string;
92
128
  type: "done";
93
129
  } | {
94
130
  error: JigsErrorData;
95
131
  type: "error";
96
132
  };
133
+ /**
134
+ * A page's props. Scalars only: the compiler types a prop only when it is
135
+ * a literal, and a define cannot declare an object prop.
136
+ */
137
+ export type PageProps = Readonly<Record<string, boolean | number | string>>;
138
+ /** A page of the host and the props it was asked for. */
139
+ export interface PageRef {
140
+ /** The page jig's name. */
141
+ name: string;
142
+ /** Its props, keys sorted. */
143
+ props: PageProps;
144
+ }
145
+ /**
146
+ * One page a push event refreshes, by name. Without `props`, every props of
147
+ * the page refetches; with them, only the pages whose props contain those
148
+ * values, as an `Invalidation`'s `input` matches.
149
+ */
150
+ export interface PageInvalidation<TName extends string = string> {
151
+ name: TName;
152
+ props?: PageProps;
153
+ }
154
+ /**
155
+ * The answer to a page request, `POST { type: "page", name, props }`: the
156
+ * page's program, its diagnostics (a saved page is compiled leniently, so
157
+ * they may hold errors), and the server's `jigs-version`, so a client can
158
+ * drop programs an older server compiled.
159
+ */
160
+ export interface PageReply {
161
+ diagnostics: ReadonlyArray<Diagnostic>;
162
+ program: Program;
163
+ version: string;
164
+ }
97
165
  /**
98
166
  * Where a chat block is: still arriving, being repaired after it closed with
99
167
  * errors, or final.
@@ -109,15 +177,23 @@ export interface ChatBlock {
109
177
  diagnostics: ReadonlyArray<Diagnostic>;
110
178
  /** Set when the block could not be built, e.g. an edit to a missing UI. */
111
179
  error?: JigsErrorData;
112
- /** The id the model gave the block, e.g. "monthly-spending". */
113
- id: string;
114
- /** `${id}@${version}`: unique in a conversation. */
180
+ /** `${name}@${version}`: unique in a conversation. */
115
181
  key: string;
182
+ /**
183
+ * The fence id the model gave the block, e.g. "monthly-spending": the
184
+ * jig's name in the conversation's scope.
185
+ */
186
+ name: string;
116
187
  program: Program;
188
+ /**
189
+ * Set when the whole block is one tag naming a page of the host, with
190
+ * literal props: the block is that page, so the app can link to it.
191
+ */
192
+ ref?: PageRef;
117
193
  /** The checked source, with its pragma. Store this, not the program. */
118
194
  source: string;
119
195
  status: ChatBlockStatus;
120
- /** 1 for the first block with this id in the conversation, then 2, 3… */
196
+ /** 1 for the first block with this name in the conversation, then 2, 3… */
121
197
  version: number;
122
198
  }
123
199
  /** A value that travels as JSON. */
@@ -126,8 +202,21 @@ export type JsonValue = boolean | null | number | string | ReadonlyArray<JsonVal
126
202
  };
127
203
  /** App options sent with a turn; the server parses them with its `options` schema. */
128
204
  export type SessionOptions = Readonly<Record<string, JsonValue>>;
205
+ /**
206
+ * What a session is about: an inline source, or a page the server serves,
207
+ * by name, opened as a document.
208
+ */
209
+ export type SessionDocument = {
210
+ source: string;
211
+ } | {
212
+ name: string;
213
+ props?: PageProps;
214
+ };
129
215
  /** What a session request carries. */
130
216
  export interface SessionBody {
217
+ /** The current UI. Absent when the turn writes a new one. */
218
+ document?: SessionDocument;
219
+ /** The conversation about it: the user's asks and the model's replies. */
131
220
  messages: ReadonlyArray<Message>;
132
221
  options?: SessionOptions;
133
222
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jigs.design/protocol",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "description": "The program format, the diagnostics, and the types and messages the server, the browser and the sandbox share. No runtime and no dependencies.",
5
5
  "license": "MIT",
6
6
  "repository": {