ankka 0.12.0 → 0.14.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/dist/_proto/ankka/protocol/v1/client_pb.d.ts +594 -0
- package/dist/_proto/ankka/protocol/v1/client_pb.js +172 -30
- package/dist/_proto/ankka/protocol/v1/consumer_pb.js +1 -1
- package/dist/_proto/ankka/protocol/v1/discovery_pb.d.ts +134 -0
- package/dist/_proto/ankka/protocol/v1/discovery_pb.js +51 -36
- package/dist/_proto/ankka/protocol/v1/event_sourced_pb.d.ts +24 -0
- package/dist/_proto/ankka/protocol/v1/event_sourced_pb.js +1 -1
- package/dist/_proto/ankka/protocol/v1/mcp_pb.d.ts +120 -0
- package/dist/_proto/ankka/protocol/v1/mcp_pb.js +29 -0
- package/dist/_proto/ankka/protocol/v1/timed_action_pb.js +1 -1
- package/dist/_proto/ankka/protocol/v1/view_pb.js +1 -1
- package/dist/_proto/ankka/protocol/v1/wasm_pb.d.ts +12 -0
- package/dist/_proto/ankka/protocol/v1/wasm_pb.js +1 -1
- package/dist/agent.d.ts +10 -0
- package/dist/agent.js +20 -0
- package/dist/autonomous.d.ts +5 -0
- package/dist/autonomous.js +10 -0
- package/dist/client-keys.d.ts +89 -0
- package/dist/client-keys.js +182 -0
- package/dist/consumer.d.ts +5 -0
- package/dist/consumer.js +10 -0
- package/dist/context.d.ts +11 -3
- package/dist/context.js +20 -4
- package/dist/endpoint.d.ts +10 -0
- package/dist/endpoint.js +20 -0
- package/dist/graph.d.ts +5 -0
- package/dist/graph.js +10 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +5 -0
- package/dist/mcp-endpoint.d.ts +144 -0
- package/dist/mcp-endpoint.js +256 -0
- package/dist/routes.d.ts +25 -2
- package/dist/routes.js +29 -2
- package/dist/server/discovery.d.ts +7 -0
- package/dist/server/discovery.js +26 -2
- package/dist/server/eventSourced.js +3 -3
- package/dist/server/http.d.ts +8 -0
- package/dist/server/http.js +10 -4
- package/dist/server/mcp.d.ts +17 -0
- package/dist/server/mcp.js +157 -0
- package/dist/server/server.d.ts +11 -1
- package/dist/server/server.js +19 -0
- package/dist/server/storageEndpoint.d.ts +14 -0
- package/dist/server/storageEndpoint.js +82 -0
- package/dist/service.d.ts +6 -1
- package/dist/service.js +47 -4
- package/dist/sigv4.d.ts +47 -0
- package/dist/sigv4.js +149 -0
- package/dist/spec.d.ts +8 -2
- package/dist/spec.js +53 -3
- package/dist/storage.d.ts +288 -0
- package/dist/storage.js +1081 -0
- package/dist/testkit/integration.d.ts +9 -0
- package/dist/testkit/integration.js +5 -1
- package/dist/testkit/kinds.d.ts +16 -4
- package/dist/testkit/kinds.js +36 -14
- package/dist/testkit/unit.d.ts +4 -1
- package/dist/testkit/unit.js +8 -4
- package/dist/timedAction.d.ts +10 -0
- package/dist/timedAction.js +20 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workflow.d.ts +8 -0
- package/dist/workflow.js +15 -0
- package/package.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ComponentClient } from "../client.ts";
|
|
2
2
|
import type { ServiceBuilder } from "../service.ts";
|
|
3
|
+
import { type Buckets } from "../storage.ts";
|
|
3
4
|
export interface AnkkaTestKitOptions {
|
|
4
5
|
/** The sidecar image; `sidecarImage()` by default. */
|
|
5
6
|
readonly image?: string;
|
|
@@ -9,6 +10,12 @@ export interface AnkkaTestKitOptions {
|
|
|
9
10
|
/** How long to wait for the sidecar to report healthy; 120s by default. */
|
|
10
11
|
readonly readyTimeoutMs?: number;
|
|
11
12
|
readonly log?: (message: string) => void;
|
|
13
|
+
/**
|
|
14
|
+
* The service's buckets. By default the store `ANKKA_STORAGE_BACKEND=memory` gives this process: in
|
|
15
|
+
* memory, with the buckets `service.json` in the working directory declares (the unnamed one, and no
|
|
16
|
+
* named one, when there is no such file). `kit.storage` is the same store.
|
|
17
|
+
*/
|
|
18
|
+
readonly storage?: Buckets;
|
|
12
19
|
}
|
|
13
20
|
/** What `http` answers with. */
|
|
14
21
|
export declare class HttpResponse {
|
|
@@ -47,6 +54,8 @@ export declare class AnkkaTestKit {
|
|
|
47
54
|
#private;
|
|
48
55
|
/** The component client every handler in `service` uses, pointed at the sidecar's mapped callback port. */
|
|
49
56
|
readonly client: ComponentClient;
|
|
57
|
+
/** The buckets the service holds: what a handler kept, a test reads here, and what a test puts here a handler reads. */
|
|
58
|
+
readonly storage: Buckets;
|
|
50
59
|
private constructor();
|
|
51
60
|
/** Starts Postgres, this process's server and the sidecar; a start that fails half-way stops what it started. */
|
|
52
61
|
static start(service: ServiceBuilder, options?: AnkkaTestKitOptions): Promise<AnkkaTestKit>;
|
|
@@ -16,6 +16,7 @@ import { randomBytes } from "node:crypto";
|
|
|
16
16
|
import { chmodSync, mkdtempSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
17
17
|
import { tmpdir } from "node:os";
|
|
18
18
|
import { join } from "node:path";
|
|
19
|
+
import { chooseStorage } from "../storage.js";
|
|
19
20
|
import { VERSION } from "../version.js";
|
|
20
21
|
const POSTGRES_IMAGE = "postgres:17-alpine";
|
|
21
22
|
const HTTP_PORT = 9000;
|
|
@@ -149,7 +150,10 @@ export class AnkkaTestKit {
|
|
|
149
150
|
#http;
|
|
150
151
|
/** The component client every handler in `service` uses, pointed at the sidecar's mapped callback port. */
|
|
151
152
|
client;
|
|
153
|
+
/** The buckets the service holds: what a handler kept, a test reads here, and what a test puts here a handler reads. */
|
|
154
|
+
storage;
|
|
152
155
|
constructor(service, options) {
|
|
156
|
+
this.storage = options.storage ?? chooseStorage({ ...process.env, ANKKA_STORAGE_BACKEND: "memory" }).buckets;
|
|
153
157
|
this.#service = service;
|
|
154
158
|
this.#image = options.image ?? sidecarImage();
|
|
155
159
|
this.#env = options.env ?? {};
|
|
@@ -203,7 +207,7 @@ export class AnkkaTestKit {
|
|
|
203
207
|
.withCopyDirectoriesToContainer([{ source: this.#ddlDir, target: "/docker-entrypoint-initdb.d", mode: 0o755 }])
|
|
204
208
|
.start();
|
|
205
209
|
// This process's server, on all interfaces: the sidecar is in a container and dials in.
|
|
206
|
-
this.#server = this.#service.server({ host: "0.0.0.0", port: 0, log: this.#log });
|
|
210
|
+
this.#server = this.#service.server({ host: "0.0.0.0", port: 0, log: this.#log, storage: this.storage });
|
|
207
211
|
this.#processPort = (await this.#server.start()).port;
|
|
208
212
|
await this.#startSidecar();
|
|
209
213
|
}
|
package/dist/testkit/kinds.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ComponentClient } from "../client.ts";
|
|
2
|
+
import { type Buckets } from "../storage.ts";
|
|
2
3
|
import { type ErrorDetail, type Metadata } from "../effects/common.ts";
|
|
3
4
|
import type { StepRef } from "../effects/workflow.ts";
|
|
4
5
|
import type { ConsumerEffect, TimedActionEffect, ViewEffect } from "../effects/stateless.ts";
|
|
@@ -42,8 +43,10 @@ export declare class WorkflowTestKit<S, C extends Workflow<S>> {
|
|
|
42
43
|
#private;
|
|
43
44
|
readonly entityId: string;
|
|
44
45
|
state: S;
|
|
46
|
+
/** The buckets the workflow's steps are given; the test reads what they kept here. */
|
|
47
|
+
readonly storage: Buckets;
|
|
45
48
|
private constructor();
|
|
46
|
-
static of<S, C extends Workflow<S>>(cls: WorkflowClass<S, C>, entityId?: string, client?: ComponentClient): WorkflowTestKit<S, C>;
|
|
49
|
+
static of<S, C extends Workflow<S>>(cls: WorkflowClass<S, C>, entityId?: string, client?: ComponentClient, storage?: Buckets): WorkflowTestKit<S, C>;
|
|
47
50
|
get progress(): WorkflowProgress;
|
|
48
51
|
call<I, R>(handler: HandlerRef<C, I, R, any> | string, input?: I, metadata?: Metadata): Promise<MaterialisedWorkflowCommand<S, R>>;
|
|
49
52
|
/** Runs one step, by name or declaration, with an input (or the pending transition's). */
|
|
@@ -102,8 +105,10 @@ export declare class ConsumerTestKit<M, Out, C extends Consumer<M, Out>> {
|
|
|
102
105
|
readonly metadata: Metadata;
|
|
103
106
|
readonly key?: string;
|
|
104
107
|
}[];
|
|
108
|
+
/** The buckets the consumer is given; the test reads what it kept here. */
|
|
109
|
+
readonly storage: Buckets;
|
|
105
110
|
private constructor();
|
|
106
|
-
static of<M, Out, C extends Consumer<M, Out>>(cls: ConsumerClass<M, Out, C>, client?: ComponentClient): ConsumerTestKit<M, Out, C>;
|
|
111
|
+
static of<M, Out, C extends Consumer<M, Out>>(cls: ConsumerClass<M, Out, C>, client?: ComponentClient, storage?: Buckets): ConsumerTestKit<M, Out, C>;
|
|
107
112
|
/**
|
|
108
113
|
* A message from source instance `subject`. The metadata says the runtime speaks this SDK's protocol
|
|
109
114
|
* version; pass `"ankka.protocol"` or `"ankka.sequence"` to say otherwise.
|
|
@@ -118,8 +123,10 @@ export declare class ConsumerTestKit<M, Out, C extends Consumer<M, Out>> {
|
|
|
118
123
|
*/
|
|
119
124
|
export declare class GraphConsumerTestKit<M> {
|
|
120
125
|
#private;
|
|
126
|
+
/** The buckets the graph consumer is given; the test reads what it kept here. */
|
|
127
|
+
readonly storage: Buckets;
|
|
121
128
|
private constructor();
|
|
122
|
-
static of<M>(cls: GraphConsumerClass<M>, client?: ComponentClient): GraphConsumerTestKit<M>;
|
|
129
|
+
static of<M>(cls: GraphConsumerClass<M>, client?: ComponentClient, storage?: Buckets): GraphConsumerTestKit<M>;
|
|
123
130
|
/** A change from source instance `subject` (default `"test"`) at `sequence` (default 1). */
|
|
124
131
|
onMessage(message: M, options?: GraphChange): Promise<Delta[]>;
|
|
125
132
|
/** The source instance was deleted, at `sequence`. */
|
|
@@ -135,8 +142,10 @@ export interface GraphChange {
|
|
|
135
142
|
/** Invokes a timed action's handlers as the sweeper would. */
|
|
136
143
|
export declare class TimedActionTestKit<C extends TimedAction> {
|
|
137
144
|
#private;
|
|
145
|
+
/** The buckets the timed action is given; the test reads what it kept here. */
|
|
146
|
+
readonly storage: Buckets;
|
|
138
147
|
private constructor();
|
|
139
|
-
static of<C extends TimedAction>(cls: TimedActionClass<C>, client?: ComponentClient): TimedActionTestKit<C>;
|
|
148
|
+
static of<C extends TimedAction>(cls: TimedActionClass<C>, client?: ComponentClient, storage?: Buckets): TimedActionTestKit<C>;
|
|
140
149
|
invoke<I>(action: HandlerRef<C, I, any, any> | string, input?: I, metadata?: Metadata): Promise<TimedActionEffect>;
|
|
141
150
|
}
|
|
142
151
|
/** What a scripted model answers next. */
|
|
@@ -189,9 +198,12 @@ export declare class AgentTestKit<C extends Agent> {
|
|
|
189
198
|
role: "user" | "assistant";
|
|
190
199
|
text: string;
|
|
191
200
|
}[];
|
|
201
|
+
/** The buckets the agent's tools are given; the test reads what they kept here. */
|
|
202
|
+
readonly storage: Buckets;
|
|
192
203
|
private constructor();
|
|
193
204
|
static of<C extends Agent>(cls: AgentClass<C>, sessionId: string, model: ScriptedModel, client?: ComponentClient, options?: {
|
|
194
205
|
readonly mcp?: ScriptedMcp;
|
|
206
|
+
readonly storage?: Buckets;
|
|
195
207
|
}): AgentTestKit<C>;
|
|
196
208
|
/** One turn: returns the reply text (JSON text for a `thenReplyJson` plan). A refusal or a blocked guardrail rejects with `CommandError`; a turn that waits, with `ApprovalAwaited`. */
|
|
197
209
|
ask<I>(handler: HandlerRef<C, I, any, any> | string, input?: I): Promise<string>;
|
package/dist/testkit/kinds.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// agents. Same rules as the event sourced kit: no sidecar, effects as values, every value round-tripped
|
|
3
3
|
// through the component's codecs, the server's reduction.
|
|
4
4
|
import { ComponentClient, noClient } from "../client.js";
|
|
5
|
+
import { InMemoryBuckets } from "../storage.js";
|
|
5
6
|
import { binaryCodecs, codecFor } from "../codec.js";
|
|
6
7
|
import { commandContext } from "../context.js";
|
|
7
8
|
import { CommandError, ErrorCode } from "../effects/common.js";
|
|
@@ -78,17 +79,20 @@ export class WorkflowTestKit {
|
|
|
78
79
|
entityId;
|
|
79
80
|
state;
|
|
80
81
|
#progress = { pending: null, paused: null, ended: false, failed: null };
|
|
81
|
-
|
|
82
|
+
/** The buckets the workflow's steps are given; the test reads what they kept here. */
|
|
83
|
+
storage;
|
|
84
|
+
constructor(cls, entityId, client, storage) {
|
|
82
85
|
this.#registered = registryFor(cls, client).component(cls.componentId);
|
|
83
86
|
this.#cls = cls;
|
|
84
87
|
this.#client = client;
|
|
88
|
+
this.storage = storage;
|
|
85
89
|
this.entityId = entityId;
|
|
86
90
|
const instance = new cls();
|
|
87
91
|
instance._bindInstance(entityId);
|
|
88
92
|
this.state = instance.emptyState();
|
|
89
93
|
}
|
|
90
|
-
static of(cls, entityId = "test", client = noClient()) {
|
|
91
|
-
return new WorkflowTestKit(cls, entityId, client);
|
|
94
|
+
static of(cls, entityId = "test", client = noClient(), storage = new InMemoryBuckets()) {
|
|
95
|
+
return new WorkflowTestKit(cls, entityId, client, storage);
|
|
92
96
|
}
|
|
93
97
|
get progress() {
|
|
94
98
|
return this.#progress;
|
|
@@ -96,6 +100,7 @@ export class WorkflowTestKit {
|
|
|
96
100
|
#instance() {
|
|
97
101
|
const w = new this.#cls();
|
|
98
102
|
w._bindInstance(this.entityId);
|
|
103
|
+
w.storage = this.storage;
|
|
99
104
|
return w;
|
|
100
105
|
}
|
|
101
106
|
async call(handler, input, metadata = {}) {
|
|
@@ -135,6 +140,7 @@ export class WorkflowTestKit {
|
|
|
135
140
|
const wireInput = ref.input ? roundTrip(codecFor(ref.input), input) : undefined;
|
|
136
141
|
const w = this.#instance();
|
|
137
142
|
w._bindCommand(this.state, commandContext(this.#registered.id, this.entityId, 0n, {}), this.#client);
|
|
143
|
+
w._enterStep();
|
|
138
144
|
let effect;
|
|
139
145
|
try {
|
|
140
146
|
effect = (await ref.run(w, wireInput));
|
|
@@ -323,17 +329,21 @@ export class ConsumerTestKit {
|
|
|
323
329
|
* `key` is the record key a message of `produceAll` named; absent, the message is keyed by its subject.
|
|
324
330
|
*/
|
|
325
331
|
produced = [];
|
|
326
|
-
|
|
332
|
+
/** The buckets the consumer is given; the test reads what it kept here. */
|
|
333
|
+
storage;
|
|
334
|
+
constructor(cls, client, storage) {
|
|
327
335
|
this.#registered = registryFor(cls, client).component(cls.componentId);
|
|
328
336
|
this.#cls = cls;
|
|
329
337
|
this.#client = client;
|
|
338
|
+
this.storage = storage;
|
|
330
339
|
}
|
|
331
|
-
static of(cls, client = noClient()) {
|
|
332
|
-
return new ConsumerTestKit(cls, client);
|
|
340
|
+
static of(cls, client = noClient(), storage = new InMemoryBuckets()) {
|
|
341
|
+
return new ConsumerTestKit(cls, client, storage);
|
|
333
342
|
}
|
|
334
343
|
async #apply(fn, metadata, standing) {
|
|
335
344
|
const consumer = new this.#cls();
|
|
336
345
|
consumer._bind(metadata, this.#client.withMetadata(metadata), standing);
|
|
346
|
+
consumer.storage = this.storage;
|
|
337
347
|
const effect = await fn(consumer);
|
|
338
348
|
const outCodec = () => {
|
|
339
349
|
const codec = this.#registered.outCodec;
|
|
@@ -374,13 +384,16 @@ export class GraphConsumerTestKit {
|
|
|
374
384
|
#registered;
|
|
375
385
|
#cls;
|
|
376
386
|
#client;
|
|
377
|
-
|
|
387
|
+
/** The buckets the graph consumer is given; the test reads what it kept here. */
|
|
388
|
+
storage;
|
|
389
|
+
constructor(cls, client, storage) {
|
|
378
390
|
this.#registered = registryFor(cls, client).component(cls.componentId);
|
|
379
391
|
this.#cls = cls;
|
|
380
392
|
this.#client = client;
|
|
393
|
+
this.storage = storage;
|
|
381
394
|
}
|
|
382
|
-
static of(cls, client = noClient()) {
|
|
383
|
-
return new GraphConsumerTestKit(cls, client);
|
|
395
|
+
static of(cls, client = noClient(), storage = new InMemoryBuckets()) {
|
|
396
|
+
return new GraphConsumerTestKit(cls, client, storage);
|
|
384
397
|
}
|
|
385
398
|
async #apply(fn, options) {
|
|
386
399
|
const metadata = {
|
|
@@ -391,6 +404,7 @@ export class GraphConsumerTestKit {
|
|
|
391
404
|
};
|
|
392
405
|
const consumer = new this.#cls();
|
|
393
406
|
consumer._bind(metadata, this.#client.withMetadata(metadata));
|
|
407
|
+
consumer.storage = this.storage;
|
|
394
408
|
const records = deltaRecords(await fn(consumer), metadata);
|
|
395
409
|
if (records.length > 0)
|
|
396
410
|
requireSeveralMessages(metadata);
|
|
@@ -411,19 +425,23 @@ export class TimedActionTestKit {
|
|
|
411
425
|
#registered;
|
|
412
426
|
#cls;
|
|
413
427
|
#client;
|
|
414
|
-
|
|
428
|
+
/** The buckets the timed action is given; the test reads what it kept here. */
|
|
429
|
+
storage;
|
|
430
|
+
constructor(cls, client, storage) {
|
|
415
431
|
this.#registered = registryFor(cls, client).component(cls.componentId);
|
|
416
432
|
this.#cls = cls;
|
|
417
433
|
this.#client = client;
|
|
434
|
+
this.storage = storage;
|
|
418
435
|
}
|
|
419
|
-
static of(cls, client = noClient()) {
|
|
420
|
-
return new TimedActionTestKit(cls, client);
|
|
436
|
+
static of(cls, client = noClient(), storage = new InMemoryBuckets()) {
|
|
437
|
+
return new TimedActionTestKit(cls, client, storage);
|
|
421
438
|
}
|
|
422
439
|
async invoke(action, input, metadata = {}) {
|
|
423
440
|
const ref = findHandler(this.#registered.actions, action, this.#registered.cls.name);
|
|
424
441
|
const wireInput = ref.input ? roundTrip(codecFor(ref.input), input) : undefined;
|
|
425
442
|
const instance = new this.#cls();
|
|
426
443
|
instance._bind({ "ankka.timer": "test", "ankka.attempts": "1", ...metadata }, this.#client.withMetadata(metadata));
|
|
444
|
+
instance.storage = this.storage;
|
|
427
445
|
return (await ref.run(instance, wireInput));
|
|
428
446
|
}
|
|
429
447
|
}
|
|
@@ -475,20 +493,24 @@ export class AgentTestKit {
|
|
|
475
493
|
#turn;
|
|
476
494
|
#decided = new Set();
|
|
477
495
|
#nextId = 0;
|
|
478
|
-
|
|
496
|
+
/** The buckets the agent's tools are given; the test reads what they kept here. */
|
|
497
|
+
storage;
|
|
498
|
+
constructor(cls, sessionId, model, client, mcp, storage) {
|
|
479
499
|
this.#registered = registryFor(cls, client).component(cls.componentId);
|
|
480
500
|
this.#cls = cls;
|
|
481
501
|
this.#client = client;
|
|
502
|
+
this.storage = storage;
|
|
482
503
|
this.#model = model;
|
|
483
504
|
this.#mcp = mcp;
|
|
484
505
|
this.sessionId = sessionId;
|
|
485
506
|
}
|
|
486
507
|
static of(cls, sessionId, model, client = noClient(), options = {}) {
|
|
487
|
-
return new AgentTestKit(cls, sessionId, model, client, options.mcp ?? {});
|
|
508
|
+
return new AgentTestKit(cls, sessionId, model, client, options.mcp ?? {}, options.storage ?? new InMemoryBuckets());
|
|
488
509
|
}
|
|
489
510
|
#agent() {
|
|
490
511
|
const a = new this.#cls();
|
|
491
512
|
a._bind(this.sessionId, {}, this.#client);
|
|
513
|
+
a.storage = this.storage;
|
|
492
514
|
return a;
|
|
493
515
|
}
|
|
494
516
|
/** One turn: returns the reply text (JSON text for a `thenReplyJson` plan). A refusal or a blocked guardrail rejects with `CommandError`; a turn that waits, with `ApprovalAwaited`. */
|
package/dist/testkit/unit.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ComponentClient } from "../client.ts";
|
|
2
|
+
import { type Buckets } from "../storage.ts";
|
|
2
3
|
import { type Principal } from "../context.ts";
|
|
3
4
|
import { type ErrorDetail, type Metadata, type Retention } from "../effects/common.ts";
|
|
4
5
|
import type { ReplicationChange } from "../effects/eventSourced.ts";
|
|
@@ -72,8 +73,10 @@ export interface SocketRun {
|
|
|
72
73
|
/** Calls an endpoint's routes by path, matching them as the sidecar's router does: literal segments outrank parameters. */
|
|
73
74
|
export declare class EndpointTestKit<C extends Endpoint> {
|
|
74
75
|
#private;
|
|
76
|
+
/** The buckets the endpoint is given; the test reads what its routes kept here. */
|
|
77
|
+
readonly storage: Buckets;
|
|
75
78
|
private constructor();
|
|
76
|
-
static of<C extends Endpoint>(cls: EndpointClass<C>, client?: ComponentClient): EndpointTestKit<C>;
|
|
79
|
+
static of<C extends Endpoint>(cls: EndpointClass<C>, client?: ComponentClient, storage?: Buckets): EndpointTestKit<C>;
|
|
77
80
|
request(method: string, path: string, body?: unknown, options?: RequestOptions): Promise<Response>;
|
|
78
81
|
/**
|
|
79
82
|
* Opens a socket route with no runtime: the handler is given `frames` one at a time and then told the
|
package/dist/testkit/unit.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { create } from "@bufbuild/protobuf";
|
|
7
7
|
import { HttpRequestSchema, SocketInSchema } from "../_proto/ankka/protocol/v1/endpoint_pb.js";
|
|
8
8
|
import { ComponentClient, noClient } from "../client.js";
|
|
9
|
+
import { InMemoryBuckets } from "../storage.js";
|
|
9
10
|
import { binaryCodecs, codecFor } from "../codec.js";
|
|
10
11
|
import { commandContext, eventContext } from "../context.js";
|
|
11
12
|
import { ErrorCode } from "../effects/common.js";
|
|
@@ -143,15 +144,18 @@ const PLACEHOLDER = /\{[A-Za-z_][A-Za-z0-9_]*\}/g;
|
|
|
143
144
|
export class EndpointTestKit {
|
|
144
145
|
#cls;
|
|
145
146
|
#dispatcher;
|
|
146
|
-
|
|
147
|
+
/** The buckets the endpoint is given; the test reads what its routes kept here. */
|
|
148
|
+
storage;
|
|
149
|
+
constructor(cls, client, storage) {
|
|
147
150
|
this.#cls = cls;
|
|
151
|
+
this.storage = storage;
|
|
148
152
|
const registry = Ankka.service({ client, log: () => { } })
|
|
149
153
|
.register(cls)
|
|
150
154
|
.validate();
|
|
151
|
-
this.#dispatcher = createHttpDispatcher({ registry, client, log: () => { } });
|
|
155
|
+
this.#dispatcher = createHttpDispatcher({ registry, client, log: () => { }, storage });
|
|
152
156
|
}
|
|
153
|
-
static of(cls, client = noClient()) {
|
|
154
|
-
return new EndpointTestKit(cls, client);
|
|
157
|
+
static of(cls, client = noClient(), storage = new InMemoryBuckets()) {
|
|
158
|
+
return new EndpointTestKit(cls, client, storage);
|
|
155
159
|
}
|
|
156
160
|
#match(method, path) {
|
|
157
161
|
const prefix = this.#cls.prefix;
|
package/dist/timedAction.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Metadata } from "./effects/common.ts";
|
|
2
|
+
import { type ClientKeys } from "./client-keys.ts";
|
|
2
3
|
import { type ComponentClient, type Secrets } from "./client.ts";
|
|
4
|
+
import { type Buckets } from "./storage.ts";
|
|
3
5
|
import type { HandlerTable } from "./handlers.ts";
|
|
4
6
|
import { TimedActionEffects } from "./effects/stateless.ts";
|
|
5
7
|
import { type Services } from "./services.ts";
|
|
@@ -19,6 +21,14 @@ export declare abstract class TimedAction {
|
|
|
19
21
|
get secrets(): Secrets;
|
|
20
22
|
/** A unit test's store in place of the runtime's: `component.secrets = new InMemorySecrets()`. */
|
|
21
23
|
set secrets(store: Secrets);
|
|
24
|
+
/** The service's client keys (1.20): issued for its MCP endpoint, kept by the runtime, each shown once. */
|
|
25
|
+
get clientKeys(): ClientKeys;
|
|
26
|
+
/** A unit test's in place of the runtime's: `component.clientKeys = new InMemoryClientKeys()`. */
|
|
27
|
+
set clientKeys(keys: ClientKeys);
|
|
28
|
+
/** The service's buckets: `this.storage.default`, or `this.storage.bucket("photos")`. */
|
|
29
|
+
get storage(): Buckets;
|
|
30
|
+
/** A unit test's store in place of the runtime's: `component.storage = new InMemoryBuckets()`. */
|
|
31
|
+
set storage(buckets: Buckets);
|
|
22
32
|
/** Other services, called as this one, through the runtime: `this.services.service("orders")`. */
|
|
23
33
|
get services(): Services;
|
|
24
34
|
/** A unit test's in place of the runtime's: `component.services = new ScriptedServices()`. */
|
package/dist/timedAction.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
// sweeper delivers it here, retrying a failure with backoff.
|
|
3
3
|
//
|
|
4
4
|
// static readonly actions = { remind: action("remind", s.string, (t: Reminder, id) => t.remind(id)) }
|
|
5
|
+
import { clientKeysFor } from "./client-keys.js";
|
|
5
6
|
import { secretsFor } from "./client.js";
|
|
7
|
+
import { processStorage } from "./storage.js";
|
|
6
8
|
import { TimedActionEffects } from "./effects/stateless.js";
|
|
7
9
|
import { servicesFor } from "./services.js";
|
|
8
10
|
export class TimedAction {
|
|
@@ -39,6 +41,24 @@ export class TimedAction {
|
|
|
39
41
|
set secrets(store) {
|
|
40
42
|
this.#secrets = store;
|
|
41
43
|
}
|
|
44
|
+
#clientKeys;
|
|
45
|
+
/** The service's client keys (1.20): issued for its MCP endpoint, kept by the runtime, each shown once. */
|
|
46
|
+
get clientKeys() {
|
|
47
|
+
return this.#clientKeys ?? clientKeysFor(this.client);
|
|
48
|
+
}
|
|
49
|
+
/** A unit test's in place of the runtime's: `component.clientKeys = new InMemoryClientKeys()`. */
|
|
50
|
+
set clientKeys(keys) {
|
|
51
|
+
this.#clientKeys = keys;
|
|
52
|
+
}
|
|
53
|
+
#storage;
|
|
54
|
+
/** The service's buckets: `this.storage.default`, or `this.storage.bucket("photos")`. */
|
|
55
|
+
get storage() {
|
|
56
|
+
return this.#storage ?? processStorage();
|
|
57
|
+
}
|
|
58
|
+
/** A unit test's store in place of the runtime's: `component.storage = new InMemoryBuckets()`. */
|
|
59
|
+
set storage(buckets) {
|
|
60
|
+
this.#storage = buckets;
|
|
61
|
+
}
|
|
42
62
|
#services;
|
|
43
63
|
/** Other services, called as this one, through the runtime: `this.services.service("orders")`. */
|
|
44
64
|
get services() {
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.14.0";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Written by scripts/proto.ts from package.json; do not edit. 0.0.0 in the tree, the tag's version in a release.
|
|
2
|
-
export const VERSION = "0.
|
|
2
|
+
export const VERSION = "0.14.0";
|
package/dist/workflow.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { HandlerTable } from "./handlers.ts";
|
|
|
4
4
|
import { type ComponentClient, type Secrets } from "./client.ts";
|
|
5
5
|
import { StepEffects, WorkflowEffects, type WorkflowSettings } from "./effects/workflow.ts";
|
|
6
6
|
import { type Services } from "./services.ts";
|
|
7
|
+
import { type Buckets } from "./storage.ts";
|
|
7
8
|
export declare abstract class Workflow<S> {
|
|
8
9
|
#private;
|
|
9
10
|
/** Inside a command handler. */
|
|
@@ -21,6 +22,13 @@ export declare abstract class Workflow<S> {
|
|
|
21
22
|
get secrets(): Secrets;
|
|
22
23
|
/** A unit test's store in place of the runtime's. */
|
|
23
24
|
set secrets(store: Secrets);
|
|
25
|
+
/**
|
|
26
|
+
* The service's buckets, in a step. A command handler is refused: a wait on a store would hold the
|
|
27
|
+
* workflow's other commands behind it.
|
|
28
|
+
*/
|
|
29
|
+
get storage(): Buckets;
|
|
30
|
+
/** A unit test's store in place of the runtime's. */
|
|
31
|
+
set storage(buckets: Buckets);
|
|
24
32
|
/**
|
|
25
33
|
* Other services, called as this one, in a step. A command handler is refused, as for the secret
|
|
26
34
|
* store: it would block the workflow's other commands behind another service.
|
package/dist/workflow.js
CHANGED
|
@@ -9,6 +9,7 @@ import { secretsFor } from "./client.js";
|
|
|
9
9
|
import { CommandError } from "./effects/common.js";
|
|
10
10
|
import { StepEffects, WorkflowEffects } from "./effects/workflow.js";
|
|
11
11
|
import { servicesFor } from "./services.js";
|
|
12
|
+
import { processStorage, StorageRefusals } from "./storage.js";
|
|
12
13
|
export class Workflow {
|
|
13
14
|
/** Inside a command handler. */
|
|
14
15
|
effects = new WorkflowEffects();
|
|
@@ -55,6 +56,20 @@ export class Workflow {
|
|
|
55
56
|
set secrets(store) {
|
|
56
57
|
this.#secrets = store;
|
|
57
58
|
}
|
|
59
|
+
#storage;
|
|
60
|
+
/**
|
|
61
|
+
* The service's buckets, in a step. A command handler is refused: a wait on a store would hold the
|
|
62
|
+
* workflow's other commands behind it.
|
|
63
|
+
*/
|
|
64
|
+
get storage() {
|
|
65
|
+
if (!this.#inStep)
|
|
66
|
+
throw StorageRefusals.stepsOnly();
|
|
67
|
+
return this.#storage ?? processStorage();
|
|
68
|
+
}
|
|
69
|
+
/** A unit test's store in place of the runtime's. */
|
|
70
|
+
set storage(buckets) {
|
|
71
|
+
this.#storage = buckets;
|
|
72
|
+
}
|
|
58
73
|
#services;
|
|
59
74
|
/**
|
|
60
75
|
* Other services, called as this one, in a step. A command handler is refused, as for the secret
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ankka",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Build services on ankka in TypeScript: entities, views, workflows, agents and endpoints hosted by the ankka sidecar.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@bufbuild/protobuf": "^2.15.0",
|
|
52
52
|
"@connectrpc/connect": "^2.2.0",
|
|
53
53
|
"@connectrpc/connect-node": "^2.2.0",
|
|
54
|
-
"canonicalize": "^
|
|
54
|
+
"canonicalize": "^5.1.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"@testcontainers/postgresql": "^12.1.0",
|