alchemy 2.0.0-beta.2 → 2.0.0-beta.test-export-fix-3

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.
Files changed (65) hide show
  1. package/bin/{alchemy-effect.js → alchemy.js} +173 -173
  2. package/bin/alchemy.js.map +1 -0
  3. package/bin/{alchemy-effect.sh → alchemy.sh} +2 -2
  4. package/lib/cli/index.js +169 -169
  5. package/lib/cli/index.js.map +1 -1
  6. package/package.json +75 -67
  7. package/src/AWS/AGENTS.md +10 -10
  8. package/src/AWS/Assets.ts +1 -1
  9. package/src/AWS/Credentials.ts +0 -1
  10. package/src/AWS/DynamoDB/Table.ts +63 -10
  11. package/src/AWS/EC2/hosted.ts +1 -1
  12. package/src/AWS/ECS/Task.ts +1 -1
  13. package/src/AWS/Kinesis/Stream.ts +44 -8
  14. package/src/AWS/Lambda/Function.ts +218 -10
  15. package/src/AWS/S3/Bucket.ts +26 -19
  16. package/src/AWS/S3/BucketNotifications.ts +1 -1
  17. package/src/AWS/SNS/Topic.ts +47 -10
  18. package/src/AWS/SQS/Queue.ts +66 -0
  19. package/src/Cloudflare/Container/Container.ts +122 -0
  20. package/src/Cloudflare/Container/ContainerApplication.ts +6 -3
  21. package/src/Cloudflare/Container/ContainerBinding.ts +2 -4
  22. package/src/Cloudflare/Container/StartContainer.ts +1 -1
  23. package/src/Cloudflare/D1/D1Database.ts +23 -4
  24. package/src/Cloudflare/KV/KVNamespace.ts +25 -0
  25. package/src/Cloudflare/Providers.ts +1 -6
  26. package/src/Cloudflare/R2/R2Bucket.ts +45 -2
  27. package/src/Cloudflare/Website/StaticSite.ts +79 -6
  28. package/src/Cloudflare/Website/Vite.ts +67 -13
  29. package/src/Cloudflare/Workers/Assets.ts +170 -207
  30. package/src/Cloudflare/Workers/DurableObjectNamespace.ts +629 -0
  31. package/src/Cloudflare/Workers/DurableObjectState.ts +63 -0
  32. package/src/Cloudflare/Workers/DurableObjectStorage.ts +256 -0
  33. package/src/Cloudflare/Workers/DynamicWorkerLoader.ts +66 -7
  34. package/src/Cloudflare/Workers/InferEnv.ts +11 -7
  35. package/src/Cloudflare/Workers/Rpc.ts +13 -2
  36. package/src/Cloudflare/Workers/ScheduledEvents.ts +185 -0
  37. package/src/Cloudflare/Workers/WebSocket.ts +1 -1
  38. package/src/Cloudflare/Workers/Worker.ts +406 -49
  39. package/src/Cloudflare/Workers/Workflow.ts +53 -11
  40. package/src/Cloudflare/Workers/index.ts +4 -1
  41. package/src/Construct.ts +2 -2
  42. package/src/GitHub/Comment.ts +224 -0
  43. package/src/GitHub/Secret.ts +257 -0
  44. package/src/GitHub/Variable.ts +166 -0
  45. package/src/GitHub/index.ts +3 -0
  46. package/src/Kubernetes/client.ts +2 -2
  47. package/src/Output.ts +1 -1
  48. package/src/Platform.ts +1 -1
  49. package/src/Provider.ts +1 -1
  50. package/src/Test/Vitest.ts +4 -3
  51. package/src/Util/PlatformServices.ts +21 -0
  52. package/src/Util/dedent.ts +59 -0
  53. package/src/Util/index.ts +1 -0
  54. package/bin/alchemy-effect.js.map +0 -1
  55. package/src/Cloudflare/Workers/DurableObject.ts +0 -527
  56. package/src/Daemon/Client.ts +0 -116
  57. package/src/Daemon/Config.ts +0 -28
  58. package/src/Daemon/Errors.ts +0 -48
  59. package/src/Daemon/Lock.ts +0 -162
  60. package/src/Daemon/ProcessRegistry.ts +0 -284
  61. package/src/Daemon/RpcSchema.ts +0 -43
  62. package/src/Daemon/RpcServer.ts +0 -231
  63. package/src/Daemon/index.ts +0 -27
  64. package/src/Spawn.ts +0 -23
  65. /package/bin/{alchemy-effect.ts → alchemy.ts} +0 -0
package/src/Construct.ts CHANGED
@@ -12,8 +12,8 @@ import * as Namespace from "./Namespace.ts";
12
12
  * @section Creating Constructs
13
13
  * @example Simple Reusable Construct
14
14
  * ```typescript
15
- * import * as Construct from "alchemy-effect/Construct";
16
- * import { Bucket } from "alchemy-effect/AWS/S3";
15
+ * import * as Construct from "alchemy/Construct";
16
+ * import { Bucket } from "alchemy/AWS/S3";
17
17
  *
18
18
  * export const Logs = Construct.fn(function* (
19
19
  * id: string,
@@ -0,0 +1,224 @@
1
+ import { Octokit } from "@octokit/rest";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Provider from "../Provider.ts";
4
+ import { Resource } from "../Resource.ts";
5
+ import { dedent } from "../Util/dedent.ts";
6
+
7
+ export interface CommentProps {
8
+ /**
9
+ * Repository owner (user or organization).
10
+ */
11
+ owner: string;
12
+
13
+ /**
14
+ * Repository name.
15
+ */
16
+ repository: string;
17
+
18
+ /**
19
+ * Issue or Pull Request number to comment on.
20
+ */
21
+ issueNumber: number;
22
+
23
+ /**
24
+ * Comment body (supports GitHub Markdown).
25
+ *
26
+ * The body is automatically dedented, so you can use indented template
27
+ * literals without worrying about leading whitespace. Accepts
28
+ * `Output<string>` at the call site via `Output.interpolate` to embed
29
+ * resource attributes that are not yet resolved.
30
+ */
31
+ body: string;
32
+
33
+ /**
34
+ * Whether to allow deletion of the comment when the resource is destroyed.
35
+ * By default, comments are never deleted to preserve discussion history.
36
+ * @default false
37
+ */
38
+ allowDelete?: boolean;
39
+
40
+ /**
41
+ * GitHub API token. If not provided, falls back to
42
+ * `GITHUB_ACCESS_TOKEN` or `GITHUB_TOKEN` environment variables.
43
+ */
44
+ token?: string;
45
+ }
46
+
47
+ export interface Comment extends Resource<
48
+ "GitHub.Comment",
49
+ CommentProps,
50
+ {
51
+ /**
52
+ * The numeric ID of the comment in GitHub.
53
+ */
54
+ commentId: number;
55
+
56
+ /**
57
+ * URL to view the comment in a browser.
58
+ */
59
+ htmlUrl: string;
60
+
61
+ /**
62
+ * ISO-8601 timestamp of the last update.
63
+ */
64
+ updatedAt: string;
65
+ }
66
+ > {}
67
+
68
+ /**
69
+ * A GitHub issue or pull request comment.
70
+ *
71
+ * `Comment` manages the lifecycle of a single comment on an issue or pull
72
+ * request. Comments are created on the first deploy and updated in place on
73
+ * subsequent deploys when the `body` changes. By default, comments are never
74
+ * deleted to preserve discussion history — set `allowDelete: true` to opt in.
75
+ *
76
+ * Authentication is resolved in order: explicit `token` prop,
77
+ * `GITHUB_ACCESS_TOKEN` env var, `GITHUB_TOKEN` env var. The token needs
78
+ * `repo` scope for private repositories or `public_repo` for public ones.
79
+ *
80
+ * @section Creating Comments
81
+ * @example Comment on an Issue
82
+ * ```typescript
83
+ * const comment = yield* GitHub.Comment("issue-comment", {
84
+ * owner: "my-org",
85
+ * repository: "my-repo",
86
+ * issueNumber: 123,
87
+ * body: "This is a comment created by Alchemy!",
88
+ * });
89
+ * ```
90
+ *
91
+ * @example Comment on a Pull Request
92
+ * ```typescript
93
+ * const prComment = yield* GitHub.Comment("pr-comment", {
94
+ * owner: "my-org",
95
+ * repository: "my-repo",
96
+ * issueNumber: 456,
97
+ * body: "## Deployment Status\n\nSuccessfully deployed to staging!",
98
+ * });
99
+ * ```
100
+ *
101
+ * @section Updating Comments
102
+ * Deploy with the same logical ID and a different `body` to update the
103
+ * existing comment in place rather than creating a new one.
104
+ *
105
+ * @example Update Comment Content
106
+ * ```typescript
107
+ * const comment = yield* GitHub.Comment("status-comment", {
108
+ * owner: "my-org",
109
+ * repository: "my-repo",
110
+ * issueNumber: 789,
111
+ * body: "Deployment completed successfully!",
112
+ * });
113
+ * ```
114
+ *
115
+ * @section Deleting Comments
116
+ * @example Allow Comment Deletion
117
+ * ```typescript
118
+ * const comment = yield* GitHub.Comment("temp-comment", {
119
+ * owner: "my-org",
120
+ * repository: "my-repo",
121
+ * issueNumber: 123,
122
+ * body: "This comment can be deleted",
123
+ * allowDelete: true,
124
+ * });
125
+ * ```
126
+ *
127
+ * @section CI Preview Comments
128
+ * A common pattern is posting a preview-deployment URL on every pull request.
129
+ * The comment auto-updates on each push because the logical ID stays the same.
130
+ *
131
+ * @example PR Preview Comment
132
+ * ```typescript
133
+ * if (process.env.PULL_REQUEST) {
134
+ * yield* GitHub.Comment("preview-comment", {
135
+ * owner: "my-org",
136
+ * repository: "my-repo",
137
+ * issueNumber: Number(process.env.PULL_REQUEST),
138
+ * body: Output.interpolate`
139
+ * ## Preview Deployed
140
+ *
141
+ * **URL:** ${website.url}
142
+ * `,
143
+ * });
144
+ * }
145
+ * ```
146
+ */
147
+ export const Comment = Resource<Comment>("GitHub.Comment");
148
+
149
+ function resolveToken(props: CommentProps): string | undefined {
150
+ return (
151
+ props.token ?? process.env.GITHUB_ACCESS_TOKEN ?? process.env.GITHUB_TOKEN
152
+ );
153
+ }
154
+
155
+ function createClient(props: CommentProps): Octokit {
156
+ return new Octokit({ auth: resolveToken(props) });
157
+ }
158
+
159
+ export const CommentProvider = () =>
160
+ Provider.succeed(Comment, {
161
+ stables: ["commentId"],
162
+
163
+ create: Effect.fn(function* ({ news }) {
164
+ const octokit = createClient(news);
165
+ const body = dedent(news.body);
166
+
167
+ const { data } = yield* Effect.tryPromise(() =>
168
+ octokit.rest.issues.createComment({
169
+ owner: news.owner,
170
+ repo: news.repository,
171
+ issue_number: news.issueNumber,
172
+ body,
173
+ }),
174
+ );
175
+
176
+ return {
177
+ commentId: data.id,
178
+ htmlUrl: data.html_url,
179
+ updatedAt: data.updated_at,
180
+ };
181
+ }),
182
+
183
+ update: Effect.fn(function* ({ news, output }) {
184
+ const octokit = createClient(news);
185
+ const body = dedent(news.body);
186
+
187
+ const { data } = yield* Effect.tryPromise(() =>
188
+ octokit.rest.issues.updateComment({
189
+ owner: news.owner,
190
+ repo: news.repository,
191
+ comment_id: output.commentId,
192
+ body,
193
+ }),
194
+ );
195
+
196
+ return {
197
+ commentId: data.id,
198
+ htmlUrl: data.html_url,
199
+ updatedAt: data.updated_at,
200
+ };
201
+ }),
202
+
203
+ delete: Effect.fn(function* ({ olds, output }) {
204
+ if (!olds.allowDelete) {
205
+ return;
206
+ }
207
+
208
+ const octokit = createClient(olds);
209
+
210
+ yield* Effect.tryPromise(async () => {
211
+ try {
212
+ await octokit.rest.issues.deleteComment({
213
+ owner: olds.owner,
214
+ repo: olds.repository,
215
+ comment_id: output.commentId,
216
+ });
217
+ } catch (error: any) {
218
+ if (error.status !== 404) {
219
+ throw error;
220
+ }
221
+ }
222
+ });
223
+ }),
224
+ });
@@ -0,0 +1,257 @@
1
+ import { Octokit } from "@octokit/rest";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Redacted from "effect/Redacted";
4
+ import * as Provider from "../Provider.ts";
5
+ import { Resource } from "../Resource.ts";
6
+
7
+ export interface SecretProps {
8
+ /**
9
+ * Repository owner (user or organization).
10
+ */
11
+ owner: string;
12
+
13
+ /**
14
+ * Repository name.
15
+ */
16
+ repository: string;
17
+
18
+ /**
19
+ * Secret name (e.g. `AWS_ROLE_ARN`).
20
+ */
21
+ name: string;
22
+
23
+ /**
24
+ * Secret value. Wrap with `Redacted.make` to prevent the value from
25
+ * appearing in logs or state.
26
+ */
27
+ value: Redacted.Redacted;
28
+
29
+ /**
30
+ * Optional environment name. When set the secret is scoped to that
31
+ * GitHub Actions environment instead of the whole repository.
32
+ */
33
+ environment?: string;
34
+
35
+ /**
36
+ * GitHub API token. If not provided, falls back to
37
+ * `GITHUB_ACCESS_TOKEN` or `GITHUB_TOKEN` environment variables.
38
+ */
39
+ token?: string;
40
+ }
41
+
42
+ export interface Secret extends Resource<
43
+ "GitHub.Secret",
44
+ SecretProps,
45
+ {
46
+ /**
47
+ * ISO-8601 timestamp of the last update.
48
+ */
49
+ updatedAt: string;
50
+ }
51
+ > {}
52
+
53
+ /**
54
+ * A GitHub Actions repository or environment secret.
55
+ *
56
+ * `Secret` manages the lifecycle of an encrypted secret in GitHub Actions.
57
+ * Secrets are encrypted using the repository's (or environment's) public
58
+ * key via `libsodium` before being stored. The resource is idempotent —
59
+ * calling it with the same name will update the secret value in place.
60
+ *
61
+ * Authentication is resolved in order: explicit `token` prop,
62
+ * `GITHUB_ACCESS_TOKEN` env var, `GITHUB_TOKEN` env var. The token needs
63
+ * `repo` scope for private repositories or `public_repo` for public ones.
64
+ *
65
+ * @section Repository Secrets
66
+ * Store secrets accessible to all GitHub Actions workflows in the
67
+ * repository.
68
+ *
69
+ * @example Create a Repository Secret
70
+ * ```typescript
71
+ * yield* GitHub.Secret("aws-role", {
72
+ * owner: "my-org",
73
+ * repository: "my-repo",
74
+ * name: "AWS_ROLE_ARN",
75
+ * value: Redacted.make(role.roleArn),
76
+ * });
77
+ * ```
78
+ *
79
+ * @section Environment Secrets
80
+ * Scope a secret to a specific GitHub Actions environment (e.g.
81
+ * `production`, `staging`). Environment secrets require environment
82
+ * protection rules to be satisfied before workflows can access them.
83
+ *
84
+ * @example Create an Environment Secret
85
+ * ```typescript
86
+ * yield* GitHub.Secret("deploy-key", {
87
+ * owner: "my-org",
88
+ * repository: "my-repo",
89
+ * environment: "production",
90
+ * name: "DEPLOY_KEY",
91
+ * value: Redacted.make("my-secret-value"),
92
+ * });
93
+ * ```
94
+ *
95
+ * @section Wiring with Other Resources
96
+ * A common pattern is wiring the output of another resource — like an
97
+ * IAM role ARN or a database URL — directly into a GitHub secret so
98
+ * that CI workflows can use it.
99
+ *
100
+ * @example Store an IAM Role ARN for CI
101
+ * ```typescript
102
+ * const role = yield* AWS.IAM.Role("ci-role", { ... });
103
+ *
104
+ * yield* GitHub.Secret("ci-role-arn", {
105
+ * owner: "my-org",
106
+ * repository: "my-repo",
107
+ * name: "AWS_ROLE_ARN",
108
+ * value: Redacted.make(role.roleArn),
109
+ * });
110
+ * ```
111
+ *
112
+ * @example Store Multiple Secrets
113
+ * ```typescript
114
+ * yield* GitHub.Secret("db-url", {
115
+ * owner: "my-org",
116
+ * repository: "my-repo",
117
+ * environment: "production",
118
+ * name: "DATABASE_URL",
119
+ * value: Redacted.make(database.connectionString),
120
+ * });
121
+ *
122
+ * yield* GitHub.Secret("api-key", {
123
+ * owner: "my-org",
124
+ * repository: "my-repo",
125
+ * environment: "production",
126
+ * name: "API_KEY",
127
+ * value: Redacted.make(apiKey),
128
+ * });
129
+ * ```
130
+ */
131
+ export const Secret = Resource<Secret>("GitHub.Secret");
132
+
133
+ function resolveToken(props: SecretProps): string | undefined {
134
+ return (
135
+ props.token ?? process.env.GITHUB_ACCESS_TOKEN ?? process.env.GITHUB_TOKEN
136
+ );
137
+ }
138
+
139
+ function createClient(props: SecretProps): Octokit {
140
+ return new Octokit({ auth: resolveToken(props) });
141
+ }
142
+
143
+ async function encryptValue(
144
+ plaintext: string,
145
+ publicKey: string,
146
+ ): Promise<string> {
147
+ const sodium = await import("libsodium-wrappers");
148
+ await sodium.ready;
149
+ const binKey = sodium.from_base64(publicKey, sodium.base64_variants.ORIGINAL);
150
+ const binMessage = sodium.from_string(plaintext);
151
+ const encrypted = sodium.crypto_box_seal(binMessage, binKey);
152
+ return sodium.to_base64(encrypted, sodium.base64_variants.ORIGINAL);
153
+ }
154
+
155
+ export const SecretProvider = () =>
156
+ Provider.succeed(Secret, {
157
+ create: Effect.fn(function* ({ news }) {
158
+ const octokit = createClient(news);
159
+ yield* upsertSecret(octokit, news);
160
+ return { updatedAt: new Date().toISOString() };
161
+ }),
162
+
163
+ update: Effect.fn(function* ({ news, olds }) {
164
+ const octokit = createClient(news);
165
+
166
+ const wasEnv = !!olds.environment;
167
+ const isEnv = !!news.environment;
168
+ if (wasEnv !== isEnv || olds.environment !== news.environment) {
169
+ yield* deleteSecret(octokit, olds);
170
+ }
171
+
172
+ yield* upsertSecret(octokit, news);
173
+ return { updatedAt: new Date().toISOString() };
174
+ }),
175
+
176
+ delete: Effect.fn(function* ({ olds }) {
177
+ const octokit = createClient(olds);
178
+ yield* deleteSecret(octokit, olds);
179
+ }),
180
+ });
181
+
182
+ const upsertSecret = Effect.fn(function* (
183
+ octokit: Octokit,
184
+ props: SecretProps,
185
+ ) {
186
+ const plaintext = Redacted.value(props.value);
187
+ const isEnv = !!props.environment;
188
+
189
+ const publicKey = yield* Effect.tryPromise(async () => {
190
+ if (isEnv) {
191
+ const { data } = await octokit.rest.actions.getEnvironmentPublicKey({
192
+ owner: props.owner,
193
+ repo: props.repository,
194
+ environment_name: props.environment!,
195
+ });
196
+ return data;
197
+ }
198
+ const { data } = await octokit.rest.actions.getRepoPublicKey({
199
+ owner: props.owner,
200
+ repo: props.repository,
201
+ });
202
+ return data;
203
+ });
204
+
205
+ const encrypted = yield* Effect.tryPromise(() =>
206
+ encryptValue(plaintext, publicKey.key),
207
+ );
208
+
209
+ yield* Effect.tryPromise(async () => {
210
+ if (isEnv) {
211
+ await octokit.rest.actions.createOrUpdateEnvironmentSecret({
212
+ owner: props.owner,
213
+ repo: props.repository,
214
+ environment_name: props.environment!,
215
+ secret_name: props.name,
216
+ encrypted_value: encrypted,
217
+ key_id: publicKey.key_id,
218
+ });
219
+ } else {
220
+ await octokit.rest.actions.createOrUpdateRepoSecret({
221
+ owner: props.owner,
222
+ repo: props.repository,
223
+ secret_name: props.name,
224
+ encrypted_value: encrypted,
225
+ key_id: publicKey.key_id,
226
+ });
227
+ }
228
+ });
229
+ });
230
+
231
+ const deleteSecret = Effect.fn(function* (
232
+ octokit: Octokit,
233
+ props: SecretProps,
234
+ ) {
235
+ yield* Effect.tryPromise(async () => {
236
+ try {
237
+ if (props.environment) {
238
+ await octokit.rest.actions.deleteEnvironmentSecret({
239
+ owner: props.owner,
240
+ repo: props.repository,
241
+ environment_name: props.environment,
242
+ secret_name: props.name,
243
+ });
244
+ } else {
245
+ await octokit.rest.actions.deleteRepoSecret({
246
+ owner: props.owner,
247
+ repo: props.repository,
248
+ secret_name: props.name,
249
+ });
250
+ }
251
+ } catch (error: any) {
252
+ if (error.status !== 404) {
253
+ throw error;
254
+ }
255
+ }
256
+ });
257
+ });
@@ -0,0 +1,166 @@
1
+ import { Octokit } from "@octokit/rest";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Provider from "../Provider.ts";
4
+ import { Resource } from "../Resource.ts";
5
+
6
+ export interface VariableProps {
7
+ /**
8
+ * Repository owner (user or organization).
9
+ */
10
+ owner: string;
11
+
12
+ /**
13
+ * Repository name.
14
+ */
15
+ repository: string;
16
+
17
+ /**
18
+ * Variable name (e.g. `AWS_ROLE_ARN`).
19
+ */
20
+ name: string;
21
+
22
+ /**
23
+ * Variable value.
24
+ */
25
+ value: string;
26
+
27
+ /**
28
+ * GitHub API token. If not provided, falls back to
29
+ * `GITHUB_ACCESS_TOKEN` or `GITHUB_TOKEN` environment variables.
30
+ */
31
+ token?: string;
32
+ }
33
+
34
+ export interface Variable extends Resource<
35
+ "GitHub.Variable",
36
+ VariableProps,
37
+ {
38
+ /**
39
+ * ISO-8601 timestamp of the last update.
40
+ */
41
+ updatedAt: string;
42
+ }
43
+ > {}
44
+
45
+ /**
46
+ * A GitHub Actions repository variable.
47
+ *
48
+ * `Variable` manages the lifecycle of a plain-text configuration variable
49
+ * in GitHub Actions. Variables are visible in workflow logs and are
50
+ * suitable for non-sensitive configuration like region names, environment
51
+ * labels, or feature flags. For sensitive values, use `GitHub.Secret`
52
+ * instead.
53
+ *
54
+ * Authentication is resolved in order: explicit `token` prop,
55
+ * `GITHUB_ACCESS_TOKEN` env var, `GITHUB_TOKEN` env var. The token needs
56
+ * `repo` scope for private repositories or `public_repo` for public ones.
57
+ *
58
+ * @section Repository Variables
59
+ * Store variables accessible to all GitHub Actions workflows in the
60
+ * repository.
61
+ *
62
+ * @example Create a Repository Variable
63
+ * ```typescript
64
+ * yield* GitHub.Variable("aws-region", {
65
+ * owner: "my-org",
66
+ * repository: "my-repo",
67
+ * name: "AWS_REGION",
68
+ * value: "us-east-1",
69
+ * });
70
+ * ```
71
+ *
72
+ * @section Wiring with Other Resources
73
+ * Pass output attributes from other resources into GitHub variables so
74
+ * that CI workflows can reference them.
75
+ *
76
+ * @example Store a Worker URL for CI
77
+ * ```typescript
78
+ * const worker = yield* Cloudflare.Worker("Api", { ... });
79
+ *
80
+ * yield* GitHub.Variable("api-url", {
81
+ * owner: "my-org",
82
+ * repository: "my-repo",
83
+ * name: "API_URL",
84
+ * value: worker.url!,
85
+ * });
86
+ * ```
87
+ *
88
+ * @example Multiple Variables
89
+ * ```typescript
90
+ * yield* GitHub.Variable("region", {
91
+ * owner: "my-org",
92
+ * repository: "my-repo",
93
+ * name: "AWS_REGION",
94
+ * value: "us-east-1",
95
+ * });
96
+ *
97
+ * yield* GitHub.Variable("stage", {
98
+ * owner: "my-org",
99
+ * repository: "my-repo",
100
+ * name: "DEPLOY_STAGE",
101
+ * value: "production",
102
+ * });
103
+ * ```
104
+ */
105
+ export const Variable = Resource<Variable>("GitHub.Variable");
106
+
107
+ function resolveToken(props: VariableProps): string | undefined {
108
+ return (
109
+ props.token ?? process.env.GITHUB_ACCESS_TOKEN ?? process.env.GITHUB_TOKEN
110
+ );
111
+ }
112
+
113
+ function createClient(props: VariableProps): Octokit {
114
+ return new Octokit({ auth: resolveToken(props) });
115
+ }
116
+
117
+ export const VariableProvider = () =>
118
+ Provider.succeed(Variable, {
119
+ create: Effect.fn(function* ({ news }) {
120
+ const octokit = createClient(news);
121
+
122
+ yield* Effect.tryPromise(() =>
123
+ octokit.rest.actions.createRepoVariable({
124
+ owner: news.owner,
125
+ repo: news.repository,
126
+ name: news.name,
127
+ value: news.value,
128
+ }),
129
+ );
130
+
131
+ return { updatedAt: new Date().toISOString() };
132
+ }),
133
+
134
+ update: Effect.fn(function* ({ news }) {
135
+ const octokit = createClient(news);
136
+
137
+ yield* Effect.tryPromise(() =>
138
+ octokit.rest.actions.updateRepoVariable({
139
+ owner: news.owner,
140
+ repo: news.repository,
141
+ name: news.name,
142
+ value: news.value,
143
+ }),
144
+ );
145
+
146
+ return { updatedAt: new Date().toISOString() };
147
+ }),
148
+
149
+ delete: Effect.fn(function* ({ olds }) {
150
+ const octokit = createClient(olds);
151
+
152
+ yield* Effect.tryPromise(async () => {
153
+ try {
154
+ await octokit.rest.actions.deleteRepoVariable({
155
+ owner: olds.owner,
156
+ repo: olds.repository,
157
+ name: olds.name,
158
+ });
159
+ } catch (error: any) {
160
+ if (error.status !== 404) {
161
+ throw error;
162
+ }
163
+ }
164
+ });
165
+ }),
166
+ });
@@ -0,0 +1,3 @@
1
+ export * from "./Comment.ts";
2
+ export * from "./Secret.ts";
3
+ export * from "./Variable.ts";
@@ -1,6 +1,6 @@
1
- import { AwsClient } from "aws4fetch";
2
1
  import { Credentials } from "@distilled.cloud/aws/Credentials";
3
2
  import { Region } from "@distilled.cloud/aws/Region";
3
+ import { AwsClient } from "aws4fetch";
4
4
  import * as Data from "effect/Data";
5
5
  import * as Effect from "effect/Effect";
6
6
  import * as Redacted from "effect/Redacted";
@@ -28,7 +28,7 @@ export interface KubernetesClusterConnection {
28
28
  certificateAuthorityData: string;
29
29
  }
30
30
 
31
- const fieldManager = "alchemy-effect";
31
+ const fieldManager = "alchemy";
32
32
 
33
33
  const createBearerToken = Effect.fn(function* (clusterName: string) {
34
34
  const credentials = yield* yield* Credentials;
package/src/Output.ts CHANGED
@@ -90,7 +90,7 @@ export abstract class BaseExpr<A = any, Req = any> implements Output<A, Req> {
90
90
  declare readonly A: A;
91
91
  declare readonly src: ResourceLike;
92
92
  declare readonly req: Req;
93
- // we use a kind tag instead of instanceof to protect ourselves from duplicate alchemy-effect module imports
93
+ // we use a kind tag instead of instanceof to protect ourselves from duplicate alchemy module imports
94
94
  constructor() {}
95
95
  as<T>(): Output<T, Req> {
96
96
  return this as any;
package/src/Platform.ts CHANGED
@@ -33,7 +33,7 @@ export type Main<Services = never> = void | {
33
33
  };
34
34
 
35
35
  export type Rpc<Shape> = {
36
- "~alchemy-effect/rpc": Shape;
36
+ "~alchemy/rpc": Shape;
37
37
  };
38
38
 
39
39
  // services provided to the Resource
package/src/Provider.ts CHANGED
@@ -369,7 +369,7 @@ export const tryFindProviderByType: {
369
369
  const Tag = Provider<R>(resourceType) as Context.Service<Provider<R>, any>;
370
370
  const direct = yield* Effect.serviceOption(Tag);
371
371
  if (Option.isSome(direct)) {
372
- return direct.value;
372
+ return direct;
373
373
  }
374
374
 
375
375
  const context = yield* Effect.context<never>();