@crowdin/app-project-module 3.0.1 → 3.2.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 (28) hide show
  1. package/out/middlewares/crowdin-client.d.ts +4 -2
  2. package/out/middlewares/crowdin-client.js +51 -14
  3. package/out/middlewares/integration-credentials.js +34 -12
  4. package/out/modules/integration/handlers/crowdin-files.js +34 -1
  5. package/out/modules/integration/handlers/user-error-detail.d.ts +2 -0
  6. package/out/modules/integration/handlers/user-error-detail.js +48 -0
  7. package/out/modules/integration/handlers/user-errors.d.ts +6 -0
  8. package/out/modules/integration/handlers/user-errors.js +39 -17
  9. package/out/modules/integration/index.js +8 -0
  10. package/out/modules/integration/types.d.ts +1 -0
  11. package/out/static/ui/main.bundle.js +116 -55
  12. package/out/static/ui/main.bundle.js.map +1 -1
  13. package/out/storage/drizzle/d1/index.js +2 -1
  14. package/out/storage/drizzle/d1/migrations/user-errors-indexes.d.ts +7 -0
  15. package/out/storage/drizzle/d1/migrations/user-errors-indexes.js +27 -0
  16. package/out/storage/drizzle/index.d.ts +8 -1
  17. package/out/storage/drizzle/index.js +75 -4
  18. package/out/storage/drizzle/postgresql/migrations/0003_user_errors_pagination_index.sql +5 -0
  19. package/out/storage/drizzle/postgresql/migrations/meta/0003_snapshot.json +646 -0
  20. package/out/storage/drizzle/postgresql/migrations/meta/_journal.json +7 -0
  21. package/out/storage/drizzle/sqlite/migrations/0002_user_errors_indexes.sql +4 -0
  22. package/out/storage/drizzle/sqlite/migrations/meta/0002_snapshot.json +687 -0
  23. package/out/storage/drizzle/sqlite/migrations/meta/_journal.json +7 -0
  24. package/out/storage/types.d.ts +30 -0
  25. package/out/types.d.ts +1 -0
  26. package/out/util/connection.d.ts +5 -0
  27. package/out/util/connection.js +7 -0
  28. package/package.json +1 -1
@@ -13,11 +13,12 @@ exports.migrateD1 = void 0;
13
13
  exports.initD1 = initD1;
14
14
  const d1_1 = require("drizzle-orm/d1");
15
15
  const init_1 = require("./migrations/init");
16
+ const user_errors_indexes_1 = require("./migrations/user-errors-indexes");
16
17
  const types_1 = require("./types");
17
18
  function initD1({ database, additionalSchema, }) {
18
19
  return (0, d1_1.drizzle)(database, { schema: Object.assign(Object.assign({}, types_1.D1_SCHEMA), additionalSchema) });
19
20
  }
20
- const migrations = [init_1.INIT_MIGRATION];
21
+ const migrations = [init_1.INIT_MIGRATION, user_errors_indexes_1.USER_ERRORS_INDEXES_MIGRATION];
21
22
  const migrationHistoryTableName = '__drizzle_migrations';
22
23
  const migrateD1 = (db_1, ...args_1) => __awaiter(void 0, [db_1, ...args_1], void 0, function* (db, additionalMigrations = []) {
23
24
  const allMigrations = [...migrations, ...additionalMigrations];
@@ -0,0 +1,7 @@
1
+ import { Migration } from '../types';
2
+ /**
3
+ * Indexes for the paginated error log query:
4
+ * WHERE crowdin_id = ? AND integration_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?
5
+ * and for the retention cron, which deletes by created_at.
6
+ */
7
+ export declare const USER_ERRORS_INDEXES_MIGRATION: Migration;
@@ -0,0 +1,27 @@
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.USER_ERRORS_INDEXES_MIGRATION = void 0;
13
+ /**
14
+ * Indexes for the paginated error log query:
15
+ * WHERE crowdin_id = ? AND integration_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?
16
+ * and for the retention cron, which deletes by created_at.
17
+ */
18
+ exports.USER_ERRORS_INDEXES_MIGRATION = {
19
+ name: 'user-errors-indexes',
20
+ run: (db) => __awaiter(void 0, void 0, void 0, function* () {
21
+ yield db.$client.batch([
22
+ db.$client.prepare(`CREATE INDEX IF NOT EXISTS idx_user_errors_crowdin_integration_created_at
23
+ ON user_errors (crowdin_id, integration_id, created_at)`),
24
+ db.$client.prepare('CREATE INDEX IF NOT EXISTS idx_user_errors_created_at ON user_errors (created_at)'),
25
+ ]);
26
+ }),
27
+ };
@@ -1,7 +1,7 @@
1
1
  import { IntegrationConfig, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, IntegrationWebhooks, Provider } from '../../modules/integration/types';
2
2
  import { CreateJobParams, GetActiveJobsParams, GetAllJobsParams, GetFileTranslationCache, GetFileTranslationCacheByLanguageParams, GetJobParams, GetUnsyncedFiles, IntegrationSyncedData, Job, TranslationCache, UnsyncedFiles, UpdateJobParams, UpdateTranslationCacheParams } from '../../modules/integration/util/types';
3
3
  import { Config, CrowdinCredentials, UnauthorizedConfig } from '../../types';
4
- import { DB_TYPE, Storage, UserErrors } from '../types';
4
+ import { DB_TYPE, GetUserErrorParams, GetUserErrorsParams, Storage, UserErrorListItem, UserErrors, UserErrorsFilter } from '../types';
5
5
  import { POSTGRESQL_DB, POSTGRESQL_SCHEMA } from './postgresql';
6
6
  export declare class DrizzleStorage implements Storage {
7
7
  readonly db: POSTGRESQL_DB;
@@ -48,7 +48,14 @@ export declare class DrizzleStorage implements Storage {
48
48
  getWebhooks(fileId: string, integrationId: string, crowdinId: string, provider: Provider): Promise<IntegrationWebhooks | undefined>;
49
49
  saveWebhooks(fileId: string, integrationId: string, crowdinId: string, provider: Provider): Promise<void>;
50
50
  deleteWebhooks(fileIds: string[], integrationId: string, crowdinId: string, provider: Provider): Promise<void>;
51
+ private userErrorsWhereClause;
52
+ /**
53
+ * @deprecated kept for backward compatibility only - see {@link Storage.getAllUserErrors}.
54
+ */
51
55
  getAllUserErrors(crowdinId: string, integrationId?: string): Promise<UserErrors[] | undefined>;
56
+ getUserErrors({ crowdinId, integrationId, search, limit, offset, orderDirection, }: GetUserErrorsParams): Promise<UserErrorListItem[]>;
57
+ countUserErrors(params: UserErrorsFilter): Promise<number>;
58
+ getUserError({ id, crowdinId, integrationId }: GetUserErrorParams): Promise<UserErrors | undefined>;
52
59
  saveUserError(action: string, message: string, data: string, createdAt: string, crowdinId: string, integrationId?: string): Promise<void>;
53
60
  deleteUserErrors(createdAt: string, crowdinId: string, integrationId?: string): Promise<void>;
54
61
  deleteAllUsersErrorsOlderThan(createdAt: string): Promise<void>;
@@ -595,13 +595,30 @@ class DrizzleStorage {
595
595
  .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.inArray)(this.schema.webhooks.file_id, fileIds), (0, drizzle_orm_1.eq)(this.schema.webhooks.integration_id, integrationId), (0, drizzle_orm_1.eq)(this.schema.webhooks.crowdin_id, crowdinId), (0, drizzle_orm_1.eq)(this.schema.webhooks.provider, provider)));
596
596
  });
597
597
  }
598
+ userErrorsWhereClause({ crowdinId, integrationId, search }) {
599
+ const conditions = [
600
+ (0, drizzle_orm_1.eq)(this.schema.userErrors.crowdin_id, crowdinId),
601
+ integrationId
602
+ ? (0, drizzle_orm_1.eq)(this.schema.userErrors.integration_id, integrationId)
603
+ : (0, drizzle_orm_1.isNull)(this.schema.userErrors.integration_id),
604
+ ];
605
+ const searchTerm = search === null || search === void 0 ? void 0 : search.trim().toLowerCase();
606
+ if (searchTerm) {
607
+ // escape LIKE wildcards so that a literal % or _ typed by the user is matched as is
608
+ const pattern = `%${searchTerm.replace(/[\\%_]/g, (char) => `\\${char}`)}%`;
609
+ conditions.push((0, drizzle_orm_1.or)((0, drizzle_orm_1.sql) `lower(${this.schema.userErrors.action}) like ${pattern} escape '\\'`, (0, drizzle_orm_1.sql) `lower(${this.schema.userErrors.message}) like ${pattern} escape '\\'`));
610
+ }
611
+ return (0, drizzle_orm_1.and)(...conditions);
612
+ }
613
+ /**
614
+ * @deprecated kept for backward compatibility only - see {@link Storage.getAllUserErrors}.
615
+ */
598
616
  getAllUserErrors(crowdinId, integrationId) {
599
617
  return __awaiter(this, void 0, void 0, function* () {
600
618
  yield this.migrationPromise;
601
- const whereClause = integrationId
602
- ? (0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.userErrors.crowdin_id, crowdinId), (0, drizzle_orm_1.eq)(this.schema.userErrors.integration_id, integrationId))
603
- : (0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.userErrors.crowdin_id, crowdinId), (0, drizzle_orm_1.isNull)(this.schema.userErrors.integration_id));
604
- const items = yield this.db.query.userErrors.findMany({ where: whereClause });
619
+ const items = yield this.db.query.userErrors.findMany({
620
+ where: this.userErrorsWhereClause({ crowdinId, integrationId }),
621
+ });
605
622
  return items.map((item) => ({
606
623
  id: item.id,
607
624
  action: item.action,
@@ -613,6 +630,60 @@ class DrizzleStorage {
613
630
  }));
614
631
  });
615
632
  }
633
+ getUserErrors(_a) {
634
+ return __awaiter(this, arguments, void 0, function* ({ crowdinId, integrationId, search, limit, offset, orderDirection = 'desc', }) {
635
+ yield this.migrationPromise;
636
+ // `columns` keeps the heavy `data` column out of the result set
637
+ const items = yield this.db.query.userErrors.findMany({
638
+ columns: { id: true, action: true, message: true, created_at: true },
639
+ where: this.userErrorsWhereClause({ crowdinId, integrationId, search }),
640
+ orderBy: [
641
+ orderDirection === 'asc'
642
+ ? (0, drizzle_orm_1.asc)(this.schema.userErrors.created_at)
643
+ : (0, drizzle_orm_1.desc)(this.schema.userErrors.created_at),
644
+ ],
645
+ limit,
646
+ offset,
647
+ });
648
+ return items.map((item) => ({
649
+ id: item.id,
650
+ action: item.action,
651
+ message: item.message,
652
+ createdAt: item.created_at,
653
+ }));
654
+ });
655
+ }
656
+ countUserErrors(params) {
657
+ return __awaiter(this, void 0, void 0, function* () {
658
+ var _a;
659
+ yield this.migrationPromise;
660
+ const [row] = yield this.db
661
+ .select({ value: (0, drizzle_orm_1.count)() })
662
+ .from(this.schema.userErrors)
663
+ .where(this.userErrorsWhereClause(params));
664
+ return Number((_a = row === null || row === void 0 ? void 0 : row.value) !== null && _a !== void 0 ? _a : 0);
665
+ });
666
+ }
667
+ getUserError(_a) {
668
+ return __awaiter(this, arguments, void 0, function* ({ id, crowdinId, integrationId }) {
669
+ yield this.migrationPromise;
670
+ const item = yield this.db.query.userErrors.findFirst({
671
+ where: (0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.userErrors.id, id), this.userErrorsWhereClause({ crowdinId, integrationId })),
672
+ });
673
+ if (!item) {
674
+ return undefined;
675
+ }
676
+ return {
677
+ id: item.id,
678
+ action: item.action,
679
+ message: item.message,
680
+ data: item.data,
681
+ createdAt: item.created_at,
682
+ crowdinId: item.crowdin_id,
683
+ integrationId: item.integration_id,
684
+ };
685
+ });
686
+ }
616
687
  saveUserError(action, message, data, createdAt, crowdinId, integrationId) {
617
688
  return __awaiter(this, void 0, void 0, function* () {
618
689
  yield this.migrationPromise;
@@ -0,0 +1,5 @@
1
+ -- index that backs the paginated error log query:
2
+ -- WHERE crowdin_id = ? AND integration_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?
3
+ CREATE INDEX IF NOT EXISTS idx_user_errors_crowdin_integration_created_at ON "user_errors" ("crowdin_id","integration_id","created_at");
4
+ -- index for the retention cron, which deletes by created_at
5
+ CREATE INDEX IF NOT EXISTS idx_user_errors_created_at ON "user_errors" ("created_at");