@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.
@@ -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
+ }