@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.mjs CHANGED
@@ -5195,6 +5195,9 @@ function normalizeIntentToken(value) {
5195
5195
  }
5196
5196
  return normalized;
5197
5197
  }
5198
+ function buildPostgresActorName(name) {
5199
+ return `${String(name ?? "").trim()}PostgresActor`;
5200
+ }
5198
5201
  function validateIntentName(intentName) {
5199
5202
  if (!intentName || typeof intentName !== "string") {
5200
5203
  throw new Error("Intent name must be a non-empty string");
@@ -5332,7 +5335,8 @@ function resolveDataRows(data) {
5332
5335
  }
5333
5336
  var DatabaseController = class _DatabaseController {
5334
5337
  constructor() {
5335
- this.registrationsByService = /* @__PURE__ */ new Map();
5338
+ this.registrationsByActorName = /* @__PURE__ */ new Map();
5339
+ this.registrationsByActorToken = /* @__PURE__ */ new Map();
5336
5340
  this.adminDbClient = new Pool({
5337
5341
  connectionString: process.env.DATABASE_ADDRESS ?? "",
5338
5342
  database: "postgres",
@@ -5343,15 +5347,11 @@ var DatabaseController = class _DatabaseController {
5343
5347
  CadenzaService.createMetaTask(
5344
5348
  "Route PostgresActor setup requests",
5345
5349
  (ctx) => {
5346
- const serviceName = String(ctx.options?.serviceName ?? ctx.serviceName ?? "");
5347
- if (!serviceName) {
5348
- return ctx;
5349
- }
5350
- const registration = this.registrationsByService.get(serviceName);
5350
+ const registration = this.resolveRegistration(ctx);
5351
5351
  if (!registration) {
5352
5352
  return ctx;
5353
5353
  }
5354
- CadenzaService.emit(`meta.postgres_actor.setup_requested.${registration.actorToken}`, ctx);
5354
+ this.requestPostgresActorSetup(registration, ctx);
5355
5355
  return ctx;
5356
5356
  },
5357
5357
  "Routes generic database init requests to actor-scoped setup signal.",
@@ -5363,23 +5363,25 @@ var DatabaseController = class _DatabaseController {
5363
5363
  return this._instance;
5364
5364
  }
5365
5365
  reset() {
5366
- for (const registration of this.registrationsByService.values()) {
5366
+ for (const registration of this.registrationsByActorName.values()) {
5367
5367
  const runtimeState = registration.actor.getRuntimeState(registration.actorKey);
5368
5368
  if (runtimeState?.pool) {
5369
5369
  runtimeState.pool.end().catch(() => void 0);
5370
5370
  }
5371
5371
  }
5372
- this.registrationsByService.clear();
5372
+ this.registrationsByActorName.clear();
5373
+ this.registrationsByActorToken.clear();
5373
5374
  this.adminDbClient.end().catch(() => void 0);
5374
5375
  }
5375
- createPostgresActor(serviceName, schema, options) {
5376
- const existing = this.registrationsByService.get(serviceName);
5376
+ createPostgresActor(name, schema, description, options) {
5377
+ const actorName = buildPostgresActorName(name);
5378
+ const existing = this.registrationsByActorName.get(actorName);
5377
5379
  if (existing) {
5378
5380
  return existing;
5379
5381
  }
5380
- const actorName = `${serviceName}PostgresActor`;
5381
5382
  const actorToken = normalizeIntentToken(actorName);
5382
- const actorKey = String(options.databaseName ?? snakeCase(serviceName));
5383
+ const actorKey = String(options.databaseName ?? snakeCase(name));
5384
+ const ownerServiceName = options.ownerServiceName ?? CadenzaService.serviceRegistry?.serviceName ?? null;
5383
5385
  const optionTimeout = typeof options.timeoutMs === "number" ? Number(options.timeoutMs) : Number(options.timeout);
5384
5386
  const safetyPolicy = {
5385
5387
  statementTimeoutMs: normalizePositiveInteger(
@@ -5397,7 +5399,7 @@ var DatabaseController = class _DatabaseController {
5397
5399
  const actor = CadenzaService.createActor(
5398
5400
  {
5399
5401
  name: actorName,
5400
- description: "Specialized PostgresActor owning pool runtime state and schema-driven DB task generation.",
5402
+ description: description || "Specialized PostgresActor owning pool runtime state and schema-driven DB task generation.",
5401
5403
  defaultKey: actorKey,
5402
5404
  keyResolver: (input) => typeof input.databaseName === "string" ? input.databaseName : void 0,
5403
5405
  loadPolicy: "eager",
@@ -5405,7 +5407,7 @@ var DatabaseController = class _DatabaseController {
5405
5407
  initState: {
5406
5408
  actorName,
5407
5409
  actorToken,
5408
- serviceName,
5410
+ ownerServiceName,
5409
5411
  databaseName: actorKey,
5410
5412
  status: "idle",
5411
5413
  schemaVersion: Number(schema.version ?? 1),
@@ -5420,23 +5422,99 @@ var DatabaseController = class _DatabaseController {
5420
5422
  { isMeta: Boolean(options.isMeta) }
5421
5423
  );
5422
5424
  const registration = {
5423
- serviceName,
5425
+ ownerServiceName,
5424
5426
  databaseName: actorKey,
5425
5427
  actorName,
5426
5428
  actorToken,
5427
5429
  actorKey,
5430
+ setupSignal: `meta.postgres_actor.setup_requested.${actorToken}`,
5431
+ setupDoneSignal: `meta.postgres_actor.setup_done.${actorToken}`,
5432
+ setupFailedSignal: `meta.postgres_actor.setup_failed.${actorToken}`,
5428
5433
  actor,
5429
5434
  schema,
5435
+ description,
5430
5436
  options,
5431
5437
  tasksGenerated: false,
5432
5438
  intentNames: /* @__PURE__ */ new Set()
5433
5439
  };
5434
- this.registrationsByService.set(serviceName, registration);
5440
+ this.registrationsByActorName.set(actorName, registration);
5441
+ this.registrationsByActorToken.set(actorToken, registration);
5435
5442
  this.registerSetupTask(registration);
5436
5443
  return registration;
5437
5444
  }
5445
+ requestPostgresActorSetup(registrationOrName, ctx = {}) {
5446
+ const registration = typeof registrationOrName === "string" ? this.resolveRegistration({
5447
+ actorName: registrationOrName
5448
+ }) : registrationOrName;
5449
+ if (!registration) {
5450
+ return void 0;
5451
+ }
5452
+ const payload = {
5453
+ ...ctx,
5454
+ actorName: registration.actorName,
5455
+ actorToken: registration.actorToken,
5456
+ databaseName: registration.databaseName,
5457
+ ownerServiceName: registration.ownerServiceName,
5458
+ options: {
5459
+ ...ctx.options ?? {},
5460
+ actorName: registration.actorName,
5461
+ actorToken: registration.actorToken,
5462
+ ownerServiceName: registration.ownerServiceName,
5463
+ databaseName: registration.databaseName
5464
+ }
5465
+ };
5466
+ const runtimeState = registration.actor.getRuntimeState(registration.actorKey);
5467
+ if (runtimeState?.ready) {
5468
+ this.emitSetupDone(registration, payload);
5469
+ return registration;
5470
+ }
5471
+ CadenzaService.emit(registration.setupSignal, payload);
5472
+ return registration;
5473
+ }
5474
+ resolveRegistration(ctx) {
5475
+ const rawActorToken = String(
5476
+ ctx.options?.actorToken ?? ctx.actorToken ?? ""
5477
+ ).trim();
5478
+ if (rawActorToken) {
5479
+ const actorToken = normalizeIntentToken(rawActorToken);
5480
+ const registration = this.registrationsByActorToken.get(actorToken);
5481
+ if (registration) {
5482
+ return registration;
5483
+ }
5484
+ }
5485
+ const rawActorName = String(
5486
+ ctx.options?.actorName ?? ctx.actorName ?? ctx.options?.postgresActorName ?? ctx.postgresActorName ?? ""
5487
+ ).trim();
5488
+ if (rawActorName) {
5489
+ const registration = this.registrationsByActorName.get(rawActorName) ?? this.registrationsByActorName.get(buildPostgresActorName(rawActorName));
5490
+ if (registration) {
5491
+ return registration;
5492
+ }
5493
+ }
5494
+ const legacyServiceName = String(
5495
+ ctx.options?.serviceName ?? ctx.serviceName ?? ""
5496
+ ).trim();
5497
+ if (legacyServiceName) {
5498
+ return this.registrationsByActorName.get(
5499
+ buildPostgresActorName(legacyServiceName)
5500
+ );
5501
+ }
5502
+ return void 0;
5503
+ }
5504
+ emitSetupDone(registration, payload) {
5505
+ const resolvedPayload = {
5506
+ ...payload,
5507
+ actorName: registration.actorName,
5508
+ actorToken: registration.actorToken,
5509
+ databaseName: registration.databaseName,
5510
+ ownerServiceName: registration.ownerServiceName,
5511
+ __success: true
5512
+ };
5513
+ CadenzaService.emit(registration.setupDoneSignal, resolvedPayload);
5514
+ CadenzaService.emit("meta.postgres_actor.setup_done", resolvedPayload);
5515
+ CadenzaService.emit("meta.database.setup_done", resolvedPayload);
5516
+ }
5438
5517
  registerSetupTask(registration) {
5439
- const setupSignal = `meta.postgres_actor.setup_requested.${registration.actorToken}`;
5440
5518
  CadenzaService.createMetaTask(
5441
5519
  `Setup ${registration.actorName}`,
5442
5520
  registration.actor.task(
@@ -5496,17 +5574,15 @@ var DatabaseController = class _DatabaseController {
5496
5574
  lastError: null,
5497
5575
  tables: Object.keys(registration.schema.tables ?? {})
5498
5576
  });
5499
- emit("meta.database.setup_done", {
5500
- serviceName: registration.serviceName,
5501
- databaseName: registration.databaseName,
5502
- actorName: registration.actorName,
5503
- __success: true
5577
+ this.emitSetupDone(registration, {
5578
+ ...input
5504
5579
  });
5505
5580
  return {
5506
5581
  ...input,
5507
5582
  __success: true,
5508
5583
  actorName: registration.actorName,
5509
- databaseName: registration.databaseName
5584
+ databaseName: registration.databaseName,
5585
+ ownerServiceName: registration.ownerServiceName
5510
5586
  };
5511
5587
  } catch (error) {
5512
5588
  const message = errorMessage(error);
@@ -5530,7 +5606,11 @@ var DatabaseController = class _DatabaseController {
5530
5606
  ),
5531
5607
  "Initializes PostgresActor runtime pool, applies schema, and generates CRUD tasks/intents.",
5532
5608
  { isMeta: true }
5533
- ).doOn(setupSignal);
5609
+ ).doOn(registration.setupSignal).emitsOnFail(
5610
+ registration.setupFailedSignal,
5611
+ "meta.postgres_actor.setup_failed",
5612
+ "meta.database.setup_failed"
5613
+ );
5534
5614
  }
5535
5615
  createTargetPool(databaseName, statementTimeoutMs) {
5536
5616
  const connectionString = this.buildDatabaseConnectionString(databaseName);
@@ -8554,87 +8634,52 @@ var CadenzaService = class {
8554
8634
  this.createCadenzaService(serviceName, description, options);
8555
8635
  }
8556
8636
  /**
8557
- * Creates and initializes a PostgresActor-backed database service.
8558
- * This is the canonical API for schema-driven postgres setup in cadenza-service.
8637
+ * Creates and initializes a specialized PostgresActor.
8638
+ * This is actor-only and does not create or register a network service.
8559
8639
  *
8560
- * @param {string} name - Logical actor/service name.
8640
+ * @param {string} name - Logical PostgresActor name.
8561
8641
  * @param {DatabaseSchemaDefinition} schema - Database schema definition.
8562
- * @param {string} [description=""] - Optional human-readable description.
8563
- * @param {ServerOptions & DatabaseOptions} [options={}] - Server/database runtime options.
8642
+ * @param {string} [description=""] - Optional human-readable actor description.
8643
+ * @param {ServerOptions & DatabaseOptions} [options={}] - Actor/database runtime options.
8564
8644
  * @return {void}
8565
8645
  */
8566
8646
  static createPostgresActor(name, schema, description = "", options = {}) {
8567
8647
  if (isBrowser) {
8568
8648
  console.warn(
8569
- "Database service creation is not supported in the browser. Use the CadenzaDB service instead."
8649
+ "PostgresActor creation is not supported in the browser."
8570
8650
  );
8571
8651
  return;
8572
8652
  }
8573
- if (this.serviceCreated) return;
8574
8653
  this.bootstrap();
8575
- this.serviceRegistry.serviceName = name;
8654
+ this.validateName(name);
8576
8655
  const databaseController = DatabaseController.instance;
8577
- options = {
8578
- loadBalance: true,
8579
- useSocket: true,
8580
- displayName: void 0,
8581
- isMeta: false,
8582
- port: parseInt(process.env.HTTP_PORT ?? "3000"),
8583
- securityProfile: process.env.SECURITY_PROFILE ?? "medium",
8584
- networkMode: process.env.NETWORK_MODE ?? "dev",
8585
- retryCount: 3,
8586
- cadenzaDB: {
8587
- connect: true,
8588
- address: process.env.CADENZA_DB_ADDRESS ?? "localhost",
8589
- port: parseInt(process.env.CADENZA_DB_PORT ?? "5000")
8590
- },
8591
- databaseType: "postgres",
8592
- databaseName: snakeCase2(name),
8593
- poolSize: parseInt(process.env.DATABASE_POOL_SIZE ?? "10"),
8594
- isDatabase: true,
8595
- ...options
8596
- };
8656
+ const normalizedOptions = this.normalizePostgresActorOptions(name, options);
8597
8657
  const registration = databaseController.createPostgresActor(
8598
8658
  name,
8599
8659
  schema,
8600
- options
8660
+ description,
8661
+ normalizedOptions
8601
8662
  );
8602
8663
  console.log("Creating PostgresActor", {
8603
- serviceName: name,
8664
+ name,
8604
8665
  actorName: registration.actorName,
8605
- options
8666
+ ownerServiceName: normalizedOptions.ownerServiceName ?? null,
8667
+ options: normalizedOptions
8606
8668
  });
8607
- this.emit("meta.database_init_requested", {
8608
- schema,
8609
- databaseName: options.databaseName,
8610
- options
8669
+ databaseController.requestPostgresActorSetup(registration, {
8670
+ actorName: registration.actorName,
8671
+ actorToken: registration.actorToken,
8672
+ databaseName: normalizedOptions.databaseName,
8673
+ ownerServiceName: normalizedOptions.ownerServiceName ?? null
8611
8674
  });
8612
- this.createMetaTask("Set database connection", () => {
8613
- this.createMetaTask("Insert database service bridge", (_, emit) => {
8614
- emit("global.meta.created_database_service", {
8615
- data: {
8616
- service_name: name,
8617
- description,
8618
- schema,
8619
- is_meta: options.isMeta
8620
- }
8621
- });
8622
- this.log("Database service created", {
8623
- name,
8624
- isMeta: options.isMeta,
8625
- actorName: registration.actorName
8626
- });
8627
- }).doOn("meta.service_registry.service_inserted");
8628
- this.createCadenzaService(name, description, options);
8629
- }).doOn("meta.database.setup_done");
8630
8675
  }
8631
8676
  /**
8632
- * Creates a meta PostgresActor service.
8677
+ * Creates a meta PostgresActor.
8633
8678
  *
8634
- * @param {string} name - Logical actor/service name.
8679
+ * @param {string} name - Logical PostgresActor name.
8635
8680
  * @param {DatabaseSchemaDefinition} schema - Database schema definition.
8636
8681
  * @param {string} [description=""] - Optional description.
8637
- * @param {ServerOptions & DatabaseOptions} [options={}] - Optional server/database options.
8682
+ * @param {ServerOptions & DatabaseOptions} [options={}] - Optional actor/database options.
8638
8683
  * @return {void}
8639
8684
  */
8640
8685
  static createMetaPostgresActor(name, schema, description = "", options = {}) {
@@ -8643,10 +8688,84 @@ var CadenzaService = class {
8643
8688
  this.createPostgresActor(name, schema, description, options);
8644
8689
  }
8645
8690
  /**
8646
- * Legacy compatibility wrapper. Prefer {@link createPostgresActor}.
8691
+ * Creates a dedicated database service by composing a PostgresActor and a Cadenza service.
8647
8692
  */
8648
8693
  static createDatabaseService(name, schema, description = "", options = {}) {
8649
- this.createPostgresActor(name, schema, description, options);
8694
+ if (isBrowser) {
8695
+ console.warn(
8696
+ "Database service creation is not supported in the browser. Use the CadenzaDB service instead."
8697
+ );
8698
+ return;
8699
+ }
8700
+ if (this.serviceCreated) return;
8701
+ this.bootstrap();
8702
+ this.validateName(name);
8703
+ this.validateServiceName(name);
8704
+ const databaseController = DatabaseController.instance;
8705
+ const actorOptions = this.normalizePostgresActorOptions(name, {
8706
+ ...options,
8707
+ ownerServiceName: options.ownerServiceName ?? name
8708
+ });
8709
+ const serviceOptions = this.normalizeDatabaseServiceOptions(name, {
8710
+ ...options,
8711
+ ownerServiceName: actorOptions.ownerServiceName
8712
+ });
8713
+ const registration = databaseController.createPostgresActor(
8714
+ name,
8715
+ schema,
8716
+ description,
8717
+ actorOptions
8718
+ );
8719
+ this.registerDatabaseServiceBridgeTask(
8720
+ name,
8721
+ description,
8722
+ schema,
8723
+ Boolean(serviceOptions.isMeta),
8724
+ registration.actorName
8725
+ );
8726
+ const createServiceTaskName = `Create database service ${name} after ${registration.actorName} setup`;
8727
+ if (!this.get(createServiceTaskName)) {
8728
+ this.createMetaTask(
8729
+ createServiceTaskName,
8730
+ () => {
8731
+ this.createCadenzaService(name, description, serviceOptions);
8732
+ return true;
8733
+ },
8734
+ "Creates the networked database service after PostgresActor setup completes."
8735
+ ).doOn(registration.setupDoneSignal);
8736
+ }
8737
+ const setupFailureTaskName = `Handle database service ${name} bootstrap failure`;
8738
+ if (!this.get(setupFailureTaskName)) {
8739
+ this.createMetaTask(
8740
+ setupFailureTaskName,
8741
+ (ctx) => {
8742
+ this.log(
8743
+ "Database service bootstrap failed before service creation.",
8744
+ {
8745
+ serviceName: name,
8746
+ actorName: registration.actorName,
8747
+ databaseName: registration.databaseName,
8748
+ error: ctx.__error
8749
+ },
8750
+ "error"
8751
+ );
8752
+ return true;
8753
+ },
8754
+ "Logs PostgresActor setup failures for database service bootstrap."
8755
+ ).doOn(registration.setupFailedSignal);
8756
+ }
8757
+ console.log("Creating database service wrapper", {
8758
+ serviceName: name,
8759
+ actorName: registration.actorName,
8760
+ actorOptions,
8761
+ serviceOptions
8762
+ });
8763
+ databaseController.requestPostgresActorSetup(registration, {
8764
+ actorName: registration.actorName,
8765
+ actorToken: registration.actorToken,
8766
+ databaseName: actorOptions.databaseName,
8767
+ ownerServiceName: actorOptions.ownerServiceName ?? name
8768
+ });
8650
8769
  }
8651
8770
  /**
8652
8771
  * Creates a meta database service with the specified configuration.
@@ -8658,7 +8777,73 @@ var CadenzaService = class {
8658
8777
  * @return {void} - This method does not return a value.
8659
8778
  */
8660
8779
  static createMetaDatabaseService(name, schema, description = "", options = {}) {
8661
- this.createMetaPostgresActor(name, schema, description, options);
8780
+ this.createDatabaseService(name, schema, description, {
8781
+ ...options,
8782
+ isMeta: true
8783
+ });
8784
+ }
8785
+ static normalizePostgresActorOptions(name, options = {}) {
8786
+ return {
8787
+ isMeta: false,
8788
+ retryCount: 3,
8789
+ databaseType: "postgres",
8790
+ databaseName: snakeCase2(name),
8791
+ poolSize: parseInt(process.env.DATABASE_POOL_SIZE ?? "10"),
8792
+ ownerServiceName: options.ownerServiceName ?? this.serviceRegistry?.serviceName ?? null,
8793
+ ...options
8794
+ };
8795
+ }
8796
+ static normalizeDatabaseServiceOptions(name, options = {}) {
8797
+ return {
8798
+ loadBalance: true,
8799
+ useSocket: true,
8800
+ displayName: void 0,
8801
+ isMeta: false,
8802
+ port: parseInt(process.env.HTTP_PORT ?? "3000"),
8803
+ securityProfile: process.env.SECURITY_PROFILE ?? "medium",
8804
+ networkMode: process.env.NETWORK_MODE ?? "dev",
8805
+ retryCount: 3,
8806
+ cadenzaDB: {
8807
+ connect: true,
8808
+ address: process.env.CADENZA_DB_ADDRESS ?? "localhost",
8809
+ port: parseInt(process.env.CADENZA_DB_PORT ?? "5000")
8810
+ },
8811
+ databaseType: "postgres",
8812
+ databaseName: snakeCase2(name),
8813
+ poolSize: parseInt(process.env.DATABASE_POOL_SIZE ?? "10"),
8814
+ isDatabase: true,
8815
+ ownerServiceName: options.ownerServiceName ?? name,
8816
+ ...options
8817
+ };
8818
+ }
8819
+ static registerDatabaseServiceBridgeTask(serviceName, description, schema, isMeta, actorName) {
8820
+ const taskName = `Insert database service bridge ${serviceName}`;
8821
+ if (this.get(taskName)) {
8822
+ return;
8823
+ }
8824
+ this.createMetaTask(
8825
+ taskName,
8826
+ (ctx, emit) => {
8827
+ if (ctx.__serviceName && ctx.__serviceName !== serviceName) {
8828
+ return false;
8829
+ }
8830
+ emit("global.meta.created_database_service", {
8831
+ data: {
8832
+ service_name: serviceName,
8833
+ description,
8834
+ schema,
8835
+ is_meta: isMeta
8836
+ }
8837
+ });
8838
+ this.log("Database service created", {
8839
+ name: serviceName,
8840
+ isMeta,
8841
+ actorName
8842
+ });
8843
+ return true;
8844
+ },
8845
+ "Bridges database service creation into the global metadata signal."
8846
+ ).doOn("meta.service_registry.service_inserted");
8662
8847
  }
8663
8848
  static createActor(spec, options = {}) {
8664
8849
  this.bootstrap();
@@ -9011,14 +9196,14 @@ var CadenzaService = class {
9011
9196
  return Cadenza.createEphemeralTask(name, func, description, options);
9012
9197
  }
9013
9198
  /**
9014
- * Creates an ephemeral meta task with the specified name, function, description, and options.
9199
+ * Creates an ephemeral meta-task with the specified name, function, description, and options.
9015
9200
  * See {@link createEphemeralTask} and {@link createMetaTask} for more details.
9016
9201
  *
9017
9202
  * @param {string} name - The name of the task to be created.
9018
9203
  * @param {TaskFunction} func - The function to be executed as part of the task.
9019
9204
  * @param {string} [description] - An optional description of the task.
9020
9205
  * @param {TaskOptions & EphemeralTaskOptions} [options={}] - Additional options for configuring the task.
9021
- * @return {EphemeralTask} The created ephemeral meta task.
9206
+ * @return {EphemeralTask} The created ephemeral meta-task.
9022
9207
  */
9023
9208
  static createEphemeralMetaTask(name, func, description, options = {}) {
9024
9209
  this.bootstrap();