@platforma-sdk/ui-vue 1.49.0 → 1.50.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.
Files changed (47) hide show
  1. package/.turbo/turbo-build.log +10 -12
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/.turbo/turbo-type-check.log +1 -1
  4. package/CHANGELOG.md +14 -0
  5. package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js.map +1 -1
  6. package/dist/defineApp.d.ts +3 -3
  7. package/dist/defineApp.d.ts.map +1 -1
  8. package/dist/defineApp.js.map +1 -1
  9. package/dist/index.js +79 -81
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal/createAppV1.d.ts +2 -2
  12. package/dist/internal/createAppV1.d.ts.map +1 -1
  13. package/dist/internal/createAppV1.js +29 -27
  14. package/dist/internal/createAppV1.js.map +1 -1
  15. package/dist/internal/createAppV2.d.ts +2 -2
  16. package/dist/internal/createAppV2.d.ts.map +1 -1
  17. package/dist/internal/createAppV2.js +68 -66
  18. package/dist/internal/createAppV2.js.map +1 -1
  19. package/dist/internal/createAppV2.test.d.ts +2 -2
  20. package/dist/internal/createAppV2.test.d.ts.map +1 -1
  21. package/dist/internal/v1.static-test.d.ts.map +1 -1
  22. package/dist/internal/v2.static-test.d.ts.map +1 -1
  23. package/dist/lib.d.ts +0 -1
  24. package/dist/lib.d.ts.map +1 -1
  25. package/dist/types.d.ts +5 -5
  26. package/dist/types.d.ts.map +1 -1
  27. package/dist/utils.d.ts +11 -3
  28. package/dist/utils.d.ts.map +1 -1
  29. package/dist/utils.js +33 -34
  30. package/dist/utils.js.map +1 -1
  31. package/package.json +6 -6
  32. package/src/defineApp.ts +4 -4
  33. package/src/internal/createAppV1.ts +9 -5
  34. package/src/internal/createAppV2.test.ts +40 -6
  35. package/src/internal/createAppV2.ts +9 -5
  36. package/src/internal/v1.static-test.ts +2 -2
  37. package/src/internal/v2.static-test.ts +2 -2
  38. package/src/lib.ts +0 -1
  39. package/src/types.ts +6 -5
  40. package/src/utils.ts +16 -13
  41. package/dist/components/ValueOrErrorsComponent.vue.d.ts +0 -27
  42. package/dist/components/ValueOrErrorsComponent.vue.d.ts.map +0 -1
  43. package/dist/components/ValueOrErrorsComponent.vue.js +0 -22
  44. package/dist/components/ValueOrErrorsComponent.vue.js.map +0 -1
  45. package/dist/components/ValueOrErrorsComponent.vue2.js +0 -5
  46. package/dist/components/ValueOrErrorsComponent.vue2.js.map +0 -1
  47. package/src/components/ValueOrErrorsComponent.vue +0 -28
package/dist/utils.js CHANGED
@@ -1,60 +1,59 @@
1
- var u = Object.defineProperty;
2
- var f = (r, o, n) => o in r ? u(r, o, { enumerable: !0, configurable: !0, writable: !0, value: n }) : r[o] = n;
3
- var e = (r, o, n) => f(r, typeof o != "symbol" ? o + "" : o, n);
4
- class a extends Error {
1
+ var f = Object.defineProperty;
2
+ var l = (r, s, n) => s in r ? f(r, s, { enumerable: !0, configurable: !0, writable: !0, value: n }) : r[s] = n;
3
+ var t = (r, s, n) => l(r, typeof s != "symbol" ? s + "" : s, n);
4
+ class i extends Error {
5
5
  constructor() {
6
6
  super(...arguments);
7
- e(this, "name", "UnresolvedError");
7
+ t(this, "name", "UnresolvedError");
8
8
  }
9
9
  }
10
- const l = (r) => Array.isArray(r) ? r : r ? [r] : [];
11
- class c extends Error {
10
+ const c = (r) => Array.isArray(r) ? r : r ? [r] : [];
11
+ class E extends Error {
12
12
  constructor(n) {
13
- n = l(n);
14
- super(n.map((t) => typeof t == "string" ? t : t.message).join(`
13
+ n = c(n);
14
+ super(n.map((e) => typeof e == "string" ? e : e.message).join(`
15
15
  `));
16
- e(this, "name", "MultiError");
17
- e(this, "fullMessage");
18
- this.errors = n, this.fullMessage = n.map((t) => typeof t == "string" ? t : t.type == "PlError" && "fullMessage" in t ? t.fullMessage : t.message).join(`
16
+ t(this, "name", "MultiError");
17
+ t(this, "fullMessage");
18
+ this.errors = n, this.fullMessage = n.map((e) => typeof e == "string" ? e : e.type == "PlError" && "fullMessage" in e ? e.fullMessage : e.message).join(`
19
19
  `);
20
20
  }
21
21
  }
22
- function d(r) {
23
- return {
24
- ok: !0,
25
- value: r
26
- };
27
- }
28
- function p(r) {
22
+ function u(r) {
29
23
  if (!r)
30
- throw new a();
24
+ throw new i();
31
25
  if (!r.ok)
32
- throw new c(r.errors);
26
+ throw new E(r.errors);
33
27
  return r.value;
34
28
  }
29
+ function g(r) {
30
+ if (!r)
31
+ throw new i();
32
+ return r.ok && (r.stable ?? (r.stable = !0)), r;
33
+ }
35
34
  function m(r) {
36
35
  return {
37
36
  value: r,
38
37
  errors: void 0
39
38
  };
40
39
  }
41
- function g(r) {
40
+ function w(r) {
42
41
  return r !== void 0;
43
42
  }
44
- const w = (r) => r, y = (r) => r instanceof Error ? r : Error(String(r)), M = (r) => r.name === "ZodError", j = (r) => {
45
- const { formErrors: o, fieldErrors: n } = r.flatten(), t = Object.entries(n).map(([i, s]) => i + ":" + (s == null ? void 0 : s.join(",")));
46
- return o.concat(t).join("; ");
43
+ const y = (r) => r, M = (r) => r instanceof Error ? r : Error(String(r)), h = (r) => r.name === "ZodError", j = (r) => {
44
+ const { formErrors: s, fieldErrors: n } = r.flatten(), e = Object.entries(n).map(([a, o]) => a + ":" + (o == null ? void 0 : o.join(",")));
45
+ return s.concat(e).join("; ");
47
46
  };
48
47
  export {
49
- c as MultiError,
50
- a as UnresolvedError,
51
- y as ensureError,
48
+ E as MultiError,
49
+ i as UnresolvedError,
50
+ M as ensureError,
51
+ g as ensureOutputHasStableFlag,
52
52
  j as formatZodError,
53
- w as identity,
54
- g as isDefined,
55
- M as isZodError,
56
- p as unwrapValueOrErrors,
57
- m as wrapOptionalResult,
58
- d as wrapValueOrErrors
53
+ y as identity,
54
+ w as isDefined,
55
+ h as isZodError,
56
+ u as unwrapOutput,
57
+ m as wrapOptionalResult
59
58
  };
60
59
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import { type ErrorLike, type ValueOrErrors } from '@platforma-sdk/model';\nimport type { OptionalResult } from './types';\nimport type { ZodError } from 'zod';\n\nexport class UnresolvedError extends Error {\n name = 'UnresolvedError';\n}\n\nconst ensureArray = <T>(value: T | T[]): T[] => {\n return Array.isArray(value) ? value : value ? [value] : [];\n};\n\n// @TODO use AggregateError\nexport class MultiError extends Error {\n name = 'MultiError';\n\n public readonly fullMessage: string;\n\n constructor(public readonly errors: (ErrorLike | string)[]) {\n errors = ensureArray(errors);\n super(errors.map((e) => typeof e == 'string' ? e : e.message).join('\\n'));\n this.fullMessage = errors.map((e) => {\n if (typeof e == 'string') {\n return e;\n } else if (e.type == 'PlError' && 'fullMessage' in e) {\n return e.fullMessage;\n }\n return e.message;\n }).join('\\n');\n }\n}\n\nexport function wrapValueOrErrors<V>(value: V): ValueOrErrors<V> {\n return {\n ok: true,\n value,\n };\n}\n\nexport function unwrapValueOrErrors<V>(valueOrErrors?: ValueOrErrors<V>): V {\n if (!valueOrErrors) {\n throw new UnresolvedError();\n }\n\n if (!valueOrErrors.ok) {\n throw new MultiError(valueOrErrors.errors);\n }\n\n return valueOrErrors.value;\n}\n\n// Optional Result\n\nexport function wrapOptionalResult<V>(value: V): OptionalResult<V> {\n return {\n value,\n errors: undefined,\n };\n}\n\nexport function isDefined<T>(v: T | undefined): v is T {\n return v !== undefined;\n}\n\nexport const identity = <T, V = T>(v: T): V => v as unknown as V;\n\nexport const ensureError = (cause: unknown) => {\n if (cause instanceof Error) {\n return cause;\n }\n\n return Error(String(cause));\n};\n\nexport const isZodError = (err: Error): err is ZodError => {\n return err.name === 'ZodError';\n};\n\nexport const formatZodError = (err: ZodError) => {\n const { formErrors, fieldErrors } = err.flatten();\n const _fieldErrors = Object.entries(fieldErrors).map(([field, errors]) => {\n return field + ':' + errors?.join(',');\n });\n return formErrors.concat(_fieldErrors).join('; ');\n};\n"],"names":["UnresolvedError","__publicField","ensureArray","value","MultiError","errors","e","wrapValueOrErrors","unwrapValueOrErrors","valueOrErrors","wrapOptionalResult","isDefined","v","identity","ensureError","cause","isZodError","err","formatZodError","formErrors","fieldErrors","_fieldErrors","field"],"mappings":";;;AAIO,MAAMA,UAAwB,MAAM;AAAA,EAApC;AAAA;AACL,IAAAC,EAAA,cAAO;AAAA;AACT;AAEA,MAAMC,IAAc,CAAIC,MACf,MAAM,QAAQA,CAAK,IAAIA,IAAQA,IAAQ,CAACA,CAAK,IAAI,CAAA;AAInD,MAAMC,UAAmB,MAAM;AAAA,EAKpC,YAA4BC,GAAgC;AAC1D,IAAAA,IAASH,EAAYG,CAAM;AAC3B,UAAMA,EAAO,IAAI,CAACC,MAAM,OAAOA,KAAK,WAAWA,IAAIA,EAAE,OAAO,EAAE,KAAK;AAAA,CAAI,CAAC;AAN1E,IAAAL,EAAA,cAAO;AAES,IAAAA,EAAA;AAEY,SAAA,SAAAI,GAG1B,KAAK,cAAcA,EAAO,IAAI,CAACC,MACzB,OAAOA,KAAK,WACPA,IACEA,EAAE,QAAQ,aAAa,iBAAiBA,IAC1CA,EAAE,cAEJA,EAAE,OACV,EAAE,KAAK;AAAA,CAAI;AAAA,EACd;AACF;AAEO,SAASC,EAAqBJ,GAA4B;AAC/D,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAAA;AAAA,EAAA;AAEJ;AAEO,SAASK,EAAuBC,GAAqC;AAC1E,MAAI,CAACA;AACH,UAAM,IAAIT,EAAA;AAGZ,MAAI,CAACS,EAAc;AACjB,UAAM,IAAIL,EAAWK,EAAc,MAAM;AAG3C,SAAOA,EAAc;AACvB;AAIO,SAASC,EAAsBP,GAA6B;AACjE,SAAO;AAAA,IACL,OAAAA;AAAA,IACA,QAAQ;AAAA,EAAA;AAEZ;AAEO,SAASQ,EAAaC,GAA0B;AACrD,SAAOA,MAAM;AACf;AAEO,MAAMC,IAAW,CAAWD,MAAYA,GAElCE,IAAc,CAACC,MACtBA,aAAiB,QACZA,IAGF,MAAM,OAAOA,CAAK,CAAC,GAGfC,IAAa,CAACC,MAClBA,EAAI,SAAS,YAGTC,IAAiB,CAACD,MAAkB;AAC/C,QAAM,EAAE,YAAAE,GAAY,aAAAC,MAAgBH,EAAI,QAAA,GAClCI,IAAe,OAAO,QAAQD,CAAW,EAAE,IAAI,CAAC,CAACE,GAAOjB,CAAM,MAC3DiB,IAAQ,OAAMjB,KAAA,gBAAAA,EAAQ,KAAK,KACnC;AACD,SAAOc,EAAW,OAAOE,CAAY,EAAE,KAAK,IAAI;AAClD;"}
1
+ {"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import type { ErrorLike, OutputWithStatus } from '@platforma-sdk/model';\nimport type { OptionalResult } from './types';\nimport type { ZodError } from 'zod';\n\nexport class UnresolvedError extends Error {\n name = 'UnresolvedError';\n}\n\nconst ensureArray = <T>(value: T | T[]): T[] => {\n return Array.isArray(value) ? value : value ? [value] : [];\n};\n\n// @TODO use AggregateError\nexport class MultiError extends Error {\n name = 'MultiError';\n\n public readonly fullMessage: string;\n\n constructor(public readonly errors: (ErrorLike | string)[]) {\n errors = ensureArray(errors);\n super(errors.map((e) => typeof e == 'string' ? e : e.message).join('\\n'));\n this.fullMessage = errors.map((e) => {\n if (typeof e == 'string') {\n return e;\n } else if (e.type == 'PlError' && 'fullMessage' in e) {\n return e.fullMessage;\n }\n return e.message;\n }).join('\\n');\n }\n}\n\nexport function unwrapOutput<V>(output?: OutputWithStatus<V>): V {\n if (!output) {\n throw new UnresolvedError();\n }\n\n if (!output.ok) {\n throw new MultiError(output.errors);\n }\n\n return output.value;\n}\n\nexport function ensureOutputHasStableFlag<T>(output?: OutputWithStatus<T>) {\n if (!output) {\n throw new UnresolvedError();\n }\n if (output.ok) {\n output.stable ??= true;\n }\n return output;\n}\n\n// Optional Result\n\nexport function wrapOptionalResult<V>(value: V): OptionalResult<V> {\n return {\n value,\n errors: undefined,\n };\n}\n\nexport function isDefined<T>(v: T | undefined): v is T {\n return v !== undefined;\n}\n\nexport const identity = <T, V = T>(v: T): V => v as unknown as V;\n\nexport const ensureError = (cause: unknown) => {\n if (cause instanceof Error) {\n return cause;\n }\n\n return Error(String(cause));\n};\n\nexport const isZodError = (err: Error): err is ZodError => {\n return err.name === 'ZodError';\n};\n\nexport const formatZodError = (err: ZodError) => {\n const { formErrors, fieldErrors } = err.flatten();\n const _fieldErrors = Object.entries(fieldErrors).map(([field, errors]) => {\n return field + ':' + errors?.join(',');\n });\n return formErrors.concat(_fieldErrors).join('; ');\n};\n"],"names":["UnresolvedError","__publicField","ensureArray","value","MultiError","errors","unwrapOutput","output","ensureOutputHasStableFlag","wrapOptionalResult","isDefined","v","identity","ensureError","cause","isZodError","err","formatZodError","formErrors","fieldErrors","_fieldErrors","field"],"mappings":";;;AAIO,MAAMA,UAAwB,MAAM;AAAA,EAApC;AAAA;AACL,IAAAC,EAAA,cAAO;AAAA;AACT;AAEA,MAAMC,IAAc,CAAIC,MACf,MAAM,QAAQA,CAAK,IAAIA,IAAQA,IAAQ,CAACA,CAAK,IAAI,CAAA;AAInD,MAAMC,UAAmB,MAAM;AAAA,EAKpC,YAA4BC,GAAgC;AAC1D,IAAAA,IAASH,EAAYG,CAAM;AAC3B,UAAMA,EAAO,IAAI,CAAC,MAAM,OAAO,KAAK,WAAW,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,CAAI,CAAC;AAN1E,IAAAJ,EAAA,cAAO;AAES,IAAAA,EAAA;AAEY,SAAA,SAAAI,GAG1B,KAAK,cAAcA,EAAO,IAAI,CAAC,MACzB,OAAO,KAAK,WACP,IACE,EAAE,QAAQ,aAAa,iBAAiB,IAC1C,EAAE,cAEJ,EAAE,OACV,EAAE,KAAK;AAAA,CAAI;AAAA,EACd;AACF;AAEO,SAASC,EAAgBC,GAAiC;AAC/D,MAAI,CAACA;AACH,UAAM,IAAIP,EAAA;AAGZ,MAAI,CAACO,EAAO;AACV,UAAM,IAAIH,EAAWG,EAAO,MAAM;AAGpC,SAAOA,EAAO;AAChB;AAEO,SAASC,EAA6BD,GAA8B;AACzE,MAAI,CAACA;AACH,UAAM,IAAIP,EAAA;AAEZ,SAAIO,EAAO,OACTA,EAAO,WAAPA,EAAO,SAAW,MAEbA;AACT;AAIO,SAASE,EAAsBN,GAA6B;AACjE,SAAO;AAAA,IACL,OAAAA;AAAA,IACA,QAAQ;AAAA,EAAA;AAEZ;AAEO,SAASO,EAAaC,GAA0B;AACrD,SAAOA,MAAM;AACf;AAEO,MAAMC,IAAW,CAAWD,MAAYA,GAElCE,IAAc,CAACC,MACtBA,aAAiB,QACZA,IAGF,MAAM,OAAOA,CAAK,CAAC,GAGfC,IAAa,CAACC,MAClBA,EAAI,SAAS,YAGTC,IAAiB,CAACD,MAAkB;AAC/C,QAAM,EAAE,YAAAE,GAAY,aAAAC,MAAgBH,EAAI,QAAA,GAClCI,IAAe,OAAO,QAAQD,CAAW,EAAE,IAAI,CAAC,CAACE,GAAOhB,CAAM,MAC3DgB,IAAQ,OAAMhB,KAAA,gBAAAA,EAAQ,KAAK,KACnC;AACD,SAAOa,EAAW,OAAOE,CAAY,EAAE,KAAK,IAAI;AAClD;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/ui-vue",
3
- "version": "1.49.0",
3
+ "version": "1.50.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "styles": "dist/index.js",
@@ -27,10 +27,10 @@
27
27
  "zod": "~3.23.8",
28
28
  "@zip.js/zip.js": "^2.8.2",
29
29
  "es-toolkit": "^1.39.10",
30
- "@milaboratories/ptabler-expression-js": "1.1.8",
31
- "@milaboratories/uikit": "2.8.8",
30
+ "@milaboratories/uikit": "2.8.9",
31
+ "@milaboratories/ptabler-expression-js": "1.1.9",
32
32
  "@milaboratories/biowasm-tools": "2.0.0",
33
- "@platforma-sdk/model": "1.49.0"
33
+ "@platforma-sdk/model": "1.50.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "happy-dom": "^15.11.7",
@@ -48,10 +48,10 @@
48
48
  "fast-json-patch": "^3.1.1",
49
49
  "@faker-js/faker": "^9.2.0",
50
50
  "@milaboratories/ts-configs": "1.2.0",
51
- "@milaboratories/build-configs": "1.2.1",
52
51
  "@milaboratories/eslint-config": "1.0.5",
52
+ "@milaboratories/build-configs": "1.2.1",
53
53
  "@milaboratories/ts-builder": "1.2.1",
54
- "@milaboratories/helpers": "1.12.1"
54
+ "@milaboratories/helpers": "1.13.0"
55
55
  },
56
56
  "scripts": {
57
57
  "test": "vitest run --coverage",
package/src/defineApp.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { notEmpty } from '@milaboratories/helpers';
2
- import type { PlatformaV1, PlatformaV2 } from '@platforma-sdk/model';
2
+ import type { PlatformaExtended, PlatformaV1, PlatformaV2 } from '@platforma-sdk/model';
3
3
  import { getPlatformaApiVersion, unwrapResult, type BlockOutputsBase, type Platforma } from '@platforma-sdk/model';
4
4
  import type { Component, Reactive } from 'vue';
5
5
  import { inject, markRaw, reactive } from 'vue';
@@ -21,7 +21,7 @@ export function defineApp<
21
21
  Href extends `/${string}` = `/${string}`,
22
22
  Extend extends ExtendSettings<Href> = ExtendSettings<Href>,
23
23
  >(
24
- platforma: PlatformaV1<Args, Outputs, UiState, Href>,
24
+ platforma: PlatformaExtended<PlatformaV1<Args, Outputs, UiState, Href>>,
25
25
  extendApp: (app: BaseAppV1<Args, Outputs, UiState, Href>) => Extend,
26
26
  settings?: AppSettings,
27
27
  ): SdkPluginV1<Args, Outputs, UiState, Href, Extend>;
@@ -33,7 +33,7 @@ export function defineApp<
33
33
  Href extends `/${string}` = `/${string}`,
34
34
  Extend extends ExtendSettings<Href> = ExtendSettings<Href>,
35
35
  >(
36
- platforma: PlatformaV2<Args, Outputs, UiState, Href>,
36
+ platforma: PlatformaExtended<PlatformaV2<Args, Outputs, UiState, Href>>,
37
37
  extendApp: (app: BaseAppV2<Args, Outputs, UiState, Href>) => Extend,
38
38
  settings?: AppSettings,
39
39
  ): SdkPluginV2<Args, Outputs, UiState, Href, Extend>;
@@ -45,7 +45,7 @@ export function defineApp<
45
45
  Href extends `/${string}` = `/${string}`,
46
46
  Extend extends ExtendSettings<Href> = ExtendSettings<Href>,
47
47
  >(
48
- platforma: Platforma<Args, Outputs, UiState, Href>,
48
+ platforma: PlatformaExtended<Platforma<Args, Outputs, UiState, Href>>,
49
49
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
50
  extendApp: (app: any) => Extend,
51
51
  settings: AppSettings = {},
@@ -1,12 +1,12 @@
1
1
  import { deepClone, isJsonEqual, tap } from '@milaboratories/helpers';
2
2
  import type { Mutable } from '@milaboratories/helpers';
3
- import type { NavigationState, BlockOutputsBase, BlockState, PlatformaV1 } from '@platforma-sdk/model';
3
+ import type { NavigationState, BlockOutputsBase, BlockState, PlatformaV1, PlatformaExtended } from '@platforma-sdk/model';
4
4
  import { reactive, nextTick, computed, watch } from 'vue';
5
5
  import type { StateModelOptions, UnwrapOutputs, OptionalResult, OutputValues, OutputErrors, AppSettings } from '../types';
6
6
  import { createModel } from '../createModel';
7
7
  import { createAppModel } from './createAppModel';
8
8
  import { parseQuery } from '../urls';
9
- import { MultiError, unwrapValueOrErrors } from '../utils';
9
+ import { ensureOutputHasStableFlag, MultiError, unwrapOutput } from '../utils';
10
10
  import { useDebounceFn } from '@vueuse/core';
11
11
  /**
12
12
  * Creates an application instance with reactive state management, outputs, and methods for state updates and navigation.
@@ -29,7 +29,7 @@ export function createAppV1<
29
29
  Href extends `/${string}` = `/${string}`,
30
30
  >(
31
31
  state: BlockState<Args, Outputs, UiState, Href>,
32
- platforma: PlatformaV1<Args, Outputs, UiState, Href>,
32
+ platforma: PlatformaExtended<PlatformaV1<Args, Outputs, UiState, Href>>,
33
33
  settings: AppSettings,
34
34
  ) {
35
35
  type AppModel = {
@@ -187,7 +187,7 @@ export function createAppV1<
187
187
  */
188
188
  unwrapOutputs<K extends keyof Outputs>(...keys: K[]): UnwrapOutputs<Outputs, K> {
189
189
  const outputs = snapshot.outputs;
190
- const entries = keys.map((key) => [key, unwrapValueOrErrors(outputs[key])]);
190
+ const entries = keys.map((key) => [key, unwrapOutput(outputs[key])]);
191
191
  return Object.fromEntries(entries);
192
192
  },
193
193
  /**
@@ -237,7 +237,11 @@ export function createAppV1<
237
237
  };
238
238
 
239
239
  const outputs = computed<OutputValues<Outputs>>(() => {
240
- const entries = Object.entries(snapshot.outputs).map(([k, vOrErr]) => [k, vOrErr.ok && vOrErr.value !== undefined ? vOrErr.value : undefined]);
240
+ const entries = Object.entries(snapshot.outputs)
241
+ .map(([k, outputWithStatus]) => platforma.blockModelInfo.outputs[k].withStatus
242
+ ? [k, ensureOutputHasStableFlag(outputWithStatus)]
243
+ : [k, outputWithStatus.ok && outputWithStatus.value !== undefined ? outputWithStatus.value : undefined],
244
+ );
241
245
  return Object.fromEntries(entries);
242
246
  });
243
247
 
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
2
  import { createAppV2 } from './createAppV2';
3
- import { unwrapResult, type ValueOrErrors } from '@platforma-sdk/model';
3
+ import { type OutputWithStatus, unwrapResult } from '@platforma-sdk/model';
4
4
  import { BlockStateMock } from './test-helpers/BlockMock';
5
5
  import { BlockMock } from './test-helpers/BlockMock';
6
6
  import { delay } from '@milaboratories/helpers';
@@ -24,7 +24,7 @@ const defaultArgs = () => ({
24
24
  });
25
25
 
26
26
  type Outputs = {
27
- sum: ValueOrErrors<number>;
27
+ sum: OutputWithStatus<number>;
28
28
  };
29
29
 
30
30
  const defaultOutputs = (): Outputs => {
@@ -32,6 +32,7 @@ const defaultOutputs = (): Outputs => {
32
32
  sum: {
33
33
  ok: true,
34
34
  value: 0,
35
+ stable: true,
35
36
  },
36
37
  };
37
38
  };
@@ -43,7 +44,7 @@ const defaultState = (): BlockStateMock<Args, Outputs, UiState, `/${string}`> =>
43
44
  class BlockSum extends BlockMock<Args, Outputs, UiState, `/${string}`> {
44
45
  async process(): Promise<void> {
45
46
  const { args, author } = this.state;
46
- this.state.setState({ author, outputs: { sum: { ok: true, value: args.x + args.y } } });
47
+ this.state.setState({ author, outputs: { sum: { ok: true, value: args.x + args.y, stable: true } } });
47
48
  }
48
49
  }
49
50
 
@@ -60,7 +61,18 @@ describe('createApp', { timeout: 20_000 }, () => {
60
61
  it('should create an app with reactive snapshot', async () => {
61
62
  const initialState = await platforma.loadBlockState().then(unwrapResult);
62
63
 
63
- const app = createAppV2(initialState, platforma, { debug: true, debounceSpan: 10 });
64
+ const app = createAppV2(
65
+ initialState,
66
+ {
67
+ ...platforma,
68
+ blockModelInfo: {
69
+ outputs: {
70
+ sum: { withStatus: false },
71
+ },
72
+ },
73
+ },
74
+ { debug: true, debounceSpan: 10 },
75
+ );
64
76
 
65
77
  expect(app.model.args).toEqual({ x: 0, y: 0 });
66
78
  expect(app.model.ui).toEqual({ label: '' });
@@ -111,8 +123,30 @@ describe('createApp', { timeout: 20_000 }, () => {
111
123
  const initialState1 = await platforma1.loadBlockState().then(unwrapResult);
112
124
  const initialState2 = await platforma2.loadBlockState().then(unwrapResult);
113
125
 
114
- const app1 = createAppV2(initialState1, platforma1, { appId: 'app1', debug: true, debounceSpan: 10 });
115
- const app2 = createAppV2(initialState2, platforma2, { appId: 'app2', debug: true, debounceSpan: 10 });
126
+ const app1 = createAppV2(
127
+ initialState1,
128
+ {
129
+ ...platforma1,
130
+ blockModelInfo: {
131
+ outputs: {
132
+ sum: { withStatus: false },
133
+ },
134
+ },
135
+ },
136
+ { appId: 'app1', debug: true, debounceSpan: 10 },
137
+ );
138
+ const app2 = createAppV2(
139
+ initialState2,
140
+ {
141
+ ...platforma2,
142
+ blockModelInfo: {
143
+ outputs: {
144
+ sum: { withStatus: false },
145
+ },
146
+ },
147
+ },
148
+ { appId: 'app2', debug: true, debounceSpan: 10 },
149
+ );
116
150
 
117
151
  app1.model.args.x = 1;
118
152
  app1.model.args.y = 2;
@@ -1,13 +1,13 @@
1
1
  import { deepClone, delay, uniqueId } from '@milaboratories/helpers';
2
2
  import type { Mutable } from '@milaboratories/helpers';
3
- import type { NavigationState, BlockOutputsBase, BlockState, PlatformaV2, ValueWithUTag, AuthorMarker } from '@platforma-sdk/model';
3
+ import type { NavigationState, BlockOutputsBase, BlockState, PlatformaV2, ValueWithUTag, AuthorMarker, PlatformaExtended } from '@platforma-sdk/model';
4
4
  import { hasAbortError, unwrapResult } from '@platforma-sdk/model';
5
5
  import type { Ref } from 'vue';
6
6
  import { reactive, computed, ref } from 'vue';
7
7
  import type { StateModelOptions, UnwrapOutputs, OutputValues, OutputErrors, AppSettings } from '../types';
8
8
  import { createModel } from '../createModel';
9
9
  import { parseQuery } from '../urls';
10
- import { MultiError, unwrapValueOrErrors } from '../utils';
10
+ import { ensureOutputHasStableFlag, MultiError, unwrapOutput } from '../utils';
11
11
  import { applyPatch } from 'fast-json-patch';
12
12
  import { UpdateSerializer } from './UpdateSerializer';
13
13
  import { watchIgnorable } from '@vueuse/core';
@@ -48,7 +48,7 @@ export function createAppV2<
48
48
  Href extends `/${string}` = `/${string}`,
49
49
  >(
50
50
  state: ValueWithUTag<BlockState<Args, Outputs, UiState, Href>>,
51
- platforma: PlatformaV2<Args, Outputs, UiState, Href>,
51
+ platforma: PlatformaExtended<PlatformaV2<Args, Outputs, UiState, Href>>,
52
52
  settings: AppSettings,
53
53
  ) {
54
54
  const debug = (msg: string, ...rest: unknown[]) => {
@@ -117,7 +117,11 @@ export function createAppV2<
117
117
  };
118
118
 
119
119
  const outputs = computed<OutputValues<Outputs>>(() => {
120
- const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>).map(([k, vOrErr]) => [k, vOrErr.ok && vOrErr.value !== undefined ? vOrErr.value : undefined]);
120
+ const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)
121
+ .map(([k, outputWithStatus]) => platforma.blockModelInfo.outputs[k].withStatus
122
+ ? [k, ensureOutputHasStableFlag(outputWithStatus)]
123
+ : [k, outputWithStatus.ok && outputWithStatus.value !== undefined ? outputWithStatus.value : undefined],
124
+ );
121
125
  return Object.fromEntries(entries);
122
126
  });
123
127
 
@@ -272,7 +276,7 @@ export function createAppV2<
272
276
  */
273
277
  unwrapOutputs<K extends keyof Outputs>(...keys: K[]): UnwrapOutputs<Outputs, K> {
274
278
  const outputs = snapshot.value.outputs as Partial<Readonly<Outputs>>;
275
- const entries = keys.map((key) => [key, unwrapValueOrErrors(outputs[key])]);
279
+ const entries = keys.map((key) => [key, unwrapOutput(outputs[key])]);
276
280
  return Object.fromEntries(entries);
277
281
  },
278
282
  /**
@@ -1,7 +1,7 @@
1
1
  import type { Expect, Equal } from '@milaboratories/helpers';
2
2
  import { z } from 'zod';
3
3
  import type { ModelOptions, Model } from '../types';
4
- import type { BlockOutputsBase, InferHrefType, InferOutputsType, Platforma, ValueOrErrors } from '@platforma-sdk/model';
4
+ import type { BlockOutputsBase, InferHrefType, InferOutputsType, OutputWithStatus, Platforma } from '@platforma-sdk/model';
5
5
  import type { BaseAppV1, createAppV1 } from './createAppV1';
6
6
  import { type App } from '../defineApp';
7
7
  import { computed, type Component } from 'vue';
@@ -49,7 +49,7 @@ type _Args = {
49
49
  };
50
50
 
51
51
  type _Outputs = {
52
- sum: ValueOrErrors<number>;
52
+ sum: OutputWithStatus<number> & { __unwrap: true };
53
53
  };
54
54
 
55
55
  type _UiState = {
@@ -1,7 +1,7 @@
1
1
  import type { Expect, Equal } from '@milaboratories/helpers';
2
2
  import { z } from 'zod';
3
3
  import type { ModelOptions, Model } from '../types';
4
- import type { BlockOutputsBase, InferHrefType, InferOutputsType, Platforma, ValueOrErrors } from '@platforma-sdk/model';
4
+ import type { BlockOutputsBase, InferHrefType, InferOutputsType, OutputWithStatus, Platforma } from '@platforma-sdk/model';
5
5
  import type { BaseAppV2, createAppV2 } from './createAppV2';
6
6
  import { type App } from '../defineApp';
7
7
  import { computed, type Component } from 'vue';
@@ -49,7 +49,7 @@ type _Args = {
49
49
  };
50
50
 
51
51
  type _Outputs = {
52
- sum: ValueOrErrors<number>;
52
+ sum: OutputWithStatus<number> & { __unwrap: true };
53
53
  };
54
54
 
55
55
  type _UiState = {
package/src/lib.ts CHANGED
@@ -4,7 +4,6 @@ export { default as BlockLayout } from './components/BlockLayout.vue';
4
4
  export { default as PlAgDataTableV2 } from './components/PlAgDataTable/PlAgDataTableV2.vue';
5
5
  export { default as PlAgOverlayLoading } from './components/PlAgDataTable/PlAgOverlayLoading.vue';
6
6
  export { default as PlAgOverlayNoRows } from './components/PlAgDataTable/PlAgOverlayNoRows.vue';
7
- export { default as ValueOrErrorsComponent } from './components/ValueOrErrorsComponent.vue';
8
7
 
9
8
  export type { ListOptionBase } from '@platforma-sdk/model';
10
9
 
package/src/types.ts CHANGED
@@ -1,8 +1,7 @@
1
- import type { Equal, Expect } from '@milaboratories/helpers';
2
- import type { BlockOutputsBase, ErrorLike, ValueOrErrors } from '@platforma-sdk/model';
1
+ import type { Equal, Expect, OmitOverUnion } from '@milaboratories/helpers';
2
+ import type { BlockOutputsBase, ErrorLike, OutputWithStatus } from '@platforma-sdk/model';
3
3
  import type { Component, ComputedGetter } from 'vue';
4
4
 
5
- export type UnwrapValueOrErrors<R extends ValueOrErrors<unknown>> = Extract<R, { ok: true }>['value'];
6
5
  export interface StateModelOptions<A, T = A> {
7
6
  transform?: (v: A) => T;
8
7
  validate?: (v: unknown) => A;
@@ -117,7 +116,9 @@ export type ModelResult<T, E = unknown> =
117
116
  };
118
117
 
119
118
  export type OutputValues<Outputs extends BlockOutputsBase> = {
120
- [P in keyof Outputs]?: UnwrapValueOrError<Outputs[P]>;
119
+ [P in keyof Outputs]: Outputs[P] extends { __unwrap: true }
120
+ ? UnwrapValueOrError<Outputs[P]> | undefined
121
+ : OmitOverUnion<Outputs[P], '__unwrap'>;
121
122
  };
122
123
 
123
124
  export type OutputErrors<Outputs extends BlockOutputsBase> = {
@@ -139,4 +140,4 @@ export type OptionalResult<T> =
139
140
 
140
141
  // Static tests
141
142
 
142
- type _cases = [Expect<Equal<number, UnwrapValueOrError<ValueOrErrors<number>>>>];
143
+ type _cases = [Expect<Equal<number, UnwrapValueOrError<OutputWithStatus<number>>>>];
package/src/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type ErrorLike, type ValueOrErrors } from '@platforma-sdk/model';
1
+ import type { ErrorLike, OutputWithStatus } from '@platforma-sdk/model';
2
2
  import type { OptionalResult } from './types';
3
3
  import type { ZodError } from 'zod';
4
4
 
@@ -30,23 +30,26 @@ export class MultiError extends Error {
30
30
  }
31
31
  }
32
32
 
33
- export function wrapValueOrErrors<V>(value: V): ValueOrErrors<V> {
34
- return {
35
- ok: true,
36
- value,
37
- };
38
- }
39
-
40
- export function unwrapValueOrErrors<V>(valueOrErrors?: ValueOrErrors<V>): V {
41
- if (!valueOrErrors) {
33
+ export function unwrapOutput<V>(output?: OutputWithStatus<V>): V {
34
+ if (!output) {
42
35
  throw new UnresolvedError();
43
36
  }
44
37
 
45
- if (!valueOrErrors.ok) {
46
- throw new MultiError(valueOrErrors.errors);
38
+ if (!output.ok) {
39
+ throw new MultiError(output.errors);
47
40
  }
48
41
 
49
- return valueOrErrors.value;
42
+ return output.value;
43
+ }
44
+
45
+ export function ensureOutputHasStableFlag<T>(output?: OutputWithStatus<T>) {
46
+ if (!output) {
47
+ throw new UnresolvedError();
48
+ }
49
+ if (output.ok) {
50
+ output.stable ??= true;
51
+ }
52
+ return output;
50
53
  }
51
54
 
52
55
  // Optional Result
@@ -1,27 +0,0 @@
1
- import { ValueOrErrors } from '@platforma-sdk/model';
2
- declare const _default: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
- props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{} & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, never>, never> & {
4
- valueOrError: ValueOrErrors<T> | undefined;
5
- } & Partial<{}>> & import('vue').PublicProps;
6
- expose(exposed: import('vue').ShallowUnwrapRef<{}>): void;
7
- attrs: any;
8
- slots: Readonly<{
9
- default(props: {
10
- value: T;
11
- }): void;
12
- }> & {
13
- default(props: {
14
- value: T;
15
- }): void;
16
- };
17
- emit: {};
18
- }>) => import('vue').VNode<import('vue').RendererNode, import('vue').RendererElement, {
19
- [key: string]: any;
20
- }> & {
21
- __ctx?: Awaited<typeof __VLS_setup>;
22
- };
23
- export default _default;
24
- type __VLS_PrettifyLocal<T> = {
25
- [K in keyof T]: T[K];
26
- } & {};
27
- //# sourceMappingURL=ValueOrErrorsComponent.vue.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ValueOrErrorsComponent.vue.d.ts","sourceRoot":"","sources":["../../src/components/ValueOrErrorsComponent.vue"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;yBAEzC,CAAC,eACJ,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,cAClD,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,iBAC5F,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC;WA0E1D,mBAAmB,CAAC;sBAvEZ,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS;mBAuEkD,CAAC,4BAA2B;oBACzG,OAAO,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI;WAClD,GAAG;;uBA9DM;YAAE,KAAK,EAAE,CAAC,CAAA;SAAE,GAAG,IAAI;;uBAAnB;YAAE,KAAK,EAAE,CAAC,CAAA;SAAE,GAAG,IAAI;;UAgE7B,EAAE;;;;YAGmC,OAAO,CAAC,OAAO,WAAW,CAAC;;AApFvE,wBAoF4E;AAC5E,KAAK,mBAAmB,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC"}
@@ -1,22 +0,0 @@
1
- import { defineComponent as d, computed as l, createElementBlock as t, openBlock as a, renderSlot as i, createCommentVNode as u, normalizeProps as c, mergeProps as p, toDisplayString as m } from "vue";
2
- const E = {
3
- key: 1,
4
- class: "alert-error"
5
- }, _ = { key: 2 }, f = /* @__PURE__ */ d({
6
- __name: "ValueOrErrorsComponent",
7
- props: {
8
- valueOrError: {}
9
- },
10
- setup(v) {
11
- const r = v, e = l(() => r.valueOrError && r.valueOrError.ok ? r.valueOrError.value : void 0), o = l(() => r.valueOrError && !r.valueOrError.ok ? r.valueOrError.errors : void 0), s = l(() => e.value === void 0 && o.value === void 0);
12
- return (n, O) => (a(), t("div", null, [
13
- e.value !== void 0 ? i(n.$slots, "default", c(p({ key: 0 }, { value: e.value }))) : u("", !0),
14
- o.value ? (a(), t("div", E, m(o.value), 1)) : u("", !0),
15
- s.value ? (a(), t("div", _, "Unresolved")) : u("", !0)
16
- ]));
17
- }
18
- });
19
- export {
20
- f as default
21
- };
22
- //# sourceMappingURL=ValueOrErrorsComponent.vue.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ValueOrErrorsComponent.vue.js","sources":["../../src/components/ValueOrErrorsComponent.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T\">\nimport { computed } from 'vue';\nimport type { ValueOrErrors } from '@platforma-sdk/model';\n\nconst props = defineProps<{\n valueOrError: ValueOrErrors<T> | undefined;\n}>();\n\nconst value = computed(() => (props.valueOrError && props.valueOrError.ok ? props.valueOrError.value : undefined));\n\nconst error = computed(() => (props.valueOrError && !props.valueOrError.ok ? props.valueOrError.errors : undefined));\n\nconst isUnresolved = computed(() => value.value === undefined && error.value === undefined);\n\ndefineSlots<{\n default(props: { value: T }): void;\n}>();\n</script>\n\n<template>\n <div>\n <slot v-if=\"value !== undefined\" name=\"default\" v-bind=\"{ value }\" />\n <div v-if=\"error\" class=\"alert-error\">\n {{ error }}\n </div>\n <div v-if=\"isUnresolved\">Unresolved</div>\n </div>\n</template>\n"],"names":["props","__props","value","computed","error","isUnresolved","_createElementBlock","_renderSlot","_ctx","_hoisted_1","_toDisplayString","_openBlock"],"mappings":";;;;;;;;;;AAIA,UAAMA,IAAQC,GAIRC,IAAQC,EAAS,MAAOH,EAAM,gBAAgBA,EAAM,aAAa,KAAKA,EAAM,aAAa,QAAQ,MAAU,GAE3GI,IAAQD,EAAS,MAAOH,EAAM,gBAAgB,CAACA,EAAM,aAAa,KAAKA,EAAM,aAAa,SAAS,MAAU,GAE7GK,IAAeF,EAAS,MAAMD,EAAM,UAAU,UAAaE,EAAM,UAAU,MAAS;2BAQxFE,EAMM,OAAA,MAAA;AAAA,MALQJ,EAAA,UAAU,SAAtBK,EAAqEC,8CAAXN,EAAA,MAAA,CAAK,CAAA,CAAA;MACpDE,EAAA,cAAXE,EAEM,OAFNG,GAEMC,EADDN,EAAA,KAAK,GAAA,CAAA;MAECC,EAAA,SAAXM,EAAA,GAAAL,EAAyC,UAAhB,YAAU;;;;"}
@@ -1,5 +0,0 @@
1
- import f from "./ValueOrErrorsComponent.vue.js";
2
- export {
3
- f as default
4
- };
5
- //# sourceMappingURL=ValueOrErrorsComponent.vue2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ValueOrErrorsComponent.vue2.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1,28 +0,0 @@
1
- <script setup lang="ts" generic="T">
2
- import { computed } from 'vue';
3
- import type { ValueOrErrors } from '@platforma-sdk/model';
4
-
5
- const props = defineProps<{
6
- valueOrError: ValueOrErrors<T> | undefined;
7
- }>();
8
-
9
- const value = computed(() => (props.valueOrError && props.valueOrError.ok ? props.valueOrError.value : undefined));
10
-
11
- const error = computed(() => (props.valueOrError && !props.valueOrError.ok ? props.valueOrError.errors : undefined));
12
-
13
- const isUnresolved = computed(() => value.value === undefined && error.value === undefined);
14
-
15
- defineSlots<{
16
- default(props: { value: T }): void;
17
- }>();
18
- </script>
19
-
20
- <template>
21
- <div>
22
- <slot v-if="value !== undefined" name="default" v-bind="{ value }" />
23
- <div v-if="error" class="alert-error">
24
- {{ error }}
25
- </div>
26
- <div v-if="isUnresolved">Unresolved</div>
27
- </div>
28
- </template>