@memberjunction/server 6.1.0-edge.2 → 6.1.0-edge.4

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 (210) hide show
  1. package/LICENSE +180 -4
  2. package/dist/agentSessions/SessionManager.d.ts +19 -5
  3. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  4. package/dist/agentSessions/SessionManager.js +27 -9
  5. package/dist/agentSessions/SessionManager.js.map +1 -1
  6. package/dist/auth/AuthProviderCatalogRouter.d.ts +31 -0
  7. package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -0
  8. package/dist/auth/AuthProviderCatalogRouter.js +69 -0
  9. package/dist/auth/AuthProviderCatalogRouter.js.map +1 -0
  10. package/dist/auth/AuthProviderEngine.d.ts +96 -0
  11. package/dist/auth/AuthProviderEngine.d.ts.map +1 -0
  12. package/dist/auth/AuthProviderEngine.js +245 -0
  13. package/dist/auth/AuthProviderEngine.js.map +1 -0
  14. package/dist/auth/index.d.ts +12 -0
  15. package/dist/auth/index.d.ts.map +1 -1
  16. package/dist/auth/index.js +57 -13
  17. package/dist/auth/index.js.map +1 -1
  18. package/dist/auth/initializeProviders.d.ts +64 -1
  19. package/dist/auth/initializeProviders.d.ts.map +1 -1
  20. package/dist/auth/initializeProviders.js +117 -5
  21. package/dist/auth/initializeProviders.js.map +1 -1
  22. package/dist/auth/scopeLimitedPrincipal.d.ts +39 -0
  23. package/dist/auth/scopeLimitedPrincipal.d.ts.map +1 -0
  24. package/dist/auth/scopeLimitedPrincipal.js +49 -0
  25. package/dist/auth/scopeLimitedPrincipal.js.map +1 -0
  26. package/dist/config.d.ts +89 -0
  27. package/dist/config.d.ts.map +1 -1
  28. package/dist/config.js +52 -35
  29. package/dist/config.js.map +1 -1
  30. package/dist/context.d.ts.map +1 -1
  31. package/dist/context.js +21 -1
  32. package/dist/context.js.map +1 -1
  33. package/dist/entitySubclasses/MJEntityPermissionEntityServer.server.d.ts.map +1 -1
  34. package/dist/entitySubclasses/MJEntityPermissionEntityServer.server.js +8 -7
  35. package/dist/entitySubclasses/MJEntityPermissionEntityServer.server.js.map +1 -1
  36. package/dist/generated/generated.d.ts +619 -1597
  37. package/dist/generated/generated.d.ts.map +1 -1
  38. package/dist/generated/generated.js +3341 -17021
  39. package/dist/generated/generated.js.map +1 -1
  40. package/dist/generic/ResolverBase.d.ts +28 -1
  41. package/dist/generic/ResolverBase.d.ts.map +1 -1
  42. package/dist/generic/ResolverBase.js +57 -8
  43. package/dist/generic/ResolverBase.js.map +1 -1
  44. package/dist/generic/RunViewResolver.d.ts +4 -0
  45. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  46. package/dist/generic/RunViewResolver.js +31 -0
  47. package/dist/generic/RunViewResolver.js.map +1 -1
  48. package/dist/index.d.ts +3 -0
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +147 -14
  51. package/dist/index.js.map +1 -1
  52. package/dist/integration/CustomColumnPromoter.d.ts +79 -15
  53. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  54. package/dist/integration/CustomColumnPromoter.js +472 -97
  55. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  56. package/dist/integration/InactiveRowWarnings.d.ts +48 -0
  57. package/dist/integration/InactiveRowWarnings.d.ts.map +1 -0
  58. package/dist/integration/InactiveRowWarnings.js +57 -0
  59. package/dist/integration/InactiveRowWarnings.js.map +1 -0
  60. package/dist/integration/RSUProgressBridge.d.ts +83 -0
  61. package/dist/integration/RSUProgressBridge.d.ts.map +1 -0
  62. package/dist/integration/RSUProgressBridge.js +230 -0
  63. package/dist/integration/RSUProgressBridge.js.map +1 -0
  64. package/dist/integration/SchemaRefreshLaunch.d.ts +62 -0
  65. package/dist/integration/SchemaRefreshLaunch.d.ts.map +1 -0
  66. package/dist/integration/SchemaRefreshLaunch.js +67 -0
  67. package/dist/integration/SchemaRefreshLaunch.js.map +1 -0
  68. package/dist/providerConfigUnits.d.ts +20 -0
  69. package/dist/providerConfigUnits.d.ts.map +1 -0
  70. package/dist/providerConfigUnits.js +22 -0
  71. package/dist/providerConfigUnits.js.map +1 -0
  72. package/dist/resolvers/AdhocQueryResolver.d.ts +4 -0
  73. package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
  74. package/dist/resolvers/AdhocQueryResolver.js +20 -6
  75. package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
  76. package/dist/resolvers/FileResolver.d.ts +34 -4
  77. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  78. package/dist/resolvers/FileResolver.js +218 -28
  79. package/dist/resolvers/FileResolver.js.map +1 -1
  80. package/dist/resolvers/IdentityClaimRedemptionResolver.d.ts +37 -0
  81. package/dist/resolvers/IdentityClaimRedemptionResolver.d.ts.map +1 -0
  82. package/dist/resolvers/IdentityClaimRedemptionResolver.js +220 -0
  83. package/dist/resolvers/IdentityClaimRedemptionResolver.js.map +1 -0
  84. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +108 -3
  85. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  86. package/dist/resolvers/IntegrationDiscoveryResolver.js +374 -87
  87. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  88. package/dist/resolvers/QueryResolver.d.ts +5 -4
  89. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  90. package/dist/resolvers/QueryResolver.js +29 -14
  91. package/dist/resolvers/QueryResolver.js.map +1 -1
  92. package/dist/resolvers/QuerySystemUserResolver.d.ts +12 -3
  93. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  94. package/dist/resolvers/QuerySystemUserResolver.js +33 -14
  95. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  96. package/dist/resolvers/RunAIAgentResolver.d.ts +3 -1
  97. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  98. package/dist/resolvers/RunAIAgentResolver.js +20 -7
  99. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  100. package/dist/resolvers/TaskGraphFrameResolver.d.ts +18 -0
  101. package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
  102. package/dist/resolvers/TaskGraphFrameResolver.js +75 -0
  103. package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
  104. package/dist/resolvers/UserResolver.d.ts +19 -17
  105. package/dist/resolvers/UserResolver.d.ts.map +1 -1
  106. package/dist/resolvers/UserResolver.js +66 -67
  107. package/dist/resolvers/UserResolver.js.map +1 -1
  108. package/dist/resolvers/currentUserRoles.d.ts +19 -0
  109. package/dist/resolvers/currentUserRoles.d.ts.map +1 -0
  110. package/dist/resolvers/currentUserRoles.js +36 -0
  111. package/dist/resolvers/currentUserRoles.js.map +1 -0
  112. package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
  113. package/dist/resolvers/meetingRecordingRegistration.js +3 -6
  114. package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
  115. package/dist/rest/MediaAccessKeys.d.ts +17 -0
  116. package/dist/rest/MediaAccessKeys.d.ts.map +1 -1
  117. package/dist/rest/MediaAccessKeys.js +42 -1
  118. package/dist/rest/MediaAccessKeys.js.map +1 -1
  119. package/dist/rest/MediaStreamHandler.d.ts +3 -2
  120. package/dist/rest/MediaStreamHandler.d.ts.map +1 -1
  121. package/dist/rest/MediaStreamHandler.js +83 -2
  122. package/dist/rest/MediaStreamHandler.js.map +1 -1
  123. package/dist/rest/OAuthCallbackHandler.d.ts +49 -1
  124. package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
  125. package/dist/rest/OAuthCallbackHandler.js +129 -43
  126. package/dist/rest/OAuthCallbackHandler.js.map +1 -1
  127. package/dist/rest/UploadTokenManager.d.ts +90 -0
  128. package/dist/rest/UploadTokenManager.d.ts.map +1 -0
  129. package/dist/rest/UploadTokenManager.js +156 -0
  130. package/dist/rest/UploadTokenManager.js.map +1 -0
  131. package/dist/services/IntegrationSyncWorkerService.d.ts +48 -0
  132. package/dist/services/IntegrationSyncWorkerService.d.ts.map +1 -0
  133. package/dist/services/IntegrationSyncWorkerService.js +132 -0
  134. package/dist/services/IntegrationSyncWorkerService.js.map +1 -0
  135. package/dist/services/StartTaskGraphDispatcher.d.ts +0 -10
  136. package/dist/services/StartTaskGraphDispatcher.d.ts.map +1 -1
  137. package/dist/services/StartTaskGraphDispatcher.js +21 -1
  138. package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
  139. package/dist/services/TaskGraphAgentRunner.d.ts +7 -0
  140. package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
  141. package/dist/services/TaskGraphAgentRunner.js +23 -0
  142. package/dist/services/TaskGraphAgentRunner.js.map +1 -1
  143. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  144. package/dist/services/TaskGraphContinuationDeliverer.js +12 -1
  145. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  146. package/dist/types.d.ts +14 -0
  147. package/dist/types.d.ts.map +1 -1
  148. package/dist/types.js.map +1 -1
  149. package/package.json +92 -92
  150. package/src/__tests__/APIKeyScopeAuth.test.ts +475 -0
  151. package/src/__tests__/AdhocQueryResolver.scopeGuard.test.ts +84 -0
  152. package/src/__tests__/AuthProviderEngine.test.ts +278 -0
  153. package/src/__tests__/CustomColumnPromoterOnePass.test.ts +387 -0
  154. package/src/__tests__/EntityCRUDHandler.test.ts +378 -0
  155. package/src/__tests__/InactiveRowWarnings.test.ts +87 -0
  156. package/src/__tests__/IntegrationSyncWorkerService.test.ts +275 -0
  157. package/src/__tests__/OAuthCallbackHandler.openRedirect.test.ts +117 -0
  158. package/src/__tests__/OAuthCallbackHandler.xss.test.ts +4 -1
  159. package/src/__tests__/RESTEndpointHandler.test.ts +672 -0
  160. package/src/__tests__/RSUProgressBridge.test.ts +250 -0
  161. package/src/__tests__/ReactivateRefreshMessage.test.ts +85 -0
  162. package/src/__tests__/RealtimeBridgeResolver.test.ts +10 -2
  163. package/src/__tests__/ResolverBase.filterEscaping.test.ts +147 -0
  164. package/src/__tests__/SchemaRefreshLaunch.test.ts +114 -0
  165. package/src/__tests__/SessionManager.test.ts +55 -0
  166. package/src/__tests__/UserResolver.currentUser.test.ts +87 -0
  167. package/src/__tests__/ViewOperationsHandler.test.ts +277 -0
  168. package/src/__tests__/config-units.test.ts +74 -0
  169. package/src/__tests__/initializeProviders.refresh.test.ts +146 -0
  170. package/src/__tests__/mjapi-bootstrap.test.ts +0 -6
  171. package/src/__tests__/newUsers.test.ts +726 -0
  172. package/src/__tests__/uploadTokenManager.test.ts +159 -0
  173. package/src/agentSessions/SessionManager.ts +27 -9
  174. package/src/auth/AuthProviderCatalogRouter.ts +76 -0
  175. package/src/auth/AuthProviderEngine.ts +253 -0
  176. package/src/auth/index.ts +60 -15
  177. package/src/auth/initializeProviders.ts +128 -7
  178. package/src/auth/scopeLimitedPrincipal.ts +50 -0
  179. package/src/config.ts +55 -36
  180. package/src/context.ts +26 -2
  181. package/src/entitySubclasses/MJEntityPermissionEntityServer.server.ts +8 -7
  182. package/src/generated/generated.ts +2347 -10551
  183. package/src/generic/ResolverBase.ts +67 -8
  184. package/src/generic/RunViewResolver.ts +31 -0
  185. package/src/index.ts +165 -16
  186. package/src/integration/CustomColumnPromoter.ts +520 -98
  187. package/src/integration/InactiveRowWarnings.ts +85 -0
  188. package/src/integration/RSUProgressBridge.ts +248 -0
  189. package/src/integration/SchemaRefreshLaunch.ts +93 -0
  190. package/src/providerConfigUnits.ts +21 -0
  191. package/src/resolvers/AdhocQueryResolver.ts +21 -6
  192. package/src/resolvers/FileResolver.ts +200 -40
  193. package/src/resolvers/IdentityClaimRedemptionResolver.ts +184 -0
  194. package/src/resolvers/IntegrationDiscoveryResolver.ts +390 -71
  195. package/src/resolvers/QueryResolver.ts +25 -11
  196. package/src/resolvers/QuerySystemUserResolver.ts +28 -13
  197. package/src/resolvers/RunAIAgentResolver.ts +21 -6
  198. package/src/resolvers/TaskGraphFrameResolver.ts +67 -0
  199. package/src/resolvers/UserResolver.ts +99 -60
  200. package/src/resolvers/currentUserRoles.ts +47 -0
  201. package/src/resolvers/meetingRecordingRegistration.ts +3 -7
  202. package/src/rest/MediaAccessKeys.ts +47 -1
  203. package/src/rest/MediaStreamHandler.ts +98 -3
  204. package/src/rest/OAuthCallbackHandler.ts +149 -41
  205. package/src/rest/UploadTokenManager.ts +211 -0
  206. package/src/services/IntegrationSyncWorkerService.ts +141 -0
  207. package/src/services/StartTaskGraphDispatcher.ts +21 -1
  208. package/src/services/TaskGraphAgentRunner.ts +23 -0
  209. package/src/services/TaskGraphContinuationDeliverer.ts +11 -1
  210. package/src/types.ts +14 -0
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @fileoverview Ephemeral in-memory staged upload token manager.
3
+ *
4
+ * Provides a secure, single-use, time-to-live (TTL) bounded staging area for raw
5
+ * binary upload buffers received via REST streaming before being committed through
6
+ * the GraphQL `UploadStorageFile` pipeline.
7
+ *
8
+ * Security properties:
9
+ * - Single-use nonce: Token and buffer are atomically destroyed on first consumption.
10
+ * - User binding: Tokens are bound to the authenticated User ID that uploaded them.
11
+ * - Auto-eviction: Abandoned tokens are automatically evicted from RAM after the TTL.
12
+ * - Memory caps: Enforces per-file max size (default 100MB) and total pool capacity (default 500MB).
13
+ *
14
+ * @module @memberjunction/server/rest/UploadTokenManager
15
+ */
16
+ import { BaseSingleton } from '@memberjunction/global';
17
+ /**
18
+ * An ephemeral in-memory staged upload record.
19
+ */
20
+ export interface StagedUploadEntry {
21
+ token: string;
22
+ buffer: Buffer;
23
+ fileName: string;
24
+ mimeType: string;
25
+ contentLength: number;
26
+ userId: string;
27
+ createdAt: number;
28
+ expiresAt: number;
29
+ timer: NodeJS.Timeout;
30
+ }
31
+ /**
32
+ * Ephemeral In-Memory Staged Upload Token Manager.
33
+ *
34
+ * Architecture & Deployment Topology Note:
35
+ * This implementation maintains staged buffers in-process RAM with a 5-minute sliding TTL.
36
+ * In a clustered/multi-replica deployment behind a load balancer, sticky sessions (or routing
37
+ * the subsequent GraphQL `UploadStorageFile` commit to the same node) are recommended.
38
+ * For shared-memory multi-node clustering, an external ephemeral store (such as Redis)
39
+ * can be plugged in behind this interface.
40
+ */
41
+ export declare class UploadTokenManager extends BaseSingleton<UploadTokenManager> {
42
+ private readonly _staged;
43
+ private _totalMemoryBytes;
44
+ defaultTtlSeconds: number;
45
+ maxFileSizeBytes: number;
46
+ maxUserMemoryBytes: number;
47
+ maxPoolMemoryBytes: number;
48
+ constructor();
49
+ static get Instance(): UploadTokenManager;
50
+ /**
51
+ * Calculates total active staged bytes currently held for a given user.
52
+ */
53
+ GetUserMemoryBytes(userId: string): number;
54
+ /**
55
+ * Stages a raw binary buffer in RAM, returning a single-use cryptographic token.
56
+ *
57
+ * @throws Error if buffer exceeds single file limit, per-user quota, or global pool memory capacity.
58
+ */
59
+ Stage(params: {
60
+ buffer: Buffer;
61
+ fileName: string;
62
+ mimeType: string;
63
+ userId: string;
64
+ ttlSeconds?: number;
65
+ }): string;
66
+ /**
67
+ * Atomically consumes and evicts a staged upload token.
68
+ *
69
+ * @param token The staged upload token.
70
+ * @param claimingUserId The user ID claiming this token. If provided, must match the user who uploaded it.
71
+ * @returns The staged buffer and metadata, or null if the token is invalid, expired, or claimed by the wrong user.
72
+ */
73
+ Consume(token: string, claimingUserId?: string): {
74
+ buffer: Buffer;
75
+ fileName: string;
76
+ mimeType: string;
77
+ contentLength: number;
78
+ } | null;
79
+ /**
80
+ * Evicts a token from RAM and reclaims memory.
81
+ */
82
+ Evict(token: string): boolean;
83
+ /** Total RAM in bytes currently consumed by all active staged uploads. */
84
+ get TotalMemoryBytes(): number;
85
+ /** Count of currently active staged uploads. */
86
+ get ActiveCount(): number;
87
+ /** Clears all active staged uploads. */
88
+ Clear(): void;
89
+ }
90
+ //# sourceMappingURL=UploadTokenManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UploadTokenManager.d.ts","sourceRoot":"","sources":["../../src/rest/UploadTokenManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,aAAa,EAAc,MAAM,wBAAwB,CAAC;AAInE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,qBAAa,kBAAmB,SAAQ,aAAa,CAAC,kBAAkB,CAAC;IACvE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAChE,OAAO,CAAC,iBAAiB,CAAK;IAEvB,iBAAiB,SAAO;IACxB,gBAAgB,SAAqB;IACrC,kBAAkB,SAAqB;IACvC,kBAAkB,SAAqB;;IAO9C,WAAkB,QAAQ,IAAI,kBAAkB,CAE/C;IAED;;OAEG;IACI,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAUjD;;;;OAIG;IACI,KAAK,CAAC,MAAM,EAAE;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,MAAM;IAsDV;;;;;;OAMG;IACI,OAAO,CACZ,KAAK,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,MAAM,GACtB;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IA0BvF;;OAEG;IACI,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAYpC,0EAA0E;IAC1E,IAAW,gBAAgB,IAAI,MAAM,CAEpC;IAED,gDAAgD;IAChD,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,wCAAwC;IACjC,KAAK,IAAI,IAAI;CAOrB"}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * @fileoverview Ephemeral in-memory staged upload token manager.
3
+ *
4
+ * Provides a secure, single-use, time-to-live (TTL) bounded staging area for raw
5
+ * binary upload buffers received via REST streaming before being committed through
6
+ * the GraphQL `UploadStorageFile` pipeline.
7
+ *
8
+ * Security properties:
9
+ * - Single-use nonce: Token and buffer are atomically destroyed on first consumption.
10
+ * - User binding: Tokens are bound to the authenticated User ID that uploaded them.
11
+ * - Auto-eviction: Abandoned tokens are automatically evicted from RAM after the TTL.
12
+ * - Memory caps: Enforces per-file max size (default 100MB) and total pool capacity (default 500MB).
13
+ *
14
+ * @module @memberjunction/server/rest/UploadTokenManager
15
+ */
16
+ import { BaseSingleton, UUIDsEqual } from '@memberjunction/global';
17
+ import { LogError } from '@memberjunction/core';
18
+ import { randomBytes } from 'node:crypto';
19
+ /**
20
+ * Ephemeral In-Memory Staged Upload Token Manager.
21
+ *
22
+ * Architecture & Deployment Topology Note:
23
+ * This implementation maintains staged buffers in-process RAM with a 5-minute sliding TTL.
24
+ * In a clustered/multi-replica deployment behind a load balancer, sticky sessions (or routing
25
+ * the subsequent GraphQL `UploadStorageFile` commit to the same node) are recommended.
26
+ * For shared-memory multi-node clustering, an external ephemeral store (such as Redis)
27
+ * can be plugged in behind this interface.
28
+ */
29
+ export class UploadTokenManager extends BaseSingleton {
30
+ // Public constructor required by BaseSingleton
31
+ constructor() {
32
+ super();
33
+ this._staged = new Map();
34
+ this._totalMemoryBytes = 0;
35
+ this.defaultTtlSeconds = 300; // 5 minutes
36
+ this.maxFileSizeBytes = 100 * 1024 * 1024; // 100 MB
37
+ this.maxUserMemoryBytes = 150 * 1024 * 1024; // 150 MB per user
38
+ this.maxPoolMemoryBytes = 500 * 1024 * 1024; // 500 MB
39
+ }
40
+ static get Instance() {
41
+ return UploadTokenManager.getInstance();
42
+ }
43
+ /**
44
+ * Calculates total active staged bytes currently held for a given user.
45
+ */
46
+ GetUserMemoryBytes(userId) {
47
+ let total = 0;
48
+ for (const entry of this._staged.values()) {
49
+ if (UUIDsEqual(entry.userId, userId)) {
50
+ total += entry.contentLength;
51
+ }
52
+ }
53
+ return total;
54
+ }
55
+ /**
56
+ * Stages a raw binary buffer in RAM, returning a single-use cryptographic token.
57
+ *
58
+ * @throws Error if buffer exceeds single file limit, per-user quota, or global pool memory capacity.
59
+ */
60
+ Stage(params) {
61
+ const size = params.buffer.length;
62
+ if (size > this.maxFileSizeBytes) {
63
+ throw new Error(`Staged upload exceeds maximum allowed file size of ${Math.round(this.maxFileSizeBytes / (1024 * 1024))}MB (received ${Math.round(size / (1024 * 1024))}MB).`);
64
+ }
65
+ const userCurrentBytes = this.GetUserMemoryBytes(params.userId);
66
+ if (userCurrentBytes + size > this.maxUserMemoryBytes) {
67
+ throw new Error(`Per-user upload memory quota reached (${Math.round(userCurrentBytes / (1024 * 1024))}MB / ${Math.round(this.maxUserMemoryBytes / (1024 * 1024))}MB used). Please wait for active uploads to finalize.`);
68
+ }
69
+ if (this._totalMemoryBytes + size > this.maxPoolMemoryBytes) {
70
+ throw new Error(`Staged upload memory capacity reached (${Math.round(this._totalMemoryBytes / (1024 * 1024))}MB / ${Math.round(this.maxPoolMemoryBytes / (1024 * 1024))}MB used). Please try again shortly.`);
71
+ }
72
+ const token = 'upt_' + randomBytes(32).toString('hex');
73
+ const ttl = params.ttlSeconds || this.defaultTtlSeconds;
74
+ const now = Date.now();
75
+ const expiresAt = now + ttl * 1000;
76
+ const timer = setTimeout(() => {
77
+ this.Evict(token);
78
+ }, ttl * 1000);
79
+ // Unref timer so it doesn't hold open process shutdown in tests or CLI
80
+ if (typeof timer.unref === 'function') {
81
+ timer.unref();
82
+ }
83
+ const entry = {
84
+ token,
85
+ buffer: params.buffer,
86
+ fileName: params.fileName,
87
+ mimeType: params.mimeType,
88
+ contentLength: size,
89
+ userId: params.userId,
90
+ createdAt: now,
91
+ expiresAt,
92
+ timer,
93
+ };
94
+ this._staged.set(token, entry);
95
+ this._totalMemoryBytes += size;
96
+ return token;
97
+ }
98
+ /**
99
+ * Atomically consumes and evicts a staged upload token.
100
+ *
101
+ * @param token The staged upload token.
102
+ * @param claimingUserId The user ID claiming this token. If provided, must match the user who uploaded it.
103
+ * @returns The staged buffer and metadata, or null if the token is invalid, expired, or claimed by the wrong user.
104
+ */
105
+ Consume(token, claimingUserId) {
106
+ if (!token || !this._staged.has(token)) {
107
+ return null;
108
+ }
109
+ const entry = this._staged.get(token);
110
+ // Security check: verify user ownership using UUIDsEqual for robust ID normalization
111
+ if (claimingUserId && entry.userId && !UUIDsEqual(entry.userId, claimingUserId)) {
112
+ LogError(`[UploadTokenManager] Security violation: User '${claimingUserId}' attempted to claim upload token owned by User '${entry.userId}'.`);
113
+ // Evict immediately to prevent further probing
114
+ this.Evict(token);
115
+ return null;
116
+ }
117
+ // Atomic consumption & memory reclamation
118
+ this.Evict(token);
119
+ return {
120
+ buffer: entry.buffer,
121
+ fileName: entry.fileName,
122
+ mimeType: entry.mimeType,
123
+ contentLength: entry.contentLength,
124
+ };
125
+ }
126
+ /**
127
+ * Evicts a token from RAM and reclaims memory.
128
+ */
129
+ Evict(token) {
130
+ const entry = this._staged.get(token);
131
+ if (!entry) {
132
+ return false;
133
+ }
134
+ clearTimeout(entry.timer);
135
+ this._staged.delete(token);
136
+ this._totalMemoryBytes = Math.max(0, this._totalMemoryBytes - entry.contentLength);
137
+ return true;
138
+ }
139
+ /** Total RAM in bytes currently consumed by all active staged uploads. */
140
+ get TotalMemoryBytes() {
141
+ return this._totalMemoryBytes;
142
+ }
143
+ /** Count of currently active staged uploads. */
144
+ get ActiveCount() {
145
+ return this._staged.size;
146
+ }
147
+ /** Clears all active staged uploads. */
148
+ Clear() {
149
+ for (const [, entry] of this._staged) {
150
+ clearTimeout(entry.timer);
151
+ }
152
+ this._staged.clear();
153
+ this._totalMemoryBytes = 0;
154
+ }
155
+ }
156
+ //# sourceMappingURL=UploadTokenManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UploadTokenManager.js","sourceRoot":"","sources":["../../src/rest/UploadTokenManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @fileoverview Worker-mode poll loop for durable integration sync runs (PR 1 item 8).
3
+ * @module MJServer/services
4
+ */
5
+ import { IntegrationSyncWorkerConfig } from '../config.js';
6
+ /**
7
+ * Polls `CompanyIntegrationRun` for `Status='Queued'` rows, claims each one atomically,
8
+ * executes it, and releases — the enqueue/execute split that lets a sync outlive the
9
+ * request that asked for it.
10
+ *
11
+ * Multiple workers (in this process or others) may poll the same queue: the claim sproc
12
+ * admits exactly one, and every loser simply moves on to the next candidate. Nothing here
13
+ * assumes it is the only worker.
14
+ */
15
+ export declare class IntegrationSyncWorkerService {
16
+ private config;
17
+ private systemUser;
18
+ private timer;
19
+ private isRunning;
20
+ private polling;
21
+ /** Run IDs currently executing in THIS process — bounds concurrency and prevents self-collision. */
22
+ private inFlight;
23
+ constructor(config: IntegrationSyncWorkerConfig);
24
+ get IsEnabled(): boolean;
25
+ get IsRunning(): boolean;
26
+ /** Number of queued runs this worker is currently executing. */
27
+ get InFlightCount(): number;
28
+ /** Resolve the system user the worker executes syncs as. */
29
+ Initialize(): Promise<void>;
30
+ /** Begin polling the queue. */
31
+ Start(): void;
32
+ /**
33
+ * Stop polling. In-flight runs are left to finish on their own — their leases are
34
+ * renewed by the engine's heartbeat, so killing them here would only strand rows.
35
+ */
36
+ Stop(): void;
37
+ /**
38
+ * One poll pass: fetch claimable candidates up to the free concurrency slots and start
39
+ * each. Overlapping passes are suppressed so a slow query can't stack up timers.
40
+ */
41
+ private pollOnce;
42
+ /**
43
+ * Execute one queued run in the background. Losing the claim race is normal — the run
44
+ * is simply someone else's — so it is logged as information, never as an error.
45
+ */
46
+ private startRun;
47
+ }
48
+ //# sourceMappingURL=IntegrationSyncWorkerService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IntegrationSyncWorkerService.d.ts","sourceRoot":"","sources":["../../src/services/IntegrationSyncWorkerService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAE3D;;;;;;;;GAQG;AACH,qBAAa,4BAA4B;IACrC,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,UAAU,CAAyB;IAC3C,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,oGAAoG;IACpG,OAAO,CAAC,QAAQ,CAAqB;gBAEzB,MAAM,EAAE,2BAA2B;IAI/C,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,gEAAgE;IAChE,IAAW,aAAa,IAAI,MAAM,CAEjC;IAED,4DAA4D;IAC/C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAWxC,+BAA+B;IACxB,KAAK,IAAI,IAAI;IAoBpB;;;OAGG;IACI,IAAI,IAAI,IAAI;IAUnB;;;OAGG;YACW,QAAQ;IAoBtB;;;OAGG;IACH,OAAO,CAAC,QAAQ;CAoBnB"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @fileoverview Worker-mode poll loop for durable integration sync runs (PR 1 item 8).
3
+ * @module MJServer/services
4
+ */
5
+ import { LogError, LogStatus } from '@memberjunction/core';
6
+ import { UserCache } from '@memberjunction/generic-database-provider';
7
+ import { IntegrationEngine } from '@memberjunction/integration-engine';
8
+ /**
9
+ * Polls `CompanyIntegrationRun` for `Status='Queued'` rows, claims each one atomically,
10
+ * executes it, and releases — the enqueue/execute split that lets a sync outlive the
11
+ * request that asked for it.
12
+ *
13
+ * Multiple workers (in this process or others) may poll the same queue: the claim sproc
14
+ * admits exactly one, and every loser simply moves on to the next candidate. Nothing here
15
+ * assumes it is the only worker.
16
+ */
17
+ export class IntegrationSyncWorkerService {
18
+ constructor(config) {
19
+ this.systemUser = null;
20
+ this.timer = null;
21
+ this.isRunning = false;
22
+ this.polling = false;
23
+ /** Run IDs currently executing in THIS process — bounds concurrency and prevents self-collision. */
24
+ this.inFlight = new Set();
25
+ this.config = config;
26
+ }
27
+ get IsEnabled() {
28
+ return this.config.enabled;
29
+ }
30
+ get IsRunning() {
31
+ return this.isRunning;
32
+ }
33
+ /** Number of queued runs this worker is currently executing. */
34
+ get InFlightCount() {
35
+ return this.inFlight.size;
36
+ }
37
+ /** Resolve the system user the worker executes syncs as. */
38
+ async Initialize() {
39
+ if (!this.config.enabled)
40
+ return;
41
+ const email = this.config.systemUserEmail;
42
+ this.systemUser = UserCache.Users.find(u => u.Email?.toLowerCase() === email.toLowerCase()) ?? null;
43
+ if (!this.systemUser) {
44
+ throw new Error(`[IntegrationSyncWorker] System user not found with email: ${email}`);
45
+ }
46
+ await IntegrationEngine.Instance.Config(false, this.systemUser);
47
+ }
48
+ /** Begin polling the queue. */
49
+ Start() {
50
+ if (!this.config.enabled || this.isRunning)
51
+ return;
52
+ if (!this.systemUser) {
53
+ throw new Error('[IntegrationSyncWorker] Not initialized — call Initialize() first');
54
+ }
55
+ this.isRunning = true;
56
+ this.timer = setInterval(() => void this.pollOnce(), this.config.pollingIntervalMs);
57
+ // Standard level, NOT verboseOnly: this states a deployment-shaping fact — that this process
58
+ // executes queued syncs — and it's one line per process lifetime. Stop() already logs at
59
+ // standard level, so hiding Start() produced logs showing a worker stopping that never
60
+ // started, and no way to confirm from logs that a deployment is in worker mode at all.
61
+ LogStatus(`🔄 Integration Sync Worker: polling every ${Math.round(this.config.pollingIntervalMs / 1000)}s, ` +
62
+ `up to ${this.config.maxConcurrentRuns} concurrent run(s)`);
63
+ // Don't wait a full interval to drain a queue that already has work.
64
+ void this.pollOnce();
65
+ }
66
+ /**
67
+ * Stop polling. In-flight runs are left to finish on their own — their leases are
68
+ * renewed by the engine's heartbeat, so killing them here would only strand rows.
69
+ */
70
+ Stop() {
71
+ if (!this.isRunning)
72
+ return;
73
+ if (this.timer) {
74
+ clearInterval(this.timer);
75
+ this.timer = null;
76
+ }
77
+ this.isRunning = false;
78
+ LogStatus(`[IntegrationSyncWorker] Stopped polling (${this.inFlight.size} run(s) still in flight)`);
79
+ }
80
+ /**
81
+ * One poll pass: fetch claimable candidates up to the free concurrency slots and start
82
+ * each. Overlapping passes are suppressed so a slow query can't stack up timers.
83
+ */
84
+ async pollOnce() {
85
+ if (this.polling || !this.isRunning || !this.systemUser)
86
+ return;
87
+ const slots = this.config.maxConcurrentRuns - this.inFlight.size;
88
+ if (slots <= 0)
89
+ return;
90
+ this.polling = true;
91
+ try {
92
+ const candidates = await IntegrationEngine.PollQueuedRuns(this.systemUser, slots);
93
+ for (const candidate of candidates) {
94
+ if (this.inFlight.has(candidate.ID))
95
+ continue;
96
+ this.startRun(candidate.ID);
97
+ }
98
+ }
99
+ catch (err) {
100
+ LogError(`[IntegrationSyncWorker] Poll failed`, undefined, err);
101
+ }
102
+ finally {
103
+ this.polling = false;
104
+ }
105
+ }
106
+ /**
107
+ * Execute one queued run in the background. Losing the claim race is normal — the run
108
+ * is simply someone else's — so it is logged as information, never as an error.
109
+ */
110
+ startRun(runID) {
111
+ if (!this.systemUser)
112
+ return;
113
+ this.inFlight.add(runID);
114
+ void IntegrationEngine.Instance
115
+ .ExecuteQueuedRun(runID, this.systemUser)
116
+ .then(result => {
117
+ if (result.Success) {
118
+ LogStatus(`[IntegrationSyncWorker] Run ${runID} completed: ${result.RecordsProcessed} record(s) processed`);
119
+ }
120
+ else {
121
+ LogStatus(`[IntegrationSyncWorker] Run ${runID} did not complete: ${result.ErrorMessage ?? 'unknown reason'}`);
122
+ }
123
+ })
124
+ .catch(err => {
125
+ LogError(`[IntegrationSyncWorker] Run ${runID} threw`, undefined, err);
126
+ })
127
+ .finally(() => {
128
+ this.inFlight.delete(runID);
129
+ });
130
+ }
131
+ }
132
+ //# sourceMappingURL=IntegrationSyncWorkerService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IntegrationSyncWorkerService.js","sourceRoot":"","sources":["../../src/services/IntegrationSyncWorkerService.ts"],"names":[],"mappings":"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"}
@@ -19,15 +19,5 @@
19
19
  import { UserInfo } from '@memberjunction/core';
20
20
  import { TaskGraphDispatcher } from '@memberjunction/task-graph';
21
21
  import sql from 'mssql';
22
- /**
23
- * Starts one dispatcher for this process and returns it.
24
- *
25
- * The instance ID must be stable for the process lifetime and distinct per instance — it is what
26
- * lets reconciliation tell "my own orphaned work, reclaim it" from "another live instance's work,
27
- * leave it alone". `pid` plus hostname satisfies both: stable while the process lives, and never
28
- * reused by a peer.
29
- *
30
- * The dispatcher self-registers with `ShutdownRegistry`, so the caller does not wire teardown.
31
- */
32
22
  export declare function StartTaskGraphDispatcher(pool: sql.ConnectionPool, contextUser: UserInfo, instanceID?: string): Promise<TaskGraphDispatcher>;
33
23
  //# sourceMappingURL=StartTaskGraphDispatcher.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StartTaskGraphDispatcher.d.ts","sourceRoot":"","sources":["../../src/services/StartTaskGraphDispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAA2B,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAE1F,OAAO,GAAG,MAAM,OAAO,CAAC;AAUxB;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAC1C,IAAI,EAAE,GAAG,CAAC,cAAc,EACxB,WAAW,EAAE,QAAQ,EACrB,UAAU,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,CAAC,CAgC9B"}
1
+ {"version":3,"file":"StartTaskGraphDispatcher.d.ts","sourceRoot":"","sources":["../../src/services/StartTaskGraphDispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAA2B,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAE1F,OAAO,GAAG,MAAM,OAAO,CAAC;AAkCxB,wBAAsB,wBAAwB,CAC1C,IAAI,EAAE,GAAG,CAAC,cAAc,EACxB,WAAW,EAAE,QAAQ,EACrB,UAAU,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,CAAC,CAsC9B"}
@@ -4,6 +4,7 @@ import { DurableEntityActionRegistry } from '@memberjunction/actions-base';
4
4
  import { CreateTaskGraphProviderFactory } from './TaskGraphProviderFactory.js';
5
5
  import { TaskGraphActionRunner } from './TaskGraphActionRunner.js';
6
6
  import { TaskGraphAgentRunner } from './TaskGraphAgentRunner.js';
7
+ import { randomBytes } from 'node:crypto';
7
8
  import { DurableEntityActionTaskSubmitter } from './DurableEntityActionTaskSubmitter.js';
8
9
  import { TaskGraphContinuationDeliverer } from './TaskGraphContinuationDeliverer.js';
9
10
  import { PubSubManager } from '../generic/PubSubManager.js';
@@ -18,11 +19,30 @@ import { TaskGraphFrameBroadcaster } from '../resolvers/TaskGraphFrameResolver.j
18
19
  *
19
20
  * The dispatcher self-registers with `ShutdownRegistry`, so the caller does not wire teardown.
20
21
  */
22
+ /**
23
+ * A per-process identity for the claim protocol.
24
+ *
25
+ * Host and pid are kept because they are what a human reads in a log; the random suffix is what
26
+ * makes the value actually unique. Generated once per call, so a restart is a new instance — which
27
+ * is correct: the previous process's claims should expire rather than be inherited.
28
+ */
29
+ function defaultInstanceID() {
30
+ const host = process.env.HOSTNAME ?? 'mjapi';
31
+ const entropy = randomBytes(4).toString('hex');
32
+ return `${host}-${process.pid}-${entropy}`;
33
+ }
21
34
  export async function StartTaskGraphDispatcher(pool, contextUser, instanceID) {
22
35
  LoadTaskGraphOperations();
23
36
  const providerFactory = CreateTaskGraphProviderFactory(pool);
24
37
  const pubSub = PubSubManager.Instance.PubSubEngine;
25
- const dispatcher = new TaskGraphDispatcher(providerFactory, new TaskGraphAgentRunner(), contextUser, { InstanceID: instanceID ?? `${process.env.HOSTNAME ?? 'mjapi'}-${process.pid}` },
38
+ const dispatcher = new TaskGraphDispatcher(providerFactory, new TaskGraphAgentRunner(), contextUser,
39
+ // A RANDOM SUFFIX, because host+pid is not unique in the deployments this runs in (C2).
40
+ // `HOSTNAME` is not exported to child processes under systemd or pm2, and a containerised
41
+ // process is routinely pid 1 — so two hosts default to the same `mjapi-1`. A shared instance
42
+ // id defeats every `ClaimedBy=@me` guard at once: A's heartbeat renews B's lease, and A's
43
+ // stale terminal write lands over B's live execution. An explicit `instanceID` still wins,
44
+ // for hosts that have a real identity to supply.
45
+ { InstanceID: instanceID ?? defaultInstanceID() },
26
46
  // Without this the dispatcher had nowhere to deliver: a finished graph logged its outcome,
27
47
  // marked itself delivered, and said nothing to the conversation that asked for it.
28
48
  new TaskGraphContinuationDeliverer(providerFactory, contextUser),
@@ -1 +1 @@
1
- {"version":3,"file":"StartTaskGraphDispatcher.js","sourceRoot":"","sources":["../../src/services/StartTaskGraphDispatcher.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AAEnF;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC1C,IAAwB,EACxB,WAAqB,EACrB,UAAmB;IAEnB,uBAAuB,EAAE,CAAC;IAE1B,MAAM,eAAe,GAAG,8BAA8B,CAAC,IAAI,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC;IACnD,MAAM,UAAU,GAAG,IAAI,mBAAmB,CACtC,eAAe,EACf,IAAI,oBAAoB,EAAE,EAC1B,WAAW,EACX,EAAE,UAAU,EAAE,UAAU,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE;IACjF,2FAA2F;IAC3F,mFAAmF;IACnF,IAAI,8BAA8B,CAAC,eAAe,EAAE,WAAW,CAAC;IAChE,0FAA0F;IAC1F,yEAAyE;IACzE,MAAM,CAAC,CAAC,CAAC,IAAI,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;IAC1D,4FAA4F;IAC5F,yBAAyB;IACzB,IAAI,qBAAqB,EAAE;IAC3B,8EAA8E;IAC9E,kFAAkF;IAClF,4DAA4D;IAC5D,IAAI,qBAAqB,EAAE,CAC9B,CAAC;IACF,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;IAEzB,wFAAwF;IACxF,gGAAgG;IAChG,2EAA2E;IAC3E,2BAA2B,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,gCAAgC,CAAC,eAAe,CAAC,CAAC,CAAC;IAErG,OAAO,UAAU,CAAC;AACtB,CAAC"}
1
+ {"version":3,"file":"StartTaskGraphDispatcher.js","sourceRoot":"","sources":["../../src/services/StartTaskGraphDispatcher.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AAEnF;;;;;;;;;GASG;AACH;;;;;;GAMG;AACH,SAAS,iBAAiB;IACtB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC;IAC7C,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC1C,IAAwB,EACxB,WAAqB,EACrB,UAAmB;IAEnB,uBAAuB,EAAE,CAAC;IAE1B,MAAM,eAAe,GAAG,8BAA8B,CAAC,IAAI,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC;IACnD,MAAM,UAAU,GAAG,IAAI,mBAAmB,CACtC,eAAe,EACf,IAAI,oBAAoB,EAAE,EAC1B,WAAW;IACX,wFAAwF;IACxF,0FAA0F;IAC1F,6FAA6F;IAC7F,0FAA0F;IAC1F,2FAA2F;IAC3F,iDAAiD;IACjD,EAAE,UAAU,EAAE,UAAU,IAAI,iBAAiB,EAAE,EAAE;IACjD,2FAA2F;IAC3F,mFAAmF;IACnF,IAAI,8BAA8B,CAAC,eAAe,EAAE,WAAW,CAAC;IAChE,0FAA0F;IAC1F,yEAAyE;IACzE,MAAM,CAAC,CAAC,CAAC,IAAI,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;IAC1D,4FAA4F;IAC5F,yBAAyB;IACzB,IAAI,qBAAqB,EAAE;IAC3B,8EAA8E;IAC9E,kFAAkF;IAClF,4DAA4D;IAC5D,IAAI,qBAAqB,EAAE,CAC9B,CAAC;IACF,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;IAEzB,wFAAwF;IACxF,gGAAgG;IAChG,2EAA2E;IAC3E,2BAA2B,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,gCAAgC,CAAC,eAAe,CAAC,CAAC,CAAC;IAErG,OAAO,UAAU,CAAC;AACtB,CAAC"}
@@ -1,6 +1,13 @@
1
1
  import type { TaskAgentRunner, TaskAgentRunParams, TaskAgentRunResult } from '@memberjunction/task-graph';
2
2
  export declare class TaskGraphAgentRunner implements TaskAgentRunner {
3
3
  RunAgentForTask(params: TaskAgentRunParams): Promise<TaskAgentRunResult>;
4
+ /**
5
+ * Adapts the agent framework's progress callback onto the dispatcher's plain sink.
6
+ *
7
+ * Undefined when nobody is listening, so the agent run pays nothing for observability it is not
8
+ * providing. Never throws — a progress announcement must not be able to fail the step.
9
+ */
10
+ private bridgeProgress;
4
11
  /**
5
12
  * The run that submitted this graph, as the entity `RunAgent` wants for `parentRun`.
6
13
  *
@@ -1 +1 @@
1
- {"version":3,"file":"TaskGraphAgentRunner.d.ts","sourceRoot":"","sources":["../../src/services/TaskGraphAgentRunner.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAE1G,qBAAa,oBAAqB,YAAW,eAAe;IAC3C,eAAe,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA+BrF;;;;;;;;;;;OAWG;YACW,iBAAiB;IAkB/B;;;;;;OAMG;IACH,OAAO,CAAC,WAAW;IAmBnB,8FAA8F;IAC9F,OAAO,CAAC,aAAa;CAKxB"}
1
+ {"version":3,"file":"TaskGraphAgentRunner.d.ts","sourceRoot":"","sources":["../../src/services/TaskGraphAgentRunner.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAE1G,qBAAa,oBAAqB,YAAW,eAAe;IAC3C,eAAe,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAmCrF;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAYtB;;;;;;;;;;;OAWG;YACW,iBAAiB;IAkB/B;;;;;;OAMG;IACH,OAAO,CAAC,WAAW;IAmBnB,8FAA8F;IAC9F,OAAO,CAAC,aAAa;CAKxB"}
@@ -30,6 +30,10 @@ export class TaskGraphAgentRunner {
30
30
  // rather than starting the chain over. Without it MAX_REINVOKE_DEPTH never fires.
31
31
  continuationDepth: params.ContinuationDepth ?? 0,
32
32
  parentRun: await this.loadSubmittingRun(params),
33
+ // The bridge from the agent's own progress stream up to graph-level observers: the
34
+ // dispatcher turns these into rate-limited `NodeProgress` frames, which is how a
35
+ // running Agent step shows "what it is doing right now" on the workflow canvas.
36
+ onProgress: this.bridgeProgress(params),
33
37
  });
34
38
  const success = result?.success === true;
35
39
  return {
@@ -45,6 +49,25 @@ export class TaskGraphAgentRunner {
45
49
  return { Success: false, ErrorMessage: message };
46
50
  }
47
51
  }
52
+ /**
53
+ * Adapts the agent framework's progress callback onto the dispatcher's plain sink.
54
+ *
55
+ * Undefined when nobody is listening, so the agent run pays nothing for observability it is not
56
+ * providing. Never throws — a progress announcement must not be able to fail the step.
57
+ */
58
+ bridgeProgress(params) {
59
+ const sink = params.OnProgress;
60
+ if (!sink)
61
+ return undefined;
62
+ return (progress) => {
63
+ try {
64
+ sink(progress.message, progress.percentage);
65
+ }
66
+ catch {
67
+ // The dispatcher's sink already guards itself; this is belt over braces.
68
+ }
69
+ };
70
+ }
48
71
  /**
49
72
  * The run that submitted this graph, as the entity `RunAgent` wants for `parentRun`.
50
73
  *
@@ -1 +1 @@
1
- {"version":3,"file":"TaskGraphAgentRunner.js","sourceRoot":"","sources":["../../src/services/TaskGraphAgentRunner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TaskGraphAgentRunner.js","sourceRoot":"","sources":["../../src/services/TaskGraphAgentRunner.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TaskGraphContinuationDeliverer.d.ts","sourceRoot":"","sources":["../../src/services/TaskGraphContinuationDeliverer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAA+C,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAKlG,OAAO,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAKrH;;;;;;;;;;;GAWG;AACH,qBAAa,8BAA+B,YAAW,yBAAyB;IAOxE,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAPhC;;;;OAIG;gBAEkB,eAAe,EAAE,eAAe,EAChC,WAAW,EAAE,QAAQ;IAG1C;;;;;;OAMG;IACU,WAAW,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCvE;;;;;;;;;OASG;IACU,QAAQ,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCpE,4CAA4C;YAC9B,qBAAqB;IAKnC;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,UAAU;CAQrB"}
1
+ {"version":3,"file":"TaskGraphContinuationDeliverer.d.ts","sourceRoot":"","sources":["../../src/services/TaskGraphContinuationDeliverer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAA+C,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAKlG,OAAO,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAKrH;;;;;;;;;;;GAWG;AACH,qBAAa,8BAA+B,YAAW,yBAAyB;IAOxE,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAPhC;;;;OAIG;gBAEkB,eAAe,EAAE,eAAe,EAChC,WAAW,EAAE,QAAQ;IAG1C;;;;;;OAMG;IACU,WAAW,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCvE;;;;;;;;;OASG;IACU,QAAQ,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDpE,4CAA4C;YAC9B,qBAAqB;IAKnC;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,UAAU;CAQrB"}
@@ -120,7 +120,18 @@ export class TaskGraphContinuationDeliverer {
120
120
  });
121
121
  }
122
122
  catch (e) {
123
- LogError(`[TaskGraphContinuationDeliverer] Reinvoking for "${params.WorkflowName}" threw`, undefined, e);
123
+ // FALL BACK, don't just log (C3). Both load-failure paths above already post instead of
124
+ // reinvoking, on the principle that a completed workflow's outcome must reach the user
125
+ // somehow — but a throw out of `RunAgent` skipped that and lost the outcome entirely.
126
+ // The marker has been claimed by the time this runs, so nothing will look at the graph
127
+ // again: the work finished, and the only record of it is a server log line.
128
+ LogError(`[TaskGraphContinuationDeliverer] Reinvoking for "${params.WorkflowName}" threw — posting instead`, undefined, e);
129
+ try {
130
+ await this.PostMessage(params);
131
+ }
132
+ catch (fallbackError) {
133
+ LogError(`[TaskGraphContinuationDeliverer] The fallback post for "${params.WorkflowName}" also failed`, undefined, fallbackError);
134
+ }
124
135
  }
125
136
  }
126
137
  /** The conversation a detail belongs to. */