@platforma-sdk/ui-vue 1.54.13 → 1.55.0

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,101 +1,119 @@
1
- import { delay as $ } from "../lib/util/helpers/dist/utils.js";
2
- import { uniqueId as V } from "../lib/util/helpers/dist/strings.js";
3
- import { deepClone as c } from "../lib/util/helpers/dist/objects.js";
4
- import { deriveDataFromStorage as M, unwrapResult as i, hasAbortError as z } from "@platforma-sdk/model";
5
- import { ref as b, computed as p, reactive as E } from "vue";
6
- import { parseQuery as J } from "../urls.js";
7
- import { MultiError as L } from "../utils.js";
8
- import { applyPatch as I } from "fast-json-patch";
1
+ import { delay as L } from "../lib/util/helpers/dist/utils.js";
2
+ import { uniqueId as R } from "../lib/util/helpers/dist/strings.js";
3
+ import { deepClone as h } from "../lib/util/helpers/dist/objects.js";
4
+ import { deriveDataFromStorage as N, unwrapResult as p, hasAbortError as G, normalizeBlockStorage as K, getPluginData as X } from "@platforma-sdk/model";
5
+ import { ref as D, reactive as y, computed as g } from "vue";
6
+ import { parseQuery as Y } from "../urls.js";
7
+ import { ensureOutputHasStableFlag as Z, MultiError as W } from "../utils.js";
8
+ import { applyPatch as V } from "fast-json-patch";
9
9
  import { UpdateSerializer as P } from "./UpdateSerializer.js";
10
- import { watchIgnorable as k } from "@vueuse/core";
11
- const j = 150, B = (n) => ({
12
- authorId: (n == null ? void 0 : n.authorId) ?? V(),
13
- localVersion: ((n == null ? void 0 : n.localVersion) ?? 0) + 1
14
- }), N = (n) => {
10
+ import { watchIgnorable as ee } from "@vueuse/core";
11
+ const _ = 150, te = (r) => ({
12
+ authorId: (r == null ? void 0 : r.authorId) ?? R(),
13
+ localVersion: ((r == null ? void 0 : r.localVersion) ?? 0) + 1
14
+ }), F = (r) => {
15
15
  try {
16
- return JSON.stringify(n, null, 2);
16
+ return JSON.stringify(r, null, 2);
17
17
  } catch (u) {
18
18
  return u instanceof Error ? u.message : String(u);
19
19
  }
20
20
  };
21
- function oe(n, u, g) {
22
- const r = (e, ...a) => {
23
- g.debug && console.log(
21
+ function de(r, u, f) {
22
+ const n = (e, ...t) => {
23
+ f.debug && console.log(
24
24
  `%c>>> %c${e}`,
25
25
  "color: orange; font-weight: bold",
26
26
  "color: orange",
27
- ...a.map((t) => N(t))
27
+ ...t.map((a) => F(a))
28
28
  );
29
- }, w = (e, ...a) => {
29
+ }, M = (e, ...t) => {
30
30
  console.error(
31
31
  `%c>>> %c${e}`,
32
32
  "color: red; font-weight: bold",
33
33
  "color: red",
34
- ...a.map((t) => N(t))
34
+ ...t.map((a) => F(a))
35
35
  );
36
36
  }, s = {
37
37
  isExternalSnapshot: !1,
38
38
  author: {
39
- authorId: V(),
39
+ authorId: R(),
40
40
  localVersion: 0
41
41
  }
42
- }, _ = () => (s.author = B(s.author), r("nextAuthorMarker", s.author), s.author), d = b(!1), m = b(n.uTag), S = g.debounceSpan ?? 200, v = new P({ debounceSpan: S }), Q = new P({ debounceSpan: S }), o = b(n.value), y = async (e) => u.mutateStorage({ operation: "update-data", value: e }, _()), R = async (e) => u.setNavigationState(e), O = p(() => {
42
+ }, T = () => (s.author = te(s.author), n("nextAuthorMarker", s.author), s.author), m = D(!1), v = D(r.uTag), b = f.debounceSpan ?? 200, S = new P({ debounceSpan: b }), w = /* @__PURE__ */ new Map(), k = (e) => {
43
+ let t = w.get(e);
44
+ return t || (t = new P({ debounceSpan: b }), w.set(e, t)), t;
45
+ }, q = new P({ debounceSpan: b }), c = y({}), o = D(r.value), A = async (e) => u.mutateStorage({ operation: "update-block-data", value: e }, T()), I = async (e, t) => u.mutateStorage(
46
+ { operation: "update-plugin-data", pluginId: e, value: t },
47
+ T()
48
+ ), E = (e) => {
49
+ const t = K(o.value.blockStorage);
50
+ return X(t, e);
51
+ }, z = async (e) => u.setNavigationState(e), C = g(() => {
43
52
  const e = Object.entries(o.value.outputs).map(
44
- ([a, t]) => [a, t.ok && t.value !== void 0 ? t.value : void 0]
53
+ ([t, a]) => {
54
+ var l;
55
+ return (l = u.blockModelInfo.outputs[t]) != null && l.withStatus ? [t, Z(a)] : [
56
+ t,
57
+ a.ok && a.value !== void 0 ? a.value : void 0
58
+ ];
59
+ }
45
60
  );
46
61
  return Object.fromEntries(e);
47
- }), q = p(() => {
62
+ }), U = g(() => {
48
63
  const e = Object.entries(o.value.outputs).map(
49
- ([a, t]) => [
50
- a,
51
- t && t.ok === !1 ? new L(t.errors) : void 0
64
+ ([t, a]) => [
65
+ t,
66
+ a && a.ok === !1 ? new W(a.errors) : void 0
52
67
  ]
53
68
  );
54
69
  return Object.fromEntries(e);
55
- }), l = E({
70
+ }), d = y({
56
71
  apiVersion: 3,
57
72
  error: "",
58
73
  model: {
59
- data: c(M(o.value.blockStorage)),
60
- outputs: O,
61
- outputErrors: q
74
+ data: h(N(o.value.blockStorage)),
75
+ outputs: C,
76
+ outputErrors: U
62
77
  }
63
- }), { ignoreUpdates: D } = k(
64
- () => l.model,
78
+ }), { ignoreUpdates: j } = ee(
79
+ () => d.model,
65
80
  (e) => {
66
- const a = c(e);
67
- r("setDataQueue appModel.model, data", a.data), v.run(() => y(a.data).then(i));
81
+ const t = h(e);
82
+ n("setDataQueue appModel.model, data", t.data), S.run(() => A(t.data).then(p));
68
83
  },
69
84
  { deep: !0 }
70
- ), C = (e) => {
71
- r("updateAppModel", e), l.model.data = c(e.data);
85
+ ), $ = (e) => {
86
+ n("updateAppModel", e), d.model.data = h(e.data);
72
87
  };
73
88
  (async () => {
74
- var e, a;
89
+ var e, t;
75
90
  for (window.addEventListener("beforeunload", () => {
76
- d.value = !0, u.dispose().then(i).catch((t) => {
77
- w("error in dispose", t);
91
+ m.value = !0, u.dispose().then(p).catch((a) => {
92
+ M("error in dispose", a);
78
93
  });
79
- }); !d.value; )
94
+ }); !m.value; )
80
95
  try {
81
- const t = await u.getPatches(m.value).then(i);
82
- if (r("patches.length", t.value.length), r("uTagRef.value", m.value), r("patches.uTag", t.uTag), r("patches.author", t.author), r("data.author", s.author), m.value = t.uTag, t.value.length === 0) {
83
- await new Promise((f) => setTimeout(f, j));
96
+ const a = await u.getPatches(v.value).then(p);
97
+ if (n("patches.length", a.value.length), n("uTagRef.value", v.value), n("patches.uTag", a.uTag), n("patches.author", a.author), n("data.author", s.author), v.value = a.uTag, a.value.length === 0) {
98
+ await new Promise((i) => setTimeout(i, _));
84
99
  continue;
85
100
  }
86
- const h = ((e = s.author) == null ? void 0 : e.authorId) !== ((a = t.author) == null ? void 0 : a.authorId);
87
- h || s.isExternalSnapshot ? (r("got external changes, applying them to the snapshot", t.value), D(() => {
88
- o.value = I(o.value, t.value, !1, !1).newDocument, C({ data: M(o.value.blockStorage) }), s.isExternalSnapshot = h;
89
- })) : (r("outputs changed", t.value), D(() => {
90
- o.value = I(o.value, t.value).newDocument;
91
- })), await new Promise((f) => setTimeout(f, j));
92
- } catch (t) {
93
- z(t) ? (r("patches loop aborted"), d.value = !0) : (w("error in patches loop", t), await new Promise((h) => setTimeout(h, 1e3)));
101
+ const l = ((e = s.author) == null ? void 0 : e.authorId) !== ((t = a.author) == null ? void 0 : t.authorId);
102
+ l || s.isExternalSnapshot ? (n("got external changes, applying them to the snapshot", a.value), j(() => {
103
+ o.value = V(o.value, a.value, !1, !1).newDocument, $({ data: N(o.value.blockStorage) });
104
+ for (const i of Object.keys(c))
105
+ c[i] = E(i);
106
+ s.isExternalSnapshot = l;
107
+ })) : (n("outputs changed", a.value), j(() => {
108
+ o.value = V(o.value, a.value).newDocument;
109
+ })), await new Promise((i) => setTimeout(i, _));
110
+ } catch (a) {
111
+ G(a) ? (n("patches loop aborted"), m.value = !0) : (M("error in patches loop", a), await new Promise((l) => setTimeout(l, 1e3)));
94
112
  }
95
113
  })();
96
- const T = () => c(l.model.data), x = () => c(o.value.navigationState), F = {
97
- cloneData: T,
98
- cloneNavigationState: x,
114
+ const x = () => h(d.model.data), O = () => h(o.value.navigationState), B = {
115
+ cloneData: x,
116
+ cloneNavigationState: O,
99
117
  /**
100
118
  * Updates the UI state by applying a callback.
101
119
  *
@@ -104,8 +122,8 @@ function oe(n, u, g) {
104
122
  * @todo Make it mutable since there is already an initial one
105
123
  */
106
124
  updateData(e) {
107
- const a = e(T());
108
- return r("updateData", a), l.model.data = a, v.run(() => y(a).then(i));
125
+ const t = e(x());
126
+ return n("updateData", t), d.model.data = t, S.run(() => A(t).then(p));
109
127
  },
110
128
  /**
111
129
  * Navigates to a specific href by updating the navigation state.
@@ -114,26 +132,41 @@ function oe(n, u, g) {
114
132
  * @returns A promise resolving after the navigation state is updated.
115
133
  */
116
134
  navigateTo(e) {
117
- const a = x();
118
- return a.href = e, Q.run(() => R(a).then(i));
135
+ const t = O();
136
+ return t.href = e, q.run(() => z(t).then(p));
119
137
  },
120
138
  async allSettled() {
121
- return await $(0), v.allSettled();
139
+ await L(0);
140
+ const e = [
141
+ S.allSettled(),
142
+ ...Array.from(w.values()).map((t) => t.allSettled())
143
+ ];
144
+ await Promise.all(e);
145
+ }
146
+ }, H = {
147
+ pluginDataMap: c,
148
+ setPluginData(e, t) {
149
+ return c[e] = t, n("setPluginData", e, t), k(e).run(
150
+ () => I(e, t).then(p)
151
+ );
152
+ },
153
+ initPluginDataSlot(e) {
154
+ e in c || (c[e] = E(e));
122
155
  }
123
- }, U = {
124
- closedRef: d,
156
+ }, J = {
157
+ closedRef: m,
125
158
  snapshot: o,
126
- queryParams: p(() => J(o.value.navigationState.href)),
127
- href: p(() => o.value.navigationState.href),
128
- hasErrors: p(
159
+ queryParams: g(() => Y(o.value.navigationState.href)),
160
+ href: g(() => o.value.navigationState.href),
161
+ hasErrors: g(
129
162
  () => Object.values(o.value.outputs).some((e) => !(e != null && e.ok))
130
163
  )
131
- }, A = E(Object.assign(l, F, U));
132
- return g.debug && (globalThis.__block_app__ = A), A;
164
+ }, Q = Object.assign(y(Object.assign(d, J)), B);
165
+ return f.debug && (globalThis.__block_app__ = Q), { app: Q, pluginAccess: H };
133
166
  }
134
167
  export {
135
- oe as createAppV3,
136
- B as createNextAuthorMarker,
137
- j as patchPoolingDelay
168
+ de as createAppV3,
169
+ te as createNextAuthorMarker,
170
+ _ as patchPoolingDelay
138
171
  };
139
172
  //# sourceMappingURL=createAppV3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createAppV3.js","sources":["../../src/internal/createAppV3.ts"],"sourcesContent":["import { deepClone, delay, uniqueId } from \"@milaboratories/helpers\";\nimport type { Mutable } from \"@milaboratories/helpers\";\nimport type {\n NavigationState,\n BlockOutputsBase,\n BlockStateV3,\n PlatformaV3,\n ValueWithUTag,\n AuthorMarker,\n} from \"@platforma-sdk/model\";\nimport { hasAbortError, unwrapResult, deriveDataFromStorage } from \"@platforma-sdk/model\";\nimport type { Ref } from \"vue\";\nimport { reactive, computed, ref } from \"vue\";\nimport type { OutputValues, OutputErrors, AppSettings } from \"../types\";\nimport { parseQuery } from \"../urls\";\nimport { MultiError } from \"../utils\";\nimport { applyPatch } from \"fast-json-patch\";\nimport { UpdateSerializer } from \"./UpdateSerializer\";\nimport { watchIgnorable } from \"@vueuse/core\";\n\nexport const patchPoolingDelay = 150;\n\nexport const createNextAuthorMarker = (marker: AuthorMarker | undefined): AuthorMarker => ({\n authorId: marker?.authorId ?? uniqueId(),\n localVersion: (marker?.localVersion ?? 0) + 1,\n});\n\nconst stringifyForDebug = (v: unknown) => {\n try {\n return JSON.stringify(v, null, 2);\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n};\n\n/**\n * Creates an application instance with reactive state management, outputs, and methods for state updates and navigation.\n *\n * @template Args - The type of arguments used in the application.\n * @template Outputs - The type of block outputs extending `BlockOutputsBase`.\n * @template Data - The type of the block data.\n * @template Href - The type of navigation href, defaulting to a string starting with `/`.\n *\n * @param state - Initial state of the application, including args, outputs, UI state, and navigation state.\n * @param platforma - A platform interface for interacting with block states.\n * @param settings - Application settings, such as debug flags.\n *\n * @returns A reactive application object with methods, getters, and state.\n */\nexport function createAppV3<\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Data = unknown,\n Href extends `/${string}` = `/${string}`,\n>(\n state: ValueWithUTag<BlockStateV3<Outputs, Data, Href>>,\n platforma: PlatformaV3<Args, Outputs, Data, Href>,\n settings: AppSettings,\n) {\n const debug = (msg: string, ...rest: unknown[]) => {\n if (settings.debug) {\n console.log(\n `%c>>> %c${msg}`,\n \"color: orange; font-weight: bold\",\n \"color: orange\",\n ...rest.map((r) => stringifyForDebug(r)),\n );\n }\n };\n\n const error = (msg: string, ...rest: unknown[]) => {\n console.error(\n `%c>>> %c${msg}`,\n \"color: red; font-weight: bold\",\n \"color: red\",\n ...rest.map((r) => stringifyForDebug(r)),\n );\n };\n\n const data = {\n isExternalSnapshot: false,\n author: {\n authorId: uniqueId(),\n localVersion: 0,\n },\n };\n\n const nextAuthorMarker = () => {\n data.author = createNextAuthorMarker(data.author);\n debug(\"nextAuthorMarker\", data.author);\n return data.author;\n };\n\n const closedRef = ref(false);\n\n const uTagRef = ref(state.uTag);\n\n const debounceSpan = settings.debounceSpan ?? 200;\n\n const setDataQueue = new UpdateSerializer({ debounceSpan });\n const setNavigationStateQueue = new UpdateSerializer({ debounceSpan });\n /**\n * Reactive snapshot of the application state, including args, outputs, UI state, and navigation state.\n */\n const snapshot = ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>(state.value) as Ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>;\n\n const updateData = async (value: Data) => {\n return platforma.mutateStorage({ operation: \"update-data\", value }, nextAuthorMarker());\n };\n\n const setNavigationState = async (state: NavigationState<Href>) => {\n return platforma.setNavigationState(state);\n };\n\n const outputs = computed<OutputValues<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>).map(\n ([k, vOrErr]) => [k, vOrErr.ok && vOrErr.value !== undefined ? vOrErr.value : undefined],\n );\n return Object.fromEntries(entries);\n });\n\n const outputErrors = computed<OutputErrors<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>).map(\n ([k, vOrErr]) => [\n k,\n vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined,\n ],\n );\n return Object.fromEntries(entries);\n });\n\n const appModel = reactive({\n apiVersion: 3,\n error: \"\",\n model: {\n data: deepClone(deriveDataFromStorage<Data>(snapshot.value.blockStorage)) as Data,\n outputs,\n outputErrors,\n },\n }) as {\n error: string;\n model: {\n data: Data;\n outputs: OutputValues<Outputs>;\n outputErrors: OutputErrors<Outputs>;\n };\n };\n\n const { ignoreUpdates } = watchIgnorable(\n () => appModel.model,\n (_newData) => {\n const newData = deepClone(_newData);\n debug(\"setDataQueue appModel.model, data\", newData.data);\n setDataQueue.run(() => updateData(newData.data).then(unwrapResult));\n },\n { deep: true },\n );\n\n const updateAppModel = (newData: { data: Data }) => {\n debug(\"updateAppModel\", newData);\n appModel.model.data = deepClone(newData.data) as Data;\n };\n\n (async () => {\n window.addEventListener(\"beforeunload\", () => {\n closedRef.value = true;\n platforma\n .dispose()\n .then(unwrapResult)\n .catch((err) => {\n error(\"error in dispose\", err);\n });\n });\n\n while (!closedRef.value) {\n try {\n const patches = await platforma.getPatches(uTagRef.value).then(unwrapResult);\n\n debug(\"patches.length\", patches.value.length);\n debug(\"uTagRef.value\", uTagRef.value);\n debug(\"patches.uTag\", patches.uTag);\n debug(\"patches.author\", patches.author);\n debug(\"data.author\", data.author);\n\n uTagRef.value = patches.uTag;\n\n if (patches.value.length === 0) {\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n continue;\n }\n\n const isAuthorChanged = data.author?.authorId !== patches.author?.authorId;\n\n // Immutable behavior, apply external changes to the snapshot\n if (isAuthorChanged || data.isExternalSnapshot) {\n debug(\"got external changes, applying them to the snapshot\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value, false, false).newDocument;\n updateAppModel({ data: deriveDataFromStorage<Data>(snapshot.value.blockStorage) });\n data.isExternalSnapshot = isAuthorChanged;\n });\n } else {\n // Mutable behavior\n debug(\"outputs changed\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value).newDocument;\n });\n }\n\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n } catch (err) {\n if (hasAbortError(err)) {\n debug(\"patches loop aborted\");\n closedRef.value = true;\n } else {\n error(\"error in patches loop\", err);\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n }\n }\n })();\n\n const cloneData = () => deepClone(appModel.model.data) as Data;\n const cloneNavigationState = () =>\n deepClone(snapshot.value.navigationState) as Mutable<NavigationState<Href>>;\n\n const methods = {\n cloneData,\n cloneNavigationState,\n /**\n * Updates the UI state by applying a callback.\n *\n * @param cb - Callback to modify the current UI state.\n * @returns A promise resolving after the update is applied.\n * @todo Make it mutable since there is already an initial one\n */\n updateData(cb: (data: Data) => Data): Promise<boolean> {\n const newData = cb(cloneData());\n debug(\"updateData\", newData);\n appModel.model.data = newData;\n return setDataQueue.run(() => updateData(newData).then(unwrapResult));\n },\n /**\n * Navigates to a specific href by updating the navigation state.\n *\n * @param href - The target href to navigate to.\n * @returns A promise resolving after the navigation state is updated.\n */\n navigateTo(href: Href) {\n const newState = cloneNavigationState();\n newState.href = href;\n return setNavigationStateQueue.run(() => setNavigationState(newState).then(unwrapResult));\n },\n async allSettled() {\n await delay(0);\n return setDataQueue.allSettled();\n },\n };\n\n const getters = {\n closedRef,\n snapshot,\n queryParams: computed(() => parseQuery<Href>(snapshot.value.navigationState.href as Href)),\n href: computed(() => snapshot.value.navigationState.href),\n hasErrors: computed(() =>\n Object.values(snapshot.value.outputs as Partial<Readonly<Outputs>>).some((v) => !v?.ok),\n ),\n };\n\n const app = reactive(Object.assign(appModel, methods, getters));\n\n if (settings.debug) {\n // @ts-expect-error (to inspect in console in debug mode)\n globalThis.__block_app__ = app;\n }\n\n return app;\n}\n\nexport type BaseAppV3<\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Data = unknown,\n Href extends `/${string}` = `/${string}`,\n> = ReturnType<typeof createAppV3<Args, Outputs, Data, Href>>;\n"],"names":["patchPoolingDelay","createNextAuthorMarker","marker","uniqueId","stringifyForDebug","v","err","createAppV3","state","platforma","settings","debug","msg","rest","r","error","data","nextAuthorMarker","closedRef","ref","uTagRef","debounceSpan","setDataQueue","UpdateSerializer","setNavigationStateQueue","snapshot","updateData","value","setNavigationState","outputs","computed","entries","k","vOrErr","outputErrors","MultiError","appModel","reactive","deepClone","deriveDataFromStorage","ignoreUpdates","watchIgnorable","_newData","newData","unwrapResult","updateAppModel","patches","resolve","isAuthorChanged","_a","_b","applyPatch","hasAbortError","cloneData","cloneNavigationState","methods","cb","href","newState","delay","getters","parseQuery","app"],"mappings":"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"}
1
+ {"version":3,"file":"createAppV3.js","sources":["../../src/internal/createAppV3.ts"],"sourcesContent":["import { deepClone, delay, uniqueId } from \"@milaboratories/helpers\";\nimport type { Mutable } from \"@milaboratories/helpers\";\nimport type {\n NavigationState,\n BlockOutputsBase,\n BlockStateV3,\n PlatformaV3,\n ValueWithUTag,\n AuthorMarker,\n PlatformaExtended,\n} from \"@platforma-sdk/model\";\nimport {\n hasAbortError,\n unwrapResult,\n deriveDataFromStorage,\n getPluginData,\n normalizeBlockStorage,\n} from \"@platforma-sdk/model\";\nimport type { Ref } from \"vue\";\nimport { reactive, computed, ref } from \"vue\";\nimport type { OutputValues, OutputErrors, AppSettings } from \"../types\";\nimport { parseQuery } from \"../urls\";\nimport { ensureOutputHasStableFlag, MultiError } from \"../utils\";\nimport { applyPatch } from \"fast-json-patch\";\nimport { UpdateSerializer } from \"./UpdateSerializer\";\nimport { watchIgnorable } from \"@vueuse/core\";\n\nexport const patchPoolingDelay = 150;\n\n/** Internal interface for plugin data access — injected separately from the app. */\nexport interface PluginDataAccess {\n readonly pluginDataMap: Record<string, unknown>;\n setPluginData(pluginId: string, value: unknown): Promise<boolean>;\n initPluginDataSlot(pluginId: string): void;\n}\n\nexport const createNextAuthorMarker = (marker: AuthorMarker | undefined): AuthorMarker => ({\n authorId: marker?.authorId ?? uniqueId(),\n localVersion: (marker?.localVersion ?? 0) + 1,\n});\n\nconst stringifyForDebug = (v: unknown) => {\n try {\n return JSON.stringify(v, null, 2);\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n};\n\n/**\n * Creates an application instance with reactive state management, outputs, and methods for state updates and navigation.\n *\n * @template Args - The type of arguments used in the application.\n * @template Outputs - The type of block outputs extending `BlockOutputsBase`.\n * @template Data - The type of the block data.\n * @template Href - The type of navigation href, defaulting to a string starting with `/`.\n *\n * @param state - Initial state of the application, including args, outputs, UI state, and navigation state.\n * @param platforma - A platform interface for interacting with block states.\n * @param settings - Application settings, such as debug flags.\n *\n * @returns A reactive application object with methods, getters, and state.\n */\nexport function createAppV3<\n Data = unknown,\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Href extends `/${string}` = `/${string}`,\n>(\n state: ValueWithUTag<BlockStateV3<Data, Outputs, Href>>,\n platforma: PlatformaExtended<PlatformaV3<Data, Args, Outputs, Href>>,\n settings: AppSettings,\n) {\n const debug = (msg: string, ...rest: unknown[]) => {\n if (settings.debug) {\n console.log(\n `%c>>> %c${msg}`,\n \"color: orange; font-weight: bold\",\n \"color: orange\",\n ...rest.map((r) => stringifyForDebug(r)),\n );\n }\n };\n\n const error = (msg: string, ...rest: unknown[]) => {\n console.error(\n `%c>>> %c${msg}`,\n \"color: red; font-weight: bold\",\n \"color: red\",\n ...rest.map((r) => stringifyForDebug(r)),\n );\n };\n\n const data = {\n isExternalSnapshot: false,\n author: {\n authorId: uniqueId(),\n localVersion: 0,\n },\n };\n\n const nextAuthorMarker = () => {\n data.author = createNextAuthorMarker(data.author);\n debug(\"nextAuthorMarker\", data.author);\n return data.author;\n };\n\n const closedRef = ref(false);\n\n const uTagRef = ref(state.uTag);\n\n const debounceSpan = settings.debounceSpan ?? 200;\n\n const setDataQueue = new UpdateSerializer({ debounceSpan });\n const pluginDataQueues = new Map<string, UpdateSerializer>();\n const getPluginDataQueue = (pluginId: string): UpdateSerializer => {\n let queue = pluginDataQueues.get(pluginId);\n if (!queue) {\n queue = new UpdateSerializer({ debounceSpan });\n pluginDataQueues.set(pluginId, queue);\n }\n return queue;\n };\n const setNavigationStateQueue = new UpdateSerializer({ debounceSpan });\n\n /** Reactive map of plugin data keyed by pluginId. Optimistic state for plugin components. */\n const pluginDataMap = reactive<Record<string, unknown>>({});\n /**\n * Reactive snapshot of the application state, including args, outputs, UI state, and navigation state.\n */\n const snapshot = ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>(state.value) as Ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>;\n\n const updateData = async (value: Data) => {\n return platforma.mutateStorage({ operation: \"update-block-data\", value }, nextAuthorMarker());\n };\n\n const updatePluginData = async (pluginId: string, value: unknown) => {\n return platforma.mutateStorage(\n { operation: \"update-plugin-data\", pluginId, value },\n nextAuthorMarker(),\n );\n };\n\n /** Derives plugin data for a given pluginId from the current snapshot. */\n const derivePluginDataFromSnapshot = (pluginId: string): unknown => {\n const storage = normalizeBlockStorage(snapshot.value.blockStorage);\n return getPluginData(storage, pluginId);\n };\n\n const setNavigationState = async (state: NavigationState<Href>) => {\n return platforma.setNavigationState(state);\n };\n\n const outputs = computed<OutputValues<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>).map(\n ([k, outputWithStatus]) =>\n platforma.blockModelInfo.outputs[k]?.withStatus\n ? [k, ensureOutputHasStableFlag(outputWithStatus)]\n : [\n k,\n outputWithStatus.ok && outputWithStatus.value !== undefined\n ? outputWithStatus.value\n : undefined,\n ],\n );\n return Object.fromEntries(entries);\n });\n\n const outputErrors = computed<OutputErrors<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>).map(\n ([k, vOrErr]) => [\n k,\n vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined,\n ],\n );\n return Object.fromEntries(entries);\n });\n\n const appModel = reactive({\n apiVersion: 3,\n error: \"\",\n model: {\n data: deepClone(deriveDataFromStorage<Data>(snapshot.value.blockStorage)) as Data,\n outputs,\n outputErrors,\n },\n }) as {\n error: string;\n model: {\n data: Data;\n outputs: OutputValues<Outputs>;\n outputErrors: OutputErrors<Outputs>;\n };\n };\n\n const { ignoreUpdates } = watchIgnorable(\n () => appModel.model,\n (_newData) => {\n const newData = deepClone(_newData);\n debug(\"setDataQueue appModel.model, data\", newData.data);\n setDataQueue.run(() => updateData(newData.data).then(unwrapResult));\n },\n { deep: true },\n );\n\n const updateAppModel = (newData: { data: Data }) => {\n debug(\"updateAppModel\", newData);\n appModel.model.data = deepClone(newData.data) as Data;\n };\n\n (async () => {\n window.addEventListener(\"beforeunload\", () => {\n closedRef.value = true;\n platforma\n .dispose()\n .then(unwrapResult)\n .catch((err) => {\n error(\"error in dispose\", err);\n });\n });\n\n while (!closedRef.value) {\n try {\n const patches = await platforma.getPatches(uTagRef.value).then(unwrapResult);\n\n debug(\"patches.length\", patches.value.length);\n debug(\"uTagRef.value\", uTagRef.value);\n debug(\"patches.uTag\", patches.uTag);\n debug(\"patches.author\", patches.author);\n debug(\"data.author\", data.author);\n\n uTagRef.value = patches.uTag;\n\n if (patches.value.length === 0) {\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n continue;\n }\n\n const isAuthorChanged = data.author?.authorId !== patches.author?.authorId;\n\n // Immutable behavior, apply external changes to the snapshot\n if (isAuthorChanged || data.isExternalSnapshot) {\n debug(\"got external changes, applying them to the snapshot\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value, false, false).newDocument;\n updateAppModel({ data: deriveDataFromStorage<Data>(snapshot.value.blockStorage) });\n // Reconcile plugin data from external source\n for (const pluginId of Object.keys(pluginDataMap)) {\n pluginDataMap[pluginId] = derivePluginDataFromSnapshot(pluginId);\n }\n data.isExternalSnapshot = isAuthorChanged;\n });\n } else {\n // Mutable behavior\n debug(\"outputs changed\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value).newDocument;\n });\n }\n\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n } catch (err) {\n if (hasAbortError(err)) {\n debug(\"patches loop aborted\");\n closedRef.value = true;\n } else {\n error(\"error in patches loop\", err);\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n }\n }\n })();\n\n const cloneData = () => deepClone(appModel.model.data) as Data;\n const cloneNavigationState = () =>\n deepClone(snapshot.value.navigationState) as Mutable<NavigationState<Href>>;\n\n const methods = {\n cloneData,\n cloneNavigationState,\n /**\n * Updates the UI state by applying a callback.\n *\n * @param cb - Callback to modify the current UI state.\n * @returns A promise resolving after the update is applied.\n * @todo Make it mutable since there is already an initial one\n */\n updateData(cb: (data: Data) => Data): Promise<boolean> {\n const newData = cb(cloneData());\n debug(\"updateData\", newData);\n appModel.model.data = newData;\n return setDataQueue.run(() => updateData(newData).then(unwrapResult));\n },\n /**\n * Navigates to a specific href by updating the navigation state.\n *\n * @param href - The target href to navigate to.\n * @returns A promise resolving after the navigation state is updated.\n */\n navigateTo(href: Href) {\n const newState = cloneNavigationState();\n newState.href = href;\n return setNavigationStateQueue.run(() => setNavigationState(newState).then(unwrapResult));\n },\n async allSettled() {\n await delay(0);\n const allQueues = [\n setDataQueue.allSettled(),\n ...Array.from(pluginDataQueues.values()).map((q) => q.allSettled()),\n ];\n await Promise.all(allQueues);\n },\n };\n\n /** Plugin internals — provided via separate injection key, not exposed on useApp(). */\n const pluginAccess: PluginDataAccess = {\n pluginDataMap,\n setPluginData(pluginId: string, value: unknown): Promise<boolean> {\n pluginDataMap[pluginId] = value;\n debug(\"setPluginData\", pluginId, value);\n return getPluginDataQueue(pluginId).run(() =>\n updatePluginData(pluginId, value).then(unwrapResult),\n );\n },\n initPluginDataSlot(pluginId: string): void {\n if (!(pluginId in pluginDataMap)) {\n pluginDataMap[pluginId] = derivePluginDataFromSnapshot(pluginId);\n }\n },\n };\n\n const getters = {\n closedRef,\n snapshot,\n queryParams: computed(() => parseQuery<Href>(snapshot.value.navigationState.href as Href)),\n href: computed(() => snapshot.value.navigationState.href),\n hasErrors: computed(() =>\n Object.values(snapshot.value.outputs as Partial<Readonly<Outputs>>).some((v) => !v?.ok),\n ),\n };\n\n const app = Object.assign(reactive(Object.assign(appModel, getters)), methods);\n\n if (settings.debug) {\n // @ts-expect-error (to inspect in console in debug mode)\n globalThis.__block_app__ = app;\n }\n\n return { app, pluginAccess };\n}\n\nexport type BaseAppV3<\n Data = unknown,\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Href extends `/${string}` = `/${string}`,\n> = ReturnType<typeof createAppV3<Data, Args, Outputs, Href>>[\"app\"];\n"],"names":["patchPoolingDelay","createNextAuthorMarker","marker","uniqueId","stringifyForDebug","v","err","createAppV3","state","platforma","settings","debug","msg","rest","r","error","data","nextAuthorMarker","closedRef","ref","uTagRef","debounceSpan","setDataQueue","UpdateSerializer","pluginDataQueues","getPluginDataQueue","pluginId","queue","setNavigationStateQueue","pluginDataMap","reactive","snapshot","updateData","value","updatePluginData","derivePluginDataFromSnapshot","storage","normalizeBlockStorage","getPluginData","setNavigationState","outputs","computed","entries","k","outputWithStatus","_a","ensureOutputHasStableFlag","outputErrors","vOrErr","MultiError","appModel","deepClone","deriveDataFromStorage","ignoreUpdates","watchIgnorable","_newData","newData","unwrapResult","updateAppModel","patches","resolve","isAuthorChanged","_b","applyPatch","hasAbortError","cloneData","cloneNavigationState","methods","cb","href","newState","delay","allQueues","q","pluginAccess","getters","parseQuery","app"],"mappings":"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"}
package/dist/lib.d.ts CHANGED
@@ -19,6 +19,7 @@ export * from './components/PlAnnotations';
19
19
  export * from './components/PlBtnExportArchive';
20
20
  export * from './components/PlAdvancedFilter';
21
21
  export * from './defineApp';
22
+ export { usePluginData } from './usePluginData';
22
23
  export * from './createModel';
23
24
  export * from './types';
24
25
  export * from './defineStore';
package/dist/lib.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,gDAAgD,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AAClG,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AAEhG,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,cAAc,aAAa,CAAC;AAE5B,cAAc,+BAA+B,CAAC;AAE9C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AAErD,cAAc,4BAA4B,CAAC;AAE3C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,oCAAoC,CAAC;AAEnD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,6BAA6B,CAAC;AAE5C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,iCAAiC,CAAC;AAEhD,cAAc,+BAA+B,CAAC;AAE9C,cAAc,aAAa,CAAC;AAE5B,cAAc,eAAe,CAAC;AAE9B,cAAc,SAAS,CAAC;AAExB,cAAc,eAAe,CAAC;AAE9B,cAAc,UAAU,CAAC;AAEzB,cAAc,SAAS,CAAC;AAExB,cAAc,cAAc,CAAC;AAE7B,cAAc,kBAAkB,CAAC;AAEjC,cAAc,2BAA2B,CAAC;AAE1C,cAAc,uBAAuB,CAAC;AAEtC,mBAAmB,uBAAuB,CAAC"}
1
+ {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,gDAAgD,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AAClG,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AAEhG,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,cAAc,aAAa,CAAC;AAE5B,cAAc,+BAA+B,CAAC;AAE9C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AAErD,cAAc,4BAA4B,CAAC;AAE3C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,oCAAoC,CAAC;AAEnD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,6BAA6B,CAAC;AAE5C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,iCAAiC,CAAC;AAEhD,cAAc,+BAA+B,CAAC;AAE9C,cAAc,aAAa,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,cAAc,eAAe,CAAC;AAE9B,cAAc,SAAS,CAAC;AAExB,cAAc,eAAe,CAAC;AAE9B,cAAc,UAAU,CAAC;AAEzB,cAAc,SAAS,CAAC;AAExB,cAAc,cAAc,CAAC;AAE7B,cAAc,kBAAkB,CAAC;AAEjC,cAAc,2BAA2B,CAAC;AAE1C,cAAc,uBAAuB,CAAC;AAEtC,mBAAmB,uBAAuB,CAAC"}
package/dist/types.d.ts CHANGED
@@ -48,7 +48,7 @@ export type AppSettings = {
48
48
  */
49
49
  debug?: boolean;
50
50
  /**
51
- * Debounce span in ms (default is 100ms)
51
+ * Debounce span in ms (default is 200ms)
52
52
  */
53
53
  debounceSpan?: number;
54
54
  /**
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Composable for accessing and updating plugin-specific data.
3
+ *
4
+ * Plugin components are self-contained: they use this composable to read/write
5
+ * their own data slice from BlockStorage without knowing about the parent block's data.
6
+ *
7
+ * Requires a V3 block (BlockModelV3). Throws if used in a V1/V2 block.
8
+ *
9
+ * @param pluginId - The plugin instance ID (must match the ID used in BlockModelV3.plugin()).
10
+ * Must be a static value; changing it after mount will not re-bind the composable.
11
+ * @returns `{ data, updateData }` where `data` is a reactive ref to the plugin's data,
12
+ * and `updateData` returns a promise resolving to `true` if the mutation was sent,
13
+ * or `false` if data is not yet available.
14
+ *
15
+ * @example
16
+ * ```vue
17
+ * <script setup lang="ts">
18
+ * const { data, updateData } = usePluginData<CounterData>('counter');
19
+ *
20
+ * function increment() {
21
+ * updateData((d) => ({ ...d, count: d.count + 1 }));
22
+ * }
23
+ * </script>
24
+ * ```
25
+ */
26
+ export declare function usePluginData<Data>(pluginId: string): {
27
+ data: import('vue').ComputedRef<Data | undefined>;
28
+ updateData: (cb: (current: Data) => Data) => Promise<boolean>;
29
+ };
30
+ //# sourceMappingURL=usePluginData.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePluginData.d.ts","sourceRoot":"","sources":["../src/usePluginData.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM;;qBAwB1B,CAAC,OAAO,EAAE,IAAI,KAAK,IAAI,KAAG,OAAO,CAAC,OAAO,CAAC;EAQnE"}
@@ -0,0 +1,22 @@
1
+ import { inject as i, computed as u } from "vue";
2
+ import { deepClone as s } from "./lib/util/helpers/dist/objects.js";
3
+ import { pluginDataKey as l } from "./defineApp.js";
4
+ function d(t) {
5
+ const e = i(l);
6
+ if (!e)
7
+ throw new Error(
8
+ "usePluginData requires a V3 block (BlockModelV3). Make sure the block uses apiVersion 3 and the plugin is installed."
9
+ );
10
+ e.initPluginDataSlot(t);
11
+ const a = u(() => e.pluginDataMap[t]);
12
+ return { data: a, updateData: (o) => {
13
+ const r = a.value;
14
+ if (r === void 0) return Promise.resolve(!1);
15
+ const n = o(s(r));
16
+ return e.setPluginData(t, n);
17
+ } };
18
+ }
19
+ export {
20
+ d as usePluginData
21
+ };
22
+ //# sourceMappingURL=usePluginData.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePluginData.js","sources":["../src/usePluginData.ts"],"sourcesContent":["import { computed, inject } from \"vue\";\nimport { deepClone } from \"@milaboratories/helpers\";\nimport { pluginDataKey } from \"./defineApp\";\nimport type { PluginDataAccess } from \"./internal/createAppV3\";\n\n/**\n * Composable for accessing and updating plugin-specific data.\n *\n * Plugin components are self-contained: they use this composable to read/write\n * their own data slice from BlockStorage without knowing about the parent block's data.\n *\n * Requires a V3 block (BlockModelV3). Throws if used in a V1/V2 block.\n *\n * @param pluginId - The plugin instance ID (must match the ID used in BlockModelV3.plugin()).\n * Must be a static value; changing it after mount will not re-bind the composable.\n * @returns `{ data, updateData }` where `data` is a reactive ref to the plugin's data,\n * and `updateData` returns a promise resolving to `true` if the mutation was sent,\n * or `false` if data is not yet available.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * const { data, updateData } = usePluginData<CounterData>('counter');\n *\n * function increment() {\n * updateData((d) => ({ ...d, count: d.count + 1 }));\n * }\n * </script>\n * ```\n */\nexport function usePluginData<Data>(pluginId: string) {\n const access = inject<PluginDataAccess>(pluginDataKey);\n\n if (!access) {\n throw new Error(\n \"usePluginData requires a V3 block (BlockModelV3). \" +\n \"Make sure the block uses apiVersion 3 and the plugin is installed.\",\n );\n }\n\n // Initialize the plugin data slot from snapshot if not already done\n access.initPluginDataSlot(pluginId);\n\n // Reactive reference to the plugin's data in the shared optimistic map\n const data = computed<Data | undefined>(() => {\n return access.pluginDataMap[pluginId] as Data | undefined;\n });\n\n /**\n * Update plugin data with optimistic feedback.\n *\n * @param cb - Callback that receives a deep clone of current data and returns new data.\n * @returns Promise that resolves to true when the mutation is sent\n */\n const updateData = (cb: (current: Data) => Data): Promise<boolean> => {\n const current = data.value;\n if (current === undefined) return Promise.resolve(false);\n const newValue = cb(deepClone(current));\n return access.setPluginData(pluginId, newValue);\n };\n\n return { data, updateData };\n}\n"],"names":["usePluginData","pluginId","access","inject","pluginDataKey","data","computed","cb","current","newValue","deepClone"],"mappings":";;;AA8BO,SAASA,EAAoBC,GAAkB;AACpD,QAAMC,IAASC,EAAyBC,CAAa;AAErD,MAAI,CAACF;AACH,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAMJ,EAAAA,EAAO,mBAAmBD,CAAQ;AAGlC,QAAMI,IAAOC,EAA2B,MAC/BJ,EAAO,cAAcD,CAAQ,CACrC;AAeD,SAAO,EAAE,MAAAI,GAAM,YAPI,CAACE,MAAkD;AACpE,UAAMC,IAAUH,EAAK;AACrB,QAAIG,MAAY,OAAW,QAAO,QAAQ,QAAQ,EAAK;AACvD,UAAMC,IAAWF,EAAGG,EAAUF,CAAO,CAAC;AACtC,WAAON,EAAO,cAAcD,GAAUQ,CAAQ;AAAA,EAChD,EAEe;AACjB;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/ui-vue",
3
- "version": "1.54.13",
3
+ "version": "1.55.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -26,8 +26,8 @@
26
26
  "lru-cache": "^11.2.2",
27
27
  "vue": "^3.5.24",
28
28
  "zod": "~3.23.8",
29
- "@platforma-sdk/model": "1.54.13",
30
- "@milaboratories/uikit": "2.10.25"
29
+ "@platforma-sdk/model": "1.55.0",
30
+ "@milaboratories/uikit": "2.10.26"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@faker-js/faker": "^9.2.0",
@@ -43,9 +43,9 @@
43
43
  "vite": "^6.4.1",
44
44
  "vitest": "^4.0.16",
45
45
  "@milaboratories/build-configs": "1.4.4",
46
- "@milaboratories/ts-configs": "1.2.1",
46
+ "@milaboratories/helpers": "1.13.5",
47
47
  "@milaboratories/ts-builder": "1.2.10",
48
- "@milaboratories/helpers": "1.13.5"
48
+ "@milaboratories/ts-configs": "1.2.1"
49
49
  },
50
50
  "styles": "dist/index.js",
51
51
  "scripts": {