alchemy 2.0.0-beta.16 → 2.0.0-beta.18

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 (99) hide show
  1. package/bin/alchemy.js +79 -6
  2. package/bin/alchemy.js.map +1 -1
  3. package/bin/cli.js +9 -7
  4. package/bin/commands/deploy.ts +11 -2
  5. package/bin/commands/profile.ts +21 -1
  6. package/bin/commands/state.ts +91 -1
  7. package/lib/AWS/CloudFront/CachePolicy.d.ts +106 -0
  8. package/lib/AWS/CloudFront/CachePolicy.d.ts.map +1 -0
  9. package/lib/AWS/CloudFront/CachePolicy.js +147 -0
  10. package/lib/AWS/CloudFront/CachePolicy.js.map +1 -0
  11. package/lib/AWS/CloudFront/KeyGroup.d.ts +72 -0
  12. package/lib/AWS/CloudFront/KeyGroup.d.ts.map +1 -0
  13. package/lib/AWS/CloudFront/KeyGroup.js +136 -0
  14. package/lib/AWS/CloudFront/KeyGroup.js.map +1 -0
  15. package/lib/AWS/CloudFront/OriginRequestPolicy.d.ts +84 -0
  16. package/lib/AWS/CloudFront/OriginRequestPolicy.d.ts.map +1 -0
  17. package/lib/AWS/CloudFront/OriginRequestPolicy.js +139 -0
  18. package/lib/AWS/CloudFront/OriginRequestPolicy.js.map +1 -0
  19. package/lib/AWS/CloudFront/PublicKey.d.ts +72 -0
  20. package/lib/AWS/CloudFront/PublicKey.d.ts.map +1 -0
  21. package/lib/AWS/CloudFront/PublicKey.js +137 -0
  22. package/lib/AWS/CloudFront/PublicKey.js.map +1 -0
  23. package/lib/AWS/CloudFront/ResponseHeadersPolicy.d.ts +114 -0
  24. package/lib/AWS/CloudFront/ResponseHeadersPolicy.d.ts.map +1 -0
  25. package/lib/AWS/CloudFront/ResponseHeadersPolicy.js +162 -0
  26. package/lib/AWS/CloudFront/ResponseHeadersPolicy.js.map +1 -0
  27. package/lib/AWS/CloudFront/index.d.ts +5 -0
  28. package/lib/AWS/CloudFront/index.d.ts.map +1 -1
  29. package/lib/AWS/CloudFront/index.js +5 -0
  30. package/lib/AWS/CloudFront/index.js.map +1 -1
  31. package/lib/AWS/ECS/CapacityProvider.d.ts +102 -0
  32. package/lib/AWS/ECS/CapacityProvider.d.ts.map +1 -0
  33. package/lib/AWS/ECS/CapacityProvider.js +217 -0
  34. package/lib/AWS/ECS/CapacityProvider.js.map +1 -0
  35. package/lib/AWS/ECS/index.d.ts +1 -0
  36. package/lib/AWS/ECS/index.d.ts.map +1 -1
  37. package/lib/AWS/ECS/index.js +1 -0
  38. package/lib/AWS/ECS/index.js.map +1 -1
  39. package/lib/AWS/Providers.d.ts.map +1 -1
  40. package/lib/AWS/Providers.js +7 -1
  41. package/lib/AWS/Providers.js.map +1 -1
  42. package/lib/Auth/Credentials.d.ts +6 -0
  43. package/lib/Auth/Credentials.d.ts.map +1 -1
  44. package/lib/Auth/Credentials.js +12 -1
  45. package/lib/Auth/Credentials.js.map +1 -1
  46. package/lib/Auth/Profile.d.ts +5 -0
  47. package/lib/Auth/Profile.d.ts.map +1 -1
  48. package/lib/Auth/Profile.js +11 -0
  49. package/lib/Auth/Profile.js.map +1 -1
  50. package/lib/Cloudflare/ApiToken/AccountApiToken.d.ts +2 -1
  51. package/lib/Cloudflare/ApiToken/AccountApiToken.d.ts.map +1 -1
  52. package/lib/Cloudflare/ApiToken/AccountApiToken.js +6 -5
  53. package/lib/Cloudflare/ApiToken/AccountApiToken.js.map +1 -1
  54. package/lib/Cloudflare/ApiToken/Common.d.ts +5 -11
  55. package/lib/Cloudflare/ApiToken/Common.d.ts.map +1 -1
  56. package/lib/Cloudflare/ApiToken/Common.js +4 -14
  57. package/lib/Cloudflare/ApiToken/Common.js.map +1 -1
  58. package/lib/Cloudflare/ApiToken/UserApiToken.js +4 -4
  59. package/lib/Cloudflare/ApiToken/UserApiToken.js.map +1 -1
  60. package/lib/GitHub/Comment.d.ts +2 -1
  61. package/lib/GitHub/Comment.d.ts.map +1 -1
  62. package/lib/GitHub/Comment.js +1 -0
  63. package/lib/GitHub/Comment.js.map +1 -1
  64. package/lib/GitHub/Providers.d.ts.map +1 -1
  65. package/lib/GitHub/Providers.js +2 -1
  66. package/lib/GitHub/Providers.js.map +1 -1
  67. package/lib/GitHub/Secret.d.ts +2 -2
  68. package/lib/GitHub/Secret.d.ts.map +1 -1
  69. package/lib/GitHub/Secrets.d.ts +45 -0
  70. package/lib/GitHub/Secrets.d.ts.map +1 -0
  71. package/lib/GitHub/Secrets.js +30 -0
  72. package/lib/GitHub/Secrets.js.map +1 -0
  73. package/lib/GitHub/Variable.d.ts +2 -2
  74. package/lib/GitHub/Variable.d.ts.map +1 -1
  75. package/lib/GitHub/index.d.ts +1 -0
  76. package/lib/GitHub/index.d.ts.map +1 -1
  77. package/lib/GitHub/index.js +1 -0
  78. package/lib/GitHub/index.js.map +1 -1
  79. package/package.json +1 -1
  80. package/src/AWS/CloudFront/CachePolicy.ts +271 -0
  81. package/src/AWS/CloudFront/KeyGroup.ts +233 -0
  82. package/src/AWS/CloudFront/OriginRequestPolicy.ts +256 -0
  83. package/src/AWS/CloudFront/PublicKey.ts +245 -0
  84. package/src/AWS/CloudFront/ResponseHeadersPolicy.ts +308 -0
  85. package/src/AWS/CloudFront/index.ts +11 -0
  86. package/src/AWS/ECS/CapacityProvider.ts +336 -0
  87. package/src/AWS/ECS/index.ts +4 -0
  88. package/src/AWS/Providers.ts +12 -0
  89. package/src/Auth/Credentials.ts +17 -1
  90. package/src/Auth/Profile.ts +15 -0
  91. package/src/Cloudflare/ApiToken/AccountApiToken.ts +6 -5
  92. package/src/Cloudflare/ApiToken/Common.ts +6 -18
  93. package/src/Cloudflare/ApiToken/UserApiToken.ts +4 -4
  94. package/src/GitHub/Comment.ts +4 -1
  95. package/src/GitHub/Providers.ts +8 -2
  96. package/src/GitHub/Secret.ts +2 -2
  97. package/src/GitHub/Secrets.ts +66 -0
  98. package/src/GitHub/Variable.ts +2 -2
  99. package/src/GitHub/index.ts +1 -0
@@ -49,13 +49,18 @@ export const providers = () =>
49
49
  AutoScaling.AutoScalingGroup,
50
50
  AutoScaling.LaunchTemplate,
51
51
  AutoScaling.ScalingPolicy,
52
+ CloudFront.CachePolicy,
52
53
  CloudFront.Distribution,
53
54
  CloudFront.Function,
54
55
  CloudFront.Invalidation,
56
+ CloudFront.KeyGroup,
55
57
  CloudFront.KeyValueStore,
56
58
  CloudFront.KvEntries,
57
59
  CloudFront.KvRoutesUpdate,
58
60
  CloudFront.OriginAccessControl,
61
+ CloudFront.OriginRequestPolicy,
62
+ CloudFront.PublicKey,
63
+ CloudFront.ResponseHeadersPolicy,
59
64
  CloudWatch.Alarm,
60
65
  CloudWatch.AlarmMuteRule,
61
66
  CloudWatch.AnomalyDetector,
@@ -124,6 +129,7 @@ export const providers = () =>
124
129
  EC2.Vpc,
125
130
  EC2.VpcEndpoint,
126
131
  ECR.Repository,
132
+ ECS.CapacityProvider,
127
133
  ECS.Cluster,
128
134
  ECS.DescribeTasksPolicy,
129
135
  ECS.ListTasksPolicy,
@@ -282,13 +288,18 @@ export const providers = () =>
282
288
  AutoScaling.AutoScalingGroupProvider(),
283
289
  AutoScaling.LaunchTemplateProvider(),
284
290
  AutoScaling.ScalingPolicyProvider(),
291
+ CloudFront.CachePolicyProvider(),
285
292
  CloudFront.DistributionProvider(),
286
293
  CloudFront.FunctionProvider(),
287
294
  CloudFront.InvalidationProvider(),
295
+ CloudFront.KeyGroupProvider(),
288
296
  CloudFront.KeyValueStoreProvider(),
289
297
  CloudFront.KvEntriesProvider(),
290
298
  CloudFront.KvRoutesUpdateProvider(),
291
299
  CloudFront.OriginAccessControlProvider(),
300
+ CloudFront.OriginRequestPolicyProvider(),
301
+ CloudFront.PublicKeyProvider(),
302
+ CloudFront.ResponseHeadersPolicyProvider(),
292
303
  CloudWatch.AlarmMuteRuleProvider(),
293
304
  CloudWatch.AlarmProvider(),
294
305
  CloudWatch.AnomalyDetectorProvider(),
@@ -357,6 +368,7 @@ export const providers = () =>
357
368
  EC2.VpcEndpointProvider(),
358
369
  EC2.VpcProvider(),
359
370
  ECR.RepositoryProvider(),
371
+ ECS.CapacityProviderProvider(),
360
372
  ECS.ClusterProvider(),
361
373
  ECS.DescribeTasksPolicyLive,
362
374
  ECS.ListTasksPolicyLive,
@@ -6,8 +6,11 @@ import { rootDir } from "./Profile.ts";
6
6
 
7
7
  const credentialsDirPath = path.join(rootDir, "credentials");
8
8
 
9
+ export const profileCredentialsDirPath = (profile: string) =>
10
+ path.join(credentialsDirPath, profile);
11
+
9
12
  export const credentialsFilePath = (profile: string, provider: string) =>
10
- path.join(credentialsDirPath, profile, `${provider}.json`);
13
+ path.join(profileCredentialsDirPath(profile), `${provider}.json`);
11
14
 
12
15
  export const readCredentials = Effect.fnUntraced(function* <T>(
13
16
  profile: string,
@@ -46,6 +49,19 @@ export const deleteCredentials = Effect.fnUntraced(function* (
46
49
  .pipe(Effect.catch(() => Effect.void));
47
50
  });
48
51
 
52
+ /**
53
+ * Recursively remove the `~/.alchemy/credentials/{profile}` directory
54
+ * containing all per-provider secrets for `profile`. No-op if it doesn't exist.
55
+ */
56
+ export const deleteProfileCredentials = Effect.fnUntraced(function* (
57
+ profile: string,
58
+ ) {
59
+ const fs = yield* FileSystem.FileSystem;
60
+ yield* fs
61
+ .remove(profileCredentialsDirPath(profile), { recursive: true })
62
+ .pipe(Effect.catch(() => Effect.void));
63
+ });
64
+
49
65
  export function displayRedacted(
50
66
  r: Redacted.Redacted<string>,
51
67
  visibleChars = 4,
@@ -91,6 +91,21 @@ export const setProfile = (name: string, profile: AlchemyProfile) =>
91
91
  Effect.flatMap(writeConfig),
92
92
  );
93
93
 
94
+ /**
95
+ * Remove `name` and all its provider credentials from the on-disk config.
96
+ * Returns `true` if the profile existed and was removed, `false` otherwise.
97
+ */
98
+ export const deleteProfile = (name: string) =>
99
+ readConfig.pipe(
100
+ Effect.flatMap((config) => {
101
+ if (!(name in config.profiles)) {
102
+ return Effect.succeed(false);
103
+ }
104
+ delete config.profiles[name];
105
+ return writeConfig(config).pipe(Effect.as(true));
106
+ }),
107
+ );
108
+
94
109
  /**
95
110
  * Returns a `ConfigProvider` that overrides `ALCHEMY_PROFILE` with the
96
111
  * given `profile` (when explicitly passed via the CLI `--profile` flag),
@@ -50,6 +50,7 @@ export type AccountApiToken = Resource<
50
50
  * ```typescript
51
51
  * const token = yield* Cloudflare.AccountApiToken("ci-token", {
52
52
  * name: "my-ci-token",
53
+ * accountId,
53
54
  * policies: [
54
55
  * {
55
56
  * effect: "allow",
@@ -57,7 +58,7 @@ export type AccountApiToken = Resource<
57
58
  * "Workers Scripts Write",
58
59
  * "Workers KV Storage Write",
59
60
  * ],
60
- * resources: { "com.cloudflare.api.account": "*" },
61
+ * resources: { [`com.cloudflare.api.account.${accountId}`]: "*" },
61
62
  * },
62
63
  * ],
63
64
  * });
@@ -120,10 +121,10 @@ export const AccountApiTokenProvider = () =>
120
121
  const oldName = output?.name ?? (yield* resolveName(id, olds?.name));
121
122
  const newName = yield* resolveName(id, news.name);
122
123
  const oldPolicyFp = policyFingerprint(
123
- resolvePolicies(olds?.policies ?? [], oldAccountId),
124
+ resolvePolicies(olds?.policies ?? []),
124
125
  );
125
126
  const newPolicyFp = policyFingerprint(
126
- resolvePolicies(news.policies, newAccountId),
127
+ resolvePolicies(news.policies),
127
128
  );
128
129
  const oldCondFp = conditionFingerprint(olds?.condition);
129
130
  const newCondFp = conditionFingerprint(news.condition);
@@ -140,7 +141,7 @@ export const AccountApiTokenProvider = () =>
140
141
  create: Effect.fn(function* ({ id, news }) {
141
142
  const accountId = news.accountId ?? defaultAccountId;
142
143
  const name = yield* resolveName(id, news.name);
143
- const policies = resolvePolicies(news.policies, accountId);
144
+ const policies = resolvePolicies(news.policies);
144
145
  const result = yield* createToken({
145
146
  accountId,
146
147
  name,
@@ -163,7 +164,7 @@ export const AccountApiTokenProvider = () =>
163
164
  update: Effect.fn(function* ({ id, news, output }) {
164
165
  const accountId = news.accountId ?? defaultAccountId;
165
166
  const name = yield* resolveName(id, news.name);
166
- const policies = resolvePolicies(news.policies, accountId);
167
+ const policies = resolvePolicies(news.policies);
167
168
  const result = yield* updateToken({
168
169
  accountId,
169
170
  tokenId: output.tokenId,
@@ -6,14 +6,13 @@ import {
6
6
  /**
7
7
  * Resource keys recognized by Cloudflare API token policies.
8
8
  *
9
- * The literal `"com.cloudflare.api.account"` is rewritten by the account-scoped
10
- * provider to `"com.cloudflare.api.account.${accountId}"` so callers don't have
11
- * to splice the account ID themselves.
9
+ * Cloudflare requires the account ID to be embedded directly in the resource
10
+ * key (e.g. `com.cloudflare.api.account.<accountId>`); pass the fully-qualified
11
+ * key — no rewriting is performed.
12
12
  *
13
13
  * @see https://developers.cloudflare.com/fundamentals/api/reference/permissions/
14
14
  */
15
15
  export type ApiTokenResourceKey =
16
- | "com.cloudflare.api.account"
17
16
  | `com.cloudflare.api.account.${string}`
18
17
  | `com.cloudflare.api.account.zone.${string}`
19
18
  | `com.cloudflare.edge.r2.bucket.${string}`
@@ -86,35 +85,24 @@ export const resolvePermissionGroup = (ref: ApiTokenPermissionGroupRef) => {
86
85
  return ref.meta ? { id: ref.id, meta: ref.meta } : { id: ref.id };
87
86
  };
88
87
 
89
- /**
90
- * Rewrite the bare `"com.cloudflare.api.account"` key to the
91
- * account-scoped form. Pass `accountId: undefined` to leave keys unchanged
92
- * (e.g. for user-owned tokens whose policies don't carry an account scope).
93
- */
94
- export const resolveResources = (
88
+ const resolveResources = (
95
89
  resources: ApiTokenPolicy["resources"],
96
- accountId: string | undefined,
97
90
  ): Record<string, string> => {
98
91
  const out: Record<string, string> = {};
99
92
  for (const [key, value] of Object.entries(resources)) {
100
93
  if (value === undefined) continue;
101
- if (key === "com.cloudflare.api.account" && accountId) {
102
- out[`com.cloudflare.api.account.${accountId}`] = value;
103
- } else {
104
- out[key] = value;
105
- }
94
+ out[key] = value;
106
95
  }
107
96
  return out;
108
97
  };
109
98
 
110
99
  export const resolvePolicies = (
111
100
  policies: ApiTokenPolicy[],
112
- accountId: string | undefined,
113
101
  ): ResolvedPolicy[] =>
114
102
  policies.map((policy) => ({
115
103
  effect: policy.effect,
116
104
  permissionGroups: policy.permissionGroups.map(resolvePermissionGroup),
117
- resources: resolveResources(policy.resources, accountId),
105
+ resources: resolveResources(policy.resources),
118
106
  }));
119
107
 
120
108
  export const policyFingerprint = (policies: ResolvedPolicy[]): string =>
@@ -100,10 +100,10 @@ export const UserApiTokenProvider = () =>
100
100
  const oldName = output?.name ?? (yield* resolveName(id, olds?.name));
101
101
  const newName = yield* resolveName(id, news.name);
102
102
  const oldPolicyFp = policyFingerprint(
103
- resolvePolicies(olds?.policies ?? [], olds?.accountId),
103
+ resolvePolicies(olds?.policies ?? []),
104
104
  );
105
105
  const newPolicyFp = policyFingerprint(
106
- resolvePolicies(news.policies, news.accountId),
106
+ resolvePolicies(news.policies),
107
107
  );
108
108
  const oldCondFp = conditionFingerprint(olds?.condition);
109
109
  const newCondFp = conditionFingerprint(news.condition);
@@ -119,7 +119,7 @@ export const UserApiTokenProvider = () =>
119
119
  }),
120
120
  create: Effect.fn(function* ({ id, news }) {
121
121
  const name = yield* resolveName(id, news.name);
122
- const policies = resolvePolicies(news.policies, news.accountId);
122
+ const policies = resolvePolicies(news.policies);
123
123
  const result = yield* createToken({
124
124
  name,
125
125
  policies,
@@ -136,7 +136,7 @@ export const UserApiTokenProvider = () =>
136
136
  }),
137
137
  update: Effect.fn(function* ({ id, news, output }) {
138
138
  const name = yield* resolveName(id, news.name);
139
- const policies = resolvePolicies(news.policies, news.accountId);
139
+ const policies = resolvePolicies(news.policies);
140
140
  const result = yield* updateToken({
141
141
  tokenId: output.tokenId,
142
142
  name,
@@ -3,6 +3,7 @@ import * as Effect from "effect/Effect";
3
3
  import * as Provider from "../Provider.ts";
4
4
  import { Resource } from "../Resource.ts";
5
5
  import { dedent } from "../Util/dedent.ts";
6
+ import * as GitHub from "./Providers.ts";
6
7
 
7
8
  export interface CommentProps {
8
9
  /**
@@ -62,7 +63,9 @@ export interface Comment extends Resource<
62
63
  * ISO-8601 timestamp of the last update.
63
64
  */
64
65
  updatedAt: string;
65
- }
66
+ },
67
+ never,
68
+ GitHub.Providers
66
69
  > {}
67
70
 
68
71
  /**
@@ -1,6 +1,7 @@
1
1
  import * as Layer from "effect/Layer";
2
2
  import * as Provider from "../Provider.ts";
3
3
  import { GitHubAuth } from "./AuthProvider.ts";
4
+ import { Comment, CommentProvider } from "./Comment.ts";
4
5
  import * as Credentials from "./Credentials.ts";
5
6
  import { Secret, SecretProvider } from "./Secret.ts";
6
7
  import { Variable, VariableProvider } from "./Variable.ts";
@@ -18,8 +19,13 @@ export type ProviderRequirements = Layer.Services<ReturnType<typeof providers>>;
18
19
  * `alchemy login` discovers.
19
20
  */
20
21
  export const providers = () =>
21
- Layer.effect(Providers, Provider.collection([Secret, Variable])).pipe(
22
- Layer.provide(Layer.mergeAll(SecretProvider(), VariableProvider())),
22
+ Layer.effect(
23
+ Providers,
24
+ Provider.collection([Comment, Secret, Variable]),
25
+ ).pipe(
26
+ Layer.provide(
27
+ Layer.mergeAll(CommentProvider(), SecretProvider(), VariableProvider()),
28
+ ),
23
29
  Layer.provideMerge(Credentials.fromAuthProvider()),
24
30
  Layer.provideMerge(GitHubAuth),
25
31
  Layer.orDie,
@@ -4,7 +4,7 @@ import * as Redacted from "effect/Redacted";
4
4
  import * as Provider from "../Provider.ts";
5
5
  import { Resource } from "../Resource.ts";
6
6
  import { GitHubCredentials } from "./Credentials.ts";
7
- import type { Providers } from "./Providers.ts";
7
+ import type * as GitHub from "./Providers.ts";
8
8
 
9
9
  export interface SecretProps {
10
10
  /**
@@ -45,7 +45,7 @@ export interface Secret extends Resource<
45
45
  updatedAt: string;
46
46
  },
47
47
  never,
48
- Providers
48
+ GitHub.Providers
49
49
  > {}
50
50
 
51
51
  /**
@@ -0,0 +1,66 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Redacted from "effect/Redacted";
3
+
4
+ import type { Input } from "../Input.ts";
5
+ import { Secret } from "./Secret.ts";
6
+
7
+ export interface SecretsProps {
8
+ /**
9
+ * Repository owner (user or organization).
10
+ */
11
+ owner: string;
12
+
13
+ /**
14
+ * Repository name.
15
+ */
16
+ repository: string;
17
+
18
+ /**
19
+ * Optional environment name. When set every secret is scoped to that
20
+ * GitHub Actions environment instead of the whole repository.
21
+ */
22
+ environment?: string;
23
+
24
+ /**
25
+ * Map of secret name to value. Plain strings are wrapped with
26
+ * `Redacted.make`; already-redacted values are passed through.
27
+ */
28
+ secrets: Record<string, Input<string | Redacted.Redacted<string>>>;
29
+ }
30
+
31
+ /**
32
+ * Bulk-creates a set of {@link Secret}s in the same repository (and
33
+ * optionally the same environment).
34
+ *
35
+ * Each entry in `secrets` becomes one `GitHub.Secret` resource, using the
36
+ * map key as both the alchemy logical id and the secret name.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * yield* GitHub.Secrets({
41
+ * owner: "alchemy-run",
42
+ * repository: "alchemy-effect",
43
+ * secrets: {
44
+ * AXIOM_INGEST_TOKEN: tokenValue,
45
+ * AXIOM_DATASET_TRACES: traces.name,
46
+ * },
47
+ * });
48
+ * ```
49
+ */
50
+ export const Secrets = ({
51
+ owner,
52
+ repository,
53
+ environment,
54
+ secrets,
55
+ }: SecretsProps) =>
56
+ Effect.all(
57
+ Object.entries(secrets).map(([name, value]) =>
58
+ Secret(name, {
59
+ owner,
60
+ repository,
61
+ environment,
62
+ name,
63
+ value: Redacted.make(value),
64
+ }),
65
+ ),
66
+ );
@@ -2,7 +2,7 @@ import * as Effect from "effect/Effect";
2
2
  import * as Provider from "../Provider.ts";
3
3
  import { Resource } from "../Resource.ts";
4
4
  import { GitHubCredentials } from "./Credentials.ts";
5
- import type { Providers } from "./Providers.ts";
5
+ import type * as GitHub from "./Providers.ts";
6
6
 
7
7
  export interface VariableProps {
8
8
  /**
@@ -36,7 +36,7 @@ export interface Variable extends Resource<
36
36
  updatedAt: string;
37
37
  },
38
38
  never,
39
- Providers
39
+ GitHub.Providers
40
40
  > {}
41
41
 
42
42
  /**
@@ -3,4 +3,5 @@ export * from "./Comment.ts";
3
3
  export { GitHubCredentials, fromEnv, fromToken } from "./Credentials.ts";
4
4
  export * from "./Providers.ts";
5
5
  export * from "./Secret.ts";
6
+ export * from "./Secrets.ts";
6
7
  export * from "./Variable.ts";