gemi 0.4.113 → 0.4.115

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.
Files changed (59) hide show
  1. package/dist/app/index.js +1 -1
  2. package/dist/{chunk-9txn8acf.js → chunk-1p6hh1c8.js} +3 -3
  3. package/dist/{chunk-9txn8acf.js.map → chunk-1p6hh1c8.js.map} +1 -1
  4. package/dist/chunk-3dsq8505.js +20 -0
  5. package/dist/{chunk-8mtrpdem.js.map → chunk-3dsq8505.js.map} +8 -7
  6. package/dist/{chunk-11azhtfq.js → chunk-40r47ff6.js} +2 -2
  7. package/dist/{chunk-11azhtfq.js.map → chunk-40r47ff6.js.map} +1 -1
  8. package/dist/chunk-45er0ax9.js +4 -0
  9. package/dist/{chunk-mvmwz99e.js.map → chunk-45er0ax9.js.map} +4 -4
  10. package/dist/chunk-52tmtmd5.js +4 -0
  11. package/dist/{chunk-yec7wnh4.js.map → chunk-52tmtmd5.js.map} +4 -4
  12. package/dist/{chunk-rb7jfsvq.js → chunk-6mhs44ws.js} +2 -2
  13. package/dist/{chunk-rb7jfsvq.js.map → chunk-6mhs44ws.js.map} +1 -1
  14. package/dist/{chunk-bn6dtgj4.js → chunk-8r4gf4db.js} +2 -2
  15. package/dist/{chunk-bn6dtgj4.js.map → chunk-8r4gf4db.js.map} +1 -1
  16. package/dist/{chunk-tqey3r3k.js → chunk-a8p9qrrx.js} +2 -2
  17. package/dist/{chunk-tqey3r3k.js.map → chunk-a8p9qrrx.js.map} +1 -1
  18. package/dist/{chunk-tr7zwxhw.js → chunk-b17rxce9.js} +2 -2
  19. package/dist/{chunk-tr7zwxhw.js.map → chunk-b17rxce9.js.map} +1 -1
  20. package/dist/{chunk-2p10c4kh.js → chunk-d5sps5cz.js} +3 -3
  21. package/dist/{chunk-2p10c4kh.js.map → chunk-d5sps5cz.js.map} +1 -1
  22. package/dist/chunk-eje4wtkf.js +3 -0
  23. package/dist/chunk-eje4wtkf.js.map +16 -0
  24. package/dist/chunk-etnryv27.js +4 -0
  25. package/dist/{chunk-bhxyhsqr.js.map → chunk-etnryv27.js.map} +4 -4
  26. package/dist/{chunk-fc27f4cb.js → chunk-g31s71mt.js} +2 -2
  27. package/dist/{chunk-fc27f4cb.js.map → chunk-g31s71mt.js.map} +1 -1
  28. package/dist/chunk-jp76yc5g.js +4 -0
  29. package/dist/{chunk-3ndk6f56.js.map → chunk-jp76yc5g.js.map} +5 -5
  30. package/dist/{chunk-tpdm7nax.js → chunk-k95a7x24.js} +2 -2
  31. package/dist/{chunk-tpdm7nax.js.map → chunk-k95a7x24.js.map} +1 -1
  32. package/dist/{chunk-x2f9x5m1.js → chunk-qc9hycem.js} +2 -2
  33. package/dist/{chunk-x2f9x5m1.js.map → chunk-qc9hycem.js.map} +1 -1
  34. package/dist/{chunk-cj78pfaa.js → chunk-vp9qt0ma.js} +2 -2
  35. package/dist/{chunk-cj78pfaa.js.map → chunk-vp9qt0ma.js.map} +1 -1
  36. package/dist/client/Link.d.ts.map +1 -1
  37. package/dist/client/Mutation.d.ts +2 -6
  38. package/dist/client/Mutation.d.ts.map +1 -1
  39. package/dist/client/index.js +514 -510
  40. package/dist/client/index.js.map +1 -1
  41. package/dist/client/useMutation.d.ts +12 -10
  42. package/dist/client/useMutation.d.ts.map +1 -1
  43. package/dist/client/useQuery.d.ts +2 -2
  44. package/dist/client/useQuery.d.ts.map +1 -1
  45. package/dist/http/index.js +2 -2
  46. package/dist/http/index.js.map +3 -3
  47. package/dist/kernel/index.js +1 -1
  48. package/dist/services/index.js +11 -2
  49. package/dist/services/index.js.map +16 -5
  50. package/package.json +1 -1
  51. package/dist/chunk-3ndk6f56.js +0 -4
  52. package/dist/chunk-8mtrpdem.js +0 -20
  53. package/dist/chunk-bhxyhsqr.js +0 -4
  54. package/dist/chunk-mvmwz99e.js +0 -4
  55. package/dist/chunk-pd22hcnn.js +0 -4
  56. package/dist/chunk-pd22hcnn.js.map +0 -16
  57. package/dist/chunk-yec7wnh4.js +0 -4
  58. /package/dist/{chunk-25y8fca8.js → chunk-ryhfg3pa.js} +0 -0
  59. /package/dist/{chunk-25y8fca8.js.map → chunk-ryhfg3pa.js.map} +0 -0
@@ -11,7 +11,7 @@ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "
11
11
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
12
12
  var _i, _n, _t, _e, _s, _l, _o, _d, _p, _g, _H_instances, r_fn, R_fn, b_fn, u_fn, m_fn, a_fn, P_fn, E_fn, S_fn, O_fn, k_fn, x_fn, h_fn, f_fn, T_fn, A_fn, y_fn, w_fn, c_fn, C_fn, _a, _i2, _n2, _t2, _e2, _s2, _l2, _b;
13
13
  import require$$1, { createContext, useRef, useContext, useEffect, useState, useCallback, useSyncExternalStore, lazy, StrictMode, Suspense, useMemo } from "react";
14
- import { jsx, Fragment, jsxs } from "react/jsx-runtime";
14
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
15
15
  import require$$2, { createPortal } from "react-dom";
16
16
  class Subject {
17
17
  constructor(initialValue) {
@@ -207,332 +207,6 @@ function omitNullishValues(input) {
207
207
  })
208
208
  );
209
209
  }
210
- const defaultConfig = {
211
- fallbackData: null,
212
- keepPreviousData: true,
213
- retryIntervalOnError: 1e4,
214
- debug: false
215
- };
216
- const defaultOptions$1 = {
217
- params: {},
218
- search: {}
219
- };
220
- function useQuery(url, ...args) {
221
- const [_options = defaultOptions$1, _config = defaultConfig] = args;
222
- const options = { ...defaultOptions$1, ..._options };
223
- const config = { ...defaultConfig, ..._config };
224
- const params = "params" in options ? options.params ?? {} : {};
225
- const paramsRef = useRef(JSON.stringify(params));
226
- const search = "search" in options ? options.search ?? {} : {};
227
- const { getResource } = useContext(QueryManagerContext);
228
- const normalPath = applyParams$1(url, params);
229
- const searchParams = new URLSearchParams(omitNullishValues(search));
230
- searchParams.sort();
231
- const variantKey = searchParams.toString();
232
- const [resource, setResource] = useState(
233
- () => getResource(
234
- normalPath,
235
- config.fallbackData ? { [variantKey]: config.fallbackData } : null
236
- )
237
- );
238
- const retryIntervalRef = useRef();
239
- const retryingMap = useRef(/* @__PURE__ */ new Map());
240
- const [state, setState] = useState(() => resource.getVariant(variantKey));
241
- const retry = (variantKey2) => {
242
- if (!retryingMap.current.get(variantKey2)) {
243
- if (config.debug) console.log("retrying", variantKey2);
244
- retryingMap.current.set(variantKey2, true);
245
- retryIntervalRef.current = setTimeout(() => {
246
- resource.getVariant(variantKey2);
247
- retryingMap.current.set(variantKey2, false);
248
- }, config.retryIntervalOnError);
249
- }
250
- };
251
- const handleReload = useCallback(() => {
252
- setResource(getResource(applyParams$1(url, params)));
253
- }, [url, params]);
254
- useEffect(() => {
255
- if (import.meta.hot) {
256
- import.meta.hot.on("http-reload", mutate);
257
- }
258
- return () => {
259
- if (import.meta.hot) {
260
- import.meta.hot.off("http-reload", mutate);
261
- }
262
- };
263
- }, [handleReload]);
264
- useEffect(() => {
265
- const key = JSON.stringify(params);
266
- if (key !== paramsRef.current) {
267
- if (config.debug) {
268
- console.log("refetching - params changed", key, paramsRef.current);
269
- }
270
- setResource(getResource(applyParams$1(url, params)));
271
- setState(resource.getVariant(variantKey));
272
- paramsRef.current = key;
273
- }
274
- }, [params]);
275
- const handleStateUpdate = useCallback(
276
- (nextState) => {
277
- if (config.debug) {
278
- console.log("state updating due to url update", variantKey);
279
- console.log(nextState);
280
- }
281
- if (nextState.error) {
282
- retry(variantKey);
283
- }
284
- if (config.keepPreviousData) {
285
- if (nextState.loading) {
286
- setState((s) => ({ ...s, loading: true }));
287
- } else {
288
- setState(nextState);
289
- }
290
- } else {
291
- setState(nextState);
292
- }
293
- },
294
- [variantKey]
295
- );
296
- useEffect(() => {
297
- handleStateUpdate(resource.getVariant(variantKey));
298
- const unsub = resource.store.subscribe.call(resource.store, (store) => {
299
- handleStateUpdate(store.get(variantKey));
300
- });
301
- return () => {
302
- unsub();
303
- clearInterval(retryIntervalRef.current);
304
- };
305
- }, [variantKey, resource]);
306
- function mutate(fn, value) {
307
- return resource.mutate.call(resource, variantKey, (data) => {
308
- try {
309
- if (typeof fn === "function") {
310
- return fn(data);
311
- } else if (typeof fn === "string") {
312
- const keys = fn.split(".");
313
- let current = structuredClone(data);
314
- for (let i = 0; i < keys.length - 1; i++) {
315
- const subKey = keys[i];
316
- current[subKey] = current[subKey] || {};
317
- current = current[subKey];
318
- }
319
- let newValue = value;
320
- if (typeof value === "function") {
321
- newValue = value(current[keys[keys.length - 1]]);
322
- }
323
- current[keys[keys.length - 1]] = newValue;
324
- return current;
325
- } else {
326
- return fn;
327
- }
328
- } catch (err) {
329
- console.log(err);
330
- }
331
- return data;
332
- });
333
- }
334
- return {
335
- data: state == null ? void 0 : state.data,
336
- loading: (state == null ? void 0 : state.loading) ?? true,
337
- error: state == null ? void 0 : state.error,
338
- mutate
339
- };
340
- }
341
- function applyParams(url, params = {}) {
342
- let out = url;
343
- for (const [key, value] of Object.entries(params)) {
344
- out = out.replace(`:${key}?`, value).replace(`:${key}`, value);
345
- }
346
- return out;
347
- }
348
- const defaultOptions = {
349
- autoInvalidate: false,
350
- onSuccess: () => {
351
- },
352
- onError: (_2) => {
353
- },
354
- onCanceled: () => {
355
- }
356
- };
357
- function useMutation(method, url, ...args) {
358
- const [state, setState] = useState({
359
- data: null,
360
- error: null,
361
- loading: false
362
- });
363
- const [abortController, setAbortController] = useState(
364
- () => new AbortController()
365
- );
366
- return {
367
- data: state.data,
368
- error: state.error,
369
- loading: state.loading,
370
- cancel: () => {
371
- const [, options = defaultOptions] = args ?? [];
372
- abortController.abort();
373
- setAbortController(new AbortController());
374
- setState({
375
- data: state.data,
376
- error: state.error,
377
- loading: false
378
- });
379
- options.onCanceled();
380
- },
381
- trigger: async (input) => {
382
- setState({
383
- data: state.data,
384
- error: state.error,
385
- loading: true
386
- });
387
- const [inputs = { params: {} }, options = defaultOptions] = args ?? [];
388
- const params = "params" in inputs ? inputs.params : {};
389
- const finalUrl = applyParams(
390
- String(url).replace(`${method}:`, ""),
391
- params
392
- );
393
- let body = null;
394
- const contentType = input instanceof FormData ? {} : { "Content-Type": "application/json" };
395
- if (input instanceof FormData) {
396
- body = input;
397
- } else if (input) {
398
- body = JSON.stringify(input);
399
- }
400
- try {
401
- const response = await fetch(`/api${finalUrl}`, {
402
- method,
403
- headers: {
404
- ...contentType
405
- },
406
- ...body ? { body } : {},
407
- signal: abortController.signal
408
- });
409
- const data = await response.json();
410
- if (!response.ok) {
411
- setState({
412
- data: null,
413
- error: data.error,
414
- loading: false
415
- });
416
- options.onError(data);
417
- return;
418
- }
419
- options.onSuccess(data);
420
- setState({
421
- data,
422
- error: null,
423
- loading: false
424
- });
425
- return data;
426
- } catch (error) {
427
- options.onError(error);
428
- setState({
429
- data: null,
430
- error,
431
- loading: false
432
- });
433
- }
434
- }
435
- };
436
- }
437
- function usePost(url, ...args) {
438
- return useMutation("POST", url, ...args);
439
- }
440
- function usePut(url, ...args) {
441
- return useMutation("PUT", url, ...args);
442
- }
443
- function usePatch(url, ...args) {
444
- return useMutation("PATCH", url, ...args);
445
- }
446
- function useDelete(url, ...args) {
447
- return useMutation("DELETE", url, ...args);
448
- }
449
- const MutationContext = createContext({
450
- isPending: false,
451
- result: null
452
- });
453
- function Form(props) {
454
- const {
455
- method = "POST",
456
- action,
457
- onSuccess = () => {
458
- },
459
- onError = () => {
460
- },
461
- params,
462
- className,
463
- ...formProps
464
- } = "params" in props ? props : { ...props, params: {} };
465
- const formRef = useRef(null);
466
- const { trigger, data, error, loading } = useMutation(
467
- method,
468
- String(action),
469
- {
470
- params
471
- },
472
- {
473
- onSuccess: (data2) => onSuccess(data2, formRef.current),
474
- onError: (error2) => onError(error2, formRef.current)
475
- }
476
- );
477
- const handleSubmit = async (e) => {
478
- if (loading) {
479
- return;
480
- }
481
- e.preventDefault();
482
- trigger(new FormData(formRef.current));
483
- };
484
- const validationErrors = (error == null ? void 0 : error.kind) === "validation_error" ? error.messages : {};
485
- const formError = (error == null ? void 0 : error.kind) === "form_error" ? error.message : null;
486
- return /* @__PURE__ */ jsx(
487
- MutationContext.Provider,
488
- {
489
- value: { isPending: loading, result: data, validationErrors, formError },
490
- children: /* @__PURE__ */ jsx(
491
- "form",
492
- {
493
- className: ["group", className].filter(Boolean).join(" "),
494
- "data-loading": loading,
495
- ref: formRef,
496
- onSubmit: handleSubmit,
497
- ...formProps,
498
- children: props.children
499
- }
500
- )
501
- }
502
- );
503
- }
504
- function useMutationStatus() {
505
- const { isPending } = useContext(MutationContext);
506
- return { isPending };
507
- }
508
- const ValidationErrors = (props) => {
509
- var _a2;
510
- const {
511
- render = (props2) => /* @__PURE__ */ jsx("div", { ...props2 }),
512
- name
513
- } = props;
514
- const { validationErrors } = useContext(MutationContext);
515
- const Comp = render;
516
- if (((_a2 = validationErrors[name]) == null ? void 0 : _a2.length) > 0) {
517
- return /* @__PURE__ */ jsx(Fragment, { children: validationErrors[name].map((error) => {
518
- return /* @__PURE__ */ jsx(Comp, { className: props.className, children: error }, error);
519
- }) });
520
- }
521
- return null;
522
- };
523
- const FormField = (props) => {
524
- const { name, children, ...rest } = props;
525
- const { validationErrors } = useContext(MutationContext);
526
- const errors = validationErrors[name] || [];
527
- return /* @__PURE__ */ jsx("div", { "data-hasError": errors.length > 0, ...rest, children });
528
- };
529
- const FormError = (props) => {
530
- const { formError } = useContext(MutationContext);
531
- if (formError) {
532
- return /* @__PURE__ */ jsx("div", { ...props, children: formError });
533
- }
534
- return null;
535
- };
536
210
  function _extends() {
537
211
  return _extends = Object.assign ? Object.assign.bind() : function(n) {
538
212
  for (var e = 1; e < arguments.length; e++) {
@@ -1834,211 +1508,540 @@ function useSearchParams() {
1834
1508
  new URLSearchParams(location.search),
1835
1509
  callback
1836
1510
  );
1837
- return searchParams;
1511
+ return searchParams;
1512
+ }
1513
+ function useRoute() {
1514
+ const { getRoutePathnameFromHref } = useContext(ClientRouterContext);
1515
+ const location = useLocation();
1516
+ const routePath = getRoutePathnameFromHref(location.pathname);
1517
+ return {
1518
+ pathname: routePath,
1519
+ startsWith: (pathname) => {
1520
+ return routePath.startsWith(pathname);
1521
+ }
1522
+ };
1523
+ }
1524
+ const HttpReload = () => {
1525
+ const { replace } = useNavigate();
1526
+ const searchParams = useSearchParams();
1527
+ const { pathname } = useRoute();
1528
+ const params = useParams();
1529
+ const [reloading, setReloading] = useState(false);
1530
+ const handleReload = () => {
1531
+ setReloading(true);
1532
+ replace(pathname, {
1533
+ params,
1534
+ search: searchParams.toJSON()
1535
+ }).catch(console.log).finally(() => {
1536
+ setReloading(false);
1537
+ });
1538
+ };
1539
+ useEffect(() => {
1540
+ if (import.meta.hot) {
1541
+ import.meta.hot.on("http-reload", handleReload);
1542
+ }
1543
+ return () => {
1544
+ if (import.meta.hot) {
1545
+ import.meta.hot.off("http-reload", handleReload);
1546
+ }
1547
+ };
1548
+ }, [handleReload]);
1549
+ if (!reloading || typeof document === "undefined") {
1550
+ return null;
1551
+ }
1552
+ return createPortal(
1553
+ /* @__PURE__ */ jsx("div", { className: "fixed z-[1000] bottom-0 right-0 p-2", children: /* @__PURE__ */ jsx("div", { className: "p-2 bg-white text-black rounded-md shadow-md", children: "..." }) }),
1554
+ document.body
1555
+ );
1556
+ };
1557
+ const ClientRouterContext = createContext(
1558
+ {}
1559
+ );
1560
+ const ClientRouterProvider = (props) => {
1561
+ const {
1562
+ children,
1563
+ pathname,
1564
+ currentPath,
1565
+ is404,
1566
+ routeManifest,
1567
+ pageData,
1568
+ params,
1569
+ searchParams
1570
+ } = props;
1571
+ const [parameters, setParameters] = useState(params);
1572
+ const navigationAbortControllerRef = useRef(new AbortController());
1573
+ const [isNavigatingSubject] = useState(() => {
1574
+ return new Subject(false);
1575
+ });
1576
+ const [progressManager] = useState(new ProgressManager(isNavigatingSubject));
1577
+ const pageDataRef = useRef(structuredClone(pageData));
1578
+ const scrollHistoryRef = useRef(/* @__PURE__ */ new Map());
1579
+ const initalViewEntries = is404 ? ["404"] : routeManifest[pathname] ?? ["404"];
1580
+ const viewEntriesSubject = useRef(new Subject(initalViewEntries));
1581
+ const [locationSubject] = useState(
1582
+ () => new Subject({
1583
+ hash: "",
1584
+ pathname: currentPath,
1585
+ search: searchParams,
1586
+ state: {},
1587
+ key: ""
1588
+ })
1589
+ );
1590
+ const [history] = useState(() => {
1591
+ let history2 = null;
1592
+ if (typeof window !== "undefined") {
1593
+ history2 = createBrowserHistory();
1594
+ }
1595
+ return history2;
1596
+ });
1597
+ const handleScroll = () => {
1598
+ const key = [
1599
+ `${locationSubject.getValue().pathname}?${locationSubject.getValue().search}`
1600
+ ].filter((item) => item.length > 0).join("");
1601
+ scrollHistoryRef.current.set(key, window.scrollY);
1602
+ };
1603
+ const findMatchingRouteFromParams = (pathname2) => {
1604
+ const candidates = [];
1605
+ for (const route2 of Object.keys(routeManifest)) {
1606
+ const urlPattern = new me({ pathname: route2 });
1607
+ if (urlPattern.test({ pathname: pathname2 })) {
1608
+ candidates.push(route2);
1609
+ }
1610
+ }
1611
+ const sortedCandidates = candidates.sort((a, b2) => {
1612
+ const x2 = a.split("/").length + a.split(":").length;
1613
+ const y2 = b2.split("/").length + b2.split(":").length;
1614
+ return x2 - y2;
1615
+ });
1616
+ const [route] = sortedCandidates ?? [];
1617
+ return route;
1618
+ };
1619
+ const getViewPathsFromPathname = (pathname2) => {
1620
+ const route = findMatchingRouteFromParams(pathname2);
1621
+ return routeManifest[route] ?? [];
1622
+ };
1623
+ const getRoutePathnameFromHref = (href) => {
1624
+ const route = findMatchingRouteFromParams(href);
1625
+ return route;
1626
+ };
1627
+ const getParams = (pathname2) => {
1628
+ var _a2;
1629
+ const route = findMatchingRouteFromParams(pathname2);
1630
+ const urlPattern = new me({ pathname: route });
1631
+ return (_a2 = urlPattern.exec({ pathname: pathname2 })) == null ? void 0 : _a2.pathname.groups;
1632
+ };
1633
+ useEffect(() => {
1634
+ history == null ? void 0 : history.listen(({ location }) => {
1635
+ locationSubject.next(structuredClone(location));
1636
+ setParameters(getParams(location.pathname));
1637
+ viewEntriesSubject.current.next(
1638
+ (() => {
1639
+ var _a2;
1640
+ if (((_a2 = location.state) == null ? void 0 : _a2.status) === 404) {
1641
+ return ["404"];
1642
+ }
1643
+ return getViewPathsFromPathname(location.pathname);
1644
+ })()
1645
+ );
1646
+ });
1647
+ window.addEventListener("scrollend", handleScroll);
1648
+ return () => {
1649
+ window.removeEventListener("scroll", handleScroll);
1650
+ };
1651
+ }, []);
1652
+ const updatePageData = (newPageData) => {
1653
+ var _a2;
1654
+ const [key, value] = Object.entries(newPageData)[0];
1655
+ if (!((_a2 = pageDataRef.current) == null ? void 0 : _a2[key])) {
1656
+ pageDataRef.current[key] = {};
1657
+ }
1658
+ pageDataRef.current[key] = value;
1659
+ };
1660
+ const getPageData = (key) => {
1661
+ return pageDataRef.current[locationSubject.getValue().pathname][key];
1662
+ };
1663
+ const setNavigationAbortController = (controller) => {
1664
+ navigationAbortControllerRef.current.abort();
1665
+ navigationAbortControllerRef.current = controller;
1666
+ };
1667
+ return /* @__PURE__ */ jsxs(
1668
+ ClientRouterContext.Provider,
1669
+ {
1670
+ value: {
1671
+ isNavigatingSubject,
1672
+ getViewPathsFromPathname,
1673
+ history,
1674
+ params: parameters,
1675
+ locationSubject,
1676
+ getScrollPosition: (path) => {
1677
+ return scrollHistoryRef.current.get(path) || 0;
1678
+ },
1679
+ viewEntriesSubject: viewEntriesSubject.current,
1680
+ updatePageData,
1681
+ getPageData,
1682
+ getRoutePathnameFromHref,
1683
+ setNavigationAbortController,
1684
+ progressManager
1685
+ },
1686
+ children: [
1687
+ children,
1688
+ import.meta.hot && /* @__PURE__ */ jsx(HttpReload, {})
1689
+ ]
1690
+ }
1691
+ );
1692
+ };
1693
+ function useLocationChange(cb) {
1694
+ const { locationSubject } = useContext(ClientRouterContext);
1695
+ useEffect(() => {
1696
+ cb(locationSubject.getValue());
1697
+ return locationSubject.subscribe(cb);
1698
+ }, []);
1838
1699
  }
1839
- function useRoute() {
1840
- const { getRoutePathnameFromHref } = useContext(ClientRouterContext);
1841
- const location = useLocation();
1842
- const routePath = getRoutePathnameFromHref(location.pathname);
1843
- return {
1844
- pathname: routePath,
1845
- startsWith: (pathname) => {
1846
- return routePath.startsWith(pathname);
1847
- }
1848
- };
1700
+ function useLocation() {
1701
+ const ctx = useContext(ClientRouterContext);
1702
+ if (!ctx) {
1703
+ throw new Error("useLocation must be used within a ClientRouterProvider");
1704
+ }
1705
+ const { locationSubject } = ctx;
1706
+ const [location, setLocation] = useState(locationSubject == null ? void 0 : locationSubject.getValue());
1707
+ useLocationChange((newLocation) => {
1708
+ setLocation(newLocation);
1709
+ });
1710
+ return location;
1849
1711
  }
1850
1712
  function useParams() {
1851
1713
  const { params } = useContext(ClientRouterContext);
1852
1714
  return params;
1853
1715
  }
1854
- const HttpReload = () => {
1855
- const { replace } = useNavigate();
1856
- const searchParams = useSearchParams();
1857
- const { pathname } = useRoute();
1858
- const params = useParams();
1859
- const [reloading, setReloading] = useState(false);
1860
- const handleReload = () => {
1861
- setReloading(true);
1862
- replace(pathname, {
1863
- params,
1864
- search: searchParams.toJSON()
1865
- }).catch(console.log).finally(() => {
1866
- setReloading(false);
1867
- });
1716
+ const defaultConfig = {
1717
+ fallbackData: null,
1718
+ keepPreviousData: true,
1719
+ retryIntervalOnError: 1e4,
1720
+ debug: false
1721
+ };
1722
+ const defaultOptions$1 = {
1723
+ params: {},
1724
+ search: {}
1725
+ };
1726
+ function useQuery(url, ...args) {
1727
+ const _params = useParams();
1728
+ const [_options = defaultOptions$1, _config = defaultConfig] = args;
1729
+ const options = { ...defaultOptions$1, ..._options };
1730
+ const config = { ...defaultConfig, ..._config };
1731
+ const params = "params" in options ? { ..._params, ...options.params } : _params;
1732
+ const paramsRef = useRef(JSON.stringify(params));
1733
+ const search = "search" in options ? options.search ?? {} : {};
1734
+ const { getResource } = useContext(QueryManagerContext);
1735
+ const normalPath = applyParams$1(url, params);
1736
+ const searchParams = new URLSearchParams(omitNullishValues(search));
1737
+ searchParams.sort();
1738
+ const variantKey = searchParams.toString();
1739
+ const [resource, setResource] = useState(
1740
+ () => getResource(
1741
+ normalPath,
1742
+ config.fallbackData ? { [variantKey]: config.fallbackData } : null
1743
+ )
1744
+ );
1745
+ const retryIntervalRef = useRef();
1746
+ const retryingMap = useRef(/* @__PURE__ */ new Map());
1747
+ const [state, setState] = useState(() => resource.getVariant(variantKey));
1748
+ const retry = (variantKey2) => {
1749
+ if (!retryingMap.current.get(variantKey2)) {
1750
+ if (config.debug) console.log("retrying", variantKey2);
1751
+ retryingMap.current.set(variantKey2, true);
1752
+ retryIntervalRef.current = setTimeout(() => {
1753
+ resource.getVariant(variantKey2);
1754
+ retryingMap.current.set(variantKey2, false);
1755
+ }, config.retryIntervalOnError);
1756
+ }
1868
1757
  };
1758
+ const handleReload = useCallback(() => {
1759
+ setResource(getResource(applyParams$1(url, params)));
1760
+ }, [url, params]);
1869
1761
  useEffect(() => {
1870
1762
  if (import.meta.hot) {
1871
- import.meta.hot.on("http-reload", handleReload);
1763
+ import.meta.hot.on("http-reload", mutate);
1872
1764
  }
1873
1765
  return () => {
1874
1766
  if (import.meta.hot) {
1875
- import.meta.hot.off("http-reload", handleReload);
1767
+ import.meta.hot.off("http-reload", mutate);
1768
+ }
1769
+ };
1770
+ }, [handleReload]);
1771
+ useEffect(() => {
1772
+ const key = JSON.stringify(params);
1773
+ if (key !== paramsRef.current) {
1774
+ if (config.debug) {
1775
+ console.log("refetching - params changed", key, paramsRef.current);
1776
+ }
1777
+ setResource(getResource(applyParams$1(url, params)));
1778
+ setState(resource.getVariant(variantKey));
1779
+ paramsRef.current = key;
1780
+ }
1781
+ }, [params]);
1782
+ const handleStateUpdate = useCallback(
1783
+ (nextState) => {
1784
+ if (config.debug) {
1785
+ console.log("state updating due to url update", variantKey);
1786
+ console.log(nextState);
1787
+ }
1788
+ if (nextState.error) {
1789
+ retry(variantKey);
1790
+ }
1791
+ if (config.keepPreviousData) {
1792
+ if (nextState.loading) {
1793
+ setState((s) => ({ ...s, loading: true }));
1794
+ } else {
1795
+ setState(nextState);
1796
+ }
1797
+ } else {
1798
+ setState(nextState);
1799
+ }
1800
+ },
1801
+ [variantKey]
1802
+ );
1803
+ useEffect(() => {
1804
+ handleStateUpdate(resource.getVariant(variantKey));
1805
+ const unsub = resource.store.subscribe.call(resource.store, (store) => {
1806
+ handleStateUpdate(store.get(variantKey));
1807
+ });
1808
+ return () => {
1809
+ unsub();
1810
+ clearInterval(retryIntervalRef.current);
1811
+ };
1812
+ }, [variantKey, resource]);
1813
+ function mutate(fn, value) {
1814
+ return resource.mutate.call(resource, variantKey, (data) => {
1815
+ try {
1816
+ if (typeof fn === "function") {
1817
+ return fn(data);
1818
+ } else if (typeof fn === "string") {
1819
+ const keys = fn.split(".");
1820
+ let current = structuredClone(data);
1821
+ for (let i = 0; i < keys.length - 1; i++) {
1822
+ const subKey = keys[i];
1823
+ current[subKey] = current[subKey] || {};
1824
+ current = current[subKey];
1825
+ }
1826
+ let newValue = value;
1827
+ if (typeof value === "function") {
1828
+ newValue = value(current[keys[keys.length - 1]]);
1829
+ }
1830
+ current[keys[keys.length - 1]] = newValue;
1831
+ return current;
1832
+ } else {
1833
+ return fn;
1834
+ }
1835
+ } catch (err) {
1836
+ console.log(err);
1837
+ }
1838
+ return data;
1839
+ });
1840
+ }
1841
+ return {
1842
+ data: state == null ? void 0 : state.data,
1843
+ loading: (state == null ? void 0 : state.loading) ?? true,
1844
+ error: state == null ? void 0 : state.error,
1845
+ mutate
1846
+ };
1847
+ }
1848
+ function applyParams(url, params = {}) {
1849
+ let out = url;
1850
+ for (const [key, value] of Object.entries(params)) {
1851
+ out = out.replace(`:${key}?`, value).replace(`:${key}`, value);
1852
+ }
1853
+ return out;
1854
+ }
1855
+ const defaultOptions = {
1856
+ autoInvalidate: false,
1857
+ onSuccess: () => {
1858
+ },
1859
+ onError: (_2) => {
1860
+ },
1861
+ onCanceled: () => {
1862
+ }
1863
+ };
1864
+ function useMutation(method, url, ...args) {
1865
+ const _params = useParams();
1866
+ const [state, setState] = useState({
1867
+ data: null,
1868
+ error: null,
1869
+ loading: false
1870
+ });
1871
+ const [abortController, setAbortController] = useState(
1872
+ () => new AbortController()
1873
+ );
1874
+ return {
1875
+ data: state.data,
1876
+ error: state.error,
1877
+ loading: state.loading,
1878
+ cancel: () => {
1879
+ const [, options = defaultOptions] = args ?? [];
1880
+ abortController.abort();
1881
+ setAbortController(new AbortController());
1882
+ setState({
1883
+ data: state.data,
1884
+ error: state.error,
1885
+ loading: false
1886
+ });
1887
+ options.onCanceled();
1888
+ },
1889
+ trigger: async (input) => {
1890
+ setState({
1891
+ data: state.data,
1892
+ error: state.error,
1893
+ loading: true
1894
+ });
1895
+ const [inputs = {}, options = defaultOptions] = args ?? [];
1896
+ const params = "params" in inputs ? { ..._params, ...inputs.params } : _params;
1897
+ const finalUrl = applyParams(
1898
+ String(url).replace(`${method}:`, ""),
1899
+ params
1900
+ );
1901
+ let body = null;
1902
+ const contentType = input instanceof FormData ? {} : { "Content-Type": "application/json" };
1903
+ if (input instanceof FormData) {
1904
+ body = input;
1905
+ } else if (input) {
1906
+ body = JSON.stringify(input);
1907
+ }
1908
+ try {
1909
+ const response = await fetch(`/api${finalUrl}`, {
1910
+ method,
1911
+ headers: {
1912
+ ...contentType
1913
+ },
1914
+ ...body ? { body } : {},
1915
+ signal: abortController.signal
1916
+ });
1917
+ const data = await response.json();
1918
+ if (!response.ok) {
1919
+ setState({
1920
+ data: null,
1921
+ error: data.error,
1922
+ loading: false
1923
+ });
1924
+ options.onError(data);
1925
+ return;
1926
+ }
1927
+ options.onSuccess(data);
1928
+ setState({
1929
+ data,
1930
+ error: null,
1931
+ loading: false
1932
+ });
1933
+ return data;
1934
+ } catch (error) {
1935
+ options.onError(error);
1936
+ setState({
1937
+ data: null,
1938
+ error,
1939
+ loading: false
1940
+ });
1876
1941
  }
1877
- };
1878
- }, [handleReload]);
1879
- if (!reloading || typeof document === "undefined") {
1880
- return null;
1881
- }
1882
- return createPortal(
1883
- /* @__PURE__ */ jsx("div", { className: "fixed z-[1000] bottom-0 right-0 p-2", children: /* @__PURE__ */ jsx("div", { className: "p-2 bg-white text-black rounded-md shadow-md", children: "..." }) }),
1884
- document.body
1885
- );
1886
- };
1887
- const ClientRouterContext = createContext(
1888
- {}
1889
- );
1890
- const ClientRouterProvider = (props) => {
1891
- const {
1892
- children,
1893
- pathname,
1894
- currentPath,
1895
- is404,
1896
- routeManifest,
1897
- pageData,
1898
- params,
1899
- searchParams
1900
- } = props;
1901
- const [parameters, setParameters] = useState(params);
1902
- const navigationAbortControllerRef = useRef(new AbortController());
1903
- const [isNavigatingSubject] = useState(() => {
1904
- return new Subject(false);
1905
- });
1906
- const [progressManager] = useState(new ProgressManager(isNavigatingSubject));
1907
- const pageDataRef = useRef(structuredClone(pageData));
1908
- const scrollHistoryRef = useRef(/* @__PURE__ */ new Map());
1909
- const initalViewEntries = is404 ? ["404"] : routeManifest[pathname] ?? ["404"];
1910
- const viewEntriesSubject = useRef(new Subject(initalViewEntries));
1911
- const [locationSubject] = useState(
1912
- () => new Subject({
1913
- hash: "",
1914
- pathname: currentPath,
1915
- search: searchParams,
1916
- state: {},
1917
- key: ""
1918
- })
1919
- );
1920
- const [history] = useState(() => {
1921
- let history2 = null;
1922
- if (typeof window !== "undefined") {
1923
- history2 = createBrowserHistory();
1924
1942
  }
1925
- return history2;
1926
- });
1927
- const handleScroll = () => {
1928
- const key = [
1929
- `${locationSubject.getValue().pathname}?${locationSubject.getValue().search}`
1930
- ].filter((item) => item.length > 0).join("");
1931
- scrollHistoryRef.current.set(key, window.scrollY);
1932
1943
  };
1933
- const findMatchingRouteFromParams = (pathname2) => {
1934
- const candidates = [];
1935
- for (const route2 of Object.keys(routeManifest)) {
1936
- const urlPattern = new me({ pathname: route2 });
1937
- if (urlPattern.test({ pathname: pathname2 })) {
1938
- candidates.push(route2);
1939
- }
1944
+ }
1945
+ function usePost(url, ...args) {
1946
+ return useMutation("POST", url, ...args);
1947
+ }
1948
+ function usePut(url, ...args) {
1949
+ return useMutation("PUT", url, ...args);
1950
+ }
1951
+ function usePatch(url, ...args) {
1952
+ return useMutation("PATCH", url, ...args);
1953
+ }
1954
+ function useDelete(url, ...args) {
1955
+ return useMutation("DELETE", url, ...args);
1956
+ }
1957
+ const MutationContext = createContext({
1958
+ isPending: false,
1959
+ result: null
1960
+ });
1961
+ function Form(props) {
1962
+ const _params = useParams();
1963
+ const {
1964
+ method = "POST",
1965
+ action,
1966
+ onSuccess = () => {
1967
+ },
1968
+ onError = () => {
1969
+ },
1970
+ params,
1971
+ className,
1972
+ ...formProps
1973
+ } = "params" in props ? { ...props, params: { ..._params, ...props.params } } : { ...props, params: _params };
1974
+ const formRef = useRef(null);
1975
+ const { trigger, data, error, loading } = useMutation(
1976
+ method,
1977
+ String(action),
1978
+ {
1979
+ params
1980
+ },
1981
+ {
1982
+ onSuccess: (data2) => onSuccess(data2, formRef.current),
1983
+ onError: (error2) => onError(error2, formRef.current)
1940
1984
  }
1941
- const sortedCandidates = candidates.sort((a, b2) => {
1942
- const x2 = a.split("/").length + a.split(":").length;
1943
- const y2 = b2.split("/").length + b2.split(":").length;
1944
- return x2 - y2;
1945
- });
1946
- const [route] = sortedCandidates ?? [];
1947
- return route;
1948
- };
1949
- const getViewPathsFromPathname = (pathname2) => {
1950
- const route = findMatchingRouteFromParams(pathname2);
1951
- return routeManifest[route] ?? [];
1952
- };
1953
- const getRoutePathnameFromHref = (href) => {
1954
- const route = findMatchingRouteFromParams(href);
1955
- return route;
1956
- };
1957
- const getParams = (pathname2) => {
1958
- var _a2;
1959
- const route = findMatchingRouteFromParams(pathname2);
1960
- const urlPattern = new me({ pathname: route });
1961
- return (_a2 = urlPattern.exec({ pathname: pathname2 })) == null ? void 0 : _a2.pathname.groups;
1962
- };
1963
- useEffect(() => {
1964
- history == null ? void 0 : history.listen(({ location }) => {
1965
- locationSubject.next(structuredClone(location));
1966
- setParameters(getParams(location.pathname));
1967
- viewEntriesSubject.current.next(
1968
- (() => {
1969
- var _a2;
1970
- if (((_a2 = location.state) == null ? void 0 : _a2.status) === 404) {
1971
- return ["404"];
1972
- }
1973
- return getViewPathsFromPathname(location.pathname);
1974
- })()
1975
- );
1976
- });
1977
- window.addEventListener("scrollend", handleScroll);
1978
- return () => {
1979
- window.removeEventListener("scroll", handleScroll);
1980
- };
1981
- }, []);
1982
- const updatePageData = (newPageData) => {
1983
- var _a2;
1984
- const [key, value] = Object.entries(newPageData)[0];
1985
- if (!((_a2 = pageDataRef.current) == null ? void 0 : _a2[key])) {
1986
- pageDataRef.current[key] = {};
1985
+ );
1986
+ const handleSubmit = async (e) => {
1987
+ if (loading) {
1988
+ return;
1987
1989
  }
1988
- pageDataRef.current[key] = value;
1989
- };
1990
- const getPageData = (key) => {
1991
- return pageDataRef.current[locationSubject.getValue().pathname][key];
1992
- };
1993
- const setNavigationAbortController = (controller) => {
1994
- navigationAbortControllerRef.current.abort();
1995
- navigationAbortControllerRef.current = controller;
1990
+ e.preventDefault();
1991
+ trigger(new FormData(formRef.current));
1996
1992
  };
1997
- return /* @__PURE__ */ jsxs(
1998
- ClientRouterContext.Provider,
1993
+ const validationErrors = (error == null ? void 0 : error.kind) === "validation_error" ? error.messages : {};
1994
+ const formError = (error == null ? void 0 : error.kind) === "form_error" ? error.message : null;
1995
+ return /* @__PURE__ */ jsx(
1996
+ MutationContext.Provider,
1999
1997
  {
2000
- value: {
2001
- isNavigatingSubject,
2002
- getViewPathsFromPathname,
2003
- history,
2004
- params: parameters,
2005
- locationSubject,
2006
- getScrollPosition: (path) => {
2007
- return scrollHistoryRef.current.get(path) || 0;
2008
- },
2009
- viewEntriesSubject: viewEntriesSubject.current,
2010
- updatePageData,
2011
- getPageData,
2012
- getRoutePathnameFromHref,
2013
- setNavigationAbortController,
2014
- progressManager
2015
- },
2016
- children: [
2017
- children,
2018
- import.meta.hot && /* @__PURE__ */ jsx(HttpReload, {})
2019
- ]
1998
+ value: { isPending: loading, result: data, validationErrors, formError },
1999
+ children: /* @__PURE__ */ jsx(
2000
+ "form",
2001
+ {
2002
+ className: ["group", className].filter(Boolean).join(" "),
2003
+ "data-loading": loading,
2004
+ ref: formRef,
2005
+ onSubmit: handleSubmit,
2006
+ ...formProps,
2007
+ children: props.children
2008
+ }
2009
+ )
2020
2010
  }
2021
2011
  );
2022
- };
2023
- function useLocationChange(cb) {
2024
- const { locationSubject } = useContext(ClientRouterContext);
2025
- useEffect(() => {
2026
- cb(locationSubject.getValue());
2027
- return locationSubject.subscribe(cb);
2028
- }, []);
2029
2012
  }
2030
- function useLocation() {
2031
- const ctx = useContext(ClientRouterContext);
2032
- if (!ctx) {
2033
- throw new Error("useLocation must be used within a ClientRouterProvider");
2034
- }
2035
- const { locationSubject } = ctx;
2036
- const [location, setLocation] = useState(locationSubject == null ? void 0 : locationSubject.getValue());
2037
- useLocationChange((newLocation) => {
2038
- setLocation(newLocation);
2039
- });
2040
- return location;
2013
+ function useMutationStatus() {
2014
+ const { isPending } = useContext(MutationContext);
2015
+ return { isPending };
2041
2016
  }
2017
+ const ValidationErrors = (props) => {
2018
+ var _a2;
2019
+ const {
2020
+ render = (props2) => /* @__PURE__ */ jsx("div", { ...props2 }),
2021
+ name
2022
+ } = props;
2023
+ const { validationErrors } = useContext(MutationContext);
2024
+ const Comp = render;
2025
+ if (((_a2 = validationErrors[name]) == null ? void 0 : _a2.length) > 0) {
2026
+ return /* @__PURE__ */ jsx(Fragment, { children: validationErrors[name].map((error) => {
2027
+ return /* @__PURE__ */ jsx(Comp, { className: props.className, children: error }, error);
2028
+ }) });
2029
+ }
2030
+ return null;
2031
+ };
2032
+ const FormField = (props) => {
2033
+ const { name, children, ...rest } = props;
2034
+ const { validationErrors } = useContext(MutationContext);
2035
+ const errors = validationErrors[name] || [];
2036
+ return /* @__PURE__ */ jsx("div", { "data-hasError": errors.length > 0, ...rest, children });
2037
+ };
2038
+ const FormError = (props) => {
2039
+ const { formError } = useContext(MutationContext);
2040
+ if (formError) {
2041
+ return /* @__PURE__ */ jsx("div", { ...props, children: formError });
2042
+ }
2043
+ return null;
2044
+ };
2042
2045
  function useIsNavigationPending() {
2043
2046
  const { isNavigatingSubject } = useContext(ClientRouterContext);
2044
2047
  const isNavigating = useSyncExternalStore(
@@ -2065,6 +2068,7 @@ function normalizeSearch(search) {
2065
2068
  );
2066
2069
  }
2067
2070
  const Link = (props) => {
2071
+ const _params = useParams();
2068
2072
  const {
2069
2073
  href,
2070
2074
  onClick,
@@ -2072,7 +2076,7 @@ const Link = (props) => {
2072
2076
  params = {},
2073
2077
  search = {},
2074
2078
  ...rest
2075
- } = { params: {}, search: {}, ...props };
2079
+ } = { params: _params, search: {}, ...props };
2076
2080
  const { push } = useNavigate();
2077
2081
  const location = useLocation();
2078
2082
  const searchParams = new URLSearchParams(normalizeSearch(search));