@ai-ecoverse/slicc-browsers 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,59 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-browsers",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "SLICC's shared browser catalog, JSON schemas and discovery conformance corpus",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ai-ecoverse/slicc-browsers.git"
10
+ },
11
+ "engines": {
12
+ "node": ">=24"
13
+ },
14
+ "fledgling": {
15
+ "provider": "github",
16
+ "workflow": "release.yml",
17
+ "repo": "ai-ecoverse/slicc-browsers",
18
+ "publish": true
19
+ },
20
+ "publishConfig": {
21
+ "access": "public",
22
+ "provenance": true
23
+ },
24
+ "exports": {
25
+ ".": "./catalog.json",
26
+ "./catalog.json": "./catalog.json",
27
+ "./corpus.json": "./corpus.json",
28
+ "./schema/catalog.schema.json": "./schema/catalog.schema.json",
29
+ "./schema/browsers.schema.json": "./schema/browsers.schema.json",
30
+ "./schema/corpus.schema.json": "./schema/corpus.schema.json",
31
+ "./package.json": "./package.json"
32
+ },
33
+ "files": [
34
+ "catalog.json",
35
+ "corpus.json",
36
+ "schema"
37
+ ],
38
+ "scripts": {
39
+ "prepare": "lefthook install",
40
+ "corpus": "node scripts/corpus.mjs",
41
+ "validate": "node scripts/validate.mjs",
42
+ "lint": "slicc-lint && test -z \"$(gofmt -l .)\" && go mod tidy -diff && go vet ./... && golangci-lint run && cargo fmt --check && cargo clippy --all-features --all-targets -- -D warnings",
43
+ "format": "biome check --write . && gofmt -w . && cargo fmt",
44
+ "test": "npm run validate && go test -race -count=1 ./test/integration/... && cargo test --all-features",
45
+ "test:unit": "go test -race -cover ./...",
46
+ "build": "go build ./... && cargo build --all-features && cargo build --target wasm32-wasip1 --all-features && npm pack --dry-run",
47
+ "trust": "npx fledgling sync -y --skip-publish",
48
+ "trust:dry": "npx fledgling sync --dry-run -y --skip-publish",
49
+ "release": "semantic-release"
50
+ },
51
+ "devDependencies": {
52
+ "@ai-ecoverse/slicc-shared-web": "1.12.3",
53
+ "@biomejs/biome": "2.5.15",
54
+ "ajv": "8.20.0",
55
+ "ajv-formats": "3.0.1",
56
+ "lefthook": "2.1.16",
57
+ "semantic-release": "25.0.9"
58
+ }
59
+ }
@@ -0,0 +1,95 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/ai-ecoverse/slicc-browsers/schema/browsers.schema.json",
4
+ "title": "slicc browsers --json and playwright-cli list --json, schema 1",
5
+ "type": "object",
6
+ "required": ["schema", "minChromium", "entries"],
7
+ "properties": {
8
+ "schema": { "const": 1 },
9
+ "minChromium": { "type": "integer", "minimum": 1 },
10
+ "entries": { "type": "array", "items": { "$ref": "#/$defs/entry" } }
11
+ },
12
+ "$defs": {
13
+ "text": { "type": "string", "minLength": 1 },
14
+ "entry": {
15
+ "type": "object",
16
+ "required": ["id", "kind", "tier", "name"],
17
+ "properties": {
18
+ "id": { "$ref": "#/$defs/text" },
19
+ "kind": { "enum": ["endpoint", "installed"] },
20
+ "tier": { "type": "integer", "minimum": 1, "maximum": 5 },
21
+ "name": { "type": "string" },
22
+ "version": { "$ref": "#/$defs/text" },
23
+ "endpoint": { "$ref": "#/$defs/endpoint" },
24
+ "installed": { "$ref": "#/$defs/installed" }
25
+ },
26
+ "oneOf": [
27
+ {
28
+ "properties": {
29
+ "kind": { "const": "endpoint" },
30
+ "id": { "type": "string", "pattern": "^cdp:" },
31
+ "tier": { "enum": [1, 2] }
32
+ },
33
+ "required": ["endpoint"],
34
+ "not": { "required": ["installed"] }
35
+ },
36
+ {
37
+ "properties": {
38
+ "kind": { "const": "installed" },
39
+ "id": { "type": "string", "pattern": "^(?!cdp:)" },
40
+ "tier": { "enum": [3, 4, 5] }
41
+ },
42
+ "required": ["installed"],
43
+ "not": { "required": ["endpoint"] }
44
+ }
45
+ ]
46
+ },
47
+ "tab": {
48
+ "type": "object",
49
+ "required": ["id", "url", "title"],
50
+ "properties": {
51
+ "id": { "type": "string" },
52
+ "url": { "type": "string" },
53
+ "title": { "type": "string" }
54
+ }
55
+ },
56
+ "endpoint": {
57
+ "type": "object",
58
+ "required": ["cdp", "webSocketDebuggerUrl", "name", "source", "sevenOpen", "sevenTabs"],
59
+ "properties": {
60
+ "cdp": { "type": "string", "pattern": "^https?://[^/]+$" },
61
+ "webSocketDebuggerUrl": { "type": "string" },
62
+ "name": { "type": "string" },
63
+ "version": { "$ref": "#/$defs/text" },
64
+ "product": { "$ref": "#/$defs/text" },
65
+ "userAgent": { "$ref": "#/$defs/text" },
66
+ "source": { "enum": ["devtools-active-port", "flag", "probe", "process"] },
67
+ "browser": { "$ref": "#/$defs/text" },
68
+ "userDataDir": { "$ref": "#/$defs/text" },
69
+ "profile": { "$ref": "#/$defs/text" },
70
+ "wsOnly": { "const": true },
71
+ "sevenOpen": { "type": "boolean" },
72
+ "sevenTabs": { "type": "array", "items": { "$ref": "#/$defs/tab" } }
73
+ }
74
+ },
75
+ "installed": {
76
+ "type": "object",
77
+ "required": ["id", "name", "engine", "path", "executable", "debugSupport"],
78
+ "properties": {
79
+ "id": { "$ref": "#/$defs/text" },
80
+ "name": { "type": "string" },
81
+ "engine": { "enum": ["chromium", "electron"] },
82
+ "channel": { "$ref": "#/$defs/text" },
83
+ "version": { "$ref": "#/$defs/text" },
84
+ "path": { "type": "string" },
85
+ "executable": { "type": "string" },
86
+ "bundleId": { "$ref": "#/$defs/text" },
87
+ "via": { "enum": ["snap", "flatpak"] },
88
+ "package": { "$ref": "#/$defs/text" },
89
+ "userDataDir": { "$ref": "#/$defs/text" },
90
+ "debugSupport": { "enum": ["supported", "disabled", "unknown"] },
91
+ "debugBuild": { "const": true }
92
+ }
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,335 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/ai-ecoverse/slicc-browsers/schema/catalog.schema.json",
4
+ "title": "slicc-browsers catalog, schema 1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schema",
9
+ "minChromiumMajor",
10
+ "browsers",
11
+ "electron",
12
+ "rank",
13
+ "discovery",
14
+ "seven",
15
+ "profiles",
16
+ "launch",
17
+ "platforms"
18
+ ],
19
+ "properties": {
20
+ "schema": { "const": 1 },
21
+ "minChromiumMajor": { "type": "integer", "minimum": 1 },
22
+ "browsers": {
23
+ "description": "Every known Chromium browser, in rank priority order.",
24
+ "type": "array",
25
+ "minItems": 1,
26
+ "items": { "$ref": "#/$defs/browser" }
27
+ },
28
+ "electron": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": ["macosApps", "debugBlocked", "idPrefix"],
32
+ "properties": {
33
+ "macosApps": {
34
+ "type": "array",
35
+ "items": {
36
+ "type": "object",
37
+ "additionalProperties": false,
38
+ "required": ["bundleId", "name"],
39
+ "properties": {
40
+ "bundleId": { "$ref": "#/$defs/name" },
41
+ "name": { "$ref": "#/$defs/name" }
42
+ }
43
+ }
44
+ },
45
+ "debugBlocked": { "$ref": "#/$defs/names" },
46
+ "idPrefix": { "const": "electron:" }
47
+ }
48
+ },
49
+ "rank": {
50
+ "type": "object",
51
+ "additionalProperties": false,
52
+ "required": ["tiers", "chromeId"],
53
+ "properties": {
54
+ "tiers": {
55
+ "type": "object",
56
+ "additionalProperties": false,
57
+ "required": ["sevenOpen", "endpoint", "chrome", "chromium", "electron"],
58
+ "properties": {
59
+ "sevenOpen": { "$ref": "#/$defs/tier" },
60
+ "endpoint": { "$ref": "#/$defs/tier" },
61
+ "chrome": { "$ref": "#/$defs/tier" },
62
+ "chromium": { "$ref": "#/$defs/tier" },
63
+ "electron": { "$ref": "#/$defs/tier" }
64
+ }
65
+ },
66
+ "chromeId": { "$ref": "#/$defs/id" }
67
+ }
68
+ },
69
+ "discovery": {
70
+ "type": "object",
71
+ "additionalProperties": false,
72
+ "required": [
73
+ "activePortFile",
74
+ "probePorts",
75
+ "sourceRank",
76
+ "chromeMajorPattern",
77
+ "names",
78
+ "process"
79
+ ],
80
+ "properties": {
81
+ "activePortFile": { "$ref": "#/$defs/name" },
82
+ "probePorts": { "$ref": "#/$defs/ports" },
83
+ "sourceRank": {
84
+ "type": "object",
85
+ "additionalProperties": false,
86
+ "required": ["devtools-active-port", "flag", "process", "probe"],
87
+ "properties": {
88
+ "devtools-active-port": { "type": "integer", "minimum": 0 },
89
+ "flag": { "type": "integer", "minimum": 0 },
90
+ "process": { "type": "integer", "minimum": 0 },
91
+ "probe": { "type": "integer", "minimum": 0 }
92
+ }
93
+ },
94
+ "chromeMajorPattern": { "type": "string", "format": "regex" },
95
+ "names": {
96
+ "type": "object",
97
+ "additionalProperties": false,
98
+ "required": ["electronUserAgent", "electron", "products", "fallback"],
99
+ "properties": {
100
+ "electronUserAgent": { "$ref": "#/$defs/name" },
101
+ "electron": { "$ref": "#/$defs/name" },
102
+ "products": { "type": "object", "additionalProperties": { "$ref": "#/$defs/name" } },
103
+ "fallback": { "$ref": "#/$defs/name" }
104
+ }
105
+ },
106
+ "process": {
107
+ "type": "object",
108
+ "additionalProperties": false,
109
+ "required": [
110
+ "unix",
111
+ "windows",
112
+ "portFlag",
113
+ "userDataDirFlag",
114
+ "wrappers",
115
+ "wrapperSuffixes"
116
+ ],
117
+ "properties": {
118
+ "unix": { "$ref": "#/$defs/names" },
119
+ "windows": { "$ref": "#/$defs/names" },
120
+ "portFlag": { "type": "string", "pattern": "^--" },
121
+ "userDataDirFlag": { "type": "string", "pattern": "^--" },
122
+ "wrappers": { "$ref": "#/$defs/names" },
123
+ "wrapperSuffixes": { "$ref": "#/$defs/names" }
124
+ }
125
+ }
126
+ }
127
+ },
128
+ "seven": {
129
+ "type": "object",
130
+ "additionalProperties": false,
131
+ "required": [
132
+ "originScheme",
133
+ "originHostPattern",
134
+ "excludedLabels",
135
+ "sitePattern",
136
+ "switches",
137
+ "disabledFeatures",
138
+ "prefs",
139
+ "discardExceptions",
140
+ "cleanExit"
141
+ ],
142
+ "properties": {
143
+ "originScheme": { "const": "https" },
144
+ "originHostPattern": { "type": "string", "format": "regex" },
145
+ "excludedLabels": { "$ref": "#/$defs/names" },
146
+ "sitePattern": { "$ref": "#/$defs/name" },
147
+ "switches": { "type": "array", "items": { "type": "string", "pattern": "^--" } },
148
+ "disabledFeatures": { "$ref": "#/$defs/names" },
149
+ "prefs": { "type": "array", "items": { "$ref": "#/$defs/pref" } },
150
+ "discardExceptions": {
151
+ "type": "array",
152
+ "items": {
153
+ "type": "object",
154
+ "additionalProperties": false,
155
+ "required": ["path", "type", "form"],
156
+ "properties": {
157
+ "path": { "$ref": "#/$defs/segments" },
158
+ "type": { "enum": ["list", "chrome-time-map"] },
159
+ "form": { "$ref": "#/$defs/form" }
160
+ }
161
+ }
162
+ },
163
+ "cleanExit": { "type": "array", "items": { "$ref": "#/$defs/pref" } }
164
+ }
165
+ },
166
+ "profiles": {
167
+ "type": "object",
168
+ "additionalProperties": false,
169
+ "required": ["root", "snapRoot", "legacyRoot", "sixProfilePattern", "namePattern"],
170
+ "properties": {
171
+ "root": { "$ref": "#/$defs/segments" },
172
+ "snapRoot": { "$ref": "#/$defs/segments" },
173
+ "legacyRoot": { "$ref": "#/$defs/segments" },
174
+ "sixProfilePattern": { "type": "string", "format": "regex" },
175
+ "namePattern": { "type": "string", "format": "regex" }
176
+ }
177
+ },
178
+ "launch": {
179
+ "type": "object",
180
+ "additionalProperties": false,
181
+ "required": ["chromiumArgs", "headless", "disableFeaturesFlag", "electron"],
182
+ "properties": {
183
+ "chromiumArgs": { "type": "array", "items": { "type": "string", "pattern": "^--" } },
184
+ "headless": { "type": "string", "pattern": "^--" },
185
+ "disableFeaturesFlag": { "type": "string", "pattern": "^--.*=$" },
186
+ "electron": {
187
+ "type": "object",
188
+ "additionalProperties": false,
189
+ "required": ["portFlag", "minPort", "reservedPorts"],
190
+ "properties": {
191
+ "portFlag": { "type": "string", "pattern": "\\{port\\}" },
192
+ "minPort": { "$ref": "#/$defs/port" },
193
+ "reservedPorts": { "$ref": "#/$defs/ports" }
194
+ }
195
+ }
196
+ }
197
+ },
198
+ "platforms": {
199
+ "type": "object",
200
+ "additionalProperties": false,
201
+ "required": ["macos", "windows", "linux"],
202
+ "properties": {
203
+ "macos": {
204
+ "type": "object",
205
+ "additionalProperties": false,
206
+ "required": ["config"],
207
+ "properties": { "config": { "$ref": "#/$defs/location" } }
208
+ },
209
+ "windows": {
210
+ "type": "object",
211
+ "additionalProperties": false,
212
+ "required": ["config", "roots", "registry"],
213
+ "properties": {
214
+ "config": { "$ref": "#/$defs/location" },
215
+ "roots": { "type": "object", "additionalProperties": { "$ref": "#/$defs/location" } },
216
+ "registry": {
217
+ "type": "object",
218
+ "additionalProperties": false,
219
+ "required": ["hives", "startMenuInternet", "openCommand", "appPaths", "appPathNames"],
220
+ "properties": {
221
+ "hives": { "type": "array", "items": { "enum": ["HKCU", "HKLM"] } },
222
+ "startMenuInternet": { "$ref": "#/$defs/names" },
223
+ "openCommand": { "$ref": "#/$defs/name" },
224
+ "appPaths": { "$ref": "#/$defs/name" },
225
+ "appPathNames": { "$ref": "#/$defs/names" }
226
+ }
227
+ }
228
+ }
229
+ },
230
+ "linux": {
231
+ "type": "object",
232
+ "additionalProperties": false,
233
+ "required": ["config"],
234
+ "properties": { "config": { "$ref": "#/$defs/location" } }
235
+ }
236
+ }
237
+ }
238
+ },
239
+ "$defs": {
240
+ "name": { "type": "string", "minLength": 1 },
241
+ "names": { "type": "array", "items": { "$ref": "#/$defs/name" } },
242
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" },
243
+ "segments": {
244
+ "description": "A relative path, one segment per item.",
245
+ "type": "array",
246
+ "minItems": 1,
247
+ "items": { "type": "string", "minLength": 1, "pattern": "^[^/\\\\]+$" }
248
+ },
249
+ "port": { "type": "integer", "minimum": 1, "maximum": 65535 },
250
+ "ports": { "type": "array", "items": { "$ref": "#/$defs/port" } },
251
+ "tier": { "type": "integer", "minimum": 1, "maximum": 5 },
252
+ "form": { "enum": ["six", "chrome-154"] },
253
+ "pref": {
254
+ "type": "object",
255
+ "additionalProperties": false,
256
+ "required": ["path", "value"],
257
+ "properties": {
258
+ "path": { "$ref": "#/$defs/segments" },
259
+ "value": { "type": ["boolean", "number", "string"] },
260
+ "form": { "$ref": "#/$defs/form" }
261
+ }
262
+ },
263
+ "location": {
264
+ "description": "An environment variable, else a dir under the home dir or an absolute path.",
265
+ "type": "object",
266
+ "additionalProperties": false,
267
+ "properties": {
268
+ "env": { "$ref": "#/$defs/name" },
269
+ "home": { "$ref": "#/$defs/segments" },
270
+ "absolute": { "$ref": "#/$defs/name" }
271
+ },
272
+ "oneOf": [{ "required": ["home"] }, { "required": ["absolute"] }]
273
+ },
274
+ "browser": {
275
+ "type": "object",
276
+ "additionalProperties": false,
277
+ "required": ["id", "name", "channel", "engine", "chromiumVersion", "macos"],
278
+ "properties": {
279
+ "id": { "$ref": "#/$defs/id" },
280
+ "name": { "$ref": "#/$defs/name" },
281
+ "channel": {
282
+ "enum": ["stable", "beta", "dev", "canary", "nightly", "snapshot", "testing"]
283
+ },
284
+ "engine": { "const": "chromium" },
285
+ "chromiumVersion": {
286
+ "description": "The browser's version is the Chromium version, so minChromiumMajor applies to it.",
287
+ "type": "boolean"
288
+ },
289
+ "macos": {
290
+ "type": "object",
291
+ "additionalProperties": false,
292
+ "required": ["bundleId", "app", "executable"],
293
+ "properties": {
294
+ "bundleId": { "$ref": "#/$defs/name" },
295
+ "app": { "type": "string", "pattern": "\\.app$" },
296
+ "executable": { "$ref": "#/$defs/name" },
297
+ "dataDir": { "$ref": "#/$defs/segments" }
298
+ }
299
+ },
300
+ "windows": {
301
+ "type": "object",
302
+ "additionalProperties": false,
303
+ "required": ["dataRoot", "dataDir"],
304
+ "properties": {
305
+ "roots": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/name" } },
306
+ "executables": {
307
+ "type": "array",
308
+ "minItems": 1,
309
+ "items": { "$ref": "#/$defs/segments" }
310
+ },
311
+ "dataRoot": { "$ref": "#/$defs/name" },
312
+ "dataDir": { "$ref": "#/$defs/segments" },
313
+ "startMenuInternet": { "$ref": "#/$defs/names" }
314
+ },
315
+ "dependentRequired": { "executables": ["roots"], "roots": ["executables"] }
316
+ },
317
+ "linux": {
318
+ "type": "object",
319
+ "additionalProperties": false,
320
+ "required": ["configDir"],
321
+ "properties": {
322
+ "bins": { "$ref": "#/$defs/names" },
323
+ "desktopIds": { "$ref": "#/$defs/names" },
324
+ "flatpak": { "$ref": "#/$defs/name" },
325
+ "snap": { "$ref": "#/$defs/name" },
326
+ "snapDataDir": { "$ref": "#/$defs/segments" },
327
+ "configDir": { "$ref": "#/$defs/segments" },
328
+ "debs": { "$ref": "#/$defs/names" }
329
+ },
330
+ "dependentRequired": { "snapDataDir": ["snap"] }
331
+ }
332
+ }
333
+ }
334
+ }
335
+ }
@@ -0,0 +1,106 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/ai-ecoverse/slicc-browsers/schema/corpus.schema.json",
4
+ "title": "slicc-browsers conformance corpus, schema 1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schema", "cases"],
8
+ "properties": {
9
+ "schema": { "const": 1 },
10
+ "cases": {
11
+ "type": "array",
12
+ "items": {
13
+ "type": "object",
14
+ "additionalProperties": false,
15
+ "required": ["name", "case", "expected"],
16
+ "properties": {
17
+ "name": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" },
18
+ "case": { "$ref": "#/$defs/case" },
19
+ "expected": { "$ref": "browsers.schema.json" }
20
+ }
21
+ }
22
+ }
23
+ },
24
+ "$defs": {
25
+ "case": {
26
+ "type": "object",
27
+ "additionalProperties": false,
28
+ "required": ["description", "needs"],
29
+ "properties": {
30
+ "description": { "type": "string", "minLength": 1 },
31
+ "os": {
32
+ "type": "array",
33
+ "minItems": 1,
34
+ "uniqueItems": true,
35
+ "items": { "enum": ["darwin", "linux", "windows"] }
36
+ },
37
+ "needs": {
38
+ "type": "array",
39
+ "minItems": 1,
40
+ "uniqueItems": true,
41
+ "items": {
42
+ "enum": [
43
+ "user-data-dirs",
44
+ "seven-profiles",
45
+ "flag",
46
+ "process",
47
+ "probe",
48
+ "origins",
49
+ "installed"
50
+ ]
51
+ }
52
+ },
53
+ "env": { "type": "object", "additionalProperties": { "type": "string" } },
54
+ "files": {
55
+ "type": "object",
56
+ "propertyNames": {
57
+ "type": "string",
58
+ "pattern": "^\\{(home|config|sevenProfiles|userData:[a-z0-9-]+)\\}/[^\\\\]+$"
59
+ },
60
+ "additionalProperties": { "type": "string" }
61
+ },
62
+ "cdp": { "type": "array", "items": { "type": "string", "minLength": 1 } },
63
+ "origins": { "type": "array", "items": { "type": "string", "minLength": 1 } },
64
+ "probePorts": {
65
+ "type": "array",
66
+ "items": {
67
+ "type": "integer",
68
+ "minimum": 1,
69
+ "maximum": 65535,
70
+ "not": { "type": "integer", "minimum": 9222, "maximum": 9229 }
71
+ }
72
+ },
73
+ "processes": {
74
+ "type": "array",
75
+ "items": {
76
+ "type": "object",
77
+ "additionalProperties": false,
78
+ "required": ["command"],
79
+ "properties": {
80
+ "pid": { "type": "integer", "minimum": 0 },
81
+ "self": { "const": true },
82
+ "command": { "type": "string" }
83
+ },
84
+ "oneOf": [{ "required": ["pid"] }, { "required": ["self"] }]
85
+ }
86
+ },
87
+ "http": {
88
+ "type": "object",
89
+ "propertyNames": { "type": "string", "pattern": "^(?!.*:922[2-9]$)[a-z0-9.-]+:[0-9]+$" },
90
+ "additionalProperties": {
91
+ "type": "object",
92
+ "additionalProperties": false,
93
+ "properties": {
94
+ "version": { "type": "object" },
95
+ "list": { "type": "array" }
96
+ }
97
+ }
98
+ },
99
+ "installed": {
100
+ "type": "array",
101
+ "items": { "$ref": "browsers.schema.json#/$defs/installed" }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }