---
# System prepended metadata

title: effects

---

# effects

- we have new provider thingy with api that returns effects

  ```ts
  Server.provider2(cap, ({ invocation, invoke, id }) => {
    return {
      result: { ok: {} }
      fx: {
        join: invoke("offer/arrange", {
          with: id.did(),
          ...
        })
      }
    }
  })
  ```

- Server sends receipt back
- Calls the local handler for the effects concurrently
- handler for the scheduled events can be something like

```ts
Server.schedule(OfferArrange, async ({ capability }) => {
  const response = await fetch(ribar.url, {
    body: capability.input
  })
  
  const result = await response.json()
  if (result.ok) {
    return { result }
  } else {
    const sleep = invoke({
      'scheduler/sleep': {
        ms: 1000
      }
    })
    
    const reschedule = invoke({
      'offer/arrange': {
        ...cap.input
        _: sleep.wait()
      }
    })
    
    return {
      result: { ok: {} },
      fx: {
        fork: [sleep],
        join: reschedule
      }
    }
  }
})
```

- ⚠️ We need a way to not do request / response
- ⚠️ We need a way to do `await/ok` from invocation spec


```ts

Server.promise({ can: "wait/s3/put" }, async ({ input, context }) => {
    // writes into dynamo cid to invoke when that event
    // happens
    await context.s3.putListeners({
      path: input.path,
      invoke: context.cid
    })
    
    
    return context.suspend()
}, (response) => {
  return { result: format(response) }
})

Server.provide("wait/s3/put", async ({ invocation, input, context }) => {
    // writes into dynamo cid to invoke when that event
    // happens
    await context.s3.putListeners({
      path: input.path,
      invoke: invocation.link()
    })
  
  return Server.suspend()
})
    
invoke("ucanto/resume", {
  task: { ... }
  data
})
  
Server.create({
  loadInvocation(cid) => {
  
  }
})




Server.join(OfferArrange, async ({ capability, tx, events }) => {
  const response = await fetch(ribar.url, {
    body: capability.input
  })
  
  const result = await response.json()
  if (result.ok) {
    return tx.return(result)
  } else {
    return tx
        .wait(invoke("wait/s3/put"))
        .and(invoke(myself))
  }
})


```

- we need a schedulery thing on the server

```ts
Server.create({
  ...,
  events: {
    wait(time, invocation): WaitEvent,
    S3Put(path, invocation): S3PutEvent
  }
//   scheduler: {
//     wait: (date, invocation):void => {
      
//     },
//     poll: (event, invocation):void => {
      
//     }
//   }
})
```

```typescript
Provider.task('s3/await/put', ({ input, invocation, agent }) => {
  // We create an `s3/wait/resume` invocation that we'll write
  // into s3 listener queue so that once it happens listener
  // (lambada) will be able to invoke it.
  const task = agent.invoke('s3/receive/put', {
    job: invocation.link()
  })
  
  // We write into some place like dynamo db an event that we
  // want to receive and invocation in a CAR file that listener
  // will be able to use to send it to us.
  s3.listeners.put({ put: input.path }, await task.archive())
  

  // We join this invocation with task which will be run by
  // the s3 listener. Whatever the result of the task is will
  // end up been result of this invocation as well ??
  return Provider.join(task)
})

Provider.provider('s3/receive/put', ({ input, invocation }) => {
  // we complete task with whatever was passed inside the input
  return input.result.ok ?
    { ok: {} }
    { error: input.result.error }
})

function* s3(event) {
  const id = yield* Task.current()
  s3.listeners.put(event, id)
  
  const result = yield* Task.suspend(id)
  
  
  return { ok: {} }
}
```


### Spade Proxy Example

```typescript
const OfferDetail = Schema.struct({
  // CAR CID
  link: Schema.link(),
  // CAR size
  size: Schema.integer(),
  // CAR commP
  commitmentProof: Schema.link(),
  // URLs CAR can be fetched from
  src: Schema.url().array()
})

const Offer = capability({
  can: "aggregate/offer",
  with: BrokerDID,
  nb: Schema.struct({
    // link to the offers who's blocks
    // will be attached to invocation
    offer: OfferDetail
            .array()
            .link()
            .attach(),
    // aggregate commP
    commitmentProof: Schema.link(),
  })
})

const Arrange = capability({
  can: "offer/arrange",
  with: BrokerDID,
  nb: Schema.struct({
    // aggregate commP
    commitmentProof: Schema.link()
  })
})


Provider.provide(Offer, async ({ capability, context }) => {
  // We create an invocation that can be executed later by
  // another actor if we give it to them
  //
  // ⚠️ This is a simple case because we do not need to compute
  // some data to be passed to the arrange handler. If we had to
  // do it we would have two options at our disposal
  //
  // 1. Delegate capability to invoke this as opposed to creating
  //    an invocation. That would actually be better from OCAP
  //    perspective but would imply caller should be capable of
  //    doing ucan signing and invoking.
  // 2. Alternatively we could have pre-arranged a place where
  //    data could be written and then read by `arrange` handler.
  //    E.g we could presign S3 PUT URL and include it in `nb`
  //    field when job of arrangment is done system could write
  //    result into that URL and run this invocation. Handler
  //    will then read the data from the URL and incorporate it
  //    in the result.
  const arrange = await Arrange.invoke({
    issuer: context.signer,
    audience: context.signer,
    with: context.signer.did(),
    nb: {
      commitmentProof: capability.commitmentProof
    },
    expiration: monthFromNow
  }).delegate()
  
  
  // Then put in the DB record for this offer (keyed by commP)
  // and archived invocation which can be invoked by someone else
  db.put({
    commitmentProof,
    run: await arrange.archive()
  })
  
  
  return Provider
    // we return ok result
    .ok({ status: "queued" })
     // and add a join effect we have not ran it however
     // so server will do no attempt to do so.
    .join(arrange.link())
})

Provider.provide(Arrange, async ({ capability }) => {
  // aggregate offer does not actually do anyithing because all
  // of the actual work was done by the outside system which
  // simply reported a result
  return Provider.ok({
    commitmentProof: capability.commitmentProof
  })
})
```