import { type ConvertTypesForDb } from '../../../utils/index.js'; import type { Address, Instruction, TransactionSigner } from '@solana/kit'; import type { ProgramDeps } from '../../../types.js'; import type { BatchTransactionResult, SignedBatchTransaction } from '../../solana/SolanaService.js'; import { type DecodedJobsInstruction } from './decode.js'; import type { ProgramConfig } from '../../../config/types.js'; import * as Instructions from './instructions/index.js'; import * as programClient from '@nosana/jobs-program'; import type { SimpleMonitorEvent, MonitorEvent } from './monitor/index.js'; export declare enum JobState { QUEUED = 0, RUNNING = 1, COMPLETED = 2, STOPPED = 3 } export declare enum MarketQueueType { JOB_QUEUE = 0, NODE_QUEUE = 1 } export type Job = Omit, 'state'> & { address: Address; state: JobState; }; export type Market = Omit, 'queueType'> & { address: Address; queueType: MarketQueueType; }; export type Run = ConvertTypesForDb & { address: Address; }; export { MonitorEventType } from './monitor/index.js'; export type { SimpleMonitorEvent, MonitorEvent } from './monitor/index.js'; export type PostParams = Instructions.ListParams | Instructions.AssignParams; export type PostInstruction = Instructions.ListInstruction | Instructions.AssignInstruction; export type { DecodedJobsInstruction } from './decode.js'; /** * A {@link BatchTransactionResult} enriched with the decoded jobs instructions it * contained. `decoded[i]` corresponds to `instructions[i]` and is `undefined` for * any instruction that is not a recognised jobs instruction. * * Use it to recover accounts a transaction created or acted on — e.g. the `job` * and `run` addresses minted by each `list` — without a separate `*Many` helper. * @group @nosana/kit */ export interface JobsBatchTransactionResult extends BatchTransactionResult { /** Each instruction in the transaction, decoded to its name and labelled accounts. */ decoded: Array; /** * All accounts the transaction's instructions referenced, grouped by their * (pluralised) role name across every instruction in the transaction — e.g. * `accounts.jobs` is every `job` address, `accounts.runs` every `run`. This is * the quick "just give me the created jobs" view; use {@link decoded} together * with `groupIndices` when you need to tie an account back to a specific input. */ accounts: Record; } /** * A {@link SignedBatchTransaction} enriched with the same decoded view as * {@link JobsBatchTransactionResult}, so the per-bucket job/run addresses are * available without decoding the raw instructions. Returned by {@link JobsProgram.signBatch}. * @group @nosana/kit */ export interface SignedJobsBatchTransaction extends SignedBatchTransaction { /** Each instruction in the transaction, decoded to its name and labelled accounts. */ decoded: Array; /** Accounts grouped by pluralised role (e.g. `accounts.jobs`, `accounts.runs`). See {@link JobsBatchTransactionResult.accounts}. */ accounts: Record; } export declare const JOB_POSTING_NETWORK_FEE = 0.1; /** * Returns the current network fee ratio applied when posting jobs. * A value of 0.1 represents a 10% fee. * @group @nosana/kit */ export declare function getNetworkFee(): number; /** * Jobs program interface * @group @nosana/kit */ export interface JobsProgram { /** * Fetch a job account by address */ get(addr: Address, checkRun?: boolean): Promise; /** * Fetch a run account by address */ run(addr: Address): Promise; /** * Fetch a market account by address */ market(addr: Address): Promise; /** * Fetch multiple job accounts by address */ multiple(addresses: Address[], checkRuns?: boolean): Promise; /** * Fetch all job accounts */ all(filters?: { state?: JobState; market?: Address; node?: Address; project?: Address; }, checkRuns?: boolean): Promise; /** * Fetch all run accounts */ runs(filters?: { node?: Address; job?: Address; }): Promise; /** * Fetch all market accounts */ markets(): Promise; /** * List a new job to the marketplace */ list: Instructions.List; /** * Build many list instructions at once — the bulk-create counterpart to * {@link list}. Each instruction mints its own fresh job/run accounts. Returns * instructions only; pass them to {@link sendBatch} to send them in the fewest * transactions. * * Call it with the same params repeated `count` times, or with one entry per job * when the jobs differ. * * @example * ```typescript * const instructions = await client.jobs.listMany({ market, ipfsHash, timeout }, 7); * const results = await client.jobs.sendBatch(instructions); * ``` */ listMany(params: Instructions.ListParams, count: number): Promise; listMany(params: Instructions.ListParams[]): Promise; /** * Post a new job to the marketplace (can list or assign based on params) */ post(params: Instructions.ListParams | Instructions.AssignParams): Promise; /** * Assign a job directly to a host node */ assign: Instructions.Assign; /** * Assign many jobs at once — the bulk counterpart to {@link assign}. Each * instruction mints its own fresh job/run accounts. Call with the same params * repeated `count` times, or with one entry per job when they differ. Returns * instructions only; pass them to {@link sendBatch}. */ assignMany(params: Instructions.AssignParams, count: number): Promise; assignMany(params: Instructions.AssignParams[]): Promise; /** * Extend an existing job's timeout */ extend: Instructions.Extend; /** * Extend many jobs at once — the bulk counterpart to {@link extend}. Takes one * params entry per job (each carries its own `timeout`); pass the result to * {@link sendBatch}. */ extendMany(params: Instructions.ExtendParams[]): Promise; /** * Delist a job from the marketplace */ delist: Instructions.Delist; /** * Delist many jobs at once — the bulk counterpart to {@link delist}. Takes the * job addresses and returns one instruction each; pass them to {@link sendBatch}. */ delistMany(jobs: Address[]): Promise; /** * Create a new market */ open(params?: Instructions.OpenParams): Promise; /** * Create a new market (synonym for open) */ createMarket(params?: Instructions.OpenParams): Promise; /** * Close a market */ close: Instructions.Close; /** * Close many markets at once — the bulk counterpart to {@link close}. Takes the * market addresses and returns one instruction each; pass them to {@link sendBatch}. */ closeMany(markets: Address[]): Promise; /** * Close a market (synonym for close) */ closeMarket: Instructions.Close; /** * Stop a running job */ end: Instructions.End; /** * End many running jobs at once — the bulk counterpart to {@link end}. Takes the * job addresses and returns one instruction each; pass them to {@link sendBatch}. */ endMany(jobs: Address[]): Promise; /** * Enters the MarketAccount queue, or create a RunAccount. */ work: Instructions.Work; /** * Complete a job that has been stopped. */ finish: Instructions.Finish; /** * Finish many jobs at once — the bulk counterpart to {@link finish}. Each entry * may expand to several instructions (token-account setup plus the finish), so * this returns one atomic group per job; pass the result to {@link sendBatch}, * which keeps each group in a single transaction. */ finishMany(params: Instructions.FinishParams[]): Promise; /** * Post the result for a JobAccount to finish it and get paid. */ complete: Instructions.Complete; /** * Complete many jobs at once — the bulk counterpart to {@link complete}. Takes * one params entry per job (each carries its own result hash); pass the result * to {@link sendBatch}. */ completeMany(params: Instructions.CompleteParams[]): Promise; /** * Quit a JobAccount that you have started. */ quit: Instructions.Quit; /** * Quit many runs at once — the bulk counterpart to {@link quit}. Takes the run * addresses and returns one instruction each; pass them to {@link sendBatch}. */ quitMany(runs: Address[]): Promise; /** * Exit the node queue */ stop: Instructions.Stop; /** * Exit the node queue for many markets at once — the bulk counterpart to * {@link stop}. Takes the market addresses and returns one instruction each; * pass them to {@link sendBatch}. */ stopMany(markets: Address[]): Promise; /** * Bulk-send many jobs instructions, automatically packing them into the fewest * transactions that each stay within Solana's size and compute-unit limits. * * Each entry of `groups` is a single instruction or an atomic group of * instructions that must stay in the same transaction. By default each * transaction's compute-unit limit is estimated by simulation, because jobs * instruction cost scales with the market queue size (a static estimate would * under-provision large batches). Pass `estimateComputeUnits: false` to use the * measured static table instead (no RPC, see `pnpm gen:cu`). All transactions are * attempted regardless of individual failures; the result reports each outcome. * * Each result carries `confirmed`, the `accounts` it touched (grouped by role, * e.g. `accounts.jobs`), the `decoded` instructions, and the `groupIndices` of * the inputs it packed — so created accounts can be collected directly, or tied * back to the exact input that produced them, without a bespoke `*Many` helper. * * @example * ```typescript * // Collect every created job from the confirmed transactions. * const instructions = await client.jobs.listMany({ market, ipfsHash, timeout }, 7); * const results = await client.jobs.sendBatch(instructions); * * const jobs = []; * for (const tx of results) { * if (tx.confirmed) jobs.push(...tx.accounts.jobs); * } * ``` * @example * ```typescript * // Or tie each created job back to its input (groupIndices bridges tx -> input; * // for single-instruction inputs decoded[k] lines up with groupIndices[k]). * for (const tx of results) { * tx.groupIndices.forEach((inputIndex, k) => { * console.log(inputIndex, tx.confirmed, tx.decoded[k]?.accounts.job); * }); * } * ``` * * @param groups Atomic instruction groups to bulk together. * @param options Optional configuration (fee payer, commitment, limits, simulation). * @returns A per-transaction result array, in the order the buckets were packed. */ sendBatch(groups: Array, options?: { feePayer?: TransactionSigner; commitment?: 'processed' | 'confirmed' | 'finalized'; computeUnitMargin?: number; maxComputeUnits?: number; estimateComputeUnits?: boolean; maxTransactionSize?: number; sequential?: boolean; }): Promise; /** * Bulk-pack and **sign** jobs instructions without sending them — the build-and * -sign-only counterpart to {@link sendBatch}. Returns one signed, base64 * transaction per packed bucket for a separate process to persist and broadcast * later (persist-before-send idempotency: a crash mid-send can replay the * identical signed transaction, which the chain dedups by signature). * * Each bucket is signed with all of its embedded signers (the fresh job/run * keypairs minted by each `list`/`assign` plus the fee payer), and the result * carries the same `decoded`/`accounts` view as {@link sendBatch} so the * per-bucket job/run addresses are available without decoding raw accounts. * * Compute-unit limits are set statically from the measured table (no simulation), * since nothing is sent — then scaled by `computeUnitMargin` (default 3). The * margin matters because jobs CU grows with market-queue depth (~131 CU/entry for * `list`) and the table is a shallow measurement: a transaction signed now but * broadcast later against a deeper queue could exceed a tight static limit and * fail the whole bucket on landing. The protocol caps a queue at depth 250 * (worst-case `list` ≈51,900 CU), so the default 3 (budget ≈69,000, ~depth 380) * covers the entire legal range with headroom. To size it explicitly, use * `computeUnitMargin >= (≈19000 + 131·D_max) / 23000`. Over-provisioning only costs * fee — `list` packing is size-bound, so a larger margin does not reduce density. * * Bucket atomicity applies: for operations whose instructions can already be * settled (e.g. STOP/END on a finished job), a single failing instruction fails * its whole bucket — pre-filter and/or use smaller buckets. LIST never hits this * (every `list` mints fresh accounts). * * @example * ```typescript * const signed = await client.jobs.signBatch(await client.jobs.listMany(params, 7)); * for (const tx of signed) { * await persist({ blob: tx.blob, lastValidBlockHeight: tx.lastValidBlockHeight, jobs: tx.accounts.jobs }); * // ...later, from a separate process: rpc.sendTransaction(tx.blob, { encoding: 'base64' }) * } * ``` * * @param groups Atomic instruction groups to bulk together. * @param options Optional configuration (fee payer, limits). No `commitment`/`sequential` — nothing is sent. * @param options.computeUnitMargin Multiplier on each instruction's static compute-unit estimate (default 3, covers the protocol's max queue depth of 250). Raise it only for deeper-than-protocol scenarios. * @returns One signed, un-sent transaction per packed bucket, in packing order. */ signBatch(groups: Array, options?: { feePayer?: TransactionSigner; computeUnitMargin?: number; maxComputeUnits?: number; estimateComputeUnits?: boolean; maxTransactionSize?: number; }): Promise; /** * Monitor program account updates using async iterators. * Automatically merges run account data into job account updates. * Returns a tuple of [eventStream, stopFunction]. * * @example * ```typescript * const [eventStream, stop] = await jobsProgram.monitor(); * for await (const event of eventStream) { * if (event.type === MonitorEventType.JOB) { * console.log('Job updated:', event.data.address); * } else if (event.type === MonitorEventType.MARKET) { * console.log('Market updated:', event.data.address); * } * } * ``` */ monitor(): Promise<[AsyncIterable, () => void]>; /** * Monitor program account updates with detailed events for each account type. * Provides separate events for job, market, and run accounts. * Returns a tuple of [eventStream, stopFunction]. * * @example * ```typescript * const [eventStream, stop] = await jobsProgram.monitorDetailed(); * for await (const event of eventStream) { * switch (event.type) { * case MonitorEventType.JOB: * console.log('Job updated:', event.data.address); * break; * case MonitorEventType.MARKET: * console.log('Market updated:', event.data.address); * break; * case MonitorEventType.RUN: * console.log('Run updated:', event.data.address); * break; * } * } * ``` */ monitorDetailed(): Promise<[AsyncIterable, () => void]>; } /** * Creates a new JobsProgram instance. * * @param deps - Program dependencies (config, logger, solana service, wallet getter) * @returns A JobsProgram instance with methods to interact with the jobs program * * @example * ```ts * import { createJobsProgram } from '@nosana/kit'; * * const jobsProgram = createJobsProgram({ * config, * logger, * solana, * getWallet, * }); * * const job = await jobsProgram.get('job-address'); * ``` */ export declare function createJobsProgram(deps: ProgramDeps, config: ProgramConfig): JobsProgram; //# sourceMappingURL=JobsProgram.d.ts.map