@solidxai/core 0.1.11-beta.8 → 0.1.11

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.
Files changed (98) hide show
  1. package/CHANGELOG.md +456 -0
  2. package/dist/controllers/datasource-introspection.controller.d.ts +8 -0
  3. package/dist/controllers/datasource-introspection.controller.d.ts.map +1 -1
  4. package/dist/controllers/media.controller.js +0 -2
  5. package/dist/controllers/media.controller.js.map +1 -1
  6. package/dist/helpers/module-metadata-helper.service.js +1 -1
  7. package/dist/helpers/module-metadata-helper.service.js.map +1 -1
  8. package/dist/helpers/solid-registry.d.ts +1 -2
  9. package/dist/helpers/solid-registry.d.ts.map +1 -1
  10. package/dist/helpers/solid-registry.js.map +1 -1
  11. package/dist/helpers/typeorm-db-helper.d.ts +1 -0
  12. package/dist/helpers/typeorm-db-helper.d.ts.map +1 -1
  13. package/dist/helpers/typeorm-db-helper.js +12 -0
  14. package/dist/helpers/typeorm-db-helper.js.map +1 -1
  15. package/dist/index.d.ts +0 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +0 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/interfaces.d.ts +1 -0
  20. package/dist/interfaces.d.ts.map +1 -1
  21. package/dist/interfaces.js.map +1 -1
  22. package/dist/seeders/seed-data/solid-core-metadata.json +62 -33
  23. package/dist/services/authentication.service.d.ts +2 -0
  24. package/dist/services/authentication.service.d.ts.map +1 -1
  25. package/dist/services/authentication.service.js +32 -11
  26. package/dist/services/authentication.service.js.map +1 -1
  27. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
  28. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +5 -6
  29. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
  30. package/dist/services/crud-helper.service.d.ts.map +1 -1
  31. package/dist/services/crud-helper.service.js +32 -12
  32. package/dist/services/crud-helper.service.js.map +1 -1
  33. package/dist/services/datasource-introspection.service.d.ts +10 -0
  34. package/dist/services/datasource-introspection.service.d.ts.map +1 -1
  35. package/dist/services/datasource-introspection.service.js +109 -17
  36. package/dist/services/datasource-introspection.service.js.map +1 -1
  37. package/dist/services/menu-item-metadata.service.d.ts.map +1 -1
  38. package/dist/services/menu-item-metadata.service.js +1 -0
  39. package/dist/services/menu-item-metadata.service.js.map +1 -1
  40. package/dist/services/model-metadata.service.d.ts +2 -0
  41. package/dist/services/model-metadata.service.d.ts.map +1 -1
  42. package/dist/services/model-metadata.service.js +49 -15
  43. package/dist/services/model-metadata.service.js.map +1 -1
  44. package/dist/services/module-metadata.service.d.ts.map +1 -1
  45. package/dist/services/module-metadata.service.js +0 -27
  46. package/dist/services/module-metadata.service.js.map +1 -1
  47. package/dist/services/settings/default-settings-provider.service.d.ts +212 -0
  48. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  49. package/dist/services/settings/default-settings-provider.service.js +106 -0
  50. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  51. package/dist/services/solid-ts-morph.service.d.ts +6 -0
  52. package/dist/services/solid-ts-morph.service.d.ts.map +1 -1
  53. package/dist/services/solid-ts-morph.service.js +43 -0
  54. package/dist/services/solid-ts-morph.service.js.map +1 -1
  55. package/dist/subscribers/audit.subscriber.d.ts +0 -1
  56. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  57. package/dist/subscribers/audit.subscriber.js +1 -10
  58. package/dist/subscribers/audit.subscriber.js.map +1 -1
  59. package/dist/subscribers/computed-entity-field.subscriber.d.ts +1 -1
  60. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  61. package/dist/subscribers/computed-entity-field.subscriber.js +11 -13
  62. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  63. package/dist/subscribers/created-by-updated-by.subscriber.d.ts.map +1 -1
  64. package/dist/subscribers/created-by-updated-by.subscriber.js.map +1 -1
  65. package/dist/subscribers/field-metadata.subscriber.d.ts.map +1 -1
  66. package/dist/subscribers/field-metadata.subscriber.js.map +1 -1
  67. package/dist/subscribers/scheduled-job.subscriber.js +1 -1
  68. package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
  69. package/dist/subscribers/security-rule.subscriber.js +1 -1
  70. package/dist/subscribers/security-rule.subscriber.js.map +1 -1
  71. package/package.json +1 -1
  72. package/src/controllers/media.controller.ts +1 -1
  73. package/src/helpers/module-metadata-helper.service.ts +1 -1
  74. package/src/helpers/solid-registry.ts +1 -7
  75. package/src/helpers/typeorm-db-helper.ts +15 -0
  76. package/src/index.ts +0 -1
  77. package/src/interfaces.ts +1 -0
  78. package/src/seeders/seed-data/solid-core-metadata.json +62 -33
  79. package/src/services/authentication.service.ts +46 -12
  80. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +5 -10
  81. package/src/services/crud-helper.service.ts +32 -12
  82. package/src/services/datasource-introspection.service.ts +176 -16
  83. package/src/services/menu-item-metadata.service.ts +2 -1
  84. package/src/services/model-metadata.service.ts +63 -21
  85. package/src/services/module-metadata.service.ts +0 -35
  86. package/src/services/settings/default-settings-provider.service.ts +106 -0
  87. package/src/services/solid-ts-morph.service.ts +61 -1
  88. package/src/subscribers/audit.subscriber.ts +1 -12
  89. package/src/subscribers/computed-entity-field.subscriber.ts +23 -29
  90. package/src/subscribers/created-by-updated-by.subscriber.ts +0 -3
  91. package/src/subscribers/field-metadata.subscriber.ts +0 -3
  92. package/src/subscribers/scheduled-job.subscriber.ts +1 -1
  93. package/src/subscribers/security-rule.subscriber.ts +1 -1
  94. package/dist/helpers/nodemon-heartbeat.d.ts +0 -5
  95. package/dist/helpers/nodemon-heartbeat.d.ts.map +0 -1
  96. package/dist/helpers/nodemon-heartbeat.js +0 -67
  97. package/dist/helpers/nodemon-heartbeat.js.map +0 -1
  98. package/src/helpers/nodemon-heartbeat.ts +0 -59
@@ -2,7 +2,7 @@
2
2
  import { Injectable, Logger } from "@nestjs/common";
3
3
  import { join, dirname, normalize, isAbsolute, basename } from "node:path";
4
4
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
- import { Project, Node, ObjectLiteralExpression, ArrayLiteralExpression, QuoteKind, IndentationText } from "ts-morph";
5
+ import { Project, Node, ObjectLiteralExpression, ArrayLiteralExpression, QuoteKind, IndentationText, SyntaxKind } from "ts-morph";
6
6
  import { MethodDeclarationStructure, StructureKind } from "ts-morph";
7
7
 
8
8
  type Bucket = "imports" | "providers" | "exports";
@@ -468,6 +468,66 @@ export class SolidTsMorphService {
468
468
  return { staged: true, overwritten: false, skipped: false };
469
469
  }
470
470
 
471
+ cleanupTypeormDatasourceEntity(
472
+ filePath: string,
473
+ entityImportPath: string,
474
+ entityClassName: string,
475
+ ): { staged: boolean; skipped: boolean; removedImport: boolean; removedEntity: boolean } {
476
+ const abs = this.resolveRepoPath(filePath);
477
+ if (!existsSync(abs)) {
478
+ this.logger.warn(`cleanupTypeormDatasourceEntity: file not found at ${filePath}, skipping.`);
479
+ return { staged: false, skipped: true, removedImport: false, removedEntity: false };
480
+ }
481
+
482
+ const existing = this.project.getSourceFile(abs);
483
+ const sourceFile = existing
484
+ ? existing
485
+ : this.project.createSourceFile(abs, readFileSync(abs, "utf8"), { overwrite: true });
486
+
487
+ let removedImport = false;
488
+ let removedEntity = false;
489
+
490
+ const importDeclaration = sourceFile.getImportDeclarations().find((declaration) =>
491
+ declaration.getModuleSpecifierValue().replace(/\\/g, "/") === entityImportPath.replace(/\\/g, "/"),
492
+ );
493
+
494
+ if (importDeclaration) {
495
+ const namedImport = importDeclaration.getNamedImports().find((named) => named.getName() === entityClassName);
496
+ if (namedImport) {
497
+ namedImport.remove();
498
+ removedImport = true;
499
+ }
500
+
501
+ if (
502
+ importDeclaration.getNamedImports().length === 0 &&
503
+ !importDeclaration.getDefaultImport() &&
504
+ !importDeclaration.getNamespaceImport()
505
+ ) {
506
+ importDeclaration.remove();
507
+ }
508
+ }
509
+
510
+ const entitiesDeclaration = sourceFile.getVariableDeclaration("entities");
511
+ const entitiesArray = entitiesDeclaration?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression);
512
+ if (entitiesArray) {
513
+ const elements = entitiesArray.getElements();
514
+ for (let i = elements.length - 1; i >= 0; i--) {
515
+ if (elements[i].getText().replace(/\s+/g, "") === entityClassName) {
516
+ entitiesArray.removeElement(i);
517
+ removedEntity = true;
518
+ }
519
+ }
520
+ }
521
+
522
+ if (!removedImport && !removedEntity) {
523
+ return { staged: false, skipped: true, removedImport, removedEntity };
524
+ }
525
+
526
+ this.dirtySourceFiles.add(abs);
527
+ this.logger.log(`Staged datasource cleanup in ${this.rel(abs)} for entity ${entityClassName}`);
528
+ return { staged: true, skipped: false, removedImport, removedEntity };
529
+ }
530
+
471
531
 
472
532
 
473
533
  }
@@ -106,7 +106,7 @@ export class AuditSubscriber implements EntitySubscriberInterface {
106
106
 
107
107
  const relationBefore = event.entity?.[AUDIT_BEFORE_SNAPSHOT] ?? null;
108
108
 
109
- const relationAfter = await event.manager.getRepository(event.metadata.target as any).findOne({
109
+ const relationAfter = await this.dataSource.getRepository(event.metadata.target as any).findOne({
110
110
  where: { id: entityId } as any,
111
111
  relations: relations as any,
112
112
  });
@@ -151,11 +151,6 @@ export class AuditSubscriber implements EntitySubscriberInterface {
151
151
 
152
152
  if (batch.length === 0) return;
153
153
 
154
- if (this.shouldDeferAuditPublish()) {
155
- setImmediate(() => void this.publishAuditBatch(batch));
156
- return;
157
- }
158
-
159
154
  await this.publishAuditBatch(batch);
160
155
  }
161
156
 
@@ -164,12 +159,6 @@ export class AuditSubscriber implements EntitySubscriberInterface {
164
159
  this.perTxn.delete(event.queryRunner);
165
160
  }
166
161
 
167
- private shouldDeferAuditPublish(): boolean {
168
- const driver = (process.env.DEFAULT_DATABASE_DRIVER ?? '').toLowerCase();
169
- const poolMax = Number(process.env.DEFAULT_DATABASE_POOL_MAX ?? 20);
170
- return driver === 'pglite' && Number.isFinite(poolMax) && poolMax <= 1;
171
- }
172
-
173
162
  private async publishAuditBatch(batch: AuditQueuePayload[]) {
174
163
  try {
175
164
  // allSettled: publish in parallel; a single failure does not block the rest.
@@ -1,7 +1,5 @@
1
1
  import { camelCase } from 'lodash';
2
- import { Delete } from "@aws-sdk/client-s3";
3
2
  import { forwardRef, Inject, Injectable, InternalServerErrorException, Logger, Scope } from "@nestjs/common";
4
- import { model } from "mongoose";
5
3
  import { ComputedFieldTriggerOperation } from "src/dtos/create-field-metadata.dto";
6
4
  import { ComputedFieldMetadata, SolidRegistry, TypeOrmEventContext } from "src/helpers/solid-registry";
7
5
  import { IEntityPreComputeFieldProvider } from "src/interfaces";
@@ -14,19 +12,15 @@ export interface ComputedFieldEvaluationPayload extends ComputedFieldMetadata {
14
12
  }
15
13
 
16
14
  @Injectable({ scope: Scope.TRANSIENT })
17
- // @EventSubscriber()
18
15
  export class ComputedEntityFieldSubscriber implements EntitySubscriberInterface {
19
16
  private readonly logger = new Logger(this.constructor.name);
20
17
  private dataSource: DataSource;
18
+
21
19
  constructor(
22
- // @InjectDataSource()
23
- // private readonly dataSource: DataSource,
24
20
  private readonly solidRegistry: SolidRegistry,
25
21
  @Inject(forwardRef(() => PublisherFactory))
26
22
  private readonly publisherFactory: PublisherFactory<ComputedFieldEvaluationPayload>
27
- // private readonly computedFieldPublisher: ComputedFieldEvaluationPublisherDatabase,
28
23
  ) {
29
- // this.dataSource.subscribers.push(this);
30
24
  }
31
25
 
32
26
  bindToDataSource(dataSource: DataSource) {
@@ -43,47 +37,54 @@ export class ComputedEntityFieldSubscriber implements EntitySubscriberInterface
43
37
  async beforeUpdate(event: UpdateEvent<any>): Promise<any> {
44
38
  const modelName = camelCase(event.metadata?.name ?? event.entity?.constructor?.name ?? '');
45
39
  const eventContext = this.sanitizeEventContext(event, 'beforeUpdate');
46
- // await this.handleComputedFieldEvaluation(event.databaseEntity, ComputedFieldTriggerOperation.beforeUpdate, modelName, eventContext);
47
40
  await this.handleComputedFieldEvaluation(event.entity, ComputedFieldTriggerOperation.beforeUpdate, modelName, eventContext);
48
41
  }
49
42
 
50
43
  afterInsert(event: InsertEvent<any>) {
51
44
  const modelName = camelCase(event.metadata?.name ?? event.entity?.constructor?.name ?? '');
52
45
  const eventContext = this.sanitizeEventContext(event, 'afterInsert');
53
- this.handleComputedFieldEvaluationJob(event.entity, ComputedFieldTriggerOperation.afterInsert, modelName, eventContext);
46
+ this.handlePostEventJobs(event, event.entity, ComputedFieldTriggerOperation.afterInsert, modelName, eventContext);
54
47
  }
55
48
 
56
49
  afterUpdate(event: UpdateEvent<any>) {
57
50
  const modelName = camelCase(event.metadata?.name ?? event.entity?.constructor?.name ?? event.databaseEntity?.constructor?.name ?? '');
58
51
  const eventContext = this.sanitizeEventContext(event, 'afterUpdate');
59
- // this.handleComputedFieldEvaluationJob(event.databaseEntity, ComputedFieldTriggerOperation.afterUpdate, modelName, eventContext);
60
- this.handleComputedFieldEvaluationJob(event.entity, ComputedFieldTriggerOperation.afterUpdate, modelName, eventContext);
52
+ this.handlePostEventJobs(event, event.entity, ComputedFieldTriggerOperation.afterUpdate, modelName, eventContext);
61
53
  }
62
54
 
63
55
  afterRemove(event: RemoveEvent<any>) {
64
56
  const modelName = camelCase(event.metadata?.name ?? event.entity?.constructor?.name ?? event.databaseEntity?.constructor?.name ?? '');
65
57
  const eventContext = this.sanitizeEventContext(event, 'afterRemove');
66
- this.handleComputedFieldEvaluationJob(event.databaseEntity, ComputedFieldTriggerOperation.afterRemove, modelName, eventContext);
58
+ this.handlePostEventJobs(event, event.databaseEntity, ComputedFieldTriggerOperation.afterRemove, modelName, eventContext);
67
59
  }
68
60
 
69
61
  //FIXME: Need to add support for beforeRemove, beforeSoftRemove, afterSoftRemove, beforeRecover, afterRecover
70
62
 
71
- private async handleComputedFieldEvaluation(entity: any, currentOperation: ComputedFieldTriggerOperation, modelName: string, eventContext?: TypeOrmEventContext): Promise<void> {
72
- if (!entity) {
73
- return;
74
- }
63
+ private handlePostEventJobs(
64
+ _event: InsertEvent<any> | UpdateEvent<any> | RemoveEvent<any>,
65
+ entity: any,
66
+ currentOperation: ComputedFieldTriggerOperation,
67
+ modelName: string,
68
+ eventContext?: TypeOrmEventContext,
69
+ ) {
70
+ if (!entity) return;
71
+
75
72
  const computedFieldsTobeEvaluated = this.getComputedFieldsForEvaluation(
76
73
  this.solidRegistry.getComputedFieldMetadata(),
77
74
  currentOperation,
78
75
  modelName
79
76
  );
80
- //TODO: We can add a feature i.e dependsOn, where we can check if the computed field depends on other computed fields and evaluate them first
77
+ if (computedFieldsTobeEvaluated.length === 0) return;
78
+
81
79
  for (const computedField of computedFieldsTobeEvaluated) {
82
- await this.evaluateComputedField(this.attachContext(computedField, eventContext), entity, currentOperation);
80
+ this.enqueueComputedFieldEvaluationJob(
81
+ this.attachContext(computedField, eventContext),
82
+ entity,
83
+ );
83
84
  }
84
85
  }
85
86
 
86
- private handleComputedFieldEvaluationJob(entity: any, currentOperation: ComputedFieldTriggerOperation, modelName: string, eventContext?: TypeOrmEventContext) {
87
+ private async handleComputedFieldEvaluation(entity: any, currentOperation: ComputedFieldTriggerOperation, modelName: string, eventContext?: TypeOrmEventContext): Promise<void> {
87
88
  if (!entity) {
88
89
  return;
89
90
  }
@@ -92,9 +93,8 @@ export class ComputedEntityFieldSubscriber implements EntitySubscriberInterface
92
93
  currentOperation,
93
94
  modelName
94
95
  );
95
- //TODO: We can add a feature i.e dependsOn, where we can check if the computed field depends on other computed fields and evaluate them first
96
96
  for (const computedField of computedFieldsTobeEvaluated) {
97
- this.enqueueComputedFieldEvaluationJob(this.attachContext(computedField, eventContext), entity, eventContext);
97
+ await this.evaluateComputedField(this.attachContext(computedField, eventContext), entity, currentOperation);
98
98
  }
99
99
  }
100
100
 
@@ -147,17 +147,12 @@ export class ComputedEntityFieldSubscriber implements EntitySubscriberInterface
147
147
  }
148
148
  }
149
149
 
150
- private enqueueComputedFieldEvaluationJob(computedField: ComputedFieldMetadata<any>, databaseEntity: any, eventContext?: any) {
151
- const { manager: _manager, ...serializableEventContext } = computedField.eventContext ?? {};
150
+ private enqueueComputedFieldEvaluationJob(computedField: ComputedFieldMetadata<any>, databaseEntity: any) {
152
151
  const payload = {
153
152
  ...computedField,
154
- eventContext: serializableEventContext,
155
153
  databaseEntity,
156
154
  };
157
- this.publisherFactory.publish({ payload }, 'ComputedFieldEvaluationPublisher')
158
- // this.computedFieldPublisher.publish({
159
- // payload
160
- // });
155
+ this.publisherFactory.publish({ payload }, 'ComputedFieldEvaluationPublisher');
161
156
  }
162
157
 
163
158
  private attachContext<T extends ComputedFieldMetadata<any>>(computedField: T, eventContext?: any): T {
@@ -176,7 +171,6 @@ export class ComputedEntityFieldSubscriber implements EntitySubscriberInterface
176
171
  const base: TypeOrmEventContext = {
177
172
  metadataName: event.metadata?.name,
178
173
  eventType: eventType,
179
- manager: event.manager,
180
174
  };
181
175
  if ("entityId" in event && event.entityId) {
182
176
  base.entityId = event.entityId;
@@ -38,9 +38,6 @@ export class CreatedByUpdatedBySubscriber implements EntitySubscriberInterface {
38
38
  return;
39
39
  }
40
40
 
41
- // NOTE: If re-enabling loadUser below, query via `event.queryRunner.manager`, NOT
42
- // `this.defaultDataSource.getRepository(...)`. A second connection opened mid-transaction
43
- // deadlocks single-threaded engines (PGlite).
44
41
  // const loadedUser = await this.loadUser(activeUserOrUndefined as unknown as ActiveUserData);
45
42
  // if (isInsert) {
46
43
  // event.entity.createdBy = loadedUser?.id;
@@ -21,9 +21,6 @@ export class FieldMetadataSubscriber implements EntitySubscriberInterface<FieldM
21
21
  }
22
22
 
23
23
  async afterUpdate(event: UpdateEvent<FieldMetadata>): Promise<void> {
24
- // NOTE: If re-enabling the block below, use `event.queryRunner.manager` (the active
25
- // transaction's connection), NOT `this.dataSource.getRepository(...)`. A second
26
- // connection opened here mid-transaction deadlocks single-threaded engines (PGlite).
27
24
  // If a field of type relation.many-to-one is marked for removal, and this field had an inverse relation created
28
25
  // It means there is a field of type relation.one-to-many in the co-model, which needs to be removed
29
26
  // if (event.entity && event.entity.isMarkedForRemoval && event.entity.type === 'relation' && event.entity.relationType === 'many-to-one' && event.entity.relationCreateInverse === true) {
@@ -83,7 +83,7 @@ export class ScheduledJobSubscriber
83
83
  return;
84
84
  }
85
85
 
86
- const moduleMetadataRepo = event.queryRunner.manager.getRepository(ModuleMetadata);
86
+ const moduleMetadataRepo = this.dataSource.getRepository(ModuleMetadata);
87
87
  const populatedModuleMetadata = await moduleMetadataRepo.findOne({
88
88
  where: { id: moduleMetadata.id },
89
89
  });
@@ -40,7 +40,7 @@ export class SecurityRuleSubscriber implements EntitySubscriberInterface<Securit
40
40
  return;
41
41
  }
42
42
 
43
- const modelMetadataRepo = event.manager.getRepository(ModelMetadata);
43
+ const modelMetadataRepo = this.dataSource.getRepository(ModelMetadata);
44
44
  const populatedModelMetadata = await modelMetadataRepo.findOne({
45
45
  where: {
46
46
  id: modelMetadata.id
@@ -1,5 +0,0 @@
1
- export interface NodemonHeartbeatHandle {
2
- stop: () => void;
3
- }
4
- export declare function startNodemonHeartbeat(srcDir: string): NodemonHeartbeatHandle;
5
- //# sourceMappingURL=nodemon-heartbeat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"nodemon-heartbeat.d.ts","sourceRoot":"","sources":["../../src/helpers/nodemon-heartbeat.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AASD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,sBAAsB,CA8B5E"}
@@ -1,67 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.startNodemonHeartbeat = startNodemonHeartbeat;
37
- const fsSync = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
- const HEARTBEAT_FILENAME = 'solidx-nodemon-heartbeat.json';
40
- const HEARTBEAT_INTERVAL_MS = 1500;
41
- function startNodemonHeartbeat(srcDir) {
42
- const filePath = path.join(srcDir, HEARTBEAT_FILENAME);
43
- let stopped = false;
44
- const touch = () => {
45
- try {
46
- fsSync.writeFileSync(filePath, String(Date.now()));
47
- }
48
- catch {
49
- }
50
- };
51
- touch();
52
- const timer = setInterval(touch, HEARTBEAT_INTERVAL_MS);
53
- return {
54
- stop() {
55
- if (stopped)
56
- return;
57
- stopped = true;
58
- clearInterval(timer);
59
- try {
60
- fsSync.unlinkSync(filePath);
61
- }
62
- catch {
63
- }
64
- },
65
- };
66
- }
67
- //# sourceMappingURL=nodemon-heartbeat.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"nodemon-heartbeat.js","sourceRoot":"","sources":["../../src/helpers/nodemon-heartbeat.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,sDA8BC;AA1DD,2CAA6B;AAC7B,2CAA6B;AAa7B,MAAM,kBAAkB,GAAG,+BAA+B,CAAC;AAC3D,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAanC,SAAgB,qBAAqB,CAAC,MAAc;IAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACvD,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;QAGT,CAAC;IACH,CAAC,CAAC;IAGF,KAAK,EAAE,CAAC;IAER,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC;IAExD,OAAO;QACL,IAAI;YACF,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,aAAa,CAAC,KAAK,CAAC,CAAC;YACrB,IAAI,CAAC;gBACH,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC9B,CAAC;YAAC,MAAM,CAAC;YAET,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import * as fsSync from 'fs';\nimport * as path from 'path';\n\n/**\n * The heartbeat file is placed inside the nodemon-watched src/ directory so\n * that touching it resets nodemon's restart delay. This prevents nodemon from\n * restarting the API server while in-process code generation is writing files\n * (which is especially important for embedded PGlite projects where the\n * generate-code endpoint runs schematics in-process).\n *\n * The file uses a .json extension because nodemon is configured to watch\n * ts,json files. It is placed at the src/ root (not inside any metadata\n * directory) so it is not caught by the metadata JSON ignore rule.\n */\nconst HEARTBEAT_FILENAME = 'solidx-nodemon-heartbeat.json';\nconst HEARTBEAT_INTERVAL_MS = 1500;\n\nexport interface NodemonHeartbeatHandle {\n stop: () => void;\n}\n\n/**\n * Starts a heartbeat that touches a file in the nodemon-watched directory\n * every ~1.5 s. Call `stop()` after the response has been flushed to allow\n * nodemon to restart.\n *\n * @param srcDir Absolute path to the `src/` directory nodemon watches.\n */\nexport function startNodemonHeartbeat(srcDir: string): NodemonHeartbeatHandle {\n const filePath = path.join(srcDir, HEARTBEAT_FILENAME);\n let stopped = false;\n\n const touch = () => {\n try {\n fsSync.writeFileSync(filePath, String(Date.now()));\n } catch {\n // best-effort — if the file can't be written, nodemon will simply\n // restart as usual, which is the safe fallback.\n }\n };\n\n // Write immediately so the delay resets before any schematic output lands.\n touch();\n\n const timer = setInterval(touch, HEARTBEAT_INTERVAL_MS);\n\n return {\n stop() {\n if (stopped) return;\n stopped = true;\n clearInterval(timer);\n try {\n fsSync.unlinkSync(filePath);\n } catch {\n // file may not exist — ignore\n }\n },\n };\n}\n"]}
@@ -1,59 +0,0 @@
1
- import * as fsSync from 'fs';
2
- import * as path from 'path';
3
-
4
- /**
5
- * The heartbeat file is placed inside the nodemon-watched src/ directory so
6
- * that touching it resets nodemon's restart delay. This prevents nodemon from
7
- * restarting the API server while in-process code generation is writing files
8
- * (which is especially important for embedded PGlite projects where the
9
- * generate-code endpoint runs schematics in-process).
10
- *
11
- * The file uses a .json extension because nodemon is configured to watch
12
- * ts,json files. It is placed at the src/ root (not inside any metadata
13
- * directory) so it is not caught by the metadata JSON ignore rule.
14
- */
15
- const HEARTBEAT_FILENAME = 'solidx-nodemon-heartbeat.json';
16
- const HEARTBEAT_INTERVAL_MS = 1500;
17
-
18
- export interface NodemonHeartbeatHandle {
19
- stop: () => void;
20
- }
21
-
22
- /**
23
- * Starts a heartbeat that touches a file in the nodemon-watched directory
24
- * every ~1.5 s. Call `stop()` after the response has been flushed to allow
25
- * nodemon to restart.
26
- *
27
- * @param srcDir Absolute path to the `src/` directory nodemon watches.
28
- */
29
- export function startNodemonHeartbeat(srcDir: string): NodemonHeartbeatHandle {
30
- const filePath = path.join(srcDir, HEARTBEAT_FILENAME);
31
- let stopped = false;
32
-
33
- const touch = () => {
34
- try {
35
- fsSync.writeFileSync(filePath, String(Date.now()));
36
- } catch {
37
- // best-effort — if the file can't be written, nodemon will simply
38
- // restart as usual, which is the safe fallback.
39
- }
40
- };
41
-
42
- // Write immediately so the delay resets before any schematic output lands.
43
- touch();
44
-
45
- const timer = setInterval(touch, HEARTBEAT_INTERVAL_MS);
46
-
47
- return {
48
- stop() {
49
- if (stopped) return;
50
- stopped = true;
51
- clearInterval(timer);
52
- try {
53
- fsSync.unlinkSync(filePath);
54
- } catch {
55
- // file may not exist — ignore
56
- }
57
- },
58
- };
59
- }