@effected/github-actions 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.
package/index.d.ts ADDED
@@ -0,0 +1,2467 @@
1
+ import { NodeServices } from "@effect/platform-node";
2
+ import { Cause, Config, ConfigProvider, Context, Duration, Effect, FileSystem, Layer, Logger, Option, Path, Redacted, Result, Schema } from "effect";
3
+ import { HttpClient } from "effect/unstable/http";
4
+ import { ChildProcessSpawner } from "effect/unstable/process";
5
+ import { BotIdentity, GitHubApp, GitHubClient, InstallationToken, PermissionLevel, RetryPolicy } from "@effected/github";
6
+ //#region src/ActionEnvironment.d.ts
7
+ declare const ActionEnvironmentError_base: Schema.Class<ActionEnvironmentError, Schema.TaggedStruct<"ActionEnvironmentError", {
8
+ readonly reason: Schema.Literals<readonly ["missing", "malformed"]>;
9
+ /** The environment variable involved. */
10
+ readonly name: Schema.String;
11
+ /** What was wrong, when the reason is `malformed`. */
12
+ readonly detail: Schema.optionalKey<Schema.String>;
13
+ }>, import("effect/Cause").YieldableError>;
14
+ /**
15
+ * Raised when the runner environment does not say what an action needs.
16
+ *
17
+ * @remarks
18
+ * Two reasons, and the distinction is actionable: `missing` means the variable
19
+ * is absent or empty (the workflow did not grant something, or the action is
20
+ * running outside Actions); `malformed` means it is present but unusable (a
21
+ * non-numeric run id, an unparseable event payload). The first is usually a
22
+ * workflow fix, the second usually a bug report.
23
+ *
24
+ * @public
25
+ */
26
+ declare class ActionEnvironmentError extends ActionEnvironmentError_base {
27
+ get message(): string;
28
+ }
29
+ declare const GitHubContext_base: Schema.Class<GitHubContext, Schema.Struct<{
30
+ /** `owner/repo`. */
31
+ readonly repository: Schema.String;
32
+ readonly repositoryOwner: Schema.String;
33
+ /** The full ref, e.g. `refs/heads/main`. */
34
+ readonly ref: Schema.String;
35
+ /** The short ref, e.g. `main`. */
36
+ readonly refName: Schema.String;
37
+ readonly sha: Schema.String;
38
+ readonly workflow: Schema.String;
39
+ readonly job: Schema.String;
40
+ readonly runId: Schema.Number;
41
+ readonly runAttempt: Schema.Number;
42
+ readonly eventName: Schema.String;
43
+ readonly actor: Schema.String;
44
+ readonly serverUrl: Schema.String;
45
+ readonly apiUrl: Schema.String;
46
+ readonly graphqlUrl: Schema.String;
47
+ readonly workspace: Schema.String;
48
+ }>, {}>;
49
+ /**
50
+ * The workflow's GitHub context, projected from the `GITHUB_*` variables.
51
+ *
52
+ * @public
53
+ */
54
+ declare class GitHubContext extends GitHubContext_base {}
55
+ declare const RunnerContext_base: Schema.Class<RunnerContext, Schema.Struct<{
56
+ readonly os: Schema.String;
57
+ readonly arch: Schema.String;
58
+ readonly name: Schema.String;
59
+ /** A scratch directory emptied between jobs. */
60
+ readonly temp: Schema.String;
61
+ /** Where `ToolInstaller` caches toolchains. */
62
+ readonly toolCache: Schema.String;
63
+ }>, {}>;
64
+ /**
65
+ * The runner's own context, projected from the `RUNNER_*` variables.
66
+ *
67
+ * @public
68
+ */
69
+ declare class RunnerContext extends RunnerContext_base {}
70
+ /**
71
+ * The {@link ActionEnvironment} service shape.
72
+ *
73
+ * @public
74
+ */
75
+ interface ActionEnvironmentShape {
76
+ /** A required variable. Absent or empty fails typed. */
77
+ readonly get: (name: string) => Effect.Effect<string, ActionEnvironmentError>;
78
+ /** An optional variable. Empty reads as absent, as the runner treats it. */
79
+ readonly getOptional: (name: string) => Effect.Effect<Option.Option<string>>;
80
+ /** The `GITHUB_*` context. */
81
+ readonly github: Effect.Effect<GitHubContext, ActionEnvironmentError>;
82
+ /** The `RUNNER_*` context. */
83
+ readonly runner: Effect.Effect<RunnerContext, ActionEnvironmentError>;
84
+ /** Whether the runner is in step-debug mode. */
85
+ readonly isDebug: Effect.Effect<boolean>;
86
+ /**
87
+ * The webhook event payload.
88
+ *
89
+ * @remarks
90
+ * `R` is `never`: the layer resolves `FileSystem` once at construction, so
91
+ * a caller never re-injects one to keep its own requirements clean.
92
+ */
93
+ readonly payload: Effect.Effect<unknown, ActionEnvironmentError>;
94
+ /**
95
+ * Run an effect with environment overrides applied.
96
+ *
97
+ * @remarks
98
+ * Fiber-local and parallel-safe — `process.env` is never mutated, so
99
+ * concurrent callers cannot corrupt each other and there is nothing to
100
+ * restore. Overrides **merge** with any enclosing `withEnv`.
101
+ *
102
+ * The trade, stated: a variable exported mid-run by
103
+ * `ActionOutputs.exportVariable` is not observed here, because the snapshot
104
+ * is taken once. That matches GitHub's own model, where `exportVariable`
105
+ * targets *subsequent* steps rather than the running one.
106
+ */
107
+ readonly withEnv: <A, E, R>(overrides: Readonly<Record<string, string>>, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
108
+ }
109
+ declare const ActionEnvironment_base: Context.ServiceClass<ActionEnvironment, "@effected/github-actions/ActionEnvironment", ActionEnvironmentShape>;
110
+ /**
111
+ * The runner environment an action is executing inside.
112
+ *
113
+ * @remarks
114
+ * The single reader of `process.env` in this package. Everything else — inputs,
115
+ * outputs, state, the token bridge — goes through a service rather than
116
+ * reaching for a global, which is what makes them all testable without
117
+ * mutating the test process.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * import { ActionEnvironment } from "@effected/github-actions";
122
+ * import { Effect } from "effect";
123
+ *
124
+ * const program = Effect.gen(function* () {
125
+ * const env = yield* ActionEnvironment;
126
+ * const { repository, runId } = yield* env.github;
127
+ * return `${repository}#${runId}`;
128
+ * });
129
+ * ```
130
+ *
131
+ * @public
132
+ */
133
+ declare class ActionEnvironment extends ActionEnvironment_base {
134
+ /** Seeded from `process.env`, once, at layer construction. */
135
+ static readonly layer: Layer.Layer<ActionEnvironment, never, FileSystem.FileSystem>;
136
+ /**
137
+ * Seeded from an explicit record.
138
+ *
139
+ * @remarks
140
+ * A parameterized layer factory mints a fresh reference per call and layers
141
+ * memoize by reference — bind it to a `const` rather than calling it at each
142
+ * composition site.
143
+ */
144
+ static readonly layerFrom: (env: Readonly<Record<string, string>>) => Layer.Layer<ActionEnvironment, never, FileSystem.FileSystem>;
145
+ /**
146
+ * A test double seeded with a complete `GITHUB_*` / `RUNNER_*` block.
147
+ *
148
+ * @remarks
149
+ * **A recorded exception to the die-on-unstubbed rule.** Every other service
150
+ * in this package dies when a suite calls something it did not stub, because
151
+ * a plausible default hides a real gap. Here the opposite is true: the twelve
152
+ * context variables have one obviously-correct shape, and requiring each
153
+ * suite to restate them produced a byte-identical block duplicated six times
154
+ * across the consumers. Overrides merge on top.
155
+ */
156
+ static readonly makeTest: (overrides?: Readonly<Record<string, string>>) => Effect.Effect<ActionEnvironmentShape, never, FileSystem.FileSystem>;
157
+ /** {@link ActionEnvironment.makeTest} behind a layer, with `FileSystem` stubbed out. */
158
+ static readonly layerTest: (overrides?: Readonly<Record<string, string>>) => Layer.Layer<ActionEnvironment>;
159
+ }
160
+ //#endregion
161
+ //#region src/WorkflowCommand.d.ts
162
+ /**
163
+ * Where an annotation points in the repository.
164
+ *
165
+ * @remarks
166
+ * The field names here are the readable ones; GitHub's wire protocol uses
167
+ * abbreviations (`line`, `col`) that this module maps on the way out, so a
168
+ * caller never has to remember which of the six is abbreviated.
169
+ *
170
+ * @public
171
+ */
172
+ interface AnnotationProperties {
173
+ /** A short title shown above the annotation. */
174
+ readonly title?: string;
175
+ /** Repository-relative path of the annotated file. */
176
+ readonly file?: string;
177
+ /** First annotated line, 1-based. */
178
+ readonly startLine?: number;
179
+ /** Last annotated line, 1-based. */
180
+ readonly endLine?: number;
181
+ /** First annotated column, 1-based. */
182
+ readonly startColumn?: number;
183
+ /** Last annotated column, 1-based. */
184
+ readonly endColumn?: number;
185
+ }
186
+ /**
187
+ * The GitHub Actions workflow-command wire protocol: `::name key=value::message`.
188
+ *
189
+ * @remarks
190
+ * **Pure.** This module renders strings and nothing else — it performs no IO
191
+ * and holds no service — which is what makes the escaping rules testable
192
+ * without a runner, and what lets a non-Actions consumer reuse the protocol.
193
+ * Writing a rendered command to stdout is {@link ActionOutputs}'s job.
194
+ *
195
+ * The escaping is the whole point of the module. A message carrying a raw
196
+ * newline does not merely render oddly: the runner reads the text after it as
197
+ * a **new command**, so an unescaped log line is a command-injection vector.
198
+ *
199
+ * @example
200
+ * ```ts
201
+ * import { WorkflowCommand } from "@effected/github-actions";
202
+ *
203
+ * WorkflowCommand.error("build failed", { file: "src/main.ts", startLine: 12 });
204
+ * // "::error file=src/main.ts,line=12::build failed"
205
+ * ```
206
+ *
207
+ * @public
208
+ */
209
+ declare class WorkflowCommand {
210
+ private constructor();
211
+ /**
212
+ * Render an arbitrary command. The primitive every other member uses.
213
+ *
214
+ * @remarks
215
+ * The property type is written out structurally rather than as the module's
216
+ * `CommandProperties` alias: an internal named type on a `@public` signature
217
+ * fails the API Extractor gate, and neither an `@internal` tag nor a second
218
+ * alias helps — only inlining does.
219
+ */
220
+ static render(name: string, properties: Readonly<Record<string, string | number | boolean | undefined>>, message: string): string;
221
+ /** `::debug::` — shown only when `ACTIONS_STEP_DEBUG` is enabled. */
222
+ static debug(message: string): string;
223
+ /** `::notice::` with optional source annotation. */
224
+ static notice(message: string, properties?: AnnotationProperties): string;
225
+ /** `::warning::` with optional source annotation. */
226
+ static warning(message: string, properties?: AnnotationProperties): string;
227
+ /** `::error::` with optional source annotation. */
228
+ static error(message: string, properties?: AnnotationProperties): string;
229
+ /** `::group::` — opens a collapsible section in the runner log. */
230
+ static group(name: string): string;
231
+ /** `::endgroup::` — closes the innermost open group. */
232
+ static endGroup(): string;
233
+ /** `::add-mask::` — registers a value for redaction in the runner log. */
234
+ static addMask(value: string): string;
235
+ /** Map readable annotation fields onto GitHub's abbreviated wire names. */
236
+ private static annotation;
237
+ }
238
+ //#endregion
239
+ //#region src/ActionLogger.d.ts
240
+ /**
241
+ * The {@link ActionLogger} service shape.
242
+ *
243
+ * @public
244
+ */
245
+ interface ActionLoggerShape {
246
+ /** Run an effect inside a collapsible log group. */
247
+ readonly group: <A, E, R>(name: string, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
248
+ /**
249
+ * Run an effect with its verbose output captured and replayed on exit.
250
+ *
251
+ * @remarks
252
+ * Warnings and errors are **not** buffered — they go out as they happen, so a
253
+ * long step still reports trouble while it is running. Everything at `Info`
254
+ * and below is held and flushed on every exit path, including a defect or an
255
+ * interruption, so a clean run still prints its transcript.
256
+ *
257
+ * Buffering is skipped entirely when the runner has step debugging enabled or
258
+ * the ambient minimum log level is already `Debug` or lower — someone asking
259
+ * for verbose output wants it live.
260
+ */
261
+ readonly withBuffer: <A, E, R>(label: string, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
262
+ /**
263
+ * Emit a `::notice::` annotation.
264
+ *
265
+ * @remarks
266
+ * A dedicated member rather than a log level, because Effect has no level
267
+ * between `Info` and `Warn` to map onto notices.
268
+ */
269
+ readonly notice: (message: string, properties?: AnnotationProperties) => Effect.Effect<void>;
270
+ /**
271
+ * Attach source annotations to every `Effect.log*` inside an effect.
272
+ *
273
+ * @remarks
274
+ * The point is that a caller never spells an annotation key: the fields go in
275
+ * as {@link AnnotationProperties} and come out as `file=`/`line=` on the
276
+ * rendered command.
277
+ */
278
+ readonly annotated: <A, E, R>(properties: AnnotationProperties, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
279
+ }
280
+ declare const ActionLogger_base: Context.ServiceClass<ActionLogger, "@effected/github-actions/ActionLogger", ActionLoggerShape>;
281
+ /**
282
+ * Groups, buffered step transcripts, notices — and the `Logger` that renders
283
+ * every `Effect.log*` in the kit as a workflow command.
284
+ *
285
+ * @remarks
286
+ * The `Logger` is the seam that lets every other `@effected` package stay
287
+ * telemetry-agnostic: libraries call `Effect.logWarning`, and exactly one
288
+ * logger — installed at the edge by an action — turns those into `::warning::`
289
+ * annotations. No library needs to know it is running inside Actions.
290
+ *
291
+ * @example
292
+ * ```ts
293
+ * import { ActionLogger } from "@effected/github-actions";
294
+ * import { Effect } from "effect";
295
+ *
296
+ * const program = Effect.gen(function* () {
297
+ * const logger = yield* ActionLogger;
298
+ * yield* logger.group("install", logger.withBuffer("pnpm", Effect.logInfo("resolving")));
299
+ * });
300
+ * ```
301
+ *
302
+ * @public
303
+ */
304
+ declare class ActionLogger extends ActionLogger_base {
305
+ static readonly layer: Layer.Layer<ActionLogger, never, ActionEnvironment>;
306
+ /**
307
+ * The `Logger` that maps Effect log levels onto workflow commands.
308
+ *
309
+ * @remarks
310
+ * `Error` and `Fatal` render `::error::`, `Warn` renders `::warning::`,
311
+ * `Debug` and `Trace` render `::debug::`, and `Info` renders as plain text.
312
+ * Annotations set by `annotated` travel with the entry.
313
+ *
314
+ * It writes through core `Console`, which is what makes its output
315
+ * observable in a test without a runner.
316
+ */
317
+ static readonly logger: Logger.Logger<unknown, void>;
318
+ /** {@link ActionLogger.logger} installed as the only logger. */
319
+ static readonly layerLogger: Layer.Layer<never>;
320
+ /**
321
+ * A silent double.
322
+ *
323
+ * @remarks
324
+ * **A recorded exception to the die-on-unstubbed rule**, alongside
325
+ * {@link ActionEnvironment.makeTest}. A logger that dies when a suite logs
326
+ * would make every double unusable, and silence is the honest default for a
327
+ * service whose whole job is output. Group and buffer wrappers pass their
328
+ * effect through unchanged.
329
+ */
330
+ static readonly makeTest: (overrides?: Partial<ActionLoggerShape>) => ActionLoggerShape;
331
+ /** {@link ActionLogger.makeTest} behind `Layer.succeed`. */
332
+ static readonly layerTest: (overrides?: Partial<ActionLoggerShape>) => Layer.Layer<ActionLogger>;
333
+ /**
334
+ * A silent service **and** a silent `Effect.log*`.
335
+ *
336
+ * @remarks
337
+ * This one layer replaces the bare `Effect.provide(Logger.layer([]))` that
338
+ * appeared thirteen times in one consuming action and twenty-three in
339
+ * another, purely to keep test output quiet. Bound to a constant rather than
340
+ * exposed as a factory, so composing it twice is free.
341
+ */
342
+ static readonly layerSilent: Layer.Layer<ActionLogger>;
343
+ }
344
+ //#endregion
345
+ //#region src/ActionOutputs.d.ts
346
+ declare const ActionOutputError_base: Schema.Class<ActionOutputError, Schema.TaggedStruct<"ActionOutputError", {
347
+ /**
348
+ * `unavailable` — the runner file variable is not set, which usually means
349
+ * the code is running outside a GitHub runner. `writeFailed` — the file
350
+ * exists but could not be appended to. `invalidName` — the name would
351
+ * corrupt the file's block structure. `encodeFailed` — a value did not
352
+ * satisfy its schema.
353
+ */
354
+ readonly reason: Schema.Literals<readonly ["unavailable", "writeFailed", "invalidName", "encodeFailed"]>;
355
+ /** Which runner file was involved, by environment variable name. */
356
+ readonly file: Schema.optionalKey<Schema.String>;
357
+ /** The output or variable name, when one is involved. */
358
+ readonly name: Schema.optionalKey<Schema.String>;
359
+ /** The underlying failure, preserved structurally. */
360
+ readonly cause: Schema.optionalKey<Schema.Defect>;
361
+ }>, import("effect/Cause").YieldableError>;
362
+ /**
363
+ * Raised when an action cannot publish an output.
364
+ *
365
+ * @public
366
+ */
367
+ declare class ActionOutputError extends ActionOutputError_base {
368
+ get message(): string;
369
+ }
370
+ /**
371
+ * The {@link ActionOutputs} service shape.
372
+ *
373
+ * @public
374
+ */
375
+ interface ActionOutputsShape {
376
+ /** Publish a step output. */
377
+ readonly set: (name: string, value: string) => Effect.Effect<void, ActionOutputError>;
378
+ /** Publish a step output as JSON, encoded through a schema. */
379
+ readonly setJson: <A, I>(name: string, value: A, schema: Schema.Codec<A, I>) => Effect.Effect<void, ActionOutputError>;
380
+ /** Append to the job summary. */
381
+ readonly summary: (content: string) => Effect.Effect<void, ActionOutputError>;
382
+ /** Export an environment variable to **subsequent** steps. */
383
+ readonly exportVariable: (name: string, value: string) => Effect.Effect<void, ActionOutputError>;
384
+ /** Prepend a directory to `PATH` for subsequent steps. */
385
+ readonly addPath: (path: string) => Effect.Effect<void, ActionOutputError>;
386
+ /** Emit an error annotation. Does not itself set the exit code. */
387
+ readonly setFailed: (message: string) => Effect.Effect<void>;
388
+ /** Register a value for redaction in the runner log. */
389
+ readonly setSecret: (value: string) => Effect.Effect<void>;
390
+ }
391
+ declare const ActionOutputs_base: Context.ServiceClass<ActionOutputs, "@effected/github-actions/ActionOutputs", ActionOutputsShape>;
392
+ /**
393
+ * Everything an action publishes: step outputs, exported variables, `PATH`
394
+ * additions, the job summary, log masking and failure annotations.
395
+ *
396
+ * @remarks
397
+ * Outputs and variables go to the runner's **files** (`GITHUB_OUTPUT` and
398
+ * friends); masking and annotations go to stdout as workflow commands, through
399
+ * core `Console` so a test can observe them without a runner.
400
+ *
401
+ * `setFailed` emits the annotation but does **not** set the process exit code
402
+ * — that is `Action.run`'s job, so that an action which reports a failure and
403
+ * then recovers is not silently doomed by a side effect it cannot undo.
404
+ *
405
+ * @public
406
+ */
407
+ declare class ActionOutputs extends ActionOutputs_base {
408
+ static readonly layer: Layer.Layer<ActionOutputs, never, ActionEnvironment | FileSystem.FileSystem>;
409
+ /** A test double. Unstubbed members die rather than silently succeeding. */
410
+ static readonly makeTest: (overrides?: Partial<ActionOutputsShape>) => ActionOutputsShape;
411
+ /** {@link ActionOutputs.makeTest} behind `Layer.succeed`. */
412
+ static readonly layerTest: (overrides?: Partial<ActionOutputsShape>) => Layer.Layer<ActionOutputs>;
413
+ }
414
+ //#endregion
415
+ //#region src/ActionState.d.ts
416
+ declare const ActionStateError_base: Schema.Class<ActionStateError, Schema.TaggedStruct<"ActionStateError", {
417
+ /**
418
+ * `missing` — no value was saved under this key in an earlier phase.
419
+ * `malformed` — a value is there but is not JSON, or does not satisfy the
420
+ * schema it was read with. `writeFailed` — the state file could not be
421
+ * appended to.
422
+ */
423
+ readonly reason: Schema.Literals<readonly ["missing", "malformed", "writeFailed"]>;
424
+ readonly key: Schema.String;
425
+ readonly cause: Schema.optionalKey<Schema.Defect>;
426
+ }>, import("effect/Cause").YieldableError>;
427
+ /**
428
+ * Raised when state cannot cross the phase boundary.
429
+ *
430
+ * @public
431
+ */
432
+ declare class ActionStateError extends ActionStateError_base {
433
+ get message(): string;
434
+ }
435
+ /**
436
+ * The {@link ActionState} service shape.
437
+ *
438
+ * @public
439
+ */
440
+ interface ActionStateShape {
441
+ /** Persist a value for a later phase. */
442
+ readonly save: <A, I>(key: string, value: A, schema: Schema.Codec<A, I>) => Effect.Effect<void, ActionStateError>;
443
+ /** Read a value saved by an earlier phase. */
444
+ readonly get: <A, I>(key: string, schema: Schema.Codec<A, I>) => Effect.Effect<A, ActionStateError>;
445
+ /** Read a value that may not have been saved. */
446
+ readonly getOptional: <A, I>(key: string, schema: Schema.Codec<A, I>) => Effect.Effect<Option.Option<A>, ActionStateError>;
447
+ /**
448
+ * Persist a secret, masking it in the runner log first.
449
+ *
450
+ * @remarks
451
+ * `GITHUB_STATE` is plaintext by GitHub's protocol — a `Redacted` cannot
452
+ * survive that boundary by design — so masking is the only available
453
+ * defense, and coupling it to the write is what makes it unforgettable.
454
+ */
455
+ readonly saveSecret: (key: string, secret: string) => Effect.Effect<void, ActionStateError>;
456
+ }
457
+ declare const ActionState_base: Context.ServiceClass<ActionState, "@effected/github-actions/ActionState", ActionStateShape>;
458
+ /**
459
+ * State that survives the `pre` → `main` → `post` phase boundary.
460
+ *
461
+ * @remarks
462
+ * Each phase of an action is a **separate process**. GitHub's protocol is a
463
+ * write-only file (`GITHUB_STATE`) whose entries the runner republishes to the
464
+ * next phase as `STATE_<key>` environment variables — so saving and reading go
465
+ * through different mechanisms, which is why this is a service rather than a
466
+ * pair of helpers.
467
+ *
468
+ * @public
469
+ */
470
+ declare class ActionState extends ActionState_base {
471
+ static readonly layer: Layer.Layer<ActionState, never, ActionEnvironment | FileSystem.FileSystem | ActionOutputs>;
472
+ /** A test double. Unstubbed members die rather than answering wrongly. */
473
+ static readonly makeTest: (overrides?: Partial<ActionStateShape>) => ActionStateShape;
474
+ /** {@link ActionState.makeTest} behind `Layer.succeed`. */
475
+ static readonly layerTest: (overrides?: Partial<ActionStateShape>) => Layer.Layer<ActionState>;
476
+ }
477
+ //#endregion
478
+ //#region src/Action.d.ts
479
+ /**
480
+ * Everything {@link ActionRuntime.layer} provides.
481
+ *
482
+ * @remarks
483
+ * Spelled out rather than inferred so a caller can name it — a program written
484
+ * against `ActionServices` is a program `Action.run` can run, and the compiler
485
+ * says so before the runner does.
486
+ *
487
+ * @public
488
+ */
489
+ type ActionServices = ActionEnvironment | ActionLogger | ActionOutputs | ActionState | NodeServices.NodeServices | HttpClient.HttpClient;
490
+ /**
491
+ * The default runtime an action executes inside.
492
+ *
493
+ * @remarks
494
+ * The one place in the kit where `@effect/platform-node` is composed rather
495
+ * than left to the consumer, and the reason is that there is no second answer:
496
+ * a GitHub Action is a Node process on a GitHub-provided runner.
497
+ *
498
+ * **The cache, artifact and blob services are deliberately NOT in here.** They
499
+ * are the only modules that import `@azure/storage-blob`, and folding them into
500
+ * the default runtime would put a blob-storage client in the bundle of every
501
+ * action that merely sets an output. Their requirements are all satisfied by
502
+ * this layer, so taking one costs a caller exactly one line:
503
+ * `Action.run(program, { layer: ActionCache.layer })`.
504
+ *
505
+ * @public
506
+ */
507
+ declare class ActionRuntime {
508
+ private constructor();
509
+ /**
510
+ * The composed default: the runner services, the platform, an HTTP client
511
+ * and the workflow-command `Logger`.
512
+ *
513
+ * @remarks
514
+ * A bound constant rather than a factory. A layer-returning function mints a
515
+ * fresh layer per call, and layers memoize by reference — a factory here
516
+ * would rebuild the environment snapshot for every composition site.
517
+ */
518
+ static readonly layer: Layer.Layer<ActionServices>;
519
+ }
520
+ /**
521
+ * How to run an action.
522
+ *
523
+ * @public
524
+ */
525
+ interface ActionRunOptions<R> {
526
+ /**
527
+ * Services the program needs beyond {@link ActionServices}.
528
+ *
529
+ * @remarks
530
+ * It may require anything {@link ActionRuntime.layer} provides — which is
531
+ * what makes `{ layer: ActionCache.layer }` compile with no further wiring.
532
+ */
533
+ readonly layer?: Layer.Layer<R, never, ActionServices> | undefined;
534
+ }
535
+ /**
536
+ * A readable one-line summary of why an action failed.
537
+ *
538
+ * @remarks
539
+ * `[Tag] message` because a workflow log is read by a human scanning for the
540
+ * first red line, and every error in this kit carries both. The `_tag` is what
541
+ * makes two failures with the same wording distinguishable, and the `message`
542
+ * getter is what makes the line worth reading.
543
+ *
544
+ * An interruption has neither, and `Cause.pretty` is the honest answer for it.
545
+ *
546
+ * @public
547
+ */
548
+ declare const describeCause: (cause: Cause.Cause<unknown>) => string;
549
+ /**
550
+ * The entry point an action's `main`, `pre` and `post` scripts call.
551
+ *
552
+ * @remarks
553
+ * Everything an action entry point does that is not the action: compose the
554
+ * runtime, run the program, render a failure as a `::error::` annotation, and
555
+ * **set the exit code** — which is the piece
556
+ * `ActionOutputs.setFailed` deliberately leaves alone, so an action that
557
+ * reports a failure and then recovers is not doomed by a side effect it cannot
558
+ * undo.
559
+ *
560
+ * Two things it deliberately does **not** do:
561
+ *
562
+ * - **It does not wrap the program in a log buffer.** The package this replaces
563
+ * did, and an unhandled defect inside the buffer swallowed the entire
564
+ * transcript — the run failed and printed nothing. `ActionLogger.withBuffer`
565
+ * is opt-in and flushes on every exit path including a defect, so the
566
+ * buffering is where the caller can see it.
567
+ * - **It does not throw.** The returned promise always resolves; the failure is
568
+ * in `process.exitCode`, which is what the runner reads. An action entry
569
+ * point that rejected would produce an unhandled rejection *and* a failed
570
+ * step, and only the first would be legible.
571
+ *
572
+ * The rendering depth is deliberate too: one `::error::` line carrying
573
+ * `[Tag]: message`, and the fiddly diagnostics — the full `Cause.pretty` render
574
+ * with its span trace and stack — behind `::debug::`, which the runner shows
575
+ * only when someone turns step debugging on. The package this replaces spliced
576
+ * a JS stack into the visible error, which in a bundled action points at one
577
+ * line of `dist/main.js`.
578
+ *
579
+ * @example
580
+ * ```ts
581
+ * import { Action, ActionCache } from "@effected/github-actions";
582
+ *
583
+ * await Action.run(program, { layer: ActionCache.layer });
584
+ * ```
585
+ *
586
+ * @public
587
+ */
588
+ declare class Action {
589
+ private constructor();
590
+ /** {@link describeCause}, so an action can render its own failures the same way. */
591
+ static readonly describeCause: (cause: Cause.Cause<unknown>) => string;
592
+ /**
593
+ * Run an action program to completion.
594
+ *
595
+ * @remarks
596
+ * Resolves whether the program succeeded or not; read `process.exitCode` for
597
+ * the verdict.
598
+ */
599
+ static readonly run: <E, R = never>(program: Effect.Effect<void, E, ActionServices | R>, options?: ActionRunOptions<R>) => Promise<void>;
600
+ }
601
+ //#endregion
602
+ //#region src/BlobTransfer.d.ts
603
+ declare const BlobTransferError_base: Schema.Class<BlobTransferError, Schema.TaggedStruct<"BlobTransferError", {
604
+ /** Which direction failed. */
605
+ readonly reason: Schema.Literals<readonly ["uploadFailed", "downloadFailed"]>;
606
+ /** The underlying failure, preserved structurally. */
607
+ readonly cause: Schema.optionalKey<Schema.Defect>;
608
+ }>, import("effect/Cause").YieldableError>;
609
+ /**
610
+ * Raised when bytes could not be moved to or from a signed blob url.
611
+ *
612
+ * @public
613
+ */
614
+ declare class BlobTransferError extends BlobTransferError_base {
615
+ get message(): string;
616
+ }
617
+ /**
618
+ * Moving whole files to and from the signed blob url a results-backend RPC
619
+ * hands back.
620
+ *
621
+ * @remarks
622
+ * The seam exists because the *protocol* is what this package owns and the
623
+ * *transport* is not: the Actions results backend answers a Twirp RPC with a
624
+ * pre-signed Azure url, and everything interesting — the RPC sequence, the
625
+ * conflict handling, the retry policy, the version hash — happens on this side
626
+ * of it. Taking the transport as an argument means all of that is exercised by
627
+ * a test rather than described by one, and the Azure client stays confined to
628
+ * the three modules permitted to import it.
629
+ *
630
+ * A url is a plain string on purpose: it is a **credential** (the signature is
631
+ * in the query), and it is never logged, annotated on a span, or carried on an
632
+ * error.
633
+ *
634
+ * @public
635
+ */
636
+ interface FileBlobTransfer {
637
+ /** Upload a file's contents to the url. */
638
+ readonly uploadFile: (url: string, file: string) => Effect.Effect<void, BlobTransferError>;
639
+ /** Download the url's contents into a file. */
640
+ readonly downloadToFile: (url: string, file: string) => Effect.Effect<void, BlobTransferError>;
641
+ }
642
+ /**
643
+ * Moving in-memory bytes to and from a signed blob url.
644
+ *
645
+ * @remarks
646
+ * The {@link FileBlobTransfer} counterpart for payloads that never touch the
647
+ * filesystem. Split rather than merged because the cache and artifact protocols
648
+ * only ever move files and the blob store only ever moves buffers — a single
649
+ * four-member interface would make every implementation stub two members it can
650
+ * never be asked for.
651
+ *
652
+ * @public
653
+ */
654
+ interface DataBlobTransfer {
655
+ /** Upload bytes to the url. */
656
+ readonly uploadData: (url: string, data: Uint8Array) => Effect.Effect<void, BlobTransferError>;
657
+ /** Download the url's contents. */
658
+ readonly downloadToBuffer: (url: string) => Effect.Effect<Uint8Array, BlobTransferError>;
659
+ }
660
+ //#endregion
661
+ //#region src/CacheKey.d.ts
662
+ declare const CacheKeyError_base: Schema.Class<CacheKeyError, Schema.TaggedStruct<"CacheKeyError", {
663
+ /**
664
+ * `readFailed` — a file or directory that was going to be hashed could not be
665
+ * read. `badPattern` — a glob pattern would not compile. Key *derivation*
666
+ * itself is pure and total once the bytes are in hand, so these are the only
667
+ * two things that can go wrong.
668
+ */
669
+ readonly reason: Schema.Literals<readonly ["readFailed", "badPattern"]>;
670
+ /** The path being read when it went wrong. */
671
+ readonly path: Schema.optionalKey<Schema.String>;
672
+ /** The pattern that would not compile. */
673
+ readonly pattern: Schema.optionalKey<Schema.String>;
674
+ /** The underlying failure, preserved structurally. */
675
+ readonly cause: Schema.optionalKey<Schema.Defect>;
676
+ }>, import("effect/Cause").YieldableError>;
677
+ /**
678
+ * Raised when a cache key cannot be derived from the filesystem.
679
+ *
680
+ * @public
681
+ */
682
+ declare class CacheKeyError extends CacheKeyError_base {
683
+ get message(): string;
684
+ }
685
+ declare const CacheKey_base: Schema.Class<CacheKey, Schema.Struct<{
686
+ /** The components, most general first. */
687
+ readonly segments: Schema.NonEmptyArray<Schema.String>;
688
+ }>, {}>;
689
+ /**
690
+ * A GitHub Actions cache key and the restore-key ladder that goes with it.
691
+ *
692
+ * @remarks
693
+ * The ladder is the part every consumer re-derives and gets subtly wrong. A
694
+ * restore key is a **prefix match** on GitHub's side, so `Linux-pnpm` would
695
+ * also match `Linux-pnpm-store-…` from an unrelated cache; every rung here
696
+ * therefore ends in the separator. Deriving the rungs from the segments makes
697
+ * the primary key and its fallbacks impossible to drift apart, which is the
698
+ * failure that produces a cache that never hits and never says why.
699
+ *
700
+ * @example
701
+ * ```ts
702
+ * import { CacheKey } from "@effected/github-actions";
703
+ *
704
+ * const key = CacheKey.of("Linux", "pnpm-store", "abc123");
705
+ * key.key; // "Linux-pnpm-store-abc123"
706
+ * key.restoreKeys; // ["Linux-pnpm-store-", "Linux-"]
707
+ * ```
708
+ *
709
+ * @public
710
+ */
711
+ declare class CacheKey extends CacheKey_base {
712
+ /** The primary key: every segment, joined. */
713
+ get key(): string;
714
+ /**
715
+ * The restore keys, most specific first.
716
+ *
717
+ * @remarks
718
+ * Each rung drops the last segment and keeps the trailing separator, so a
719
+ * three-segment key falls back to two prefixes and a one-segment key falls
720
+ * back to nothing — there is no rung that would match every cache in the
721
+ * repository.
722
+ */
723
+ get restoreKeys(): ReadonlyArray<string>;
724
+ /** Build a key from its segments. */
725
+ static of(...segments: readonly [string, ...ReadonlyArray<string>]): CacheKey;
726
+ /**
727
+ * A branch-aware key.
728
+ *
729
+ * @remarks
730
+ * Ordering the segments `os → scope → branch → hash` is what makes the
731
+ * derived ladder do the right thing: the first rung falls back to any earlier
732
+ * cache **on this branch**, and only the next one reaches across branches. The
733
+ * reverse order would make the first fallback jump branches, which is how a
734
+ * feature branch ends up warming its cache from `main` and never noticing its
735
+ * own.
736
+ *
737
+ * Every part is an explicit argument rather than read from the environment,
738
+ * so a key is reproducible outside a runner and a test needs no ambient
739
+ * state.
740
+ */
741
+ static forBranch(options: {
742
+ /** What is being cached, e.g. `"pnpm-store"`. */
743
+ readonly scope: string;
744
+ /** The short ref, e.g. `GITHUB_REF_NAME`. */
745
+ readonly branch: string;
746
+ /** The runner OS, e.g. `RUNNER_OS`. Included first when given. */
747
+ readonly os?: string;
748
+ /** The content hash, e.g. from {@link CacheKey.hashFiles}. Included last when given. */
749
+ readonly hash?: string;
750
+ }): CacheKey;
751
+ /**
752
+ * Hash a set of files into a single digest.
753
+ *
754
+ * @remarks
755
+ * **Byte-compatible with `@actions/glob`'s `hashFiles`**, and the three
756
+ * details that make it so are all easy to get wrong: the paths are sorted, each
757
+ * file is hashed on its own, and the per-file digest is fed into the
758
+ * accumulator as **binary** rather than hex. A hex-fed accumulator produces a
759
+ * perfectly plausible digest that simply never matches a cache entry written
760
+ * by any other action.
761
+ *
762
+ * Sorting and de-duplication happen here rather than at the call site, so a
763
+ * caller cannot accidentally make its key depend on the order it discovered
764
+ * files in.
765
+ *
766
+ * `Option.none()` for an empty set, because "nothing matched" is not a
767
+ * digest — it is the signal that the pattern is wrong, and a caller that
768
+ * folds it into a key silently caches against a constant.
769
+ */
770
+ static readonly hashFiles: (files: readonly string[]) => Effect.Effect<Option.Option<string>, CacheKeyError, FileSystem.FileSystem>;
771
+ /**
772
+ * Every file under `workspace` that the pattern set matches.
773
+ *
774
+ * @remarks
775
+ * Discovery and matching are **two different jobs**, and separating them is
776
+ * what makes this testable and correct. The walk is core
777
+ * `FileSystem.readDirectory(recursive)`; the matching is `@effected/glob`'s
778
+ * full minimatch dialect — the same dialect `@actions/glob` uses, so a workflow
779
+ * author's `!**\/node_modules/**` behaves here exactly as it does in every
780
+ * other cache step in the same workflow. `node:fs.globSync` would have welded
781
+ * the two together behind one non-stubbable call *and* changed the dialect,
782
+ * and a dialect divergence surfaces as a silent cache-key difference — the
783
+ * worst failure mode a cache key has.
784
+ *
785
+ * Candidates are matched by their path **relative to the workspace**, which
786
+ * is what makes "never hash a file outside the workspace" structural rather
787
+ * than a rule someone has to remember. Directories are excluded: a directory
788
+ * called `notes.txt` matches `**\/*.txt` and is not a file, and hashing it
789
+ * would fail rather than being ignored.
790
+ *
791
+ * The answer is sorted, so a caller cannot make its key depend on the order
792
+ * the filesystem happened to report.
793
+ */
794
+ static readonly matchingFiles: (options: {
795
+ /** The directory to walk. Nothing outside it is ever considered. */
796
+ readonly workspace: string;
797
+ /** Include patterns, with a leading `!` marking an exclusion. */
798
+ readonly patterns: ReadonlyArray<string>;
799
+ }) => Effect.Effect<readonly string[], CacheKeyError, FileSystem.FileSystem | Path.Path>;
800
+ /**
801
+ * Hash every file under `workspace` that the pattern set matches.
802
+ *
803
+ * @remarks
804
+ * {@link CacheKey.matchingFiles} into {@link CacheKey.hashFiles}, which is
805
+ * the pairing every consumer writes by hand — and the pairing whose two
806
+ * halves have to agree about ordering and about what counts as a file for the
807
+ * digest to match anything anyone else computed.
808
+ *
809
+ * `Option.none()` when nothing matched, for the same reason `hashFiles` gives:
810
+ * "no files" is not a digest, it is the signal that the patterns are wrong,
811
+ * and folding it into a key silently caches against a constant.
812
+ *
813
+ * @example
814
+ * ```ts
815
+ * import { CacheKey } from "@effected/github-actions";
816
+ * import { Effect, Option } from "effect";
817
+ *
818
+ * const key = Effect.gen(function* () {
819
+ * const hash = yield* CacheKey.hashMatching({
820
+ * workspace: "/home/runner/work/repo/repo",
821
+ * patterns: ["**\/pnpm-lock.yaml", "!**\/node_modules/**"],
822
+ * });
823
+ * return CacheKey.of("Linux", "pnpm-store", Option.getOrElse(hash, () => "empty"));
824
+ * });
825
+ * ```
826
+ */
827
+ static readonly hashMatching: (options: {
828
+ readonly workspace: string;
829
+ readonly patterns: ReadonlyArray<string>;
830
+ }) => Effect.Effect<Option.Option<string>, CacheKeyError, FileSystem.FileSystem | Path.Path>;
831
+ }
832
+ //#endregion
833
+ //#region src/ActionCache.d.ts
834
+ declare const ActionCacheError_base: Schema.Class<ActionCacheError, Schema.TaggedStruct<"ActionCacheError", {
835
+ /**
836
+ * `misconfigured` — the results backend is not reachable from here (see
837
+ * {@link ActionCache}). `unreachable` — it could not be contacted, or
838
+ * answered with something that is not a Twirp body. `refused` — it answered,
839
+ * unhappily. `archiveFailed` — `tar` would not pack or unpack the paths.
840
+ * `transferFailed` — the archive itself did not move.
841
+ */
842
+ readonly reason: Schema.Literals<readonly ["misconfigured", "unreachable", "refused", "archiveFailed", "transferFailed"]>;
843
+ /** The cache key involved. A stable identifier, never a value. */
844
+ readonly key: Schema.optionalKey<Schema.String>;
845
+ /** The HTTP status, when the backend answered. */
846
+ readonly status: Schema.optionalKey<Schema.Number>;
847
+ /** What went wrong, when the reason alone does not say. */
848
+ readonly detail: Schema.optionalKey<Schema.String>;
849
+ /** `tar`'s own complaint, which is the only useful part of an archive failure. */
850
+ readonly stderr: Schema.optionalKey<Schema.String>;
851
+ /** The underlying failure, preserved structurally. */
852
+ readonly cause: Schema.optionalKey<Schema.Defect>;
853
+ }>, import("effect/Cause").YieldableError>;
854
+ /**
855
+ * Raised when the runner's cache cannot be read or written.
856
+ *
857
+ * @public
858
+ */
859
+ declare class ActionCacheError extends ActionCacheError_base {
860
+ get message(): string;
861
+ }
862
+ /**
863
+ * The {@link ActionCache} service shape.
864
+ *
865
+ * @public
866
+ */
867
+ interface ActionCacheShape {
868
+ /**
869
+ * Archive `paths` and store them under `key`.
870
+ *
871
+ * @remarks
872
+ * A key that already exists is a **success**: cache entries are immutable, so
873
+ * another job having written it first is the outcome the caller wanted.
874
+ */
875
+ readonly save: (paths: ReadonlyArray<string>, key: string | CacheKey) => Effect.Effect<void, ActionCacheError>;
876
+ /**
877
+ * Restore `paths` from the first entry that matches, and answer with the key
878
+ * that matched.
879
+ *
880
+ * @remarks
881
+ * `Option.none()` is a miss, not a failure — a cold cache is the normal state
882
+ * of a new branch. Passing a {@link CacheKey} supplies its restore-key ladder
883
+ * automatically; passing a `string` and no ladder means "this key or nothing".
884
+ */
885
+ readonly restore: (paths: ReadonlyArray<string>, key: string | CacheKey, restoreKeys?: ReadonlyArray<string>) => Effect.Effect<Option.Option<string>, ActionCacheError>;
886
+ }
887
+ declare const ActionCache_base: Context.ServiceClass<ActionCache, "@effected/github-actions/ActionCache", ActionCacheShape>;
888
+ /**
889
+ * The runner's own cache: archive a set of paths under a key, and get them back
890
+ * in a later job.
891
+ *
892
+ * @remarks
893
+ * Speaks the Actions cache **Twirp v2** protocol at `ACTIONS_RESULTS_URL`,
894
+ * which answers with a pre-signed Azure blob url for the archive itself. No
895
+ * `@actions/cache` dependency — that package alone brings a dependency tree
896
+ * larger than this one.
897
+ *
898
+ * **Only reachable from a `uses:` step.** The runner injects
899
+ * `ACTIONS_RESULTS_URL` and `ACTIONS_RUNTIME_TOKEN` into action execution
900
+ * contexts and not into `run:` shell steps, so the identical code fails as
901
+ * `misconfigured` when a workflow invokes it with `node ./main.js`. The failure
902
+ * names the absent variable, because nothing else distinguishes the two cases.
903
+ *
904
+ * @example
905
+ * ```ts
906
+ * import { ActionCache, CacheKey } from "@effected/github-actions";
907
+ * import { Effect, Option } from "effect";
908
+ *
909
+ * const program = Effect.gen(function* () {
910
+ * const cache = yield* ActionCache;
911
+ * const key = CacheKey.of("Linux", "pnpm-store", "abc123");
912
+ * const hit = yield* cache.restore(["~/.pnpm-store"], key);
913
+ * if (Option.isNone(hit)) {
914
+ * yield* cache.save(["~/.pnpm-store"], key);
915
+ * }
916
+ * });
917
+ * ```
918
+ *
919
+ * @public
920
+ */
921
+ declare class ActionCache extends ActionCache_base {
922
+ /** The cache, over the real Azure client and the real `tar`. */
923
+ static readonly layer: Layer.Layer<ActionCache, never, ActionEnvironment | HttpClient.HttpClient | FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
924
+ /**
925
+ * The cache, over a supplied transport.
926
+ *
927
+ * @remarks
928
+ * The protocol, the version derivation, the conflict handling and the archive
929
+ * are what this package owns; the pre-signed `PUT` is not. Supplying the
930
+ * transport is what lets a test exercise all of the first group without the
931
+ * second, and what an integration test uses to point the same protocol at a
932
+ * local blob endpoint.
933
+ *
934
+ * A parameterized layer factory mints a fresh layer per call and layers
935
+ * memoize by reference — bind it to a `const` rather than calling it at each
936
+ * composition site.
937
+ */
938
+ static readonly layerWith: (transfer: FileBlobTransfer) => Layer.Layer<ActionCache, never, ActionEnvironment | HttpClient.HttpClient | FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
939
+ /** A test double. Unstubbed members die rather than reporting a miss. */
940
+ static readonly makeTest: (overrides?: Partial<ActionCacheShape>) => ActionCacheShape;
941
+ /** {@link ActionCache.makeTest} behind `Layer.succeed`. */
942
+ static readonly layerTest: (overrides?: Partial<ActionCacheShape>) => Layer.Layer<ActionCache>;
943
+ }
944
+ //#endregion
945
+ //#region src/ActionInput.d.ts
946
+ /**
947
+ * Action inputs, read as `Config` values.
948
+ *
949
+ * @remarks
950
+ * Inputs are **never** read from `process.env` directly. Every accessor names
951
+ * the input the way the workflow author wrote it and lets this module derive
952
+ * the runner's variable name — see `inputVariable` for why that matters. (A
953
+ * `{@link}` cannot reach it: it is internal, so it is not exported from the
954
+ * entrypoint and the reference would not resolve.)
955
+ *
956
+ * `lines`, `list` and `pairs` exist because the `@actions/core`-faithful
957
+ * newline split was not enough for real consumers: two of them reinvented
958
+ * richer parsing independently, one parsing JSON arrays and bullet lists, the
959
+ * other stripping comments and reading `key=value` pairs. Those are now one
960
+ * implementation with one set of tests instead of two divergent ones with
961
+ * none.
962
+ *
963
+ * These are grouped statics over one concept reaching nothing but `Config` —
964
+ * not a namespace object over engines.
965
+ *
966
+ * **The absence contract, shared by every accessor:** the runner writes `""`
967
+ * for an input the workflow left out, and the provider reads an empty string
968
+ * as absent — so *unset* and *empty* are the same case, **missing data**, and
969
+ * the read fails rather than yielding an empty value. `Config.withDefault`
970
+ * falls back for exactly that class, which makes
971
+ * `.pipe(Config.withDefault(…))` the idiom for every optional input. What a
972
+ * default never swallows is a *present but malformed* value — see
973
+ * {@link ActionInput.boolean}.
974
+ *
975
+ * @example
976
+ * ```ts
977
+ * import { ActionInput } from "@effected/github-actions";
978
+ * import { Effect } from "effect";
979
+ *
980
+ * const program = Effect.gen(function* () {
981
+ * const dryRun = yield* ActionInput.boolean("dry-run");
982
+ * const globs = yield* ActionInput.list("paths");
983
+ * });
984
+ * ```
985
+ *
986
+ * @public
987
+ */
988
+ declare class ActionInput {
989
+ private constructor();
990
+ /**
991
+ * A required string input.
992
+ *
993
+ * @remarks
994
+ * Fails as *missing data* when the input is absent **or set to the empty
995
+ * string** — the runner writes `""` for an unsupplied input, and both the
996
+ * runtime's provider and {@link ActionInput.provider} read that as absent.
997
+ * Every accessor on this class shares the rule, so an **optional** input
998
+ * needs `Config.withDefault` (or `Config.option`) at the call site or the
999
+ * read fails outright.
1000
+ */
1001
+ static string(name: string): Config.Config<string>;
1002
+ /**
1003
+ * A boolean input, per the runner's documented YAML 1.2 core schema.
1004
+ *
1005
+ * @remarks
1006
+ * Absent or `""` is **missing data** — wrap with `Config.withDefault` for
1007
+ * an optional flag. A **present but malformed** value (`yes`, `on`, `1`) is
1008
+ * a different class: it fails carrying its `actual`, deliberately, so a
1009
+ * default does NOT swallow it — the shipped defect this guards against was
1010
+ * a malformed `dry-run` quietly reading as `false`.
1011
+ */
1012
+ static boolean(name: string): Config.Config<boolean>;
1013
+ /**
1014
+ * An integer input.
1015
+ *
1016
+ * @remarks
1017
+ * Unset and `""` both fail as **missing data**; for an optional input,
1018
+ * `.pipe(Config.withDefault(n))`.
1019
+ */
1020
+ static integer(name: string): Config.Config<number>;
1021
+ /**
1022
+ * A secret input, kept redacted.
1023
+ *
1024
+ * @remarks
1025
+ * Unset and `""` both fail as **missing data**; `Config.option` is the
1026
+ * usual shape for an optional secret, since there is rarely a meaningful
1027
+ * default to redact.
1028
+ */
1029
+ static redacted(name: string): Config.Config<Redacted.Redacted<string>>;
1030
+ /**
1031
+ * A multiline input, split on newlines.
1032
+ *
1033
+ * @remarks
1034
+ * The `@actions/core`-faithful shape: blank lines are dropped and each entry
1035
+ * is trimmed, because a YAML block scalar carries the workflow's own
1036
+ * indentation.
1037
+ *
1038
+ * Absent or `""` fails as missing data (see {@link ActionInput.string}) —
1039
+ * `Config.withDefault([])` is load-bearing for an optional multiline input.
1040
+ */
1041
+ static lines(name: string): Config.Config<ReadonlyArray<string>>;
1042
+ /**
1043
+ * A list input, accepting the shapes workflow authors actually write.
1044
+ *
1045
+ * @remarks
1046
+ * A JSON array (`["a","b"]`), a bullet list (`- a` or `* a`), or comma- and
1047
+ * newline-separated values, with full-line `#` comments dropped — any
1048
+ * combination of these in the same input. Each shape was reinvented
1049
+ * independently by a consumer (one a bullet-list-and-JSON parser, the other
1050
+ * comment-stripping); accepting the union means a workflow author's first
1051
+ * guess works and nothing either prior consumer relied on regresses.
1052
+ *
1053
+ * Parsing order, applied per newline/comma-separated item after trimming:
1054
+ *
1055
+ * 1. **Comment lines are dropped first.** A trimmed item whose first
1056
+ * character is `#` is a full-line comment and is discarded entirely,
1057
+ * before any bullet marker is considered. This means `- #tag` is a
1058
+ * value, not a comment: the check runs on the untouched, still-bulleted
1059
+ * item, and `-` is not `#`.
1060
+ * 2. **Only then is a leading bullet marker stripped** — `- ` or `* `
1061
+ * (dash-or-asterisk followed by a space), mirroring the indentation a
1062
+ * YAML block scalar carries in. So `- #tag` becomes the value `#tag`.
1063
+ * 3. Blank results (an empty line, or a comment line) are dropped from the
1064
+ * final list.
1065
+ *
1066
+ * A `#` that is not the first character of a trimmed item — a trailing or
1067
+ * mid-value `#` — is left alone; unlike {@link ActionInput.pairs}, `list`
1068
+ * has no trailing-comment rule, only a whole-line one.
1069
+ *
1070
+ * Absent or `""` fails as **missing data** (see {@link ActionInput.string}),
1071
+ * so `Config.withDefault([])` is load-bearing at every optional-input call
1072
+ * site — omitting an optional multi-value input otherwise fails the read
1073
+ * outright. A *whitespace-only* value (a block scalar holding only a
1074
+ * newline) is present, and parses to `[]`.
1075
+ */
1076
+ static list(name: string): Config.Config<ReadonlyArray<string>>;
1077
+ /**
1078
+ * A `key=value` input, one pair per line, with `#` comments stripped.
1079
+ *
1080
+ * @remarks
1081
+ * Only the **first** `=` splits, so a value may contain one.
1082
+ *
1083
+ * Absent or `""` fails as missing data (see {@link ActionInput.string}) —
1084
+ * `Config.withDefault({})` is the idiom for an optional pairs input.
1085
+ */
1086
+ static pairs(name: string): Config.Config<Record<string, string>>;
1087
+ /**
1088
+ * A JSON-valued input, decoded through a schema.
1089
+ *
1090
+ * @remarks
1091
+ * Absent or `""` fails as **missing data** before any JSON parsing runs
1092
+ * (see {@link ActionInput.string}) — `Config.withDefault` or
1093
+ * `Config.option` for an optional input. A present value that is not valid
1094
+ * JSON, or does not satisfy the schema, fails carrying its `actual` and is
1095
+ * never swallowed by a default.
1096
+ */
1097
+ static schema<A, I>(name: string, schema: Schema.Codec<A, I>): Config.Config<A>;
1098
+ /**
1099
+ * A `ConfigProvider` over a record of runner variables.
1100
+ *
1101
+ * @remarks
1102
+ * Subsumes the source package's free-standing `ActionsConfigProvider`, whose
1103
+ * three behaviors are preserved exactly: the path is joined with `_`, spaces
1104
+ * become underscores and the whole is uppercased; and an **empty string
1105
+ * reads as absent**, because the runner sets unsupplied inputs to `""` and
1106
+ * treating that as present would make every optional input look supplied.
1107
+ *
1108
+ * Taking the environment as an argument rather than reading `process.env`
1109
+ * is what makes inputs testable without mutating the test process.
1110
+ */
1111
+ static provider(env?: Readonly<Record<string, string | undefined>>): ConfigProvider.ConfigProvider;
1112
+ /**
1113
+ * A layer installing {@link ActionInput.provider}.
1114
+ *
1115
+ * @remarks
1116
+ * `ConfigProvider.ConfigProvider` is a `Context.Reference` in v4, so this is
1117
+ * a reference override rather than a service — there is no
1118
+ * `Effect.withConfigProvider`.
1119
+ *
1120
+ * A parameterized layer factory mints a fresh reference per call; bind it to
1121
+ * a `const` rather than calling it at each composition site.
1122
+ */
1123
+ static layer(env?: Readonly<Record<string, string | undefined>>): Layer.Layer<never>;
1124
+ /**
1125
+ * Inputs-first resolution layered over an existing provider.
1126
+ *
1127
+ * @remarks
1128
+ * A bare `Config.string("dry-run")` resolves a **flat** name — one string
1129
+ * segment — by first trying the variable the runner would have published for
1130
+ * an input of that name (the `INPUT_` derivation this module owns), and only
1131
+ * then trying the name unchanged through `ambient`. Anything the runner
1132
+ * could not have set as an input — a nested path, a numeric segment — is
1133
+ * passed to `ambient` untouched, so no path semantics are invented that the
1134
+ * runner does not have.
1135
+ *
1136
+ * This exists because a live action shipped a **false green**: every bare
1137
+ * `Config` read fell back to its `withDefault` because the runner exposes
1138
+ * inputs as `INPUT_<MANGLED>` variables and a plain-named lookup finds
1139
+ * nothing. Under this provider a bare read resolves through the same
1140
+ * derivation `ActionInput.string` uses, so side-stepping the typed accessors
1141
+ * degrades to the right answer instead of to the default.
1142
+ *
1143
+ * The documented trade: a workflow input named like an environment variable
1144
+ * **shadows it** for bare reads — and because the derivation uppercases,
1145
+ * any casing of the name sees the input. An unsupplied input does not
1146
+ * shadow: the runner writes `""` for it, and the ambient provider's
1147
+ * empty-is-absent rule (which the attempt resolves through) drops it. The
1148
+ * `ActionInput` accessors themselves are unaffected — they read
1149
+ * `INPUT_<MANGLED>` names, whose re-mangled form (`INPUT_INPUT_…`) never
1150
+ * matches, so they fall through to the ambient lookup they always used.
1151
+ */
1152
+ static providerOver(ambient: ConfigProvider.ConfigProvider): ConfigProvider.ConfigProvider;
1153
+ /**
1154
+ * The provider the default action runtime installs: {@link ActionInput.providerOver}
1155
+ * composed over the ambient environment lookup.
1156
+ *
1157
+ * @remarks
1158
+ * Installed by `ActionRuntime.layer`, and therefore by `Action.run` — a bare
1159
+ * `Config` read inside an action resolves through the runner's `INPUT_`
1160
+ * derivation instead of silently missing. A caller-supplied
1161
+ * `ConfigProvider` layer still wins by normal layer precedence.
1162
+ *
1163
+ * The ambient half is whatever provider is **explicitly installed** when the
1164
+ * layer builds — which is how a test injects a deterministic environment by
1165
+ * providing `ConfigProvider.layer(ConfigProvider.fromEnv({ env }))` beneath
1166
+ * the runtime. When none is installed, a **fresh** `ConfigProvider.fromEnv()`
1167
+ * is built rather than reading the reference's default: v4 caches that
1168
+ * default once per process, and a snapshot taken before the runner's
1169
+ * variables are visible would resurrect exactly the missed-input class this
1170
+ * layer exists to kill. An action's environment is fixed before the process
1171
+ * starts, so production cannot tell the difference; a test mutating
1172
+ * `process.env` around `Action.run` can.
1173
+ *
1174
+ * A bound constant rather than a factory: layers memoize by reference.
1175
+ */
1176
+ static readonly layerDefault: Layer.Layer<never>;
1177
+ }
1178
+ //#endregion
1179
+ //#region src/Artifact.d.ts
1180
+ declare const ArtifactError_base: Schema.Class<ArtifactError, Schema.TaggedStruct<"ArtifactError", {
1181
+ /**
1182
+ * `misconfigured` — the results backend is not reachable from here (see
1183
+ * {@link Artifact}). `unreachable` — it could not be contacted, or answered
1184
+ * with something that is not a Twirp body. `refused` — it answered,
1185
+ * unhappily; re-uploading a name that already exists in the run is the
1186
+ * common case. `notFound` — no artifact by that name or id exists in this
1187
+ * run. `archiveFailed` — `zip` would not pack or unpack the files.
1188
+ * `transferFailed` — the archive itself did not move. `invalidOptions` — the
1189
+ * call cannot be made as asked.
1190
+ */
1191
+ readonly reason: Schema.Literals<readonly ["misconfigured", "unreachable", "refused", "notFound", "archiveFailed", "transferFailed", "invalidOptions"]>;
1192
+ /** The artifact's name or id. A stable identifier, never a value. */
1193
+ readonly artifact: Schema.optionalKey<Schema.String>;
1194
+ /** The HTTP status, when the backend answered. */
1195
+ readonly status: Schema.optionalKey<Schema.Number>;
1196
+ /** What went wrong, when the reason alone does not say. */
1197
+ readonly detail: Schema.optionalKey<Schema.String>;
1198
+ /** `zip`'s own complaint, which is the only useful part of an archive failure. */
1199
+ readonly stderr: Schema.optionalKey<Schema.String>;
1200
+ /** The underlying failure, preserved structurally. */
1201
+ readonly cause: Schema.optionalKey<Schema.Defect>;
1202
+ }>, import("effect/Cause").YieldableError>;
1203
+ /**
1204
+ * Raised when an artifact cannot be uploaded, listed, downloaded or deleted.
1205
+ *
1206
+ * @public
1207
+ */
1208
+ declare class ArtifactError extends ArtifactError_base {
1209
+ get message(): string;
1210
+ }
1211
+ /**
1212
+ * One artifact, as the backend describes it.
1213
+ *
1214
+ * @public
1215
+ */
1216
+ interface ArtifactItem {
1217
+ /** The database id, which is what `download` takes. */
1218
+ readonly id: number;
1219
+ readonly name: string;
1220
+ /** The size of the stored zip, in bytes. */
1221
+ readonly size: number;
1222
+ /** When it was created, ISO-8601, when the backend says. */
1223
+ readonly createdAt?: string | undefined;
1224
+ }
1225
+ /**
1226
+ * How to pack an upload.
1227
+ *
1228
+ * @public
1229
+ */
1230
+ interface UploadOptions {
1231
+ /**
1232
+ * How long to keep it, in days.
1233
+ *
1234
+ * @remarks
1235
+ * Bounded by the repository's own retention setting; omitted means the
1236
+ * repository default. Zero or negative fails as `invalidOptions` rather than
1237
+ * being silently corrected, because "delete it immediately" and "keep it for
1238
+ * the default period" are too far apart to guess between.
1239
+ */
1240
+ readonly retentionDays?: number | undefined;
1241
+ /**
1242
+ * The zlib level, 0–9, defaulting to 6 as `@actions/artifact` does.
1243
+ *
1244
+ * @remarks
1245
+ * Out-of-range values are clamped. No effect on Windows, where
1246
+ * `Compress-Archive` has no numeric equivalent.
1247
+ */
1248
+ readonly compressionLevel?: number | undefined;
1249
+ }
1250
+ /**
1251
+ * What an upload produced.
1252
+ *
1253
+ * @public
1254
+ */
1255
+ interface UploadResult {
1256
+ readonly id: number;
1257
+ /** The size of the uploaded zip, in bytes. */
1258
+ readonly size: number;
1259
+ }
1260
+ /**
1261
+ * Where a download should land.
1262
+ *
1263
+ * @public
1264
+ */
1265
+ interface DownloadOptions {
1266
+ /** The destination directory. A fresh temporary directory when omitted. */
1267
+ readonly path?: string | undefined;
1268
+ }
1269
+ /**
1270
+ * What a download produced.
1271
+ *
1272
+ * @public
1273
+ */
1274
+ interface DownloadResult {
1275
+ /** The directory the artifact's contents were extracted into. */
1276
+ readonly downloadPath: string;
1277
+ }
1278
+ /**
1279
+ * A reference to an artifact that is no longer there.
1280
+ *
1281
+ * @public
1282
+ */
1283
+ interface ArtifactRef {
1284
+ readonly id: number;
1285
+ }
1286
+ /**
1287
+ * The {@link Artifact} service shape.
1288
+ *
1289
+ * @public
1290
+ */
1291
+ interface ArtifactShape {
1292
+ /**
1293
+ * Zip `files` — paths under `rootDirectory` — and upload them under `name`.
1294
+ *
1295
+ * @remarks
1296
+ * Entries are stored relative to `rootDirectory`, so what a later download
1297
+ * extracts is the layout the caller meant rather than its absolute path on
1298
+ * whichever runner produced it. A name already used in this run is refused by
1299
+ * the backend: artifacts are immutable within a run.
1300
+ */
1301
+ readonly upload: (name: string, files: ReadonlyArray<string>, rootDirectory: string, options?: UploadOptions) => Effect.Effect<UploadResult, ArtifactError>;
1302
+ /** Every artifact in the current run. */
1303
+ readonly list: () => Effect.Effect<ReadonlyArray<ArtifactItem>, ArtifactError>;
1304
+ /** One artifact by name, or nothing — absent is not a failure. */
1305
+ readonly get: (name: string) => Effect.Effect<Option.Option<ArtifactItem>, ArtifactError>;
1306
+ /** Download an artifact by id and unzip it. Answers with where it landed. */
1307
+ readonly download: (artifactId: number, options?: DownloadOptions) => Effect.Effect<DownloadResult, ArtifactError>;
1308
+ /** Delete an artifact by name, answering with the id that is now gone. */
1309
+ readonly delete: (name: string) => Effect.Effect<ArtifactRef, ArtifactError>;
1310
+ }
1311
+ declare const Artifact_base: Context.ServiceClass<Artifact, "@effected/github-actions/Artifact", ArtifactShape>;
1312
+ /**
1313
+ * Upload, list, download and delete GitHub Actions artifacts.
1314
+ *
1315
+ * @remarks
1316
+ * Speaks the artifact **Twirp v2** protocol at `ACTIONS_RESULTS_URL`, which
1317
+ * answers with a pre-signed Azure blob url for the zip. No `@actions/artifact`
1318
+ * dependency.
1319
+ *
1320
+ * **Only reachable from a `uses:` step**, like {@link ActionCache} — the two
1321
+ * variables it needs are injected into action execution contexts and not into
1322
+ * `run:` shell steps. The `Actions.Results` scope inside the runtime token is a
1323
+ * third thing that can be absent, and it is reported as `misconfigured` for the
1324
+ * same reason.
1325
+ *
1326
+ * **This surface is provisional.** Unlike every other service here it was
1327
+ * ported without a call site to shape it against, so it keeps the source's
1328
+ * shape rather than a narrower one invented from nothing. The first consumer to
1329
+ * adopt it is the one whose feedback reshapes it — the members lost their
1330
+ * `Artifact` prefix (`artifact.uploadArtifact(...)` stutters) and the
1331
+ * cross-run `findBy` lookup is **not** ported, because every path through it in
1332
+ * the source is a typed "not implemented" failure. Adding it later is additive;
1333
+ * shipping a parameter that has never had behavior is not.
1334
+ *
1335
+ * @example
1336
+ * ```ts
1337
+ * import { Artifact } from "@effected/github-actions";
1338
+ * import { Effect } from "effect";
1339
+ *
1340
+ * const program = Effect.gen(function* () {
1341
+ * const artifacts = yield* Artifact;
1342
+ * return yield* artifacts.upload("logs", ["/tmp/build/log.txt"], "/tmp/build");
1343
+ * });
1344
+ * ```
1345
+ *
1346
+ * @public
1347
+ */
1348
+ declare class Artifact extends Artifact_base {
1349
+ /** The service, over the real Azure client and the real `zip`. */
1350
+ static readonly layer: Layer.Layer<Artifact, never, ActionEnvironment | HttpClient.HttpClient | FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
1351
+ /**
1352
+ * The service, over a supplied transport.
1353
+ *
1354
+ * @remarks
1355
+ * The protocol, the zip, the digest and the conflict handling are what this
1356
+ * package owns; the pre-signed `PUT` is not. Supplying the transport is what
1357
+ * lets a test exercise all of the first group without the second.
1358
+ *
1359
+ * A parameterized layer factory mints a fresh layer per call and layers
1360
+ * memoize by reference — bind it to a `const` rather than calling it at each
1361
+ * composition site.
1362
+ */
1363
+ static readonly layerWith: (transfer: FileBlobTransfer) => Layer.Layer<Artifact, never, ActionEnvironment | HttpClient.HttpClient | FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
1364
+ /** A test double. Unstubbed members die rather than reporting an empty run. */
1365
+ static readonly makeTest: (overrides?: Partial<ArtifactShape>) => ArtifactShape;
1366
+ /** {@link Artifact.makeTest} behind `Layer.succeed`. */
1367
+ static readonly layerTest: (overrides?: Partial<ArtifactShape>) => Layer.Layer<Artifact>;
1368
+ }
1369
+ //#endregion
1370
+ //#region src/BlobEnvelope.d.ts
1371
+ declare const BlobEnvelopeError_base: Schema.Class<BlobEnvelopeError, Schema.TaggedStruct<"BlobEnvelopeError", {
1372
+ /**
1373
+ * `notAnEnvelope` — the magic prefix is absent, so these are raw bytes
1374
+ * written before this format existed (or by something else entirely).
1375
+ * `unsupportedVersion` — an envelope from a newer revision.
1376
+ * `truncated` — the frame ends mid-header or mid-metadata.
1377
+ * `metadataDecodeFailed` — the metadata is well-framed but does not satisfy
1378
+ * the caller's schema. `metadataEncodeFailed` — the value being stored does
1379
+ * not satisfy it.
1380
+ */
1381
+ readonly reason: Schema.Literals<readonly ["notAnEnvelope", "unsupportedVersion", "truncated", "metadataDecodeFailed", "metadataEncodeFailed"]>;
1382
+ /** The envelope version found, when one was readable. */
1383
+ readonly version: Schema.optionalKey<Schema.Number>;
1384
+ readonly cause: Schema.optionalKey<Schema.Defect>;
1385
+ }>, import("effect/Cause").YieldableError>;
1386
+ /**
1387
+ * Raised when bytes cannot be read as an envelope.
1388
+ *
1389
+ * @public
1390
+ */
1391
+ declare class BlobEnvelopeError extends BlobEnvelopeError_base {
1392
+ get message(): string;
1393
+ }
1394
+ /**
1395
+ * The schema-versioned frame that gives a stored blob a **metadata channel**.
1396
+ *
1397
+ * @remarks
1398
+ * Layout:
1399
+ *
1400
+ * ```text
1401
+ * [4B magic "EFBS"][1B version][4B metadata length, big-endian][metadata JSON][body]
1402
+ * ```
1403
+ *
1404
+ * Three properties earn the format, and each replaces something a consumer was
1405
+ * hand-rolling:
1406
+ *
1407
+ * - **The magic prefix makes a legacy blob legible.** Raw, unframed bytes
1408
+ * decode as `notAnEnvelope` rather than as garbage metadata, so a store
1409
+ * holding pre-envelope entries produces a clean miss instead of a corrupt
1410
+ * read.
1411
+ * - **The version lives in the blob, not in the key.** A consumer previously
1412
+ * namespaced keys (`v2/...`) to represent a format change, because there was
1413
+ * no in-band version. Here a revision is detected on read and reported
1414
+ * typed, so **keys stay stable** and old entries age out naturally.
1415
+ * - **The metadata is the caller's own schema.** This module owns *framing*;
1416
+ * the caller owns *meaning*. Fields like a cache tag or a duration stop
1417
+ * being bytes at fixed offsets in a consumer's private codec.
1418
+ *
1419
+ * **Pure**: `Result`-returning, no IO, no service — the framing is testable
1420
+ * from a byte array, which is the point.
1421
+ *
1422
+ * @public
1423
+ */
1424
+ declare class BlobEnvelope {
1425
+ private constructor();
1426
+ /** The version this build writes. */
1427
+ static readonly version: number;
1428
+ /** Frame metadata and a body into a single blob. */
1429
+ static encodeResult<A, I>(metadata: A, body: Uint8Array, schema: Schema.Codec<A, I>): Result.Result<Uint8Array, BlobEnvelopeError>;
1430
+ /** Read a framed blob back into its metadata and body. */
1431
+ static decodeResult<A, I>(bytes: Uint8Array, schema: Schema.Codec<A, I>): Result.Result<{
1432
+ readonly metadata: A;
1433
+ readonly body: Uint8Array;
1434
+ }, BlobEnvelopeError>;
1435
+ }
1436
+ //#endregion
1437
+ //#region src/BlobStore.d.ts
1438
+ declare const BlobStoreError_base: Schema.Class<BlobStoreError, Schema.TaggedStruct<"BlobStoreError", {
1439
+ /**
1440
+ * `unreachable` — the store could not be contacted. `refused` — it answered,
1441
+ * unhappily; `status` says how. `misconfigured` — the layer was built with
1442
+ * settings the store cannot use.
1443
+ */
1444
+ readonly reason: Schema.Literals<readonly ["unreachable", "refused", "misconfigured"]>;
1445
+ /** The key involved. A stable identifier, never a value. */
1446
+ readonly key: Schema.optionalKey<Schema.String>;
1447
+ /** The HTTP status, when the store answered. */
1448
+ readonly status: Schema.optionalKey<Schema.Number>;
1449
+ /** What is wrong, when the reason alone does not say. */
1450
+ readonly detail: Schema.optionalKey<Schema.String>;
1451
+ /** The underlying failure, preserved structurally. */
1452
+ readonly cause: Schema.optionalKey<Schema.Defect>;
1453
+ }>, import("effect/Cause").YieldableError>;
1454
+ /**
1455
+ * Raised when a blob cannot be stored or retrieved.
1456
+ *
1457
+ * @public
1458
+ */
1459
+ declare class BlobStoreError extends BlobStoreError_base {
1460
+ get message(): string;
1461
+ }
1462
+ /**
1463
+ * A stored value: the caller's metadata beside the bytes it describes.
1464
+ *
1465
+ * @public
1466
+ */
1467
+ interface Blob<A> {
1468
+ /** The caller's own metadata, decoded through the caller's own schema. */
1469
+ readonly metadata: A;
1470
+ /** The payload, verbatim. */
1471
+ readonly body: Uint8Array;
1472
+ }
1473
+ /**
1474
+ * The {@link BlobStore} service shape.
1475
+ *
1476
+ * @public
1477
+ */
1478
+ interface BlobStoreShape {
1479
+ /** Read a blob, or nothing if the key is absent. */
1480
+ readonly get: <A, I>(key: string, schema: Schema.Codec<A, I>) => Effect.Effect<Option.Option<Blob<A>>, BlobStoreError | BlobEnvelopeError>;
1481
+ /** Write a blob. */
1482
+ readonly put: <A, I>(key: string, blob: Blob<A>, schema: Schema.Codec<A, I>) => Effect.Effect<void, BlobStoreError | BlobEnvelopeError>;
1483
+ /** Whether a key is present, without transferring the body. */
1484
+ readonly has: (key: string) => Effect.Effect<boolean, BlobStoreError>;
1485
+ }
1486
+ /**
1487
+ * How to reach an S3-compatible object store.
1488
+ *
1489
+ * @public
1490
+ */
1491
+ interface S3Config {
1492
+ readonly bucket: string;
1493
+ readonly region: string;
1494
+ /**
1495
+ * A custom endpoint, e.g. `https://<account>.r2.cloudflarestorage.com`.
1496
+ *
1497
+ * @remarks
1498
+ * Omitting it targets AWS itself. Addressing is always **path-style**
1499
+ * (`<endpoint>/<bucket>/<key>`), which is what makes the same layer work
1500
+ * against R2, MinIO and Spaces — virtual-host addressing needs per-bucket
1501
+ * DNS that none of them provide the same way.
1502
+ */
1503
+ readonly endpoint?: string | undefined;
1504
+ readonly accessKeyId: string;
1505
+ readonly secretAccessKey: Redacted.Redacted<string>;
1506
+ /** For temporary credentials. */
1507
+ readonly sessionToken?: Redacted.Redacted<string> | undefined;
1508
+ /** Prepended to every key, so one bucket can hold several caches. */
1509
+ readonly prefix?: string | undefined;
1510
+ }
1511
+ declare const BlobStore_base: Context.ServiceClass<BlobStore, "@effected/github-actions/BlobStore", BlobStoreShape>;
1512
+ /**
1513
+ * Durable blob storage with a metadata channel.
1514
+ *
1515
+ * @remarks
1516
+ * `get`/`put`/`has` over `Uint8Array` **plus the caller's own metadata**, framed
1517
+ * by {@link BlobEnvelope}. The metadata channel is the reason this exists: the
1518
+ * consumer it was designed against hand-rolled a binary frame
1519
+ * (`[4B tagLen][4B durationMs][tag][body]`) and namespaced its keys with a `v2`
1520
+ * prefix to represent a format change. Both are framing concerns that had
1521
+ * leaked into a consumer, and both are absorbed here.
1522
+ *
1523
+ * Deliberately no `list` and no `delete`: eviction belongs to the backend, both
1524
+ * backends already have one, and no consumer asked for either.
1525
+ *
1526
+ * @example
1527
+ * ```ts
1528
+ * import { BlobStore } from "@effected/github-actions";
1529
+ * import { Effect, Schema } from "effect";
1530
+ *
1531
+ * class Meta extends Schema.Class<Meta>("Meta")({ tag: Schema.String, durationMs: Schema.Number }) {}
1532
+ *
1533
+ * const program = Effect.gen(function* () {
1534
+ * const store = yield* BlobStore;
1535
+ * yield* store.put("build/1", { metadata: Meta.make({ tag: "x", durationMs: 12 }), body: bytes }, Meta);
1536
+ * return yield* store.get("build/1", Meta);
1537
+ * });
1538
+ * ```
1539
+ *
1540
+ * @public
1541
+ */
1542
+ declare class BlobStore extends BlobStore_base {
1543
+ /**
1544
+ * An S3-compatible backend, signed with SigV4.
1545
+ *
1546
+ * @remarks
1547
+ * No `@aws-sdk/*` dependency: signing is a specified algorithm over strings
1548
+ * and HMACs, and this package already has `node:crypto`. The SDK's weight is
1549
+ * in credential management, retries and a service catalogue none of which
1550
+ * this needs.
1551
+ *
1552
+ * A parameterized layer factory mints a fresh layer per call and layers
1553
+ * memoize by reference — bind it to a `const` rather than calling it at each
1554
+ * composition site.
1555
+ */
1556
+ static readonly layerS3: (config: S3Config) => Layer.Layer<BlobStore, never, HttpClient.HttpClient | ActionOutputs>;
1557
+ /** A test double. Unstubbed members die rather than reporting a miss. */
1558
+ static readonly makeTest: (overrides?: Partial<BlobStoreShape>) => BlobStoreShape;
1559
+ /** {@link BlobStore.makeTest} behind `Layer.succeed`. */
1560
+ static readonly layerTest: (overrides?: Partial<BlobStoreShape>) => Layer.Layer<BlobStore>;
1561
+ /**
1562
+ * An in-memory backend.
1563
+ *
1564
+ * @remarks
1565
+ * Not a stub: it runs the real {@link BlobEnvelope} framing, so a round trip
1566
+ * through it exercises encode and decode exactly as a network backend would.
1567
+ * A test that wants to prove its metadata survives storage should use this
1568
+ * rather than a double whose `get` returns whatever its `put` was handed.
1569
+ */
1570
+ static readonly layerMemory: Layer.Layer<BlobStore>;
1571
+ }
1572
+ //#endregion
1573
+ //#region src/BlobStore.githubCache.d.ts
1574
+ /**
1575
+ * The {@link BlobStore} backend that stores blobs in the runner's own Actions
1576
+ * cache.
1577
+ *
1578
+ * @remarks
1579
+ * The Actions cache is reachable over a Twirp v2 protocol at
1580
+ * `ACTIONS_RESULTS_URL`, which answers a `CreateCacheEntry` /
1581
+ * `GetCacheEntryDownloadURL` RPC with a **pre-signed Azure blob url** — which is
1582
+ * why this backend lives in its own module rather than beside the S3 one, and
1583
+ * why the spec's "Azure is confined to the cache and the artifact service" is
1584
+ * three modules rather than two.
1585
+ *
1586
+ * **Only reachable from a `uses:` step.** The runner injects
1587
+ * `ACTIONS_RESULTS_URL` and `ACTIONS_RUNTIME_TOKEN` into action execution
1588
+ * contexts and not into `run:` shell steps, so a program that works when
1589
+ * invoked from a bundled action fails as `misconfigured` when the same code is
1590
+ * run by `node ./main.js` in a workflow step. The failure names the variable
1591
+ * for exactly that reason.
1592
+ *
1593
+ * The layer statics live here rather than on {@link BlobStore} because a static
1594
+ * belongs to the module that owns the dependency it needs: putting
1595
+ * `BlobStore.layerGitHubCache` on the service class would make `@azure/storage-blob`
1596
+ * reachable from every module that reads a blob.
1597
+ *
1598
+ * @example
1599
+ * ```ts
1600
+ * import { GitHubCacheBlobStore } from "@effected/github-actions";
1601
+ *
1602
+ * const layer = GitHubCacheBlobStore.layer;
1603
+ * ```
1604
+ *
1605
+ * @public
1606
+ */
1607
+ declare class GitHubCacheBlobStore {
1608
+ private constructor();
1609
+ /** The backend, over the real Azure client. */
1610
+ static readonly layer: Layer.Layer<BlobStore, never, HttpClient.HttpClient | ActionEnvironment>;
1611
+ /**
1612
+ * The backend, over a supplied transport.
1613
+ *
1614
+ * @remarks
1615
+ * The Twirp protocol — the RPC sequence, the conflict handling, the retry
1616
+ * policy, the framing — is what this package owns and what a test needs to
1617
+ * exercise; the Azure client is a pre-signed `PUT` that owns none of it. This
1618
+ * is also the seam an integration test uses to point the same protocol at a
1619
+ * local blob endpoint.
1620
+ *
1621
+ * A parameterized layer factory mints a fresh layer per call and layers
1622
+ * memoize by reference — bind it to a `const` rather than calling it at each
1623
+ * composition site.
1624
+ */
1625
+ static readonly layerWith: (transfer: DataBlobTransfer) => Layer.Layer<BlobStore, never, HttpClient.HttpClient | ActionEnvironment>;
1626
+ }
1627
+ //#endregion
1628
+ //#region src/DetachedProcess.d.ts
1629
+ declare const DetachedProcessError_base: Schema.Class<DetachedProcessError, Schema.TaggedStruct<"DetachedProcessError", {
1630
+ /**
1631
+ * `logUnavailable` — the log file could not be opened, so there is nowhere
1632
+ * for the child's output to go. `spawnFailed` — the child did not start.
1633
+ * `invalidPid` — a non-positive pid was handed to {@link DetachedProcess.reap};
1634
+ * see there for why this is the most important value in the module.
1635
+ * `signalFailed` — the signal was refused, e.g. the process belongs to
1636
+ * another user. `notReady` — the readiness probe never held.
1637
+ */
1638
+ readonly reason: Schema.Literals<readonly ["logUnavailable", "spawnFailed", "invalidPid", "signalFailed", "notReady"]>;
1639
+ /** The pid involved, when one is. */
1640
+ readonly pid: Schema.optionalKey<Schema.Number>;
1641
+ /** The path involved, when one is. */
1642
+ readonly path: Schema.optionalKey<Schema.String>;
1643
+ /** The underlying failure, preserved structurally. */
1644
+ readonly cause: Schema.optionalKey<Schema.Defect>;
1645
+ }>, import("effect/Cause").YieldableError>;
1646
+ /**
1647
+ * Raised when a detached child cannot be started, waited for, or reaped.
1648
+ *
1649
+ * @public
1650
+ */
1651
+ declare class DetachedProcessError extends DetachedProcessError_base {
1652
+ get message(): string;
1653
+ }
1654
+ /**
1655
+ * The schema a pid crosses the phase boundary through.
1656
+ *
1657
+ * @remarks
1658
+ * A pid is persisted in `GITHUB_STATE` by `main` and read back by `post`, which
1659
+ * means it makes the round trip as **text**. This is the boundary check on the
1660
+ * way back in: a truncated file, an absent key or a `Number("")` all decode to
1661
+ * `0`, and `0` is not a process — it is the current process's whole group.
1662
+ * Refusing it here means the bad value never reaches {@link DetachedProcess.reap}
1663
+ * in the first place, and reap's own guard is the second of two defenses rather
1664
+ * than the only one.
1665
+ *
1666
+ * **The brand is core's**, from `ChildProcessSpawner` — the subprocess
1667
+ * vocabulary belongs to core and this package does not get to re-declare it.
1668
+ * What core does not have is a *validating* way to reconstruct one: its
1669
+ * constructor is `Brand.nominal`, which applies no runtime check, so
1670
+ * `ChildProcessSpawner.ProcessId(0)` succeeds. That is exactly right for a pid
1671
+ * the spawner just produced, and exactly wrong for a pid that has been through a
1672
+ * text file. This schema is that missing check, and it decodes to core's type so
1673
+ * the two are interchangeable.
1674
+ *
1675
+ * @example
1676
+ * ```ts
1677
+ * import { ActionState, DetachedProcess, ProcessId } from "@effected/github-actions";
1678
+ * import { Effect } from "effect";
1679
+ *
1680
+ * const post = Effect.gen(function* () {
1681
+ * const pid = yield* (yield* ActionState).get("server-pid", ProcessId);
1682
+ * return yield* DetachedProcess.reap(pid);
1683
+ * });
1684
+ * ```
1685
+ *
1686
+ * @public
1687
+ */
1688
+ declare const ProcessId: Schema.brand<Schema.Number, "ProcessId">;
1689
+ /**
1690
+ * How a detached child is started.
1691
+ *
1692
+ * @public
1693
+ */
1694
+ interface DetachedSpawnOptions {
1695
+ /** The executable. */
1696
+ readonly command: string;
1697
+ /** Its arguments. */
1698
+ readonly args?: ReadonlyArray<string> | undefined;
1699
+ /**
1700
+ * Where the child's stdout and stderr go, opened for append.
1701
+ *
1702
+ * @remarks
1703
+ * A file **descriptor**, not a pipe. An in-process pipe would keep the parent
1704
+ * attached to the child and defeat the detachment, which is the upstream
1705
+ * limitation this module exists to work around — core's `CommandOptions.stdout`
1706
+ * maps to a pipe, and so do its additional fds. If core grows fd routing this
1707
+ * becomes a thin adapter over it.
1708
+ */
1709
+ readonly logFile: string;
1710
+ /** The working directory. */
1711
+ readonly cwd?: string | undefined;
1712
+ /**
1713
+ * Environment additions.
1714
+ *
1715
+ * @remarks
1716
+ * **Merged over the parent's environment, not substituted for it.** A bare
1717
+ * environment costs the child `PATH`, which usually means it cannot find its
1718
+ * own runtime and dies before writing a word to the log — a failure that
1719
+ * looks like a spawn bug and is not. Secrets belong here only via
1720
+ * `Secret.forChildEnv`, which masks them on the way out.
1721
+ */
1722
+ readonly env?: Readonly<Record<string, string>> | undefined;
1723
+ }
1724
+ /**
1725
+ * How long to wait for a child to become ready.
1726
+ *
1727
+ * @public
1728
+ */
1729
+ interface ReadinessOptions {
1730
+ /** Time between probes. Defaults to 150 milliseconds. */
1731
+ readonly interval?: Duration.Input | undefined;
1732
+ /** How many times to retry after the first probe. Defaults to 40. */
1733
+ readonly attempts?: number | undefined;
1734
+ }
1735
+ /**
1736
+ * A long-lived child that outlives the phase that started it.
1737
+ *
1738
+ * @remarks
1739
+ * The shape an action needs is three separate things, because the child
1740
+ * survives the process that spawned it: `main` starts it and persists the pid,
1741
+ * `main` or `post` waits on a domain predicate rather than on time, and `post`
1742
+ * — a **different process**, holding no handle to the child — signals the pid
1743
+ * it read back out of `GITHUB_STATE`.
1744
+ *
1745
+ * That last step is why this lives here rather than in a command runner. There
1746
+ * is no `ChildProcess` to `.kill()`; there is only a number that has been
1747
+ * through a text file. See {@link DetachedProcess.reap}.
1748
+ *
1749
+ * @example
1750
+ * ```ts
1751
+ * import { DetachedProcess } from "@effected/github-actions";
1752
+ * import { Effect } from "effect";
1753
+ *
1754
+ * const program = Effect.gen(function* () {
1755
+ * const pid = yield* DetachedProcess.spawn({
1756
+ * command: "node",
1757
+ * args: ["server.js"],
1758
+ * logFile: "/tmp/server.log",
1759
+ * });
1760
+ * yield* DetachedProcess.awaitReady(healthCheck);
1761
+ * return pid;
1762
+ * });
1763
+ * ```
1764
+ *
1765
+ * @public
1766
+ */
1767
+ declare class DetachedProcess {
1768
+ private constructor();
1769
+ /**
1770
+ * Start a detached child with its output routed to a log file.
1771
+ *
1772
+ * @remarks
1773
+ * The parent closes its own copy of the descriptor immediately — the child
1774
+ * holds a duplicate, so the log keeps filling after the action's process
1775
+ * exits, which is the entire point.
1776
+ */
1777
+ static readonly spawn: (options: DetachedSpawnOptions) => Effect.Effect<ChildProcessSpawner.ProcessId, DetachedProcessError, never>;
1778
+ /**
1779
+ * Poll a predicate until it holds.
1780
+ *
1781
+ * @remarks
1782
+ * A domain predicate rather than a sleep: "the server answers" is the thing
1783
+ * being waited for, and any fixed delay is simultaneously too long on a fast
1784
+ * runner and too short on a slow one. Two consumers hand-rolled this, one of
1785
+ * them around an `Effect.suspend` footgun it had to explain in a comment.
1786
+ *
1787
+ * A probe *failure* is propagated rather than treated as "not ready" — a
1788
+ * probe that cannot run is a different situation from a child that is not up
1789
+ * yet, and silently retrying the first is how a misconfigured probe becomes a
1790
+ * timeout six seconds later with nothing to show for it.
1791
+ */
1792
+ static readonly awaitReady: <E, R>(probe: Effect.Effect<boolean, E, R>, options?: ReadinessOptions | undefined) => Effect.Effect<void, E | DetachedProcessError, R>;
1793
+ /**
1794
+ * Signal a pid that came back across the phase boundary.
1795
+ *
1796
+ * @remarks
1797
+ * **The guard is the reason this function exists.** `process.kill(0, …)`
1798
+ * signals the caller's entire process group and `process.kill(-1, …)` signals
1799
+ * every process the user owns — so on a GitHub runner, an unguarded reap of a
1800
+ * pid that decoded to `0` takes down the job that is running it. The value is
1801
+ * exactly the one most likely to be wrong: it is what an absent state key, a
1802
+ * truncated state file or a `Number("")` all produce.
1803
+ *
1804
+ * A non-positive pid therefore fails **typed and before any signal is sent**.
1805
+ * The parameter is a plain `number` rather than a {@link ProcessId} on purpose:
1806
+ * the value arrives as text from another process, so the type system stopped
1807
+ * applying the moment it crossed that boundary, and a guard that only a
1808
+ * well-typed caller can trip is not a guard.
1809
+ *
1810
+ * Returns `false` for a process that is already gone, because a `post` phase
1811
+ * finding its child already dead is the normal ending, not a failure.
1812
+ */
1813
+ static readonly reap: (pid: number, signal?: NodeJS.Signals | undefined) => Effect.Effect<boolean, DetachedProcessError, never>;
1814
+ }
1815
+ //#endregion
1816
+ //#region src/DryRun.d.ts
1817
+ /**
1818
+ * The {@link DryRun} service shape.
1819
+ *
1820
+ * @public
1821
+ */
1822
+ interface DryRunShape {
1823
+ /** Whether this run is a rehearsal. */
1824
+ readonly isDryRun: Effect.Effect<boolean>;
1825
+ /**
1826
+ * Run a mutation, or skip it and take the fallback.
1827
+ *
1828
+ * @remarks
1829
+ * The `label` is what a dry run reports instead of doing the work, so it
1830
+ * should name the mutation from the workflow author's point of view
1831
+ * (`"publish @acme/thing@1.2.3"`), not the function that would have run it.
1832
+ *
1833
+ * The fallback is required rather than optional on purpose: a mutation whose
1834
+ * result the caller uses must say what a rehearsal produces instead, and the
1835
+ * type is the place to force that. For a `void` mutation it is simply
1836
+ * `undefined`.
1837
+ */
1838
+ readonly guard: <A, E, R>(label: string, effect: Effect.Effect<A, E, R>, fallback: A) => Effect.Effect<A, E, R>;
1839
+ }
1840
+ declare const DryRun_base: Context.ServiceClass<DryRun, "@effected/github-actions/DryRun", DryRunShape>;
1841
+ /**
1842
+ * The rehearsal guard: every mutation an action performs goes through it, so a
1843
+ * workflow can be run end to end without changing anything.
1844
+ *
1845
+ * @remarks
1846
+ * A service rather than a boolean threaded through call sites, because the
1847
+ * decision has to be available wherever a mutation is, and because a test that
1848
+ * wants to prove "this path mutates nothing" provides one layer instead of
1849
+ * auditing every branch.
1850
+ *
1851
+ * @example
1852
+ * ```ts
1853
+ * import { DryRun } from "@effected/github-actions";
1854
+ * import { Effect } from "effect";
1855
+ *
1856
+ * const program = Effect.gen(function* () {
1857
+ * const dryRun = yield* DryRun;
1858
+ * yield* dryRun.guard("publish @acme/thing@1.2.3", publish, undefined);
1859
+ * });
1860
+ * ```
1861
+ *
1862
+ * @public
1863
+ */
1864
+ declare class DryRun extends DryRun_base {
1865
+ /**
1866
+ * Driven by the `dry-run` action input, defaulting to a real run.
1867
+ *
1868
+ * @remarks
1869
+ * Fails with a `ConfigError` when the input is present but is not a YAML 1.2
1870
+ * core-schema boolean — a workflow that writes `dry-run: yes` should stop,
1871
+ * not quietly perform the mutations it meant to rehearse.
1872
+ */
1873
+ static readonly layer: Layer.Layer<DryRun, Config.ConfigError>;
1874
+ /**
1875
+ * Driven by a named input.
1876
+ *
1877
+ * @remarks
1878
+ * A parameterized layer factory mints a fresh layer per call and layers
1879
+ * memoize by reference — bind it to a `const` rather than calling it at each
1880
+ * composition site.
1881
+ */
1882
+ static readonly layerFromInput: (name: string) => Layer.Layer<DryRun, Config.ConfigError>;
1883
+ /** Driven by an explicit decision the caller has already made. */
1884
+ static readonly layerFrom: (enabled: boolean) => Layer.Layer<DryRun>;
1885
+ /**
1886
+ * A double that rehearses.
1887
+ *
1888
+ * @remarks
1889
+ * **A recorded exception to the die-on-unstubbed rule.** The default is not a
1890
+ * fabrication but the safe direction: a test that forgot to say which mode it
1891
+ * wants gets the mode that mutates nothing. The members are the real
1892
+ * implementation, so the double cannot drift from it.
1893
+ */
1894
+ static readonly makeTest: (overrides?: Partial<DryRunShape>) => DryRunShape;
1895
+ /** {@link DryRun.makeTest} behind `Layer.succeed`. */
1896
+ static readonly layerTest: (overrides?: Partial<DryRunShape>) => Layer.Layer<DryRun>;
1897
+ }
1898
+ //#endregion
1899
+ //#region src/GitHubToken.d.ts
1900
+ declare const GitHubTokenError_base: Schema.Class<GitHubTokenError, Schema.TaggedStruct<"GitHubTokenError", {
1901
+ /**
1902
+ * One reason, deliberately: everything else that can go wrong here already
1903
+ * has an owner — persistence is an `ActionStateError`, minting is a
1904
+ * `GitHubAppError`, and scope verification is a `TokenPermissionError`.
1905
+ */
1906
+ readonly reason: Schema.Literals<readonly ["expired"]>;
1907
+ /** When GitHub stopped accepting it, ISO-8601. */
1908
+ readonly expiresAt: Schema.String;
1909
+ }>, import("effect/Cause").YieldableError>;
1910
+ /**
1911
+ * Raised when the token an earlier phase persisted cannot be used.
1912
+ *
1913
+ * @public
1914
+ */
1915
+ declare class GitHubTokenError extends GitHubTokenError_base {
1916
+ get message(): string;
1917
+ }
1918
+ /**
1919
+ * What to mint a token for.
1920
+ *
1921
+ * @public
1922
+ */
1923
+ interface ProvisionOptions {
1924
+ /** The app id or client id. */
1925
+ readonly appId: string;
1926
+ /** The app's private key, in PEM. */
1927
+ readonly privateKey: Redacted.Redacted<string>;
1928
+ /** The installation. Discovered from `owner`, or from the app's only installation, when omitted. */
1929
+ readonly installationId?: number | undefined;
1930
+ /** The account whose installation to use, when `installationId` is omitted. */
1931
+ readonly owner?: string | undefined;
1932
+ /**
1933
+ * The permissions the action needs.
1934
+ *
1935
+ * @remarks
1936
+ * Verified against what GitHub actually granted, which can be narrower than
1937
+ * what was asked for. Checked **before** the token is persisted, so a
1938
+ * workflow with a misconfigured installation fails at `pre` with a message
1939
+ * naming the missing permission rather than in the middle of `main` with a
1940
+ * `403` on one request.
1941
+ */
1942
+ readonly required?: Readonly<Record<string, PermissionLevel>> | undefined;
1943
+ /** The `GITHUB_STATE` key. One default, so `pre` and `post` agree without saying so. */
1944
+ readonly stateKey?: string | undefined;
1945
+ }
1946
+ /** Where to read a persisted token from. @public */
1947
+ interface ReadOptions {
1948
+ /** The `GITHUB_STATE` key. */
1949
+ readonly stateKey?: string | undefined;
1950
+ /**
1951
+ * How long before the stated expiry to treat the token as spent.
1952
+ *
1953
+ * @remarks
1954
+ * A minute by default. The window exists because the check and the request
1955
+ * it guards are not the same instant.
1956
+ */
1957
+ readonly skew?: Duration.Duration | undefined;
1958
+ }
1959
+ /** How to build a client from a persisted token. @public */
1960
+ interface ClientLayerOptions extends ReadOptions {
1961
+ /** Retry behavior. Defaults to the client's own policy; `"off"` disables it. */
1962
+ readonly retry?: RetryPolicy | "off" | undefined;
1963
+ /** A GitHub Enterprise API root. */
1964
+ readonly baseUrl?: string | undefined;
1965
+ /** Appended to octokit's own user agent. */
1966
+ readonly userAgent?: string | undefined;
1967
+ /** A replacement for the global `fetch`. */
1968
+ readonly fetch?: typeof globalThis.fetch | undefined;
1969
+ }
1970
+ /**
1971
+ * The GitHub App token lifecycle, shaped like a workflow.
1972
+ *
1973
+ * @remarks
1974
+ * One of the two seams between this package and
1975
+ * [`@effected/github`](https://npmjs.com) — mint in `pre`, use in `main`,
1976
+ * revoke in `post`. The three phases are **three separate processes**, so
1977
+ * nothing survives between them except what `GITHUB_STATE` carries, which is
1978
+ * why this is a persistence problem rather than a `Scope`.
1979
+ *
1980
+ * That is also why `GitHubApp.scopedToken` is the wrong primitive here and
1981
+ * `GitHubApp.clientLayer` is a different thing entirely: both revoke when their
1982
+ * scope closes, and the scope closes at the end of `pre` — before `main` has
1983
+ * run a single request.
1984
+ *
1985
+ * **The token lives about an hour, and no later phase can re-mint one.** The
1986
+ * credentials that could are the app's private key, and persisting *that*
1987
+ * through `GITHUB_STATE` — a plaintext file by GitHub's protocol — would trade
1988
+ * a one-hour token for a permanent one. So the v1 contract is stated rather
1989
+ * than worked around: {@link GitHubToken.read} fails typed when the persisted
1990
+ * token is spent, and a phase that can outlive the hour calls
1991
+ * {@link GitHubToken.provision} itself.
1992
+ *
1993
+ * Grouped statics on one module reaching one dependency — the carve-out to the
1994
+ * no-namespace-objects rule, not the hazard it names. Every member's `R` says
1995
+ * exactly which services it needs, and the members below say which parts of
1996
+ * each they touch, so a partial double is built from the documentation rather
1997
+ * than from a stack trace:
1998
+ *
1999
+ * | Member | `ActionState` | `ActionOutputs` | `GitHubApp` |
2000
+ * | --- | --- | --- | --- |
2001
+ * | `provision` | `save` | `setSecret` | `token`, `identity`, `revoke` |
2002
+ * | `read` | `get` | — | — |
2003
+ * | `botIdentity` | `get` | — | — |
2004
+ * | `clientLayer` | `get` | — | — |
2005
+ * | `dispose` | `getOptional` | — | `revoke` |
2006
+ *
2007
+ * @example
2008
+ * ```ts
2009
+ * import { GitHubToken } from "@effected/github-actions";
2010
+ * import { Effect, Redacted } from "effect";
2011
+ *
2012
+ * const pre = Effect.gen(function* () {
2013
+ * return yield* GitHubToken.provision({
2014
+ * appId: "123456",
2015
+ * privateKey: Redacted.make(pem),
2016
+ * owner: "acme",
2017
+ * required: { contents: "write", pull_requests: "write" },
2018
+ * });
2019
+ * });
2020
+ * ```
2021
+ *
2022
+ * @public
2023
+ */
2024
+ declare class GitHubToken {
2025
+ private constructor();
2026
+ /**
2027
+ * Mint a token, verify its scopes, mask it and persist it for later phases.
2028
+ *
2029
+ * @remarks
2030
+ * An `acquireUseRelease`, and the release arm is the load-bearing part: if
2031
+ * scope verification or persistence fails, the minted token is **revoked**
2032
+ * rather than left live until GitHub expires it. A workflow that retries a
2033
+ * failing `pre` would otherwise leave an hour's worth of unreferenced write
2034
+ * tokens behind, each of which is a credential nobody is tracking.
2035
+ *
2036
+ * The masking happens **before** the persistence, through
2037
+ * {@link Secret.forRunnerFile}, so the ordering is structural rather than
2038
+ * remembered: `GITHUB_STATE` is plaintext by protocol, and the runner's log
2039
+ * filter is the only defense available.
2040
+ */
2041
+ static readonly provision: (options: ProvisionOptions) => Effect.Effect<InstallationToken, ActionStateError | import("@effected/github").GitHubAppError | import("@effected/github").TokenPermissionError, ActionOutputs | ActionState | GitHubApp>;
2042
+ /**
2043
+ * The token an earlier phase persisted.
2044
+ *
2045
+ * @remarks
2046
+ * Fails typed when it is spent. The package this replaces persisted the
2047
+ * expiry and read it nowhere, so a `main` phase that outlived the hour simply
2048
+ * started answering `401` with no explanation — which is the single hardest
2049
+ * failure in this whole lifecycle to diagnose from a workflow log.
2050
+ */
2051
+ static readonly read: (options?: ReadOptions | undefined) => Effect.Effect<InstallationToken, ActionStateError | GitHubTokenError, ActionState>;
2052
+ /**
2053
+ * The committer identity a commit made with the persisted token should carry.
2054
+ *
2055
+ * @remarks
2056
+ * Pure once the token is in hand — the identity fields travel with it — so
2057
+ * this costs one state read and no request.
2058
+ */
2059
+ static readonly botIdentity: (options?: ReadOptions | undefined) => Effect.Effect<BotIdentity, ActionStateError | GitHubTokenError, ActionState>;
2060
+ /**
2061
+ * A client built from the persisted token.
2062
+ *
2063
+ * @remarks
2064
+ * Built with `GitHubClient.layerFromToken` rather than through `GitHubApp`,
2065
+ * and the difference matters: the App path links a JWT signer and needs the
2066
+ * private key, neither of which a later phase has or should have. This path
2067
+ * needs only the token the `pre` phase already minted.
2068
+ *
2069
+ * A parameterized layer factory mints a fresh layer per call and layers
2070
+ * memoize by reference — bind it to a `const` rather than calling it at each
2071
+ * composition site.
2072
+ */
2073
+ static readonly clientLayer: (options?: ClientLayerOptions) => Layer.Layer<GitHubClient, ActionStateError | GitHubTokenError, ActionState>;
2074
+ /**
2075
+ * Revoke the persisted token, if there is one.
2076
+ *
2077
+ * @remarks
2078
+ * `getOptional`, so a `post` phase that runs after a `pre` that never got as
2079
+ * far as provisioning is a **no-op rather than a failure** — which is the
2080
+ * common shape of a workflow that failed early, and the last thing it needs
2081
+ * is a second failure on the way out.
2082
+ *
2083
+ * An already-expired token is not revoked either: GitHub has already stopped
2084
+ * accepting it, so the request would fail and the only thing it could
2085
+ * accomplish is turning a successful run into a failed one.
2086
+ */
2087
+ static readonly dispose: (options?: ReadOptions | undefined) => Effect.Effect<void, ActionStateError | import("@effected/github").GitHubAppError, ActionState | GitHubApp>;
2088
+ }
2089
+ //#endregion
2090
+ //#region src/OidcTokenIssuer.d.ts
2091
+ declare const OidcTokenError_base: Schema.Class<OidcTokenError, Schema.TaggedStruct<"OidcTokenError", {
2092
+ /**
2093
+ * `unavailable` — the runner did not publish the token-service variables,
2094
+ * which almost always means the workflow is missing `permissions: id-token:
2095
+ * write`. `requestFailed` — the token service could not be reached or refused
2096
+ * the request. `malformedResponse` — it answered with something that is not a
2097
+ * token envelope. `malformedToken` — the token is not a decodable JWT.
2098
+ * `missingClaims` — it decoded, but without the claims a provenance statement
2099
+ * needs.
2100
+ */
2101
+ readonly reason: Schema.Literals<readonly ["unavailable", "requestFailed", "malformedResponse", "malformedToken", "missingClaims"]>;
2102
+ /** What was wrong, in one line. */
2103
+ readonly detail: Schema.optionalKey<Schema.String>;
2104
+ /** The HTTP status, when the token service answered. */
2105
+ readonly status: Schema.optionalKey<Schema.Number>;
2106
+ /** The underlying failure, preserved structurally. */
2107
+ readonly cause: Schema.optionalKey<Schema.Defect>;
2108
+ }>, import("effect/Cause").YieldableError>;
2109
+ /**
2110
+ * Raised when an OIDC token cannot be issued or read.
2111
+ *
2112
+ * @public
2113
+ */
2114
+ declare class OidcTokenError extends OidcTokenError_base {
2115
+ get message(): string;
2116
+ }
2117
+ declare const OidcClaims_base: Schema.Class<OidcClaims, Schema.Struct<{
2118
+ /** The issuer, e.g. `https://token.actions.githubusercontent.com`. */
2119
+ readonly iss: Schema.String;
2120
+ /** The full ref the workflow ran on. */
2121
+ readonly ref: Schema.String;
2122
+ /** The commit. */
2123
+ readonly sha: Schema.String;
2124
+ /** `owner/repo`. */
2125
+ readonly repository: Schema.String;
2126
+ /** The event that triggered the run. */
2127
+ readonly event_name: Schema.String;
2128
+ /** The reusable-workflow ref, which is what a verifier pins against. */
2129
+ readonly job_workflow_ref: Schema.String;
2130
+ /** The calling workflow's ref. */
2131
+ readonly workflow_ref: Schema.String;
2132
+ /** The numeric repository id, as a string. */
2133
+ readonly repository_id: Schema.String;
2134
+ /** The numeric owner id, as a string. */
2135
+ readonly repository_owner_id: Schema.String;
2136
+ /** `github-hosted` or `self-hosted`. */
2137
+ readonly runner_environment: Schema.String;
2138
+ /** The run id, as a string. */
2139
+ readonly run_id: Schema.String;
2140
+ /** The run attempt, as a string. */
2141
+ readonly run_attempt: Schema.String;
2142
+ }>, {}>;
2143
+ /**
2144
+ * The claims a GitHub Actions OIDC token carries about the workflow that ran.
2145
+ *
2146
+ * @remarks
2147
+ * The field names are GitHub's own JWT claim names, kept verbatim rather than
2148
+ * translated to the kit's casing. They are an **external vocabulary** — the
2149
+ * same strings that appear in a SLSA provenance predicate and in every
2150
+ * published example of an Actions OIDC policy — and renaming them would put a
2151
+ * translation layer between a consumer and the specification they are reading.
2152
+ *
2153
+ * @public
2154
+ */
2155
+ declare class OidcClaims extends OidcClaims_base {}
2156
+ /**
2157
+ * The {@link OidcTokenIssuer} service shape.
2158
+ *
2159
+ * @public
2160
+ */
2161
+ interface OidcTokenIssuerShape {
2162
+ /**
2163
+ * Request an ID token, optionally bound to an audience.
2164
+ *
2165
+ * @remarks
2166
+ * Omitting the audience sends no `audience` parameter at all, matching
2167
+ * `@actions/core.getIDToken` — the runner's default audience is not the empty
2168
+ * string.
2169
+ */
2170
+ readonly token: (audience?: string) => Effect.Effect<Redacted.Redacted<string>, OidcTokenError>;
2171
+ /**
2172
+ * The token's claims, decoded.
2173
+ *
2174
+ * @remarks
2175
+ * **The signature is deliberately not verified**, for three reasons that are
2176
+ * recorded so nobody "fixes" it:
2177
+ *
2178
+ * 1. The token comes from the runner's own token-service endpoint over TLS.
2179
+ * The transport is the trust boundary, and the process asking for the
2180
+ * token is the process that received it.
2181
+ * 2. The claims populate a provenance predicate, not a trust decision.
2182
+ * Nothing branches on them for authorization; they are recorded as
2183
+ * attested facts about the workflow that ran.
2184
+ * 3. Verifying would need a JWKS fetch, which turns a decode into a network
2185
+ * call — untestable without a fixture server, and dependent on GitHub's
2186
+ * key endpoint being reachable at attestation time.
2187
+ *
2188
+ * A consumer that needs a *verified* token needs a different operation with a
2189
+ * different name and a different error channel, not an option on this one.
2190
+ *
2191
+ * Claims are on the surface rather than left to the call site because that is
2192
+ * what makes the provenance path reachable in a test: a double built with
2193
+ * {@link OidcTokenIssuer.layerFor} answers with real, decodable claims, where
2194
+ * the synthetic non-JWT its predecessor returned made every consumer's
2195
+ * `decodeJwtClaims` yield nothing and silently skipped the path under test.
2196
+ */
2197
+ readonly claims: (audience?: string) => Effect.Effect<OidcClaims, OidcTokenError>;
2198
+ }
2199
+ declare const OidcTokenIssuer_base: Context.ServiceClass<OidcTokenIssuer, "@effected/github-actions/OidcTokenIssuer", OidcTokenIssuerShape>;
2200
+ /**
2201
+ * The runner's OIDC token service.
2202
+ *
2203
+ * @remarks
2204
+ * Lives here rather than with attestation because it reads
2205
+ * `ACTIONS_ID_TOKEN_REQUEST_TOKEN` and `ACTIONS_ID_TOKEN_REQUEST_URL`, which
2206
+ * exist only when a workflow declares `permissions: id-token: write` — that is
2207
+ * a fact about the runner, not about signing.
2208
+ *
2209
+ * @example
2210
+ * ```ts
2211
+ * import { OidcTokenIssuer } from "@effected/github-actions";
2212
+ * import { Effect } from "effect";
2213
+ *
2214
+ * const program = Effect.gen(function* () {
2215
+ * const issuer = yield* OidcTokenIssuer;
2216
+ * const claims = yield* issuer.claims("sigstore");
2217
+ * return claims.job_workflow_ref;
2218
+ * });
2219
+ * ```
2220
+ *
2221
+ * @public
2222
+ */
2223
+ declare class OidcTokenIssuer extends OidcTokenIssuer_base {
2224
+ static readonly layer: Layer.Layer<OidcTokenIssuer, never, ActionEnvironment | HttpClient.HttpClient>;
2225
+ /**
2226
+ * An **unsigned** JWT carrying these claims.
2227
+ *
2228
+ * @remarks
2229
+ * For building test doubles, and nothing else: the signature segment is a
2230
+ * placeholder, so this token would fail any verifier. It exists because the
2231
+ * alternative — a double returning a synthetic non-JWT — is what made the
2232
+ * provenance path structurally unreachable in the source package, drawing
2233
+ * four separate apologetic comments from one consumer.
2234
+ */
2235
+ static readonly unsignedTokenFor: (claims: OidcClaims) => Redacted.Redacted<string>;
2236
+ /** A test double. Unstubbed members die rather than answering with a non-token. */
2237
+ static readonly makeTest: (overrides?: Partial<OidcTokenIssuerShape>) => OidcTokenIssuerShape;
2238
+ /** {@link OidcTokenIssuer.makeTest} behind `Layer.succeed`. */
2239
+ static readonly layerTest: (overrides?: Partial<OidcTokenIssuerShape>) => Layer.Layer<OidcTokenIssuer>;
2240
+ /**
2241
+ * A double that answers with these claims, consistently on both members.
2242
+ *
2243
+ * @remarks
2244
+ * `token()` returns a real decodable JWT built from the same claims
2245
+ * `claims()` returns, so a consumer that decodes the token itself and a
2246
+ * consumer that asks the service both see the same thing. A double whose two
2247
+ * members can disagree is how a test proves a path works while production
2248
+ * takes the other one.
2249
+ */
2250
+ static readonly layerFor: (claims: OidcClaims) => Layer.Layer<OidcTokenIssuer>;
2251
+ }
2252
+ //#endregion
2253
+ //#region src/Secret.d.ts
2254
+ /**
2255
+ * The declassification seam: the **only** place in this package where a
2256
+ * `Redacted` value becomes a plain string.
2257
+ *
2258
+ * @remarks
2259
+ * Some boundaries cannot carry a `Redacted`. A detached child process reads
2260
+ * its configuration from environment variables; `GITHUB_STATE` is a plaintext
2261
+ * file by GitHub's protocol. `Redacted` refusing to serialize is the whole
2262
+ * value of the type, so this module does not try to make it serializable —
2263
+ * it makes declassification **explicit, auditable, and impossible to do
2264
+ * quietly**.
2265
+ *
2266
+ * The invariant: **masking and declassification are the same call.** Every
2267
+ * member registers the value with the runner's log filter (`::add-mask::`)
2268
+ * *before* returning plaintext, so a secret cannot reach a child's environment
2269
+ * or a state file without the runner already knowing to redact it from logs.
2270
+ *
2271
+ * `Redacted.value` appears nowhere else in this package, and a test asserts
2272
+ * that structurally — a reintroduction elsewhere fails the suite rather than
2273
+ * review.
2274
+ *
2275
+ * What this deliberately does **not** do is encrypt the handoff. The child
2276
+ * runs on the same runner, as the same user, as the parent; a key would have
2277
+ * to travel the same channel as the secret it protects.
2278
+ *
2279
+ * @example
2280
+ * ```ts
2281
+ * import { Secret } from "@effected/github-actions";
2282
+ * import { Effect } from "effect";
2283
+ *
2284
+ * const program = Effect.gen(function* () {
2285
+ * const env = yield* Secret.forChildEnv({ MY_TOKEN: theToken });
2286
+ * // every value in `env` is already masked in the runner log
2287
+ * return env;
2288
+ * });
2289
+ * ```
2290
+ *
2291
+ * @public
2292
+ */
2293
+ declare class Secret {
2294
+ private constructor();
2295
+ /**
2296
+ * Declassify a set of secrets for a child process's environment.
2297
+ *
2298
+ * @remarks
2299
+ * Every value is masked before any plaintext is returned — including when
2300
+ * one of them fails, because masking happens for the whole set first.
2301
+ */
2302
+ static readonly forChildEnv: (entries: Readonly<Record<string, Redacted.Redacted<string>>>) => Effect.Effect<Record<string, string>, never, ActionOutputs>;
2303
+ /**
2304
+ * Declassify one secret for a runner file (`GITHUB_STATE`, `GITHUB_OUTPUT`).
2305
+ *
2306
+ * @remarks
2307
+ * Masks first. The runner file is plaintext regardless; the mask is what
2308
+ * keeps the value out of the visible log.
2309
+ */
2310
+ static readonly forRunnerFile: (secret: Redacted.Redacted<string>) => Effect.Effect<string, never, ActionOutputs>;
2311
+ /**
2312
+ * Declassify one secret for an in-process use that needs the raw bytes.
2313
+ *
2314
+ * @remarks
2315
+ * Request signing is the case this exists for: an HMAC cannot be computed
2316
+ * over a `Redacted`, so a signing key has to become a string somewhere, and
2317
+ * the point of this module is that "somewhere" is here and nowhere else.
2318
+ *
2319
+ * It masks even though the value is never *written* anywhere, and that is
2320
+ * deliberate rather than superstitious: a signing key that leaks does so
2321
+ * through something nobody audited — a debug log of outgoing headers, a
2322
+ * serialized error, a stack trace carrying the closure. Registering it with
2323
+ * the runner's filter costs one call and makes every one of those redacted.
2324
+ *
2325
+ * Call it **once, at layer construction**, not per operation: masking is
2326
+ * idempotent but a workflow command per request is noise in the log.
2327
+ */
2328
+ static readonly forSigning: (secret: Redacted.Redacted<string>) => Effect.Effect<string, never, ActionOutputs>;
2329
+ /**
2330
+ * The far side of a handoff: re-wrap a plaintext environment variable.
2331
+ *
2332
+ * @remarks
2333
+ * A `Config`, so a missing or empty handoff is an honest `ConfigError`
2334
+ * naming the variable rather than an empty `Redacted` that fails much later
2335
+ * as an authentication error.
2336
+ */
2337
+ static readonly adopt: (name: string) => Config.Config<Redacted.Redacted<string>>;
2338
+ }
2339
+ //#endregion
2340
+ //#region src/ToolInstaller.d.ts
2341
+ declare const ToolInstallerError_base: Schema.Class<ToolInstallerError, Schema.TaggedStruct<"ToolInstallerError", {
2342
+ /**
2343
+ * `downloadFailed` — the archive could not be fetched. `extractFailed` — the
2344
+ * extraction tool refused the archive or is not installed. `cacheFailed` —
2345
+ * the tool could not be written into the runner's tool cache.
2346
+ */
2347
+ readonly reason: Schema.Literals<readonly ["downloadFailed", "extractFailed", "cacheFailed"]>;
2348
+ /** The HTTP status, when there was one. Drives the retry decision. */
2349
+ readonly status: Schema.optionalKey<Schema.Number>;
2350
+ /** What was being worked on — a url, an archive path, or a tool name. */
2351
+ readonly subject: Schema.optionalKey<Schema.String>;
2352
+ /** The extraction tool's own complaint, which is the only useful part of a tar failure. */
2353
+ readonly stderr: Schema.optionalKey<Schema.String>;
2354
+ /** The underlying failure, preserved structurally. */
2355
+ readonly cause: Schema.optionalKey<Schema.Defect>;
2356
+ }>, import("effect/Cause").YieldableError>;
2357
+ /**
2358
+ * Raised when a tool cannot be downloaded, extracted or cached.
2359
+ *
2360
+ * @public
2361
+ */
2362
+ declare class ToolInstallerError extends ToolInstallerError_base {
2363
+ get message(): string;
2364
+ /**
2365
+ * Whether retrying could plausibly help.
2366
+ *
2367
+ * @remarks
2368
+ * A derived getter rather than a field, so it cannot be set inconsistently
2369
+ * with the status it is derived from. `408`, `429` and any `5xx` are the
2370
+ * server saying "later"; a `404` is it saying "never", and retrying that
2371
+ * three times just makes a broken url take longer to fail.
2372
+ */
2373
+ get retryable(): boolean;
2374
+ }
2375
+ /**
2376
+ * Where extraction should put its output.
2377
+ *
2378
+ * @public
2379
+ */
2380
+ interface ExtractOptions {
2381
+ /** The destination. A fresh temporary directory when omitted. */
2382
+ readonly destination?: string | undefined;
2383
+ /** Flags for `tar`. Defaults to `["xzf"]`, i.e. a gzipped tarball. */
2384
+ readonly flags?: ReadonlyArray<string> | undefined;
2385
+ }
2386
+ /**
2387
+ * The {@link ToolInstaller} service shape.
2388
+ *
2389
+ * @public
2390
+ */
2391
+ interface ToolInstallerShape {
2392
+ /**
2393
+ * A cached tool, if this runner already has it.
2394
+ *
2395
+ * @remarks
2396
+ * Absent is not an error, and neither is an unreadable cache: both mean
2397
+ * "install it", which is the only thing a caller can do about either.
2398
+ */
2399
+ readonly find: (tool: string, version: string) => Effect.Effect<Option.Option<string>>;
2400
+ /** Download a url to a temporary file, retrying what is worth retrying. */
2401
+ readonly download: (url: string) => Effect.Effect<string, ToolInstallerError>;
2402
+ /** Extract a tarball. Returns the directory its contents landed in. */
2403
+ readonly extractTar: (archive: string, options?: ExtractOptions) => Effect.Effect<string, ToolInstallerError>;
2404
+ /** Extract a zip. Returns the directory its contents landed in. */
2405
+ readonly extractZip: (archive: string, options?: ExtractOptions) => Effect.Effect<string, ToolInstallerError>;
2406
+ /** Install a directory into the tool cache. Returns its cached path. */
2407
+ readonly cacheDir: (source: string, tool: string, version: string) => Effect.Effect<string, ToolInstallerError>;
2408
+ /** Install a single file into the tool cache under `name`. Returns the cached directory. */
2409
+ readonly cacheFile: (source: string, name: string, tool: string, version: string) => Effect.Effect<string, ToolInstallerError>;
2410
+ }
2411
+ declare const ToolInstaller_base: Context.ServiceClass<ToolInstaller, "@effected/github-actions/ToolInstaller", ToolInstallerShape>;
2412
+ /**
2413
+ * Download, extract and cache a toolchain in the runner's tool cache.
2414
+ *
2415
+ * @remarks
2416
+ * The primitives, not a workflow: a consumer composes `find` → `download` →
2417
+ * `extractTar` → `cacheDir` in whatever order its tool needs, because the
2418
+ * orders genuinely differ (a single binary skips extraction, a tarball with a
2419
+ * nested root directory needs a path fixup between extract and cache).
2420
+ *
2421
+ * No `@actions/tool-cache` dependency — the cache is a directory layout, and
2422
+ * this reproduces the layout rather than importing a package to compute it.
2423
+ *
2424
+ * @example
2425
+ * ```ts
2426
+ * import { ToolInstaller } from "@effected/github-actions";
2427
+ * import { Effect, Option } from "effect";
2428
+ *
2429
+ * const install = Effect.gen(function* () {
2430
+ * const installer = yield* ToolInstaller;
2431
+ * const cached = yield* installer.find("node", "22.11.0");
2432
+ * if (Option.isSome(cached)) return cached.value;
2433
+ * const archive = yield* installer.download("https://nodejs.org/dist/v22.11.0/node.tar.gz");
2434
+ * const extracted = yield* installer.extractTar(archive);
2435
+ * return yield* installer.cacheDir(extracted, "node", "22.11.0");
2436
+ * });
2437
+ * ```
2438
+ *
2439
+ * @public
2440
+ */
2441
+ declare class ToolInstaller extends ToolInstaller_base {
2442
+ static readonly layer: Layer.Layer<ToolInstaller, never, ActionEnvironment | FileSystem.FileSystem | Path.Path | HttpClient.HttpClient | ChildProcessSpawner.ChildProcessSpawner>;
2443
+ /**
2444
+ * Where a tool lives in the cache.
2445
+ *
2446
+ * @remarks
2447
+ * Pure, exported and tested on its own, because the layout is a **contract
2448
+ * with the runner**: `<root>/<tool>/<version>/<arch>` is what the hosted
2449
+ * image populates and what `@actions/tool-cache` reads, so a tool cached at
2450
+ * any other path is invisible to every other step in the workflow. The `arch`
2451
+ * segment uses Node's `process.arch` spelling (`x64`) rather than the
2452
+ * runner's `RUNNER_ARCH` (`X64`) for the same reason.
2453
+ */
2454
+ static readonly cachePath: (options: {
2455
+ readonly root: string;
2456
+ readonly tool: string;
2457
+ readonly version: string;
2458
+ readonly arch: string;
2459
+ }) => string;
2460
+ /** A test double. Unstubbed members die rather than reporting a tool that is not there. */
2461
+ static readonly makeTest: (overrides?: Partial<ToolInstallerShape>) => ToolInstallerShape;
2462
+ /** {@link ToolInstaller.makeTest} behind `Layer.succeed`. */
2463
+ static readonly layerTest: (overrides?: Partial<ToolInstallerShape>) => Layer.Layer<ToolInstaller>;
2464
+ }
2465
+ //#endregion
2466
+ export { Action, ActionCache, ActionCacheError, type ActionCacheShape, ActionEnvironment, ActionEnvironmentError, type ActionEnvironmentShape, ActionInput, ActionLogger, type ActionLoggerShape, ActionOutputError, ActionOutputs, type ActionOutputsShape, type ActionRunOptions, ActionRuntime, type ActionServices, ActionState, ActionStateError, type ActionStateShape, type AnnotationProperties, Artifact, ArtifactError, type ArtifactItem, type ArtifactRef, type ArtifactShape, type Blob, BlobEnvelope, BlobEnvelopeError, BlobStore, BlobStoreError, type BlobStoreShape, BlobTransferError, CacheKey, CacheKeyError, type ClientLayerOptions, type DataBlobTransfer, DetachedProcess, DetachedProcessError, type DetachedSpawnOptions, type DownloadOptions, type DownloadResult, DryRun, type DryRunShape, type ExtractOptions, type FileBlobTransfer, GitHubCacheBlobStore, GitHubContext, GitHubToken, GitHubTokenError, OidcClaims, OidcTokenError, OidcTokenIssuer, type OidcTokenIssuerShape, ProcessId, type ProvisionOptions, type ReadOptions, type ReadinessOptions, RunnerContext, type S3Config, Secret, ToolInstaller, ToolInstallerError, type ToolInstallerShape, type UploadOptions, type UploadResult, WorkflowCommand, describeCause };
2467
+ //# sourceMappingURL=index.d.ts.map