@savvy-web/github-action-effects 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/LICENSE +21 -0
- package/README.md +73 -0
- package/index.d.ts +416 -0
- package/index.js +295 -0
- package/package.json +66 -0
- package/tsdoc-metadata.json +11 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Savvy Web Strategy, LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# @savvy-web/github-action-effects
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@savvy-web/github-action-effects)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Build GitHub Actions with [Effect](https://effect.website) -- schema-validated
|
|
7
|
+
inputs, structured logging with buffered output, and type-safe outputs through
|
|
8
|
+
composable service layers.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Schema-validated inputs and outputs** using Effect Schema
|
|
13
|
+
- **Three-tier action logger** (info/verbose/debug) with automatic log buffering
|
|
14
|
+
- **GitHub Flavored Markdown builders** for step summaries
|
|
15
|
+
- **Test layers for every service** -- no mocking `@actions/core` required
|
|
16
|
+
- **Full TypeScript** with strict mode and ESM
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @savvy-web/github-action-effects effect @actions/core
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { Effect, Layer, Schema } from "effect";
|
|
28
|
+
import {
|
|
29
|
+
ActionInputs,
|
|
30
|
+
ActionInputsLive,
|
|
31
|
+
ActionOutputs,
|
|
32
|
+
ActionOutputsLive,
|
|
33
|
+
ActionLoggerLive,
|
|
34
|
+
ActionLoggerLayer,
|
|
35
|
+
LogLevelInput,
|
|
36
|
+
resolveLogLevel,
|
|
37
|
+
setLogLevel,
|
|
38
|
+
table,
|
|
39
|
+
} from "@savvy-web/github-action-effects";
|
|
40
|
+
|
|
41
|
+
const program = Effect.gen(function* () {
|
|
42
|
+
const inputs = yield* ActionInputs;
|
|
43
|
+
const outputs = yield* ActionOutputs;
|
|
44
|
+
|
|
45
|
+
const level = yield* inputs.get("log-level", LogLevelInput);
|
|
46
|
+
yield* setLogLevel(resolveLogLevel(level));
|
|
47
|
+
|
|
48
|
+
const name = yield* inputs.get("name", Schema.String);
|
|
49
|
+
yield* outputs.set("greeting", `Hello, ${name}!`);
|
|
50
|
+
yield* outputs.summary(table(["Input", "Value"], [["name", name]]));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const MainLive = Layer.mergeAll(
|
|
54
|
+
ActionInputsLive,
|
|
55
|
+
ActionOutputsLive,
|
|
56
|
+
ActionLoggerLive,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
program.pipe(
|
|
60
|
+
Effect.provide(ActionLoggerLayer),
|
|
61
|
+
Effect.provide(MainLive),
|
|
62
|
+
Effect.runPromise,
|
|
63
|
+
);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Documentation
|
|
67
|
+
|
|
68
|
+
For architecture, API reference, testing guides, and advanced usage, see
|
|
69
|
+
[docs](./docs/).
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
[MIT](LICENSE)
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \@savvy-web/github-action-effects
|
|
3
|
+
*
|
|
4
|
+
* Effect-based utility library for building robust, well-logged,
|
|
5
|
+
* and schema-validated GitHub Actions.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { AnnotationProperties } from '@actions/core';
|
|
11
|
+
import { Context } from 'effect';
|
|
12
|
+
import { Effect } from 'effect';
|
|
13
|
+
import { Equals } from 'effect/Types';
|
|
14
|
+
import { FiberRef } from 'effect';
|
|
15
|
+
import { Layer } from 'effect';
|
|
16
|
+
import { Logger } from 'effect';
|
|
17
|
+
import type { Option } from 'effect';
|
|
18
|
+
import { Schema } from 'effect';
|
|
19
|
+
import { YieldableError } from 'effect/Cause';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Error when a GitHub Action input is missing or fails schema validation.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ActionInputError extends ActionInputErrorBase<{
|
|
25
|
+
/** The input name from action.yml. */
|
|
26
|
+
readonly inputName: string;
|
|
27
|
+
/** Human-readable description of what went wrong. */
|
|
28
|
+
readonly reason: string;
|
|
29
|
+
/** The raw string value received, if any. */
|
|
30
|
+
readonly rawValue: string | undefined;
|
|
31
|
+
}> {
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Base class for ActionInputError.
|
|
36
|
+
*
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export declare const ActionInputErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
|
|
40
|
+
readonly _tag: "ActionInputError";
|
|
41
|
+
} & Readonly<A>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Service interface for reading GitHub Action inputs with schema validation.
|
|
45
|
+
*
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
export declare interface ActionInputs {
|
|
49
|
+
/**
|
|
50
|
+
* Read a required input and validate it against a schema.
|
|
51
|
+
*/
|
|
52
|
+
readonly get: <A, I>(name: string, schema: Schema.Schema<A, I, never>) => Effect.Effect<A, ActionInputError>;
|
|
53
|
+
/**
|
|
54
|
+
* Read an optional input. Returns `Option.none()` if empty.
|
|
55
|
+
*/
|
|
56
|
+
readonly getOptional: <A, I>(name: string, schema: Schema.Schema<A, I, never>) => Effect.Effect<Option.Option<A>, ActionInputError>;
|
|
57
|
+
/**
|
|
58
|
+
* Read a required input and mask it as a secret in logs.
|
|
59
|
+
*/
|
|
60
|
+
readonly getSecret: <A, I>(name: string, schema: Schema.Schema<A, I, never>) => Effect.Effect<A, ActionInputError>;
|
|
61
|
+
/**
|
|
62
|
+
* Read a required input as a JSON string, parse and validate it.
|
|
63
|
+
*/
|
|
64
|
+
readonly getJson: <A, I>(name: string, schema: Schema.Schema<A, I, never>) => Effect.Effect<A, ActionInputError>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* ActionInputs tag for dependency injection.
|
|
69
|
+
*
|
|
70
|
+
* @public
|
|
71
|
+
*/
|
|
72
|
+
export declare const ActionInputs: Context.Tag<ActionInputs, ActionInputs>;
|
|
73
|
+
|
|
74
|
+
export declare const ActionInputsLive: Layer.Layer<ActionInputs>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Test implementation that reads from a provided record.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const layer = ActionInputsTest.layer({ "package-name": "my-pkg" });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare const ActionInputsTest: {
|
|
85
|
+
readonly layer: (inputs: Record<string, string>) => Layer.Layer<ActionInputs, never, never>;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Service interface for action-specific logging operations beyond the Effect Logger.
|
|
90
|
+
*
|
|
91
|
+
* @remarks
|
|
92
|
+
* The core log-level routing is handled by the Effect Logger installed
|
|
93
|
+
* via {@link ActionLoggerLayer}. This service provides additional
|
|
94
|
+
* GitHub Actions-specific operations like log groups and buffering.
|
|
95
|
+
*
|
|
96
|
+
* @public
|
|
97
|
+
*/
|
|
98
|
+
export declare interface ActionLogger {
|
|
99
|
+
/**
|
|
100
|
+
* Run an effect inside a collapsible log group.
|
|
101
|
+
*/
|
|
102
|
+
readonly group: <A, E, R>(name: string, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
|
|
103
|
+
/**
|
|
104
|
+
* Run an effect with buffered logging. At `info` level, verbose output
|
|
105
|
+
* is captured in memory. On success the buffer is discarded. On failure
|
|
106
|
+
* the buffer is flushed before the error is reported.
|
|
107
|
+
*/
|
|
108
|
+
readonly withBuffer: <A, E, R>(label: string, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
|
|
109
|
+
/**
|
|
110
|
+
* Emit an error annotation (red, blocks PR checks).
|
|
111
|
+
*/
|
|
112
|
+
readonly annotationError: (message: string, properties?: AnnotationProperties) => Effect.Effect<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Emit a warning annotation (yellow, informational).
|
|
115
|
+
*/
|
|
116
|
+
readonly annotationWarning: (message: string, properties?: AnnotationProperties) => Effect.Effect<void>;
|
|
117
|
+
/**
|
|
118
|
+
* Emit a notice annotation (blue, informational).
|
|
119
|
+
*/
|
|
120
|
+
readonly annotationNotice: (message: string, properties?: AnnotationProperties) => Effect.Effect<void>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* ActionLogger tag for dependency injection.
|
|
125
|
+
*
|
|
126
|
+
* @public
|
|
127
|
+
*/
|
|
128
|
+
export declare const ActionLogger: Context.Tag<ActionLogger, ActionLogger>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Layer that installs the GitHub Actions logger as the default Effect logger.
|
|
132
|
+
*/
|
|
133
|
+
export declare const ActionLoggerLayer: Layer.Layer<never>;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Live implementation of the ActionLogger service.
|
|
137
|
+
*/
|
|
138
|
+
export declare const ActionLoggerLive: Layer.Layer<ActionLogger>;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Test implementation that captures log operations in memory.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* const state = ActionLoggerTest.empty();
|
|
146
|
+
* const layer = ActionLoggerTest.layer(state);
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export declare const ActionLoggerTest: {
|
|
150
|
+
/**
|
|
151
|
+
* Create a fresh empty test state container.
|
|
152
|
+
*/
|
|
153
|
+
readonly empty: () => ActionLoggerTestState;
|
|
154
|
+
/**
|
|
155
|
+
* Create a test layer from the given state.
|
|
156
|
+
*/
|
|
157
|
+
readonly layer: (state: ActionLoggerTestState) => Layer.Layer<ActionLogger, never, never>;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* In-memory state captured by the test logger.
|
|
162
|
+
*/
|
|
163
|
+
export declare interface ActionLoggerTestState {
|
|
164
|
+
readonly entries: Array<{
|
|
165
|
+
readonly level: string;
|
|
166
|
+
readonly message: string;
|
|
167
|
+
}>;
|
|
168
|
+
readonly groups: Array<{
|
|
169
|
+
readonly name: string;
|
|
170
|
+
readonly entries: Array<{
|
|
171
|
+
readonly level: string;
|
|
172
|
+
readonly message: string;
|
|
173
|
+
}>;
|
|
174
|
+
}>;
|
|
175
|
+
readonly annotations: Array<{
|
|
176
|
+
readonly type: TestAnnotationType;
|
|
177
|
+
readonly message: string;
|
|
178
|
+
readonly properties?: AnnotationProperties;
|
|
179
|
+
}>;
|
|
180
|
+
readonly flushedBuffers: Array<{
|
|
181
|
+
readonly label: string;
|
|
182
|
+
readonly entries: Array<string>;
|
|
183
|
+
}>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* The three log levels supported by the action logger.
|
|
188
|
+
*
|
|
189
|
+
* - `info` — Buffered. Shows only outcome summaries. Flushes verbose buffer on failure.
|
|
190
|
+
* - `verbose` — Unbuffered milestones. Start/finish markers for operations.
|
|
191
|
+
* - `debug` — Everything. Full command output, input/output values, internal state.
|
|
192
|
+
*/
|
|
193
|
+
export declare const ActionLogLevel: Schema.Literal<["info", "verbose", "debug"]>;
|
|
194
|
+
|
|
195
|
+
export declare type ActionLogLevel = typeof ActionLogLevel.Type;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Error when a GitHub Action output fails schema validation or writing.
|
|
199
|
+
*/
|
|
200
|
+
export declare class ActionOutputError extends ActionOutputErrorBase<{
|
|
201
|
+
/** The output name. */
|
|
202
|
+
readonly outputName: string;
|
|
203
|
+
/** Human-readable description of what went wrong. */
|
|
204
|
+
readonly reason: string;
|
|
205
|
+
}> {
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Base class for ActionOutputError.
|
|
210
|
+
*
|
|
211
|
+
* @internal
|
|
212
|
+
*/
|
|
213
|
+
export declare const ActionOutputErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
|
|
214
|
+
readonly _tag: "ActionOutputError";
|
|
215
|
+
} & Readonly<A>;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Service interface for setting GitHub Action outputs with schema validation.
|
|
219
|
+
*
|
|
220
|
+
* @public
|
|
221
|
+
*/
|
|
222
|
+
export declare interface ActionOutputs {
|
|
223
|
+
/**
|
|
224
|
+
* Set a string output value.
|
|
225
|
+
*/
|
|
226
|
+
readonly set: (name: string, value: string) => Effect.Effect<void>;
|
|
227
|
+
/**
|
|
228
|
+
* Serialize a value as JSON and set it as an output.
|
|
229
|
+
* Validates against the schema before serializing.
|
|
230
|
+
*/
|
|
231
|
+
readonly setJson: <A, I>(name: string, value: A, schema: Schema.Schema<A, I, never>) => Effect.Effect<void, ActionOutputError>;
|
|
232
|
+
/**
|
|
233
|
+
* Write markdown content to the step summary.
|
|
234
|
+
*/
|
|
235
|
+
readonly summary: (content: string) => Effect.Effect<void, ActionOutputError>;
|
|
236
|
+
/**
|
|
237
|
+
* Export an environment variable for subsequent steps.
|
|
238
|
+
*/
|
|
239
|
+
readonly exportVariable: (name: string, value: string) => Effect.Effect<void>;
|
|
240
|
+
/**
|
|
241
|
+
* Add a directory to PATH for subsequent steps.
|
|
242
|
+
*/
|
|
243
|
+
readonly addPath: (path: string) => Effect.Effect<void>;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* ActionOutputs tag for dependency injection.
|
|
248
|
+
*
|
|
249
|
+
* @public
|
|
250
|
+
*/
|
|
251
|
+
export declare const ActionOutputs: Context.Tag<ActionOutputs, ActionOutputs>;
|
|
252
|
+
|
|
253
|
+
export declare const ActionOutputsLive: Layer.Layer<ActionOutputs>;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Test implementation that captures outputs in memory.
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```ts
|
|
260
|
+
* const state = ActionOutputsTest.empty();
|
|
261
|
+
* const layer = ActionOutputsTest.layer(state);
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
export declare const ActionOutputsTest: {
|
|
265
|
+
/**
|
|
266
|
+
* Create a fresh empty test state container.
|
|
267
|
+
*/
|
|
268
|
+
readonly empty: () => ActionOutputsTestState;
|
|
269
|
+
/**
|
|
270
|
+
* Create a test layer from the given state.
|
|
271
|
+
*/
|
|
272
|
+
readonly layer: (state: ActionOutputsTestState) => Layer.Layer<ActionOutputs, never, never>;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* In-memory state captured by the test output layer.
|
|
277
|
+
*/
|
|
278
|
+
export declare interface ActionOutputsTestState {
|
|
279
|
+
readonly outputs: Array<CapturedOutput>;
|
|
280
|
+
readonly summaries: Array<string>;
|
|
281
|
+
readonly variables: Array<CapturedOutput>;
|
|
282
|
+
readonly paths: Array<string>;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Bold text.
|
|
287
|
+
*/
|
|
288
|
+
export declare const bold: (text: string) => string;
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* A captured output entry.
|
|
292
|
+
*/
|
|
293
|
+
export declare const CapturedOutput: Schema.Struct<{
|
|
294
|
+
name: typeof Schema.String;
|
|
295
|
+
value: typeof Schema.String;
|
|
296
|
+
}>;
|
|
297
|
+
|
|
298
|
+
export declare type CapturedOutput = typeof CapturedOutput.Type;
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Build a checkbox checklist.
|
|
302
|
+
*/
|
|
303
|
+
export declare const checklist: (items: readonly {
|
|
304
|
+
readonly label: string;
|
|
305
|
+
readonly checked: boolean;
|
|
306
|
+
}[]) => string;
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* A single item in a checklist.
|
|
310
|
+
*/
|
|
311
|
+
export declare const ChecklistItem: Schema.Struct<{
|
|
312
|
+
label: typeof Schema.String;
|
|
313
|
+
checked: typeof Schema.Boolean;
|
|
314
|
+
}>;
|
|
315
|
+
|
|
316
|
+
export declare type ChecklistItem = typeof ChecklistItem.Type;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Inline code.
|
|
320
|
+
*/
|
|
321
|
+
export declare const code: (text: string) => string;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Fenced code block.
|
|
325
|
+
*/
|
|
326
|
+
export declare const codeBlock: (content: string, language?: string) => string;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* FiberRef that holds the current action log level for the fiber.
|
|
330
|
+
*/
|
|
331
|
+
export declare const CurrentLogLevel: FiberRef.FiberRef<ActionLogLevel>;
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Build a collapsible `<details>` block.
|
|
335
|
+
*/
|
|
336
|
+
export declare const details: (summary: string, content: string) => string;
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Build a markdown heading.
|
|
340
|
+
*
|
|
341
|
+
* @param level - Heading level 1-6, defaults to 2.
|
|
342
|
+
*/
|
|
343
|
+
export declare const heading: (text: string, level?: 1 | 2 | 3 | 4 | 5 | 6) => string;
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Build a markdown link.
|
|
347
|
+
*/
|
|
348
|
+
export declare const link: (text: string, url: string) => string;
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Build a bulleted list.
|
|
352
|
+
*/
|
|
353
|
+
export declare const list: (items: readonly string[]) => string;
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Log level input values accepted by the standardized `log-level` action input.
|
|
357
|
+
* Includes `auto` which resolves based on the GitHub Actions environment.
|
|
358
|
+
*/
|
|
359
|
+
export declare const LogLevelInput: Schema.Literal<["info", "verbose", "debug", "auto"]>;
|
|
360
|
+
|
|
361
|
+
export declare type LogLevelInput = typeof LogLevelInput.Type;
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Create an Effect Logger that routes to GitHub Actions log functions.
|
|
365
|
+
*
|
|
366
|
+
* - Always writes to `core.debug()` (GitHub-gated shadow channel).
|
|
367
|
+
* - Writes to user-facing output based on the action log level.
|
|
368
|
+
*/
|
|
369
|
+
export declare const makeActionLogger: () => Logger.Logger<unknown, void>;
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Resolve a {@link LogLevelInput} to a concrete {@link ActionLogLevel}.
|
|
373
|
+
*
|
|
374
|
+
* `"auto"` resolves to `"info"` unless `RUNNER_DEBUG` is `"1"`,
|
|
375
|
+
* in which case it resolves to `"debug"`.
|
|
376
|
+
*/
|
|
377
|
+
export declare const resolveLogLevel: (input: "auto" | "debug" | "info" | "verbose") => "debug" | "info" | "verbose";
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Horizontal rule.
|
|
381
|
+
*/
|
|
382
|
+
export declare const rule: () => string;
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Set the action log level for the current scope.
|
|
386
|
+
*/
|
|
387
|
+
export declare const setLogLevel: (level: "debug" | "info" | "verbose") => Effect.Effect<void, never, never>;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Status values for {@link statusIcon}.
|
|
391
|
+
*/
|
|
392
|
+
export declare const Status: Schema.Literal<["pass", "fail", "skip", "warn"]>;
|
|
393
|
+
|
|
394
|
+
export declare type Status = typeof Status.Type;
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Map a {@link Status} to its emoji indicator.
|
|
398
|
+
*/
|
|
399
|
+
export declare const statusIcon: (status: "fail" | "pass" | "skip" | "warn") => string;
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Build a GFM table from headers and rows.
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```ts
|
|
406
|
+
* table(["Name", "Status"], [["build", "pass"], ["test", "fail"]])
|
|
407
|
+
* ```
|
|
408
|
+
*/
|
|
409
|
+
export declare const table: (headers: readonly string[], rows: readonly (readonly string[])[]) => string;
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Annotation type captured by the test layer.
|
|
413
|
+
*/
|
|
414
|
+
export declare type TestAnnotationType = "error" | "warning" | "notice";
|
|
415
|
+
|
|
416
|
+
export { }
|
package/index.js
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { Context, Data, Effect, FiberRef, FiberRefs, Layer, LogLevel, Logger, Option, Schema } from "effect";
|
|
2
|
+
import { addPath, debug, endGroup, error as core_error, exportVariable, getInput, info, notice, setOutput, setSecret, startGroup, summary as core_summary, warning } from "@actions/core";
|
|
3
|
+
const ActionInputErrorBase = Data.TaggedError("ActionInputError");
|
|
4
|
+
class ActionInputError extends ActionInputErrorBase {
|
|
5
|
+
}
|
|
6
|
+
const ActionOutputErrorBase = Data.TaggedError("ActionOutputError");
|
|
7
|
+
class ActionOutputError extends ActionOutputErrorBase {
|
|
8
|
+
}
|
|
9
|
+
const ActionInputs = Context.GenericTag("ActionInputs");
|
|
10
|
+
const decodeInput = (name, raw, schema)=>Schema.decode(schema)(raw).pipe(Effect.mapError((parseError)=>new ActionInputError({
|
|
11
|
+
inputName: name,
|
|
12
|
+
reason: `Input "${name}" validation failed: ${parseError.message}`,
|
|
13
|
+
rawValue: raw
|
|
14
|
+
})));
|
|
15
|
+
const decodeJsonInput = (name, raw, schema)=>Effect["try"]({
|
|
16
|
+
try: ()=>JSON.parse(raw),
|
|
17
|
+
catch: (error)=>new ActionInputError({
|
|
18
|
+
inputName: name,
|
|
19
|
+
reason: `Input "${name}" is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
20
|
+
rawValue: raw
|
|
21
|
+
})
|
|
22
|
+
}).pipe(Effect.flatMap((parsed)=>Schema.decode(schema)(parsed).pipe(Effect.mapError((parseError)=>new ActionInputError({
|
|
23
|
+
inputName: name,
|
|
24
|
+
reason: `Input "${name}" JSON validation failed: ${parseError.message}`,
|
|
25
|
+
rawValue: raw
|
|
26
|
+
})))));
|
|
27
|
+
const ActionInputsLive = Layer.succeed(ActionInputs, {
|
|
28
|
+
get: (name, schema)=>Effect.sync(()=>getInput(name, {
|
|
29
|
+
required: true
|
|
30
|
+
})).pipe(Effect.flatMap((raw)=>decodeInput(name, raw, schema))),
|
|
31
|
+
getOptional: (name, schema)=>Effect.sync(()=>getInput(name, {
|
|
32
|
+
required: false
|
|
33
|
+
})).pipe(Effect.flatMap((raw)=>{
|
|
34
|
+
if ("" === raw) return Effect.succeed(Option.none());
|
|
35
|
+
return decodeInput(name, raw, schema).pipe(Effect.map((a)=>Option.some(a)));
|
|
36
|
+
})),
|
|
37
|
+
getSecret: (name, schema)=>Effect.sync(()=>{
|
|
38
|
+
const raw = getInput(name, {
|
|
39
|
+
required: true
|
|
40
|
+
});
|
|
41
|
+
setSecret(raw);
|
|
42
|
+
return raw;
|
|
43
|
+
}).pipe(Effect.flatMap((raw)=>decodeInput(name, raw, schema))),
|
|
44
|
+
getJson: (name, schema)=>Effect.sync(()=>getInput(name, {
|
|
45
|
+
required: true
|
|
46
|
+
})).pipe(Effect.flatMap((raw)=>decodeJsonInput(name, raw, schema)))
|
|
47
|
+
});
|
|
48
|
+
const missingInput = (name)=>new ActionInputError({
|
|
49
|
+
inputName: name,
|
|
50
|
+
reason: `Input "${name}" is required but not provided`,
|
|
51
|
+
rawValue: void 0
|
|
52
|
+
});
|
|
53
|
+
const ActionInputsTest = {
|
|
54
|
+
layer: (inputs)=>Layer.succeed(ActionInputs, {
|
|
55
|
+
get: (name, schema)=>{
|
|
56
|
+
const raw = inputs[name];
|
|
57
|
+
if (void 0 === raw) return Effect.fail(missingInput(name));
|
|
58
|
+
return decodeInput(name, raw, schema);
|
|
59
|
+
},
|
|
60
|
+
getOptional: (name, schema)=>{
|
|
61
|
+
const raw = inputs[name];
|
|
62
|
+
if (void 0 === raw || "" === raw) return Effect.succeed(Option.none());
|
|
63
|
+
return decodeInput(name, raw, schema).pipe(Effect.map((a)=>Option.some(a)));
|
|
64
|
+
},
|
|
65
|
+
getSecret: (name, schema)=>{
|
|
66
|
+
const raw = inputs[name];
|
|
67
|
+
if (void 0 === raw) return Effect.fail(missingInput(name));
|
|
68
|
+
return decodeInput(name, raw, schema);
|
|
69
|
+
},
|
|
70
|
+
getJson: (name, schema)=>{
|
|
71
|
+
const raw = inputs[name];
|
|
72
|
+
if (void 0 === raw) return Effect.fail(missingInput(name));
|
|
73
|
+
return decodeJsonInput(name, raw, schema);
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
};
|
|
77
|
+
const ActionLogger = Context.GenericTag("ActionLogger");
|
|
78
|
+
const CurrentLogLevel = FiberRef.unsafeMake("info");
|
|
79
|
+
const setLogLevel = (level)=>FiberRef.set(CurrentLogLevel, level);
|
|
80
|
+
const formatMessage = (message)=>{
|
|
81
|
+
const value = Array.isArray(message) && 1 === message.length ? message[0] : message;
|
|
82
|
+
return "string" == typeof value ? value : JSON.stringify(value);
|
|
83
|
+
};
|
|
84
|
+
const shouldEmitUserFacing = (effectLevel, actionLevel)=>{
|
|
85
|
+
if ("debug" === actionLevel) return true;
|
|
86
|
+
if ("verbose" === actionLevel) return LogLevel.greaterThanEqual(effectLevel, LogLevel.Info);
|
|
87
|
+
return LogLevel.greaterThanEqual(effectLevel, LogLevel.Warning);
|
|
88
|
+
};
|
|
89
|
+
const emitToGitHub = (level, message)=>{
|
|
90
|
+
if (LogLevel.greaterThanEqual(level, LogLevel.Error)) core_error(message);
|
|
91
|
+
else if (LogLevel.greaterThanEqual(level, LogLevel.Warning)) warning(message);
|
|
92
|
+
else info(message);
|
|
93
|
+
};
|
|
94
|
+
const makeActionLogger = ()=>Logger.make(({ logLevel, message, context })=>{
|
|
95
|
+
const text = formatMessage(message);
|
|
96
|
+
debug(text);
|
|
97
|
+
const actionLevel = FiberRefs.getOrDefault(context, CurrentLogLevel);
|
|
98
|
+
if (shouldEmitUserFacing(logLevel, actionLevel)) emitToGitHub(logLevel, text);
|
|
99
|
+
});
|
|
100
|
+
const ActionLoggerLayer = Logger.replace(Logger.defaultLogger, makeActionLogger());
|
|
101
|
+
const createBuffer = ()=>({
|
|
102
|
+
entries: []
|
|
103
|
+
});
|
|
104
|
+
const flushBuffer = (label, buffer)=>{
|
|
105
|
+
if (buffer.entries.length > 0) {
|
|
106
|
+
info(`--- Buffered output for "${label}" ---`);
|
|
107
|
+
for (const entry of buffer.entries)info(entry);
|
|
108
|
+
info(`--- End buffered output for "${label}" ---`);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const ActionLoggerLive = Layer.succeed(ActionLogger, {
|
|
112
|
+
group: (name, effect)=>Effect.acquireUseRelease(Effect.sync(()=>startGroup(name)), ()=>effect, ()=>Effect.sync(()=>endGroup())),
|
|
113
|
+
withBuffer: (label, effect)=>FiberRef.get(CurrentLogLevel).pipe(Effect.flatMap((level)=>{
|
|
114
|
+
if ("info" !== level) return effect;
|
|
115
|
+
const buffer = createBuffer();
|
|
116
|
+
const bufferingLogger = Logger.make(({ logLevel, message })=>{
|
|
117
|
+
const text = formatMessage(message);
|
|
118
|
+
debug(text);
|
|
119
|
+
if (LogLevel.greaterThanEqual(logLevel, LogLevel.Warning)) emitToGitHub(logLevel, text);
|
|
120
|
+
else buffer.entries.push(text);
|
|
121
|
+
});
|
|
122
|
+
return effect.pipe(Logger.withMinimumLogLevel(LogLevel.All), Effect.provide(Logger.replace(Logger.defaultLogger, bufferingLogger)), Effect.tapErrorCause(()=>Effect.sync(()=>flushBuffer(label, buffer))));
|
|
123
|
+
})),
|
|
124
|
+
annotationError: (message, properties)=>Effect.sync(()=>{
|
|
125
|
+
void 0 !== properties ? core_error(message, properties) : core_error(message);
|
|
126
|
+
}),
|
|
127
|
+
annotationWarning: (message, properties)=>Effect.sync(()=>{
|
|
128
|
+
void 0 !== properties ? warning(message, properties) : warning(message);
|
|
129
|
+
}),
|
|
130
|
+
annotationNotice: (message, properties)=>Effect.sync(()=>{
|
|
131
|
+
void 0 !== properties ? notice(message, properties) : notice(message);
|
|
132
|
+
})
|
|
133
|
+
});
|
|
134
|
+
const makeAnnotation = (state, type)=>(message, properties)=>Effect.sync(()=>{
|
|
135
|
+
state.annotations.push({
|
|
136
|
+
type,
|
|
137
|
+
message,
|
|
138
|
+
...void 0 !== properties ? {
|
|
139
|
+
properties
|
|
140
|
+
} : {}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
const ActionLoggerTest = {
|
|
144
|
+
empty: ()=>({
|
|
145
|
+
entries: [],
|
|
146
|
+
groups: [],
|
|
147
|
+
annotations: [],
|
|
148
|
+
flushedBuffers: []
|
|
149
|
+
}),
|
|
150
|
+
layer: (state)=>Layer.succeed(ActionLogger, {
|
|
151
|
+
group: (name, effect)=>{
|
|
152
|
+
const groupEntries = [];
|
|
153
|
+
state.groups.push({
|
|
154
|
+
name,
|
|
155
|
+
entries: groupEntries
|
|
156
|
+
});
|
|
157
|
+
return effect;
|
|
158
|
+
},
|
|
159
|
+
withBuffer: (label, effect)=>FiberRef.get(CurrentLogLevel).pipe(Effect.flatMap((level)=>{
|
|
160
|
+
if ("info" !== level) return effect;
|
|
161
|
+
return effect.pipe(Effect.tapErrorCause(()=>Effect.sync(()=>{
|
|
162
|
+
state.flushedBuffers.push({
|
|
163
|
+
label,
|
|
164
|
+
entries: []
|
|
165
|
+
});
|
|
166
|
+
})));
|
|
167
|
+
})),
|
|
168
|
+
annotationError: makeAnnotation(state, "error"),
|
|
169
|
+
annotationWarning: makeAnnotation(state, "warning"),
|
|
170
|
+
annotationNotice: makeAnnotation(state, "notice")
|
|
171
|
+
})
|
|
172
|
+
};
|
|
173
|
+
const ActionOutputs = Context.GenericTag("ActionOutputs");
|
|
174
|
+
const ActionOutputsLive = Layer.succeed(ActionOutputs, {
|
|
175
|
+
set: (name, value)=>Effect.sync(()=>setOutput(name, value)),
|
|
176
|
+
setJson: (name, value, schema)=>Schema.encode(schema)(value).pipe(Effect.tap((encoded)=>Effect.sync(()=>setOutput(name, JSON.stringify(encoded)))), Effect.asVoid, Effect.mapError((parseError)=>new ActionOutputError({
|
|
177
|
+
outputName: name,
|
|
178
|
+
reason: `Output "${name}" validation failed: ${parseError.message}`
|
|
179
|
+
}))),
|
|
180
|
+
summary: (content)=>Effect.tryPromise({
|
|
181
|
+
try: ()=>core_summary.addRaw(content).write(),
|
|
182
|
+
catch: (error)=>new ActionOutputError({
|
|
183
|
+
outputName: "summary",
|
|
184
|
+
reason: `Failed to write step summary: ${error instanceof Error ? error.message : String(error)}`
|
|
185
|
+
})
|
|
186
|
+
}).pipe(Effect.asVoid),
|
|
187
|
+
exportVariable: (name, value)=>Effect.sync(()=>exportVariable(name, value)),
|
|
188
|
+
addPath: (path)=>Effect.sync(()=>addPath(path))
|
|
189
|
+
});
|
|
190
|
+
const ActionOutputsTest = {
|
|
191
|
+
empty: ()=>({
|
|
192
|
+
outputs: [],
|
|
193
|
+
summaries: [],
|
|
194
|
+
variables: [],
|
|
195
|
+
paths: []
|
|
196
|
+
}),
|
|
197
|
+
layer: (state)=>Layer.succeed(ActionOutputs, {
|
|
198
|
+
set: (name, value)=>Effect.sync(()=>{
|
|
199
|
+
state.outputs.push({
|
|
200
|
+
name,
|
|
201
|
+
value
|
|
202
|
+
});
|
|
203
|
+
}),
|
|
204
|
+
setJson: (name, value, schema)=>Schema.encode(schema)(value).pipe(Effect.tap((encoded)=>Effect.sync(()=>{
|
|
205
|
+
state.outputs.push({
|
|
206
|
+
name,
|
|
207
|
+
value: JSON.stringify(encoded)
|
|
208
|
+
});
|
|
209
|
+
})), Effect.asVoid, Effect.mapError((parseError)=>new ActionOutputError({
|
|
210
|
+
outputName: name,
|
|
211
|
+
reason: `Output "${name}" validation failed: ${parseError.message}`
|
|
212
|
+
}))),
|
|
213
|
+
summary: (content)=>Effect.sync(()=>{
|
|
214
|
+
state.summaries.push(content);
|
|
215
|
+
}),
|
|
216
|
+
exportVariable: (name, value)=>Effect.sync(()=>{
|
|
217
|
+
state.variables.push({
|
|
218
|
+
name,
|
|
219
|
+
value
|
|
220
|
+
});
|
|
221
|
+
}),
|
|
222
|
+
addPath: (path)=>Effect.sync(()=>{
|
|
223
|
+
state.paths.push(path);
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
};
|
|
227
|
+
const Status = Schema.Literal("pass", "fail", "skip", "warn").annotations({
|
|
228
|
+
identifier: "Status",
|
|
229
|
+
title: "Check Status",
|
|
230
|
+
description: "Status indicator for check run outcomes"
|
|
231
|
+
});
|
|
232
|
+
const ChecklistItem = Schema.Struct({
|
|
233
|
+
label: Schema.String,
|
|
234
|
+
checked: Schema.Boolean
|
|
235
|
+
}).annotations({
|
|
236
|
+
identifier: "ChecklistItem",
|
|
237
|
+
title: "Checklist Item"
|
|
238
|
+
});
|
|
239
|
+
const CapturedOutput = Schema.Struct({
|
|
240
|
+
name: Schema.String,
|
|
241
|
+
value: Schema.String
|
|
242
|
+
}).annotations({
|
|
243
|
+
identifier: "CapturedOutput",
|
|
244
|
+
title: "Captured Output"
|
|
245
|
+
});
|
|
246
|
+
const ActionLogLevel = Schema.Literal("info", "verbose", "debug").annotations({
|
|
247
|
+
identifier: "ActionLogLevel",
|
|
248
|
+
title: "Action Log Level",
|
|
249
|
+
description: "Logging verbosity for GitHub Action output"
|
|
250
|
+
});
|
|
251
|
+
const LogLevelInput = Schema.Literal("info", "verbose", "debug", "auto").annotations({
|
|
252
|
+
identifier: "LogLevelInput",
|
|
253
|
+
title: "Log Level Input",
|
|
254
|
+
description: "Logging verbosity: info, verbose, debug, or auto",
|
|
255
|
+
message: ()=>({
|
|
256
|
+
message: 'log-level must be one of: "info", "verbose", "debug", "auto"',
|
|
257
|
+
override: true
|
|
258
|
+
})
|
|
259
|
+
});
|
|
260
|
+
const resolveLogLevel = (input)=>{
|
|
261
|
+
if ("auto" !== input) return input;
|
|
262
|
+
return "1" === process.env.RUNNER_DEBUG ? "debug" : "info";
|
|
263
|
+
};
|
|
264
|
+
const table = (headers, rows)=>{
|
|
265
|
+
const headerRow = `| ${headers.join(" | ")} |`;
|
|
266
|
+
const separator = `| ${headers.map(()=>"---").join(" | ")} |`;
|
|
267
|
+
const dataRows = rows.map((row)=>`| ${row.join(" | ")} |`);
|
|
268
|
+
return [
|
|
269
|
+
headerRow,
|
|
270
|
+
separator,
|
|
271
|
+
...dataRows
|
|
272
|
+
].join("\n");
|
|
273
|
+
};
|
|
274
|
+
const heading = (text, level = 2)=>`${"#".repeat(level)} ${text}`;
|
|
275
|
+
const details = (summary, content)=>`<details>\n<summary>${summary}</summary>\n\n${content}\n\n</details>`;
|
|
276
|
+
const rule = ()=>"---";
|
|
277
|
+
const statusIcon = (status)=>{
|
|
278
|
+
switch(status){
|
|
279
|
+
case "pass":
|
|
280
|
+
return "\u2705";
|
|
281
|
+
case "fail":
|
|
282
|
+
return "\u274C";
|
|
283
|
+
case "skip":
|
|
284
|
+
return "\uD83D\uDDC3\uFE0F";
|
|
285
|
+
case "warn":
|
|
286
|
+
return "\u26A0\uFE0F";
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
const GithubMarkdown_link = (text, url)=>`[${text}](${url})`;
|
|
290
|
+
const list = (items)=>items.map((item)=>`- ${item}`).join("\n");
|
|
291
|
+
const checklist = (items)=>items.map((item)=>`- [${item.checked ? "x" : " "}] ${item.label}`).join("\n");
|
|
292
|
+
const bold = (text)=>`**${text}**`;
|
|
293
|
+
const code = (text)=>`\`${text}\``;
|
|
294
|
+
const codeBlock = (content, language = "")=>`\`\`\`${language}\n${content}\n\`\`\``;
|
|
295
|
+
export { ActionInputError, ActionInputErrorBase, ActionInputs, ActionInputsLive, ActionInputsTest, ActionLogLevel, ActionLogger, ActionLoggerLayer, ActionLoggerLive, ActionLoggerTest, ActionOutputError, ActionOutputErrorBase, ActionOutputs, ActionOutputsLive, ActionOutputsTest, CapturedOutput, ChecklistItem, CurrentLogLevel, GithubMarkdown_link as link, LogLevelInput, Status, bold, checklist, code, codeBlock, details, heading, list, makeActionLogger, resolveLogLevel, rule, setLogLevel, statusIcon, table };
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@savvy-web/github-action-effects",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Effect-based utility library for building robust, well-logged, and schema-validated GitHub Actions.",
|
|
6
|
+
"homepage": "https://github.com/savvy-web/github-action-effects#readme",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/savvy-web/github-action-effects/issues"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/savvy-web/github-action-effects.git"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "C. Spencer Beggs",
|
|
17
|
+
"email": "spencer@savvyweb.systems",
|
|
18
|
+
"url": "https://savvyweb.systems"
|
|
19
|
+
},
|
|
20
|
+
"type": "module",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./index.d.ts",
|
|
24
|
+
"import": "./index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@actions/core": "^3.0.0",
|
|
29
|
+
"@actions/exec": "^3.0.0",
|
|
30
|
+
"@actions/github": "^9.0.0",
|
|
31
|
+
"@effect/platform": ">=0.94.0",
|
|
32
|
+
"@effect/platform-node": ">=0.104.0",
|
|
33
|
+
"effect": "^3.19.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependenciesMeta": {
|
|
36
|
+
"@actions/core": {
|
|
37
|
+
"optional": false
|
|
38
|
+
},
|
|
39
|
+
"@actions/exec": {
|
|
40
|
+
"optional": true
|
|
41
|
+
},
|
|
42
|
+
"@actions/github": {
|
|
43
|
+
"optional": true
|
|
44
|
+
},
|
|
45
|
+
"@effect/platform": {
|
|
46
|
+
"optional": true
|
|
47
|
+
},
|
|
48
|
+
"@effect/platform-node": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"effect": {
|
|
52
|
+
"optional": false
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"!github-action-effects.api.json",
|
|
57
|
+
"!tsconfig.json",
|
|
58
|
+
"!tsdoc.json",
|
|
59
|
+
"LICENSE",
|
|
60
|
+
"README.md",
|
|
61
|
+
"index.d.ts",
|
|
62
|
+
"index.js",
|
|
63
|
+
"package.json",
|
|
64
|
+
"tsdoc-metadata.json"
|
|
65
|
+
]
|
|
66
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
|
2
|
+
// It should be published with your NPM package. It should not be tracked by Git.
|
|
3
|
+
{
|
|
4
|
+
"tsdocVersion": "0.12",
|
|
5
|
+
"toolPackages": [
|
|
6
|
+
{
|
|
7
|
+
"packageName": "@microsoft/api-extractor",
|
|
8
|
+
"packageVersion": "7.57.6"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|