@polytric/openws-spec 0.0.1 → 0.0.2

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/dist/index.cjs ADDED
@@ -0,0 +1,1110 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // ../node_modules/.pnpm/rfdc@1.4.1/node_modules/rfdc/index.js
34
+ var require_rfdc = __commonJS({
35
+ "../node_modules/.pnpm/rfdc@1.4.1/node_modules/rfdc/index.js"(exports2, module2) {
36
+ "use strict";
37
+ module2.exports = rfdc;
38
+ function copyBuffer(cur) {
39
+ if (cur instanceof Buffer) {
40
+ return Buffer.from(cur);
41
+ }
42
+ return new cur.constructor(cur.buffer.slice(), cur.byteOffset, cur.length);
43
+ }
44
+ function rfdc(opts) {
45
+ opts = opts || {};
46
+ if (opts.circles) return rfdcCircles(opts);
47
+ const constructorHandlers = /* @__PURE__ */ new Map();
48
+ constructorHandlers.set(Date, (o) => new Date(o));
49
+ constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)));
50
+ constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)));
51
+ if (opts.constructorHandlers) {
52
+ for (const handler2 of opts.constructorHandlers) {
53
+ constructorHandlers.set(handler2[0], handler2[1]);
54
+ }
55
+ }
56
+ let handler = null;
57
+ return opts.proto ? cloneProto : clone;
58
+ function cloneArray(a, fn) {
59
+ const keys = Object.keys(a);
60
+ const a2 = new Array(keys.length);
61
+ for (let i = 0; i < keys.length; i++) {
62
+ const k = keys[i];
63
+ const cur = a[k];
64
+ if (typeof cur !== "object" || cur === null) {
65
+ a2[k] = cur;
66
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
67
+ a2[k] = handler(cur, fn);
68
+ } else if (ArrayBuffer.isView(cur)) {
69
+ a2[k] = copyBuffer(cur);
70
+ } else {
71
+ a2[k] = fn(cur);
72
+ }
73
+ }
74
+ return a2;
75
+ }
76
+ function clone(o) {
77
+ if (typeof o !== "object" || o === null) return o;
78
+ if (Array.isArray(o)) return cloneArray(o, clone);
79
+ if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
80
+ return handler(o, clone);
81
+ }
82
+ const o2 = {};
83
+ for (const k in o) {
84
+ if (Object.hasOwnProperty.call(o, k) === false) continue;
85
+ const cur = o[k];
86
+ if (typeof cur !== "object" || cur === null) {
87
+ o2[k] = cur;
88
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
89
+ o2[k] = handler(cur, clone);
90
+ } else if (ArrayBuffer.isView(cur)) {
91
+ o2[k] = copyBuffer(cur);
92
+ } else {
93
+ o2[k] = clone(cur);
94
+ }
95
+ }
96
+ return o2;
97
+ }
98
+ function cloneProto(o) {
99
+ if (typeof o !== "object" || o === null) return o;
100
+ if (Array.isArray(o)) return cloneArray(o, cloneProto);
101
+ if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
102
+ return handler(o, cloneProto);
103
+ }
104
+ const o2 = {};
105
+ for (const k in o) {
106
+ const cur = o[k];
107
+ if (typeof cur !== "object" || cur === null) {
108
+ o2[k] = cur;
109
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
110
+ o2[k] = handler(cur, cloneProto);
111
+ } else if (ArrayBuffer.isView(cur)) {
112
+ o2[k] = copyBuffer(cur);
113
+ } else {
114
+ o2[k] = cloneProto(cur);
115
+ }
116
+ }
117
+ return o2;
118
+ }
119
+ }
120
+ function rfdcCircles(opts) {
121
+ const refs = [];
122
+ const refsNew = [];
123
+ const constructorHandlers = /* @__PURE__ */ new Map();
124
+ constructorHandlers.set(Date, (o) => new Date(o));
125
+ constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)));
126
+ constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)));
127
+ if (opts.constructorHandlers) {
128
+ for (const handler2 of opts.constructorHandlers) {
129
+ constructorHandlers.set(handler2[0], handler2[1]);
130
+ }
131
+ }
132
+ let handler = null;
133
+ return opts.proto ? cloneProto : clone;
134
+ function cloneArray(a, fn) {
135
+ const keys = Object.keys(a);
136
+ const a2 = new Array(keys.length);
137
+ for (let i = 0; i < keys.length; i++) {
138
+ const k = keys[i];
139
+ const cur = a[k];
140
+ if (typeof cur !== "object" || cur === null) {
141
+ a2[k] = cur;
142
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
143
+ a2[k] = handler(cur, fn);
144
+ } else if (ArrayBuffer.isView(cur)) {
145
+ a2[k] = copyBuffer(cur);
146
+ } else {
147
+ const index = refs.indexOf(cur);
148
+ if (index !== -1) {
149
+ a2[k] = refsNew[index];
150
+ } else {
151
+ a2[k] = fn(cur);
152
+ }
153
+ }
154
+ }
155
+ return a2;
156
+ }
157
+ function clone(o) {
158
+ if (typeof o !== "object" || o === null) return o;
159
+ if (Array.isArray(o)) return cloneArray(o, clone);
160
+ if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
161
+ return handler(o, clone);
162
+ }
163
+ const o2 = {};
164
+ refs.push(o);
165
+ refsNew.push(o2);
166
+ for (const k in o) {
167
+ if (Object.hasOwnProperty.call(o, k) === false) continue;
168
+ const cur = o[k];
169
+ if (typeof cur !== "object" || cur === null) {
170
+ o2[k] = cur;
171
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
172
+ o2[k] = handler(cur, clone);
173
+ } else if (ArrayBuffer.isView(cur)) {
174
+ o2[k] = copyBuffer(cur);
175
+ } else {
176
+ const i = refs.indexOf(cur);
177
+ if (i !== -1) {
178
+ o2[k] = refsNew[i];
179
+ } else {
180
+ o2[k] = clone(cur);
181
+ }
182
+ }
183
+ }
184
+ refs.pop();
185
+ refsNew.pop();
186
+ return o2;
187
+ }
188
+ function cloneProto(o) {
189
+ if (typeof o !== "object" || o === null) return o;
190
+ if (Array.isArray(o)) return cloneArray(o, cloneProto);
191
+ if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
192
+ return handler(o, cloneProto);
193
+ }
194
+ const o2 = {};
195
+ refs.push(o);
196
+ refsNew.push(o2);
197
+ for (const k in o) {
198
+ const cur = o[k];
199
+ if (typeof cur !== "object" || cur === null) {
200
+ o2[k] = cur;
201
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
202
+ o2[k] = handler(cur, cloneProto);
203
+ } else if (ArrayBuffer.isView(cur)) {
204
+ o2[k] = copyBuffer(cur);
205
+ } else {
206
+ const i = refs.indexOf(cur);
207
+ if (i !== -1) {
208
+ o2[k] = refsNew[i];
209
+ } else {
210
+ o2[k] = cloneProto(cur);
211
+ }
212
+ }
213
+ }
214
+ refs.pop();
215
+ refsNew.pop();
216
+ return o2;
217
+ }
218
+ }
219
+ }
220
+ });
221
+
222
+ // ../node_modules/.pnpm/@pocketgems+schema@0.1.3/node_modules/@pocketgems/schema/src/schema.js
223
+ var require_schema = __commonJS({
224
+ "../node_modules/.pnpm/@pocketgems+schema@0.1.3/node_modules/@pocketgems/schema/src/schema.js"(exports2, module2) {
225
+ "use strict";
226
+ var assert = require("assert");
227
+ var ajv;
228
+ var deepcopy = require_rfdc()();
229
+ var ValidationError = class extends Error {
230
+ /**
231
+ * @param {string} name a user-provided name describing the schema
232
+ * @param {*} badValue the value which did not validate
233
+ * @param {Object} errors how badValue failed to conform to the schema
234
+ * @param {Object} expectedSchema The JSON schema used in schema validation
235
+ */
236
+ constructor(name, badValue, errors, expectedSchema) {
237
+ super(`Validation Error: ${name}`);
238
+ this.badValue = badValue;
239
+ this.validationErrors = errors;
240
+ this.expectedSchema = expectedSchema;
241
+ if (["localhost", "webpack"].includes(process.env.NODE_ENV)) {
242
+ console.error(JSON.stringify(errors, null, 2));
243
+ }
244
+ }
245
+ };
246
+ var INT32_MAX = Math.pow(2, 31) - 1;
247
+ var INT32_MIN = -Math.pow(2, 31);
248
+ var TIMESTAMP_MIN = "2000-01-01T00:00:00Z";
249
+ var TIMESTAMP_MAX = "9999-01-01T00:00:00Z";
250
+ var EPOCH_IN_MILLISECONDS_MIN = new Date(TIMESTAMP_MIN).getTime();
251
+ var EPOCH_IN_MILLISECONDS_MAX = new Date(TIMESTAMP_MAX).getTime();
252
+ var EPOCH_IN_SECONDS_MIN = EPOCH_IN_MILLISECONDS_MIN / 1e3;
253
+ var EPOCH_IN_SECONDS_MAX = EPOCH_IN_MILLISECONDS_MAX / 1e3;
254
+ var INT64_MAX = Math.pow(2, 62);
255
+ var INT64_MIN = -Math.pow(2, 62);
256
+ var BaseSchema = class {
257
+ /**
258
+ * The json schema type
259
+ */
260
+ static JSON_SCHEMA_TYPE;
261
+ /**
262
+ * The max* property name.
263
+ */
264
+ static MAX_PROP_NAME;
265
+ /**
266
+ * The min* property name.
267
+ */
268
+ static MIN_PROP_NAME;
269
+ /**
270
+ * Constructs a schema object
271
+ */
272
+ constructor() {
273
+ this.isTodeaSchema = true;
274
+ this.isFluentSchema = true;
275
+ this.__properties = {};
276
+ this.__isLocked = false;
277
+ this.__isOptional = false;
278
+ this.__setProp("type", this.constructor.JSON_SCHEMA_TYPE);
279
+ }
280
+ /**
281
+ * Locks a Todea Schema object from modifications.
282
+ */
283
+ lock() {
284
+ this.__isLocked = true;
285
+ return this;
286
+ }
287
+ /**
288
+ * Sets a value in __properties. Throws if object is locked (unless the
289
+ * property is allowed to be overridden), or property with
290
+ * the same name already exists and override is not allowed.
291
+ * @param {String} name Name of the property
292
+ * @param {*} val The value for the property
293
+ * @param {Object} [options={}]
294
+ * @param {Boolean} [options.allowOverride=false] If true property override
295
+ * is allowed.
296
+ */
297
+ __setProp(name, val, { allowOverride = false } = {}) {
298
+ assert.ok(
299
+ !this.__isLocked || allowOverride,
300
+ "Schema is locked. Call copy then further modify the schema"
301
+ );
302
+ assert.ok(
303
+ allowOverride || !Object.prototype.hasOwnProperty.call(this.__properties, name),
304
+ `Property ${name} is already set.`
305
+ );
306
+ const shouldCopy = this.__isLocked || allowOverride && Object.prototype.hasOwnProperty.call(this.__properties, name);
307
+ const ret = shouldCopy ? this.copy() : this;
308
+ ret.__properties[name] = val;
309
+ if (this.__isLocked) {
310
+ ret.lock();
311
+ }
312
+ return ret;
313
+ }
314
+ /**
315
+ * @param {String} name Name of a property
316
+ * @return The value associated with name.
317
+ */
318
+ getProp(name) {
319
+ return this.__properties[name];
320
+ }
321
+ /**
322
+ * If property with name does not exist, the default value is set.
323
+ * @param {String} name
324
+ * @param {*} defaultValue
325
+ * @return The value associated with name.
326
+ */
327
+ __setDefaultProp(name, defaultValue) {
328
+ if (!Object.prototype.hasOwnProperty.call(this.__properties, name)) {
329
+ this.__setProp(name, defaultValue);
330
+ }
331
+ return this.getProp(name);
332
+ }
333
+ /**
334
+ * Sets a title.
335
+ * @param {String} t The title of the schema.
336
+ */
337
+ title(t) {
338
+ assert.ok(typeof t === "string", "Title must be a string.");
339
+ return this.__setProp("title", t, { allowOverride: true });
340
+ }
341
+ /**
342
+ * Sets a description.
343
+ * @param {String|Array<String>} t The description of the schema. If an array
344
+ * of strings are passed in, they will be joined by a space to form the
345
+ * description.
346
+ */
347
+ desc(d) {
348
+ assert.ok(typeof d === "string", "Description must be a string.");
349
+ d = d.trim().replace(/\n/g, " ");
350
+ return this.__setProp("description", d, { allowOverride: true });
351
+ }
352
+ /**
353
+ * Sets a default value for schema.
354
+ *
355
+ * According to JsonSchema, default value is just metadata and does not
356
+ * serve any validation purpose with in JsonSchema. External tools may
357
+ * choose to use this value to setup defaults, and implementations of
358
+ * JsonSchema validator may choose to validate the type of default values,
359
+ * but it's not required. Since when the default is used to populate the
360
+ * json, there will be something downstream that validates the json and
361
+ * catches issues, we omit schema validation for simplicity.
362
+ *
363
+ * @param {*} d The default value.
364
+ */
365
+ default(d) {
366
+ assert(d !== void 0, "Default value must be defined");
367
+ Object.freeze(d);
368
+ return this.__setProp("default", d);
369
+ }
370
+ getDefault() {
371
+ return this.properties().default;
372
+ }
373
+ hasDefault() {
374
+ return Object.prototype.hasOwnProperty.call(this.properties(), "default");
375
+ }
376
+ /**
377
+ * Marks a schema as optional. Schemas are required by default.
378
+ */
379
+ optional() {
380
+ assert(!this.__isLocked, "Schema is locked.");
381
+ this.__isOptional = true;
382
+ return this;
383
+ }
384
+ /**
385
+ * Convenient getter indicates if the schema is required / not optional.
386
+ * See {@link optional}.
387
+ */
388
+ get required() {
389
+ return !this.__isOptional;
390
+ }
391
+ /**
392
+ * Sets schemas readOnly property.
393
+ * @param {Boolean} [r=true] If the schema value should be readOnly.
394
+ */
395
+ readOnly(r = true) {
396
+ return this.__setProp("readOnly", r);
397
+ }
398
+ /**
399
+ * Updates schemas examples.
400
+ * @param {Array<String|Array<String>>} es A list of examples. Each example
401
+ * may be a string, or a list of strings. In case of a list of strings, the
402
+ * strings will be joined by a space character and used as one example.
403
+ */
404
+ examples(es) {
405
+ assert.ok(Array.isArray(es), "Examples must be an array");
406
+ es = es.map((e) => {
407
+ return Array.isArray(e) ? e.join(" ") : e;
408
+ });
409
+ return this.__setProp("examples", es, { allowOverride: true });
410
+ }
411
+ /**
412
+ * Returns a JSON Schema. It exists for compatibility with fluent-schema.
413
+ */
414
+ valueOf() {
415
+ return this.jsonSchema();
416
+ }
417
+ /**
418
+ * The visitable in a visitor pattern. Used for exporting schema.
419
+ * @param {Exporter} visitor a schema exporter. @see JSONSchemaExporter
420
+ */
421
+ // istanbul ignore next
422
+ export(visitor) {
423
+ throw new Error("Subclass must override");
424
+ }
425
+ properties() {
426
+ return this.__properties;
427
+ }
428
+ /**
429
+ * @return JSON Schema with the schema version keyword at the root level.
430
+ */
431
+ jsonSchema() {
432
+ const exporter = new JSONSchemaExporter();
433
+ return exporter.export(this);
434
+ }
435
+ /**
436
+ * Returns a validator function which throws ValidationError if the value it
437
+ * is asked to validate does not match the schema.
438
+ *
439
+ * Locks the current schema.
440
+ *
441
+ * @param {string} name the name of this schema (to distinguish errors)
442
+ * @param {*} [compiler] the ajv or equivalent JSON schema compiler to use
443
+ * @param {returnSchemaToo} [returnSchemaToo] whether to return jsonSchema as
444
+ * well as the validator
445
+ * @returns {Function} call on a value to validate it; throws on error
446
+ */
447
+ compile(name, compiler, returnSchemaToo) {
448
+ assert.ok(name, "name is required");
449
+ if (!compiler) {
450
+ if (!ajv) {
451
+ ajv = new (require("ajv"))({
452
+ allErrors: true,
453
+ useDefaults: true,
454
+ strictSchema: false
455
+ });
456
+ }
457
+ compiler = ajv;
458
+ }
459
+ this.lock();
460
+ const jsonSchema = this.jsonSchema();
461
+ const validate2 = compiler.compile(jsonSchema);
462
+ const assertValid = (v) => {
463
+ if (!validate2(v)) {
464
+ throw new ValidationError(name, v, validate2.errors, jsonSchema);
465
+ }
466
+ };
467
+ if (returnSchemaToo) {
468
+ return { jsonSchema, assertValid };
469
+ }
470
+ return assertValid;
471
+ }
472
+ /**
473
+ * See {@link compile}.
474
+ * @returns {Object} contains jsonSchema and assertValid
475
+ */
476
+ getValidatorAndJSONSchema(name, compiler) {
477
+ return this.compile(name, compiler, true);
478
+ }
479
+ /**
480
+ * @return A copy of the Todea Schema object. Locked objects become unlocked.
481
+ *
482
+ */
483
+ copy() {
484
+ const ret = new this.constructor();
485
+ ret.__properties = deepcopy(this.__properties);
486
+ ret.__isOptional = this.__isOptional;
487
+ return ret;
488
+ }
489
+ // max / min support
490
+ /**
491
+ * Validate input to min/max.
492
+ * @param {String} name Property name
493
+ * @param {Integer} val A non-negative integer for min/max.
494
+ */
495
+ __validateRangeProperty(name, val) {
496
+ assert.ok(Number.isInteger(val), `${name} must be an integer`);
497
+ assert.ok(val >= 0, `${name} must be a non-negative number`);
498
+ }
499
+ /**
500
+ * Set a min property depending on schema type.
501
+ * @param {Integer} val A non-negative integer for min/max.
502
+ */
503
+ min(val) {
504
+ const name = this.constructor.MIN_PROP_NAME;
505
+ this.__validateRangeProperty(name, val);
506
+ const max = this.getProp(this.constructor.MAX_PROP_NAME);
507
+ assert.ok(max === void 0 || max >= val, "min must be less than max");
508
+ return this.__setProp(name, val);
509
+ }
510
+ /**
511
+ * Set a max property depending on schema type.
512
+ * @param {Integer} val A non-negative integer for min/max.
513
+ */
514
+ max(val) {
515
+ const name = this.constructor.MAX_PROP_NAME;
516
+ this.__validateRangeProperty(name, val);
517
+ const min = this.getProp(this.constructor.MIN_PROP_NAME);
518
+ assert.ok(min === void 0 || min <= val, "max must be more than min");
519
+ return this.__setProp(name, val);
520
+ }
521
+ };
522
+ var ObjectSchema = class extends BaseSchema {
523
+ static JSON_SCHEMA_TYPE = "object";
524
+ static MAX_PROP_NAME = "maxProperties";
525
+ static MIN_PROP_NAME = "minProperties";
526
+ /**
527
+ * Creates an object schema object.
528
+ * @param {Object} [props={}] Keys must be strings, values must be schema
529
+ * objects. Passing props is the same as calling S.obj().props(props).
530
+ */
531
+ constructor(props = {}) {
532
+ super();
533
+ this.objectSchemas = {};
534
+ this.patternSchemas = {};
535
+ this.props(props);
536
+ }
537
+ /**
538
+ * Set an object schema's object property.
539
+ * @param {String} name The name of the property.
540
+ * @param {BaseSchema} schema Any subclass of BaseSchema. Schema gets locked.
541
+ */
542
+ prop(name, schema) {
543
+ assert.ok(
544
+ !this.__isLocked,
545
+ "Schema is locked. Call copy then further modify the schema"
546
+ );
547
+ assert.ok(typeof name === "string", "Property name must be strings.");
548
+ const properties = this.__setDefaultProp("properties", {});
549
+ assert.ok(
550
+ !Object.prototype.hasOwnProperty.call(properties, name),
551
+ `Property with key ${name} already exists`
552
+ );
553
+ assert.ok(schema !== void 0, `Property ${name} must define a schema`);
554
+ this.objectSchemas[name] = schema.lock();
555
+ properties[name] = schema.properties();
556
+ if (schema.required) {
557
+ this.__setDefaultProp("required", []).push(name);
558
+ }
559
+ return this;
560
+ }
561
+ /**
562
+ * A mapping of property names to schemas. Calls this.prop() in a loop.
563
+ * @param {Object} props Keys must be strings, values must be schema
564
+ * objects.
565
+ */
566
+ props(props) {
567
+ for (const [name, p] of Object.entries(props)) {
568
+ this.prop(name, p);
569
+ }
570
+ return this;
571
+ }
572
+ /**
573
+ * A mapping of propertyProperties to schemas.
574
+ * @param {Object} props Keys must be regex, values must be schema
575
+ */
576
+ patternProps(props) {
577
+ for (const [name, schema] of Object.entries(props)) {
578
+ const properties = this.__setDefaultProp("patternProperties", {});
579
+ assert.ok(
580
+ !Object.prototype.hasOwnProperty.call(properties, name),
581
+ `Pattern ${name} already exists`
582
+ );
583
+ const anchoredName = getAnchoredPattern(name);
584
+ this.patternSchemas[anchoredName] = schema.lock();
585
+ properties[anchoredName] = schema.properties();
586
+ }
587
+ return this;
588
+ }
589
+ copy() {
590
+ const ret = super.copy();
591
+ Object.assign(ret.objectSchemas, this.objectSchemas);
592
+ Object.assign(ret.patternSchemas, this.patternSchemas);
593
+ return ret;
594
+ }
595
+ properties() {
596
+ const ret = super.properties();
597
+ const hasProperty = Object.keys(this.objectSchemas).length > 0 || Object.keys(this.patternSchemas).length > 0;
598
+ const hasAdditionalProperties = !!this.additionalProperties;
599
+ ret.additionalProperties = !hasProperty || hasAdditionalProperties;
600
+ return ret;
601
+ }
602
+ export(visitor) {
603
+ return visitor.exportObject(this);
604
+ }
605
+ };
606
+ var ArraySchema = class extends BaseSchema {
607
+ static JSON_SCHEMA_TYPE = "array";
608
+ static MAX_PROP_NAME = "maxItems";
609
+ static MIN_PROP_NAME = "minItems";
610
+ /**
611
+ * Creates an array schema object.
612
+ * @param {BaseSchema} [items] An optional parameter to items(). If provided,
613
+ * it is the same as calling S.arr().items(items).
614
+ */
615
+ constructor(items) {
616
+ super();
617
+ this.itemsSchema = void 0;
618
+ if (items) {
619
+ this.items(items);
620
+ }
621
+ }
622
+ /**
623
+ * Set the schema for items in array
624
+ * @param {BaseSchema} items Any subclass of BaseSchema. Schema gets locked.
625
+ */
626
+ items(items) {
627
+ assert.ok(!this.itemsSchema, "Items is already set.");
628
+ this.itemsSchema = items.lock();
629
+ this.__setProp("items", items.properties());
630
+ return this;
631
+ }
632
+ copy() {
633
+ const ret = super.copy();
634
+ ret.itemsSchema = this.itemsSchema;
635
+ return ret;
636
+ }
637
+ export(visitor) {
638
+ return visitor.exportArray(this);
639
+ }
640
+ };
641
+ var NumberSchema = class extends BaseSchema {
642
+ static JSON_SCHEMA_TYPE = "number";
643
+ static MAX_PROP_NAME = "maximum";
644
+ static MIN_PROP_NAME = "minimum";
645
+ constructor() {
646
+ super();
647
+ this.__isFloat = false;
648
+ }
649
+ /**
650
+ * Validate input to min/max.
651
+ * @param {String} name Property name
652
+ * @param {Integer} val A finite number for min/max.
653
+ */
654
+ __validateRangeProperty(name, val) {
655
+ assert.ok(Number.isFinite(val), `${name} must be a number`);
656
+ }
657
+ asFloat() {
658
+ assert(!this.__isLocked, "Schema is locked");
659
+ this.__isFloat = true;
660
+ return this;
661
+ }
662
+ get isFloat() {
663
+ return this.__isFloat;
664
+ }
665
+ export(visitor) {
666
+ return visitor.exportNumber(this);
667
+ }
668
+ copy() {
669
+ const ret = super.copy();
670
+ ret.__isFloat = this.__isFloat;
671
+ return ret;
672
+ }
673
+ };
674
+ var IntegerSchema = class extends NumberSchema {
675
+ static JSON_SCHEMA_TYPE = "integer";
676
+ /**
677
+ * Validate input to min/max.
678
+ * @param {String} name Property name
679
+ * @param {Integer} val An integer for min/max.
680
+ */
681
+ __validateRangeProperty(name, val) {
682
+ assert.ok(Number.isInteger(val), `${name} must be an integer`);
683
+ }
684
+ /**
685
+ * sets limit on how large max or min can be.
686
+ * Validates current min/max to ensure they work correctly
687
+ */
688
+ __setSafeRangeLimit(val) {
689
+ const max = this.getProp(this.constructor.MAX_PROP_NAME);
690
+ if (max === void 0) {
691
+ this.max(val);
692
+ } else {
693
+ assert.ok(max <= val, `max cannot exceed ${val}`);
694
+ }
695
+ const min = this.getProp(this.constructor.MIN_PROP_NAME);
696
+ if (min === void 0) {
697
+ this.min(-val);
698
+ } else {
699
+ assert.ok(min >= -val, `min must be larger than ${-val}`);
700
+ }
701
+ return this;
702
+ }
703
+ /**
704
+ * applies range for Int32 values
705
+ */
706
+ asInt32() {
707
+ return this.__setSafeRangeLimit(INT32_MAX);
708
+ }
709
+ /**
710
+ * applies range for int64 values
711
+ */
712
+ asInt64() {
713
+ return this.__setSafeRangeLimit(INT64_MAX);
714
+ }
715
+ asFloat = void 0;
716
+ export(visitor) {
717
+ return visitor.exportInteger(this);
718
+ }
719
+ };
720
+ var StringSchema = class extends BaseSchema {
721
+ static JSON_SCHEMA_TYPE = "string";
722
+ static MAX_PROP_NAME = "maxLength";
723
+ static MIN_PROP_NAME = "minLength";
724
+ /**
725
+ * Set valid values for the string schema.
726
+ * @param {Array<String>} validValues Valid values for the string. There must
727
+ * be at least 2 valid values.
728
+ */
729
+ enum(validValues) {
730
+ const values = Array.isArray(validValues) ? validValues : [...arguments];
731
+ assert(values.length >= 1, "Enum must contain at least 1 value.");
732
+ return this.__setProp("enum", values);
733
+ }
734
+ /**
735
+ * A pattern for the string.
736
+ * @param {String|RegExp} pattern The pattern for the string. Can be a string
737
+ * with regex syntax, or a RegExp object.
738
+ */
739
+ pattern(pattern) {
740
+ if (pattern instanceof RegExp) {
741
+ pattern = pattern.source;
742
+ }
743
+ assert(typeof pattern === "string", "Pattern must be a string");
744
+ const anchoredPattern = getAnchoredPattern(pattern);
745
+ return this.__setProp("pattern", anchoredPattern);
746
+ }
747
+ export(visitor) {
748
+ return visitor.exportString(this);
749
+ }
750
+ };
751
+ var BooleanSchema = class extends BaseSchema {
752
+ static JSON_SCHEMA_TYPE = "boolean";
753
+ export(visitor) {
754
+ return visitor.exportBoolean(this);
755
+ }
756
+ };
757
+ var MapSchema = class extends ObjectSchema {
758
+ constructor() {
759
+ super();
760
+ this.prop = void 0;
761
+ this.props = void 0;
762
+ this.patternProps = void 0;
763
+ this.finalized = false;
764
+ this.keySchema = void 0;
765
+ this.valueSchema = void 0;
766
+ }
767
+ /**
768
+ * Set a key pattern for the map.
769
+ * @param {String} keyPattern A pattern for keys
770
+ */
771
+ keyPattern(pattern) {
772
+ assert(!this.keySchema, "key pattern already set");
773
+ this.keySchema = S2.str.pattern(pattern).lock();
774
+ this.__tryFinalizeSchema();
775
+ return this;
776
+ }
777
+ /**
778
+ * Set a value schema for the map.
779
+ * @param {BaseSchema} value Any subclass of BaseSchema for the values of map
780
+ */
781
+ value(value) {
782
+ assert(!this.valueSchema, "value schema already set");
783
+ assert(value.required, "value must be required");
784
+ this.valueSchema = value.lock();
785
+ this.__tryFinalizeSchema();
786
+ return this;
787
+ }
788
+ lock() {
789
+ this.__finalizeSchema();
790
+ return super.lock();
791
+ }
792
+ __finalizeSchema() {
793
+ assert(this.valueSchema, "Must have a value schema");
794
+ if (!this.keySchema) {
795
+ this.keySchema = S2.str;
796
+ }
797
+ this.__tryFinalizeSchema();
798
+ }
799
+ __tryFinalizeSchema() {
800
+ if (this.keySchema && this.valueSchema && !this.finalized) {
801
+ this.finalized = true;
802
+ super.patternProps({
803
+ [this.keySchema?.getProp("pattern") ?? ".*"]: this.valueSchema
804
+ });
805
+ }
806
+ }
807
+ export(visitor) {
808
+ this.__finalizeSchema();
809
+ return visitor.exportMap(this);
810
+ }
811
+ copy() {
812
+ const ret = super.copy();
813
+ ret.finalized = this.finalized;
814
+ ret.keySchema = this.keySchema.copy();
815
+ ret.valueSchema = this.valueSchema.copy();
816
+ return ret;
817
+ }
818
+ };
819
+ var MediaSchema = class extends StringSchema {
820
+ type(t) {
821
+ this.__setProp("contentMediaType", t);
822
+ return this;
823
+ }
824
+ encoding(e) {
825
+ assert(
826
+ ["binary", "base64", "utf-8"].includes(e),
827
+ "Encoding must be binary, base64 or utf-8"
828
+ );
829
+ this.__setProp("contentEncoding", e);
830
+ return this;
831
+ }
832
+ export(visitor) {
833
+ return visitor.exportMedia(this);
834
+ }
835
+ };
836
+ var JSONSchemaExporter = class {
837
+ constructor() {
838
+ const methods = [
839
+ "exportString",
840
+ "exportInteger",
841
+ "exportNumber",
842
+ "exportObject",
843
+ "exportArray",
844
+ "exportBoolean",
845
+ "exportMap",
846
+ "exportMedia"
847
+ ];
848
+ for (const method of methods) {
849
+ Object.defineProperty(this, method, {
850
+ get: () => {
851
+ return (schema) => {
852
+ return schema.properties();
853
+ };
854
+ }
855
+ });
856
+ }
857
+ }
858
+ export(schema) {
859
+ const ret = deepcopy(schema.export(this));
860
+ ret.$schema = "http://json-schema.org/draft-07/schema#";
861
+ return ret;
862
+ }
863
+ };
864
+ var S2 = class _S {
865
+ /**
866
+ * @param {Object} object See {@link ObjectSchema#constructor}
867
+ * @return A new ObjectSchema object.
868
+ */
869
+ static obj(object) {
870
+ return new ObjectSchema(object);
871
+ }
872
+ /**
873
+ * @param {BaseSchema} schema See {@link ArraySchema#constructor}
874
+ * @return A new ArraySchema object.
875
+ */
876
+ static arr(schema) {
877
+ return new ArraySchema(schema);
878
+ }
879
+ /**
880
+ * Get a new NumberSchema object.
881
+ */
882
+ static get double() {
883
+ return new NumberSchema();
884
+ }
885
+ /**
886
+ * Get a new IntegerSchema object.
887
+ */
888
+ static get int() {
889
+ return new IntegerSchema();
890
+ }
891
+ /**
892
+ * Get a new StringSchema object.
893
+ */
894
+ static get str() {
895
+ return new StringSchema();
896
+ }
897
+ /**
898
+ * Get a new BooleanSchema object.
899
+ */
900
+ static get bool() {
901
+ return new BooleanSchema();
902
+ }
903
+ /**
904
+ * Get a new MapSchema object.
905
+ */
906
+ static get map() {
907
+ return new MapSchema();
908
+ }
909
+ /**
910
+ * Get a new MediaSchema object.
911
+ */
912
+ static get media() {
913
+ return new MediaSchema();
914
+ }
915
+ /**
916
+ * Lock all schemas in a dictionary (in-place).
917
+ * @param {Object<Schema>} schemas a map of schema values
918
+ * @returns the input map of schema values
919
+ */
920
+ static lock(schemas) {
921
+ Object.values(schemas).forEach((x) => x.lock());
922
+ return schemas;
923
+ }
924
+ /**
925
+ * Sets all schemas as optional (in-place).
926
+ * @param {Object<Schema>} schemas a map of schema values
927
+ * @returns the input map of schema values
928
+ */
929
+ static optional(schemas) {
930
+ Object.values(schemas).forEach((x) => x.optional());
931
+ return schemas;
932
+ }
933
+ static PATTERN = {
934
+ UUID_PATTERN: /^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/
935
+ };
936
+ /**
937
+ * Common schemas.
938
+ */
939
+ static SCHEMAS = _S.lock({
940
+ UUID: _S.str.desc("An UUID. It is normally generated by calling uuidv4().").pattern(_S.PATTERN.UUID_PATTERN),
941
+ STR_ANDU: _S.str.desc("Only hyphens, underscores, letters and numbers are permitted.").pattern(/^[-_a-zA-Z0-9]+$/),
942
+ // oversimplified, quick regex to check that a string looks like an email
943
+ STR_EMAIL: _S.str.pattern(/^[^A-Z ]+@.+$/).desc("an e-mail address (lowercase only)").lock(),
944
+ TIMESTAMP: _S.str.pattern(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d{3}Z/).desc(`An UTC timestamp with millisecond precision, for example,
945
+ 2021-02-15T20:15:59.321Z`),
946
+ TIMESTAMP_WITH_TZ: _S.str.pattern(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(\.\d*)?([+-][0-2]\d:[0-5]\d|Z)/).desc(`Timestamp with time zone and optional millisecond precision,
947
+ for example,
948
+ 2021-02-15T20:15:59Z,
949
+ 2022-09-15T16:48:28.9097226Z,
950
+ 2021-02-15T11:55:20-05:00,
951
+ 2021-02-15T11:55:20.9097226+08:00`),
952
+ EPOCH_IN_SECONDS: _S.int.min(EPOCH_IN_SECONDS_MIN).max(EPOCH_IN_SECONDS_MAX).desc(`Unix epoch time format in seconds from
953
+ ${TIMESTAMP_MIN} to ${TIMESTAMP_MAX}.`),
954
+ EPOCH_IN_MILLISECONDS: _S.int.min(EPOCH_IN_MILLISECONDS_MIN).max(EPOCH_IN_MILLISECONDS_MAX).desc(`Unix epoch time format in
955
+ milliseconds from ${TIMESTAMP_MIN} to ${TIMESTAMP_MAX}.`).asInt64()
956
+ });
957
+ /** Thrown if validation fails. */
958
+ static ValidationError = ValidationError;
959
+ static INT32_MAX = INT32_MAX;
960
+ static INT32_MIN = INT32_MIN;
961
+ static INT64_MAX = INT64_MAX;
962
+ static INT64_MIN = INT64_MIN;
963
+ };
964
+ function getAnchoredPattern(pattern) {
965
+ let anchoredName = pattern;
966
+ if (pattern[0] !== "^") {
967
+ anchoredName = "^" + pattern;
968
+ }
969
+ if (pattern[pattern.length - 1] !== "$") {
970
+ anchoredName += "$";
971
+ }
972
+ return anchoredName;
973
+ }
974
+ module2.exports = S2;
975
+ }
976
+ });
977
+
978
+ // src/index.ts
979
+ var index_exports = {};
980
+ __export(index_exports, {
981
+ VERSION: () => VERSION,
982
+ specSchema: () => spec_schema_default2,
983
+ validate: () => validate
984
+ });
985
+ module.exports = __toCommonJS(index_exports);
986
+
987
+ // package.json
988
+ var package_default = {
989
+ name: "@polytric/openws-spec",
990
+ version: "0.0.2",
991
+ description: "Polytric OpenWS Specification",
992
+ type: "module",
993
+ main: "./dist/index.js",
994
+ types: "./dist/index.d.ts",
995
+ exports: {
996
+ ".": {
997
+ types: "./dist/index.d.ts",
998
+ import: "./dist/index.js",
999
+ require: "./dist/index.cjs"
1000
+ },
1001
+ "./builder": {
1002
+ types: "./dist/builder.d.ts",
1003
+ import: "./dist/builder.js",
1004
+ require: "./dist/builder.cjs"
1005
+ },
1006
+ "./types": {
1007
+ types: "./dist/types.d.ts",
1008
+ import: "./dist/types.js",
1009
+ require: "./dist/types.cjs"
1010
+ }
1011
+ },
1012
+ files: [
1013
+ "dist",
1014
+ "LICENSE",
1015
+ "README.md"
1016
+ ],
1017
+ keywords: [
1018
+ "openws",
1019
+ "specification",
1020
+ "websocket"
1021
+ ],
1022
+ author: "Polytric",
1023
+ license: "Apache-2.0",
1024
+ scripts: {
1025
+ build: "pnpm emit && tsup",
1026
+ emit: `tsx -e "import schema from './src/spec-schema.ts'; console.log(JSON.stringify(schema.jsonSchema()))" > ./src/spec-schema.json`,
1027
+ prepublishOnly: "pnpm build",
1028
+ "test:builder": "nodemon -w dist -w test/builder.cjs test/builder.cjs",
1029
+ "test:validate": "tsx test/validate-spec.ts",
1030
+ typecheck: "tsc --noEmit"
1031
+ },
1032
+ dependencies: {
1033
+ ajv: "^8.17.1"
1034
+ },
1035
+ devDependencies: {
1036
+ "@pocketgems/schema": "^0.1.3",
1037
+ nodemon: "^3.1.11",
1038
+ tsup: "^8.5.1",
1039
+ tsx: "^4.21.0",
1040
+ typescript: "^5.9.3"
1041
+ },
1042
+ packageManager: "pnpm@10.26.1",
1043
+ publishConfig: {
1044
+ access: "public"
1045
+ }
1046
+ };
1047
+
1048
+ // src/spec-schema.ts
1049
+ var import_schema = __toESM(require_schema(), 1);
1050
+ var keyPattern = "[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])?";
1051
+ var messageSchema = import_schema.default.obj({
1052
+ payload: import_schema.default.obj({}).desc(
1053
+ "Must be a valid JSON schema spec. For brevity, openws omits this spec, but implementations should valid this"
1054
+ ),
1055
+ description: import_schema.default.str.optional(),
1056
+ from: import_schema.default.arr(import_schema.default.str).desc("A list of roles that can send this message").optional()
1057
+ });
1058
+ messageSchema.additionalProperties = true;
1059
+ var endpointSchema = import_schema.default.obj({
1060
+ host: import_schema.default.str,
1061
+ port: import_schema.default.int.min(1).max(65535),
1062
+ path: import_schema.default.str
1063
+ });
1064
+ endpointSchema.additionalProperties = true;
1065
+ var roleSchema = import_schema.default.obj({
1066
+ endpoints: import_schema.default.arr(endpointSchema).min(1).optional().desc(
1067
+ "A role can declare an endpoint to accept connections from other roles, normally used by servers"
1068
+ ),
1069
+ messages: import_schema.default.map.keyPattern(keyPattern).value(messageSchema).desc(
1070
+ "A message accepted by the role and handled by the role, and roles can send messages other roles accepts. The OpenWS spec only defines the shape of the payload, and how things get encoded / decoded on the wire, it doesn't determine behavior (through through description the behavior can be documented)."
1071
+ ),
1072
+ description: import_schema.default.str.optional()
1073
+ });
1074
+ roleSchema.additionalProperties = true;
1075
+ var networkSchema = import_schema.default.obj({
1076
+ roles: import_schema.default.map.min(1).keyPattern(keyPattern).desc(
1077
+ "A network is a collection of roles that exchange messages. Multiple roles can coexist in the same network. The simplest network contains a server-client pair."
1078
+ ).value(roleSchema),
1079
+ description: import_schema.default.str.optional()
1080
+ });
1081
+ networkSchema.additionalProperties = true;
1082
+ var openWsSchema = import_schema.default.obj({
1083
+ openws: import_schema.default.str.enum("0.0.1", "0.0.2").desc("The OpenWS schema version"),
1084
+ title: import_schema.default.str.desc("A title for the overall system.").optional(),
1085
+ description: import_schema.default.str.desc(
1086
+ "A high level description of the overall system, including all networks and all roles"
1087
+ ).optional(),
1088
+ version: import_schema.default.str.desc("A version string").optional(),
1089
+ networks: import_schema.default.map.min(1).keyPattern(keyPattern).value(networkSchema)
1090
+ });
1091
+ openWsSchema.additionalProperties = true;
1092
+ var spec_schema_default = openWsSchema;
1093
+
1094
+ // src/spec-schema.json
1095
+ var spec_schema_default2 = { type: "object", properties: { openws: { type: "string", enum: ["0.0.1", "0.0.2"], description: "The OpenWS schema version" }, title: { type: "string", description: "A title for the overall system." }, description: { type: "string", description: "A high level description of the overall system, including all networks and all roles" }, version: { type: "string", description: "A version string" }, networks: { type: "object", minProperties: 1, patternProperties: { "^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])?$": { type: "object", properties: { roles: { type: "object", minProperties: 1, description: "A network is a collection of roles that exchange messages. Multiple roles can coexist in the same network. The simplest network contains a server-client pair.", patternProperties: { "^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])?$": { type: "object", properties: { endpoints: { type: "array", items: { type: "object", properties: { host: { type: "string" }, port: { type: "integer", minimum: 1, maximum: 65535 }, path: { type: "string" } }, required: ["host", "port", "path"], additionalProperties: true }, minItems: 1, description: "A role can declare an endpoint to accept connections from other roles, normally used by servers" }, messages: { type: "object", patternProperties: { "^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])?$": { type: "object", properties: { payload: { type: "object", description: "Must be a valid JSON schema spec. For brevity, openws omits this spec, but implementations should valid this", additionalProperties: true }, description: { type: "string" }, from: { type: "array", items: { type: "string" }, description: "A list of roles that can send this message" } }, required: ["payload"], additionalProperties: true } }, description: "A message accepted by the role and handled by the role, and roles can send messages other roles accepts. The OpenWS spec only defines the shape of the payload, and how things get encoded / decoded on the wire, it doesn't determine behavior (through through description the behavior can be documented).", additionalProperties: false }, description: { type: "string" } }, required: ["messages"], additionalProperties: true } }, additionalProperties: false }, description: { type: "string" } }, required: ["roles"], additionalProperties: true } }, additionalProperties: false } }, required: ["openws", "networks"], additionalProperties: true, $schema: "http://json-schema.org/draft-07/schema#" };
1096
+
1097
+ // src/index.ts
1098
+ var VERSION = package_default.version;
1099
+ var validator;
1100
+ function validate(spec) {
1101
+ validator = validator ?? spec_schema_default.compile("Validator");
1102
+ validator(spec);
1103
+ }
1104
+ // Annotate the CommonJS export names for ESM import in node:
1105
+ 0 && (module.exports = {
1106
+ VERSION,
1107
+ specSchema,
1108
+ validate
1109
+ });
1110
+ //# sourceMappingURL=index.cjs.map