@statezero/core 0.2.26 → 0.2.28

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.
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Register a global error handler for StateZero errors.
3
+ * Errors still propagate to call sites - this is for side effects like toasts.
4
+ *
5
+ * @param {Function} handler - Callback receiving the error
6
+ * @returns {Function} Unsubscribe function
7
+ *
8
+ * @example
9
+ * // In a Vue component with access to toast
10
+ * const unsubscribe = onStateZeroError((error) => {
11
+ * toast.error(error.message)
12
+ * })
13
+ * onUnmounted(() => unsubscribe())
14
+ */
15
+ export function onStateZeroError(handler: Function): Function;
16
+ /**
17
+ * Emit an error to all registered handlers.
18
+ * @param {Error} error - The error that occurred
19
+ */
20
+ export function emitError(error: Error): void;
21
+ export const errorEmitter: any;
@@ -0,0 +1,27 @@
1
+ import mitt from 'mitt';
2
+ export const errorEmitter = mitt();
3
+ /**
4
+ * Register a global error handler for StateZero errors.
5
+ * Errors still propagate to call sites - this is for side effects like toasts.
6
+ *
7
+ * @param {Function} handler - Callback receiving the error
8
+ * @returns {Function} Unsubscribe function
9
+ *
10
+ * @example
11
+ * // In a Vue component with access to toast
12
+ * const unsubscribe = onStateZeroError((error) => {
13
+ * toast.error(error.message)
14
+ * })
15
+ * onUnmounted(() => unsubscribe())
16
+ */
17
+ export function onStateZeroError(handler) {
18
+ errorEmitter.on('error', handler);
19
+ return () => errorEmitter.off('error', handler);
20
+ }
21
+ /**
22
+ * Emit an error to all registered handlers.
23
+ * @param {Error} error - The error that occurred
24
+ */
25
+ export function emitError(error) {
26
+ errorEmitter.emit('error', error);
27
+ }
@@ -164,7 +164,18 @@ function processFieldPath(fieldPath, value, ModelClass, options = {}) {
164
164
  if (isLastPart) {
165
165
  break;
166
166
  }
167
- // If it's not the last part but it's a regular field,
167
+ // Check if this is a JSON field - if so, we can traverse into it
168
+ const fieldSchema = currentModel.schema?.properties?.[part];
169
+ if (fieldSchema && fieldSchema.format === 'json') {
170
+ // This is a JSON field - add remaining parts as nested key access
171
+ // e.g., json_field__nested__active becomes json_field.nested.active
172
+ const remainingParts = fieldParts.slice(i + 1);
173
+ processedPath.push(...remainingParts);
174
+ // The final field name for schema lookup is still the JSON field itself
175
+ // (remaining parts are just keys within the JSON)
176
+ break;
177
+ }
178
+ // If it's not the last part and not a JSON field,
168
179
  // we can't continue traversal
169
180
  throw new Error(`Field '${part}' in '${fieldPath}' is not a relationship field and cannot be traversed.`);
170
181
  }
@@ -1,3 +1,4 @@
1
+ import { emitError } from '../../errorHandler.js';
1
2
  /**
2
3
  * @typedef {Object} IErrorResponse
3
4
  * @property {number} status - The HTTP status code.
@@ -28,6 +29,7 @@ export class StateZeroError extends Error {
28
29
  this.detail = detail;
29
30
  this.status = status;
30
31
  Object.setPrototypeOf(this, new.target.prototype);
32
+ emitError(this);
31
33
  }
32
34
  /**
33
35
  * Returns a full error message including the detail.
package/dist/index.d.ts CHANGED
@@ -37,4 +37,5 @@ import { setAdapters } from "./reactiveAdaptor.js";
37
37
  import { wrapReactiveModel } from "./reactiveAdaptor.js";
38
38
  import { wrapReactiveQuerySet } from "./reactiveAdaptor.js";
39
39
  import { serializeActionPayload } from "./flavours/django/serializers.js";
40
- export { EventType, PusherEventReceiver, setEventReceiver, getEventReceiver, setNamespaceResolver, setupStateZero, resetStateZero, FileObject, querysetStoreRegistry, modelStoreRegistry, metricRegistry, syncManager, Operation, operationRegistry, Q, StateZeroError, ValidationError, DoesNotExist, PermissionDenied, MultipleObjectsReturned, ASTValidationError, ConfigError, parseStateZeroError, QuerySet, Manager, ResultTuple, Model, setConfig, getConfig, setBackendConfig, initializeEventReceiver, configInstance, getModelClass, initEventHandler, cleanupEventHandler, setAdapters, wrapReactiveModel, wrapReactiveQuerySet, serializeActionPayload };
40
+ import { onStateZeroError } from "./errorHandler.js";
41
+ export { EventType, PusherEventReceiver, setEventReceiver, getEventReceiver, setNamespaceResolver, setupStateZero, resetStateZero, FileObject, querysetStoreRegistry, modelStoreRegistry, metricRegistry, syncManager, Operation, operationRegistry, Q, StateZeroError, ValidationError, DoesNotExist, PermissionDenied, MultipleObjectsReturned, ASTValidationError, ConfigError, parseStateZeroError, QuerySet, Manager, ResultTuple, Model, setConfig, getConfig, setBackendConfig, initializeEventReceiver, configInstance, getModelClass, initEventHandler, cleanupEventHandler, setAdapters, wrapReactiveModel, wrapReactiveQuerySet, serializeActionPayload, onStateZeroError };
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ import { setAdapters, wrapReactiveModel, wrapReactiveQuerySet, } from "./reactiv
20
20
  import { syncManager } from "./syncEngine/sync.js";
21
21
  import { initEventHandler, cleanupEventHandler, } from "./syncEngine/stores/operationEventHandlers.js";
22
22
  import { resetStateZero } from "./reset.js";
23
+ import { onStateZeroError } from "./errorHandler.js";
23
24
  // Explicitly export everything
24
25
  export {
25
26
  // Core event receivers
@@ -39,4 +40,6 @@ setConfig, getConfig, setBackendConfig, initializeEventReceiver, configInstance,
39
40
  // Reactivity framework integration
40
41
  initEventHandler, cleanupEventHandler, setAdapters, wrapReactiveModel, wrapReactiveQuerySet,
41
42
  // Action utilities
42
- serializeActionPayload, };
43
+ serializeActionPayload,
44
+ // Error handling
45
+ onStateZeroError, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statezero/core",
3
- "version": "0.2.26",
3
+ "version": "0.2.28",
4
4
  "type": "module",
5
5
  "module": "ESNext",
6
6
  "description": "The type-safe frontend client for StateZero - connect directly to your backend models with zero boilerplate",