@t4h.framework/amber 0.1.0 → 0.2.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/.ai/skills/framework-amber/SKILL.md +225 -0
- package/LICENSE +21 -0
- package/README.md +78 -68
- package/dist/activities/AbstractAmberHttpRequestActivity.d.ts +2 -5
- package/dist/activities/AbstractAmberHttpRequestActivity.d.ts.map +1 -1
- package/dist/activities/AbstractAmberHttpRequestActivity.js.map +1 -1
- package/dist/activities/AmberTabulateServiceActivity.d.ts +10 -0
- package/dist/activities/AmberTabulateServiceActivity.d.ts.map +1 -0
- package/dist/activities/AmberTabulateServiceActivity.js +20 -0
- package/dist/activities/AmberTabulateServiceActivity.js.map +1 -0
- package/dist/activities/AmberTransferServiceActivity.d.ts +86 -0
- package/dist/activities/AmberTransferServiceActivity.d.ts.map +1 -0
- package/dist/activities/AmberTransferServiceActivity.js +95 -0
- package/dist/activities/AmberTransferServiceActivity.js.map +1 -0
- package/dist/activities/AmberUpdateServiceActivity.d.ts +10 -0
- package/dist/activities/AmberUpdateServiceActivity.d.ts.map +1 -0
- package/dist/activities/AmberUpdateServiceActivity.js +23 -0
- package/dist/activities/AmberUpdateServiceActivity.js.map +1 -0
- package/dist/activities/ticket/AmberCommentTicketActivity.d.ts +10 -0
- package/dist/activities/ticket/AmberCommentTicketActivity.d.ts.map +1 -0
- package/dist/activities/ticket/AmberCommentTicketActivity.js +19 -0
- package/dist/activities/ticket/AmberCommentTicketActivity.js.map +1 -0
- package/dist/activities/ticket/AmberCreateTicketActivity.d.ts +13 -0
- package/dist/activities/ticket/AmberCreateTicketActivity.d.ts.map +1 -0
- package/dist/activities/ticket/AmberCreateTicketActivity.js +47 -0
- package/dist/activities/ticket/AmberCreateTicketActivity.js.map +1 -0
- package/dist/activities/ticket/AmberFindTicketFieldsActivity.d.ts +7 -0
- package/dist/activities/ticket/AmberFindTicketFieldsActivity.d.ts.map +1 -0
- package/dist/activities/ticket/AmberFindTicketFieldsActivity.js +20 -0
- package/dist/activities/ticket/AmberFindTicketFieldsActivity.js.map +1 -0
- package/dist/activities/ticket/AmberGetTicketActivity.d.ts +7 -0
- package/dist/activities/ticket/AmberGetTicketActivity.d.ts.map +1 -0
- package/dist/activities/ticket/AmberGetTicketActivity.js +27 -0
- package/dist/activities/ticket/AmberGetTicketActivity.js.map +1 -0
- package/dist/activities/ticket/AmberInteractTicketActivity.d.ts +10 -0
- package/dist/activities/ticket/AmberInteractTicketActivity.d.ts.map +1 -0
- package/dist/activities/ticket/AmberInteractTicketActivity.js +20 -0
- package/dist/activities/ticket/AmberInteractTicketActivity.js.map +1 -0
- package/dist/activities/ticket/AmberLockTicketActivity.d.ts +11 -0
- package/dist/activities/ticket/AmberLockTicketActivity.d.ts.map +1 -0
- package/dist/activities/ticket/AmberLockTicketActivity.js +29 -0
- package/dist/activities/ticket/AmberLockTicketActivity.js.map +1 -0
- package/dist/activities/ticket/AmberReleaseTicketLockActivity.d.ts +10 -0
- package/dist/activities/ticket/AmberReleaseTicketLockActivity.d.ts.map +1 -0
- package/dist/activities/ticket/AmberReleaseTicketLockActivity.js +27 -0
- package/dist/activities/ticket/AmberReleaseTicketLockActivity.js.map +1 -0
- package/dist/activities/ticket/AmberUpdateTicketFieldValueActivity.d.ts +14 -0
- package/dist/activities/ticket/AmberUpdateTicketFieldValueActivity.d.ts.map +1 -0
- package/dist/activities/ticket/AmberUpdateTicketFieldValueActivity.js +19 -0
- package/dist/activities/ticket/AmberUpdateTicketFieldValueActivity.js.map +1 -0
- package/dist/constants/urls.d.ts +3 -0
- package/dist/constants/urls.d.ts.map +1 -0
- package/dist/constants/urls.js +3 -0
- package/dist/constants/urls.js.map +1 -0
- package/dist/constants/webhook.d.ts +12 -0
- package/dist/constants/webhook.d.ts.map +1 -0
- package/dist/constants/webhook.js +11 -0
- package/dist/constants/webhook.js.map +1 -0
- package/dist/errors/AmberRequestError.d.ts +23 -0
- package/dist/errors/AmberRequestError.d.ts.map +1 -0
- package/dist/errors/AmberRequestError.js +43 -0
- package/dist/errors/AmberRequestError.js.map +1 -0
- package/dist/index.d.ts +26 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -9
- package/dist/index.js.map +1 -1
- package/dist/inputs/AmberServiceTabulateEvent.d.ts +75 -0
- package/dist/inputs/AmberServiceTabulateEvent.d.ts.map +1 -0
- package/dist/inputs/AmberServiceTabulateEvent.js +26 -0
- package/dist/inputs/AmberServiceTabulateEvent.js.map +1 -0
- package/dist/inputs/AmberWebhookEvent.d.ts +19 -0
- package/dist/inputs/AmberWebhookEvent.d.ts.map +1 -0
- package/dist/inputs/AmberWebhookEvent.js +15 -0
- package/dist/inputs/AmberWebhookEvent.js.map +1 -0
- package/dist/models/Amber.d.ts +8 -5
- package/dist/models/Amber.d.ts.map +1 -1
- package/dist/models/Amber.js +20 -26
- package/dist/models/Amber.js.map +1 -1
- package/dist/models/Service.d.ts +26 -0
- package/dist/models/Service.d.ts.map +1 -0
- package/dist/models/Service.js +53 -0
- package/dist/models/Service.js.map +1 -0
- package/dist/models/Ticket.d.ts +24 -25
- package/dist/models/Ticket.d.ts.map +1 -1
- package/dist/models/Ticket.js +44 -109
- package/dist/models/Ticket.js.map +1 -1
- package/dist/tools/AmberWebhook.d.ts +22 -0
- package/dist/tools/AmberWebhook.d.ts.map +1 -0
- package/dist/tools/AmberWebhook.js +51 -0
- package/dist/tools/AmberWebhook.js.map +1 -0
- package/dist/typings/ServiceTabulate.d.ts.map +1 -0
- package/dist/typings/ServiceTabulate.js.map +1 -0
- package/dist/{types → typings}/ServiceTicket.d.ts +4 -4
- package/dist/typings/ServiceTicket.d.ts.map +1 -0
- package/dist/typings/ServiceTicket.js.map +1 -0
- package/dist/typings/ServiceTicketComment.d.ts.map +1 -0
- package/dist/typings/ServiceTicketComment.js.map +1 -0
- package/dist/typings/ServiceTicketField.d.ts +12 -0
- package/dist/typings/ServiceTicketField.d.ts.map +1 -0
- package/dist/typings/ServiceTicketField.js +2 -0
- package/dist/typings/ServiceTicketField.js.map +1 -0
- package/dist/typings/ServiceTicketInteraction.d.ts.map +1 -0
- package/dist/typings/ServiceTicketInteraction.js.map +1 -0
- package/dist/{types → typings}/ServiceTicketLock.d.ts +0 -1
- package/dist/typings/ServiceTicketLock.d.ts.map +1 -0
- package/dist/typings/ServiceTicketLock.js.map +1 -0
- package/dist/typings/ServiceTransfer.d.ts.map +1 -0
- package/dist/typings/ServiceTransfer.js.map +1 -0
- package/dist/typings/ServiceUpdate.d.ts.map +1 -0
- package/dist/typings/ServiceUpdate.js.map +1 -0
- package/package.json +10 -7
- package/dist/activities/AmberCommentTicketActivity.d.ts +0 -13
- package/dist/activities/AmberCommentTicketActivity.d.ts.map +0 -1
- package/dist/activities/AmberCommentTicketActivity.js +0 -22
- package/dist/activities/AmberCommentTicketActivity.js.map +0 -1
- package/dist/activities/AmberCreateTicketActivity.d.ts +0 -15
- package/dist/activities/AmberCreateTicketActivity.d.ts.map +0 -1
- package/dist/activities/AmberCreateTicketActivity.js +0 -68
- package/dist/activities/AmberCreateTicketActivity.js.map +0 -1
- package/dist/activities/AmberGetTicketActivity.d.ts +0 -12
- package/dist/activities/AmberGetTicketActivity.d.ts.map +0 -1
- package/dist/activities/AmberGetTicketActivity.js +0 -30
- package/dist/activities/AmberGetTicketActivity.js.map +0 -1
- package/dist/activities/AmberInteractTicketActivity.d.ts +0 -13
- package/dist/activities/AmberInteractTicketActivity.d.ts.map +0 -1
- package/dist/activities/AmberInteractTicketActivity.js +0 -23
- package/dist/activities/AmberInteractTicketActivity.js.map +0 -1
- package/dist/activities/AmberLockTicketActivity.d.ts +0 -14
- package/dist/activities/AmberLockTicketActivity.d.ts.map +0 -1
- package/dist/activities/AmberLockTicketActivity.js +0 -33
- package/dist/activities/AmberLockTicketActivity.js.map +0 -1
- package/dist/activities/AmberReleaseTicketLockActivity.d.ts +0 -12
- package/dist/activities/AmberReleaseTicketLockActivity.d.ts.map +0 -1
- package/dist/activities/AmberReleaseTicketLockActivity.js +0 -30
- package/dist/activities/AmberReleaseTicketLockActivity.js.map +0 -1
- package/dist/activities/AmberTabulateTicketActivity.d.ts +0 -13
- package/dist/activities/AmberTabulateTicketActivity.d.ts.map +0 -1
- package/dist/activities/AmberTabulateTicketActivity.js +0 -22
- package/dist/activities/AmberTabulateTicketActivity.js.map +0 -1
- package/dist/activities/AmberTransferTicketActivity.d.ts +0 -77
- package/dist/activities/AmberTransferTicketActivity.d.ts.map +0 -1
- package/dist/activities/AmberTransferTicketActivity.js +0 -121
- package/dist/activities/AmberTransferTicketActivity.js.map +0 -1
- package/dist/activities/AmberUpdateTicketActivity.d.ts +0 -13
- package/dist/activities/AmberUpdateTicketActivity.d.ts.map +0 -1
- package/dist/activities/AmberUpdateTicketActivity.js +0 -22
- package/dist/activities/AmberUpdateTicketActivity.js.map +0 -1
- package/dist/models/AmberConnection.d.ts +0 -7
- package/dist/models/AmberConnection.d.ts.map +0 -1
- package/dist/models/AmberConnection.js +0 -11
- package/dist/models/AmberConnection.js.map +0 -1
- package/dist/types/ServiceTabulate.d.ts.map +0 -1
- package/dist/types/ServiceTabulate.js.map +0 -1
- package/dist/types/ServiceTicket.d.ts.map +0 -1
- package/dist/types/ServiceTicket.js.map +0 -1
- package/dist/types/ServiceTicketComment.d.ts.map +0 -1
- package/dist/types/ServiceTicketComment.js.map +0 -1
- package/dist/types/ServiceTicketInteraction.d.ts.map +0 -1
- package/dist/types/ServiceTicketInteraction.js.map +0 -1
- package/dist/types/ServiceTicketLock.d.ts.map +0 -1
- package/dist/types/ServiceTicketLock.js.map +0 -1
- package/dist/types/ServiceTransfer.d.ts.map +0 -1
- package/dist/types/ServiceTransfer.js.map +0 -1
- package/dist/types/ServiceUpdate.d.ts.map +0 -1
- package/dist/types/ServiceUpdate.js.map +0 -1
- /package/dist/{types → typings}/ServiceTabulate.d.ts +0 -0
- /package/dist/{types → typings}/ServiceTabulate.js +0 -0
- /package/dist/{types → typings}/ServiceTicket.js +0 -0
- /package/dist/{types → typings}/ServiceTicketComment.d.ts +0 -0
- /package/dist/{types → typings}/ServiceTicketComment.js +0 -0
- /package/dist/{types → typings}/ServiceTicketInteraction.d.ts +0 -0
- /package/dist/{types → typings}/ServiceTicketInteraction.js +0 -0
- /package/dist/{types → typings}/ServiceTicketLock.js +0 -0
- /package/dist/{types → typings}/ServiceTransfer.d.ts +0 -0
- /package/dist/{types → typings}/ServiceTransfer.js +0 -0
- /package/dist/{types → typings}/ServiceUpdate.d.ts +0 -0
- /package/dist/{types → typings}/ServiceUpdate.js +0 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: framework-amber
|
|
3
|
+
description: >-
|
|
4
|
+
Guides correct use of @t4h.framework/amber in T4H Framework workflows: the
|
|
5
|
+
`Amber` client, the generic `Service` model and the `Ticket` model, the
|
|
6
|
+
workflow-run lock, waiting for an agent to tabulate a ticket, the webhook
|
|
7
|
+
event schema, `AmberWebhook.authorization`, host registration of the
|
|
8
|
+
activities, and how to test workflows that use them. Use when a workflow
|
|
9
|
+
must open or drive Amber tickets, when wiring an Amber webhook channel to a
|
|
10
|
+
host, or when working in packages/amber.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# @t4h.framework/amber
|
|
14
|
+
|
|
15
|
+
Drive an Amber **webhook channel** from a workflow: create tickets, act on
|
|
16
|
+
them, and suspend until something happens on the Amber side (an agent
|
|
17
|
+
tabulates the ticket) without polling. Package path:
|
|
18
|
+
`alexandria/packages/amber`. Peer dependencies: `@t4h.framework/core`, `@t4h.framework/http`, `@t4h.framework/fs`,
|
|
19
|
+
`@t4h.framework/cache`, `typebox`.
|
|
20
|
+
|
|
21
|
+
## Import surface
|
|
22
|
+
|
|
23
|
+
Import from the package root only. Everything else under `src/` (form
|
|
24
|
+
builders, message converters, webhook header constants, schema factories) is
|
|
25
|
+
internal and not exported.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import {
|
|
29
|
+
Amber,
|
|
30
|
+
Service,
|
|
31
|
+
Ticket,
|
|
32
|
+
AmberWebhook,
|
|
33
|
+
AMBER_WEBHOOK_EVENT_TYPES,
|
|
34
|
+
AmberServiceTabulateEventSchema,
|
|
35
|
+
type AmberConfig,
|
|
36
|
+
type ServiceRequestConfig,
|
|
37
|
+
} from '@t4h.framework/amber'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`Service` is the generic base (`transfer`, `tabulate`, `update`, `finish`);
|
|
41
|
+
`Ticket` adds the ticket-only methods. Workflow code uses **`Amber` /
|
|
42
|
+
`Ticket`**. The activity classes (`Amber*Activity`) are exported so hosts can
|
|
43
|
+
register them; workflow code never instantiates them.
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const amber = new Amber({
|
|
49
|
+
url: env.AMBER_URL, // Amber API root, e.g. https://amber.example.com
|
|
50
|
+
tenant: env.AMBER_TENANT,
|
|
51
|
+
channel: env.AMBER_CHANNEL, // the webhook channel id
|
|
52
|
+
clientId: env.AMBER_CLIENT_ID,
|
|
53
|
+
clientSecret: env.AMBER_CLIENT_SECRET,
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Every request goes to `{url}/v1/tenants/{tenant}/channels/{channel}` with the
|
|
58
|
+
channel credentials as basic auth. Secrets come from `env`, never literals.
|
|
59
|
+
Every method takes an optional last argument `{ retry }` (`ServiceRequestConfig`)
|
|
60
|
+
forwarded to the HTTP activity.
|
|
61
|
+
|
|
62
|
+
## Tickets
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
const ticket = await amber.createTicket({
|
|
66
|
+
protocol: 'P-123',
|
|
67
|
+
skill: 'skill-id',
|
|
68
|
+
tabulationOption: 'option-id',
|
|
69
|
+
customers: [{ isOwner: true, type: 'customer' }],
|
|
70
|
+
fields: { customer: [{ name: 'email', value: 'a@b.c' }] },
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
await ticket.comment({ type: 'public', content: 'Looking into it' })
|
|
74
|
+
await ticket.interact({ content: 'Hello', contentType: 'text/plain' })
|
|
75
|
+
await ticket.updateField({ field: 'field-id', value: 'new value' })
|
|
76
|
+
const fields = await ticket.fields()
|
|
77
|
+
await ticket.lock({ expiresAt: new Date(Date.now() + 3600_000) })
|
|
78
|
+
await ticket.releaseLock()
|
|
79
|
+
await ticket.tabulate({ tabulationOption: 'option-id', notes: [{ type: 'public', content: 'ok' }] })
|
|
80
|
+
await ticket.finish() // update({ status: 'finished' })
|
|
81
|
+
|
|
82
|
+
const again = await amber.getTicket(ticket.id) // rejects if the service is not a ticket
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### The workflow lock
|
|
86
|
+
|
|
87
|
+
A ticket is **born locked** with `ref` = the workflow unique identifier
|
|
88
|
+
(`GetWorkflowUniqueIdentifierClaim`), so no agent picks it up while the workflow
|
|
89
|
+
still works on it. `lock`, `releaseLock` and the `lockRelease` of a transfer all
|
|
90
|
+
use the same ref, which is why they need no state passed between them.
|
|
91
|
+
|
|
92
|
+
- `createTicket({ lock: false })` creates it unlocked.
|
|
93
|
+
- `createTicket({ lock: { expiresAt, metadata } })` customises the lock.
|
|
94
|
+
- The ref is never user-supplied; do not try to release a lock owned by
|
|
95
|
+
another workflow.
|
|
96
|
+
|
|
97
|
+
### Handing the ticket to a human and waiting
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const transfer = await ticket.transfer({
|
|
101
|
+
skill: 'human-skill-id',
|
|
102
|
+
status: 'in-queue',
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const { tabulation } = await transfer.wait()
|
|
106
|
+
tabulation?.tabulationOption.id
|
|
107
|
+
tabulation?.notes
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- `transfer` (like every async activity bound through `History.bind`) returns
|
|
111
|
+
an `AsyncActivityAwaitable`; the output comes from `await transfer.wait()`.
|
|
112
|
+
Do other work between the two awaits if you need to.
|
|
113
|
+
- `status: 'in-queue'` releases the workflow lock and `wait()` **suspends** the
|
|
114
|
+
workflow until an agent tabulates the ticket (`service:tabulate` event).
|
|
115
|
+
Informative tabulations are ignored; the wait continues.
|
|
116
|
+
- A transfer to a `user` or without `status: 'in-queue'` settles at once and
|
|
117
|
+
`wait()` resolves with `{ service, serviceTransfer }` and no `tabulation`.
|
|
118
|
+
Add `lockRelease: true` to release the lock on those too.
|
|
119
|
+
- There is no timeout on the transfer wait. Wrap it in your own deadline logic
|
|
120
|
+
if the workflow must not hang forever.
|
|
121
|
+
- An HTTP status other than 200 on the transfer request rejects the activity.
|
|
122
|
+
|
|
123
|
+
## Activities (host registration)
|
|
124
|
+
|
|
125
|
+
Every model method is an activity recorded in the history and replayable.
|
|
126
|
+
Hosts register them by class:
|
|
127
|
+
|
|
128
|
+
| Activity | Kind | Claims used |
|
|
129
|
+
|---|---|---|
|
|
130
|
+
| `AmberCreateTicketActivity` | HTTP | `HttpClientRequestClaim`, `FileSystemClaim`, `GetWorkflowUniqueIdentifierClaim` |
|
|
131
|
+
| `AmberLockTicketActivity`, `AmberReleaseTicketLockActivity` | HTTP | same as above |
|
|
132
|
+
| `AmberGetTicketActivity`, `AmberCommentTicketActivity`, `AmberInteractTicketActivity`, `AmberFindTicketFieldsActivity`, `AmberUpdateTicketFieldValueActivity` | HTTP | `HttpClientRequestClaim`, `FileSystemClaim` |
|
|
133
|
+
| `AmberTabulateServiceActivity`, `AmberUpdateServiceActivity` | HTTP | `HttpClientRequestClaim`, `FileSystemClaim` |
|
|
134
|
+
| `AmberTransferServiceActivity` | **Async** | `HttpClientRequestClaim`, `GetWorkflowUniqueIdentifierClaim` |
|
|
135
|
+
|
|
136
|
+
HTTP activities extend `AbstractAmberHttpRequestActivity`, which extends the
|
|
137
|
+
`http` package's `AbstractHttpRequestActivity` (hence `FileSystemClaim`, where
|
|
138
|
+
the response body is persisted). Extend it only when adding a new Amber
|
|
139
|
+
endpoint to this package.
|
|
140
|
+
|
|
141
|
+
## Webhook channel and host contract
|
|
142
|
+
|
|
143
|
+
Amber emits events (`service:tabulate`) to the URL configured on the webhook
|
|
144
|
+
channel. Point it at the **events route** of the workflow on the host that
|
|
145
|
+
runs it:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
POST {runtime}/tenants/{tenant}/projects/{project}/workflows/{workflow}/events
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Nothing is stored on the Amber side to find the run back (no metadata, no ids
|
|
152
|
+
in the ticket). The host must:
|
|
153
|
+
|
|
154
|
+
1. Ask each pending async activity for `toCorrelationKey(event)`.
|
|
155
|
+
`AmberTransferServiceActivity` answers with the Amber **service id** taken
|
|
156
|
+
from `event.body.data.service.id`, or `undefined` when the event is not
|
|
157
|
+
theirs (it also ignores `isInformative: true`).
|
|
158
|
+
2. Verify the signature with the `auth` the pending declares:
|
|
159
|
+
`AmberWebhook.authorization(channelUrl)` returns an
|
|
160
|
+
`AsyncActivityCallbackAuthJwks` (detached signature over `{timestamp}.{body}`,
|
|
161
|
+
key resolved by `kid` at `{url}/tenants/{tenant}/.well-known/jwks.json`,
|
|
162
|
+
300 s tolerance). The host needs the `jwks` authorizer from
|
|
163
|
+
`@t4h.framework/jwks/callback` and the **raw body**.
|
|
164
|
+
3. Validate the body against the pending `schema`
|
|
165
|
+
(`AmberServiceTabulateEventSchema`) and advance.
|
|
166
|
+
|
|
167
|
+
`AmberWebhook.isEvent(body, type)` and `AmberWebhook.serviceId(event, type)`
|
|
168
|
+
are the helpers the activities use and are safe for host-side routing.
|
|
169
|
+
`AMBER_WEBHOOK_EVENT_TYPES` holds the event type strings; Amber may prefix
|
|
170
|
+
them (`amber.service:tabulate`), the matchers accept both.
|
|
171
|
+
|
|
172
|
+
**One webhook channel serves one workflow.** A project with several Amber
|
|
173
|
+
workflows needs one channel per workflow, because correlation is by service id
|
|
174
|
+
only.
|
|
175
|
+
|
|
176
|
+
## Testing
|
|
177
|
+
|
|
178
|
+
Test the **workflow**, not the activities, with `TestWorkflowEnvironment`
|
|
179
|
+
from `@t4h.framework/core/testing` (see the **framework-workflow-testing**
|
|
180
|
+
skill). Provide:
|
|
181
|
+
|
|
182
|
+
- `HttpClientRequestClaim` and `FileSystemClaim` mocks for the HTTP activities
|
|
183
|
+
(same shape as in the **framework-http** skill). Create/get responses must be
|
|
184
|
+
`200` with a JSON body carrying `id` and, for `get`, `type: 'ticket'`.
|
|
185
|
+
- `GetWorkflowUniqueIdentifierClaim` returning a fixed string; it becomes the
|
|
186
|
+
lock `ref` you can assert on.
|
|
187
|
+
- `mockAsync()` outcomes for the async activity:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { mockAsync, fulfilled, rejected } from '@t4h.framework/core/testing'
|
|
191
|
+
import { AmberTransferServiceActivity } from '@t4h.framework/amber'
|
|
192
|
+
|
|
193
|
+
mockAsyncActivity: mockAsync().on(
|
|
194
|
+
AmberTransferServiceActivity,
|
|
195
|
+
fulfilled({
|
|
196
|
+
service: 'svc-1',
|
|
197
|
+
serviceTransfer: 'transfer-1',
|
|
198
|
+
tabulation: {
|
|
199
|
+
id: 'tabulation-1',
|
|
200
|
+
name: 'Outcome',
|
|
201
|
+
tabulationOption: { id: 'opt-1', name: 'Resolved' },
|
|
202
|
+
notes: [],
|
|
203
|
+
},
|
|
204
|
+
}),
|
|
205
|
+
)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Use `rejected({ reason: 'timeout', service: 'svc-1', serviceTransfer: 'transfer-1' })`
|
|
209
|
+
to exercise the transfer timeout path.
|
|
210
|
+
|
|
211
|
+
## Pitfalls
|
|
212
|
+
|
|
213
|
+
- Do not import from `@t4h.framework/amber/dist/...` or `src/...`; only the root
|
|
214
|
+
export is stable.
|
|
215
|
+
- Do not create the ticket unlocked and lock it later "to be safe"; the default
|
|
216
|
+
lock already covers the window between creation and the first transfer.
|
|
217
|
+
- `ticket.transfer` returns an awaitable, not the output. Forgetting `.wait()`
|
|
218
|
+
gives you an object with no `tabulation` and no type error at the call site.
|
|
219
|
+
- `ticket.transfer` without `status: 'in-queue'` does **not** wait. If the
|
|
220
|
+
workflow expects a tabulation, it must send `in-queue`.
|
|
221
|
+
- `transfer` without `timeoutInMs` suspends indefinitely if nobody tabulates.
|
|
222
|
+
- `amber.getTicket` on a service that is not a ticket rejects; the model
|
|
223
|
+
returned by `createTicket` is already the right type.
|
|
224
|
+
- `Amber` and `Ticket` hold credentials in memory only; they are rebuilt from
|
|
225
|
+
the activity output on replay, never persisted by you.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tech for humans
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @t4h.framework/amber
|
|
2
2
|
|
|
3
|
-
Amber module for the [T4H Framework](https://github.com/tech4humans-brasil/alexandria). It
|
|
3
|
+
Amber module for the [T4H Framework](https://github.com/tech4humans-brasil/alexandria). It drives an Amber **webhook channel** from a workflow: create tickets, act on them, and wait for what happens on the Amber side (an agent tabulating a ticket) without polling.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,107 +8,117 @@ Amber module for the [T4H Framework](https://github.com/tech4humans-brasil/alexa
|
|
|
8
8
|
yarn add @t4h.framework/amber
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
**Peer dependencies:** `@t4h.framework/core`, `@t4h.framework/http`, `@t4h.framework/
|
|
11
|
+
**Peer dependencies:** `@t4h.framework/core`, `@t4h.framework/http`, `@t4h.framework/fs`, `@t4h.framework/cache` and `typebox`.
|
|
12
12
|
|
|
13
13
|
## Configuration
|
|
14
14
|
|
|
15
|
-
Create a `Amber` instance with the Amber base URL and LapisLazuli OAuth2 credentials:
|
|
16
|
-
|
|
17
15
|
```ts
|
|
18
16
|
import { Amber } from '@t4h.framework/amber'
|
|
19
17
|
|
|
20
18
|
const amber = new Amber({
|
|
21
|
-
url: 'https://
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
tenantId: 'your-tenant-id',
|
|
27
|
-
},
|
|
19
|
+
url: 'https://amber.example.com', // Amber API root
|
|
20
|
+
tenant: 'your-tenant-id',
|
|
21
|
+
channel: 'your-webhook-channel-id',
|
|
22
|
+
clientId: 'channel-client-id',
|
|
23
|
+
clientSecret: 'channel-client-secret',
|
|
28
24
|
})
|
|
29
25
|
```
|
|
30
26
|
|
|
31
|
-
|
|
27
|
+
Every call goes to `{url}/v1/tenants/{tenant}/channels/{channel}` with the channel credentials as basic auth.
|
|
28
|
+
|
|
29
|
+
### Point the channel webhook at the workflow
|
|
30
|
+
|
|
31
|
+
Amber emits its events (`service:tabulate`, …) to the URL configured on the webhook channel. Set it to the **events route** of the workflow that uses this package, on the host that runs it:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
POST {runtime}/tenants/{tenant}/projects/{project}/workflows/{workflow}/events
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The host asks the waiting activities which event is theirs (`toCorrelationKey`, keyed by the Amber service id), verifies the signature Amber puts on every event (detached signature over `timestamp.body`, key resolved by `kid` at `{url}/tenants/{tenant}/.well-known/jwks.json`) and advances the right wait. Nothing is stored on the Amber side to find the run back: no metadata, no ids in the ticket.
|
|
38
|
+
|
|
39
|
+
One webhook channel serves one workflow. A project with several Amber workflows needs one channel per workflow.
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
## Tickets
|
|
34
42
|
|
|
35
43
|
```ts
|
|
36
44
|
const ticket = await amber.createTicket({
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
protocol: 'P-123',
|
|
46
|
+
skill: 'skill-id',
|
|
47
|
+
tabulationOption: 'option-id',
|
|
48
|
+
customers: [{ isOwner: true, type: 'customer' }],
|
|
49
|
+
fields: { customer: [{ name: 'email', value: 'a@b.c' }] },
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
A ticket is **born locked** by the workflow (`lock: { ref: <workflow id> }`), so no agent picks it up while the workflow still works on it. Pass `lock: false` to create it unlocked, or `lock: { expiresAt, metadata }` to customize the lock.
|
|
54
|
+
|
|
55
|
+
The lock `ref` is the **workflow id** the host reports through `GetWorkflowUniqueIdentifierClaim` (`amber-ticket` for a workflow declared with `id: 'amber-ticket'`), not the id of the run. `lock()`, `releaseLock()` and the lock release of `transfer()` use the same `ref`, so every run of a workflow can release a lock another run of it took.
|
|
56
|
+
|
|
57
|
+
A locked ticket still takes comments, interactions and field updates from the workflow, but Amber answers `423` to a `lock()` while a lock exists (release first, lock again) and to a `tabulate()` while the ticket is locked, even by the workflow itself. Release the lock before tabulating or finishing the ticket. Transfers release it for you with `status: 'in-queue'` or `lockRelease: true`.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
await ticket.comment({ type: 'public', content: 'Looking into it' })
|
|
61
|
+
await ticket.interact({ content: 'Hello', contentType: 'text/plain' })
|
|
62
|
+
await ticket.updateField({ field: 'field-id', value: 'new value' })
|
|
63
|
+
const fields = await ticket.fields()
|
|
64
|
+
|
|
65
|
+
await ticket.lock({ expiresAt: new Date(Date.now() + 3600_000) })
|
|
66
|
+
await ticket.releaseLock()
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Handing the ticket to a human and waiting
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
const transfer = await ticket.transfer({
|
|
73
|
+
skill: 'human-skill-id',
|
|
74
|
+
status: 'in-queue',
|
|
50
75
|
})
|
|
76
|
+
|
|
77
|
+
const { tabulation } = await transfer.wait()
|
|
51
78
|
```
|
|
52
79
|
|
|
53
|
-
`
|
|
80
|
+
`transfer` returns an awaitable. Transferring to `in-queue` **releases the workflow lock**, and `wait()` suspends the workflow until an agent tabulates the ticket, resolving with the tabulation the agent chose (`tabulation.tabulationOption`, `tabulation.notes`). Informative tabulations are ignored. A transfer to a user or without `status: 'in-queue'` settles at once and `wait()` resolves without `tabulation`; add `lockRelease: true` to release the lock on those too.
|
|
54
81
|
|
|
55
|
-
|
|
82
|
+
The wait has no deadline by default. Pass `timeoutInMs` in the second argument, next to `retry`, to bound it; `wait()` then rejects with `{ reason: 'timeout', service, serviceTransfer }` when the agent has not tabulated in time:
|
|
56
83
|
|
|
57
84
|
```ts
|
|
58
|
-
const
|
|
85
|
+
const transfer = await ticket.transfer(
|
|
86
|
+
{ skill: 'human-skill-id', status: 'in-queue' },
|
|
87
|
+
{ timeoutInMs: 24 * 60 * 60 * 1000, retry: true },
|
|
88
|
+
)
|
|
59
89
|
```
|
|
60
90
|
|
|
61
|
-
|
|
91
|
+
When the transfer released the lock (`status: 'in-queue'` or `lockRelease: true`), `wait()` on a **ticket** **locks it back** for the workflow before resolving, with no expiration, so no agent picks it up again while the workflow finishes it. Pass `lock: false` in the second argument to skip that, or `lock: { expiresAt, metadata }` to customize the lock. The lock is a separate `AmberLockTicketActivity` recorded after the transfer, and a refusal by Amber rejects `wait()` with its `AmberRequestError`.
|
|
62
92
|
|
|
63
|
-
|
|
93
|
+
```ts
|
|
94
|
+
const transfer = await ticket.transfer(
|
|
95
|
+
{ skill: 'human-skill-id', status: 'in-queue' },
|
|
96
|
+
{ lock: { expiresAt: new Date(Date.now() + 3600_000) } },
|
|
97
|
+
)
|
|
64
98
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
- **Tabulate** — update tabulation data
|
|
68
|
-
- **Transfer** — transfer the ticket
|
|
69
|
-
- **Update** — update ticket fields
|
|
70
|
-
- **Finish** — set the ticket status to finished
|
|
99
|
+
const { tabulation } = await transfer.wait() // ticket locked again here
|
|
100
|
+
```
|
|
71
101
|
|
|
72
102
|
```ts
|
|
73
|
-
await ticket.comment({ input: { body: 'Comment text' } })
|
|
74
|
-
await ticket.interact({
|
|
75
|
-
input: {
|
|
76
|
-
/* interaction data */
|
|
77
|
-
},
|
|
78
|
-
})
|
|
79
103
|
await ticket.tabulate({
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
},
|
|
83
|
-
})
|
|
84
|
-
await ticket.transfer({
|
|
85
|
-
input: {
|
|
86
|
-
/* transfer data */
|
|
87
|
-
},
|
|
104
|
+
tabulationOption: 'option-id',
|
|
105
|
+
notes: [{ type: 'public', content: 'ok' }],
|
|
88
106
|
})
|
|
89
|
-
await ticket.update({ input: { status: 'in-attendance' } })
|
|
90
107
|
await ticket.finish()
|
|
91
108
|
```
|
|
92
109
|
|
|
93
|
-
##
|
|
94
|
-
|
|
95
|
-
The package also exports individual activities for use within T4H workflows:
|
|
110
|
+
## Errors
|
|
96
111
|
|
|
97
|
-
|
|
98
|
-
- `AmberGetTicketActivity`
|
|
99
|
-
- `AmberCommentTicketActivity`
|
|
100
|
-
- `AmberInteractTicketActivity`
|
|
101
|
-
- `AmberTabulateTicketActivity`
|
|
102
|
-
- `AmberTransferTicketActivity`
|
|
103
|
-
- `AmberUpdateTicketActivity`
|
|
112
|
+
Every call that Amber answers with a status other than `200` rejects with an `AmberRequestError`. Its `message` carries the status and the response body, which is where Amber says what it refused, so the reason shows up in any log that prints only the message:
|
|
104
113
|
|
|
105
|
-
|
|
114
|
+
```
|
|
115
|
+
Failed to create ticket: Amber responded 400 {"errors":{"$.tabulationOption":["Not found tabulation option"]}}
|
|
116
|
+
```
|
|
106
117
|
|
|
107
|
-
|
|
118
|
+
The same data is available as `error.status`, `error.body` and `error.cause` (`{ httpStatusCode, body }`). Bodies longer than 2000 characters are truncated. The activity that waits on Amber events, `transfer()`, rejects its awaitable with that message as the payload instead.
|
|
108
119
|
|
|
109
|
-
|
|
110
|
-
- T4H Framework peer packages
|
|
120
|
+
## Activities
|
|
111
121
|
|
|
112
|
-
|
|
122
|
+
Every method above is an activity, recorded in the workflow history and replayable. Hosts register them by class: `AmberCreateTicketActivity`, `AmberGetTicketActivity`, `AmberCommentTicketActivity`, `AmberInteractTicketActivity`, `AmberTabulateServiceActivity`, `AmberTransferServiceActivity`, `AmberUpdateServiceActivity`, `AmberLockTicketActivity`, `AmberReleaseTicketLockActivity`, `AmberFindTicketFieldsActivity`, `AmberUpdateTicketFieldValueActivity`.
|
|
113
123
|
|
|
114
|
-
|
|
124
|
+
`AmberTransferServiceActivity` is the one that waits on Amber events; the schema it validates the events against (`AmberServiceTabulateEventSchema`) and the `auth` it declares (`AmberWebhook.authorization(channelUrl)`) are exported by the package.
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { AbstractHttpRequestActivity, type HttpRequestActivityInput, type HttpRequestActivityOutput } from '@t4h.framework/http';
|
|
1
|
+
import { AbstractHttpRequestActivity, type HttpRequestActivityInput, type HttpRequestActivityOutput, type HttpRequestBasicAuth } from '@t4h.framework/http';
|
|
2
2
|
export type AmberHttpRequestActivityInput = HttpRequestActivityInput & {
|
|
3
|
-
auth:
|
|
4
|
-
username: string;
|
|
5
|
-
password: string;
|
|
6
|
-
};
|
|
3
|
+
auth: HttpRequestBasicAuth;
|
|
7
4
|
};
|
|
8
5
|
export declare abstract class AbstractAmberHttpRequestActivity<TArgs extends readonly any[], TInput extends AmberHttpRequestActivityInput, TOutput = any> extends AbstractHttpRequestActivity<TArgs, TInput, HttpRequestActivityOutput, TOutput> {
|
|
9
6
|
protected toHttpInput(input: AmberHttpRequestActivityInput): HttpRequestActivityInput;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AbstractAmberHttpRequestActivity.d.ts","sourceRoot":"","sources":["../../src/activities/AbstractAmberHttpRequestActivity.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,
|
|
1
|
+
{"version":3,"file":"AbstractAmberHttpRequestActivity.d.ts","sourceRoot":"","sources":["../../src/activities/AbstractAmberHttpRequestActivity.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAA;AAE5B,MAAM,MAAM,6BAA6B,GAAG,wBAAwB,GAAG;IACrE,IAAI,EAAE,oBAAoB,CAAA;CAC3B,CAAA;AAED,8BAAsB,gCAAgC,CACpD,KAAK,SAAS,SAAS,GAAG,EAAE,EAC5B,MAAM,SAAS,6BAA6B,EAC5C,OAAO,GAAG,GAAG,CACb,SAAQ,2BAA2B,CACnC,KAAK,EACL,MAAM,EACN,yBAAyB,EACzB,OAAO,CACR;IACC,SAAS,CAAC,WAAW,CACnB,KAAK,EAAE,6BAA6B,GACnC,wBAAwB;IAgB3B,SAAS,CAAC,YAAY,CACpB,MAAM,EAAE,yBAAyB,GAChC,yBAAyB;CAG7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AbstractAmberHttpRequestActivity.js","sourceRoot":"","sources":["../../src/activities/AbstractAmberHttpRequestActivity.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,
|
|
1
|
+
{"version":3,"file":"AbstractAmberHttpRequestActivity.js","sourceRoot":"","sources":["../../src/activities/AbstractAmberHttpRequestActivity.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,GAI5B,MAAM,qBAAqB,CAAA;AAM5B,MAAM,OAAgB,gCAIpB,SAAQ,2BAKT;IACW,WAAW,CACnB,KAAoC;QAEpC,MAAM,SAAS,GAA6B;YAC1C,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;YAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAA;QAED,IAAI,KAAK,CAAC,MAAM;YAAE,SAAS,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAA;QAEjD,IAAI,KAAK,CAAC,IAAI;YAAE,SAAS,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAA;QAE3C,IAAI,KAAK,CAAC,KAAK;YAAE,SAAS,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;QAE9C,OAAO,SAAS,CAAA;IAClB,CAAC;IAES,YAAY,CACpB,MAAiC;QAEjC,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AbstractAmberHttpRequestActivity, type AmberHttpRequestActivityInput } from './AbstractAmberHttpRequestActivity.js';
|
|
2
|
+
import type { ServiceTabulationInput } from '../typings/ServiceTabulate.js';
|
|
3
|
+
export type AmberTabulateServiceActivityInput = ServiceTabulationInput & {
|
|
4
|
+
id: string;
|
|
5
|
+
};
|
|
6
|
+
export declare class AmberTabulateServiceActivity extends AbstractAmberHttpRequestActivity<readonly [AmberTabulateServiceActivityInput, AmberHttpRequestActivityInput], AmberHttpRequestActivityInput> {
|
|
7
|
+
toInput(input: AmberTabulateServiceActivityInput, settings: AmberHttpRequestActivityInput): AmberHttpRequestActivityInput;
|
|
8
|
+
toOutput(output: any, input: AmberTabulateServiceActivityInput): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=AmberTabulateServiceActivity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AmberTabulateServiceActivity.d.ts","sourceRoot":"","sources":["../../src/activities/AmberTabulateServiceActivity.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gCAAgC,EAChC,KAAK,6BAA6B,EACnC,MAAM,uCAAuC,CAAA;AAE9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AAE3E,MAAM,MAAM,iCAAiC,GAAG,sBAAsB,GAAG;IACvE,EAAE,EAAE,MAAM,CAAA;CACX,CAAA;AAED,qBAAa,4BAA6B,SAAQ,gCAAgC,CAChF,SAAS,CAAC,iCAAiC,EAAE,6BAA6B,CAAC,EAC3E,6BAA6B,CAC9B;IACQ,OAAO,CACZ,KAAK,EAAE,iCAAiC,EACxC,QAAQ,EAAE,6BAA6B,GACtC,6BAA6B;IAWnB,QAAQ,CACnB,MAAM,EAAE,GAAG,EACX,KAAK,EAAE,iCAAiC,GACvC,OAAO,CAAC,IAAI,CAAC;CASjB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Response } from '@t4h.framework/http';
|
|
2
|
+
import { AbstractAmberHttpRequestActivity, } from './AbstractAmberHttpRequestActivity.js';
|
|
3
|
+
import { AmberRequestError } from '../errors/AmberRequestError.js';
|
|
4
|
+
export class AmberTabulateServiceActivity extends AbstractAmberHttpRequestActivity {
|
|
5
|
+
toInput(input, settings) {
|
|
6
|
+
const { id, ...tabulation } = input;
|
|
7
|
+
return {
|
|
8
|
+
...settings,
|
|
9
|
+
url: `${settings.url}/services/${id}/tabulations`,
|
|
10
|
+
method: 'POST',
|
|
11
|
+
body: { json: tabulation },
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async toOutput(output, input) {
|
|
15
|
+
const response = new Response(output);
|
|
16
|
+
if (response.status !== 200)
|
|
17
|
+
throw await AmberRequestError.from(`Failed to tabulate service ${input.id}`, response);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=AmberTabulateServiceActivity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AmberTabulateServiceActivity.js","sourceRoot":"","sources":["../../src/activities/AmberTabulateServiceActivity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAE9C,OAAO,EACL,gCAAgC,GAEjC,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAOlE,MAAM,OAAO,4BAA6B,SAAQ,gCAGjD;IACQ,OAAO,CACZ,KAAwC,EACxC,QAAuC;QAEvC,MAAM,EAAE,EAAE,EAAE,GAAG,UAAU,EAAE,GAAG,KAAK,CAAA;QAEnC,OAAO;YACL,GAAG,QAAQ;YACX,GAAG,EAAE,GAAG,QAAQ,CAAC,GAAG,aAAa,EAAE,cAAc;YACjD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;SAC3B,CAAA;IACH,CAAC;IAEM,KAAK,CAAC,QAAQ,CACnB,MAAW,EACX,KAAwC;QAExC,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAA;QAErC,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YACzB,MAAM,MAAM,iBAAiB,CAAC,IAAI,CAChC,8BAA8B,KAAK,CAAC,EAAE,EAAE,EACxC,QAAQ,CACT,CAAA;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { AsyncActivity, type AsyncActivityCallback, type AsyncActivityResultPending } from '@t4h.framework/core';
|
|
2
|
+
import type { Type } from 'typebox';
|
|
3
|
+
import type { AmberHttpRequestActivityInput } from './AbstractAmberHttpRequestActivity.js';
|
|
4
|
+
import { AmberServiceTabulateEventSchema } from '../inputs/AmberServiceTabulateEvent.js';
|
|
5
|
+
import type { ServiceTransferInput } from '../typings/ServiceTransfer.js';
|
|
6
|
+
export type AmberTransferServiceActivityInput = ServiceTransferInput & {
|
|
7
|
+
id: string;
|
|
8
|
+
/**
|
|
9
|
+
* How long an `in-queue` transfer waits for the agent's tabulation before
|
|
10
|
+
* rejecting with `{ reason: 'timeout' }`. Waits indefinitely when omitted.
|
|
11
|
+
*/
|
|
12
|
+
timeoutInMs?: number;
|
|
13
|
+
};
|
|
14
|
+
export type AmberTransferServiceActivityBootstrap = {
|
|
15
|
+
service: string;
|
|
16
|
+
serviceTransfer: string;
|
|
17
|
+
};
|
|
18
|
+
export type AmberTransferServiceActivityOutput = AmberTransferServiceActivityBootstrap & {
|
|
19
|
+
tabulation?: {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
tabulationOption: {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
};
|
|
26
|
+
notes: {
|
|
27
|
+
id: string;
|
|
28
|
+
type: 'public' | 'private';
|
|
29
|
+
content: string;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
}[];
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
type AmberTransferServiceActivityBootstrapInput = AmberTransferServiceActivityInput & {
|
|
35
|
+
settings: AmberHttpRequestActivityInput;
|
|
36
|
+
};
|
|
37
|
+
export declare class AmberTransferServiceActivity extends AsyncActivity<readonly [AmberTransferServiceActivityInput, AmberHttpRequestActivityInput], AmberTransferServiceActivityBootstrapInput, AmberTransferServiceActivityOutput, AmberTransferServiceActivityOutput, AmberTransferServiceActivityBootstrap, typeof AmberServiceTabulateEventSchema> {
|
|
38
|
+
private readonly claims;
|
|
39
|
+
toInput(input: AmberTransferServiceActivityInput, settings: AmberHttpRequestActivityInput): AmberTransferServiceActivityBootstrapInput;
|
|
40
|
+
bootstrap(input: AmberTransferServiceActivityBootstrapInput): Promise<AsyncActivityResultPending<AmberTransferServiceActivityBootstrap, Type.TObject<{
|
|
41
|
+
specversion: Type.TString;
|
|
42
|
+
id: Type.TString;
|
|
43
|
+
type: Type.TString;
|
|
44
|
+
source: Type.TString;
|
|
45
|
+
subject: Type.TString;
|
|
46
|
+
time: Type.TString;
|
|
47
|
+
data: Type.TObject<{
|
|
48
|
+
id: Type.TString;
|
|
49
|
+
isInformative: Type.TBoolean;
|
|
50
|
+
tabulationOption: Type.TObject<{
|
|
51
|
+
id: Type.TString;
|
|
52
|
+
name: Type.TString;
|
|
53
|
+
tabulation: Type.TObject<{
|
|
54
|
+
id: Type.TString;
|
|
55
|
+
name: Type.TString;
|
|
56
|
+
}>;
|
|
57
|
+
}>;
|
|
58
|
+
serviceTransfer: Type.TObject<{
|
|
59
|
+
id: Type.TString;
|
|
60
|
+
skill: Type.TObject<{
|
|
61
|
+
id: Type.TString;
|
|
62
|
+
name: Type.TString;
|
|
63
|
+
}>;
|
|
64
|
+
}>;
|
|
65
|
+
notes: Type.TArray<Type.TObject<{
|
|
66
|
+
id: Type.TString;
|
|
67
|
+
type: Type.TUnion<[Type.TLiteral<"public">, Type.TLiteral<"private">]>;
|
|
68
|
+
content: Type.TString;
|
|
69
|
+
createdAt: Type.TString;
|
|
70
|
+
}>>;
|
|
71
|
+
service: Type.TObject<{
|
|
72
|
+
id: Type.TString;
|
|
73
|
+
}>;
|
|
74
|
+
tenant: Type.TObject<{
|
|
75
|
+
id: Type.TString;
|
|
76
|
+
name: Type.TOptional<Type.TString>;
|
|
77
|
+
}>;
|
|
78
|
+
}>;
|
|
79
|
+
}>> | import("@t4h.framework/core").AsyncActivityResultRejected<void | import("@t4h.framework/core").Serializable> | import("@t4h.framework/core").AsyncActivityResultFulfilled<AmberTransferServiceActivityOutput | undefined>>;
|
|
80
|
+
toCorrelationKey(event: AsyncActivityCallback.Event): string | undefined;
|
|
81
|
+
advance(event: Type.Static<typeof AmberServiceTabulateEventSchema>): import("@t4h.framework/core").AsyncActivityResultFulfilled<AmberTransferServiceActivityOutput | undefined>;
|
|
82
|
+
onTimeout(bootstrap: AsyncActivityResultPending): import("@t4h.framework/core").AsyncActivityResultRejected<void | import("@t4h.framework/core").Serializable>;
|
|
83
|
+
toOutput(output: AmberTransferServiceActivityOutput): AmberTransferServiceActivityOutput;
|
|
84
|
+
}
|
|
85
|
+
export {};
|
|
86
|
+
//# sourceMappingURL=AmberTransferServiceActivity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AmberTransferServiceActivity.d.ts","sourceRoot":"","sources":["../../src/activities/AmberTransferServiceActivity.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAIb,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAChC,MAAM,qBAAqB,CAAA;AAE5B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAEnC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAA;AAG1F,OAAO,EAAE,+BAA+B,EAAE,MAAM,wCAAwC,CAAA;AAExF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AAEzE,MAAM,MAAM,iCAAiC,GAAG,oBAAoB,GAAG;IACrE,EAAE,EAAE,MAAM,CAAA;IACV;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,qCAAqC,GAAG;IAClD,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,kCAAkC,GAC5C,qCAAqC,GAAG;IACtC,UAAU,CAAC,EAAE;QACX,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,gBAAgB,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;QAC9C,KAAK,EAAE;YACL,EAAE,EAAE,MAAM,CAAA;YACV,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAA;YAC1B,OAAO,EAAE,MAAM,CAAA;YACf,SAAS,EAAE,MAAM,CAAA;SAClB,EAAE,CAAA;KACJ,CAAA;CACF,CAAA;AAEH,KAAK,0CAA0C,GAC7C,iCAAiC,GAAG;IAClC,QAAQ,EAAE,6BAA6B,CAAA;CACxC,CAAA;AAEH,qBAAa,4BAA6B,SAAQ,aAAa,CAC7D,SAAS,CAAC,iCAAiC,EAAE,6BAA6B,CAAC,EAC3E,0CAA0C,EAC1C,kCAAkC,EAClC,kCAAkC,EAClC,qCAAqC,EACrC,OAAO,+BAA+B,CACvC;IACC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGrB;IAEK,OAAO,CACZ,KAAK,EAAE,iCAAiC,EACxC,QAAQ,EAAE,6BAA6B,GACtC,0CAA0C;IAIhC,SAAS,CAAC,KAAK,EAAE,0CAA0C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAyDxD,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,CAAC,KAAK;IAe5D,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,+BAA+B,CAAC;IAuBzD,SAAS,CAAC,SAAS,EAAE,0BAA0B;IAYxD,QAAQ,CACb,MAAM,EAAE,kCAAkC,GACzC,kCAAkC;CAGtC"}
|