@canmi/seam-adapter-hono 0.4.11 → 0.5.10
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.
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -42,11 +42,18 @@ function seam(router, opts) {
|
|
|
42
42
|
}))(c, next);
|
|
43
43
|
}
|
|
44
44
|
const raw = c.req.raw;
|
|
45
|
+
const isMultipart = (raw.headers.get("content-type") ?? "").startsWith("multipart/form-data");
|
|
46
|
+
let formDataCache;
|
|
47
|
+
const getFormData = async () => formDataCache ??= await raw.formData();
|
|
45
48
|
return toWebResponse(await handler({
|
|
46
49
|
method: raw.method,
|
|
47
50
|
url: raw.url,
|
|
48
|
-
body: () => raw.json(),
|
|
49
|
-
header: (name) => raw.headers.get(name)
|
|
51
|
+
body: isMultipart ? async () => JSON.parse((await getFormData()).get("metadata")) : () => raw.json(),
|
|
52
|
+
header: (name) => raw.headers.get(name),
|
|
53
|
+
file: isMultipart ? async () => {
|
|
54
|
+
const f = (await getFormData()).get("file");
|
|
55
|
+
return f ? { stream: () => f.stream() } : null;
|
|
56
|
+
} : void 0
|
|
50
57
|
}));
|
|
51
58
|
};
|
|
52
59
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/* src/server/adapter/hono/src/index.ts */\n\nimport { createHttpHandler, toWebResponse, startChannelWs } from
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/* src/server/adapter/hono/src/index.ts */\n\nimport { createHttpHandler, toWebResponse, startChannelWs } from '@canmi/seam-server'\nimport type {\n DefinitionMap,\n Router,\n HttpHandler,\n HttpHandlerOptions,\n RpcHashMap,\n ChannelWsOptions,\n ChannelWsSession,\n} from '@canmi/seam-server'\nimport type { MiddlewareHandler } from 'hono'\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Hono-compatible upgradeWebSocket factory.\n * Runtimes (Deno, Bun, Cloudflare) provide their own implementation;\n * the user injects it via options so the adapter stays runtime-agnostic.\n */\nexport type UpgradeWebSocket = (\n handler: (c: any) => {\n onOpen?: (evt: any, ws: any) => void\n onMessage?: (evt: any, ws: any) => void\n onClose?: (evt: any, ws: any) => void\n },\n) => MiddlewareHandler\n\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nexport interface SeamHonoOptions {\n staticDir?: string\n fallback?: HttpHandler\n rpcHashMap?: RpcHashMap\n upgradeWebSocket?: UpgradeWebSocket\n wsOptions?: ChannelWsOptions\n}\n\nconst SEAM_PREFIX = '/_seam/'\nconst PROCEDURE_PREFIX = '/_seam/procedure/'\nconst EVENTS_SUFFIX = '.events'\n\n// Track WS sessions without patching the ws object\nconst wsSessions = new WeakMap<object, ChannelWsSession>()\n\n/** Hono middleware that handles all /_seam/* routes via the seam router */\nexport function seam<T extends DefinitionMap>(\n router: Router<T>,\n opts?: SeamHonoOptions,\n): MiddlewareHandler {\n const handlerOpts: HttpHandlerOptions = {}\n if (opts?.staticDir) handlerOpts.staticDir = opts.staticDir\n if (opts?.fallback) handlerOpts.fallback = opts.fallback\n if (opts?.rpcHashMap) handlerOpts.rpcHashMap = opts.rpcHashMap\n\n const handler = createHttpHandler(router, handlerOpts)\n\n return async (c, next) => {\n const url = new URL(c.req.url)\n\n if (!url.pathname.startsWith(SEAM_PREFIX)) {\n return next()\n }\n\n // WebSocket upgrade for channel paths\n if (\n opts?.upgradeWebSocket &&\n c.req.header('upgrade') === 'websocket' &&\n url.pathname.startsWith(PROCEDURE_PREFIX) &&\n url.pathname.endsWith(EVENTS_SUFFIX)\n ) {\n const channelName = url.pathname.slice(PROCEDURE_PREFIX.length, -EVENTS_SUFFIX.length)\n const rawInput = url.searchParams.get('input')\n let channelInput: unknown\n try {\n channelInput = rawInput ? JSON.parse(rawInput) : {}\n } catch {\n return c.text('Invalid input query parameter', 400)\n }\n\n const wsHandler = opts.upgradeWebSocket(() => ({\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onOpen(_evt: any, ws: any) {\n const wsObj = ws as object\n const session = startChannelWs(\n router,\n channelName,\n channelInput,\n { send: (data: string) => (ws as { send: (d: string) => void }).send(data) },\n opts.wsOptions,\n )\n wsSessions.set(wsObj, session)\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onMessage(evt: any, ws: any) {\n const session = wsSessions.get(ws as object)\n const text =\n typeof (evt as { data: unknown }).data === 'string'\n ? (evt as { data: string }).data\n : String((evt as { data: unknown }).data)\n session?.onMessage(text)\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onClose(_evt: any, ws: any) {\n const session = wsSessions.get(ws as object)\n session?.close()\n wsSessions.delete(ws as object)\n },\n }))\n return wsHandler(c, next)\n }\n\n const raw = c.req.raw\n const contentType = raw.headers.get('content-type') ?? ''\n const isMultipart = contentType.startsWith('multipart/form-data')\n\n let formDataCache: FormData | undefined\n const getFormData = async () => (formDataCache ??= await raw.formData())\n\n const result = await handler({\n method: raw.method,\n url: raw.url,\n body: isMultipart\n ? async () => JSON.parse((await getFormData()).get('metadata') as string) as unknown\n : () => raw.json(),\n header: (name) => raw.headers.get(name),\n file: isMultipart\n ? async () => {\n const f = (await getFormData()).get('file') as File | null\n return f ? { stream: () => f.stream() } : null\n }\n : undefined,\n })\n\n return toWebResponse(result)\n }\n}\n"],"mappings":";;;AAuCA,MAAM,cAAc;AACpB,MAAM,mBAAmB;AACzB,MAAM,gBAAgB;AAGtB,MAAM,6BAAa,IAAI,SAAmC;;AAG1D,SAAgB,KACd,QACA,MACmB;CACnB,MAAM,cAAkC,EAAE;AAC1C,KAAI,MAAM,UAAW,aAAY,YAAY,KAAK;AAClD,KAAI,MAAM,SAAU,aAAY,WAAW,KAAK;AAChD,KAAI,MAAM,WAAY,aAAY,aAAa,KAAK;CAEpD,MAAM,UAAU,kBAAkB,QAAQ,YAAY;AAEtD,QAAO,OAAO,GAAG,SAAS;EACxB,MAAM,MAAM,IAAI,IAAI,EAAE,IAAI,IAAI;AAE9B,MAAI,CAAC,IAAI,SAAS,WAAW,YAAY,CACvC,QAAO,MAAM;AAIf,MACE,MAAM,oBACN,EAAE,IAAI,OAAO,UAAU,KAAK,eAC5B,IAAI,SAAS,WAAW,iBAAiB,IACzC,IAAI,SAAS,SAAS,cAAc,EACpC;GACA,MAAM,cAAc,IAAI,SAAS,MAAM,IAAyB,GAAsB;GACtF,MAAM,WAAW,IAAI,aAAa,IAAI,QAAQ;GAC9C,IAAI;AACJ,OAAI;AACF,mBAAe,WAAW,KAAK,MAAM,SAAS,GAAG,EAAE;WAC7C;AACN,WAAO,EAAE,KAAK,iCAAiC,IAAI;;AAgCrD,UA7BkB,KAAK,wBAAwB;IAE7C,OAAO,MAAW,IAAS;KACzB,MAAM,QAAQ;KACd,MAAM,UAAU,eACd,QACA,aACA,cACA,EAAE,OAAO,SAAkB,GAAqC,KAAK,KAAK,EAAE,EAC5E,KAAK,UACN;AACD,gBAAW,IAAI,OAAO,QAAQ;;IAGhC,UAAU,KAAU,IAAS;KAC3B,MAAM,UAAU,WAAW,IAAI,GAAa;KAC5C,MAAM,OACJ,OAAQ,IAA0B,SAAS,WACtC,IAAyB,OAC1B,OAAQ,IAA0B,KAAK;AAC7C,cAAS,UAAU,KAAK;;IAG1B,QAAQ,MAAW,IAAS;AAE1B,KADgB,WAAW,IAAI,GAAa,EACnC,OAAO;AAChB,gBAAW,OAAO,GAAa;;IAElC,EAAE,CACc,GAAG,KAAK;;EAG3B,MAAM,MAAM,EAAE,IAAI;EAElB,MAAM,eADc,IAAI,QAAQ,IAAI,eAAe,IAAI,IACvB,WAAW,sBAAsB;EAEjE,IAAI;EACJ,MAAM,cAAc,YAAa,kBAAkB,MAAM,IAAI,UAAU;AAiBvE,SAAO,cAfQ,MAAM,QAAQ;GAC3B,QAAQ,IAAI;GACZ,KAAK,IAAI;GACT,MAAM,cACF,YAAY,KAAK,OAAO,MAAM,aAAa,EAAE,IAAI,WAAW,CAAW,SACjE,IAAI,MAAM;GACpB,SAAS,SAAS,IAAI,QAAQ,IAAI,KAAK;GACvC,MAAM,cACF,YAAY;IACV,MAAM,KAAK,MAAM,aAAa,EAAE,IAAI,OAAO;AAC3C,WAAO,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG;OAE5C;GACL,CAAC,CAE0B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canmi/seam-adapter-hono",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.10",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
"test": "vitest run"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@canmi/seam-server": "0.
|
|
20
|
+
"@canmi/seam-server": "0.5.10",
|
|
21
21
|
"hono": "^4.12.3",
|
|
22
22
|
"tsdown": "^0.20.3",
|
|
23
23
|
"typescript": "^5.9.3",
|
|
24
24
|
"vitest": "^4.0.18"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@canmi/seam-server": "0.
|
|
27
|
+
"@canmi/seam-server": "0.5.10",
|
|
28
28
|
"hono": "^4.0.0"
|
|
29
29
|
}
|
|
30
30
|
}
|