@memberjunction/server 5.30.1 → 5.32.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.
Files changed (104) hide show
  1. package/dist/agents/skip-sdk.d.ts +17 -1
  2. package/dist/agents/skip-sdk.d.ts.map +1 -1
  3. package/dist/agents/skip-sdk.js +18 -5
  4. package/dist/agents/skip-sdk.js.map +1 -1
  5. package/dist/auth/exampleNewUserSubClass.js +1 -1
  6. package/dist/auth/exampleNewUserSubClass.js.map +1 -1
  7. package/dist/auth/index.js +2 -2
  8. package/dist/auth/index.js.map +1 -1
  9. package/dist/auth/newUsers.js +2 -2
  10. package/dist/auth/newUsers.js.map +1 -1
  11. package/dist/context.js +3 -3
  12. package/dist/context.js.map +1 -1
  13. package/dist/generated/generated.d.ts +217 -4
  14. package/dist/generated/generated.d.ts.map +1 -1
  15. package/dist/generated/generated.js +1251 -24
  16. package/dist/generated/generated.js.map +1 -1
  17. package/dist/generic/ResolverBase.d.ts +5 -5
  18. package/dist/generic/ResolverBase.d.ts.map +1 -1
  19. package/dist/generic/ResolverBase.js +21 -18
  20. package/dist/generic/ResolverBase.js.map +1 -1
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +9 -8
  24. package/dist/index.js.map +1 -1
  25. package/dist/multiTenancy/index.js +1 -1
  26. package/dist/multiTenancy/index.js.map +1 -1
  27. package/dist/resolvers/APIKeyResolver.d.ts.map +1 -1
  28. package/dist/resolvers/APIKeyResolver.js +5 -3
  29. package/dist/resolvers/APIKeyResolver.js.map +1 -1
  30. package/dist/resolvers/AutotagPipelineResolver.d.ts +3 -3
  31. package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -1
  32. package/dist/resolvers/AutotagPipelineResolver.js +18 -12
  33. package/dist/resolvers/AutotagPipelineResolver.js.map +1 -1
  34. package/dist/resolvers/ComponentRegistryResolver.d.ts +1 -1
  35. package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
  36. package/dist/resolvers/ComponentRegistryResolver.js +6 -4
  37. package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
  38. package/dist/resolvers/FileResolver.js +2 -2
  39. package/dist/resolvers/FileResolver.js.map +1 -1
  40. package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
  41. package/dist/resolvers/GetDataContextDataResolver.js +1 -2
  42. package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
  43. package/dist/resolvers/ISAEntityResolver.d.ts.map +1 -1
  44. package/dist/resolvers/ISAEntityResolver.js +2 -5
  45. package/dist/resolvers/ISAEntityResolver.js.map +1 -1
  46. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  47. package/dist/resolvers/IntegrationDiscoveryResolver.js +75 -66
  48. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  49. package/dist/resolvers/SyncDataResolver.d.ts +4 -4
  50. package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
  51. package/dist/resolvers/SyncDataResolver.js +9 -8
  52. package/dist/resolvers/SyncDataResolver.js.map +1 -1
  53. package/dist/resolvers/SyncRolesUsersResolver.d.ts +6 -6
  54. package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
  55. package/dist/resolvers/SyncRolesUsersResolver.js +22 -18
  56. package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
  57. package/dist/resolvers/TagGovernanceResolver.d.ts +43 -0
  58. package/dist/resolvers/TagGovernanceResolver.d.ts.map +1 -0
  59. package/dist/resolvers/TagGovernanceResolver.js +245 -0
  60. package/dist/resolvers/TagGovernanceResolver.js.map +1 -0
  61. package/dist/resolvers/TaskResolver.d.ts +1 -1
  62. package/dist/resolvers/TaskResolver.d.ts.map +1 -1
  63. package/dist/resolvers/TaskResolver.js +4 -2
  64. package/dist/resolvers/TaskResolver.js.map +1 -1
  65. package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
  66. package/dist/resolvers/TransactionGroupResolver.js +2 -1
  67. package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
  68. package/dist/rest/EntityCRUDHandler.js +4 -4
  69. package/dist/rest/EntityCRUDHandler.js.map +1 -1
  70. package/dist/rest/RESTEndpointHandler.js +9 -9
  71. package/dist/rest/RESTEndpointHandler.js.map +1 -1
  72. package/dist/rest/ViewOperationsHandler.js +4 -4
  73. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  74. package/dist/services/TaskOrchestrator.d.ts +4 -2
  75. package/dist/services/TaskOrchestrator.d.ts.map +1 -1
  76. package/dist/services/TaskOrchestrator.js +16 -12
  77. package/dist/services/TaskOrchestrator.js.map +1 -1
  78. package/package.json +68 -66
  79. package/src/__tests__/TagGovernanceResolver.test.ts +255 -0
  80. package/src/agents/skip-sdk.ts +30 -7
  81. package/src/auth/exampleNewUserSubClass.ts +1 -1
  82. package/src/auth/index.ts +2 -2
  83. package/src/auth/newUsers.ts +2 -2
  84. package/src/context.ts +3 -3
  85. package/src/generated/generated.ts +861 -21
  86. package/src/generic/ResolverBase.ts +28 -21
  87. package/src/index.ts +9 -9
  88. package/src/multiTenancy/index.ts +1 -1
  89. package/src/resolvers/APIKeyResolver.ts +7 -4
  90. package/src/resolvers/AutotagPipelineResolver.ts +20 -11
  91. package/src/resolvers/ComponentRegistryResolver.ts +8 -5
  92. package/src/resolvers/FileResolver.ts +2 -2
  93. package/src/resolvers/GetDataContextDataResolver.ts +1 -2
  94. package/src/resolvers/ISAEntityResolver.ts +3 -5
  95. package/src/resolvers/IntegrationDiscoveryResolver.ts +83 -66
  96. package/src/resolvers/SyncDataResolver.ts +12 -11
  97. package/src/resolvers/SyncRolesUsersResolver.ts +23 -19
  98. package/src/resolvers/TagGovernanceResolver.ts +189 -0
  99. package/src/resolvers/TaskResolver.ts +5 -3
  100. package/src/resolvers/TransactionGroupResolver.ts +3 -2
  101. package/src/rest/EntityCRUDHandler.ts +4 -4
  102. package/src/rest/RESTEndpointHandler.ts +9 -9
  103. package/src/rest/ViewOperationsHandler.ts +4 -4
  104. package/src/services/TaskOrchestrator.ts +18 -13
@@ -12,7 +12,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  };
13
13
  var IntegrationDiscoveryResolver_1;
14
14
  import { Resolver, Query, Mutation, Arg, Ctx, ObjectType, Field, InputType } from "type-graphql";
15
- import { CompositeKey, LocalCacheManager, Metadata, RunView, LogError } from "@memberjunction/core";
15
+ import { CompositeKey, LocalCacheManager, RunView, LogError } from "@memberjunction/core";
16
+ import { GetReadOnlyProvider, GetReadWriteProvider } from "../util.js";
16
17
  import { CronExpressionHelper } from "@memberjunction/scheduling-engine";
17
18
  import { ConnectorFactory, IntegrationEngine, IntegrationSchemaSync } from "@memberjunction/integration-engine";
18
19
  import { IntegrationEngineBase } from "@memberjunction/integration-engine-base";
@@ -1606,7 +1607,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
1606
1607
  async IntegrationDiscoverObjects(companyIntegrationID, ctx) {
1607
1608
  try {
1608
1609
  const user = this.getAuthenticatedUser(ctx);
1609
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1610
+ const provider = GetReadOnlyProvider(ctx.providers, { allowFallbackToReadWrite: true });
1611
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, provider);
1610
1612
  // Cast through unknown to bridge duplicate package type declarations
1611
1613
  // (integration-engine resolves its own node_modules copies of core/core-entities)
1612
1614
  const discoverObjects = connector.DiscoverObjects.bind(connector);
@@ -1637,7 +1639,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
1637
1639
  async IntegrationListSourceObjects(companyIntegrationID, ctx) {
1638
1640
  try {
1639
1641
  const user = this.getAuthenticatedUser(ctx);
1640
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1642
+ const provider = GetReadOnlyProvider(ctx.providers, { allowFallbackToReadWrite: true });
1643
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, provider);
1641
1644
  // Use the engine cache for already-persisted IntegrationObject
1642
1645
  // rows — single in-memory read instead of a per-call DB roundtrip.
1643
1646
  await IntegrationEngine.Instance.Config(false, user);
@@ -1721,7 +1724,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
1721
1724
  async IntegrationDiscoverFields(companyIntegrationID, objectName, ctx) {
1722
1725
  try {
1723
1726
  const user = this.getAuthenticatedUser(ctx);
1724
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1727
+ const provider = GetReadOnlyProvider(ctx.providers, { allowFallbackToReadWrite: true });
1728
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, provider);
1725
1729
  // Cast through unknown to bridge duplicate package type declarations
1726
1730
  const discoverFields = connector.DiscoverFields.bind(connector);
1727
1731
  const fields = await discoverFields(companyIntegration, objectName, user);
@@ -1748,7 +1752,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
1748
1752
  async IntegrationTestConnection(companyIntegrationID, ctx) {
1749
1753
  try {
1750
1754
  const user = this.getAuthenticatedUser(ctx);
1751
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1755
+ const provider = GetReadOnlyProvider(ctx.providers, { allowFallbackToReadWrite: true });
1756
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, provider);
1752
1757
  // Cast through unknown to bridge duplicate package type declarations
1753
1758
  const testConnection = connector.TestConnection.bind(connector);
1754
1759
  const result = await testConnection(companyIntegration, user);
@@ -1773,7 +1778,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
1773
1778
  async IntegrationGetDefaultConfig(companyIntegrationID, ctx) {
1774
1779
  try {
1775
1780
  const user = this.getAuthenticatedUser(ctx);
1776
- const { connector } = await this.resolveConnector(companyIntegrationID, user);
1781
+ const provider = GetReadOnlyProvider(ctx.providers, { allowFallbackToReadWrite: true });
1782
+ const { connector } = await this.resolveConnector(companyIntegrationID, user, provider);
1777
1783
  const config = connector.GetDefaultConfiguration();
1778
1784
  if (!config) {
1779
1785
  return {
@@ -1813,7 +1819,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
1813
1819
  async IntegrationSchemaPreview(companyIntegrationID, objects, platform, ctx) {
1814
1820
  try {
1815
1821
  const user = this.getAuthenticatedUser(ctx);
1816
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1822
+ const provider = GetReadOnlyProvider(ctx.providers, { allowFallbackToReadWrite: true });
1823
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, provider);
1817
1824
  // Introspect schema from the external system
1818
1825
  const introspect = connector.IntrospectSchema.bind(connector);
1819
1826
  const sourceSchema = await introspect(companyIntegration, user);
@@ -1834,7 +1841,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
1834
1841
  AdditionalSchemaInfoPath: process.env.RSU_ADDITIONAL_SCHEMA_INFO_PATH ?? 'additionalSchemaInfo.json',
1835
1842
  MigrationsDir: process.env.RSU_MIGRATIONS_PATH ?? 'migrations/rsu',
1836
1843
  MetadataDir: process.env.RSU_METADATA_DIR ?? 'metadata',
1837
- ExistingTables: this.buildExistingTables(targetConfigs),
1844
+ ExistingTables: this.buildExistingTables(targetConfigs, provider),
1838
1845
  EntitySettingsForTargets: {}
1839
1846
  };
1840
1847
  const builder = new SchemaBuilder();
@@ -1877,7 +1884,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
1877
1884
  async IntegrationPreviewData(companyIntegrationID, objectName, limit, ctx) {
1878
1885
  try {
1879
1886
  const user = this.getAuthenticatedUser(ctx);
1880
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1887
+ const provider = GetReadOnlyProvider(ctx.providers, { allowFallbackToReadWrite: true });
1888
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, provider);
1881
1889
  const fetchChanges = connector.FetchChanges.bind(connector);
1882
1890
  const result = await fetchChanges({
1883
1891
  CompanyIntegration: companyIntegration,
@@ -2007,11 +2015,10 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2007
2015
  }
2008
2016
  /** Builds a lookup of object name → { objectDescription, fields: fieldName → description } from the connector's static metadata. */
2009
2017
  /** Build ExistingTableInfo[] from MJ Metadata for tables that already exist in the target schemas. */
2010
- buildExistingTables(targetConfigs) {
2011
- const md = new Metadata();
2018
+ buildExistingTables(targetConfigs, provider) {
2012
2019
  const result = [];
2013
2020
  for (const config of targetConfigs) {
2014
- const entity = md.Entities.find(e => e.SchemaName.toLowerCase() === config.SchemaName.toLowerCase() &&
2021
+ const entity = provider.Entities.find(e => e.SchemaName.toLowerCase() === config.SchemaName.toLowerCase() &&
2015
2022
  e.BaseTable.toLowerCase() === config.TableName.toLowerCase());
2016
2023
  if (entity) {
2017
2024
  result.push({
@@ -2303,8 +2310,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2303
2310
  * TypeScript nominal type mismatches. At runtime the objects are structurally identical,
2304
2311
  * so we cast through `unknown` at the boundary calls.
2305
2312
  */
2306
- async resolveConnector(companyIntegrationID, contextUser) {
2307
- const md = new Metadata();
2313
+ async resolveConnector(companyIntegrationID, contextUser, provider) {
2314
+ const md = provider;
2308
2315
  // Load the CompanyIntegration record
2309
2316
  const companyIntegration = await md.GetEntityObject('MJ: Company Integrations', contextUser);
2310
2317
  const loaded = await companyIntegration.Load(companyIntegrationID);
@@ -2344,8 +2351,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2344
2351
  /**
2345
2352
  * Tests connectivity for a given CompanyIntegration, reusing the same pattern as IntegrationTestConnection.
2346
2353
  */
2347
- async testConnectionForCI(companyIntegrationID, user) {
2348
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
2354
+ async testConnectionForCI(companyIntegrationID, user, provider) {
2355
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, provider);
2349
2356
  const testFn = connector.TestConnection.bind(connector);
2350
2357
  return testFn(companyIntegration, user);
2351
2358
  }
@@ -2369,11 +2376,10 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2369
2376
  /**
2370
2377
  * Snapshots the current credential Values for a given credential ID so they can be restored on rollback.
2371
2378
  */
2372
- async snapshotCredentialValues(credentialID, user) {
2379
+ async snapshotCredentialValues(credentialID, user, provider) {
2373
2380
  if (!credentialID)
2374
2381
  return undefined;
2375
- const md = new Metadata();
2376
- const credential = await md.GetEntityObject('MJ: Credentials', user);
2382
+ const credential = await provider.GetEntityObject('MJ: Credentials', user);
2377
2383
  const loaded = await credential.InnerLoad(CompositeKey.FromID(credentialID));
2378
2384
  return loaded ? credential.Values : undefined;
2379
2385
  }
@@ -2381,7 +2387,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2381
2387
  * Reverts an update to a CompanyIntegration by restoring old configuration, externalSystemID,
2382
2388
  * and credential values.
2383
2389
  */
2384
- async revertUpdateConnection(ci, oldConfiguration, oldExternalSystemID, oldCredentialValues, user) {
2390
+ async revertUpdateConnection(ci, oldConfiguration, oldExternalSystemID, oldCredentialValues, user, provider) {
2385
2391
  try {
2386
2392
  // Revert CI fields
2387
2393
  let dirty = false;
@@ -2397,8 +2403,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2397
2403
  await ci.Save();
2398
2404
  // Revert credential values
2399
2405
  if (oldCredentialValues !== undefined && ci.CredentialID) {
2400
- const md = new Metadata();
2401
- const credential = await md.GetEntityObject('MJ: Credentials', user);
2406
+ const credential = await provider.GetEntityObject('MJ: Credentials', user);
2402
2407
  const loaded = await credential.InnerLoad(CompositeKey.FromID(ci.CredentialID));
2403
2408
  if (loaded) {
2404
2409
  credential.Values = oldCredentialValues;
@@ -2465,7 +2470,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2465
2470
  async IntegrationCreateConnection(input, testConnection, ctx) {
2466
2471
  try {
2467
2472
  const user = this.getAuthenticatedUser(ctx);
2468
- const md = new Metadata();
2473
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
2469
2474
  // 1. Create Credential record with encrypted values
2470
2475
  const credential = await md.GetEntityObject('MJ: Credentials', user);
2471
2476
  credential.NewRecord();
@@ -2498,7 +2503,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2498
2503
  }
2499
2504
  // 3. Optionally test the connection; rollback on failure
2500
2505
  if (testConnection) {
2501
- const testResult = await this.testConnectionForCI(ci.ID, user);
2506
+ const testResult = await this.testConnectionForCI(ci.ID, user, md);
2502
2507
  if (!testResult.Success) {
2503
2508
  await this.rollbackCreatedConnection(ci, credential);
2504
2509
  return {
@@ -2535,13 +2540,13 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2535
2540
  async IntegrationUpdateConnection(companyIntegrationID, credentialValues, configuration, externalSystemID, testConnection, ctx) {
2536
2541
  try {
2537
2542
  const user = this.getAuthenticatedUser(ctx);
2538
- const md = new Metadata();
2543
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
2539
2544
  const ci = await md.GetEntityObject('MJ: Company Integrations', user);
2540
2545
  const loaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
2541
2546
  if (!loaded)
2542
2547
  return { Success: false, Message: 'CompanyIntegration not found' };
2543
2548
  // Snapshot old values for rollback if testConnection is requested
2544
- const oldCredentialValues = credentialValues ? await this.snapshotCredentialValues(ci.CredentialID, user) : undefined;
2549
+ const oldCredentialValues = credentialValues ? await this.snapshotCredentialValues(ci.CredentialID, user, md) : undefined;
2545
2550
  const oldConfiguration = ci.Configuration;
2546
2551
  const oldExternalSystemID = ci.ExternalSystemID;
2547
2552
  // Update linked Credential values if provided
@@ -2571,9 +2576,9 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2571
2576
  return { Success: false, Message: 'Failed to save CompanyIntegration' };
2572
2577
  // Optionally test the connection; revert on failure
2573
2578
  if (testConnection) {
2574
- const testResult = await this.testConnectionForCI(companyIntegrationID, user);
2579
+ const testResult = await this.testConnectionForCI(companyIntegrationID, user, md);
2575
2580
  if (!testResult.Success) {
2576
- await this.revertUpdateConnection(ci, oldConfiguration, oldExternalSystemID, oldCredentialValues, user);
2581
+ await this.revertUpdateConnection(ci, oldConfiguration, oldExternalSystemID, oldCredentialValues, user, md);
2577
2582
  return { Success: false, Message: `Connection test failed: ${testResult.Message}. Changes have been reverted.` };
2578
2583
  }
2579
2584
  return { Success: true, Message: 'Updated and connection test passed' };
@@ -2591,7 +2596,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2591
2596
  async IntegrationDeactivateConnection(companyIntegrationID, ctx) {
2592
2597
  try {
2593
2598
  const user = this.getAuthenticatedUser(ctx);
2594
- const md = new Metadata();
2599
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
2595
2600
  const ci = await md.GetEntityObject('MJ: Company Integrations', user);
2596
2601
  const loaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
2597
2602
  if (!loaded)
@@ -2612,7 +2617,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2612
2617
  async IntegrationReactivateConnection(companyIntegrationID, ctx) {
2613
2618
  try {
2614
2619
  const user = this.getAuthenticatedUser(ctx);
2615
- const md = new Metadata();
2620
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
2616
2621
  const ci = await md.GetEntityObject('MJ: Company Integrations', user);
2617
2622
  const loaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
2618
2623
  if (!loaded)
@@ -2635,7 +2640,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2635
2640
  async IntegrationCreateEntityMaps(companyIntegrationID, entityMaps, ctx) {
2636
2641
  try {
2637
2642
  const user = this.getAuthenticatedUser(ctx);
2638
- const md = new Metadata();
2643
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
2639
2644
  // Batch resolve entity names → IDs using cached Metadata
2640
2645
  const namesToResolve = entityMaps.filter(m => m.EntityName && !m.EntityID).map(m => m.EntityName);
2641
2646
  const nameToID = new Map();
@@ -2716,7 +2721,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2716
2721
  async IntegrationApplySchema(companyIntegrationID, objects, platform, skipGitCommit, skipRestart, ctx) {
2717
2722
  try {
2718
2723
  const user = this.getAuthenticatedUser(ctx);
2719
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
2724
+ const provider = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
2725
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, provider);
2720
2726
  const introspect = connector.IntrospectSchema.bind(connector);
2721
2727
  const sourceSchema = await introspect(companyIntegration, user);
2722
2728
  await this.resolveObjectInputs(objects, sourceSchema, user);
@@ -2735,7 +2741,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2735
2741
  AdditionalSchemaInfoPath: process.env.RSU_ADDITIONAL_SCHEMA_INFO_PATH ?? 'additionalSchemaInfo.json',
2736
2742
  MigrationsDir: process.env.RSU_MIGRATIONS_PATH ?? 'migrations/rsu',
2737
2743
  MetadataDir: process.env.RSU_METADATA_DIR ?? 'metadata',
2738
- ExistingTables: this.buildExistingTables(targetConfigs),
2744
+ ExistingTables: this.buildExistingTables(targetConfigs, provider),
2739
2745
  EntitySettingsForTargets: {}
2740
2746
  };
2741
2747
  const builder = new SchemaBuilder();
@@ -2774,13 +2780,14 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2774
2780
  async IntegrationApplySchemaBatch(items, platform, skipGitCommit, skipRestart, ctx) {
2775
2781
  try {
2776
2782
  const user = this.getAuthenticatedUser(ctx);
2783
+ const provider = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
2777
2784
  const validatedPlatform = this.validatePlatform(platform);
2778
2785
  const pipelineInputs = [];
2779
2786
  const itemResults = [];
2780
2787
  // Phase 1: Build schema artifacts for each connector's objects
2781
2788
  for (const item of items) {
2782
2789
  try {
2783
- const { schemaOutput, rsuInput } = await this.buildSchemaForConnector(item.CompanyIntegrationID, item.Objects, validatedPlatform, user, skipGitCommit, skipRestart);
2790
+ const { schemaOutput, rsuInput } = await this.buildSchemaForConnector(item.CompanyIntegrationID, item.Objects, validatedPlatform, user, skipGitCommit, skipRestart, provider);
2784
2791
  pipelineInputs.push(rsuInput);
2785
2792
  itemResults.push({
2786
2793
  CompanyIntegrationID: item.CompanyIntegrationID,
@@ -2832,9 +2839,10 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2832
2839
  async IntegrationApplyAll(input, platform, skipGitCommit, skipRestart, ctx) {
2833
2840
  try {
2834
2841
  const user = this.getAuthenticatedUser(ctx);
2842
+ const provider = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
2835
2843
  const validatedPlatform = this.validatePlatform(platform);
2836
2844
  // Step 1: Resolve connector and derive schema name
2837
- const { connector, companyIntegration } = await this.resolveConnector(input.CompanyIntegrationID, user);
2845
+ const { connector, companyIntegration } = await this.resolveConnector(input.CompanyIntegrationID, user, provider);
2838
2846
  const schemaName = this.deriveSchemaName(companyIntegration.Integration);
2839
2847
  // Step 1b: Ensure IntegrationEngine cache is populated so IntrospectSchema's
2840
2848
  // DB fallback (GetCachedObject/GetCachedFields) can find IntegrationObject records
@@ -2914,7 +2922,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2914
2922
  return obj;
2915
2923
  });
2916
2924
  // Step 3: Build schema and RSU pipeline input
2917
- const { schemaOutput, rsuInput } = await this.buildSchemaForConnector(input.CompanyIntegrationID, objects, validatedPlatform, user, skipGitCommit, skipRestart);
2925
+ const { schemaOutput, rsuInput } = await this.buildSchemaForConnector(input.CompanyIntegrationID, objects, validatedPlatform, user, skipGitCommit, skipRestart, provider);
2918
2926
  // Step 4: Inject integration post-restart payload into RSU input.
2919
2927
  const { join } = await import('node:path');
2920
2928
  const rsuWorkDir = process.env.RSU_WORK_DIR || process.cwd();
@@ -2967,8 +2975,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2967
2975
  // If restart happened, this code never executes (process died).
2968
2976
  // If skipRestart=true, we can do entity maps now.
2969
2977
  if (skipRestart) {
2970
- await Metadata.Provider.Refresh();
2971
- const entityMapsCreated = await this.createEntityAndFieldMaps(input.CompanyIntegrationID, objects, connector, companyIntegration, schemaName, user, input.DefaultSyncDirection ?? 'Pull');
2978
+ await provider.Refresh();
2979
+ const entityMapsCreated = await this.createEntityAndFieldMaps(input.CompanyIntegrationID, objects, connector, companyIntegration, schemaName, user, provider, input.DefaultSyncDirection ?? 'Pull');
2972
2980
  const createdMapIDs = entityMapsCreated.map(em => em.EntityMapID).filter(Boolean);
2973
2981
  const scopedMapIDs = input.SyncScope === 'all' ? undefined : createdMapIDs;
2974
2982
  // Skip sync when SyncScope='created' but 0 new maps were
@@ -2984,7 +2992,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
2984
2992
  let scheduledJobID;
2985
2993
  if (input.CronExpression) {
2986
2994
  try {
2987
- scheduledJobID = await this.createScheduleForConnector(input.CompanyIntegrationID, companyIntegration.Integration, input.CronExpression, input.ScheduleTimezone, user) ?? undefined;
2995
+ scheduledJobID = await this.createScheduleForConnector(input.CompanyIntegrationID, companyIntegration.Integration, input.CronExpression, input.ScheduleTimezone, user, provider) ?? undefined;
2988
2996
  }
2989
2997
  catch (schedErr) {
2990
2998
  console.warn(`[Integration] Schedule creation failed: ${schedErr}`);
@@ -3041,11 +3049,10 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3041
3049
  * After pipeline success, creates CompanyIntegrationEntityMap + CompanyIntegrationFieldMap
3042
3050
  * records for each source object by matching schema + table name to newly created entities.
3043
3051
  */
3044
- async createEntityAndFieldMaps(companyIntegrationID, objects, connector, companyIntegration, schemaName, user, defaultSyncDirection = 'Pull') {
3045
- const md = new Metadata();
3052
+ async createEntityAndFieldMaps(companyIntegrationID, objects, connector, companyIntegration, schemaName, user, provider, defaultSyncDirection = 'Pull') {
3046
3053
  const results = [];
3047
3054
  for (const obj of objects) {
3048
- const entityMapResult = await this.createSingleEntityMap(companyIntegrationID, obj, connector, companyIntegration, schemaName, user, md, defaultSyncDirection);
3055
+ const entityMapResult = await this.createSingleEntityMap(companyIntegrationID, obj, connector, companyIntegration, schemaName, user, provider, defaultSyncDirection);
3049
3056
  if (entityMapResult) {
3050
3057
  results.push(entityMapResult);
3051
3058
  }
@@ -3148,8 +3155,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3148
3155
  * Build schema artifacts for a single connector's objects.
3149
3156
  * Shared by IntegrationApplySchema (single) and IntegrationApplySchemaBatch (batch).
3150
3157
  */
3151
- async buildSchemaForConnector(companyIntegrationID, objects, platform, user, skipGitCommit, skipRestart, prefetchedSourceSchema) {
3152
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
3158
+ async buildSchemaForConnector(companyIntegrationID, objects, platform, user, skipGitCommit, skipRestart, provider, prefetchedSourceSchema) {
3159
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, provider);
3153
3160
  // If the caller already ran IntrospectSchema (e.g. IntegrationApplyAllBatch),
3154
3161
  // reuse it. The legacy path was running introspect TWICE per apply — once
3155
3162
  // in the resolver and once here — which doubled probe time on connectors
@@ -3186,7 +3193,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3186
3193
  AdditionalSchemaInfoPath: process.env.RSU_ADDITIONAL_SCHEMA_INFO_PATH ?? 'additionalSchemaInfo.json',
3187
3194
  MigrationsDir: process.env.RSU_MIGRATIONS_PATH ?? 'migrations/rsu',
3188
3195
  MetadataDir: process.env.RSU_METADATA_DIR ?? 'metadata',
3189
- ExistingTables: this.buildExistingTables(targetConfigs),
3196
+ ExistingTables: this.buildExistingTables(targetConfigs, provider),
3190
3197
  EntitySettingsForTargets: {}
3191
3198
  };
3192
3199
  const builder = new SchemaBuilder();
@@ -3354,7 +3361,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3354
3361
  async IntegrationCreateSchedule(input, ctx) {
3355
3362
  try {
3356
3363
  const user = this.getAuthenticatedUser(ctx);
3357
- const md = new Metadata();
3364
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
3358
3365
  const rv = new RunView();
3359
3366
  // Find IntegrationSync job type
3360
3367
  const jobTypeResult = await rv.RunView({
@@ -3406,7 +3413,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3406
3413
  async IntegrationUpdateSchedule(scheduledJobID, cronExpression, timezone, name, ctx) {
3407
3414
  try {
3408
3415
  const user = this.getAuthenticatedUser(ctx);
3409
- const md = new Metadata();
3416
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
3410
3417
  const job = await md.GetEntityObject('MJ: Scheduled Jobs', user);
3411
3418
  const loaded = await job.InnerLoad(CompositeKey.FromID(scheduledJobID));
3412
3419
  if (!loaded)
@@ -3433,7 +3440,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3433
3440
  try {
3434
3441
  this.getAuthenticatedUser(ctx); // verify caller is authenticated
3435
3442
  const sysUser = this.getSystemUser();
3436
- const md = new Metadata();
3443
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
3437
3444
  const job = await md.GetEntityObject('MJ: Scheduled Jobs', sysUser);
3438
3445
  const loaded = await job.InnerLoad(CompositeKey.FromID(scheduledJobID));
3439
3446
  if (!loaded)
@@ -3454,7 +3461,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3454
3461
  try {
3455
3462
  this.getAuthenticatedUser(ctx); // verify caller is authenticated
3456
3463
  const sysUser = this.getSystemUser(); // use system user for delete operations
3457
- const md = new Metadata();
3464
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
3458
3465
  // Unlink from CI if provided
3459
3466
  if (companyIntegrationID) {
3460
3467
  const ci = await md.GetEntityObject('MJ: Company Integrations', sysUser);
@@ -3503,7 +3510,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3503
3510
  }
3504
3511
  }
3505
3512
  // Now delete job runs + job in a transaction
3506
- const tg = await Metadata.Provider.CreateTransactionGroup();
3513
+ const tg = await md.CreateTransactionGroup();
3507
3514
  if (jobRunsResult.Success) {
3508
3515
  for (const run of jobRunsResult.Results) {
3509
3516
  run.TransactionGroup = tg;
@@ -3615,7 +3622,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3615
3622
  async IntegrationUpdateEntityMaps(updates, ctx) {
3616
3623
  try {
3617
3624
  const user = this.getAuthenticatedUser(ctx);
3618
- const md = new Metadata();
3625
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
3619
3626
  const errors = [];
3620
3627
  for (const update of updates) {
3621
3628
  const em = await md.GetEntityObject('MJ: Company Integration Entity Maps', user);
@@ -3656,9 +3663,9 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3656
3663
  try {
3657
3664
  this.getAuthenticatedUser(ctx);
3658
3665
  const sysUser = this.getSystemUser();
3659
- const md = new Metadata();
3666
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
3660
3667
  const rv = new RunView();
3661
- const tg = await Metadata.Provider.CreateTransactionGroup();
3668
+ const tg = await md.CreateTransactionGroup();
3662
3669
  const errors = [];
3663
3670
  for (const entityMapID of entityMapIDs) {
3664
3671
  const em = await md.GetEntityObject('MJ: Company Integration Entity Maps', sysUser);
@@ -3773,7 +3780,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3773
3780
  async IntegrationGetStatus(companyIntegrationID, ctx) {
3774
3781
  try {
3775
3782
  const user = this.getAuthenticatedUser(ctx);
3776
- const md = new Metadata();
3783
+ const md = GetReadOnlyProvider(ctx.providers, { allowFallbackToReadWrite: true });
3777
3784
  const ci = await md.GetEntityObject('MJ: Company Integrations', user);
3778
3785
  const loaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
3779
3786
  if (!loaded)
@@ -3859,7 +3866,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3859
3866
  async IntegrationGetConnectorCapabilities(companyIntegrationID, ctx) {
3860
3867
  try {
3861
3868
  const user = this.getAuthenticatedUser(ctx);
3862
- const { connector } = await this.resolveConnector(companyIntegrationID, user);
3869
+ const provider = GetReadOnlyProvider(ctx.providers, { allowFallbackToReadWrite: true });
3870
+ const { connector } = await this.resolveConnector(companyIntegrationID, user, provider);
3863
3871
  return {
3864
3872
  Success: true,
3865
3873
  Message: 'OK',
@@ -3885,6 +3893,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3885
3893
  async IntegrationApplyAllBatch(input, platform, skipGitCommit, skipRestart, ctx) {
3886
3894
  try {
3887
3895
  const user = this.getAuthenticatedUser(ctx);
3896
+ const provider = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
3888
3897
  const validatedPlatform = this.validatePlatform(platform);
3889
3898
  // Bust RunView caches for integration metadata BEFORE Config(true).
3890
3899
  // mj sync push writes records via stored procedures which do NOT fire
@@ -3897,7 +3906,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
3897
3906
  await IntegrationEngine.Instance.Config(true, user);
3898
3907
  // Phase 1: Build schema for each connector in parallel
3899
3908
  const buildResults = await Promise.allSettled(input.Connectors.map(async (connInput) => {
3900
- const { connector, companyIntegration } = await this.resolveConnector(connInput.CompanyIntegrationID, user);
3909
+ const { connector, companyIntegration } = await this.resolveConnector(connInput.CompanyIntegrationID, user, provider);
3901
3910
  const schemaName = this.deriveSchemaName(companyIntegration.Integration);
3902
3911
  console.log(`[IntegrationApplyAllBatch] connector=${companyIntegration.Integration} ` +
3903
3912
  `received ${connInput.SourceObjects.length} selections: ` +
@@ -4001,7 +4010,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4001
4010
  obj.Fields = fieldsByName.get(name.toLowerCase()) ?? undefined;
4002
4011
  return obj;
4003
4012
  });
4004
- const { schemaOutput, rsuInput } = await this.buildSchemaForConnector(connInput.CompanyIntegrationID, objects, validatedPlatform, user, skipGitCommit, skipRestart, sourceSchema);
4013
+ const { schemaOutput, rsuInput } = await this.buildSchemaForConnector(connInput.CompanyIntegrationID, objects, validatedPlatform, user, skipGitCommit, skipRestart, provider, sourceSchema);
4005
4014
  // Build per-object field map for pending file
4006
4015
  const sourceObjectFields = {};
4007
4016
  for (const name of resolvedNames) {
@@ -4101,8 +4110,8 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4101
4110
  };
4102
4111
  if (skipRestart) {
4103
4112
  // Entity maps, field maps, sync
4104
- await Metadata.Provider.Refresh();
4105
- const entityMapsCreated = await this.createEntityAndFieldMaps(build.connInput.CompanyIntegrationID, build.objects, build.connector, build.companyIntegration, build.schemaName, user, build.connInput.DefaultSyncDirection ?? 'Pull');
4113
+ await provider.Refresh();
4114
+ const entityMapsCreated = await this.createEntityAndFieldMaps(build.connInput.CompanyIntegrationID, build.objects, build.connector, build.companyIntegration, build.schemaName, user, provider, build.connInput.DefaultSyncDirection ?? 'Pull');
4106
4115
  connResult.EntityMapsCreated = entityMapsCreated;
4107
4116
  const createdMapIDs = entityMapsCreated.map(em => em.EntityMapID).filter(Boolean);
4108
4117
  const scopedMapIDs = input.SyncScope === 'all' ? undefined : createdMapIDs;
@@ -4121,7 +4130,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4121
4130
  connResult.SyncRunID = syncRunID;
4122
4131
  // Create schedule if CronExpression provided
4123
4132
  if (build.connInput.CronExpression) {
4124
- const scheduleResult = await this.createScheduleForConnector(build.connInput.CompanyIntegrationID, integrationName, build.connInput.CronExpression, build.connInput.ScheduleTimezone, user);
4133
+ const scheduleResult = await this.createScheduleForConnector(build.connInput.CompanyIntegrationID, integrationName, build.connInput.CronExpression, build.connInput.ScheduleTimezone, user, provider);
4125
4134
  if (scheduleResult)
4126
4135
  connResult.ScheduledJobID = scheduleResult;
4127
4136
  }
@@ -4159,9 +4168,9 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4159
4168
  }
4160
4169
  }
4161
4170
  /** Helper: creates a schedule for a connector, returns ScheduledJobID or null. */
4162
- async createScheduleForConnector(companyIntegrationID, integrationName, cronExpression, timezone, user) {
4171
+ async createScheduleForConnector(companyIntegrationID, integrationName, cronExpression, timezone, user, provider) {
4163
4172
  try {
4164
- const md = new Metadata();
4173
+ const md = provider;
4165
4174
  const rv = new RunView();
4166
4175
  // Find IntegrationSync job type
4167
4176
  const jobTypeResult = await rv.RunView({
@@ -4212,7 +4221,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4212
4221
  try {
4213
4222
  this.getAuthenticatedUser(ctx); // verify caller is authenticated
4214
4223
  const sysUser = this.getSystemUser(); // use system user for cascade delete
4215
- const md = new Metadata();
4224
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
4216
4225
  const rv = new RunView();
4217
4226
  // Step 1: Load CompanyIntegration
4218
4227
  const ci = await md.GetEntityObject('MJ: Company Integrations', sysUser);
@@ -4220,7 +4229,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4220
4229
  if (!ciLoaded)
4221
4230
  return { Success: false, Message: 'CompanyIntegration not found' };
4222
4231
  // Cascade delete in FK-safe order using TransactionGroup
4223
- const tg = await Metadata.Provider.CreateTransactionGroup();
4232
+ const tg = await md.CreateTransactionGroup();
4224
4233
  let fieldMapsDeleted = 0;
4225
4234
  let entityMapsDeleted = 0;
4226
4235
  let schedulesDeleted = 0;
@@ -4382,9 +4391,9 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4382
4391
  try {
4383
4392
  const user = this.getAuthenticatedUser(ctx);
4384
4393
  const validatedPlatform = this.validatePlatform(platform);
4385
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
4394
+ const md = GetReadWriteProvider(ctx.providers, { allowFallbackToReadOnly: true });
4395
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, md);
4386
4396
  const schemaName = this.deriveSchemaName(companyIntegration.Integration);
4387
- const md = new Metadata();
4388
4397
  const rv = new RunView();
4389
4398
  // Step 1: Get existing entity maps for this CompanyIntegration
4390
4399
  const entityMapsResult = await rv.RunView({