effect-encore 0.1.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.
@@ -0,0 +1,67 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { Effect } from "effect";
3
+ import { Activity, DurableDeferred, Workflow } from "effect/unstable/workflow";
4
+ //#region src/workflow.ts
5
+ var workflow_exports = /* @__PURE__ */ __exportAll({
6
+ Activity: () => Activity,
7
+ DurableDeferred: () => DurableDeferred,
8
+ makeWorkflowReceipt: () => makeWorkflowReceipt,
9
+ workflow: () => workflow,
10
+ workflowClient: () => workflowClient,
11
+ workflowHandlers: () => workflowHandlers,
12
+ workflowPoll: () => workflowPoll
13
+ });
14
+ const makeWorkflowReceipt = (workflowName, executionId) => ({
15
+ _tag: "WorkflowReceipt",
16
+ workflowName,
17
+ executionId
18
+ });
19
+ const workflow = (name, options) => {
20
+ const wfOptions = {
21
+ name,
22
+ payload: options.payload,
23
+ idempotencyKey: options.idempotencyKey
24
+ };
25
+ if (options.success) wfOptions["success"] = options.success;
26
+ if (options.error) wfOptions["error"] = options.error;
27
+ return {
28
+ _tag: "WorkflowDefinition",
29
+ name,
30
+ workflow: Workflow.make(wfOptions)
31
+ };
32
+ };
33
+ const workflowClient = (def) => {
34
+ const wf = def.workflow;
35
+ return (_executionId) => ({
36
+ call: (payload) => wf.execute(payload),
37
+ cast: (payload) => Effect.map(wf.execute(payload, { discard: true }), (execId) => makeWorkflowReceipt(def.name, execId)),
38
+ interrupt: () => wf.interrupt(_executionId),
39
+ resume: () => wf.resume(_executionId)
40
+ });
41
+ };
42
+ const workflowPoll = (def, executionId) => {
43
+ const wf = def.workflow;
44
+ return Effect.map(wf.poll(executionId), (optResult) => {
45
+ const opt = optResult;
46
+ if (opt._tag === "None") return { _tag: "Pending" };
47
+ const result = opt.value;
48
+ if (result?._tag === "Suspended") return { _tag: "Suspended" };
49
+ if (result?._tag === "Complete") {
50
+ const exit = result.exit;
51
+ if (exit?._tag === "Success") return {
52
+ _tag: "Success",
53
+ value: exit.value
54
+ };
55
+ return {
56
+ _tag: "Failure",
57
+ error: exit?.cause
58
+ };
59
+ }
60
+ return { _tag: "Pending" };
61
+ });
62
+ };
63
+ const workflowHandlers = (def, handler) => {
64
+ return def.workflow.toLayer(handler);
65
+ };
66
+ //#endregion
67
+ export { Activity, DurableDeferred, makeWorkflowReceipt, workflow, workflowClient, workflowHandlers, workflowPoll, workflow_exports };
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "effect-encore",
3
+ "version": "0.1.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/cevr/effect-encore.git"
7
+ },
8
+ "files": [
9
+ "dist",
10
+ "v3/dist"
11
+ ],
12
+ "type": "module",
13
+ "exports": {
14
+ ".": {
15
+ "import": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ }
19
+ },
20
+ "./v3": {
21
+ "import": {
22
+ "types": "./v3/dist/index.d.ts",
23
+ "default": "./v3/dist/index.js"
24
+ }
25
+ }
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "scripts": {
31
+ "typecheck": "tsgo --noEmit",
32
+ "typecheck:v3": "tsgo --noEmit -p v3/tsconfig.json",
33
+ "lint": "concurrently -n ox,effect -c yellow,blue \"oxlint\" \"bun run lint:effect\"",
34
+ "lint:ox": "oxlint",
35
+ "lint:effect": "effect-language-service diagnostics --project tsconfig.lsp.json",
36
+ "lint:fix": "oxlint --fix",
37
+ "fmt": "oxfmt",
38
+ "fmt:check": "oxfmt --check",
39
+ "test": "bun test",
40
+ "test:v3": "bun test --tsconfig-override=v3/tsconfig.json v3/test/",
41
+ "test:watch": "bun test --watch",
42
+ "gate": "concurrently -n type,style,build,test -c blue,yellow,cyan,green \"bun run typecheck\" \"bun run lint && bun run fmt\" \"bun run build\" \"bun run test\"",
43
+ "build": "tsdown && tsdown --config v3/tsdown.config.ts",
44
+ "release": "bun run build && changeset publish",
45
+ "version": "changeset version",
46
+ "prepare": "lefthook install"
47
+ },
48
+ "devDependencies": {
49
+ "@changesets/changelog-github": "^0.6.0",
50
+ "@changesets/cli": "^2.30.0",
51
+ "@effect/cluster": "^0.56.2",
52
+ "@effect/language-service": "^0.85.1",
53
+ "@effect/rpc": "^0.73.0",
54
+ "@effect/workflow": "^0.18.0",
55
+ "@types/bun": "^1.3.11",
56
+ "@typescript/native-preview": "^7.0.0-dev.20260410.1",
57
+ "concurrently": "^9.2.1",
58
+ "effect": "4.0.0-beta.46",
59
+ "effect-bun-test": "^0.3.0",
60
+ "effect-v3": "npm:effect@^3.21.0",
61
+ "lefthook": "^2.1.4",
62
+ "oxfmt": "^0.42.0",
63
+ "oxlint": "^1.57.0",
64
+ "tsdown": "^0.21.7",
65
+ "typescript": "^5.9.3"
66
+ },
67
+ "peerDependencies": {
68
+ "@effect/cluster": "*",
69
+ "@effect/rpc": "*",
70
+ "@effect/workflow": "*",
71
+ "effect": ">=4.0.0-beta.46"
72
+ },
73
+ "peerDependenciesMeta": {
74
+ "@effect/cluster": {
75
+ "optional": true
76
+ },
77
+ "@effect/rpc": {
78
+ "optional": true
79
+ },
80
+ "@effect/workflow": {
81
+ "optional": true
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll };
@@ -0,0 +1,113 @@
1
+ import { CastReceipt } from "./receipt.js";
2
+ import { Entity, Sharding, ShardingConfig } from "@effect/cluster";
3
+ import { Rpc } from "@effect/rpc";
4
+ import { Context, DateTime, Effect, Layer, Schema, Scope } from "effect";
5
+
6
+ //#region src/actor.d.ts
7
+ interface OperationDef {
8
+ readonly payload?: Schema.Schema.Any | Schema.Struct.Fields;
9
+ readonly success?: Schema.Schema.Any;
10
+ readonly error?: Schema.Schema.Any;
11
+ readonly persisted?: boolean;
12
+ readonly primaryKey?: (payload: never) => string;
13
+ readonly deliverAt?: (payload: never) => DateTime.DateTime;
14
+ }
15
+ type OperationDefs = Record<string, OperationDef>;
16
+ type ReservedKeys = "_tag" | "_meta" | "$is" | "Context";
17
+ type AssertNoReservedKeys<Defs extends OperationDefs> = Extract<keyof Defs, ReservedKeys> extends never ? Defs : never;
18
+ type PayloadOf<C extends OperationDef> = C extends {
19
+ readonly payload: infer P extends Schema.Schema.Any;
20
+ } ? P : C extends {
21
+ readonly payload: infer F extends Schema.Struct.Fields;
22
+ } ? Schema.Struct<F> : typeof Schema.Void;
23
+ type SuccessOf<C extends OperationDef> = C extends {
24
+ readonly success: infer S extends Schema.Schema.Any;
25
+ } ? S : typeof Schema.Void;
26
+ type ErrorOf<C extends OperationDef> = C extends {
27
+ readonly error: infer E extends Schema.Schema.Any;
28
+ } ? E : typeof Schema.Never;
29
+ type DefRpc<Tag extends string, C extends OperationDef> = Rpc.Rpc<Tag, PayloadOf<C>, SuccessOf<C>, ErrorOf<C>>;
30
+ type DefRpcs<Defs extends OperationDefs> = { readonly [Tag in keyof Defs & string]: DefRpc<Tag, Defs[Tag]> }[keyof Defs & string];
31
+ declare const OperationBrandId: unique symbol;
32
+ interface OperationBrand<Name extends string, Tag extends string, Output, Error> {
33
+ readonly [OperationBrandId]: {
34
+ readonly name: Name;
35
+ readonly tag: Tag;
36
+ readonly output: Output;
37
+ readonly error: Error;
38
+ };
39
+ }
40
+ type OperationOutput<V> = V extends {
41
+ readonly [OperationBrandId]: {
42
+ readonly output: infer A;
43
+ };
44
+ } ? A : never;
45
+ type OperationError<V> = V extends {
46
+ readonly [OperationBrandId]: {
47
+ readonly error: infer E;
48
+ };
49
+ } ? E : never;
50
+ type OperationValue<Name extends string, Tag extends string, C extends OperationDef> = {
51
+ readonly _tag: Tag;
52
+ } & PayloadFieldsType<C> & OperationBrand<Name, Tag, Schema.Schema.Type<SuccessOf<C>>, Schema.Schema.Type<ErrorOf<C>>>;
53
+ type PayloadFieldsType<C extends OperationDef> = C extends {
54
+ readonly payload: infer F extends Schema.Struct.Fields;
55
+ } ? { readonly [K in keyof F]: Schema.Schema.Type<F[K] extends Schema.Schema.Any ? F[K] : never> } : C extends {
56
+ readonly payload: infer P extends Schema.Schema.Any;
57
+ } ? Schema.Schema.Type<P> : {};
58
+ type OperationConstructorPayload<C extends OperationDef> = C extends {
59
+ readonly payload: infer F extends Schema.Struct.Fields;
60
+ } ? {} extends { [K in keyof F]: Schema.Schema.Type<F[K] extends Schema.Schema.Any ? F[K] : never> } ? [] : [payload: { readonly [K in keyof F]: Schema.Schema.Type<F[K] extends Schema.Schema.Any ? F[K] : never> }] : C extends {
61
+ readonly payload: infer _P extends Schema.Schema.Any;
62
+ } ? [payload: unknown] : [];
63
+ type OperationConstructor<Name extends string, Tag extends string, C extends OperationDef> = (...args: OperationConstructorPayload<C>) => OperationValue<Name, Tag, C>;
64
+ type OperationUnion<Name extends string, Defs extends OperationDefs> = { [Tag in keyof Defs & string]: OperationValue<Name, Tag, Defs[Tag]> }[keyof Defs & string];
65
+ interface ActorRef<Name extends string, Defs extends OperationDefs> {
66
+ readonly call: <V extends OperationUnion<Name, Defs>>(op: V) => Effect.Effect<OperationOutput<V>, OperationError<V>>;
67
+ readonly cast: <V extends OperationUnion<Name, Defs>>(op: V) => Effect.Effect<CastReceipt>;
68
+ }
69
+ type HandlerRequest<Tag extends string, C extends OperationDef> = {
70
+ readonly operation: {
71
+ readonly _tag: Tag;
72
+ } & PayloadFieldsType<C>;
73
+ readonly request: unknown;
74
+ };
75
+ type ActorHandlers<Defs extends OperationDefs> = { readonly [Tag in keyof Defs & string]: (req: HandlerRequest<Tag, Defs[Tag]>) => Effect.Effect<Schema.Schema.Type<SuccessOf<Defs[Tag]>>, Schema.Schema.Type<ErrorOf<Defs[Tag]>>, any> };
76
+ interface HandlerOptions {
77
+ readonly spanAttributes?: Record<string, string>;
78
+ readonly maxIdleTime?: number;
79
+ readonly concurrency?: number | "unbounded";
80
+ readonly mailboxCapacity?: number | "unbounded";
81
+ }
82
+ interface ActorMeta<Name extends string, Defs extends OperationDefs, Rpcs extends Rpc.Any = DefRpcs<Defs>> {
83
+ readonly name: Name;
84
+ readonly definitions: Defs;
85
+ readonly entity: Entity.Entity<Name, Rpcs>;
86
+ }
87
+ declare const ActorClientServiceId: unique symbol;
88
+ interface ActorClientService<Name extends string, Defs extends OperationDefs> {
89
+ readonly [ActorClientServiceId]: {
90
+ readonly name: Name;
91
+ readonly defs: Defs;
92
+ };
93
+ }
94
+ type ActorConstructors<Name extends string, Defs extends OperationDefs> = { readonly [Tag in keyof Defs & string]: OperationConstructor<Name, Tag, Defs[Tag]> };
95
+ type ActorObject<Name extends string, Defs extends OperationDefs, Rpcs extends Rpc.Any = DefRpcs<Defs>> = ActorConstructors<Name, Defs> & {
96
+ readonly _tag: "ActorObject";
97
+ readonly _meta: ActorMeta<Name, Defs, Rpcs>;
98
+ readonly Context: Context.Tag<ActorClientService<Name, Defs>, (entityId: string) => ActorRef<Name, Defs>>;
99
+ readonly $is: <Tag extends keyof Defs & string>(tag: Tag) => (value: unknown) => value is OperationValue<Name, Tag, Defs[Tag]>;
100
+ };
101
+ declare const Actor: {
102
+ readonly make: <const Name extends string, const Defs extends OperationDefs>(name: Name, definitions: AssertNoReservedKeys<Defs>) => ActorObject<Name, Defs>;
103
+ readonly toLayer: <Name extends string, Defs extends OperationDefs, Rpcs extends Rpc.Any = DefRpcs<Defs>, RX = never>(actor: ActorObject<Name, Defs, Rpcs>, build: ActorHandlers<Defs> | Effect.Effect<ActorHandlers<Defs>, never, RX>, options?: HandlerOptions) => ReturnType<Entity.Entity<Name, Rpcs>["toLayer"]>;
104
+ readonly Live: <Name extends string, Defs extends OperationDefs, Rpcs extends Rpc.Any = DefRpcs<Defs>>(actor: ActorObject<Name, Defs, Rpcs>) => Layer.Layer<ActorClientService<Name, Defs>, never, Scope.Scope | Rpc.MiddlewareClient<Rpcs>>;
105
+ readonly Test: <Name extends string, Defs extends OperationDefs, Rpcs extends Rpc.Any = DefRpcs<Defs>, LA = never, LE = never, LR = never>(actor: ActorObject<Name, Defs, Rpcs>, handlerLayer: Layer.Layer<LA, LE, LR>) => Effect.Effect<(entityId: string) => Effect.Effect<ActorRef<Name, Defs>>, LE, Scope.Scope | ShardingConfig.ShardingConfig | Exclude<LR, Sharding.Sharding> | Rpc.MiddlewareClient<Rpcs>>;
106
+ };
107
+ declare const fromRpcs: <const Name extends string, const Rpcs extends ReadonlyArray<Rpc.Any>>(name: Name, rpcs: Rpcs) => {
108
+ readonly _tag: "RawActorDefinition";
109
+ readonly name: Name;
110
+ readonly entity: Entity.Entity<Name, Rpcs[number]>;
111
+ };
112
+ //#endregion
113
+ export { Actor, ActorMeta, ActorObject, ActorRef, HandlerOptions, OperationBrand, OperationDef, OperationDefs, OperationError, OperationOutput, fromRpcs };
@@ -0,0 +1,127 @@
1
+ import { makeCastReceipt } from "./receipt.js";
2
+ import { ClusterSchema, Entity } from "@effect/cluster";
3
+ import * as DeliverAt from "@effect/cluster/DeliverAt";
4
+ import { Rpc } from "@effect/rpc";
5
+ import { Context, Effect, Layer, PrimaryKey, Schema } from "effect";
6
+ //#region src/actor.ts
7
+ const RESERVED_KEYS = new Set([
8
+ "_tag",
9
+ "_meta",
10
+ "$is",
11
+ "Context"
12
+ ]);
13
+ const compileRpc = (actorName, tag, def) => {
14
+ const options = {};
15
+ const payload = def["payload"];
16
+ const pkFn = def["primaryKey"];
17
+ const daFn = def["deliverAt"];
18
+ if (payload) if (Schema.isSchema(payload)) options["payload"] = payload;
19
+ else {
20
+ const fields = payload;
21
+ const Base = Schema.Class(`effect-encore/${actorName}/${tag}/Payload`)(fields);
22
+ class PayloadClass extends Base {}
23
+ const proto = PayloadClass.prototype;
24
+ if (pkFn) proto[PrimaryKey.symbol] = function() {
25
+ return pkFn(this);
26
+ };
27
+ if (daFn) proto[DeliverAt.symbol] = function() {
28
+ return daFn(this);
29
+ };
30
+ options["payload"] = PayloadClass;
31
+ }
32
+ if (def["success"]) options["success"] = def["success"];
33
+ if (def["error"]) options["error"] = def["error"];
34
+ let rpc = Rpc.make(tag, options);
35
+ if (def["persisted"]) rpc = rpc.annotate(ClusterSchema.Persisted, true);
36
+ return rpc;
37
+ };
38
+ const make = (name, definitions) => {
39
+ for (const tag of Object.keys(definitions)) if (RESERVED_KEYS.has(tag)) throw new Error(`effect-encore: operation "${tag}" collides with reserved property. Reserved: ${[...RESERVED_KEYS].join(", ")}`);
40
+ const rpcs = Object.entries(definitions).map(([tag, def]) => compileRpc(name, tag, def));
41
+ const entity = Entity.make(name, rpcs);
42
+ const constructors = {};
43
+ for (const tag of Object.keys(definitions)) constructors[tag] = (input) => ({
44
+ _tag: tag,
45
+ ...input != null && typeof input === "object" ? input : {}
46
+ });
47
+ const contextTag = Context.GenericTag(`effect-encore/${name}/Client`);
48
+ const $is = (tag) => (value) => value != null && typeof value === "object" && "_tag" in value && value["_tag"] === tag;
49
+ return {
50
+ _tag: "ActorObject",
51
+ _meta: {
52
+ name,
53
+ definitions,
54
+ entity
55
+ },
56
+ Context: contextTag,
57
+ $is,
58
+ ...constructors
59
+ };
60
+ };
61
+ const toLayer = (actor, build, options) => {
62
+ const transformed = transformHandlers(build);
63
+ return actor._meta.entity.toLayer(transformed, {
64
+ spanAttributes: options?.spanAttributes,
65
+ maxIdleTime: options?.maxIdleTime,
66
+ concurrency: options?.concurrency,
67
+ mailboxCapacity: options?.mailboxCapacity
68
+ });
69
+ };
70
+ const Live = (actor) => Layer.effect(actor.Context, Effect.map(actor._meta.entity.client, (makeClient) => (entityId) => buildActorRef(actor._meta.name, entityId, actor._meta.definitions, makeClient(entityId))));
71
+ const Test = (actor, handlerLayer) => Effect.map(Entity.makeTestClient(actor._meta.entity, handlerLayer), (makeClient) => (entityId) => Effect.map(makeClient(entityId), (rpcClient) => buildActorRef(actor._meta.name, entityId, actor._meta.definitions, rpcClient)));
72
+ const transformHandlers = (build) => {
73
+ if (build != null && typeof build === "object" && !Effect.isEffect(build)) {
74
+ const handlers = build;
75
+ const transformed = {};
76
+ for (const tag of Object.keys(handlers)) {
77
+ const handler = handlers[tag];
78
+ if (!handler) continue;
79
+ transformed[tag] = (request) => {
80
+ return handler({
81
+ operation: {
82
+ _tag: tag,
83
+ ...request["payload"] ?? {}
84
+ },
85
+ request
86
+ });
87
+ };
88
+ }
89
+ return transformed;
90
+ }
91
+ return Effect.map(build, transformHandlers);
92
+ };
93
+ const buildActorRef = (actorName, entityId, definitions, rpcClient) => {
94
+ const client = rpcClient;
95
+ return {
96
+ call: (op) => {
97
+ const tag = op["_tag"];
98
+ const fn = client[tag];
99
+ return definitions[tag]?.["payload"] !== void 0 ? fn?.(op) : fn?.();
100
+ },
101
+ cast: (op) => {
102
+ const tag = op["_tag"];
103
+ const fn = client[tag];
104
+ const def = definitions[tag];
105
+ const discardCall = def?.["payload"] !== void 0 ? fn?.(op, { discard: true }) : fn?.(void 0, { discard: true });
106
+ return Effect.map(discardCall ?? Effect.void, () => makeCastReceipt({
107
+ actorType: actorName,
108
+ entityId,
109
+ operation: tag,
110
+ primaryKey: def?.["primaryKey"] ? def["primaryKey"](op) : void 0
111
+ }));
112
+ }
113
+ };
114
+ };
115
+ const Actor = {
116
+ make,
117
+ toLayer,
118
+ Live,
119
+ Test
120
+ };
121
+ const fromRpcs = (name, rpcs) => ({
122
+ _tag: "RawActorDefinition",
123
+ name,
124
+ entity: Entity.make(name, rpcs)
125
+ });
126
+ //#endregion
127
+ export { Actor, fromRpcs };
@@ -0,0 +1,2 @@
1
+ import { ActorRef, OperationError, OperationOutput } from "./actor.js";
2
+ export { type ActorRef, type OperationError, type OperationOutput };
File without changes
@@ -0,0 +1,2 @@
1
+ import { HandlerOptions } from "./actor.js";
2
+ export { type HandlerOptions };
File without changes
@@ -0,0 +1,6 @@
1
+ import { CastReceipt, Defect, Failure, Interrupted, PeekResult, Pending, Success, isFailure, isPending, isSuccess, isTerminal, makeCastReceipt } from "./receipt.js";
2
+ import { Actor, ActorMeta, ActorObject, ActorRef, HandlerOptions, OperationBrand, OperationDef, OperationDefs, OperationError, OperationOutput, fromRpcs } from "./actor.js";
3
+ import { NoPrimaryKeyError, peek, watch } from "./peek.js";
4
+ import { observability_d_exports } from "./observability.js";
5
+ import { workflow_d_exports } from "./workflow.js";
6
+ export { Actor, type ActorMeta, type ActorObject, type ActorRef, CastReceipt, Defect, Failure, type HandlerOptions, Interrupted, NoPrimaryKeyError, observability_d_exports as Observability, type OperationBrand, type OperationDef, type OperationDefs, type OperationError, type OperationOutput, type PeekResult, Pending, Success, workflow_d_exports as Workflow, fromRpcs, isFailure, isPending, isSuccess, isTerminal, makeCastReceipt, peek, watch };
@@ -0,0 +1,6 @@
1
+ import { CastReceipt, Defect, Failure, Interrupted, Pending, Success, isFailure, isPending, isSuccess, isTerminal, makeCastReceipt } from "./receipt.js";
2
+ import { Actor, fromRpcs } from "./actor.js";
3
+ import { NoPrimaryKeyError, peek, watch } from "./peek.js";
4
+ import { observability_exports } from "./observability.js";
5
+ import { workflow_exports } from "./workflow.js";
6
+ export { Actor, CastReceipt, Defect, Failure, Interrupted, NoPrimaryKeyError, observability_exports as Observability, Pending, Success, workflow_exports as Workflow, fromRpcs, isFailure, isPending, isSuccess, isTerminal, makeCastReceipt, peek, watch };
@@ -0,0 +1,9 @@
1
+ import { CurrentAddress } from "@effect/cluster/Entity";
2
+
3
+ //#region src/observability.d.ts
4
+ declare namespace observability_d_exports {
5
+ export { CurrentAddress, defaultSpanAttributes };
6
+ }
7
+ declare const defaultSpanAttributes: (actorName: string) => Record<string, string>;
8
+ //#endregion
9
+ export { CurrentAddress, defaultSpanAttributes, observability_d_exports };
@@ -0,0 +1,13 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { CurrentAddress } from "@effect/cluster/Entity";
3
+ //#region src/observability.ts
4
+ var observability_exports = /* @__PURE__ */ __exportAll({
5
+ CurrentAddress: () => CurrentAddress,
6
+ defaultSpanAttributes: () => defaultSpanAttributes
7
+ });
8
+ const defaultSpanAttributes = (actorName) => ({
9
+ "actor.name": actorName,
10
+ "actor.library": "effect-encore"
11
+ });
12
+ //#endregion
13
+ export { CurrentAddress, defaultSpanAttributes, observability_exports };
@@ -0,0 +1,19 @@
1
+ import { CastReceipt, PeekResult } from "./receipt.js";
2
+ import { ActorObject, OperationDefs } from "./actor.js";
3
+ import { MessageStorage, Sharding } from "@effect/cluster";
4
+ import { Duration, Effect, Stream } from "effect";
5
+ import { MalformedMessage, PersistenceError } from "@effect/cluster/ClusterError";
6
+
7
+ //#region src/peek.d.ts
8
+ declare class NoPrimaryKeyError {
9
+ readonly receipt: CastReceipt;
10
+ readonly _tag = "NoPrimaryKeyError";
11
+ readonly message: string;
12
+ constructor(receipt: CastReceipt);
13
+ }
14
+ declare const peek: <Name extends string, Defs extends OperationDefs>(actor: ActorObject<Name, Defs>, receipt: CastReceipt) => Effect.Effect<PeekResult, PersistenceError | MalformedMessage | NoPrimaryKeyError, MessageStorage.MessageStorage | Sharding.Sharding>;
15
+ declare const watch: <Name extends string, Defs extends OperationDefs>(actor: ActorObject<Name, Defs>, receipt: CastReceipt, options?: {
16
+ readonly interval?: Duration.DurationInput;
17
+ }) => Stream.Stream<PeekResult, PersistenceError | MalformedMessage | NoPrimaryKeyError, MessageStorage.MessageStorage | Sharding.Sharding>;
18
+ //#endregion
19
+ export { NoPrimaryKeyError, peek, watch };
@@ -0,0 +1,72 @@
1
+ import { Defect, Failure, Interrupted, Pending, Success, isTerminal } from "./receipt.js";
2
+ import { EntityAddress, EntityId, MessageStorage, Sharding } from "@effect/cluster";
3
+ import { Duration, Effect, Option, Schedule, Stream } from "effect";
4
+ //#region src/peek.ts
5
+ var NoPrimaryKeyError = class {
6
+ constructor(receipt) {
7
+ this.receipt = receipt;
8
+ this._tag = "NoPrimaryKeyError";
9
+ this.message = `Cannot peek receipt for ${receipt.actorType}.${receipt.operation}: no primaryKey defined on operation`;
10
+ }
11
+ };
12
+ const peek = (actor, receipt) => {
13
+ const op = actor._meta.definitions[receipt.operation];
14
+ if (!op || !op["primaryKey"] || !receipt.primaryKey) return Effect.fail(new NoPrimaryKeyError(receipt));
15
+ const primaryKey = receipt.primaryKey;
16
+ return Effect.gen(function* () {
17
+ const sharding = yield* Sharding.Sharding;
18
+ const storage = yield* MessageStorage.MessageStorage;
19
+ const entityId = EntityId.make(receipt.entityId);
20
+ const group = actor._meta.entity.getShardGroup(entityId);
21
+ const shardId = sharding.getShardId(entityId, group);
22
+ const address = EntityAddress.make({
23
+ entityType: actor._meta.name,
24
+ entityId,
25
+ shardId
26
+ });
27
+ const maybeRequestId = yield* storage.requestIdForPrimaryKey({
28
+ address,
29
+ tag: receipt.operation,
30
+ id: primaryKey
31
+ });
32
+ if (Option.isNone(maybeRequestId)) return Pending;
33
+ const replies = yield* storage.repliesForUnfiltered([maybeRequestId.value]);
34
+ const last = replies[replies.length - 1];
35
+ if (!last || last._tag !== "WithExit") return Pending;
36
+ return mapCauseEncodedToPeekResult(last.exit);
37
+ });
38
+ };
39
+ const watch = (actor, receipt, options) => {
40
+ const interval = options?.interval ?? Duration.millis(200);
41
+ return Stream.repeatEffectWithSchedule(peek(actor, receipt), Schedule.spaced(interval)).pipe(Stream.changesWith(peekResultEquals), Stream.takeUntil(isTerminal));
42
+ };
43
+ const peekResultEquals = (a, b) => {
44
+ if (a._tag !== b._tag) return false;
45
+ if (a._tag === "Success" && b._tag === "Success") return a.value === b.value;
46
+ if (a._tag === "Failure" && b._tag === "Failure") return a.error === b.error;
47
+ if (a._tag === "Defect" && b._tag === "Defect") return a.cause === b.cause;
48
+ return true;
49
+ };
50
+ const mapCauseEncodedToPeekResult = (exit) => {
51
+ if (exit._tag === "Success") return Success(exit.value);
52
+ const first = findFirstCause(exit.cause);
53
+ if (!first) return Pending;
54
+ switch (first._tag) {
55
+ case "Fail": return Failure(first.error);
56
+ case "Die": return Defect(first.defect);
57
+ case "Interrupt": return Interrupted;
58
+ default: return Pending;
59
+ }
60
+ };
61
+ const findFirstCause = (cause) => {
62
+ switch (cause._tag) {
63
+ case "Fail":
64
+ case "Die":
65
+ case "Interrupt": return cause;
66
+ case "Empty": return null;
67
+ case "Sequential":
68
+ case "Parallel": return findFirstCause(cause.left) ?? findFirstCause(cause.right);
69
+ }
70
+ };
71
+ //#endregion
72
+ export { NoPrimaryKeyError, peek, watch };
@@ -0,0 +1,66 @@
1
+ import { Schema } from "effect";
2
+
3
+ //#region src/receipt.d.ts
4
+ declare const CastReceipt_base: Schema.Class<CastReceipt, {
5
+ _tag: Schema.Literal<["CastReceipt"]>;
6
+ actorType: typeof Schema.String;
7
+ entityId: typeof Schema.String;
8
+ operation: typeof Schema.String;
9
+ primaryKey: Schema.optional<typeof Schema.String>;
10
+ }, Schema.Struct.Encoded<{
11
+ _tag: Schema.Literal<["CastReceipt"]>;
12
+ actorType: typeof Schema.String;
13
+ entityId: typeof Schema.String;
14
+ operation: typeof Schema.String;
15
+ primaryKey: Schema.optional<typeof Schema.String>;
16
+ }>, never, {
17
+ readonly _tag: "CastReceipt";
18
+ } & {
19
+ readonly actorType: string;
20
+ } & {
21
+ readonly entityId: string;
22
+ } & {
23
+ readonly operation: string;
24
+ } & {
25
+ readonly primaryKey?: string;
26
+ }, {}, {}>;
27
+ declare class CastReceipt extends CastReceipt_base {}
28
+ declare const makeCastReceipt: (options: {
29
+ readonly actorType: string;
30
+ readonly entityId: string;
31
+ readonly operation: string;
32
+ readonly primaryKey?: string | undefined;
33
+ }) => CastReceipt;
34
+ type PeekResult<A = unknown, E = unknown> = {
35
+ readonly _tag: "Pending";
36
+ } | {
37
+ readonly _tag: "Success";
38
+ readonly value: A;
39
+ } | {
40
+ readonly _tag: "Failure";
41
+ readonly error: E;
42
+ } | {
43
+ readonly _tag: "Interrupted";
44
+ } | {
45
+ readonly _tag: "Defect";
46
+ readonly cause: unknown;
47
+ };
48
+ declare const Pending: PeekResult;
49
+ declare const Success: <A>(value: A) => PeekResult<A, never>;
50
+ declare const Failure: <E>(error: E) => PeekResult<never, E>;
51
+ declare const Interrupted: PeekResult;
52
+ declare const Defect: (cause: unknown) => PeekResult;
53
+ declare const isPending: <A, E>(result: PeekResult<A, E>) => result is {
54
+ _tag: "Pending";
55
+ };
56
+ declare const isSuccess: <A, E>(result: PeekResult<A, E>) => result is {
57
+ _tag: "Success";
58
+ value: A;
59
+ };
60
+ declare const isFailure: <A, E>(result: PeekResult<A, E>) => result is {
61
+ _tag: "Failure";
62
+ error: E;
63
+ };
64
+ declare const isTerminal: <A, E>(result: PeekResult<A, E>) => boolean;
65
+ //#endregion
66
+ export { CastReceipt, Defect, Failure, Interrupted, PeekResult, Pending, Success, isFailure, isPending, isSuccess, isTerminal, makeCastReceipt };
@@ -0,0 +1,36 @@
1
+ import { Schema } from "effect";
2
+ //#region src/receipt.ts
3
+ var CastReceipt = class extends Schema.Class("effect-encore/CastReceipt")({
4
+ _tag: Schema.Literal("CastReceipt"),
5
+ actorType: Schema.String,
6
+ entityId: Schema.String,
7
+ operation: Schema.String,
8
+ primaryKey: Schema.optional(Schema.String)
9
+ }) {};
10
+ const makeCastReceipt = (options) => new CastReceipt({
11
+ _tag: "CastReceipt",
12
+ actorType: options.actorType,
13
+ entityId: options.entityId,
14
+ operation: options.operation,
15
+ primaryKey: options.primaryKey
16
+ });
17
+ const Pending = { _tag: "Pending" };
18
+ const Success = (value) => ({
19
+ _tag: "Success",
20
+ value
21
+ });
22
+ const Failure = (error) => ({
23
+ _tag: "Failure",
24
+ error
25
+ });
26
+ const Interrupted = { _tag: "Interrupted" };
27
+ const Defect = (cause) => ({
28
+ _tag: "Defect",
29
+ cause
30
+ });
31
+ const isPending = (result) => result._tag === "Pending";
32
+ const isSuccess = (result) => result._tag === "Success";
33
+ const isFailure = (result) => result._tag === "Failure";
34
+ const isTerminal = (result) => result._tag !== "Pending";
35
+ //#endregion
36
+ export { CastReceipt, Defect, Failure, Interrupted, Pending, Success, isFailure, isPending, isSuccess, isTerminal, makeCastReceipt };
@@ -0,0 +1,2 @@
1
+ import { ActorRef } from "./actor.js";
2
+ export { type ActorRef };
File without changes