@hybridly/core 0.10.0-beta.15 → 0.10.0-beta.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -109,7 +109,7 @@ interface RequestHooks {
109
109
  */
110
110
  fail: (error: Error, request: PendingHybridRequest, context: InternalRouterContext) => MaybePromise<any>;
111
111
  /**
112
- * Called after a request has been made, even if it didn't succeed.
112
+ * Called after a response has been received, even if it didn't succeed in a navigation.
113
113
  */
114
114
  after: (request: PendingHybridRequest, context: InternalRouterContext) => MaybePromise<any>;
115
115
  }
@@ -271,11 +271,23 @@ interface CloseDialogOptions extends HybridRequestOptions {
271
271
  local?: boolean;
272
272
  }
273
273
  //#endregion
274
+ //#region src/query.d.ts
275
+ type QueryArrayFormat = 'indices' | 'brackets';
276
+ type QueryValue = string | number | boolean | null | undefined | QueryValue[] | Set<QueryValue> | {
277
+ [key: string]: QueryValue;
278
+ };
279
+ interface StringifyQueryOptions {
280
+ arrayFormat?: QueryArrayFormat;
281
+ addQueryPrefix?: boolean;
282
+ }
283
+ declare function parseQueryString(query: string): Record<string, any>;
284
+ declare function stringifyQueryString(value: QueryValue, options?: StringifyQueryOptions): string;
285
+ //#endregion
274
286
  //#region src/url.d.ts
275
287
  type UrlResolvable = string | URL | Location;
276
288
  type UrlTransformable = BaseUrlTransformable | ((string: URL) => BaseUrlTransformable);
277
289
  type BaseUrlTransformable = Partial<Omit<URL, 'searchParams' | 'toJSON' | 'toString'>> & {
278
- query?: any;
290
+ query?: Record<string, QueryValue>;
279
291
  trailingSlash?: boolean;
280
292
  };
281
293
  /** Normalizes the given input to an URL. */
@@ -553,7 +565,7 @@ type Validation = Record<string, Errors>;
553
565
  declare const router: {
554
566
  abort: () => void;
555
567
  navigate: (options: HybridRequestOptions) => Promise<NavigationResponse>;
556
- reload: (options: HybridRequestOptions | undefined) => Promise<NavigationResponse>;
568
+ reload: (options?: HybridRequestOptions | undefined) => Promise<NavigationResponse>;
557
569
  get: (url: UrlResolvable, options?: Omit<HybridRequestOptions, "method" | "url"> | undefined) => Promise<NavigationResponse>;
558
570
  post: (url: UrlResolvable, options?: Omit<HybridRequestOptions, "method" | "url"> | undefined) => Promise<NavigationResponse>;
559
571
  put: (url: UrlResolvable, options?: Omit<HybridRequestOptions, "method" | "url"> | undefined) => Promise<NavigationResponse>;
@@ -561,8 +573,8 @@ declare const router: {
561
573
  delete: (url: UrlResolvable, options?: Omit<HybridRequestOptions, "method" | "url"> | undefined) => Promise<NavigationResponse>;
562
574
  local: (url: UrlResolvable, options?: ComponentNavigationOptions) => Promise<void>;
563
575
  external: (url: UrlResolvable, data?: _hybridly_utils0.RequestData) => void;
564
- to: <T extends RouteName>(name: T, parameters: Record<string, any> | undefined, options: Omit<HybridRequestOptions, "url"> | undefined) => Promise<NavigationResponse>;
565
- matches: <T extends RouteName>(name: T, parameters: Record<string, any> | undefined) => boolean;
576
+ to: <T extends RouteName>(name: T, parameters?: Record<string, any> | undefined, options?: Omit<HybridRequestOptions, "url"> | undefined) => Promise<NavigationResponse>;
577
+ matches: <T extends RouteName>(name: T, parameters?: Record<string, any> | undefined) => boolean;
566
578
  current: () => string | undefined;
567
579
  dialog: {
568
580
  close: (options?: CloseDialogOptions | undefined) => Promise<void | NavigationResponse>;
@@ -575,15 +587,6 @@ declare const router: {
575
587
  /** Creates the hybridly router. */
576
588
  declare function createRouter(options: RouterContextOptions): Promise<InternalRouterContext>;
577
589
  //#endregion
578
- //#region src/query.d.ts
579
- type QueryArrayFormat = 'indices' | 'brackets';
580
- interface StringifyQueryOptions {
581
- arrayFormat?: QueryArrayFormat;
582
- addQueryPrefix?: boolean;
583
- }
584
- declare function parseQueryString(query: string): Record<string, any>;
585
- declare function stringifyQueryString(value: unknown, options?: StringifyQueryOptions): string;
586
- //#endregion
587
590
  //#region src/authorization.d.ts
588
591
  interface Authorizable<Authorizations extends Record<string, boolean>> {
589
592
  authorization: Authorizations;
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { t as __exportAll } from "./_chunks/chunk.mjs";
2
- import { debug, getByPath, hasFiles, merge, mergeObject, objectToFormData, random, showResponseErrorModal, wrap } from "@hybridly/utils";
2
+ import { debug, hasFiles, merge, mergeObject, objectToFormData, random, showResponseErrorModal, wrap } from "@hybridly/utils";
3
3
  import { trimEnd } from "es-toolkit/string";
4
- import { parse, stringify } from "picoquery";
4
+ import { isPlainObject } from "es-toolkit/predicate";
5
+ import { parse, stringify } from "neoqs";
5
6
  import { debounce } from "es-toolkit/function";
6
7
  import { parse as parse$1, stringify as stringify$1 } from "superjson";
7
8
  import { get, set, uniqBy } from "es-toolkit/compat";
@@ -9,35 +10,15 @@ import { get, set, uniqBy } from "es-toolkit/compat";
9
10
  function parseQueryString(query) {
10
11
  const source = query.startsWith("?") ? query.slice(1) : query;
11
12
  if (!source) return {};
12
- return parse(source, {
13
- nesting: true,
14
- nestingSyntax: "index",
15
- arrayRepeat: true,
16
- arrayRepeatSyntax: "bracket"
17
- });
13
+ return parse(source);
18
14
  }
19
15
  function stringifyQueryString(value, options = {}) {
20
- const normalizedQuery = unescapeBracketSyntaxInKeys(stringify(normalizeQueryValue(value), {
21
- nesting: true,
22
- nestingSyntax: "index",
23
- arrayRepeat: (options.arrayFormat ?? "brackets") === "brackets",
24
- arrayRepeatSyntax: "bracket"
25
- }));
26
- if (!normalizedQuery) return "";
27
- return options.addQueryPrefix ? `?${normalizedQuery}` : normalizedQuery;
28
- }
29
- function unescapeBracketSyntaxInKeys(query) {
30
- if (!query) return query;
31
- return query.split("&").map((entry) => {
32
- const separator = entry.indexOf("=");
33
- if (separator < 0) return decodeBracketSyntax(entry);
34
- const key = entry.slice(0, separator);
35
- const value = entry.slice(separator);
36
- return `${decodeBracketSyntax(key)}${value}`;
37
- }).join("&");
38
- }
39
- function decodeBracketSyntax(value) {
40
- return value.replace(/%5B/gi, "[").replace(/%5D/gi, "]");
16
+ const query = stringify(normalizeQueryValue(value), {
17
+ arrayFormat: options.arrayFormat ?? "brackets",
18
+ encodeValuesOnly: true
19
+ });
20
+ if (!query) return "";
21
+ return options.addQueryPrefix ? `?${query}` : query;
41
22
  }
42
23
  function normalizeQueryValue(value) {
43
24
  if (value instanceof Set) return [...value].map((entry) => normalizeQueryValue(entry));
@@ -48,11 +29,6 @@ function normalizeQueryValue(value) {
48
29
  }), {});
49
30
  return value;
50
31
  }
51
- function isPlainObject(value) {
52
- if (typeof value !== "object" || value === null) return false;
53
- const prototype = Object.getPrototypeOf(value);
54
- return prototype === null || prototype === Object.prototype;
55
- }
56
32
  //#endregion
57
33
  //#region src/url.ts
58
34
  /** Normalizes the given input to an URL. */
@@ -69,9 +45,8 @@ function makeUrl(href, transformations = {}) {
69
45
  transformations = typeof transformations === "function" ? transformations(url) ?? {} : transformations ?? {};
70
46
  Object.entries(transformations).forEach(([key, value]) => {
71
47
  if (key === "query") {
72
- const currentQueryParameters = merge(parseQueryString(url.search), value, { mergePlainObjects: true });
73
48
  key = "search";
74
- value = stringifyQueryString(currentQueryParameters, { arrayFormat: "brackets" });
49
+ value = stringifyQueryString(merge(parseQueryString(url.search), value, { mergePlainObjects: true }), { arrayFormat: "brackets" });
75
50
  }
76
51
  Reflect.set(url, key, value);
77
52
  });
@@ -699,8 +674,8 @@ async function transformOptions(options) {
699
674
  debug.router("Converted data to FormData.", options.data);
700
675
  }
701
676
  if (!(options.data instanceof FormData) && options.method === "GET" && Object.keys(options.data ?? {}).length) {
702
- debug.router("Transforming data to query parameters.", options.data);
703
677
  options.url = makeUrl(options.url ?? context.url, { query: options.data });
678
+ debug.router("Transforming data to query parameters.", options.data, options.url);
704
679
  options.data = {};
705
680
  }
706
681
  if ([
@@ -949,8 +924,8 @@ function isPartial(options) {
949
924
  function resolveProperties(original, payload) {
950
925
  const mergedPayloadProperties = merge(original, payload.properties);
951
926
  (payload.mergeable ?? []).forEach(([mergeableProperty, prepends, uniqueBy]) => {
952
- const originalValue = getByPath(original, mergeableProperty);
953
- const newValue = getByPath(payload.properties, mergeableProperty);
927
+ const originalValue = get(original, mergeableProperty);
928
+ const newValue = get(payload.properties, mergeableProperty);
954
929
  const mergeArrays = (current, incoming) => {
955
930
  const merged = prepends === true ? [...incoming, ...current] : [...current, ...incoming];
956
931
  if (typeof uniqueBy !== "string") return merged;
@@ -1014,7 +989,12 @@ async function processNextResponse() {
1014
989
  return;
1015
990
  }
1016
991
  debug.queue("Processing response", response);
1017
- response.request.resolve(await handleHybridRequestResponse(response));
992
+ try {
993
+ response.request.resolve(await handleHybridRequestResponse(response));
994
+ } finally {
995
+ debug.router("Ended navigation.", response.request);
996
+ await runHooks("after", response.request.options.hooks, response.request, getInternalRouterContext());
997
+ }
1018
998
  return await processNextResponse();
1019
999
  }
1020
1000
  //#endregion
@@ -1071,8 +1051,6 @@ async function processRequest(request, onFinally) {
1071
1051
  await handleTransportError(request, error);
1072
1052
  } finally {
1073
1053
  request.completed = true;
1074
- debug.router("Ended navigation.", request);
1075
- await runHooks("after", request.options.hooks, request, getRouterContext());
1076
1054
  onFinally();
1077
1055
  }
1078
1056
  }
@@ -1535,7 +1513,7 @@ async function closeDialog(options) {
1535
1513
  const router = {
1536
1514
  abort: () => cancelNavigationRequest(),
1537
1515
  navigate: async (options) => await performHybridNavigation(options),
1538
- reload: async (options) => await performHybridNavigation({
1516
+ reload: async (options = {}) => await performHybridNavigation({
1539
1517
  preserveScroll: true,
1540
1518
  preserveState: true,
1541
1519
  replace: true,
@@ -1573,7 +1551,7 @@ const router = {
1573
1551
  }),
1574
1552
  local: async (url, options = {}) => await performLocalNavigation(url, options),
1575
1553
  external: (url, data = {}) => navigateToExternalUrl(url, data),
1576
- to: async (name, parameters, options) => {
1554
+ to: async (name, parameters = void 0, options = {}) => {
1577
1555
  const url = generateRouteFromName(name, parameters);
1578
1556
  const method = getRouteDefinition(name).method.at(0);
1579
1557
  return await performHybridNavigation({
@@ -1582,7 +1560,7 @@ const router = {
1582
1560
  method
1583
1561
  });
1584
1562
  },
1585
- matches: (name, parameters) => currentRouteMatches(name, parameters),
1563
+ matches: (name, parameters = void 0) => currentRouteMatches(name, parameters),
1586
1564
  current: () => getCurrentRouteName(),
1587
1565
  dialog: { close: (options = {}) => closeDialog(options) },
1588
1566
  history: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hybridly/core",
3
3
  "type": "module",
4
- "version": "0.10.0-beta.15",
4
+ "version": "0.10.0-beta.17",
5
5
  "description": "Core functionality of Hybridly",
6
6
  "author": "Enzo Innocenzi <enzo@innocenzi.dev>",
7
7
  "license": "MIT",
@@ -40,8 +40,8 @@
40
40
  "build:stub": "obuild --stub"
41
41
  },
42
42
  "dependencies": {
43
- "@hybridly/utils": "0.10.0-beta.15",
44
- "picoquery": "^2.5.0",
43
+ "@hybridly/utils": "0.10.0-beta.17",
44
+ "neoqs": "^6.13.0",
45
45
  "superjson": "^2.2.2",
46
46
  "es-toolkit": "^1.45.1"
47
47
  },