@cadenza.io/service 2.12.0 → 2.15.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.js CHANGED
@@ -5244,6 +5244,9 @@ function normalizeIntentToken(value) {
5244
5244
  }
5245
5245
  return normalized;
5246
5246
  }
5247
+ function buildPostgresActorName(name) {
5248
+ return `${String(name ?? "").trim()}PostgresActor`;
5249
+ }
5247
5250
  function validateIntentName(intentName) {
5248
5251
  if (!intentName || typeof intentName !== "string") {
5249
5252
  throw new Error("Intent name must be a non-empty string");
@@ -5381,7 +5384,8 @@ function resolveDataRows(data) {
5381
5384
  }
5382
5385
  var DatabaseController = class _DatabaseController {
5383
5386
  constructor() {
5384
- this.registrationsByService = /* @__PURE__ */ new Map();
5387
+ this.registrationsByActorName = /* @__PURE__ */ new Map();
5388
+ this.registrationsByActorToken = /* @__PURE__ */ new Map();
5385
5389
  this.adminDbClient = new import_pg.Pool({
5386
5390
  connectionString: process.env.DATABASE_ADDRESS ?? "",
5387
5391
  database: "postgres",
@@ -5392,15 +5396,11 @@ var DatabaseController = class _DatabaseController {
5392
5396
  CadenzaService.createMetaTask(
5393
5397
  "Route PostgresActor setup requests",
5394
5398
  (ctx) => {
5395
- const serviceName = String(ctx.options?.serviceName ?? ctx.serviceName ?? "");
5396
- if (!serviceName) {
5397
- return ctx;
5398
- }
5399
- const registration = this.registrationsByService.get(serviceName);
5399
+ const registration = this.resolveRegistration(ctx);
5400
5400
  if (!registration) {
5401
5401
  return ctx;
5402
5402
  }
5403
- CadenzaService.emit(`meta.postgres_actor.setup_requested.${registration.actorToken}`, ctx);
5403
+ this.requestPostgresActorSetup(registration, ctx);
5404
5404
  return ctx;
5405
5405
  },
5406
5406
  "Routes generic database init requests to actor-scoped setup signal.",
@@ -5412,23 +5412,25 @@ var DatabaseController = class _DatabaseController {
5412
5412
  return this._instance;
5413
5413
  }
5414
5414
  reset() {
5415
- for (const registration of this.registrationsByService.values()) {
5415
+ for (const registration of this.registrationsByActorName.values()) {
5416
5416
  const runtimeState = registration.actor.getRuntimeState(registration.actorKey);
5417
5417
  if (runtimeState?.pool) {
5418
5418
  runtimeState.pool.end().catch(() => void 0);
5419
5419
  }
5420
5420
  }
5421
- this.registrationsByService.clear();
5421
+ this.registrationsByActorName.clear();
5422
+ this.registrationsByActorToken.clear();
5422
5423
  this.adminDbClient.end().catch(() => void 0);
5423
5424
  }
5424
- createPostgresActor(serviceName, schema, options) {
5425
- const existing = this.registrationsByService.get(serviceName);
5425
+ createPostgresActor(name, schema, description, options) {
5426
+ const actorName = buildPostgresActorName(name);
5427
+ const existing = this.registrationsByActorName.get(actorName);
5426
5428
  if (existing) {
5427
5429
  return existing;
5428
5430
  }
5429
- const actorName = `${serviceName}PostgresActor`;
5430
5431
  const actorToken = normalizeIntentToken(actorName);
5431
- const actorKey = String(options.databaseName ?? (0, import_lodash_es.snakeCase)(serviceName));
5432
+ const actorKey = String(options.databaseName ?? (0, import_lodash_es.snakeCase)(name));
5433
+ const ownerServiceName = options.ownerServiceName ?? CadenzaService.serviceRegistry?.serviceName ?? null;
5432
5434
  const optionTimeout = typeof options.timeoutMs === "number" ? Number(options.timeoutMs) : Number(options.timeout);
5433
5435
  const safetyPolicy = {
5434
5436
  statementTimeoutMs: normalizePositiveInteger(
@@ -5446,7 +5448,7 @@ var DatabaseController = class _DatabaseController {
5446
5448
  const actor = CadenzaService.createActor(
5447
5449
  {
5448
5450
  name: actorName,
5449
- description: "Specialized PostgresActor owning pool runtime state and schema-driven DB task generation.",
5451
+ description: description || "Specialized PostgresActor owning pool runtime state and schema-driven DB task generation.",
5450
5452
  defaultKey: actorKey,
5451
5453
  keyResolver: (input) => typeof input.databaseName === "string" ? input.databaseName : void 0,
5452
5454
  loadPolicy: "eager",
@@ -5454,7 +5456,7 @@ var DatabaseController = class _DatabaseController {
5454
5456
  initState: {
5455
5457
  actorName,
5456
5458
  actorToken,
5457
- serviceName,
5459
+ ownerServiceName,
5458
5460
  databaseName: actorKey,
5459
5461
  status: "idle",
5460
5462
  schemaVersion: Number(schema.version ?? 1),
@@ -5469,23 +5471,99 @@ var DatabaseController = class _DatabaseController {
5469
5471
  { isMeta: Boolean(options.isMeta) }
5470
5472
  );
5471
5473
  const registration = {
5472
- serviceName,
5474
+ ownerServiceName,
5473
5475
  databaseName: actorKey,
5474
5476
  actorName,
5475
5477
  actorToken,
5476
5478
  actorKey,
5479
+ setupSignal: `meta.postgres_actor.setup_requested.${actorToken}`,
5480
+ setupDoneSignal: `meta.postgres_actor.setup_done.${actorToken}`,
5481
+ setupFailedSignal: `meta.postgres_actor.setup_failed.${actorToken}`,
5477
5482
  actor,
5478
5483
  schema,
5484
+ description,
5479
5485
  options,
5480
5486
  tasksGenerated: false,
5481
5487
  intentNames: /* @__PURE__ */ new Set()
5482
5488
  };
5483
- this.registrationsByService.set(serviceName, registration);
5489
+ this.registrationsByActorName.set(actorName, registration);
5490
+ this.registrationsByActorToken.set(actorToken, registration);
5484
5491
  this.registerSetupTask(registration);
5485
5492
  return registration;
5486
5493
  }
5494
+ requestPostgresActorSetup(registrationOrName, ctx = {}) {
5495
+ const registration = typeof registrationOrName === "string" ? this.resolveRegistration({
5496
+ actorName: registrationOrName
5497
+ }) : registrationOrName;
5498
+ if (!registration) {
5499
+ return void 0;
5500
+ }
5501
+ const payload = {
5502
+ ...ctx,
5503
+ actorName: registration.actorName,
5504
+ actorToken: registration.actorToken,
5505
+ databaseName: registration.databaseName,
5506
+ ownerServiceName: registration.ownerServiceName,
5507
+ options: {
5508
+ ...ctx.options ?? {},
5509
+ actorName: registration.actorName,
5510
+ actorToken: registration.actorToken,
5511
+ ownerServiceName: registration.ownerServiceName,
5512
+ databaseName: registration.databaseName
5513
+ }
5514
+ };
5515
+ const runtimeState = registration.actor.getRuntimeState(registration.actorKey);
5516
+ if (runtimeState?.ready) {
5517
+ this.emitSetupDone(registration, payload);
5518
+ return registration;
5519
+ }
5520
+ CadenzaService.emit(registration.setupSignal, payload);
5521
+ return registration;
5522
+ }
5523
+ resolveRegistration(ctx) {
5524
+ const rawActorToken = String(
5525
+ ctx.options?.actorToken ?? ctx.actorToken ?? ""
5526
+ ).trim();
5527
+ if (rawActorToken) {
5528
+ const actorToken = normalizeIntentToken(rawActorToken);
5529
+ const registration = this.registrationsByActorToken.get(actorToken);
5530
+ if (registration) {
5531
+ return registration;
5532
+ }
5533
+ }
5534
+ const rawActorName = String(
5535
+ ctx.options?.actorName ?? ctx.actorName ?? ctx.options?.postgresActorName ?? ctx.postgresActorName ?? ""
5536
+ ).trim();
5537
+ if (rawActorName) {
5538
+ const registration = this.registrationsByActorName.get(rawActorName) ?? this.registrationsByActorName.get(buildPostgresActorName(rawActorName));
5539
+ if (registration) {
5540
+ return registration;
5541
+ }
5542
+ }
5543
+ const legacyServiceName = String(
5544
+ ctx.options?.serviceName ?? ctx.serviceName ?? ""
5545
+ ).trim();
5546
+ if (legacyServiceName) {
5547
+ return this.registrationsByActorName.get(
5548
+ buildPostgresActorName(legacyServiceName)
5549
+ );
5550
+ }
5551
+ return void 0;
5552
+ }
5553
+ emitSetupDone(registration, payload) {
5554
+ const resolvedPayload = {
5555
+ ...payload,
5556
+ actorName: registration.actorName,
5557
+ actorToken: registration.actorToken,
5558
+ databaseName: registration.databaseName,
5559
+ ownerServiceName: registration.ownerServiceName,
5560
+ __success: true
5561
+ };
5562
+ CadenzaService.emit(registration.setupDoneSignal, resolvedPayload);
5563
+ CadenzaService.emit("meta.postgres_actor.setup_done", resolvedPayload);
5564
+ CadenzaService.emit("meta.database.setup_done", resolvedPayload);
5565
+ }
5487
5566
  registerSetupTask(registration) {
5488
- const setupSignal = `meta.postgres_actor.setup_requested.${registration.actorToken}`;
5489
5567
  CadenzaService.createMetaTask(
5490
5568
  `Setup ${registration.actorName}`,
5491
5569
  registration.actor.task(
@@ -5545,17 +5623,15 @@ var DatabaseController = class _DatabaseController {
5545
5623
  lastError: null,
5546
5624
  tables: Object.keys(registration.schema.tables ?? {})
5547
5625
  });
5548
- emit("meta.database.setup_done", {
5549
- serviceName: registration.serviceName,
5550
- databaseName: registration.databaseName,
5551
- actorName: registration.actorName,
5552
- __success: true
5626
+ this.emitSetupDone(registration, {
5627
+ ...input
5553
5628
  });
5554
5629
  return {
5555
5630
  ...input,
5556
5631
  __success: true,
5557
5632
  actorName: registration.actorName,
5558
- databaseName: registration.databaseName
5633
+ databaseName: registration.databaseName,
5634
+ ownerServiceName: registration.ownerServiceName
5559
5635
  };
5560
5636
  } catch (error) {
5561
5637
  const message = errorMessage(error);
@@ -5579,7 +5655,11 @@ var DatabaseController = class _DatabaseController {
5579
5655
  ),
5580
5656
  "Initializes PostgresActor runtime pool, applies schema, and generates CRUD tasks/intents.",
5581
5657
  { isMeta: true }
5582
- ).doOn(setupSignal);
5658
+ ).doOn(registration.setupSignal).emitsOnFail(
5659
+ registration.setupFailedSignal,
5660
+ "meta.postgres_actor.setup_failed",
5661
+ "meta.database.setup_failed"
5662
+ );
5583
5663
  }
5584
5664
  createTargetPool(databaseName, statementTimeoutMs) {
5585
5665
  const connectionString = this.buildDatabaseConnectionString(databaseName);
@@ -8603,87 +8683,52 @@ var CadenzaService = class {
8603
8683
  this.createCadenzaService(serviceName, description, options);
8604
8684
  }
8605
8685
  /**
8606
- * Creates and initializes a PostgresActor-backed database service.
8607
- * This is the canonical API for schema-driven postgres setup in cadenza-service.
8686
+ * Creates and initializes a specialized PostgresActor.
8687
+ * This is actor-only and does not create or register a network service.
8608
8688
  *
8609
- * @param {string} name - Logical actor/service name.
8689
+ * @param {string} name - Logical PostgresActor name.
8610
8690
  * @param {DatabaseSchemaDefinition} schema - Database schema definition.
8611
- * @param {string} [description=""] - Optional human-readable description.
8612
- * @param {ServerOptions & DatabaseOptions} [options={}] - Server/database runtime options.
8691
+ * @param {string} [description=""] - Optional human-readable actor description.
8692
+ * @param {ServerOptions & DatabaseOptions} [options={}] - Actor/database runtime options.
8613
8693
  * @return {void}
8614
8694
  */
8615
8695
  static createPostgresActor(name, schema, description = "", options = {}) {
8616
8696
  if (isBrowser) {
8617
8697
  console.warn(
8618
- "Database service creation is not supported in the browser. Use the CadenzaDB service instead."
8698
+ "PostgresActor creation is not supported in the browser."
8619
8699
  );
8620
8700
  return;
8621
8701
  }
8622
- if (this.serviceCreated) return;
8623
8702
  this.bootstrap();
8624
- this.serviceRegistry.serviceName = name;
8703
+ this.validateName(name);
8625
8704
  const databaseController = DatabaseController.instance;
8626
- options = {
8627
- loadBalance: true,
8628
- useSocket: true,
8629
- displayName: void 0,
8630
- isMeta: false,
8631
- port: parseInt(process.env.HTTP_PORT ?? "3000"),
8632
- securityProfile: process.env.SECURITY_PROFILE ?? "medium",
8633
- networkMode: process.env.NETWORK_MODE ?? "dev",
8634
- retryCount: 3,
8635
- cadenzaDB: {
8636
- connect: true,
8637
- address: process.env.CADENZA_DB_ADDRESS ?? "localhost",
8638
- port: parseInt(process.env.CADENZA_DB_PORT ?? "5000")
8639
- },
8640
- databaseType: "postgres",
8641
- databaseName: (0, import_lodash_es2.snakeCase)(name),
8642
- poolSize: parseInt(process.env.DATABASE_POOL_SIZE ?? "10"),
8643
- isDatabase: true,
8644
- ...options
8645
- };
8705
+ const normalizedOptions = this.normalizePostgresActorOptions(name, options);
8646
8706
  const registration = databaseController.createPostgresActor(
8647
8707
  name,
8648
8708
  schema,
8649
- options
8709
+ description,
8710
+ normalizedOptions
8650
8711
  );
8651
8712
  console.log("Creating PostgresActor", {
8652
- serviceName: name,
8713
+ name,
8653
8714
  actorName: registration.actorName,
8654
- options
8715
+ ownerServiceName: normalizedOptions.ownerServiceName ?? null,
8716
+ options: normalizedOptions
8655
8717
  });
8656
- this.emit("meta.database_init_requested", {
8657
- schema,
8658
- databaseName: options.databaseName,
8659
- options
8718
+ databaseController.requestPostgresActorSetup(registration, {
8719
+ actorName: registration.actorName,
8720
+ actorToken: registration.actorToken,
8721
+ databaseName: normalizedOptions.databaseName,
8722
+ ownerServiceName: normalizedOptions.ownerServiceName ?? null
8660
8723
  });
8661
- this.createMetaTask("Set database connection", () => {
8662
- this.createMetaTask("Insert database service bridge", (_, emit) => {
8663
- emit("global.meta.created_database_service", {
8664
- data: {
8665
- service_name: name,
8666
- description,
8667
- schema,
8668
- is_meta: options.isMeta
8669
- }
8670
- });
8671
- this.log("Database service created", {
8672
- name,
8673
- isMeta: options.isMeta,
8674
- actorName: registration.actorName
8675
- });
8676
- }).doOn("meta.service_registry.service_inserted");
8677
- this.createCadenzaService(name, description, options);
8678
- }).doOn("meta.database.setup_done");
8679
8724
  }
8680
8725
  /**
8681
- * Creates a meta PostgresActor service.
8726
+ * Creates a meta PostgresActor.
8682
8727
  *
8683
- * @param {string} name - Logical actor/service name.
8728
+ * @param {string} name - Logical PostgresActor name.
8684
8729
  * @param {DatabaseSchemaDefinition} schema - Database schema definition.
8685
8730
  * @param {string} [description=""] - Optional description.
8686
- * @param {ServerOptions & DatabaseOptions} [options={}] - Optional server/database options.
8731
+ * @param {ServerOptions & DatabaseOptions} [options={}] - Optional actor/database options.
8687
8732
  * @return {void}
8688
8733
  */
8689
8734
  static createMetaPostgresActor(name, schema, description = "", options = {}) {
@@ -8692,10 +8737,84 @@ var CadenzaService = class {
8692
8737
  this.createPostgresActor(name, schema, description, options);
8693
8738
  }
8694
8739
  /**
8695
- * Legacy compatibility wrapper. Prefer {@link createPostgresActor}.
8740
+ * Creates a dedicated database service by composing a PostgresActor and a Cadenza service.
8696
8741
  */
8697
8742
  static createDatabaseService(name, schema, description = "", options = {}) {
8698
- this.createPostgresActor(name, schema, description, options);
8743
+ if (isBrowser) {
8744
+ console.warn(
8745
+ "Database service creation is not supported in the browser. Use the CadenzaDB service instead."
8746
+ );
8747
+ return;
8748
+ }
8749
+ if (this.serviceCreated) return;
8750
+ this.bootstrap();
8751
+ this.validateName(name);
8752
+ this.validateServiceName(name);
8753
+ const databaseController = DatabaseController.instance;
8754
+ const actorOptions = this.normalizePostgresActorOptions(name, {
8755
+ ...options,
8756
+ ownerServiceName: options.ownerServiceName ?? name
8757
+ });
8758
+ const serviceOptions = this.normalizeDatabaseServiceOptions(name, {
8759
+ ...options,
8760
+ ownerServiceName: actorOptions.ownerServiceName
8761
+ });
8762
+ const registration = databaseController.createPostgresActor(
8763
+ name,
8764
+ schema,
8765
+ description,
8766
+ actorOptions
8767
+ );
8768
+ this.registerDatabaseServiceBridgeTask(
8769
+ name,
8770
+ description,
8771
+ schema,
8772
+ Boolean(serviceOptions.isMeta),
8773
+ registration.actorName
8774
+ );
8775
+ const createServiceTaskName = `Create database service ${name} after ${registration.actorName} setup`;
8776
+ if (!this.get(createServiceTaskName)) {
8777
+ this.createMetaTask(
8778
+ createServiceTaskName,
8779
+ () => {
8780
+ this.createCadenzaService(name, description, serviceOptions);
8781
+ return true;
8782
+ },
8783
+ "Creates the networked database service after PostgresActor setup completes."
8784
+ ).doOn(registration.setupDoneSignal);
8785
+ }
8786
+ const setupFailureTaskName = `Handle database service ${name} bootstrap failure`;
8787
+ if (!this.get(setupFailureTaskName)) {
8788
+ this.createMetaTask(
8789
+ setupFailureTaskName,
8790
+ (ctx) => {
8791
+ this.log(
8792
+ "Database service bootstrap failed before service creation.",
8793
+ {
8794
+ serviceName: name,
8795
+ actorName: registration.actorName,
8796
+ databaseName: registration.databaseName,
8797
+ error: ctx.__error
8798
+ },
8799
+ "error"
8800
+ );
8801
+ return true;
8802
+ },
8803
+ "Logs PostgresActor setup failures for database service bootstrap."
8804
+ ).doOn(registration.setupFailedSignal);
8805
+ }
8806
+ console.log("Creating database service wrapper", {
8807
+ serviceName: name,
8808
+ actorName: registration.actorName,
8809
+ actorOptions,
8810
+ serviceOptions
8811
+ });
8812
+ databaseController.requestPostgresActorSetup(registration, {
8813
+ actorName: registration.actorName,
8814
+ actorToken: registration.actorToken,
8815
+ databaseName: actorOptions.databaseName,
8816
+ ownerServiceName: actorOptions.ownerServiceName ?? name
8817
+ });
8699
8818
  }
8700
8819
  /**
8701
8820
  * Creates a meta database service with the specified configuration.
@@ -8707,7 +8826,73 @@ var CadenzaService = class {
8707
8826
  * @return {void} - This method does not return a value.
8708
8827
  */
8709
8828
  static createMetaDatabaseService(name, schema, description = "", options = {}) {
8710
- this.createMetaPostgresActor(name, schema, description, options);
8829
+ this.createDatabaseService(name, schema, description, {
8830
+ ...options,
8831
+ isMeta: true
8832
+ });
8833
+ }
8834
+ static normalizePostgresActorOptions(name, options = {}) {
8835
+ return {
8836
+ isMeta: false,
8837
+ retryCount: 3,
8838
+ databaseType: "postgres",
8839
+ databaseName: (0, import_lodash_es2.snakeCase)(name),
8840
+ poolSize: parseInt(process.env.DATABASE_POOL_SIZE ?? "10"),
8841
+ ownerServiceName: options.ownerServiceName ?? this.serviceRegistry?.serviceName ?? null,
8842
+ ...options
8843
+ };
8844
+ }
8845
+ static normalizeDatabaseServiceOptions(name, options = {}) {
8846
+ return {
8847
+ loadBalance: true,
8848
+ useSocket: true,
8849
+ displayName: void 0,
8850
+ isMeta: false,
8851
+ port: parseInt(process.env.HTTP_PORT ?? "3000"),
8852
+ securityProfile: process.env.SECURITY_PROFILE ?? "medium",
8853
+ networkMode: process.env.NETWORK_MODE ?? "dev",
8854
+ retryCount: 3,
8855
+ cadenzaDB: {
8856
+ connect: true,
8857
+ address: process.env.CADENZA_DB_ADDRESS ?? "localhost",
8858
+ port: parseInt(process.env.CADENZA_DB_PORT ?? "5000")
8859
+ },
8860
+ databaseType: "postgres",
8861
+ databaseName: (0, import_lodash_es2.snakeCase)(name),
8862
+ poolSize: parseInt(process.env.DATABASE_POOL_SIZE ?? "10"),
8863
+ isDatabase: true,
8864
+ ownerServiceName: options.ownerServiceName ?? name,
8865
+ ...options
8866
+ };
8867
+ }
8868
+ static registerDatabaseServiceBridgeTask(serviceName, description, schema, isMeta, actorName) {
8869
+ const taskName = `Insert database service bridge ${serviceName}`;
8870
+ if (this.get(taskName)) {
8871
+ return;
8872
+ }
8873
+ this.createMetaTask(
8874
+ taskName,
8875
+ (ctx, emit) => {
8876
+ if (ctx.__serviceName && ctx.__serviceName !== serviceName) {
8877
+ return false;
8878
+ }
8879
+ emit("global.meta.created_database_service", {
8880
+ data: {
8881
+ service_name: serviceName,
8882
+ description,
8883
+ schema,
8884
+ is_meta: isMeta
8885
+ }
8886
+ });
8887
+ this.log("Database service created", {
8888
+ name: serviceName,
8889
+ isMeta,
8890
+ actorName
8891
+ });
8892
+ return true;
8893
+ },
8894
+ "Bridges database service creation into the global metadata signal."
8895
+ ).doOn("meta.service_registry.service_inserted");
8711
8896
  }
8712
8897
  static createActor(spec, options = {}) {
8713
8898
  this.bootstrap();
@@ -9060,14 +9245,14 @@ var CadenzaService = class {
9060
9245
  return import_core4.default.createEphemeralTask(name, func, description, options);
9061
9246
  }
9062
9247
  /**
9063
- * Creates an ephemeral meta task with the specified name, function, description, and options.
9248
+ * Creates an ephemeral meta-task with the specified name, function, description, and options.
9064
9249
  * See {@link createEphemeralTask} and {@link createMetaTask} for more details.
9065
9250
  *
9066
9251
  * @param {string} name - The name of the task to be created.
9067
9252
  * @param {TaskFunction} func - The function to be executed as part of the task.
9068
9253
  * @param {string} [description] - An optional description of the task.
9069
9254
  * @param {TaskOptions & EphemeralTaskOptions} [options={}] - Additional options for configuring the task.
9070
- * @return {EphemeralTask} The created ephemeral meta task.
9255
+ * @return {EphemeralTask} The created ephemeral meta-task.
9071
9256
  */
9072
9257
  static createEphemeralMetaTask(name, func, description, options = {}) {
9073
9258
  this.bootstrap();