@cadenza.io/service 2.3.16 → 2.4.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.
package/dist/index.mjs CHANGED
@@ -281,12 +281,11 @@ var ServiceRegistry = class _ServiceRegistry {
281
281
  deleted
282
282
  } = serviceInstance;
283
283
  if (uuid4 === this.serviceInstanceId) return;
284
- console.log("service instance", serviceName, uuid4, address);
285
284
  if (deleted) {
286
- this.instances.get(serviceName)?.splice(
287
- this.instances.get(serviceName)?.findIndex((i) => i.uuid === uuid4) ?? -1,
288
- 1
289
- );
285
+ const indexToDelete = this.instances.get(serviceName)?.findIndex((i) => i.uuid === uuid4) ?? -1;
286
+ if (indexToDelete >= 0) {
287
+ this.instances.get(serviceName)?.splice(indexToDelete, 1);
288
+ }
290
289
  if (this.instances.get(serviceName)?.length === 0) {
291
290
  this.instances.delete(serviceName);
292
291
  } else if (this.instances.get(serviceName)?.filter((i) => i.address === address && i.port === port).length === 0) {
@@ -329,7 +328,7 @@ var ServiceRegistry = class _ServiceRegistry {
329
328
  communicationTypes
330
329
  });
331
330
  instances?.filter(
332
- (i) => i.address === address && i.port === port && i.clientCreated && i.isActive
331
+ (i) => i.address === address && i.port === port && i.isActive
333
332
  ).forEach((i) => {
334
333
  i.clientCreated = true;
335
334
  });
@@ -361,7 +360,6 @@ var ServiceRegistry = class _ServiceRegistry {
361
360
  this.handleGlobalSignalRegistrationTask = CadenzaService.createMetaTask(
362
361
  "Handle global Signal Registration",
363
362
  (ctx) => {
364
- console.log("Handling global signal registration...");
365
363
  const { signalToTaskMaps } = ctx;
366
364
  const sortedSignalToTaskMap = signalToTaskMaps.sort(
367
365
  (a, b) => {
@@ -370,9 +368,7 @@ var ServiceRegistry = class _ServiceRegistry {
370
368
  return 0;
371
369
  }
372
370
  );
373
- console.log(sortedSignalToTaskMap);
374
371
  const locallyEmittedSignals = CadenzaService.signalBroker.listEmittedSignals().filter((s) => s.startsWith("global."));
375
- console.log(locallyEmittedSignals);
376
372
  for (const map of sortedSignalToTaskMap) {
377
373
  if (map.deleted) {
378
374
  this.remoteSignals.get(map.serviceName)?.delete(map.signalName);
@@ -389,9 +385,6 @@ var ServiceRegistry = class _ServiceRegistry {
389
385
  this.remoteSignals.set(map.serviceName, /* @__PURE__ */ new Set());
390
386
  }
391
387
  if (!this.remoteSignals.get(map.serviceName)?.has(map.signalName)) {
392
- console.log(
393
- `Creating signal transmission task for: ${map.signalName} to ${map.serviceName}`
394
- );
395
388
  CadenzaService.createSignalTransmissionTask(
396
389
  map.signalName,
397
390
  map.serviceName
@@ -439,7 +432,12 @@ var ServiceRegistry = class _ServiceRegistry {
439
432
  return true;
440
433
  },
441
434
  "Handles service not responding"
442
- ).doOn("meta.fetch.handshake_failed", "meta.socket_client.disconnected").attachSignal("global.meta.service_registry.service_not_responding");
435
+ ).doOn(
436
+ "meta.fetch.handshake_failed",
437
+ "meta.fetch.handshake_failed.*",
438
+ "meta.socket_client.disconnected",
439
+ "meta.socket_client.disconnected.*"
440
+ ).attachSignal("global.meta.service_registry.service_not_responding");
443
441
  this.handleServiceHandshakeTask = CadenzaService.createMetaTask(
444
442
  "Handle service handshake",
445
443
  (ctx, emit) => {
@@ -466,7 +464,10 @@ var ServiceRegistry = class _ServiceRegistry {
466
464
  (i) => i.uuid !== serviceInstanceId && i.address === serviceAddress && i.port === servicePort
467
465
  );
468
466
  for (const i of instancesToDelete ?? []) {
469
- this.instances.get(serviceName)?.splice(this.instances.get(serviceName)?.indexOf(i) ?? -1, 1);
467
+ const indexToDelete = this.instances.get(serviceName)?.indexOf(i) ?? -1;
468
+ if (indexToDelete >= 0) {
469
+ this.instances.get(serviceName)?.splice(indexToDelete, 1);
470
+ }
470
471
  emit("global.meta.service_registry.deleted", {
471
472
  data: {
472
473
  isActive: false,
@@ -503,23 +504,14 @@ var ServiceRegistry = class _ServiceRegistry {
503
504
  const mergeSyncDataTask = CadenzaService.createUniqueMetaTask(
504
505
  "Merge sync data",
505
506
  (ctx) => {
506
- try {
507
- let joinedContext = {};
508
- ctx.joinedContexts.forEach((ctx2) => {
509
- joinedContext = { ...joinedContext, ...ctx2 };
510
- });
511
- console.log("merging contexts of full sync...", joinedContext);
512
- return joinedContext;
513
- } catch (e) {
514
- console.log("Error", e.message, ctx);
515
- return false;
516
- }
507
+ let joinedContext = {};
508
+ ctx.joinedContexts.forEach((ctx2) => {
509
+ joinedContext = { ...joinedContext, ...ctx2 };
510
+ });
511
+ return joinedContext;
517
512
  }
518
513
  ).emits("meta.service_registry.initial_sync_complete").then(this.handleGlobalSignalRegistrationTask);
519
514
  this.fullSyncTask = CadenzaService.createMetaRoutine("Full sync", [
520
- CadenzaService.createTask("Confirm full sync", () => {
521
- console.log("Confirming full sync...");
522
- }),
523
515
  CadenzaService.createCadenzaDBQueryTask("signal_to_task_map", {
524
516
  filter: {
525
517
  isGlobal: true
@@ -635,8 +627,9 @@ var ServiceRegistry = class _ServiceRegistry {
635
627
  }
636
628
  if (__broadcast || instances[0].isFrontend) {
637
629
  for (const instance of instances) {
630
+ const socketKey = instance.isFrontend ? instance.address : `${instance.address}_${instance.port}`;
638
631
  emit(
639
- `meta.service_registry.selected_instance_for_socket:${instance.address}`,
632
+ `meta.service_registry.selected_instance_for_socket:${socketKey}`,
640
633
  context
641
634
  );
642
635
  }
@@ -1627,6 +1620,46 @@ var RestController = class _RestController {
1627
1620
  import { Server } from "socket.io";
1628
1621
  import { RateLimiterMemory as RateLimiterMemory2 } from "rate-limiter-flexible";
1629
1622
  import { io } from "socket.io-client";
1623
+
1624
+ // src/network/socketClientUtils.ts
1625
+ var waitForSocketConnection = async (socket, timeoutMs, createError) => {
1626
+ if (!socket) {
1627
+ return { ok: false, error: createError("disconnected") };
1628
+ }
1629
+ if (socket.connected) {
1630
+ return { ok: true };
1631
+ }
1632
+ return new Promise((resolve) => {
1633
+ let timer = null;
1634
+ let settled = false;
1635
+ const cleanup = () => {
1636
+ if (timer) {
1637
+ clearTimeout(timer);
1638
+ timer = null;
1639
+ }
1640
+ socket.off("connect", onConnect);
1641
+ socket.off("connect_error", onConnectError);
1642
+ socket.off("disconnect", onDisconnect);
1643
+ };
1644
+ const settle = (outcome) => {
1645
+ if (settled) return;
1646
+ settled = true;
1647
+ cleanup();
1648
+ resolve(outcome);
1649
+ };
1650
+ const onConnect = () => settle({ ok: true });
1651
+ const onConnectError = (error) => settle({ ok: false, error: createError("connect_error", error) });
1652
+ const onDisconnect = () => settle({ ok: false, error: createError("disconnected") });
1653
+ socket.once("connect", onConnect);
1654
+ socket.once("connect_error", onConnectError);
1655
+ socket.once("disconnect", onDisconnect);
1656
+ timer = setTimeout(() => {
1657
+ settle({ ok: false, error: createError("connect_timeout") });
1658
+ }, timeoutMs);
1659
+ });
1660
+ };
1661
+
1662
+ // src/network/SocketController.ts
1630
1663
  var SocketController = class _SocketController {
1631
1664
  static get instance() {
1632
1665
  if (!this._instance) this._instance = new _SocketController();
@@ -1763,10 +1796,6 @@ var SocketController = class _SocketController {
1763
1796
  "delegation",
1764
1797
  (ctx2, callback) => {
1765
1798
  const deputyExecId = ctx2.__metadata.__deputyExecId;
1766
- console.log(
1767
- "Delegation request received:",
1768
- ctx2.__localTaskName
1769
- );
1770
1799
  CadenzaService.createEphemeralMetaTask(
1771
1800
  "Resolve delegation",
1772
1801
  (ctx3) => {
@@ -1801,7 +1830,6 @@ var SocketController = class _SocketController {
1801
1830
  "signal",
1802
1831
  (ctx2, callback) => {
1803
1832
  if (CadenzaService.signalBroker.listObservedSignals().includes(ctx2.__signalName)) {
1804
- console.log("Signal received:", ctx2.__signalName);
1805
1833
  callback({
1806
1834
  __status: "success",
1807
1835
  __signalName: ctx2.__signalName
@@ -1907,35 +1935,71 @@ var SocketController = class _SocketController {
1907
1935
  });
1908
1936
  emitWhenReady = (event, data, timeoutMs = 6e4, ack) => {
1909
1937
  return new Promise((resolve) => {
1910
- const tryEmit = () => {
1911
- if (!socket?.connected) {
1912
- socket?.once("connect", tryEmit);
1938
+ const resolveWithError = (errorMessage, fallbackError) => {
1939
+ resolve({
1940
+ ...data,
1941
+ errored: true,
1942
+ __error: errorMessage,
1943
+ error: fallbackError instanceof Error ? fallbackError.message : errorMessage,
1944
+ socketId: socket?.id,
1945
+ serviceName,
1946
+ URL
1947
+ });
1948
+ };
1949
+ const tryEmit = async () => {
1950
+ const waitTimeoutMs = timeoutMs > 0 ? timeoutMs + 10 : 1e4;
1951
+ const waitResult = await waitForSocketConnection(
1952
+ socket,
1953
+ waitTimeoutMs,
1954
+ (reason, error) => {
1955
+ if (reason === "connect_timeout") {
1956
+ return `Socket connect timed out before '${event}'`;
1957
+ }
1958
+ if (reason === "connect_error") {
1959
+ const errMessage = error instanceof Error ? error.message : String(error);
1960
+ return `Socket connect error before '${event}': ${errMessage}`;
1961
+ }
1962
+ return `Socket disconnected before '${event}'`;
1963
+ }
1964
+ );
1965
+ if (!waitResult.ok) {
1966
+ CadenzaService.log(
1967
+ waitResult.error,
1968
+ { socketId: socket?.id, serviceName, URL, event },
1969
+ "error"
1970
+ );
1971
+ resolveWithError(waitResult.error);
1913
1972
  return;
1914
1973
  }
1915
- let timer;
1974
+ let timer = null;
1916
1975
  if (timeoutMs !== 0) {
1917
1976
  timer = setTimeout(() => {
1977
+ if (timer) {
1978
+ pendingTimers.delete(timer);
1979
+ timer = null;
1980
+ }
1918
1981
  CadenzaService.log(
1919
1982
  `Socket event '${event}' timed out`,
1920
1983
  { socketId: socket?.id, serviceName, URL },
1921
1984
  "error"
1922
1985
  );
1923
- resolve({
1924
- ...data,
1925
- errored: true,
1926
- __error: `Socket event '${event}' timed out`,
1927
- error: `Socket event '${event}' timed out`,
1928
- socketId: socket?.id,
1929
- serviceName,
1930
- URL
1931
- });
1986
+ resolveWithError(`Socket event '${event}' timed out`);
1932
1987
  }, timeoutMs + 10);
1933
1988
  pendingTimers.add(timer);
1934
1989
  }
1935
- socket.timeout(timeoutMs).emit(event, data, (err, response) => {
1936
- if (timer) clearTimeout(timer);
1937
- pendingTimers.delete(timer);
1938
- timer = null;
1990
+ const connectedSocket = socket;
1991
+ if (!connectedSocket) {
1992
+ resolveWithError(
1993
+ `Socket unavailable before emitting '${event}'`
1994
+ );
1995
+ return;
1996
+ }
1997
+ connectedSocket.timeout(timeoutMs).emit(event, data, (err, response) => {
1998
+ if (timer) {
1999
+ clearTimeout(timer);
2000
+ pendingTimers.delete(timer);
2001
+ timer = null;
2002
+ }
1939
2003
  if (err) {
1940
2004
  CadenzaService.log(
1941
2005
  "Socket timeout.",
@@ -1958,11 +2022,7 @@ var SocketController = class _SocketController {
1958
2022
  resolve(response);
1959
2023
  });
1960
2024
  };
1961
- if (socket?.connected) {
1962
- tryEmit();
1963
- } else {
1964
- socket?.once("connect", tryEmit);
1965
- }
2025
+ void tryEmit();
1966
2026
  });
1967
2027
  };
1968
2028
  socket.on("connect", () => {
@@ -2078,7 +2138,6 @@ var SocketController = class _SocketController {
2078
2138
  delete ctx2.__broadcast;
2079
2139
  const requestSentAt = Date.now();
2080
2140
  pendingDelegationIds.add(ctx2.__metadata.__deputyExecId);
2081
- console.log("Delegating task:", ctx2.__remoteRoutineName);
2082
2141
  emitWhenReady?.(
2083
2142
  "delegation",
2084
2143
  ctx2,
@@ -2087,12 +2146,6 @@ var SocketController = class _SocketController {
2087
2146
  const requestDuration = Date.now() - requestSentAt;
2088
2147
  const metadata = resultContext.__metadata;
2089
2148
  delete resultContext.__metadata;
2090
- console.log(
2091
- "Delegation response received:",
2092
- ctx2.__remoteRoutineName,
2093
- "Duration:",
2094
- requestDuration
2095
- );
2096
2149
  emit(
2097
2150
  `meta.socket_client.delegated:${ctx2.__metadata.__deputyExecId}`,
2098
2151
  {
@@ -2120,7 +2173,6 @@ var SocketController = class _SocketController {
2120
2173
  }
2121
2174
  return new Promise((resolve) => {
2122
2175
  delete ctx2.__broadcast;
2123
- console.log("Transmitting signal:", ctx2.__signalName);
2124
2176
  emitWhenReady?.("signal", ctx2, 5e3, (response) => {
2125
2177
  if (ctx2.__routineExecId) {
2126
2178
  emit(
@@ -2287,14 +2339,25 @@ var GraphMetadataController = class _GraphMetadataController {
2287
2339
  return {
2288
2340
  data: {
2289
2341
  ...ctx.data,
2290
- serviceName: CadenzaService.serviceRegistry.serviceName
2291
- // input_context_schema_id: ctx.data.inputContextSchema ? { // TODO
2292
- //
2293
- // } : null,
2294
- // output_context_schema_id: ctx.data.outputContextSchema ? {
2295
- //
2296
- // } : null,
2297
- }
2342
+ serviceName: CadenzaService.serviceRegistry.serviceName,
2343
+ inputContextSchemaId: ctx.data.inputContextSchemaId ? {
2344
+ subOperation: "insert",
2345
+ table: "context_schema",
2346
+ data: {
2347
+ ...ctx.data.inputContextSchemaId
2348
+ },
2349
+ return: "uuid"
2350
+ } : null,
2351
+ outputContextSchemaId: ctx.data.outputContextSchemaId ? {
2352
+ subOperation: "insert",
2353
+ table: "context_schema",
2354
+ data: {
2355
+ ...ctx.data.outputContextSchemaId
2356
+ },
2357
+ return: "uuid"
2358
+ } : null
2359
+ },
2360
+ transaction: true
2298
2361
  };
2299
2362
  }).doOn("meta.task.created").emits("global.meta.graph_metadata.task_created");
2300
2363
  CadenzaService.createMetaTask("Handle task update", (ctx) => {
@@ -2426,7 +2489,7 @@ var GraphMetadataController = class _GraphMetadataController {
2426
2489
  data: {
2427
2490
  ...ctx.data,
2428
2491
  serviceName: CadenzaService.serviceRegistry.serviceName,
2429
- serviceInstance_id: CadenzaService.serviceRegistry.serviceInstanceId
2492
+ serviceInstanceId: CadenzaService.serviceRegistry.serviceInstanceId
2430
2493
  },
2431
2494
  filter: {
2432
2495
  ...ctx.filter
@@ -2954,7 +3017,6 @@ var DatabaseController = class _DatabaseController {
2954
3017
  if (ddl && ddl.length > 0) {
2955
3018
  for (const sql of ddl) {
2956
3019
  try {
2957
- console.log("Executing DDL", sql);
2958
3020
  await this.dbClient.query(sql);
2959
3021
  } catch (error) {
2960
3022
  console.error(
@@ -3603,9 +3665,9 @@ var DatabaseController = class _DatabaseController {
3603
3665
  createDatabaseTask(op, tableName, table, queryFunction, options) {
3604
3666
  const opAction = op === "query" ? "queried" : op === "insert" ? "inserted" : op === "update" ? "updated" : op === "delete" ? "deleted" : "";
3605
3667
  const defaultSignal = `global.${options.isMeta ? "meta." : ""}${tableName}.${opAction}`;
3606
- const tableNameFormatted = tableName.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
3607
- const taskName = `db${op.charAt(0).toUpperCase() + op.slice(1)}${tableNameFormatted}`;
3608
- CadenzaService.createThrottledTask(
3668
+ const taskName = `${op.charAt(0).toUpperCase() + op.slice(1)} ${tableName}`;
3669
+ const schema = this.getInputSchema(op, tableName, table);
3670
+ const task = CadenzaService.createThrottledTask(
3609
3671
  taskName,
3610
3672
  async (context, emit) => {
3611
3673
  for (const action of Object.keys(table.customSignals?.triggers ?? {})) {
@@ -3700,17 +3762,8 @@ var DatabaseController = class _DatabaseController {
3700
3762
  {
3701
3763
  isMeta: options.isMeta,
3702
3764
  isSubMeta: options.isMeta,
3703
- validateInputContext: false,
3704
- // TODO
3705
- inputSchema: {
3706
- // TODO
3707
- type: "object",
3708
- properties: {
3709
- filter: {
3710
- type: "object"
3711
- }
3712
- }
3713
- }
3765
+ validateInputContext: options.securityProfile !== "low",
3766
+ inputSchema: schema
3714
3767
  }
3715
3768
  ).doOn(
3716
3769
  ...table.customSignals?.triggers?.[op]?.map((signal) => {
@@ -3721,8 +3774,382 @@ var DatabaseController = class _DatabaseController {
3721
3774
  return typeof signal === "string" ? signal : signal.signal;
3722
3775
  }) ?? []
3723
3776
  );
3777
+ if (op === "query") {
3778
+ const intentName = `query-${CadenzaService.serviceRegistry.serviceName}-${tableName}`;
3779
+ CadenzaService.defineIntent({
3780
+ name: intentName,
3781
+ description: `Perform a query operation on the ${tableName} table`,
3782
+ input: schema
3783
+ });
3784
+ task.respondsTo(intentName);
3785
+ }
3786
+ }
3787
+ getInputSchema(op, tableName, table) {
3788
+ const inputSchema = {
3789
+ type: "object",
3790
+ properties: {
3791
+ queryData: {
3792
+ type: "object",
3793
+ properties: {},
3794
+ strict: true
3795
+ }
3796
+ },
3797
+ strict: true
3798
+ };
3799
+ if (!inputSchema.properties) {
3800
+ return inputSchema;
3801
+ }
3802
+ inputSchema.properties.transaction = getTransactionSchema();
3803
+ inputSchema.properties.queryData.properties.transaction = inputSchema.properties.transaction;
3804
+ switch (op) {
3805
+ case "insert":
3806
+ inputSchema.properties.data = getInsertDataSchemaFromTable(
3807
+ table,
3808
+ tableName
3809
+ );
3810
+ inputSchema.properties.queryData.properties.data = inputSchema.properties.data;
3811
+ inputSchema.properties.batch = getQueryBatchSchemaFromTable();
3812
+ inputSchema.properties.queryData.properties.batch = inputSchema.properties.batch;
3813
+ inputSchema.properties.onConflict = getQueryOnConflictSchemaFromTable(
3814
+ table,
3815
+ tableName
3816
+ );
3817
+ inputSchema.properties.queryData.properties.onConflict = inputSchema.properties.onConflict;
3818
+ break;
3819
+ case "query":
3820
+ inputSchema.properties.filter = getQueryFilterSchemaFromTable(
3821
+ table,
3822
+ tableName
3823
+ );
3824
+ inputSchema.properties.queryData.properties.filter = inputSchema.properties.filter;
3825
+ inputSchema.properties.fields = getQueryFieldsSchemaFromTable(
3826
+ table,
3827
+ tableName
3828
+ );
3829
+ inputSchema.properties.queryData.properties.fields = inputSchema.properties.fields;
3830
+ inputSchema.properties.joins = getQueryJoinsSchemaFromTable(
3831
+ table,
3832
+ tableName
3833
+ );
3834
+ inputSchema.properties.queryData.properties.joins = inputSchema.properties.joins;
3835
+ inputSchema.properties.sort = getQuerySortSchemaFromTable(
3836
+ table,
3837
+ tableName
3838
+ );
3839
+ inputSchema.properties.queryData.properties.sort = inputSchema.properties.sort;
3840
+ inputSchema.properties.limit = getQueryLimitSchemaFromTable();
3841
+ inputSchema.properties.queryData.properties.limit = inputSchema.properties.limit;
3842
+ inputSchema.properties.offset = getQueryOffsetSchemaFromTable();
3843
+ inputSchema.properties.queryData.properties.offset = inputSchema.properties.offset;
3844
+ break;
3845
+ case "update":
3846
+ inputSchema.properties.filter = getQueryFilterSchemaFromTable(
3847
+ table,
3848
+ tableName
3849
+ );
3850
+ inputSchema.properties.queryData.properties.filter = inputSchema.properties.filter;
3851
+ inputSchema.properties.fields = getQueryFieldsSchemaFromTable(
3852
+ table,
3853
+ tableName
3854
+ );
3855
+ inputSchema.properties.queryData.properties.fields = inputSchema.properties.fields;
3856
+ break;
3857
+ case "delete":
3858
+ inputSchema.properties.filter = getQueryFilterSchemaFromTable(
3859
+ table,
3860
+ tableName
3861
+ );
3862
+ inputSchema.properties.queryData.properties.filter = inputSchema.properties.filter;
3863
+ break;
3864
+ }
3865
+ return inputSchema;
3724
3866
  }
3725
3867
  };
3868
+ function getInsertDataSchemaFromTable(table, tableName) {
3869
+ const dataSchema = {
3870
+ type: "object",
3871
+ properties: {
3872
+ ...Object.fromEntries(
3873
+ Object.entries(table.fields).map((field) => {
3874
+ return [
3875
+ field[0],
3876
+ [
3877
+ {
3878
+ type: tableFieldTypeToSchemaType(field[1].type),
3879
+ description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
3880
+ },
3881
+ {
3882
+ type: "string",
3883
+ constraints: {
3884
+ oneOf: ["increment", "decrement", "set"]
3885
+ }
3886
+ },
3887
+ {
3888
+ type: "object",
3889
+ properties: {
3890
+ subOperation: {
3891
+ type: "string",
3892
+ enum: ["insert", "query"]
3893
+ },
3894
+ table: {
3895
+ type: "string"
3896
+ },
3897
+ data: [
3898
+ {
3899
+ type: "object"
3900
+ },
3901
+ {
3902
+ type: "array",
3903
+ items: {
3904
+ type: "object"
3905
+ }
3906
+ }
3907
+ ],
3908
+ filter: {
3909
+ type: "object"
3910
+ },
3911
+ fields: {
3912
+ type: "array",
3913
+ items: {
3914
+ type: "string"
3915
+ }
3916
+ },
3917
+ return: {
3918
+ type: "string"
3919
+ }
3920
+ },
3921
+ required: ["subOperation", "table"]
3922
+ }
3923
+ ]
3924
+ ];
3925
+ })
3926
+ )
3927
+ },
3928
+ required: Object.entries(table.fields).filter((field) => field[1].required || field[1].primary).map((field) => field[0]),
3929
+ strict: true
3930
+ };
3931
+ return [
3932
+ dataSchema,
3933
+ {
3934
+ type: "array",
3935
+ items: dataSchema
3936
+ }
3937
+ ];
3938
+ }
3939
+ function getQueryFilterSchemaFromTable(table, tableName) {
3940
+ return {
3941
+ type: "object",
3942
+ properties: {
3943
+ ...Object.fromEntries(
3944
+ Object.entries(table.fields).map((field) => {
3945
+ return [
3946
+ field[0],
3947
+ [
3948
+ {
3949
+ type: tableFieldTypeToSchemaType(field[1].type),
3950
+ description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
3951
+ },
3952
+ {
3953
+ type: "array",
3954
+ items: {
3955
+ type: tableFieldTypeToSchemaType(field[1].type)
3956
+ }
3957
+ }
3958
+ ]
3959
+ ];
3960
+ })
3961
+ )
3962
+ },
3963
+ strict: true,
3964
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
3965
+ };
3966
+ }
3967
+ function getQueryFieldsSchemaFromTable(table, tableName) {
3968
+ return {
3969
+ type: "array",
3970
+ items: {
3971
+ type: "string",
3972
+ constraints: {
3973
+ oneOf: Object.keys(table.fields)
3974
+ }
3975
+ },
3976
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
3977
+ };
3978
+ }
3979
+ function getQueryJoinsSchemaFromTable(table, tableName) {
3980
+ return {
3981
+ type: "object",
3982
+ properties: {
3983
+ ...Object.fromEntries(
3984
+ Object.entries(table.fields).map((field) => {
3985
+ return [
3986
+ field[0],
3987
+ {
3988
+ type: "object",
3989
+ properties: {
3990
+ on: {
3991
+ type: "string"
3992
+ },
3993
+ fields: {
3994
+ type: "array",
3995
+ items: {
3996
+ type: "string"
3997
+ }
3998
+ },
3999
+ filter: {
4000
+ type: "object"
4001
+ },
4002
+ returnAs: {
4003
+ type: "string",
4004
+ constraints: {
4005
+ oneOf: ["array", "object"]
4006
+ }
4007
+ },
4008
+ alias: {
4009
+ type: "string"
4010
+ },
4011
+ joins: {
4012
+ type: "object"
4013
+ }
4014
+ },
4015
+ required: ["on", "fields"],
4016
+ strict: true
4017
+ }
4018
+ ];
4019
+ })
4020
+ )
4021
+ },
4022
+ strict: true,
4023
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
4024
+ };
4025
+ }
4026
+ function getQuerySortSchemaFromTable(table, tableName) {
4027
+ return {
4028
+ type: "object",
4029
+ properties: {
4030
+ ...Object.fromEntries(
4031
+ Object.entries(table.fields).map((field) => {
4032
+ return [
4033
+ field[0],
4034
+ {
4035
+ type: "string",
4036
+ constraints: {
4037
+ oneOf: ["asc", "desc"]
4038
+ }
4039
+ }
4040
+ ];
4041
+ })
4042
+ )
4043
+ },
4044
+ strict: true,
4045
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
4046
+ };
4047
+ }
4048
+ function getQueryLimitSchemaFromTable() {
4049
+ return {
4050
+ type: "number",
4051
+ constraints: {
4052
+ min: 1
4053
+ },
4054
+ description: "Limit for query results"
4055
+ };
4056
+ }
4057
+ function getQueryOffsetSchemaFromTable() {
4058
+ return {
4059
+ type: "number",
4060
+ constraints: {
4061
+ min: 0
4062
+ },
4063
+ description: "Offset for query results"
4064
+ };
4065
+ }
4066
+ function getTransactionSchema() {
4067
+ return {
4068
+ type: "boolean",
4069
+ description: "Whether to run the query in a transaction"
4070
+ };
4071
+ }
4072
+ function getQueryBatchSchemaFromTable() {
4073
+ return {
4074
+ type: "boolean",
4075
+ description: "Whether to run the query in batch mode"
4076
+ };
4077
+ }
4078
+ function getQueryOnConflictSchemaFromTable(table, tableName) {
4079
+ return {
4080
+ type: "object",
4081
+ properties: {
4082
+ target: {
4083
+ type: "array",
4084
+ items: {
4085
+ type: "string",
4086
+ constraints: {
4087
+ oneOf: Object.keys(table.fields)
4088
+ }
4089
+ }
4090
+ },
4091
+ action: {
4092
+ type: "object",
4093
+ properties: {
4094
+ do: {
4095
+ type: "string",
4096
+ constraints: {
4097
+ oneOf: ["nothing", "update"]
4098
+ }
4099
+ },
4100
+ set: {
4101
+ type: "object",
4102
+ properties: {
4103
+ ...Object.fromEntries(
4104
+ Object.entries(table.fields).map((field) => {
4105
+ return [
4106
+ field[0],
4107
+ [
4108
+ {
4109
+ type: tableFieldTypeToSchemaType(field[1].type),
4110
+ description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
4111
+ }
4112
+ ]
4113
+ ];
4114
+ })
4115
+ )
4116
+ }
4117
+ },
4118
+ where: {
4119
+ type: "string"
4120
+ }
4121
+ },
4122
+ required: ["do"]
4123
+ }
4124
+ },
4125
+ required: ["target", "action"],
4126
+ strict: true
4127
+ };
4128
+ }
4129
+ function tableFieldTypeToSchemaType(type) {
4130
+ switch (type) {
4131
+ case "varchar":
4132
+ case "text":
4133
+ case "jsonb":
4134
+ case "uuid":
4135
+ case "date":
4136
+ case "geo_point":
4137
+ case "bytea":
4138
+ return "string";
4139
+ case "int":
4140
+ case "bigint":
4141
+ case "decimal":
4142
+ case "timestamp":
4143
+ return "number";
4144
+ case "boolean":
4145
+ return "boolean";
4146
+ case "array":
4147
+ return "array";
4148
+ case "object":
4149
+ return "object";
4150
+ }
4151
+ return "any";
4152
+ }
3726
4153
 
3727
4154
  // src/Cadenza.ts
3728
4155
  import { v4 as uuid3 } from "uuid";
@@ -4194,7 +4621,6 @@ var GraphSyncController = class _GraphSyncController {
4194
4621
  );
4195
4622
  CadenzaService.schedule("meta.sync_requested", { __syncing: true }, 2e3);
4196
4623
  }
4197
- console.log("Syncing initiated", this.isCadenzaDBReady);
4198
4624
  }
4199
4625
  };
4200
4626
 
@@ -4597,10 +5023,9 @@ var CadenzaService = class {
4597
5023
  this.bootstrap();
4598
5024
  this.validateName(tableName);
4599
5025
  this.validateName(operation);
4600
- const tableNameFormatted = tableName.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
4601
5026
  const name = `${operation.charAt(0).toUpperCase() + operation.slice(1)} ${tableName} in ${databaseServiceName ?? "default database service"}`;
4602
5027
  const description = `Executes a ${operation} on table ${tableName} in ${databaseServiceName ?? "default database service"}`;
4603
- const taskName = `db${operation.charAt(0).toUpperCase() + operation.slice(1)}${tableNameFormatted}`;
5028
+ const taskName = `${operation.charAt(0).toUpperCase() + operation.slice(1)} ${tableName}`;
4604
5029
  options = {
4605
5030
  concurrency: 100,
4606
5031
  timeout: 0,
@@ -4862,7 +5287,7 @@ var CadenzaService = class {
4862
5287
  * This method is not supported in a browser environment and will log a warning if called in such an environment.
4863
5288
  *
4864
5289
  * @param {string} name - The name of the database service to be created.
4865
- * @param {SchemaDefinition} schema - The schema definition for the database service.
5290
+ * @param {DatabaseSchemaDefinition} schema - The schema definition for the database service.
4866
5291
  * @param {string} [description=""] - An optional description of the database service.
4867
5292
  * @param {ServerOptions & DatabaseOptions} [options={}] - Optional configuration settings for the database and server.
4868
5293
  * @return {void} This method does not return a value.
@@ -4926,7 +5351,7 @@ var CadenzaService = class {
4926
5351
  * Creates a meta database service with the specified configuration.
4927
5352
  *
4928
5353
  * @param {string} name - The name of the database service to be created.
4929
- * @param {SchemaDefinition} schema - The schema definition for the database.
5354
+ * @param {DatabaseSchemaDefinition} schema - The schema definition for the database.
4930
5355
  * @param {string} [description=""] - An optional description of the database service.
4931
5356
  * @param {ServerOptions & DatabaseOptions} [options={}] - Optional server and database configuration options. The `isMeta` flag will be automatically set to true.
4932
5357
  * @return {void} - This method does not return a value.