@studiometa/productive-mcp 0.10.7 → 0.10.9

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.
Files changed (64) hide show
  1. package/dist/errors.d.ts.map +1 -1
  2. package/dist/formatters.d.ts +4 -0
  3. package/dist/formatters.d.ts.map +1 -1
  4. package/dist/handlers/activities.d.ts +98 -3
  5. package/dist/handlers/activities.d.ts.map +1 -1
  6. package/dist/handlers/attachments.d.ts +98 -3
  7. package/dist/handlers/attachments.d.ts.map +1 -1
  8. package/dist/handlers/bookings.d.ts +98 -3
  9. package/dist/handlers/bookings.d.ts.map +1 -1
  10. package/dist/handlers/comments.d.ts +98 -3
  11. package/dist/handlers/comments.d.ts.map +1 -1
  12. package/dist/handlers/companies.d.ts +98 -3
  13. package/dist/handlers/companies.d.ts.map +1 -1
  14. package/dist/handlers/custom-fields.d.ts +121 -0
  15. package/dist/handlers/custom-fields.d.ts.map +1 -0
  16. package/dist/handlers/deals.d.ts +98 -3
  17. package/dist/handlers/deals.d.ts.map +1 -1
  18. package/dist/handlers/discussions.d.ts +98 -3
  19. package/dist/handlers/discussions.d.ts.map +1 -1
  20. package/dist/handlers/help.d.ts.map +1 -1
  21. package/dist/handlers/index.d.ts.map +1 -1
  22. package/dist/handlers/pages.d.ts +98 -3
  23. package/dist/handlers/pages.d.ts.map +1 -1
  24. package/dist/handlers/projects.d.ts +98 -3
  25. package/dist/handlers/projects.d.ts.map +1 -1
  26. package/dist/handlers/schema.d.ts.map +1 -1
  27. package/dist/handlers/services.d.ts +98 -3
  28. package/dist/handlers/services.d.ts.map +1 -1
  29. package/dist/handlers/tasks.d.ts +98 -3
  30. package/dist/handlers/tasks.d.ts.map +1 -1
  31. package/dist/handlers/time.d.ts +98 -3
  32. package/dist/handlers/time.d.ts.map +1 -1
  33. package/dist/handlers/timers.d.ts +98 -3
  34. package/dist/handlers/timers.d.ts.map +1 -1
  35. package/dist/handlers/valid-includes.d.ts.map +1 -1
  36. package/dist/{handlers-CzOijI7B.js → handlers-t95fhdps.js} +159 -3
  37. package/dist/handlers-t95fhdps.js.map +1 -0
  38. package/dist/handlers.js +1 -1
  39. package/dist/hints.d.ts +4 -0
  40. package/dist/hints.d.ts.map +1 -1
  41. package/dist/http.d.ts +7 -7
  42. package/dist/http.d.ts.map +1 -1
  43. package/dist/http.js +52 -42
  44. package/dist/http.js.map +1 -1
  45. package/dist/index.js +3 -3
  46. package/dist/oauth.d.ts +9 -9
  47. package/dist/oauth.d.ts.map +1 -1
  48. package/dist/oauth.js +39 -39
  49. package/dist/oauth.js.map +1 -1
  50. package/dist/schema.d.ts +64 -62
  51. package/dist/schema.d.ts.map +1 -1
  52. package/dist/server.js +4 -4
  53. package/dist/server.js.map +1 -1
  54. package/dist/{handlers-Cha6_ulB.js → stdio-Bi1Lvp8O.js} +97 -2
  55. package/dist/stdio-Bi1Lvp8O.js.map +1 -0
  56. package/dist/stdio.d.ts +4 -4
  57. package/dist/stdio.js +2 -99
  58. package/dist/{version-zLvx5_bN.js → version-BFw4junA.js} +3 -3
  59. package/dist/{version-zLvx5_bN.js.map → version-BFw4junA.js.map} +1 -1
  60. package/package.json +10 -18
  61. package/skills/SKILL.md +36 -18
  62. package/dist/handlers-Cha6_ulB.js.map +0 -1
  63. package/dist/handlers-CzOijI7B.js.map +0 -1
  64. package/dist/stdio.js.map +0 -1
package/dist/hints.d.ts CHANGED
@@ -74,6 +74,10 @@ export declare function getPageHints(pageId: string): ContextualHints;
74
74
  * Generate hints for a discussion
75
75
  */
76
76
  export declare function getDiscussionHints(discussionId: string, pageId?: string): ContextualHints;
77
+ /**
78
+ * Generate hints for a custom field definition
79
+ */
80
+ export declare function getCustomFieldHints(fieldId: string): ContextualHints;
77
81
  /**
78
82
  * Generate hints for a timer
79
83
  */
@@ -1 +1 @@
1
- {"version":3,"file":"hints.d.ts","sourceRoot":"","sources":["../src/hints.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,iBAAiB,CAAC,EAAE,YAAY,EAAE,CAAC;IACnC,cAAc,CAAC,EAAE,UAAU,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CA6DhF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CA8DlE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAoD5D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAyChE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,eAAe,GAAG,IAAI,CAkBxB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAqDlE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAyClE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,eAAe,CA0CjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,eAAe,CAAC,EAAE,MAAM,EACxB,aAAa,CAAC,EAAE,MAAM,GACrB,eAAe,CA4BjB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EACrB,cAAc,CAAC,EAAE,MAAM,GACtB,eAAe,CAqCjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,CA6BrF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAqD5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,CA+CzF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CA4BlF"}
1
+ {"version":3,"file":"hints.d.ts","sourceRoot":"","sources":["../src/hints.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,iBAAiB,CAAC,EAAE,YAAY,EAAE,CAAC;IACnC,cAAc,CAAC,EAAE,UAAU,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAsEhF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CA8DlE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CA6D5D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAyChE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,eAAe,GAAG,IAAI,CAkBxB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAqDlE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAmDlE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,eAAe,CA0CjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,eAAe,CAAC,EAAE,MAAM,EACxB,aAAa,CAAC,EAAE,MAAM,GACrB,eAAe,CA4BjB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EACrB,cAAc,CAAC,EAAE,MAAM,GACtB,eAAe,CAqCjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,CA6BrF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAqD5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,CA+CzF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAyBpE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CA4BlF"}
package/dist/http.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * This module contains the app/router creation logic for the HTTP transport.
5
5
  * The actual server startup is in server.ts.
6
6
  */
7
- import { type App } from 'h3';
7
+ import { H3 } from 'h3';
8
8
  /**
9
9
  * JSON-RPC error response
10
10
  */
@@ -44,6 +44,7 @@ export declare function handleInitialize(): {
44
44
  */
45
45
  export declare function handleToolsList(): {
46
46
  tools: {
47
+ description?: string | undefined;
47
48
  inputSchema: {
48
49
  [x: string]: unknown;
49
50
  type: "object";
@@ -52,8 +53,6 @@ export declare function handleToolsList(): {
52
53
  } | undefined;
53
54
  required?: string[] | undefined;
54
55
  };
55
- name: string;
56
- description?: string | undefined;
57
56
  outputSchema?: {
58
57
  [x: string]: unknown;
59
58
  type: "object";
@@ -70,7 +69,7 @@ export declare function handleToolsList(): {
70
69
  openWorldHint?: boolean | undefined;
71
70
  } | undefined;
72
71
  execution?: {
73
- taskSupport?: "optional" | "required" | "forbidden" | undefined;
72
+ taskSupport?: "forbidden" | "optional" | "required" | undefined;
74
73
  } | undefined;
75
74
  _meta?: {
76
75
  [x: string]: unknown;
@@ -79,13 +78,14 @@ export declare function handleToolsList(): {
79
78
  src: string;
80
79
  mimeType?: string | undefined;
81
80
  sizes?: string[] | undefined;
82
- theme?: "light" | "dark" | undefined;
81
+ theme?: "dark" | "light" | undefined;
83
82
  }[] | undefined;
83
+ name: string;
84
84
  title?: string | undefined;
85
85
  }[];
86
86
  };
87
87
  /**
88
- * Create the h3 application with all routes
88
+ * Create the H3 application with all routes
89
89
  */
90
- export declare function createHttpApp(): App;
90
+ export declare function createHttpApp(): H3;
91
91
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAOL,KAAK,GAAG,EACT,MAAM,IAAI,CAAC;AAgBZ;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,MAAM,GAAG,MAAM,GAAG,IAAW;;;;;;;EAM5F;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,GAAE,MAAM,GAAG,MAAM,GAAG,IAAW;;;;EAMhF;AAED;;GAEG;AACH,wBAAgB,gBAAgB;;;;;;;;;;;EAa/B;AAED;;GAEG;AACH,wBAAgB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE9B;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,GAAG,CA0LnC"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,EAAE,EAA+B,MAAM,IAAI,CAAC;AAgBrD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,MAAM,GAAG,MAAM,GAAG,IAAW;;;;;;;EAM5F;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,GAAE,MAAM,GAAG,MAAM,GAAG,IAAW;;;;EAMhF;AAED;;GAEG;AACH,wBAAgB,gBAAgB;;;;;;;;;;;EAa/B;AAED;;GAEG;AACH,wBAAgB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE9B;AAWD;;GAEG;AACH,wBAAgB,aAAa,IAAI,EAAE,CA0LlC"}
package/dist/http.js CHANGED
@@ -1,10 +1,9 @@
1
- import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-zLvx5_bN.js";
2
- import { t as executeToolWithCredentials } from "./handlers-CzOijI7B.js";
3
- import "./handlers.js";
1
+ import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-BFw4junA.js";
2
+ import { t as executeToolWithCredentials } from "./handlers-t95fhdps.js";
4
3
  import { TOOLS } from "./tools.js";
5
4
  import { parseAuthHeader } from "./auth.js";
6
5
  import { authorizeGetHandler, authorizePostHandler, oauthMetadataHandler, registerHandler, tokenHandler } from "./oauth.js";
7
- import { createApp, createRouter, defineEventHandler, getHeader, readBody, setResponseHeader } from "h3";
6
+ import { H3, defineHandler } from "h3";
8
7
  /**
9
8
  * HTTP transport handlers for Productive MCP Server
10
9
  *
@@ -58,21 +57,26 @@ function handleToolsList() {
58
57
  return { tools: TOOLS };
59
58
  }
60
59
  /**
61
- * Create the h3 application with all routes
60
+ * Get base URL from event headers
61
+ */
62
+ function getBaseUrl(event) {
63
+ const host = event.req.headers.get("host") || "localhost:3000";
64
+ return `${event.req.headers.get("x-forwarded-proto") || "http"}://${host}`;
65
+ }
66
+ /**
67
+ * Create the H3 application with all routes
62
68
  */
63
69
  function createHttpApp() {
64
- const app = createApp();
65
- const router = createRouter();
66
- router.get("/.well-known/oauth-authorization-server", oauthMetadataHandler);
67
- router.post("/register", registerHandler);
68
- router.get("/authorize", authorizeGetHandler);
69
- router.post("/authorize", authorizePostHandler);
70
- router.post("/token", tokenHandler);
71
- router.get("/.well-known/oauth-protected-resource", defineEventHandler((event) => {
72
- const host = event.node.req.headers.host || "localhost:3000";
73
- const baseUrl = `${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`;
74
- setResponseHeader(event, "Content-Type", "application/json");
75
- setResponseHeader(event, "Cache-Control", "public, max-age=3600");
70
+ const app = new H3();
71
+ app.get("/.well-known/oauth-authorization-server", oauthMetadataHandler);
72
+ app.post("/register", registerHandler);
73
+ app.get("/authorize", authorizeGetHandler);
74
+ app.post("/authorize", authorizePostHandler);
75
+ app.post("/token", tokenHandler);
76
+ app.get("/.well-known/oauth-protected-resource", defineHandler((event) => {
77
+ const baseUrl = getBaseUrl(event);
78
+ event.res.headers.set("Content-Type", "application/json");
79
+ event.res.headers.set("Cache-Control", "public, max-age=3600");
76
80
  return {
77
81
  resource: `${baseUrl}/mcp`,
78
82
  authorization_servers: [baseUrl],
@@ -80,36 +84,35 @@ function createHttpApp() {
80
84
  bearer_methods_supported: ["header"]
81
85
  };
82
86
  }));
83
- router.get("/", defineEventHandler(() => {
87
+ app.get("/", defineHandler(() => {
84
88
  return {
85
89
  status: "ok",
86
90
  service: "productive-mcp",
87
91
  version: VERSION
88
92
  };
89
93
  }));
90
- router.get("/health", defineEventHandler(() => {
94
+ app.get("/health", defineHandler(() => {
91
95
  return { status: "ok" };
92
96
  }));
93
- router.post("/mcp", defineEventHandler(async (event) => {
94
- const credentials = parseAuthHeader(getHeader(event, "authorization"));
97
+ app.post("/mcp", defineHandler(async (event) => {
98
+ const credentials = parseAuthHeader(event.req.headers.get("authorization"));
95
99
  if (!credentials) {
96
- const host = event.node.req.headers.host || "localhost:3000";
97
- const baseUrl = `${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`;
98
- setResponseHeader(event, "Content-Type", "application/json");
99
- setResponseHeader(event, "WWW-Authenticate", `Bearer resource_metadata="${baseUrl}/.well-known/oauth-protected-resource"`);
100
- event.node.res.statusCode = 401;
100
+ const baseUrl = getBaseUrl(event);
101
+ event.res.headers.set("Content-Type", "application/json");
102
+ event.res.headers.set("WWW-Authenticate", `Bearer resource_metadata="${baseUrl}/.well-known/oauth-protected-resource"`);
103
+ event.res.status = 401;
101
104
  return jsonRpcError(-32001, "Authentication required. Provide Bearer token with base64(organizationId:apiToken:userId)");
102
105
  }
103
- setResponseHeader(event, "Content-Type", "application/json");
106
+ event.res.headers.set("Content-Type", "application/json");
104
107
  let body;
105
108
  try {
106
- body = await readBody(event);
109
+ body = await event.req.json();
107
110
  } catch {
108
- event.node.res.statusCode = 400;
111
+ event.res.status = 400;
109
112
  return jsonRpcError(-32700, "Parse error: Invalid JSON");
110
113
  }
111
114
  if (!body || typeof body !== "object") {
112
- event.node.res.statusCode = 400;
115
+ event.res.status = 400;
113
116
  return jsonRpcError(-32700, "Parse error: Invalid JSON");
114
117
  }
115
118
  const { method, params, id } = body;
@@ -132,27 +135,34 @@ function createHttpApp() {
132
135
  return jsonRpcError(-32603, `Internal error: ${error instanceof Error ? error.message : String(error)}`, id ?? null);
133
136
  }
134
137
  }));
135
- router.get("/mcp/sse", defineEventHandler(async (event) => {
136
- if (!parseAuthHeader(getHeader(event, "authorization"))) {
137
- const host = event.node.req.headers.host || "localhost:3000";
138
- setResponseHeader(event, "WWW-Authenticate", `Bearer resource_metadata="${`${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`}/.well-known/oauth-protected-resource"`);
139
- event.node.res.statusCode = 401;
138
+ app.get("/mcp/sse", defineHandler(async (event) => {
139
+ if (!parseAuthHeader(event.req.headers.get("authorization"))) {
140
+ const baseUrl = getBaseUrl(event);
141
+ event.res.headers.set("WWW-Authenticate", `Bearer resource_metadata="${baseUrl}/.well-known/oauth-protected-resource"`);
142
+ event.res.status = 401;
140
143
  return { error: "Authentication required" };
141
144
  }
142
- setResponseHeader(event, "Content-Type", "text/event-stream");
143
- setResponseHeader(event, "Cache-Control", "no-cache");
144
- setResponseHeader(event, "Connection", "keep-alive");
145
+ const nodeRuntime = event.runtime?.node;
146
+ const nodeRes = nodeRuntime?.res;
147
+ if (!nodeRes) {
148
+ event.res.status = 501;
149
+ return { error: "SSE requires Node.js runtime" };
150
+ }
151
+ nodeRes.writeHead(200, {
152
+ "Content-Type": "text/event-stream",
153
+ "Cache-Control": "no-cache",
154
+ Connection: "keep-alive"
155
+ });
145
156
  const sessionId = crypto.randomUUID();
146
- event.node.res.write(`event: session\ndata: ${JSON.stringify({ sessionId })}\n\n`);
157
+ nodeRes.write(`event: session\ndata: ${JSON.stringify({ sessionId })}\n\n`);
147
158
  const keepAlive = setInterval(() => {
148
- event.node.res.write(": keepalive\n\n");
159
+ nodeRes.write(": keepalive\n\n");
149
160
  }, 3e4);
150
- event.node.req.on("close", () => {
161
+ nodeRuntime?.req.on("close", () => {
151
162
  clearInterval(keepAlive);
152
163
  });
153
164
  return new Promise(() => {});
154
165
  }));
155
- app.use(router);
156
166
  return app;
157
167
  }
158
168
  export { createHttpApp, handleInitialize, handleToolsList, jsonRpcError, jsonRpcSuccess };
package/dist/http.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","names":[],"sources":["../src/http.ts"],"sourcesContent":["/**\n * HTTP transport handlers for Productive MCP Server\n *\n * This module contains the app/router creation logic for the HTTP transport.\n * The actual server startup is in server.ts.\n */\n\nimport {\n createApp,\n createRouter,\n defineEventHandler,\n readBody,\n getHeader,\n setResponseHeader,\n type App,\n} from 'h3';\n\nimport { parseAuthHeader } from './auth.js';\nimport { executeToolWithCredentials } from './handlers.js';\nimport { INSTRUCTIONS } from './instructions.js';\nimport {\n oauthMetadataHandler,\n registerHandler,\n authorizeGetHandler,\n authorizePostHandler,\n tokenHandler,\n} from './oauth.js';\nimport { listResources, listResourceTemplates, readResource } from './resources.js';\nimport { TOOLS } from './tools.js';\nimport { VERSION } from './version.js';\n\n/**\n * JSON-RPC error response\n */\nexport function jsonRpcError(code: number, message: string, id: string | number | null = null) {\n return {\n jsonrpc: '2.0',\n error: { code, message },\n id,\n };\n}\n\n/**\n * JSON-RPC success response\n */\nexport function jsonRpcSuccess(result: unknown, id: string | number | null = null) {\n return {\n jsonrpc: '2.0',\n result,\n id,\n };\n}\n\n/**\n * Handle the initialize JSON-RPC method\n */\nexport function handleInitialize() {\n return {\n protocolVersion: '2024-11-05',\n serverInfo: {\n name: 'productive-mcp',\n version: VERSION,\n },\n capabilities: {\n tools: {},\n resources: {},\n },\n instructions: INSTRUCTIONS,\n };\n}\n\n/**\n * Handle the tools/list JSON-RPC method\n */\nexport function handleToolsList() {\n return { tools: TOOLS };\n}\n\n/**\n * Create the h3 application with all routes\n */\nexport function createHttpApp(): App {\n const app = createApp();\n const router = createRouter();\n\n // OAuth 2.0 endpoints for Claude Desktop integration (MCP auth spec)\n router.get('/.well-known/oauth-authorization-server', oauthMetadataHandler);\n router.post('/register', registerHandler); // Dynamic Client Registration (RFC 7591)\n router.get('/authorize', authorizeGetHandler);\n router.post('/authorize', authorizePostHandler);\n router.post('/token', tokenHandler);\n\n // OAuth Protected Resource Metadata (RFC 9728 / MCP spec 2025-03-26)\n // This endpoint tells clients where to find the authorization server\n router.get(\n '/.well-known/oauth-protected-resource',\n defineEventHandler((event) => {\n const host = event.node.req.headers.host || 'localhost:3000';\n const protocol = event.node.req.headers['x-forwarded-proto'] || 'http';\n const baseUrl = `${protocol}://${host}`;\n\n setResponseHeader(event, 'Content-Type', 'application/json');\n setResponseHeader(event, 'Cache-Control', 'public, max-age=3600');\n\n return {\n resource: `${baseUrl}/mcp`,\n authorization_servers: [baseUrl],\n scopes_supported: ['productive'],\n bearer_methods_supported: ['header'],\n };\n }),\n );\n\n // Health check endpoint\n router.get(\n '/',\n defineEventHandler(() => {\n return { status: 'ok', service: 'productive-mcp', version: VERSION };\n }),\n );\n\n router.get(\n '/health',\n defineEventHandler(() => {\n return { status: 'ok' };\n }),\n );\n\n // MCP endpoint - handles JSON-RPC over HTTP\n router.post(\n '/mcp',\n defineEventHandler(async (event) => {\n // Parse authorization header\n const authHeader = getHeader(event, 'authorization');\n const credentials = parseAuthHeader(authHeader);\n\n if (!credentials) {\n // RFC 6750: Return WWW-Authenticate header to trigger OAuth flow\n const host = event.node.req.headers.host || 'localhost:3000';\n const protocol = event.node.req.headers['x-forwarded-proto'] || 'http';\n const baseUrl = `${protocol}://${host}`;\n\n setResponseHeader(event, 'Content-Type', 'application/json');\n setResponseHeader(\n event,\n 'WWW-Authenticate',\n `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`,\n );\n event.node.res.statusCode = 401;\n return jsonRpcError(\n -32001,\n 'Authentication required. Provide Bearer token with base64(organizationId:apiToken:userId)',\n );\n }\n\n setResponseHeader(event, 'Content-Type', 'application/json');\n\n // Parse JSON-RPC request\n let body: { method?: string; params?: unknown; id?: string | number };\n try {\n body = await readBody(event);\n } catch {\n event.node.res.statusCode = 400;\n return jsonRpcError(-32700, 'Parse error: Invalid JSON');\n }\n\n if (!body || typeof body !== 'object') {\n event.node.res.statusCode = 400;\n return jsonRpcError(-32700, 'Parse error: Invalid JSON');\n }\n\n const { method, params, id } = body;\n\n try {\n if (method === 'initialize') {\n return jsonRpcSuccess(handleInitialize(), id ?? null);\n }\n\n if (method === 'tools/list') {\n return jsonRpcSuccess(handleToolsList(), id ?? null);\n }\n\n if (method === 'tools/call') {\n const { name, arguments: args } = params as {\n name: string;\n arguments?: Record<string, unknown>;\n };\n const result = await executeToolWithCredentials(name, args || {}, credentials);\n return jsonRpcSuccess(result, id ?? null);\n }\n\n if (method === 'resources/list') {\n return jsonRpcSuccess({ resources: listResources() }, id ?? null);\n }\n\n if (method === 'resources/templates/list') {\n return jsonRpcSuccess({ resourceTemplates: listResourceTemplates() }, id ?? null);\n }\n\n if (method === 'resources/read') {\n const { uri } = (params as { uri: string }) ?? {};\n if (!uri) {\n return jsonRpcError(-32602, 'Invalid params: uri is required', id ?? null);\n }\n const result = await readResource(uri, credentials);\n return jsonRpcSuccess(result, id ?? null);\n }\n\n // Unknown method\n return jsonRpcError(-32601, `Method not found: ${method}`, id ?? null);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return jsonRpcError(-32603, `Internal error: ${message}`, id ?? null);\n }\n }),\n );\n\n // SSE endpoint for server-sent events (optional, for streaming responses)\n router.get(\n '/mcp/sse',\n defineEventHandler(async (event) => {\n const authHeader = getHeader(event, 'authorization');\n const credentials = parseAuthHeader(authHeader);\n\n if (!credentials) {\n // RFC 6750: Return WWW-Authenticate header to trigger OAuth flow\n const host = event.node.req.headers.host || 'localhost:3000';\n const protocol = event.node.req.headers['x-forwarded-proto'] || 'http';\n const baseUrl = `${protocol}://${host}`;\n\n setResponseHeader(\n event,\n 'WWW-Authenticate',\n `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`,\n );\n event.node.res.statusCode = 401;\n return { error: 'Authentication required' };\n }\n\n // Set SSE headers\n setResponseHeader(event, 'Content-Type', 'text/event-stream');\n setResponseHeader(event, 'Cache-Control', 'no-cache');\n setResponseHeader(event, 'Connection', 'keep-alive');\n\n // Generate session ID and send it\n const sessionId = crypto.randomUUID();\n\n // Send initial session event\n event.node.res.write(`event: session\\ndata: ${JSON.stringify({ sessionId })}\\n\\n`);\n\n // Keep connection alive\n const keepAlive = setInterval(() => {\n event.node.res.write(': keepalive\\n\\n');\n }, 30000);\n\n // Clean up on close\n event.node.req.on('close', () => {\n clearInterval(keepAlive);\n });\n\n // Don't end the response - keep it open for SSE\n return new Promise(() => {});\n }),\n );\n\n app.use(router);\n return app;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"http.js","names":[],"sources":["../src/http.ts"],"sourcesContent":["/**\n * HTTP transport handlers for Productive MCP Server\n *\n * This module contains the app/router creation logic for the HTTP transport.\n * The actual server startup is in server.ts.\n */\n\nimport { H3, defineHandler, type H3Event } from 'h3';\n\nimport { parseAuthHeader } from './auth.js';\nimport { executeToolWithCredentials } from './handlers.js';\nimport { INSTRUCTIONS } from './instructions.js';\nimport {\n oauthMetadataHandler,\n registerHandler,\n authorizeGetHandler,\n authorizePostHandler,\n tokenHandler,\n} from './oauth.js';\nimport { listResources, listResourceTemplates, readResource } from './resources.js';\nimport { TOOLS } from './tools.js';\nimport { VERSION } from './version.js';\n\n/**\n * JSON-RPC error response\n */\nexport function jsonRpcError(code: number, message: string, id: string | number | null = null) {\n return {\n jsonrpc: '2.0',\n error: { code, message },\n id,\n };\n}\n\n/**\n * JSON-RPC success response\n */\nexport function jsonRpcSuccess(result: unknown, id: string | number | null = null) {\n return {\n jsonrpc: '2.0',\n result,\n id,\n };\n}\n\n/**\n * Handle the initialize JSON-RPC method\n */\nexport function handleInitialize() {\n return {\n protocolVersion: '2024-11-05',\n serverInfo: {\n name: 'productive-mcp',\n version: VERSION,\n },\n capabilities: {\n tools: {},\n resources: {},\n },\n instructions: INSTRUCTIONS,\n };\n}\n\n/**\n * Handle the tools/list JSON-RPC method\n */\nexport function handleToolsList() {\n return { tools: TOOLS };\n}\n\n/**\n * Get base URL from event headers\n */\nfunction getBaseUrl(event: H3Event): string {\n const host = event.req.headers.get('host') || 'localhost:3000';\n const protocol = event.req.headers.get('x-forwarded-proto') || 'http';\n return `${protocol}://${host}`;\n}\n\n/**\n * Create the H3 application with all routes\n */\nexport function createHttpApp(): H3 {\n const app = new H3();\n\n // OAuth 2.0 endpoints for Claude Desktop integration (MCP auth spec)\n app.get('/.well-known/oauth-authorization-server', oauthMetadataHandler);\n app.post('/register', registerHandler); // Dynamic Client Registration (RFC 7591)\n app.get('/authorize', authorizeGetHandler);\n app.post('/authorize', authorizePostHandler);\n app.post('/token', tokenHandler);\n\n // OAuth Protected Resource Metadata (RFC 9728 / MCP spec 2025-03-26)\n // This endpoint tells clients where to find the authorization server\n app.get(\n '/.well-known/oauth-protected-resource',\n defineHandler((event) => {\n const baseUrl = getBaseUrl(event);\n\n event.res.headers.set('Content-Type', 'application/json');\n event.res.headers.set('Cache-Control', 'public, max-age=3600');\n\n return {\n resource: `${baseUrl}/mcp`,\n authorization_servers: [baseUrl],\n scopes_supported: ['productive'],\n bearer_methods_supported: ['header'],\n };\n }),\n );\n\n // Health check endpoint\n app.get(\n '/',\n defineHandler(() => {\n return { status: 'ok', service: 'productive-mcp', version: VERSION };\n }),\n );\n\n app.get(\n '/health',\n defineHandler(() => {\n return { status: 'ok' };\n }),\n );\n\n // MCP endpoint - handles JSON-RPC over HTTP\n app.post(\n '/mcp',\n defineHandler(async (event) => {\n // Parse authorization header\n const authHeader = event.req.headers.get('authorization');\n const credentials = parseAuthHeader(authHeader);\n\n if (!credentials) {\n // RFC 6750: Return WWW-Authenticate header to trigger OAuth flow\n const baseUrl = getBaseUrl(event);\n\n event.res.headers.set('Content-Type', 'application/json');\n event.res.headers.set(\n 'WWW-Authenticate',\n `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`,\n );\n event.res.status = 401;\n return jsonRpcError(\n -32001,\n 'Authentication required. Provide Bearer token with base64(organizationId:apiToken:userId)',\n );\n }\n\n event.res.headers.set('Content-Type', 'application/json');\n\n // Parse JSON-RPC request\n let body: { method?: string; params?: unknown; id?: string | number } | undefined;\n try {\n body = await event.req.json();\n } catch {\n event.res.status = 400;\n return jsonRpcError(-32700, 'Parse error: Invalid JSON');\n }\n\n if (!body || typeof body !== 'object') {\n event.res.status = 400;\n return jsonRpcError(-32700, 'Parse error: Invalid JSON');\n }\n\n const { method, params, id } = body;\n\n try {\n if (method === 'initialize') {\n return jsonRpcSuccess(handleInitialize(), id ?? null);\n }\n\n if (method === 'tools/list') {\n return jsonRpcSuccess(handleToolsList(), id ?? null);\n }\n\n if (method === 'tools/call') {\n const { name, arguments: args } = params as {\n name: string;\n arguments?: Record<string, unknown>;\n };\n const result = await executeToolWithCredentials(name, args || {}, credentials);\n return jsonRpcSuccess(result, id ?? null);\n }\n\n if (method === 'resources/list') {\n return jsonRpcSuccess({ resources: listResources() }, id ?? null);\n }\n\n if (method === 'resources/templates/list') {\n return jsonRpcSuccess({ resourceTemplates: listResourceTemplates() }, id ?? null);\n }\n\n if (method === 'resources/read') {\n const { uri } = (params as { uri: string }) ?? {};\n if (!uri) {\n return jsonRpcError(-32602, 'Invalid params: uri is required', id ?? null);\n }\n const result = await readResource(uri, credentials);\n return jsonRpcSuccess(result, id ?? null);\n }\n\n // Unknown method\n return jsonRpcError(-32601, `Method not found: ${method}`, id ?? null);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return jsonRpcError(-32603, `Internal error: ${message}`, id ?? null);\n }\n }),\n );\n\n // SSE endpoint for server-sent events (optional, for streaming responses)\n app.get(\n '/mcp/sse',\n defineHandler(async (event) => {\n const authHeader = event.req.headers.get('authorization');\n const credentials = parseAuthHeader(authHeader);\n\n if (!credentials) {\n // RFC 6750: Return WWW-Authenticate header to trigger OAuth flow\n const baseUrl = getBaseUrl(event);\n\n event.res.headers.set(\n 'WWW-Authenticate',\n `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`,\n );\n event.res.status = 401;\n return { error: 'Authentication required' };\n }\n\n // Node.js-specific SSE: access raw res for streaming\n const nodeRuntime = event.runtime?.node;\n const nodeRes = nodeRuntime?.res as import('node:http').ServerResponse | undefined;\n if (!nodeRes) {\n event.res.status = 501;\n return { error: 'SSE requires Node.js runtime' };\n }\n\n // Write SSE headers directly to Node.js response (bypassing h3's pipeline)\n nodeRes.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n // Generate session ID and send it\n const sessionId = crypto.randomUUID();\n\n // Send initial session event\n nodeRes.write(`event: session\\ndata: ${JSON.stringify({ sessionId })}\\n\\n`);\n\n // Keep connection alive\n const keepAlive = setInterval(() => {\n nodeRes.write(': keepalive\\n\\n');\n }, 30000);\n\n // Clean up on close\n nodeRuntime?.req.on('close', () => {\n clearInterval(keepAlive);\n });\n\n // Don't end the response - keep it open for SSE\n return new Promise(() => {});\n }),\n );\n\n return app;\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-zLvx5_bN.js";
3
- import "./handlers-CzOijI7B.js";
4
- import { getAvailablePrompts, getAvailableTools, handlePrompt, handleToolCall } from "./stdio.js";
2
+ import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-BFw4junA.js";
3
+ import "./handlers-t95fhdps.js";
4
+ import { a as handlePrompt, n as getAvailableTools, s as handleToolCall, t as getAvailablePrompts } from "./stdio-Bi1Lvp8O.js";
5
5
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
7
  import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
package/dist/oauth.d.ts CHANGED
@@ -20,7 +20,7 @@
20
20
  *
21
21
  * MCP clients MUST check this endpoint first for server capabilities.
22
22
  */
23
- export declare const oauthMetadataHandler: import("h3").EventHandler<import("h3").EventHandlerRequest, {
23
+ export declare const oauthMetadataHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, {
24
24
  issuer: string;
25
25
  authorization_endpoint: string;
26
26
  token_endpoint: string;
@@ -40,7 +40,7 @@ export declare const oauthMetadataHandler: import("h3").EventHandler<import("h3"
40
40
  * Since we use stateless tokens, we accept any registration and return
41
41
  * a generated client_id.
42
42
  */
43
- export declare const registerHandler: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
43
+ export declare const registerHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
44
44
  error: string;
45
45
  error_description: string;
46
46
  client_id?: undefined;
@@ -50,25 +50,25 @@ export declare const registerHandler: import("h3").EventHandler<import("h3").Eve
50
50
  grant_types?: undefined;
51
51
  response_types?: undefined;
52
52
  } | {
53
+ error?: undefined;
54
+ error_description?: undefined;
53
55
  client_id: string;
54
56
  client_name: string;
55
57
  redirect_uris: string[];
56
58
  token_endpoint_auth_method: string;
57
59
  grant_types: string[];
58
60
  response_types: string[];
59
- error?: undefined;
60
- error_description?: undefined;
61
61
  }>>;
62
62
  /**
63
63
  * Authorization endpoint - shows login form
64
64
  * GET /authorize
65
65
  */
66
- export declare const authorizeGetHandler: import("h3").EventHandler<import("h3").EventHandlerRequest, string | Promise<void>>;
66
+ export declare const authorizeGetHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, string | import("h3").HTTPResponse>;
67
67
  /**
68
68
  * Authorization endpoint - process login
69
69
  * POST /authorize
70
70
  */
71
- export declare const authorizePostHandler: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string>>;
71
+ export declare const authorizePostHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<string>>;
72
72
  /**
73
73
  * Token endpoint - exchange code for access token
74
74
  * POST /token
@@ -77,7 +77,7 @@ export declare const authorizePostHandler: import("h3").EventHandler<import("h3"
77
77
  * - authorization_code grant (with PKCE validation)
78
78
  * - refresh_token grant
79
79
  */
80
- export declare const tokenHandler: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
80
+ export declare const tokenHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
81
81
  error: string;
82
82
  error_description: string;
83
83
  access_token?: undefined;
@@ -85,11 +85,11 @@ export declare const tokenHandler: import("h3").EventHandler<import("h3").EventH
85
85
  expires_in?: undefined;
86
86
  refresh_token?: undefined;
87
87
  } | {
88
+ error?: undefined;
89
+ error_description?: undefined;
88
90
  access_token: string;
89
91
  token_type: string;
90
92
  expires_in: number;
91
93
  refresh_token: string;
92
- error?: undefined;
93
- error_description?: undefined;
94
94
  }>>;
95
95
  //# sourceMappingURL=oauth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAeH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;EAyB/B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;GAoC1B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,mBAAmB,qFA+C9B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,8EAyD/B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;GA+FvB,CAAC"}
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAQH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;EAyB/B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;GAoC1B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,mBAAmB,0GA+C9B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,uFA0D/B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;GA2FvB,CAAC"}
package/dist/oauth.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createAuthToken } from "./auth.js";
2
2
  import { createAuthCode, decodeAuthCode } from "./crypto.js";
3
- import { defineEventHandler, getQuery, readBody, sendRedirect, setResponseHeader } from "h3";
3
+ import { defineHandler, getQuery, redirect } from "h3";
4
4
  import { createHash } from "node:crypto";
5
5
  /**
6
6
  * OAuth 2.0 endpoints for Claude Desktop integration
@@ -24,11 +24,11 @@ import { createHash } from "node:crypto";
24
24
  *
25
25
  * MCP clients MUST check this endpoint first for server capabilities.
26
26
  */
27
- const oauthMetadataHandler = defineEventHandler((event) => {
28
- const host = event.node.req.headers.host || "localhost:3000";
29
- const baseUrl = `${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`;
30
- setResponseHeader(event, "Content-Type", "application/json");
31
- setResponseHeader(event, "Cache-Control", "public, max-age=3600");
27
+ const oauthMetadataHandler = defineHandler((event) => {
28
+ const host = event.req.headers.get("host") || "localhost:3000";
29
+ const baseUrl = `${event.req.headers.get("x-forwarded-proto") || "http"}://${host}`;
30
+ event.res.headers.set("Content-Type", "application/json");
31
+ event.res.headers.set("Cache-Control", "public, max-age=3600");
32
32
  return {
33
33
  issuer: baseUrl,
34
34
  authorization_endpoint: `${baseUrl}/authorize`,
@@ -50,13 +50,13 @@ const oauthMetadataHandler = defineEventHandler((event) => {
50
50
  * Since we use stateless tokens, we accept any registration and return
51
51
  * a generated client_id.
52
52
  */
53
- const registerHandler = defineEventHandler(async (event) => {
54
- setResponseHeader(event, "Content-Type", "application/json");
53
+ const registerHandler = defineHandler(async (event) => {
54
+ event.res.headers.set("Content-Type", "application/json");
55
55
  let body;
56
56
  try {
57
- body = await readBody(event);
57
+ body = await event.req.json();
58
58
  } catch {
59
- event.node.res.statusCode = 400;
59
+ event.res.status = 400;
60
60
  return {
61
61
  error: "invalid_request",
62
62
  error_description: "Invalid JSON body"
@@ -68,7 +68,7 @@ const registerHandler = defineEventHandler(async (event) => {
68
68
  name: clientName,
69
69
  ts: Date.now()
70
70
  })).toString("base64url");
71
- event.node.res.statusCode = 201;
71
+ event.res.status = 201;
72
72
  return {
73
73
  client_id: clientId,
74
74
  client_name: clientName,
@@ -82,7 +82,7 @@ const registerHandler = defineEventHandler(async (event) => {
82
82
  * Authorization endpoint - shows login form
83
83
  * GET /authorize
84
84
  */
85
- const authorizeGetHandler = defineEventHandler((event) => {
85
+ const authorizeGetHandler = defineHandler((event) => {
86
86
  const query = getQuery(event);
87
87
  const clientId = query.client_id;
88
88
  const redirectUri = query.redirect_uri;
@@ -91,8 +91,8 @@ const authorizeGetHandler = defineEventHandler((event) => {
91
91
  const codeChallengeMethod = query.code_challenge_method;
92
92
  const scope = query.scope;
93
93
  if (!redirectUri) {
94
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
95
- event.node.res.statusCode = 400;
94
+ event.res.headers.set("Content-Type", "text/html; charset=utf-8");
95
+ event.res.status = 400;
96
96
  return renderErrorPage("Missing required parameter: redirect_uri");
97
97
  }
98
98
  if (!codeChallenge) {
@@ -100,16 +100,16 @@ const authorizeGetHandler = defineEventHandler((event) => {
100
100
  errorUrl.searchParams.set("error", "invalid_request");
101
101
  errorUrl.searchParams.set("error_description", "code_challenge is required");
102
102
  if (state) errorUrl.searchParams.set("state", state);
103
- return sendRedirect(event, errorUrl.toString());
103
+ return redirect(errorUrl.toString());
104
104
  }
105
105
  if (codeChallengeMethod && codeChallengeMethod !== "S256") {
106
106
  const errorUrl = new URL(redirectUri);
107
107
  errorUrl.searchParams.set("error", "invalid_request");
108
108
  errorUrl.searchParams.set("error_description", "Only S256 code_challenge_method is supported");
109
109
  if (state) errorUrl.searchParams.set("state", state);
110
- return sendRedirect(event, errorUrl.toString());
110
+ return redirect(errorUrl.toString());
111
111
  }
112
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
112
+ event.res.headers.set("Content-Type", "text/html; charset=utf-8");
113
113
  return renderLoginForm({
114
114
  clientId,
115
115
  redirectUri,
@@ -123,11 +123,12 @@ const authorizeGetHandler = defineEventHandler((event) => {
123
123
  * Authorization endpoint - process login
124
124
  * POST /authorize
125
125
  */
126
- const authorizePostHandler = defineEventHandler(async (event) => {
127
- const { orgId, apiToken, userId, redirectUri, state, codeChallenge, codeChallengeMethod } = await readBody(event);
126
+ const authorizePostHandler = defineHandler(async (event) => {
127
+ const formData = await event.req.formData();
128
+ const { orgId, apiToken, userId, redirectUri, state, codeChallenge, codeChallengeMethod } = Object.fromEntries(formData.entries());
128
129
  if (!redirectUri) {
129
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
130
- event.node.res.statusCode = 400;
130
+ event.res.headers.set("Content-Type", "text/html; charset=utf-8");
131
+ event.res.status = 400;
131
132
  return renderErrorPage("Missing redirect_uri parameter");
132
133
  }
133
134
  try {
@@ -135,15 +136,15 @@ const authorizePostHandler = defineEventHandler(async (event) => {
135
136
  const isLocalhost = uri.hostname === "localhost" || uri.hostname === "127.0.0.1";
136
137
  const isHttps = uri.protocol === "https:";
137
138
  if (!isLocalhost && !isHttps) {
138
- event.node.res.statusCode = 400;
139
+ event.res.status = 400;
139
140
  return renderErrorPage("redirect_uri must be HTTPS or localhost");
140
141
  }
141
142
  } catch {
142
- event.node.res.statusCode = 400;
143
+ event.res.status = 400;
143
144
  return renderErrorPage("Invalid redirect_uri format");
144
145
  }
145
146
  if (!orgId || !apiToken) {
146
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
147
+ event.res.headers.set("Content-Type", "text/html; charset=utf-8");
147
148
  return renderLoginForm({
148
149
  redirectUri,
149
150
  state,
@@ -162,7 +163,7 @@ const authorizePostHandler = defineEventHandler(async (event) => {
162
163
  const redirectUrl = new URL(redirectUri);
163
164
  redirectUrl.searchParams.set("code", code);
164
165
  if (state) redirectUrl.searchParams.set("state", state);
165
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
166
+ event.res.headers.set("Content-Type", "text/html; charset=utf-8");
166
167
  return renderSuccessPage(redirectUrl.toString());
167
168
  });
168
169
  /**
@@ -173,32 +174,31 @@ const authorizePostHandler = defineEventHandler(async (event) => {
173
174
  * - authorization_code grant (with PKCE validation)
174
175
  * - refresh_token grant
175
176
  */
176
- const tokenHandler = defineEventHandler(async (event) => {
177
- setResponseHeader(event, "Content-Type", "application/json");
177
+ const tokenHandler = defineHandler(async (event) => {
178
+ event.res.headers.set("Content-Type", "application/json");
178
179
  let body;
179
- if ((event.node.req.headers["content-type"] || "").includes("application/x-www-form-urlencoded")) {
180
- const rawBody = await readBody(event);
181
- if (typeof rawBody === "string") body = Object.fromEntries(new URLSearchParams(rawBody));
182
- else body = rawBody;
183
- } else body = await readBody(event);
180
+ if ((event.req.headers.get("content-type") || "").includes("application/x-www-form-urlencoded")) {
181
+ const rawText = await event.req.text();
182
+ body = Object.fromEntries(new URLSearchParams(rawText));
183
+ } else body = await event.req.json();
184
184
  const { grant_type, code, code_verifier, refresh_token } = body;
185
185
  if (grant_type === "refresh_token") return handleRefreshToken(event, refresh_token);
186
186
  if (grant_type !== "authorization_code") {
187
- event.node.res.statusCode = 400;
187
+ event.res.status = 400;
188
188
  return {
189
189
  error: "unsupported_grant_type",
190
190
  error_description: "Supported grant types: authorization_code, refresh_token"
191
191
  };
192
192
  }
193
193
  if (!code) {
194
- event.node.res.statusCode = 400;
194
+ event.res.status = 400;
195
195
  return {
196
196
  error: "invalid_request",
197
197
  error_description: "Missing authorization code"
198
198
  };
199
199
  }
200
200
  if (!code_verifier) {
201
- event.node.res.statusCode = 400;
201
+ event.res.status = 400;
202
202
  return {
203
203
  error: "invalid_request",
204
204
  error_description: "Missing code_verifier (PKCE required)"
@@ -208,7 +208,7 @@ const tokenHandler = defineEventHandler(async (event) => {
208
208
  const payload = decodeAuthCode(code);
209
209
  if (payload.codeChallenge) {
210
210
  if (createS256Challenge(code_verifier) !== payload.codeChallenge) {
211
- event.node.res.statusCode = 400;
211
+ event.res.status = 400;
212
212
  return {
213
213
  error: "invalid_grant",
214
214
  error_description: "Invalid code_verifier"
@@ -230,7 +230,7 @@ const tokenHandler = defineEventHandler(async (event) => {
230
230
  }, 86400 * 30)
231
231
  };
232
232
  } catch (error) {
233
- event.node.res.statusCode = 400;
233
+ event.res.status = 400;
234
234
  return {
235
235
  error: "invalid_grant",
236
236
  error_description: error instanceof Error ? error.message : "Invalid authorization code"
@@ -242,7 +242,7 @@ const tokenHandler = defineEventHandler(async (event) => {
242
242
  */
243
243
  function handleRefreshToken(event, refreshToken) {
244
244
  if (!refreshToken) {
245
- event.node.res.statusCode = 400;
245
+ event.res.status = 400;
246
246
  return {
247
247
  error: "invalid_request",
248
248
  error_description: "Missing refresh_token"
@@ -265,7 +265,7 @@ function handleRefreshToken(event, refreshToken) {
265
265
  }, 86400 * 30)
266
266
  };
267
267
  } catch (error) {
268
- event.node.res.statusCode = 400;
268
+ event.res.status = 400;
269
269
  return {
270
270
  error: "invalid_grant",
271
271
  error_description: error instanceof Error ? error.message : "Invalid refresh token"