shokupan 0.16.3 → 0.16.5

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.
@@ -51,7 +51,7 @@ const node_stream = require("node:stream");
51
51
  const zlib = require("node:zlib");
52
52
  const Ajv = require("ajv");
53
53
  const addFormats = require("ajv-formats");
54
- const crypto = require("crypto");
54
+ const crypto$1 = require("crypto");
55
55
  const events = require("events");
56
56
  var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
57
57
  function _interopNamespaceDefault(e) {
@@ -2744,145 +2744,270 @@ class NotFoundError extends HttpError {
2744
2744
  this.name = "NotFoundError";
2745
2745
  }
2746
2746
  }
2747
- class McpProtocol {
2748
- tools = /* @__PURE__ */ new Map();
2749
- prompts = /* @__PURE__ */ new Map();
2750
- resources = /* @__PURE__ */ new Map();
2751
- constructor(tools = [], prompts = [], resources = []) {
2752
- tools.forEach((t) => this.tools.set(t.name, t));
2753
- prompts.forEach((p) => this.prompts.set(p.name, p));
2754
- resources.forEach((r) => this.resources.set(r.uri, r));
2747
+ class McpSession {
2748
+ constructor(sessionId, protocol) {
2749
+ this.protocol = protocol;
2750
+ this.sessionId = sessionId;
2755
2751
  }
2756
- addTool(tool) {
2757
- this.tools.set(tool.name, tool);
2752
+ sessionId;
2753
+ initialized = false;
2754
+ writeController;
2755
+ activeRequests = /* @__PURE__ */ new Map();
2756
+ pendingCallbacks = /* @__PURE__ */ new Map();
2757
+ nextMessageId = 1;
2758
+ attachStream(controller) {
2759
+ this.writeController = controller;
2758
2760
  }
2759
- addPrompt(prompt) {
2760
- this.prompts.set(prompt.name, prompt);
2761
+ close() {
2762
+ if (this.writeController) {
2763
+ try {
2764
+ this.writeController.close();
2765
+ } catch (e) {
2766
+ }
2767
+ }
2768
+ this.activeRequests.forEach((controller) => {
2769
+ controller.abort(new Error("Session closed"));
2770
+ });
2771
+ this.activeRequests.clear();
2772
+ this.pendingCallbacks.forEach(({ reject }) => {
2773
+ reject(new Error("Session closed"));
2774
+ });
2775
+ this.pendingCallbacks.clear();
2776
+ this.initialized = false;
2761
2777
  }
2762
- addResource(resource) {
2763
- this.resources.set(resource.uri, resource);
2778
+ send(message) {
2779
+ if (!this.writeController) return;
2780
+ try {
2781
+ this.writeController.enqueue(`event: message
2782
+ data: ${JSON.stringify(message)}
2783
+
2784
+ `);
2785
+ } catch (e) {
2786
+ this.close();
2787
+ }
2764
2788
  }
2765
- merge(other) {
2766
- other.tools.forEach((t) => this.tools.set(t.name, t));
2767
- other.prompts.forEach((p) => this.prompts.set(p.name, p));
2768
- other.resources.forEach((r) => this.resources.set(r.uri, r));
2789
+ async sendRequest(method, params) {
2790
+ const id = this.nextMessageId++;
2791
+ return new Promise((resolve, reject) => {
2792
+ this.pendingCallbacks.set(id, { resolve, reject });
2793
+ this.send({ jsonrpc: "2.0", id, method, params });
2794
+ });
2795
+ }
2796
+ sendNotification(method, params) {
2797
+ this.send({ jsonrpc: "2.0", method, params });
2798
+ }
2799
+ /**
2800
+ * Request the current roots from the client.
2801
+ */
2802
+ async listRoots() {
2803
+ return this.sendRequest("roots/list");
2804
+ }
2805
+ /**
2806
+ * Request the client to sample an LLM completion.
2807
+ */
2808
+ async createMessageSampling(params) {
2809
+ return this.sendRequest("sampling/createMessage", params);
2769
2810
  }
2770
2811
  async handleMessage(message) {
2771
- if (message.jsonrpc !== "2.0") {
2772
- return this.error(message.id, -32600, "Invalid Request");
2812
+ if (!message || typeof message !== "object" || message.jsonrpc !== "2.0") {
2813
+ return this.error(message?.id ?? null, -32600, "Invalid Request");
2814
+ }
2815
+ if ("result" in message || "error" in message) {
2816
+ const cb = this.pendingCallbacks.get(message.id);
2817
+ if (cb) {
2818
+ this.pendingCallbacks.delete(message.id);
2819
+ if (message.error) {
2820
+ cb.reject(new Error(message.error.message));
2821
+ } else {
2822
+ cb.resolve(message.result);
2823
+ }
2824
+ }
2825
+ return null;
2826
+ }
2827
+ const req = message;
2828
+ const isNotification = !("id" in req);
2829
+ if (isNotification) {
2830
+ if (req.method === "notifications/cancel") {
2831
+ const requestId = req.params?.requestId;
2832
+ if (requestId) {
2833
+ const controller = this.activeRequests.get(requestId);
2834
+ if (controller) {
2835
+ controller.abort(new Error("Cancelled by client"));
2836
+ this.activeRequests.delete(requestId);
2837
+ }
2838
+ }
2839
+ } else if (req.method === "notifications/initialized") {
2840
+ this.initialized = true;
2841
+ } else if (req.method === "notifications/progress") ;
2842
+ return null;
2773
2843
  }
2774
2844
  try {
2775
- switch (message.method) {
2845
+ const controller = new AbortController();
2846
+ this.activeRequests.set(req.id, controller);
2847
+ const context = {
2848
+ session: this,
2849
+ signal: controller.signal,
2850
+ onProgress: (progress, total) => {
2851
+ const progressToken = req.params?.meta?.progressToken;
2852
+ if (progressToken) {
2853
+ this.sendNotification("notifications/progress", {
2854
+ progressToken,
2855
+ progress,
2856
+ total
2857
+ });
2858
+ }
2859
+ }
2860
+ };
2861
+ let result;
2862
+ switch (req.method) {
2776
2863
  case "initialize":
2777
- return this.success(message.id, {
2864
+ result = {
2778
2865
  protocolVersion: "2024-11-05",
2779
2866
  serverInfo: {
2780
2867
  name: "Shokupan MCP",
2781
2868
  version: "1.0.0"
2782
2869
  },
2783
2870
  capabilities: {
2784
- tools: this.tools.size > 0 ? {} : void 0,
2785
- prompts: this.prompts.size > 0 ? {} : void 0,
2786
- resources: this.resources.size > 0 ? {} : void 0
2871
+ tools: this.protocol.hasTools() ? {} : void 0,
2872
+ prompts: this.protocol.hasPrompts() ? {} : void 0,
2873
+ resources: this.protocol.hasResources() ? {} : void 0
2787
2874
  }
2788
- });
2875
+ };
2876
+ break;
2789
2877
  case "ping":
2790
- return this.success(message.id, {});
2878
+ result = {};
2879
+ break;
2791
2880
  case "tools/list":
2792
- if (this.tools.size === 0) return this.success(message.id, { tools: [] });
2793
- return this.success(message.id, {
2794
- tools: Array.from(this.tools.values()).map((t) => ({
2795
- name: t.name,
2796
- description: t.description,
2797
- inputSchema: t.inputSchema || { type: "object", properties: {} }
2798
- }))
2799
- });
2800
- case "tools/call": {
2801
- if (!message.params || !message.params.name) {
2802
- return this.error(message.id, -32602, "Invalid params: name required");
2803
- }
2804
- const tool = this.tools.get(message.params.name);
2805
- if (!tool) {
2806
- return this.error(message.id, -32601, `Tool not found: ${message.params.name}`);
2807
- }
2808
- try {
2809
- const result = await tool.handler(message.params.arguments || {});
2810
- return this.success(message.id, result);
2811
- } catch (e) {
2812
- return {
2813
- jsonrpc: "2.0",
2814
- id: message.id ?? null,
2815
- result: {
2816
- isError: true,
2817
- content: [{ type: "text", text: e.message || String(e) }]
2818
- }
2819
- };
2820
- }
2821
- }
2881
+ result = this.protocol.listTools(req.params?.cursor);
2882
+ break;
2883
+ case "tools/call":
2884
+ if (!req.params || !req.params.name) throw new Error("Invalid params: name required");
2885
+ result = await this.protocol.callTool(req.params.name, req.params.arguments, context);
2886
+ break;
2822
2887
  case "prompts/list":
2823
- if (this.prompts.size === 0) return this.success(message.id, { prompts: [] });
2824
- return this.success(message.id, {
2825
- prompts: Array.from(this.prompts.values()).map((p) => ({
2826
- name: p.name,
2827
- description: p.description,
2828
- arguments: p.arguments
2829
- }))
2830
- });
2831
- case "prompts/get": {
2832
- if (!message.params || !message.params.name) {
2833
- return this.error(message.id, -32602, "Invalid params: name required");
2834
- }
2835
- const prompt = this.prompts.get(message.params.name);
2836
- if (!prompt) {
2837
- return this.error(message.id, -32601, `Prompt not found: ${message.params.name}`);
2838
- }
2839
- const result = await prompt.handler(message.params.arguments || {});
2840
- return this.success(message.id, result);
2841
- }
2888
+ result = this.protocol.listPrompts(req.params?.cursor);
2889
+ break;
2890
+ case "prompts/get":
2891
+ if (!req.params || !req.params.name) throw new Error("Invalid params: name required");
2892
+ result = await this.protocol.getPrompt(req.params.name, req.params.arguments, context);
2893
+ break;
2842
2894
  case "resources/list":
2843
- if (this.resources.size === 0) return this.success(message.id, { resources: [] });
2844
- return this.success(message.id, {
2845
- resources: Array.from(this.resources.values()).map((r) => ({
2846
- uri: r.uri,
2847
- name: r.name,
2848
- description: r.description,
2849
- mimeType: r.mimeType
2850
- }))
2851
- });
2852
- case "resources/read": {
2853
- if (!message.params || !message.params.uri) {
2854
- return this.error(message.id, -32602, "Invalid params: uri required");
2855
- }
2856
- let resource = this.resources.get(message.params.uri);
2857
- if (!resource) {
2858
- return this.error(message.id, -32601, `Resource not found: ${message.params.uri}`);
2859
- }
2860
- const result = await resource.handler(message.params.uri);
2861
- return this.success(message.id, result);
2862
- }
2895
+ result = this.protocol.listResources(req.params?.cursor);
2896
+ break;
2897
+ case "resources/read":
2898
+ if (!req.params || !req.params.uri) throw new Error("Invalid params: uri required");
2899
+ result = await this.protocol.readResource(req.params.uri, context);
2900
+ break;
2863
2901
  default:
2864
- if (message.id === void 0) return null;
2865
- return this.error(message.id, -32601, "Method not found");
2902
+ return this.error(req.id, -32601, "Method not found");
2866
2903
  }
2904
+ this.activeRequests.delete(req.id);
2905
+ return this.success(req.id, result);
2867
2906
  } catch (err) {
2868
- return this.error(message.id, -32603, "Internal Error", err.message);
2907
+ this.activeRequests.delete(req.id);
2908
+ if (req.method === "tools/call") {
2909
+ return this.success(req.id, {
2910
+ isError: true,
2911
+ content: [{ type: "text", text: err.message || String(err) }]
2912
+ });
2913
+ }
2914
+ return this.error(req.id, -32603, "Internal Error", err.message);
2869
2915
  }
2870
2916
  }
2871
2917
  success(id, result) {
2872
2918
  return {
2873
2919
  jsonrpc: "2.0",
2874
- id: id ?? null,
2920
+ id,
2875
2921
  result
2876
2922
  };
2877
2923
  }
2878
2924
  error(id, code, message, data) {
2879
2925
  return {
2880
2926
  jsonrpc: "2.0",
2881
- id: id ?? null,
2927
+ id,
2882
2928
  error: { code, message, data }
2883
2929
  };
2884
2930
  }
2885
2931
  }
2932
+ class McpProtocol {
2933
+ tools = /* @__PURE__ */ new Map();
2934
+ prompts = /* @__PURE__ */ new Map();
2935
+ resources = /* @__PURE__ */ new Map();
2936
+ constructor(tools = [], prompts = [], resources = []) {
2937
+ tools.forEach((t) => this.tools.set(t.name, t));
2938
+ prompts.forEach((p) => this.prompts.set(p.name, p));
2939
+ resources.forEach((r) => this.resources.set(r.uri, r));
2940
+ }
2941
+ hasTools() {
2942
+ return this.tools.size > 0;
2943
+ }
2944
+ hasPrompts() {
2945
+ return this.prompts.size > 0;
2946
+ }
2947
+ hasResources() {
2948
+ return this.resources.size > 0;
2949
+ }
2950
+ addTool(tool) {
2951
+ this.tools.set(tool.name, tool);
2952
+ }
2953
+ addPrompt(prompt) {
2954
+ this.prompts.set(prompt.name, prompt);
2955
+ }
2956
+ addResource(resource) {
2957
+ this.resources.set(resource.uri, resource);
2958
+ }
2959
+ merge(other) {
2960
+ other.tools.forEach((t) => this.tools.set(t.name, t));
2961
+ other.prompts.forEach((p) => this.prompts.set(p.name, p));
2962
+ other.resources.forEach((r) => this.resources.set(r.uri, r));
2963
+ }
2964
+ createSession(sessionId) {
2965
+ return new McpSession(sessionId, this);
2966
+ }
2967
+ listTools(cursor) {
2968
+ return {
2969
+ tools: Array.from(this.tools.values()).map((t) => ({
2970
+ name: t.name,
2971
+ description: t.description,
2972
+ inputSchema: t.inputSchema || { type: "object", properties: {} }
2973
+ }))
2974
+ };
2975
+ }
2976
+ async callTool(name, args, context) {
2977
+ const tool = this.tools.get(name);
2978
+ if (!tool) throw new Error(`Tool not found: ${name}`);
2979
+ return await tool.handler(args || {}, context);
2980
+ }
2981
+ listPrompts(cursor) {
2982
+ return {
2983
+ prompts: Array.from(this.prompts.values()).map((p) => ({
2984
+ name: p.name,
2985
+ description: p.description,
2986
+ arguments: p.arguments
2987
+ }))
2988
+ };
2989
+ }
2990
+ async getPrompt(name, args, context) {
2991
+ const prompt = this.prompts.get(name);
2992
+ if (!prompt) throw new Error(`Prompt not found: ${name}`);
2993
+ return await prompt.handler(args || {}, context);
2994
+ }
2995
+ listResources(cursor) {
2996
+ return {
2997
+ resources: Array.from(this.resources.values()).map((r) => ({
2998
+ uri: r.uri,
2999
+ name: r.name,
3000
+ description: r.description,
3001
+ mimeType: r.mimeType
3002
+ }))
3003
+ };
3004
+ }
3005
+ async readResource(uri, context) {
3006
+ const resource = this.resources.get(uri);
3007
+ if (!resource) throw new Error(`Resource not found: ${uri}`);
3008
+ return await resource.handler(uri, context);
3009
+ }
3010
+ }
2886
3011
  class MiddlewareTracker {
2887
3012
  static wrap(handler, context) {
2888
3013
  const { file, line, name, isBuiltin, pluginName } = context;
@@ -4763,7 +4888,7 @@ class ApiExplorerPlugin extends ShokupanRouter {
4763
4888
  }
4764
4889
  }
4765
4890
  static getBasePath() {
4766
- const dir = path$1.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index-8Ylk5R0q.cjs", document.baseURI).href));
4891
+ const dir = path$1.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index-Cx60P13T.cjs", document.baseURI).href));
4767
4892
  if (dir.endsWith("dist")) {
4768
4893
  return dir + "/plugins/application/api-explorer";
4769
4894
  }
@@ -5567,7 +5692,7 @@ class AsyncApiPlugin extends ShokupanRouter {
5567
5692
  this.init();
5568
5693
  }
5569
5694
  static getBasePath() {
5570
- const dir = path$1.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index-8Ylk5R0q.cjs", document.baseURI).href));
5695
+ const dir = path$1.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index-Cx60P13T.cjs", document.baseURI).href));
5571
5696
  if (dir.endsWith("dist")) {
5572
5697
  return dir + "/plugins/application/asyncapi";
5573
5698
  }
@@ -6091,7 +6216,7 @@ function createHTTPLogger() {
6091
6216
  return result;
6092
6217
  };
6093
6218
  }
6094
- const require$1 = node_module.createRequire(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index-8Ylk5R0q.cjs", document.baseURI).href);
6219
+ const require$1 = node_module.createRequire(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index-Cx60P13T.cjs", document.baseURI).href);
6095
6220
  const http = require$1("node:http");
6096
6221
  const https = require$1("node:https");
6097
6222
  class FetchInterceptor {
@@ -6698,7 +6823,7 @@ class Dashboard {
6698
6823
  }
6699
6824
  // Get base path for dashboard files - works in both dev (src/) and production (dist/)
6700
6825
  static getBasePath() {
6701
- const dir = path$1.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index-8Ylk5R0q.cjs", document.baseURI).href));
6826
+ const dir = path$1.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index-Cx60P13T.cjs", document.baseURI).href));
6702
6827
  if (dir.endsWith("dist")) {
6703
6828
  return dir + "/plugins/application/dashboard";
6704
6829
  }
@@ -9689,6 +9814,7 @@ class Shokupan extends ShokupanRouter {
9689
9814
  startupHooks = [];
9690
9815
  plugins = [];
9691
9816
  specAvailableHooks = [];
9817
+ pluginInitPromises = [];
9692
9818
  get db() {
9693
9819
  return this.datastore;
9694
9820
  }
@@ -9801,24 +9927,24 @@ class Shokupan extends ShokupanRouter {
9801
9927
  try {
9802
9928
  switch (adapterName) {
9803
9929
  case "sqlite": {
9804
- const { SqliteAdapter } = await Promise.resolve().then(() => require("./sqlite-4_h2xf9-.cjs"));
9930
+ const { SqliteAdapter } = await Promise.resolve().then(() => require("./sqlite-CvoMrQNx.cjs"));
9805
9931
  this.datastore = new SqliteAdapter(options);
9806
9932
  break;
9807
9933
  }
9808
9934
  case "level": {
9809
- const { LevelAdapter } = await Promise.resolve().then(() => require("./level-3Mg_5PYx.cjs"));
9935
+ const { LevelAdapter } = await Promise.resolve().then(() => require("./level-DzWOqk9S.cjs"));
9810
9936
  this.datastore = new LevelAdapter(options);
9811
9937
  break;
9812
9938
  }
9813
9939
  case "surrealdb": {
9814
- const { SurrealAdapter } = await Promise.resolve().then(() => require("./surreal-wFuSfb5c.cjs"));
9940
+ const { SurrealAdapter } = await Promise.resolve().then(() => require("./surreal-DOJpgKP7.cjs"));
9815
9941
  const legacyConfig = this.applicationConfig.surreal || {};
9816
9942
  const effectiveOptions = { ...legacyConfig, ...options };
9817
9943
  this.datastore = new SurrealAdapter(effectiveOptions);
9818
9944
  break;
9819
9945
  }
9820
9946
  default: {
9821
- const { SurrealAdapter } = await Promise.resolve().then(() => require("./surreal-wFuSfb5c.cjs"));
9947
+ const { SurrealAdapter } = await Promise.resolve().then(() => require("./surreal-DOJpgKP7.cjs"));
9822
9948
  const legacy = this.applicationConfig.surreal;
9823
9949
  this.datastore = new SurrealAdapter(options || legacy || {});
9824
9950
  }
@@ -9854,11 +9980,16 @@ class Shokupan extends ShokupanRouter {
9854
9980
  }
9855
9981
  /**
9856
9982
  * Registers a plugin.
9983
+ * This returns a promise that resolves when the plugin is initialized. You do not
9984
+ * need to await it unless you want to run code specifically after the plugin is initialized.
9985
+ * Shokupan automatically awaits plugin initialization promises when calling listen().
9857
9986
  */
9858
9987
  async register(plugin, options) {
9859
9988
  this.plugins.push(plugin);
9860
9989
  try {
9861
- await plugin.onInit(this, options);
9990
+ const promise = plugin.onInit(this, options);
9991
+ this.pluginInitPromises.push(promise);
9992
+ await promise;
9862
9993
  } catch (err) {
9863
9994
  this.logger?.error("Shokupan", "Failed to initialize plugin", { error: err });
9864
9995
  throw err;
@@ -10024,6 +10155,7 @@ class Shokupan extends ShokupanRouter {
10024
10155
  */
10025
10156
  async listen(port, callback) {
10026
10157
  this.httpServer = new ShokupanServer(this);
10158
+ await Promise.allSettled(this.pluginInitPromises);
10027
10159
  this.server = await this.httpServer.listen(port);
10028
10160
  const protocol = this.applicationConfig.tls || this.applicationConfig.development ? "https" : "http";
10029
10161
  const url = `${protocol}://${this.applicationConfig.hostname}:${this.applicationConfig.port}`;
@@ -10478,6 +10610,21 @@ class AuthPlugin extends ShokupanRouter {
10478
10610
  return jwt;
10479
10611
  }
10480
10612
  init() {
10613
+ this.get("/auth/me", async (ctx) => {
10614
+ const cookieHeader = ctx.req.headers.get("Cookie");
10615
+ const token = cookieHeader?.match(/auth_token=([^;]+)/)?.[1];
10616
+ if (!token) return ctx.json({ error: "Unauthenticated" }, 401);
10617
+ try {
10618
+ const { payload } = await this.jose.jwtVerify(token, this.secret);
10619
+ return ctx.json(payload);
10620
+ } catch {
10621
+ return ctx.json({ error: "Invalid or expired token" }, 401);
10622
+ }
10623
+ });
10624
+ this.post("/auth/logout", (ctx) => {
10625
+ ctx.set("Set-Cookie", "auth_token=; Path=/; HttpOnly; Max-Age=0; SameSite=Lax");
10626
+ return ctx.json({ ok: true });
10627
+ });
10481
10628
  const { generateState, generateCodeVerifier, GitHub, Google, MicrosoftEntraId, Apple, Auth0, Okta, OAuth2Client } = this.arctic;
10482
10629
  const providerEntries = Object.entries(this.authConfig.providers);
10483
10630
  for (let i = 0; i < providerEntries.length; i++) {
@@ -10515,6 +10662,7 @@ class AuthPlugin extends ShokupanRouter {
10515
10662
  const url = new URL(ctx.req.url);
10516
10663
  const code = url.searchParams.get("code");
10517
10664
  const state = url.searchParams.get("state");
10665
+ console.log("== OAuth Callback Hit ==", { providerName, code, state });
10518
10666
  const cookieHeader = ctx.req.headers.get("Cookie");
10519
10667
  const storedState = cookieHeader?.match(/oauth_state=([^;]+)/)?.[1];
10520
10668
  const storedVerifier = cookieHeader?.match(/oauth_verifier=([^;]+)/)?.[1];
@@ -10538,17 +10686,38 @@ class AuthPlugin extends ShokupanRouter {
10538
10686
  if (!providerConfig.tokenUrl) return ctx.text("Config error: tokenUrl required for oauth2", 500);
10539
10687
  tokens = await provider.validateAuthorizationCode(providerConfig.tokenUrl, code, null);
10540
10688
  }
10541
- const accessToken = tokens.accessToken || tokens.access_token;
10689
+ const accessToken = typeof tokens.accessToken === "function" ? tokens.accessToken() : tokens.accessToken || tokens.access_token;
10690
+ try {
10691
+ if (typeof tokens.idToken === "function") {
10692
+ idToken = tokens.idToken();
10693
+ } else if (tokens.idToken) {
10694
+ idToken = tokens.idToken;
10695
+ }
10696
+ } catch (e) {
10697
+ }
10542
10698
  const user = await this.fetchUser(providerName, accessToken, providerConfig, idToken);
10543
10699
  if (this.authConfig.onSuccess) {
10544
10700
  const res = await this.authConfig.onSuccess(user, ctx);
10545
10701
  if (res) return res;
10546
10702
  }
10547
10703
  const jwt = await this.createSession(user, ctx);
10704
+ if (this.authConfig.successRedirect) {
10705
+ return ctx.redirect(this.authConfig.successRedirect);
10706
+ }
10548
10707
  return ctx.json({ token: jwt, user });
10549
10708
  } catch (e) {
10709
+ console.error("Auth Exception:", e);
10710
+ let extradata = "";
10711
+ try {
10712
+ if (e && e.response) extradata = " | Body: " + await e.response.text();
10713
+ } catch {
10714
+ }
10550
10715
  ctx.app?.logger?.error("Auth", "Authentication failed", e);
10551
- return ctx.text("Authentication failed. Please try again.", 500);
10716
+ return ctx.text(`Authentication failed.
10717
+ Error: ${e?.message ?? String(e)}${extradata}
10718
+
10719
+ Stack:
10720
+ ${e?.stack}`, 500);
10552
10721
  }
10553
10722
  });
10554
10723
  }
@@ -10557,7 +10726,10 @@ class AuthPlugin extends ShokupanRouter {
10557
10726
  let user = { id: "unknown", provider };
10558
10727
  if (provider === "github") {
10559
10728
  const res = await fetch("https://api.github.com/user", {
10560
- headers: { Authorization: `Bearer ${token}` }
10729
+ headers: {
10730
+ Authorization: `Bearer ${token}`,
10731
+ "User-Agent": "Shokupan-Auth/1.0"
10732
+ }
10561
10733
  });
10562
10734
  const data = await res.json();
10563
10735
  user = {
@@ -11115,19 +11287,26 @@ class MCPServerPlugin {
11115
11287
  };
11116
11288
  collect(app);
11117
11289
  }
11290
+ sessions = /* @__PURE__ */ new Map();
11118
11291
  setupRoutes() {
11119
11292
  this.router.get("", (ctx) => {
11120
- const endpointUrl = `${ctx.protocol}://${ctx.host}${this.options.path}`;
11121
- const enc = new TextEncoder();
11293
+ const sessionId = crypto.randomUUID();
11294
+ const session = this.router.mcpProtocol.createSession(sessionId);
11295
+ this.sessions.set(sessionId, session);
11296
+ const base = ctx.request.url.replace(/\/$/, "");
11297
+ const endpointUrl = `${base}/message?sessionId=${sessionId}`;
11122
11298
  return new Response(
11123
11299
  new ReadableStream({
11124
11300
  start(controller) {
11125
- controller.enqueue(enc.encode(`event: endpoint
11126
- data: ${JSON.stringify(endpointUrl)}
11301
+ session.attachStream(controller);
11302
+ controller.enqueue(`event: endpoint
11303
+ data: ${endpointUrl}
11127
11304
 
11128
- `));
11305
+ `);
11129
11306
  },
11130
- cancel() {
11307
+ cancel: () => {
11308
+ session.close();
11309
+ this.sessions.delete(sessionId);
11131
11310
  }
11132
11311
  }),
11133
11312
  {
@@ -11139,7 +11318,16 @@ data: ${JSON.stringify(endpointUrl)}
11139
11318
  }
11140
11319
  );
11141
11320
  });
11142
- this.router.post("", async (ctx) => {
11321
+ this.router.post("/message", async (ctx) => {
11322
+ const url = new URL(ctx.request.url);
11323
+ const sessionId = url.searchParams.get("sessionId");
11324
+ if (!sessionId) {
11325
+ return ctx.text("Missing sessionId", 400);
11326
+ }
11327
+ const session = this.sessions.get(sessionId);
11328
+ if (!session) {
11329
+ return ctx.text("Session not found", 404);
11330
+ }
11143
11331
  let parsedBody;
11144
11332
  try {
11145
11333
  parsedBody = await ctx.body();
@@ -11150,7 +11338,7 @@ data: ${JSON.stringify(endpointUrl)}
11150
11338
  error: { code: -32700, message: "Parse error" }
11151
11339
  }, 400);
11152
11340
  }
11153
- const response = await this.router.mcpProtocol.handleMessage(parsedBody);
11341
+ const response = await session.handleMessage(parsedBody);
11154
11342
  if (response) {
11155
11343
  return ctx.json(response);
11156
11344
  }
@@ -12569,7 +12757,7 @@ class MemoryStore extends events.EventEmitter {
12569
12757
  function sign(val, secret) {
12570
12758
  if (typeof val !== "string") throw new TypeError("Cookie value must be provided as a string.");
12571
12759
  if (typeof secret !== "string") throw new TypeError("Secret string must be provided.");
12572
- return val + "." + crypto.createHmac("sha256", secret).update(val).digest("base64").replace(/\=+$/, "");
12760
+ return val + "." + crypto$1.createHmac("sha256", secret).update(val).digest("base64").replace(/\=+$/, "");
12573
12761
  }
12574
12762
  function unsign(input, secret) {
12575
12763
  if (typeof input !== "string") throw new TypeError("Signed cookie string must be provided.");
@@ -12582,7 +12770,7 @@ function unsign(input, secret) {
12582
12770
  Buffer.from(expectedInput).copy(paddedExpected);
12583
12771
  Buffer.from(input).copy(paddedInput);
12584
12772
  try {
12585
- const valid = crypto.timingSafeEqual(paddedExpected, paddedInput);
12773
+ const valid = crypto$1.timingSafeEqual(paddedExpected, paddedInput);
12586
12774
  return valid ? tentValue : false;
12587
12775
  } catch {
12588
12776
  return false;
@@ -12592,7 +12780,7 @@ function Session(options) {
12592
12780
  const store = options.store || new MemoryStore();
12593
12781
  const name = options.name || "connect.sid";
12594
12782
  const secrets = Array.isArray(options.secret) ? options.secret : [options.secret];
12595
- const generateId = options.genid || (() => crypto.randomUUID());
12783
+ const generateId = options.genid || (() => crypto$1.randomUUID());
12596
12784
  const resave = options.resave === void 0 ? true : options.resave;
12597
12785
  const saveUninitialized = options.saveUninitialized === void 0 ? true : options.saveUninitialized;
12598
12786
  const rolling = options.rolling || false;
@@ -12926,4 +13114,4 @@ exports.traceMiddleware = traceMiddleware;
12926
13114
  exports.useExpress = useExpress;
12927
13115
  exports.valibot = valibot;
12928
13116
  exports.validate = validate;
12929
- //# sourceMappingURL=index-8Ylk5R0q.cjs.map
13117
+ //# sourceMappingURL=index-Cx60P13T.cjs.map