@gjermundgaraba/effect-actions 0.19.0 → 0.21.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/README.md +19 -41
- package/dist/Action.d.mts +140 -48
- package/dist/Action.mjs +88 -44
- package/dist/ActionCli.d.mts +70 -35
- package/dist/ActionCli.mjs +53 -34
- package/dist/ActionHttp.d.mts +70 -38
- package/dist/ActionHttp.mjs +76 -25
- package/dist/ActionMcp.d.mts +56 -24
- package/dist/ActionMcp.mjs +104 -61
- package/dist/ActionRpc.d.mts +222 -57
- package/dist/ActionRpc.mjs +301 -49
- package/dist/ActionToolkit.d.mts +22 -7
- package/dist/ActionToolkit.mjs +37 -14
- package/dist/Authentication.d.mts +42 -12
- package/dist/Authentication.mjs +38 -32
- package/dist/Event.d.mts +370 -0
- package/dist/Event.mjs +103 -0
- package/dist/Testing.d.mts +1 -3
- package/dist/Testing.mjs +2 -3
- package/dist/Webhook.d.mts +146 -0
- package/dist/Webhook.mjs +72 -0
- package/dist/authentication/provider.d.mts +35 -12
- package/dist/authentication/provider.mjs +2 -3
- package/dist/authentication/refusal.mjs +3 -4
- package/dist/cli/commands.d.mts +9 -7
- package/dist/cli/commands.mjs +85 -35
- package/dist/contract/ast.mjs +5 -3
- package/dist/contract/authorizer.d.mts +8 -0
- package/dist/contract/authorizer.mjs +20 -0
- package/dist/contract/call.d.mts +9 -8
- package/dist/contract/call.mjs +49 -8
- package/dist/contract/callback.d.mts +7 -0
- package/dist/contract/callback.mjs +27 -0
- package/dist/contract/caller.d.mts +12 -3
- package/dist/contract/caller.mjs +23 -5
- package/dist/contract/canonical.mjs +10 -0
- package/dist/contract/codec.d.mts +9 -0
- package/dist/contract/codec.mjs +9 -0
- package/dist/contract/codes.mjs +81 -0
- package/dist/contract/declared.d.mts +0 -2
- package/dist/contract/declared.mjs +26 -11
- package/dist/contract/digest.mjs +6 -0
- package/dist/contract/errors.d.mts +9 -5
- package/dist/contract/errors.mjs +2 -3
- package/dist/contract/feed.d.mts +127 -0
- package/dist/contract/feed.mjs +249 -0
- package/dist/contract/hints.mjs +1 -2
- package/dist/contract/hub.d.mts +94 -0
- package/dist/contract/hub.mjs +133 -0
- package/dist/contract/idempotency.d.mts +47 -0
- package/dist/contract/idempotency.mjs +99 -0
- package/dist/contract/implementation.d.mts +73 -51
- package/dist/contract/implementation.mjs +94 -60
- package/dist/contract/input-check.d.mts +15 -0
- package/dist/contract/input-check.mjs +16 -0
- package/dist/contract/lease.mjs +28 -0
- package/dist/contract/listed.d.mts +4 -0
- package/dist/contract/listed.mjs +22 -0
- package/dist/contract/log.d.mts +41 -0
- package/dist/contract/log.mjs +144 -0
- package/dist/contract/media.d.mts +1 -3
- package/dist/contract/media.mjs +1 -2
- package/dist/contract/names.mjs +15 -6
- package/dist/contract/occurrence.d.mts +29 -0
- package/dist/contract/occurrence.mjs +45 -0
- package/dist/contract/pages.d.mts +13 -0
- package/dist/contract/pages.mjs +39 -0
- package/dist/contract/progress.d.mts +26 -0
- package/dist/contract/progress.mjs +72 -0
- package/dist/contract/push.d.mts +20 -0
- package/dist/contract/push.mjs +96 -0
- package/dist/contract/receiving.d.mts +29 -0
- package/dist/contract/receiving.mjs +42 -0
- package/dist/contract/recent.mjs +12 -0
- package/dist/contract/reported.mjs +16 -0
- package/dist/contract/serving.mjs +63 -0
- package/dist/contract/status.mjs +15 -7
- package/dist/contract/stream.d.mts +34 -0
- package/dist/contract/stream.mjs +31 -0
- package/dist/contract/subscribe.d.mts +45 -0
- package/dist/contract/subscribe.mjs +50 -0
- package/dist/contract/transient.mjs +28 -0
- package/dist/contract/watch.d.mts +18 -0
- package/dist/contract/watch.mjs +105 -0
- package/dist/contract/webhooks.d.mts +42 -0
- package/dist/contract/webhooks.mjs +53 -0
- package/dist/http/client.d.mts +37 -14
- package/dist/http/client.mjs +52 -14
- package/dist/http/events.d.mts +56 -0
- package/dist/http/events.mjs +102 -0
- package/dist/http/placed.d.mts +36 -0
- package/dist/http/placed.mjs +71 -0
- package/dist/http/schema-errors.mjs +2 -3
- package/dist/http/streamed.d.mts +21 -0
- package/dist/http/streamed.mjs +94 -0
- package/dist/http/watch.mjs +50 -0
- package/dist/mcp/bridge.mjs +283 -0
- package/dist/mcp/client.d.mts +30 -99
- package/dist/mcp/client.mjs +60 -134
- package/dist/mcp/events.mjs +142 -0
- package/dist/mcp/progress.mjs +34 -0
- package/dist/mcp/protocol.mjs +40 -15
- package/dist/mcp/reply.d.mts +79 -0
- package/dist/mcp/reply.mjs +99 -0
- package/dist/mcp/request.d.mts +40 -0
- package/dist/mcp/request.mjs +51 -0
- package/dist/mcp/watch.mjs +115 -0
- package/dist/rpc/watch.mjs +39 -0
- package/dist/stdio/console.mjs +14 -7
- package/dist/testing/memory.d.mts +1 -3
- package/dist/testing/memory.mjs +4 -5
- package/dist/webhook/address.mjs +47 -0
- package/dist/webhook/attempt.mjs +65 -0
- package/dist/webhook/receiver.mjs +67 -0
- package/dist/webhook/signing.mjs +28 -0
- package/dist/webhook/stored.mjs +57 -0
- package/dist/webhook/subscriptions.mjs +342 -0
- package/docs/Action-failures.md +2 -2
- package/docs/Action-streams.md +115 -0
- package/docs/Action.md +58 -124
- package/docs/ActionCli-failures.md +1 -2
- package/docs/ActionCli.md +83 -88
- package/docs/ActionHttp-failures.md +3 -3
- package/docs/ActionHttp.md +90 -70
- package/docs/ActionMcp-failures.md +2 -1
- package/docs/ActionMcp.md +120 -92
- package/docs/ActionRpc-events.md +126 -0
- package/docs/ActionRpc-failures.md +1 -2
- package/docs/ActionRpc.md +108 -79
- package/docs/ActionToolkit-failures.md +1 -2
- package/docs/ActionToolkit.md +33 -90
- package/docs/Authentication-advanced.md +57 -61
- package/docs/Authentication-failures.md +5 -4
- package/docs/Authentication.md +23 -58
- package/docs/Event-failures.md +15 -0
- package/docs/Event.md +281 -0
- package/docs/README.md +51 -82
- package/docs/Testing-failures.md +1 -5
- package/docs/Testing.md +126 -86
- package/docs/Webhook-failures.md +8 -0
- package/docs/Webhook.md +319 -0
- package/docs/setup-failures.md +2 -3
- package/docs/setup.md +32 -53
- package/examples/README.md +12 -37
- package/examples/assistant/README.md +21 -26
- package/examples/assistant/src/agent.ts +66 -24
- package/examples/assistant/src/cli.ts +7 -4
- package/examples/assistant/src/commands.ts +9 -4
- package/examples/assistant/src/identity/Identity.ts +5 -4
- package/examples/assistant/src/identity/authorize.ts +13 -5
- package/examples/assistant/src/identity/handlers.ts +3 -2
- package/examples/assistant/src/identity/permissions.ts +9 -3
- package/examples/assistant/src/platform/tasks-file.ts +15 -11
- package/examples/assistant/src/scripted.ts +7 -4
- package/examples/assistant/src/tasks/Tasks.ts +20 -6
- package/examples/assistant/src/tasks/handlers.ts +9 -5
- package/examples/assistant/src/tasks/store.ts +38 -11
- package/examples/assistant/src/toolkit.ts +11 -7
- package/examples/assistant/test/commands.test.ts +53 -27
- package/examples/assistant/test/identity/identity.test.ts +27 -11
- package/examples/assistant/test/platform/tasks-file.test.ts +39 -23
- package/examples/assistant/test/tasks/tasks.test.ts +62 -34
- package/examples/assistant/test/toolkit.test.ts +104 -75
- package/examples/build-events/README.md +83 -0
- package/examples/build-events/src/Api.ts +27 -0
- package/examples/build-events/src/Rpc.ts +26 -0
- package/examples/build-events/src/builds/Builds.ts +108 -0
- package/examples/build-events/src/builds/events.ts +54 -0
- package/examples/build-events/src/builds/handlers.ts +58 -0
- package/examples/build-events/src/builds/log.ts +30 -0
- package/examples/build-events/src/builds/status.ts +28 -0
- package/examples/build-events/src/builds/store.ts +130 -0
- package/examples/build-events/src/cli.ts +18 -0
- package/examples/build-events/src/commands.ts +32 -0
- package/examples/build-events/src/deploys/Deploys.ts +44 -0
- package/examples/build-events/src/deploys/approvers.ts +55 -0
- package/examples/build-events/src/deploys/events.ts +32 -0
- package/examples/build-events/src/deploys/handlers.ts +38 -0
- package/examples/build-events/src/identity/Identity.ts +29 -0
- package/examples/build-events/src/identity/members.ts +7 -0
- package/examples/build-events/src/identity/verifier.ts +22 -0
- package/examples/build-events/src/notifier/Notices.ts +26 -0
- package/examples/build-events/src/notifier/routes.ts +71 -0
- package/examples/build-events/src/notifier.ts +48 -0
- package/examples/build-events/src/routes.ts +71 -0
- package/examples/build-events/src/server.ts +62 -0
- package/examples/build-events/test/builds/events.test.ts +68 -0
- package/examples/build-events/test/builds/log.test.ts +71 -0
- package/examples/build-events/test/builds/progress.test.ts +57 -0
- package/examples/build-events/test/builds/status.test.ts +42 -0
- package/examples/build-events/test/commands.test.ts +103 -0
- package/examples/build-events/test/deploys/events.test.ts +52 -0
- package/examples/build-events/test/http.test.ts +95 -0
- package/examples/build-events/test/notifier.test.ts +80 -0
- package/examples/build-events/test/routes.test.ts +96 -0
- package/examples/build-events/test/rpc.test.ts +84 -0
- package/examples/build-events/test/support/as.ts +8 -0
- package/examples/build-events/test/support/memory.ts +43 -0
- package/examples/build-events/test/webhooks.test.ts +143 -0
- package/examples/kitchen-sink/README.md +178 -166
- package/examples/kitchen-sink/src/Actions.ts +11 -3
- package/examples/kitchen-sink/src/Api.ts +12 -6
- package/examples/kitchen-sink/src/Rpc.ts +7 -5
- package/examples/kitchen-sink/src/admin/Admin.ts +21 -10
- package/examples/kitchen-sink/src/admin/authenticate.ts +8 -4
- package/examples/kitchen-sink/src/admin/authorize.ts +13 -5
- package/examples/kitchen-sink/src/admin/grants.ts +5 -3
- package/examples/kitchen-sink/src/admin/handlers.ts +9 -5
- package/examples/kitchen-sink/src/agent.ts +14 -6
- package/examples/kitchen-sink/src/assistant/Assistant.ts +21 -15
- package/examples/kitchen-sink/src/assistant/conversations.ts +14 -9
- package/examples/kitchen-sink/src/assistant/demo-model.ts +2 -2
- package/examples/kitchen-sink/src/assistant/handlers.ts +42 -22
- package/examples/kitchen-sink/src/attachments/Attachments.ts +6 -6
- package/examples/kitchen-sink/src/attachments/download.ts +7 -6
- package/examples/kitchen-sink/src/attachments/handlers.ts +9 -4
- package/examples/kitchen-sink/src/attachments/store.ts +25 -18
- package/examples/kitchen-sink/src/browser.ts +10 -4
- package/examples/kitchen-sink/src/cli.ts +28 -12
- package/examples/kitchen-sink/src/config.ts +1 -1
- package/examples/kitchen-sink/src/identity/Identity.ts +24 -10
- package/examples/kitchen-sink/src/identity/authenticate.ts +19 -11
- package/examples/kitchen-sink/src/identity/authorize.ts +14 -4
- package/examples/kitchen-sink/src/identity/directory.ts +16 -7
- package/examples/kitchen-sink/src/identity/handlers.ts +1 -0
- package/examples/kitchen-sink/src/identity/members.ts +7 -2
- package/examples/kitchen-sink/src/identity/quota.ts +23 -20
- package/examples/kitchen-sink/src/issues/Issues.ts +91 -15
- package/examples/kitchen-sink/src/issues/assistant.ts +4 -2
- package/examples/kitchen-sink/src/issues/events.ts +46 -0
- package/examples/kitchen-sink/src/issues/export.ts +35 -0
- package/examples/kitchen-sink/src/issues/guide.ts +4 -3
- package/examples/kitchen-sink/src/issues/handlers.ts +20 -7
- package/examples/kitchen-sink/src/issues/store.ts +156 -67
- package/examples/kitchen-sink/src/issues/write-limit.ts +44 -18
- package/examples/kitchen-sink/src/memory.ts +11 -2
- package/examples/kitchen-sink/src/ops.ts +10 -5
- package/examples/kitchen-sink/src/request-policy.ts +25 -9
- package/examples/kitchen-sink/src/routes.ts +67 -27
- package/examples/kitchen-sink/src/sdk.ts +22 -12
- package/examples/kitchen-sink/src/seed.ts +15 -9
- package/examples/kitchen-sink/src/server.ts +24 -10
- package/examples/kitchen-sink/src/stdio.ts +9 -3
- package/examples/kitchen-sink/src/workspaces/Workspaces.ts +10 -7
- package/examples/kitchen-sink/src/workspaces/handlers.ts +3 -2
- package/examples/kitchen-sink/src/workspaces/registry.ts +16 -10
- package/examples/kitchen-sink/src/workspaces/tenant.ts +12 -5
- package/examples/kitchen-sink/test/admin/admin.test.ts +38 -23
- package/examples/kitchen-sink/test/assistant/assistant.test.ts +471 -299
- package/examples/kitchen-sink/test/attachments/attachments.test.ts +135 -94
- package/examples/kitchen-sink/test/identity/identity.test.ts +110 -82
- package/examples/kitchen-sink/test/identity/session.test.ts +65 -43
- package/examples/kitchen-sink/test/issues/assistant.test.ts +50 -31
- package/examples/kitchen-sink/test/issues/events.test.ts +273 -0
- package/examples/kitchen-sink/test/issues/export.test.ts +120 -0
- package/examples/kitchen-sink/test/issues/issues.test.ts +105 -75
- package/examples/kitchen-sink/test/request-policy.test.ts +130 -33
- package/examples/kitchen-sink/test/routes.test.ts +102 -57
- package/examples/kitchen-sink/test/support/as.ts +9 -0
- package/examples/kitchen-sink/test/support/scripted.ts +6 -5
- package/examples/kitchen-sink/test/support/services.ts +17 -0
- package/examples/live-rpc/README.md +33 -35
- package/examples/live-rpc/src/Rpc.ts +9 -5
- package/examples/live-rpc/src/browser.ts +39 -11
- package/examples/live-rpc/src/chat/Chat.ts +30 -16
- package/examples/live-rpc/src/chat/authorize.ts +2 -1
- package/examples/live-rpc/src/chat/events.ts +74 -0
- package/examples/live-rpc/src/chat/handlers.ts +13 -5
- package/examples/live-rpc/src/chat/room.ts +9 -5
- package/examples/live-rpc/src/chat/store.ts +51 -14
- package/examples/live-rpc/src/client.ts +22 -5
- package/examples/live-rpc/src/identity/Identity.ts +3 -3
- package/examples/live-rpc/src/identity/verifier.ts +8 -4
- package/examples/live-rpc/src/page.ts +58 -12
- package/examples/live-rpc/src/routes.ts +14 -10
- package/examples/live-rpc/src/server.ts +15 -5
- package/examples/live-rpc/test/browser.test.ts +127 -50
- package/examples/live-rpc/test/chat/chat.test.ts +215 -23
- package/examples/live-rpc/test/routes.test.ts +130 -46
- package/examples/live-rpc/test/server.test.ts +94 -33
- package/examples/mcp-tools/README.md +24 -38
- package/examples/mcp-tools/src/platform/fake-farm.ts +63 -24
- package/examples/mcp-tools/src/platform/print-farm.ts +59 -29
- package/examples/mcp-tools/src/printers/Printers.ts +18 -7
- package/examples/mcp-tools/src/printers/farm.ts +15 -5
- package/examples/mcp-tools/src/printers/handlers.ts +12 -6
- package/examples/mcp-tools/src/routes.ts +8 -6
- package/examples/mcp-tools/src/server.ts +12 -5
- package/examples/mcp-tools/src/stdio.ts +3 -2
- package/examples/mcp-tools/test/printers/printers.test.ts +132 -89
- package/examples/mcp-tools/test/routes.test.ts +140 -81
- package/examples/notes-service/README.md +30 -45
- package/examples/notes-service/src/Api.ts +1 -0
- package/examples/notes-service/src/browser.ts +15 -14
- package/examples/notes-service/src/cli.ts +8 -3
- package/examples/notes-service/src/commands.ts +46 -20
- package/examples/notes-service/src/identity/Identity.ts +2 -2
- package/examples/notes-service/src/identity/authorize.ts +6 -2
- package/examples/notes-service/src/identity/handlers.ts +3 -2
- package/examples/notes-service/src/identity/users.ts +2 -1
- package/examples/notes-service/src/identity/verifier.ts +12 -6
- package/examples/notes-service/src/notes/Notes.ts +46 -22
- package/examples/notes-service/src/notes/handlers.ts +18 -9
- package/examples/notes-service/src/notes/store.ts +70 -43
- package/examples/notes-service/src/routes.ts +7 -5
- package/examples/notes-service/src/server.ts +12 -5
- package/examples/notes-service/src/status/Status.ts +1 -1
- package/examples/notes-service/src/status/handlers.ts +5 -3
- package/examples/notes-service/src/stdio.ts +7 -3
- package/examples/notes-service/src/worker.ts +6 -3
- package/examples/notes-service/test/commands.test.ts +164 -91
- package/examples/notes-service/test/notes/as.ts +3 -1
- package/examples/notes-service/test/notes/idempotency.test.ts +97 -67
- package/examples/notes-service/test/notes/in-process.test.ts +26 -15
- package/examples/notes-service/test/notes/notes.test.ts +49 -31
- package/examples/notes-service/test/routes.test.ts +106 -71
- package/examples/notes-service/test/worker.test.ts +21 -13
- package/examples/quickstart/README.md +2 -6
- package/examples/quickstart/src/Api.ts +1 -0
- package/examples/quickstart/src/client.ts +6 -3
- package/examples/quickstart/src/greeting/Greeting.ts +1 -1
- package/examples/quickstart/src/greeting/handlers.ts +5 -2
- package/examples/quickstart/src/routes.ts +3 -2
- package/examples/quickstart/src/server.ts +6 -2
- package/examples/quickstart/test/routes.test.ts +3 -2
- package/package.json +19 -17
package/dist/Event.d.mts
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { Codec, CodecOf, Fields, NoInput } from "./contract/codec.mjs";
|
|
2
|
+
import { Refusal } from "./contract/errors.mjs";
|
|
3
|
+
import { Gap, OccurrenceSchema } from "./contract/occurrence.mjs";
|
|
4
|
+
import { AnyEventImplementation, EventImplementation } from "./contract/feed.mjs";
|
|
5
|
+
import { Listed, LogStorage } from "./contract/log.mjs";
|
|
6
|
+
import { Events, KeyOptions, MakeEventsOptions, RevisionStorage, layerMemory, makeEvents } from "./contract/hub.mjs";
|
|
7
|
+
import { Protected } from "./contract/implementation.mjs";
|
|
8
|
+
import { Authorizer, Deferred as Deferred$1 } from "./contract/authorizer.mjs";
|
|
9
|
+
import { Options as Options$1 } from "./Action.mjs";
|
|
10
|
+
import { DateTime, Duration, Effect, Schema, Scope, Stream } from "effect";
|
|
11
|
+
declare const TypeId = "~@gjermundgaraba/effect-actions/Event";
|
|
12
|
+
/** What `make` needs to define an event type. */
|
|
13
|
+
export interface Options {
|
|
14
|
+
/**
|
|
15
|
+
* Who may subscribe: `Action.Anyone`, or the identity service a subscriber must have, as an
|
|
16
|
+
* action's `caller` says; the rules of an identity are on `Action.Options.caller`.
|
|
17
|
+
*/
|
|
18
|
+
readonly caller: Options$1["caller"];
|
|
19
|
+
/** What happens when the event fires; a model and a CLI user read it beside the event's name. */
|
|
20
|
+
readonly description: string;
|
|
21
|
+
/**
|
|
22
|
+
* The subscription's arguments, a schema or struct fields, as an action's `input` is: they may
|
|
23
|
+
* filter the occurrences, shape them, or configure the subscription. Omit for an event without
|
|
24
|
+
* arguments. Its rules are `Action.Options.input`'s.
|
|
25
|
+
*/
|
|
26
|
+
readonly input?: Codec | Fields | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* What each occurrence carries, a schema or struct fields: an object, since MCP sends it as an
|
|
29
|
+
* occurrence's `data`.
|
|
30
|
+
*/
|
|
31
|
+
readonly payload: Codec | Fields;
|
|
32
|
+
}
|
|
33
|
+
type OnlyOptions<O> = { readonly [K in Exclude<O extends unknown ? keyof O : never, keyof Options>]: never; };
|
|
34
|
+
type Rules<O> = Options extends O ? unknown : OnlyOptions<O>;
|
|
35
|
+
type InputOf<O> = O extends {
|
|
36
|
+
readonly input?: infer I;
|
|
37
|
+
} ? CodecOf<Extract<Exclude<I, undefined>, Codec | Fields>> | ([undefined] extends [I] ? typeof NoInput : never) : typeof NoInput;
|
|
38
|
+
type PayloadOf<O> = O extends {
|
|
39
|
+
readonly payload: infer P extends Codec | Fields;
|
|
40
|
+
} ? CodecOf<P> : never;
|
|
41
|
+
/**
|
|
42
|
+
* A pure contract for something that happens, bound to its source by `implement`: subscribers
|
|
43
|
+
* receive its occurrences, each carrying a `payload`, filtered and shaped by the subscription's
|
|
44
|
+
* `input`. Its `name`, `input` and `payload` are public: reuse them, as in
|
|
45
|
+
* `Schema.Array(NoteCreated.payload)`.
|
|
46
|
+
*/
|
|
47
|
+
export interface Event<Name extends string, Input extends Codec, Payload extends Codec, Caller extends Options["caller"] = Options["caller"]> {
|
|
48
|
+
readonly [TypeId]: typeof TypeId;
|
|
49
|
+
readonly caller: Caller;
|
|
50
|
+
readonly name: Name;
|
|
51
|
+
readonly description: string;
|
|
52
|
+
/** The subscription's arguments as a schema, a `Schema.Struct` where fields were given. */
|
|
53
|
+
readonly input: Input;
|
|
54
|
+
/** What each occurrence carries, as a schema. */
|
|
55
|
+
readonly payload: Payload;
|
|
56
|
+
}
|
|
57
|
+
/** Any event type, with its schemas erased. */
|
|
58
|
+
export type Any = Event<string, Codec, Codec>;
|
|
59
|
+
/** Whether `u` is an event type `make` defined: a binding's list tells events from actions by it. */
|
|
60
|
+
export declare const isEvent: (u: unknown) => u is Any;
|
|
61
|
+
/**
|
|
62
|
+
* Define an event type: what a subscription takes, what each occurrence carries, and who may
|
|
63
|
+
* subscribe. A surface serving it names it by `name`.
|
|
64
|
+
* Guide: `docs/Event.md` in this package; in an application: `examples/build-events/src/builds/`.
|
|
65
|
+
*
|
|
66
|
+
* **Gotchas**
|
|
67
|
+
*
|
|
68
|
+
* - A name is lowercase segments joined by dots, `note.created`: its form is in the message `Invalid event name` throws; it is unique among the events each surface serves, apart from action names.
|
|
69
|
+
* - Surfaces match an implementation to a contract by object identity, never by name, as for actions.
|
|
70
|
+
*/
|
|
71
|
+
export declare function make<const Name extends string, const O extends Options>(name: Name, options: O & NoInfer<Rules<O>>): Event<Name, InputOf<O>, PayloadOf<O>, O["caller"]>;
|
|
72
|
+
/**
|
|
73
|
+
* One occurrence as a source produces it: its `data`, and optionally the upstream's own id, which
|
|
74
|
+
* subscribers deduplicate by, and when it happened. Without them, a log source's occurrence
|
|
75
|
+
* takes its cursor as its id and the time it was appended, the same on every read; a check's
|
|
76
|
+
* takes a generated id and the time it is read.
|
|
77
|
+
*/
|
|
78
|
+
export interface Emitted<E extends Any> {
|
|
79
|
+
readonly data: E["payload"]["Type"];
|
|
80
|
+
/**
|
|
81
|
+
* A stable id: give the upstream's own, such as a message or delivery id, so a retry or a replay repeats it.
|
|
82
|
+
*
|
|
83
|
+
* **Gotchas**
|
|
84
|
+
*
|
|
85
|
+
* - An id given again for another occurrence is dropped as a duplicate by a `watch` and by `Webhook.layerReceiver`, each keeping its last 1,000: an id from a counter that restarts with the process repeats, so leave it out rather than give one.
|
|
86
|
+
*/
|
|
87
|
+
readonly eventId?: string | undefined;
|
|
88
|
+
readonly timestamp?: DateTime.Utc | undefined;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* What a check answers for a cursor: the occurrences since it, and the cursor after them.
|
|
92
|
+
*
|
|
93
|
+
* **Gotchas**
|
|
94
|
+
*
|
|
95
|
+
* - A cursor the upstream no longer serves, such as one older than its retention, is answered with `truncated: true` and a fresh cursor: the subscriber then knows it missed occurrences.
|
|
96
|
+
* - A `nextPoll` under a second is read as a second, and one over 5 minutes, `Duration.infinity` included, as 5 minutes, by the server's loop and by a polling client alike.
|
|
97
|
+
*/
|
|
98
|
+
export interface Page<E extends Any> {
|
|
99
|
+
readonly events: ReadonlyArray<Emitted<E>>;
|
|
100
|
+
readonly cursor: string;
|
|
101
|
+
readonly truncated?: boolean | undefined;
|
|
102
|
+
/** More occurrences are ready: the subscriber asks again without waiting. */
|
|
103
|
+
readonly hasMore?: boolean | undefined;
|
|
104
|
+
/** How long a subscriber waits before it asks again; defaults to 5 seconds. */
|
|
105
|
+
readonly nextPoll?: Duration.Input | undefined;
|
|
106
|
+
}
|
|
107
|
+
interface Hooked<E extends Any, R> {
|
|
108
|
+
/**
|
|
109
|
+
* What a subscription needs set up upstream while it lasts, such as joining a channel: a scoped
|
|
110
|
+
* Effect, whose finalizer tears it down, run as the subscriber. A stream's lasts as long as the
|
|
111
|
+
* stream, a poll subscription's until `lease` after its last poll, or, watched in process, until
|
|
112
|
+
* the watch ends, and a webhook subscription's until it is unsubscribed or lapses, set up again
|
|
113
|
+
* as `persist` restores it.
|
|
114
|
+
*
|
|
115
|
+
* **Gotchas**
|
|
116
|
+
*
|
|
117
|
+
* - Write it so it may run twice for one subscription: a lease does not outlive the process, so a poll after a restart sets it up again.
|
|
118
|
+
* - A poll subscription's runs in its first poll's context, that request included, held until its lease ends, where a webhook subscription's runs without the request: read what it needs from the request in middleware, which provides it as a service.
|
|
119
|
+
*/
|
|
120
|
+
readonly subscription?: ((input: E["input"]["Type"]) => Effect.Effect<void, never, R | Scope.Scope>) | undefined;
|
|
121
|
+
/** How long a poll subscription's `subscription` lasts after its last poll; defaults to 5 minutes. */
|
|
122
|
+
readonly lease?: Duration.Input | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* The key a subscriber of `input` is reached by, run as the subscriber, such as the room it
|
|
125
|
+
* follows: `Events.notify` and `Events.publish` given a key reach the subscribers of that key
|
|
126
|
+
* alone, and those it answers `undefined` for, who follow every key. Without it, every
|
|
127
|
+
* announcement reaches every subscriber.
|
|
128
|
+
*
|
|
129
|
+
* **Gotchas**
|
|
130
|
+
*
|
|
131
|
+
* - An occurrence a log's `emit` gives without a `key` reaches every subscriber, whatever key it follows: give each one its key.
|
|
132
|
+
*/
|
|
133
|
+
readonly key?: ((input: E["input"]["Type"]) => string | undefined | Effect.Effect<string | undefined, never, R>) | undefined;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* An event type read from an upstream that can be asked what happened since a cursor, such as a
|
|
137
|
+
* change feed or a history API: one function answers every subscriber, whatever the surface.
|
|
138
|
+
*
|
|
139
|
+
* **Gotchas**
|
|
140
|
+
*
|
|
141
|
+
* - An occurrence without `eventId` takes a fresh id at each read, and a page's occurrences before its last are read again from the cursor asked after a reconnect mid-page: give the upstream's ids, or a subscriber receives them again under ids no `watch` drops.
|
|
142
|
+
*/
|
|
143
|
+
export interface Check<E extends Any, R = never> extends Hooked<E, R> {
|
|
144
|
+
/**
|
|
145
|
+
* What happened since `cursor`, as the subscriber's `input` selects it, run as the subscriber.
|
|
146
|
+
* A `null` cursor is a subscriber with no position: answer nothing, so it starts after the last
|
|
147
|
+
* occurrence. An event whose occurrence is the whole value, such as a status, is a `Current`.
|
|
148
|
+
*/
|
|
149
|
+
readonly check: (input: E["input"]["Type"], cursor: string | null) => Effect.Effect<Page<E>, Refusal, R>;
|
|
150
|
+
readonly log?: never;
|
|
151
|
+
readonly current?: never;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* An event type whose occurrence is the whole value, such as a status or a list small enough to
|
|
155
|
+
* send whole: a subscriber receives the value as it is first, then again after each
|
|
156
|
+
* `Events.notify` that reaches it, never a change it missed one by one. The library keeps a
|
|
157
|
+
* revision per key, which each such notify moves, as the cursor and each occurrence's id.
|
|
158
|
+
*
|
|
159
|
+
* **Gotchas**
|
|
160
|
+
*
|
|
161
|
+
* - A notify without a change sends the value again, under a new id: notify after a write that changed it.
|
|
162
|
+
* - The revision is read before `current`, so a value written between them is sent again at the next read, never missed: write the value, then notify.
|
|
163
|
+
*/
|
|
164
|
+
export interface Current<E extends Any, R = never> extends Hooked<E, R> {
|
|
165
|
+
/** The value as it is, as the subscriber's `input` selects it, run as the subscriber. */
|
|
166
|
+
readonly current: (input: E["input"]["Type"]) => Effect.Effect<E["payload"]["Type"], Refusal, R>;
|
|
167
|
+
readonly check?: never;
|
|
168
|
+
readonly log?: never;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* An event type whose occurrences the library keeps as they are announced, for an upstream with
|
|
172
|
+
* no history of its own: `Events.publish` appends each, and `log.emit`, where given, a stream of
|
|
173
|
+
* them. Each subscriber receives the occurrences its `match` accepts, shaped by its `transform`.
|
|
174
|
+
*
|
|
175
|
+
* **Gotchas**
|
|
176
|
+
*
|
|
177
|
+
* - A cursor is only good where the log that minted it lives, for as long as it keeps its occurrences: after a restart, or once they are dropped, a subscriber resuming from it receives `truncated` and a fresh cursor.
|
|
178
|
+
* - A subscriber reading slower than occurrences arrive falls behind the log like a resumed one: it receives `truncated`, never a backlog held for it alone.
|
|
179
|
+
* - An `emit` stream is consumed from startup, in the server's scope, by one build at a time, until it ends, even past its build's release: a failure ends it and is reported, an end is logged, and the next held build's stream, if any, takes over; the log then holds what was published.
|
|
180
|
+
*/
|
|
181
|
+
export interface Log<E extends Any, R = never> extends Hooked<E, R> {
|
|
182
|
+
/** What the log keeps, and the stream feeding it besides `Events.publish`; `{}` for none. */
|
|
183
|
+
readonly log: LogOptions<E>;
|
|
184
|
+
/** Whether a subscriber of `input` receives an occurrence carrying `data`; defaults to every one. */
|
|
185
|
+
readonly match?: ((input: E["input"]["Type"], data: E["payload"]["Type"]) => boolean | Effect.Effect<boolean, never, R>) | undefined;
|
|
186
|
+
/** The data a subscriber of `input` receives in place of `data`, such as one with fields removed. */
|
|
187
|
+
readonly transform?: ((input: E["input"]["Type"], data: E["payload"]["Type"]) => E["payload"]["Type"] | Effect.Effect<E["payload"]["Type"], never, R>) | undefined;
|
|
188
|
+
readonly check?: never;
|
|
189
|
+
readonly current?: never;
|
|
190
|
+
}
|
|
191
|
+
/** What a log source keeps, and what feeds it besides `Events.publish`. */
|
|
192
|
+
export interface LogOptions<E extends Any> {
|
|
193
|
+
/**
|
|
194
|
+
* A stream of occurrences, such as a message bus's, appended as they arrive from startup, each
|
|
195
|
+
* reaching the subscribers of its `key`, as `Events.publish` given one does.
|
|
196
|
+
*/
|
|
197
|
+
readonly emit?: Stream.Stream<Emitted<E> & KeyOptions> | undefined;
|
|
198
|
+
/**
|
|
199
|
+
* How long an occurrence is kept for subscribers resuming from a cursor; defaults to 10 minutes.
|
|
200
|
+
* The first build attached to its log sets it, and later builds share that log.
|
|
201
|
+
*/
|
|
202
|
+
readonly maxAge?: Duration.Input | undefined;
|
|
203
|
+
/**
|
|
204
|
+
* How many occurrences are kept at most, of every key together; defaults to 10,000.
|
|
205
|
+
*
|
|
206
|
+
* **Gotchas**
|
|
207
|
+
*
|
|
208
|
+
* - A busy key drops a quiet one's occurrences too: a subscriber of the quiet key resuming after them receives a gap, though none of its own was dropped.
|
|
209
|
+
*/
|
|
210
|
+
readonly maxEvents?: number | undefined;
|
|
211
|
+
}
|
|
212
|
+
/** Where an event type's occurrences come from: exactly one of `check`, `current` or `log`. */
|
|
213
|
+
export type Source<E extends Any, R = never> = Check<E, R> | Current<E, R> | Log<E, R>;
|
|
214
|
+
/**
|
|
215
|
+
* One occurrence as a subscriber receives it: `eventId`, the source's id or one generated, which
|
|
216
|
+
* a subscriber deduplicates by; `cursor`, where to resume after it, `null` for an event type that
|
|
217
|
+
* cannot be resumed.
|
|
218
|
+
*/
|
|
219
|
+
export type Occurrence<E extends Any> = OccurrenceSchema<E>["Type"];
|
|
220
|
+
/** What a subscriber receives: occurrences, and gaps where it missed some. */
|
|
221
|
+
export type Received<E extends Any> = Occurrence<E> | Gap;
|
|
222
|
+
declare const NotServed_base: Schema.Class<NotServed, Schema.TaggedStruct<"NotServed", {}>, import("effect/Cause").YieldableError & {
|
|
223
|
+
readonly brand: unique symbol;
|
|
224
|
+
}>;
|
|
225
|
+
/** The server serves no event type of that name, or no longer does. */
|
|
226
|
+
export declare class NotServed extends NotServed_base {}
|
|
227
|
+
declare const Unsupported_base: Schema.Class<Unsupported, Schema.TaggedStruct<"Unsupported", {
|
|
228
|
+
readonly feature: Schema.String;
|
|
229
|
+
readonly value: Schema.optional<Schema.String>;
|
|
230
|
+
}>, import("effect/Cause").YieldableError & {
|
|
231
|
+
readonly brand: unique symbol;
|
|
232
|
+
}>;
|
|
233
|
+
/**
|
|
234
|
+
* The server serves the event type, but not as asked: `feature` names what it does not offer,
|
|
235
|
+
* such as `deliveryMode`, and `value` which one, such as `push`.
|
|
236
|
+
*/
|
|
237
|
+
export declare class Unsupported extends Unsupported_base {}
|
|
238
|
+
/**
|
|
239
|
+
* Why a webhook's callback endpoint failed, in SEP-3415's categories: it refused the connection
|
|
240
|
+
* or was unreachable, timed out, failed TLS, answered a status from 300 to 499 (`http_4xx`, as
|
|
241
|
+
* the categories name no 3xx) or a 5xx, or did not echo the verification challenge.
|
|
242
|
+
*/
|
|
243
|
+
export declare const CallbackCategory: Schema.Literals<readonly ["connection_refused", "timeout", "tls_error", "http_4xx", "http_5xx", "challenge_failed"]>;
|
|
244
|
+
export type CallbackCategory = typeof CallbackCategory.Type;
|
|
245
|
+
declare const CallbackFailed_base: Schema.Class<CallbackFailed, Schema.TaggedStruct<"CallbackFailed", {
|
|
246
|
+
readonly category: Schema.Literals<readonly ["connection_refused", "timeout", "tls_error", "http_4xx", "http_5xx", "challenge_failed"]>;
|
|
247
|
+
}>, import("effect/Cause").YieldableError & {
|
|
248
|
+
readonly brand: unique symbol;
|
|
249
|
+
}>;
|
|
250
|
+
/** A webhook subscription's callback endpoint failed its verification, or was unreachable. */
|
|
251
|
+
export declare class CallbackFailed extends CallbackFailed_base {}
|
|
252
|
+
declare const NotSubscribed_base: Schema.Class<NotSubscribed, Schema.TaggedStruct<"NotSubscribed", {}>, import("effect/Cause").YieldableError & {
|
|
253
|
+
readonly brand: unique symbol;
|
|
254
|
+
}>;
|
|
255
|
+
/** No webhook subscription matches the one an unsubscribe names. */
|
|
256
|
+
export declare class NotSubscribed extends NotSubscribed_base {}
|
|
257
|
+
declare const Reason: Schema.Union<readonly [typeof NotServed, typeof Unsupported, typeof CallbackFailed, typeof NotSubscribed]>;
|
|
258
|
+
declare const SubscriptionError_base: Schema.Class<SubscriptionError, Schema.TaggedStruct<"SubscriptionError", {
|
|
259
|
+
readonly event: Schema.String;
|
|
260
|
+
readonly reason: Schema.Union<readonly [typeof NotServed, typeof Unsupported, typeof CallbackFailed, typeof NotSubscribed]>;
|
|
261
|
+
readonly message: Schema.String;
|
|
262
|
+
}>, import("effect/Cause").YieldableError & {
|
|
263
|
+
readonly brand: unique symbol;
|
|
264
|
+
}>;
|
|
265
|
+
/**
|
|
266
|
+
* A subscription that cannot start or go on: `reason` says why, so a subscriber branches on it
|
|
267
|
+
* with `Effect.catchReason("SubscriptionError", "NotServed", ...)`; `message` names the event and
|
|
268
|
+
* the reason. A refusal is `Action.Unauthenticated` or `Action.Forbidden`, and input that does not
|
|
269
|
+
* decode `Action.InvalidInput`, as for an action.
|
|
270
|
+
*/
|
|
271
|
+
export declare class SubscriptionError extends SubscriptionError_base {
|
|
272
|
+
/** The error for `event` failing with `reason`, its message built from both. */
|
|
273
|
+
static of(event: string, reason: (typeof Reason)["Type"]): SubscriptionError;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Where a watch keeps its cursor: what it kept under a key, and keeping a new one; a failure `E`
|
|
277
|
+
* of either ends the watch with it.
|
|
278
|
+
*/
|
|
279
|
+
export interface CursorStore<E = never> {
|
|
280
|
+
readonly get: (key: string) => Effect.Effect<string | undefined, E>;
|
|
281
|
+
readonly set: (key: string, cursor: string) => Effect.Effect<void, E>;
|
|
282
|
+
}
|
|
283
|
+
declare const WebhookDelivery_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => Readonly<A> & {
|
|
284
|
+
readonly _tag: "WebhookDelivery";
|
|
285
|
+
} & import("effect/Pipeable").Pipeable;
|
|
286
|
+
/**
|
|
287
|
+
* A watch delivered by webhook, which `Webhook.delivery` makes: the server POSTs each occurrence
|
|
288
|
+
* to the route `Webhook.layerReceiver` serves in the watching process, reached under `baseUrl`,
|
|
289
|
+
* for as long as the watch is read, each grant asking for `ttl`.
|
|
290
|
+
*/
|
|
291
|
+
export declare class WebhookDelivery extends WebhookDelivery_base<{
|
|
292
|
+
/**
|
|
293
|
+
* The https URL the server reaches the watching process at: its `layerReceiver` route's path
|
|
294
|
+
* is appended to it, `https://notifier.example.com` with `/hooks/builds` delivering to
|
|
295
|
+
* `https://notifier.example.com/hooks/builds`.
|
|
296
|
+
*/
|
|
297
|
+
readonly baseUrl: string;
|
|
298
|
+
/** The lifetime each subscribe asks for; omitted, the server's longest. */
|
|
299
|
+
readonly ttl?: Duration.Input | undefined;
|
|
300
|
+
}> {}
|
|
301
|
+
/**
|
|
302
|
+
* How a client watches an event type; `E` is what its `resume` store fails with.
|
|
303
|
+
*
|
|
304
|
+
* **Gotchas**
|
|
305
|
+
*
|
|
306
|
+
* - Each run of a watch's stream starts from these options, a retry or a repeat included: to go on where a failed run stopped, give `resume`, which every run reads.
|
|
307
|
+
* - `resume` keeps an occurrence's cursor once the next is pulled, so a consumer stopped while handling one receives it again: deduplicate by `eventId` where that matters.
|
|
308
|
+
*/
|
|
309
|
+
export interface WatchOptions<E = never> {
|
|
310
|
+
/** Where to start: a cursor an occurrence or a gap carried; defaults to now. */
|
|
311
|
+
readonly cursor?: string | null | undefined;
|
|
312
|
+
/**
|
|
313
|
+
* `"stream"` holds one subscription open, `"poll"` asks again and again, and a
|
|
314
|
+
* `Webhook.delivery` has the server POST each occurrence to a receiver this process serves,
|
|
315
|
+
* which the watch then requires; left out, a watch streams where its surface can and polls
|
|
316
|
+
* where the server serves the event by poll alone.
|
|
317
|
+
*/
|
|
318
|
+
readonly mode?: "stream" | "poll" | WebhookDelivery | undefined;
|
|
319
|
+
/**
|
|
320
|
+
* Where to keep the cursor between watches, such as across restarts: it starts from the cursor
|
|
321
|
+
* kept under `key`, when no `cursor` is given, and keeps each new one there. Effect's
|
|
322
|
+
* `KeyValueStore` is one: `{ store: yield* KeyValueStore.KeyValueStore, key: "builds" }`.
|
|
323
|
+
*/
|
|
324
|
+
readonly resume?: {
|
|
325
|
+
readonly store: CursorStore<E>;
|
|
326
|
+
readonly key: string;
|
|
327
|
+
} | undefined;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Authorization for protected event types: it refuses, and fails with nothing else. It runs for
|
|
331
|
+
* every subscription of a protected event type, before its source.
|
|
332
|
+
*/
|
|
333
|
+
export type Authorize<E extends Any, R = never> = (event: E) => Effect.Effect<void, Refusal, R>;
|
|
334
|
+
/** Every authenticated subscriber may subscribe to a protected event type. */
|
|
335
|
+
export declare const allowAll: Authorize<Any>;
|
|
336
|
+
type Target = Any | readonly Any[];
|
|
337
|
+
type EventsOf<T extends Target> = T extends readonly Any[] ? T[number] : Extract<T, Any>;
|
|
338
|
+
type TakesNoAuthorize<T extends Target> = [Protected<EventsOf<T>>] extends [never] ? unknown : "A protected event takes { authorize }: your rule, or Event.allowAll";
|
|
339
|
+
type NamesOf<T extends Target> = EventsOf<T>["name"];
|
|
340
|
+
type SourcesOf<T extends Target, R, RequestServices> = T extends Any ? Check<T, R> | Current<T, R> | Log<T, R> : { readonly [K in keyof RequestServices]: K extends NamesOf<T> ? Check<Extract<EventsOf<T>, {
|
|
341
|
+
readonly name: K;
|
|
342
|
+
}>, RequestServices[K]> | Current<Extract<EventsOf<T>, {
|
|
343
|
+
readonly name: K;
|
|
344
|
+
}>, RequestServices[K]> | Log<Extract<EventsOf<T>, {
|
|
345
|
+
readonly name: K;
|
|
346
|
+
}>, RequestServices[K]> : never; };
|
|
347
|
+
type Implemented<T extends Target, RequestServices, R, EX, RX, RA, EAX, RAX> = EventImplementation<EventsOf<T>, { readonly [K in NamesOf<T>]: Exclude<T extends readonly Any[] ? RequestServices[K & keyof RequestServices] : R, Scope.Scope>; }, Deferred$1<EX>, Deferred$1<Exclude<RX, Scope.Scope>> | Events, Exclude<RA, Scope.Scope>, Deferred$1<EAX>, Deferred$1<Exclude<RAX, Scope.Scope>>>;
|
|
348
|
+
/**
|
|
349
|
+
* Bind sources to event types, behind authorization: one event type and its source, or a list
|
|
350
|
+
* and a record of sources keyed by event name, given directly or built by an Effect whose
|
|
351
|
+
* services are startup requirements, while what a source yields per subscriber is a request-time
|
|
352
|
+
* requirement. `authorize` is required when the list holds a protected event type. Every surface
|
|
353
|
+
* serving events takes the implementation it returns, beside action implementations in one list.
|
|
354
|
+
*
|
|
355
|
+
* **Gotchas**
|
|
356
|
+
*
|
|
357
|
+
* - The builder runs once per layer graph, however many surfaces serve it, as the first event type a surface serves attaches; a log source's `emit` starts being consumed once its event type is served or watched, and an event type no surface serves starts nothing.
|
|
358
|
+
* - `check`, `current`, `match`, `transform`, `key` and `subscription` run as the subscriber: what they yield, such as the caller, is resolved per subscription.
|
|
359
|
+
* - A source holds exactly one of `check`, `current` or `log`, checked as a surface serving its event type builds, which fails otherwise: a source of an event type no surface serves is not checked.
|
|
360
|
+
* - Serving or watching an event type needs `Event.Events`, which its source attaches to as it builds: provide `Event.layerMemory` once, around the handlers announcing and the surfaces serving.
|
|
361
|
+
* - An occurrence whose data breaks the event's payload is reported, and every surface sends a `Gap` in its place, a poll's page `truncated`: the rest of its page is still delivered.
|
|
362
|
+
* - A read failing with no refusal is reported once, and the subscription reads on from where it reached: a stream a server holds, a webhook's and `Action.client`'s `watch` after 5 seconds, a client's poll, which a server answers with an error, after its reconnect backoff, from 1 second doubling to 30; a refusal ends the subscription.
|
|
363
|
+
*/
|
|
364
|
+
export declare function implement<const T extends Target, RequestServices extends (T extends readonly Any[] ? { readonly [K in NamesOf<T>]: unknown; } : never), R = never, EX = never, RX = never, RA = never, EAX = never, RAX = never>(events: T, sources: SourcesOf<T, R, RequestServices> | Effect.Effect<SourcesOf<T, R, RequestServices>, EX, RX>, options: [Protected<EventsOf<T>>] extends [never] ? {
|
|
365
|
+
readonly authorize?: "A public-only target takes no authorize";
|
|
366
|
+
} | undefined : {
|
|
367
|
+
readonly authorize: Authorizer<Protected<EventsOf<T>>, RA, EAX, RAX>;
|
|
368
|
+
}): Implemented<T, RequestServices, R, EX, RX, RA, EAX, RAX>;
|
|
369
|
+
export declare function implement<const T extends Target, RequestServices extends (T extends readonly Any[] ? { readonly [K in NamesOf<T>]: unknown; } : never), R = never, EX = never, RX = never>(events: T & TakesNoAuthorize<T>, sources: SourcesOf<T, R, RequestServices> | Effect.Effect<SourcesOf<T, R, RequestServices>, EX, RX>): Implemented<T, RequestServices, R, EX, RX, never, never, never>;
|
|
370
|
+
export { type AnyEventImplementation as AnyImplementation, Events, Gap, type EventImplementation as Implementation, type KeyOptions, type Listed, type LogStorage, type MakeEventsOptions, type RevisionStorage, layerMemory, makeEvents };
|
package/dist/Event.mjs
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Anyone, assertCaller } from "./contract/caller.mjs";
|
|
2
|
+
import { assertEventName, assertOnce } from "./contract/names.mjs";
|
|
3
|
+
import { codecOf } from "./contract/codec.mjs";
|
|
4
|
+
import { authorizerOf } from "./contract/authorizer.mjs";
|
|
5
|
+
import { Events, layerMemory, makeEvents } from "./contract/hub.mjs";
|
|
6
|
+
import { Gap } from "./contract/occurrence.mjs";
|
|
7
|
+
import { EventImplementation, sourcesOf } from "./contract/feed.mjs";
|
|
8
|
+
import { Array as Array$1, Data, Effect, Match, Predicate, Schema } from "effect";
|
|
9
|
+
// src/contract/Event.ts
|
|
10
|
+
const TypeId = "~@gjermundgaraba/effect-actions/Event";
|
|
11
|
+
/** Whether `u` is an event type `make` defined: a binding's list tells events from actions by it. */
|
|
12
|
+
const isEvent = (u) => Predicate.hasProperty(u, TypeId);
|
|
13
|
+
function make(name, options) {
|
|
14
|
+
assertEventName(name);
|
|
15
|
+
const { caller } = options;
|
|
16
|
+
assertCaller(caller);
|
|
17
|
+
if (options.payload === void 0) throw new Error(`Missing payload: event "${name}" (declare what each occurrence carries)`);
|
|
18
|
+
return {
|
|
19
|
+
[TypeId]: TypeId,
|
|
20
|
+
caller,
|
|
21
|
+
name,
|
|
22
|
+
description: options.description,
|
|
23
|
+
input: codecOf(options.input ?? {}),
|
|
24
|
+
payload: codecOf(options.payload)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** The server serves no event type of that name, or no longer does. */
|
|
28
|
+
var NotServed = class extends Schema.TaggedError()("NotServed", {}) {};
|
|
29
|
+
/**
|
|
30
|
+
* The server serves the event type, but not as asked: `feature` names what it does not offer,
|
|
31
|
+
* such as `deliveryMode`, and `value` which one, such as `push`.
|
|
32
|
+
*/
|
|
33
|
+
var Unsupported = class extends Schema.TaggedError()("Unsupported", {
|
|
34
|
+
feature: Schema.String,
|
|
35
|
+
value: Schema.optional(Schema.String)
|
|
36
|
+
}) {};
|
|
37
|
+
/**
|
|
38
|
+
* Why a webhook's callback endpoint failed, in SEP-3415's categories: it refused the connection
|
|
39
|
+
* or was unreachable, timed out, failed TLS, answered a status from 300 to 499 (`http_4xx`, as
|
|
40
|
+
* the categories name no 3xx) or a 5xx, or did not echo the verification challenge.
|
|
41
|
+
*/
|
|
42
|
+
const CallbackCategory = Schema.Literals([
|
|
43
|
+
"connection_refused",
|
|
44
|
+
"timeout",
|
|
45
|
+
"tls_error",
|
|
46
|
+
"http_4xx",
|
|
47
|
+
"http_5xx",
|
|
48
|
+
"challenge_failed"
|
|
49
|
+
]);
|
|
50
|
+
/** A webhook subscription's callback endpoint failed its verification, or was unreachable. */
|
|
51
|
+
var CallbackFailed = class extends Schema.TaggedError()("CallbackFailed", { category: CallbackCategory }) {};
|
|
52
|
+
/** No webhook subscription matches the one an unsubscribe names. */
|
|
53
|
+
var NotSubscribed = class extends Schema.TaggedError()("NotSubscribed", {}) {};
|
|
54
|
+
const Reason = Schema.Union([
|
|
55
|
+
NotServed,
|
|
56
|
+
Unsupported,
|
|
57
|
+
CallbackFailed,
|
|
58
|
+
NotSubscribed
|
|
59
|
+
]);
|
|
60
|
+
const sentenceOf = Match.typeTags()({
|
|
61
|
+
NotServed: () => "is not served",
|
|
62
|
+
Unsupported: ({ feature, value }) => `is not served with this ${feature}${value === void 0 ? "" : `: ${value}`}`,
|
|
63
|
+
CallbackFailed: ({ category }) => `could not reach its webhook's callback: ${category}`,
|
|
64
|
+
NotSubscribed: () => "has no such webhook subscription"
|
|
65
|
+
});
|
|
66
|
+
/**
|
|
67
|
+
* A subscription that cannot start or go on: `reason` says why, so a subscriber branches on it
|
|
68
|
+
* with `Effect.catchReason("SubscriptionError", "NotServed", ...)`; `message` names the event and
|
|
69
|
+
* the reason. A refusal is `Action.Unauthenticated` or `Action.Forbidden`, and input that does not
|
|
70
|
+
* decode `Action.InvalidInput`, as for an action.
|
|
71
|
+
*/
|
|
72
|
+
var SubscriptionError = class SubscriptionError extends Schema.TaggedError()("SubscriptionError", {
|
|
73
|
+
event: Schema.String,
|
|
74
|
+
reason: Reason,
|
|
75
|
+
message: Schema.String
|
|
76
|
+
}, { httpApiStatus: 409 }) {
|
|
77
|
+
/** The error for `event` failing with `reason`, its message built from both. */
|
|
78
|
+
static of(event, reason) {
|
|
79
|
+
return new SubscriptionError({
|
|
80
|
+
event,
|
|
81
|
+
reason,
|
|
82
|
+
message: `Event "${event}" ${sentenceOf(reason)}`
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* A watch delivered by webhook, which `Webhook.delivery` makes: the server POSTs each occurrence
|
|
88
|
+
* to the route `Webhook.layerReceiver` serves in the watching process, reached under `baseUrl`,
|
|
89
|
+
* for as long as the watch is read, each grant asking for `ttl`.
|
|
90
|
+
*/
|
|
91
|
+
var WebhookDelivery = class extends Data.TaggedClass("WebhookDelivery") {};
|
|
92
|
+
/** Every authenticated subscriber may subscribe to a protected event type. */
|
|
93
|
+
const allowAll = () => Effect.void;
|
|
94
|
+
function implement(events, sources, options) {
|
|
95
|
+
const listed = Array$1.ensure(events);
|
|
96
|
+
assertOnce("event", listed);
|
|
97
|
+
const authorizer = authorizerOf({
|
|
98
|
+
singular: "event",
|
|
99
|
+
module: "Event"
|
|
100
|
+
}, listed.some((event) => event.caller !== Anyone), options?.authorize);
|
|
101
|
+
return new EventImplementation(listed, sourcesOf(listed, !Array.isArray(events), sources), authorizer);
|
|
102
|
+
}
|
|
103
|
+
export { CallbackCategory, CallbackFailed, Events, Gap, NotServed, NotSubscribed, SubscriptionError, Unsupported, WebhookDelivery, allowAll, implement, isEvent, layerMemory, make, makeEvents };
|
package/dist/Testing.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Served } from "./testing/memory.mjs";
|
|
2
2
|
import { Layer } from "effect";
|
|
3
3
|
import { HttpClient, HttpRouter } from "effect/http";
|
|
4
|
-
//#region src/testing/Testing.d.ts
|
|
5
4
|
/**
|
|
6
5
|
* The native `HttpClient`, answered by `handler` instead of the network: a web handler the test
|
|
7
6
|
* serves and disposes of, which other tests and raw web `Request`s may share, such as
|
|
@@ -29,5 +28,4 @@ export declare function layer(handler: (request: Request) => Promise<Response>):
|
|
|
29
28
|
* - It never requires `FileSystem`, `Path`, `HttpPlatform` or `Etag.Generator`: one provided around it is the routes', and `HttpServer.layerServices`' defaults stand in for the rest, whose `FileSystem` is a no-op, so a file the routes read is `NotFound` until `NodeFileSystem.layer` is provided around it.
|
|
30
29
|
* - It answers HTTP requests and cannot upgrade a WebSocket: give an rpc layer `RpcServer.layerProtocolHttp` in the test, and its client `RpcClient.layerProtocolHttp` over this layer.
|
|
31
30
|
*/
|
|
32
|
-
export declare function layer<A, E, R>(routes: Layer.Layer<A, E, R>): Layer.Layer<HttpClient.HttpClient, E, Exclude<HttpRouter.Request.Without<R> | HttpRouter.Request.Only<"Requires", R> | HttpRouter.Request.Only<"GlobalRequires", R>, Served>>;
|
|
33
|
-
//#endregion
|
|
31
|
+
export declare function layer<A, E, R>(routes: Layer.Layer<A, E, R>): Layer.Layer<HttpClient.HttpClient, E, Exclude<HttpRouter.Request.Without<R> | HttpRouter.Request.Only<"Requires", R> | HttpRouter.Request.Only<"GlobalRequires", R>, Served>>;
|
package/dist/Testing.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { clientOf } from "./testing/memory.mjs";
|
|
2
2
|
import { Cause, Console, Context, Effect, ErrorReporter, FileSystem, Layer, Option, Path } from "effect";
|
|
3
3
|
import { Etag, HttpEffect, HttpPlatform, HttpRouter } from "effect/http";
|
|
4
|
-
|
|
4
|
+
// src/testing/Testing.ts
|
|
5
|
+
const isReported = (cause) => cause.reasons.some((reason) => Cause.isFailReason(reason) && !ErrorReporter.isIgnored(reason.error) || Cause.isDieReason(reason) && !ErrorReporter.isIgnored(reason.defect));
|
|
5
6
|
function layer(routes) {
|
|
6
7
|
if (!Layer.isLayer(routes)) return clientOf(routes);
|
|
7
8
|
return Layer.unwrap(Effect.gen(function* () {
|
|
@@ -12,6 +13,4 @@ function layer(routes) {
|
|
|
12
13
|
return clientOf(HttpEffect.toWebHandlerWith(context)(Effect.tapCause(app, (cause) => isReported(cause) ? Effect.logError(cause).pipe(Effect.provideService(Console.Console, globalThis.console)) : Effect.void)));
|
|
13
14
|
}));
|
|
14
15
|
}
|
|
15
|
-
const isReported = (cause) => cause.reasons.some((reason) => Cause.isFailReason(reason) && !ErrorReporter.isIgnored(reason.error) || Cause.isDieReason(reason) && !ErrorReporter.isIgnored(reason.defect));
|
|
16
|
-
//#endregion
|
|
17
16
|
export { layer };
|