@cadenza.io/service 2.9.0 → 2.11.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
@@ -1,7 +1,5 @@
1
1
  // src/Cadenza.ts
2
- import Cadenza, {
3
- Actor
4
- } from "@cadenza.io/core";
2
+ import Cadenza from "@cadenza.io/core";
5
3
 
6
4
  // src/graph/definition/DeputyTask.ts
7
5
  import { v4 as uuid } from "uuid";
@@ -3299,6 +3297,44 @@ var SocketController = class _SocketController {
3299
3297
  this.diagnosticsMaxClientEntries = 500;
3300
3298
  this.destroyedDiagnosticsTtlMs = 15 * 6e4;
3301
3299
  this.socketServerDefaultKey = "socket-server-default";
3300
+ this.socketServerInitialSessionState = {
3301
+ serverKey: this.socketServerDefaultKey,
3302
+ useSocket: false,
3303
+ status: "inactive",
3304
+ securityProfile: "medium",
3305
+ networkType: "internal",
3306
+ connectionCount: 0,
3307
+ lastStartedAt: null,
3308
+ lastConnectedAt: null,
3309
+ lastDisconnectedAt: null,
3310
+ lastShutdownAt: null,
3311
+ updatedAt: 0
3312
+ };
3313
+ this.socketClientInitialSessionState = {
3314
+ fetchId: "",
3315
+ serviceInstanceId: "",
3316
+ communicationTypes: [],
3317
+ serviceName: "",
3318
+ serviceAddress: "",
3319
+ servicePort: 0,
3320
+ protocol: "http",
3321
+ url: "",
3322
+ socketId: null,
3323
+ connected: false,
3324
+ handshake: false,
3325
+ pendingDelegations: 0,
3326
+ pendingTimers: 0,
3327
+ reconnectAttempts: 0,
3328
+ connectErrors: 0,
3329
+ reconnectErrors: 0,
3330
+ socketErrors: 0,
3331
+ errorCount: 0,
3332
+ destroyed: false,
3333
+ lastHandshakeAt: null,
3334
+ lastHandshakeError: null,
3335
+ lastDisconnectAt: null,
3336
+ updatedAt: 0
3337
+ };
3302
3338
  this.socketServerActor = CadenzaService.createActor(
3303
3339
  {
3304
3340
  name: "SocketServerActor",
@@ -3307,9 +3343,7 @@ var SocketController = class _SocketController {
3307
3343
  keyResolver: (input) => this.resolveSocketServerKey(input),
3308
3344
  loadPolicy: "lazy",
3309
3345
  writeContract: "overwrite",
3310
- initState: this.createInitialSocketServerSessionState(
3311
- this.socketServerDefaultKey
3312
- )
3346
+ initState: this.socketServerInitialSessionState
3313
3347
  },
3314
3348
  { isMeta: true }
3315
3349
  );
@@ -3321,7 +3355,7 @@ var SocketController = class _SocketController {
3321
3355
  keyResolver: (input) => this.resolveSocketClientFetchId(input),
3322
3356
  loadPolicy: "lazy",
3323
3357
  writeContract: "overwrite",
3324
- initState: this.createInitialSocketClientSessionState()
3358
+ initState: this.socketClientInitialSessionState
3325
3359
  },
3326
3360
  { isMeta: true }
3327
3361
  );
@@ -4402,48 +4436,6 @@ var SocketController = class _SocketController {
4402
4436
  "Connects to a specified socket server and wires runtime tasks."
4403
4437
  ).doOn("meta.fetch.handshake_complete").emitsOnFail("meta.socket_client.connect_failed");
4404
4438
  }
4405
- createInitialSocketServerSessionState(serverKey) {
4406
- return {
4407
- serverKey,
4408
- useSocket: false,
4409
- status: "inactive",
4410
- securityProfile: "medium",
4411
- networkType: "internal",
4412
- connectionCount: 0,
4413
- lastStartedAt: null,
4414
- lastConnectedAt: null,
4415
- lastDisconnectedAt: null,
4416
- lastShutdownAt: null,
4417
- updatedAt: 0
4418
- };
4419
- }
4420
- createInitialSocketClientSessionState() {
4421
- return {
4422
- fetchId: "",
4423
- serviceInstanceId: "",
4424
- communicationTypes: [],
4425
- serviceName: "",
4426
- serviceAddress: "",
4427
- servicePort: 0,
4428
- protocol: "http",
4429
- url: "",
4430
- socketId: null,
4431
- connected: false,
4432
- handshake: false,
4433
- pendingDelegations: 0,
4434
- pendingTimers: 0,
4435
- reconnectAttempts: 0,
4436
- connectErrors: 0,
4437
- reconnectErrors: 0,
4438
- socketErrors: 0,
4439
- errorCount: 0,
4440
- destroyed: false,
4441
- lastHandshakeAt: null,
4442
- lastHandshakeError: null,
4443
- lastDisconnectAt: null,
4444
- updatedAt: 0
4445
- };
4446
- }
4447
4439
  resolveSocketServerKey(input) {
4448
4440
  return String(input.serverKey ?? input.__socketServerKey ?? this.socketServerDefaultKey).trim() || this.socketServerDefaultKey;
4449
4441
  }
@@ -4776,6 +4768,7 @@ var SignalController = class _SignalController {
4776
4768
  };
4777
4769
 
4778
4770
  // src/graph/controllers/GraphMetadataController.ts
4771
+ import { META_ACTOR_SESSION_STATE_PERSIST_INTENT } from "@cadenza.io/core";
4779
4772
  var GraphMetadataController = class _GraphMetadataController {
4780
4773
  static get instance() {
4781
4774
  if (!this._instance) this._instance = new _GraphMetadataController();
@@ -4993,6 +4986,139 @@ var GraphMetadataController = class _GraphMetadataController {
4993
4986
  "Handles task execution relationship creation",
4994
4987
  { concurrency: 100, isSubMeta: true }
4995
4988
  ).doOn("meta.node.mapped", "meta.node.detected_previous_task_execution").emits("global.meta.graph_metadata.relationship_executed");
4989
+ CadenzaService.createMetaTask("Handle actor creation", (ctx) => {
4990
+ return {
4991
+ data: {
4992
+ ...ctx.data,
4993
+ service_name: CadenzaService.serviceRegistry.serviceName
4994
+ }
4995
+ };
4996
+ }).doOn("meta.actor.created").emits("global.meta.graph_metadata.actor_created");
4997
+ CadenzaService.createMetaTask("Handle actor task association", (ctx) => {
4998
+ return {
4999
+ data: {
5000
+ ...ctx.data,
5001
+ service_name: CadenzaService.serviceRegistry.serviceName
5002
+ }
5003
+ };
5004
+ }).doOn("meta.actor.task_associated").emits("global.meta.graph_metadata.actor_task_associated");
5005
+ const actorSessionStateInsertTask = CadenzaService.get("dbInsertActorSessionState") ?? CadenzaService.get("Insert actor_session_state in CadenzaDB") ?? CadenzaService.createCadenzaDBInsertTask(
5006
+ "actor_session_state",
5007
+ {},
5008
+ { concurrency: 100, isSubMeta: true }
5009
+ );
5010
+ const validateActorSessionStatePersistenceTask = CadenzaService.createMetaTask(
5011
+ "Validate actor session state persistence",
5012
+ (ctx) => {
5013
+ if (ctx.errored || ctx.failed || ctx.__success !== true) {
5014
+ throw new Error(
5015
+ String(
5016
+ ctx.__error ?? ctx.error ?? "actor_session_state persistence query failed"
5017
+ )
5018
+ );
5019
+ }
5020
+ const rowCount = Number(ctx.rowCount ?? 0);
5021
+ if (!Number.isFinite(rowCount) || rowCount <= 0) {
5022
+ throw new Error(
5023
+ "actor_session_state persistence did not affect any rows (possible stale durable_version)"
5024
+ );
5025
+ }
5026
+ return {
5027
+ __success: true,
5028
+ persisted: true,
5029
+ actor_name: ctx.actor_name,
5030
+ actor_version: ctx.actor_version,
5031
+ actor_key: ctx.actor_key,
5032
+ service_name: ctx.service_name,
5033
+ durable_version: ctx.durable_version
5034
+ };
5035
+ },
5036
+ "Enforces strict actor session persistence success contract.",
5037
+ { isSubMeta: true, concurrency: 100 }
5038
+ );
5039
+ const insertAndValidateActorSessionStateTask = actorSessionStateInsertTask.then(
5040
+ validateActorSessionStatePersistenceTask
5041
+ );
5042
+ CadenzaService.createMetaTask(
5043
+ "Persist actor session state",
5044
+ (ctx) => {
5045
+ const actorName = typeof ctx.actor_name === "string" ? ctx.actor_name.trim() : "";
5046
+ const actorKey = typeof ctx.actor_key === "string" ? ctx.actor_key.trim() : "";
5047
+ const actorVersion = Number(ctx.actor_version ?? 1);
5048
+ const durableVersion = Number(ctx.durable_version);
5049
+ if (!actorName) {
5050
+ throw new Error("actor_name is required for actor session persistence");
5051
+ }
5052
+ if (!actorKey) {
5053
+ throw new Error("actor_key is required for actor session persistence");
5054
+ }
5055
+ if (!Number.isInteger(actorVersion) || actorVersion < 1) {
5056
+ throw new Error("actor_version must be a positive integer");
5057
+ }
5058
+ if (!Number.isInteger(durableVersion) || durableVersion < 0) {
5059
+ throw new Error("durable_version must be a non-negative integer");
5060
+ }
5061
+ if (typeof ctx.durable_state !== "object" || ctx.durable_state === null || Array.isArray(ctx.durable_state)) {
5062
+ throw new Error("durable_state must be a non-null object");
5063
+ }
5064
+ const serviceName = CadenzaService.serviceRegistry.serviceName;
5065
+ if (!serviceName) {
5066
+ throw new Error("service_name is not available for actor session persistence");
5067
+ }
5068
+ let expiresAt = null;
5069
+ if (ctx.expires_at !== void 0 && ctx.expires_at !== null) {
5070
+ if (ctx.expires_at instanceof Date) {
5071
+ expiresAt = ctx.expires_at.toISOString();
5072
+ } else if (typeof ctx.expires_at === "string" && ctx.expires_at.trim().length > 0) {
5073
+ expiresAt = ctx.expires_at;
5074
+ } else {
5075
+ throw new Error("expires_at must be null, Date, or non-empty string");
5076
+ }
5077
+ }
5078
+ const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
5079
+ return {
5080
+ ...ctx,
5081
+ actor_name: actorName,
5082
+ actor_key: actorKey,
5083
+ actor_version: actorVersion,
5084
+ durable_version: durableVersion,
5085
+ expires_at: expiresAt,
5086
+ service_name: serviceName,
5087
+ queryData: {
5088
+ data: {
5089
+ actor_name: actorName,
5090
+ actor_version: actorVersion,
5091
+ actor_key: actorKey,
5092
+ service_name: serviceName,
5093
+ durable_state: ctx.durable_state,
5094
+ durable_version: durableVersion,
5095
+ expires_at: expiresAt,
5096
+ updated: updatedAt
5097
+ },
5098
+ onConflict: {
5099
+ target: [
5100
+ "actor_name",
5101
+ "actor_version",
5102
+ "actor_key",
5103
+ "service_name"
5104
+ ],
5105
+ action: {
5106
+ do: "update",
5107
+ set: {
5108
+ durable_state: "excluded",
5109
+ durable_version: "excluded",
5110
+ expires_at: "excluded",
5111
+ updated: "excluded"
5112
+ },
5113
+ where: "actor_session_state.durable_version <= excluded.durable_version"
5114
+ }
5115
+ }
5116
+ }
5117
+ };
5118
+ },
5119
+ "Validates and prepares actor_session_state payload for strict write-through persistence.",
5120
+ { isSubMeta: true, concurrency: 100 }
5121
+ ).then(insertAndValidateActorSessionStateTask).respondsTo(META_ACTOR_SESSION_STATE_PERSIST_INTENT);
4996
5122
  CadenzaService.createMetaTask("Handle Intent Creation", (ctx) => {
4997
5123
  const intentName = ctx.data?.name;
4998
5124
  return {
@@ -6664,8 +6790,69 @@ function tableFieldTypeToSchemaType(type) {
6664
6790
  import { v4 as uuid3 } from "uuid";
6665
6791
 
6666
6792
  // src/graph/controllers/GraphSyncController.ts
6793
+ var ACTOR_TASK_METADATA = /* @__PURE__ */ Symbol.for("@cadenza.io/core/actor-task-meta");
6794
+ function getActorTaskRuntimeMetadata(taskFunction) {
6795
+ if (typeof taskFunction !== "function") {
6796
+ return void 0;
6797
+ }
6798
+ return taskFunction[ACTOR_TASK_METADATA];
6799
+ }
6800
+ function sanitizeActorMetadataValue(value) {
6801
+ if (value === null) {
6802
+ return null;
6803
+ }
6804
+ if (value === void 0 || typeof value === "function") {
6805
+ return void 0;
6806
+ }
6807
+ if (Array.isArray(value)) {
6808
+ const items = [];
6809
+ for (const item of value) {
6810
+ const sanitizedItem = sanitizeActorMetadataValue(item);
6811
+ if (sanitizedItem !== void 0) {
6812
+ items.push(sanitizedItem);
6813
+ }
6814
+ }
6815
+ return items;
6816
+ }
6817
+ if (typeof value === "object") {
6818
+ const output = {};
6819
+ for (const [key, nestedValue] of Object.entries(value)) {
6820
+ const sanitizedNestedValue = sanitizeActorMetadataValue(nestedValue);
6821
+ if (sanitizedNestedValue !== void 0) {
6822
+ output[key] = sanitizedNestedValue;
6823
+ }
6824
+ }
6825
+ return output;
6826
+ }
6827
+ return value;
6828
+ }
6829
+ function buildActorRegistrationData(actor) {
6830
+ const definition = sanitizeActorMetadataValue(
6831
+ typeof actor?.toDefinition === "function" ? actor.toDefinition() : {}
6832
+ );
6833
+ const stateDefinition = definition?.state && typeof definition.state === "object" ? definition.state : {};
6834
+ const actorKind = typeof definition?.kind === "string" ? definition.kind : actor?.kind;
6835
+ return {
6836
+ name: definition?.name ?? actor?.spec?.name ?? "",
6837
+ description: definition?.description ?? actor?.spec?.description ?? "",
6838
+ default_key: definition?.defaultKey ?? actor?.spec?.defaultKey ?? "default",
6839
+ load_policy: definition?.loadPolicy ?? actor?.spec?.loadPolicy ?? "eager",
6840
+ write_contract: definition?.writeContract ?? actor?.spec?.writeContract ?? "overwrite",
6841
+ runtime_read_guard: definition?.runtimeReadGuard ?? actor?.spec?.runtimeReadGuard ?? "none",
6842
+ consistency_profile: definition?.consistencyProfile ?? actor?.spec?.consistencyProfile ?? null,
6843
+ key_definition: definition?.key ?? null,
6844
+ state_definition: stateDefinition,
6845
+ retry_policy: definition?.retry ?? {},
6846
+ idempotency_policy: definition?.idempotency ?? {},
6847
+ session_policy: definition?.session ?? {},
6848
+ is_meta: actorKind === "meta",
6849
+ version: 1
6850
+ };
6851
+ }
6667
6852
  var GraphSyncController = class _GraphSyncController {
6668
6853
  constructor() {
6854
+ this.registeredActors = /* @__PURE__ */ new Set();
6855
+ this.registeredActorTaskMaps = /* @__PURE__ */ new Set();
6669
6856
  this.isCadenzaDBReady = false;
6670
6857
  }
6671
6858
  static get instance() {
@@ -6923,6 +7110,120 @@ var GraphSyncController = class _GraphSyncController {
6923
7110
  )
6924
7111
  )
6925
7112
  );
7113
+ this.splitActorsForRegistration = CadenzaService.createMetaTask(
7114
+ "Split actors for registration",
7115
+ function* (ctx) {
7116
+ CadenzaService.debounce("meta.sync_controller.synced_resource", {
7117
+ delayMs: 3e3
7118
+ });
7119
+ const actors = ctx.actors ?? [];
7120
+ for (const actor of actors) {
7121
+ const data = {
7122
+ ...buildActorRegistrationData(actor),
7123
+ service_name: CadenzaService.serviceRegistry.serviceName
7124
+ };
7125
+ if (!data.name) {
7126
+ continue;
7127
+ }
7128
+ const registrationKey = `${data.name}|${data.version}|${data.service_name}`;
7129
+ if (this.registeredActors.has(registrationKey)) {
7130
+ continue;
7131
+ }
7132
+ yield {
7133
+ data,
7134
+ __actorRegistrationKey: registrationKey
7135
+ };
7136
+ }
7137
+ }.bind(this)
7138
+ ).then(
7139
+ (this.isCadenzaDBReady ? CadenzaService.createCadenzaDBInsertTask(
7140
+ "actor",
7141
+ {
7142
+ onConflict: {
7143
+ target: ["name", "service_name", "version"],
7144
+ action: {
7145
+ do: "nothing"
7146
+ }
7147
+ }
7148
+ },
7149
+ { concurrency: 30 }
7150
+ ) : CadenzaService.get("dbInsertActor"))?.then(
7151
+ CadenzaService.createMetaTask("Record actor registration", (ctx) => {
7152
+ if (!ctx.__syncing) {
7153
+ return;
7154
+ }
7155
+ CadenzaService.debounce("meta.sync_controller.synced_resource", {
7156
+ delayMs: 3e3
7157
+ });
7158
+ this.registeredActors.add(ctx.__actorRegistrationKey);
7159
+ return true;
7160
+ }).then(
7161
+ CadenzaService.createUniqueMetaTask(
7162
+ "Gather actor registration",
7163
+ () => true
7164
+ ).emits("meta.sync_controller.synced_actors")
7165
+ )
7166
+ )
7167
+ );
7168
+ this.registerActorTaskMapTask = CadenzaService.createMetaTask(
7169
+ "Split actor task maps",
7170
+ function* (ctx) {
7171
+ const task = ctx.task;
7172
+ if (task.hidden || !task.register) {
7173
+ return;
7174
+ }
7175
+ const metadata = getActorTaskRuntimeMetadata(task.taskFunction);
7176
+ if (!metadata?.actorName) {
7177
+ return;
7178
+ }
7179
+ const registrationKey = `${metadata.actorName}|${task.name}|${task.version}|${CadenzaService.serviceRegistry.serviceName}`;
7180
+ if (this.registeredActorTaskMaps.has(registrationKey)) {
7181
+ return;
7182
+ }
7183
+ yield {
7184
+ data: {
7185
+ actor_name: metadata.actorName,
7186
+ actor_version: 1,
7187
+ task_name: task.name,
7188
+ task_version: task.version,
7189
+ service_name: CadenzaService.serviceRegistry.serviceName,
7190
+ mode: metadata.mode,
7191
+ description: task.description ?? metadata.actorDescription ?? "",
7192
+ is_meta: metadata.actorKind === "meta" || task.isMeta === true
7193
+ },
7194
+ __actorTaskMapRegistrationKey: registrationKey
7195
+ };
7196
+ }.bind(this)
7197
+ ).then(
7198
+ (this.isCadenzaDBReady ? CadenzaService.createCadenzaDBInsertTask(
7199
+ "actor_task_map",
7200
+ {
7201
+ onConflict: {
7202
+ target: [
7203
+ "actor_name",
7204
+ "actor_version",
7205
+ "task_name",
7206
+ "task_version",
7207
+ "service_name"
7208
+ ],
7209
+ action: {
7210
+ do: "nothing"
7211
+ }
7212
+ }
7213
+ },
7214
+ { concurrency: 30 }
7215
+ ) : CadenzaService.get("dbInsertActorTaskMap"))?.then(
7216
+ CadenzaService.createMetaTask("Record actor task map registration", (ctx) => {
7217
+ if (!ctx.__syncing) {
7218
+ return;
7219
+ }
7220
+ CadenzaService.debounce("meta.sync_controller.synced_resource", {
7221
+ delayMs: 3e3
7222
+ });
7223
+ this.registeredActorTaskMaps.add(ctx.__actorTaskMapRegistrationKey);
7224
+ })
7225
+ )
7226
+ );
6926
7227
  const registerSignalTask = CadenzaService.createMetaTask(
6927
7228
  "Record signal registration",
6928
7229
  (ctx) => {
@@ -7164,12 +7465,19 @@ var GraphSyncController = class _GraphSyncController {
7164
7465
  ).then(this.splitSignalsTask);
7165
7466
  CadenzaService.registry.getAllTasks.clone().doOn("meta.sync_controller.synced_signals").then(this.splitTasksForRegistration);
7166
7467
  CadenzaService.registry.getAllRoutines.clone().doOn("meta.sync_controller.synced_tasks").then(this.splitRoutinesTask);
7468
+ CadenzaService.createMetaTask("Get all actors", (ctx) => {
7469
+ return {
7470
+ ...ctx,
7471
+ actors: CadenzaService.getAllActors()
7472
+ };
7473
+ }).doOn("meta.sync_controller.synced_tasks").then(this.splitActorsForRegistration);
7167
7474
  CadenzaService.registry.doForEachTask.clone().doOn("meta.sync_controller.synced_tasks").then(
7168
7475
  this.registerTaskMapTask,
7169
7476
  this.registerSignalToTaskMapTask,
7170
7477
  this.registerIntentToTaskMapTask,
7171
7478
  this.registerDeputyRelationshipTask
7172
7479
  );
7480
+ CadenzaService.registry.doForEachTask.clone().doOn("meta.sync_controller.synced_tasks", "meta.sync_controller.synced_actors").then(this.registerActorTaskMapTask);
7173
7481
  CadenzaService.registry.getAllRoutines.clone().doOn("meta.sync_controller.synced_routines").then(this.splitTasksInRoutines);
7174
7482
  CadenzaService.createMetaTask("Finish sync", (ctx, emit) => {
7175
7483
  emit("global.meta.sync_controller.synced", {
@@ -7556,6 +7864,14 @@ var CadenzaService = class {
7556
7864
  static get(taskName) {
7557
7865
  return Cadenza.get(taskName);
7558
7866
  }
7867
+ static getActor(actorName) {
7868
+ const cadenzaWithActors = Cadenza;
7869
+ return cadenzaWithActors.getActor?.(actorName);
7870
+ }
7871
+ static getAllActors() {
7872
+ const cadenzaWithActors = Cadenza;
7873
+ return cadenzaWithActors.getAllActors?.() ?? [];
7874
+ }
7559
7875
  static getRoutine(routineName) {
7560
7876
  return Cadenza.getRoutine(routineName);
7561
7877
  }
@@ -8123,7 +8439,7 @@ var CadenzaService = class {
8123
8439
  }
8124
8440
  static createActor(spec, options = {}) {
8125
8441
  this.bootstrap();
8126
- return new Actor(spec, options);
8442
+ return Cadenza.createActor(spec, options);
8127
8443
  }
8128
8444
  static createActorFromDefinition(definition, options = {}) {
8129
8445
  this.bootstrap();