@app-connect/core 1.7.37 → 1.7.38

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 (286) hide show
  1. package/README.md +17 -16
  2. package/dist/connector/developerPortal.d.ts +6 -0
  3. package/{connector → dist/connector}/developerPortal.js +29 -12
  4. package/dist/connector/mock.d.ts +1 -0
  5. package/{connector → dist/connector}/mock.js +33 -17
  6. package/dist/connector/proxy/engine.d.ts +10 -0
  7. package/dist/connector/proxy/engine.js +222 -0
  8. package/dist/connector/proxy/index.d.ts +5 -0
  9. package/dist/connector/proxy/index.js +511 -0
  10. package/dist/connector/registry.d.ts +1 -0
  11. package/dist/connector/registry.js +243 -0
  12. package/dist/handlers/admin.d.ts +1 -0
  13. package/{handlers → dist/handlers}/admin.js +137 -78
  14. package/dist/handlers/appointment.d.ts +9 -0
  15. package/{handlers → dist/handlers}/appointment.js +58 -29
  16. package/dist/handlers/auth.d.ts +9 -0
  17. package/{handlers → dist/handlers}/auth.js +68 -40
  18. package/dist/handlers/calldown.d.ts +10 -0
  19. package/dist/handlers/calldown.js +134 -0
  20. package/dist/handlers/contact.d.ts +1 -0
  21. package/{handlers → dist/handlers}/contact.js +61 -39
  22. package/dist/handlers/disposition.d.ts +1 -0
  23. package/{handlers → dist/handlers}/disposition.js +20 -10
  24. package/dist/handlers/log.d.ts +1 -0
  25. package/{handlers → dist/handlers}/log.js +91 -124
  26. package/dist/handlers/managedAuth.d.ts +1 -0
  27. package/{handlers → dist/handlers}/managedAuth.js +134 -61
  28. package/dist/handlers/managedOAuth.d.ts +13 -0
  29. package/{handlers → dist/handlers}/managedOAuth.js +102 -30
  30. package/dist/handlers/plugin.d.ts +1 -0
  31. package/{handlers → dist/handlers}/plugin.js +59 -27
  32. package/dist/handlers/user.d.ts +1 -0
  33. package/{handlers → dist/handlers}/user.js +45 -27
  34. package/dist/index.d.ts +1 -0
  35. package/{index.js → dist/index.js} +538 -449
  36. package/dist/jest.config.d.ts +1 -0
  37. package/dist/jest.config.js +65 -0
  38. package/dist/lib/analytics.d.ts +4 -0
  39. package/{lib → dist/lib}/analytics.js +8 -6
  40. package/dist/lib/authSession.d.ts +5 -0
  41. package/{lib → dist/lib}/authSession.js +15 -43
  42. package/dist/lib/cacheCleanup.d.ts +4 -0
  43. package/{lib → dist/lib}/cacheCleanup.js +5 -17
  44. package/dist/lib/callLogComposer.d.ts +109 -0
  45. package/{lib → dist/lib}/callLogComposer.js +157 -197
  46. package/dist/lib/callLogLookup.d.ts +6 -0
  47. package/{lib → dist/lib}/callLogLookup.js +12 -34
  48. package/dist/lib/constants.d.ts +6 -0
  49. package/dist/lib/constants.js +9 -0
  50. package/dist/lib/debugTracer.d.ts +17 -0
  51. package/{lib → dist/lib}/debugTracer.js +7 -83
  52. package/dist/lib/encode.d.ts +3 -0
  53. package/dist/lib/encode.js +50 -0
  54. package/dist/lib/errorHandler.d.ts +7 -0
  55. package/dist/lib/errorHandler.js +161 -0
  56. package/dist/lib/generalErrorMessage.d.ts +7 -0
  57. package/{lib → dist/lib}/generalErrorMessage.js +6 -6
  58. package/dist/lib/jwt.d.ts +4 -0
  59. package/dist/lib/jwt.js +18 -0
  60. package/dist/lib/logger.d.ts +24 -0
  61. package/dist/lib/logger.js +126 -0
  62. package/dist/lib/migrateCallLogsSchema.d.ts +32 -0
  63. package/{lib → dist/lib}/migrateCallLogsSchema.js +75 -160
  64. package/dist/lib/oauth.d.ts +4 -0
  65. package/{lib → dist/lib}/oauth.js +157 -160
  66. package/dist/lib/ringcentral.d.ts +24 -0
  67. package/dist/lib/ringcentral.js +226 -0
  68. package/dist/lib/s3ErrorLogReport.d.ts +4 -0
  69. package/{lib → dist/lib}/s3ErrorLogReport.js +11 -23
  70. package/dist/lib/sharedSMSComposer.d.ts +7 -0
  71. package/{lib → dist/lib}/sharedSMSComposer.js +21 -107
  72. package/dist/lib/util.d.ts +7 -0
  73. package/{lib → dist/lib}/util.js +9 -20
  74. package/dist/mcp/lib/oauthError.d.ts +1 -0
  75. package/dist/mcp/lib/oauthError.js +25 -0
  76. package/dist/mcp/lib/validator.d.ts +1 -0
  77. package/{mcp → dist/mcp}/lib/validator.js +16 -20
  78. package/dist/mcp/lib/widgetSessionToken.d.ts +1 -0
  79. package/dist/mcp/lib/widgetSessionToken.js +46 -0
  80. package/dist/mcp/mcpHandler.d.ts +8 -0
  81. package/{mcp → dist/mcp}/mcpHandler.js +98 -88
  82. package/dist/mcp/tools/cancelAppointment.d.ts +1 -0
  83. package/{mcp → dist/mcp}/tools/cancelAppointment.js +7 -16
  84. package/dist/mcp/tools/checkAuthStatus.d.ts +1 -0
  85. package/{mcp → dist/mcp}/tools/checkAuthStatus.js +21 -14
  86. package/dist/mcp/tools/confirmAppointment.d.ts +1 -0
  87. package/{mcp → dist/mcp}/tools/confirmAppointment.js +7 -16
  88. package/dist/mcp/tools/createAppointment.d.ts +1 -0
  89. package/{mcp → dist/mcp}/tools/createAppointment.js +7 -19
  90. package/dist/mcp/tools/createCallLog.d.ts +1 -0
  91. package/{mcp → dist/mcp}/tools/createCallLog.js +18 -29
  92. package/dist/mcp/tools/createContact.d.ts +1 -0
  93. package/{mcp → dist/mcp}/tools/createContact.js +8 -20
  94. package/dist/mcp/tools/createMessageLog.d.ts +1 -0
  95. package/{mcp → dist/mcp}/tools/createMessageLog.js +14 -26
  96. package/dist/mcp/tools/doAuth.d.ts +1 -0
  97. package/{mcp → dist/mcp}/tools/doAuth.js +17 -13
  98. package/dist/mcp/tools/findContactByName.d.ts +1 -0
  99. package/{mcp → dist/mcp}/tools/findContactByName.js +9 -15
  100. package/dist/mcp/tools/findContactByPhone.d.ts +1 -0
  101. package/{mcp → dist/mcp}/tools/findContactByPhone.js +8 -15
  102. package/dist/mcp/tools/getCallLog.d.ts +1 -0
  103. package/{mcp → dist/mcp}/tools/getCallLog.js +12 -21
  104. package/dist/mcp/tools/getGoogleFilePicker.d.ts +1 -0
  105. package/{mcp → dist/mcp}/tools/getGoogleFilePicker.js +9 -18
  106. package/dist/mcp/tools/getHelp.d.ts +1 -0
  107. package/{mcp → dist/mcp}/tools/getHelp.js +5 -6
  108. package/dist/mcp/tools/getPublicConnectors.d.ts +1 -0
  109. package/{mcp → dist/mcp}/tools/getPublicConnectors.js +19 -18
  110. package/dist/mcp/tools/getSessionInfo.d.ts +1 -0
  111. package/{mcp → dist/mcp}/tools/getSessionInfo.js +10 -16
  112. package/dist/mcp/tools/index.d.ts +8 -0
  113. package/dist/mcp/tools/index.js +50 -0
  114. package/dist/mcp/tools/listAppointments.d.ts +1 -0
  115. package/{mcp → dist/mcp}/tools/listAppointments.js +7 -19
  116. package/dist/mcp/tools/logout.d.ts +1 -0
  117. package/{mcp → dist/mcp}/tools/logout.js +16 -14
  118. package/dist/mcp/tools/rcGetCallLogs.d.ts +1 -0
  119. package/{mcp → dist/mcp}/tools/rcGetCallLogs.js +10 -8
  120. package/dist/mcp/tools/updateAppointment.d.ts +1 -0
  121. package/{mcp → dist/mcp}/tools/updateAppointment.js +17 -22
  122. package/dist/mcp/tools/updateCallLog.d.ts +1 -0
  123. package/{mcp → dist/mcp}/tools/updateCallLog.js +16 -26
  124. package/dist/models/accountDataModel.d.ts +3 -0
  125. package/dist/models/accountDataModel.js +39 -0
  126. package/dist/models/adminConfigModel.d.ts +2 -0
  127. package/dist/models/adminConfigModel.js +39 -0
  128. package/dist/models/cacheModel.d.ts +2 -0
  129. package/{models → dist/models}/cacheModel.js +7 -3
  130. package/dist/models/callDownListModel.d.ts +2 -0
  131. package/{models → dist/models}/callDownListModel.js +8 -4
  132. package/dist/models/callLogModel.d.ts +2 -0
  133. package/dist/models/callLogModel.js +43 -0
  134. package/dist/models/dynamo/connectorSchema.d.ts +2 -0
  135. package/dist/models/dynamo/connectorSchema.js +141 -0
  136. package/dist/models/dynamo/lockSchema.d.ts +2 -0
  137. package/{models → dist/models}/dynamo/lockSchema.js +5 -7
  138. package/dist/models/dynamo/noteCacheSchema.d.ts +2 -0
  139. package/{models → dist/models}/dynamo/noteCacheSchema.js +4 -6
  140. package/dist/models/llmSessionModel.d.ts +2 -0
  141. package/dist/models/llmSessionModel.js +21 -0
  142. package/dist/models/messageLogModel.d.ts +2 -0
  143. package/{models → dist/models}/messageLogModel.js +8 -4
  144. package/dist/models/sequelize.d.ts +2 -0
  145. package/dist/models/sequelize.js +68 -0
  146. package/dist/models/userModel.d.ts +2 -0
  147. package/dist/models/userModel.js +49 -0
  148. package/dist/package.json +100 -0
  149. package/dist/releaseNotes.json +1222 -0
  150. package/dist/tsconfig.json +14 -0
  151. package/dist/types/admin.d.ts +141 -0
  152. package/dist/types/analytics.d.ts +14 -0
  153. package/dist/types/appointment.d.ts +50 -0
  154. package/dist/types/auth.d.ts +137 -0
  155. package/dist/types/authSession.d.ts +35 -0
  156. package/dist/types/cacheCleanup.d.ts +12 -0
  157. package/dist/types/calldown.d.ts +54 -0
  158. package/dist/types/common.d.ts +46 -0
  159. package/dist/types/connector.d.ts +165 -0
  160. package/dist/types/contact.d.ts +125 -0
  161. package/dist/types/errorHandler.d.ts +60 -0
  162. package/dist/types/index.d.ts +76 -0
  163. package/dist/types/json.d.ts +9 -0
  164. package/dist/types/jwt.d.ts +8 -0
  165. package/dist/types/logging.d.ts +224 -0
  166. package/dist/types/managedAuth.d.ts +114 -0
  167. package/dist/types/managedOAuth.d.ts +59 -0
  168. package/dist/types/manifest.d.ts +120 -0
  169. package/dist/types/migration.d.ts +15 -0
  170. package/dist/types/plugin.d.ts +74 -0
  171. package/dist/types/ringcentral.d.ts +61 -0
  172. package/dist/types/s3ErrorLogReport.d.ts +16 -0
  173. package/dist/types/sharedSMSComposer.d.ts +105 -0
  174. package/dist/types/user.d.ts +46 -0
  175. package/dist/types/util.d.ts +7 -0
  176. package/package.json +34 -6
  177. package/releaseNotes.json +8 -0
  178. package/.env.test +0 -5
  179. package/connector/proxy/engine.js +0 -165
  180. package/connector/proxy/index.js +0 -500
  181. package/connector/registry.js +0 -252
  182. package/docs/README.md +0 -50
  183. package/docs/architecture.md +0 -94
  184. package/docs/connectors.md +0 -116
  185. package/docs/handlers.md +0 -128
  186. package/docs/libraries.md +0 -98
  187. package/docs/models.md +0 -146
  188. package/docs/routes.md +0 -119
  189. package/docs/tests.md +0 -73
  190. package/handlers/calldown.js +0 -99
  191. package/jest.config.js +0 -57
  192. package/lib/constants.js +0 -9
  193. package/lib/encode.js +0 -30
  194. package/lib/errorHandler.js +0 -218
  195. package/lib/jwt.js +0 -18
  196. package/lib/logger.js +0 -190
  197. package/lib/ringcentral.js +0 -267
  198. package/mcp/README.md +0 -420
  199. package/mcp/tools/index.js +0 -51
  200. package/mcp/ui/App/App.tsx +0 -358
  201. package/mcp/ui/App/components/AuthInfoForm.tsx +0 -113
  202. package/mcp/ui/App/components/AuthSuccess.tsx +0 -22
  203. package/mcp/ui/App/components/ConnectorList.tsx +0 -82
  204. package/mcp/ui/App/components/DebugPanel.tsx +0 -43
  205. package/mcp/ui/App/components/OAuthConnect.tsx +0 -270
  206. package/mcp/ui/App/lib/callTool.ts +0 -130
  207. package/mcp/ui/App/lib/debugLog.ts +0 -41
  208. package/mcp/ui/App/lib/developerPortal.ts +0 -111
  209. package/mcp/ui/App/main.css +0 -6
  210. package/mcp/ui/App/root.tsx +0 -13
  211. package/mcp/ui/dist/index.html +0 -53
  212. package/mcp/ui/vite.config.ts +0 -16
  213. package/models/accountDataModel.js +0 -34
  214. package/models/adminConfigModel.js +0 -35
  215. package/models/callLogModel.js +0 -39
  216. package/models/dynamo/connectorSchema.js +0 -146
  217. package/models/llmSessionModel.js +0 -17
  218. package/models/sequelize.js +0 -17
  219. package/models/userModel.js +0 -45
  220. package/test/connector/developerPortal.test.js +0 -166
  221. package/test/connector/mock.test.js +0 -131
  222. package/test/connector/proxy/engine.test.js +0 -211
  223. package/test/connector/proxy/index.test.js +0 -525
  224. package/test/connector/proxy/sample.json +0 -162
  225. package/test/connector/registry.test.js +0 -416
  226. package/test/handlers/admin.test.js +0 -960
  227. package/test/handlers/appointment.test.js +0 -260
  228. package/test/handlers/auth.test.js +0 -1096
  229. package/test/handlers/calldown.test.js +0 -310
  230. package/test/handlers/contact.test.js +0 -1014
  231. package/test/handlers/disposition.test.js +0 -396
  232. package/test/handlers/log.test.js +0 -1847
  233. package/test/handlers/managedAuth.test.js +0 -458
  234. package/test/handlers/managedOAuth.test.js +0 -262
  235. package/test/handlers/plugin.test.js +0 -429
  236. package/test/handlers/user.test.js +0 -381
  237. package/test/index.test.js +0 -301
  238. package/test/lib/analytics.test.js +0 -146
  239. package/test/lib/authSession.test.js +0 -173
  240. package/test/lib/cacheCleanup.test.js +0 -127
  241. package/test/lib/callLogComposer.test.js +0 -1231
  242. package/test/lib/debugTracer.test.js +0 -328
  243. package/test/lib/encode.test.js +0 -59
  244. package/test/lib/errorHandler.test.js +0 -246
  245. package/test/lib/generalErrorMessage.test.js +0 -82
  246. package/test/lib/jwt.test.js +0 -176
  247. package/test/lib/logger.test.js +0 -206
  248. package/test/lib/oauth.test.js +0 -359
  249. package/test/lib/ringcentral.test.js +0 -467
  250. package/test/lib/s3ErrorLogReport.test.js +0 -187
  251. package/test/lib/sharedSMSComposer.test.js +0 -1084
  252. package/test/lib/util.test.js +0 -329
  253. package/test/mcp/mcpHandler.test.js +0 -73
  254. package/test/mcp/mcpHandlerMore.test.js +0 -384
  255. package/test/mcp/tools/appointmentTools.test.js +0 -362
  256. package/test/mcp/tools/checkAuthStatus.test.js +0 -83
  257. package/test/mcp/tools/createCallLog.test.js +0 -436
  258. package/test/mcp/tools/createContact.test.js +0 -58
  259. package/test/mcp/tools/createMessageLog.test.js +0 -595
  260. package/test/mcp/tools/doAuth.test.js +0 -113
  261. package/test/mcp/tools/findContactByName.test.js +0 -275
  262. package/test/mcp/tools/findContactByPhone.test.js +0 -296
  263. package/test/mcp/tools/getCallLog.test.js +0 -298
  264. package/test/mcp/tools/getGoogleFilePicker.test.js +0 -281
  265. package/test/mcp/tools/getPublicConnectors.test.js +0 -107
  266. package/test/mcp/tools/getSessionInfo.test.js +0 -127
  267. package/test/mcp/tools/logout.test.js +0 -233
  268. package/test/mcp/tools/rcGetCallLogs.test.js +0 -56
  269. package/test/mcp/tools/updateCallLog.test.js +0 -360
  270. package/test/models/accountDataModel.test.js +0 -98
  271. package/test/models/callDownListModel.test.js +0 -125
  272. package/test/models/dynamo/connectorSchema.test.js +0 -189
  273. package/test/models/dynamo/lockSchema.test.js +0 -37
  274. package/test/models/dynamo/noteCacheSchema.test.js +0 -45
  275. package/test/models/llmSessionModel.test.js +0 -91
  276. package/test/models/models.test.js +0 -660
  277. package/test/routes/calldownRoutes.test.js +0 -224
  278. package/test/routes/coreRouterBroadRoutes.test.js +0 -855
  279. package/test/routes/dispositionRoutes.test.js +0 -192
  280. package/test/routes/managedAuthRoutes.test.js +0 -386
  281. package/test/routes/pluginRoutes.test.js +0 -262
  282. package/test/setup.js +0 -178
  283. /package/{mcp → dist/mcp}/ui/index.html +0 -0
  284. /package/{mcp → dist/mcp}/ui/package-lock.json +0 -0
  285. /package/{mcp → dist/mcp}/ui/package.json +0 -0
  286. /package/{mcp → dist/mcp}/ui/tsconfig.json +0 -0
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ const util = require('util');
3
+ const LOG_LEVELS = {
4
+ ERROR: 0,
5
+ WARN: 1,
6
+ INFO: 2,
7
+ DEBUG: 3
8
+ };
9
+ const COLORS = {
10
+ ERROR: '\x1b[31m',
11
+ WARN: '\x1b[33m',
12
+ INFO: '\x1b[36m',
13
+ DEBUG: '\x1b[90m',
14
+ RESET: '\x1b[0m'
15
+ };
16
+ class Logger {
17
+ constructor(options = {}) {
18
+ this.level = this._getLogLevel(options.level || process.env.LOG_LEVEL || 'INFO');
19
+ this.isProd = process.env.NODE_ENV === 'production';
20
+ this.enableColors = !this.isProd && Boolean(process.stdout.isTTY);
21
+ }
22
+ _getLogLevel(levelName) {
23
+ const upperLevel = levelName.toUpperCase();
24
+ return LOG_LEVELS[upperLevel] !== undefined ? LOG_LEVELS[upperLevel] : LOG_LEVELS.INFO;
25
+ }
26
+ _shouldLog(level) {
27
+ return LOG_LEVELS[level] <= this.level;
28
+ }
29
+ _formatMessage(level, message, context = {}) {
30
+ const timestamp = new Date().toISOString();
31
+ if (this.isProd) {
32
+ return JSON.stringify({
33
+ timestamp,
34
+ level,
35
+ message,
36
+ ...context
37
+ });
38
+ }
39
+ const color = this.enableColors ? COLORS[level] : '';
40
+ const reset = this.enableColors ? COLORS.RESET : '';
41
+ const contextStr = Object.keys(context).length > 0
42
+ ? '\n' + util.inspect(context, { depth: 4, colors: this.enableColors })
43
+ : '';
44
+ return `${color}[${timestamp}] [${level}]${reset} ${message}${contextStr}`;
45
+ }
46
+ _log(level, message, context = {}) {
47
+ if (!this._shouldLog(level)) {
48
+ return;
49
+ }
50
+ const formattedMessage = this._formatMessage(level, message, context);
51
+ if (level === 'ERROR' || level === 'WARN') {
52
+ console.error(formattedMessage);
53
+ }
54
+ else {
55
+ console.log(formattedMessage);
56
+ }
57
+ }
58
+ error(message, context = {}) {
59
+ let enrichedContext = context;
60
+ if (context.error instanceof Error) {
61
+ const { error, ...rest } = context;
62
+ const response = error.response;
63
+ enrichedContext = {
64
+ ...rest,
65
+ errorMessage: error.message,
66
+ errorStack: error.stack,
67
+ errorResponse: response?.data,
68
+ errorStatus: response?.status
69
+ };
70
+ }
71
+ this._log('ERROR', message, enrichedContext);
72
+ }
73
+ warn(message, context = {}) {
74
+ this._log('WARN', message, context);
75
+ }
76
+ info(message, context = {}) {
77
+ this._log('INFO', message, context);
78
+ }
79
+ debug(message, context = {}) {
80
+ this._log('DEBUG', message, context);
81
+ }
82
+ child(defaultContext = {}) {
83
+ return {
84
+ error: (message, context = {}) => this.error(message, { ...defaultContext, ...context }),
85
+ warn: (message, context = {}) => this.warn(message, { ...defaultContext, ...context }),
86
+ info: (message, context = {}) => this.info(message, { ...defaultContext, ...context }),
87
+ debug: (message, context = {}) => this.debug(message, { ...defaultContext, ...context }),
88
+ child: (additionalContext = {}) => this.child({ ...defaultContext, ...additionalContext })
89
+ };
90
+ }
91
+ logApiRequest({ method, url, status, duration, platform, error }) {
92
+ const context = {
93
+ method,
94
+ url,
95
+ status,
96
+ duration: duration ? `${duration}ms` : undefined,
97
+ platform
98
+ };
99
+ if (error) {
100
+ this.error('API request failed', { ...context, error });
101
+ }
102
+ else if (status !== undefined && status >= 400) {
103
+ this.warn('API request returned error status', context);
104
+ }
105
+ else {
106
+ this.debug('API request completed', context);
107
+ }
108
+ }
109
+ logDatabaseQuery({ operation, table, duration, error }) {
110
+ const context = {
111
+ operation,
112
+ table,
113
+ duration: duration ? `${duration}ms` : undefined
114
+ };
115
+ if (error) {
116
+ this.error('Database query failed', { ...context, error });
117
+ }
118
+ else {
119
+ this.debug('Database query completed', context);
120
+ }
121
+ }
122
+ }
123
+ const logger = new Logger();
124
+ logger.Logger = Logger;
125
+ logger.LOG_LEVELS = LOG_LEVELS;
126
+ module.exports = logger;
@@ -0,0 +1,32 @@
1
+ import type { MigrationLogger, SequelizeLike, SequelizeTransactionLike, TableDescription } from '../types';
2
+ declare function findColumnKey(tableDescription: TableDescription, name: string): string | undefined;
3
+ declare function sqliteCallLogsPkIncludesExtension(sequelize: SequelizeLike, options?: Record<string, unknown>): Promise<boolean>;
4
+ declare function sqliteCallLogsPkIncludesHashedExtension(sequelize: SequelizeLike, options?: Record<string, unknown>): Promise<boolean>;
5
+ /**
6
+ * SQLite cannot change composite PK via Sequelize addConstraint (it appends a second PRIMARY KEY).
7
+ * Rebuild the table with the current call-log identity primary key and copy rows.
8
+ */
9
+ declare function migrateCallLogsIdentitySqlite(sequelize: SequelizeLike, transaction: SequelizeTransactionLike): Promise<void>;
10
+ declare function migrateCallLogsExtensionNumberSqlite(sequelize: SequelizeLike, transaction: SequelizeTransactionLike): Promise<void>;
11
+ declare function ensureCallLogsHashedExtensionIdSchema(sequelize: SequelizeLike): Promise<void>;
12
+ /**
13
+ * Online (non-blocking) Postgres migration.
14
+ *
15
+ * Adds the hashedExtensionId column and rebuilds the primary key to the call-log
16
+ * identity WITHOUT holding an ACCESS EXCLUSIVE lock for the duration of the index
17
+ * build. This is the safe path for large production tables:
18
+ * - ADD COLUMN ... NOT NULL DEFAULT '' is metadata-only on PG 11+.
19
+ * - CREATE UNIQUE INDEX CONCURRENTLY builds the index while reads/writes continue.
20
+ * - ADD PRIMARY KEY USING INDEX attaches the prebuilt index with only a brief lock.
21
+ *
22
+ * Runs on a single dedicated pooled connection so the advisory lock and the
23
+ * (necessarily non-transactional) CONCURRENTLY statements share one backend session.
24
+ */
25
+ declare function ensureCallLogsHashedExtensionIdSchemaPostgresOnline(sequelize: SequelizeLike, logger?: MigrationLogger): Promise<void>;
26
+ /**
27
+ * Automatic entry point. Safe to call fire-and-forget off the startup critical path:
28
+ * it never throws (failures are logged and retried on the next boot) and, on Postgres,
29
+ * never blocks readiness or live traffic.
30
+ */
31
+ declare function runCallLogsSchemaMigration(sequelize: SequelizeLike, logger?: MigrationLogger): Promise<void>;
32
+ export { findColumnKey, migrateCallLogsExtensionNumberSqlite, migrateCallLogsIdentitySqlite, sqliteCallLogsPkIncludesExtension, sqliteCallLogsPkIncludesHashedExtension, ensureCallLogsHashedExtensionIdSchema, ensureCallLogsHashedExtensionIdSchemaPostgresOnline, runCallLogsSchemaMigration };
@@ -1,22 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findColumnKey = findColumnKey;
4
+ exports.migrateCallLogsExtensionNumberSqlite = migrateCallLogsExtensionNumberSqlite;
5
+ exports.migrateCallLogsIdentitySqlite = migrateCallLogsIdentitySqlite;
6
+ exports.sqliteCallLogsPkIncludesExtension = sqliteCallLogsPkIncludesExtension;
7
+ exports.sqliteCallLogsPkIncludesHashedExtension = sqliteCallLogsPkIncludesHashedExtension;
8
+ exports.ensureCallLogsHashedExtensionIdSchema = ensureCallLogsHashedExtensionIdSchema;
9
+ exports.ensureCallLogsHashedExtensionIdSchemaPostgresOnline = ensureCallLogsHashedExtensionIdSchemaPostgresOnline;
10
+ exports.runCallLogsSchemaMigration = runCallLogsSchemaMigration;
1
11
  const Sequelize = require('sequelize');
2
-
3
12
  const CALL_LOGS_TABLE = 'callLogs';
4
13
  const HASHED_EXTENSION_ID_COLUMN = 'hashedExtensionId';
5
14
  const CALL_LOG_IDENTITY_PK_COLUMNS = ['id', 'sessionId', 'extensionNumber', HASHED_EXTENSION_ID_COLUMN];
6
-
7
15
  function findColumnKey(tableDescription, name) {
8
16
  const lower = name.toLowerCase();
9
17
  return Object.keys(tableDescription).find((k) => k.toLowerCase() === lower);
10
18
  }
11
-
12
19
  async function fetchCallLogsCreateSqlSqlite(sequelize, options = {}) {
13
- const rows = await sequelize.query(
14
- "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'callLogs'",
15
- { type: Sequelize.QueryTypes.SELECT, ...options },
16
- );
20
+ const rows = await sequelize.query("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'callLogs'", { type: Sequelize.QueryTypes.SELECT, ...options });
17
21
  return rows[0]?.sql ?? null;
18
22
  }
19
-
20
23
  function callLogsCreateSqlClaimsPkColumns(createSql, columns) {
21
24
  if (!createSql || typeof createSql !== 'string') {
22
25
  return false;
@@ -33,25 +36,20 @@ function callLogsCreateSqlClaimsPkColumns(createSql, columns) {
33
36
  }
34
37
  return false;
35
38
  }
36
-
37
39
  function callLogsCreateSqlClaimsExtensionPk(createSql) {
38
40
  return callLogsCreateSqlClaimsPkColumns(createSql, ['extensionNumber']);
39
41
  }
40
-
41
42
  async function sqliteCallLogsPkIncludesExtension(sequelize, options = {}) {
42
43
  const sql = await fetchCallLogsCreateSqlSqlite(sequelize, options);
43
44
  return callLogsCreateSqlClaimsExtensionPk(sql);
44
45
  }
45
-
46
46
  async function sqliteCallLogsPkIncludesHashedExtension(sequelize, options = {}) {
47
47
  const sql = await fetchCallLogsCreateSqlSqlite(sequelize, options);
48
48
  return callLogsCreateSqlClaimsPkColumns(sql, CALL_LOG_IDENTITY_PK_COLUMNS);
49
49
  }
50
-
51
50
  async function describeCallLogsTable(sequelize, options = {}) {
52
51
  return sequelize.getQueryInterface().describeTable(CALL_LOGS_TABLE, options);
53
52
  }
54
-
55
53
  /**
56
54
  * SQLite cannot change composite PK via Sequelize addConstraint (it appends a second PRIMARY KEY).
57
55
  * Rebuild the table with the current call-log identity primary key and copy rows.
@@ -63,14 +61,8 @@ async function migrateCallLogsIdentitySqlite(sequelize, transaction) {
63
61
  const tmpName = `callLogs_mig_legacy_${Date.now()}`;
64
62
  const mainTableSql = qg.quoteTable({ tableName: CALL_LOGS_TABLE });
65
63
  const tmpTableSql = qg.quoteTable({ tableName: tmpName });
66
-
67
- await sequelize.query(
68
- `ALTER TABLE ${mainTableSql} RENAME TO ${qg.quoteIdentifier(tmpName)};`,
69
- { transaction },
70
- );
71
-
72
- await sequelize.query(
73
- `
64
+ await sequelize.query(`ALTER TABLE ${mainTableSql} RENAME TO ${qg.quoteIdentifier(tmpName)};`, { transaction });
65
+ await sequelize.query(`
74
66
  CREATE TABLE ${mainTableSql} (
75
67
  ${q('id')} VARCHAR(255) NOT NULL,
76
68
  ${q('sessionId')} VARCHAR(255) NOT NULL,
@@ -84,12 +76,8 @@ async function migrateCallLogsIdentitySqlite(sequelize, transaction) {
84
76
  ${q('updatedAt')} DATETIME NOT NULL,
85
77
  PRIMARY KEY (${CALL_LOG_IDENTITY_PK_COLUMNS.map(q).join(', ')})
86
78
  );
87
- `,
88
- { transaction },
89
- );
90
-
79
+ `, { transaction });
91
80
  const oldDesc = await qi.describeTable(tmpName, { transaction });
92
-
93
81
  const targetCols = [
94
82
  'id',
95
83
  'sessionId',
@@ -102,102 +90,73 @@ async function migrateCallLogsIdentitySqlite(sequelize, transaction) {
102
90
  'createdAt',
103
91
  'updatedAt',
104
92
  ];
105
-
106
- const missingRequired = targetCols.filter(
107
- (c) => findColumnKey(oldDesc, c) == null && c !== 'extensionNumber' && c !== HASHED_EXTENSION_ID_COLUMN,
108
- );
93
+ const missingRequired = targetCols.filter((c) => findColumnKey(oldDesc, c) == null && c !== 'extensionNumber' && c !== HASHED_EXTENSION_ID_COLUMN);
109
94
  if (missingRequired.length) {
110
- throw new Error(
111
- `unexpected callLogs schema before migration (missing columns: ${missingRequired.join(', ')})`,
112
- );
95
+ throw new Error(`unexpected callLogs schema before migration (missing columns: ${missingRequired.join(', ')})`);
113
96
  }
114
-
115
97
  const insertCols = targetCols.map(q).join(', ');
116
98
  const selectExprs = targetCols
117
99
  .map((col) => {
118
- const key = findColumnKey(oldDesc, col);
119
- if (key != null) {
120
- return q(key);
121
- }
122
- return `CAST('' AS VARCHAR(255))`;
123
- })
100
+ const key = findColumnKey(oldDesc, col);
101
+ if (key != null) {
102
+ return q(key);
103
+ }
104
+ return `CAST('' AS VARCHAR(255))`;
105
+ })
124
106
  .join(', ');
125
-
126
- await sequelize.query(
127
- `INSERT INTO ${mainTableSql} (${insertCols}) SELECT ${selectExprs} FROM ${tmpTableSql};`,
128
- { transaction },
129
- );
130
-
107
+ await sequelize.query(`INSERT INTO ${mainTableSql} (${insertCols}) SELECT ${selectExprs} FROM ${tmpTableSql};`, { transaction });
131
108
  await sequelize.query(`DROP TABLE ${tmpTableSql};`, { transaction });
132
109
  }
133
-
134
110
  async function migrateCallLogsExtensionNumberSqlite(sequelize, transaction) {
135
111
  return migrateCallLogsIdentitySqlite(sequelize, transaction);
136
112
  }
137
-
138
113
  async function getPostgresPrimaryKeyConstraint(sequelize, options = {}) {
139
- const constraints = await sequelize.query(
140
- `
114
+ const constraints = await sequelize.query(`
141
115
  SELECT tc.constraint_name AS "constraintName"
142
116
  FROM information_schema.table_constraints tc
143
117
  WHERE tc.table_name = :tableName
144
118
  AND tc.constraint_type = 'PRIMARY KEY'
145
119
  LIMIT 1
146
- `,
147
- {
148
- type: Sequelize.QueryTypes.SELECT,
149
- replacements: { tableName: CALL_LOGS_TABLE },
150
- ...options,
151
- },
152
- );
120
+ `, {
121
+ type: Sequelize.QueryTypes.SELECT,
122
+ replacements: { tableName: CALL_LOGS_TABLE },
123
+ ...options,
124
+ });
153
125
  return constraints[0]?.constraintName ?? null;
154
126
  }
155
-
156
127
  async function postgresCallLogsPkIncludesHashedExtension(sequelize, options = {}) {
157
128
  const pkConstraintName = await getPostgresPrimaryKeyConstraint(sequelize, options);
158
129
  if (!pkConstraintName) {
159
130
  return false;
160
131
  }
161
- const rows = await sequelize.query(
162
- `
132
+ const rows = await sequelize.query(`
163
133
  SELECT kcu.column_name AS "columnName"
164
134
  FROM information_schema.key_column_usage kcu
165
135
  WHERE kcu.table_name = :tableName
166
136
  AND kcu.constraint_name = :constraintName
167
137
  ORDER BY kcu.ordinal_position
168
- `,
169
- {
170
- type: Sequelize.QueryTypes.SELECT,
171
- replacements: { tableName: CALL_LOGS_TABLE, constraintName: pkConstraintName },
172
- ...options,
173
- },
174
- );
138
+ `, {
139
+ type: Sequelize.QueryTypes.SELECT,
140
+ replacements: { tableName: CALL_LOGS_TABLE, constraintName: pkConstraintName },
141
+ ...options,
142
+ });
175
143
  const pkColumns = rows.map((row) => row.columnName.toLowerCase());
176
144
  return CALL_LOG_IDENTITY_PK_COLUMNS.every((column) => pkColumns.includes(column.toLowerCase()));
177
145
  }
178
-
179
146
  async function migrateCallLogsIdentityPostgres(sequelize, transaction) {
180
147
  const qi = sequelize.getQueryInterface();
181
148
  const qg = qi.queryGenerator;
182
149
  const table = qg.quoteTable({ tableName: CALL_LOGS_TABLE });
183
150
  const pkConstraintName = await getPostgresPrimaryKeyConstraint(sequelize, { transaction });
184
151
  if (pkConstraintName) {
185
- await sequelize.query(
186
- `ALTER TABLE ${table} DROP CONSTRAINT ${qg.quoteIdentifier(pkConstraintName)};`,
187
- { transaction },
188
- );
152
+ await sequelize.query(`ALTER TABLE ${table} DROP CONSTRAINT ${qg.quoteIdentifier(pkConstraintName)};`, { transaction });
189
153
  }
190
- await sequelize.query(
191
- `ALTER TABLE ${table} ADD PRIMARY KEY (${CALL_LOG_IDENTITY_PK_COLUMNS.map((column) => qg.quoteIdentifier(column)).join(', ')});`,
192
- { transaction },
193
- );
154
+ await sequelize.query(`ALTER TABLE ${table} ADD PRIMARY KEY (${CALL_LOG_IDENTITY_PK_COLUMNS.map((column) => qg.quoteIdentifier(column)).join(', ')});`, { transaction });
194
155
  }
195
-
196
156
  async function ensureCallLogsHashedExtensionIdSchema(sequelize) {
197
157
  const qi = sequelize.getQueryInterface();
198
158
  const dialect = sequelize.getDialect();
199
159
  let desc = await describeCallLogsTable(sequelize);
200
-
201
160
  if (findColumnKey(desc, HASHED_EXTENSION_ID_COLUMN) == null) {
202
161
  await qi.addColumn(CALL_LOGS_TABLE, HASHED_EXTENSION_ID_COLUMN, {
203
162
  type: Sequelize.STRING,
@@ -206,7 +165,6 @@ async function ensureCallLogsHashedExtensionIdSchema(sequelize) {
206
165
  });
207
166
  desc = await describeCallLogsTable(sequelize);
208
167
  }
209
-
210
168
  if (dialect === 'sqlite') {
211
169
  const hasIdentityPk = await sqliteCallLogsPkIncludesHashedExtension(sequelize);
212
170
  if (!hasIdentityPk) {
@@ -216,7 +174,6 @@ async function ensureCallLogsHashedExtensionIdSchema(sequelize) {
216
174
  }
217
175
  return;
218
176
  }
219
-
220
177
  if (dialect === 'postgres') {
221
178
  const hasIdentityPk = await postgresCallLogsPkIncludesHashedExtension(sequelize);
222
179
  if (!hasIdentityPk) {
@@ -226,59 +183,43 @@ async function ensureCallLogsHashedExtensionIdSchema(sequelize) {
226
183
  }
227
184
  }
228
185
  }
229
-
230
186
  // Dedicated name for the online-built unique index that becomes the new PK.
231
187
  const IDENTITY_INDEX_NAME = 'callLogs_identity_pk';
232
188
  // Stable application-wide key for the Postgres advisory lock that serializes the
233
189
  // migration across concurrently-booting instances. Any fixed integer works as long
234
190
  // as it is unique within the app; keep it constant so every instance agrees on it.
235
191
  const CALL_LOGS_MIGRATION_LOCK_KEY = 4972001;
236
-
237
192
  async function postgresPrimaryKeyNameOnConnection(client) {
238
- const { rows } = await client.query(
239
- `SELECT conname FROM pg_constraint
240
- WHERE conrelid = '"${CALL_LOGS_TABLE}"'::regclass AND contype = 'p' LIMIT 1`,
241
- );
193
+ const { rows } = await client.query(`SELECT conname FROM pg_constraint
194
+ WHERE conrelid = '"${CALL_LOGS_TABLE}"'::regclass AND contype = 'p' LIMIT 1`);
242
195
  return rows[0]?.conname ?? null;
243
196
  }
244
-
245
197
  async function postgresPkIncludesIdentityOnConnection(client) {
246
- const { rows } = await client.query(
247
- `SELECT kcu.column_name AS col
198
+ const { rows } = await client.query(`SELECT kcu.column_name AS col
248
199
  FROM information_schema.table_constraints tc
249
200
  JOIN information_schema.key_column_usage kcu
250
201
  ON kcu.constraint_name = tc.constraint_name
251
202
  AND kcu.table_name = tc.table_name
252
- WHERE tc.table_name = $1 AND tc.constraint_type = 'PRIMARY KEY'`,
253
- [CALL_LOGS_TABLE],
254
- );
203
+ WHERE tc.table_name = $1 AND tc.constraint_type = 'PRIMARY KEY'`, [CALL_LOGS_TABLE]);
255
204
  const cols = rows.map((r) => String(r.col).toLowerCase());
256
205
  return CALL_LOG_IDENTITY_PK_COLUMNS.every((c) => cols.includes(c.toLowerCase()));
257
206
  }
258
-
259
207
  async function postgresColumnIsNullableOnConnection(client, column) {
260
- const { rows } = await client.query(
261
- `SELECT is_nullable FROM information_schema.columns
262
- WHERE table_name = $1 AND column_name = $2`,
263
- [CALL_LOGS_TABLE, column],
264
- );
208
+ const { rows } = await client.query(`SELECT is_nullable FROM information_schema.columns
209
+ WHERE table_name = $1 AND column_name = $2`, [CALL_LOGS_TABLE, column]);
265
210
  return rows[0]?.is_nullable === 'YES';
266
211
  }
267
-
268
- // 'absent' | 'valid' | 'invalid' — an INVALID index is the residue of a
212
+ // 'absent' | 'valid' | 'invalid' - an INVALID index is the residue of a
269
213
  // CONCURRENTLY build that was interrupted (process killed, connection dropped).
270
214
  async function postgresIdentityIndexState(client) {
271
- const { rows } = await client.query(
272
- `SELECT (i.indisvalid AND i.indisready) AS ok
215
+ const { rows } = await client.query(`SELECT (i.indisvalid AND i.indisready) AS ok
273
216
  FROM pg_class c
274
217
  JOIN pg_index i ON i.indexrelid = c.oid
275
- WHERE c.relname = $1`,
276
- [IDENTITY_INDEX_NAME],
277
- );
278
- if (rows.length === 0) return 'absent';
218
+ WHERE c.relname = $1`, [IDENTITY_INDEX_NAME]);
219
+ if (rows.length === 0)
220
+ return 'absent';
279
221
  return rows[0].ok ? 'valid' : 'invalid';
280
222
  }
281
-
282
223
  /**
283
224
  * Online (non-blocking) Postgres migration.
284
225
  *
@@ -297,48 +238,33 @@ async function ensureCallLogsHashedExtensionIdSchemaPostgresOnline(sequelize, lo
297
238
  if (await postgresCallLogsPkIncludesHashedExtension(sequelize)) {
298
239
  return;
299
240
  }
300
-
301
241
  const connectionManager = sequelize.connectionManager;
302
242
  const client = await connectionManager.getConnection({ type: 'write' });
303
243
  let lockAcquired = false;
304
244
  try {
305
- const lockRes = await client.query(
306
- `SELECT pg_try_advisory_lock(${CALL_LOGS_MIGRATION_LOCK_KEY}) AS locked`,
307
- );
245
+ const lockRes = await client.query(`SELECT pg_try_advisory_lock(${CALL_LOGS_MIGRATION_LOCK_KEY}) AS locked`);
308
246
  lockAcquired = lockRes.rows[0]?.locked === true;
309
247
  if (!lockAcquired) {
310
248
  logger?.info?.('[callLogs migration] another instance is migrating; skipping this run');
311
249
  return;
312
250
  }
313
-
314
- // Re-check under the lock — another instance may have finished between the
251
+ // Re-check under the lock - another instance may have finished between the
315
252
  // pre-check and acquiring the lock.
316
253
  if (await postgresPkIncludesIdentityOnConnection(client)) {
317
254
  return;
318
255
  }
319
-
320
256
  logger?.info?.('[callLogs migration] starting online migration (add column + rebuild primary key)');
321
-
322
257
  // A server-side statement_timeout (common in RDS parameter groups) would abort
323
258
  // the long CONCURRENTLY build and leave an INVALID index. Disable it for this
324
259
  // session only; it is reset before the connection returns to the pool.
325
260
  await client.query(`SET statement_timeout = 0`);
326
-
327
261
  // 1. Add the column (metadata-only on PG 11+, safe to repeat).
328
- await client.query(
329
- `ALTER TABLE "${CALL_LOGS_TABLE}" ADD COLUMN IF NOT EXISTS "${HASHED_EXTENSION_ID_COLUMN}" varchar(255) NOT NULL DEFAULT ''`,
330
- );
331
-
262
+ await client.query(`ALTER TABLE "${CALL_LOGS_TABLE}" ADD COLUMN IF NOT EXISTS "${HASHED_EXTENSION_ID_COLUMN}" varchar(255) NOT NULL DEFAULT ''`);
332
263
  // 2. Primary-key columns must be NOT NULL. Only touch extensionNumber if needed.
333
264
  if (await postgresColumnIsNullableOnConnection(client, 'extensionNumber')) {
334
- await client.query(
335
- `UPDATE "${CALL_LOGS_TABLE}" SET "extensionNumber" = '' WHERE "extensionNumber" IS NULL`,
336
- );
337
- await client.query(
338
- `ALTER TABLE "${CALL_LOGS_TABLE}" ALTER COLUMN "extensionNumber" SET NOT NULL`,
339
- );
265
+ await client.query(`UPDATE "${CALL_LOGS_TABLE}" SET "extensionNumber" = '' WHERE "extensionNumber" IS NULL`);
266
+ await client.query(`ALTER TABLE "${CALL_LOGS_TABLE}" ALTER COLUMN "extensionNumber" SET NOT NULL`);
340
267
  }
341
-
342
268
  // 3. Build the unique index without blocking traffic (cannot run in a transaction).
343
269
  // Reuse an already-valid index from a prior run so a failed *attach* (step 4)
344
270
  // never forces us to redo the expensive build; only rebuild if it is missing
@@ -348,11 +274,8 @@ async function ensureCallLogsHashedExtensionIdSchemaPostgresOnline(sequelize, lo
348
274
  await client.query(`DROP INDEX CONCURRENTLY IF EXISTS "${IDENTITY_INDEX_NAME}"`);
349
275
  }
350
276
  if (indexState !== 'valid') {
351
- await client.query(
352
- `CREATE UNIQUE INDEX CONCURRENTLY "${IDENTITY_INDEX_NAME}" ON "${CALL_LOGS_TABLE}" (${CALL_LOG_IDENTITY_PK_COLUMNS.map((c) => `"${c}"`).join(', ')})`,
353
- );
277
+ await client.query(`CREATE UNIQUE INDEX CONCURRENTLY "${IDENTITY_INDEX_NAME}" ON "${CALL_LOGS_TABLE}" (${CALL_LOG_IDENTITY_PK_COLUMNS.map((c) => `"${c}"`).join(', ')})`);
354
278
  }
355
-
356
279
  // 4. Swap the primary key onto the prebuilt index (brief ACCESS EXCLUSIVE lock,
357
280
  // no rebuild). Bound the lock wait so that if a long-running query holds the
358
281
  // table we fail fast and retry next boot, instead of parking an exclusive-lock
@@ -360,36 +283,36 @@ async function ensureCallLogsHashedExtensionIdSchemaPostgresOnline(sequelize, lo
360
283
  await client.query(`SET lock_timeout = '5s'`);
361
284
  const pkName = await postgresPrimaryKeyNameOnConnection(client);
362
285
  if (pkName) {
363
- await client.query(
364
- `ALTER TABLE "${CALL_LOGS_TABLE}" DROP CONSTRAINT "${pkName}", ADD PRIMARY KEY USING INDEX "${IDENTITY_INDEX_NAME}"`,
365
- );
366
- } else {
367
- await client.query(
368
- `ALTER TABLE "${CALL_LOGS_TABLE}" ADD PRIMARY KEY USING INDEX "${IDENTITY_INDEX_NAME}"`,
369
- );
286
+ await client.query(`ALTER TABLE "${CALL_LOGS_TABLE}" DROP CONSTRAINT "${pkName}", ADD PRIMARY KEY USING INDEX "${IDENTITY_INDEX_NAME}"`);
287
+ }
288
+ else {
289
+ await client.query(`ALTER TABLE "${CALL_LOGS_TABLE}" ADD PRIMARY KEY USING INDEX "${IDENTITY_INDEX_NAME}"`);
370
290
  }
371
-
372
291
  logger?.info?.('[callLogs migration] completed');
373
- } finally {
292
+ }
293
+ finally {
374
294
  // Restore session defaults before the connection goes back to the pool, so no
375
295
  // other query inherits statement_timeout=0 / the short lock_timeout.
376
296
  try {
377
297
  await client.query('RESET statement_timeout');
378
298
  await client.query('RESET lock_timeout');
379
- } catch (e) {
380
- logger?.warn?.('[callLogs migration] failed to reset session settings', { message: e?.message });
299
+ }
300
+ catch (e) {
301
+ const error = e;
302
+ logger?.warn?.('[callLogs migration] failed to reset session settings', { message: error?.message });
381
303
  }
382
304
  if (lockAcquired) {
383
305
  try {
384
306
  await client.query(`SELECT pg_advisory_unlock(${CALL_LOGS_MIGRATION_LOCK_KEY})`);
385
- } catch (e) {
386
- logger?.warn?.('[callLogs migration] failed to release advisory lock', { message: e?.message });
307
+ }
308
+ catch (e) {
309
+ const error = e;
310
+ logger?.warn?.('[callLogs migration] failed to release advisory lock', { message: error?.message });
387
311
  }
388
312
  }
389
313
  connectionManager.releaseConnection(client);
390
314
  }
391
315
  }
392
-
393
316
  /**
394
317
  * Automatic entry point. Safe to call fire-and-forget off the startup critical path:
395
318
  * it never throws (failures are logged and retried on the next boot) and, on Postgres,
@@ -400,25 +323,17 @@ async function runCallLogsSchemaMigration(sequelize, logger) {
400
323
  const dialect = sequelize.getDialect();
401
324
  if (dialect === 'postgres') {
402
325
  await ensureCallLogsHashedExtensionIdSchemaPostgresOnline(sequelize, logger);
403
- } else {
326
+ }
327
+ else {
404
328
  // sqlite / local / tests: tables are tiny, the transactional rebuild is instant.
405
329
  await ensureCallLogsHashedExtensionIdSchema(sequelize);
406
330
  }
407
- } catch (e) {
331
+ }
332
+ catch (e) {
333
+ const error = e;
408
334
  logger?.error?.('[callLogs migration] failed; will retry on next start', {
409
- message: e?.message,
410
- stack: e?.stack,
335
+ message: error?.message,
336
+ stack: error?.stack,
411
337
  });
412
338
  }
413
339
  }
414
-
415
- module.exports = {
416
- findColumnKey,
417
- migrateCallLogsExtensionNumberSqlite,
418
- migrateCallLogsIdentitySqlite,
419
- sqliteCallLogsPkIncludesExtension,
420
- sqliteCallLogsPkIncludesHashedExtension,
421
- ensureCallLogsHashedExtensionIdSchema,
422
- ensureCallLogsHashedExtensionIdSchemaPostgresOnline,
423
- runCallLogsSchemaMigration,
424
- };
@@ -0,0 +1,4 @@
1
+ import type { OAuthAppLike, OAuthInfo, OperationFailureResult, RefreshableOAuthUser } from '../types';
2
+ declare function getOAuthApp({ clientId, clientSecret, accessTokenUri, authorizationUri, redirectUri, scopes }: OAuthInfo): OAuthAppLike;
3
+ declare function checkAndRefreshAccessToken(oauthApp: OAuthAppLike, user: RefreshableOAuthUser, tokenLockTimeout?: number): Promise<RefreshableOAuthUser | OperationFailureResult | null>;
4
+ export { checkAndRefreshAccessToken, getOAuthApp };