@usebetterdev/console 0.3.0-beta.2

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hono.ts","../src/hono/middleware.ts"],"sourcesContent":["export { createConsoleMiddleware } from \"./hono/middleware.js\";\nexport type {\n ConsoleMiddleware,\n CreateConsoleMiddlewareOptions,\n HonoConsoleLike,\n HonoContextLike,\n} from \"./hono/middleware.js\";\n","import type {\n ConsoleRequest,\n ConsoleResponse,\n} from \"../types.js\";\n\n/**\n * Duck-typed Hono context — no tight coupling to the hono package.\n * Matches Hono's Context shape for the fields we need.\n */\nexport interface HonoContextLike {\n req: { raw: Request; url: string; method: string };\n}\n\n/**\n * Structural subset of BetterConsoleInstance needed by the middleware.\n * The middleware is a thin adapter — all routing, auth, CORS, and error\n * handling live inside handleConsoleRequest.\n */\nexport interface HonoConsoleLike {\n handleConsoleRequest(request: ConsoleRequest): Promise<ConsoleResponse>;\n}\n\nexport interface CreateConsoleMiddlewareOptions {\n /** Base path for console routes. Default: \"/.well-known/better\" */\n basePath?: string;\n}\n\nexport type ConsoleMiddleware = (\n context: HonoContextLike,\n next: () => Promise<void>,\n) => Promise<Response | void>;\n\nasync function parseBody(request: Request): Promise<unknown> {\n const contentType = request.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n try {\n return await request.json();\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction toConsoleRequest(\n raw: Request,\n url: URL,\n basePath: string,\n body: unknown,\n): ConsoleRequest {\n const path = url.pathname.slice(basePath.length);\n\n return {\n method: raw.method,\n path,\n url: raw.url,\n headers: raw.headers,\n // Last value wins for duplicate keys — intentional for console APIs\n query: Object.fromEntries(url.searchParams),\n params: {},\n body,\n };\n}\n\nfunction toResponse(result: ConsoleResponse): Response {\n const headers = new Headers(result.headers);\n\n // No-content responses (e.g. 204 preflight) must have null body\n if (result.status === 204 || result.body === null) {\n return new Response(null, { status: result.status, headers });\n }\n\n const contentType = headers.get(\"content-type\");\n if (contentType && !contentType.includes(\"application/json\")) {\n // Non-JSON content type: pass body through as-is if it's a string\n const responseBody =\n typeof result.body === \"string\" ? result.body : JSON.stringify(result.body);\n return new Response(responseBody, { status: result.status, headers });\n }\n\n if (!contentType) {\n headers.set(\"content-type\", \"application/json\");\n }\n return new Response(JSON.stringify(result.body), {\n status: result.status,\n headers,\n });\n}\n\n/**\n * Creates Hono middleware that intercepts `/.well-known/better/*` requests\n * and delegates them to handleConsoleRequest(). Everything else passes through.\n *\n * All routing, auth, CORS, and error handling are owned by handleConsoleRequest.\n * This middleware is a thin adapter that converts between Hono Request/Response\n * and ConsoleRequest/ConsoleResponse.\n *\n * Usage:\n * ```ts\n * import { createConsoleMiddleware } from \"@usebetterdev/console/hono\"\n * app.use(\"*\", createConsoleMiddleware(consoleInstance))\n * ```\n */\nexport function createConsoleMiddleware(\n consoleInstance: HonoConsoleLike,\n options?: CreateConsoleMiddlewareOptions,\n): ConsoleMiddleware {\n const basePath = options?.basePath ?? \"/.well-known/better\";\n\n return async (context, next) => {\n let url: URL;\n try {\n url = new URL(context.req.url);\n } catch {\n return new Response(\n JSON.stringify({ error: \"Malformed request URL\" }),\n { status: 400, headers: { \"content-type\": \"application/json\" } },\n );\n }\n\n if (!url.pathname.startsWith(basePath + \"/\")) {\n await next();\n return;\n }\n\n const body = await parseBody(context.req.raw);\n const consoleRequest = toConsoleRequest(\n context.req.raw,\n url,\n basePath,\n body,\n );\n const result = await consoleInstance.handleConsoleRequest(consoleRequest);\n return toResponse(result);\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACgCA,eAAe,UAAU,SAAoC;AAC3D,QAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc,KAAK;AAC3D,MAAI,YAAY,SAAS,kBAAkB,GAAG;AAC5C,QAAI;AACF,aAAO,MAAM,QAAQ,KAAK;AAAA,IAC5B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iBACP,KACA,KACA,UACA,MACgB;AAChB,QAAM,OAAO,IAAI,SAAS,MAAM,SAAS,MAAM;AAE/C,SAAO;AAAA,IACL,QAAQ,IAAI;AAAA,IACZ;AAAA,IACA,KAAK,IAAI;AAAA,IACT,SAAS,IAAI;AAAA;AAAA,IAEb,OAAO,OAAO,YAAY,IAAI,YAAY;AAAA,IAC1C,QAAQ,CAAC;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,WAAW,QAAmC;AACrD,QAAM,UAAU,IAAI,QAAQ,OAAO,OAAO;AAG1C,MAAI,OAAO,WAAW,OAAO,OAAO,SAAS,MAAM;AACjD,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,OAAO,QAAQ,QAAQ,CAAC;AAAA,EAC9D;AAEA,QAAM,cAAc,QAAQ,IAAI,cAAc;AAC9C,MAAI,eAAe,CAAC,YAAY,SAAS,kBAAkB,GAAG;AAE5D,UAAM,eACJ,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,KAAK,UAAU,OAAO,IAAI;AAC5E,WAAO,IAAI,SAAS,cAAc,EAAE,QAAQ,OAAO,QAAQ,QAAQ,CAAC;AAAA,EACtE;AAEA,MAAI,CAAC,aAAa;AAChB,YAAQ,IAAI,gBAAgB,kBAAkB;AAAA,EAChD;AACA,SAAO,IAAI,SAAS,KAAK,UAAU,OAAO,IAAI,GAAG;AAAA,IAC/C,QAAQ,OAAO;AAAA,IACf;AAAA,EACF,CAAC;AACH;AAgBO,SAAS,wBACd,iBACA,SACmB;AACnB,QAAM,WAAW,SAAS,YAAY;AAEtC,SAAO,OAAO,SAAS,SAAS;AAC9B,QAAI;AACJ,QAAI;AACF,YAAM,IAAI,IAAI,QAAQ,IAAI,GAAG;AAAA,IAC/B,QAAQ;AACN,aAAO,IAAI;AAAA,QACT,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC;AAAA,QACjD,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,MACjE;AAAA,IACF;AAEA,QAAI,CAAC,IAAI,SAAS,WAAW,WAAW,GAAG,GAAG;AAC5C,YAAM,KAAK;AACX;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,UAAU,QAAQ,IAAI,GAAG;AAC5C,UAAM,iBAAiB;AAAA,MACrB,QAAQ,IAAI;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,MAAM,gBAAgB,qBAAqB,cAAc;AACxE,WAAO,WAAW,MAAM;AAAA,EAC1B;AACF;","names":[]}
@@ -0,0 +1,43 @@
1
+ import { c as ConsoleRequest, d as ConsoleResponse } from './types-Bm35VBpM.cjs';
2
+
3
+ /**
4
+ * Duck-typed Hono context — no tight coupling to the hono package.
5
+ * Matches Hono's Context shape for the fields we need.
6
+ */
7
+ interface HonoContextLike {
8
+ req: {
9
+ raw: Request;
10
+ url: string;
11
+ method: string;
12
+ };
13
+ }
14
+ /**
15
+ * Structural subset of BetterConsoleInstance needed by the middleware.
16
+ * The middleware is a thin adapter — all routing, auth, CORS, and error
17
+ * handling live inside handleConsoleRequest.
18
+ */
19
+ interface HonoConsoleLike {
20
+ handleConsoleRequest(request: ConsoleRequest): Promise<ConsoleResponse>;
21
+ }
22
+ interface CreateConsoleMiddlewareOptions {
23
+ /** Base path for console routes. Default: "/.well-known/better" */
24
+ basePath?: string;
25
+ }
26
+ type ConsoleMiddleware = (context: HonoContextLike, next: () => Promise<void>) => Promise<Response | void>;
27
+ /**
28
+ * Creates Hono middleware that intercepts `/.well-known/better/*` requests
29
+ * and delegates them to handleConsoleRequest(). Everything else passes through.
30
+ *
31
+ * All routing, auth, CORS, and error handling are owned by handleConsoleRequest.
32
+ * This middleware is a thin adapter that converts between Hono Request/Response
33
+ * and ConsoleRequest/ConsoleResponse.
34
+ *
35
+ * Usage:
36
+ * ```ts
37
+ * import { createConsoleMiddleware } from "@usebetterdev/console/hono"
38
+ * app.use("*", createConsoleMiddleware(consoleInstance))
39
+ * ```
40
+ */
41
+ declare function createConsoleMiddleware(consoleInstance: HonoConsoleLike, options?: CreateConsoleMiddlewareOptions): ConsoleMiddleware;
42
+
43
+ export { type ConsoleMiddleware, type CreateConsoleMiddlewareOptions, type HonoConsoleLike, type HonoContextLike, createConsoleMiddleware };
package/dist/hono.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { c as ConsoleRequest, d as ConsoleResponse } from './types-Bm35VBpM.js';
2
+
3
+ /**
4
+ * Duck-typed Hono context — no tight coupling to the hono package.
5
+ * Matches Hono's Context shape for the fields we need.
6
+ */
7
+ interface HonoContextLike {
8
+ req: {
9
+ raw: Request;
10
+ url: string;
11
+ method: string;
12
+ };
13
+ }
14
+ /**
15
+ * Structural subset of BetterConsoleInstance needed by the middleware.
16
+ * The middleware is a thin adapter — all routing, auth, CORS, and error
17
+ * handling live inside handleConsoleRequest.
18
+ */
19
+ interface HonoConsoleLike {
20
+ handleConsoleRequest(request: ConsoleRequest): Promise<ConsoleResponse>;
21
+ }
22
+ interface CreateConsoleMiddlewareOptions {
23
+ /** Base path for console routes. Default: "/.well-known/better" */
24
+ basePath?: string;
25
+ }
26
+ type ConsoleMiddleware = (context: HonoContextLike, next: () => Promise<void>) => Promise<Response | void>;
27
+ /**
28
+ * Creates Hono middleware that intercepts `/.well-known/better/*` requests
29
+ * and delegates them to handleConsoleRequest(). Everything else passes through.
30
+ *
31
+ * All routing, auth, CORS, and error handling are owned by handleConsoleRequest.
32
+ * This middleware is a thin adapter that converts between Hono Request/Response
33
+ * and ConsoleRequest/ConsoleResponse.
34
+ *
35
+ * Usage:
36
+ * ```ts
37
+ * import { createConsoleMiddleware } from "@usebetterdev/console/hono"
38
+ * app.use("*", createConsoleMiddleware(consoleInstance))
39
+ * ```
40
+ */
41
+ declare function createConsoleMiddleware(consoleInstance: HonoConsoleLike, options?: CreateConsoleMiddlewareOptions): ConsoleMiddleware;
42
+
43
+ export { type ConsoleMiddleware, type CreateConsoleMiddlewareOptions, type HonoConsoleLike, type HonoContextLike, createConsoleMiddleware };
package/dist/hono.js ADDED
@@ -0,0 +1,74 @@
1
+ // src/hono/middleware.ts
2
+ async function parseBody(request) {
3
+ const contentType = request.headers.get("content-type") ?? "";
4
+ if (contentType.includes("application/json")) {
5
+ try {
6
+ return await request.json();
7
+ } catch {
8
+ return null;
9
+ }
10
+ }
11
+ return null;
12
+ }
13
+ function toConsoleRequest(raw, url, basePath, body) {
14
+ const path = url.pathname.slice(basePath.length);
15
+ return {
16
+ method: raw.method,
17
+ path,
18
+ url: raw.url,
19
+ headers: raw.headers,
20
+ // Last value wins for duplicate keys — intentional for console APIs
21
+ query: Object.fromEntries(url.searchParams),
22
+ params: {},
23
+ body
24
+ };
25
+ }
26
+ function toResponse(result) {
27
+ const headers = new Headers(result.headers);
28
+ if (result.status === 204 || result.body === null) {
29
+ return new Response(null, { status: result.status, headers });
30
+ }
31
+ const contentType = headers.get("content-type");
32
+ if (contentType && !contentType.includes("application/json")) {
33
+ const responseBody = typeof result.body === "string" ? result.body : JSON.stringify(result.body);
34
+ return new Response(responseBody, { status: result.status, headers });
35
+ }
36
+ if (!contentType) {
37
+ headers.set("content-type", "application/json");
38
+ }
39
+ return new Response(JSON.stringify(result.body), {
40
+ status: result.status,
41
+ headers
42
+ });
43
+ }
44
+ function createConsoleMiddleware(consoleInstance, options) {
45
+ const basePath = options?.basePath ?? "/.well-known/better";
46
+ return async (context, next) => {
47
+ let url;
48
+ try {
49
+ url = new URL(context.req.url);
50
+ } catch {
51
+ return new Response(
52
+ JSON.stringify({ error: "Malformed request URL" }),
53
+ { status: 400, headers: { "content-type": "application/json" } }
54
+ );
55
+ }
56
+ if (!url.pathname.startsWith(basePath + "/")) {
57
+ await next();
58
+ return;
59
+ }
60
+ const body = await parseBody(context.req.raw);
61
+ const consoleRequest = toConsoleRequest(
62
+ context.req.raw,
63
+ url,
64
+ basePath,
65
+ body
66
+ );
67
+ const result = await consoleInstance.handleConsoleRequest(consoleRequest);
68
+ return toResponse(result);
69
+ };
70
+ }
71
+ export {
72
+ createConsoleMiddleware
73
+ };
74
+ //# sourceMappingURL=hono.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hono/middleware.ts"],"sourcesContent":["import type {\n ConsoleRequest,\n ConsoleResponse,\n} from \"../types.js\";\n\n/**\n * Duck-typed Hono context — no tight coupling to the hono package.\n * Matches Hono's Context shape for the fields we need.\n */\nexport interface HonoContextLike {\n req: { raw: Request; url: string; method: string };\n}\n\n/**\n * Structural subset of BetterConsoleInstance needed by the middleware.\n * The middleware is a thin adapter — all routing, auth, CORS, and error\n * handling live inside handleConsoleRequest.\n */\nexport interface HonoConsoleLike {\n handleConsoleRequest(request: ConsoleRequest): Promise<ConsoleResponse>;\n}\n\nexport interface CreateConsoleMiddlewareOptions {\n /** Base path for console routes. Default: \"/.well-known/better\" */\n basePath?: string;\n}\n\nexport type ConsoleMiddleware = (\n context: HonoContextLike,\n next: () => Promise<void>,\n) => Promise<Response | void>;\n\nasync function parseBody(request: Request): Promise<unknown> {\n const contentType = request.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n try {\n return await request.json();\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction toConsoleRequest(\n raw: Request,\n url: URL,\n basePath: string,\n body: unknown,\n): ConsoleRequest {\n const path = url.pathname.slice(basePath.length);\n\n return {\n method: raw.method,\n path,\n url: raw.url,\n headers: raw.headers,\n // Last value wins for duplicate keys — intentional for console APIs\n query: Object.fromEntries(url.searchParams),\n params: {},\n body,\n };\n}\n\nfunction toResponse(result: ConsoleResponse): Response {\n const headers = new Headers(result.headers);\n\n // No-content responses (e.g. 204 preflight) must have null body\n if (result.status === 204 || result.body === null) {\n return new Response(null, { status: result.status, headers });\n }\n\n const contentType = headers.get(\"content-type\");\n if (contentType && !contentType.includes(\"application/json\")) {\n // Non-JSON content type: pass body through as-is if it's a string\n const responseBody =\n typeof result.body === \"string\" ? result.body : JSON.stringify(result.body);\n return new Response(responseBody, { status: result.status, headers });\n }\n\n if (!contentType) {\n headers.set(\"content-type\", \"application/json\");\n }\n return new Response(JSON.stringify(result.body), {\n status: result.status,\n headers,\n });\n}\n\n/**\n * Creates Hono middleware that intercepts `/.well-known/better/*` requests\n * and delegates them to handleConsoleRequest(). Everything else passes through.\n *\n * All routing, auth, CORS, and error handling are owned by handleConsoleRequest.\n * This middleware is a thin adapter that converts between Hono Request/Response\n * and ConsoleRequest/ConsoleResponse.\n *\n * Usage:\n * ```ts\n * import { createConsoleMiddleware } from \"@usebetterdev/console/hono\"\n * app.use(\"*\", createConsoleMiddleware(consoleInstance))\n * ```\n */\nexport function createConsoleMiddleware(\n consoleInstance: HonoConsoleLike,\n options?: CreateConsoleMiddlewareOptions,\n): ConsoleMiddleware {\n const basePath = options?.basePath ?? \"/.well-known/better\";\n\n return async (context, next) => {\n let url: URL;\n try {\n url = new URL(context.req.url);\n } catch {\n return new Response(\n JSON.stringify({ error: \"Malformed request URL\" }),\n { status: 400, headers: { \"content-type\": \"application/json\" } },\n );\n }\n\n if (!url.pathname.startsWith(basePath + \"/\")) {\n await next();\n return;\n }\n\n const body = await parseBody(context.req.raw);\n const consoleRequest = toConsoleRequest(\n context.req.raw,\n url,\n basePath,\n body,\n );\n const result = await consoleInstance.handleConsoleRequest(consoleRequest);\n return toResponse(result);\n };\n}\n"],"mappings":";AAgCA,eAAe,UAAU,SAAoC;AAC3D,QAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc,KAAK;AAC3D,MAAI,YAAY,SAAS,kBAAkB,GAAG;AAC5C,QAAI;AACF,aAAO,MAAM,QAAQ,KAAK;AAAA,IAC5B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iBACP,KACA,KACA,UACA,MACgB;AAChB,QAAM,OAAO,IAAI,SAAS,MAAM,SAAS,MAAM;AAE/C,SAAO;AAAA,IACL,QAAQ,IAAI;AAAA,IACZ;AAAA,IACA,KAAK,IAAI;AAAA,IACT,SAAS,IAAI;AAAA;AAAA,IAEb,OAAO,OAAO,YAAY,IAAI,YAAY;AAAA,IAC1C,QAAQ,CAAC;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,WAAW,QAAmC;AACrD,QAAM,UAAU,IAAI,QAAQ,OAAO,OAAO;AAG1C,MAAI,OAAO,WAAW,OAAO,OAAO,SAAS,MAAM;AACjD,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,OAAO,QAAQ,QAAQ,CAAC;AAAA,EAC9D;AAEA,QAAM,cAAc,QAAQ,IAAI,cAAc;AAC9C,MAAI,eAAe,CAAC,YAAY,SAAS,kBAAkB,GAAG;AAE5D,UAAM,eACJ,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,KAAK,UAAU,OAAO,IAAI;AAC5E,WAAO,IAAI,SAAS,cAAc,EAAE,QAAQ,OAAO,QAAQ,QAAQ,CAAC;AAAA,EACtE;AAEA,MAAI,CAAC,aAAa;AAChB,YAAQ,IAAI,gBAAgB,kBAAkB;AAAA,EAChD;AACA,SAAO,IAAI,SAAS,KAAK,UAAU,OAAO,IAAI,GAAG;AAAA,IAC/C,QAAQ,OAAO;AAAA,IACf;AAAA,EACF,CAAC;AACH;AAgBO,SAAS,wBACd,iBACA,SACmB;AACnB,QAAM,WAAW,SAAS,YAAY;AAEtC,SAAO,OAAO,SAAS,SAAS;AAC9B,QAAI;AACJ,QAAI;AACF,YAAM,IAAI,IAAI,QAAQ,IAAI,GAAG;AAAA,IAC/B,QAAQ;AACN,aAAO,IAAI;AAAA,QACT,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC;AAAA,QACjD,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,MACjE;AAAA,IACF;AAEA,QAAI,CAAC,IAAI,SAAS,WAAW,WAAW,GAAG,GAAG;AAC5C,YAAM,KAAK;AACX;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,UAAU,QAAQ,IAAI,GAAG;AAC5C,UAAM,iBAAiB;AAAA,MACrB,QAAQ,IAAI;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,MAAM,gBAAgB,qBAAqB,cAAc;AACxE,WAAO,WAAW,MAAM;AAAA,EAC1B;AACF;","names":[]}