Validating a Job Definition
The SDK ships a validator for job definitions, so you can catch mistakes locally before uploading anything to IPFS or spending credits on a job or deployment.
validateJobDefinition is exported from @nosana/kit (and from the standalone @nosana/types package). It checks an unknown value against the full job definition schema:
- Strict: unknown or misspelled properties are rejected, not silently ignored
- Complete: every field is checked against the schema, including nested
opsarguments - Unique op ids: duplicate
idvalues across operations are reported as errors
Usage
import { const validateJobDefinition: (input: unknown) => IValidation<JobDefinitionWithRule>validateJobDefinition } from '@nosana/kit';
const const result: IValidation<JobDefinitionWithRule>result = function validateJobDefinition(input: unknown): IValidation<JobDefinitionWithRule>validateJobDefinition({
version: stringversion: '0.1',
type: stringtype: 'container',
ops: {
type: string;
id: string;
args: {
cmd: string;
image: string;
};
}[]
ops: [
{
type: stringtype: 'container/run',
id: stringid: 'hello-world',
args: {
cmd: string;
image: string;
}
args: {
cmd: stringcmd: 'echo hello world',
image: stringimage: 'ubuntu',
},
},
],
});
if (const result: IValidation<JobDefinitionWithRule>result.success: booleanIndicates validation failure
Indicates validation successsuccess) {
// result.data is a fully-typed JobDefinition
var console: ConsoleThe `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v24.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v24.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v24.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args) for more information.log('Valid job definition with', const result: IValidation.ISuccess<JobDefinitionWithRule>result.IValidation<T = unknown>.ISuccess<JobDefinitionWithRule>.data: JobDefinitionWithRuleThe validated data of type Tdata.ops: Ops & UniqueById & GpuTeeConflictops.Array<Operation<keyof OperationArgsMap>>.length: numberGets or sets the length of the array. This is a number one higher than the highest index in the array.length, 'op(s)');
} else {
// Each error tells you where it is, what was expected, and what was found
for (const const error: IValidation.IErrorerror of const result: IValidation.IFailureresult.IValidation<T = unknown>.IFailure.errors: IValidation.IError[]Array of detailed validation errorserrors) {
var console: ConsoleThe `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v24.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v24.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v24.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)Prints to `stderr` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args)).
```js
const code = 5;
console.error('error #%d', code);
// Prints: error #5, to stderr
console.error('error', code);
// Prints: error 5, to stderr
```
If formatting elements (e.g. `%d`) are not found in the first string then
[`util.inspect()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilinspectobject-options) is called on each argument and the
resulting string values are concatenated. See [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args)
for more information.error(`${const error: IValidation.IErrorerror.IValidation<T = unknown>.IError.path: stringThe path to the property that failed validation
Dot-notation path using $input prefix indicating the exact location of
the validation failure within the input object structure. Examples
include "$input.member.age", "$input.categories[0]",
"$input.user.profile.email"path}: expected ${const error: IValidation.IErrorerror.IValidation<T = unknown>.IError.expected: stringThe expected type name or type expression
Technical type specification that describes what type was expected at
this path. This follows TypeScript-like syntax with embedded constraint
information, such as "string", "number & Type<'uint32'>",
"Array<string>", "string & Format<'uuid'> & MinLength<8>", etc.expected}`);
}
}On failure, each entry in errors contains:
| Field | Description |
|---|---|
path | Where in the document the error is (e.g. $input.ops[0].args.image) |
expected | The type or value the schema expects at that path |
value | The value that was actually found |
Validate before posting
Validation is most useful right before you spend credits — as a gate in front of posting a job or creating a deployment:
const const result: IValidation<JobDefinitionWithRule>result = function validateJobDefinition(input: unknown): IValidation<JobDefinitionWithRule>validateJobDefinition(const jobDefinitionJson: unknownjobDefinitionJson);
if (!const result: IValidation<JobDefinitionWithRule>result.success: booleanIndicates validation failure
Indicates validation successsuccess) {
throw new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error(
`Invalid job definition:\n` +
const result: IValidation.IFailureresult.IValidation<T = unknown>.IFailure.errors: IValidation.IError[]Array of detailed validation errorserrors.Array<IValidation<T = unknown>.IError>.map<string>(callbackfn: (value: IValidation<T = unknown>.IError, index: number, array: IValidation.IError[]) => string, thisArg?: any): string[]Calls a defined callback function on each element of an array, and returns an array that contains the results.map((e: IValidation.IErrore) => ` ${e: IValidation.IErrore.IValidation<T = unknown>.IError.path: stringThe path to the property that failed validation
Dot-notation path using $input prefix indicating the exact location of
the validation failure within the input object structure. Examples
include "$input.member.age", "$input.categories[0]",
"$input.user.profile.email"path}: expected ${e: IValidation.IErrore.IValidation<T = unknown>.IError.expected: stringThe expected type name or type expression
Technical type specification that describes what type was expected at
this path. This follows TypeScript-like syntax with embedded constraint
information, such as "string", "number & Type<'uint32'>",
"Array<string>", "string & Format<'uuid'> & MinLength<8>", etc.expected}`).Array<string>.join(separator?: string): stringAdds all the elements of an array into a string, separated by the specified separator string.join('\n'),
);
}
// Safe to upload and post — result.data is a valid JobDefinition
const const ipfsHash: stringipfsHash = await const client: NosanaClientclient.NosanaClient.ipfs: NosanaIpfsClientipfs.pin: (data: object) => Promise<string>pin(const result: IValidation.ISuccess<JobDefinitionWithRule>result.IValidation<T = unknown>.ISuccess<JobDefinitionWithRule>.data: JobDefinitionWithRuleThe validated data of type Tdata);
const const job: {
tx: string;
job: string;
run: string;
credits: {
costUSD: number;
creditsUsed: number;
reservationId: string;
project: string;
};
}
job = await const client: NosanaClientclient.NosanaClient.api: NosanaApiClientapi.jobs: NosanaJobsApijobs.list: (request: NosanaApiListJobRequest, options?: NosanaJobActionOptions) => Promise<NosanaApiListJobResponse>list({
ipfsHash: stringipfsHash,
market: stringmarket: 'CA5pMpqkYFKtme7K31pNB1s62X2SdhEv1nN9RdxKCpuQ',
});This is especially valuable when the job definition comes from outside your code — a JSON file, a template, user input, or an API — where TypeScript can't check it at compile time.
JSON Schemas (jobSchemas)
If you want to validate outside TypeScript — in CI pipelines, other languages, or editors — the SDK also exports the job definition as OpenAPI 3.0 JSON Schemas:
import { const jobSchemas: IJsonSchemaCollection.IV3_0<[JobDefinition, FlowState]>jobSchemas } from '@nosana/kit';
// OpenAPI 3.0 JSON Schemas for JobDefinition and FlowState
var console: ConsoleThe `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v24.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v24.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v24.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args) for more information.log(var JSON: JSONAn intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.JSON.JSON.stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string (+1 overload)Converts a JavaScript value to a JavaScript Object Notation (JSON) string.stringify(const jobSchemas: IJsonSchemaCollection.IV3_0<[JobDefinition, FlowState]>jobSchemas, null, 2));You can feed these schemas to any JSON Schema validator (Ajv, jsonschema, an IDE's YAML/JSON language server, and so on) to get the same structural checks without running TypeScript.