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