@pushchain/core 6.0.27-alpha.3 → 6.0.27-alpha.5

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.
Files changed (90) hide show
  1. package/AGW.md +35 -6
  2. package/CHANGELOG.md +13 -0
  3. package/MARKETPLACE.md +206 -0
  4. package/package.json +2 -1
  5. package/src/lib/agentic/codec/rules.js +74 -69
  6. package/src/lib/agentic/codec/universal.js +15 -3
  7. package/src/lib/agentic/constants.d.ts +36 -1
  8. package/src/lib/agentic/constants.js +14 -1
  9. package/src/lib/agentic/contracts/reader.d.ts +21 -0
  10. package/src/lib/agentic/contracts/reader.js +3 -0
  11. package/src/lib/agentic/error-messages.d.ts +3 -0
  12. package/src/lib/agentic/error-messages.js +127 -0
  13. package/src/lib/agentic/errors.d.ts +12 -3
  14. package/src/lib/agentic/errors.js +76 -0
  15. package/src/lib/agentic/management/common.js +6 -0
  16. package/src/lib/agentic/management/destination.d.ts +5 -0
  17. package/src/lib/agentic/management/destination.js +32 -0
  18. package/src/lib/agentic/management/prepare.js +80 -55
  19. package/src/lib/agentic/management/svm-public.js +13 -4
  20. package/src/lib/agentic/presets/index.js +8 -9
  21. package/src/lib/agentic/presets/routes.d.ts +1 -1
  22. package/src/lib/agentic/presets/routes.js +6 -7
  23. package/src/lib/agentic/presets/types.d.ts +1 -6
  24. package/src/lib/agentic/public-rule.js +18 -2
  25. package/src/lib/constants/index.d.ts +35 -0
  26. package/src/lib/index.d.ts +4 -0
  27. package/src/lib/index.js +6 -2
  28. package/src/lib/job/job.d.ts +35 -0
  29. package/src/lib/job/job.js +382 -0
  30. package/src/lib/job/types.d.ts +94 -0
  31. package/src/lib/job/types.js +3 -0
  32. package/src/lib/job/watch.d.ts +3 -0
  33. package/src/lib/job/watch.js +169 -0
  34. package/src/lib/job-spec/codec.d.ts +18 -0
  35. package/src/lib/job-spec/codec.js +348 -0
  36. package/src/lib/job-spec/constants.d.ts +32 -0
  37. package/src/lib/job-spec/constants.js +36 -0
  38. package/src/lib/job-spec/helpers.d.ts +19 -0
  39. package/src/lib/job-spec/helpers.js +138 -0
  40. package/src/lib/job-spec/index.d.ts +14 -0
  41. package/src/lib/job-spec/index.js +17 -0
  42. package/src/lib/job-spec/preview.d.ts +8 -0
  43. package/src/lib/job-spec/preview.js +298 -0
  44. package/src/lib/job-spec/read.d.ts +20 -0
  45. package/src/lib/job-spec/read.js +224 -0
  46. package/src/lib/job-spec/schema.d.ts +290 -0
  47. package/src/lib/job-spec/schema.js +70 -0
  48. package/src/lib/job-spec/types.d.ts +139 -0
  49. package/src/lib/job-spec/types.js +3 -0
  50. package/src/lib/market/contracts/AgenticCommerce.d.ts +1026 -0
  51. package/src/lib/market/contracts/AgenticCommerce.js +1317 -0
  52. package/src/lib/market/contracts/RulesBindingHook.d.ts +235 -0
  53. package/src/lib/market/contracts/RulesBindingHook.js +314 -0
  54. package/src/lib/market/contracts/UniversalMarketplace.d.ts +1770 -0
  55. package/src/lib/market/contracts/UniversalMarketplace.js +2295 -0
  56. package/src/lib/market/contracts/UniversalMarketplaceErrors.d.ts +309 -0
  57. package/src/lib/market/contracts/UniversalMarketplaceErrors.js +416 -0
  58. package/src/lib/market/contracts/UniversalMarketplaceRules.d.ts +241 -0
  59. package/src/lib/market/contracts/UniversalMarketplaceRules.js +323 -0
  60. package/src/lib/market/data.d.ts +8 -0
  61. package/src/lib/market/data.js +60 -0
  62. package/src/lib/market/deployment.d.ts +14 -0
  63. package/src/lib/market/deployment.js +23 -0
  64. package/src/lib/market/deposit.d.ts +24 -0
  65. package/src/lib/market/deposit.js +271 -0
  66. package/src/lib/market/errors.d.ts +13 -0
  67. package/src/lib/market/errors.js +81 -0
  68. package/src/lib/market/history.d.ts +6 -0
  69. package/src/lib/market/history.js +83 -0
  70. package/src/lib/market/index.d.ts +4 -0
  71. package/src/lib/market/index.js +12 -0
  72. package/src/lib/market/kernel-wire.d.ts +15 -0
  73. package/src/lib/market/kernel-wire.js +41 -0
  74. package/src/lib/market/market.d.ts +55 -0
  75. package/src/lib/market/market.js +635 -0
  76. package/src/lib/market/rules.d.ts +106 -0
  77. package/src/lib/market/rules.js +293 -0
  78. package/src/lib/market/runtime.d.ts +35 -0
  79. package/src/lib/market/runtime.js +130 -0
  80. package/src/lib/market/types.d.ts +180 -0
  81. package/src/lib/market/types.js +3 -0
  82. package/src/lib/orchestrator/internals/errors.d.ts +9 -2
  83. package/src/lib/orchestrator/internals/errors.js +9 -2
  84. package/src/lib/orchestrator/internals/push-chain-tx.js +17 -3
  85. package/src/lib/push-chain/push-chain.d.ts +44 -1
  86. package/src/lib/push-chain/push-chain.js +23 -3
  87. package/src/lib/read-state/read-params.d.ts +9 -0
  88. package/src/lib/read-state/read-params.js +5 -1
  89. package/src/lib/utils.d.ts +15 -0
  90. package/src/lib/utils.js +4 -0
@@ -0,0 +1,382 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JobNamespaceImpl = void 0;
4
+ const viem_1 = require("viem");
5
+ const AgenticCommerce_1 = require("../market/contracts/AgenticCommerce");
6
+ const RulesBindingHook_1 = require("../market/contracts/RulesBindingHook");
7
+ const UniversalMarketplace_1 = require("../market/contracts/UniversalMarketplace");
8
+ const kernel_wire_1 = require("../market/kernel-wire");
9
+ const runtime_1 = require("../market/runtime");
10
+ const errors_1 = require("../market/errors");
11
+ const deployments_1 = require("../agentic/deployments");
12
+ const rules_1 = require("../agentic/reads/rules");
13
+ const snapshot_1 = require("../agentic/reads/snapshot");
14
+ const codec_1 = require("../job-spec/codec");
15
+ const watch_1 = require("./watch");
16
+ const STATES = [
17
+ 'Open',
18
+ 'Funded',
19
+ 'Submitted',
20
+ 'Completed',
21
+ 'Rejected',
22
+ 'Expired',
23
+ ];
24
+ function validId(jobId) {
25
+ if (typeof jobId !== 'bigint' || jobId < BigInt(1))
26
+ throw new errors_1.JobError('INVALID_JOB_ID', 'Job IDs are positive bigint values.');
27
+ }
28
+ function amount(n) {
29
+ if (typeof n !== 'bigint' || n < BigInt(0) || n >= BigInt(1) << BigInt(256))
30
+ throw new errors_1.JobError('INVALID_AMOUNT', 'The amount must fit uint256.');
31
+ }
32
+ class JobNamespaceImpl {
33
+ rt;
34
+ constructor(rt) {
35
+ this.rt = rt;
36
+ }
37
+ async raw(jobId, s) {
38
+ validId(jobId);
39
+ const j = await s.read((0, runtime_1.deployment)(this.rt).kernel, kernel_wire_1.KERNEL_READ_ABI, 'getJob', [jobId]);
40
+ if ((0, viem_1.getAddress)(j.client) === viem_1.zeroAddress || !STATES[j.status])
41
+ throw new errors_1.JobError('JOB_NOT_FOUND', 'This job does not exist.');
42
+ return j;
43
+ }
44
+ async jobAt(jobId, s) {
45
+ const d = (0, runtime_1.deployment)(this.rt);
46
+ const j = await this.raw(jobId, s);
47
+ const paymentToken = await s.read(d.kernel, AgenticCommerce_1.JOB_KERNEL_ABI, 'paymentToken');
48
+ let spec;
49
+ let decodeError;
50
+ if (j.description !== '0x') {
51
+ try {
52
+ spec = (0, codec_1.decodeJobSpec)(j.description, { format: 'spec' });
53
+ }
54
+ catch (e) {
55
+ decodeError = e.message;
56
+ }
57
+ }
58
+ const rulesId = (0, viem_1.getAddress)(j.hook) === (0, viem_1.getAddress)(d.hook)
59
+ ? await s.read(d.hook, RulesBindingHook_1.RULES_HOOK_ABI, 'rulesOfJob', [jobId])
60
+ : undefined;
61
+ let deliverable;
62
+ if (j.status >= 2) {
63
+ const logs = await (0, snapshot_1.scanLogs)(this.rt.agw.reader, {
64
+ address: d.kernel,
65
+ event: (0, viem_1.getAbiItem)({ abi: AgenticCommerce_1.JOB_KERNEL_ABI, name: 'JobSubmitted' }),
66
+ args: { jobId },
67
+ }, this.rt.jobBlocks?.get(jobId) ?? d.startBlock, s.blockNumber);
68
+ if (logs.length > 1)
69
+ throw new errors_1.JobError('INCONSISTENT_READ', 'The job has multiple submission events.');
70
+ if (logs.length === 1) {
71
+ const event = (0, viem_1.decodeEventLog)({
72
+ abi: AgenticCommerce_1.JOB_KERNEL_ABI,
73
+ eventName: 'JobSubmitted',
74
+ data: logs[0].data,
75
+ topics: logs[0].topics,
76
+ });
77
+ deliverable = event.args.deliverable;
78
+ }
79
+ }
80
+ return {
81
+ ...j,
82
+ jobId,
83
+ status: STATES[j.status],
84
+ paymentToken,
85
+ ...(deliverable ? { deliverable } : {}),
86
+ ...(rulesId && rulesId !== viem_1.zeroHash ? { rulesId } : {}),
87
+ ...(spec ? { jobSpec: { spec, bytes: j.description } } : {}),
88
+ ...(decodeError ? { jobSpecDecodeError: decodeError } : {}),
89
+ evaluation: {
90
+ available: false,
91
+ reason: (0, viem_1.getAddress)(j.evaluator) === (0, viem_1.getAddress)(d.evaluator)
92
+ ? 'MANUAL_EVALUATOR'
93
+ : 'UNVERIFIED_EVALUATOR',
94
+ },
95
+ };
96
+ }
97
+ async status(jobId) {
98
+ return this.jobAt(jobId, await (0, runtime_1.snapshot)(this.rt));
99
+ }
100
+ async list(options = {}) {
101
+ const s = await (0, runtime_1.snapshot)(this.rt);
102
+ const count = await s.read((0, runtime_1.deployment)(this.rt).kernel, AgenticCommerce_1.JOB_KERNEL_ABI, 'jobCounter');
103
+ const from = options.fromJobId ?? BigInt(1);
104
+ validId(from);
105
+ const jobs = [];
106
+ for (let i = from; i <= count; i += BigInt(8)) {
107
+ const rows = await Promise.all(Array.from({
108
+ length: Number(count - i + BigInt(1) > BigInt(8)
109
+ ? BigInt(8)
110
+ : count - i + BigInt(1)),
111
+ }, (_, n) => this.jobAt(i + BigInt(n), s)));
112
+ jobs.push(...rows.filter((j) => (!options.client ||
113
+ (0, viem_1.getAddress)(options.client) === (0, viem_1.getAddress)(j.client)) &&
114
+ (!options.provider ||
115
+ (0, viem_1.getAddress)(options.provider) === (0, viem_1.getAddress)(j.provider)) &&
116
+ (!options.status || options.status === j.status)));
117
+ }
118
+ return { jobs };
119
+ }
120
+ async create(options) {
121
+ options = { ...options };
122
+ const d = (0, runtime_1.deployment)(this.rt);
123
+ const s = await (0, runtime_1.snapshot)(this.rt);
124
+ const token = await s.read(d.kernel, AgenticCommerce_1.JOB_KERNEL_ABI, 'paymentToken');
125
+ if ((0, viem_1.getAddress)(options.paymentToken) !== (0, viem_1.getAddress)(token))
126
+ throw new errors_1.JobError('TOKEN_MISMATCH', 'The job token must equal this kernel’s payment token.');
127
+ if (options.jobSpec) {
128
+ const spec = (0, codec_1.decodeJobSpec)(options.jobSpec, {
129
+ format: 'spec',
130
+ });
131
+ if (spec.allowedMutability !== 'NONE')
132
+ (0, errors_1.unavailable)('Mutable job criteria');
133
+ if (spec.origin !== viem_1.zeroHash)
134
+ throw new errors_1.JobError('INVALID_JOB_SPEC', 'A plain job must have a zero marketplace origin.');
135
+ if (spec.failFinalAt >= options.expiredAt)
136
+ throw new errors_1.JobError('INVALID_JOB_SPEC', 'The failure deadline must precede expiry.');
137
+ }
138
+ const min = await s.read(d.kernel, AgenticCommerce_1.JOB_KERNEL_ABI, 'MIN_EXPIRY_WINDOW');
139
+ if (!Number.isSafeInteger(options.expiredAt) ||
140
+ options.expiredAt <= s.timestamp + Number(min) ||
141
+ options.expiredAt >= 2 ** 48)
142
+ throw new errors_1.JobError('EXPIRY_TOO_SHORT', 'Choose a future expiry beyond the kernel minimum window.');
143
+ const call = {
144
+ target: d.kernel,
145
+ value: BigInt(0),
146
+ data: (0, kernel_wire_1.encodeCreateJob)((0, viem_1.getAddress)(options.provider), (0, viem_1.getAddress)(options.evaluator), options.expiredAt, options, (0, viem_1.getAddress)(options.hook)),
147
+ };
148
+ const wallet = this.rt.wallet();
149
+ const tx = wallet
150
+ ? await (0, runtime_1.ownerBatch)(this.rt, wallet, [call], options.progressHook)
151
+ : await (0, runtime_1.write)(this.rt, call, options.progressHook, 'JOB', true);
152
+ const e = await (0, runtime_1.eventArgs)(this.rt, tx, d.kernel, AgenticCommerce_1.JOB_KERNEL_ABI, 'JobCreated');
153
+ if ((0, viem_1.getAddress)(e['client']) !== (0, viem_1.getAddress)(this.rt.account()))
154
+ throw new errors_1.JobError('RECEIPT_MISMATCH', 'The created job has a different client.', { txHash: tx.hash });
155
+ return { jobId: e['jobId'], tx };
156
+ }
157
+ provider(j) {
158
+ if ((0, viem_1.getAddress)(j.provider) !== (0, viem_1.getAddress)(this.rt.agw.signerPushAccount()))
159
+ throw new errors_1.JobError('NOT_PROVIDER', 'Connect this job’s provider.');
160
+ }
161
+ open(j, now) {
162
+ if (j.status !== 0 || j.expiredAt <= now)
163
+ throw new errors_1.JobError('WRONG_STATUS', 'The job must be Open and unexpired.');
164
+ }
165
+ async setBudget(jobId, budget, options = {}) {
166
+ if (options.jobSpec !== undefined)
167
+ (0, errors_1.unavailable)('Replacement JobSpec proposals');
168
+ amount(budget);
169
+ const s = await (0, runtime_1.snapshot)(this.rt);
170
+ const j = await this.raw(jobId, s);
171
+ this.provider(j);
172
+ this.open(j, s.timestamp);
173
+ const d = (0, runtime_1.deployment)(this.rt);
174
+ return (0, runtime_1.write)(this.rt, {
175
+ target: d.kernel,
176
+ value: BigInt(0),
177
+ data: (0, viem_1.encodeFunctionData)({
178
+ abi: AgenticCommerce_1.JOB_KERNEL_ABI,
179
+ functionName: 'setBudget',
180
+ args: [jobId, budget, '0x'],
181
+ }),
182
+ }, options.progressHook, 'JOB', true);
183
+ }
184
+ async fund(jobId, options = {}) {
185
+ options = { ...options };
186
+ const rt = this.rt;
187
+ const d = (0, runtime_1.deployment)(rt);
188
+ const s = await (0, runtime_1.snapshot)(rt);
189
+ const j = await this.raw(jobId, s);
190
+ this.open(j, s.timestamp);
191
+ const gen = (0, deployments_1.currentGeneration)(rt.agw.network);
192
+ const isWallet = await s.read(gen.addresses.factory, gen.contracts.abis.factory, 'isWallet', [j.client]);
193
+ if (isWallet) {
194
+ const owner = await s.read(j.client, gen.contracts.abis.wallet, 'owner');
195
+ if ((0, viem_1.getAddress)(owner) !== (0, viem_1.getAddress)(rt.agw.signerPushAccount()))
196
+ throw new errors_1.JobError('NOT_CLIENT', 'Connect the job wallet’s owner.');
197
+ }
198
+ else if ((0, viem_1.getAddress)(j.client) !== (0, viem_1.getAddress)(rt.agw.signerPushAccount()))
199
+ throw new errors_1.JobError('NOT_CLIENT', 'Connect this job’s client.');
200
+ let expected = options.expectedBudget;
201
+ const cardId = await s.read(d.marketplace, UniversalMarketplace_1.MARKETPLACE_ABI, 'cardOfJob', [jobId]);
202
+ let rulesId = options.rulesId;
203
+ if (cardId) {
204
+ const [version, view, recordedRules] = await Promise.all([
205
+ s.read(d.marketplace, UniversalMarketplace_1.MARKETPLACE_ABI, 'cardVersionOfJob', [
206
+ jobId,
207
+ ]),
208
+ s.read(d.marketplace, UniversalMarketplace_1.MARKETPLACE_ABI, 'getAgentCard', [cardId]),
209
+ s.read(d.marketplace, UniversalMarketplace_1.MARKETPLACE_ABI, 'rulesOfJob', [jobId]),
210
+ ]);
211
+ if (rulesId && rulesId !== recordedRules)
212
+ throw new errors_1.JobError('RULES_MISMATCH', 'Use the permission recorded when this job was opened.');
213
+ rulesId = recordedRules;
214
+ if (expected === undefined && version === view.version)
215
+ expected = view.card.providerFee;
216
+ }
217
+ if (expected === undefined)
218
+ throw new errors_1.JobError('EXPECTED_BUDGET_REQUIRED', 'Pass the exact budget you reviewed; this SDK does not silently accept the latest provider quote.');
219
+ amount(expected);
220
+ if (expected !== j.budget)
221
+ throw new errors_1.JobError('BUDGET_MISMATCH', 'The provider’s current price differs from the budget you reviewed.', { expectedBudget: expected, currentBudget: j.budget });
222
+ let optParams = '0x';
223
+ if ((0, viem_1.getAddress)(j.hook) === (0, viem_1.getAddress)(d.hook)) {
224
+ if (!isWallet || !rulesId || !/^0x[\da-f]{64}$/i.test(rulesId))
225
+ throw new errors_1.JobError('RULES_REQUIRED', 'This rules hook needs an AGW client and its rulesId.');
226
+ const record = await (0, rules_1.getRule)(new snapshot_1.Snapshot(rt.agw.reader, s.blockNumber), gen, j.client, rulesId, rt.agw.pushChainNamespace);
227
+ if ((0, viem_1.getAddress)(record.agent) !== (0, viem_1.getAddress)(j.provider) ||
228
+ record.validUntil < j.expiredAt)
229
+ throw new errors_1.JobError('RULES_MISMATCH', 'The live rule must authorize this provider through the job expiry.');
230
+ if (await s.read(d.hook, RulesBindingHook_1.RULES_HOOK_ABI, 'activeJobOf', [j.client]))
231
+ throw new errors_1.JobError('WALLET_HAS_ACTIVE_JOB', 'This wallet already has a funded job under the rules hook.');
232
+ optParams = (0, viem_1.encodeAbiParameters)([{ type: 'bytes32' }], [rulesId]);
233
+ }
234
+ else if (rulesId)
235
+ throw new errors_1.JobError('HOOK_MISMATCH', 'A rulesId payload is supported only for the verified rules hook.');
236
+ const token = await s.read(d.kernel, AgenticCommerce_1.JOB_KERNEL_ABI, 'paymentToken');
237
+ const calls = [];
238
+ if (expected > BigInt(0)) {
239
+ const [balance, allowance] = await Promise.all([
240
+ s.read(token, viem_1.erc20Abi, 'balanceOf', [j.client]),
241
+ s.read(token, viem_1.erc20Abi, 'allowance', [j.client, d.kernel]),
242
+ ]);
243
+ if (balance < expected)
244
+ throw new errors_1.JobError('INSUFFICIENT_FUNDS', 'The job client lacks the payment tokens required for escrow.');
245
+ if (allowance < expected) {
246
+ if (allowance > BigInt(0))
247
+ calls.push({
248
+ target: token,
249
+ value: BigInt(0),
250
+ data: (0, viem_1.encodeFunctionData)({
251
+ abi: viem_1.erc20Abi,
252
+ functionName: 'approve',
253
+ args: [d.kernel, BigInt(0)],
254
+ }),
255
+ });
256
+ calls.push({
257
+ target: token,
258
+ value: BigInt(0),
259
+ data: (0, viem_1.encodeFunctionData)({
260
+ abi: viem_1.erc20Abi,
261
+ functionName: 'approve',
262
+ args: [d.kernel, expected],
263
+ }),
264
+ });
265
+ }
266
+ }
267
+ calls.push({
268
+ target: d.kernel,
269
+ value: BigInt(0),
270
+ data: (0, viem_1.encodeFunctionData)({
271
+ abi: AgenticCommerce_1.JOB_KERNEL_ABI,
272
+ functionName: 'fund',
273
+ args: [jobId, expected, optParams],
274
+ }),
275
+ });
276
+ if (isWallet)
277
+ return (0, runtime_1.ownerBatch)(rt, j.client, calls, options.progressHook);
278
+ if (calls.length === 1)
279
+ return (0, runtime_1.write)(rt, calls[0], options.progressHook, 'JOB', true);
280
+ if (rt.agw.isReadOnly)
281
+ throw new errors_1.JobError('READ_ONLY', 'Connect a signer to fund escrow.');
282
+ // No sequential fallback: allowance and acceptance must belong to one atomic batch.
283
+ return rt.agw.executeAtomicBatch({
284
+ to: d.kernel,
285
+ value: BigInt(0),
286
+ data: calls.map((c) => ({
287
+ to: c.target,
288
+ value: c.value,
289
+ data: c.data,
290
+ })),
291
+ }, { progressHook: options.progressHook });
292
+ }
293
+ async submit(jobId, options) {
294
+ options = { ...options };
295
+ const s = await (0, runtime_1.snapshot)(this.rt);
296
+ const j = await this.raw(jobId, s);
297
+ this.provider(j);
298
+ if (j.status !== 1 || j.expiredAt <= s.timestamp)
299
+ throw new errors_1.JobError('WRONG_STATUS', 'Only an unexpired Funded job can be submitted.');
300
+ const deliverable = /^0x[\da-f]{64}$/i.test(options.deliverable)
301
+ ? options.deliverable
302
+ : (0, viem_1.keccak256)((0, viem_1.stringToHex)(options.deliverable));
303
+ return (0, runtime_1.write)(this.rt, {
304
+ target: (0, runtime_1.deployment)(this.rt).kernel,
305
+ value: BigInt(0),
306
+ data: (0, viem_1.encodeFunctionData)({
307
+ abi: AgenticCommerce_1.JOB_KERNEL_ABI,
308
+ functionName: 'submit',
309
+ args: [jobId, deliverable, '0x'],
310
+ }),
311
+ }, options.progressHook, 'JOB', true);
312
+ }
313
+ async cancel(jobId, options = {}) {
314
+ const rt = this.rt;
315
+ const d = (0, runtime_1.deployment)(rt);
316
+ const s = await (0, runtime_1.snapshot)(rt);
317
+ const j = await this.raw(jobId, s);
318
+ if (j.status !== 0)
319
+ throw new errors_1.JobError('WRONG_STATUS', 'Only an Open job can be cancelled by its client.');
320
+ const gen = (0, deployments_1.currentGeneration)(rt.agw.network);
321
+ const isWallet = await s.read(gen.addresses.factory, gen.contracts.abis.factory, 'isWallet', [j.client]);
322
+ const calls = [
323
+ {
324
+ target: d.kernel,
325
+ value: BigInt(0),
326
+ data: (0, viem_1.encodeFunctionData)({
327
+ abi: AgenticCommerce_1.JOB_KERNEL_ABI,
328
+ functionName: 'reject',
329
+ args: [jobId, viem_1.zeroHash, '0x'],
330
+ }),
331
+ },
332
+ ];
333
+ if (isWallet) {
334
+ const wallet = await s.read(d.marketplace, UniversalMarketplace_1.MARKETPLACE_ABI, 'agwOfJob', [jobId]);
335
+ const rulesId = await s.read(d.marketplace, UniversalMarketplace_1.MARKETPLACE_ABI, 'rulesOfJob', [jobId]);
336
+ if ((0, viem_1.getAddress)(wallet) === (0, viem_1.getAddress)(j.client) &&
337
+ rulesId !== viem_1.zeroHash &&
338
+ (await s.read(gen.addresses.sessionEngine, gen.contracts.abis.engine, 'isPermissionEnabled', [rulesId, j.client])))
339
+ calls.push({
340
+ target: j.client,
341
+ value: BigInt(0),
342
+ data: gen.contracts.encodeRevokeRules(rulesId),
343
+ });
344
+ return (0, runtime_1.ownerBatch)(rt, j.client, calls, options.progressHook);
345
+ }
346
+ if ((0, viem_1.getAddress)(j.client) !== (0, viem_1.getAddress)(rt.agw.signerPushAccount()))
347
+ throw new errors_1.JobError('NOT_CLIENT', 'Only the client can use this cancellation method.');
348
+ return (0, runtime_1.write)(rt, calls[0], options.progressHook, 'JOB', true);
349
+ }
350
+ async claimRefund(jobId, options = {}) {
351
+ const s = await (0, runtime_1.snapshot)(this.rt);
352
+ const j = await this.raw(jobId, s);
353
+ const d = (0, runtime_1.deployment)(this.rt);
354
+ if (![0, 1, 2].includes(j.status))
355
+ throw new errors_1.JobError('WRONG_STATUS', 'This job is already terminal.');
356
+ const grace = j.status === 2
357
+ ? Number(await s.read(d.kernel, AgenticCommerce_1.JOB_KERNEL_ABI, 'EVALUATOR_GRACE_PERIOD'))
358
+ : 0;
359
+ if (s.timestamp < j.expiredAt + grace)
360
+ throw new errors_1.JobError('REFUND_NOT_READY', 'The expiry or evaluator grace window has not elapsed.');
361
+ return (0, runtime_1.write)(this.rt, {
362
+ target: d.kernel,
363
+ value: BigInt(0),
364
+ data: (0, viem_1.encodeFunctionData)({
365
+ abi: AgenticCommerce_1.JOB_KERNEL_ABI,
366
+ functionName: 'claimRefund',
367
+ args: [jobId],
368
+ }),
369
+ }, options.progressHook, 'JOB', true);
370
+ }
371
+ async verify(_jobId, _options) {
372
+ void _jobId;
373
+ void _options;
374
+ return (0, errors_1.unavailable)('Automatic job verification; the configured evaluator is manual');
375
+ }
376
+ watch(jobId, callback, options = {}) {
377
+ validId(jobId);
378
+ return (0, watch_1.watchJob)(this.rt, jobId, callback, { ...options });
379
+ }
380
+ }
381
+ exports.JobNamespaceImpl = JobNamespaceImpl;
382
+ //# sourceMappingURL=job.js.map
@@ -0,0 +1,94 @@
1
+ import type { Address, Hex } from 'viem';
2
+ import type { UniversalTxResponse } from '../orchestrator/orchestrator.types';
3
+ import type { JobSpec } from '../job-spec/types';
4
+ import type { StackProgressHook } from '../market/runtime';
5
+ export type JobStatus = 'Open' | 'Funded' | 'Submitted' | 'Completed' | 'Rejected' | 'Expired';
6
+ export interface CreateJobOptions {
7
+ provider: Address;
8
+ evaluator: Address;
9
+ hook: Address;
10
+ expiredAt: number;
11
+ paymentToken: Address;
12
+ jobSpec?: Hex;
13
+ description?: string;
14
+ progressHook?: StackProgressHook;
15
+ }
16
+ export interface Job {
17
+ jobId: bigint;
18
+ client: Address;
19
+ provider: Address;
20
+ evaluator: Address;
21
+ hook: Address;
22
+ status: JobStatus;
23
+ expiredAt: number;
24
+ budget: bigint;
25
+ paymentToken: Address;
26
+ /** Raw Solidity string bytes, which may contain a binary JobSpec rather than UTF-8. */
27
+ description: Hex;
28
+ deliverable?: Hex;
29
+ rulesId?: Hex;
30
+ jobSpec?: {
31
+ spec: JobSpec;
32
+ bytes: Hex;
33
+ /** Unavailable without a compatible evaluator. */ frozen?: boolean;
34
+ };
35
+ jobSpecDecodeError?: string;
36
+ evaluation: {
37
+ available: false;
38
+ reason: 'MANUAL_EVALUATOR' | 'UNVERIFIED_EVALUATOR';
39
+ };
40
+ }
41
+ export interface JobWriteOptions {
42
+ progressHook?: StackProgressHook;
43
+ }
44
+ export interface FundJobOptions extends JobWriteOptions {
45
+ rulesId?: Hex;
46
+ /** The price the client reviewed. Required for plain jobs or an updated card version. */
47
+ expectedBudget?: bigint;
48
+ }
49
+ export interface JobEvent {
50
+ jobId: bigint;
51
+ kind: string;
52
+ txHash?: Hex;
53
+ blockNumber?: bigint;
54
+ data?: unknown;
55
+ error?: unknown;
56
+ cursor?: JobWatchCursor;
57
+ }
58
+ /** Last delivered log; resume includes its block and excludes this log and earlier logs. */
59
+ export interface JobWatchCursor {
60
+ blockNumber: bigint;
61
+ logIndex: number;
62
+ blockHash?: Hex;
63
+ }
64
+ export interface JobWatchOptions {
65
+ fromBlock?: bigint;
66
+ cursor?: JobWatchCursor;
67
+ pollIntervalMs?: number;
68
+ }
69
+ export interface JobNamespace {
70
+ create(options: CreateJobOptions): Promise<{
71
+ jobId: bigint;
72
+ tx: UniversalTxResponse;
73
+ }>;
74
+ setBudget(jobId: bigint, amount: bigint, options?: JobWriteOptions & {
75
+ jobSpec?: Hex;
76
+ }): Promise<UniversalTxResponse>;
77
+ fund(jobId: bigint, options?: FundJobOptions): Promise<UniversalTxResponse>;
78
+ submit(jobId: bigint, options: JobWriteOptions & {
79
+ deliverable: Hex | string;
80
+ }): Promise<UniversalTxResponse>;
81
+ cancel(jobId: bigint, options?: JobWriteOptions): Promise<UniversalTxResponse>;
82
+ claimRefund(jobId: bigint, options?: JobWriteOptions): Promise<UniversalTxResponse>;
83
+ verify(jobId: bigint, options?: JobWriteOptions): Promise<never>;
84
+ status(jobId: bigint): Promise<Job>;
85
+ list(options?: {
86
+ client?: Address;
87
+ provider?: Address;
88
+ status?: JobStatus;
89
+ fromJobId?: bigint;
90
+ }): Promise<{
91
+ jobs: Job[];
92
+ }>;
93
+ watch(jobId: bigint, callback: (event: JobEvent) => void, options?: JobWatchOptions): () => void;
94
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,3 @@
1
+ import { type StackRuntime } from '../market/runtime';
2
+ import type { JobEvent, JobWatchOptions } from './types';
3
+ export declare function watchJob(rt: StackRuntime, jobId: bigint, callback: (event: JobEvent) => void, options: JobWatchOptions): () => void;
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.watchJob = watchJob;
4
+ const viem_1 = require("viem");
5
+ const AgenticCommerce_1 = require("../market/contracts/AgenticCommerce");
6
+ const runtime_1 = require("../market/runtime");
7
+ const errors_1 = require("../market/errors");
8
+ const data_1 = require("../market/data");
9
+ const names = [
10
+ 'JobCreated',
11
+ 'BudgetSet',
12
+ 'JobFunded',
13
+ 'JobSubmitted',
14
+ 'JobCompleted',
15
+ 'JobRejected',
16
+ 'JobExpired',
17
+ 'Refunded',
18
+ ];
19
+ const kinds = [
20
+ 'Created',
21
+ 'BudgetSet',
22
+ 'Funded',
23
+ 'Submitted',
24
+ 'Completed',
25
+ 'Rejected',
26
+ 'Expired',
27
+ 'Refunded',
28
+ ];
29
+ function watchJob(rt, jobId, callback, options) {
30
+ const d = (0, runtime_1.deployment)(rt);
31
+ let stopped = false;
32
+ let timer;
33
+ let cursor = options.cursor && { ...options.cursor };
34
+ let next = cursor?.blockNumber ?? options.fromBlock;
35
+ const interval = options.pollIntervalMs ?? 3000;
36
+ if (!Number.isSafeInteger(interval) ||
37
+ interval < 25 ||
38
+ (next !== undefined && (typeof next !== 'bigint' || next < BigInt(0))) ||
39
+ (cursor &&
40
+ (!Number.isSafeInteger(cursor.logIndex) ||
41
+ cursor.logIndex < 0 ||
42
+ (cursor.blockHash && !/^0x[\da-f]{64}$/i.test(cursor.blockHash)))) ||
43
+ (cursor && options.fromBlock !== undefined))
44
+ throw new errors_1.JobError('INVALID_WATCH_OPTIONS', 'Use a nonnegative block or a delivered-log cursor, and a polling interval of at least 25ms.');
45
+ const notify = (event) => {
46
+ try {
47
+ callback(event);
48
+ }
49
+ catch (error) {
50
+ if (event.kind !== 'Error' && !stopped) {
51
+ try {
52
+ callback({
53
+ jobId,
54
+ kind: 'Error',
55
+ error,
56
+ cursor: cursor && { ...cursor },
57
+ });
58
+ }
59
+ catch {
60
+ /* A consumer exception must not rewind delivery or reject an unobserved promise. */
61
+ }
62
+ }
63
+ }
64
+ };
65
+ const poll = async () => {
66
+ try {
67
+ const head = await rt.agw.reader.getBlockNumber();
68
+ if (stopped)
69
+ return;
70
+ if (cursor) {
71
+ if (head < cursor.blockNumber)
72
+ throw new errors_1.JobError('WATCH_REORG', 'The delivered cursor is ahead of the canonical head. Reload status before continuing.');
73
+ const block = rt.agw.reader.getBlock &&
74
+ (await rt.agw.reader.getBlock({ blockNumber: cursor.blockNumber }));
75
+ if (head < cursor.blockNumber ||
76
+ (cursor.blockHash &&
77
+ block?.hash &&
78
+ cursor.blockHash.toLowerCase() !== block.hash.toLowerCase()))
79
+ throw new errors_1.JobError('WATCH_REORG', 'The delivered cursor is no longer canonical. Reload job status and restart from a reviewed block.');
80
+ }
81
+ if (next === undefined)
82
+ next = head;
83
+ const end = next + BigInt(999) < head ? next + BigInt(999) : head;
84
+ if (next <= end) {
85
+ const start = next;
86
+ const groups = await Promise.all(names.map((name) => rt.agw.reader.getLogs({
87
+ address: d.kernel,
88
+ event: (0, viem_1.getAbiItem)({ abi: AgenticCommerce_1.JOB_KERNEL_ABI, name }),
89
+ args: { jobId },
90
+ fromBlock: start,
91
+ toBlock: end,
92
+ })));
93
+ if (stopped)
94
+ return;
95
+ const unique = new Map();
96
+ for (const log of groups.flat()) {
97
+ if (log.removed)
98
+ throw new errors_1.JobError('WATCH_REORG', 'The RPC returned a removed job log. Reload status before continuing.');
99
+ if ((0, viem_1.getAddress)(log.address) !== (0, viem_1.getAddress)(d.kernel) ||
100
+ log.blockNumber === null ||
101
+ log.logIndex === null ||
102
+ log.blockNumber < start ||
103
+ log.blockNumber > end)
104
+ throw new errors_1.JobError('INCONSISTENT_READ', 'The RPC returned an unmined or out-of-range job log.');
105
+ const event = (0, viem_1.decodeEventLog)({
106
+ abi: AgenticCommerce_1.JOB_KERNEL_ABI,
107
+ data: log.data,
108
+ topics: log.topics,
109
+ strict: true,
110
+ });
111
+ if (event.args.jobId !== jobId ||
112
+ !names.includes(event.eventName))
113
+ throw new errors_1.JobError('INCONSISTENT_READ', 'The RPC returned a different job or unsupported event.');
114
+ const key = `${log.blockNumber}:${log.logIndex}`;
115
+ const previous = unique.get(key);
116
+ if (previous && (0, data_1.fingerprint)(previous.log) !== (0, data_1.fingerprint)(log))
117
+ throw new errors_1.JobError('INCONSISTENT_READ', 'Two different logs occupy the same job cursor.');
118
+ unique.set(key, { log, event });
119
+ }
120
+ const ordered = [...unique.values()].sort((a, b) => Number(a.log.blockNumber - b.log.blockNumber) || a.log.logIndex - b.log.logIndex);
121
+ for (const { log, event } of ordered) {
122
+ if (stopped)
123
+ return;
124
+ const blockNumber = log.blockNumber;
125
+ const logIndex = log.logIndex;
126
+ if (cursor &&
127
+ (blockNumber < cursor.blockNumber ||
128
+ (blockNumber === cursor.blockNumber &&
129
+ logIndex <= cursor.logIndex)))
130
+ continue;
131
+ cursor = {
132
+ blockNumber,
133
+ logIndex,
134
+ ...(log.blockHash ? { blockHash: log.blockHash } : {}),
135
+ };
136
+ notify({
137
+ jobId,
138
+ kind: kinds[names.indexOf(event.eventName)],
139
+ txHash: log.transactionHash ?? undefined,
140
+ blockNumber,
141
+ data: event.args,
142
+ cursor: { ...cursor },
143
+ });
144
+ }
145
+ next = end + BigInt(1);
146
+ }
147
+ }
148
+ catch (error) {
149
+ if (stopped)
150
+ return;
151
+ if (error instanceof errors_1.JobError && error.code === 'WATCH_REORG')
152
+ stopped = true;
153
+ notify({ jobId, kind: 'Error', error, cursor: cursor && { ...cursor } });
154
+ }
155
+ finally {
156
+ if (!stopped)
157
+ timer = setTimeout(() => {
158
+ void poll();
159
+ }, interval);
160
+ }
161
+ };
162
+ void poll();
163
+ return () => {
164
+ stopped = true;
165
+ if (timer)
166
+ clearTimeout(timer);
167
+ };
168
+ }
169
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1,18 @@
1
+ import { type Hex } from 'viem';
2
+ import type { BuildJobSpecOptions, BuildJobSpecTemplateOptions, JobSpec, JobSpecTemplate, LogicTree } from './types';
3
+ interface LogicWire {
4
+ kind: number;
5
+ checks: readonly number[];
6
+ children: readonly number[];
7
+ k: number;
8
+ }
9
+ export declare function int256(value: bigint, what?: string): bigint;
10
+ export declare function flattenLogic(tree: LogicTree, checkCount: number): LogicWire[];
11
+ export declare function buildJobSpec(options: BuildJobSpecOptions): JobSpec;
12
+ export declare function buildJobSpecTemplate(options: BuildJobSpecTemplateOptions): JobSpecTemplate;
13
+ export declare function encodeJobSpec(spec: JobSpec | JobSpecTemplate): Hex;
14
+ /** Known callers pass the format; inference requires one canonical validated decode. */
15
+ export declare function decodeJobSpec(bytes: Hex, options?: {
16
+ format?: 'spec' | 'template';
17
+ }): JobSpec | JobSpecTemplate;
18
+ export {};