@fnndsc/calypso 0.2.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.
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/daemon/engine.d.ts +44 -0
- package/dist/daemon/engine.js +3 -0
- package/dist/daemon/engine.js.map +1 -0
- package/dist/daemon/server.d.ts +217 -0
- package/dist/daemon/server.js +466 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/token.d.ts +24 -0
- package/dist/daemon/token.js +56 -0
- package/dist/daemon/token.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/envelope.d.ts +136 -0
- package/dist/protocol/envelope.js +49 -0
- package/dist/protocol/envelope.js.map +1 -0
- package/dist/protocol/messages.d.ts +1032 -0
- package/dist/protocol/messages.js +189 -0
- package/dist/protocol/messages.js.map +1 -0
- package/dist/protocol/validate.d.ts +57 -0
- package/dist/protocol/validate.js +94 -0
- package/dist/protocol/validate.js.map +1 -0
- package/dist/protocol/version.d.ts +25 -0
- package/dist/protocol/version.js +32 -0
- package/dist/protocol/version.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serverMessageSchema = exports.editMessageSchema = exports.pipeMessageSchema = exports.promptLineMessageSchema = exports.promptMessageSchema = exports.errorMessageSchema = exports.sessionMessageSchema = exports.progressMessageSchema = exports.progressStatusSchema = exports.progressUnitSchema = exports.progressPhaseSchema = exports.progressKindSchema = exports.progressOperationSchema = exports.outputMessageSchema = exports.completeReplySchema = exports.resultMessageSchema = exports.attachedMessageSchema = exports.clientMessageSchema = exports.editResultMessageSchema = exports.pipeResultMessageSchema = exports.promptAnswerMessageSchema = exports.completeRequestSchema = exports.executeMessageSchema = exports.attachMessageSchema = exports.channelSchema = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @file The wire-contract message schemas.
|
|
6
|
+
*
|
|
7
|
+
* Two discriminated unions, one per direction, keyed on a `type` tag:
|
|
8
|
+
* {@link clientMessageSchema} (surface → daemon) and
|
|
9
|
+
* {@link serverMessageSchema} (daemon → surface). Every request carries a
|
|
10
|
+
* correlation `id` so its reply and any streamed output can be matched to
|
|
11
|
+
* it, and output events carry the sink channel they belong to. These schemas
|
|
12
|
+
* are the single source of truth for the protocol; the human-readable
|
|
13
|
+
* description in `docs/calypso.adoc` is checked against them.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
const zod_1 = require("zod");
|
|
18
|
+
const envelope_js_1 = require("./envelope.js");
|
|
19
|
+
/** The sink channel an output event belongs to. */
|
|
20
|
+
exports.channelSchema = zod_1.z.enum(['data', 'err', 'status']);
|
|
21
|
+
// --- Surface → daemon ------------------------------------------------------
|
|
22
|
+
/** Attach to a session: declares the contract version and the attach token. */
|
|
23
|
+
exports.attachMessageSchema = zod_1.z.object({
|
|
24
|
+
type: zod_1.z.literal('attach'),
|
|
25
|
+
protocolVersion: zod_1.z.number().int(),
|
|
26
|
+
token: zod_1.z.string(),
|
|
27
|
+
session: zod_1.z.string().optional(),
|
|
28
|
+
});
|
|
29
|
+
/** Execute one input line, correlated by `id`. */
|
|
30
|
+
exports.executeMessageSchema = zod_1.z.object({
|
|
31
|
+
type: zod_1.z.literal('execute'),
|
|
32
|
+
id: zod_1.z.string(),
|
|
33
|
+
line: zod_1.z.string(),
|
|
34
|
+
});
|
|
35
|
+
/** Request completion candidates for a partial line, correlated by `id`. */
|
|
36
|
+
exports.completeRequestSchema = zod_1.z.object({
|
|
37
|
+
type: zod_1.z.literal('complete'),
|
|
38
|
+
id: zod_1.z.string(),
|
|
39
|
+
prefix: zod_1.z.string(),
|
|
40
|
+
});
|
|
41
|
+
/** Answers a prompt the daemon requested during a command, correlated by `promptId`. */
|
|
42
|
+
exports.promptAnswerMessageSchema = zod_1.z.object({
|
|
43
|
+
type: zod_1.z.literal('promptAnswer'),
|
|
44
|
+
promptId: zod_1.z.string(),
|
|
45
|
+
answer: zod_1.z.string(),
|
|
46
|
+
});
|
|
47
|
+
/** Returns the output of a pipeline segment the daemon asked the surface to run, correlated by `pipeId`. */
|
|
48
|
+
exports.pipeResultMessageSchema = zod_1.z.object({
|
|
49
|
+
type: zod_1.z.literal('pipeResult'),
|
|
50
|
+
pipeId: zod_1.z.string(),
|
|
51
|
+
output: zod_1.z.string(),
|
|
52
|
+
});
|
|
53
|
+
/** Returns the edited content from a local-edit the daemon requested, correlated by `editId`. */
|
|
54
|
+
exports.editResultMessageSchema = zod_1.z.object({
|
|
55
|
+
type: zod_1.z.literal('editResult'),
|
|
56
|
+
editId: zod_1.z.string(),
|
|
57
|
+
content: zod_1.z.string(),
|
|
58
|
+
changed: zod_1.z.boolean(),
|
|
59
|
+
});
|
|
60
|
+
/** Any message a surface may send to the daemon. */
|
|
61
|
+
exports.clientMessageSchema = zod_1.z.discriminatedUnion('type', [
|
|
62
|
+
exports.attachMessageSchema,
|
|
63
|
+
exports.executeMessageSchema,
|
|
64
|
+
exports.completeRequestSchema,
|
|
65
|
+
exports.promptAnswerMessageSchema,
|
|
66
|
+
exports.pipeResultMessageSchema,
|
|
67
|
+
exports.editResultMessageSchema,
|
|
68
|
+
]);
|
|
69
|
+
// --- Daemon → surface ------------------------------------------------------
|
|
70
|
+
/** Acknowledges a successful attach. */
|
|
71
|
+
exports.attachedMessageSchema = zod_1.z.object({
|
|
72
|
+
type: zod_1.z.literal('attached'),
|
|
73
|
+
session: zod_1.z.string(),
|
|
74
|
+
protocolVersion: zod_1.z.number().int(),
|
|
75
|
+
});
|
|
76
|
+
/** The final result of one executed line: one envelope per command. */
|
|
77
|
+
exports.resultMessageSchema = zod_1.z.object({
|
|
78
|
+
type: zod_1.z.literal('result'),
|
|
79
|
+
id: zod_1.z.string(),
|
|
80
|
+
envelopes: zod_1.z.array(envelope_js_1.commandEnvelopeSchema),
|
|
81
|
+
});
|
|
82
|
+
/** The reply to a completion request. */
|
|
83
|
+
exports.completeReplySchema = zod_1.z.object({
|
|
84
|
+
type: zod_1.z.literal('complete'),
|
|
85
|
+
id: zod_1.z.string(),
|
|
86
|
+
prefix: zod_1.z.string(),
|
|
87
|
+
candidates: zod_1.z.array(zod_1.z.string()),
|
|
88
|
+
});
|
|
89
|
+
/** A streamed output event on one channel, correlated to its command. */
|
|
90
|
+
exports.outputMessageSchema = zod_1.z.object({
|
|
91
|
+
type: zod_1.z.literal('output'),
|
|
92
|
+
id: zod_1.z.string(),
|
|
93
|
+
channel: exports.channelSchema,
|
|
94
|
+
chunk: zod_1.z.string(),
|
|
95
|
+
});
|
|
96
|
+
/** The operation producing structured progress. */
|
|
97
|
+
exports.progressOperationSchema = zod_1.z.enum(['upload', 'download', 'pull', 'workflow']);
|
|
98
|
+
/** Broad class of progress producer. */
|
|
99
|
+
exports.progressKindSchema = zod_1.z.enum(['transfer', 'retrieve', 'workflow']);
|
|
100
|
+
/** Lifecycle phase of a progress operation. */
|
|
101
|
+
exports.progressPhaseSchema = zod_1.z.enum(['scanning', 'transferring', 'watching', 'retrying', 'complete', 'failed']);
|
|
102
|
+
/** Unit used by the primary progress counter. */
|
|
103
|
+
exports.progressUnitSchema = zod_1.z.enum(['files', 'bytes', 'series', 'jobs', 'nodes']);
|
|
104
|
+
/** State of the operation or item being reported. */
|
|
105
|
+
exports.progressStatusSchema = zod_1.z.enum(['running', 'done', 'unconfirmed', 'stalled', 'timeout', 'error', 'unknown']);
|
|
106
|
+
/** A structured progress event correlated to a command. */
|
|
107
|
+
exports.progressMessageSchema = zod_1.z.object({
|
|
108
|
+
type: zod_1.z.literal('progress'),
|
|
109
|
+
id: zod_1.z.string(),
|
|
110
|
+
operation: exports.progressOperationSchema,
|
|
111
|
+
kind: exports.progressKindSchema.optional(),
|
|
112
|
+
phase: exports.progressPhaseSchema,
|
|
113
|
+
label: zod_1.z.string().optional(),
|
|
114
|
+
itemId: zod_1.z.string().optional(),
|
|
115
|
+
current: zod_1.z.number().nonnegative().optional(),
|
|
116
|
+
total: zod_1.z.number().nonnegative().optional(),
|
|
117
|
+
percent: zod_1.z.number().min(0).max(100).optional(),
|
|
118
|
+
unit: exports.progressUnitSchema.optional(),
|
|
119
|
+
status: exports.progressStatusSchema.optional(),
|
|
120
|
+
});
|
|
121
|
+
/** A session-bus broadcast: an envelope tagged with its originating surface. */
|
|
122
|
+
exports.sessionMessageSchema = zod_1.z.object({
|
|
123
|
+
type: zod_1.z.literal('session'),
|
|
124
|
+
surface: zod_1.z.string(),
|
|
125
|
+
envelope: envelope_js_1.commandEnvelopeSchema,
|
|
126
|
+
});
|
|
127
|
+
/** A boundary error: a refused attach, a malformed message, correlated when possible. */
|
|
128
|
+
exports.errorMessageSchema = zod_1.z.object({
|
|
129
|
+
type: zod_1.z.literal('error'),
|
|
130
|
+
id: zod_1.z.string().optional(),
|
|
131
|
+
reason: zod_1.z.string(),
|
|
132
|
+
});
|
|
133
|
+
/**
|
|
134
|
+
* A prompt request the daemon raises during a command: the surface that
|
|
135
|
+
* submitted the command must answer it (with `promptAnswer`) before the
|
|
136
|
+
* command can proceed. `hidden` requests no-echo entry (password).
|
|
137
|
+
*/
|
|
138
|
+
exports.promptMessageSchema = zod_1.z.object({
|
|
139
|
+
type: zod_1.z.literal('prompt'),
|
|
140
|
+
promptId: zod_1.z.string(),
|
|
141
|
+
message: zod_1.z.string(),
|
|
142
|
+
hidden: zod_1.z.boolean(),
|
|
143
|
+
});
|
|
144
|
+
/**
|
|
145
|
+
* The themed prompt string, pushed by the daemon with each result and on any
|
|
146
|
+
* context change. Only the daemon knows the session context the prompt
|
|
147
|
+
* renders; a surface prints what it receives, so prompt themes work
|
|
148
|
+
* identically everywhere.
|
|
149
|
+
*/
|
|
150
|
+
exports.promptLineMessageSchema = zod_1.z.object({
|
|
151
|
+
type: zod_1.z.literal('promptline'),
|
|
152
|
+
text: zod_1.z.string(),
|
|
153
|
+
});
|
|
154
|
+
/**
|
|
155
|
+
* Asks the surface to run a pipeline segment on its own machine (never on the
|
|
156
|
+
* daemon host) and return the output. `input` and the reply's `output` are
|
|
157
|
+
* base64, since segment data is arbitrary bytes.
|
|
158
|
+
*/
|
|
159
|
+
exports.pipeMessageSchema = zod_1.z.object({
|
|
160
|
+
type: zod_1.z.literal('pipe'),
|
|
161
|
+
pipeId: zod_1.z.string(),
|
|
162
|
+
command: zod_1.z.string(),
|
|
163
|
+
input: zod_1.z.string(),
|
|
164
|
+
});
|
|
165
|
+
/**
|
|
166
|
+
* Asks the surface to open content in its local editor (never on the daemon
|
|
167
|
+
* host) and return the edited result.
|
|
168
|
+
*/
|
|
169
|
+
exports.editMessageSchema = zod_1.z.object({
|
|
170
|
+
type: zod_1.z.literal('edit'),
|
|
171
|
+
editId: zod_1.z.string(),
|
|
172
|
+
content: zod_1.z.string(),
|
|
173
|
+
extension: zod_1.z.string().optional(),
|
|
174
|
+
});
|
|
175
|
+
/** Any message the daemon may send to a surface. */
|
|
176
|
+
exports.serverMessageSchema = zod_1.z.discriminatedUnion('type', [
|
|
177
|
+
exports.attachedMessageSchema,
|
|
178
|
+
exports.resultMessageSchema,
|
|
179
|
+
exports.completeReplySchema,
|
|
180
|
+
exports.outputMessageSchema,
|
|
181
|
+
exports.progressMessageSchema,
|
|
182
|
+
exports.sessionMessageSchema,
|
|
183
|
+
exports.errorMessageSchema,
|
|
184
|
+
exports.promptMessageSchema,
|
|
185
|
+
exports.promptLineMessageSchema,
|
|
186
|
+
exports.pipeMessageSchema,
|
|
187
|
+
exports.editMessageSchema,
|
|
188
|
+
]);
|
|
189
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/protocol/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Boundary validation.
|
|
3
|
+
*
|
|
4
|
+
* Every message is validated on the way in and out. Structural violations
|
|
5
|
+
* (missing required fields, wrong types, an unknown `type`) are rejected;
|
|
6
|
+
* unknown *additional* fields are tolerated (stripped), so a daemon accepts
|
|
7
|
+
* additive extensions from a newer minor without understanding them. Parsing
|
|
8
|
+
* never throws — it returns a {@link ParseResult} so the caller can answer a
|
|
9
|
+
* malformed message with an `error` message rather than dropping the socket.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
import { attachMessageSchema, type ClientMessage, type ServerMessage } from './messages.js';
|
|
15
|
+
/**
|
|
16
|
+
* The outcome of validating a message at the boundary.
|
|
17
|
+
*
|
|
18
|
+
* @property ok - Whether the input was a valid message.
|
|
19
|
+
* @property value - The parsed message, when `ok`.
|
|
20
|
+
* @property error - A human-readable reason, when not `ok`.
|
|
21
|
+
*/
|
|
22
|
+
export interface ParseResult<T> {
|
|
23
|
+
ok: boolean;
|
|
24
|
+
value?: T;
|
|
25
|
+
error?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validates a message a surface sent to the daemon.
|
|
29
|
+
*
|
|
30
|
+
* @param raw - The untrusted input (already JSON-parsed).
|
|
31
|
+
* @returns The parse result.
|
|
32
|
+
*/
|
|
33
|
+
export declare function clientMessage_parse(raw: unknown): ParseResult<ClientMessage>;
|
|
34
|
+
/**
|
|
35
|
+
* Validates a message the daemon sent to a surface.
|
|
36
|
+
*
|
|
37
|
+
* @param raw - The untrusted input (already JSON-parsed).
|
|
38
|
+
* @returns The parse result.
|
|
39
|
+
*/
|
|
40
|
+
export declare function serverMessage_parse(raw: unknown): ParseResult<ServerMessage>;
|
|
41
|
+
/**
|
|
42
|
+
* Parses a JSON string into a client message, rejecting both malformed JSON
|
|
43
|
+
* and structurally invalid messages with a clear reason.
|
|
44
|
+
*
|
|
45
|
+
* @param json - The raw JSON text received on the socket.
|
|
46
|
+
* @returns The parse result.
|
|
47
|
+
*/
|
|
48
|
+
export declare function clientMessage_fromJson(json: string): ParseResult<ClientMessage>;
|
|
49
|
+
/**
|
|
50
|
+
* Validates an attach message and checks its declared contract version
|
|
51
|
+
* against this build. A structurally valid attach on an incompatible major
|
|
52
|
+
* is rejected with a clear reason.
|
|
53
|
+
*
|
|
54
|
+
* @param raw - The untrusted input (already JSON-parsed).
|
|
55
|
+
* @returns The parse result; an incompatible version is a validation failure.
|
|
56
|
+
*/
|
|
57
|
+
export declare function attach_parse(raw: unknown): ParseResult<z.infer<typeof attachMessageSchema>>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clientMessage_parse = clientMessage_parse;
|
|
4
|
+
exports.serverMessage_parse = serverMessage_parse;
|
|
5
|
+
exports.clientMessage_fromJson = clientMessage_fromJson;
|
|
6
|
+
exports.attach_parse = attach_parse;
|
|
7
|
+
const messages_js_1 = require("./messages.js");
|
|
8
|
+
const version_js_1 = require("./version.js");
|
|
9
|
+
/**
|
|
10
|
+
* Formats a Zod error into a compact, single-line boundary reason.
|
|
11
|
+
*
|
|
12
|
+
* @param error - The Zod validation error.
|
|
13
|
+
* @returns A human-readable reason string.
|
|
14
|
+
*/
|
|
15
|
+
function zodError_format(error) {
|
|
16
|
+
return error.issues
|
|
17
|
+
.map((issue) => {
|
|
18
|
+
const path = issue.path.join('.');
|
|
19
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
20
|
+
})
|
|
21
|
+
.join('; ');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Validates a raw value against a schema, never throwing.
|
|
25
|
+
*
|
|
26
|
+
* @param schema - The schema to validate against.
|
|
27
|
+
* @param raw - The untrusted input.
|
|
28
|
+
* @returns The parse result.
|
|
29
|
+
*/
|
|
30
|
+
function schema_parse(schema, raw) {
|
|
31
|
+
const result = schema.safeParse(raw);
|
|
32
|
+
if (result.success) {
|
|
33
|
+
return { ok: true, value: result.data };
|
|
34
|
+
}
|
|
35
|
+
return { ok: false, error: zodError_format(result.error) };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validates a message a surface sent to the daemon.
|
|
39
|
+
*
|
|
40
|
+
* @param raw - The untrusted input (already JSON-parsed).
|
|
41
|
+
* @returns The parse result.
|
|
42
|
+
*/
|
|
43
|
+
function clientMessage_parse(raw) {
|
|
44
|
+
return schema_parse(messages_js_1.clientMessageSchema, raw);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validates a message the daemon sent to a surface.
|
|
48
|
+
*
|
|
49
|
+
* @param raw - The untrusted input (already JSON-parsed).
|
|
50
|
+
* @returns The parse result.
|
|
51
|
+
*/
|
|
52
|
+
function serverMessage_parse(raw) {
|
|
53
|
+
return schema_parse(messages_js_1.serverMessageSchema, raw);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Parses a JSON string into a client message, rejecting both malformed JSON
|
|
57
|
+
* and structurally invalid messages with a clear reason.
|
|
58
|
+
*
|
|
59
|
+
* @param json - The raw JSON text received on the socket.
|
|
60
|
+
* @returns The parse result.
|
|
61
|
+
*/
|
|
62
|
+
function clientMessage_fromJson(json) {
|
|
63
|
+
let parsed;
|
|
64
|
+
try {
|
|
65
|
+
parsed = JSON.parse(json);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
69
|
+
return { ok: false, error: `malformed JSON: ${message}` };
|
|
70
|
+
}
|
|
71
|
+
return clientMessage_parse(parsed);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validates an attach message and checks its declared contract version
|
|
75
|
+
* against this build. A structurally valid attach on an incompatible major
|
|
76
|
+
* is rejected with a clear reason.
|
|
77
|
+
*
|
|
78
|
+
* @param raw - The untrusted input (already JSON-parsed).
|
|
79
|
+
* @returns The parse result; an incompatible version is a validation failure.
|
|
80
|
+
*/
|
|
81
|
+
function attach_parse(raw) {
|
|
82
|
+
const parsed = schema_parse(messages_js_1.attachMessageSchema, raw);
|
|
83
|
+
if (!parsed.ok || parsed.value === undefined) {
|
|
84
|
+
return parsed;
|
|
85
|
+
}
|
|
86
|
+
if (!(0, version_js_1.version_isCompatible)(parsed.value.protocolVersion)) {
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
error: `incompatible contract version ${parsed.value.protocolVersion}`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return parsed;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/protocol/validate.ts"],"names":[],"mappings":";;AAuEA,kDAEC;AAQD,kDAEC;AASD,wDASC;AAUD,oCAYC;AA9GD,+CAMuB;AACvB,6CAAoD;AAepD;;;;;GAKG;AACH,SAAS,eAAe,CAAC,KAAiB;IACxC,OAAO,KAAK,CAAC,MAAM;SAChB,GAAG,CAAC,CAAC,KAAiB,EAAU,EAAE;QACjC,MAAM,IAAI,GAAW,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IAC5D,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CAAI,MAAoB,EAAE,GAAY;IACzD,MAAM,MAAM,GAAsC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACxE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IAC1C,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,GAAY;IAC9C,OAAO,YAAY,CAAC,iCAAmB,EAAE,GAAG,CAAC,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,GAAY;IAC9C,OAAO,YAAY,CAAC,iCAAmB,EAAE,GAAG,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,sBAAsB,CAAC,IAAY;IACjD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAW,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,OAAO,EAAE,EAAE,CAAC;IAC5D,CAAC;IACD,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,YAAY,CAAC,GAAY;IACvC,MAAM,MAAM,GAAqD,YAAY,CAAC,iCAAmB,EAAE,GAAG,CAAC,CAAC;IACxG,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC7C,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,IAAA,iCAAoB,EAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC;QACxD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,iCAAiC,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE;SACvE,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The wire-contract version and its compatibility rule.
|
|
3
|
+
*
|
|
4
|
+
* The contract version is carried by a client in the attach handshake and
|
|
5
|
+
* refused by the daemon on mismatch, with no silent degradation. Per
|
|
6
|
+
* `docs/calypso.adoc`, it tracks the calypso package's major version at
|
|
7
|
+
* release; within a major, changes are additive only (new message types,
|
|
8
|
+
* new optional fields, new model kinds), so a daemon tolerates unknown
|
|
9
|
+
* additions from a newer minor but rejects a different major outright.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* The wire-contract major version this build speaks.
|
|
15
|
+
*/
|
|
16
|
+
export declare const CONTRACT_VERSION: number;
|
|
17
|
+
/**
|
|
18
|
+
* Decides whether a client's declared contract version is compatible with
|
|
19
|
+
* this build. Compatibility is exact-major: a client on a different major is
|
|
20
|
+
* refused, because a major bump removes or re-types something.
|
|
21
|
+
*
|
|
22
|
+
* @param clientVersion - The contract major the client declared at attach.
|
|
23
|
+
* @returns True when the client may attach.
|
|
24
|
+
*/
|
|
25
|
+
export declare function version_isCompatible(clientVersion: number): boolean;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file The wire-contract version and its compatibility rule.
|
|
4
|
+
*
|
|
5
|
+
* The contract version is carried by a client in the attach handshake and
|
|
6
|
+
* refused by the daemon on mismatch, with no silent degradation. Per
|
|
7
|
+
* `docs/calypso.adoc`, it tracks the calypso package's major version at
|
|
8
|
+
* release; within a major, changes are additive only (new message types,
|
|
9
|
+
* new optional fields, new model kinds), so a daemon tolerates unknown
|
|
10
|
+
* additions from a newer minor but rejects a different major outright.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.CONTRACT_VERSION = void 0;
|
|
16
|
+
exports.version_isCompatible = version_isCompatible;
|
|
17
|
+
/**
|
|
18
|
+
* The wire-contract major version this build speaks.
|
|
19
|
+
*/
|
|
20
|
+
exports.CONTRACT_VERSION = 1;
|
|
21
|
+
/**
|
|
22
|
+
* Decides whether a client's declared contract version is compatible with
|
|
23
|
+
* this build. Compatibility is exact-major: a client on a different major is
|
|
24
|
+
* refused, because a major bump removes or re-types something.
|
|
25
|
+
*
|
|
26
|
+
* @param clientVersion - The contract major the client declared at attach.
|
|
27
|
+
* @returns True when the client may attach.
|
|
28
|
+
*/
|
|
29
|
+
function version_isCompatible(clientVersion) {
|
|
30
|
+
return clientVersion === exports.CONTRACT_VERSION;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/protocol/version.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAeH,oDAEC;AAfD;;GAEG;AACU,QAAA,gBAAgB,GAAW,CAAC,CAAC;AAE1C;;;;;;;GAOG;AACH,SAAgB,oBAAoB,CAAC,aAAqB;IACxD,OAAO,aAAa,KAAK,wBAAgB,CAAC;AAC5C,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fnndsc/calypso",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "The CALYPSO wire contract: typed protocol schemas and boundary validation for the ChRIS session daemon",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/FNNDSC/mise.git",
|
|
8
|
+
"directory": "packages/calypso"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/FNNDSC/mise/tree/main/packages/calypso#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/FNNDSC/mise/issues"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"module": "dist/index.js",
|
|
16
|
+
"types": "dist/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"require": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "rm -fr dist && tsc",
|
|
30
|
+
"test": "jest --coverage",
|
|
31
|
+
"prepublishOnly": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"chris",
|
|
35
|
+
"calypso",
|
|
36
|
+
"wire-contract",
|
|
37
|
+
"websocket",
|
|
38
|
+
"fnndsc"
|
|
39
|
+
],
|
|
40
|
+
"author": "Rudolph Pienaar",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/jest": "^30.0.0",
|
|
44
|
+
"@types/node": "^22.0.0",
|
|
45
|
+
"@types/ws": "^8.5.10",
|
|
46
|
+
"jest": "^30.2.0",
|
|
47
|
+
"ts-jest": "^29.4.5",
|
|
48
|
+
"typescript": "^5.0.0"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@fnndsc/cumin": "^3.5.0",
|
|
52
|
+
"ws": "^8.18.0",
|
|
53
|
+
"zod": "^3.23.8"
|
|
54
|
+
}
|
|
55
|
+
}
|