@opencraw/driver 0.4.0 → 0.6.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/README.md +13 -0
- package/dist/index.esm.js +42 -14
- package/dist/main.esm.js +15 -14
- package/dist/src/index.d.ts +3 -1
- package/dist/src/runtime-manifest/index.d.ts +4 -0
- package/dist/src/runtime-manifest/runtime-manifest-json-schema.mapper.d.ts +8 -0
- package/dist/src/runtime-manifest/runtime-manifest.contract.d.ts +28 -0
- package/dist/src/session/index.d.ts +1 -1
- package/dist/src/session/run-session.use-case.d.ts +12 -1
- package/package.json +1 -1
- package/schemas/driver-runtime.fixture.json +9 -0
- package/schemas/driver-runtime.schema.json +63 -0
package/README.md
CHANGED
|
@@ -60,6 +60,19 @@ stdin at once. Answers may arrive out of order; match them by `id`.
|
|
|
60
60
|
`-32602` (bad params, the problems listed), `-32000` (a failure to act on: its message says what to do).
|
|
61
61
|
- stdout carries protocol messages only. The driver's own logs go to stderr.
|
|
62
62
|
|
|
63
|
+
## The runtime: no Node needed
|
|
64
|
+
|
|
65
|
+
Each driver release carries, as assets of its GitHub release `driver@<version>`, an archive per platform
|
|
66
|
+
(`win32-x64`, `darwin-arm64`, `darwin-x64`, `linux-x64`, `linux-arm64`): a Node binary, the driver and its
|
|
67
|
+
dependencies, and `runtime.json`, whose `command` starts it (both paths relative to the unpacked folder).
|
|
68
|
+
`driver-runtime.json` lists them with their SHA-256 and size; its schema is `schemas/driver-runtime.schema.json`
|
|
69
|
+
and `schemas/driver-runtime.fixture.json` is an example. A client downloads its platform's archive once, refuses
|
|
70
|
+
one whose hash does not match, unpacks it into a per-user cache and starts the driver from there.
|
|
71
|
+
|
|
72
|
+
`node packages/driver/packaging/stage-runtime.mjs` builds this platform's archive into `dist/drop/driver-runtime`
|
|
73
|
+
(after `smith build -p driver`), and starts the staged driver once with `PATH` emptied, to prove it needs nothing
|
|
74
|
+
else. Browsers are not in it: they are installed through the driver, the Playwright way.
|
|
75
|
+
|
|
63
76
|
## Development
|
|
64
77
|
|
|
65
78
|
`smith run lint typecheck test build -p driver`. After changing a contract in `src/protocol/`, run
|
package/dist/index.esm.js
CHANGED
|
@@ -240,8 +240,8 @@ function clientAccessPlugins(names, runId, ask) {
|
|
|
240
240
|
// src/site-access/resolve-site-access.use-case.ts
|
|
241
241
|
import { resolveAccess } from "@opencraw/cli";
|
|
242
242
|
async function resolveSiteAccess(params, runId, ask, env = process.env) {
|
|
243
|
-
const file = params.accessConfig ?? env.OPENCRAW_ACCESS;
|
|
244
|
-
if (file === void 0 && params.access !== void 0) throw new Error(`access profile "${params.access}" needs an access config:
|
|
243
|
+
const file = params.accessConfig ?? (env.OPENCRAW_ACCESS === "" ? void 0 : env.OPENCRAW_ACCESS);
|
|
244
|
+
if (file === void 0 && params.access !== void 0) throw new Error(`access profile "${params.access}" needs an access config, and there is none: no "accessConfig" was given, and OPENCRAW_ACCESS is not set where OpenCraw runs`);
|
|
245
245
|
const access = await resolveAccess({ insecureTls: false, access: file, accessProfile: params.access });
|
|
246
246
|
return { access, accessPlugins: clientAccessPlugins(params.accessPlugins ?? [], runId, ask) };
|
|
247
247
|
}
|
|
@@ -344,17 +344,17 @@ function streamingSink() {
|
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
// src/session/run-session.use-case.ts
|
|
347
|
-
function runSessions(notify, ask) {
|
|
347
|
+
function runSessions(notify, ask, local = {}) {
|
|
348
348
|
const running = /* @__PURE__ */ new Map();
|
|
349
349
|
let next = 1;
|
|
350
350
|
const crawlerFor = async (runId, params) => {
|
|
351
351
|
const { access, accessPlugins } = await resolveSiteAccess(params, runId, ask);
|
|
352
352
|
return createCrawler({
|
|
353
353
|
sink: params.out === void 0 ? streamingSink() : fileSink2(params.out, { append: params.append, browser: { executablePath: params.browser?.executablePath } }),
|
|
354
|
-
hooks: clientHooks(params.hooks ?? [], runId, ask),
|
|
355
|
-
captchaSolvers: clientCaptchaSolvers(params.captchaSolvers ?? [], runId, ask),
|
|
354
|
+
hooks: { ...local.hooks, ...clientHooks(params.hooks ?? [], runId, ask) },
|
|
355
|
+
captchaSolvers: [...local.captchaSolvers ?? [], ...clientCaptchaSolvers(params.captchaSolvers ?? [], runId, ask)],
|
|
356
356
|
access,
|
|
357
|
-
accessPlugins,
|
|
357
|
+
accessPlugins: [...local.accessPlugins ?? [], ...accessPlugins],
|
|
358
358
|
profilesDir: process.env.OPENCRAW_PROFILES,
|
|
359
359
|
parallel: params.parallel,
|
|
360
360
|
resume: params.resume,
|
|
@@ -380,15 +380,16 @@ function runSessions(notify, ask) {
|
|
|
380
380
|
}
|
|
381
381
|
})();
|
|
382
382
|
};
|
|
383
|
+
const startLoaded = async (loaded, params) => {
|
|
384
|
+
const set = params.dryRun === true ? new RecipeSet(loaded.output, loaded.inputs.map((input) => ({ ...input, limits: { ...input.limits, maxRecords: 1 } }))) : loaded;
|
|
385
|
+
const runId = `run-${next++}`;
|
|
386
|
+
const crawler = await crawlerFor(runId, params);
|
|
387
|
+
track(runId, crawler, async () => await crawler.run(set));
|
|
388
|
+
return runId;
|
|
389
|
+
};
|
|
383
390
|
return {
|
|
384
|
-
start: async (params) =>
|
|
385
|
-
|
|
386
|
-
const set = params.dryRun === true ? new RecipeSet(loaded.output, loaded.inputs.map((input) => ({ ...input, limits: { ...input.limits, maxRecords: 1 } }))) : loaded;
|
|
387
|
-
const runId = `run-${next++}`;
|
|
388
|
-
const crawler = await crawlerFor(runId, params);
|
|
389
|
-
track(runId, crawler, async () => await crawler.run(set));
|
|
390
|
-
return runId;
|
|
391
|
-
},
|
|
391
|
+
start: async (params) => await startLoaded(await loadRecipes(params), params),
|
|
392
|
+
startLoaded,
|
|
392
393
|
startWork: async (params) => {
|
|
393
394
|
const set = await loadRecipes(params);
|
|
394
395
|
const runId = `run-${next++}`;
|
|
@@ -574,10 +575,35 @@ async function serveDriver(input, output, identity) {
|
|
|
574
575
|
await channel.drained();
|
|
575
576
|
await sessions.closeAll();
|
|
576
577
|
}
|
|
578
|
+
|
|
579
|
+
// src/runtime-manifest/runtime-manifest.contract.ts
|
|
580
|
+
import { z as z3 } from "zod";
|
|
581
|
+
var RUNTIME_PLATFORMS = ["win32-x64", "darwin-arm64", "darwin-x64", "linux-x64", "linux-arm64"];
|
|
582
|
+
var archiveSchema = z3.strictObject({
|
|
583
|
+
/** The archive's file name, an asset of the same GitHub release as the manifest. */
|
|
584
|
+
file: z3.string().regex(/^opencraw-driver-[\w.-]+\.tar\.gz$/),
|
|
585
|
+
/** Its SHA-256, lowercase hex: a client refuses an archive that does not match. */
|
|
586
|
+
sha256: z3.string().regex(/^[0-9a-f]{64}$/),
|
|
587
|
+
size: z3.number().int().positive()
|
|
588
|
+
});
|
|
589
|
+
var runtimeManifestSchema = z3.strictObject({
|
|
590
|
+
driverVersion: z3.string().min(1),
|
|
591
|
+
protocolVersion: z3.string().regex(/^\d+\.\d+\.\d+$/),
|
|
592
|
+
/** The Node version every archive carries. */
|
|
593
|
+
node: z3.string().regex(/^v\d+\.\d+\.\d+$/),
|
|
594
|
+
archives: z3.partialRecord(z3.enum(RUNTIME_PLATFORMS), archiveSchema)
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// src/runtime-manifest/runtime-manifest-json-schema.mapper.ts
|
|
598
|
+
import { z as z4 } from "zod";
|
|
599
|
+
function runtimeManifestJsonSchema() {
|
|
600
|
+
return { $id: "https://opencraw.dev/schemas/driver-runtime.schema.json", ...z4.toJSONSchema(runtimeManifestSchema, { target: "draft-2020-12" }) };
|
|
601
|
+
}
|
|
577
602
|
export {
|
|
578
603
|
MESSAGES,
|
|
579
604
|
PROTOCOL_VERSION,
|
|
580
605
|
RPC_ERRORS,
|
|
606
|
+
RUNTIME_PLATFORMS,
|
|
581
607
|
RpcFailure,
|
|
582
608
|
calloutParamsSchema,
|
|
583
609
|
calloutResultSchema,
|
|
@@ -606,6 +632,8 @@ export {
|
|
|
606
632
|
runParamsSchema,
|
|
607
633
|
runResultSchema,
|
|
608
634
|
runSessions,
|
|
635
|
+
runtimeManifestJsonSchema,
|
|
636
|
+
runtimeManifestSchema,
|
|
609
637
|
serveDriver,
|
|
610
638
|
streamingSink,
|
|
611
639
|
validateParamsSchema,
|
package/dist/main.esm.js
CHANGED
|
@@ -201,8 +201,8 @@ function clientAccessPlugins(names, runId, ask) {
|
|
|
201
201
|
// src/site-access/resolve-site-access.use-case.ts
|
|
202
202
|
import { resolveAccess } from "@opencraw/cli";
|
|
203
203
|
async function resolveSiteAccess(params, runId, ask, env = process.env) {
|
|
204
|
-
const file = params.accessConfig ?? env.OPENCRAW_ACCESS;
|
|
205
|
-
if (file === void 0 && params.access !== void 0) throw new Error(`access profile "${params.access}" needs an access config:
|
|
204
|
+
const file = params.accessConfig ?? (env.OPENCRAW_ACCESS === "" ? void 0 : env.OPENCRAW_ACCESS);
|
|
205
|
+
if (file === void 0 && params.access !== void 0) throw new Error(`access profile "${params.access}" needs an access config, and there is none: no "accessConfig" was given, and OPENCRAW_ACCESS is not set where OpenCraw runs`);
|
|
206
206
|
const access = await resolveAccess({ insecureTls: false, access: file, accessProfile: params.access });
|
|
207
207
|
return { access, accessPlugins: clientAccessPlugins(params.accessPlugins ?? [], runId, ask) };
|
|
208
208
|
}
|
|
@@ -305,17 +305,17 @@ function streamingSink() {
|
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
// src/session/run-session.use-case.ts
|
|
308
|
-
function runSessions(notify, ask) {
|
|
308
|
+
function runSessions(notify, ask, local = {}) {
|
|
309
309
|
const running = /* @__PURE__ */ new Map();
|
|
310
310
|
let next = 1;
|
|
311
311
|
const crawlerFor = async (runId, params) => {
|
|
312
312
|
const { access, accessPlugins } = await resolveSiteAccess(params, runId, ask);
|
|
313
313
|
return createCrawler({
|
|
314
314
|
sink: params.out === void 0 ? streamingSink() : fileSink2(params.out, { append: params.append, browser: { executablePath: params.browser?.executablePath } }),
|
|
315
|
-
hooks: clientHooks(params.hooks ?? [], runId, ask),
|
|
316
|
-
captchaSolvers: clientCaptchaSolvers(params.captchaSolvers ?? [], runId, ask),
|
|
315
|
+
hooks: { ...local.hooks, ...clientHooks(params.hooks ?? [], runId, ask) },
|
|
316
|
+
captchaSolvers: [...local.captchaSolvers ?? [], ...clientCaptchaSolvers(params.captchaSolvers ?? [], runId, ask)],
|
|
317
317
|
access,
|
|
318
|
-
accessPlugins,
|
|
318
|
+
accessPlugins: [...local.accessPlugins ?? [], ...accessPlugins],
|
|
319
319
|
profilesDir: process.env.OPENCRAW_PROFILES,
|
|
320
320
|
parallel: params.parallel,
|
|
321
321
|
resume: params.resume,
|
|
@@ -341,15 +341,16 @@ function runSessions(notify, ask) {
|
|
|
341
341
|
}
|
|
342
342
|
})();
|
|
343
343
|
};
|
|
344
|
+
const startLoaded = async (loaded, params) => {
|
|
345
|
+
const set = params.dryRun === true ? new RecipeSet(loaded.output, loaded.inputs.map((input) => ({ ...input, limits: { ...input.limits, maxRecords: 1 } }))) : loaded;
|
|
346
|
+
const runId = `run-${next++}`;
|
|
347
|
+
const crawler = await crawlerFor(runId, params);
|
|
348
|
+
track(runId, crawler, async () => await crawler.run(set));
|
|
349
|
+
return runId;
|
|
350
|
+
};
|
|
344
351
|
return {
|
|
345
|
-
start: async (params) =>
|
|
346
|
-
|
|
347
|
-
const set = params.dryRun === true ? new RecipeSet(loaded.output, loaded.inputs.map((input) => ({ ...input, limits: { ...input.limits, maxRecords: 1 } }))) : loaded;
|
|
348
|
-
const runId = `run-${next++}`;
|
|
349
|
-
const crawler = await crawlerFor(runId, params);
|
|
350
|
-
track(runId, crawler, async () => await crawler.run(set));
|
|
351
|
-
return runId;
|
|
352
|
-
},
|
|
352
|
+
start: async (params) => await startLoaded(await loadRecipes(params), params),
|
|
353
|
+
startLoaded,
|
|
353
354
|
startWork: async (params) => {
|
|
354
355
|
const set = await loadRecipes(params);
|
|
355
356
|
const runId = `run-${next++}`;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -2,10 +2,12 @@ export { serveDriver } from './server/index.js';
|
|
|
2
2
|
export type { DriverIdentity } from './server/index.js';
|
|
3
3
|
export { PROTOCOL_VERSION, MESSAGES, driverProtocolJsonSchema, initializeParamsSchema, initializeResultSchema, validateParamsSchema, validateResultSchema, runParamsSchema, runResultSchema, cancelParamsSchema, cancelResultSchema, eventParamsSchema, recordParamsSchema, finishedParamsSchema, calloutParamsSchema, calloutResultSchema, probeParamsSchema, probeResultSchema, diffParamsSchema, diffResultSchema, exportParamsSchema, exportResultSchema, workParamsSchema, workItemSchema, workNextParamsSchema, workNextResultSchema, workDoneParamsSchema, workFailedParamsSchema, } from './protocol/index.js';
|
|
4
4
|
export type { InitializeParams, InitializeResult, ValidateParams, ValidateResult, RunParams, RunResult, CancelParams, CancelResult, EventParams, RecordParams, FinishedParams, CalloutParams, ProbeParams, DiffParams, DiffResult, ExportParams, ExportResult, WorkParams, WorkItemMessage, WorkNextResult, WorkDoneParams, WorkFailedParams, } from './protocol/index.js';
|
|
5
|
+
export { RUNTIME_PLATFORMS, runtimeManifestSchema, runtimeManifestJsonSchema } from './runtime-manifest/index.js';
|
|
6
|
+
export type { RuntimeManifest, RuntimePlatform } from './runtime-manifest/index.js';
|
|
5
7
|
export { openLineChannel, RPC_ERRORS, RpcFailure } from './transport/index.js';
|
|
6
8
|
export type { LineChannel, RequestHandler, RpcError, RpcMessage } from './transport/index.js';
|
|
7
9
|
export { runSessions, validateRecipes, streamingSink } from './session/index.js';
|
|
8
|
-
export type { RunSessions } from './session/index.js';
|
|
10
|
+
export type { LocalPlugins, RunSessions } from './session/index.js';
|
|
9
11
|
export { clientHooks, clientCaptchaSolvers, clientAccessPlugins } from './callout-bridge/index.js';
|
|
10
12
|
export type { AskClient, NotifyClient } from './callout-bridge/index.js';
|
|
11
13
|
export { clientWorkSource } from './work-bridge/index.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { RUNTIME_PLATFORMS, runtimeManifestSchema } from './runtime-manifest.contract.js';
|
|
2
|
+
export type { RuntimeManifest, RuntimePlatform } from './runtime-manifest.contract.js';
|
|
3
|
+
export { runtimeManifestJsonSchema } from './runtime-manifest-json-schema.mapper.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `driver-runtime.json`'s JSON Schema, written to `schemas/driver-runtime.schema.json`: what clients in
|
|
3
|
+
* other languages generate their manifest model from.
|
|
4
|
+
*
|
|
5
|
+
* @returns The schema.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runtimeManifestJsonSchema(): Record<string, unknown>;
|
|
8
|
+
//# sourceMappingURL=runtime-manifest-json-schema.mapper.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** The platforms the driver's runtime is built for: `<process.platform>-<process.arch>`. */
|
|
3
|
+
export declare const RUNTIME_PLATFORMS: readonly ['win32-x64', 'darwin-arm64', 'darwin-x64', 'linux-x64', 'linux-arm64'];
|
|
4
|
+
export type RuntimePlatform = typeof RUNTIME_PLATFORMS[number];
|
|
5
|
+
/**
|
|
6
|
+
* `driver-runtime.json`, an asset of each driver release beside the archives: what a client in any
|
|
7
|
+
* language reads to download the runtime for its platform, check it and start it. The archive holds a
|
|
8
|
+
* Node binary, the driver and its dependencies, and `runtime.json` (`command`: the Node binary and the
|
|
9
|
+
* driver's entry, both relative to the folder the archive is unpacked into).
|
|
10
|
+
*/
|
|
11
|
+
export declare const runtimeManifestSchema: z.ZodObject<{
|
|
12
|
+
driverVersion: z.ZodString;
|
|
13
|
+
protocolVersion: z.ZodString;
|
|
14
|
+
node: z.ZodString;
|
|
15
|
+
archives: z.ZodRecord<z.ZodEnum<{
|
|
16
|
+
"darwin-arm64": "darwin-arm64";
|
|
17
|
+
"darwin-x64": "darwin-x64";
|
|
18
|
+
"linux-arm64": "linux-arm64";
|
|
19
|
+
"linux-x64": "linux-x64";
|
|
20
|
+
"win32-x64": "win32-x64";
|
|
21
|
+
}> & z.core.$partial, z.ZodObject<{
|
|
22
|
+
file: z.ZodString;
|
|
23
|
+
sha256: z.ZodString;
|
|
24
|
+
size: z.ZodNumber;
|
|
25
|
+
}, z.core.$strict>>;
|
|
26
|
+
}, z.core.$strict>;
|
|
27
|
+
export type RuntimeManifest = z.infer<typeof runtimeManifestSchema>;
|
|
28
|
+
//# sourceMappingURL=runtime-manifest.contract.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { runSessions } from './run-session.use-case.js';
|
|
2
|
-
export type { RunSessions } from './run-session.use-case.js';
|
|
2
|
+
export type { LocalPlugins, RunSessions } from './run-session.use-case.js';
|
|
3
3
|
export { validateRecipes, hooksOf, loadRecipes, sourceOf } from './recipe-loading.use-case.js';
|
|
4
4
|
export { streamingSink } from './streaming-sink.repository.js';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
import { RecipeSet } from '@opencraw/core';
|
|
2
|
+
import type { AccessPlugin, CaptchaSolver, HookMap } from '@opencraw/core';
|
|
1
3
|
import type { AskClient, NotifyClient } from '../callout-bridge/index.js';
|
|
2
4
|
import type { RunParams, WorkParams } from '../protocol/index.js';
|
|
3
5
|
/** The runs a driver has going, by id, so `cancel` can reach them and `shutdown` close them all. */
|
|
4
6
|
export interface RunSessions {
|
|
5
7
|
start: (params: RunParams) => Promise<string>;
|
|
8
|
+
/** As `start`, for recipes the host has already loaded and bound (`params`' recipe source is ignored). */
|
|
9
|
+
startLoaded: (set: RecipeSet, params: Omit<RunParams, 'paths' | 'recipes'>) => Promise<string>;
|
|
6
10
|
startWork: (params: WorkParams) => Promise<string>;
|
|
7
11
|
cancel: (runId: string) => Promise<boolean>;
|
|
8
12
|
closeAll: () => Promise<void>;
|
|
9
13
|
}
|
|
14
|
+
/** What the host serves itself, in process, besides what the client serves: an MCP server's plugins module. */
|
|
15
|
+
export interface LocalPlugins {
|
|
16
|
+
hooks?: HookMap;
|
|
17
|
+
captchaSolvers?: CaptchaSolver[];
|
|
18
|
+
accessPlugins?: AccessPlugin[];
|
|
19
|
+
}
|
|
10
20
|
/**
|
|
11
21
|
* Starts and tracks runs and worker pools. `start` and `startWork` load and bind the recipes (a bad
|
|
12
22
|
* recipe fails the request itself, with its problems), answer with a run id at once, and crawl in the
|
|
@@ -18,7 +28,8 @@ export interface RunSessions {
|
|
|
18
28
|
*
|
|
19
29
|
* @param notify - The channel's notify.
|
|
20
30
|
* @param ask - The channel's request, for callouts and work.
|
|
31
|
+
* @param local - Hooks, captcha solvers and access plugins the host serves itself, beside the client's.
|
|
21
32
|
* @returns The sessions.
|
|
22
33
|
*/
|
|
23
|
-
export declare function runSessions(notify: NotifyClient, ask: AskClient): RunSessions;
|
|
34
|
+
export declare function runSessions(notify: NotifyClient, ask: AskClient, local?: LocalPlugins): RunSessions;
|
|
24
35
|
//# sourceMappingURL=run-session.use-case.d.ts.map
|
package/package.json
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"driverVersion": "0.6.0",
|
|
3
|
+
"protocolVersion": "1.2.0",
|
|
4
|
+
"node": "v24.12.0",
|
|
5
|
+
"archives": {
|
|
6
|
+
"linux-x64": { "file": "opencraw-driver-0.6.0-linux-x64.tar.gz", "sha256": "697d28005ed87b2887cf79edca25f06da89ab19bcb48f49c0a67dbdbcb004ad7", "size": 65410362 },
|
|
7
|
+
"win32-x64": { "file": "opencraw-driver-0.6.0-win32-x64.tar.gz", "sha256": "0f1e2d3c4b5a69788796a5b4c3d2e1f00f1e2d3c4b5a69788796a5b4c3d2e1f0", "size": 66120448 }
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://opencraw.dev/schemas/driver-runtime.schema.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"driverVersion": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"minLength": 1
|
|
9
|
+
},
|
|
10
|
+
"protocolVersion": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$"
|
|
13
|
+
},
|
|
14
|
+
"node": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"pattern": "^v\\d+\\.\\d+\\.\\d+$"
|
|
17
|
+
},
|
|
18
|
+
"archives": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"propertyNames": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"enum": [
|
|
23
|
+
"win32-x64",
|
|
24
|
+
"darwin-arm64",
|
|
25
|
+
"darwin-x64",
|
|
26
|
+
"linux-x64",
|
|
27
|
+
"linux-arm64"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"additionalProperties": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"properties": {
|
|
33
|
+
"file": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"pattern": "^opencraw-driver-[\\w.-]+\\.tar\\.gz$"
|
|
36
|
+
},
|
|
37
|
+
"sha256": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"pattern": "^[0-9a-f]{64}$"
|
|
40
|
+
},
|
|
41
|
+
"size": {
|
|
42
|
+
"type": "integer",
|
|
43
|
+
"exclusiveMinimum": 0,
|
|
44
|
+
"maximum": 9007199254740991
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"required": [
|
|
48
|
+
"file",
|
|
49
|
+
"sha256",
|
|
50
|
+
"size"
|
|
51
|
+
],
|
|
52
|
+
"additionalProperties": false
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"required": [
|
|
57
|
+
"driverVersion",
|
|
58
|
+
"protocolVersion",
|
|
59
|
+
"node",
|
|
60
|
+
"archives"
|
|
61
|
+
],
|
|
62
|
+
"additionalProperties": false
|
|
63
|
+
}
|