@memberjunction/server 5.42.0 → 5.44.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 (101) hide show
  1. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  2. package/dist/agentSessions/SessionJanitor.js +5 -1
  3. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  4. package/dist/agentSessions/SessionManager.d.ts +15 -2
  5. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  6. package/dist/agentSessions/SessionManager.js +53 -11
  7. package/dist/agentSessions/SessionManager.js.map +1 -1
  8. package/dist/agentSessions/index.d.ts.map +1 -1
  9. package/dist/agentSessions/index.js +3 -1
  10. package/dist/agentSessions/index.js.map +1 -1
  11. package/dist/generated/generated.d.ts +1180 -51
  12. package/dist/generated/generated.d.ts.map +1 -1
  13. package/dist/generated/generated.js +35564 -29262
  14. package/dist/generated/generated.js.map +1 -1
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +14 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts +20 -1
  20. package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts.map +1 -1
  21. package/dist/resolvers/ExecuteRemoteOperationResolver.js +61 -5
  22. package/dist/resolvers/ExecuteRemoteOperationResolver.js.map +1 -1
  23. package/dist/resolvers/FileResolver.d.ts +74 -0
  24. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  25. package/dist/resolvers/FileResolver.js +211 -2
  26. package/dist/resolvers/FileResolver.js.map +1 -1
  27. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  28. package/dist/resolvers/IntegrationDiscoveryResolver.js +98 -29
  29. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  30. package/dist/resolvers/QueryResolver.d.ts +6 -4
  31. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  32. package/dist/resolvers/QueryResolver.js +29 -14
  33. package/dist/resolvers/QueryResolver.js.map +1 -1
  34. package/dist/resolvers/RealtimeBridgeResolver.d.ts +17 -1
  35. package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
  36. package/dist/resolvers/RealtimeBridgeResolver.js +78 -7
  37. package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
  38. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +81 -2
  39. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  40. package/dist/resolvers/RealtimeClientSessionResolver.js +293 -17
  41. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  42. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  43. package/dist/resolvers/RemoteBrowserActionResolver.js +17 -2
  44. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  45. package/dist/resolvers/RunAIAgentResolver.d.ts +12 -3
  46. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  47. package/dist/resolvers/RunAIAgentResolver.js +37 -15
  48. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  49. package/dist/resolvers/RunTemplateResolver.d.ts +8 -0
  50. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  51. package/dist/resolvers/RunTemplateResolver.js +8 -0
  52. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  53. package/dist/resolvers/meetingRecordingRegistration.d.ts +124 -0
  54. package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -0
  55. package/dist/resolvers/meetingRecordingRegistration.js +311 -0
  56. package/dist/resolvers/meetingRecordingRegistration.js.map +1 -0
  57. package/dist/resolvers/peaksSidecar.d.ts +30 -0
  58. package/dist/resolvers/peaksSidecar.d.ts.map +1 -0
  59. package/dist/resolvers/peaksSidecar.js +51 -0
  60. package/dist/resolvers/peaksSidecar.js.map +1 -0
  61. package/dist/rest/MediaAccessKeys.d.ts +68 -0
  62. package/dist/rest/MediaAccessKeys.d.ts.map +1 -0
  63. package/dist/rest/MediaAccessKeys.js +96 -0
  64. package/dist/rest/MediaAccessKeys.js.map +1 -0
  65. package/dist/rest/MediaStreamHandler.d.ts +26 -0
  66. package/dist/rest/MediaStreamHandler.d.ts.map +1 -0
  67. package/dist/rest/MediaStreamHandler.js +192 -0
  68. package/dist/rest/MediaStreamHandler.js.map +1 -0
  69. package/dist/rest/mediaRange.d.ts +41 -0
  70. package/dist/rest/mediaRange.d.ts.map +1 -0
  71. package/dist/rest/mediaRange.js +60 -0
  72. package/dist/rest/mediaRange.js.map +1 -0
  73. package/package.json +83 -82
  74. package/src/__tests__/FileResolverPeaks.test.ts +64 -0
  75. package/src/__tests__/MediaAccessKeys.test.ts +68 -0
  76. package/src/__tests__/MediaStreamHandler.test.ts +91 -0
  77. package/src/__tests__/RealtimeBridgeResolver.test.ts +10 -1
  78. package/src/__tests__/RealtimeClientSessionResolver.test.ts +69 -0
  79. package/src/__tests__/RealtimeCoAgentAppAwareness.integration.test.ts +191 -0
  80. package/src/__tests__/RemoteBrowserSnapshot.test.ts +123 -0
  81. package/src/__tests__/SessionManager.test.ts +2 -0
  82. package/src/__tests__/meetingRecordingRegistration.test.ts +248 -0
  83. package/src/agentSessions/SessionJanitor.ts +15 -1
  84. package/src/agentSessions/SessionManager.ts +62 -10
  85. package/src/agentSessions/index.ts +3 -1
  86. package/src/generated/generated.ts +17659 -13322
  87. package/src/index.ts +15 -1
  88. package/src/resolvers/ExecuteRemoteOperationResolver.ts +60 -4
  89. package/src/resolvers/FileResolver.ts +199 -1
  90. package/src/resolvers/IntegrationDiscoveryResolver.ts +108 -30
  91. package/src/resolvers/QueryResolver.ts +33 -19
  92. package/src/resolvers/RealtimeBridgeResolver.ts +82 -7
  93. package/src/resolvers/RealtimeClientSessionResolver.ts +326 -9
  94. package/src/resolvers/RemoteBrowserActionResolver.ts +18 -2
  95. package/src/resolvers/RunAIAgentResolver.ts +44 -11
  96. package/src/resolvers/RunTemplateResolver.ts +8 -0
  97. package/src/resolvers/meetingRecordingRegistration.ts +432 -0
  98. package/src/resolvers/peaksSidecar.ts +52 -0
  99. package/src/rest/MediaAccessKeys.ts +121 -0
  100. package/src/rest/MediaStreamHandler.ts +220 -0
  101. package/src/rest/mediaRange.ts +76 -0
@@ -4279,8 +4279,25 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4279
4279
  */
4280
4280
  async createEntityAndFieldMaps(companyIntegrationID, objects, connector, companyIntegration, schemaName, user, provider, defaultSyncDirection = 'Pull') {
4281
4281
  const results = [];
4282
+ // PERF (large-catalog ApplyAll, e.g. Salesforce 1695 objects): precompute O(1) lookups ONCE before
4283
+ // the per-object loop. The per-object path previously did an O(N) `provider.Entities.find` + a
4284
+ // BypassCache RunView for the existing entity map PER object → O(N²) scans + N DB round-trips, so a
4285
+ // 1695-object connector burned its whole budget in ApplyAll and FullSync never started. One entity
4286
+ // index + one batched entity-map query make both O(1) per object.
4287
+ const entityByKey = new Map(provider.Entities.map(e => [`${e.SchemaName.toLowerCase()}|${e.BaseTable.toLowerCase()}`, e]));
4288
+ const existingMapByExternalName = new Map();
4289
+ const allMaps = await new RunView().RunView({
4290
+ EntityName: 'MJ: Company Integration Entity Maps',
4291
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
4292
+ ResultType: 'entity_object',
4293
+ BypassCache: true, // idempotency must read COMMITTED state, not a possibly-stale filtered cache
4294
+ }, user);
4295
+ if (allMaps.Success) {
4296
+ for (const m of allMaps.Results)
4297
+ existingMapByExternalName.set((m.ExternalObjectName ?? '').toLowerCase(), m);
4298
+ }
4282
4299
  for (const obj of objects) {
4283
- const entityMapResult = await this.createSingleEntityMap(companyIntegrationID, obj, connector, companyIntegration, schemaName, user, provider, defaultSyncDirection);
4300
+ const entityMapResult = await this.createSingleEntityMap(companyIntegrationID, obj, connector, companyIntegration, schemaName, user, provider, defaultSyncDirection, entityByKey, existingMapByExternalName);
4284
4301
  if (entityMapResult) {
4285
4302
  results.push(entityMapResult);
4286
4303
  }
@@ -4288,10 +4305,12 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4288
4305
  return results;
4289
4306
  }
4290
4307
  /** Creates a single entity map + field maps for one source object. */
4291
- async createSingleEntityMap(companyIntegrationID, obj, connector, companyIntegration, schemaName, user, md, defaultSyncDirection = 'Pull') {
4292
- // Find the entity by schema + table name
4293
- const entityInfo = md.Entities.find(e => e.SchemaName.toLowerCase() === schemaName.toLowerCase()
4294
- && e.BaseTable.toLowerCase() === obj.TableName.toLowerCase());
4308
+ async createSingleEntityMap(companyIntegrationID, obj, connector, companyIntegration, schemaName, user, md, defaultSyncDirection = 'Pull', entityByKey, existingMapByExternalName) {
4309
+ // Find the entity by schema + table name. PERF: O(1) precomputed index when provided
4310
+ // (large-catalog ApplyAll); falls back to the O(N) scan when called without it.
4311
+ const entityInfo = entityByKey?.get(`${schemaName.toLowerCase()}|${obj.TableName.toLowerCase()}`)
4312
+ ?? md.Entities.find(e => e.SchemaName.toLowerCase() === schemaName.toLowerCase()
4313
+ && e.BaseTable.toLowerCase() === obj.TableName.toLowerCase());
4295
4314
  if (!entityInfo) {
4296
4315
  LogError(`IntegrationApplyAll: entity not found for ${schemaName}.${obj.TableName}`);
4297
4316
  return null;
@@ -4301,18 +4320,28 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4301
4320
  // multiplies the maps in lockstep (N applies → N duplicate maps per object), which
4302
4321
  // silently corrupts the record-map 1:1 completeness gate and makes the forward sync
4303
4322
  // process each object N times. Reuse the existing (connection, external object) map instead.
4304
- const escapedObjectName = obj.SourceObjectName.replace(/'/g, "''");
4305
- const existingMapResult = await new RunView().RunView({
4306
- EntityName: 'MJ: Company Integration Entity Maps',
4307
- ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}' AND ExternalObjectName='${escapedObjectName}'`,
4308
- OrderBy: '__mj_CreatedAt ASC',
4309
- MaxRows: 1,
4310
- ResultType: 'entity_object',
4311
- BypassCache: true, // idempotency must read COMMITTED state, not a possibly-stale filtered cache
4312
- }, user);
4323
+ // PERF: use the precomputed existing-map index when provided (one batched query for the whole
4324
+ // ApplyAll instead of one BypassCache RunView per object); falls back to a per-object query.
4325
+ let existing;
4326
+ if (existingMapByExternalName) {
4327
+ existing = existingMapByExternalName.get(obj.SourceObjectName.toLowerCase());
4328
+ }
4329
+ else {
4330
+ const escapedObjectName = obj.SourceObjectName.replace(/'/g, "''");
4331
+ const existingMapResult = await new RunView().RunView({
4332
+ EntityName: 'MJ: Company Integration Entity Maps',
4333
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}' AND ExternalObjectName='${escapedObjectName}'`,
4334
+ OrderBy: '__mj_CreatedAt ASC',
4335
+ MaxRows: 1,
4336
+ ResultType: 'entity_object',
4337
+ BypassCache: true, // idempotency must read COMMITTED state, not a possibly-stale filtered cache
4338
+ }, user);
4339
+ if (existingMapResult.Success && existingMapResult.Results.length > 0)
4340
+ existing = existingMapResult.Results[0];
4341
+ }
4313
4342
  let em;
4314
- if (existingMapResult.Success && existingMapResult.Results.length > 0) {
4315
- em = existingMapResult.Results[0]; // reuse — keeps the map stable across re-applies
4343
+ if (existing) {
4344
+ em = existing; // reuse — keeps the map stable across re-applies
4316
4345
  }
4317
4346
  else {
4318
4347
  em = await md.GetEntityObject('MJ: Company Integration Entity Maps', user);
@@ -4426,24 +4455,61 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4426
4455
  * still surfaces every object/field; only materialization is capped. Per-table column count = the selected
4427
4456
  * field subset, or the object's full discovered field count when all fields are selected.
4428
4457
  */
4429
- enforceSchemaLimits(objects, filteredSchema) {
4430
- const envInt = (name) => {
4431
- const v = parseInt(process.env[name] ?? '', 10);
4432
- return Number.isFinite(v) && v > 0 ? v : null;
4433
- };
4458
+ async enforceSchemaLimits(objects, filteredSchema, companyIntegration, user, md) {
4459
+ const warnings = [];
4434
4460
  const fullCountByName = new Map(filteredSchema.Objects.map(o => [o.ExternalName.toLowerCase(), o.Fields.length]));
4435
- // Delegate the cap decision to the engine's pure, unit-tested decideSchemaLimitViolations.
4461
+ // Use the MAX of the input object's Fields and the filtered-schema count — the batch path can pass
4462
+ // objects with empty Fields (the real columns come from filteredSchema, which is what buildSchema
4463
+ // materializes). `?? ` would wrongly read an empty [] as 0 (0 is not nullish); Math.max is robust to
4464
+ // either source being empty and reflects the count that will actually become columns.
4465
+ const colCount = (o) => Math.max(fullCountByName.get(o.SourceObjectName.toLowerCase()) ?? 0, o.Fields?.length ?? 0);
4466
+ // ── Per-table COLUMN limit: DISABLE-the-offender, NOT reject-the-apply. The limit is clamped at
4467
+ // startup to ≤ IntegrationEngine.MAX_COLUMNS_CEILING (SQL Server's 1024 minus framework column
4468
+ // headroom). An object exceeding it is set Status='Disabled' (reversible — it re-enables on a later
4469
+ // discovery if it has shrunk back under the limit) and dropped from THIS apply, so the materializable
4470
+ // objects still sync instead of the whole apply failing CREATE TABLE. One CLI warning per disabled object.
4471
+ const limit = IntegrationEngine.Instance.MaxColumnsPerTable;
4472
+ const overLimit = objects.filter(o => colCount(o) > limit);
4473
+ if (overLimit.length > 0) {
4474
+ const ioIDByName = new Map(IntegrationEngineBase.Instance.GetActiveIntegrationObjects(companyIntegration.IntegrationID)
4475
+ .map(io => [io.Name.toLowerCase(), io.ID]));
4476
+ for (const o of overLimit) {
4477
+ warnings.push(`Disabled "${o.SourceObjectName}" (${colCount(o)} columns > limit ${limit}) — too wide to materialize as one table; reduce its columns or it stays disabled.`);
4478
+ const ioID = ioIDByName.get(o.SourceObjectName.toLowerCase());
4479
+ if (ioID) {
4480
+ const io = await md.GetEntityObject('MJ: Integration Objects', user);
4481
+ if (await io.Load(ioID)) {
4482
+ io.Status = 'Disabled';
4483
+ if (!await io.Save()) {
4484
+ LogError(`enforceSchemaLimits: failed to disable over-wide IO '${o.SourceObjectName}': ${io.LatestResult?.CompleteMessage ?? 'unknown error'}`);
4485
+ }
4486
+ }
4487
+ }
4488
+ }
4489
+ // Drop the disabled objects from BOTH the shared objects array (used downstream by
4490
+ // buildTargetConfigs + createEntityAndFieldMaps) and filteredSchema, in place.
4491
+ const disabled = new Set(overLimit.map(o => o.SourceObjectName.toLowerCase()));
4492
+ for (let i = objects.length - 1; i >= 0; i--) {
4493
+ if (disabled.has(objects[i].SourceObjectName.toLowerCase()))
4494
+ objects.splice(i, 1);
4495
+ }
4496
+ filteredSchema.Objects = filteredSchema.Objects.filter(o => !disabled.has(o.ExternalName.toLowerCase()));
4497
+ }
4498
+ // MaxTables remains an operator/env REJECT guardrail (unchanged), evaluated on the surviving objects.
4499
+ // Columns are handled above via disable, so the pure decision is asked about tables only here.
4500
+ const maxTables = (() => {
4501
+ const v = parseInt(process.env.MJ_INTEGRATION_MAX_TABLES ?? '', 10);
4502
+ return Number.isFinite(v) && v > 0 ? v : null;
4503
+ })();
4436
4504
  const violations = decideSchemaLimitViolations({
4437
4505
  TableCount: objects.length,
4438
- ColumnCountByTable: objects.map(o => ({
4439
- Name: o.SourceObjectName,
4440
- ColumnCount: o.Fields?.length ?? fullCountByName.get(o.SourceObjectName.toLowerCase()) ?? 0,
4441
- })),
4442
- MaxTables: envInt('MJ_INTEGRATION_MAX_TABLES'),
4443
- MaxColumnsPerTable: envInt('MJ_INTEGRATION_MAX_COLUMNS_PER_TABLE'),
4506
+ ColumnCountByTable: [],
4507
+ MaxTables: maxTables,
4508
+ MaxColumnsPerTable: null,
4444
4509
  });
4445
4510
  if (violations.length > 0)
4446
4511
  throw new Error(violations.join(' '));
4512
+ return warnings;
4447
4513
  }
4448
4514
  async buildSchemaForConnector(companyIntegrationID, objects, platform, user, skipGitCommit, skipRestart, provider, prefetchedSourceSchema) {
4449
4515
  const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user, provider);
@@ -4490,7 +4556,7 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4490
4556
  // §B — reject an over-limit table/column SELECTION before ANY table is materialized. This is the
4491
4557
  // single shared gate for ApplyAll / ApplyAllBatch / ApplySchemaBatch (all route through here).
4492
4558
  // Caps are operator/env guardrails (MJ_INTEGRATION_MAX_TABLES / _MAX_COLUMNS_PER_TABLE).
4493
- this.enforceSchemaLimits(objects, filteredSchema);
4559
+ const limitWarnings = await this.enforceSchemaLimits(objects, filteredSchema, companyIntegration, user, provider);
4494
4560
  const targetConfigs = this.buildTargetConfigs(objects, filteredSchema, platform, connector);
4495
4561
  const input = {
4496
4562
  SourceSchema: filteredSchema,
@@ -4506,6 +4572,9 @@ let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends Re
4506
4572
  };
4507
4573
  const builder = new SchemaBuilder();
4508
4574
  const schemaOutput = builder.BuildSchema(input);
4575
+ // Surface the auto-disabled over-wide objects (if any) in the apply's Warnings → CLI output.
4576
+ if (limitWarnings.length > 0)
4577
+ schemaOutput.Warnings.unshift(...limitWarnings);
4509
4578
  if (schemaOutput.Errors.length > 0) {
4510
4579
  throw new Error(`Schema generation failed: ${schemaOutput.Errors.join('; ')}`);
4511
4580
  }