@hulla/api-nuxt 0.0.0-stage → 2.0.0

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,15 @@
1
+ import { ClientTransport } from "@hulla/api/client";
2
+ import { $Fetch } from "ofetch";
3
+ //#region src/client.d.ts
4
+ type NuxtRequestFetch = Pick<$Fetch, 'raw'> | {
5
+ /** Nitro's request-scoped event.fetch preserves local dispatch and native response metadata. */
6
+ readonly fetch: (url: string, options: RequestInit) => Promise<Response>;
7
+ };
8
+ type NuxtFetchTransportOptions = {
9
+ /** URL prefix placed before the contract base path. Relative paths retain Nitro's local SSR dispatch. */
10
+ readonly baseUrl?: string | URL;
11
+ };
12
+ /** Preserves response metadata over browser $fetch.raw or Nitro's request-scoped event.fetch. */
13
+ declare function nuxtFetchTransport(fetcher: NuxtRequestFetch, options?: NuxtFetchTransportOptions): ClientTransport;
14
+ //#endregion
15
+ export { NuxtFetchTransportOptions, NuxtRequestFetch, nuxtFetchTransport };
package/dist/client.js ADDED
@@ -0,0 +1,72 @@
1
+ import { fetchTransportResponse } from "@hulla/api/fetch";
2
+
3
+ //#region src/client.ts
4
+ function normalizedBaseUrl(baseUrl) {
5
+ return baseUrl === void 0 ? "" : String(baseUrl).replace(/\/+$/, "");
6
+ }
7
+ function assertBaseUrl(baseUrl) {
8
+ if (baseUrl === void 0) return;
9
+ const value = String(baseUrl);
10
+ if (value.includes("?")) throw new TypeError(`Nuxt fetch base URL "${value}" cannot contain a query string`);
11
+ if (value.includes("#")) throw new TypeError(`Nuxt fetch base URL "${value}" cannot contain a hash fragment`);
12
+ }
13
+ function appendBaseUrl(prefix, path) {
14
+ if (prefix === "") return path;
15
+ return path === "/" ? prefix || "/" : `${prefix}${path}`;
16
+ }
17
+ function requestUrl(request, baseUrl) {
18
+ const url = appendBaseUrl(baseUrl, request.path);
19
+ if (request.query === void 0) return url;
20
+ const parameters = new URLSearchParams();
21
+ for (const [key, field] of Object.entries(request.query)) {
22
+ if (field === void 0) continue;
23
+ if (typeof field === "string") parameters.append(key, field);
24
+ else for (const value of field) parameters.append(key, value);
25
+ }
26
+ const encoded = parameters.toString();
27
+ return encoded === "" ? url : `${url}?${encoded}`;
28
+ }
29
+ function requestBody(request) {
30
+ const body = request.body;
31
+ if (body === void 0) return void 0;
32
+ switch (body.kind) {
33
+ case "json": {
34
+ const encoded = JSON.stringify(body.value);
35
+ if (encoded === void 0) throw new TypeError("JSON request body cannot encode to undefined");
36
+ return encoded;
37
+ }
38
+ case "text": return body.value;
39
+ case "bytes": return body.value;
40
+ case "form-data":
41
+ if (!(body.value instanceof FormData)) throw new TypeError("Form data request body must be FormData");
42
+ return body.value;
43
+ }
44
+ }
45
+ /** Preserves response metadata over browser $fetch.raw or Nitro's request-scoped event.fetch. */
46
+ function nuxtFetchTransport(fetcher, options = {}) {
47
+ assertBaseUrl(options.baseUrl);
48
+ const baseUrl = normalizedBaseUrl(options.baseUrl);
49
+ const nativeFetch = "fetch" in fetcher ? fetcher.fetch : void 0;
50
+ const rawFetch = "raw" in fetcher ? fetcher.raw : void 0;
51
+ if (typeof nativeFetch !== "function" && typeof rawFetch !== "function") throw new TypeError("Nuxt transport requires $fetch.raw or { fetch: event.fetch }; useRequestFetch() can return a parsed-only fetcher on the server");
52
+ const send = typeof nativeFetch === "function" ? (url, init) => nativeFetch(url, init) : (url, init) => rawFetch(url, {
53
+ ...init,
54
+ ignoreResponseError: true,
55
+ responseType: "stream",
56
+ retry: false
57
+ });
58
+ return async (request) => {
59
+ request.signal?.throwIfAborted();
60
+ const body = requestBody(request);
61
+ const response = await send(requestUrl(request, baseUrl), {
62
+ ...body === void 0 ? {} : { body },
63
+ headers: request.headers,
64
+ method: request.method,
65
+ ...request.signal === void 0 ? {} : { signal: request.signal }
66
+ });
67
+ return fetchTransportResponse(response);
68
+ };
69
+ }
70
+
71
+ //#endregion
72
+ export { nuxtFetchTransport };
@@ -0,0 +1,25 @@
1
+ import { FetchServerErrorInput } from "@hulla/api/fetch";
2
+ import { Awaitable, ServerAdapter, ServerContextInput, ServerExecutableFor } from "@hulla/api/server";
3
+ import { H3Event } from "h3";
4
+ import { Contract } from "@hulla/api";
5
+ //#region src/server.d.ts
6
+ type NuxtRequestEvent = H3Event;
7
+ type NuxtRouteHandler = (event: NuxtRequestEvent) => Promise<Response>;
8
+ type NuxtAdapterContext = {
9
+ readonly request: Request;
10
+ readonly nuxtEvent: NuxtRequestEvent;
11
+ };
12
+ type NuxtServerErrorInput = Omit<FetchServerErrorInput<NuxtRequestEvent>, 'handlerContext'> & {
13
+ readonly nuxtEvent: NuxtRequestEvent;
14
+ };
15
+ type NuxtServerOptions = {
16
+ readonly onError?: ((input: NuxtServerErrorInput) => Awaitable<Response | undefined | void>) | undefined;
17
+ };
18
+ type NuxtContextInput<ContractType extends Contract = Contract> = ServerContextInput<ContractType> & NuxtAdapterContext;
19
+ type NuxtAdapter = ServerAdapter<'nuxt', NuxtAdapterContext> & {
20
+ readonly mount: <const ContractType extends Contract, const Context extends object>(implementation: ServerExecutableFor<ContractType, Context, 'nuxt', NuxtAdapterContext>, options?: NuxtServerOptions) => NuxtRouteHandler;
21
+ };
22
+ /** Creates a Nuxt adapter with native Nitro request-event context and mounting operations. */
23
+ declare function nuxtAdapter(options?: NuxtServerOptions): NuxtAdapter;
24
+ //#endregion
25
+ export { NuxtAdapter, NuxtAdapterContext, NuxtContextInput, NuxtRequestEvent, NuxtRouteHandler, NuxtServerErrorInput, NuxtServerOptions, nuxtAdapter };
package/dist/server.js ADDED
@@ -0,0 +1,41 @@
1
+ import { createFetchHandler } from "@hulla/api/fetch";
2
+ import { createAdapterRuntime } from "@hulla/api/adapters";
3
+ import { createServerAdapter } from "@hulla/api/server";
4
+ import { toWebRequest } from "h3";
5
+
6
+ //#region src/server.ts
7
+ /** Creates a Nitro event handler backed by an @hulla/api server implementation. */
8
+ function createRouteHandler(implementation, options = {}) {
9
+ const unsupported = createAdapterRuntime(implementation).routes.filter((route) => route.method === "QUERY");
10
+ if (unsupported.length > 0) throw new TypeError(`Nuxt server routes do not support QUERY routes: ${unsupported.map((route) => route.key.join(".")).join(", ")}`);
11
+ const handler = createFetchHandler(implementation, {
12
+ contextAdapter: "nuxt",
13
+ contextInput: (_request, nuxtEvent) => ({ nuxtEvent }),
14
+ ...options.onError === void 0 ? {} : { onError: ({ handlerContext, ...input }) => options.onError?.({
15
+ ...input,
16
+ nuxtEvent: handlerContext
17
+ }) }
18
+ });
19
+ return async (nuxtEvent) => {
20
+ const request = toWebRequest(nuxtEvent);
21
+ if (request.method !== "HEAD") return handler(request, nuxtEvent);
22
+ const response = await handler(new Request(request, { method: "GET" }), nuxtEvent);
23
+ return new Response(null, response);
24
+ };
25
+ }
26
+ let nuxtAdapterValue;
27
+ function createNuxtAdapter(defaults) {
28
+ return createServerAdapter("nuxt", { mount: (implementation, options) => createRouteHandler(implementation, options === void 0 ? defaults : {
29
+ ...defaults,
30
+ ...options
31
+ }) });
32
+ }
33
+ /** Creates a Nuxt adapter with native Nitro request-event context and mounting operations. */
34
+ function nuxtAdapter(options) {
35
+ if (options !== void 0) return createNuxtAdapter({ ...options });
36
+ nuxtAdapterValue ??= createNuxtAdapter({});
37
+ return nuxtAdapterValue;
38
+ }
39
+
40
+ //#endregion
41
+ export { nuxtAdapter };
package/package.json CHANGED
@@ -1,6 +1,54 @@
1
1
  {
2
2
  "name": "@hulla/api-nuxt",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "2.0.0",
4
+ "description": "Nuxt and Nitro integration for @hulla/api",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/hulladev/api.git",
9
+ "directory": "packages/nuxt"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "type": "module",
15
+ "sideEffects": false,
16
+ "exports": {
17
+ "./client": {
18
+ "types": "./dist/client.d.ts",
19
+ "import": "./dist/client.js"
20
+ },
21
+ "./server": {
22
+ "types": "./dist/server.d.ts",
23
+ "import": "./dist/server.js"
24
+ }
25
+ },
26
+ "publishConfig": {
27
+ "access": "public",
28
+ "registry": "https://registry.npmjs.org/"
29
+ },
30
+ "scripts": {
31
+ "build": "tsdown",
32
+ "clean": "rm -rf dist coverage .nuxt .output",
33
+ "test": "bun run build && vitest run",
34
+ "test:coverage": "bun run build && vitest run --coverage",
35
+ "test:watch": "vitest",
36
+ "typecheck": "tsc --noEmit"
37
+ },
38
+ "dependencies": {
39
+ "h3": "^1.15.4",
40
+ "ofetch": "^1.5.1"
41
+ },
42
+ "devDependencies": {
43
+ "@hulla/api": "2.0.0",
44
+ "nuxt": "^4.5.2",
45
+ "zod": "^4.4.3"
46
+ },
47
+ "peerDependencies": {
48
+ "@hulla/api": "^2.0.0",
49
+ "nuxt": "^3.0.0 || ^4.0.0"
50
+ },
51
+ "engines": {
52
+ "node": ">=22"
53
+ }
54
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.