Merge branch 'main' into request-auth-info
This commit is contained in:
commit
b5b322e859
15 changed files with 105 additions and 53 deletions
3
.github/workflows/main.yml
vendored
3
.github/workflows/main.yml
vendored
|
|
@ -46,7 +46,6 @@ jobs:
|
|||
|
||||
- run: npm ci
|
||||
|
||||
# TODO: Add --provenance once the repo is public
|
||||
- run: npm publish --access public
|
||||
- run: npm publish --provenance --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
|
|
|||
18
README.md
18
README.md
|
|
@ -455,13 +455,6 @@ const client = new Client(
|
|||
{
|
||||
name: "example-client",
|
||||
version: "1.0.0"
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
prompts: {},
|
||||
resources: {},
|
||||
tools: {}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -471,15 +464,20 @@ await client.connect(transport);
|
|||
const prompts = await client.listPrompts();
|
||||
|
||||
// Get a prompt
|
||||
const prompt = await client.getPrompt("example-prompt", {
|
||||
arg1: "value"
|
||||
const prompt = await client.getPrompt({
|
||||
name: "example-prompt",
|
||||
arguments: {
|
||||
arg1: "value"
|
||||
}
|
||||
});
|
||||
|
||||
// List resources
|
||||
const resources = await client.listResources();
|
||||
|
||||
// Read a resource
|
||||
const resource = await client.readResource("file:///example.txt");
|
||||
const resource = await client.readResource({
|
||||
uri: "file:///example.txt"
|
||||
});
|
||||
|
||||
// Call a tool
|
||||
const result = await client.callTool({
|
||||
|
|
|
|||
59
package-lock.json
generated
59
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@modelcontextprotocol/sdk",
|
||||
"version": "1.7.0",
|
||||
"version": "1.9.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@modelcontextprotocol/sdk",
|
||||
"version": "1.7.0",
|
||||
"version": "1.9.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"content-type": "^1.0.5",
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
"eventsource": "^3.0.2",
|
||||
"express": "^5.0.1",
|
||||
"express-rate-limit": "^7.5.0",
|
||||
"pkce-challenge": "^4.1.0",
|
||||
"pkce-challenge": "^5.0.0",
|
||||
"raw-body": "^3.0.0",
|
||||
"zod": "^3.23.8",
|
||||
"zod-to-json-schema": "^3.24.1"
|
||||
|
|
@ -60,10 +60,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.0.tgz",
|
||||
"integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==",
|
||||
"version": "7.26.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
|
||||
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.25.9",
|
||||
"js-tokens": "^4.0.0",
|
||||
|
|
@ -211,25 +212,27 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz",
|
||||
"integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz",
|
||||
"integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.25.9",
|
||||
"@babel/types": "^7.26.0"
|
||||
"@babel/template": "^7.27.0",
|
||||
"@babel/types": "^7.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.26.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz",
|
||||
"integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz",
|
||||
"integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.26.0"
|
||||
"@babel/types": "^7.27.0"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
|
|
@ -461,14 +464,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
|
||||
"integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz",
|
||||
"integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.25.9",
|
||||
"@babel/parser": "^7.25.9",
|
||||
"@babel/types": "^7.25.9"
|
||||
"@babel/code-frame": "^7.26.2",
|
||||
"@babel/parser": "^7.27.0",
|
||||
"@babel/types": "^7.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
|
|
@ -502,10 +506,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz",
|
||||
"integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
|
||||
"integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.25.9",
|
||||
"@babel/helper-validator-identifier": "^7.25.9"
|
||||
|
|
@ -5416,9 +5421,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/pkce-challenge": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-4.1.0.tgz",
|
||||
"integrity": "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
|
||||
"integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@modelcontextprotocol/sdk",
|
||||
"version": "1.8.0",
|
||||
"version": "1.9.0",
|
||||
"description": "Model Context Protocol implementation for TypeScript",
|
||||
"license": "MIT",
|
||||
"author": "Anthropic, PBC (https://anthropic.com)",
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
"eventsource": "^3.0.2",
|
||||
"express": "^5.0.1",
|
||||
"express-rate-limit": "^7.5.0",
|
||||
"pkce-challenge": "^4.1.0",
|
||||
"pkce-challenge": "^5.0.0",
|
||||
"raw-body": "^3.0.0",
|
||||
"zod": "^3.23.8",
|
||||
"zod-to-json-schema": "^3.24.1"
|
||||
|
|
|
|||
|
|
@ -227,10 +227,19 @@ test("should respect server capabilities", async () => {
|
|||
await expect(client.listResources()).resolves.not.toThrow();
|
||||
await expect(client.listTools()).resolves.not.toThrow();
|
||||
|
||||
// This should throw because prompts are not supported
|
||||
// These should throw because prompts, logging, and completions are not supported
|
||||
await expect(client.listPrompts()).rejects.toThrow(
|
||||
"Server does not support prompts",
|
||||
);
|
||||
await expect(client.setLoggingLevel("error")).rejects.toThrow(
|
||||
"Server does not support logging",
|
||||
);
|
||||
await expect(
|
||||
client.complete({
|
||||
ref: { type: "ref/prompt", name: "test" },
|
||||
argument: { name: "test", value: "test" },
|
||||
}),
|
||||
).rejects.toThrow("Server does not support completions");
|
||||
});
|
||||
|
||||
test("should respect client notification capabilities", async () => {
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ export class Client<
|
|||
}
|
||||
}
|
||||
|
||||
override async connect(transport: Transport): Promise<void> {
|
||||
override async connect(transport: Transport, options?: RequestOptions): Promise<void> {
|
||||
await super.connect(transport);
|
||||
|
||||
try {
|
||||
|
|
@ -138,6 +138,7 @@ export class Client<
|
|||
},
|
||||
},
|
||||
InitializeResultSchema,
|
||||
options
|
||||
);
|
||||
|
||||
if (result === undefined) {
|
||||
|
|
@ -237,9 +238,9 @@ export class Client<
|
|||
break;
|
||||
|
||||
case "completion/complete":
|
||||
if (!this._serverCapabilities?.prompts) {
|
||||
if (!this._serverCapabilities?.completions) {
|
||||
throw new Error(
|
||||
`Server does not support prompts (required for ${method})`,
|
||||
`Server does not support completions (required for ${method})`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ describe("SSEClientTransport", () => {
|
|||
// Send SSE headers
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Cache-Control": "no-cache, no-transform",
|
||||
Connection: "keep-alive",
|
||||
});
|
||||
|
||||
|
|
@ -56,6 +56,8 @@ describe("SSEClientTransport", () => {
|
|||
baseUrl = new URL(`http://127.0.0.1:${addr.port}`);
|
||||
done();
|
||||
});
|
||||
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
|
@ -183,7 +185,7 @@ describe("SSEClientTransport", () => {
|
|||
if (req.method === "GET") {
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Cache-Control": "no-cache, no-transform",
|
||||
Connection: "keep-alive",
|
||||
});
|
||||
res.write("event: endpoint\n");
|
||||
|
|
@ -397,7 +399,7 @@ describe("SSEClientTransport", () => {
|
|||
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Cache-Control": "no-cache, no-transform",
|
||||
Connection: "keep-alive",
|
||||
});
|
||||
res.write("event: endpoint\n");
|
||||
|
|
@ -524,7 +526,7 @@ describe("SSEClientTransport", () => {
|
|||
if (auth === "Bearer new-token") {
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Cache-Control": "no-cache, no-transform",
|
||||
Connection: "keep-alive",
|
||||
});
|
||||
res.write("event: endpoint\n");
|
||||
|
|
@ -610,7 +612,7 @@ describe("SSEClientTransport", () => {
|
|||
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Cache-Control": "no-cache, no-transform",
|
||||
Connection: "keep-alive",
|
||||
});
|
||||
res.write("event: endpoint\n");
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ describe("requireBearerAuth middleware", () => {
|
|||
set: jest.fn().mockReturnThis(),
|
||||
};
|
||||
nextFunction = jest.fn();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -259,6 +259,11 @@ describe('MCP Auth Router', () => {
|
|||
issuerUrl: new URL('https://auth.example.com')
|
||||
};
|
||||
app.use(mcpAuthRouter(options));
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('routes to authorization endpoint', async () => {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export class SSEServerTransport implements Transport {
|
|||
|
||||
this.res.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Cache-Control": "no-cache, no-transform",
|
||||
Connection: "keep-alive",
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export class ReadBuffer {
|
|||
return null;
|
||||
}
|
||||
|
||||
const line = this._buffer.toString("utf8", 0, index);
|
||||
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, '');
|
||||
this._buffer = this._buffer.subarray(index + 1);
|
||||
return deserializeMessage(line);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@ describe("UriTemplate", () => {
|
|||
expect(template.expand({ username: "fred" })).toBe(
|
||||
"http://example.com/users/fred",
|
||||
);
|
||||
expect(template.variableNames).toEqual(['username'])
|
||||
});
|
||||
|
||||
it("should handle multiple variables", () => {
|
||||
const template = new UriTemplate("{x,y}");
|
||||
expect(template.expand({ x: "1024", y: "768" })).toBe("1024,768");
|
||||
expect(template.variableNames).toEqual(['x', 'y'])
|
||||
});
|
||||
|
||||
it("should encode reserved characters", () => {
|
||||
|
|
@ -43,6 +45,7 @@ describe("UriTemplate", () => {
|
|||
it("should not encode reserved characters with + operator", () => {
|
||||
const template = new UriTemplate("{+path}/here");
|
||||
expect(template.expand({ path: "/foo/bar" })).toBe("/foo/bar/here");
|
||||
expect(template.variableNames).toEqual(['path'])
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -50,6 +53,7 @@ describe("UriTemplate", () => {
|
|||
it("should add # prefix and not encode reserved chars", () => {
|
||||
const template = new UriTemplate("X{#var}");
|
||||
expect(template.expand({ var: "/test" })).toBe("X#/test");
|
||||
expect(template.variableNames).toEqual(['var'])
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -57,6 +61,7 @@ describe("UriTemplate", () => {
|
|||
it("should add . prefix", () => {
|
||||
const template = new UriTemplate("X{.var}");
|
||||
expect(template.expand({ var: "test" })).toBe("X.test");
|
||||
expect(template.variableNames).toEqual(['var'])
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -64,6 +69,7 @@ describe("UriTemplate", () => {
|
|||
it("should add / prefix", () => {
|
||||
const template = new UriTemplate("X{/var}");
|
||||
expect(template.expand({ var: "test" })).toBe("X/test");
|
||||
expect(template.variableNames).toEqual(['var'])
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ describe("UriTemplate", () => {
|
|||
it("should add ? prefix and name=value format", () => {
|
||||
const template = new UriTemplate("X{?var}");
|
||||
expect(template.expand({ var: "test" })).toBe("X?var=test");
|
||||
expect(template.variableNames).toEqual(['var'])
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -78,6 +85,7 @@ describe("UriTemplate", () => {
|
|||
it("should add & prefix and name=value format", () => {
|
||||
const template = new UriTemplate("X{&var}");
|
||||
expect(template.expand({ var: "test" })).toBe("X&var=test");
|
||||
expect(template.variableNames).toEqual(['var'])
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -133,6 +141,7 @@ describe("UriTemplate", () => {
|
|||
resource: "users",
|
||||
id: "123"
|
||||
})).toBe("/api/v1/users/123");
|
||||
expect(template.variableNames).toEqual(['version', 'resource', 'id'])
|
||||
});
|
||||
|
||||
it("should handle query parameters with arrays", () => {
|
||||
|
|
@ -140,6 +149,7 @@ describe("UriTemplate", () => {
|
|||
expect(template.expand({
|
||||
tags: ["nodejs", "typescript", "testing"]
|
||||
})).toBe("/search?tags=nodejs,typescript,testing");
|
||||
expect(template.variableNames).toEqual(['tags'])
|
||||
});
|
||||
|
||||
it("should handle multiple query parameters", () => {
|
||||
|
|
@ -149,6 +159,7 @@ describe("UriTemplate", () => {
|
|||
page: "1",
|
||||
limit: "10"
|
||||
})).toBe("/search?q=test&page=1&limit=10");
|
||||
expect(template.variableNames).toEqual(['q', 'page', 'limit'])
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -161,18 +172,21 @@ describe("UriTemplate", () => {
|
|||
resource: "users",
|
||||
id: "123"
|
||||
});
|
||||
expect(template.variableNames).toEqual(['version', 'resource', 'id'])
|
||||
});
|
||||
|
||||
it("should match query parameters", () => {
|
||||
const template = new UriTemplate("/search{?q}");
|
||||
const match = template.match("/search?q=test");
|
||||
expect(match).toEqual({ q: "test" });
|
||||
expect(template.variableNames).toEqual(['q'])
|
||||
});
|
||||
|
||||
it("should match multiple query parameters", () => {
|
||||
const template = new UriTemplate("/search{?q,page}");
|
||||
const match = template.match("/search?q=test&page=1");
|
||||
expect(match).toEqual({ q: "test", page: "1" });
|
||||
expect(template.variableNames).toEqual(['q', 'page'])
|
||||
});
|
||||
|
||||
it("should handle partial matches correctly", () => {
|
||||
|
|
@ -229,17 +243,20 @@ describe("UriTemplate", () => {
|
|||
it("should handle repeated operators", () => {
|
||||
const template = new UriTemplate("{?a}{?b}{?c}");
|
||||
expect(template.expand({ a: "1", b: "2", c: "3" })).toBe("?a=1&b=2&c=3");
|
||||
expect(template.variableNames).toEqual(['a', 'b', 'c'])
|
||||
});
|
||||
|
||||
it("should handle overlapping variable names", () => {
|
||||
const template = new UriTemplate("{var}{vara}");
|
||||
expect(template.expand({ var: "1", vara: "2" })).toBe("12");
|
||||
expect(template.variableNames).toEqual(['var', 'vara'])
|
||||
});
|
||||
|
||||
it("should handle empty segments", () => {
|
||||
const template = new UriTemplate("///{a}////{b}////");
|
||||
expect(template.expand({ a: "1", b: "2" })).toBe("///1////2////");
|
||||
expect(template.match("///1////2////")).toEqual({ a: "1", b: "2" });
|
||||
expect(template.variableNames).toEqual(['a', 'b'])
|
||||
});
|
||||
|
||||
it("should handle maximum template expression limit", () => {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ export class UriTemplate {
|
|||
| { name: string; operator: string; names: string[]; exploded: boolean }
|
||||
>;
|
||||
|
||||
get variableNames(): string[] {
|
||||
return this.parts.flatMap((part) => typeof part === 'string' ? [] : part.names);
|
||||
}
|
||||
|
||||
constructor(template: string) {
|
||||
UriTemplate.validateLength(template, MAX_TEMPLATE_LENGTH, "Template");
|
||||
this.template = template;
|
||||
|
|
|
|||
|
|
@ -247,6 +247,10 @@ export const ServerCapabilitiesSchema = z
|
|||
* Present if the server supports sending log messages to the client.
|
||||
*/
|
||||
logging: z.optional(z.object({}).passthrough()),
|
||||
/**
|
||||
* Present if the server supports sending completions to the client.
|
||||
*/
|
||||
completions: z.optional(z.object({}).passthrough()),
|
||||
/**
|
||||
* Present if the server offers any prompt templates.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -12,7 +12,11 @@
|
|||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"pkce-challenge": ["node_modules/pkce-challenge/dist/index.node"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
|
|
|
|||
Loading…
Reference in a new issue