@worker-protocol/client 0.1.0 → 0.1.2
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/README.md +126 -0
- package/package.json +4 -4
package/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# @worker-protocol/client
|
|
2
|
+
|
|
3
|
+
Read a Worker, and take work from it. The consumer half of worker-protocol.
|
|
4
|
+
|
|
5
|
+
**worker-protocol is an open specification for Workers that can be seen, operated and given work by
|
|
6
|
+
people who did not build them.** HTTP and JSON Schema, no runtime. A *Worker* describes itself in a
|
|
7
|
+
Descriptor served at `/.well-known/worker-protocol` — the one address this protocol fixes — and
|
|
8
|
+
declares there which of its Capabilities it implements and at which addresses.
|
|
9
|
+
|
|
10
|
+
`consume(url)` reads that document once, resolves every address the Worker declared, and answers an
|
|
11
|
+
object with one member per Capability that Worker implements — and nothing for the ones it does not.
|
|
12
|
+
A console, a Control Tower, a teams app or a Worker that answers another Worker's Tasks is built on
|
|
13
|
+
this.
|
|
14
|
+
|
|
15
|
+
It depends on `@worker-protocol/schemas` and on `fetch`, and on nothing else. **A consumer is not a
|
|
16
|
+
server**, so nothing here asks you to install a web framework in order to make HTTP requests.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
npm i @worker-protocol/client zod
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`zod` is a peer dependency (`^4.5.4`), shared with `@worker-protocol/schemas`.
|
|
25
|
+
|
|
26
|
+
## Reading a Worker
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { consume } from "@worker-protocol/client";
|
|
30
|
+
|
|
31
|
+
const worker = await consume("https://fleet.example.com", { credential: process.env.TOKEN });
|
|
32
|
+
|
|
33
|
+
worker.descriptor; // the document itself, validated
|
|
34
|
+
worker.edition; // the edition this Worker declares it speaks
|
|
35
|
+
|
|
36
|
+
// Each of these is present only where the Worker declared the Capability.
|
|
37
|
+
const health = await worker.health?.();
|
|
38
|
+
const alerts = await worker.alerts?.();
|
|
39
|
+
const activity = await worker.activity?.();
|
|
40
|
+
|
|
41
|
+
const buckets = await worker.metrics?.read("vehicles.quiet", {
|
|
42
|
+
granularity: "day",
|
|
43
|
+
from: new Date("2026-09-01T00:00:00Z"),
|
|
44
|
+
by: ["region"],
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Paging, the cursor, the ordering, the retry that must not happen on a refusal the caller cannot fix,
|
|
49
|
+
and the classification of an answer that cannot be read are all carried here. Nine of the rules this
|
|
50
|
+
package implements oblige a *consumer* rather than a Worker, and a consumer that wrote this itself
|
|
51
|
+
would be deriving every one of them again.
|
|
52
|
+
|
|
53
|
+
## Taking work
|
|
54
|
+
|
|
55
|
+
A Task is work a Worker needs somebody to do. Nobody is assigned one and nobody closes one: it
|
|
56
|
+
exists while its condition holds and it is gone when that stops being true.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const open = await worker.tasks?.list();
|
|
60
|
+
|
|
61
|
+
for (const task of open ?? []) {
|
|
62
|
+
// How to answer this type: the Action to post, and the JSON Schema of what it takes. Both are
|
|
63
|
+
// read out of the Descriptor you already hold — the Task itself says nothing about how to answer
|
|
64
|
+
// it, because that belongs to the Worker that raised it.
|
|
65
|
+
const answer = worker.tasks?.answers(task.type);
|
|
66
|
+
if (answer === undefined) continue;
|
|
67
|
+
|
|
68
|
+
const input = doTheWork(task.payload);
|
|
69
|
+
await worker.actions?.perform(answer.action, input, { idempotencyKey: crypto.randomUUID() });
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The schema comes back as it travels, so a console can render a form from it and an agent can build
|
|
74
|
+
the document, neither having been told anything about this Worker in advance. Where a Task can end
|
|
75
|
+
several ways, that schema is a discriminated union and each ending is a variant.
|
|
76
|
+
|
|
77
|
+
`worker.nudges?.(type)` tells a Worker there is work of a type it answers. It buys latency and
|
|
78
|
+
nothing else — a consumer reading on its own schedule is slower and never wrong — so it answers
|
|
79
|
+
nothing and is safe to lose.
|
|
80
|
+
|
|
81
|
+
## When a call does not succeed
|
|
82
|
+
|
|
83
|
+
| Thrown | What happened |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `Refused` | The Worker answered a refusal, and it carries the code. A `reject` is not repeated; a `retry` already was, with backoff, before you saw this. |
|
|
86
|
+
| `Malformed` | The Worker answered something this protocol does not admit, naming the rule it broke. |
|
|
87
|
+
| `Unserved` | The Worker declared an address that serves nothing there. |
|
|
88
|
+
|
|
89
|
+
Retries and their backoff are `retries` and `backoffMs` on the options, and default to three
|
|
90
|
+
attempts from 200ms. A credential is presented as `Authorization: Bearer <token>` and is never sent
|
|
91
|
+
to an origin the Descriptor did not record as the Worker's own.
|
|
92
|
+
|
|
93
|
+
## Before any work changes hands
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { canAnswer } from "@worker-protocol/client";
|
|
97
|
+
|
|
98
|
+
const { verdict, why } = canAnswer(owner.descriptor, answerer.descriptor, taskType);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
A Worker declares its *Skills*: the Task types it can answer, what it needs to be handed to answer
|
|
102
|
+
one, and what it produces. `canAnswer` compares that against what the owner sends and what the
|
|
103
|
+
owner's answering Action takes, in both directions, and answers `compatible`, `incompatible` or
|
|
104
|
+
`unknown` with a reason. `unknown` is not `false`: an answerer that declares the Skill and states no
|
|
105
|
+
requirement has claimed the capability and said nothing about what it needs, which the protocol
|
|
106
|
+
allows, and reporting that as a refusal would be inventing an obligation.
|
|
107
|
+
|
|
108
|
+
## Strict about what this protocol fixes, blind to what it does not
|
|
109
|
+
|
|
110
|
+
Every document the protocol's schemas describe is validated, and a Worker that answers something
|
|
111
|
+
else raises `Malformed` naming the rule. A Task's payload, an Action's input and result, an event's
|
|
112
|
+
data are the Worker's own — this protocol has no data model — and nothing here looks inside them.
|
|
113
|
+
|
|
114
|
+
## Related packages
|
|
115
|
+
|
|
116
|
+
- `@worker-protocol/schemas` — the Zod objects that generate the normative JSON Schemas.
|
|
117
|
+
- `@worker-protocol/hono` — the other half: `mount()`, for building a Worker on Hono.
|
|
118
|
+
- `@worker-protocol/conformance` — point it at a Worker's base URL, get a report of what it complies
|
|
119
|
+
with.
|
|
120
|
+
|
|
121
|
+
## License and name
|
|
122
|
+
|
|
123
|
+
Apache-2.0, patent grant included — implement the protocol in any product, commercial or not,
|
|
124
|
+
without asking anyone. The name is not part of that grant (Apache-2.0 §6): a claim that something
|
|
125
|
+
*speaks worker-protocol* is one this project vouches for, and the conformance tool is how it is
|
|
126
|
+
earned.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@worker-protocol/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"workerProtocolEdition": "0.1",
|
|
5
5
|
"description": "Read a Worker, and take work from it. The consumer half of worker-protocol",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"url": "git+https://github.com/rowing-tech/worker-protocol.git",
|
|
10
10
|
"directory": "packages/client"
|
|
11
11
|
},
|
|
12
|
-
"homepage": "https://github.com/rowing-tech/worker-protocol#readme",
|
|
12
|
+
"homepage": "https://github.com/rowing-tech/worker-protocol/tree/main/packages/client#readme",
|
|
13
13
|
"bugs": "https://github.com/rowing-tech/worker-protocol/issues",
|
|
14
14
|
"publishConfig": {
|
|
15
15
|
"access": "public"
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
"NOTICE"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@worker-protocol/schemas": "0.1.
|
|
32
|
+
"@worker-protocol/schemas": "0.1.2"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"zod": "^4.5.4"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "26.5.1",
|
|
39
|
-
"@worker-protocol/hono": "0.1.
|
|
39
|
+
"@worker-protocol/hono": "0.1.2",
|
|
40
40
|
"hono": "4.13.7",
|
|
41
41
|
"typescript": "7.0.2",
|
|
42
42
|
"vitest": "5.0.0",
|