Create ResourceTemplate class and move listCallback into it
This commit is contained in:
parent
45f99e6590
commit
8356cb900c
2 changed files with 88 additions and 55 deletions
|
|
@ -25,6 +25,7 @@ import { Transport } from "../shared/transport.js";
|
|||
import { InMemoryTransport } from "../inMemory.js";
|
||||
import { Client } from "../client/index.js";
|
||||
import { UriTemplate } from "../shared/uriTemplate.js";
|
||||
import { ResourceTemplate } from "./index.js";
|
||||
|
||||
test("should accept latest protocol version", async () => {
|
||||
let sendPromiseResolve: (value: unknown) => void;
|
||||
|
|
@ -553,6 +554,34 @@ test("should handle request timeout", async () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("ResourceTemplate", () => {
|
||||
test("should create ResourceTemplate with string pattern", () => {
|
||||
const template = new ResourceTemplate("test://{category}/{id}", undefined);
|
||||
expect(template.uriTemplate.toString()).toBe("test://{category}/{id}");
|
||||
expect(template.listCallback).toBeUndefined();
|
||||
});
|
||||
|
||||
test("should create ResourceTemplate with UriTemplate", () => {
|
||||
const uriTemplate = new UriTemplate("test://{category}/{id}");
|
||||
const template = new ResourceTemplate(uriTemplate, undefined);
|
||||
expect(template.uriTemplate).toBe(uriTemplate);
|
||||
expect(template.listCallback).toBeUndefined();
|
||||
});
|
||||
|
||||
test("should create ResourceTemplate with list callback", async () => {
|
||||
const listCallback = jest.fn().mockResolvedValue({
|
||||
resources: [{ name: "Test", uri: "test://example" }],
|
||||
});
|
||||
|
||||
const template = new ResourceTemplate("test://{id}", listCallback);
|
||||
expect(template.listCallback).toBe(listCallback);
|
||||
|
||||
const result = await template.listCallback?.();
|
||||
expect(result?.resources).toHaveLength(1);
|
||||
expect(listCallback).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Server.tool", () => {
|
||||
test("should register zero-argument tool", async () => {
|
||||
const server = new Server({
|
||||
|
|
@ -1032,7 +1061,7 @@ describe("Server.resource", () => {
|
|||
|
||||
server.resource(
|
||||
"test",
|
||||
new UriTemplate("test://resource/{id}"),
|
||||
new ResourceTemplate("test://resource/{id}", undefined),
|
||||
async () => ({
|
||||
contents: [
|
||||
{
|
||||
|
|
@ -1077,8 +1106,7 @@ describe("Server.resource", () => {
|
|||
|
||||
server.resource(
|
||||
"test",
|
||||
new UriTemplate("test://resource/{id}"),
|
||||
async () => ({
|
||||
new ResourceTemplate("test://resource/{id}", async () => ({
|
||||
resources: [
|
||||
{
|
||||
name: "Resource 1",
|
||||
|
|
@ -1089,7 +1117,7 @@ describe("Server.resource", () => {
|
|||
uri: "test://resource/2",
|
||||
},
|
||||
],
|
||||
}),
|
||||
})),
|
||||
async (uri) => ({
|
||||
contents: [
|
||||
{
|
||||
|
|
@ -1134,7 +1162,7 @@ describe("Server.resource", () => {
|
|||
|
||||
server.resource(
|
||||
"test",
|
||||
new UriTemplate("test://resource/{category}/{id}"),
|
||||
new ResourceTemplate("test://resource/{category}/{id}", undefined),
|
||||
async (uri, { category, id }) => ({
|
||||
contents: [
|
||||
{
|
||||
|
|
@ -1201,7 +1229,7 @@ describe("Server.resource", () => {
|
|||
|
||||
server.resource(
|
||||
"test",
|
||||
new UriTemplate("test://resource/{id}"),
|
||||
new ResourceTemplate("test://resource/{id}", undefined),
|
||||
async () => ({
|
||||
contents: [
|
||||
{
|
||||
|
|
@ -1215,7 +1243,7 @@ describe("Server.resource", () => {
|
|||
expect(() => {
|
||||
server.resource(
|
||||
"test",
|
||||
new UriTemplate("test://resource/{id}"),
|
||||
new ResourceTemplate("test://resource/{id}", undefined),
|
||||
async () => ({
|
||||
contents: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -98,9 +98,8 @@ export type ReadResourceTemplateCallback = (
|
|||
) => ReadResourceResult | Promise<ReadResourceResult>;
|
||||
|
||||
type RegisteredResourceTemplate = {
|
||||
uriTemplate: UriTemplate;
|
||||
resourceTemplate: ResourceTemplate;
|
||||
metadata?: ResourceMetadata;
|
||||
listCallback?: ListResourcesCallback;
|
||||
readCallback: ReadResourceTemplateCallback;
|
||||
};
|
||||
|
||||
|
|
@ -558,11 +557,11 @@ export class Server<
|
|||
|
||||
const templateResources: Resource[] = [];
|
||||
for (const template of Object.values(this._registeredResourceTemplates)) {
|
||||
if (!template.listCallback) {
|
||||
if (!template.resourceTemplate.listCallback) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const result = await template.listCallback();
|
||||
const result = await template.resourceTemplate.listCallback();
|
||||
for (const resource of result.resources) {
|
||||
templateResources.push({
|
||||
...resource,
|
||||
|
|
@ -579,7 +578,7 @@ export class Server<
|
|||
this._registeredResourceTemplates,
|
||||
).map(([name, template]) => ({
|
||||
name,
|
||||
uriTemplate: template.uriTemplate.toString(),
|
||||
uriTemplate: template.resourceTemplate.uriTemplate.toString(),
|
||||
...template.metadata,
|
||||
}));
|
||||
|
||||
|
|
@ -597,7 +596,9 @@ export class Server<
|
|||
|
||||
// Then check templates
|
||||
for (const template of Object.values(this._registeredResourceTemplates)) {
|
||||
const variables = template.uriTemplate.match(uri.toString());
|
||||
const variables = template.resourceTemplate.uriTemplate.match(
|
||||
uri.toString(),
|
||||
);
|
||||
if (variables) {
|
||||
return template.readCallback(uri, variables);
|
||||
}
|
||||
|
|
@ -623,48 +624,27 @@ export class Server<
|
|||
): void;
|
||||
|
||||
/**
|
||||
* Registers a resource `name` with a URI template pattern, which will use the given callback to respond to read requests.
|
||||
* Registers a resource `name` with a template pattern, which will use the given callback to respond to read requests.
|
||||
*/
|
||||
resource(
|
||||
name: string,
|
||||
uriTemplate: UriTemplate,
|
||||
template: ResourceTemplate,
|
||||
readCallback: ReadResourceTemplateCallback,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Registers a resource `name` with a URI template pattern and metadata, which will use the given callback to respond to read requests.
|
||||
* Registers a resource `name` with a template pattern and metadata, which will use the given callback to respond to read requests.
|
||||
*/
|
||||
resource(
|
||||
name: string,
|
||||
uriTemplate: UriTemplate,
|
||||
template: ResourceTemplate,
|
||||
metadata: ResourceMetadata,
|
||||
readCallback: ReadResourceTemplateCallback,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Registers a resource `name` with a URI template pattern, which will use the list callback to enumerate matching resources and read callback to respond to read requests.
|
||||
*/
|
||||
resource(
|
||||
name: string,
|
||||
uriTemplate: UriTemplate,
|
||||
listCallback: ListResourcesCallback,
|
||||
readCallback: ReadResourceTemplateCallback,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Registers a resource `name` with a URI template pattern and metadata, which will use the list callback to enumerate matching resources and read callback to respond to read requests.
|
||||
*/
|
||||
resource(
|
||||
name: string,
|
||||
uriTemplate: UriTemplate,
|
||||
metadata: ResourceMetadata,
|
||||
listCallback: ListResourcesCallback,
|
||||
readCallback: ReadResourceTemplateCallback,
|
||||
): void;
|
||||
|
||||
resource(
|
||||
name: string,
|
||||
uriOrTemplate: string | UriTemplate,
|
||||
uriOrTemplate: string | ResourceTemplate,
|
||||
...rest: unknown[]
|
||||
): void {
|
||||
let metadata: ResourceMetadata | undefined;
|
||||
|
|
@ -672,27 +652,23 @@ export class Server<
|
|||
metadata = rest.shift() as ResourceMetadata;
|
||||
}
|
||||
|
||||
let listCallback: ListResourcesCallback | undefined;
|
||||
if (rest.length > 1) {
|
||||
listCallback = rest.shift() as ListResourcesCallback;
|
||||
}
|
||||
const readCallback = rest[0] as
|
||||
| ReadResourceCallback
|
||||
| ReadResourceTemplateCallback;
|
||||
|
||||
if (typeof uriOrTemplate === "string") {
|
||||
const readCallback = rest[0] as ReadResourceCallback;
|
||||
this.registerResource({
|
||||
name,
|
||||
uri: uriOrTemplate,
|
||||
metadata,
|
||||
readCallback,
|
||||
readCallback: readCallback as ReadResourceCallback,
|
||||
});
|
||||
} else {
|
||||
const readCallback = rest[0] as ReadResourceTemplateCallback;
|
||||
this.registerResourceTemplate({
|
||||
name,
|
||||
uriTemplate: uriOrTemplate,
|
||||
resourceTemplate: uriOrTemplate,
|
||||
metadata,
|
||||
listCallback,
|
||||
readCallback,
|
||||
readCallback: readCallback as ReadResourceTemplateCallback,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -723,15 +699,13 @@ export class Server<
|
|||
|
||||
private registerResourceTemplate({
|
||||
name,
|
||||
uriTemplate,
|
||||
resourceTemplate,
|
||||
metadata,
|
||||
listCallback,
|
||||
readCallback,
|
||||
}: {
|
||||
name: string;
|
||||
uriTemplate: UriTemplate;
|
||||
resourceTemplate: ResourceTemplate;
|
||||
metadata?: ResourceMetadata;
|
||||
listCallback?: ListResourcesCallback;
|
||||
readCallback: ReadResourceTemplateCallback;
|
||||
}): void {
|
||||
if (this._registeredResourceTemplates[name]) {
|
||||
|
|
@ -739,12 +713,43 @@ export class Server<
|
|||
}
|
||||
|
||||
this._registeredResourceTemplates[name] = {
|
||||
uriTemplate,
|
||||
resourceTemplate,
|
||||
metadata,
|
||||
listCallback,
|
||||
readCallback,
|
||||
};
|
||||
|
||||
this.setResourceRequestHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A resource template combines a URI pattern with optional functionality to enumerate
|
||||
* all resources matching that pattern.
|
||||
*/
|
||||
export class ResourceTemplate {
|
||||
private _uriTemplate: UriTemplate;
|
||||
|
||||
constructor(
|
||||
uriTemplate: string | UriTemplate,
|
||||
private _listCallback: ListResourcesCallback | undefined,
|
||||
) {
|
||||
this._uriTemplate =
|
||||
typeof uriTemplate === "string"
|
||||
? new UriTemplate(uriTemplate)
|
||||
: uriTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URI template pattern.
|
||||
*/
|
||||
get uriTemplate(): UriTemplate {
|
||||
return this._uriTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list callback, if one was provided.
|
||||
*/
|
||||
get listCallback(): ListResourcesCallback | undefined {
|
||||
return this._listCallback;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue