@clockworkdog/cogs-client 3.1.0 → 3.1.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.
@@ -1,6 +1,2 @@
1
- import { CogsPluginManifestJson, CogsValueTypeOptionWithDefault } from '../types/CogsPluginManifest';
2
- import { z } from 'zod/v4';
3
- export declare const cogsValueTypeOptionWithDefaultSchema: (options: {
4
- defaultRequired: boolean;
5
- }) => z.ZodType<CogsValueTypeOptionWithDefault>;
1
+ import { CogsPluginManifestJson } from '../types/CogsPluginManifest';
6
2
  export declare function getPluginManifestErrors(manifest: CogsPluginManifestJson): string[] | null;
@@ -1,165 +1,170 @@
1
1
  import { z } from 'zod/v4';
2
2
  import semver from 'semver';
3
3
  import { NetworkHostPattern } from './NetworkHostPattern';
4
- const uniqueStringArray = z.array(z.string().min(1)).refine((items) => new Set(items).size === items.length, {
4
+ const uniqueStringArraySchema = z.array(z.string().min(1)).refine((items) => new Set(items).size === items.length, {
5
5
  message: 'Array items must be unique',
6
6
  });
7
- const cogsValueTypeStringSchema = z.strictObject({
8
- type: z.literal('string'),
9
- });
10
- const cogsValueTypeNumberSchema = z.strictObject({
11
- type: z.literal('number'),
12
- integer: z.literal(true).optional(),
13
- min: z.number().optional(),
14
- max: z.number().optional(),
15
- });
16
- const cogsValueTypeBooleanSchema = z.strictObject({
17
- type: z.literal('boolean'),
18
- });
19
- const cogsValueTypeOptionSchema = z.strictObject({
20
- type: z.literal('option'),
21
- options: uniqueStringArray,
22
- });
23
- const pluginCogsValueTypeJsonSchema = z.union([
24
- cogsValueTypeStringSchema,
25
- cogsValueTypeNumberSchema,
26
- cogsValueTypeBooleanSchema,
27
- cogsValueTypeOptionSchema,
28
- ]);
29
- const cogsValueTypeStringWithDefaultSchema = (options) => (options.defaultRequired
30
- ? z.strictObject({ type: z.literal('string'), default: z.string() })
31
- : z.strictObject({ type: z.literal('string'), default: z.string().optional() }));
32
- const cogsValueTypeNumberWithDefaultSchema = (options) => (options.defaultRequired
33
- ? z.strictObject({
7
+ /** Returns a schema either allowing object to have on not have extra keys */
8
+ function createManifestSchema(objectSchemaFactory) {
9
+ // This function should always use `objectSchemaFactory` to create objects instead of `z.object` or `z.strictObject`
10
+ const cogsValueTypeStringSchema = objectSchemaFactory({
11
+ type: z.literal('string'),
12
+ });
13
+ const cogsValueTypeNumberSchema = objectSchemaFactory({
34
14
  type: z.literal('number'),
35
- integer: z.boolean().optional(),
15
+ integer: z.literal(true).optional(),
36
16
  min: z.number().optional(),
37
17
  max: z.number().optional(),
38
- default: z.number(),
39
- })
40
- : z.strictObject({
18
+ });
19
+ const cogsValueTypeBooleanSchema = objectSchemaFactory({
20
+ type: z.literal('boolean'),
21
+ });
22
+ const cogsValueTypeOptionSchema = objectSchemaFactory({
23
+ type: z.literal('option'),
24
+ options: uniqueStringArraySchema,
25
+ });
26
+ const pluginCogsValueTypeJsonSchema = z.union([
27
+ cogsValueTypeStringSchema,
28
+ cogsValueTypeNumberSchema,
29
+ cogsValueTypeBooleanSchema,
30
+ cogsValueTypeOptionSchema,
31
+ ]);
32
+ const makeOptionalWhen = (schema, condition) => {
33
+ return condition ? schema.optional() : schema;
34
+ };
35
+ const cogsValueTypeStringWithDefaultSchema = (options) => objectSchemaFactory({
36
+ type: z.literal('string'),
37
+ default: makeOptionalWhen(z.string(), !options.defaultRequired),
38
+ });
39
+ const cogsValueTypeNumberWithDefaultSchema = (options) => objectSchemaFactory({
41
40
  type: z.literal('number'),
42
41
  integer: z.boolean().optional(),
43
42
  min: z.number().optional(),
44
43
  max: z.number().optional(),
45
- default: z.number().optional(),
46
- }));
47
- const cogsValueTypeBooleanWithDefaultSchema = (options) => (options.defaultRequired
48
- ? z.strictObject({ type: z.literal('boolean'), default: z.boolean() })
49
- : z.strictObject({ type: z.literal('boolean'), default: z.boolean().optional() }));
50
- export const cogsValueTypeOptionWithDefaultSchema = (options) => (options.defaultRequired
51
- ? z.strictObject({
52
- type: z.literal('option'),
53
- options: uniqueStringArray.optional(),
54
- default: z.string().min(1),
55
- })
56
- : z.strictObject({
44
+ default: makeOptionalWhen(z.number(), !options.defaultRequired),
45
+ });
46
+ const cogsValueTypeBooleanWithDefaultSchema = (options) => objectSchemaFactory({
47
+ type: z.literal('boolean'),
48
+ default: makeOptionalWhen(z.boolean(), !options.defaultRequired),
49
+ });
50
+ const cogsValueTypeOptionWithDefaultSchema = (options) => objectSchemaFactory({
57
51
  type: z.literal('option'),
58
- options: uniqueStringArray.optional(),
59
- default: z.string().min(1).optional(),
60
- }));
61
- const pluginCogsValueTypeWithDefaultJsonSchema = (options) => z.union([
62
- cogsValueTypeStringWithDefaultSchema(options),
63
- cogsValueTypeNumberWithDefaultSchema(options),
64
- cogsValueTypeBooleanWithDefaultSchema(options),
65
- cogsValueTypeOptionWithDefaultSchema(options),
66
- ]);
67
- const pluginManifestConfigJsonSchema = z.strictObject({
68
- name: z.string().min(1),
69
- value: pluginCogsValueTypeWithDefaultJsonSchema({ defaultRequired: false }),
70
- });
71
- const pluginManifestEventJsonSchema = z.strictObject({
72
- name: z.string().min(1),
73
- value: pluginCogsValueTypeJsonSchema.optional(),
74
- });
75
- const pluginManifestStateJsonSchema = z.strictObject({
76
- name: z.string().min(1),
77
- value: pluginCogsValueTypeWithDefaultJsonSchema({ defaultRequired: true }),
78
- writableFromCogs: z.literal(true).optional(),
79
- writableFromClient: z.literal(true).optional(),
80
- });
81
- const validateNetworkHostPattern = (pattern) => {
82
- try {
83
- new NetworkHostPattern(pattern);
84
- return true;
85
- }
86
- catch {
87
- return false;
88
- }
89
- };
90
- const cogsPluginManifestJsonSchema = z
91
- .strictObject({
92
- version: z.union([
93
- z.templateLiteral([z.uint32()]),
94
- z.templateLiteral([z.uint32(), z.literal('.'), z.uint32()]),
95
- z.templateLiteral([z.uint32(), z.literal('.'), z.uint32(), z.literal('.'), z.uint32()]),
96
- ]),
97
- name: z.string(),
98
- minCogsVersion: z.templateLiteral([z.uint32(), z.literal('.'), z.uint32(), z.literal('.'), z.uint32()]).optional(),
99
- description: z.string().optional(),
100
- icon: z.string().optional(),
101
- indexPath: z.string().optional(),
102
- window: z
103
- .object({
104
- width: z.number().gt(0).int(),
105
- height: z.number().gt(0).int(),
106
- visible: z.boolean().optional(),
107
- })
108
- .optional(),
109
- config: z.array(pluginManifestConfigJsonSchema).optional(),
110
- events: z
111
- .object({
112
- fromCogs: z.array(pluginManifestEventJsonSchema).optional(),
113
- toCogs: z.array(pluginManifestEventJsonSchema).optional(),
114
- })
115
- .optional(),
116
- state: z.array(pluginManifestStateJsonSchema).optional(),
117
- media: z
118
- .object({
119
- audio: z.literal(true).optional(),
120
- video: z.literal(true).optional(),
121
- images: z.literal(true).optional(),
122
- })
123
- .optional(),
124
- store: z
125
- .object({
126
- items: z
127
- .record(z.string(), z.strictObject({
128
- persistValue: z.boolean().optional(),
129
- }))
52
+ options: uniqueStringArraySchema.optional(),
53
+ default: makeOptionalWhen(z.string(), !options.defaultRequired),
54
+ });
55
+ const pluginCogsValueTypeWithDefaultJsonSchema = (options) => z.union([
56
+ cogsValueTypeStringWithDefaultSchema(options),
57
+ cogsValueTypeNumberWithDefaultSchema(options),
58
+ cogsValueTypeBooleanWithDefaultSchema(options),
59
+ cogsValueTypeOptionWithDefaultSchema(options),
60
+ ]);
61
+ const pluginManifestConfigJsonSchema = objectSchemaFactory({
62
+ name: z.string().min(1),
63
+ value: pluginCogsValueTypeWithDefaultJsonSchema({ defaultRequired: false }),
64
+ });
65
+ const pluginManifestEventJsonSchema = objectSchemaFactory({
66
+ name: z.string().min(1),
67
+ value: pluginCogsValueTypeJsonSchema.optional(),
68
+ });
69
+ const pluginManifestStateJsonSchema = objectSchemaFactory({
70
+ name: z.string().min(1),
71
+ value: pluginCogsValueTypeWithDefaultJsonSchema({ defaultRequired: true }),
72
+ writableFromCogs: z.literal(true).optional(),
73
+ writableFromClient: z.literal(true).optional(),
74
+ });
75
+ const validateNetworkHostPattern = (pattern) => {
76
+ try {
77
+ new NetworkHostPattern(pattern);
78
+ return true;
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ };
84
+ const manifestSchema = objectSchemaFactory({
85
+ version: z.union([
86
+ z.templateLiteral([z.uint32()]),
87
+ z.templateLiteral([z.uint32(), z.literal('.'), z.uint32()]),
88
+ z.templateLiteral([z.uint32(), z.literal('.'), z.uint32(), z.literal('.'), z.uint32()]),
89
+ ]),
90
+ name: z.string(),
91
+ minCogsVersion: z.templateLiteral([z.uint32(), z.literal('.'), z.uint32(), z.literal('.'), z.uint32()]).optional(),
92
+ description: z.string().optional(),
93
+ icon: z.string().optional(),
94
+ indexPath: z.string().optional(),
95
+ window: z
96
+ .object({
97
+ width: z.number().gt(0).int(),
98
+ height: z.number().gt(0).int(),
99
+ visible: z.boolean().optional(),
100
+ })
130
101
  .optional(),
131
- })
132
- .optional(),
133
- permissions: z
134
- .strictObject({
135
- network: z
136
- .strictObject({
137
- access: z
138
- .array(z.strictObject({
139
- hosts: z.array(z.string().refine(validateNetworkHostPattern, { error: 'Invalid network host pattern' })).min(1),
140
- caCertificate: z.string().optional(),
102
+ config: z.array(pluginManifestConfigJsonSchema).optional(),
103
+ events: z
104
+ .object({
105
+ fromCogs: z.array(pluginManifestEventJsonSchema).optional(),
106
+ toCogs: z.array(pluginManifestEventJsonSchema).optional(),
107
+ })
108
+ .optional(),
109
+ state: z.array(pluginManifestStateJsonSchema).optional(),
110
+ media: z
111
+ .object({
112
+ audio: z.literal(true).optional(),
113
+ video: z.literal(true).optional(),
114
+ images: z.literal(true).optional(),
115
+ })
116
+ .optional(),
117
+ store: z
118
+ .object({
119
+ items: z
120
+ .record(z.string(), objectSchemaFactory({
121
+ persistValue: z.boolean().optional(),
141
122
  }))
142
123
  .optional(),
143
124
  })
144
125
  .optional(),
126
+ permissions: z
127
+ .strictObject({
128
+ network: z
129
+ .strictObject({
130
+ access: z
131
+ .array(objectSchemaFactory({
132
+ hosts: z.array(z.string().refine(validateNetworkHostPattern, { error: 'Invalid network host pattern' })).min(1),
133
+ caCertificate: z.string().optional(),
134
+ }))
135
+ .optional(),
136
+ })
137
+ .optional(),
138
+ })
139
+ .optional(),
145
140
  })
146
- .optional(),
147
- })
148
- // Check that network access rules are only present if minCogsVersion is at least 5.11.0
149
- .refine((manifest) => {
150
- if (!manifest.permissions?.network?.access) {
151
- return true;
152
- }
153
- if (manifest.minCogsVersion && semver.gte(manifest.minCogsVersion, '5.11.0')) {
154
- return true;
155
- }
156
- return false;
157
- }, {
158
- path: ['permissions', 'network', 'access'],
159
- message: 'minCogsVersion must be at least 5.11.0',
160
- });
161
- const validate = cogsPluginManifestJsonSchema;
141
+ // Check that network access rules are only present if minCogsVersion is at least 5.11.0
142
+ .refine((manifest) => {
143
+ if (!manifest.permissions?.network?.access) {
144
+ return true;
145
+ }
146
+ if (manifest.minCogsVersion && semver.gte(manifest.minCogsVersion, '5.11.0')) {
147
+ return true;
148
+ }
149
+ return false;
150
+ }, {
151
+ path: ['permissions', 'network', 'access'],
152
+ message: 'minCogsVersion must be at least 5.11.0',
153
+ });
154
+ return manifestSchema;
155
+ }
156
+ const cogsPluginManifestJsonSchema = createManifestSchema(z.object);
157
+ const cogsPluginManifestJsonStrictSchema = createManifestSchema(z.strictObject);
162
158
  export function getPluginManifestErrors(manifest) {
159
+ let validate = cogsPluginManifestJsonSchema;
160
+ // minCogsVersion 5.11.0 requires strict schema
161
+ // i.e. no unexpected keys
162
+ if (typeof manifest === 'object' &&
163
+ manifest.minCogsVersion &&
164
+ semver.valid(manifest.minCogsVersion) &&
165
+ semver.gte(manifest.minCogsVersion, '5.11.0')) {
166
+ validate = cogsPluginManifestJsonStrictSchema;
167
+ }
163
168
  const result = validate.safeParse(manifest);
164
169
  if (result.success)
165
170
  return null;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Connect to COGS to build a custom Media Master",
4
4
  "author": "Clockwork Dog <info@clockwork.dog>",
5
5
  "homepage": "https://github.com/clockwork-dog/cogs-sdk/tree/main/packages/javascript",
6
- "version": "3.1.0",
6
+ "version": "3.1.2",
7
7
  "keywords": [],
8
8
  "license": "MIT",
9
9
  "repository": {
@@ -37,7 +37,7 @@
37
37
  "cy:generate": "cypress run --e2e"
38
38
  },
39
39
  "dependencies": {
40
- "@clockworkdog/timesync": "^3.1.0",
40
+ "@clockworkdog/timesync": "^3.1.2",
41
41
  "ip-address": "^10.2.0",
42
42
  "reconnecting-websocket": "^4.4.0",
43
43
  "semver": "^7.8.5",