@getunblocked/sdk 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 +211 -0
- package/dist/agents.d.ts +301 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +262 -0
- package/dist/agents.js.map +1 -0
- package/dist/client.d.ts +39 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +76 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +70 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +96 -0
- package/dist/errors.js.map +1 -0
- package/dist/http.d.ts +16 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +222 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/timing.d.ts +9 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +86 -0
- package/dist/timing.js.map +1 -0
- package/dist/types.d.ts +273 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +14 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +22 -0
- package/dist/version.js.map +1 -0
- package/docs/README.md +28 -0
- package/docs/agent-frameworks.md +84 -0
- package/docs/api-design.md +53 -0
- package/docs/authentication.md +71 -0
- package/docs/configuration.md +67 -0
- package/docs/context.md +131 -0
- package/docs/contributing.md +51 -0
- package/docs/errors-and-retries.md +135 -0
- package/docs/getting-started.md +62 -0
- package/docs/low-level-requests.md +72 -0
- package/docs/pagination.md +29 -0
- package/docs/release.md +73 -0
- package/docs/runtime-and-packaging.md +57 -0
- package/docs/typescript.md +102 -0
- package/examples/context-research-tool.ts +10 -0
- package/package.json +51 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
`@getunblocked/sdk` is a lightweight TypeScript wrapper for the Unblocked Public API. It uses the platform `fetch`, ships as ESM, and has no runtime dependencies.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @getunblocked/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Create a Client
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import Unblocked from "@getunblocked/sdk";
|
|
15
|
+
|
|
16
|
+
const unblocked = new Unblocked({
|
|
17
|
+
apiKey: process.env.UNBLOCKED_API_TOKEN,
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The SDK also exports named client aliases:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { Unblocked, UnblockedClient } from "@getunblocked/sdk";
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Research the Connected Context
|
|
28
|
+
|
|
29
|
+
`client.context.research` runs unified multi-source research and synthesizes an answer with references.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
const research = await unblocked.context.research({
|
|
33
|
+
query: "How does the user authentication system work?",
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
console.log(research.summary);
|
|
37
|
+
for (const source of research.sources) {
|
|
38
|
+
console.log(source.content);
|
|
39
|
+
console.log(source.url);
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`context.research` resolves to a `ContextResearchResponse` with `summary`, `sources`, and `effort`. Search, query, and get methods resolve to responses carrying a `sources` array.
|
|
44
|
+
|
|
45
|
+
## Search a Single Source
|
|
46
|
+
|
|
47
|
+
Use the nested `context.search.*` methods to search one source at a time.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const code = await unblocked.context.search.code({
|
|
51
|
+
query: "rate limiting",
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
console.log(code.sources.map((source) => source.content));
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Next Steps
|
|
58
|
+
|
|
59
|
+
- Read [Context](./context.md) for the full research, search, query, and get surface.
|
|
60
|
+
- Read [Authentication](./authentication.md) before using the SDK in automation.
|
|
61
|
+
- Read [Configuration](./configuration.md) for retries, timeouts, custom fetch, and custom base URLs.
|
|
62
|
+
- Read [Agent Frameworks](./agent-frameworks.md) to expose Unblocked as agent tools.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Low-Level Requests
|
|
2
|
+
|
|
3
|
+
Use `request` or `requestRaw` when an endpoint is not yet wrapped by a resource helper or when you need direct response access.
|
|
4
|
+
|
|
5
|
+
## JSON Request
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
const result = await unblocked.request("POST", "/tools/context/research", {
|
|
9
|
+
body: {
|
|
10
|
+
query: "How does auth work?",
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Request Body
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const result = await unblocked.request("POST", "/tools/context/search/code", {
|
|
19
|
+
body: {
|
|
20
|
+
query: "rate limiting",
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Raw Response
|
|
26
|
+
|
|
27
|
+
`requestRaw` returns both the parsed value and the original `Response`.
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
const { value, response, requestId } = await unblocked.requestRaw(
|
|
31
|
+
"POST",
|
|
32
|
+
"/tools/context/research",
|
|
33
|
+
{
|
|
34
|
+
body: { query: "How does auth work?" },
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
console.log(response.headers.get("x-request-id"));
|
|
39
|
+
console.log(requestId);
|
|
40
|
+
console.log(value);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Request Options
|
|
44
|
+
|
|
45
|
+
Low-level requests accept the same options as resource methods:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
await unblocked.request("POST", "/tools/context/research", {
|
|
49
|
+
body: { query: "How does auth work?" },
|
|
50
|
+
timeoutMs: 10_000,
|
|
51
|
+
maxRetries: 1,
|
|
52
|
+
headers: {
|
|
53
|
+
"X-Request-Id": requestId,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Type Parameters
|
|
59
|
+
|
|
60
|
+
Use a type parameter when you know the response shape.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import type { ContextResearchResponse } from "@getunblocked/sdk";
|
|
64
|
+
|
|
65
|
+
const result = await unblocked.request<ContextResearchResponse>(
|
|
66
|
+
"POST",
|
|
67
|
+
"/tools/context/research",
|
|
68
|
+
{
|
|
69
|
+
body: { query: "How does auth work?" },
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Pagination
|
|
2
|
+
|
|
3
|
+
Context methods do not paginate. They return their response directly: search, query, and get methods return `sources`, and `research` returns `summary`, `sources`, and `effort`.
|
|
4
|
+
|
|
5
|
+
For list-style endpoints you reach through low-level `request` or `requestRaw`, the SDK does not return a page object or parsed cursors. Use `requestRaw` when you need the raw `Response`, then parse the `Link` header yourself.
|
|
6
|
+
|
|
7
|
+
## Manual Cursor Pagination
|
|
8
|
+
|
|
9
|
+
The SDK does not parse cursors for you on the low-level path, so read the raw `Link` header from the `Response`, find its `rel="next"` URL, and extract the `after` cursor yourself. Keep the request path relative and pass the cursor through the `query` option — do not pass the full `Link` URL as the path.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
let after: string | undefined;
|
|
13
|
+
|
|
14
|
+
do {
|
|
15
|
+
const { value, response } = await unblocked.requestRaw("GET", "/some/list", {
|
|
16
|
+
query: { limit: 100, after },
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
for (const item of value.items) {
|
|
20
|
+
console.log(item);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const link = response.headers.get("link");
|
|
24
|
+
const match = link?.match(/<([^>]+)>\s*;\s*rel="next"/);
|
|
25
|
+
after = match ? new URL(match[1]).searchParams.get("after") ?? undefined : undefined;
|
|
26
|
+
} while (after);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`requestRaw` exposes the raw `Response` including its `Link` header, but it does not expose parsed cursors — callers parse the header themselves to drive cursor pagination against arbitrary endpoints.
|
package/docs/release.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Release Guide
|
|
2
|
+
|
|
3
|
+
The SDK is currently distributed from this private GitHub repo (not npm). A
|
|
4
|
+
release is a git tag `vX.Y.Z`; consumers install it over SSH with
|
|
5
|
+
`bun add git+ssh://git@github.com/unblocked/unblocked-typescript-sdk.git#vX.Y.Z`.
|
|
6
|
+
|
|
7
|
+
The compiled `dist/` is committed to the repo, so installs need no build step
|
|
8
|
+
and no devDependencies. (bun does not run a dependency's `prepare` script or
|
|
9
|
+
install its devDependencies, so build-on-install is not an option.) This means
|
|
10
|
+
**every release must ship a fresh `dist/`** — the `version` script below
|
|
11
|
+
rebuilds and stages it automatically, and CI fails if a commit's `dist/` is
|
|
12
|
+
stale.
|
|
13
|
+
|
|
14
|
+
## Versioning
|
|
15
|
+
|
|
16
|
+
Use semantic versioning:
|
|
17
|
+
|
|
18
|
+
- Patch for bug fixes and documentation-only corrections.
|
|
19
|
+
- Minor for additive API features.
|
|
20
|
+
- Major for breaking API or runtime support changes.
|
|
21
|
+
|
|
22
|
+
`package.json` is the single source of truth for the version. `npm run build`
|
|
23
|
+
syncs it into `src/version.ts` (which feeds the `User-Agent` header), so the two
|
|
24
|
+
never drift.
|
|
25
|
+
|
|
26
|
+
## Preflight
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install
|
|
30
|
+
npm test # builds, then runs the test suite
|
|
31
|
+
npm run typecheck
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Cut the release
|
|
35
|
+
|
|
36
|
+
`npm version` bumps `package.json`, runs the `version` hook (which rebuilds
|
|
37
|
+
`dist/`, syncs `src/version.ts`, and stages both), then creates the commit and
|
|
38
|
+
tag:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm version minor # or: patch | major
|
|
42
|
+
git push --follow-tags
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Pushing the `vX.Y.Z` tag triggers the release workflow (`.github/workflows/release.yml`),
|
|
46
|
+
which builds, tests, and creates a GitHub Release.
|
|
47
|
+
|
|
48
|
+
## Release notes
|
|
49
|
+
|
|
50
|
+
Include:
|
|
51
|
+
|
|
52
|
+
- New API methods or types.
|
|
53
|
+
- Behavior changes in retries, timeouts, auth, or pagination.
|
|
54
|
+
- Deprecated or removed exports.
|
|
55
|
+
- Required user action.
|
|
56
|
+
|
|
57
|
+
## Post-release check
|
|
58
|
+
|
|
59
|
+
Install the tag into a clean project and verify it builds and imports:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
bun add git+ssh://git@github.com/unblocked/unblocked-typescript-sdk.git#vX.Y.Z
|
|
63
|
+
node -e "import('@getunblocked/sdk').then((m) => console.log(Boolean(m.default), m.VERSION))"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Publishing to npm (future)
|
|
67
|
+
|
|
68
|
+
When ready to publish to the registry, the package is already configured for it
|
|
69
|
+
(`files`, `exports`, `types`, and a `prepare` build). The flow becomes:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm publish --access public
|
|
73
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Runtime and Packaging
|
|
2
|
+
|
|
3
|
+
## Runtime Support
|
|
4
|
+
|
|
5
|
+
The SDK is intended for:
|
|
6
|
+
|
|
7
|
+
- Node.js 18 and newer
|
|
8
|
+
- Worker and edge runtimes with `fetch`
|
|
9
|
+
- TypeScript agent harnesses that execute ESM modules
|
|
10
|
+
|
|
11
|
+
The SDK requires:
|
|
12
|
+
|
|
13
|
+
- `fetch`
|
|
14
|
+
- `Headers`
|
|
15
|
+
- `Response`
|
|
16
|
+
- `AbortController` for request timeouts and cancellation
|
|
17
|
+
|
|
18
|
+
## ESM Package
|
|
19
|
+
|
|
20
|
+
The package is ESM only.
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import Unblocked from "@getunblocked/sdk";
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
CommonJS consumers should use dynamic import:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
const { default: Unblocked } = await import("@getunblocked/sdk");
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Package Contents
|
|
33
|
+
|
|
34
|
+
The package allowlist includes:
|
|
35
|
+
|
|
36
|
+
- `dist`
|
|
37
|
+
- `docs`
|
|
38
|
+
- `examples`
|
|
39
|
+
- `README.md`
|
|
40
|
+
- `LICENSE`
|
|
41
|
+
|
|
42
|
+
Source TypeScript is compiled into `dist` before packing.
|
|
43
|
+
|
|
44
|
+
## No Runtime Dependencies
|
|
45
|
+
|
|
46
|
+
The SDK intentionally has no runtime dependencies. TypeScript is a development dependency only.
|
|
47
|
+
|
|
48
|
+
## Custom Fetch
|
|
49
|
+
|
|
50
|
+
Pass a custom `fetch` when running in a test harness or runtime with a non-global fetch implementation.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const unblocked = new Unblocked({
|
|
54
|
+
apiKey,
|
|
55
|
+
fetch: customFetch,
|
|
56
|
+
});
|
|
57
|
+
```
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# TypeScript Guide
|
|
2
|
+
|
|
3
|
+
The SDK exports runtime clients and type-only helpers from the package root.
|
|
4
|
+
|
|
5
|
+
## Client Imports
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import Unblocked from "@getunblocked/sdk";
|
|
9
|
+
import { UnblockedClient, Unblocked as NamedUnblocked } from "@getunblocked/sdk";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Context Types
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import type {
|
|
16
|
+
ContextSearchEffort,
|
|
17
|
+
ContextSearchSource,
|
|
18
|
+
ContextSearchSourceType,
|
|
19
|
+
ContextSearchRequest,
|
|
20
|
+
ContextSearchResponse,
|
|
21
|
+
ContextResearchRequest,
|
|
22
|
+
ContextResearchResponse,
|
|
23
|
+
ContextQueryIssuesRequest,
|
|
24
|
+
ContextQueryPrsRequest,
|
|
25
|
+
ContextQueryResponse,
|
|
26
|
+
ContextGetUrlsRequest,
|
|
27
|
+
ContextGetRulesRequest,
|
|
28
|
+
ContextGetResponse,
|
|
29
|
+
} from "@getunblocked/sdk";
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Working With Results
|
|
33
|
+
|
|
34
|
+
`client.context.research` resolves to `ContextResearchResponse` (`summary`, `sources`, `effort`). Search, query, and get methods resolve to responses carrying a `sources` array of `ContextSearchSource`, each with a `content` string and optional `title`, `url`, `sourceType`, and `provider`.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const result: ContextResearchResponse = await unblocked.context.research({
|
|
38
|
+
query: "How does auth work?",
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
console.log(result.summary);
|
|
42
|
+
result.sources.map((source: ContextSearchSource) => source.content);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`ContextSearchEffort` is the shared `"low" | "medium" | "high"` union accepted by the research `effort` field.
|
|
46
|
+
|
|
47
|
+
## Request Types
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import type {
|
|
51
|
+
ApiKey,
|
|
52
|
+
TokenProvider,
|
|
53
|
+
UnblockedClientOptions,
|
|
54
|
+
UnblockedRequestOptions,
|
|
55
|
+
RequestOptions,
|
|
56
|
+
JsonRequestOptions,
|
|
57
|
+
RawResponse,
|
|
58
|
+
} from "@getunblocked/sdk";
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Public API Contract Types
|
|
62
|
+
|
|
63
|
+
`PublicApiSchemas` mirrors the component schemas from the public OpenAPI contract.
|
|
64
|
+
Use it when you need the raw schema-level type.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import type { PublicApiSchemas } from "@getunblocked/sdk";
|
|
68
|
+
|
|
69
|
+
type ContractTool = PublicApiSchemas["Tool"];
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
SDK method input types can be stricter than the shared schema when an operation
|
|
73
|
+
rejects missing fields. For example, `ContextResearchRequest` requires `query`,
|
|
74
|
+
which the research endpoint rejects when missing.
|
|
75
|
+
|
|
76
|
+
## Exact Optional Properties
|
|
77
|
+
|
|
78
|
+
The SDK is built with `exactOptionalPropertyTypes`. Prefer omitting optional fields instead of setting them to `undefined`.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const request: ContextResearchRequest = {
|
|
82
|
+
query: "How does auth work?",
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Avoid:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const request = {
|
|
90
|
+
query: "How does auth work?",
|
|
91
|
+
effort: undefined,
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Type-Only Imports
|
|
96
|
+
|
|
97
|
+
Use `import type` for SDK types to keep emitted JavaScript small.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import Unblocked from "@getunblocked/sdk";
|
|
101
|
+
import type { ContextResearchResponse } from "@getunblocked/sdk";
|
|
102
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createUnblockedTools, unblockedToolSchemas } from "@getunblocked/sdk";
|
|
2
|
+
|
|
3
|
+
const tools = createUnblockedTools({
|
|
4
|
+
apiKey: process.env.UNBLOCKED_API_TOKEN,
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
export const research = {
|
|
8
|
+
...unblockedToolSchemas.research,
|
|
9
|
+
execute: tools.research,
|
|
10
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@getunblocked/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lightweight TypeScript SDK for the Unblocked Public API.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Unblocked",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/unblocked/unblocked-typescript-sdk.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://docs.getunblocked.com/api-reference/quickstart",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/unblocked/unblocked-typescript-sdk/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"unblocked",
|
|
18
|
+
"sdk",
|
|
19
|
+
"typescript",
|
|
20
|
+
"agents",
|
|
21
|
+
"ai"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"docs",
|
|
27
|
+
"examples/quickstart.mjs",
|
|
28
|
+
"examples/context-research-tool.ts",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "node scripts/sync-version.mjs && tsc -p tsconfig.json",
|
|
41
|
+
"typecheck": "tsc -p tsconfig.typecheck.json",
|
|
42
|
+
"test": "npm run build && node --test tests/*.test.mjs",
|
|
43
|
+
"version": "npm run build && git add dist src/version.ts"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"typescript": "^5.8.3"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18"
|
|
50
|
+
}
|
|
51
|
+
}
|