@effected/oidc 0.0.0-stage → 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.
@@ -0,0 +1,36 @@
1
+ import { Schema } from "effect";
2
+ import { RegisteredClaims } from "@effected/jwt";
3
+
4
+ // src/IdTokenClaims.ts
5
+ /**
6
+ * The claims of an OpenID Connect ID token: RFC 7519's registered claims
7
+ * plus the ID-token claims OpenID Connect Core 1.0 §2 adds.
8
+ *
9
+ * @remarks
10
+ * Every claim is optional, so the schema decodes any provider's token, and
11
+ * the schema is open: claims it does not name survive the decode. A
12
+ * provider's own claims belong in a caller-supplied schema passed to
13
+ * {@link (Oidc:class).verify} or {@link (Oidc:class).decodeUnverified},
14
+ * not in a subclass here. `@effected/github`'s `ActionsOidcClaims` is one.
15
+ *
16
+ * Optional here does not mean optional in a verified token:
17
+ * {@link (Oidc:class).verify} still requires `exp` and checks `iss`, `aud`,
18
+ * `nbf` and `iat` whatever schema the payload is then decoded with.
19
+ *
20
+ * @public
21
+ */
22
+ const IdTokenClaims = Schema.StructWithRest(Schema.Struct({
23
+ ...RegisteredClaims.schema.fields,
24
+ /** Authorized party: the client the token was issued to, when it differs from the audience. */
25
+ azp: Schema.optionalKey(Schema.String),
26
+ /** The value the client sent in its authentication request, echoed back to bind the token to it. */
27
+ nonce: Schema.optionalKey(Schema.String),
28
+ /** When the end user authenticated, in seconds since the epoch. */
29
+ auth_time: Schema.optionalKey(Schema.Finite),
30
+ /** Authentication context class reference. */
31
+ acr: Schema.optionalKey(Schema.String),
32
+ /** Authentication method references, e.g. `pwd` or `mfa`. */
33
+ amr: Schema.optionalKey(Schema.Array(Schema.String))
34
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
35
+
36
+ export { IdTokenClaims };
@@ -0,0 +1,74 @@
1
+ import { Context, Effect, Layer, Redacted, Schema } from "effect";
2
+
3
+ // src/IdentityToken.ts
4
+ /**
5
+ * Raised when an identity token cannot be obtained.
6
+ *
7
+ * @remarks
8
+ * The audience is on the error because "which audience" is the first thing a
9
+ * caller checks when an exchange is refused — a token minted for the wrong one
10
+ * fails at the certificate authority, far from here.
11
+ *
12
+ * @public
13
+ */
14
+ var IdentityTokenError = class extends Schema.TaggedError()("IdentityTokenError", {
15
+ /** The audience the token was requested for. */
16
+ audience: Schema.String,
17
+ /** The underlying failure, preserved structurally. */
18
+ cause: Schema.Defect()
19
+ }) {
20
+ get message() {
21
+ return `Could not obtain an identity token for the "${this.audience}" audience`;
22
+ }
23
+ };
24
+ /** The token every double answers with unless a test says otherwise. */
25
+ const TEST_TOKEN = "test-identity-token";
26
+ /**
27
+ * A source of workload identity tokens (OIDC): the input `@effected/sbom`'s
28
+ * `SigstoreSigner` needs to obtain a signing certificate, and any other
29
+ * consumer needs to present a workload identity.
30
+ *
31
+ * @remarks
32
+ * In GitHub Actions, provide `ActionsIdentityToken.layer` from
33
+ * `@effected/github-actions`. A consumer that already holds a token uses
34
+ * {@link (IdentityToken:class).layerStatic}; tests use
35
+ * {@link (IdentityToken:class).layerTest}.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * import { IdentityToken } from "@effected/oidc";
40
+ * import { SigstoreSigner } from "@effected/sbom";
41
+ * import { Layer } from "effect";
42
+ *
43
+ * const token = process.env.OIDC_TOKEN ?? "";
44
+ * const layer = SigstoreSigner.layer.pipe(Layer.provide(IdentityToken.layerStatic(token)));
45
+ * ```
46
+ *
47
+ * @public
48
+ */
49
+ var IdentityToken = class IdentityToken extends Context.Service()("@effected/oidc/IdentityToken") {
50
+ /**
51
+ * A layer answering with a token the caller already holds.
52
+ *
53
+ * @remarks
54
+ * For a consumer that obtained a token by some other route — a CI system
55
+ * that is not GitHub Actions, or a script that exchanged one itself. The
56
+ * audience is **ignored**, so it is the caller's job to have minted the token
57
+ * for the audience it will be used with; a layer cannot check that, and
58
+ * pretending otherwise would be theatre.
59
+ */
60
+ static layerStatic = (token) => Layer.succeed(IdentityToken, { token: () => Effect.succeed(typeof token === "string" ? Redacted.make(token) : token) });
61
+ /**
62
+ * An in-memory double.
63
+ *
64
+ * @remarks
65
+ * Unlike `@effected/sbom`'s `SigstoreSigner.makeTest`, this one **answers** rather than
66
+ * dying: a fabricated OIDC token is a real answer to "give me a token" in a
67
+ * test, where a fabricated signature would be a lie about cryptography.
68
+ */
69
+ static makeTest = (overrides = {}) => ({ token: overrides.token ?? (() => Effect.succeed(Redacted.make(TEST_TOKEN))) });
70
+ /** {@link (IdentityToken:class).makeTest} behind a `Layer`. */
71
+ static layerTest = (overrides = {}) => Layer.succeed(IdentityToken, IdentityToken.makeTest(overrides));
72
+ };
73
+
74
+ export { IdentityToken, IdentityTokenError };
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 C. Spencer Beggs
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/Oidc.js ADDED
@@ -0,0 +1,94 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { JwksResolver, Jws, Jwt, JwtError } from "@effected/jwt";
3
+
4
+ // src/Oidc.ts
5
+ const audiences = (audience) => typeof audience === "string" ? [audience] : audience;
6
+ const decodeUnverified = Effect.fn("Oidc.decodeUnverified")(function* (token, claims) {
7
+ const { payload } = yield* Effect.fromResult(Jws.decodeUnverified(token));
8
+ return yield* Schema.decodeUnknownEffect(claims)(payload).pipe(Effect.mapError((cause) => new JwtError({
9
+ reason: "claims",
10
+ detail: "the payload does not match the expected claims",
11
+ cause
12
+ })));
13
+ });
14
+ const verify = Effect.fn("Oidc.verify")(function* (token, options) {
15
+ const expected = audiences(options.audience);
16
+ yield* Effect.annotateCurrentSpan({
17
+ issuer: options.issuer,
18
+ audience: expected.join(" ")
19
+ });
20
+ if (expected.length === 0 || expected.some((value) => value.length === 0)) return yield* new JwtError({
21
+ reason: "wrongAudience",
22
+ detail: "no audience was given; an OIDC token is never verified without one"
23
+ });
24
+ return yield* Jwt.verify(token, {
25
+ key: JwksResolver.forIssuer(options.issuer),
26
+ claims: options.claims,
27
+ issuer: options.issuer,
28
+ audience: expected,
29
+ ...options.clockTolerance !== void 0 ? { clockTolerance: options.clockTolerance } : {}
30
+ });
31
+ });
32
+ /**
33
+ * Read and verify OpenID Connect ID tokens.
34
+ *
35
+ * @remarks
36
+ * Both operations fail with `@effected/jwt`'s `JwtError` and add no error of
37
+ * their own; route on its `reason`, never on its message.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * import { JwksResolver } from "@effected/jwt";
42
+ * import { IdTokenClaims, Oidc } from "@effected/oidc";
43
+ * import { Effect } from "effect";
44
+ *
45
+ * const program = Oidc.verify("eyJ...", {
46
+ * issuer: "https://accounts.example.com",
47
+ * audience: "my-client-id",
48
+ * claims: IdTokenClaims,
49
+ * });
50
+ *
51
+ * // JwksResolver.layer needs an HttpClient and a JwksStore, provided once at the edge.
52
+ * export const main = program.pipe(Effect.provide(JwksResolver.layer));
53
+ * ```
54
+ *
55
+ * @public
56
+ */
57
+ var Oidc = class {
58
+ constructor() {}
59
+ /**
60
+ * Decode a token's payload with `claims` **without verifying it**.
61
+ *
62
+ * @remarks
63
+ * `Jws.decodeUnverified` plus a schema decode. No signature, issuer,
64
+ * audience or time check runs, as the name says. For reading a token this
65
+ * process was handed by a runtime it already trusts, never for
66
+ * authorizing anything: the result is whatever the token's author wrote.
67
+ *
68
+ * Fails as `malformed` when the token is not a compact JWS with a JOSE
69
+ * header, and as `claims` when the payload does not decode.
70
+ *
71
+ * @public
72
+ */
73
+ static decodeUnverified = decodeUnverified;
74
+ /**
75
+ * Verify an ID token from `options.issuer` and decode its payload with
76
+ * `options.claims`.
77
+ *
78
+ * @remarks
79
+ * `Jwt.verify` keyed through `JwksResolver.forIssuer(options.issuer)`:
80
+ * the signature against the issuer's discovered JWKS, then `exp`, `nbf`,
81
+ * `iat`, `iss` and `aud`, then the schema decode. An empty audience, or an
82
+ * empty string among several, fails as `wrongAudience` before anything
83
+ * else, with no network call.
84
+ *
85
+ * The key is always looked up for the configured issuer, never for the
86
+ * token's own `iss`, so a token naming another issuer is never checked
87
+ * against that issuer's keys.
88
+ *
89
+ * @public
90
+ */
91
+ static verify = verify;
92
+ };
93
+
94
+ export { Oidc };
package/README.md CHANGED
@@ -1,3 +1,3 @@
1
- # Temporary Holding Version
1
+ # @effected/oidc
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ OpenID Connect for Effect v4: the IdentityToken issuer contract, ID-token claims, and a discovery-backed verify over @effected/jwt.
package/index.d.ts ADDED
@@ -0,0 +1,214 @@
1
+ import { Context, Duration, Effect, Layer, Redacted, Schema } from "effect";
2
+ import { JwksResolver, JwtError } from "@effected/jwt";
3
+ declare const IdentityTokenError_base: Schema.Class<IdentityTokenError, Schema.TaggedStruct<"IdentityTokenError", {
4
+ /** The audience the token was requested for. */
5
+ readonly audience: Schema.String;
6
+ /** The underlying failure, preserved structurally. */
7
+ readonly cause: Schema.Defect;
8
+ }>, import("effect/Cause").YieldableError>;
9
+ /**
10
+ * Raised when an identity token cannot be obtained.
11
+ *
12
+ * @remarks
13
+ * The audience is on the error because "which audience" is the first thing a
14
+ * caller checks when an exchange is refused — a token minted for the wrong one
15
+ * fails at the certificate authority, far from here.
16
+ *
17
+ * @public
18
+ */
19
+ export declare class IdentityTokenError extends IdentityTokenError_base {
20
+ get message(): string;
21
+ }
22
+ /**
23
+ * The contract: one method, one audience, one redacted token.
24
+ *
25
+ * @remarks
26
+ * Deliberately smaller than any issuer's own surface. An implementation may
27
+ * cache, may decode claims, may do neither — none of that is the contract's
28
+ * business, and a wider contract would make github-actions' issuer the only
29
+ * thing that could satisfy it.
30
+ *
31
+ * @public
32
+ */
33
+ interface IdentityTokenShape {
34
+ /** A workload identity token for `audience`. */
35
+ readonly token: (audience: string) => Effect.Effect<Redacted.Redacted<string>, IdentityTokenError>;
36
+ }
37
+ declare const IdentityToken_base: Context.ServiceClass<IdentityToken, "@effected/oidc/IdentityToken", IdentityTokenShape>;
38
+ /**
39
+ * A source of workload identity tokens (OIDC): the input `@effected/sbom`'s
40
+ * `SigstoreSigner` needs to obtain a signing certificate, and any other
41
+ * consumer needs to present a workload identity.
42
+ *
43
+ * @remarks
44
+ * In GitHub Actions, provide `ActionsIdentityToken.layer` from
45
+ * `@effected/github-actions`. A consumer that already holds a token uses
46
+ * {@link (IdentityToken:class).layerStatic}; tests use
47
+ * {@link (IdentityToken:class).layerTest}.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * import { IdentityToken } from "@effected/oidc";
52
+ * import { SigstoreSigner } from "@effected/sbom";
53
+ * import { Layer } from "effect";
54
+ *
55
+ * const token = process.env.OIDC_TOKEN ?? "";
56
+ * const layer = SigstoreSigner.layer.pipe(Layer.provide(IdentityToken.layerStatic(token)));
57
+ * ```
58
+ *
59
+ * @public
60
+ */
61
+ export declare class IdentityToken extends IdentityToken_base {
62
+ /**
63
+ * A layer answering with a token the caller already holds.
64
+ *
65
+ * @remarks
66
+ * For a consumer that obtained a token by some other route — a CI system
67
+ * that is not GitHub Actions, or a script that exchanged one itself. The
68
+ * audience is **ignored**, so it is the caller's job to have minted the token
69
+ * for the audience it will be used with; a layer cannot check that, and
70
+ * pretending otherwise would be theatre.
71
+ */
72
+ static readonly layerStatic: (token: Redacted.Redacted<string> | string) => Layer.Layer<IdentityToken>;
73
+ /**
74
+ * An in-memory double.
75
+ *
76
+ * @remarks
77
+ * Unlike `@effected/sbom`'s `SigstoreSigner.makeTest`, this one **answers** rather than
78
+ * dying: a fabricated OIDC token is a real answer to "give me a token" in a
79
+ * test, where a fabricated signature would be a lie about cryptography.
80
+ */
81
+ static readonly makeTest: (overrides?: Partial<IdentityTokenShape>) => IdentityTokenShape;
82
+ /** {@link (IdentityToken:class).makeTest} behind a `Layer`. */
83
+ static readonly layerTest: (overrides?: Partial<IdentityTokenShape>) => Layer.Layer<IdentityToken>;
84
+ }
85
+ /**
86
+ * The claims of an OpenID Connect ID token: RFC 7519's registered claims
87
+ * plus the ID-token claims OpenID Connect Core 1.0 §2 adds.
88
+ *
89
+ * @remarks
90
+ * Every claim is optional, so the schema decodes any provider's token, and
91
+ * the schema is open: claims it does not name survive the decode. A
92
+ * provider's own claims belong in a caller-supplied schema passed to
93
+ * {@link (Oidc:class).verify} or {@link (Oidc:class).decodeUnverified},
94
+ * not in a subclass here. `@effected/github`'s `ActionsOidcClaims` is one.
95
+ *
96
+ * Optional here does not mean optional in a verified token:
97
+ * {@link (Oidc:class).verify} still requires `exp` and checks `iss`, `aud`,
98
+ * `nbf` and `iat` whatever schema the payload is then decoded with.
99
+ *
100
+ * @public
101
+ */
102
+ export declare const IdTokenClaims: Schema.StructWithRest<Schema.Struct<{
103
+ readonly iss: Schema.optionalKey<Schema.String>;
104
+ readonly sub: Schema.optionalKey<Schema.String>;
105
+ readonly aud: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
106
+ readonly exp: Schema.optionalKey<Schema.Finite>;
107
+ readonly nbf: Schema.optionalKey<Schema.Finite>;
108
+ readonly iat: Schema.optionalKey<Schema.Finite>;
109
+ readonly jti: Schema.optionalKey<Schema.String>;
110
+ /** Authorized party: the client the token was issued to, when it differs from the audience. */
111
+ readonly azp: Schema.optionalKey<Schema.String>;
112
+ /** The value the client sent in its authentication request, echoed back to bind the token to it. */
113
+ readonly nonce: Schema.optionalKey<Schema.String>;
114
+ /** When the end user authenticated, in seconds since the epoch. */
115
+ readonly auth_time: Schema.optionalKey<Schema.Finite>;
116
+ /** Authentication context class reference. */
117
+ readonly acr: Schema.optionalKey<Schema.String>;
118
+ /** Authentication method references, e.g. `pwd` or `mfa`. */
119
+ readonly amr: Schema.optionalKey<Schema.$Array<Schema.String>>;
120
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>;
121
+ /**
122
+ * A decoded {@link (IdTokenClaims:variable)}.
123
+ *
124
+ * @public
125
+ */
126
+ export type IdTokenClaims = typeof IdTokenClaims.Type;
127
+ /**
128
+ * Options for {@link (Oidc:class).verify}.
129
+ *
130
+ * @typeParam S - The schema the verified payload is decoded with.
131
+ *
132
+ * @public
133
+ */
134
+ interface OidcVerifyOptions<S extends Schema.Constraint> {
135
+ /**
136
+ * The issuer the token must come from. Its keys are discovered from
137
+ * `<issuer>/.well-known/openid-configuration` and `iss` must equal it.
138
+ */
139
+ readonly issuer: string;
140
+ /**
141
+ * The audience the token must have been minted for, or any of several.
142
+ * Required and non-empty: an OIDC issuer's one key set signs tokens for
143
+ * every relying party, so without an audience check a token minted for
144
+ * any of them would verify.
145
+ */
146
+ readonly audience: string | ReadonlyArray<string>;
147
+ /** The schema the payload is decoded with once every check has passed; `IdTokenClaims` for the standard set. */
148
+ readonly claims: S;
149
+ /** Allowed clock skew for `exp`, `nbf` and `iat`; 60 seconds by default. */
150
+ readonly clockTolerance?: Duration.Input | undefined;
151
+ }
152
+ /**
153
+ * Read and verify OpenID Connect ID tokens.
154
+ *
155
+ * @remarks
156
+ * Both operations fail with `@effected/jwt`'s `JwtError` and add no error of
157
+ * their own; route on its `reason`, never on its message.
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * import { JwksResolver } from "@effected/jwt";
162
+ * import { IdTokenClaims, Oidc } from "@effected/oidc";
163
+ * import { Effect } from "effect";
164
+ *
165
+ * const program = Oidc.verify("eyJ...", {
166
+ * issuer: "https://accounts.example.com",
167
+ * audience: "my-client-id",
168
+ * claims: IdTokenClaims,
169
+ * });
170
+ *
171
+ * // JwksResolver.layer needs an HttpClient and a JwksStore, provided once at the edge.
172
+ * export const main = program.pipe(Effect.provide(JwksResolver.layer));
173
+ * ```
174
+ *
175
+ * @public
176
+ */
177
+ export declare class Oidc {
178
+ private constructor();
179
+ /**
180
+ * Decode a token's payload with `claims` **without verifying it**.
181
+ *
182
+ * @remarks
183
+ * `Jws.decodeUnverified` plus a schema decode. No signature, issuer,
184
+ * audience or time check runs, as the name says. For reading a token this
185
+ * process was handed by a runtime it already trusts, never for
186
+ * authorizing anything: the result is whatever the token's author wrote.
187
+ *
188
+ * Fails as `malformed` when the token is not a compact JWS with a JOSE
189
+ * header, and as `claims` when the payload does not decode.
190
+ *
191
+ * @public
192
+ */
193
+ static readonly decodeUnverified: <S extends Schema.Constraint>(token: string, claims: S) => Effect.Effect<S["Type"], JwtError, S["DecodingServices"]>;
194
+ /**
195
+ * Verify an ID token from `options.issuer` and decode its payload with
196
+ * `options.claims`.
197
+ *
198
+ * @remarks
199
+ * `Jwt.verify` keyed through `JwksResolver.forIssuer(options.issuer)`:
200
+ * the signature against the issuer's discovered JWKS, then `exp`, `nbf`,
201
+ * `iat`, `iss` and `aud`, then the schema decode. An empty audience, or an
202
+ * empty string among several, fails as `wrongAudience` before anything
203
+ * else, with no network call.
204
+ *
205
+ * The key is always looked up for the configured issuer, never for the
206
+ * token's own `iss`, so a token naming another issuer is never checked
207
+ * against that issuer's keys.
208
+ *
209
+ * @public
210
+ */
211
+ static readonly verify: <S extends Schema.Constraint>(token: string, options: OidcVerifyOptions<S>) => Effect.Effect<S["Type"], JwtError, JwksResolver | S["DecodingServices"]>;
212
+ }
213
+ export type { IdentityTokenShape, OidcVerifyOptions };
214
+ //# sourceMappingURL=index.d.ts.map
package/index.js ADDED
@@ -0,0 +1,5 @@
1
+ import { IdentityToken, IdentityTokenError } from "./IdentityToken.js";
2
+ import { IdTokenClaims } from "./IdTokenClaims.js";
3
+ import { Oidc } from "./Oidc.js";
4
+
5
+ export { IdTokenClaims, IdentityToken, IdentityTokenError, Oidc };
package/package.json CHANGED
@@ -1,6 +1,49 @@
1
1
  {
2
- "name": "@effected/oidc",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@effected/oidc",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "OpenID Connect for Effect v4: the IdentityToken issuer contract, ID-token claims, and a discovery-backed verify over @effected/jwt.",
6
+ "keywords": [
7
+ "oidc",
8
+ "openid-connect",
9
+ "id-token",
10
+ "jwt",
11
+ "jwks",
12
+ "effect",
13
+ "effected"
14
+ ],
15
+ "homepage": "https://github.com/spencerbeggs/effected/tree/main/packages/oidc#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/spencerbeggs/effected/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/spencerbeggs/effected.git",
22
+ "directory": "packages/oidc"
23
+ },
24
+ "license": "MIT",
25
+ "author": {
26
+ "name": "C. Spencer Beggs",
27
+ "email": "spencer@beggs.codes",
28
+ "url": "https://spencerbeg.gs"
29
+ },
30
+ "sideEffects": false,
31
+ "type": "module",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./index.d.ts",
35
+ "import": "./index.js",
36
+ "default": "./index.js"
37
+ },
38
+ "./package.json": "./package.json"
39
+ },
40
+ "dependencies": {
41
+ "@effected/jwt": "^0.5.0"
42
+ },
43
+ "peerDependencies": {
44
+ "effect": "^4.0.0"
45
+ },
46
+ "engines": {
47
+ "node": ">=24.11.0"
48
+ }
49
+ }
@@ -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.59.1"
9
+ }
10
+ ]
11
+ }