@atscript/ui-table 0.1.132 → 0.1.134

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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ClientError } from "@atscript/db-client";
2
- import { getDefaultClientFactory } from "@atscript/ui";
2
+ import { getDefaultClientFactory, str } from "@atscript/ui";
3
3
  import { buildUrl } from "@uniqu/url/builder";
4
4
  import { parseUrl } from "@uniqu/url";
5
5
  //#region src/filters/filter-conditions.ts
@@ -148,13 +148,22 @@ function unescapeRegex(input) {
148
148
  //#region src/filters/filter-input-format.ts
149
149
  /**
150
150
  * Coerce a raw string value to the appropriate JS type for the column.
151
- * Number columns get numeric values; everything else stays as string.
151
+ * Number columns get numeric values, boolean columns understand the
152
+ * `true` / `false` vocabulary (case-insensitive) so the condition carries a
153
+ * real boolean and round-trips through the URL as one. Anything else stays
154
+ * a string. Since 0.1.133 for booleans.
152
155
  */
153
156
  function coerceValue(raw, columnType) {
154
157
  if (columnType === "number") {
155
158
  const n = Number(raw);
156
159
  return Number.isNaN(n) ? raw : n;
157
160
  }
161
+ if (columnType === "boolean") {
162
+ const lower = raw.toLowerCase();
163
+ if (lower === "true") return true;
164
+ if (lower === "false") return false;
165
+ return raw;
166
+ }
158
167
  return raw;
159
168
  }
160
169
  /** Default condition type when no symbol matches the input. */
@@ -579,6 +588,10 @@ function derivePresetAspects(content) {
579
588
  * Convert in-memory dict-form snapshot to the wire form persisted on the
580
589
  * server. Entries-arrays are sorted by `field` so consumers (server-side
581
590
  * aspect derivation, dirty detection, equality checks) see a stable order.
591
+ *
592
+ * Empty aspects round-trip as empty (since 0.1.133): a saved view with no
593
+ * filters owns `filterOps` and clears them on apply, which is not the same
594
+ * thing as a view that never claimed the aspect.
582
595
  */
583
596
  function toWireSnapshot(snapshot) {
584
597
  const wire = {};
@@ -591,7 +604,7 @@ function toWireSnapshot(snapshot) {
591
604
  field,
592
605
  width: columnWidths[field]
593
606
  });
594
- if (entries.length > 0) columns.columnWidths = entries;
607
+ columns.columnWidths = entries;
595
608
  }
596
609
  wire.columns = columns;
597
610
  }
@@ -602,7 +615,7 @@ function toWireSnapshot(snapshot) {
602
615
  field,
603
616
  conditions: snapshot.filterOps[field]
604
617
  });
605
- if (entries.length > 0) wire.filterOps = entries;
618
+ wire.filterOps = entries;
606
619
  }
607
620
  if (snapshot.sorters) wire.sorters = snapshot.sorters;
608
621
  if (snapshot.itemsPerPage !== void 0) wire.itemsPerPage = snapshot.itemsPerPage;
@@ -613,7 +626,7 @@ function fromWireSnapshot(wire) {
613
626
  if (wire.columns) {
614
627
  const { columnNames, columnWidths } = wire.columns;
615
628
  const columns = { columnNames };
616
- if (columnWidths && columnWidths.length > 0) {
629
+ if (columnWidths) {
617
630
  const dict = {};
618
631
  for (const entry of columnWidths) dict[entry.field] = entry.width;
619
632
  columns.columnWidths = dict;
@@ -621,7 +634,7 @@ function fromWireSnapshot(wire) {
621
634
  snapshot.columns = columns;
622
635
  }
623
636
  if (wire.filters) snapshot.filters = wire.filters;
624
- if (wire.filterOps && wire.filterOps.length > 0) {
637
+ if (wire.filterOps) {
625
638
  const dict = {};
626
639
  for (const entry of wire.filterOps) dict[entry.field] = entry.conditions;
627
640
  snapshot.filterOps = dict;
@@ -818,7 +831,7 @@ function draftMatchesPreset(draft, presetSnapshot, availableAspects) {
818
831
  /**
819
832
  * Framework-agnostic wrapper over `@atscript/db-client`'s `Client` for the
820
833
  * `AsPresetEntry` table. Handles wire serialisation, list-splitting by
821
- * `type`, capabilities side-channel, and 401/403 → `denied` semantics.
834
+ * `type`, capabilities side-channel, and 401/403/404 → `denied` semantics.
822
835
  *
823
836
  * Stateless: every method is a fresh request. The Vue composable layer
824
837
  * holds reactive state; this class only translates intent → HTTP.
@@ -844,8 +857,8 @@ var PresetsClient = class {
844
857
  * `(app, tableKey)`. By default also fetches `capabilities` in parallel —
845
858
  * pass `{ capabilities: false }` for refresh-after-mutation calls (fav
846
859
  * toggle, default change, save/save-as, public toggle, rename, delete)
847
- * where role-derived capabilities can't have changed. Auth errors
848
- * (401/403) collapse to `denied: true` with empty data so the UI hides
860
+ * where role-derived capabilities can't have changed. Unavailable
861
+ * responses (401/403/404) collapse to `denied: true` with empty data so the UI hides
849
862
  * itself silently.
850
863
  */
851
864
  async list(opts = {}) {
@@ -857,7 +870,7 @@ var PresetsClient = class {
857
870
  };
858
871
  try {
859
872
  const [rows, capabilities] = await Promise.all([this.client.query({ filter }), fetchCapabilities ? this.loadCapabilities().catch((err) => {
860
- if (isAuthError(err)) throw err;
873
+ if (isUnavailableError(err)) throw err;
861
874
  return null;
862
875
  }) : Promise.resolve(void 0)]);
863
876
  const presets = [];
@@ -871,7 +884,7 @@ var PresetsClient = class {
871
884
  denied: false
872
885
  };
873
886
  } catch (err) {
874
- if (isAuthError(err)) return {
887
+ if (isUnavailableError(err)) return {
875
888
  presets: [],
876
889
  userConf: null,
877
890
  capabilities: null,
@@ -987,12 +1000,22 @@ var PresetsHttpError = class extends Error {
987
1000
  this.name = "PresetsHttpError";
988
1001
  }
989
1002
  };
990
- /** True for HTTP 401/403 across both `ClientError` and `PresetsHttpError`. */
991
- function isAuthError(err) {
992
- if (err instanceof ClientError && (err.status === 401 || err.status === 403)) return true;
993
- if (err instanceof PresetsHttpError && (err.status === 401 || err.status === 403)) return true;
994
- return false;
1003
+ /**
1004
+ * True when the presets/app-prefs surface is simply not available to this
1005
+ * client: HTTP 401/403 (not signed in / not permitted) or 404 (the
1006
+ * controller is not mounted on this server). All three collapse to
1007
+ * `denied: true` — the UI hides itself silently instead of surfacing an
1008
+ * error. Covers both `ClientError` and `PresetsHttpError`.
1009
+ */
1010
+ function isUnavailableError(err) {
1011
+ const status = err instanceof ClientError || err instanceof PresetsHttpError ? err.status : void 0;
1012
+ return status === 401 || status === 403 || status === 404;
995
1013
  }
1014
+ /**
1015
+ * @deprecated Renamed to `isUnavailableError` in 0.1.133 — it also covers
1016
+ * 404 (feature not mounted), not just auth failures.
1017
+ */
1018
+ const isAuthError = isUnavailableError;
996
1019
  //#endregion
997
1020
  //#region src/presets/app-prefs-client.ts
998
1021
  /**
@@ -1025,7 +1048,7 @@ var AppPrefsClient = class {
1025
1048
  denied: false
1026
1049
  };
1027
1050
  } catch (err) {
1028
- if (isAuthError(err)) return {
1051
+ if (isUnavailableError(err)) return {
1029
1052
  row: null,
1030
1053
  prefs: null,
1031
1054
  denied: true
@@ -1231,6 +1254,36 @@ function stateToUrlQueryString(state, defaults) {
1231
1254
  return buildUrl(query);
1232
1255
  }
1233
1256
  /**
1257
+ * The `$`-controls {@link urlQueryStringToState} actually reads. Any other
1258
+ * `$key` is ignored by the parser, so it is NOT the table's to remove.
1259
+ */
1260
+ const CONSUMED_CONTROLS = new Set([
1261
+ "$sort",
1262
+ "$search",
1263
+ "$relevance",
1264
+ "$skip"
1265
+ ]);
1266
+ /** Characters that can only appear in a uniqu filter key, never in a page flag. */
1267
+ const FILTER_OPERATOR_CHAR = /[<>!~]/;
1268
+ /**
1269
+ * Whether {@link urlQueryStringToState} would consume the query key `key` —
1270
+ * i.e. whether the key belongs to the table rather than to the page hosting
1271
+ * it. This is the ownership rule the `useTableUrlQuery` router bridge reads
1272
+ * and writes by, so both directions agree: a key the parser ignores is never
1273
+ * removed, and a key it reads is the table's to remove.
1274
+ *
1275
+ * Shape-only, and deliberately conservative for bare `field=value` keys: a
1276
+ * filter on a column and a host flag are indistinguishable without the table
1277
+ * definition, so those are owned only once the bridge has written them
1278
+ * itself (or once a `prefix` namespaces them).
1279
+ *
1280
+ * @since 0.1.133
1281
+ */
1282
+ function urlQueryConsumesKey(key) {
1283
+ if (key.startsWith("$")) return CONSUMED_CONTROLS.has(key);
1284
+ return FILTER_OPERATOR_CHAR.test(key);
1285
+ }
1286
+ /**
1234
1287
  * Parse a URL query string back into the table state subset.
1235
1288
  *
1236
1289
  * Robust by design — schema drift and copy-paste errors must not break the
@@ -1627,4 +1680,222 @@ function reorderColumnNames(names, fromPath, toPath, position) {
1627
1680
  return without.slice(0, insertAt).concat(fromPath, without.slice(insertAt));
1628
1681
  }
1629
1682
  //#endregion
1630
- export { APP_CONF_PREFIX, AppPrefsClient, DEFAULT_ROW_HEIGHT_PX, DRAFT_PERSISTED_ASPECTS, MAX_DEFAULT_COLUMN_WIDTH_PX, NULL_OPS, PRESET_ASPECTS, PresetsClient, PresetsHttpError, RESERVED_ID_PREFIXES, STANDARD_PRESET_ID, SYSTEM_PRESET_PREFIX, USER_CONF_PREFIX, appConfId, arraysEqual, blockStartFor, buildTableQuery, clampTopIndex, columnFilterType, computeDefaultColumnWidth, conditionLabel, conditionsForType, dateShortcuts, debounce, defaultCondition, derivePresetAspects, deserializeDraft, draftMatchesPreset, escapeRegex, filledFilterCount, filterTokenLabel, filtersToUniqueryFilter, formatFilterCondition, fromWireSnapshot, hasSecondValue, isAuthError, isDirtyAgainst, isEmptyDraft, isFilled, isSimpleEq, isSystemPresetId, mergeFilters, mergeSorters, normaliseSystemPresetId, pageAlignedBlocksFor, parseFilterInput, planFetch, reconcileColumnWidthDefaults, reorderColumnNames, resolveAspectGate, resolveSystemPresets, rowsToPks, sameColumnSet, serializeDraft, setsEqual, sortersEqual, stableStringify, stateToUrlQueryString, toWireSnapshot, togglePk, trimSelection, unescapeRegex, uniqueryFilterToFieldFilters, urlQueryStringToState, userConfId, walkBackwardAbsorb, walkForwardAbsorb };
1683
+ //#region src/export/csv.ts
1684
+ const FORMULA_LEADERS = new Set([
1685
+ "=",
1686
+ "+",
1687
+ "-",
1688
+ "@",
1689
+ " ",
1690
+ "\r"
1691
+ ]);
1692
+ /** RFC 4180 row separator. */
1693
+ const CRLF = "\r\n";
1694
+ /**
1695
+ * Render one value as an RFC 4180 field: formula-escaped (unless opted out),
1696
+ * then quoted when it contains the delimiter, a quote, CR or LF — with inner
1697
+ * quotes doubled.
1698
+ */
1699
+ function csvCell(value, opts = {}) {
1700
+ const delimiter = opts.delimiter ?? ",";
1701
+ let text = value === null || value === void 0 ? "" : String(value);
1702
+ if (typeof value === "string" && opts.escapeFormulas !== false && text.length > 0 && FORMULA_LEADERS.has(text[0])) text = `'${text}`;
1703
+ return text.includes(delimiter) || text.includes("\"") || text.includes("\n") || text.includes("\r") ? `"${text.replaceAll("\"", "\"\"")}"` : text;
1704
+ }
1705
+ /**
1706
+ * Serialise a header row + data rows to an RFC 4180 CSV string (`\r\n` row
1707
+ * separators, quoted fields where required, optional UTF-8 BOM).
1708
+ *
1709
+ * Pure — no DOM, no framework. See {@link csvCell} for the per-field rules.
1710
+ */
1711
+ function toCsv(header, rows, opts = {}) {
1712
+ const delimiter = opts.delimiter ?? ",";
1713
+ const lines = [header.map((h) => csvCell(h, opts)).join(delimiter)];
1714
+ for (const row of rows) lines.push(row.map((v) => csvCell(v, opts)).join(delimiter));
1715
+ const body = lines.join(CRLF) + CRLF;
1716
+ return opts.bom ? `${body}` : body;
1717
+ }
1718
+ //#endregion
1719
+ //#region src/export/export-paging.ts
1720
+ /** Default page size used by the export pager when the caller gives none. */
1721
+ const DEFAULT_EXPORT_PAGE_SIZE = 500;
1722
+ /** Rejection raised when an export is cancelled through its `AbortSignal`. */
1723
+ var ExportAbortError = class extends Error {
1724
+ /** Matches the DOM convention so `err.name === "AbortError"` checks work. */
1725
+ name = "AbortError";
1726
+ constructor(message = "Export aborted") {
1727
+ super(message);
1728
+ }
1729
+ };
1730
+ /**
1731
+ * Append the primary key(s) to a query's `$sort` as a tiebreaker so paging is
1732
+ * stable: two rows equal on every user sorter keep a deterministic relative
1733
+ * order, and no row is skipped or duplicated across page boundaries.
1734
+ *
1735
+ * Existing sort fields are preserved in order and never replaced — a pk the
1736
+ * user already sorts by is left where it is. Returns the input query when
1737
+ * there is nothing to add.
1738
+ */
1739
+ function withStableOrder(query, primaryKeys) {
1740
+ if (primaryKeys.length === 0) return query;
1741
+ const current = query.controls?.$sort ?? {};
1742
+ const missing = primaryKeys.filter((pk) => !(pk in current));
1743
+ if (missing.length === 0) return query;
1744
+ const $sort = { ...current };
1745
+ for (const pk of missing) $sort[pk] = 1;
1746
+ return {
1747
+ ...query,
1748
+ controls: {
1749
+ ...query.controls,
1750
+ $sort
1751
+ }
1752
+ };
1753
+ }
1754
+ /**
1755
+ * Page through `query` until the endpoint runs out of rows, collecting every
1756
+ * row into one array.
1757
+ *
1758
+ * Stops when a page comes back short (fewer rows than `pageSize`), when the
1759
+ * reported `count` is reached, or when `maxRows` is hit. Checks `signal`
1760
+ * before and after every request so a cancel lands between pages rather than
1761
+ * mid-flight.
1762
+ */
1763
+ async function collectExportRows(opts) {
1764
+ const pageSize = opts.pageSize && opts.pageSize > 0 ? opts.pageSize : 500;
1765
+ const mapRow = opts.mapRow ?? ((row) => row);
1766
+ const rows = [];
1767
+ let total;
1768
+ let page = 1;
1769
+ for (;;) {
1770
+ throwIfAborted(opts.signal);
1771
+ const result = await opts.fetchPage(opts.query, page, pageSize);
1772
+ throwIfAborted(opts.signal);
1773
+ if (page === 1 && typeof result.count === "number") total = result.count;
1774
+ const data = result.data ?? [];
1775
+ const take = opts.maxRows === void 0 ? data.length : Math.min(data.length, opts.maxRows - rows.length);
1776
+ for (let i = 0; i < take; i++) rows.push(mapRow(data[i]));
1777
+ opts.onProgress?.(rows.length, total);
1778
+ if (data.length < pageSize || opts.maxRows !== void 0 && rows.length >= opts.maxRows || total !== void 0 && rows.length >= total) break;
1779
+ page++;
1780
+ }
1781
+ return {
1782
+ rows,
1783
+ total
1784
+ };
1785
+ }
1786
+ function throwIfAborted(signal) {
1787
+ if (signal?.aborted) throw new ExportAbortError();
1788
+ }
1789
+ //#endregion
1790
+ //#region src/export/export-value.ts
1791
+ /**
1792
+ * Turn a raw cell value into the scalar an export carries, using the same
1793
+ * column metadata the cell renderers read:
1794
+ *
1795
+ * - `null` / `undefined` → `null` (an empty CSV field).
1796
+ * - union / enum columns (`column.options`) → the option's **label**, so the
1797
+ * file reads like the screen; an unknown key falls back to the raw value.
1798
+ * - `Date` → ISO 8601 (spreadsheet- and re-import-friendly, unlike a
1799
+ * locale-formatted date).
1800
+ * - arrays → comma-joined scalars; other objects → JSON.
1801
+ * - numbers / booleans pass through untouched so a spreadsheet keeps them
1802
+ * numeric.
1803
+ *
1804
+ * Callers override per column (`formatters`) or globally (`formatCell`) when
1805
+ * they want different text.
1806
+ */
1807
+ function resolveExportValue(value, column) {
1808
+ if (value === null || value === void 0) return null;
1809
+ const options = column?.options;
1810
+ if (options?.length) {
1811
+ const key = typeof value === "string" || typeof value === "number" ? String(value) : void 0;
1812
+ if (key !== void 0) {
1813
+ const hit = options.find((o) => o.key === key);
1814
+ if (hit) return hit.label;
1815
+ }
1816
+ }
1817
+ if (typeof value === "number" || typeof value === "boolean") return value;
1818
+ if (typeof value === "string") return value;
1819
+ if (value instanceof Date) return value.toISOString();
1820
+ if (Array.isArray(value)) return value.map((v) => scalarText(v)).join(", ");
1821
+ return scalarText(value);
1822
+ }
1823
+ function scalarText(value) {
1824
+ if (value === null || value === void 0 || typeof value === "function") return "";
1825
+ try {
1826
+ return str(value);
1827
+ } catch {
1828
+ return "";
1829
+ }
1830
+ }
1831
+ //#endregion
1832
+ //#region src/columns/display-columns.ts
1833
+ /** Columns with no explicit `order` land after every server column. */
1834
+ const TRAILING_ORDER = Number.MAX_SAFE_INTEGER;
1835
+ /** Turn a {@link DisplayColumnDef} into the `ColumnDef` the table renders. */
1836
+ function displayColumnToDef(def) {
1837
+ return {
1838
+ path: def.key,
1839
+ label: def.label,
1840
+ type: def.type ?? "text",
1841
+ component: def.component,
1842
+ sortable: def.sortable === "local",
1843
+ filterable: false,
1844
+ nullable: true,
1845
+ order: def.order ?? TRAILING_ORDER,
1846
+ width: def.width,
1847
+ local: true
1848
+ };
1849
+ }
1850
+ /**
1851
+ * Merge client-owned columns into the server's column list, ordered by each
1852
+ * column's `order`. `Array#sort` is stable, so server columns that share an
1853
+ * `order` keep their `/meta` sequence. Returns `base` untouched when there is
1854
+ * nothing to merge.
1855
+ */
1856
+ function mergeDisplayColumns(base, display) {
1857
+ if (display.length === 0) return base;
1858
+ return [...base, ...display.map(displayColumnToDef)].toSorted((a, b) => a.order - b.order);
1859
+ }
1860
+ //#endregion
1861
+ //#region src/utils/sort-rows.ts
1862
+ /**
1863
+ * Coerce a primitive cell value to the text used for comparing and matching
1864
+ * cells — the string compare in {@link sortRowsLocally} and the substring
1865
+ * search of an in-memory table. Objects and functions collapse to `""` so
1866
+ * `'[object Object]'` never drives an ordering or matches a search.
1867
+ */
1868
+ function cellAsString(v) {
1869
+ if (v == null) return "";
1870
+ if (typeof v === "string") return v;
1871
+ if (typeof v === "number" || typeof v === "boolean") return v.toString();
1872
+ return "";
1873
+ }
1874
+ /**
1875
+ * Sort rows in memory by `sorters`, numerically when both sides are numbers
1876
+ * and locale-aware otherwise. Returns a NEW array; the input is untouched. A
1877
+ * no-op (returns the input reference) when there is nothing to sort.
1878
+ *
1879
+ * `getValue` reads a sorter's field off a row — pass a dot-path reader for
1880
+ * nested fields; the default is a flat property read.
1881
+ */
1882
+ function sortRowsLocally(rows, sorters, getValue = (row, field) => row[field]) {
1883
+ if (sorters.length === 0 || rows.length < 2) return rows;
1884
+ return rows.toSorted((a, b) => {
1885
+ for (const s of sorters) {
1886
+ const dir = s.direction === "desc" ? -1 : 1;
1887
+ const av = getValue(a, s.field);
1888
+ const bv = getValue(b, s.field);
1889
+ if (typeof av === "number" && typeof bv === "number") {
1890
+ if (av < bv) return -dir;
1891
+ if (av > bv) return dir;
1892
+ } else {
1893
+ const cmp = cellAsString(av).localeCompare(cellAsString(bv));
1894
+ if (cmp !== 0) return cmp * dir;
1895
+ }
1896
+ }
1897
+ return 0;
1898
+ });
1899
+ }
1900
+ //#endregion
1901
+ export { APP_CONF_PREFIX, AppPrefsClient, DEFAULT_EXPORT_PAGE_SIZE, DEFAULT_ROW_HEIGHT_PX, DRAFT_PERSISTED_ASPECTS, ExportAbortError, MAX_DEFAULT_COLUMN_WIDTH_PX, NULL_OPS, PRESET_ASPECTS, PresetsClient, PresetsHttpError, RESERVED_ID_PREFIXES, STANDARD_PRESET_ID, SYSTEM_PRESET_PREFIX, USER_CONF_PREFIX, appConfId, arraysEqual, blockStartFor, buildTableQuery, cellAsString, clampTopIndex, collectExportRows, columnFilterType, computeDefaultColumnWidth, conditionLabel, conditionsForType, csvCell, dateShortcuts, debounce, defaultCondition, derivePresetAspects, deserializeDraft, draftMatchesPreset, escapeRegex, filledFilterCount, filterTokenLabel, filtersToUniqueryFilter, formatFilterCondition, fromWireSnapshot, hasSecondValue, isAuthError, isDirtyAgainst, isEmptyDraft, isFilled, isSimpleEq, isSystemPresetId, isUnavailableError, mergeDisplayColumns, mergeFilters, mergeSorters, normaliseSystemPresetId, pageAlignedBlocksFor, parseFilterInput, planFetch, reconcileColumnWidthDefaults, reorderColumnNames, resolveAspectGate, resolveExportValue, resolveSystemPresets, rowsToPks, sameColumnSet, serializeDraft, setsEqual, sortRowsLocally, sortersEqual, stableStringify, stateToUrlQueryString, toCsv, toWireSnapshot, togglePk, trimSelection, unescapeRegex, uniqueryFilterToFieldFilters, urlQueryConsumesKey, urlQueryStringToState, userConfId, walkBackwardAbsorb, walkForwardAbsorb, withStableOrder };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/ui-table",
3
- "version": "0.1.132",
3
+ "version": "0.1.134",
4
4
  "description": "Framework-agnostic filter model, filter-to-Uniquery conversion, and preset serialization for atscript tables",
5
5
  "keywords": [
6
6
  "atscript",
@@ -42,18 +42,18 @@
42
42
  "access": "public"
43
43
  },
44
44
  "dependencies": {
45
- "@atscript/ui": "0.1.132"
45
+ "@atscript/ui": "0.1.134"
46
46
  },
47
47
  "devDependencies": {
48
- "@atscript/db-client": "^0.1.127",
49
- "@uniqu/core": "^0.1.7",
50
- "@uniqu/url": "^0.1.7",
48
+ "@atscript/db-client": "^0.1.129",
49
+ "@uniqu/core": "^0.1.8",
50
+ "@uniqu/url": "^0.1.8",
51
51
  "vitest": "npm:@voidzero-dev/vite-plus-test@0.1.14"
52
52
  },
53
53
  "peerDependencies": {
54
- "@atscript/db-client": "^0.1.127",
55
- "@uniqu/core": "^0.1.7",
56
- "@uniqu/url": "^0.1.7"
54
+ "@atscript/db-client": "^0.1.129",
55
+ "@uniqu/core": "^0.1.8",
56
+ "@uniqu/url": "^0.1.8"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "vp pack",