@blueprint-ts/core 4.1.0-beta.6 → 5.0.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 (62) hide show
  1. package/dist/bulkRequests/BulkRequestSender.js +81 -102
  2. package/dist/bulkRequests/BulkRequestWrapper.js +16 -26
  3. package/dist/laravel/pagination/dataDrivers/RequestDriver.js +1 -0
  4. package/dist/pagination/BasePaginator.js +4 -4
  5. package/dist/pagination/PageAwarePaginator.js +4 -1
  6. package/dist/pagination/StatePaginator.js +6 -3
  7. package/dist/pagination/dataDrivers/ArrayDriver.js +1 -0
  8. package/dist/pagination/dtos/PaginationDataDto.js +2 -0
  9. package/dist/pagination/dtos/StatePaginationDataDto.js +1 -0
  10. package/dist/pagination/frontendDrivers/VueBaseViewDriver.js +2 -0
  11. package/dist/pagination/frontendDrivers/VuePaginationDriver.js +6 -0
  12. package/dist/persistenceDrivers/LocalStorageDriver.js +1 -0
  13. package/dist/persistenceDrivers/MemoryPersistenceDriver.js +2 -1
  14. package/dist/persistenceDrivers/SessionStorageDriver.js +1 -0
  15. package/dist/requests/BaseRequest.js +93 -100
  16. package/dist/requests/ErrorHandler.js +21 -31
  17. package/dist/requests/RequestErrorRouter.js +12 -25
  18. package/dist/requests/bodies/BinaryBody.js +2 -0
  19. package/dist/requests/bodies/FormDataBody.js +1 -0
  20. package/dist/requests/bodies/JsonBody.js +1 -0
  21. package/dist/requests/drivers/fetch/FetchDriver.js +26 -26
  22. package/dist/requests/drivers/fetch/FetchResponse.js +7 -21
  23. package/dist/requests/drivers/mock/MockRequestDriver.js +190 -169
  24. package/dist/requests/drivers/mock/MockRequestTestHelpers.js +10 -4
  25. package/dist/requests/drivers/mock/MockResponseHandler.js +12 -23
  26. package/dist/requests/drivers/xhr/XMLHttpRequestDriver.js +68 -74
  27. package/dist/requests/drivers/xhr/XMLHttpRequestResponse.js +9 -21
  28. package/dist/requests/exceptions/InvalidJsonException.js +1 -0
  29. package/dist/requests/exceptions/ResponseBodyException.js +1 -0
  30. package/dist/requests/exceptions/ResponseException.js +1 -0
  31. package/dist/requests/exceptions/StaleResponseException.js +1 -0
  32. package/dist/requests/factories/BinaryBodyFactory.js +1 -0
  33. package/dist/requests/responses/BaseResponse.js +9 -21
  34. package/dist/requests/responses/BlobResponse.js +1 -0
  35. package/dist/support/DeferredPromise.js +5 -4
  36. package/dist/vue/composables/useConfirmDialog.js +7 -18
  37. package/dist/vue/composables/useGlobalCheckbox.js +55 -66
  38. package/dist/vue/forms/BaseForm.d.ts +11 -8
  39. package/dist/vue/forms/BaseForm.js +153 -149
  40. package/dist/vue/forms/PropertyAwareArray.js +0 -1
  41. package/dist/vue/forms/PropertyAwareObject.js +4 -2
  42. package/dist/vue/forms/index.d.ts +2 -2
  43. package/dist/vue/forms/persistence/types.d.ts +2 -0
  44. package/dist/vue/forms/validation/rules/BaseRule.js +3 -16
  45. package/dist/vue/forms/validation/rules/ConfirmedRule.js +2 -0
  46. package/dist/vue/forms/validation/rules/EmailRule.js +1 -0
  47. package/dist/vue/forms/validation/rules/JsonRule.js +2 -1
  48. package/dist/vue/forms/validation/rules/MinRule.js +2 -0
  49. package/dist/vue/forms/validation/rules/PrecognitiveRule.js +21 -31
  50. package/dist/vue/forms/validation/rules/RequiredRule.js +1 -0
  51. package/dist/vue/forms/validation/rules/UrlRule.js +2 -1
  52. package/dist/vue/requests/loaders/VueRequestBatchLoader.js +3 -3
  53. package/dist/vue/requests/loaders/VueRequestLoader.js +1 -0
  54. package/dist/vue/router/routeResourceBinding/RouteResourceBoundView.js +8 -18
  55. package/dist/vue/router/routeResourceBinding/RouteResourceRequestResolver.js +4 -14
  56. package/dist/vue/router/routeResourceBinding/defineRoute.js +8 -7
  57. package/dist/vue/router/routeResourceBinding/installRouteInjection.js +12 -21
  58. package/dist/vue/router/routeResourceBinding/useRouteResource.js +5 -17
  59. package/dist/vue/state/State.d.ts +2 -0
  60. package/dist/vue/state/State.js +24 -11
  61. package/dist/vue/state/index.d.ts +2 -1
  62. package/package.json +27 -27
@@ -1,21 +1,8 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  export class BaseRule {
11
- constructor() {
12
- this.dependsOn = [];
13
- }
2
+ dependsOn = [];
14
3
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
15
- validateAsync(_value, _state, _context) {
16
- return __awaiter(this, void 0, void 0, function* () {
17
- return null;
18
- });
4
+ async validateAsync(_value, _state, _context) {
5
+ return null;
19
6
  }
20
7
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
21
8
  getAsyncValidationPaths(field, _state) {
@@ -1,5 +1,7 @@
1
1
  import { BaseRule } from './BaseRule';
2
2
  export class ConfirmedRule extends BaseRule {
3
+ confirmationField;
4
+ message;
3
5
  constructor(confirmationField, message) {
4
6
  super();
5
7
  this.confirmationField = confirmationField;
@@ -1,5 +1,6 @@
1
1
  import { BaseRule } from './BaseRule';
2
2
  export class EmailRule extends BaseRule {
3
+ message;
3
4
  constructor(message = 'Please enter a valid email address') {
4
5
  super();
5
6
  this.message = message;
@@ -1,5 +1,6 @@
1
1
  import { BaseRule } from './BaseRule';
2
2
  export class JsonRule extends BaseRule {
3
+ message;
3
4
  constructor(message = 'Please enter valid JSON') {
4
5
  super();
5
6
  this.message = message;
@@ -15,7 +16,7 @@ export class JsonRule extends BaseRule {
15
16
  JSON.parse(value);
16
17
  return true;
17
18
  }
18
- catch (_a) {
19
+ catch {
19
20
  return false;
20
21
  }
21
22
  }
@@ -1,5 +1,7 @@
1
1
  import { BaseRule } from './BaseRule';
2
2
  export class MinRule extends BaseRule {
3
+ min;
4
+ message;
3
5
  /**
4
6
  * Creates a new MinRule
5
7
  * @param min The minimum value (length for strings, value for numbers, length for arrays)
@@ -1,15 +1,8 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { ValidationException } from '../../../../requests/exceptions/ValidationException';
11
2
  import { BaseRule } from './BaseRule';
12
3
  export class PrecognitiveRule extends BaseRule {
4
+ requestFactory;
5
+ options;
13
6
  constructor(requestFactory, options = {}) {
14
7
  super();
15
8
  this.requestFactory = requestFactory;
@@ -31,28 +24,25 @@ export class PrecognitiveRule extends BaseRule {
31
24
  }
32
25
  return [String(field)];
33
26
  }
34
- validateAsync(_value, state, context) {
35
- return __awaiter(this, void 0, void 0, function* () {
36
- var _a, _b, _c, _d, _e;
37
- const request = this.requestFactory();
38
- const validateOnly = this.getAsyncValidationPaths(context.field, state);
39
- request.setBody(context.payload);
40
- request.setHeaders({
41
- Accept: (_a = this.options.acceptHeader) !== null && _a !== void 0 ? _a : 'application/json',
42
- Precognition: 'true',
43
- 'Precognition-Validate-Only': validateOnly.join(',')
44
- });
45
- try {
46
- yield request.send({ resolveBody: false });
47
- return {};
48
- }
49
- catch (error) {
50
- if (error instanceof ValidationException) {
51
- const body = error.getBody();
52
- return (_e = (_d = (_c = (_b = this.options).resolveErrors) === null || _c === void 0 ? void 0 : _c.call(_b, body)) !== null && _d !== void 0 ? _d : body.errors) !== null && _e !== void 0 ? _e : {};
53
- }
54
- throw error;
55
- }
27
+ async validateAsync(_value, state, context) {
28
+ const request = this.requestFactory();
29
+ const validateOnly = this.getAsyncValidationPaths(context.field, state);
30
+ request.setBody(context.payload);
31
+ request.setHeaders({
32
+ Accept: this.options.acceptHeader ?? 'application/json',
33
+ Precognition: 'true',
34
+ 'Precognition-Validate-Only': validateOnly.join(',')
56
35
  });
36
+ try {
37
+ await request.send({ resolveBody: false });
38
+ return {};
39
+ }
40
+ catch (error) {
41
+ if (error instanceof ValidationException) {
42
+ const body = error.getBody();
43
+ return this.options.resolveErrors?.(body) ?? body.errors ?? {};
44
+ }
45
+ throw error;
46
+ }
57
47
  }
58
48
  }
@@ -1,5 +1,6 @@
1
1
  import { BaseRule } from './BaseRule';
2
2
  export class RequiredRule extends BaseRule {
3
+ message;
3
4
  constructor(message = 'This field is required') {
4
5
  super();
5
6
  this.message = message;
@@ -1,5 +1,6 @@
1
1
  import { BaseRule } from './BaseRule';
2
2
  export class UrlRule extends BaseRule {
3
+ message;
3
4
  constructor(message = 'Please enter a valid URL') {
4
5
  super();
5
6
  this.message = message;
@@ -12,7 +13,7 @@ export class UrlRule extends BaseRule {
12
13
  new URL(value);
13
14
  return true;
14
15
  }
15
- catch (_a) {
16
+ catch {
16
17
  return false;
17
18
  }
18
19
  }
@@ -1,9 +1,9 @@
1
1
  import { ref, computed } from 'vue';
2
2
  export class VueRequestBatchLoader {
3
+ inFlight = ref(0);
4
+ completed = ref(0);
5
+ expected = 0;
3
6
  constructor(expectedRequests = 0) {
4
- this.inFlight = ref(0);
5
- this.completed = ref(0);
6
- this.expected = 0;
7
7
  this.expected = expectedRequests;
8
8
  }
9
9
  startBatch(count) {
@@ -1,5 +1,6 @@
1
1
  import { ref } from 'vue';
2
2
  export class VueRequestLoader {
3
+ loading;
3
4
  constructor(initialLoading = false) {
4
5
  this.loading = ref(initialLoading);
5
6
  }
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { computed, defineComponent, h } from 'vue';
11
2
  import { RouterView, useRoute } from 'vue-router';
12
3
  /**
@@ -75,7 +66,7 @@ export const RouteResourceBoundView = defineComponent({
75
66
  return null;
76
67
  for (const key of Object.keys(state)) {
77
68
  const entry = state[key];
78
- if (entry === null || entry === void 0 ? void 0 : entry.error)
69
+ if (entry?.error)
79
70
  return entry.error;
80
71
  }
81
72
  return null;
@@ -84,21 +75,20 @@ export const RouteResourceBoundView = defineComponent({
84
75
  const state = injectionState.value;
85
76
  if (!state)
86
77
  return false;
87
- return Object.keys(state).some((key) => { var _a; return (_a = state[key]) === null || _a === void 0 ? void 0 : _a.loading; });
78
+ return Object.keys(state).some((key) => state[key]?.loading);
88
79
  });
89
- const refresh = () => __awaiter(this, void 0, void 0, function* () {
80
+ const refresh = async () => {
90
81
  const state = injectionState.value;
91
82
  if (!state)
92
83
  return;
93
- const erroredProps = Object.keys(state).filter((key) => { var _a; return (_a = state[key]) === null || _a === void 0 ? void 0 : _a.error; });
94
- yield Promise.all(erroredProps.map((propName) => { var _a, _b; return (_b = (_a = route.meta).refresh) === null || _b === void 0 ? void 0 : _b.call(_a, propName); }));
95
- });
84
+ const erroredProps = Object.keys(state).filter((key) => state[key]?.error);
85
+ await Promise.all(erroredProps.map((propName) => route.meta.refresh?.(propName)));
86
+ };
96
87
  /**
97
88
  * Core render logic that decides which slot/component to show
98
89
  * given the resolved Component and route from RouterView.
99
90
  */
100
91
  function renderContent(Component, resolvedRoute) {
101
- var _a, _b;
102
92
  const isLazy = resolvedRoute.meta._lazy !== false;
103
93
  if (isLazy) {
104
94
  if (firstError.value) {
@@ -106,14 +96,14 @@ export const RouteResourceBoundView = defineComponent({
106
96
  if (errorComponent) {
107
97
  return h(errorComponent, { error: firstError.value, refresh });
108
98
  }
109
- return (_a = slots['error']) === null || _a === void 0 ? void 0 : _a.call(slots, { error: firstError.value, refresh });
99
+ return slots['error']?.({ error: firstError.value, refresh });
110
100
  }
111
101
  if (anyLoading.value) {
112
102
  const loadingComponent = resolvedRoute.meta._loadingComponent;
113
103
  if (loadingComponent) {
114
104
  return h(loadingComponent);
115
105
  }
116
- return (_b = slots['loading']) === null || _b === void 0 ? void 0 : _b.call(slots);
106
+ return slots['loading']?.();
117
107
  }
118
108
  }
119
109
  if (slots['default']) {
@@ -1,20 +1,10 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  export class RouteResourceRequestResolver {
2
+ request;
11
3
  constructor(request) {
12
4
  this.request = request;
13
5
  }
14
- resolve() {
15
- return __awaiter(this, void 0, void 0, function* () {
16
- const response = yield this.request.send();
17
- return response.getData();
18
- });
6
+ async resolve() {
7
+ const response = await this.request.send();
8
+ return response.getData();
19
9
  }
20
10
  }
@@ -15,27 +15,28 @@ import { markRaw } from 'vue';
15
15
  */
16
16
  export function defineRoute() {
17
17
  return function (route) {
18
- var _a, _b, _c;
19
18
  const originalProps = route.props;
20
19
  if (route.errorComponent) {
21
- route.meta = (_a = route.meta) !== null && _a !== void 0 ? _a : {};
20
+ route.meta = route.meta ?? {};
22
21
  route.meta._errorComponent = markRaw(route.errorComponent);
23
22
  delete route.errorComponent;
24
23
  }
25
24
  if (route.loadingComponent) {
26
- route.meta = (_b = route.meta) !== null && _b !== void 0 ? _b : {};
25
+ route.meta = route.meta ?? {};
27
26
  route.meta._loadingComponent = markRaw(route.loadingComponent);
28
27
  delete route.loadingComponent;
29
28
  }
30
29
  if (route.lazy !== undefined) {
31
- route.meta = (_c = route.meta) !== null && _c !== void 0 ? _c : {};
30
+ route.meta = route.meta ?? {};
32
31
  route.meta._lazy = route.lazy;
33
32
  delete route.lazy;
34
33
  }
35
34
  route.props = (to) => {
36
- var _a;
37
- const baseProps = typeof originalProps === 'function' ? originalProps(to) : originalProps === true ? to.params : (originalProps !== null && originalProps !== void 0 ? originalProps : {});
38
- return Object.assign(Object.assign({}, baseProps), ((_a = to.meta._injectedProps) !== null && _a !== void 0 ? _a : {}));
35
+ const baseProps = typeof originalProps === 'function' ? originalProps(to) : originalProps === true ? to.params : (originalProps ?? {});
36
+ return {
37
+ ...baseProps,
38
+ ...(to.meta._injectedProps ?? {})
39
+ };
39
40
  };
40
41
  return route;
41
42
  };
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { reactive } from 'vue';
11
2
  /**
12
3
  * Installs the runtime part:
@@ -22,7 +13,7 @@ import { reactive } from 'vue';
22
13
  */
23
14
  export function installRouteInjection(router) {
24
15
  const cache = {};
25
- router.beforeResolve((to) => __awaiter(this, void 0, void 0, function* () {
16
+ router.beforeResolve(async (to) => {
26
17
  console.log('[Route Injection] Resolving route injections...');
27
18
  if (!to.meta._injectedProps) {
28
19
  to.meta._injectedProps = reactive({});
@@ -60,15 +51,15 @@ export function installRouteInjection(router) {
60
51
  state[propName] = reactive({ loading: false, error: null });
61
52
  }
62
53
  // Define the refresh logic for this specific prop (always fetches fresh data)
63
- const resolveProp = (options) => __awaiter(this, void 0, void 0, function* () {
54
+ const resolveProp = async (options) => {
64
55
  const propState = to.meta._injectionState[propName];
65
- if (!(options === null || options === void 0 ? void 0 : options.silent)) {
56
+ if (!options?.silent) {
66
57
  propState.loading = true;
67
58
  }
68
59
  propState.error = null;
69
60
  try {
70
61
  const resolver = cfg.resolve(paramValue);
71
- let payload = yield resolver.resolve();
62
+ let payload = await resolver.resolve();
72
63
  if (typeof cfg.getter === 'function') {
73
64
  payload = cfg.getter(payload);
74
65
  }
@@ -86,7 +77,7 @@ export function installRouteInjection(router) {
86
77
  finally {
87
78
  propState.loading = false;
88
79
  }
89
- });
80
+ };
90
81
  resolvers[propName] = resolveProp;
91
82
  // Reuse cached value if the param hasn't changed (e.g. navigating between child routes)
92
83
  const cached = cache[propName];
@@ -99,14 +90,14 @@ export function installRouteInjection(router) {
99
90
  // Set loading immediately and queue resolver (non-blocking)
100
91
  const injectionState = to.meta._injectionState;
101
92
  injectionState[propName].loading = true;
102
- pendingResolvers.push(() => __awaiter(this, void 0, void 0, function* () {
93
+ pendingResolvers.push(async () => {
103
94
  try {
104
- yield resolveProp();
95
+ await resolveProp();
105
96
  }
106
97
  catch (e) {
107
98
  console.error(`[Route Injection] Failed to resolve prop "${propName}"`, e);
108
99
  }
109
- }));
100
+ });
110
101
  console.debug(`[Route Injection] Queued resolution for prop "${propName}" for route "${record.path}"`);
111
102
  }
112
103
  }
@@ -118,16 +109,16 @@ export function installRouteInjection(router) {
118
109
  }
119
110
  // Attach the resolvers and a global refresh helper to the route meta
120
111
  to.meta['_injectedResolvers'] = resolvers;
121
- to.meta['refresh'] = (propName, options) => __awaiter(this, void 0, void 0, function* () {
112
+ to.meta['refresh'] = async (propName, options) => {
122
113
  if (resolvers[propName]) {
123
- return yield resolvers[propName](options);
114
+ return await resolvers[propName](options);
124
115
  }
125
116
  console.warn(`[Route Injection] No resolver found for "${propName}"`);
126
117
  return undefined;
127
- });
118
+ };
128
119
  // Fire pending resolvers without blocking navigation
129
120
  if (pendingResolvers.length > 0) {
130
121
  Promise.all(pendingResolvers.map((fn) => fn()));
131
122
  }
132
- }));
123
+ });
133
124
  }
@@ -1,29 +1,17 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { computed } from 'vue';
11
2
  import { useRoute } from 'vue-router';
12
3
  export function useRouteResource(propName) {
13
4
  const route = useRoute();
14
- const refresh = (options) => __awaiter(this, void 0, void 0, function* () {
15
- var _a, _b;
16
- return yield ((_b = (_a = route.meta).refresh) === null || _b === void 0 ? void 0 : _b.call(_a, propName, options));
17
- });
5
+ const refresh = async (options) => {
6
+ return await route.meta.refresh?.(propName, options);
7
+ };
18
8
  const isLoading = computed(() => {
19
- var _a, _b;
20
9
  const state = route.meta._injectionState;
21
- return (_b = (_a = state === null || state === void 0 ? void 0 : state[propName]) === null || _a === void 0 ? void 0 : _a.loading) !== null && _b !== void 0 ? _b : false;
10
+ return state?.[propName]?.loading ?? false;
22
11
  });
23
12
  const error = computed(() => {
24
- var _a, _b;
25
13
  const state = route.meta._injectionState;
26
- return (_b = (_a = state === null || state === void 0 ? void 0 : state[propName]) === null || _a === void 0 ? void 0 : _a.error) !== null && _b !== void 0 ? _b : null;
14
+ return state?.[propName]?.error ?? null;
27
15
  });
28
16
  return { refresh, isLoading, error };
29
17
  }
@@ -1,6 +1,7 @@
1
1
  import { type PersistenceDriver } from '../../persistenceDrivers';
2
2
  export interface StateOptions {
3
3
  persist?: boolean;
4
+ persistKey?: string;
4
5
  persistSuffix?: string;
5
6
  }
6
7
  /** Generic type for change handlers. */
@@ -24,6 +25,7 @@ export declare abstract class State<T extends object> {
24
25
  private _resetHandlers;
25
26
  private _watchIdCounter;
26
27
  protected constructor(initial: T, options?: StateOptions);
28
+ private resolvePersistKey;
27
29
  /**
28
30
  * Safe deep clone that preserves types
29
31
  */
@@ -15,15 +15,19 @@ function getNestedValue(root, pathParts) {
15
15
  return current;
16
16
  }
17
17
  export class State {
18
+ properties;
19
+ _initial;
20
+ _persist;
21
+ _persistKey;
22
+ _driver;
23
+ _stateProxy = null;
24
+ _watchStopFunctions = new Map();
25
+ _resetHandlers = new Map();
26
+ _watchIdCounter = 0;
18
27
  constructor(initial, options) {
19
- this._stateProxy = null;
20
- this._watchStopFunctions = new Map();
21
- this._resetHandlers = new Map();
22
- this._watchIdCounter = 0;
23
28
  this._initial = initial;
24
- this._persist = !!(options === null || options === void 0 ? void 0 : options.persist);
25
- const className = this.constructor.name;
26
- this._persistKey = className + ((options === null || options === void 0 ? void 0 : options.persistSuffix) ? `_${options.persistSuffix}` : '');
29
+ this._persist = !!options?.persist;
30
+ this._persistKey = this.resolvePersistKey(options);
27
31
  this._driver = this.getPersistenceDriver();
28
32
  let loaded = null;
29
33
  if (this._persist) {
@@ -38,7 +42,7 @@ export class State {
38
42
  }
39
43
  }
40
44
  }
41
- const base = loaded !== null && loaded !== void 0 ? loaded : initial;
45
+ const base = loaded ?? initial;
42
46
  this.properties = {};
43
47
  const keys = Object.keys(base);
44
48
  for (const k of keys) {
@@ -56,6 +60,15 @@ export class State {
56
60
  });
57
61
  }
58
62
  }
63
+ resolvePersistKey(options) {
64
+ if (this._persist && !options?.persistKey) {
65
+ throw new Error('State persistence requires a stable persistKey option.');
66
+ }
67
+ if (!options?.persistKey) {
68
+ return '';
69
+ }
70
+ return options.persistSuffix ? `${options.persistKey}_${options.persistSuffix}` : options.persistKey;
71
+ }
59
72
  /**
60
73
  * Safe deep clone that preserves types
61
74
  */
@@ -115,7 +128,7 @@ export class State {
115
128
  ;
116
129
  handler(path, this.export());
117
130
  };
118
- if (options === null || options === void 0 ? void 0 : options.executeOnReset) {
131
+ if (options?.executeOnReset) {
119
132
  resetHandlers.push(pathHandler);
120
133
  }
121
134
  const stop = this.setupWatcher(path, pathHandler, options);
@@ -124,7 +137,7 @@ export class State {
124
137
  }
125
138
  else {
126
139
  const pathHandler = handler;
127
- if (options === null || options === void 0 ? void 0 : options.executeOnReset) {
140
+ if (options?.executeOnReset) {
128
141
  resetHandlers.push(() => pathHandler(undefined, undefined));
129
142
  }
130
143
  const stop = this.setupWatcher(paths, pathHandler, options);
@@ -144,7 +157,7 @@ export class State {
144
157
  */
145
158
  setupWatcher(path, handler, options) {
146
159
  const pathParts = path.split('.');
147
- const debouncedHandler = (options === null || options === void 0 ? void 0 : options.debounce) && options.debounce > 0 ? debounce(handler, options.debounce) : undefined;
160
+ const debouncedHandler = options?.debounce && options.debounce > 0 ? debounce(handler, options.debounce) : undefined;
148
161
  const effectiveHandler = debouncedHandler || handler;
149
162
  if (pathParts.length === 1 && path in this.properties) {
150
163
  const key = path;
@@ -1,2 +1,3 @@
1
- import { State } from './State';
1
+ import { State, type StateOptions } from './State';
2
2
  export { State };
3
+ export type { StateOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blueprint-ts/core",
3
- "version": "4.1.0-beta.6",
3
+ "version": "5.0.0",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -85,7 +85,7 @@
85
85
  },
86
86
  "scripts": {
87
87
  "dev": "vite",
88
- "build": "run-p type-check build:package \"build-only {@}\" --",
88
+ "build": "run-p type-check build:package",
89
89
  "build:package": "tsc -p tsconfig.build.json",
90
90
  "preview": "vite preview",
91
91
  "test": "vitest",
@@ -103,37 +103,37 @@
103
103
  "prepare": "npm run build:package"
104
104
  },
105
105
  "devDependencies": {
106
+ "@eslint/js": "^10.0.1",
106
107
  "@rushstack/eslint-patch": "^1.3.3",
107
108
  "@tsconfig/node20": "^20.1.2",
108
- "@types/jsdom": "^21.1.6",
109
+ "@types/jsdom": "^28.0.3",
109
110
  "@types/lodash-es": "^4.17.12",
110
- "@types/node": "^20.11.28",
111
- "@types/qs": "^6.9.18",
112
- "@typescript-eslint/eslint-plugin": "^8.21.0",
113
- "@typescript-eslint/parser": "^8.21.0",
114
- "@typescript-eslint/typescript-estree": "^8.21.0",
115
- "@vitejs/plugin-vue": "^5.0.4",
116
- "@vitejs/plugin-vue-jsx": "^3.1.0",
117
- "@vitest/coverage-v8": "^3.0.4",
118
- "@vue/eslint-config-typescript": "^14.0.0",
119
- "autoprefixer": "^10.4.19",
120
- "eslint": "^9.0.0",
111
+ "@types/node": "^26.0.0",
112
+ "@types/qs": "^6.15.1",
113
+ "@typescript-eslint/eslint-plugin": "^8.62.0",
114
+ "@typescript-eslint/parser": "^8.62.0",
115
+ "@typescript-eslint/typescript-estree": "^8.62.0",
116
+ "@vitejs/plugin-vue": "^6.0.7",
117
+ "@vitest/coverage-v8": "^4.1.9",
118
+ "@vue/eslint-config-typescript": "^14.9.0",
119
+ "autoprefixer": "^10.5.0",
120
+ "eslint": "^10.5.0",
121
121
  "eslint-config-prettier": "^10.0.1",
122
- "eslint-plugin-vue": "^9.31.0",
123
- "jsdom": "^24.0.0",
124
- "npm-run-all2": "^6.1.2",
125
- "prettier": "^3.0.3",
126
- "typescript": "^5.7.2",
127
- "typescript-eslint": "^8.21.0",
128
- "vite": "^5.1.6",
122
+ "eslint-plugin-vue": "^10.9.2",
123
+ "jsdom": "^29.1.1",
124
+ "npm-run-all2": "^9.0.2",
125
+ "prettier": "^3.8.4",
126
+ "typescript": "^6.0.3",
127
+ "typescript-eslint": "^8.62.0",
128
+ "vite": "^8.0.16",
129
129
  "vitepress": "^1.6.3",
130
- "vitest": "^3.0.4",
131
- "vue": "^3.4.25",
132
- "vue-router": "^4.3.2"
130
+ "vitest": "^4.1.9",
131
+ "vue": "^3.5.38",
132
+ "vue-router": "^5.1.0"
133
133
  },
134
134
  "dependencies": {
135
- "lodash-es": "^4.17.23",
136
- "qs": "^6.15.0",
137
- "uuid": "^13.0.0"
135
+ "lodash-es": "^4.18.1",
136
+ "qs": "^6.15.2",
137
+ "uuid": "^14.0.1"
138
138
  }
139
139
  }