enlace 0.0.1-beta.1 → 0.0.1-beta.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.
@@ -1,120 +1,8 @@
1
1
  "use client";
2
2
  "use client";
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
-
21
- // src/next/index.ts
22
- var next_exports = {};
23
- __export(next_exports, {
24
- createEnlace: () => createEnlace
25
- });
26
- import {
27
- createProxyHandler
28
- } from "enlace-core";
29
-
30
- // src/next/fetch.ts
31
- import {
32
- buildUrl,
33
- isJsonBody,
34
- mergeHeaders
35
- } from "enlace-core";
36
-
37
- // src/utils/generateTags.ts
38
- function generateTags(path) {
39
- return path.map((_, i) => path.slice(0, i + 1).join("/"));
40
- }
41
-
42
- // src/next/fetch.ts
43
- async function executeNextFetch(baseUrl, path, method, combinedOptions, requestOptions) {
44
- const {
45
- autoGenerateTags = true,
46
- autoRevalidateTags = true,
47
- revalidator,
48
- headers: defaultHeaders,
49
- ...restOptions
50
- } = combinedOptions;
51
- const url = buildUrl(baseUrl, path, requestOptions?.query);
52
- let headers = mergeHeaders(defaultHeaders, requestOptions?.headers);
53
- const isGet = method === "GET";
54
- const autoTags = generateTags(path);
55
- const fetchOptions = {
56
- ...restOptions,
57
- method
58
- };
59
- if (requestOptions?.cache) {
60
- fetchOptions.cache = requestOptions.cache;
61
- }
62
- if (isGet) {
63
- const tags = requestOptions?.tags ?? (autoGenerateTags ? autoTags : void 0);
64
- const nextFetchOptions = {};
65
- if (tags) {
66
- nextFetchOptions.tags = tags;
67
- }
68
- if (requestOptions?.revalidate !== void 0) {
69
- nextFetchOptions.revalidate = requestOptions.revalidate;
70
- }
71
- fetchOptions.next = nextFetchOptions;
72
- }
73
- if (headers) {
74
- fetchOptions.headers = headers;
75
- }
76
- if (requestOptions?.body !== void 0) {
77
- if (isJsonBody(requestOptions.body)) {
78
- fetchOptions.body = JSON.stringify(requestOptions.body);
79
- headers = mergeHeaders(headers, { "Content-Type": "application/json" });
80
- if (headers) {
81
- fetchOptions.headers = headers;
82
- }
83
- } else {
84
- fetchOptions.body = requestOptions.body;
85
- }
86
- }
87
- const response = await fetch(url, fetchOptions);
88
- const contentType = response.headers.get("content-type");
89
- const isJson = contentType?.includes("application/json");
90
- if (response.ok) {
91
- if (!isGet && !requestOptions?.skipRevalidator) {
92
- const revalidateTags = requestOptions?.revalidateTags ?? (autoRevalidateTags ? autoTags : []);
93
- const revalidatePaths = requestOptions?.revalidatePaths ?? [];
94
- if (revalidateTags.length || revalidatePaths.length) {
95
- revalidator?.(revalidateTags, revalidatePaths);
96
- }
97
- }
98
- return {
99
- ok: true,
100
- status: response.status,
101
- data: isJson ? await response.json() : response
102
- };
103
- }
104
- return {
105
- ok: false,
106
- status: response.status,
107
- error: isJson ? await response.json() : response
108
- };
109
- }
110
3
 
111
- // src/next/index.ts
112
- __reExport(next_exports, enlace_core_star);
113
- import * as enlace_core_star from "enlace-core";
114
- function createEnlace(baseUrl, defaultOptions = {}, nextOptions = {}) {
115
- const combinedOptions = { ...defaultOptions, ...nextOptions };
116
- return createProxyHandler(baseUrl, combinedOptions, [], executeNextFetch);
117
- }
4
+ // src/react/createEnlaceHookReact.ts
5
+ import { createEnlace } from "enlace-core";
118
6
 
119
7
  // src/react/useQueryMode.ts
120
8
  import { useRef, useReducer, useEffect } from "react";
@@ -123,14 +11,13 @@ import { useRef, useReducer, useEffect } from "react";
123
11
  var initialState = {
124
12
  loading: false,
125
13
  fetching: false,
126
- ok: void 0,
127
14
  data: void 0,
128
15
  error: void 0
129
16
  };
130
17
  function hookReducer(state, action) {
131
18
  switch (action.type) {
132
19
  case "RESET":
133
- return action.state;
20
+ return action.state ?? initialState;
134
21
  case "FETCH_START":
135
22
  return {
136
23
  ...state,
@@ -141,7 +28,6 @@ function hookReducer(state, action) {
141
28
  return {
142
29
  loading: false,
143
30
  fetching: false,
144
- ok: true,
145
31
  data: action.data,
146
32
  error: void 0
147
33
  };
@@ -149,7 +35,6 @@ function hookReducer(state, action) {
149
35
  return {
150
36
  loading: false,
151
37
  fetching: false,
152
- ok: false,
153
38
  data: void 0,
154
39
  error: action.error
155
40
  };
@@ -160,6 +45,11 @@ function hookReducer(state, action) {
160
45
  }
161
46
  }
162
47
 
48
+ // src/utils/generateTags.ts
49
+ function generateTags(path) {
50
+ return path.map((_, i) => path.slice(0, i + 1).join("/"));
51
+ }
52
+
163
53
  // src/utils/sortObjectKeys.ts
164
54
  function sortObjectKeys(obj) {
165
55
  if (obj === null || typeof obj !== "object") return obj;
@@ -190,7 +80,7 @@ function getCache(key) {
190
80
  function setCache(key, entry) {
191
81
  const existing = cache.get(key);
192
82
  if (existing) {
193
- if ("ok" in entry) {
83
+ if ("data" in entry || "error" in entry) {
194
84
  delete existing.promise;
195
85
  }
196
86
  Object.assign(existing, entry);
@@ -199,7 +89,6 @@ function setCache(key, entry) {
199
89
  cache.set(key, {
200
90
  data: void 0,
201
91
  error: void 0,
202
- ok: void 0,
203
92
  timestamp: 0,
204
93
  tags: [],
205
94
  subscribers: /* @__PURE__ */ new Set(),
@@ -213,7 +102,6 @@ function subscribeCache(key, callback) {
213
102
  cache.set(key, {
214
103
  data: void 0,
215
104
  error: void 0,
216
- ok: void 0,
217
105
  timestamp: 0,
218
106
  tags: [],
219
107
  subscribers: /* @__PURE__ */ new Set()
@@ -236,7 +124,6 @@ function clearCacheByTags(tags) {
236
124
  if (hasMatch) {
237
125
  entry.data = void 0;
238
126
  entry.error = void 0;
239
- entry.ok = void 0;
240
127
  entry.timestamp = 0;
241
128
  delete entry.promise;
242
129
  }
@@ -255,11 +142,29 @@ function onRevalidate(callback) {
255
142
  }
256
143
 
257
144
  // src/react/useQueryMode.ts
145
+ function resolvePath(path, pathParams) {
146
+ if (!pathParams) return path;
147
+ return path.map((segment) => {
148
+ if (segment.startsWith(":")) {
149
+ const paramName = segment.slice(1);
150
+ const value = pathParams[paramName];
151
+ if (value === void 0) {
152
+ throw new Error(`Missing path parameter: ${paramName}`);
153
+ }
154
+ return String(value);
155
+ }
156
+ return segment;
157
+ });
158
+ }
258
159
  function useQueryMode(api, trackedCall, options) {
259
- const { autoGenerateTags, staleTime } = options;
160
+ const { autoGenerateTags, staleTime, enabled } = options;
260
161
  const queryKey = createQueryKey(trackedCall);
261
162
  const requestOptions = trackedCall.options;
262
- const queryTags = requestOptions?.tags ?? (autoGenerateTags ? generateTags(trackedCall.path) : []);
163
+ const resolvedPath = resolvePath(
164
+ trackedCall.path,
165
+ requestOptions?.pathParams
166
+ );
167
+ const queryTags = requestOptions?.tags ?? (autoGenerateTags ? generateTags(resolvedPath) : []);
263
168
  const getCacheState = (includeNeedsFetch = false) => {
264
169
  const cached = getCache(queryKey);
265
170
  const hasCachedData = cached?.data !== void 0;
@@ -268,22 +173,26 @@ function useQueryMode(api, trackedCall, options) {
268
173
  return {
269
174
  loading: !hasCachedData && (isFetching || needsFetch),
270
175
  fetching: isFetching || needsFetch,
271
- ok: cached?.ok,
272
176
  data: cached?.data,
273
177
  error: cached?.error
274
178
  };
275
179
  };
276
- const [state, dispatch] = useReducer(hookReducer, null, () => getCacheState(true));
180
+ const [state, dispatch] = useReducer(
181
+ hookReducer,
182
+ null,
183
+ () => getCacheState(true)
184
+ );
277
185
  const mountedRef = useRef(true);
278
186
  const fetchRef = useRef(null);
279
187
  useEffect(() => {
280
188
  mountedRef.current = true;
189
+ if (!enabled) {
190
+ dispatch({ type: "RESET" });
191
+ return () => {
192
+ mountedRef.current = false;
193
+ };
194
+ }
281
195
  dispatch({ type: "RESET", state: getCacheState(true) });
282
- const unsubscribe = subscribeCache(queryKey, () => {
283
- if (mountedRef.current) {
284
- dispatch({ type: "SYNC_CACHE", state: getCacheState() });
285
- }
286
- });
287
196
  const doFetch = () => {
288
197
  const cached2 = getCache(queryKey);
289
198
  if (cached2?.promise) {
@@ -291,16 +200,15 @@ function useQueryMode(api, trackedCall, options) {
291
200
  }
292
201
  dispatch({ type: "FETCH_START" });
293
202
  let current = api;
294
- for (const segment of trackedCall.path) {
203
+ for (const segment of resolvedPath) {
295
204
  current = current[segment];
296
205
  }
297
206
  const method = current[trackedCall.method];
298
207
  const fetchPromise = method(trackedCall.options).then((res) => {
299
208
  if (mountedRef.current) {
300
209
  setCache(queryKey, {
301
- data: res.ok ? res.data : void 0,
302
- error: res.ok ? void 0 : res.error,
303
- ok: res.ok,
210
+ data: res.error ? void 0 : res.data,
211
+ error: res.error,
304
212
  timestamp: Date.now(),
305
213
  tags: queryTags
306
214
  });
@@ -318,12 +226,17 @@ function useQueryMode(api, trackedCall, options) {
318
226
  } else {
319
227
  doFetch();
320
228
  }
229
+ const unsubscribe = subscribeCache(queryKey, () => {
230
+ if (mountedRef.current) {
231
+ dispatch({ type: "SYNC_CACHE", state: getCacheState() });
232
+ }
233
+ });
321
234
  return () => {
322
235
  mountedRef.current = false;
323
236
  fetchRef.current = null;
324
237
  unsubscribe();
325
238
  };
326
- }, [queryKey]);
239
+ }, [queryKey, enabled]);
327
240
  useEffect(() => {
328
241
  if (queryTags.length === 0) return;
329
242
  return onRevalidate((invalidatedTags) => {
@@ -336,25 +249,90 @@ function useQueryMode(api, trackedCall, options) {
336
249
  return state;
337
250
  }
338
251
 
252
+ // src/react/types.ts
253
+ var HTTP_METHODS = ["get", "post", "put", "patch", "delete"];
254
+
255
+ // src/react/trackingProxy.ts
256
+ function createTrackingProxy(onTrack) {
257
+ const createProxy = (path = []) => {
258
+ return new Proxy(() => {
259
+ }, {
260
+ get(_, prop) {
261
+ if (HTTP_METHODS.includes(prop)) {
262
+ const methodFn = (options) => {
263
+ onTrack({
264
+ trackedCall: { path, method: prop, options },
265
+ selectorPath: null,
266
+ selectorMethod: null
267
+ });
268
+ return Promise.resolve({ status: 200, data: void 0, error: void 0 });
269
+ };
270
+ onTrack({
271
+ trackedCall: null,
272
+ selectorPath: path,
273
+ selectorMethod: prop
274
+ });
275
+ return methodFn;
276
+ }
277
+ return createProxy([...path, prop]);
278
+ }
279
+ });
280
+ };
281
+ return createProxy();
282
+ }
283
+
339
284
  // src/react/useSelectorMode.ts
340
285
  import { useRef as useRef2, useReducer as useReducer2 } from "react";
341
- function useSelectorMode(method, path, autoRevalidateTags) {
286
+ function resolvePath2(path, pathParams) {
287
+ if (!pathParams) return path;
288
+ return path.map((segment) => {
289
+ if (segment.startsWith(":")) {
290
+ const paramName = segment.slice(1);
291
+ const value = pathParams[paramName];
292
+ if (value === void 0) {
293
+ throw new Error(`Missing path parameter: ${paramName}`);
294
+ }
295
+ return String(value);
296
+ }
297
+ return segment;
298
+ });
299
+ }
300
+ function hasPathParams(path) {
301
+ return path.some((segment) => segment.startsWith(":"));
302
+ }
303
+ function useSelectorMode(config) {
304
+ const { method, api, path, methodName, autoRevalidateTags } = config;
342
305
  const [state, dispatch] = useReducer2(hookReducer, initialState);
343
306
  const methodRef = useRef2(method);
307
+ const apiRef = useRef2(api);
344
308
  const triggerRef = useRef2(null);
345
309
  const pathRef = useRef2(path);
310
+ const methodNameRef = useRef2(methodName);
346
311
  const autoRevalidateRef = useRef2(autoRevalidateTags);
347
312
  methodRef.current = method;
313
+ apiRef.current = api;
348
314
  pathRef.current = path;
315
+ methodNameRef.current = methodName;
349
316
  autoRevalidateRef.current = autoRevalidateTags;
350
317
  if (!triggerRef.current) {
351
318
  triggerRef.current = (async (...args) => {
352
319
  dispatch({ type: "FETCH_START" });
353
- const res = await methodRef.current(...args);
354
- if (res.ok) {
320
+ const options = args[0];
321
+ const resolvedPath = resolvePath2(pathRef.current, options?.pathParams);
322
+ let res;
323
+ if (hasPathParams(pathRef.current)) {
324
+ let current = apiRef.current;
325
+ for (const segment of resolvedPath) {
326
+ current = current[segment];
327
+ }
328
+ const resolvedMethod = current[methodNameRef.current];
329
+ res = await resolvedMethod(...args);
330
+ } else {
331
+ res = await methodRef.current(...args);
332
+ }
333
+ if (!res.error) {
355
334
  dispatch({ type: "FETCH_SUCCESS", data: res.data });
356
- const options = args[0];
357
- const tagsToInvalidate = options?.revalidateTags ?? (autoRevalidateRef.current ? generateTags(pathRef.current) : []);
335
+ const tagsToInvalidate = options?.revalidateTags ?? (autoRevalidateRef.current ? generateTags(resolvedPath) : []);
358
336
  if (tagsToInvalidate.length > 0) {
359
337
  invalidateTags(tagsToInvalidate);
360
338
  }
@@ -370,75 +348,151 @@ function useSelectorMode(method, path, autoRevalidateTags) {
370
348
  };
371
349
  }
372
350
 
373
- // src/react/types.ts
374
- var HTTP_METHODS = ["get", "post", "put", "patch", "delete"];
351
+ // src/react/createEnlaceHookReact.ts
352
+ function createEnlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
353
+ const {
354
+ autoGenerateTags = true,
355
+ autoRevalidateTags = true,
356
+ staleTime = 0,
357
+ onSuccess,
358
+ onError
359
+ } = hookOptions;
360
+ const api = createEnlace(baseUrl, defaultOptions, { onSuccess, onError });
361
+ function useEnlaceHook(selectorOrQuery, queryOptions) {
362
+ let trackingResult = {
363
+ trackedCall: null,
364
+ selectorPath: null,
365
+ selectorMethod: null
366
+ };
367
+ const trackingProxy = createTrackingProxy((result2) => {
368
+ trackingResult = result2;
369
+ });
370
+ const result = selectorOrQuery(
371
+ trackingProxy
372
+ );
373
+ if (typeof result === "function") {
374
+ const actualResult = selectorOrQuery(api);
375
+ return useSelectorMode({
376
+ method: actualResult,
377
+ api,
378
+ path: trackingResult.selectorPath ?? [],
379
+ methodName: trackingResult.selectorMethod ?? "",
380
+ autoRevalidateTags
381
+ });
382
+ }
383
+ return useQueryMode(
384
+ api,
385
+ trackingResult.trackedCall,
386
+ { autoGenerateTags, staleTime, enabled: queryOptions?.enabled ?? true }
387
+ );
388
+ }
389
+ return useEnlaceHook;
390
+ }
375
391
 
376
- // src/react/trackingProxy.ts
377
- function createTrackingProxy(onTrack) {
378
- const createProxy = (path = []) => {
379
- return new Proxy(() => {
380
- }, {
381
- get(_, prop) {
382
- if (HTTP_METHODS.includes(prop)) {
383
- const methodFn = (options) => {
384
- onTrack({
385
- trackedCall: { path, method: prop, options },
386
- selectorPath: null,
387
- selectorMethod: null
388
- });
389
- return Promise.resolve({ ok: true, data: void 0 });
390
- };
391
- onTrack({
392
- trackedCall: null,
393
- selectorPath: path,
394
- selectorMethod: prop
395
- });
396
- return methodFn;
397
- }
398
- return createProxy([...path, prop]);
392
+ // src/next/index.ts
393
+ import {
394
+ createProxyHandler
395
+ } from "enlace-core";
396
+
397
+ // src/next/fetch.ts
398
+ import {
399
+ executeFetch
400
+ } from "enlace-core";
401
+ async function executeNextFetch(baseUrl, path, method, combinedOptions, requestOptions) {
402
+ const {
403
+ autoGenerateTags = true,
404
+ autoRevalidateTags = true,
405
+ revalidator,
406
+ onSuccess,
407
+ ...coreOptions
408
+ } = combinedOptions;
409
+ const isGet = method === "GET";
410
+ const autoTags = generateTags(path);
411
+ const nextOnSuccess = (payload) => {
412
+ if (!isGet && !requestOptions?.skipRevalidator) {
413
+ const revalidateTags = requestOptions?.revalidateTags ?? (autoRevalidateTags ? autoTags : []);
414
+ const revalidatePaths = requestOptions?.revalidatePaths ?? [];
415
+ if (revalidateTags.length || revalidatePaths.length) {
416
+ revalidator?.(revalidateTags, revalidatePaths);
399
417
  }
400
- });
418
+ }
419
+ onSuccess?.(payload);
401
420
  };
402
- return createProxy();
421
+ const nextRequestOptions = { ...requestOptions };
422
+ if (isGet) {
423
+ const tags = requestOptions?.tags ?? (autoGenerateTags ? autoTags : void 0);
424
+ const nextFetchOptions = {};
425
+ if (tags) {
426
+ nextFetchOptions.tags = tags;
427
+ }
428
+ if (requestOptions?.revalidate !== void 0) {
429
+ nextFetchOptions.revalidate = requestOptions.revalidate;
430
+ }
431
+ nextRequestOptions.next = nextFetchOptions;
432
+ }
433
+ return executeFetch(
434
+ baseUrl,
435
+ path,
436
+ method,
437
+ { ...coreOptions, onSuccess: nextOnSuccess },
438
+ nextRequestOptions
439
+ );
403
440
  }
404
441
 
405
- // src/next/createEnlaceHook.ts
406
- function createEnlaceHook(baseUrl, defaultOptions = {}, hookOptions = {}) {
442
+ // src/next/index.ts
443
+ function createEnlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
444
+ const combinedOptions = { ...defaultOptions, ...nextOptions };
445
+ return createProxyHandler(
446
+ baseUrl,
447
+ combinedOptions,
448
+ [],
449
+ executeNextFetch
450
+ );
451
+ }
452
+
453
+ // src/next/createEnlaceHookNext.ts
454
+ function createEnlaceHookNext(baseUrl, defaultOptions = {}, hookOptions = {}) {
407
455
  const {
408
456
  autoGenerateTags = true,
409
457
  autoRevalidateTags = true,
410
458
  staleTime = 0,
411
459
  ...nextOptions
412
460
  } = hookOptions;
413
- const api = createEnlace(baseUrl, defaultOptions, {
461
+ const api = createEnlaceNext(baseUrl, defaultOptions, {
414
462
  autoGenerateTags,
415
463
  autoRevalidateTags,
416
464
  ...nextOptions
417
465
  });
418
- function useEnlaceHook(selectorOrQuery) {
466
+ function useEnlaceHook(selectorOrQuery, queryOptions) {
419
467
  let trackedCall = null;
420
468
  let selectorPath = null;
469
+ let selectorMethod = null;
421
470
  const trackingProxy = createTrackingProxy((result2) => {
422
471
  trackedCall = result2.trackedCall;
423
472
  selectorPath = result2.selectorPath;
473
+ selectorMethod = result2.selectorMethod;
424
474
  });
425
475
  const result = selectorOrQuery(trackingProxy);
426
476
  if (typeof result === "function") {
427
477
  const actualResult = selectorOrQuery(api);
428
- return useSelectorMode(
429
- actualResult,
430
- selectorPath ?? [],
478
+ return useSelectorMode({
479
+ method: actualResult,
480
+ api,
481
+ path: selectorPath ?? [],
482
+ methodName: selectorMethod ?? "",
431
483
  autoRevalidateTags
432
- );
484
+ });
433
485
  }
434
486
  return useQueryMode(
435
487
  api,
436
488
  trackedCall,
437
- { autoGenerateTags, staleTime }
489
+ { autoGenerateTags, staleTime, enabled: queryOptions?.enabled ?? true }
438
490
  );
439
491
  }
440
492
  return useEnlaceHook;
441
493
  }
442
494
  export {
443
- createEnlaceHook
495
+ HTTP_METHODS,
496
+ createEnlaceHookNext,
497
+ createEnlaceHookReact
444
498
  };