Skip to content

Commit aaec377

Browse files
committed
fix: missing props in Capability, Bindingm, Resource and Service
1 parent cfb285a commit aaec377

File tree

11 files changed

+90
-68
lines changed

11 files changed

+90
-68
lines changed

alchemy-effect-aws/src/lambda/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
export * from "./consume.ts";
21
export * from "./function.client.ts";
32
export * from "./function.handler.ts";
43
export * from "./function.invoke.ts";
54
export * from "./function.provider.ts";
65
export * from "./function.ts";
76
export * from "./serve.ts";
87

8+
export * from "./consume.ts";
9+
910
export type * from "../account.ts";
1011
export type * from "../region.ts";
1112

alchemy-effect-cli/src/components/Plan.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ export function Plan({ plan }: PlanProps): React.JSX.Element {
2121

2222
if (items.length === 0) {
2323
return <Text color="gray">No changes planned</Text>;
24-
}
25-
24+
}
25+
2626
const counts = items.reduce((acc, item) => (acc[item.action]++, acc), {
2727
create: 0,
2828
update: 0,

alchemy-effect/src/apply.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,9 @@ import * as Effect from "effect/Effect";
33
import * as Option from "effect/Option";
44
import type { Simplify } from "effect/Types";
55
import { PlanReviewer, type PlanRejected } from "./approve.ts";
6-
import type { SerializedBinding } from "./binding.ts";
76
import type { Capability } from "./capability.ts";
87
import type { ApplyEvent, ApplyStatus } from "./event.ts";
9-
import {
10-
isBindNode,
11-
type BindNode,
12-
type CRUD,
13-
type Delete,
14-
type Plan,
15-
} from "./plan.ts";
8+
import { type BindNode, type CRUD, type Delete, type Plan } from "./plan.ts";
169
import type { Resource } from "./resource.ts";
1710
import { State } from "./state.ts";
1811

@@ -57,15 +50,13 @@ export const apply = <P extends Plan, Err, Req>(
5750
const { emit, done } = session;
5851

5952
const apply: (
60-
node: (BindNode | SerializedBinding)[] | CRUD,
53+
node: BindNode[] | CRUD,
6154
) => Effect.Effect<any, never, never> = (node) =>
6255
Effect.gen(function* () {
6356
if (Array.isArray(node)) {
6457
return yield* Effect.all(
6558
node.map((node) => {
66-
const resourceId = isBindNode(node)
67-
? node.binding.capability.resource.id
68-
: node.resource.id;
59+
const resourceId = node.binding.capability.resource.id;
6960
const resource = plan.resources[resourceId];
7061
return !resource
7162
? Effect.dieMessage(`Resource ${resourceId} not found`)

alchemy-effect/src/binding.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as Context from "effect/Context";
22
import type { Effect } from "effect/Effect";
33
import * as Layer from "effect/Layer";
4-
import type { Capability } from "./capability.ts";
4+
import type { Capability, ICapability } from "./capability.ts";
55
import type { Resource } from "./resource.ts";
66
import type { Runtime } from "./runtime.ts";
77

@@ -66,9 +66,20 @@ export const Binding: {
6666
} = (runtime: any, cap: string, tag?: string) => {
6767
const Tag = Context.Tag(`${runtime.type}(${cap}, ${tag ?? cap})`)();
6868
return Object.assign(
69-
() => {
70-
throw new Error(`Not implemented`);
71-
},
69+
(resource: any, props?: any) =>
70+
({
71+
runtime,
72+
capability: {
73+
type: cap,
74+
resource,
75+
constraint: undefined!,
76+
sid: `${cap}${resource.id}`.replace(/[^a-zA-Z0-9]/g, ""),
77+
label: `${cap}(${resource.type})`,
78+
} satisfies ICapability,
79+
props,
80+
isCustom: false,
81+
tag: tag ?? cap,
82+
}) satisfies Binding<any, any, any, string, false>,
7283
{
7384
provider: {
7485
effect: (eff) => Layer.effect(Tag, eff),

alchemy-effect/src/capability.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export interface Capability<
1+
export interface ICapability<
22
Type extends string = string,
33
Resource = unknown,
44
Constraint = unknown,
@@ -7,7 +7,13 @@ export interface Capability<
77
resource: Resource;
88
constraint: Constraint;
99
sid: string;
10-
action: string;
1110
label: string;
11+
}
12+
13+
export interface Capability<
14+
Type extends string = string,
15+
Resource = unknown,
16+
Constraint = unknown,
17+
> extends ICapability<Type, Resource, Constraint> {
1218
new (): {};
1319
}

alchemy-effect/src/provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export type Diff =
2222

2323
type BindingData<Res extends Resource> = [Res] extends [Runtime]
2424
? Res["binding"][]
25-
: undefined;
25+
: any[];
2626

2727
export interface ProviderService<Res extends Resource = Resource> {
2828
// tail();

alchemy-effect/src/resource.ts

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -38,42 +38,52 @@ export const Resource = <Ctor extends (id: string, props: any) => Resource>(
3838
type: ReturnType<Ctor>["type"],
3939
) => {
4040
const Tag = Context.Tag(type)();
41-
return class Resource {
42-
static readonly type = type;
43-
static readonly provider = {
44-
tag: Tag,
45-
effect: <Err, Req>(
46-
eff: Effect<ProviderService<ReturnType<Ctor>>, Err, Req>,
47-
) => Layer.effect(Tag, eff),
48-
succeed: (service: ProviderService<ReturnType<Ctor>>) =>
49-
Layer.succeed(Tag, service),
50-
} as const;
51-
constructor(id: string, props: any) {
52-
if (!new.target) {
53-
return class {
54-
static readonly id = id;
55-
static readonly type = type;
56-
static readonly props = props;
5741

58-
readonly id = id;
59-
readonly type = type;
60-
readonly props = props;
42+
return Object.assign(
43+
function (id: string, props: any) {
44+
return class Resource {
45+
static readonly id = id;
46+
static readonly type = type;
47+
static readonly props = props;
48+
49+
static readonly provider = {
50+
tag: Tag,
51+
effect: <Err, Req>(
52+
eff: Effect<ProviderService<ReturnType<Ctor>>, Err, Req>,
53+
) => Layer.effect(Tag, eff),
54+
succeed: (service: ProviderService<ReturnType<Ctor>>) =>
55+
Layer.succeed(Tag, service),
6156
};
62-
}
63-
}
64-
} as unknown as Ctor & {
65-
type: ReturnType<Ctor>["type"];
66-
new (): ReturnType<Ctor> & {
67-
parent: ReturnType<Ctor>;
68-
};
69-
provider: {
70-
tag: typeof Tag;
71-
effect<Err, Req>(
72-
eff: Effect<ProviderService<ReturnType<Ctor>>, Err, Req>,
73-
): Layer.Layer<Provider<ReturnType<Ctor>>, Err, Req>;
74-
succeed(
75-
service: ProviderService<ReturnType<Ctor>>,
76-
): Layer.Layer<Provider<ReturnType<Ctor>>>;
77-
};
78-
};
57+
58+
readonly id = id;
59+
readonly type = type;
60+
readonly props = props;
61+
};
62+
} as unknown as Ctor & {
63+
type: ReturnType<Ctor>["type"];
64+
new (): ReturnType<Ctor> & {
65+
parent: ReturnType<Ctor>;
66+
};
67+
provider: {
68+
tag: typeof Tag;
69+
effect<Err, Req>(
70+
eff: Effect<ProviderService<ReturnType<Ctor>>, Err, Req>,
71+
): Layer.Layer<Provider<ReturnType<Ctor>>, Err, Req>;
72+
succeed(
73+
service: ProviderService<ReturnType<Ctor>>,
74+
): Layer.Layer<Provider<ReturnType<Ctor>>>;
75+
};
76+
},
77+
{
78+
type: type,
79+
provider: {
80+
tag: Tag,
81+
effect: <Err, Req>(
82+
eff: Effect<ProviderService<ReturnType<Ctor>>, Err, Req>,
83+
) => Layer.effect(Tag, eff),
84+
succeed: (service: ProviderService<ReturnType<Ctor>>) =>
85+
Layer.succeed(Tag, service),
86+
} as const,
87+
},
88+
);
7989
};

alchemy-effect/src/runtime.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ export const Runtime =
8080
};
8181
} => {
8282
const Tag = Context.Tag(type)();
83+
const provider = {
84+
tag: Tag,
85+
effect: (eff: Effect<ProviderService<Self>, any, any>) =>
86+
Layer.effect(Tag, eff),
87+
succeed: (service: ProviderService<Self>) => Layer.succeed(Tag, service),
88+
};
8389
const self = Object.assign(
8490
(
8591
...args:
@@ -114,6 +120,8 @@ export const Runtime =
114120
runtime: self,
115121
// TODO(sam): is this right?
116122
parent: self,
123+
// @ts-expect-error
124+
provider,
117125
} satisfies IService<string, Self, any, any>,
118126
);
119127
}
@@ -123,12 +131,7 @@ export const Runtime =
123131
type: type,
124132
id: undefined! as string,
125133
capability: undefined! as Capability[],
126-
provider: {
127-
effect: (eff: Effect<ProviderService<Self>, any, any>) =>
128-
Layer.effect(Tag, eff),
129-
succeed: (service: ProviderService<Self>) =>
130-
Layer.succeed(Tag, service),
131-
},
134+
provider,
132135
toString() {
133136
return `${this.type}(${this.id}${
134137
this.capability?.length

alchemy-effect/src/service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Resource } from "./resource.ts";
1+
import type { IResource, Resource } from "./resource.ts";
22
import type { Runtime, RuntimeHandler, RuntimeProps } from "./runtime.ts";
33

44
export interface IService<
@@ -7,7 +7,7 @@ export interface IService<
77
Handler extends RuntimeHandler = RuntimeHandler,
88
Props extends RuntimeProps<F, any> = RuntimeProps<F, any>,
99
Attr = (F & { props: Props })["attr"],
10-
> {
10+
> extends IResource<F["type"], ID, Props, Attr> {
1111
kind: "Service";
1212
type: F["type"];
1313
id: ID;

example/alchemy.run.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const stack = await plan.pipe(
2626
Effect.provide(NodeContext.layer),
2727
Effect.provide(FetchHttpClient.layer),
2828
Effect.tap((stack) => Effect.log(stack?.Api.functionUrl)),
29-
Effect.runPromise,
29+
Effect.runPromiseExit,
3030
);
3131

3232
if (stack) {

0 commit comments

Comments
 (0)