enlace 0.0.0-alpha.3 → 0.0.1-beta.1

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.
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,7 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
18
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
28
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
20
 
30
21
  // src/next/index.ts
@@ -33,129 +24,54 @@ __export(next_exports, {
33
24
  createEnlace: () => createEnlace
34
25
  });
35
26
  module.exports = __toCommonJS(next_exports);
36
-
37
- // src/utils/buildUrl.ts
38
- var import_query_string = __toESM(require("query-string"));
39
- function buildUrl(baseUrl, path, query) {
40
- const url = new URL(path.join("/"), baseUrl);
41
- if (query) {
42
- url.search = import_query_string.default.stringify(query, { skipNull: true, skipEmptyString: true });
43
- }
44
- return url.toString();
45
- }
46
-
47
- // src/utils/isJsonBody.ts
48
- function isJsonBody(body) {
49
- if (body === null || body === void 0) return false;
50
- if (body instanceof FormData) return false;
51
- if (body instanceof Blob) return false;
52
- if (body instanceof ArrayBuffer) return false;
53
- if (body instanceof URLSearchParams) return false;
54
- if (body instanceof ReadableStream) return false;
55
- if (typeof body === "string") return false;
56
- return typeof body === "object";
57
- }
58
-
59
- // src/utils/mergeHeaders.ts
60
- function mergeHeaders(defaultHeaders, requestHeaders) {
61
- if (!defaultHeaders && !requestHeaders) return void 0;
62
- if (!defaultHeaders) return requestHeaders;
63
- if (!requestHeaders) return defaultHeaders;
64
- return {
65
- ...Object.fromEntries(new Headers(defaultHeaders)),
66
- ...Object.fromEntries(new Headers(requestHeaders))
67
- };
68
- }
69
-
70
- // src/core/fetch.ts
71
- async function executeFetch(baseUrl, path, method, defaultOptions, requestOptions) {
72
- const url = buildUrl(baseUrl, path, requestOptions?.query);
73
- let headers = mergeHeaders(defaultOptions.headers, requestOptions?.headers);
74
- const fetchOptions = {
75
- ...defaultOptions,
76
- method
77
- };
78
- if (headers) {
79
- fetchOptions.headers = headers;
80
- }
81
- if (requestOptions?.body !== void 0) {
82
- if (isJsonBody(requestOptions.body)) {
83
- fetchOptions.body = JSON.stringify(requestOptions.body);
84
- headers = mergeHeaders(headers, { "Content-Type": "application/json" });
85
- if (headers) {
86
- fetchOptions.headers = headers;
87
- }
88
- } else {
89
- fetchOptions.body = requestOptions.body;
90
- }
91
- }
92
- const response = await fetch(url, fetchOptions);
93
- const contentType = response.headers.get("content-type");
94
- const isJson = contentType?.includes("application/json");
95
- if (response.ok) {
96
- return {
97
- ok: true,
98
- status: response.status,
99
- data: isJson ? await response.json() : response
100
- };
101
- }
102
- return {
103
- ok: false,
104
- status: response.status,
105
- error: isJson ? await response.json() : response
106
- };
107
- }
108
-
109
- // src/core/proxy.ts
110
- var HTTP_METHODS = {
111
- get: "GET",
112
- post: "POST",
113
- put: "PUT",
114
- patch: "PATCH",
115
- delete: "DELETE"
116
- };
117
- function createProxyHandler(baseUrl, defaultOptions, path = [], fetchExecutor = executeFetch) {
118
- const handler = {
119
- get(_target, prop) {
120
- if (typeof prop === "symbol") return void 0;
121
- const method = HTTP_METHODS[prop];
122
- if (method) {
123
- return (options) => fetchExecutor(baseUrl, path, method, defaultOptions, options);
124
- }
125
- return createProxyHandler(baseUrl, defaultOptions, [...path, prop], fetchExecutor);
126
- }
127
- };
128
- return new Proxy({}, handler);
129
- }
27
+ var import_enlace_core2 = require("enlace-core");
130
28
 
131
29
  // src/next/fetch.ts
30
+ var import_enlace_core = require("enlace-core");
31
+
32
+ // src/utils/generateTags.ts
132
33
  function generateTags(path) {
133
34
  return path.map((_, i) => path.slice(0, i + 1).join("/"));
134
35
  }
135
- async function executeNextFetch(baseUrl, path, method, defaultOptions, requestOptions) {
136
- const url = buildUrl(baseUrl, path, requestOptions?.query);
137
- let headers = mergeHeaders(defaultOptions.headers, requestOptions?.headers);
138
- const nextOptions = requestOptions?.next;
139
- const tags = nextOptions?.tags ?? generateTags(path);
36
+
37
+ // src/next/fetch.ts
38
+ async function executeNextFetch(baseUrl, path, method, combinedOptions, requestOptions) {
39
+ const {
40
+ autoGenerateTags = true,
41
+ autoRevalidateTags = true,
42
+ revalidator,
43
+ headers: defaultHeaders,
44
+ ...restOptions
45
+ } = combinedOptions;
46
+ const url = (0, import_enlace_core.buildUrl)(baseUrl, path, requestOptions?.query);
47
+ let headers = (0, import_enlace_core.mergeHeaders)(defaultHeaders, requestOptions?.headers);
48
+ const isGet = method === "GET";
49
+ const autoTags = generateTags(path);
140
50
  const fetchOptions = {
141
- ...defaultOptions,
51
+ ...restOptions,
142
52
  method
143
53
  };
144
54
  if (requestOptions?.cache) {
145
55
  fetchOptions.cache = requestOptions.cache;
146
56
  }
147
- const nextFetchOptions = { tags };
148
- if (nextOptions?.revalidate !== void 0) {
149
- nextFetchOptions.revalidate = nextOptions.revalidate;
57
+ if (isGet) {
58
+ const tags = requestOptions?.tags ?? (autoGenerateTags ? autoTags : void 0);
59
+ const nextFetchOptions = {};
60
+ if (tags) {
61
+ nextFetchOptions.tags = tags;
62
+ }
63
+ if (requestOptions?.revalidate !== void 0) {
64
+ nextFetchOptions.revalidate = requestOptions.revalidate;
65
+ }
66
+ fetchOptions.next = nextFetchOptions;
150
67
  }
151
- fetchOptions.next = nextFetchOptions;
152
68
  if (headers) {
153
69
  fetchOptions.headers = headers;
154
70
  }
155
71
  if (requestOptions?.body !== void 0) {
156
- if (isJsonBody(requestOptions.body)) {
72
+ if ((0, import_enlace_core.isJsonBody)(requestOptions.body)) {
157
73
  fetchOptions.body = JSON.stringify(requestOptions.body);
158
- headers = mergeHeaders(headers, { "Content-Type": "application/json" });
74
+ headers = (0, import_enlace_core.mergeHeaders)(headers, { "Content-Type": "application/json" });
159
75
  if (headers) {
160
76
  fetchOptions.headers = headers;
161
77
  }
@@ -167,6 +83,13 @@ async function executeNextFetch(baseUrl, path, method, defaultOptions, requestOp
167
83
  const contentType = response.headers.get("content-type");
168
84
  const isJson = contentType?.includes("application/json");
169
85
  if (response.ok) {
86
+ if (!isGet && !requestOptions?.skipRevalidator) {
87
+ const revalidateTags = requestOptions?.revalidateTags ?? (autoRevalidateTags ? autoTags : []);
88
+ const revalidatePaths = requestOptions?.revalidatePaths ?? [];
89
+ if (revalidateTags.length || revalidatePaths.length) {
90
+ revalidator?.(revalidateTags, revalidatePaths);
91
+ }
92
+ }
170
93
  return {
171
94
  ok: true,
172
95
  status: response.status,
@@ -181,6 +104,8 @@ async function executeNextFetch(baseUrl, path, method, defaultOptions, requestOp
181
104
  }
182
105
 
183
106
  // src/next/index.ts
184
- function createEnlace(baseUrl, defaultOptions = {}) {
185
- return createProxyHandler(baseUrl, defaultOptions, [], executeNextFetch);
107
+ __reExport(next_exports, require("enlace-core"), module.exports);
108
+ function createEnlace(baseUrl, defaultOptions = {}, nextOptions = {}) {
109
+ const combinedOptions = { ...defaultOptions, ...nextOptions };
110
+ return (0, import_enlace_core2.createProxyHandler)(baseUrl, combinedOptions, [], executeNextFetch);
186
111
  }
@@ -1,31 +1,51 @@
1
+ // src/next/index.ts
2
+ import {
3
+ createProxyHandler
4
+ } from "enlace-core";
5
+
6
+ // src/next/fetch.ts
1
7
  import {
2
8
  buildUrl,
3
- createProxyHandler,
4
9
  isJsonBody,
5
10
  mergeHeaders
6
- } from "../chunk-PNORT7RX.mjs";
11
+ } from "enlace-core";
7
12
 
8
- // src/next/fetch.ts
13
+ // src/utils/generateTags.ts
9
14
  function generateTags(path) {
10
15
  return path.map((_, i) => path.slice(0, i + 1).join("/"));
11
16
  }
12
- async function executeNextFetch(baseUrl, path, method, defaultOptions, requestOptions) {
17
+
18
+ // src/next/fetch.ts
19
+ async function executeNextFetch(baseUrl, path, method, combinedOptions, requestOptions) {
20
+ const {
21
+ autoGenerateTags = true,
22
+ autoRevalidateTags = true,
23
+ revalidator,
24
+ headers: defaultHeaders,
25
+ ...restOptions
26
+ } = combinedOptions;
13
27
  const url = buildUrl(baseUrl, path, requestOptions?.query);
14
- let headers = mergeHeaders(defaultOptions.headers, requestOptions?.headers);
15
- const nextOptions = requestOptions?.next;
16
- const tags = nextOptions?.tags ?? generateTags(path);
28
+ let headers = mergeHeaders(defaultHeaders, requestOptions?.headers);
29
+ const isGet = method === "GET";
30
+ const autoTags = generateTags(path);
17
31
  const fetchOptions = {
18
- ...defaultOptions,
32
+ ...restOptions,
19
33
  method
20
34
  };
21
35
  if (requestOptions?.cache) {
22
36
  fetchOptions.cache = requestOptions.cache;
23
37
  }
24
- const nextFetchOptions = { tags };
25
- if (nextOptions?.revalidate !== void 0) {
26
- nextFetchOptions.revalidate = nextOptions.revalidate;
38
+ if (isGet) {
39
+ const tags = requestOptions?.tags ?? (autoGenerateTags ? autoTags : void 0);
40
+ const nextFetchOptions = {};
41
+ if (tags) {
42
+ nextFetchOptions.tags = tags;
43
+ }
44
+ if (requestOptions?.revalidate !== void 0) {
45
+ nextFetchOptions.revalidate = requestOptions.revalidate;
46
+ }
47
+ fetchOptions.next = nextFetchOptions;
27
48
  }
28
- fetchOptions.next = nextFetchOptions;
29
49
  if (headers) {
30
50
  fetchOptions.headers = headers;
31
51
  }
@@ -44,6 +64,13 @@ async function executeNextFetch(baseUrl, path, method, defaultOptions, requestOp
44
64
  const contentType = response.headers.get("content-type");
45
65
  const isJson = contentType?.includes("application/json");
46
66
  if (response.ok) {
67
+ if (!isGet && !requestOptions?.skipRevalidator) {
68
+ const revalidateTags = requestOptions?.revalidateTags ?? (autoRevalidateTags ? autoTags : []);
69
+ const revalidatePaths = requestOptions?.revalidatePaths ?? [];
70
+ if (revalidateTags.length || revalidatePaths.length) {
71
+ revalidator?.(revalidateTags, revalidatePaths);
72
+ }
73
+ }
47
74
  return {
48
75
  ok: true,
49
76
  status: response.status,
@@ -58,8 +85,10 @@ async function executeNextFetch(baseUrl, path, method, defaultOptions, requestOp
58
85
  }
59
86
 
60
87
  // src/next/index.ts
61
- function createEnlace(baseUrl, defaultOptions = {}) {
62
- return createProxyHandler(baseUrl, defaultOptions, [], executeNextFetch);
88
+ export * from "enlace-core";
89
+ function createEnlace(baseUrl, defaultOptions = {}, nextOptions = {}) {
90
+ const combinedOptions = { ...defaultOptions, ...nextOptions };
91
+ return createProxyHandler(baseUrl, combinedOptions, [], executeNextFetch);
63
92
  }
64
93
  export {
65
94
  createEnlace
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "enlace",
3
- "version": "0.0.0-alpha.3",
3
+ "version": "0.0.1-beta.1",
4
+ "license": "MIT",
4
5
  "files": [
5
6
  "dist"
6
7
  ],
@@ -14,31 +15,23 @@
14
15
  "types": "./dist/next/index.d.ts",
15
16
  "import": "./dist/next/index.mjs",
16
17
  "require": "./dist/next/index.js"
18
+ },
19
+ "./next/hook": {
20
+ "types": "./dist/next/hook/index.d.ts",
21
+ "import": "./dist/next/hook/index.mjs",
22
+ "require": "./dist/next/hook/index.js"
17
23
  }
18
24
  },
19
- "license": "MIT",
25
+ "dependencies": {
26
+ "enlace-core": "0.0.1-beta.1"
27
+ },
28
+ "peerDependencies": {
29
+ "react": "^19"
30
+ },
20
31
  "scripts": {
21
32
  "dev": "tsup --watch",
22
33
  "build": "tsup",
23
34
  "typecheck": "tsc --noEmit",
24
35
  "lint": "eslint src --max-warnings 0"
25
- },
26
- "peerDependencies": {
27
- "react": "^19"
28
- },
29
- "devDependencies": {
30
- "@eslint/js": "^9.39.1",
31
- "@types/react": "^19.1.0",
32
- "eslint": "^9.39.1",
33
- "eslint-plugin-react": "^7.37.5",
34
- "globals": "^16.5.0",
35
- "jiti": "^2.6.1",
36
- "tsup": "^8.5.1",
37
- "tsx": "^4.21.0",
38
- "typescript": "5.9.2",
39
- "typescript-eslint": "^8.48.1"
40
- },
41
- "dependencies": {
42
- "query-string": "^9.3.1"
43
36
  }
44
- }
37
+ }
@@ -1,101 +0,0 @@
1
- // src/utils/buildUrl.ts
2
- import qs from "query-string";
3
- function buildUrl(baseUrl, path, query) {
4
- const url = new URL(path.join("/"), baseUrl);
5
- if (query) {
6
- url.search = qs.stringify(query, { skipNull: true, skipEmptyString: true });
7
- }
8
- return url.toString();
9
- }
10
-
11
- // src/utils/isJsonBody.ts
12
- function isJsonBody(body) {
13
- if (body === null || body === void 0) return false;
14
- if (body instanceof FormData) return false;
15
- if (body instanceof Blob) return false;
16
- if (body instanceof ArrayBuffer) return false;
17
- if (body instanceof URLSearchParams) return false;
18
- if (body instanceof ReadableStream) return false;
19
- if (typeof body === "string") return false;
20
- return typeof body === "object";
21
- }
22
-
23
- // src/utils/mergeHeaders.ts
24
- function mergeHeaders(defaultHeaders, requestHeaders) {
25
- if (!defaultHeaders && !requestHeaders) return void 0;
26
- if (!defaultHeaders) return requestHeaders;
27
- if (!requestHeaders) return defaultHeaders;
28
- return {
29
- ...Object.fromEntries(new Headers(defaultHeaders)),
30
- ...Object.fromEntries(new Headers(requestHeaders))
31
- };
32
- }
33
-
34
- // src/core/fetch.ts
35
- async function executeFetch(baseUrl, path, method, defaultOptions, requestOptions) {
36
- const url = buildUrl(baseUrl, path, requestOptions?.query);
37
- let headers = mergeHeaders(defaultOptions.headers, requestOptions?.headers);
38
- const fetchOptions = {
39
- ...defaultOptions,
40
- method
41
- };
42
- if (headers) {
43
- fetchOptions.headers = headers;
44
- }
45
- if (requestOptions?.body !== void 0) {
46
- if (isJsonBody(requestOptions.body)) {
47
- fetchOptions.body = JSON.stringify(requestOptions.body);
48
- headers = mergeHeaders(headers, { "Content-Type": "application/json" });
49
- if (headers) {
50
- fetchOptions.headers = headers;
51
- }
52
- } else {
53
- fetchOptions.body = requestOptions.body;
54
- }
55
- }
56
- const response = await fetch(url, fetchOptions);
57
- const contentType = response.headers.get("content-type");
58
- const isJson = contentType?.includes("application/json");
59
- if (response.ok) {
60
- return {
61
- ok: true,
62
- status: response.status,
63
- data: isJson ? await response.json() : response
64
- };
65
- }
66
- return {
67
- ok: false,
68
- status: response.status,
69
- error: isJson ? await response.json() : response
70
- };
71
- }
72
-
73
- // src/core/proxy.ts
74
- var HTTP_METHODS = {
75
- get: "GET",
76
- post: "POST",
77
- put: "PUT",
78
- patch: "PATCH",
79
- delete: "DELETE"
80
- };
81
- function createProxyHandler(baseUrl, defaultOptions, path = [], fetchExecutor = executeFetch) {
82
- const handler = {
83
- get(_target, prop) {
84
- if (typeof prop === "symbol") return void 0;
85
- const method = HTTP_METHODS[prop];
86
- if (method) {
87
- return (options) => fetchExecutor(baseUrl, path, method, defaultOptions, options);
88
- }
89
- return createProxyHandler(baseUrl, defaultOptions, [...path, prop], fetchExecutor);
90
- }
91
- };
92
- return new Proxy({}, handler);
93
- }
94
-
95
- export {
96
- buildUrl,
97
- isJsonBody,
98
- mergeHeaders,
99
- executeFetch,
100
- createProxyHandler
101
- };
@@ -1,104 +0,0 @@
1
- type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
2
- type SchemaMethod = '$get' | '$post' | '$put' | '$patch' | '$delete';
3
- type EnlaceResponse<TData, TError> = {
4
- ok: true;
5
- status: number;
6
- data: TData;
7
- error?: never;
8
- } | {
9
- ok: false;
10
- status: number;
11
- data?: never;
12
- error: TError;
13
- };
14
- type EnlaceOptions = Omit<RequestInit, 'method' | 'body'>;
15
- type FetchExecutor<TOptions = EnlaceOptions, TRequestOptions = RequestOptions<unknown>> = <TData, TError>(baseUrl: string, path: string[], method: HttpMethod, defaultOptions: TOptions, requestOptions?: TRequestOptions) => Promise<EnlaceResponse<TData, TError>>;
16
- type RequestOptions<TBody = never> = {
17
- body?: TBody;
18
- query?: Record<string, string | number | boolean | undefined>;
19
- headers?: HeadersInit;
20
- };
21
- type MethodDefinition = {
22
- data: unknown;
23
- error: unknown;
24
- body?: unknown;
25
- };
26
- /**
27
- * Helper to define an endpoint with proper typing.
28
- * Provides cleaner syntax than writing { data, error, body } manually.
29
- *
30
- * @example
31
- * type MyApi = {
32
- * posts: {
33
- * $get: Endpoint<Post[], ApiError>;
34
- * $post: Endpoint<Post, ApiError, CreatePost>; // with body
35
- * _: {
36
- * $get: Endpoint<Post, NotFoundError>;
37
- * };
38
- * };
39
- * };
40
- */
41
- type Endpoint<TData, TError, TBody = never> = [TBody] extends [never] ? {
42
- data: TData;
43
- error: TError;
44
- } : {
45
- data: TData;
46
- error: TError;
47
- body: TBody;
48
- };
49
- type ExtractMethodDef<TSchema, TMethod extends SchemaMethod> = TSchema extends {
50
- [K in TMethod]: infer M;
51
- } ? M extends MethodDefinition ? M : never : never;
52
- type ExtractData<TSchema, TMethod extends SchemaMethod> = ExtractMethodDef<TSchema, TMethod> extends {
53
- data: infer D;
54
- } ? D : never;
55
- type ExtractError<TSchema, TMethod extends SchemaMethod> = ExtractMethodDef<TSchema, TMethod> extends {
56
- error: infer E;
57
- } ? E : never;
58
- type ExtractBody<TSchema, TMethod extends SchemaMethod> = ExtractMethodDef<TSchema, TMethod> extends {
59
- body: infer B;
60
- } ? B : never;
61
- type HasMethod<TSchema, TMethod extends SchemaMethod> = TSchema extends {
62
- [K in TMethod]: MethodDefinition;
63
- } ? true : false;
64
- type MethodFn<TSchema, TMethod extends SchemaMethod, TRequestOptionsBase = object> = HasMethod<TSchema, TMethod> extends true ? ExtractBody<TSchema, TMethod> extends never ? (options?: RequestOptions<never> & TRequestOptionsBase) => Promise<EnlaceResponse<ExtractData<TSchema, TMethod>, ExtractError<TSchema, TMethod>>> : (options: RequestOptions<ExtractBody<TSchema, TMethod>> & TRequestOptionsBase) => Promise<EnlaceResponse<ExtractData<TSchema, TMethod>, ExtractError<TSchema, TMethod>>> : never;
65
- type IsSpecialKey<K> = K extends SchemaMethod | '_' ? true : false;
66
- type StaticPathKeys<TSchema> = {
67
- [K in keyof TSchema as IsSpecialKey<K> extends true ? never : K extends string ? K : never]: TSchema[K];
68
- };
69
- type ExtractDynamicSchema<TSchema> = TSchema extends {
70
- _: infer D;
71
- } ? D : never;
72
- type MethodOrPath<TSchema, TMethodName extends string, TSchemaMethod extends SchemaMethod, TRequestOptionsBase = object> = TMethodName extends keyof TSchema ? EnlaceClient<TSchema[TMethodName], TRequestOptionsBase> : MethodFn<TSchema, TSchemaMethod, TRequestOptionsBase>;
73
- type HttpMethods<TSchema, TRequestOptionsBase = object> = {
74
- get: MethodOrPath<TSchema, 'get', '$get', TRequestOptionsBase>;
75
- post: MethodOrPath<TSchema, 'post', '$post', TRequestOptionsBase>;
76
- put: MethodOrPath<TSchema, 'put', '$put', TRequestOptionsBase>;
77
- patch: MethodOrPath<TSchema, 'patch', '$patch', TRequestOptionsBase>;
78
- delete: MethodOrPath<TSchema, 'delete', '$delete', TRequestOptionsBase>;
79
- };
80
- type DynamicAccess<TSchema, TRequestOptionsBase = object> = ExtractDynamicSchema<TSchema> extends never ? object : {
81
- [key: string]: EnlaceClient<ExtractDynamicSchema<TSchema>, TRequestOptionsBase>;
82
- [key: number]: EnlaceClient<ExtractDynamicSchema<TSchema>, TRequestOptionsBase>;
83
- };
84
- type MethodNameKeys = 'get' | 'post' | 'put' | 'patch' | 'delete';
85
- type EnlaceClient<TSchema, TRequestOptionsBase = object> = HttpMethods<TSchema, TRequestOptionsBase> & DynamicAccess<TSchema, TRequestOptionsBase> & {
86
- [K in keyof StaticPathKeys<TSchema> as K extends MethodNameKeys ? never : K]: EnlaceClient<TSchema[K], TRequestOptionsBase>;
87
- };
88
- type WildcardMethodFn<TRequestOptionsBase = object> = (options?: RequestOptions<unknown> & TRequestOptionsBase) => Promise<EnlaceResponse<unknown, unknown>>;
89
- /**
90
- * Wildcard client type - allows any path access when no schema is provided.
91
- * All methods are available at every level and return unknown types.
92
- */
93
- type WildcardClient<TRequestOptionsBase = object> = {
94
- get: WildcardMethodFn<TRequestOptionsBase>;
95
- post: WildcardMethodFn<TRequestOptionsBase>;
96
- put: WildcardMethodFn<TRequestOptionsBase>;
97
- patch: WildcardMethodFn<TRequestOptionsBase>;
98
- delete: WildcardMethodFn<TRequestOptionsBase>;
99
- } & {
100
- [key: string]: WildcardClient<TRequestOptionsBase>;
101
- [key: number]: WildcardClient<TRequestOptionsBase>;
102
- };
103
-
104
- export type { EnlaceOptions as E, FetchExecutor as F, HttpMethod as H, MethodDefinition as M, RequestOptions as R, SchemaMethod as S, WildcardClient as W, EnlaceResponse as a, EnlaceClient as b, Endpoint as c };
@@ -1,104 +0,0 @@
1
- type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
2
- type SchemaMethod = '$get' | '$post' | '$put' | '$patch' | '$delete';
3
- type EnlaceResponse<TData, TError> = {
4
- ok: true;
5
- status: number;
6
- data: TData;
7
- error?: never;
8
- } | {
9
- ok: false;
10
- status: number;
11
- data?: never;
12
- error: TError;
13
- };
14
- type EnlaceOptions = Omit<RequestInit, 'method' | 'body'>;
15
- type FetchExecutor<TOptions = EnlaceOptions, TRequestOptions = RequestOptions<unknown>> = <TData, TError>(baseUrl: string, path: string[], method: HttpMethod, defaultOptions: TOptions, requestOptions?: TRequestOptions) => Promise<EnlaceResponse<TData, TError>>;
16
- type RequestOptions<TBody = never> = {
17
- body?: TBody;
18
- query?: Record<string, string | number | boolean | undefined>;
19
- headers?: HeadersInit;
20
- };
21
- type MethodDefinition = {
22
- data: unknown;
23
- error: unknown;
24
- body?: unknown;
25
- };
26
- /**
27
- * Helper to define an endpoint with proper typing.
28
- * Provides cleaner syntax than writing { data, error, body } manually.
29
- *
30
- * @example
31
- * type MyApi = {
32
- * posts: {
33
- * $get: Endpoint<Post[], ApiError>;
34
- * $post: Endpoint<Post, ApiError, CreatePost>; // with body
35
- * _: {
36
- * $get: Endpoint<Post, NotFoundError>;
37
- * };
38
- * };
39
- * };
40
- */
41
- type Endpoint<TData, TError, TBody = never> = [TBody] extends [never] ? {
42
- data: TData;
43
- error: TError;
44
- } : {
45
- data: TData;
46
- error: TError;
47
- body: TBody;
48
- };
49
- type ExtractMethodDef<TSchema, TMethod extends SchemaMethod> = TSchema extends {
50
- [K in TMethod]: infer M;
51
- } ? M extends MethodDefinition ? M : never : never;
52
- type ExtractData<TSchema, TMethod extends SchemaMethod> = ExtractMethodDef<TSchema, TMethod> extends {
53
- data: infer D;
54
- } ? D : never;
55
- type ExtractError<TSchema, TMethod extends SchemaMethod> = ExtractMethodDef<TSchema, TMethod> extends {
56
- error: infer E;
57
- } ? E : never;
58
- type ExtractBody<TSchema, TMethod extends SchemaMethod> = ExtractMethodDef<TSchema, TMethod> extends {
59
- body: infer B;
60
- } ? B : never;
61
- type HasMethod<TSchema, TMethod extends SchemaMethod> = TSchema extends {
62
- [K in TMethod]: MethodDefinition;
63
- } ? true : false;
64
- type MethodFn<TSchema, TMethod extends SchemaMethod, TRequestOptionsBase = object> = HasMethod<TSchema, TMethod> extends true ? ExtractBody<TSchema, TMethod> extends never ? (options?: RequestOptions<never> & TRequestOptionsBase) => Promise<EnlaceResponse<ExtractData<TSchema, TMethod>, ExtractError<TSchema, TMethod>>> : (options: RequestOptions<ExtractBody<TSchema, TMethod>> & TRequestOptionsBase) => Promise<EnlaceResponse<ExtractData<TSchema, TMethod>, ExtractError<TSchema, TMethod>>> : never;
65
- type IsSpecialKey<K> = K extends SchemaMethod | '_' ? true : false;
66
- type StaticPathKeys<TSchema> = {
67
- [K in keyof TSchema as IsSpecialKey<K> extends true ? never : K extends string ? K : never]: TSchema[K];
68
- };
69
- type ExtractDynamicSchema<TSchema> = TSchema extends {
70
- _: infer D;
71
- } ? D : never;
72
- type MethodOrPath<TSchema, TMethodName extends string, TSchemaMethod extends SchemaMethod, TRequestOptionsBase = object> = TMethodName extends keyof TSchema ? EnlaceClient<TSchema[TMethodName], TRequestOptionsBase> : MethodFn<TSchema, TSchemaMethod, TRequestOptionsBase>;
73
- type HttpMethods<TSchema, TRequestOptionsBase = object> = {
74
- get: MethodOrPath<TSchema, 'get', '$get', TRequestOptionsBase>;
75
- post: MethodOrPath<TSchema, 'post', '$post', TRequestOptionsBase>;
76
- put: MethodOrPath<TSchema, 'put', '$put', TRequestOptionsBase>;
77
- patch: MethodOrPath<TSchema, 'patch', '$patch', TRequestOptionsBase>;
78
- delete: MethodOrPath<TSchema, 'delete', '$delete', TRequestOptionsBase>;
79
- };
80
- type DynamicAccess<TSchema, TRequestOptionsBase = object> = ExtractDynamicSchema<TSchema> extends never ? object : {
81
- [key: string]: EnlaceClient<ExtractDynamicSchema<TSchema>, TRequestOptionsBase>;
82
- [key: number]: EnlaceClient<ExtractDynamicSchema<TSchema>, TRequestOptionsBase>;
83
- };
84
- type MethodNameKeys = 'get' | 'post' | 'put' | 'patch' | 'delete';
85
- type EnlaceClient<TSchema, TRequestOptionsBase = object> = HttpMethods<TSchema, TRequestOptionsBase> & DynamicAccess<TSchema, TRequestOptionsBase> & {
86
- [K in keyof StaticPathKeys<TSchema> as K extends MethodNameKeys ? never : K]: EnlaceClient<TSchema[K], TRequestOptionsBase>;
87
- };
88
- type WildcardMethodFn<TRequestOptionsBase = object> = (options?: RequestOptions<unknown> & TRequestOptionsBase) => Promise<EnlaceResponse<unknown, unknown>>;
89
- /**
90
- * Wildcard client type - allows any path access when no schema is provided.
91
- * All methods are available at every level and return unknown types.
92
- */
93
- type WildcardClient<TRequestOptionsBase = object> = {
94
- get: WildcardMethodFn<TRequestOptionsBase>;
95
- post: WildcardMethodFn<TRequestOptionsBase>;
96
- put: WildcardMethodFn<TRequestOptionsBase>;
97
- patch: WildcardMethodFn<TRequestOptionsBase>;
98
- delete: WildcardMethodFn<TRequestOptionsBase>;
99
- } & {
100
- [key: string]: WildcardClient<TRequestOptionsBase>;
101
- [key: number]: WildcardClient<TRequestOptionsBase>;
102
- };
103
-
104
- export type { EnlaceOptions as E, FetchExecutor as F, HttpMethod as H, MethodDefinition as M, RequestOptions as R, SchemaMethod as S, WildcardClient as W, EnlaceResponse as a, EnlaceClient as b, Endpoint as c };