@crowdin/app-project-module 1.16.0 → 2.0.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 (99) hide show
  1. package/out/index.js +8 -15
  2. package/out/middlewares/auto-credentials-masker.js +5 -2
  3. package/out/middlewares/crowdin-client.d.ts +1 -1
  4. package/out/middlewares/crowdin-client.js +1 -1
  5. package/out/middlewares/export.d.ts +2 -2
  6. package/out/middlewares/export.js +4 -35
  7. package/out/middlewares/json-response.d.ts +1 -1
  8. package/out/middlewares/json-response.js +1 -1
  9. package/out/modules/ai-prompt-provider/index.js +6 -6
  10. package/out/modules/ai-provider/index.js +7 -7
  11. package/out/modules/ai-provider/types.d.ts +10 -0
  12. package/out/modules/ai-provider/types.js +12 -0
  13. package/out/modules/ai-provider/util/index.d.ts +0 -10
  14. package/out/modules/ai-provider/util/index.js +2 -13
  15. package/out/modules/ai-request-processors/index.js +4 -4
  16. package/out/modules/api/api.js +18 -18
  17. package/out/modules/auth-guard/index.js +4 -5
  18. package/out/modules/automation-action/index.js +4 -6
  19. package/out/modules/context-menu/index.js +4 -13
  20. package/out/modules/custom-mt/index.js +4 -4
  21. package/out/modules/custom-spell-check/index.js +11 -11
  22. package/out/modules/editor-right-panel/index.js +1 -1
  23. package/out/modules/external-qa-check/index.js +7 -7
  24. package/out/modules/file-processing/index.js +14 -14
  25. package/out/modules/integration/index.js +26 -26
  26. package/out/modules/integration/types.d.ts +4 -4
  27. package/out/modules/integration/util/files.js +1 -1
  28. package/out/modules/integration/util/types.d.ts +1 -1
  29. package/out/modules/manifest.js +70 -281
  30. package/out/modules/modal/index.js +4 -13
  31. package/out/modules/organization-menu/index.js +1 -1
  32. package/out/modules/organization-settings-menu/index.js +1 -1
  33. package/out/modules/profile-resources-menu/index.js +1 -1
  34. package/out/modules/profile-settings-menu/index.js +1 -1
  35. package/out/modules/project-menu/index.js +1 -1
  36. package/out/modules/project-menu-crowdsource/index.js +1 -1
  37. package/out/modules/project-reports/index.js +1 -1
  38. package/out/modules/project-tools/index.js +1 -1
  39. package/out/modules/webhooks/index.js +3 -6
  40. package/out/modules/workflow-step-type/index.js +6 -6
  41. package/out/storage/drizzle/d1/index.d.ts +7 -0
  42. package/out/storage/drizzle/d1/index.js +48 -0
  43. package/out/storage/drizzle/d1/migrations/init.d.ts +2 -0
  44. package/out/storage/drizzle/d1/migrations/init.js +122 -0
  45. package/out/storage/drizzle/d1/types.d.ts +13 -0
  46. package/out/storage/drizzle/d1/types.js +38 -0
  47. package/out/storage/{sqlite.d.ts → drizzle/index.d.ts} +37 -58
  48. package/out/storage/drizzle/index.js +939 -0
  49. package/out/storage/drizzle/postgresql/config.d.ts +5 -0
  50. package/out/storage/drizzle/postgresql/config.js +11 -0
  51. package/out/storage/drizzle/postgresql/index.d.ts +14 -0
  52. package/out/storage/drizzle/postgresql/index.js +144 -0
  53. package/out/storage/drizzle/postgresql/migrations/0000_init.sql +113 -0
  54. package/out/storage/drizzle/postgresql/migrations/0001_init_indexes.sql +28 -0
  55. package/out/storage/drizzle/postgresql/migrations/meta/0000_snapshot.json +646 -0
  56. package/out/storage/drizzle/postgresql/migrations/meta/0001_snapshot.json +646 -0
  57. package/out/storage/drizzle/postgresql/migrations/meta/_journal.json +20 -0
  58. package/out/storage/drizzle/postgresql/schema.d.ts +1410 -0
  59. package/out/storage/drizzle/postgresql/schema.js +106 -0
  60. package/out/storage/drizzle/sqlite/config.d.ts +5 -0
  61. package/out/storage/drizzle/sqlite/config.js +11 -0
  62. package/out/storage/drizzle/sqlite/index.d.ts +8 -0
  63. package/out/storage/drizzle/sqlite/index.js +63 -0
  64. package/out/storage/drizzle/sqlite/migrations/0000_init.sql +113 -0
  65. package/out/storage/drizzle/sqlite/migrations/meta/0000_snapshot.json +687 -0
  66. package/out/storage/drizzle/sqlite/migrations/meta/_journal.json +13 -0
  67. package/out/storage/drizzle/sqlite/schema.d.ts +1544 -0
  68. package/out/storage/drizzle/sqlite/schema.js +106 -0
  69. package/out/storage/index.d.ts +2 -88
  70. package/out/storage/index.js +12 -128
  71. package/out/storage/internal/backup.d.ts +3 -0
  72. package/out/storage/internal/backup.js +94 -0
  73. package/out/storage/types.d.ts +66 -0
  74. package/out/types.d.ts +43 -47
  75. package/out/util/credentials-masker.js +2 -2
  76. package/out/util/export.d.ts +1 -0
  77. package/out/util/export.js +2 -1
  78. package/out/util/index.d.ts +2 -1
  79. package/out/util/index.js +12 -9
  80. package/out/util/normalize-module.d.ts +0 -1
  81. package/out/util/normalize-module.js +0 -4
  82. package/package.json +18 -22
  83. package/out/modules/ai-tools/handlers/tool-calls.d.ts +0 -4
  84. package/out/modules/ai-tools/handlers/tool-calls.js +0 -52
  85. package/out/modules/ai-tools/index.d.ts +0 -10
  86. package/out/modules/ai-tools/index.js +0 -46
  87. package/out/modules/ai-tools/types.d.ts +0 -63
  88. package/out/modules/ai-tools/types.js +0 -2
  89. package/out/modules/ai-tools/util/index.d.ts +0 -5
  90. package/out/modules/ai-tools/util/index.js +0 -24
  91. package/out/storage/d1.d.ts +0 -107
  92. package/out/storage/d1.js +0 -837
  93. package/out/storage/export.d.ts +0 -1
  94. package/out/storage/export.js +0 -2
  95. package/out/storage/mysql.d.ts +0 -109
  96. package/out/storage/mysql.js +0 -984
  97. package/out/storage/postgre.d.ts +0 -124
  98. package/out/storage/postgre.js +0 -1027
  99. package/out/storage/sqlite.js +0 -786
package/out/types.d.ts CHANGED
@@ -6,16 +6,12 @@ import { CustomSpellcheckerModule } from './modules/custom-spell-check/types';
6
6
  import { EditorPanels } from './modules/editor-right-panel/types';
7
7
  import { CustomFileFormatLogic, FilePostExportLogic, FilePostImportLogic, FilePreExportLogic, FilePreImportLogic, TranslationsAlignmentLogic } from './modules/file-processing/types';
8
8
  import { IntegrationLogic } from './modules/integration/types';
9
- import { Storage } from './storage';
10
- import { MySQLStorageConfig } from './storage/mysql';
11
- import { PostgreStorageConfig } from './storage/postgre';
12
- import { D1StorageConfig } from './storage/d1';
9
+ import { Storage } from './storage/types';
13
10
  import type { Fetcher } from '@cloudflare/workers-types';
14
11
  import { ApiModule } from './modules/api/types';
15
12
  import { LogErrorFunction, LogFunction } from './util/logger';
16
13
  import { AiProviderModule } from './modules/ai-provider/types';
17
14
  import { AiPromptProviderModule } from './modules/ai-prompt-provider/types';
18
- import { AiTool, AiToolWidget } from './modules/ai-tools/types';
19
15
  import { ExternalQaCheckModule } from './modules/external-qa-check/types';
20
16
  import { Webhook } from './modules/webhooks/types';
21
17
  import { WorkflowStepTypeModule } from './modules/workflow-step-type/types';
@@ -23,7 +19,11 @@ import { AiRequestProcessorModule, AiStreamProcessorModule } from './modules/ai-
23
19
  import { AutomationActionModule } from './modules/automation-action/types';
24
20
  import { AuthGuardModule } from './modules/auth-guard/types';
25
21
  import { Cron } from './util/cron';
22
+ import { PostgreStorageConfig } from './storage/drizzle/postgresql';
23
+ import { Migration as D1Migration, D1StorageConfig } from './storage/drizzle/d1/types';
24
+ export { Storage } from './storage/types';
26
25
  export { Cron };
26
+ export { D1StorageConfig } from './storage/drizzle/d1/types';
27
27
  export interface ClientConfig extends ImagePath {
28
28
  /**
29
29
  * Authentication Crowdin App type: "authorization_code", "crowdin_app", "crowdin_agent". Default: "crowdin_app"
@@ -101,14 +101,18 @@ export interface ClientConfig extends ImagePath {
101
101
  * config to configure PostgreSQL as a storage
102
102
  */
103
103
  postgreConfig?: PostgreStorageConfig;
104
- /**
105
- * config to configure MySQL as a storage
106
- */
107
- mysqlConfig?: MySQLStorageConfig;
108
104
  /**
109
105
  * config to configure Cloudflare D1 as a storage
110
106
  */
111
107
  d1Config?: D1StorageConfig;
108
+ /**
109
+ * custom tables for application
110
+ */
111
+ customTables?: {
112
+ migrationFolder?: string;
113
+ d1Migrations?: D1Migration[];
114
+ schema: Record<string, unknown>;
115
+ };
112
116
  /**
113
117
  * Custom cron for scheduling background jobs.
114
118
  * If not provided, the default node-cron will be used.
@@ -126,47 +130,47 @@ export interface ClientConfig extends ImagePath {
126
130
  /**
127
131
  * custom file format module logic
128
132
  */
129
- customFileFormat?: OneOrMany<CustomFileFormatLogic>;
133
+ customFileFormat?: CustomFileFormatLogic[];
130
134
  /**
131
135
  * custom MT module logic
132
136
  */
133
- customMT?: OneOrMany<CustomMTLogic & ImagePath & Environments>;
137
+ customMT?: (CustomMTLogic & ImagePath & Environments)[];
134
138
  /**
135
139
  * resources module
136
140
  */
137
- profileResourcesMenu?: OneOrMany<UiModule & ImagePath & Environments>;
141
+ profileResourcesMenu?: (UiModule & ImagePath & Environments)[];
138
142
  /**
139
143
  * profile-settings-menu module
140
144
  */
141
- profileSettingsMenu?: OneOrMany<UiModule & ImagePath & Environments>;
145
+ profileSettingsMenu?: (UiModule & ImagePath & Environments)[];
142
146
  /**
143
147
  * organization-menu module
144
148
  */
145
- organizationMenu?: OneOrMany<UiModule & ImagePath>;
149
+ organizationMenu?: (UiModule & ImagePath)[];
146
150
  /**
147
151
  * organization-settings-menu module
148
152
  */
149
- organizationSettingsMenu?: OneOrMany<UiModule & ImagePath>;
153
+ organizationSettingsMenu?: (UiModule & ImagePath)[];
150
154
  /**
151
155
  * editor-right-panel module
152
156
  */
153
- editorRightPanel?: OneOrMany<EditorPanels & Environments>;
157
+ editorRightPanel?: (EditorPanels & Environments)[];
154
158
  /**
155
159
  * project menu module
156
160
  */
157
- projectMenu?: OneOrMany<UiModule & Environments>;
161
+ projectMenu?: (UiModule & Environments)[];
158
162
  /**
159
163
  * project menu crowdsource module
160
164
  */
161
- projectMenuCrowdsource?: OneOrMany<UiModule>;
165
+ projectMenuCrowdsource?: UiModule[];
162
166
  /**
163
167
  * tools module
164
168
  */
165
- projectTools?: OneOrMany<UiModule & ImagePath & Environments>;
169
+ projectTools?: (UiModule & ImagePath & Environments)[];
166
170
  /**
167
171
  * reports module
168
172
  */
169
- projectReports?: OneOrMany<UiModule & ImagePath>;
173
+ projectReports?: (UiModule & ImagePath)[];
170
174
  /**
171
175
  * API module
172
176
  */
@@ -174,11 +178,11 @@ export interface ClientConfig extends ImagePath {
174
178
  /**
175
179
  * context menu module
176
180
  */
177
- contextMenu?: OneOrMany<ContextModule>;
181
+ contextMenu?: ContextModule[];
178
182
  /**
179
183
  * modal module
180
184
  */
181
- modal?: OneOrMany<ModalModule>;
185
+ modal?: ModalModule[];
182
186
  /**
183
187
  * chat module
184
188
  */
@@ -228,11 +232,11 @@ export interface ClientConfig extends ImagePath {
228
232
  * Configuration of app pricing
229
233
  */
230
234
  pricing?: Pricing;
231
- filePreImport?: OneOrMany<FilePreImportLogic>;
232
- filePostImport?: OneOrMany<FilePostImportLogic>;
233
- filePreExport?: OneOrMany<FilePreExportLogic>;
234
- filePostExport?: OneOrMany<FilePostExportLogic>;
235
- fileTranslationsAlignmentExport?: OneOrMany<TranslationsAlignmentLogic>;
235
+ filePreImport?: FilePreImportLogic[];
236
+ filePostImport?: FilePostImportLogic[];
237
+ filePreExport?: FilePreExportLogic[];
238
+ filePostExport?: FilePostExportLogic[];
239
+ fileTranslationsAlignmentExport?: TranslationsAlignmentLogic[];
236
240
  /**
237
241
  * Disable formatting logs
238
242
  */
@@ -243,51 +247,43 @@ export interface ClientConfig extends ImagePath {
243
247
  * Not necessary to configure if environment variables AWS_REGION and AWS_TMP_BUCKET_NAME are properly set.
244
248
  */
245
249
  awsConfig?: AWSConfig;
246
- customSpellchecker?: OneOrMany<CustomSpellcheckerModule>;
250
+ customSpellchecker?: CustomSpellcheckerModule[];
247
251
  /**
248
252
  * ai provider module
249
253
  */
250
- aiProvider?: OneOrMany<AiProviderModule & ImagePath>;
254
+ aiProvider?: (AiProviderModule & ImagePath)[];
251
255
  /**
252
256
  * ai prompt provider module
253
257
  */
254
- aiPromptProvider?: OneOrMany<AiPromptProviderModule & ImagePath>;
258
+ aiPromptProvider?: (AiPromptProviderModule & ImagePath)[];
255
259
  /**
256
260
  * ai request pre-compile processor module
257
261
  */
258
- aiRequestPreCompile?: OneOrMany<AiRequestProcessorModule>;
262
+ aiRequestPreCompile?: AiRequestProcessorModule[];
259
263
  /**
260
264
  * ai request post-compile processor module
261
265
  */
262
- aiRequestPostCompile?: OneOrMany<AiRequestProcessorModule>;
266
+ aiRequestPostCompile?: AiRequestProcessorModule[];
263
267
  /**
264
268
  * ai request pre-parse processor module
265
269
  */
266
- aiRequestPreParse?: OneOrMany<AiStreamProcessorModule>;
270
+ aiRequestPreParse?: AiStreamProcessorModule[];
267
271
  /**
268
272
  * ai request post-parse processor module
269
273
  */
270
- aiRequestPostParse?: OneOrMany<AiRequestProcessorModule>;
271
- /**
272
- * AI tool_calls modules
273
- */
274
- aiTools?: OneOrMany<AiTool>;
275
- /**
276
- * AI tool_calls modules with UI widgets
277
- */
278
- aiToolsWidget?: OneOrMany<AiToolWidget>;
274
+ aiRequestPostParse?: AiRequestProcessorModule[];
279
275
  /**
280
276
  * qa check module
281
277
  */
282
- externalQaCheck?: OneOrMany<ExternalQaCheckModule & ImagePath>;
278
+ externalQaCheck?: (ExternalQaCheckModule & ImagePath)[];
283
279
  /**
284
280
  * webhook modules
285
281
  */
286
- webhooks?: OneOrMany<Webhook>;
282
+ webhooks?: Webhook[];
287
283
  /**
288
284
  * workflow step modules
289
285
  */
290
- workflowStepType?: OneOrMany<WorkflowStepTypeModule>;
286
+ workflowStepType?: WorkflowStepTypeModule[];
291
287
  /**
292
288
  * property that tells backend that AiProvider and AiPromptProvider modules can cooperate only with each one
293
289
  */
@@ -299,11 +295,11 @@ export interface ClientConfig extends ImagePath {
299
295
  /**
300
296
  * Automation action module
301
297
  */
302
- automationAction?: OneOrMany<AutomationActionModule>;
298
+ automationAction?: AutomationActionModule[];
303
299
  /**
304
300
  * Auth guard module for custom authentication/authorization checks
305
301
  */
306
- authGuard?: OneOrMany<AuthGuardModule>;
302
+ authGuard?: AuthGuardModule[];
307
303
  /**
308
304
  * custom file storage
309
305
  */
@@ -81,8 +81,8 @@ function postRequestCredentialsMasker({ secret, moduleConfig, credentialsExtract
81
81
  // most common way of storing data
82
82
  const jwtToken = (0, crowdin_client_1.getToken)(req) || '';
83
83
  const jwtPayload = yield (0, token_1.validateJwtToken)(jwtToken, secret);
84
- const crowdinId = `${jwtPayload.context.organization_id}`;
85
- unmaskedFields = yield index_1.metadataStore.getMetadata(`form-data-${crowdinId}`);
84
+ const formDataMetadataId = (0, index_2.prepareFormDataMetadataIdFromContext)(jwtPayload.context);
85
+ unmaskedFields = yield index_1.metadataStore.getMetadata(formDataMetadataId);
86
86
  }
87
87
  unmaskedFields = unmaskedFields || {};
88
88
  const maskableFieldsKeys = getMaskableFieldsKeys(moduleConfig);
@@ -2,3 +2,4 @@ export { prepareCrowdinClient } from './connection';
2
2
  export { isAppFree } from './subscription';
3
3
  export { CodeError, extractBaseUrlFromRequest, encryptData, decryptData, executeWithRetry } from './';
4
4
  export * as logger from './logger';
5
+ export * as integrationUtil from '../modules/integration/util/export';
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.logger = exports.executeWithRetry = exports.decryptData = exports.encryptData = exports.extractBaseUrlFromRequest = exports.CodeError = exports.isAppFree = exports.prepareCrowdinClient = void 0;
36
+ exports.integrationUtil = exports.logger = exports.executeWithRetry = exports.decryptData = exports.encryptData = exports.extractBaseUrlFromRequest = exports.CodeError = exports.isAppFree = exports.prepareCrowdinClient = void 0;
37
37
  var connection_1 = require("./connection");
38
38
  Object.defineProperty(exports, "prepareCrowdinClient", { enumerable: true, get: function () { return connection_1.prepareCrowdinClient; } });
39
39
  var subscription_1 = require("./subscription");
@@ -45,3 +45,4 @@ Object.defineProperty(exports, "encryptData", { enumerable: true, get: function
45
45
  Object.defineProperty(exports, "decryptData", { enumerable: true, get: function () { return _1.decryptData; } });
46
46
  Object.defineProperty(exports, "executeWithRetry", { enumerable: true, get: function () { return _1.executeWithRetry; } });
47
47
  exports.logger = __importStar(require("./logger"));
48
+ exports.integrationUtil = __importStar(require("../modules/integration/util/export"));
@@ -1,5 +1,5 @@
1
1
  import { Request, Response } from 'express';
2
- import { Config, CrowdinClientRequest, ImagePath, UnauthorizedConfig } from '../types';
2
+ import { Config, CrowdinClientRequest, ImagePath, JwtPayloadContext, UnauthorizedConfig } from '../types';
3
3
  export declare class CodeError extends Error {
4
4
  code: number | undefined;
5
5
  constructor(message: string, code?: number);
@@ -23,6 +23,7 @@ export declare function isJson(string: string): boolean;
23
23
  export declare function isDefined(value: any): boolean;
24
24
  export declare function isString(value: any): value is string;
25
25
  export declare function getPreviousDate(days: number): Date;
26
+ export declare function prepareFormDataMetadataIdFromContext(context: JwtPayloadContext): string;
26
27
  export declare function prepareFormDataMetadataId(req: CrowdinClientRequest, config: Config): Promise<string>;
27
28
  export declare function validateEmail(email: string | number): boolean;
28
29
  export declare function getFormattedDate({ date, userTimezone }: {
package/out/util/index.js CHANGED
@@ -55,6 +55,7 @@ exports.isJson = isJson;
55
55
  exports.isDefined = isDefined;
56
56
  exports.isString = isString;
57
57
  exports.getPreviousDate = getPreviousDate;
58
+ exports.prepareFormDataMetadataIdFromContext = prepareFormDataMetadataIdFromContext;
58
59
  exports.prepareFormDataMetadataId = prepareFormDataMetadataId;
59
60
  exports.validateEmail = validateEmail;
60
61
  exports.getFormattedDate = getFormattedDate;
@@ -282,19 +283,21 @@ function getPreviousDate(days) {
282
283
  date.setDate(date.getDate() - days);
283
284
  return date;
284
285
  }
286
+ function prepareFormDataMetadataIdFromContext(context) {
287
+ const id = ['form-data'];
288
+ if (context.organization_id) {
289
+ id.push(`${context.organization_id}`);
290
+ }
291
+ if (context.project_id) {
292
+ id.push(`${context.project_id}`);
293
+ }
294
+ return id.join('-');
295
+ }
285
296
  function prepareFormDataMetadataId(req, config) {
286
297
  return __awaiter(this, void 0, void 0, function* () {
287
298
  const jwtToken = req.query.jwtToken;
288
299
  const jwtPayload = yield (0, token_1.validateJwtToken)(jwtToken, config.clientSecret, config.jwtValidationOptions);
289
- const context = jwtPayload.context;
290
- const id = ['form-data'];
291
- if (context.organization_id) {
292
- id.push(`${context.organization_id}`);
293
- }
294
- if (context.project_id) {
295
- id.push(`${context.project_id}`);
296
- }
297
- return id.join('-');
300
+ return prepareFormDataMetadataIdFromContext(jwtPayload.context);
298
301
  });
299
302
  }
300
303
  function validateEmail(email) {
@@ -1,4 +1,3 @@
1
- export declare function normalizeToArray<T>(value: T | T[]): T[];
2
1
  export declare function resolveInstanceKey({ identifier, suffix, item, index, isSingle, }: {
3
2
  identifier: string;
4
3
  suffix: string;
@@ -1,11 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizeToArray = normalizeToArray;
4
3
  exports.resolveInstanceKey = resolveInstanceKey;
5
4
  const index_1 = require("./index");
6
- function normalizeToArray(value) {
7
- return Array.isArray(value) ? value : [value];
8
- }
9
5
  function resolveInstanceKey({ identifier, suffix, item, index, isSingle, }) {
10
6
  if (isSingle) {
11
7
  return identifier + '-' + suffix;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "1.16.0",
3
+ "version": "2.0.0",
4
4
  "description": "Module that generates for you all common endpoints for serving standalone Crowdin App",
5
5
  "main": "out/index.js",
6
6
  "types": "out/index.d.ts",
@@ -10,52 +10,46 @@
10
10
  "import": "./out/index.js",
11
11
  "types": "./out/index.d.ts"
12
12
  },
13
+ "./util": {
14
+ "require": "./out/util/export.js",
15
+ "import": "./out/util/export.js",
16
+ "types": "./out/util/export.d.ts"
17
+ },
13
18
  "./functions/*": {
14
19
  "require": "./out/util/app-functions/*.js",
15
20
  "import": "./out/util/app-functions/*.js",
16
21
  "types": "./out/util/app-functions/*.d.ts"
17
22
  },
18
- "./out/*": {
19
- "require": "./out/*.js",
20
- "import": "./out/*.js",
21
- "types": "./out/*.d.ts"
22
- },
23
23
  "./modules/*": {
24
24
  "require": "./out/modules/*/types.js",
25
25
  "import": "./out/modules/*/types.js",
26
26
  "types": "./out/modules/*/types.d.ts"
27
27
  },
28
- "./storage": {
29
- "require": "./out/storage/export.js",
30
- "import": "./out/storage/export.js",
31
- "types": "./out/storage/export.d.ts"
32
- },
33
- "./util": {
34
- "require": "./out/util/export.js",
35
- "import": "./out/util/export.js",
36
- "types": "./out/util/export.d.ts"
37
- },
38
28
  "./middlewares": {
39
29
  "require": "./out/middlewares/export.js",
40
30
  "import": "./out/middlewares/export.js",
41
31
  "types": "./out/middlewares/export.d.ts"
42
32
  },
43
- "./modules/integration/util": {
44
- "require": "./out/modules/integration/util/export.js",
45
- "import": "./out/modules/integration/util/export.js",
46
- "types": "./out/modules/integration/util/export.d.ts"
33
+ "./test": {
34
+ "require": "./out/app-test/index.js",
35
+ "import": "./out/app-test/index.js",
36
+ "types": "./out/app-test/index.d.ts"
47
37
  }
48
38
  },
49
39
  "scripts": {
50
40
  "build": "npm run build-main && npm run build-ui",
51
- "build-main": "tsc -p ./ && cp -R static out && cp logo.png out",
41
+ "build-main": "tsc -p ./ && cp -R static out && cp logo.png out && npm run copy-migrations",
52
42
  "build-ui": "rollup -c rollup-ui.config.mjs",
53
43
  "watch-main": "tsc --watch -p ./ && cp -R static out && cp logo.png out",
44
+ "format": "npm run prettier && npm run lint",
54
45
  "lint": "eslint --fix \"{src,tests,ui}/**/*.{js,ts,tsx}\"",
55
46
  "prettier": "prettier --config .prettierrc {src,ui}/**/*.{ts,tsx} --write",
56
47
  "lint-ci": "eslint \"{src,tests}/**/*.{js,ts}\"",
57
48
  "test-coverage": "jest --ci --reporters=jest-junit --reporters=default --coverage --coverageReporters=cobertura --coverageReporters=html",
58
- "test": "jest"
49
+ "test": "jest",
50
+ "copy-migrations": "cp -R src/storage/drizzle/sqlite/migrations out/storage/drizzle/sqlite/migrations && cp -R src/storage/drizzle/postgresql/migrations out/storage/drizzle/postgresql/migrations",
51
+ "drizzle:sqlite:generate": "drizzle-kit generate --config ./src/storage/drizzle/sqlite/config.ts",
52
+ "drizzle:postgresql:generate": "drizzle-kit generate --config ./src/storage/drizzle/postgresql/config.ts"
59
53
  },
60
54
  "files": [
61
55
  "out/**/*"
@@ -68,6 +62,7 @@
68
62
  "amqplib": "^0.10.9",
69
63
  "better-sqlite3": "^12.6.2",
70
64
  "cors": "^2.8.6",
65
+ "drizzle-orm": "^0.45.2",
71
66
  "express": "^5.2.1",
72
67
  "express-rate-limit": "^8.2.1",
73
68
  "jsonwebtoken": "^9.0.0",
@@ -126,6 +121,7 @@
126
121
  "@typescript-eslint/eslint-plugin": "^8.56.0",
127
122
  "@typescript-eslint/parser": "^8.56.0",
128
123
  "auto-changelog": "^2.5.0",
124
+ "drizzle-kit": "^0.31.10",
129
125
  "eslint": "^10.0.1",
130
126
  "eslint-config-prettier": "^10.1.8",
131
127
  "eslint-plugin-prettier": "^5.5.5",
@@ -1,4 +0,0 @@
1
- import { Response } from 'express';
2
- import { CrowdinClientRequest } from '../../../types';
3
- import { AiTool } from '../types';
4
- export default function handle(aiTool: AiTool): (req: import("express").Request | CrowdinClientRequest, res: Response, next: Function) => void;
@@ -1,52 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.default = handle;
13
- const util_1 = require("../../../util");
14
- const logger_1 = require("../../../util/logger");
15
- function handle(aiTool) {
16
- return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
17
- try {
18
- const { crowdinApiClient: client, crowdinContext: context, body: payload } = req;
19
- const { function: { arguments: stringArgs = '' }, } = payload;
20
- const { jwtPayload: { context: { project_id: projectId }, }, } = context;
21
- let args = null;
22
- try {
23
- args = JSON.parse(stringArgs);
24
- }
25
- catch (e) {
26
- if (req.logError) {
27
- req.logError(e);
28
- }
29
- }
30
- const { content, error: message } = yield aiTool.toolCalls({
31
- client,
32
- args,
33
- projectId,
34
- payload,
35
- context,
36
- request: req,
37
- });
38
- res.send({
39
- data: {
40
- content: typeof content === 'string' ? content : JSON.stringify(content),
41
- error: message ? { message } : undefined,
42
- },
43
- });
44
- }
45
- catch (e) {
46
- if (req.logError) {
47
- req.logError(e);
48
- }
49
- res.send({ error: { message: (0, logger_1.getErrorMessage)(e) } });
50
- }
51
- }));
52
- }
@@ -1,10 +0,0 @@
1
- import { Express } from 'express';
2
- import { Config } from '../../types';
3
- export declare function registerAiTools({ config, app }: {
4
- config: Config;
5
- app: Express;
6
- }): void;
7
- export declare function registerAiToolWidgets({ config, app }: {
8
- config: Config;
9
- app: Express;
10
- }): void;
@@ -1,46 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.registerAiTools = registerAiTools;
7
- exports.registerAiToolWidgets = registerAiToolWidgets;
8
- const json_response_1 = __importDefault(require("../../middlewares/json-response"));
9
- const tool_calls_1 = __importDefault(require("./handlers/tool-calls"));
10
- const ui_module_1 = __importDefault(require("../../middlewares/ui-module"));
11
- const render_ui_module_1 = __importDefault(require("../../middlewares/render-ui-module"));
12
- const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client"));
13
- const util_1 = require("./util");
14
- function registerAiTools({ config, app }) {
15
- if (!config.aiTools) {
16
- return;
17
- }
18
- const tools = Array.isArray(config.aiTools) ? config.aiTools : [config.aiTools];
19
- for (const tool of tools) {
20
- if ((0, util_1.isUniqueFunctionName)(tool)) {
21
- app.post((0, util_1.getAiToolUrl)(tool), json_response_1.default, (0, crowdin_client_1.default)({
22
- config,
23
- optional: false,
24
- checkSubscriptionExpiration: true,
25
- moduleKey: tool.key,
26
- }), (0, tool_calls_1.default)(tool));
27
- }
28
- else {
29
- throw new Error(`The function name '${tool.function.name}' is not unique within aiTools and aiToolsWidget`);
30
- }
31
- }
32
- }
33
- function registerAiToolWidgets({ config, app }) {
34
- if (!config.aiToolsWidget) {
35
- return;
36
- }
37
- const tools = Array.isArray(config.aiToolsWidget) ? config.aiToolsWidget : [config.aiToolsWidget];
38
- for (const tool of tools) {
39
- if ((0, util_1.isUniqueFunctionName)(tool)) {
40
- app.use((0, util_1.getAiToolWidgetUrl)(tool), (0, ui_module_1.default)({ config, moduleType: tool.key }), (0, render_ui_module_1.default)(tool, config));
41
- }
42
- else {
43
- throw new Error(`The function name '${tool.function.name}' is not unique within aiTools and aiToolsWidget`);
44
- }
45
- }
46
- }
@@ -1,63 +0,0 @@
1
- import { CrowdinClientRequest, CrowdinContextInfo, Environments, ModuleKey, UiModule } from '../../types';
2
- import Crowdin from '@crowdin/crowdin-api-client';
3
- export interface AiToolWidget extends BaseAiTool, UiModule {
4
- }
5
- export interface AiTool extends BaseAiTool, ModuleKey {
6
- /**
7
- * function to handle requests
8
- */
9
- toolCalls: (options: AiToolArguments) => Promise<AiToolResponse>;
10
- }
11
- interface BaseAiTool extends Environments {
12
- /**
13
- * Tool type, default is 'function'
14
- */
15
- toolType: string;
16
- /**
17
- * describe function object
18
- */
19
- function: AiToolFunction;
20
- }
21
- interface AiToolFunction {
22
- /**
23
- * The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes.
24
- */
25
- name: string;
26
- /**
27
- * A description of what the function does, used by the AI model to choose when and how to call the function.
28
- */
29
- description: string;
30
- /**
31
- * Describe as a JSON Schema object
32
- */
33
- parameters?: {
34
- type: string;
35
- properties: object;
36
- required?: string[];
37
- };
38
- }
39
- interface AiToolArguments {
40
- client: Crowdin;
41
- args: object | null;
42
- projectId: number;
43
- payload: AiToolPayload;
44
- context: CrowdinContextInfo;
45
- request: CrowdinClientRequest;
46
- }
47
- interface AiToolPayload {
48
- function: {
49
- name: string;
50
- arguments: string;
51
- };
52
- organization: {
53
- [key: string]: any;
54
- };
55
- project: {
56
- [key: string]: any;
57
- };
58
- }
59
- interface AiToolResponse {
60
- content: string | object;
61
- error?: string;
62
- }
63
- export {};
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,5 +0,0 @@
1
- import { AiTool, AiToolWidget } from '../types';
2
- export declare function isUniqueFunctionName(tool: AiTool | AiToolWidget): boolean;
3
- export declare function getAiToolName(tool: AiTool | AiToolWidget): string;
4
- export declare function getAiToolUrl(tool: AiTool): string;
5
- export declare function getAiToolWidgetUrl(tool: AiToolWidget, isFull?: boolean): string;
@@ -1,24 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isUniqueFunctionName = isUniqueFunctionName;
4
- exports.getAiToolName = getAiToolName;
5
- exports.getAiToolUrl = getAiToolUrl;
6
- exports.getAiToolWidgetUrl = getAiToolWidgetUrl;
7
- const uniqueNames = [];
8
- function isUniqueFunctionName(tool) {
9
- if (uniqueNames.includes(tool.function.name)) {
10
- return false;
11
- }
12
- uniqueNames.push(tool.function.name);
13
- return true;
14
- }
15
- function getAiToolName(tool) {
16
- return tool.function.name;
17
- }
18
- function getAiToolUrl(tool) {
19
- return `/ai-tools/${getAiToolName(tool)}`;
20
- }
21
- function getAiToolWidgetUrl(tool, isFull = false) {
22
- const suffix = isFull ? `/${tool.fileName || 'index.html'}` : '';
23
- return `/ai-tools-widget/${getAiToolName(tool)}${suffix}`;
24
- }