@effected/github-actions 0.23.1 → 0.25.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/Action.js CHANGED
@@ -8,7 +8,7 @@ import { NodeServices } from "@effect/platform-node";
8
8
  import { Cause, Effect, Exit, Layer, LogLevel, Option, References, Result } from "effect";
9
9
  import { FetchHttpClient } from "effect/http";
10
10
 
11
- //#region src/Action.ts
11
+ // src/Action.ts
12
12
  /**
13
13
  * The default runtime an action executes inside.
14
14
  *
@@ -152,5 +152,4 @@ var Action = class {
152
152
  };
153
153
  };
154
154
 
155
- //#endregion
156
155
  export { Action, ActionRuntime, describeCause };
package/ActionCache.js CHANGED
@@ -13,7 +13,7 @@ import { BlobClient, BlockBlobClient } from "@azure/storage-blob";
13
13
  import { GlobPattern, GlobSet } from "@effected/glob";
14
14
  import { ChildProcess, ChildProcessSpawner } from "effect/process";
15
15
 
16
- //#region src/ActionCache.ts
16
+ // src/ActionCache.ts
17
17
  /**
18
18
  * Raised when the runner's cache cannot be read or written.
19
19
  *
@@ -379,5 +379,4 @@ var ActionCache = class ActionCache extends Context.Service()("@effected/github-
379
379
  static layerTest = (overrides = {}) => Layer.succeed(ActionCache, ActionCache.makeTest(overrides));
380
380
  };
381
381
 
382
- //#endregion
383
382
  export { ActionCache, ActionCacheError };
@@ -1,6 +1,7 @@
1
+ import { decodeJson } from "./internal/json.js";
1
2
  import { Context, Effect, FileSystem, Layer, Option, Schema } from "effect";
2
3
 
3
- //#region src/ActionEnvironment.ts
4
+ // src/ActionEnvironment.ts
4
5
  /**
5
6
  * Raised when the runner environment does not say what an action needs.
6
7
  *
@@ -176,14 +177,11 @@ const make = (base) => Effect.gen(function* () {
176
177
  name: "GITHUB_EVENT_PATH",
177
178
  detail: `could not read "${path}": ${String(cause)}`
178
179
  })));
179
- return yield* Effect.try({
180
- try: () => JSON.parse(raw),
181
- catch: (cause) => new ActionEnvironmentError({
182
- reason: "malformed",
183
- name: "GITHUB_EVENT_PATH",
184
- detail: `not valid JSON: ${String(cause)}`
185
- })
186
- });
180
+ return yield* decodeJson(raw).pipe(Effect.mapError((cause) => new ActionEnvironmentError({
181
+ reason: "malformed",
182
+ name: "GITHUB_EVENT_PATH",
183
+ detail: `not valid JSON: ${cause.message}`
184
+ })));
187
185
  }),
188
186
  withEnv: (overrides, effect) => Effect.flatMap(EnvOverrides, (current) => Effect.provideService(effect, EnvOverrides, {
189
187
  ...current,
@@ -324,5 +322,4 @@ var ActionEnvironment = class ActionEnvironment extends Context.Service()("@effe
324
322
  static layerTest = (overrides = {}, payload) => Layer.effect(ActionEnvironment, ActionEnvironment.makeTest(overrides, payload)).pipe(Layer.provide(FileSystem.layerNoop({})));
325
323
  };
326
324
 
327
- //#endregion
328
325
  export { ActionEnvironment, ActionEnvironmentError, GitHubContext, RunnerContext };
package/ActionInput.js CHANGED
@@ -1,6 +1,7 @@
1
+ import { decodeJson } from "./internal/json.js";
1
2
  import { Config, ConfigProvider, Context, Effect, Schema, SchemaIssue } from "effect";
2
3
 
3
- //#region src/ActionInput.ts
4
+ // src/ActionInput.ts
4
5
  /**
5
6
  * The variable name the runner publishes an input under.
6
7
  *
@@ -29,7 +30,17 @@ const inputVariable = (name) => `INPUT_${name.replaceAll(" ", "_").toUpperCase()
29
30
  * mutations the author meant to rehearse. `actual` carries the offending value
30
31
  * so the rendered error names it.
31
32
  */
32
- const configError = (message, actual) => new Config.ConfigError(new Schema.SchemaError(new SchemaIssue.InvalidValue({ message }, actual)));
33
+ /**
34
+ * A `ConfigError` carrying `message` as its first issue and, when a decode
35
+ * failed, that decode's own issue beside it, so the cause is structured
36
+ * rather than flattened into the message.
37
+ */
38
+ const configError = (message, actual, cause) => {
39
+ const stated = new SchemaIssue.InvalidValue({ message }, actual);
40
+ return new Config.ConfigError(new Schema.SchemaError(cause === void 0 ? stated : new SchemaIssue.Composite(Schema.Unknown.ast, [stated, cause.issue], actual)));
41
+ };
42
+ /** The JSON-array form of {@link ActionInput.list}. */
43
+ const decodeStringArray = Schema.decodeUnknownEffect(Schema.Array(Schema.String));
33
44
  /** YAML 1.2 core-schema booleans, which is what the runner documents. */
34
45
  const TRUE = /* @__PURE__ */ new Set([
35
46
  "true",
@@ -267,13 +278,7 @@ var ActionInput = class ActionInput {
267
278
  return Config.String(inputVariable(name)).pipe(Config.mapEffect((raw) => {
268
279
  const trimmed = raw.trim();
269
280
  if (trimmed === "") return Effect.succeed([]);
270
- if (trimmed.startsWith("[")) try {
271
- const parsed = JSON.parse(trimmed);
272
- if (Array.isArray(parsed) && parsed.every((item) => typeof item === "string")) return Effect.succeed(parsed);
273
- return Effect.fail(configError(`Input "${name}" is a JSON array but not an array of strings`, raw));
274
- } catch {
275
- return Effect.fail(configError(`Input "${name}" looks like JSON but could not be parsed`, raw));
276
- }
281
+ if (trimmed.startsWith("[")) return decodeJson(trimmed).pipe(Effect.mapError((cause) => configError(`Input "${name}" looks like JSON but could not be parsed`, raw, cause)), Effect.flatMap((parsed) => decodeStringArray(parsed).pipe(Effect.mapError((cause) => configError(`Input "${name}" is a JSON array but not an array of strings`, raw, cause)))));
277
282
  const entries = trimmed.split(/[\n,]/).map((item) => item.trim()).filter((item) => !item.startsWith("#")).map((item) => item.startsWith("- ") || item.startsWith("* ") ? item.slice(2).trim() : item).filter((item) => item !== "");
278
283
  return Effect.succeed(entries);
279
284
  }));
@@ -332,15 +337,7 @@ var ActionInput = class ActionInput {
332
337
  * which is exactly the missing-versus-malformed split above.
333
338
  */
334
339
  static schema(name, schema) {
335
- return Config.String(inputVariable(name)).pipe(Config.mapEffect((raw) => {
336
- let parsed;
337
- try {
338
- parsed = JSON.parse(raw);
339
- } catch {
340
- return Effect.fail(configError(`Input "${name}" is not valid JSON`, raw));
341
- }
342
- return Schema.decodeUnknownEffect(schema)(parsed).pipe(Effect.mapError(() => configError(`Input "${name}" did not satisfy its schema`, parsed)));
343
- }));
340
+ return Config.String(inputVariable(name)).pipe(Config.mapEffect((raw) => decodeJson(raw).pipe(Effect.mapError((cause) => configError(`Input "${name}" is not valid JSON`, raw, cause)), Effect.flatMap((parsed) => Schema.decodeUnknownEffect(schema)(parsed).pipe(Effect.mapError((cause) => configError(`Input "${name}" did not satisfy its schema`, parsed, cause)))))));
344
341
  }
345
342
  /**
346
343
  * A `ConfigProvider` over a record of runner variables **or input names**.
@@ -512,5 +509,4 @@ var ActionInput = class ActionInput {
512
509
  static layerDefault = ConfigProvider.layer(Effect.map(Effect.context(), (context) => ActionInput.providerOver(Context.getOrUndefined(context, ConfigProvider.ConfigProvider) ?? ConfigProvider.fromEnv())));
513
510
  };
514
511
 
515
- //#endregion
516
512
  export { ActionInput, inputVariable };
package/ActionLogger.js CHANGED
@@ -2,7 +2,7 @@ import { ActionEnvironment } from "./ActionEnvironment.js";
2
2
  import { CommandNeutralizer, WorkflowCommand } from "@effected/github-commands";
3
3
  import { Console, Context, Effect, Exit, Inspectable, Layer, LogLevel, Logger, References } from "effect";
4
4
 
5
- //#region src/ActionLogger.ts
5
+ // src/ActionLogger.ts
6
6
  /**
7
7
  * Render a log message, which arrives as an array of the values passed to
8
8
  * `Effect.log*`.
@@ -223,5 +223,4 @@ var ActionLogger = class ActionLogger extends Context.Service()("@effected/githu
223
223
  static layerSilent = Layer.mergeAll(ActionLogger.layerTest(), Logger.layer([]));
224
224
  };
225
225
 
226
- //#endregion
227
226
  export { ActionLogger };
package/ActionOutputs.js CHANGED
@@ -4,7 +4,7 @@ import { unstubbed } from "./internal/unstubbed.js";
4
4
  import { CommandNeutralizer, WorkflowCommand } from "@effected/github-commands";
5
5
  import { Console, Context, Effect, FileSystem, Layer, Schema } from "effect";
6
6
 
7
- //#region src/ActionOutputs.ts
7
+ // src/ActionOutputs.ts
8
8
  /**
9
9
  * Raised when an action cannot publish an output.
10
10
  *
@@ -337,5 +337,4 @@ var ActionOutputs = class ActionOutputs extends Context.Service()("@effected/git
337
337
  };
338
338
  };
339
339
 
340
- //#endregion
341
340
  export { ActionOutputs, DetachedOutputError, InvalidOutputNameError, OutputEncodeError, RecordedOutput, RunnerFileUnavailableError, RunnerFileWriteError };
package/ActionState.js CHANGED
@@ -4,7 +4,7 @@ import { unstubbed } from "./internal/unstubbed.js";
4
4
  import { ActionOutputs } from "./ActionOutputs.js";
5
5
  import { Context, Effect, FileSystem, Layer, Option, Schema } from "effect";
6
6
 
7
- //#region src/ActionState.ts
7
+ // src/ActionState.ts
8
8
  /**
9
9
  * Raised when action state cannot be saved, read or decoded across the phase
10
10
  * boundary.
@@ -157,5 +157,4 @@ var ActionState = class ActionState extends Context.Service()("@effected/github-
157
157
  static layerTest = (overrides = {}) => Layer.succeed(ActionState, ActionState.makeTest(overrides));
158
158
  };
159
159
 
160
- //#endregion
161
160
  export { ActionState, ActionStateError };
@@ -1,16 +1,16 @@
1
1
  import { OidcTokenIssuer } from "./OidcTokenIssuer.js";
2
2
  import { Effect, Layer } from "effect";
3
- import { IdentityToken, IdentityTokenError } from "@effected/sbom";
3
+ import { IdentityToken, IdentityTokenError } from "@effected/oidc";
4
4
 
5
- //#region src/ActionsIdentityToken.ts
5
+ // src/ActionsIdentityToken.ts
6
6
  /**
7
- * Serves `@effected/sbom`'s `IdentityToken` contract from the runner's own OIDC
7
+ * Serves `@effected/oidc`'s `IdentityToken` contract from the runner's own OIDC
8
8
  * token service, so signing an SBOM inside a workflow needs no further wiring.
9
9
  *
10
10
  * @remarks
11
- * `@effected/sbom` declares `IdentityToken` — one method, one audience,
12
- * one redacted token — precisely so that signing does not drag the Actions
13
- * runtime into every consumer that only wants to emit an SBOM. This is the
11
+ * `@effected/oidc` declares `IdentityToken` — one method, one audience,
12
+ * one redacted token — precisely so that a consumer of a token, such as
13
+ * `@effected/sbom`'s signer, does not drag the Actions runtime in. This is the
14
14
  * layer that closes the inversion from the other side: it serves that contract
15
15
  * from the runner's own OIDC token service ({@link OidcTokenIssuer}), the same
16
16
  * arrangement as `@effected/workspaces` implementing `@effected/commands`'
@@ -58,5 +58,4 @@ var ActionsIdentityToken = class {
58
58
  }))) })));
59
59
  };
60
60
 
61
- //#endregion
62
61
  export { ActionsIdentityToken };
@@ -3,7 +3,7 @@ import { OidcTokenIssuer } from "./OidcTokenIssuer.js";
3
3
  import { Effect, Option } from "effect";
4
4
  import { SlsaProvenance } from "@effected/sbom";
5
5
 
6
- //#region src/ActionsProvenance.ts
6
+ // src/ActionsProvenance.ts
7
7
  /**
8
8
  * The server URL a workflow on github.com runs against.
9
9
  *
@@ -20,12 +20,14 @@ const DEFAULT_SERVER_URL = "https://github.com";
20
20
  *
21
21
  * @remarks
22
22
  * `SlsaProvenance.forGitHubWorkflow` is total and does the real work, but it
23
- * takes a camelCase input record — and the only input anyone inside a workflow
24
- * actually holds is the runner's own OIDC claims, spelled in GitHub's
25
- * snake_case claim names. The rename between the two is eleven all-string
26
- * fields, so transposing `repository_id` and `repository_owner_id` compiles,
27
- * passes every type check, and produces a validly signed attestation asserting
28
- * the **wrong** provenance. This module owns that rename once, on the same
23
+ * takes an all-string input record — and the only input anyone inside a
24
+ * workflow actually holds is the runner's own OIDC claims, decoded as
25
+ * `@effected/github`'s `ActionsOidcClaims` with integer ids. The projection
26
+ * between the two is eleven close-cousin fields, so transposing `repositoryId`
27
+ * and `repositoryOwnerId` compiles, passes every type check, and produces a
28
+ * validly signed attestation asserting the **wrong** provenance. This module
29
+ * owns that projection once, rendering the ids back to the decimal strings the
30
+ * token carried, on the same
29
31
  * `github-actions` ↔ `sbom` seam as {@link ActionsIdentityToken}: `sbom` must
30
32
  * not depend on the Actions runtime, so the adapter lives here, beside the
31
33
  * services it reads.
@@ -55,7 +57,7 @@ var ActionsProvenance = class {
55
57
  *
56
58
  * @remarks
57
59
  * Every field `GitHubWorkflowProvenance` declares is populated from
58
- * {@link OidcClaims}, except `serverUrl`, which is read from
60
+ * the runner's `ActionsOidcClaims`, except `serverUrl`, which is read from
59
61
  * `GITHUB_SERVER_URL` through {@link ActionEnvironment}'s `getOptional`
60
62
  * with `https://github.com` as the default — **not** through the
61
63
  * `GitHubContext` projection. The projection fails typed when a `GITHUB_*`
@@ -88,17 +90,16 @@ var ActionsProvenance = class {
88
90
  repository: claims.repository,
89
91
  ref: claims.ref,
90
92
  sha: claims.sha,
91
- eventName: claims.event_name,
92
- workflowRef: claims.workflow_ref,
93
- jobWorkflowRef: claims.job_workflow_ref,
94
- repositoryId: claims.repository_id,
95
- repositoryOwnerId: claims.repository_owner_id,
96
- runnerEnvironment: claims.runner_environment,
97
- runId: claims.run_id,
98
- runAttempt: claims.run_attempt
93
+ eventName: claims.eventName,
94
+ workflowRef: claims.workflowRef,
95
+ jobWorkflowRef: claims.jobWorkflowRef,
96
+ repositoryId: String(claims.repositoryId),
97
+ repositoryOwnerId: String(claims.repositoryOwnerId),
98
+ runnerEnvironment: claims.runnerEnvironment,
99
+ runId: String(claims.runId),
100
+ runAttempt: String(claims.runAttempt)
99
101
  });
100
102
  });
101
103
  };
102
104
 
103
- //#endregion
104
105
  export { ActionsProvenance };
package/Artifact.js CHANGED
@@ -7,12 +7,12 @@ import { digestFileHex } from "./internal/digest.js";
7
7
  import { isWindowsRunner } from "./internal/runner.js";
8
8
  import { spawnOnce } from "./internal/spawn.js";
9
9
  import { unzipCommand, zipCommand, zipManifest } from "./internal/archiveCommands.js";
10
- import { Context, Effect, FileSystem, Layer, Option, Path, Result, Schema } from "effect";
10
+ import { Context, DateTime, Duration, Effect, FileSystem, Layer, Option, Path, Result, Schema } from "effect";
11
11
  import { HttpClient } from "effect/http";
12
12
  import { BlobClient, BlockBlobClient } from "@azure/storage-blob";
13
13
  import { ChildProcessSpawner } from "effect/process";
14
14
 
15
- //#region src/Artifact.ts
15
+ // src/Artifact.ts
16
16
  /**
17
17
  * Raised when an artifact cannot be uploaded, listed, downloaded or deleted.
18
18
  *
@@ -263,11 +263,12 @@ const make = (transfer) => Effect.gen(function* () {
263
263
  cause
264
264
  })));
265
265
  const digest = yield* digestOf(packed, name);
266
+ const expiresAt = options?.retentionDays === void 0 ? void 0 : DateTime.formatIso(DateTime.addDuration(yield* DateTime.now, Duration.days(options.retentionDays)));
266
267
  const finalized = yield* call("FinalizeArtifact", () => ({
267
268
  name,
268
269
  size: String(size.size),
269
270
  hash: `sha256:${digest}`,
270
- ...options?.retentionDays === void 0 ? {} : { expiresAt: new Date(Date.now() + options.retentionDays * 864e5).toISOString() }
271
+ ...expiresAt === void 0 ? {} : { expiresAt }
271
272
  }), name);
272
273
  if (finalized === CONFLICT || !isOk(finalized)) return yield* Effect.fail(new ArtifactError({
273
274
  reason: "refused",
@@ -399,5 +400,4 @@ var Artifact = class Artifact extends Context.Service()("@effected/github-action
399
400
  static layerTest = (overrides = {}) => Layer.succeed(Artifact, Artifact.makeTest(overrides));
400
401
  };
401
402
 
402
- //#endregion
403
403
  export { Artifact, ArtifactError };
package/BlobEnvelope.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Result, Schema } from "effect";
2
2
 
3
- //#region src/BlobEnvelope.ts
3
+ // src/BlobEnvelope.ts
4
4
  /**
5
5
  * Raised when bytes cannot be read as an envelope.
6
6
  *
@@ -166,5 +166,4 @@ var BlobEnvelope = class {
166
166
  }
167
167
  };
168
168
 
169
- //#endregion
170
169
  export { BlobEnvelope, BlobMetadataDecodeError, BlobMetadataEncodeError, NotABlobEnvelopeError, TruncatedBlobEnvelopeError, UnsupportedBlobEnvelopeVersionError };
@@ -10,7 +10,7 @@ import { Effect, Layer, Option } from "effect";
10
10
  import { HttpClient } from "effect/http";
11
11
  import { BlobClient, BlockBlobClient } from "@azure/storage-blob";
12
12
 
13
- //#region src/BlobStore.githubCache.ts
13
+ // src/BlobStore.githubCache.ts
14
14
  /**
15
15
  * The `version` every entry is filed under.
16
16
  *
@@ -166,5 +166,4 @@ var GitHubCacheBlobStore = class {
166
166
  static layerWith = (transfer) => Layer.effect(BlobStore, make(transfer));
167
167
  };
168
168
 
169
- //#endregion
170
169
  export { GitHubCacheBlobStore };
package/BlobStore.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { unstubbed } from "./internal/unstubbed.js";
2
2
  import { BlobEnvelope } from "./BlobEnvelope.js";
3
- import { sign } from "./internal/sigv4.js";
4
3
  import { Secret } from "./Secret.js";
5
- import { Context, Effect, Layer, Option, Schema } from "effect";
4
+ import { Context, Crypto, DateTime, Effect, Layer, Option, Schema } from "effect";
6
5
  import { HttpClient, HttpClientRequest } from "effect/http";
6
+ import { SigV4 } from "@effected/crypto";
7
7
 
8
- //#region src/BlobStore.ts
8
+ // src/BlobStore.ts
9
9
  /**
10
10
  * Raised when a blob cannot be stored or retrieved.
11
11
  *
@@ -15,12 +15,17 @@ var BlobStoreError = class extends Schema.TaggedError()("BlobStoreError", {
15
15
  /**
16
16
  * `unreachable` — the store could not be contacted. `refused` — it answered,
17
17
  * unhappily; `status` says how. `misconfigured` — the layer was built with
18
- * settings the store cannot use.
18
+ * settings the store cannot use, or a request could not be signed with them
19
+ * (no WebCrypto in the runtime, or key material it refuses). `invalidKey` —
20
+ * the caller's key cannot be stored at all, whatever the settings: on S3, a
21
+ * key with a `.` or `..` path segment, which no URL carries as signed.
22
+ * Nothing is sent.
19
23
  */
20
24
  reason: Schema.Literals([
21
25
  "unreachable",
22
26
  "refused",
23
- "misconfigured"
27
+ "misconfigured",
28
+ "invalidKey"
24
29
  ]),
25
30
  /** The key involved. A stable identifier, never a value. */
26
31
  key: Schema.optionalKey(Schema.String),
@@ -35,6 +40,7 @@ var BlobStoreError = class extends Schema.TaggedError()("BlobStoreError", {
35
40
  switch (this.reason) {
36
41
  case "unreachable": return `The blob store could not be reached${this.key === void 0 ? "" : ` for "${this.key}"`}`;
37
42
  case "refused": return `The blob store refused "${this.key}"${this.status === void 0 ? "" : ` with status ${this.status}`}${this.detail === void 0 ? "" : `: ${this.detail}`}`;
43
+ case "invalidKey": return `The blob store cannot hold the key "${this.key}"${this.detail === void 0 ? "" : `: ${this.detail}`}`;
38
44
  default: return `The blob store is misconfigured${this.detail === void 0 ? "" : `: ${this.detail}`}`;
39
45
  }
40
46
  }
@@ -75,10 +81,17 @@ var BlobStore = class BlobStore extends Context.Service()("@effected/github-acti
75
81
  * An S3-compatible backend, signed with SigV4.
76
82
  *
77
83
  * @remarks
78
- * No `@aws-sdk/*` dependency: signing is a specified algorithm over strings
79
- * and HMACs, and this package already has `node:crypto`. The SDK's weight is
80
- * in credential management, retries and a service catalogue none of which
81
- * this needs.
84
+ * No `@aws-sdk/*` dependency: signing is `@effected/crypto`'s `SigV4`, a
85
+ * specified algorithm over strings and HMACs. The SDK's weight is in
86
+ * credential management, retries and a service catalogue none of which this
87
+ * needs.
88
+ *
89
+ * Requires core `Crypto` for the SHA-256 digests signing takes, resolved
90
+ * once when the layer is built; `NodeServices.layer` supplies it. A request
91
+ * that cannot be signed fails as {@link BlobStoreError} `misconfigured`. A
92
+ * key with a `.` or `..` path segment fails as `invalidKey` before anything
93
+ * is signed or sent: every URL parser collapses such a segment, so the store
94
+ * would receive another path than the one signed.
82
95
  *
83
96
  * A parameterized layer factory mints a fresh layer per call and layers
84
97
  * memoize by reference — bind it to a `const` rather than calling it at each
@@ -119,43 +132,60 @@ var BlobStore = class BlobStore extends Context.Service()("@effected/github-acti
119
132
  };
120
133
  const dies = unstubbed("BlobStore.makeTest");
121
134
  const makeS3 = (config) => Effect.gen(function* () {
122
- const http = yield* HttpClient.HttpClient;
135
+ const http = HttpClient.transform(yield* HttpClient.HttpClient, (effect) => Effect.provideService(effect, HttpClient.TracerPropagationEnabled, false));
136
+ const crypto = yield* Crypto.Crypto;
123
137
  let endpoint = config.endpoint ?? `https://s3.${config.region}.amazonaws.com`;
124
138
  while (endpoint.endsWith("/")) endpoint = endpoint.slice(0, -1);
125
139
  const host = new URL(endpoint).host;
126
- const secretAccessKey = yield* Secret.forSigning(config.secretAccessKey);
127
- const sessionToken = config.sessionToken === void 0 ? void 0 : yield* Secret.forSigning(config.sessionToken);
140
+ yield* Secret.mask(config.secretAccessKey);
141
+ if (config.sessionToken !== void 0) yield* Secret.mask(config.sessionToken);
142
+ const credentials = {
143
+ accessKeyId: config.accessKeyId,
144
+ secretAccessKey: config.secretAccessKey,
145
+ ...config.sessionToken === void 0 ? {} : { sessionToken: config.sessionToken },
146
+ region: config.region,
147
+ service: "s3"
148
+ };
128
149
  const objectPath = (key) => [
129
150
  config.bucket,
130
151
  ...config.prefix === void 0 ? [] : [config.prefix],
131
152
  key
132
153
  ].join("/").replaceAll(/\/{2,}/g, "/");
133
- const request = (method, key, body) => {
154
+ const unsignable = (key, cause) => new BlobStoreError({
155
+ reason: "misconfigured",
156
+ key,
157
+ detail: "the request could not be signed",
158
+ cause
159
+ });
160
+ const request = (method, key, body) => Effect.gen(function* () {
134
161
  const path = objectPath(key);
135
- const headers = sign({
162
+ const now = yield* DateTime.now;
163
+ const signed = yield* SigV4.sign({
136
164
  method,
137
165
  path,
138
166
  host,
139
- headers: {},
140
167
  body,
141
- now: /* @__PURE__ */ new Date()
142
- }, {
143
- accessKeyId: config.accessKeyId,
144
- secretAccessKey,
145
- ...sessionToken === void 0 ? {} : { sessionToken },
146
- region: config.region,
147
- service: "s3"
148
- });
168
+ now
169
+ }, credentials).pipe(Effect.provideService(Crypto.Crypto, crypto), Effect.catchTags({
170
+ SigV4PathError: (cause) => Effect.fail(new BlobStoreError({
171
+ reason: "invalidKey",
172
+ key,
173
+ detail: `the path has a "${cause.segment}" segment, which a URL collapses, so it cannot be sent as signed`,
174
+ cause
175
+ })),
176
+ CryptoError: (cause) => Effect.fail(unsignable(key, cause)),
177
+ PlatformError: (cause) => Effect.fail(unsignable(key, cause))
178
+ }));
149
179
  return {
150
- url: `${endpoint}/${path}`,
151
- headers
180
+ url: `${endpoint}${signed.path}${signed.query === "" ? "" : `?${signed.query}`}`,
181
+ headers: signed.headers
152
182
  };
153
- };
154
- const send = (method, key, body) => Effect.suspend(() => {
155
- const { url, headers } = request(method, key, body);
183
+ });
184
+ const send = (method, key, body) => Effect.gen(function* () {
185
+ const { url, headers } = yield* request(method, key, body);
156
186
  const base = HttpClientRequest.make(method)(url, { headers });
157
187
  const built = body.length === 0 ? base : HttpClientRequest.bodyUint8Array(base, body);
158
- return http.execute(built).pipe(Effect.mapError((cause) => new BlobStoreError({
188
+ return yield* http.execute(built).pipe(Effect.mapError((cause) => new BlobStoreError({
159
189
  reason: "unreachable",
160
190
  key,
161
191
  cause
@@ -193,5 +223,4 @@ const makeS3 = (config) => Effect.gen(function* () {
193
223
  };
194
224
  });
195
225
 
196
- //#endregion
197
226
  export { BlobStore, BlobStoreError };
package/BlobTransfer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Schema } from "effect";
2
2
 
3
- //#region src/BlobTransfer.ts
3
+ // src/BlobTransfer.ts
4
4
  /**
5
5
  * Raised when bytes could not be moved to or from a signed blob url.
6
6
  *
@@ -17,5 +17,4 @@ var BlobTransferError = class extends Schema.TaggedError()("BlobTransferError",
17
17
  }
18
18
  };
19
19
 
20
- //#endregion
21
20
  export { BlobTransferError };
package/CacheKey.js CHANGED
@@ -3,7 +3,7 @@ import { Effect, FileSystem, Option, Path, Schema } from "effect";
3
3
  import { GlobSet } from "@effected/glob";
4
4
  import { descend } from "@effected/walker";
5
5
 
6
- //#region src/CacheKey.ts
6
+ // src/CacheKey.ts
7
7
  /**
8
8
  * Raised when a file or directory that was going to be hashed could not be
9
9
  * read.
@@ -441,5 +441,4 @@ var CacheKey = class CacheKey extends Schema.Class("CacheKey")(Schema.Struct({
441
441
  });
442
442
  };
443
443
 
444
- //#endregion
445
444
  export { CacheKey, CacheKeyBadPatternError, CacheKeyReadError };
package/CheckDocument.js CHANGED
@@ -3,7 +3,7 @@ import { CheckState } from "./CheckState.js";
3
3
  import { ManagedDocument } from "./ManagedDocument.js";
4
4
  import { Clock, Context, Duration, Effect, Latch, Layer, Ref, Schema, Semaphore } from "effect";
5
5
 
6
- //#region src/CheckDocument.ts
6
+ // src/CheckDocument.ts
7
7
  /**
8
8
  * What a run knows about one of its checks: the authoritative state, and the
9
9
  * presentation facts a renderer projects into the document.
@@ -311,5 +311,4 @@ var CheckDocument = class CheckDocument extends Context.Service()("@effected/git
311
311
  };
312
312
  const dies = unstubbed("CheckDocument.makeTest");
313
313
 
314
- //#endregion
315
314
  export { CheckDocument, CheckDocumentError, CheckDocumentStamp, CheckReport };
package/CheckState.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Schema } from "effect";
2
2
 
3
- //#region src/CheckState.ts
3
+ // src/CheckState.ts
4
4
  /**
5
5
  * The kit's check-state vocabulary.
6
6
  *
@@ -71,5 +71,4 @@ const projectCheckState = (state) => {
71
71
  }
72
72
  };
73
73
 
74
- //#endregion
75
74
  export { CheckState, projectCheckState };
package/ChildEnv.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/ChildEnv.ts
1
+ // src/ChildEnv.ts
2
2
  /**
3
3
  * Child-process environment construction: prepending directories to `PATH`
4
4
  * without falling into three cross-platform traps.
@@ -127,5 +127,4 @@ var ChildEnv = class ChildEnv {
127
127
  }
128
128
  };
129
129
 
130
- //#endregion
131
130
  export { ChildEnv };
@@ -6,7 +6,7 @@ import { ChildProcessSpawner } from "effect/process";
6
6
  import { spawn } from "node:child_process";
7
7
  import { closeSync, openSync } from "node:fs";
8
8
 
9
- //#region src/DetachedProcess.ts
9
+ // src/DetachedProcess.ts
10
10
  /**
11
11
  * Raised when the log file for a detached child's output cannot be opened.
12
12
  *
@@ -309,5 +309,4 @@ var DetachedProcess = class DetachedProcess {
309
309
  });
310
310
  };
311
311
 
312
- //#endregion
313
312
  export { DetachedLogUnavailableError, DetachedNotReadyError, DetachedProcess, DetachedSignalFailedError, DetachedSpawnFailedError, InvalidPidError, ProcessId };
package/DryRun.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ActionInput } from "./ActionInput.js";
2
2
  import { Config, Context, Effect, Layer } from "effect";
3
3
 
4
- //#region src/DryRun.ts
4
+ // src/DryRun.ts
5
5
  /** The input a workflow author sets to rehearse a run. */
6
6
  const DEFAULT_INPUT = "dry-run";
7
7
  const make = (enabled) => ({
@@ -69,5 +69,4 @@ var DryRun = class DryRun extends Context.Service()("@effected/github-actions/Dr
69
69
  static layerTest = (overrides = {}) => Layer.succeed(DryRun, DryRun.makeTest(overrides));
70
70
  };
71
71
 
72
- //#endregion
73
72
  export { DryRun };
package/GitHubMarkdown.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Result, Schema, SchemaAST } from "effect";
2
2
  import { Code, Html, InlineCode, Link, List, ListItem, Markdown, Paragraph, Root, Table, TableCell, TableRow } from "@effected/markdown";
3
3
 
4
- //#region src/GitHubMarkdown.ts
4
+ // src/GitHubMarkdown.ts
5
5
  /**
6
6
  * A block node whose value passes through the serializer verbatim, which is
7
7
  * exactly how a pre-rendered markdown fragment must travel: GFM structure
@@ -234,5 +234,4 @@ var GitHubMarkdown = class GitHubMarkdown {
234
234
  }
235
235
  };
236
236
 
237
- //#endregion
238
237
  export { GitHubMarkdown };
package/GitHubToken.js CHANGED
@@ -3,7 +3,7 @@ import { Secret } from "./Secret.js";
3
3
  import { DateTime, Duration, Effect, Exit, Layer, Option, Result, Schema } from "effect";
4
4
  import { GitHubApp, GitHubClient, InstallationToken, TokenPermissions } from "@effected/github";
5
5
 
6
- //#region src/GitHubToken.ts
6
+ // src/GitHubToken.ts
7
7
  /**
8
8
  * Raised when the token an earlier phase persisted cannot be used.
9
9
  *
@@ -220,5 +220,4 @@ var GitHubToken = class GitHubToken {
220
220
  });
221
221
  };
222
222
 
223
- //#endregion
224
223
  export { GitHubToken, GitHubTokenError };
@@ -1,7 +1,7 @@
1
1
  import { Effect, Option, Result, Schema } from "effect";
2
2
  import { CommentStyle, SectionDialect, SectionDocument, SectionId } from "@effected/templates";
3
3
 
4
- //#region src/ManagedDocument.ts
4
+ // src/ManagedDocument.ts
5
5
  /**
6
6
  * The grammar shared by a document's `namespace`, its `key` and every region
7
7
  * key.
@@ -316,5 +316,4 @@ var ManagedDocument = class ManagedDocument extends Schema.Class("ManagedDocumen
316
316
  }
317
317
  };
318
318
 
319
- //#endregion
320
319
  export { ManagedDocument, ManagedDocumentError };