@jinn-network/sdk 0.1.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 ADDED
@@ -0,0 +1,61 @@
1
+ # @jinn-network/sdk
2
+
3
+ Stable SDK surface for Jinn SolverNets, Harnesses, plugins, and typed
4
+ payloads.
5
+
6
+ Runtime internals live in `@jinn-network/client`. The SDK builds, validates,
7
+ describes, and prepares; the client runs, stores, posts, claims, signs,
8
+ submits, and watches.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install @jinn-network/sdk
14
+ ```
15
+
16
+ ## Harness authoring
17
+
18
+ ```ts
19
+ import type {
20
+ Harness,
21
+ ExternalHarnessEnv,
22
+ HarnessContext,
23
+ Solution,
24
+ } from '@jinn-network/sdk/harness';
25
+ import { buildSolutionOutput } from '@jinn-network/sdk/solvernets/prediction-v1';
26
+
27
+ export default function createHarness(env: ExternalHarnessEnv): Harness {
28
+ return {
29
+ name: env.implName,
30
+ version: env.implVersion,
31
+ supports: ({ solverType, role }) =>
32
+ solverType === 'prediction.v1' && role !== 'evaluation',
33
+ async run(ctx: HarnessContext): Promise<Solution> {
34
+ return buildSolutionOutput({
35
+ solverType: 'prediction.v1',
36
+ venueName: 'polymarket',
37
+ payload: {
38
+ probabilityYes: '0.50',
39
+ submittedAt: new Date().toISOString(),
40
+ format: 'decimal',
41
+ modelId: 'example-harness',
42
+ },
43
+ });
44
+ },
45
+ };
46
+ }
47
+ ```
48
+
49
+ ## Public subpaths
50
+
51
+ - `@jinn-network/sdk/harness` — Harness interfaces, context, capability
52
+ handles, and signed Harness manifest types.
53
+ - `@jinn-network/sdk/solvernets` — SolverNet contract registry, validation, and
54
+ generic typed output builders.
55
+ - `@jinn-network/sdk/solvernets/prediction-v1` — first-party Prediction v1
56
+ schemas, payload types, validation, and output helpers.
57
+ - `@jinn-network/sdk/plugins` — SolverPlugin manifest types and validation
58
+ helpers for normal AI tooling plugins.
59
+
60
+ The daemon still performs final runtime validation, envelope assembly, signing,
61
+ storage, and submission.
@@ -0,0 +1,52 @@
1
+ import type { Address, Hex } from './types.js';
2
+ export interface SignTypedDataArgs {
3
+ domain: {
4
+ name?: string;
5
+ version?: string;
6
+ chainId?: number;
7
+ verifyingContract?: Address;
8
+ };
9
+ types: Record<string, Array<{
10
+ name: string;
11
+ type: string;
12
+ }>>;
13
+ primaryType: string;
14
+ message: Record<string, unknown>;
15
+ }
16
+ /**
17
+ * The runtime gate on `ScopedSigner.signTypedData` is enforced
18
+ * daemon-side: the daemon constructs the signer with an allow-list
19
+ * derived from the manifest's `capabilities.signer.typedDataDomains`
20
+ * (see {@link TypedDataAllowEntry} on `manifest.ts`) and refuses any
21
+ * domain not on the list. An impl that ships no `typedDataDomains`
22
+ * entry cannot call `signTypedData` at all (default-deny). The
23
+ * `ScopedSigner` interface itself is unchanged — the gate lives in
24
+ * the construction args, not the contract surface.
25
+ */
26
+ export interface SendAllowedCallArgs {
27
+ to: Address;
28
+ data: Hex;
29
+ value?: bigint;
30
+ }
31
+ export interface ScopedSigner {
32
+ readonly address: Address;
33
+ signTypedData(args: SignTypedDataArgs): Promise<Hex>;
34
+ sendAllowedCall(call: SendAllowedCallArgs): Promise<Hex>;
35
+ }
36
+ export interface ScopedRpc {
37
+ readContract(args: {
38
+ address: Address;
39
+ abi: readonly unknown[];
40
+ functionName: string;
41
+ args?: readonly unknown[];
42
+ }): Promise<unknown>;
43
+ getBlockNumber(): Promise<bigint>;
44
+ getBalance(args: {
45
+ address: Address;
46
+ }): Promise<bigint>;
47
+ getCode(args: {
48
+ address: Address;
49
+ }): Promise<Hex | undefined>;
50
+ getChainId(): Promise<number>;
51
+ }
52
+ export type ScopedSecrets = Readonly<Record<string, string>>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,107 @@
1
+ import type { z } from 'zod';
2
+ import type { OutputArtifact, RationaleEntry, Solution } from './types.js';
3
+ import { type PredictionV1Task } from './prediction-v1.js';
4
+ import { type PredictionV1RestorationPayload, type PredictionV1VerdictPayload } from './payloads/prediction-v1.js';
5
+ export type SolverNetContractRole = 'creator' | 'solver' | 'evaluator';
6
+ export type PayloadKind = 'task' | 'solution' | 'verdict';
7
+ export type SupportedSolverType = 'prediction.v1';
8
+ export interface CredentialRequirement {
9
+ id: string;
10
+ kind: 'public-api' | 'client-owned' | 'operator-credential';
11
+ required: boolean;
12
+ description: string;
13
+ }
14
+ export interface SolverNetEvaluationFunction {
15
+ id: string;
16
+ deterministic: boolean;
17
+ inputs: readonly string[];
18
+ output: string;
19
+ implementation: string;
20
+ }
21
+ export interface SolverNetAggregationFunction {
22
+ id: string;
23
+ deterministic: boolean;
24
+ inputs: readonly string[];
25
+ output: string;
26
+ windowDays?: number;
27
+ }
28
+ export interface SolverNetClaimPolicyDefaults {
29
+ kind: string;
30
+ maxClaims: number;
31
+ maxClaimsPerSolver: number;
32
+ claimWindow: string;
33
+ selection: string;
34
+ economics: string;
35
+ }
36
+ export interface SolverNetContract {
37
+ name: string;
38
+ solverType: SupportedSolverType;
39
+ schemas: {
40
+ task: z.ZodTypeAny;
41
+ solution: z.ZodTypeAny;
42
+ verdict: z.ZodTypeAny;
43
+ };
44
+ claimPolicyDefaults: SolverNetClaimPolicyDefaults;
45
+ credentialRequirements: Record<SolverNetContractRole, CredentialRequirement[]>;
46
+ evaluationFunction: SolverNetEvaluationFunction;
47
+ aggregationFunction: SolverNetAggregationFunction;
48
+ referencePlugins: string[];
49
+ }
50
+ export type SolverNetContractMap = Record<SupportedSolverType, SolverNetContract>;
51
+ export declare const PREDICTION_V1_SOLVER_NET_CONTRACT: SolverNetContract;
52
+ export declare const SOLVER_NET_CONTRACTS: SolverNetContractMap;
53
+ export declare function getSolverNetContract(solverType: string): SolverNetContract | undefined;
54
+ export interface PayloadValidationIssue {
55
+ path: string;
56
+ message: string;
57
+ }
58
+ export interface PayloadValidationFailure {
59
+ ok: false;
60
+ error: {
61
+ code: 'unsupported_solver_type' | 'invalid_payload';
62
+ message: string;
63
+ issues: PayloadValidationIssue[];
64
+ };
65
+ }
66
+ export interface PayloadValidationSuccess<T> {
67
+ ok: true;
68
+ value: T;
69
+ }
70
+ export type PayloadValidationResult<T> = PayloadValidationSuccess<T> | PayloadValidationFailure;
71
+ export declare class PayloadValidationException extends Error {
72
+ readonly code: 'unsupported_solver_type' | 'invalid_payload';
73
+ readonly issues: PayloadValidationIssue[];
74
+ constructor(code: 'unsupported_solver_type' | 'invalid_payload', message: string, issues?: PayloadValidationIssue[]);
75
+ }
76
+ export declare function validateTask(solverType: 'prediction.v1', task: unknown): PayloadValidationResult<PredictionV1Task>;
77
+ export declare function validateTask(solverType: string, task: unknown): PayloadValidationResult<unknown>;
78
+ export declare function assertTask(solverType: 'prediction.v1', task: unknown): PredictionV1Task;
79
+ export declare function assertTask(solverType: string, task: unknown): unknown;
80
+ export declare function validateSolutionPayload(solverType: 'prediction.v1', payload: unknown): PayloadValidationResult<PredictionV1RestorationPayload>;
81
+ export declare function validateSolutionPayload(solverType: string, payload: unknown): PayloadValidationResult<Record<string, unknown>>;
82
+ export declare function assertSolutionPayload(solverType: 'prediction.v1', payload: unknown): PredictionV1RestorationPayload;
83
+ export declare function assertSolutionPayload(solverType: string, payload: unknown): Record<string, unknown>;
84
+ export declare function validateVerdictPayload(solverType: 'prediction.v1', payload: unknown): PayloadValidationResult<PredictionV1VerdictPayload>;
85
+ export declare function validateVerdictPayload(solverType: string, payload: unknown): PayloadValidationResult<Record<string, unknown>>;
86
+ export declare function assertVerdictPayload(solverType: 'prediction.v1', payload: unknown): PredictionV1VerdictPayload;
87
+ export declare function assertVerdictPayload(solverType: string, payload: unknown): Record<string, unknown>;
88
+ export interface BuildSolutionOutputArgs {
89
+ solverType: string;
90
+ venueName: string;
91
+ payload: Record<string, unknown>;
92
+ gating?: Record<string, unknown>;
93
+ informational?: Record<string, unknown>;
94
+ artifacts?: OutputArtifact[];
95
+ rationale?: RationaleEntry[];
96
+ }
97
+ export declare function buildSolutionOutput(args: BuildSolutionOutputArgs): Solution;
98
+ export interface BuildVerdictOutputArgs {
99
+ solverType: string;
100
+ venueName?: string;
101
+ payload: Record<string, unknown>;
102
+ gating?: Record<string, unknown>;
103
+ informational?: Record<string, unknown>;
104
+ artifacts?: OutputArtifact[];
105
+ rationale?: RationaleEntry[];
106
+ }
107
+ export declare function buildVerdictOutput(args: BuildVerdictOutputArgs): Solution;
@@ -0,0 +1,149 @@
1
+ import { PredictionV1TaskSchema } from './prediction-v1.js';
2
+ import { PredictionV1RestorationPayloadSchema, PredictionV1VerdictPayloadSchema, } from './payloads/prediction-v1.js';
3
+ export const PREDICTION_V1_SOLVER_NET_CONTRACT = {
4
+ name: 'Prediction',
5
+ solverType: 'prediction.v1',
6
+ schemas: {
7
+ task: PredictionV1TaskSchema,
8
+ solution: PredictionV1RestorationPayloadSchema,
9
+ verdict: PredictionV1VerdictPayloadSchema,
10
+ },
11
+ claimPolicyDefaults: {
12
+ kind: 'parallel',
13
+ maxClaims: 25,
14
+ maxClaimsPerSolver: 1,
15
+ claimWindow: 'task-window',
16
+ selection: 'all-valid-solutions-scored',
17
+ economics: 'testnet-flat',
18
+ },
19
+ credentialRequirements: {
20
+ creator: [
21
+ {
22
+ id: 'polymarket.public.market-data.read',
23
+ kind: 'public-api',
24
+ required: true,
25
+ description: 'Read public Polymarket market metadata and orderbook snapshots for Task creation.',
26
+ },
27
+ ],
28
+ solver: [],
29
+ evaluator: [
30
+ {
31
+ id: 'polymarket.public.resolution.read',
32
+ kind: 'public-api',
33
+ required: true,
34
+ description: 'Read public Polymarket/UMA final market state for resolution mapping.',
35
+ },
36
+ ],
37
+ },
38
+ evaluationFunction: {
39
+ id: 'prediction.brier-loss.v1',
40
+ deterministic: true,
41
+ inputs: ['prediction.v1 Task', 'prediction.v1 Solution', 'Polymarket/UMA resolution'],
42
+ output: 'prediction.v1 Verdict',
43
+ implementation: 'client/src/harnesses/impls/prediction-v1-evaluator',
44
+ },
45
+ aggregationFunction: {
46
+ id: 'prediction.trailing-mean-brier-spread.v1',
47
+ deterministic: true,
48
+ inputs: ['SCORED prediction.v1 Verdicts'],
49
+ output: 'trailing mean brierSpread',
50
+ windowDays: 84,
51
+ },
52
+ referencePlugins: ['bundled:jinn-prediction-plugin'],
53
+ };
54
+ export const SOLVER_NET_CONTRACTS = {
55
+ 'prediction.v1': PREDICTION_V1_SOLVER_NET_CONTRACT,
56
+ };
57
+ export function getSolverNetContract(solverType) {
58
+ return SOLVER_NET_CONTRACTS[solverType];
59
+ }
60
+ export class PayloadValidationException extends Error {
61
+ code;
62
+ issues;
63
+ constructor(code, message, issues = []) {
64
+ super(message);
65
+ this.name = 'PayloadValidationException';
66
+ this.code = code;
67
+ this.issues = issues;
68
+ }
69
+ }
70
+ function issuesFrom(error) {
71
+ return error.issues.map((issue) => ({
72
+ path: issue.path.length > 0 ? issue.path.join('.') : '<root>',
73
+ message: issue.message,
74
+ }));
75
+ }
76
+ function getSchema(solverType, kind) {
77
+ return getSolverNetContract(solverType)?.schemas[kind];
78
+ }
79
+ function validateWithSchema(solverType, kind, value) {
80
+ const schema = getSchema(solverType, kind);
81
+ if (!schema) {
82
+ return {
83
+ ok: false,
84
+ error: {
85
+ code: 'unsupported_solver_type',
86
+ message: `Unsupported SolverType for ${kind} validation: ${solverType}`,
87
+ issues: [],
88
+ },
89
+ };
90
+ }
91
+ const parsed = schema.safeParse(value);
92
+ if (!parsed.success) {
93
+ const issues = issuesFrom(parsed.error);
94
+ return {
95
+ ok: false,
96
+ error: {
97
+ code: 'invalid_payload',
98
+ message: `${solverType} ${kind} failed validation: ${issues.map((issue) => `${issue.path}: ${issue.message}`).join('; ')}`,
99
+ issues,
100
+ },
101
+ };
102
+ }
103
+ return { ok: true, value: parsed.data };
104
+ }
105
+ function assertValid(result) {
106
+ if (result.ok)
107
+ return result.value;
108
+ throw new PayloadValidationException(result.error.code, result.error.message, result.error.issues);
109
+ }
110
+ export function validateTask(solverType, task) {
111
+ return validateWithSchema(solverType, 'task', task);
112
+ }
113
+ export function assertTask(solverType, task) {
114
+ return assertValid(validateTask(solverType, task));
115
+ }
116
+ export function validateSolutionPayload(solverType, payload) {
117
+ return validateWithSchema(solverType, 'solution', payload);
118
+ }
119
+ export function assertSolutionPayload(solverType, payload) {
120
+ return assertValid(validateSolutionPayload(solverType, payload));
121
+ }
122
+ export function validateVerdictPayload(solverType, payload) {
123
+ return validateWithSchema(solverType, 'verdict', payload);
124
+ }
125
+ export function assertVerdictPayload(solverType, payload) {
126
+ return assertValid(validateVerdictPayload(solverType, payload));
127
+ }
128
+ export function buildSolutionOutput(args) {
129
+ const payload = assertSolutionPayload(args.solverType, args.payload);
130
+ return {
131
+ venueRef: { name: args.venueName },
132
+ gating: args.gating ?? {},
133
+ ...(args.informational ? { informational: args.informational } : {}),
134
+ solutionPayload: payload,
135
+ ...(args.artifacts ? { artifacts: args.artifacts } : {}),
136
+ ...(args.rationale ? { rationale: args.rationale } : {}),
137
+ };
138
+ }
139
+ export function buildVerdictOutput(args) {
140
+ const payload = assertVerdictPayload(args.solverType, args.payload);
141
+ return {
142
+ venueRef: { name: args.venueName ?? 'jinn-evaluator' },
143
+ gating: args.gating ?? {},
144
+ ...(args.informational ? { informational: args.informational } : {}),
145
+ verdictPayload: payload,
146
+ ...(args.artifacts ? { artifacts: args.artifacts } : {}),
147
+ ...(args.rationale ? { rationale: args.rationale } : {}),
148
+ };
149
+ }
@@ -0,0 +1,69 @@
1
+ export type { Address, Hex, IntentWindow, Task, OutputArtifact, RationaleEntry, Solution, TrajectoryCollector, TrajectorySpanInput, ReadyStatus, EnableArgDef, IntentEnableMetadata, EnableResult, } from './types.js';
2
+ export { REQUIRES_LIVE_DAEMON_READINESS, SkippableError } from './types.js';
3
+ export type { SignTypedDataArgs, SendAllowedCallArgs, ScopedSigner, ScopedRpc, ScopedSecrets, } from './capabilities.js';
4
+ export type { CapabilityAllowEntry, ManifestRpcAllow, ManifestSecretSpec, TypedDataAllowEntry, JinnManifest, } from './manifest.js';
5
+ import type { Task, Solution, TrajectoryCollector, ReadyStatus, IntentEnableMetadata, EnableResult } from './types.js';
6
+ import type { ScopedSigner, ScopedRpc, ScopedSecrets } from './capabilities.js';
7
+ export interface HarnessContext {
8
+ task: Task;
9
+ taskCid?: string;
10
+ implStateDir: string;
11
+ workingDir: string;
12
+ log: (event: {
13
+ level: 'info' | 'warn' | 'error';
14
+ msg: string;
15
+ data?: unknown;
16
+ }) => void;
17
+ abort: AbortSignal;
18
+ msUntilEndTs: () => number;
19
+ trajectory: TrajectoryCollector;
20
+ signer?: ScopedSigner;
21
+ rpc?: ScopedRpc;
22
+ secrets?: ScopedSecrets;
23
+ }
24
+ /**
25
+ * Construction-time environment passed to the impl factory.
26
+ * Per-attempt Task inputs are provided through HarnessContext.
27
+ */
28
+ export interface ExternalHarnessEnv {
29
+ readonly implName: string;
30
+ readonly implVersion: string;
31
+ readonly network: string;
32
+ readonly implStateDir: string;
33
+ readonly secrets: ScopedSecrets;
34
+ readonly log: HarnessContext['log'];
35
+ /** True for CLI introspection; impls should report stub readiness. */
36
+ readonly stub: boolean;
37
+ }
38
+ export interface Harness {
39
+ name: string;
40
+ version: string;
41
+ supports(ctx: {
42
+ solverType: string;
43
+ role?: 'restoration' | 'evaluation';
44
+ }): boolean;
45
+ canAttempt?(task: Task): Promise<{
46
+ ok: true;
47
+ } | {
48
+ ok: false;
49
+ reason: string;
50
+ }>;
51
+ run(ctx: HarnessContext): Promise<Solution>;
52
+ isReady?(spec?: {
53
+ solverType: string;
54
+ role?: 'restoration' | 'evaluation';
55
+ }): Promise<ReadyStatus>;
56
+ enableMetadata?(): IntentEnableMetadata;
57
+ onEnable?(args: Record<string, string | undefined>, spec?: {
58
+ solverType: string;
59
+ role?: 'restoration' | 'evaluation';
60
+ }): Promise<EnableResult>;
61
+ onDisable?(spec?: {
62
+ solverType: string;
63
+ role?: 'restoration' | 'evaluation';
64
+ }): Promise<void>;
65
+ }
66
+ /**
67
+ * External-impl factory: default-export shape for external Harness packages.
68
+ */
69
+ export type ExternalHarnessFactory = (env: ExternalHarnessEnv) => Harness;
@@ -0,0 +1 @@
1
+ export { REQUIRES_LIVE_DAEMON_READINESS, SkippableError } from './types.js';
@@ -0,0 +1,2 @@
1
+ export type { Address, Hex, IntentWindow, Task, OutputArtifact, RationaleEntry, Solution, TrajectoryCollector, TrajectorySpanInput, ReadyStatus, EnableArgDef, IntentEnableMetadata, EnableResult, } from './types.js';
2
+ export { REQUIRES_LIVE_DAEMON_READINESS, SkippableError } from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // @jinn-network/sdk
2
+ //
3
+ // Minimal generic SDK root. Use role-oriented subpaths for execution,
4
+ // SolverNet, plugin, and first-party SolverNet helpers.
5
+ export { REQUIRES_LIVE_DAEMON_READINESS, SkippableError } from './types.js';
@@ -0,0 +1,69 @@
1
+ export interface CapabilityAllowEntry {
2
+ chainId: number;
3
+ to: `0x${string}`;
4
+ selector: `0x${string}`;
5
+ description?: string;
6
+ }
7
+ /**
8
+ * EIP-712 typed-data domain allow-list entry.
9
+ *
10
+ * The daemon's scoped signer refuses any `signTypedData` call whose
11
+ * domain does not match one of these entries:
12
+ * - `chainId` MUST match exactly.
13
+ * - `verifyingContract` / `name` / `version` match only when set on
14
+ * the entry; an unset field on the entry means "any value".
15
+ * - An empty / omitted `typedDataDomains` array means default-deny:
16
+ * every `signTypedData` call throws.
17
+ */
18
+ export interface TypedDataAllowEntry {
19
+ chainId: number;
20
+ name?: string;
21
+ version?: string;
22
+ verifyingContract?: `0x${string}`;
23
+ }
24
+ export interface ManifestRpcAllow {
25
+ chainId: number;
26
+ methods: ReadonlyArray<'eth_call' | 'eth_getBlockByNumber' | 'eth_getLogs' | 'eth_getTransactionReceipt' | 'eth_chainId' | 'eth_blockNumber' | 'eth_getBalance' | 'eth_getCode'>;
27
+ rateLimit?: {
28
+ perSec: number;
29
+ };
30
+ }
31
+ export interface ManifestSecretSpec {
32
+ name: string;
33
+ description: string;
34
+ required: boolean;
35
+ }
36
+ export interface JinnManifest {
37
+ schemaVersion: '1.0.0';
38
+ name: string;
39
+ version: string;
40
+ description?: string;
41
+ /** Each entry follows `<domain>.v<major>(>=<semver>)` from spec/2026-05-schema-versioning.md. */
42
+ supportedSolverTypes: readonly string[];
43
+ /** Path to the entrypoint module, relative to the package root. */
44
+ entry: string;
45
+ /** Tarball CID + sha256 (set at publish time). */
46
+ package: {
47
+ cid: string;
48
+ hash: `sha256:${string}`;
49
+ };
50
+ capabilities: {
51
+ signer?: {
52
+ selectors: ReadonlyArray<CapabilityAllowEntry>;
53
+ typedDataDomains?: ReadonlyArray<TypedDataAllowEntry>;
54
+ };
55
+ rpc?: ReadonlyArray<ManifestRpcAllow>;
56
+ secrets?: ReadonlyArray<ManifestSecretSpec>;
57
+ };
58
+ /** Detached signature object — not part of the canonicalised manifest. */
59
+ signature: {
60
+ alg: 'ed25519';
61
+ publicKey: string;
62
+ sig: string;
63
+ };
64
+ author?: {
65
+ name: string;
66
+ url?: string;
67
+ };
68
+ license?: string;
69
+ }
@@ -0,0 +1,3 @@
1
+ // JinnManifest — the signed package manifest each external Harness ships.
2
+ // See `spec/2026-05-executor-trust-boundary.md` §5.
3
+ export {};