@cadenza.io/service 2.19.0 → 2.20.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
@@ -8549,6 +8549,8 @@ var ServiceRegistry = class _ServiceRegistry {
8549
8549
  }
8550
8550
  }
8551
8551
  }
8552
+ const hasExplicitSignalRoutingRows = signalToTaskMaps.length > 0;
8553
+ const hasExplicitIntentRoutingRows = intentToTaskMaps.length > 0;
8552
8554
  const latestManifestSnapshots = selectLatestServiceManifestSnapshots(manifestSnapshots);
8553
8555
  const explodedManifest = explodeServiceManifestSnapshots(
8554
8556
  latestManifestSnapshots
@@ -8629,26 +8631,30 @@ var ServiceRegistry = class _ServiceRegistry {
8629
8631
  row.task_version ?? 1
8630
8632
  ).trim()}`
8631
8633
  );
8632
- pushUnique(
8633
- explodedManifest.signalToTaskMaps,
8634
- signalToTaskMaps,
8635
- seenSignalMaps,
8636
- (row) => `${String(row.signal_name ?? "").trim()}|${String(
8637
- row.service_name ?? ""
8638
- ).trim()}|${String(row.task_name ?? "").trim()}|${String(
8639
- row.task_version ?? 1
8640
- ).trim()}`
8641
- );
8642
- pushUnique(
8643
- explodedManifest.intentToTaskMaps,
8644
- intentToTaskMaps,
8645
- seenIntentMaps,
8646
- (row) => `${String(row.intent_name ?? "").trim()}|${String(
8647
- row.service_name ?? ""
8648
- ).trim()}|${String(row.task_name ?? "").trim()}|${String(
8649
- row.task_version ?? 1
8650
- ).trim()}`
8651
- );
8634
+ if (!hasExplicitSignalRoutingRows) {
8635
+ pushUnique(
8636
+ explodedManifest.signalToTaskMaps,
8637
+ signalToTaskMaps,
8638
+ seenSignalMaps,
8639
+ (row) => `${String(row.signal_name ?? "").trim()}|${String(
8640
+ row.service_name ?? ""
8641
+ ).trim()}|${String(row.task_name ?? "").trim()}|${String(
8642
+ row.task_version ?? 1
8643
+ ).trim()}`
8644
+ );
8645
+ }
8646
+ if (!hasExplicitIntentRoutingRows) {
8647
+ pushUnique(
8648
+ explodedManifest.intentToTaskMaps,
8649
+ intentToTaskMaps,
8650
+ seenIntentMaps,
8651
+ (row) => `${String(row.intent_name ?? "").trim()}|${String(
8652
+ row.service_name ?? ""
8653
+ ).trim()}|${String(row.task_name ?? "").trim()}|${String(
8654
+ row.task_version ?? 1
8655
+ ).trim()}`
8656
+ );
8657
+ }
8652
8658
  return {
8653
8659
  serviceInstances,
8654
8660
  serviceInstanceTransports,
@@ -9251,16 +9257,35 @@ var ServiceRegistry = class _ServiceRegistry {
9251
9257
  const authorityFullSyncResponderTask = CadenzaService.createMetaTask(
9252
9258
  BOOTSTRAP_FULL_SYNC_RESPONDER_TASK_NAME,
9253
9259
  async (ctx) => {
9260
+ const queryOptionalAuthorityRoutingRows = async (tableName) => {
9261
+ try {
9262
+ return await DatabaseController.instance.queryAuthorityTableRows(
9263
+ tableName
9264
+ );
9265
+ } catch (error) {
9266
+ const message = error instanceof Error ? error.message : String(error);
9267
+ if (message.includes(
9268
+ `Table '${tableName}' is not registered on the CadenzaDB PostgresActor`
9269
+ )) {
9270
+ return [];
9271
+ }
9272
+ throw error;
9273
+ }
9274
+ };
9254
9275
  const [
9255
9276
  serviceInstances,
9256
9277
  serviceInstanceTransports,
9257
- serviceManifests
9278
+ serviceManifests,
9279
+ signalToTaskMaps,
9280
+ intentToTaskMaps
9258
9281
  ] = await Promise.all([
9259
9282
  DatabaseController.instance.queryAuthorityTableRows("service_instance"),
9260
9283
  DatabaseController.instance.queryAuthorityTableRows(
9261
9284
  "service_instance_transport"
9262
9285
  ),
9263
- DatabaseController.instance.queryAuthorityTableRows("service_manifest")
9286
+ DatabaseController.instance.queryAuthorityTableRows("service_manifest"),
9287
+ queryOptionalAuthorityRoutingRows("signal_to_task_map"),
9288
+ queryOptionalAuthorityRoutingRows("intent_to_task_map")
9264
9289
  ]);
9265
9290
  return {
9266
9291
  ...ctx,
@@ -9268,7 +9293,9 @@ var ServiceRegistry = class _ServiceRegistry {
9268
9293
  ...this.collectBootstrapFullSyncPayload({
9269
9294
  serviceInstances,
9270
9295
  serviceInstanceTransports,
9271
- serviceManifests
9296
+ serviceManifests,
9297
+ signalToTaskMaps,
9298
+ intentToTaskMaps
9272
9299
  })
9273
9300
  };
9274
9301
  },
@@ -15928,12 +15955,13 @@ var RuntimeValidationController = class _RuntimeValidationController {
15928
15955
  // src/graph/controllers/registerActorSessionPersistence.ts
15929
15956
  import { META_ACTOR_SESSION_STATE_PERSIST_INTENT } from "@cadenza.io/core";
15930
15957
  var ACTOR_SESSION_STATE_PERSIST_CONCURRENCY = 20;
15958
+ var META_ACTOR_SESSION_STATE_HYDRATE_INTENT = "meta-actor-session-state-hydrate";
15931
15959
  var ACTOR_SESSION_TRACE_ENABLED4 = process.env.CADENZA_ACTOR_SESSION_TRACE === "1" || process.env.CADENZA_ACTOR_SESSION_TRACE === "true";
15932
15960
  function shouldAssumeSuccessfulActorSessionRowCount(ctx) {
15933
15961
  return ctx.__success === true && ctx.rowCount === void 0 && ctx.__status === "success" && ctx.__serviceName === "CadenzaDB" && ctx.__localTaskName === "Insert actor_session_state in CadenzaDB";
15934
15962
  }
15935
15963
  function registerActorSessionPersistenceTasks() {
15936
- if (CadenzaService.get("Persist actor session state")) {
15964
+ if (CadenzaService.get("Persist actor session state") && CadenzaService.get("Hydrate actor session state")) {
15937
15965
  return;
15938
15966
  }
15939
15967
  const localActorSessionTaskOptions = {
@@ -15950,6 +15978,14 @@ function registerActorSessionPersistenceTasks() {
15950
15978
  isSubMeta: true
15951
15979
  }
15952
15980
  );
15981
+ const actorSessionStateQueryTask = CadenzaService.getLocalCadenzaDBQueryTask("actor_session_state") ?? CadenzaService.get("dbQueryActorSessionState") ?? CadenzaService.get("Query actor_session_state in CadenzaDB") ?? CadenzaService.createCadenzaDBQueryTask(
15982
+ "actor_session_state",
15983
+ {},
15984
+ {
15985
+ concurrency: ACTOR_SESSION_STATE_PERSIST_CONCURRENCY,
15986
+ isSubMeta: true
15987
+ }
15988
+ );
15953
15989
  const validateActorSessionStatePersistenceTask = CadenzaService.createMetaTask(
15954
15990
  "Validate actor session state persistence",
15955
15991
  (ctx) => {
@@ -15983,6 +16019,103 @@ function registerActorSessionPersistenceTasks() {
15983
16019
  const insertAndValidateActorSessionStateTask = actorSessionStateInsertTask.then(
15984
16020
  validateActorSessionStatePersistenceTask
15985
16021
  );
16022
+ const validateActorSessionStateHydrationTask = CadenzaService.createMetaTask(
16023
+ "Validate actor session state hydration",
16024
+ (ctx) => {
16025
+ if (ctx.errored || ctx.failed || ctx.__success !== true) {
16026
+ throw new Error(
16027
+ String(
16028
+ ctx.__error ?? ctx.error ?? "actor_session_state hydration query failed"
16029
+ )
16030
+ );
16031
+ }
16032
+ const row = ctx.actorSessionState && typeof ctx.actorSessionState === "object" && !Array.isArray(ctx.actorSessionState) ? ctx.actorSessionState : null;
16033
+ if (!row) {
16034
+ return {
16035
+ __success: true,
16036
+ hydrated: false
16037
+ };
16038
+ }
16039
+ const expiresAt = typeof row.expiresAt === "string" ? row.expiresAt : typeof row.expires_at === "string" ? row.expires_at : null;
16040
+ const expiresAtMs = expiresAt ? Date.parse(expiresAt) : Number.NaN;
16041
+ if (Number.isFinite(expiresAtMs) && expiresAtMs <= Date.now()) {
16042
+ return {
16043
+ __success: true,
16044
+ hydrated: false
16045
+ };
16046
+ }
16047
+ const durableState = row.durableState ?? row.durable_state ?? null;
16048
+ const durableVersion = Number(
16049
+ row.durableVersion ?? row.durable_version ?? Number.NaN
16050
+ );
16051
+ if (typeof durableState !== "object" || durableState === null || Array.isArray(durableState)) {
16052
+ throw new Error("actor_session_state durable_state must be a non-null object");
16053
+ }
16054
+ if (!Number.isInteger(durableVersion) || durableVersion < 0) {
16055
+ throw new Error(
16056
+ "actor_session_state durable_version must be a non-negative integer"
16057
+ );
16058
+ }
16059
+ return {
16060
+ __success: true,
16061
+ hydrated: true,
16062
+ actor_name: row.actorName ?? row.actor_name,
16063
+ actor_version: row.actorVersion ?? row.actor_version,
16064
+ actor_key: row.actorKey ?? row.actor_key,
16065
+ service_name: row.serviceName ?? row.service_name,
16066
+ durable_state: durableState,
16067
+ durable_version: durableVersion
16068
+ };
16069
+ },
16070
+ "Validates and normalizes hydrated actor_session_state rows.",
16071
+ localActorSessionTaskOptions
16072
+ );
16073
+ const queryAndValidateActorSessionStateTask = actorSessionStateQueryTask.then(
16074
+ validateActorSessionStateHydrationTask
16075
+ );
16076
+ CadenzaService.createMetaTask(
16077
+ "Hydrate actor session state",
16078
+ (ctx) => {
16079
+ const actorName = typeof ctx.actor_name === "string" ? ctx.actor_name.trim() : "";
16080
+ const actorKey = typeof ctx.actor_key === "string" ? ctx.actor_key.trim() : "";
16081
+ const actorVersion = Number(ctx.actor_version ?? 1);
16082
+ const serviceName = CadenzaService.serviceRegistry.serviceName;
16083
+ if (!actorName) {
16084
+ throw new Error("actor_name is required for actor session hydration");
16085
+ }
16086
+ if (!actorKey) {
16087
+ throw new Error("actor_key is required for actor session hydration");
16088
+ }
16089
+ if (!Number.isInteger(actorVersion) || actorVersion < 1) {
16090
+ throw new Error("actor_version must be a positive integer");
16091
+ }
16092
+ if (!serviceName) {
16093
+ throw new Error("service_name is not available for actor session hydration");
16094
+ }
16095
+ return {
16096
+ ...ctx,
16097
+ actor_name: actorName,
16098
+ actor_key: actorKey,
16099
+ actor_version: actorVersion,
16100
+ service_name: serviceName,
16101
+ queryData: {
16102
+ filter: {
16103
+ actor_name: actorName,
16104
+ actor_version: actorVersion,
16105
+ actor_key: actorKey,
16106
+ service_name: serviceName,
16107
+ deleted: false
16108
+ },
16109
+ queryMode: "one",
16110
+ sort: {
16111
+ updated: "desc"
16112
+ }
16113
+ }
16114
+ };
16115
+ },
16116
+ "Builds a one-row actor_session_state lookup for lazy actor hydration.",
16117
+ localActorSessionTaskOptions
16118
+ ).then(queryAndValidateActorSessionStateTask).respondsTo(META_ACTOR_SESSION_STATE_HYDRATE_INTENT);
15986
16119
  CadenzaService.createMetaTask(
15987
16120
  "Persist actor session state",
15988
16121
  (ctx) => {
@@ -20065,6 +20198,10 @@ function resolveInquiryFailureError(inquiry, value, depth = 3, seen = /* @__PURE
20065
20198
  }
20066
20199
  return `Inquiry '${inquiry}' did not complete successfully`;
20067
20200
  }
20201
+ function normalizePositiveInteger2(value, fallback) {
20202
+ const normalized = Number(value);
20203
+ return Number.isInteger(normalized) && normalized > 0 ? normalized : fallback;
20204
+ }
20068
20205
  var DEFAULT_DEPUTY_TASK_CONCURRENCY = 50;
20069
20206
  var DEFAULT_DEPUTY_TASK_TIMEOUT_MS = 12e4;
20070
20207
  var DEFAULT_DATABASE_PROXY_TASK_CONCURRENCY = 50;
@@ -21898,11 +22035,84 @@ var CadenzaService = class {
21898
22035
  }
21899
22036
  static createActor(spec, options = {}) {
21900
22037
  this.bootstrap();
21901
- return Cadenza.createActor(spec, options);
22038
+ return Cadenza.createActor(
22039
+ spec,
22040
+ this.withActorSessionHydration(
22041
+ spec,
22042
+ options
22043
+ )
22044
+ );
21902
22045
  }
21903
22046
  static createActorFromDefinition(definition, options = {}) {
21904
22047
  this.bootstrap();
21905
- return Cadenza.createActorFromDefinition(definition, options);
22048
+ return Cadenza.createActorFromDefinition(
22049
+ definition,
22050
+ this.withActorSessionHydration(
22051
+ {
22052
+ name: definition.name,
22053
+ description: definition.description,
22054
+ defaultKey: definition.defaultKey,
22055
+ kind: definition.kind,
22056
+ loadPolicy: definition.loadPolicy,
22057
+ writeContract: definition.writeContract,
22058
+ consistencyProfile: definition.consistencyProfile,
22059
+ retry: definition.retry,
22060
+ idempotency: definition.idempotency,
22061
+ session: definition.session,
22062
+ runtimeReadGuard: definition.runtimeReadGuard,
22063
+ key: definition.key,
22064
+ state: definition.state,
22065
+ taskBindings: definition.tasks,
22066
+ initState: definition.state?.durable?.initState ?? definition.state?.durable?.initialState
22067
+ },
22068
+ options
22069
+ )
22070
+ );
22071
+ }
22072
+ static withActorSessionHydration(spec, options) {
22073
+ if (options.hydrateDurableState || spec.session?.persistDurableState !== true) {
22074
+ return options;
22075
+ }
22076
+ const actorName = String(spec.name ?? "").trim();
22077
+ const actorVersion = 1;
22078
+ const timeoutMs = normalizePositiveInteger2(
22079
+ spec.session?.persistenceTimeoutMs,
22080
+ 5e3
22081
+ );
22082
+ return {
22083
+ ...options,
22084
+ hydrateDurableState: async (actorKey) => {
22085
+ registerActorSessionPersistenceTasks();
22086
+ const response = await Cadenza.inquire(
22087
+ META_ACTOR_SESSION_STATE_HYDRATE_INTENT,
22088
+ {
22089
+ actor_name: actorName,
22090
+ actor_version: actorVersion,
22091
+ actor_key: actorKey
22092
+ },
22093
+ {
22094
+ timeout: timeoutMs,
22095
+ requireComplete: true,
22096
+ rejectOnTimeout: true
22097
+ }
22098
+ );
22099
+ if (!response || typeof response !== "object" || response.__success !== true) {
22100
+ throw new Error(
22101
+ resolveInquiryFailureError(
22102
+ META_ACTOR_SESSION_STATE_HYDRATE_INTENT,
22103
+ response
22104
+ )
22105
+ );
22106
+ }
22107
+ if (response.hydrated !== true) {
22108
+ return null;
22109
+ }
22110
+ return {
22111
+ durableState: response.durable_state,
22112
+ durableVersion: Number(response.durable_version)
22113
+ };
22114
+ }
22115
+ };
21906
22116
  }
21907
22117
  /**
21908
22118
  * Creates and registers a new task with the provided name, function, and optional details.