@statezero/core 0.2.56 → 0.2.59

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.
@@ -2,11 +2,11 @@ import { ref as J, computed as I, onMounted as hs, onBeforeUnmount as fs, watch
2
2
  import { v7 as B } from "uuid";
3
3
  import { isNil as b, isEmpty as Te, trim as dt, isEqual as He } from "lodash-es";
4
4
  import Oe from "mitt";
5
- import Ft from "handlebars";
6
- import Pt from "superjson";
5
+ import Pt from "handlebars";
6
+ import Ft from "superjson";
7
7
  import ps from "p-queue";
8
8
  import ms from "axios";
9
- import { z as $ } from "zod";
9
+ import { z as O } from "zod";
10
10
  import ys from "pusher-js";
11
11
  import Wt, { createEqualsOperation as ee } from "sift";
12
12
  import { DateTime as _e } from "luxon";
@@ -47,9 +47,9 @@ function Je(n) {
47
47
  const e = Object.fromEntries(se);
48
48
  try {
49
49
  if (typeof n == "string")
50
- return Ft.compile(n, { noEscape: !0 })(e);
51
- const t = Pt.stringify(n), r = Ft.compile(t, { noEscape: !0 })(e);
52
- return Pt.parse(r);
50
+ return Pt.compile(n, { noEscape: !0 })(e);
51
+ const t = Ft.stringify(n), r = Pt.compile(t, { noEscape: !0 })(e);
52
+ return Ft.parse(r);
53
53
  } catch {
54
54
  return n;
55
55
  }
@@ -363,7 +363,7 @@ class Ss {
363
363
  */
364
364
  _loadOperations(e) {
365
365
  e.forEach((t) => {
366
- const s = Fe.get(t.operationId);
366
+ const s = Pe.get(t.operationId);
367
367
  s ? this.operationsMap.set(s.operationId, s) : this.operationsMap.set(t.operationId, new q(t, !0));
368
368
  });
369
369
  }
@@ -480,7 +480,7 @@ class Ss {
480
480
  if (r.push(...Array.from(s.values())), this.groundTruthArray = r, i.length > 0) {
481
481
  const l = /* @__PURE__ */ new Set();
482
482
  for (const c of this.operations)
483
- if ((c.type === P.UPDATE || c.type === P.UPDATE_INSTANCE) && c.status !== C.CONFIRMED && c.status !== C.REJECTED)
483
+ if ((c.type === F.UPDATE || c.type === F.UPDATE_INSTANCE) && c.status !== C.CONFIRMED && c.status !== C.REJECTED)
484
484
  for (const h of c.instances)
485
485
  h && h[t] != null && l.add(h[t]);
486
486
  const a = i.filter(
@@ -489,7 +489,7 @@ class Ss {
489
489
  if (a.length > 0) {
490
490
  const c = new q({
491
491
  operationId: `checkpoint_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
492
- type: P.CHECKPOINT,
492
+ type: F.CHECKPOINT,
493
493
  instances: a,
494
494
  status: C.CONFIRMED,
495
495
  timestamp: Date.now(),
@@ -553,21 +553,21 @@ class Ss {
553
553
  }
554
554
  let o = r[s];
555
555
  switch (e.type) {
556
- case P.CREATE:
557
- case P.BULK_CREATE:
556
+ case F.CREATE:
557
+ case F.BULK_CREATE:
558
558
  t.has(o) || t.set(o, r);
559
559
  break;
560
- case P.CHECKPOINT:
561
- case P.UPDATE_INSTANCE:
562
- case P.UPDATE: {
560
+ case F.CHECKPOINT:
561
+ case F.UPDATE_INSTANCE:
562
+ case F.UPDATE: {
563
563
  const i = t.get(o);
564
564
  i ? t.set(o, { ...i, ...r }) : this.operations.some(
565
- (a) => a.type === P.DELETE && a.status !== C.REJECTED && a.instances.some((c) => c && c[s] === o)
565
+ (a) => a.type === F.DELETE && a.status !== C.REJECTED && a.instances.some((c) => c && c[s] === o)
566
566
  ) || t.set(o, r);
567
567
  break;
568
568
  }
569
- case P.DELETE_INSTANCE:
570
- case P.DELETE:
569
+ case F.DELETE_INSTANCE:
570
+ case F.DELETE:
571
571
  t.delete(o);
572
572
  break;
573
573
  default:
@@ -726,7 +726,7 @@ const j = new Ve(), ie = Oe(), C = {
726
726
  REJECTED: "operation:rejected",
727
727
  CLEAR: "clear:all",
728
728
  MUTATED: "operation:mutated"
729
- }, P = {
729
+ }, F = {
730
730
  CREATE: "create",
731
731
  BULK_CREATE: "bulk_create",
732
732
  UPDATE: "update",
@@ -763,7 +763,7 @@ class q {
763
763
  throw new Error(`All operation instances must be objects with the '${o}' field`);
764
764
  this.#e = r;
765
765
  const i = r.map((a) => a[o]);
766
- j.getStore(s).render(i, !0, !1), this.#t = r.map((a) => s.fromPk(a[o]).serialize()), this.timestamp = e.timestamp || Date.now(), !t && (Fe.register(this), ie.emit(C.CREATED, this));
766
+ j.getStore(s).render(i, !0, !1), this.#t = r.map((a) => s.fromPk(a[o]).serialize()), this.timestamp = e.timestamp || Date.now(), !t && (Pe.register(this), ie.emit(C.CREATED, this));
767
767
  }
768
768
  /**
769
769
  * Getter for instances that replaces any temporary PKs with real PKs
@@ -915,7 +915,7 @@ class Ts {
915
915
  return t.length > 0 ? t[t.length - 1] : void 0;
916
916
  }
917
917
  }
918
- const Fe = new Ts(), Ms = Oe();
918
+ const Pe = new Ts(), Ms = Oe();
919
919
  function As(n) {
920
920
  Ms.emit("error", n);
921
921
  }
@@ -927,9 +927,10 @@ class fe extends Error {
927
927
  * @param {string} code - The error code.
928
928
  * @param {IErrorDetail|Object|string} detail - The error details.
929
929
  * @param {number} status - The HTTP status code.
930
+ * @param {Object} [data={}] - Additional structured data from the server.
930
931
  */
931
- constructor(e, t, s, r) {
932
- super(e), this.name = "StateZeroError", this.code = t, this.detail = s, this.status = r, Object.setPrototypeOf(this, new.target.prototype), As(this);
932
+ constructor(e, t, s, r, o = {}) {
933
+ super(e), this.name = "StateZeroError", this.code = t, this.detail = s, this.status = r, this.data = o, Object.setPrototypeOf(this, new.target.prototype), As(this);
933
934
  }
934
935
  /**
935
936
  * Returns a full error message including the detail.
@@ -1028,8 +1029,8 @@ class U extends fe {
1028
1029
  super("Configuration error", "config_error", e, t), this.name = "ConfigError";
1029
1030
  }
1030
1031
  }
1031
- function Fs(n) {
1032
- const { status: e, type: t, detail: s } = n;
1032
+ function Ps(n) {
1033
+ const { status: e, type: t, detail: s, data: r } = n;
1033
1034
  if (t === void 0 && s === "Invalid token.")
1034
1035
  return new lt(s, 403);
1035
1036
  switch (t) {
@@ -1054,7 +1055,13 @@ function Fs(n) {
1054
1055
  case "ValueError":
1055
1056
  return new $e(s, e);
1056
1057
  default:
1057
- return e === 400 ? new $e(s, e) : e === 403 ? new lt(s, e) : e === 404 ? new It(s, e) : e === 409 ? new Nt(s, e) : new fe("Unknown error", "unknown", s, e);
1058
+ return e === 400 ? new $e(s, e) : e === 403 ? new lt(s, e) : e === 404 ? new It(s, e) : e === 409 ? new Nt(s, e) : new fe(
1059
+ s || "Unknown error",
1060
+ t || "unknown",
1061
+ s,
1062
+ e,
1063
+ r || {}
1064
+ );
1058
1065
  }
1059
1066
  }
1060
1067
  const xt = {
@@ -1065,7 +1072,7 @@ const xt = {
1065
1072
  BULK_UPDATE: "bulk_update",
1066
1073
  BULK_DELETE: "bulk_delete"
1067
1074
  };
1068
- class Ps {
1075
+ class Fs {
1069
1076
  /**
1070
1077
  * @param {PusherReceiverOptions} options
1071
1078
  * @param {string} configKey - The backend configuration key
@@ -1075,12 +1082,13 @@ class Ps {
1075
1082
  this.configKey = t, this.connectionTimeoutId = null, s.appKey && /^\d+$/.test(s.appKey) && s.appKey.length < 15 && console.warn(
1076
1083
  `%c[Pusher Warning] The provided appKey ("${s.appKey}") looks like a numeric app_id. Pusher requires the alphanumeric key, not the ID. Please verify your configuration for backend: "${this.configKey}".`,
1077
1084
  "color: orange; font-weight: bold; font-size: 14px;"
1078
- ), this.pusherClient = new ys(s.appKey, {
1079
- cluster: s.cluster,
1085
+ );
1086
+ const l = {
1080
1087
  forceTLS: s.forceTLS ?? !0,
1081
1088
  authEndpoint: s.authEndpoint,
1082
1089
  auth: { headers: s.getAuthHeaders?.() || {} }
1083
- }), this.pusherClient.connection.bind("connected", () => {
1090
+ };
1091
+ s.wsHost ? (l.wsHost = s.wsHost, l.wsPort = s.wsPort ?? 443, l.wssPort = s.wssPort ?? 443, l.enabledTransports = s.enabledTransports ?? ["ws", "wss"]) : l.cluster = s.cluster, this.pusherClient = new ys(s.appKey, l), this.pusherClient.connection.bind("connected", () => {
1084
1092
  console.log(
1085
1093
  `Pusher client connected successfully for backend: ${this.configKey}.`
1086
1094
  ), this.connectionTimeoutId && (clearTimeout(this.connectionTimeoutId), this.connectionTimeoutId = null);
@@ -1090,7 +1098,7 @@ class Ps {
1090
1098
  this.pusherClient.connection.state !== "connected" && this._logConnectionError(
1091
1099
  `Pusher connection timed out after ${i / 1e3} seconds.`
1092
1100
  );
1093
- }, i), this.formatChannelName = r ?? ((l) => `private-${l}`), this.namespaceResolver = o ?? ((l) => l), this.channels = /* @__PURE__ */ new Map(), this.eventHandlers = /* @__PURE__ */ new Set();
1101
+ }, i), this.formatChannelName = r ?? ((a) => `private-${a}`), this.namespaceResolver = o ?? ((a) => a), this.channels = /* @__PURE__ */ new Map(), this.eventHandlers = /* @__PURE__ */ new Set();
1094
1102
  }
1095
1103
  /**
1096
1104
  * @private
@@ -1226,53 +1234,60 @@ function zs() {
1226
1234
  let Ut = {
1227
1235
  backendConfigs: {}
1228
1236
  };
1229
- const Rs = $.object({
1230
- clientOptions: $.object({
1231
- appKey: $.string({ required_error: "Pusher appKey is required" }),
1232
- cluster: $.string({ required_error: "Pusher cluster is required" }),
1233
- forceTLS: $.boolean().optional(),
1234
- authEndpoint: $.string().url("Pusher authentication endpoint URL is required"),
1235
- getAuthHeaders: $.function().optional().refine(
1237
+ const Rs = O.object({
1238
+ clientOptions: O.object({
1239
+ appKey: O.string({ required_error: "Pusher appKey is required" }),
1240
+ cluster: O.string().optional(),
1241
+ wsHost: O.string().optional(),
1242
+ wsPort: O.number().optional(),
1243
+ wssPort: O.number().optional(),
1244
+ enabledTransports: O.array(O.string()).optional(),
1245
+ forceTLS: O.boolean().optional(),
1246
+ authEndpoint: O.string().url("Pusher authentication endpoint URL is required"),
1247
+ getAuthHeaders: O.function().optional().refine(
1236
1248
  (n) => n === void 0 || typeof n == "function",
1237
1249
  "getAuthHeaders must be a function if provided"
1238
1250
  )
1239
- })
1240
- }), Ks = $.object({
1241
- type: $.enum(["websocket", "pusher", "none"]),
1242
- websocketUrl: $.string().url().optional(),
1251
+ }).refine(
1252
+ (n) => n.cluster || n.wsHost,
1253
+ "Either cluster or wsHost must be provided"
1254
+ )
1255
+ }), Ks = O.object({
1256
+ type: O.enum(["websocket", "pusher", "none"]),
1257
+ websocketUrl: O.string().url().optional(),
1243
1258
  pusher: Rs.optional(),
1244
- hotpaths: $.array($.string()).default(["default"])
1259
+ hotpaths: O.array(O.string()).default(["default"])
1245
1260
  }).superRefine((n, e) => {
1246
1261
  n.type === "websocket" && (n.websocketUrl || e.addIssue({
1247
- code: $.ZodIssueCode.custom,
1262
+ code: O.ZodIssueCode.custom,
1248
1263
  path: ["websocketUrl"],
1249
1264
  message: "WebSocket URL is required for WebSocket event receiver"
1250
1265
  })), n.type === "pusher" && (n.pusher || e.addIssue({
1251
- code: $.ZodIssueCode.custom,
1266
+ code: O.ZodIssueCode.custom,
1252
1267
  path: ["pusher"],
1253
1268
  message: "Pusher configuration is required for Pusher event receiver"
1254
1269
  }));
1255
- }), Be = $.object({
1256
- API_URL: $.string().url("API_URL must be a valid URL"),
1257
- GENERATED_TYPES_DIR: $.string({
1270
+ }), Be = O.object({
1271
+ API_URL: O.string().url("API_URL must be a valid URL"),
1272
+ GENERATED_TYPES_DIR: O.string({
1258
1273
  required_error: "GENERATED_TYPES_DIR is required"
1259
1274
  }),
1260
- GENERATED_ACTIONS_DIR: $.string().optional(),
1261
- BACKEND_TZ: $.string().optional(),
1262
- SYNC_TOKEN: $.string().optional(),
1263
- fileRootURL: $.string().url("fileRootURL must be a valid URL").optional(),
1264
- fileUploadMode: $.enum(["server", "s3"]).default("server"),
1265
- getAuthHeaders: $.function().optional().refine(
1275
+ GENERATED_ACTIONS_DIR: O.string().optional(),
1276
+ BACKEND_TZ: O.string().optional(),
1277
+ SYNC_TOKEN: O.string().optional(),
1278
+ fileRootURL: O.string().url("fileRootURL must be a valid URL").optional(),
1279
+ fileUploadMode: O.enum(["server", "s3"]).default("server"),
1280
+ getAuthHeaders: O.function().optional().refine(
1266
1281
  (n) => n === void 0 || typeof n == "function",
1267
1282
  "getAuthHeaders must be a function if provided"
1268
1283
  ),
1269
- eventInterceptor: $.function().optional().refine(
1284
+ eventInterceptor: O.function().optional().refine(
1270
1285
  (n) => n === void 0 || typeof n == "function",
1271
1286
  "eventInterceptor must be a function if provided"
1272
1287
  ),
1273
- events: $.lazy(() => Ks.optional())
1274
- }), Is = $.object({
1275
- backendConfigs: $.record($.string(), Be).refine(
1288
+ events: O.lazy(() => Ks.optional())
1289
+ }), Is = O.object({
1290
+ backendConfigs: O.record(O.string(), Be).refine(
1276
1291
  (n) => {
1277
1292
  for (const [e, t] of Object.entries(n))
1278
1293
  if (!Be.safeParse(t).success)
@@ -1291,7 +1306,7 @@ const Rs = $.object({
1291
1306
  return { message: e.join("; ") };
1292
1307
  }
1293
1308
  ),
1294
- periodicSyncIntervalSeconds: $.number().min(5).nullable().optional().default(null)
1309
+ periodicSyncIntervalSeconds: O.number().min(5).nullable().optional().default(null)
1295
1310
  });
1296
1311
  let ht = null;
1297
1312
  function Ns(n) {
@@ -1345,7 +1360,7 @@ function Yt(n = "default") {
1345
1360
  ...t.events.pusher.clientOptions,
1346
1361
  getAuthHeaders: i
1347
1362
  };
1348
- s = new Ps({ clientOptions: l }, n);
1363
+ s = new Fs({ clientOptions: l }, n);
1349
1364
  break;
1350
1365
  case "none":
1351
1366
  return null;
@@ -1549,8 +1564,8 @@ async function V(n, e, t = {}, s, r = null, o = null, i = {}) {
1549
1564
  query: _,
1550
1565
  serializerOptions: y
1551
1566
  }
1552
- }, v = w?.ast?.serializerOptions?.limit, O = w?.ast?.serializerOptions?.overfetch || 10;
1553
- v && O && (w.ast.serializerOptions.limit = v + O);
1567
+ }, v = w?.ast?.serializerOptions?.limit, $ = w?.ast?.serializerOptions?.overfetch || 10;
1568
+ v && $ && (w.ast.serializerOptions.limit = v + $);
1554
1569
  const k = [
1555
1570
  "create",
1556
1571
  "bulk_create",
@@ -1560,7 +1575,7 @@ async function V(n, e, t = {}, s, r = null, o = null, i = {}) {
1560
1575
  "delete_instance",
1561
1576
  "get_or_create",
1562
1577
  "update_or_create"
1563
- ].includes(e), Q = `${p.API_URL.replace(/\/+$/, "")}/${c.modelName}/`, N = p.getAuthHeaders ? p.getAuthHeaders() : {}, F = n.semanticKey;
1578
+ ].includes(e), Q = `${p.API_URL.replace(/\/+$/, "")}/${c.modelName}/`, N = p.getAuthHeaders ? p.getAuthHeaders() : {}, P = n.semanticKey;
1564
1579
  s && (N["X-Operation-ID"] = s), o && (N["X-Canonical-ID"] = o);
1565
1580
  const re = async () => {
1566
1581
  try {
@@ -1568,7 +1583,7 @@ async function V(n, e, t = {}, s, r = null, o = null, i = {}) {
1568
1583
  type: "request",
1569
1584
  modelName: c.modelName,
1570
1585
  configKey: c.configKey,
1571
- semanticKey: F,
1586
+ semanticKey: P,
1572
1587
  operationType: e,
1573
1588
  operationId: s,
1574
1589
  canonicalId: o,
@@ -1594,7 +1609,7 @@ async function V(n, e, t = {}, s, r = null, o = null, i = {}) {
1594
1609
  type: "response",
1595
1610
  modelName: c.modelName,
1596
1611
  configKey: c.configKey,
1597
- semanticKey: F,
1612
+ semanticKey: P,
1598
1613
  operationType: e,
1599
1614
  operationId: s,
1600
1615
  canonicalId: o,
@@ -1612,7 +1627,7 @@ async function V(n, e, t = {}, s, r = null, o = null, i = {}) {
1612
1627
  type: "error",
1613
1628
  modelName: c.modelName,
1614
1629
  configKey: c.configKey,
1615
- semanticKey: F,
1630
+ semanticKey: P,
1616
1631
  operationType: e,
1617
1632
  operationId: s,
1618
1633
  canonicalId: o,
@@ -1624,7 +1639,7 @@ async function V(n, e, t = {}, s, r = null, o = null, i = {}) {
1624
1639
  throw new Error(`${D} (${Q})`);
1625
1640
  }
1626
1641
  if (z.response && z.response.data) {
1627
- const D = Fs(z.response.data);
1642
+ const D = Ps(z.response.data);
1628
1643
  throw Error.captureStackTrace && Error.captureStackTrace(D, V), D;
1629
1644
  }
1630
1645
  throw new Error(`API call failed: ${z.message}`);
@@ -1959,11 +1974,11 @@ function ze(n, e, t, s = {}) {
1959
1974
  E === "pk" && p && (E = p.primaryKeyField);
1960
1975
  const Q = k === c.length - 1;
1961
1976
  if (p && p.relationshipFields && p.relationshipFields instanceof Map && p.relationshipFields.has(E)) {
1962
- const N = p.relationshipFields.get(E), F = N.ModelClass(), re = N.relationshipType;
1977
+ const N = p.relationshipFields.get(E), P = N.ModelClass(), re = N.relationshipType;
1963
1978
  if (!Q && re === "many-to-many") {
1964
1979
  let ae = c.slice(k + 1).join("__");
1965
1980
  a.length > 0 ? ae += "__" + a.join("__") : h && (ae += "__" + h);
1966
- const z = ze(ae, e, F, s), D = m.length > 0 ? m.join(".") + "." + E : E, K = z.requiredPath || z.field, me = `${D}.${K}`;
1981
+ const z = ze(ae, e, P, s), D = m.length > 0 ? m.join(".") + "." + E : E, K = z.requiredPath || z.field, me = `${D}.${K}`;
1967
1982
  return {
1968
1983
  field: D,
1969
1984
  operator: { $elemMatch: { [z.field]: z.operator } },
@@ -1973,23 +1988,23 @@ function ze(n, e, t, s = {}) {
1973
1988
  };
1974
1989
  }
1975
1990
  if (m.push(E), !Q)
1976
- p = F;
1991
+ p = P;
1977
1992
  else {
1978
1993
  if (y = !0, re === "many-to-many")
1979
1994
  _ = !0, w = E;
1980
1995
  else {
1981
- const pe = F.primaryKeyField || "id";
1996
+ const pe = P.primaryKeyField || "id";
1982
1997
  m.push(pe), w = pe;
1983
1998
  }
1984
- p = F;
1999
+ p = P;
1985
2000
  }
1986
2001
  } else if (p && p.fields && p.fields.includes(E)) {
1987
2002
  if (m.push(E), w = E, Q)
1988
2003
  break;
1989
2004
  const N = p.schema?.properties?.[E];
1990
2005
  if (N && N.format === "json") {
1991
- const F = c.slice(k + 1);
1992
- m.push(...F);
2006
+ const P = c.slice(k + 1);
2007
+ m.push(...P);
1993
2008
  break;
1994
2009
  }
1995
2010
  throw new Error(`Field '${E}' in '${n}' is not a relationship field and cannot be traversed.`);
@@ -2186,17 +2201,17 @@ function tr(n = "UTC", e = null) {
2186
2201
  if (!y || !(y instanceof Date) || isNaN(y.getTime()))
2187
2202
  return !1;
2188
2203
  const _ = _e.fromJSDate(y).setZone(n);
2189
- let w, v, O;
2204
+ let w, v, $;
2190
2205
  if (typeof a == "string") {
2191
2206
  const T = a.split(":");
2192
- w = parseInt(T[0], 10), v = parseInt(T[1], 10), O = parseInt(T[2], 10);
2207
+ w = parseInt(T[0], 10), v = parseInt(T[1], 10), $ = parseInt(T[2], 10);
2193
2208
  } else {
2194
2209
  const T = s(a, m);
2195
2210
  if (!T) return !1;
2196
2211
  const k = _e.fromJSDate(T).setZone(n);
2197
- w = k.hour, v = k.minute, O = k.second;
2212
+ w = k.hour, v = k.minute, $ = k.second;
2198
2213
  }
2199
- return _.hour === w && _.minute === v && _.second === O;
2214
+ return _.hour === w && _.minute === v && _.second === $;
2200
2215
  },
2201
2216
  c,
2202
2217
  h
@@ -2223,7 +2238,7 @@ function tr(n = "UTC", e = null) {
2223
2238
  const v = s(_, w);
2224
2239
  if (!v || !(v instanceof Date) || isNaN(v.getTime()))
2225
2240
  return !1;
2226
- const O = _e.fromJSDate(v).setZone(n), T = c(O), k = a === "date" ? p : typeof p == "string" ? Number(p) : p;
2241
+ const $ = _e.fromJSDate(v).setZone(n), T = c($), k = a === "date" ? p : typeof p == "string" ? Number(p) : p;
2227
2242
  switch (h) {
2228
2243
  case "gt":
2229
2244
  return T > k;
@@ -2466,7 +2481,7 @@ class ar {
2466
2481
  constructor(e, t, s, r = null, o = null, i = {}) {
2467
2482
  if (this.modelClass = e, this.fetchFn = t, this.queryset = s, this.isSyncing = !1, this.lastSync = null, this.lastHydrated = null, this._createdAt = Date.now(), this.isTemp = i.isTemp || !1, this.pruneThreshold = i.pruneThreshold || 10, this.groundTruthPks = r || [], this.operationsMap = /* @__PURE__ */ new Map(), this.includedPks = /* @__PURE__ */ new Map(), Array.isArray(o))
2468
2483
  for (const l of o) {
2469
- const c = Fe.get(l.operationId) || new q(l, !0);
2484
+ const c = Pe.get(l.operationId) || new q(l, !0);
2470
2485
  this.operationsMap.set(c.operationId, c);
2471
2486
  }
2472
2487
  if (this.qsCache = new Ct("queryset-cache", {}, this.onHydrated.bind(this)), this._lastRenderedPks = null, this.renderCallbacks = /* @__PURE__ */ new Set(), !this.isTemp) {
@@ -2599,7 +2614,7 @@ class ar {
2599
2614
  if (a == null) return null;
2600
2615
  const c = this.pkField, h = new Set(e), p = new Set(e);
2601
2616
  for (const m of s.operations)
2602
- if (m.status !== C.REJECTED && !(!t && m.status !== C.CONFIRMED) && !(m.type !== P.CREATE && m.type !== P.BULK_CREATE && m.type !== P.GET_OR_CREATE && m.type !== P.UPDATE_OR_CREATE))
2617
+ if (m.status !== C.REJECTED && !(!t && m.status !== C.CONFIRMED) && !(m.type !== F.CREATE && m.type !== F.BULK_CREATE && m.type !== F.GET_OR_CREATE && m.type !== F.UPDATE_OR_CREATE))
2603
2618
  for (const y of m.instances) {
2604
2619
  if (!y || y[c] == null || h.has(y[c])) continue;
2605
2620
  const _ = y[o];
@@ -3060,7 +3075,7 @@ class Ce {
3060
3075
  });
3061
3076
  return;
3062
3077
  }
3063
- const v = p.pks.map((k) => i.fromPk(k, e)), O = e.build(), T = ss(v, O, i, !1);
3078
+ const v = p.pks.map((k) => i.fromPk(k, e)), $ = e.build(), T = ss(v, $, i, !1);
3064
3079
  m.setGroundTruth(T), m.setOperations(m.getInflightOperations()), m.lastSync = Date.now(), G({
3065
3080
  type: "groupSync",
3066
3081
  phase: "filteredFromRoot",
@@ -3229,7 +3244,7 @@ class de {
3229
3244
  const o = e.ModelClass.primaryKeyField, i = s || `${B()}`, l = zt(i);
3230
3245
  return new q({
3231
3246
  operationId: i,
3232
- type: P.CREATE,
3247
+ type: F.CREATE,
3233
3248
  instances: [{ ...t, [o]: l }],
3234
3249
  queryset: e,
3235
3250
  args: { data: t },
@@ -3250,7 +3265,7 @@ class de {
3250
3265
  });
3251
3266
  return new q({
3252
3267
  operationId: i,
3253
- type: P.BULK_CREATE,
3268
+ type: F.BULK_CREATE,
3254
3269
  instances: l,
3255
3270
  queryset: e,
3256
3271
  args: { data: t },
@@ -3279,7 +3294,7 @@ class de {
3279
3294
  });
3280
3295
  return new q({
3281
3296
  operationId: c,
3282
- type: P.UPDATE,
3297
+ type: F.UPDATE,
3283
3298
  instances: h,
3284
3299
  queryset: e,
3285
3300
  args: { filter: s, data: t },
@@ -3296,7 +3311,7 @@ class de {
3296
3311
  const r = e.ModelClass.primaryKeyField, i = x.getStore(e).render(), l = t || `${B()}`, a = i.map((c) => ({ [r]: c }));
3297
3312
  return new q({
3298
3313
  operationId: l,
3299
- type: P.DELETE,
3314
+ type: F.DELETE,
3300
3315
  instances: a,
3301
3316
  queryset: e,
3302
3317
  args: {},
@@ -3314,7 +3329,7 @@ class de {
3314
3329
  const o = e.ModelClass.primaryKeyField, l = x.getStore(e).render(), a = s || `${B()}`, c = l.map((h) => ({ ...t, [o]: h }));
3315
3330
  return new q({
3316
3331
  operationId: a,
3317
- type: P.UPDATE_INSTANCE,
3332
+ type: F.UPDATE_INSTANCE,
3318
3333
  instances: c,
3319
3334
  queryset: e,
3320
3335
  args: { data: t },
@@ -3332,7 +3347,7 @@ class de {
3332
3347
  const r = s || `${B()}`;
3333
3348
  return new q({
3334
3349
  operationId: r,
3335
- type: P.DELETE_INSTANCE,
3350
+ type: F.DELETE_INSTANCE,
3336
3351
  instances: [t],
3337
3352
  queryset: e,
3338
3353
  args: t,
@@ -3352,7 +3367,7 @@ class de {
3352
3367
  (E) => _t(y, o.fromPk(E[i], e))
3353
3368
  ), w = mt(_, m, o), v = c.filter(
3354
3369
  (E) => w.includes(E[i])
3355
- ), O = v.length === 0, T = O ? P.CREATE : P.UPDATE, k = O ? { ...t, ...s, [i]: l } : v[0];
3370
+ ), $ = v.length === 0, T = $ ? F.CREATE : F.UPDATE, k = $ ? { ...t, ...s, [i]: l } : v[0];
3356
3371
  return new q({
3357
3372
  operationId: l,
3358
3373
  type: T,
@@ -3375,7 +3390,7 @@ class de {
3375
3390
  (E) => _t(y, o.fromPk(E[i], e))
3376
3391
  ), w = mt(_, m, o), v = c.filter(
3377
3392
  (E) => w.includes(E[i])
3378
- ), O = v.length === 0, T = O ? P.CREATE : P.UPDATE, k = O ? { ...t, ...s, [i]: l } : { ...v[0], ...s };
3393
+ ), $ = v.length === 0, T = $ ? F.CREATE : F.UPDATE, k = $ ? { ...t, ...s, [i]: l } : { ...v[0], ...s };
3379
3394
  return new q({
3380
3395
  operationId: l,
3381
3396
  type: T,
@@ -3467,9 +3482,9 @@ class hr {
3467
3482
  ).then((m) => {
3468
3483
  const { data: y, included: _, model_name: w } = m.data, v = m.metadata.created;
3469
3484
  we(j, _, r, e);
3470
- const O = Array.isArray(y) ? y[0] : y;
3471
- a && (c.pk = O);
3472
- const k = (_[w] || {})[O];
3485
+ const $ = Array.isArray(y) ? y[0] : y;
3486
+ a && (c.pk = $);
3487
+ const k = (_[w] || {})[$];
3473
3488
  return k && l.mutate({
3474
3489
  instances: [k],
3475
3490
  status: C.CONFIRMED
@@ -3493,7 +3508,7 @@ class hr {
3493
3508
  throw new Error(
3494
3509
  `Field parameter is required for ${t} operation`
3495
3510
  );
3496
- const i = Pe.getEntity(t, e, o), l = {};
3511
+ const i = Fe.getEntity(t, e, o), l = {};
3497
3512
  t !== "exists" && (l.field = o);
3498
3513
  const a = V(
3499
3514
  e,
@@ -3501,7 +3516,7 @@ class hr {
3501
3516
  l
3502
3517
  ).then((c) => {
3503
3518
  const h = c.data, p = x.getEntity(e);
3504
- return Pe.setEntity(t, e, o, h, p), Z(i), h;
3519
+ return Fe.setEntity(t, e, o, h, p), Z(i), h;
3505
3520
  });
3506
3521
  return te(i, a);
3507
3522
  }
@@ -3545,7 +3560,7 @@ class hr {
3545
3560
  i,
3546
3561
  l.operationId
3547
3562
  ).then((p) => {
3548
- const { data: m, included: y } = p.data || {}, _ = y[o] || {}, w = Array.isArray(m) ? m.map((O) => _[`${O}`]) : [];
3563
+ const { data: m, included: y } = p.data || {}, _ = y[o] || {}, w = Array.isArray(m) ? m.map(($) => _[`${$}`]) : [];
3549
3564
  l.updateStatus(C.CONFIRMED, w);
3550
3565
  const v = p.metadata?.updated_count ?? 0;
3551
3566
  return c = [v, { [o]: v }, w], Z(c), c;
@@ -3610,13 +3625,13 @@ class hr {
3610
3625
  we(j, y, r, e);
3611
3626
  const w = Array.isArray(m) ? m[0] : m;
3612
3627
  c.pk = w;
3613
- const O = (y[_] || {})[w];
3614
- if (!O)
3628
+ const $ = (y[_] || {})[w];
3629
+ if (!$)
3615
3630
  throw new Error(
3616
3631
  `Entity data not found for ${_} with pk ${w}`
3617
3632
  );
3618
3633
  return l.mutate({
3619
- instances: [O],
3634
+ instances: [$],
3620
3635
  status: C.CONFIRMED
3621
3636
  }), Z(c), c;
3622
3637
  }).catch((p) => {
@@ -3663,9 +3678,9 @@ class hr {
3663
3678
  w.forEach((T, k) => {
3664
3679
  c[k] && (c[k].pk = T);
3665
3680
  });
3666
- const v = y[_] || {}, O = w.map((T) => v[T]).filter(Boolean);
3681
+ const v = y[_] || {}, $ = w.map((T) => v[T]).filter(Boolean);
3667
3682
  return a.mutate({
3668
- instances: O,
3683
+ instances: $,
3669
3684
  status: C.CONFIRMED
3670
3685
  }), c.forEach((T) => Z(T)), Z(c), c;
3671
3686
  }).catch((p) => {
@@ -3807,7 +3822,7 @@ class fr {
3807
3822
  * Delegates to the underlying store's sync method
3808
3823
  */
3809
3824
  refreshFromDb() {
3810
- return Pe.getStore(
3825
+ return Fe.getStore(
3811
3826
  this.metricType,
3812
3827
  this.queryset,
3813
3828
  this.field
@@ -3818,7 +3833,7 @@ class fr {
3818
3833
  * Called implicitly by JS when coercing to a primitive (arithmetic, template literals, etc.)
3819
3834
  */
3820
3835
  valueOf() {
3821
- const e = Pe.getStore(
3836
+ const e = Fe.getStore(
3822
3837
  this.metricType,
3823
3838
  this.queryset,
3824
3839
  this.field
@@ -3934,7 +3949,7 @@ class wt {
3934
3949
  return this._stores.has(e) ? this._stores.get(e).queryset : null;
3935
3950
  }
3936
3951
  }
3937
- const Pe = new wt();
3952
+ const Fe = new wt();
3938
3953
  class pr {
3939
3954
  constructor(e) {
3940
3955
  this.event = e.event, this.model = e.model, this.operation_id = e.operation_id, this.pk_field_name = e.pk_field_name, this.configKey = e.configKey, this.canonical_id = e.canonical_id || null, this.server_ts_ms = e.server_ts_ms || null, this.instances = e.instances?.map((t) => t && this.pk_field_name && t[this.pk_field_name] != null ? {
@@ -4059,7 +4074,7 @@ class mr {
4059
4074
  * Checks the `verify` flag on membership state to determine which querysets need syncing.
4060
4075
  */
4061
4076
  syncQuerysetsNeedingVerification(e) {
4062
- const t = Fe.getQuerysetStates(e);
4077
+ const t = Pe.getQuerysetStates(e);
4063
4078
  if (!t) return;
4064
4079
  const s = this.registries.get(Ce);
4065
4080
  if (!s) return;
@@ -4090,7 +4105,7 @@ class mr {
4090
4105
  operationId: e.operation_id,
4091
4106
  socketId: e.socket_id
4092
4107
  });
4093
- let t = new pr(e), s = Fe.has(t.operation_id);
4108
+ let t = new pr(e), s = Pe.has(t.operation_id);
4094
4109
  if (this.registries.has(wt) && this.processMetrics(t), s) {
4095
4110
  this.syncQuerysetsNeedingVerification(t.operation_id);
4096
4111
  return;
@@ -4190,7 +4205,7 @@ class mr {
4190
4205
  const Ae = new mr();
4191
4206
  Ae.manageRegistry(x);
4192
4207
  Ae.manageRegistry(j);
4193
- Ae.manageRegistry(Pe);
4208
+ Ae.manageRegistry(Fe);
4194
4209
  const yr = /* @__PURE__ */ new Set();
4195
4210
  function gr(n) {
4196
4211
  typeof n == "function" && yr.add(n);
@@ -4217,7 +4232,7 @@ const _r = (n, e) => {
4217
4232
  }, Mr = {
4218
4233
  key: 1,
4219
4234
  class: "szd-header__badge"
4220
- }, Ar = { class: "szd-header__badge" }, Or = { class: "szd-tabs" }, $r = ["onClick"], Fr = { class: "szd-content" }, Pr = {
4235
+ }, Ar = { class: "szd-header__badge" }, Or = { class: "szd-tabs" }, $r = ["onClick"], Pr = { class: "szd-content" }, Fr = {
4221
4236
  key: 0,
4222
4237
  class: "szd-panel"
4223
4238
  }, Dr = { class: "szd-panel__section" }, zr = { class: "szd-kv" }, Rr = { class: "szd-kv__row" }, Kr = { class: "szd-kv__value" }, Ir = { class: "szd-kv__row" }, Nr = { class: "szd-kv__value" }, xr = { class: "szd-kv__row" }, jr = { class: "szd-kv__value" }, Ur = { class: "szd-kv__row" }, Qr = { class: "szd-kv__value" }, Lr = { class: "szd-panel__section" }, Vr = { class: "szd-stats" }, Br = { class: "szd-stat" }, Gr = { class: "szd-stat__value" }, Hr = { class: "szd-stat" }, qr = { class: "szd-stat__value" }, Jr = { class: "szd-stat" }, Wr = { class: "szd-stat__value" }, Zr = { class: "szd-stat" }, Yr = { class: "szd-stat__value" }, Xr = {
@@ -4259,7 +4274,7 @@ const _r = (n, e) => {
4259
4274
  }, $n = {
4260
4275
  class: "szd-kv",
4261
4276
  style: { "margin-bottom": "16px" }
4262
- }, Fn = { class: "szd-kv__row" }, Pn = { class: "szd-kv__value szd-kv__value--mono" }, Dn = { class: "szd-ast" }, zn = {
4277
+ }, Pn = { class: "szd-kv__row" }, Fn = { class: "szd-kv__value szd-kv__value--mono" }, Dn = { class: "szd-ast" }, zn = {
4263
4278
  key: 0,
4264
4279
  class: "szd-detail"
4265
4280
  }, Rn = { class: "szd-detail__panel szd-detail__panel--sm" }, Kn = { class: "szd-detail__header" }, In = { class: "szd-detail__body" }, Nn = { class: "szd-settings-section" }, xn = ["value"], jn = {
@@ -4320,7 +4335,7 @@ const _r = (n, e) => {
4320
4335
  queryset: d
4321
4336
  });
4322
4337
  }), u;
4323
- }), O = I(() => (a.value, Array.from(x._stores.entries()).map(
4338
+ }), $ = I(() => (a.value, Array.from(x._stores.entries()).map(
4324
4339
  ([u, d]) => ({
4325
4340
  semanticKey: u,
4326
4341
  modelName: d?.modelClass?.modelName,
@@ -4336,7 +4351,7 @@ const _r = (n, e) => {
4336
4351
  const u = /* @__PURE__ */ new Map();
4337
4352
  return v.value.forEach((d) => {
4338
4353
  u.set(d.semanticKey, d);
4339
- }), O.value.forEach((d) => {
4354
+ }), $.value.forEach((d) => {
4340
4355
  u.has(d.semanticKey) || u.set(d.semanticKey, d);
4341
4356
  }), Array.from(u.values());
4342
4357
  }), E = I(() => w.value?.semanticKey ? w.value.semanticKey : r.value ? r.value : ""), Q = I(() => w.value ? w.value : r.value && T.value.get(r.value) || null), N = I(() => {
@@ -4347,7 +4362,7 @@ const _r = (n, e) => {
4347
4362
  return null;
4348
4363
  }
4349
4364
  return E.value && x._stores.get(E.value) || null;
4350
- }), F = I(() => {
4365
+ }), P = I(() => {
4351
4366
  a.value;
4352
4367
  const u = N.value, d = Q.value, g = u?.modelClass?.modelName || d?.ModelClass?.modelName, R = u?.modelClass?.configKey || d?.ModelClass?.configKey, H = u?.groundTruthPks?.length ?? 0, oe = u?.operationsMap?.size ?? 0, le = u?.getInflightOperations?.() || [], ke = u?.isSyncing ?? !1, je = u?.lastSync ? new Date(u.lastSync).toLocaleString() : "—", nt = u && Array.isArray(u._lastRenderedPks) ? u._lastRenderedPks.length : null, cs = u?.groundTruthPks?.length ?? 0, ds = u ? u.lastSync === null ? "model store" : "ground truth" : "—", us = ke ? "Sync in progress — results may change." : oe > 0 ? "Optimistic operations are applied to results." : u?.lastSync === null ? "No ground truth yet — rendering from model store." : "Using ground truth + local filters.";
4353
4368
  return {
@@ -4622,11 +4637,11 @@ const _r = (n, e) => {
4622
4637
  f("div", vr, [
4623
4638
  f("div", kr, [
4624
4639
  d[9] || (d[9] = f("div", { class: "szd-header__title" }, "StateZero", -1)),
4625
- E.value ? (A(), M("span", br, S(F.value.modelName || "?"), 1)) : (A(), M("span", Er, "No queryset"))
4640
+ E.value ? (A(), M("span", br, S(P.value.modelName || "?"), 1)) : (A(), M("span", Er, "No queryset"))
4626
4641
  ]),
4627
4642
  f("div", Sr, [
4628
- F.value.isSyncing ? (A(), M("span", Tr, "Syncing")) : L("", !0),
4629
- F.value.opsCount > 0 ? (A(), M("span", Mr, S(F.value.opsCount) + " ops", 1)) : L("", !0),
4643
+ P.value.isSyncing ? (A(), M("span", Tr, "Syncing")) : L("", !0),
4644
+ P.value.opsCount > 0 ? (A(), M("span", Mr, S(P.value.opsCount) + " ops", 1)) : L("", !0),
4630
4645
  f("span", Ar, S(Ie.value) + " events", 1),
4631
4646
  f("button", {
4632
4647
  class: "szd-btn szd-btn--icon",
@@ -4659,8 +4674,8 @@ const _r = (n, e) => {
4659
4674
  }, S(g.label), 11, $r)), 64))
4660
4675
  ])
4661
4676
  ]),
4662
- f("main", Fr, [
4663
- t.value === "overview" ? (A(), M("div", Pr, [
4677
+ f("main", Pr, [
4678
+ t.value === "overview" ? (A(), M("div", Fr, [
4664
4679
  f("div", Dr, [
4665
4680
  d[15] || (d[15] = f("h3", { class: "szd-panel__heading" }, "Why This View?", -1)),
4666
4681
  f("div", zr, [
@@ -4678,7 +4693,7 @@ const _r = (n, e) => {
4678
4693
  ]),
4679
4694
  f("div", Ur, [
4680
4695
  d[14] || (d[14] = f("span", { class: "szd-kv__key" }, "Reason:", -1)),
4681
- f("span", Qr, S(F.value.reason), 1)
4696
+ f("span", Qr, S(P.value.reason), 1)
4682
4697
  ])
4683
4698
  ])
4684
4699
  ]),
@@ -4686,26 +4701,26 @@ const _r = (n, e) => {
4686
4701
  d[21] || (d[21] = f("h3", { class: "szd-panel__heading" }, "Current State", -1)),
4687
4702
  f("div", Vr, [
4688
4703
  f("div", Br, [
4689
- f("div", Gr, S(F.value.optimisticCount ?? "—"), 1),
4704
+ f("div", Gr, S(P.value.optimisticCount ?? "—"), 1),
4690
4705
  d[16] || (d[16] = f("div", { class: "szd-stat__label" }, "Optimistic", -1))
4691
4706
  ]),
4692
4707
  f("div", Hr, [
4693
- f("div", qr, S(F.value.confirmedCount), 1),
4708
+ f("div", qr, S(P.value.confirmedCount), 1),
4694
4709
  d[17] || (d[17] = f("div", { class: "szd-stat__label" }, "Confirmed", -1))
4695
4710
  ]),
4696
4711
  f("div", Jr, [
4697
- f("div", Wr, S(F.value.groundTruthCount), 1),
4712
+ f("div", Wr, S(P.value.groundTruthCount), 1),
4698
4713
  d[18] || (d[18] = f("div", { class: "szd-stat__label" }, "Ground Truth", -1))
4699
4714
  ]),
4700
4715
  f("div", Zr, [
4701
- f("div", Yr, S(F.value.inFlightCount), 1),
4716
+ f("div", Yr, S(P.value.inFlightCount), 1),
4702
4717
  d[19] || (d[19] = f("div", { class: "szd-stat__label" }, "In-Flight", -1))
4703
4718
  ])
4704
4719
  ]),
4705
4720
  f("div", Xr, [
4706
4721
  f("div", en, [
4707
4722
  d[20] || (d[20] = f("span", { class: "szd-kv__key" }, "Last Sync:", -1)),
4708
- f("span", tn, S(F.value.lastSync), 1)
4723
+ f("span", tn, S(P.value.lastSync), 1)
4709
4724
  ])
4710
4725
  ])
4711
4726
  ]),
@@ -4814,9 +4829,9 @@ const _r = (n, e) => {
4814
4829
  t.value === "ast" ? (A(), M("div", On, [
4815
4830
  d[27] || (d[27] = f("h3", { class: "szd-panel__heading" }, "Query AST", -1)),
4816
4831
  f("div", $n, [
4817
- f("div", Fn, [
4832
+ f("div", Pn, [
4818
4833
  d[26] || (d[26] = f("span", { class: "szd-kv__key" }, "Semantic Key:", -1)),
4819
- f("code", Pn, S(E.value || "—"), 1)
4834
+ f("code", Fn, S(E.value || "—"), 1)
4820
4835
  ])
4821
4836
  ]),
4822
4837
  f("pre", Dn, S(re.value ? JSON.stringify(re.value, null, 2) : "Select a queryset to view AST"), 1)
@@ -4894,23 +4909,23 @@ const _r = (n, e) => {
4894
4909
  f("div", Jn, [
4895
4910
  f("div", Wn, [
4896
4911
  d[35] || (d[35] = f("span", { class: "szd-kv__key" }, "Model:", -1)),
4897
- f("span", Zn, S(F.value.modelName || "—"), 1)
4912
+ f("span", Zn, S(P.value.modelName || "—"), 1)
4898
4913
  ]),
4899
4914
  f("div", Yn, [
4900
4915
  d[36] || (d[36] = f("span", { class: "szd-kv__key" }, "Source:", -1)),
4901
- f("span", Xn, S(F.value.source), 1)
4916
+ f("span", Xn, S(P.value.source), 1)
4902
4917
  ]),
4903
4918
  f("div", eo, [
4904
4919
  d[37] || (d[37] = f("span", { class: "szd-kv__key" }, "Syncing:", -1)),
4905
- f("span", to, S(F.value.isSyncing ? "Yes" : "No"), 1)
4920
+ f("span", to, S(P.value.isSyncing ? "Yes" : "No"), 1)
4906
4921
  ]),
4907
4922
  f("div", so, [
4908
4923
  d[38] || (d[38] = f("span", { class: "szd-kv__key" }, "Operations:", -1)),
4909
- f("span", ro, S(F.value.opsCount), 1)
4924
+ f("span", ro, S(P.value.opsCount), 1)
4910
4925
  ]),
4911
4926
  f("div", no, [
4912
4927
  d[39] || (d[39] = f("span", { class: "szd-kv__key" }, "Last Sync:", -1)),
4913
- f("span", oo, S(F.value.lastSync), 1)
4928
+ f("span", oo, S(P.value.lastSync), 1)
4914
4929
  ])
4915
4930
  ])
4916
4931
  ])) : L("", !0)
@@ -248,7 +248,7 @@ const TS_DECLARATION_TEMPLATE = `/**
248
248
 
249
249
  import { Model, Manager } from '{{modulePath}}';
250
250
  import { StringOperators, NumberOperators, BooleanOperators, DateOperators } from '{{modulePath}}';
251
- import { QuerySet, LiveQuerySet, LiveQuerySetOptions, MetricResult, ResultTuple, SerializerOptions, NestedPaths } from '{{modulePath}}';
251
+ import { QuerySet, LiveQuerySet, LiveQuerySetOptions, MetricResult, ResultTuple, SerializerOptions, NestedPaths, CompiledAST } from '{{modulePath}}';
252
252
 
253
253
  // Re-export the real Manager for runtime use
254
254
  import { Manager as RuntimeManager } from '{{modulePath}}';
@@ -387,6 +387,26 @@ export declare class {{className}}QuerySet extends QuerySet<any> {
387
387
  delete(): Promise<[number, Record<string, number>]>;
388
388
  exists(): Promise<boolean>;
389
389
  fetch(serializerOptions?: SerializerOptions): Promise<{{className}}[]>;
390
+
391
+ // Compile
392
+ get compile(): {
393
+ fetch(args?: Record<string, any>): CompiledAST;
394
+ get(args?: Record<string, any>): CompiledAST;
395
+ first(args?: Record<string, any>): CompiledAST;
396
+ last(args?: Record<string, any>): CompiledAST;
397
+ count(args?: Record<string, any>): CompiledAST;
398
+ sum(args?: Record<string, any>): CompiledAST;
399
+ avg(args?: Record<string, any>): CompiledAST;
400
+ min(args?: Record<string, any>): CompiledAST;
401
+ max(args?: Record<string, any>): CompiledAST;
402
+ exists(args?: Record<string, any>): CompiledAST;
403
+ create(args?: Record<string, any>): CompiledAST;
404
+ bulkCreate(args?: Record<string, any>): CompiledAST;
405
+ update(args?: Record<string, any>): CompiledAST;
406
+ delete(args?: Record<string, any>): CompiledAST;
407
+ getOrCreate(args?: Record<string, any>): CompiledAST;
408
+ updateOrCreate(args?: Record<string, any>): CompiledAST;
409
+ };
390
410
  }
391
411
 
392
412
  /**
@@ -400,6 +420,7 @@ export declare class {{className}}Manager extends Manager {
400
420
  get(filters?: {{className}}FilterData, serializerOptions?: SerializerOptions): Promise<{{className}}>;
401
421
  create(data: {{className}}CreateData): Promise<{{className}}>;
402
422
  delete(): Promise<[number, Record<string, number>]>;
423
+ execute(ast: CompiledAST): Promise<any>;
403
424
  }
404
425
 
405
426
  /**
@@ -471,6 +492,7 @@ export declare class {{className}} extends Model implements {{interfaceName}} {
471
492
 
472
493
  constructor(data: Partial<{{interfaceName}}>);
473
494
  serialize(): Partial<{{interfaceName}}>;
495
+ static execute(ast: CompiledAST): Promise<any>;
474
496
  }
475
497
 
476
498
  /**
package/dist/config.js CHANGED
@@ -9,13 +9,17 @@ export let liveConfig = {
9
9
  const pusherSchema = z.object({
10
10
  clientOptions: z.object({
11
11
  appKey: z.string({ required_error: 'Pusher appKey is required' }),
12
- cluster: z.string({ required_error: 'Pusher cluster is required' }),
12
+ cluster: z.string().optional(),
13
+ wsHost: z.string().optional(),
14
+ wsPort: z.number().optional(),
15
+ wssPort: z.number().optional(),
16
+ enabledTransports: z.array(z.string()).optional(),
13
17
  forceTLS: z.boolean().optional(),
14
18
  authEndpoint: z.string()
15
19
  .url('Pusher authentication endpoint URL is required'),
16
20
  getAuthHeaders: z.function().optional()
17
21
  .refine((fn) => fn === undefined || typeof fn === 'function', 'getAuthHeaders must be a function if provided')
18
- })
22
+ }).refine((opts) => opts.cluster || opts.wsHost, 'Either cluster or wsHost must be provided')
19
23
  });
20
24
  const eventConfigSchema = z.object({
21
25
  type: z.enum(['websocket', 'pusher', 'none']),
@@ -48,7 +48,11 @@ export namespace EventType {
48
48
  * Options for instantiating a Pusher client.
49
49
  * @typedef {Object} PusherClientOptions
50
50
  * @property {string} appKey
51
- * @property {string} cluster
51
+ * @property {string} [cluster] - Pusher cluster (use this OR wsHost)
52
+ * @property {string} [wsHost] - Custom WebSocket host (e.g. for Soketi)
53
+ * @property {number} [wsPort] - Custom WebSocket port (default 443)
54
+ * @property {number} [wssPort] - Custom secure WebSocket port (default 443)
55
+ * @property {string[]} [enabledTransports] - Transports to use (default ['ws', 'wss'])
52
56
  * @property {boolean} [forceTLS]
53
57
  * @property {string} authEndpoint
54
58
  * @property {function(): Object<string, string>} [getAuthHeaders]
@@ -162,7 +166,26 @@ export type NamespaceResolver = (modelName: string) => string;
162
166
  */
163
167
  export type PusherClientOptions = {
164
168
  appKey: string;
165
- cluster: string;
169
+ /**
170
+ * - Pusher cluster (use this OR wsHost)
171
+ */
172
+ cluster?: string | undefined;
173
+ /**
174
+ * - Custom WebSocket host (e.g. for Soketi)
175
+ */
176
+ wsHost?: string | undefined;
177
+ /**
178
+ * - Custom WebSocket port (default 443)
179
+ */
180
+ wsPort?: number | undefined;
181
+ /**
182
+ * - Custom secure WebSocket port (default 443)
183
+ */
184
+ wssPort?: number | undefined;
185
+ /**
186
+ * - Transports to use (default ['ws', 'wss'])
187
+ */
188
+ enabledTransports?: string[] | undefined;
166
189
  forceTLS?: boolean | undefined;
167
190
  authEndpoint: string;
168
191
  getAuthHeaders?: (() => {
@@ -41,7 +41,11 @@ export const EventType = {
41
41
  * Options for instantiating a Pusher client.
42
42
  * @typedef {Object} PusherClientOptions
43
43
  * @property {string} appKey
44
- * @property {string} cluster
44
+ * @property {string} [cluster] - Pusher cluster (use this OR wsHost)
45
+ * @property {string} [wsHost] - Custom WebSocket host (e.g. for Soketi)
46
+ * @property {number} [wsPort] - Custom WebSocket port (default 443)
47
+ * @property {number} [wssPort] - Custom secure WebSocket port (default 443)
48
+ * @property {string[]} [enabledTransports] - Transports to use (default ['ws', 'wss'])
45
49
  * @property {boolean} [forceTLS]
46
50
  * @property {string} authEndpoint
47
51
  * @property {function(): Object<string, string>} [getAuthHeaders]
@@ -71,12 +75,21 @@ export class PusherEventReceiver {
71
75
  clientOptions.appKey.length < 15) {
72
76
  console.warn(`%c[Pusher Warning] The provided appKey ("${clientOptions.appKey}") looks like a numeric app_id. Pusher requires the alphanumeric key, not the ID. Please verify your configuration for backend: "${this.configKey}".`, "color: orange; font-weight: bold; font-size: 14px;");
73
77
  }
74
- this.pusherClient = new Pusher(clientOptions.appKey, {
75
- cluster: clientOptions.cluster,
78
+ const pusherOpts = {
76
79
  forceTLS: clientOptions.forceTLS ?? true,
77
80
  authEndpoint: clientOptions.authEndpoint,
78
81
  auth: { headers: clientOptions.getAuthHeaders?.() || {} },
79
- });
82
+ };
83
+ if (clientOptions.wsHost) {
84
+ pusherOpts.wsHost = clientOptions.wsHost;
85
+ pusherOpts.wsPort = clientOptions.wsPort ?? 443;
86
+ pusherOpts.wssPort = clientOptions.wssPort ?? 443;
87
+ pusherOpts.enabledTransports = clientOptions.enabledTransports ?? ['ws', 'wss'];
88
+ }
89
+ else {
90
+ pusherOpts.cluster = clientOptions.cluster;
91
+ }
92
+ this.pusherClient = new Pusher(clientOptions.appKey, pusherOpts);
80
93
  this.pusherClient.connection.bind("connected", () => {
81
94
  console.log(`Pusher client connected successfully for backend: ${this.configKey}.`);
82
95
  if (this.connectionTimeoutId) {
@@ -28,11 +28,13 @@ export class StateZeroError extends Error {
28
28
  * @param {string} code - The error code.
29
29
  * @param {IErrorDetail|Object|string} detail - The error details.
30
30
  * @param {number} status - The HTTP status code.
31
+ * @param {Object} [data={}] - Additional structured data from the server.
31
32
  */
32
- constructor(message: string, code: string, detail: IErrorDetail | Object | string, status: number);
33
+ constructor(message: string, code: string, detail: IErrorDetail | Object | string, status: number, data?: Object);
33
34
  code: string;
34
35
  detail: string | Object | IErrorDetail;
35
36
  status: number;
37
+ data: Object;
36
38
  /**
37
39
  * Returns a full error message including the detail.
38
40
  *
@@ -21,13 +21,15 @@ export class StateZeroError extends Error {
21
21
  * @param {string} code - The error code.
22
22
  * @param {IErrorDetail|Object|string} detail - The error details.
23
23
  * @param {number} status - The HTTP status code.
24
+ * @param {Object} [data={}] - Additional structured data from the server.
24
25
  */
25
- constructor(message, code, detail, status) {
26
+ constructor(message, code, detail, status, data = {}) {
26
27
  super(message);
27
28
  this.name = "StateZeroError";
28
29
  this.code = code;
29
30
  this.detail = detail;
30
31
  this.status = status;
32
+ this.data = data;
31
33
  Object.setPrototypeOf(this, new.target.prototype);
32
34
  emitError(this);
33
35
  }
@@ -169,7 +171,7 @@ export class ConfigError extends StateZeroError {
169
171
  * @returns {StateZeroError} An instance of a StateZeroError subclass.
170
172
  */
171
173
  export function parseStateZeroError(errorResponse) {
172
- const { status, type, detail } = errorResponse;
174
+ const { status, type, detail, data } = errorResponse;
173
175
  // Handle undefined type/status case (like in permission denied)
174
176
  if (type === undefined && detail === 'Invalid token.') {
175
177
  return new PermissionDenied(detail, 403);
@@ -209,6 +211,6 @@ export function parseStateZeroError(errorResponse) {
209
211
  else if (status === 409) {
210
212
  return new ConflictError(detail, status);
211
213
  }
212
- return new StateZeroError("Unknown error", "unknown", detail, status);
214
+ return new StateZeroError(detail || "Unknown error", type || "unknown", detail, status, data || {});
213
215
  }
214
216
  }
@@ -157,6 +157,13 @@ export class Manager {
157
157
  * and a boolean indicating whether it was created.
158
158
  */
159
159
  updateOrCreate(lookupFields: any, defaults?: Object): Promise<ResultTuple>;
160
+ /**
161
+ * Executes a pre-compiled AST through the standard QueryExecutor path.
162
+ *
163
+ * @param {import('./querySet.js').CompiledAST} ast - A compiled AST from QuerySet.compile()
164
+ * @returns {Promise<any>} The query result.
165
+ */
166
+ execute(ast: import("./querySet.js").CompiledAST): Promise<any>;
160
167
  /**
161
168
  * Applies a search to the QuerySet using the specified search query and fields.
162
169
  *
@@ -200,6 +200,18 @@ export class Manager {
200
200
  async updateOrCreate(lookupFields, defaults = {}) {
201
201
  return this.newQuerySet().updateOrCreate(lookupFields, defaults);
202
202
  }
203
+ /**
204
+ * Executes a pre-compiled AST through the standard QueryExecutor path.
205
+ *
206
+ * @param {import('./querySet.js').CompiledAST} ast - A compiled AST from QuerySet.compile()
207
+ * @returns {Promise<any>} The query result.
208
+ */
209
+ execute(ast) {
210
+ const { op, args, ...buildOutput } = ast;
211
+ const qs = new this.QuerySetClass(this.ModelClass, { serializerOptions: buildOutput.serializerOptions || {} });
212
+ qs._prebuiltAST = { ...buildOutput, serializerOptions: buildOutput.serializerOptions || {} };
213
+ return QueryExecutor.execute(qs, op, args || {});
214
+ }
203
215
  /**
204
216
  * Applies a search to the QuerySet using the specified search query and fields.
205
217
  *
@@ -47,6 +47,13 @@ export class Model {
47
47
  * @returns {Promise<boolean>} Promise that resolves to true if valid, throws error if invalid
48
48
  */
49
49
  static validate(data: Object, validateType?: string, partial?: boolean): Promise<boolean>;
50
+ /**
51
+ * Executes a pre-compiled AST through the standard QueryExecutor path.
52
+ *
53
+ * @param {import('./querySet.js').CompiledAST} ast - A compiled AST from QuerySet.compile()
54
+ * @returns {Promise<any>} The query result.
55
+ */
56
+ static execute(ast: import("./querySet.js").CompiledAST): Promise<any>;
50
57
  /**
51
58
  * Get field permissions for the current user (cached on the class)
52
59
  * @param {boolean} refresh - Force refresh the cached permissions
@@ -313,6 +313,15 @@ export class Model {
313
313
  throw new Error(`Validation failed: ${error.message}`);
314
314
  }
315
315
  }
316
+ /**
317
+ * Executes a pre-compiled AST through the standard QueryExecutor path.
318
+ *
319
+ * @param {import('./querySet.js').CompiledAST} ast - A compiled AST from QuerySet.compile()
320
+ * @returns {Promise<any>} The query result.
321
+ */
322
+ static execute(ast) {
323
+ return this.objects.execute(ast);
324
+ }
316
325
  /**
317
326
  * Get field permissions for the current user (cached on the class)
318
327
  * @param {boolean} refresh - Force refresh the cached permissions
@@ -1,3 +1,15 @@
1
+ /**
2
+ * A compiled AST that can be serialized and later executed via Model.execute().
3
+ *
4
+ * @typedef {Object} CompiledAST
5
+ * @property {string} op - The operation type (e.g. 'list', 'get', 'create').
6
+ * @property {Object} args - Operation-specific arguments.
7
+ * @property {Object|null} filter - The filter AST node.
8
+ * @property {Object|null} search - The search configuration.
9
+ * @property {Array} aggregations - Aggregation operations.
10
+ * @property {Array<string>} [orderBy] - Ordering fields.
11
+ * @property {Object} serializerOptions - Serializer options.
12
+ */
1
13
  /**
2
14
  * A QuerySet provides a fluent API for constructing and executing queries.
3
15
  *
@@ -273,9 +285,30 @@ export class QuerySet<T> {
273
285
  /**
274
286
  * Builds the final query object to be sent to the backend (simple jsonable object format).
275
287
  *
276
- * @returns {Object} The final query object.
277
- */
278
- build(): Object;
288
+ * @param {string} op - The operation type.
289
+ * @param {Object} [args={}] - Operation-specific arguments.
290
+ * @returns {CompiledAST} The compiled AST.
291
+ */
292
+ _compile(op: string, args?: Object): CompiledAST;
293
+ get compile(): {
294
+ fetch: (args: any) => CompiledAST;
295
+ get: (args: any) => CompiledAST;
296
+ first: (args: any) => CompiledAST;
297
+ last: (args: any) => CompiledAST;
298
+ count: (args: any) => CompiledAST;
299
+ sum: (args: any) => CompiledAST;
300
+ avg: (args: any) => CompiledAST;
301
+ min: (args: any) => CompiledAST;
302
+ max: (args: any) => CompiledAST;
303
+ exists: (args: any) => CompiledAST;
304
+ create: (args: any) => CompiledAST;
305
+ bulkCreate: (args: any) => CompiledAST;
306
+ update: (args: any) => CompiledAST;
307
+ delete: (args: any) => CompiledAST;
308
+ getOrCreate: (args: any) => CompiledAST;
309
+ updateOrCreate: (args: any) => CompiledAST;
310
+ };
311
+ build(): any;
279
312
  /**
280
313
  * Returns the current configuration of the QuerySet.
281
314
  *
@@ -297,5 +330,38 @@ export class QuerySet<T> {
297
330
  */
298
331
  [Symbol.asyncIterator](): AsyncIterator<T>;
299
332
  }
333
+ /**
334
+ * A compiled AST that can be serialized and later executed via Model.execute().
335
+ */
336
+ export type CompiledAST = {
337
+ /**
338
+ * - The operation type (e.g. 'list', 'get', 'create').
339
+ */
340
+ op: string;
341
+ /**
342
+ * - Operation-specific arguments.
343
+ */
344
+ args: Object;
345
+ /**
346
+ * - The filter AST node.
347
+ */
348
+ filter: Object | null;
349
+ /**
350
+ * - The search configuration.
351
+ */
352
+ search: Object | null;
353
+ /**
354
+ * - Aggregation operations.
355
+ */
356
+ aggregations: any[];
357
+ /**
358
+ * - Ordering fields.
359
+ */
360
+ orderBy?: string[] | undefined;
361
+ /**
362
+ * - Serializer options.
363
+ */
364
+ serializerOptions: Object;
365
+ };
300
366
  import { ModelSerializer } from "./serializers.js";
301
367
  import { Model } from "./model.js";
@@ -7,6 +7,18 @@ import { v7 } from "uuid";
7
7
  import hash from "object-hash";
8
8
  import rfdc from "rfdc";
9
9
  const clone = rfdc();
10
+ /**
11
+ * A compiled AST that can be serialized and later executed via Model.execute().
12
+ *
13
+ * @typedef {Object} CompiledAST
14
+ * @property {string} op - The operation type (e.g. 'list', 'get', 'create').
15
+ * @property {Object} args - Operation-specific arguments.
16
+ * @property {Object|null} filter - The filter AST node.
17
+ * @property {Object|null} search - The search configuration.
18
+ * @property {Array} aggregations - Aggregation operations.
19
+ * @property {Array<string>} [orderBy] - Ordering fields.
20
+ * @property {Object} serializerOptions - Serializer options.
21
+ */
10
22
  /**
11
23
  * A QuerySet provides a fluent API for constructing and executing queries.
12
24
  *
@@ -649,9 +661,36 @@ export class QuerySet {
649
661
  /**
650
662
  * Builds the final query object to be sent to the backend (simple jsonable object format).
651
663
  *
652
- * @returns {Object} The final query object.
664
+ * @param {string} op - The operation type.
665
+ * @param {Object} [args={}] - Operation-specific arguments.
666
+ * @returns {CompiledAST} The compiled AST.
653
667
  */
668
+ _compile(op, args = {}) {
669
+ return { op, args, ...this.build() };
670
+ }
671
+ get compile() {
672
+ return {
673
+ fetch: (args) => this._compile('list', args),
674
+ get: (args) => this._compile('get', args),
675
+ first: (args) => this._compile('first', args),
676
+ last: (args) => this._compile('last', args),
677
+ count: (args) => this._compile('count', args),
678
+ sum: (args) => this._compile('sum', args),
679
+ avg: (args) => this._compile('avg', args),
680
+ min: (args) => this._compile('min', args),
681
+ max: (args) => this._compile('max', args),
682
+ exists: (args) => this._compile('exists', args),
683
+ create: (args) => this._compile('create', args),
684
+ bulkCreate: (args) => this._compile('bulk_create', args),
685
+ update: (args) => this._compile('update', args),
686
+ delete: (args) => this._compile('delete', args),
687
+ getOrCreate: (args) => this._compile('get_or_create', args),
688
+ updateOrCreate: (args) => this._compile('update_or_create', args),
689
+ };
690
+ }
654
691
  build() {
692
+ if (this._prebuiltAST)
693
+ return clone(this._prebuiltAST);
655
694
  let searchData = null;
656
695
  const nonSearchNodes = [];
657
696
  for (const node of this.nodes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statezero/core",
3
- "version": "0.2.56",
3
+ "version": "0.2.59",
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",