@allorc/a423-sdk 0.4.0 → 0.5.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.
@@ -2,7 +2,7 @@
2
2
  const {createWorkflow,hashAgreement}=require('../workflow.cjs');
3
3
  const {createCredentialAuthenticator,createAuthorityHandler}=require('../authority/index.cjs');
4
4
  function createEscrowApplication({storage,authority,escrows,signerFor,addressFor,limitsFor,approveSigning,validateArtifact,execute,keeperEnabled=false,allowAuthorityRequest=async()=>false,requireIndependentArbitrator=true}={}){
5
- const {createEscrowRegistry,createEvidenceRevalidator,escrowTerms,workerConsent,escrowTransitions}=require('../escrow/index.cjs');
5
+ const {createEscrowRegistry,createEvidenceRevalidator,escrowTerms,workerConsent,settlementConsent,escrowTransitions}=require('../escrow/index.cjs');
6
6
  const {validateTask,validateEscrowEvidence,createSpendingAuthorizer,createExpiryAdapter,createApplicationHandler,createChatTools}=require('./index.cjs');
7
7
  if(!storage||!authority||!Array.isArray(escrows)||!escrows.length||typeof approveSigning!=='function'||typeof limitsFor!=='function')throw new TypeError('Explicit storage, authority, escrow configurations and spending/signing approvals required');
8
8
  const registry=new Map(escrows.map(c=>[String(c.chainId)+':'+c.contractAddress.toLowerCase(),c]));
@@ -24,7 +24,7 @@ function createEscrowApplication({storage,authority,escrows,signerFor,addressFor
24
24
  const validators=new Map(escrows.map(c=>[String(c.chainId)+':'+c.contractAddress.toLowerCase(),createEvidenceRevalidator(c)]));
25
25
  const revalidate=(job,evidence)=>validators.get(String(configFor(job).chainId)+':'+configFor(job).contractAddress.toLowerCase())(job,evidence);
26
26
  const authenticate=createCredentialAuthenticator({authority});
27
- const applicationOptions={workflow,store:storage.jobs,queue:storage.queue,authenticate,revalidate,consentFor:async job=>workerConsent(job,configFor(job)),authorityHandler:createAuthorityHandler({authority,allowRequest:allowAuthorityRequest})};
27
+ const applicationOptions={workflow,store:storage.jobs,queue:storage.queue,authenticate,revalidate,consentFor:async job=>workerConsent(job,configFor(job)),settlementConsentFor:async job=>settlementConsent(job,configFor(job)),authorityHandler:createAuthorityHandler({authority,allowRequest:allowAuthorityRequest})};
28
28
  const workerOptions={authority,actorFor:async job=>job.pending?.actor||job.participants.requester,allowExecute:keeperEnabled,
29
29
  execute,beforeExecute:async job=>{await workflow.assertSafe(job.id,job.participants.worker);if(!await authority.isActive(job.participants.worker))return false;const result=await adapters.start.execute({job,input:{},operation:{actor:job.participants.worker}});return result.status==='confirmed';}
30
30
  };
@@ -16,8 +16,8 @@ function validateEscrowEvidence(e){
16
16
  for(const key of ['contract','token','payer','worker','verifier','arbitrator'])assert(/^0x[0-9a-fA-F]{40}$/.test(e[key]),'Invalid evidence '+key);
17
17
  for(const key of ['job_id','agreement_hash','transaction_hash','block_hash','result_hash'])assert(/^0x[0-9a-fA-F]{64}$/.test(e[key]),'Invalid evidence '+key);
18
18
  assert(Number.isSafeInteger(e.block_number)&&e.block_number>=0&&Number.isSafeInteger(e.confirmations)&&e.confirmations>0,'Invalid evidence block');
19
- assert(['Funded','Submitted','Verified','Disputed','Settled'].includes(e.event),'Invalid evidence event');
20
- assert(Number.isInteger(e.state)&&e.state>=1&&e.state<=7&&BigInt(e.worker_paid)<=BigInt(e.amount),'Invalid evidence allocation/state');
19
+ assert(['Funded','Submitted','Verified','Disputed','Settled','SettlementProposed'].includes(e.event),'Invalid evidence event');
20
+ assert(Number.isInteger(e.state)&&e.state>=1&&e.state<=8&&BigInt(e.worker_paid)<=BigInt(e.amount),'Invalid evidence allocation/state');
21
21
  return structuredClone(e);
22
22
  }
23
23
  function createSpendingAuthorizer({spending,limitsFor,authorize}={}){
@@ -40,8 +40,8 @@ async function runMaintenanceOnce({workflow,store,actorFor,allowExecute=false,no
40
40
  let result=job;
41
41
  if(job.pending){result=await workflow.reconcile(job.id,actor);if(result.pending&&allowExecute)result=await workflow.resume(job.id,actor);}
42
42
  else if(job.agreement){const e=job.agreement.terms.escrow;const seconds=Math.floor(now/1000);let action;
43
- if(e&&['funded','running'].includes(job.state)&&seconds>e.work_deadline)action='timeout';
44
- if(e&&['submitted','verified','disputed'].includes(job.state)&&seconds>e.resolution_deadline)action='timeout';
43
+ if(e&&(['funded','running'].includes(job.state)||(['settlement_negotiation','disputed'].includes(job.state)&&!job.submission))&&seconds>e.work_deadline)action='timeout';
44
+ if(e&&['submitted','verified','disputed','settlement_negotiation'].includes(job.state)&&seconds>e.resolution_deadline)action='timeout';
45
45
  const expiry=job.agreement.terms.expires_at;
46
46
  if(['quoted','accepted'].includes(job.state)&&Number.isSafeInteger(expiry)&&seconds>expiry)action='expire';
47
47
  if(action&&allowExecute)result=await workflow.act(job.id,action,{}, {actor,idempotencyKey:'keeper_'+hash(job.id+':'+action)});
@@ -58,10 +58,11 @@ function createExpiryAdapter({now=()=>Date.now()}={}){const run=async({job})=>{
58
58
  };return {execute:run,reconcile:run};}
59
59
  async function runExecutionOnce({workflow,queue,execute,beforeExecute,leaseMs=30000}={}){
60
60
  const item=await queue.claim({kind:'execution',leaseMs});if(!item)return null;
61
- const heartbeat=setInterval(()=>{queue.heartbeat(item.id,item.lease,{leaseMs}).catch(()=>{});},Math.max(1,Math.floor(leaseMs/3)));
61
+ const controller=new AbortController();
62
+ const heartbeat=setInterval(async()=>{try{if(!await queue.heartbeat(item.id,item.lease,{leaseMs}))throw Error('Execution lease lost');const current=await workflow.assertSafe(item.payload.job_id,item.payload.actor);if(current.state!=='running')throw Error('Work paused');}catch(error){controller.abort(error);}},Math.max(1,Math.min(1000,Math.floor(leaseMs/3))));
62
63
  try{
63
64
  let result=item.result;
64
- if(!result){const job=await workflow.assertSafe(item.payload.job_id,item.payload.actor);assert(job.state==='running','Work requires running state');validateTask(job.agreement.terms.task);assert(typeof beforeExecute==='function'&&await beforeExecute(job)===true,'Execution eligibility check required');result=await execute({job,idempotencyKey:item.id});assert(await queue.checkpoint(item.id,item.lease,result),'Execution lease lost');}
65
+ if(!result){const job=await workflow.assertSafe(item.payload.job_id,item.payload.actor);assert(job.state==='running','Work requires running state');validateTask(job.agreement.terms.task);assert(typeof beforeExecute==='function'&&await beforeExecute(job)===true,'Execution eligibility check required');result=await execute({job,idempotencyKey:item.id,signal:controller.signal});assert(await queue.checkpoint(item.id,item.lease,result),'Execution lease lost');}
65
66
  assert(typeof result.result_hash==='string','Execution must return artifact commitment');
66
67
  const job=await workflow.act(item.payload.job_id,'submit',result,{actor:item.payload.actor,idempotencyKey:'execution_'+hash(item.id)});
67
68
  assert(await queue.complete(item.id,item.lease,{job_id:job.id,state:job.state}),'Execution lease lost');return job;
@@ -91,7 +92,7 @@ function createWebhookDispatcher({queue,kv,subscriptions,secretFor,fetch:fetchIm
91
92
  }
92
93
  async function watchEvidenceOnce({store,revalidate}){const results=[];let after='';while(true){const jobs=await store.list({after,limit:100});if(!jobs.length)break;after=jobs.at(-1).id;for(const job of jobs){if(!job.evidence.length)continue;const checks=[];for(const item of job.evidence)if(item.evidence.transaction_hash){try{checks.push(await revalidate(job,item.evidence));}catch(error){checks.push({status:'unavailable',message:'Evidence provider unavailable'});}}
93
94
  const blocked=checks.some(c=>c.status!=='valid');const safety={blocked,checks,checked_at:new Date().toISOString()};await store.setSafety(job.id,safety);results.push({id:job.id,...safety});}}return results;}
94
- async function freshReceipts({workflow,id,actor,revalidate}){const job=await workflow.get(id,actor);const checks=[];for(const item of job.evidence)if(item.evidence.transaction_hash){const result=await revalidate(job,item.evidence);assert(result.status==='valid','Receipt evidence is not currently valid: '+result.status);checks.push(result);}return {...await workflow.receipts(id,actor),revalidated_at:new Date().toISOString(),checks};}
95
+ async function freshReceipts({workflow,id,actor,revalidate}){const job=await workflow.get(id,actor);for(const p of job.negotiation?.history||[]){const canonical=require('../closing.cjs').settlementProposal(job,{worker_amount:p.worker_amount,payer_amount:p.payer_amount,expected_revision:p.escrow_version-1,expires_at:p.expires_at,reason:p.reason,claims:p.claims});assert(canonical.proposal_hash===p.proposal_hash,'Stored settlement claims changed');}const checks=[];for(const item of job.evidence)if(item.evidence.transaction_hash){const result=await revalidate(job,item.evidence);assert(result.status==='valid','Receipt evidence is not currently valid: '+result.status);checks.push(result);}return {...await workflow.receipts(id,actor),revalidated_at:new Date().toISOString(),checks};}
95
96
  async function renderReceiptPdf(receipt){const {PDFDocument,StandardFonts}=require('pdf-lib');const pdf=await PDFDocument.create(),font=await pdf.embedFont(StandardFonts.Courier);let page,y;const newPage=()=>{page=pdf.addPage([595,842]);y=800;};newPage();const text=JSON.stringify(receipt,null,2).replace(/[^\x20-\x7e\n]/g,'?');for(const line of ['A423 Evidence Receipt',...text.split('\n')])for(let i=0;i<Math.max(1,line.length);i+=88){if(y<40)newPage();page.drawText(line.slice(i,i+88),{x:32,y,size:9,font});y-=12;}return pdf.save();}
96
97
  function planLegacyMigration(records){return records.map(record=>({id:record.id,state:record.state,automatic:false,reason:['funded','running','submitted','verified','paid','settlement_pending','completed'].includes(String(record.state).toLowerCase())?'Existing custody/evidence must stay with original contract; do not relabel':'Requires reviewed participant and accepted-terms mapping; create a new job with provenance'}));}
97
98
  module.exports={validateTask,validateEscrowEvidence,createSpendingAuthorizer,runMaintenanceOnce,createExpiryAdapter,runExecutionOnce,enqueueRunningJobs,createEventStream,createWebhookDispatcher,watchEvidenceOnce,freshReceipts,renderReceiptPdf,planLegacyMigration};
@@ -15,7 +15,7 @@ export function createSpendingAuthorizer(options: {spending: SpendingStore;limit
15
15
  export function runMaintenanceOnce(options: {workflow: Workflow;store: SqliteJobStore;actorFor(job: WorkflowJob): Promise<string | null>;allowExecute?: boolean;now?: number}): Promise<Array<{id: string;state?: string;pending?: boolean;error?: string}>>;
16
16
  export function createExpiryAdapter(options?: {now?(): number}): {execute(context: {job: WorkflowJob}): Promise<any>;reconcile(context: {job: WorkflowJob}): Promise<any>};
17
17
  export function enqueueRunningJobs(options: {store: SqliteJobStore;queue: DurableQueue}): Promise<number>;
18
- export function runExecutionOnce(options: {workflow: Workflow;queue: DurableQueue;execute(context: {job: WorkflowJob;idempotencyKey: string}): Promise<{result_hash: string;[key: string]: Json}>;beforeExecute(job: WorkflowJob): Promise<boolean>;leaseMs?: number}): Promise<WorkflowJob | null>;
18
+ export function runExecutionOnce(options: {workflow: Workflow;queue: DurableQueue;execute(context: {job: WorkflowJob;idempotencyKey: string;signal: AbortSignal}): Promise<{result_hash: string;[key: string]: Json}>;beforeExecute(job: WorkflowJob): Promise<boolean>;leaseMs?: number}): Promise<WorkflowJob | null>;
19
19
  export function createEventStream(options: {store: SqliteJobStore;authenticate(request: Request): Promise<string | null>;pollMs?: number;maxDurationMs?: number}): (request: Request) => Promise<Response>;
20
20
  export function createWebhookDispatcher(options: {queue: DurableQueue;kv: KeyValueStore;subscriptions: Array<{id: string;actor: string;url: string;after?: number}>;secretFor(id: string): Promise<string>;fetch?: typeof fetch;timeoutMs?: number}): {project(store: SqliteJobStore): Promise<void>;deliverOne(): Promise<any>};
21
21
  export function watchEvidenceOnce(options: {store: SqliteJobStore;revalidate: Revalidator}): Promise<any[]>;
@@ -24,6 +24,6 @@ export function renderReceiptPdf(receipt: object): Promise<Uint8Array>;
24
24
  export function planLegacyMigration(records: Array<{id: string;state: string}>): Array<{id: string;state: string;automatic: false;reason: string}>;
25
25
  export function migrateUnfundedLegacy(options: {records: Array<{id: string;state: string}>;workflow: Workflow;actor: string;map(source: any): Promise<Parameters<Workflow['create']>[0]>}): Promise<WorkflowJob[]>;
26
26
  export function createChatTools(options: {workflow: Workflow;store: SqliteJobStore;queue: DurableQueue;actor: string}): Record<string,(input: any) => Promise<WorkflowJob>>;
27
- export function createApplicationHandler(options: {workflow: Workflow;store: SqliteJobStore;queue: DurableQueue;authenticate(request: Request): Promise<string | null>;revalidate: Revalidator;consentFor?(job: WorkflowJob): Promise<object>;legacyState?(actor: string): Promise<object>;authorityHandler?(request: Request): Promise<Response>;basePath?: string}): (request: Request) => Promise<Response>;
27
+ export function createApplicationHandler(options: {workflow: Workflow;store: SqliteJobStore;queue: DurableQueue;authenticate(request: Request): Promise<string | null>;revalidate: Revalidator;consentFor?(job: WorkflowJob): Promise<object>;settlementConsentFor?(job: WorkflowJob): Promise<object>;legacyState?(actor: string): Promise<object>;authorityHandler?(request: Request): Promise<Response>;basePath?: string}): (request: Request) => Promise<Response>;
28
28
 
29
- export function createEscrowApplication(options: {storage: import('../storage/index.js').SqliteStorage;authority: import('../authority/index.js').Authority;escrows: Array<any>;signerFor(actor: string): Promise<any>;addressFor(actor: string): Promise<string>;limitsFor(context: SigningContext): Promise<{perTransaction: string;daily: string;total: string}>;approveSigning(context: SigningContext): Promise<boolean>;validateArtifact(context: {job: WorkflowJob;resultHash: string}): Promise<boolean>;execute?(context: {job: WorkflowJob;idempotencyKey: string}): Promise<{result_hash: string;[key: string]: Json}>;keeperEnabled?: boolean;allowAuthorityRequest?(request: Request): Promise<boolean>;requireIndependentArbitrator?: boolean}): {workflow: Workflow;applicationOptions: Parameters<typeof createApplicationHandler>[0];workerOptions: any;handler: (request: Request) => Promise<Response>;chatTools(actor: string): ReturnType<typeof createChatTools>};
29
+ export function createEscrowApplication(options: {storage: import('../storage/index.js').SqliteStorage;authority: import('../authority/index.js').Authority;escrows: Array<any>;signerFor(actor: string): Promise<any>;addressFor(actor: string): Promise<string>;limitsFor(context: SigningContext): Promise<{perTransaction: string;daily: string;total: string}>;approveSigning(context: SigningContext): Promise<boolean>;validateArtifact(context: {job: WorkflowJob;resultHash: string}): Promise<boolean>;execute?(context: {job: WorkflowJob;idempotencyKey: string;signal: AbortSignal}): Promise<{result_hash: string;[key: string]: Json}>;keeperEnabled?: boolean;allowAuthorityRequest?(request: Request): Promise<boolean>;requireIndependentArbitrator?: boolean}): {workflow: Workflow;applicationOptions: Parameters<typeof createApplicationHandler>[0];workerOptions: any;handler: (request: Request) => Promise<Response>;chatTools(actor: string): ReturnType<typeof createChatTools>};
package/src/workflow.cjs CHANGED
@@ -75,7 +75,31 @@ function createWorkflow({ store, adapters = {}, authorize, validateTerms, valida
75
75
  next.operations[pending.key] = { request_hash: pending.request_hash, status: 'confirmed', result: copy(result) };
76
76
  next.evidence.push({ action: pending.action, operation_id: pending.id, evidence: copy(result.evidence) });
77
77
  if (pending.action === 'submit') next.submission = copy(pending.input);
78
- return save(job, next, pending.action + '.confirmed', pending.actor, result.evidence);
78
+ let eventData=copy(result.evidence);
79
+ if(['propose_settlement','counter_settlement'].includes(pending.action)){
80
+ const proposal=require('./closing.cjs').settlementProposal(job,pending.input);
81
+ if(result.evidence.proposal_hash!==proposal.proposal_hash || result.evidence.escrow_version!==proposal.escrow_version)error('INVALID_ADAPTER_RESULT','Confirmed proposal must match exact claimed terms',502);
82
+ const record={...proposal,proposer_id:pending.actor,at:stamp()};
83
+ next.negotiation={status:'open',origin_state:job.negotiation?.origin_state||job.state,current:record,history:[...(job.negotiation?.history||[]),record]};
84
+ next.work_status='paused';eventData={...eventData,proposal:record};
85
+ }
86
+ if(pending.action==='accept_settlement'){
87
+ const p=job.negotiation?.current;
88
+ if(!p || result.evidence.settlement_reason!==4 || result.evidence.worker_paid!==p.worker_amount || result.evidence.proposal_hash!==p.proposal_hash || result.evidence.escrow_version!==p.escrow_version)error('INVALID_ADAPTER_RESULT','Closing settlement evidence mismatch',502);
89
+ next.negotiation={...copy(job.negotiation),status:'settled',accepted_by:pending.actor,settled_at:stamp()};next.work_status='stopped';
90
+ }
91
+ if(pending.action==='dispute'){next.work_status='paused';if(next.negotiation)next.negotiation.status='disputed';}
92
+ if(['release','refund','resolve','timeout'].includes(pending.action)){
93
+ next.work_status=pending.action==='release'?'completed':'stopped';
94
+ if(next.negotiation)next.negotiation={...next.negotiation,status:'settled',settled_at:stamp()};
95
+ }
96
+ if(['start','submit','verify'].includes(pending.action))next.work_status={start:'running',submit:'submitted',verify:'verified'}[pending.action];
97
+ const e=result.evidence;
98
+ if(typeof e.amount==='string'&&typeof e.worker_paid==='string'&&Number.isInteger(e.state)){
99
+ const closed=[5,6,7].includes(e.state);
100
+ next.escrow_ledger={funded_amount:e.amount,worker_paid:e.worker_paid,payer_refunded:closed?(BigInt(e.amount)-BigInt(e.worker_paid)).toString():'0',locked_amount:closed?'0':e.amount,escrow_version:e.escrow_version??0};
101
+ }
102
+ return save(job, next, pending.action + '.confirmed', pending.actor, eventData);
79
103
  }
80
104
  async function execute(job, reconcile = false) {
81
105
  const pending = job.pending;
@@ -94,13 +118,13 @@ function createWorkflow({ store, adapters = {}, authorize, validateTerms, valida
94
118
  if (participants.requester === participants.worker || actor !== participants.requester) error('FORBIDDEN', 'Requester must create the job and differ from worker', 403);
95
119
  canonical(metadata); canonical(participants);
96
120
  const at = stamp();
97
- const job = { id, protocol: 'a423.workflow.v1', version: 1, state: 'draft', participants: copy(participants), metadata: copy(metadata), agreement: null, submission: null, pending: null, operations: {}, evidence: [], events: [{ sequence: 1, type: 'created', actor_id: actor, at, data: {} }], created_at: at, updated_at: at };
121
+ const job = { work_status:'not_started',negotiation:null,escrow_ledger:null,id, protocol: 'a423.workflow.v1', version: 1, state: 'draft', participants: copy(participants), metadata: copy(metadata), agreement: null, submission: null, pending: null, operations: {}, evidence: [], events: [{ sequence: 1, type: 'created', actor_id: actor, at, data: {} }], created_at: at, updated_at: at };
98
122
  if (authorize && await authorize({ job: copy(job), action: 'create', actor, input: {} }) !== true) error('FORBIDDEN', 'Application policy rejected creation', 403);
99
123
  if (!await store.create(job)) error('CONFLICT', 'Job ID already exists');
100
124
  return copy(job);
101
125
  },
102
126
  get,
103
- async assertSafe(id,actor){const job=await get(id,actor);const safety=store.getSafety?await store.getSafety(id):null;if(safety?.blocked)error('SAFETY_HOLD','Evidence requires reconciliation',409);return job;},
127
+ async assertSafe(id,actor){const job=await get(id,actor);const safety=store.getSafety?await store.getSafety(id):null;if(safety?.blocked)error('SAFETY_HOLD','Evidence requires reconciliation',409);if(['propose_settlement','counter_settlement','dispute'].includes(job.pending?.action)||job.state==='settlement_negotiation')error('WORK_PAUSED','Settlement negotiation pauses work',409);return job;},
104
128
  async act(id, action, input, { actor, idempotencyKey } = {}) {
105
129
  identifier(actor); identifier(idempotencyKey); identifier(action); canonical(input);
106
130
  let job = await get(id, actor);
@@ -156,7 +180,7 @@ function createWorkflow({ store, adapters = {}, authorize, validateTerms, valida
156
180
  },
157
181
  async receipts(id, actor) {
158
182
  const job = await get(id, actor);
159
- return { protocol: job.protocol, job_id: id, state: job.state, agreement: job.agreement, submission: job.submission, evidence: job.evidence, events: job.events, pending: job.pending };
183
+ return { protocol: job.protocol, job_id: id, state: job.state, agreement: job.agreement, submission: job.submission, work_status:job.work_status,negotiation:job.negotiation,escrow_ledger:job.escrow_ledger,evidence: job.evidence, events: job.events, pending: job.pending };
160
184
  }
161
185
  };
162
186
  }
package/src/workflow.d.ts CHANGED
@@ -2,7 +2,12 @@ export type Json = null | boolean | number | string | Json[] | { [key: string]:
2
2
  export interface Agreement { revision: number; terms: { [key: string]: Json }; hash: string; accepted_by: string[] }
3
3
  export interface Operation { id: string; key: string; action: string; actor: string; input: Json; request_hash: string; target: string; created_at: string; observation: AdapterResult | null }
4
4
  export interface AdapterResult { status: 'pending' | 'confirmed' | 'rejected'; evidence?: { [key: string]: Json }; [key: string]: Json | undefined }
5
+ export interface SettlementClaim {kind: 'work' | 'expense' | 'other';description: string;amount?: string;evidence?: string[]}
6
+ export interface SettlementProposal {version: 'a423.closing.v1';job_id: string;agreement_hash: string;escrow_version: number;worker_amount: string;payer_amount: string;expires_at: number;reason: string;claims: SettlementClaim[];closes_job: true;proposal_hash: string;proposer_id?: string;at?: string}
7
+ export interface Negotiation {status: 'open' | 'disputed' | 'settled';origin_state: string;current: SettlementProposal;history: SettlementProposal[];accepted_by?: string;settled_at?: string}
8
+ export interface EscrowLedger {funded_amount: string;worker_paid: string;payer_refunded: string;locked_amount: string;escrow_version: number}
5
9
  export interface WorkflowJob {
10
+ work_status?: string;negotiation?: Negotiation | null;escrow_ledger?: EscrowLedger | null;
6
11
  id: string; protocol: 'a423.workflow.v1'; version: number; state: string;
7
12
  participants: { requester: string; worker: string; verifier: string; [role: string]: string };
8
13
  metadata: Json; agreement: Agreement | null; submission: Json;
@@ -38,7 +43,7 @@ export interface Workflow {
38
43
  act(id: string, action: string, input: Json, options: { actor: string; idempotencyKey: string }): Promise<WorkflowJob>;
39
44
  resume(id: string, actor: string): Promise<WorkflowJob>;
40
45
  reconcile(id: string, actor: string): Promise<WorkflowJob>;
41
- receipts(id: string, actor: string): Promise<Pick<WorkflowJob, 'protocol' | 'state' | 'agreement' | 'submission' | 'evidence' | 'events' | 'pending'> & { job_id: string }>;
46
+ receipts(id: string, actor: string): Promise<Pick<WorkflowJob, 'protocol' | 'state' | 'agreement' | 'submission' | 'evidence' | 'events' | 'pending' | 'work_status' | 'negotiation' | 'escrow_ledger'> & { job_id: string }>;
42
47
  }
43
48
  export function hashAgreement(terms: Json): string;
44
49
  export function createWorkflow(options: WorkflowOptions): Workflow;