@crowdin/app-project-module 1.8.0 → 1.9.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.
- package/out/middlewares/crowdin-client.js +5 -5
- package/out/middlewares/integration-access-denied.d.ts +1 -1
- package/out/middlewares/integration-access-denied.js +2 -35
- package/out/middlewares/ui-module.js +3 -3
- package/out/modules/install.js +7 -7
- package/out/modules/integration/handlers/integration-logout.js +2 -35
- package/out/modules/integration/handlers/oauth-login.js +2 -2
- package/out/modules/integration/util/cron.js +7 -40
- package/out/modules/integration/util/defaults.js +2 -35
- package/out/modules/integration/util/job.d.ts +2 -2
- package/out/modules/integration/util/job.js +5 -38
- package/out/modules/integration/util/webhooks.d.ts +1 -1
- package/out/modules/integration/util/webhooks.js +7 -7
- package/out/modules/manifest.js +6 -3
- package/out/static/ui/form.bundle.js +99 -44
- package/out/static/ui/form.bundle.js.map +1 -1
- package/out/types.d.ts +45 -1
- package/out/types.js +11 -1
- package/out/util/app-functions/crowdin.d.ts +104 -0
- package/out/util/app-functions/crowdin.js +245 -0
- package/out/util/app-functions/token.d.ts +71 -0
- package/out/util/app-functions/token.js +192 -0
- package/out/util/connection.js +11 -12
- package/out/util/credentials-masker.js +2 -2
- package/out/util/index.js +2 -2
- package/out/util/subscription.js +3 -3
- package/package.json +21 -2
package/out/types.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import Crowdin from '@crowdin/crowdin-api-client';
|
|
2
|
-
import { JwtPayload, VerifyOptions } from '@crowdin/crowdin-apps-functions';
|
|
3
2
|
import { Request } from 'express';
|
|
4
3
|
import { ContextContent } from './modules/context-menu/types';
|
|
5
4
|
import { CustomMTLogic } from './modules/custom-mt/types';
|
|
@@ -588,3 +587,48 @@ export interface FileStore {
|
|
|
588
587
|
storeFile: (content: Buffer) => Promise<string>;
|
|
589
588
|
deleteFile: (fileRef: string) => Promise<void>;
|
|
590
589
|
}
|
|
590
|
+
export interface JwtPayload {
|
|
591
|
+
aud: string;
|
|
592
|
+
sub: string;
|
|
593
|
+
domain?: string;
|
|
594
|
+
module?: string;
|
|
595
|
+
context: JwtPayloadContext;
|
|
596
|
+
iat: number;
|
|
597
|
+
exp: number;
|
|
598
|
+
code?: string;
|
|
599
|
+
}
|
|
600
|
+
export interface JwtPayloadContext {
|
|
601
|
+
project_id: number;
|
|
602
|
+
project_identifier?: string;
|
|
603
|
+
organization_id: number;
|
|
604
|
+
organization_domain?: string;
|
|
605
|
+
user_id: number;
|
|
606
|
+
user_login?: string;
|
|
607
|
+
}
|
|
608
|
+
export interface VerifyOptions {
|
|
609
|
+
ignoreExpiration: boolean;
|
|
610
|
+
}
|
|
611
|
+
export interface InstallEvent {
|
|
612
|
+
appId: string;
|
|
613
|
+
appSecret: string;
|
|
614
|
+
clientId: string;
|
|
615
|
+
userId: number;
|
|
616
|
+
agentId?: number;
|
|
617
|
+
organizationId: number;
|
|
618
|
+
domain?: string;
|
|
619
|
+
baseUrl: string;
|
|
620
|
+
code?: string;
|
|
621
|
+
}
|
|
622
|
+
export interface UninstallEvent {
|
|
623
|
+
appId: string;
|
|
624
|
+
appSecret: string;
|
|
625
|
+
clientId: string;
|
|
626
|
+
organizationId: number;
|
|
627
|
+
domain?: string;
|
|
628
|
+
baseUrl: string;
|
|
629
|
+
}
|
|
630
|
+
export declare class PaymentRequiredError extends Error {
|
|
631
|
+
subscribeLink: string;
|
|
632
|
+
initializedAt: string;
|
|
633
|
+
constructor(subscribeLink: string, initializedAt: string);
|
|
634
|
+
}
|
package/out/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.storageFiles = exports.ProjectPermissions = exports.UserPermissions = exports.EditorMode = exports.SubscriptionInfoType = exports.AccountType = exports.Scope = exports.AuthenticationType = void 0;
|
|
3
|
+
exports.PaymentRequiredError = exports.storageFiles = exports.ProjectPermissions = exports.UserPermissions = exports.EditorMode = exports.SubscriptionInfoType = exports.AccountType = exports.Scope = exports.AuthenticationType = void 0;
|
|
4
4
|
var AuthenticationType;
|
|
5
5
|
(function (AuthenticationType) {
|
|
6
6
|
AuthenticationType["CODE"] = "authorization_code";
|
|
@@ -76,3 +76,13 @@ var storageFiles;
|
|
|
76
76
|
storageFiles["SQLITE_BACKUP"] = "backup_app.sqlite";
|
|
77
77
|
storageFiles["DUMP"] = "dump_table_%s.sql";
|
|
78
78
|
})(storageFiles || (exports.storageFiles = storageFiles = {}));
|
|
79
|
+
class PaymentRequiredError extends Error {
|
|
80
|
+
constructor(subscribeLink, initializedAt) {
|
|
81
|
+
super('Payment required');
|
|
82
|
+
this.subscribeLink = subscribeLink;
|
|
83
|
+
this.initializedAt = initializedAt;
|
|
84
|
+
// @ts-expect-error: Adding custom property
|
|
85
|
+
this.code = 402;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.PaymentRequiredError = PaymentRequiredError;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import Crowdin, { ReportsModel, SourceFilesModel, TranslationsModel, WebhooksModel } from '@crowdin/crowdin-api-client';
|
|
2
|
+
interface UpdateOrCreateFileArgs {
|
|
3
|
+
client: Crowdin;
|
|
4
|
+
projectId: number;
|
|
5
|
+
name: string;
|
|
6
|
+
title?: string;
|
|
7
|
+
type?: SourceFilesModel.FileType;
|
|
8
|
+
directoryId?: number;
|
|
9
|
+
data: any;
|
|
10
|
+
file?: SourceFilesModel.File;
|
|
11
|
+
excludedTargetLanguages?: string[];
|
|
12
|
+
importOptions?: SourceFilesModel.ImportOptions;
|
|
13
|
+
}
|
|
14
|
+
export declare function updateOrCreateFile(options: UpdateOrCreateFileArgs): Promise<number>;
|
|
15
|
+
interface GetFolderArgs {
|
|
16
|
+
directories: SourceFilesModel.Directory[];
|
|
17
|
+
client: Crowdin;
|
|
18
|
+
projectId: number;
|
|
19
|
+
directoryName: string;
|
|
20
|
+
parentDirectory?: SourceFilesModel.Directory;
|
|
21
|
+
}
|
|
22
|
+
export declare function getFolder(args: GetFolderArgs): Promise<{
|
|
23
|
+
folder?: SourceFilesModel.Directory;
|
|
24
|
+
files: SourceFilesModel.File[];
|
|
25
|
+
}>;
|
|
26
|
+
interface GetOrCreateFolderArgs {
|
|
27
|
+
directories: SourceFilesModel.Directory[];
|
|
28
|
+
client: Crowdin;
|
|
29
|
+
projectId: number;
|
|
30
|
+
directoryName: string;
|
|
31
|
+
parentDirectory?: SourceFilesModel.Directory;
|
|
32
|
+
}
|
|
33
|
+
export declare function getOrCreateFolder(args: GetOrCreateFolderArgs): Promise<{
|
|
34
|
+
folder: SourceFilesModel.Directory;
|
|
35
|
+
files: SourceFilesModel.File[];
|
|
36
|
+
created: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
interface UploadTranslationsArgs {
|
|
39
|
+
client: Crowdin;
|
|
40
|
+
projectId: number;
|
|
41
|
+
fileId: number;
|
|
42
|
+
language: string;
|
|
43
|
+
fileName: string;
|
|
44
|
+
fileContent: any;
|
|
45
|
+
request?: Omit<TranslationsModel.UploadTranslationRequest, 'fileId' | 'storageId'>;
|
|
46
|
+
}
|
|
47
|
+
export declare function uploadTranslations(args: UploadTranslationsArgs): Promise<TranslationsModel.UploadTranslationResponse>;
|
|
48
|
+
interface UpdateSourceFilesArgs {
|
|
49
|
+
client: Crowdin;
|
|
50
|
+
projectId: number;
|
|
51
|
+
directory: string;
|
|
52
|
+
fileEntities: FileEntity[];
|
|
53
|
+
parentDirectory?: SourceFilesModel.Directory;
|
|
54
|
+
}
|
|
55
|
+
export declare function updateSourceFiles(args: UpdateSourceFilesArgs): Promise<void>;
|
|
56
|
+
interface HandleTranslationsArgs {
|
|
57
|
+
client: Crowdin;
|
|
58
|
+
projectId: number;
|
|
59
|
+
directory: string;
|
|
60
|
+
request: TranslationsRequest;
|
|
61
|
+
parentDirectory?: SourceFilesModel.Directory;
|
|
62
|
+
handleFn: (translations: any, language: string, file: SourceFilesModel.File) => Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
export declare function handleTranslations(args: HandleTranslationsArgs): Promise<void>;
|
|
65
|
+
interface CreateOrUpdateWebhookArgs {
|
|
66
|
+
client: Crowdin;
|
|
67
|
+
projectId: number;
|
|
68
|
+
url: string;
|
|
69
|
+
events: WebhooksModel.Event[];
|
|
70
|
+
payload: any;
|
|
71
|
+
name: string;
|
|
72
|
+
requestType?: WebhooksModel.RequestType;
|
|
73
|
+
batchingEnabled?: boolean;
|
|
74
|
+
headers?: Record<string, string>;
|
|
75
|
+
contentType?: WebhooksModel.ContentType;
|
|
76
|
+
webhookId?: number;
|
|
77
|
+
webhookMatch?: (webhook: WebhooksModel.Webhook) => boolean;
|
|
78
|
+
}
|
|
79
|
+
export declare function createOrUpdateWebhook(args: CreateOrUpdateWebhookArgs): Promise<number>;
|
|
80
|
+
export declare function getSubscription({ appIdentifier, token, organization, baseUrl, }: SubscriptionRequest): Promise<Subscription>;
|
|
81
|
+
export declare function generateReport({ client, projectId, request, }: {
|
|
82
|
+
client: Crowdin;
|
|
83
|
+
projectId: number;
|
|
84
|
+
request: ReportsModel.GenerateReportRequest;
|
|
85
|
+
}): Promise<any | undefined>;
|
|
86
|
+
interface FileEntity {
|
|
87
|
+
name: string;
|
|
88
|
+
title: string;
|
|
89
|
+
type: SourceFilesModel.FileType;
|
|
90
|
+
data: any;
|
|
91
|
+
}
|
|
92
|
+
interface TranslationsRequest {
|
|
93
|
+
[fileId: string]: string[];
|
|
94
|
+
}
|
|
95
|
+
interface SubscriptionRequest {
|
|
96
|
+
token: string;
|
|
97
|
+
organization?: string;
|
|
98
|
+
appIdentifier: string;
|
|
99
|
+
baseUrl?: string;
|
|
100
|
+
}
|
|
101
|
+
interface Subscription {
|
|
102
|
+
expires: string;
|
|
103
|
+
}
|
|
104
|
+
export {};
|
|
@@ -0,0 +1,245 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.updateOrCreateFile = updateOrCreateFile;
|
|
16
|
+
exports.getFolder = getFolder;
|
|
17
|
+
exports.getOrCreateFolder = getOrCreateFolder;
|
|
18
|
+
exports.uploadTranslations = uploadTranslations;
|
|
19
|
+
exports.updateSourceFiles = updateSourceFiles;
|
|
20
|
+
exports.handleTranslations = handleTranslations;
|
|
21
|
+
exports.createOrUpdateWebhook = createOrUpdateWebhook;
|
|
22
|
+
exports.getSubscription = getSubscription;
|
|
23
|
+
exports.generateReport = generateReport;
|
|
24
|
+
const axios_1 = __importDefault(require("axios"));
|
|
25
|
+
const types_1 = require("../../types");
|
|
26
|
+
function updateOrCreateFile(options) {
|
|
27
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
const storageFile = yield options.client.uploadStorageApi.addStorage(options.name, options.data);
|
|
29
|
+
if (options.file) {
|
|
30
|
+
yield options.client.sourceFilesApi.updateOrRestoreFile(options.projectId, options.file.id, Object.assign({ storageId: storageFile.data.id }, (options.importOptions && { importOptions: options.importOptions })));
|
|
31
|
+
const updates = [];
|
|
32
|
+
if (options.title && options.title !== options.file.title) {
|
|
33
|
+
updates.push({
|
|
34
|
+
value: options.title,
|
|
35
|
+
op: 'replace',
|
|
36
|
+
path: '/title',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (options.excludedTargetLanguages) {
|
|
40
|
+
updates.push({
|
|
41
|
+
value: options.excludedTargetLanguages,
|
|
42
|
+
op: 'replace',
|
|
43
|
+
path: '/excludedTargetLanguages',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (updates.length > 0) {
|
|
47
|
+
yield options.client.sourceFilesApi.editFile(options.projectId, options.file.id, updates);
|
|
48
|
+
}
|
|
49
|
+
return options.file.id;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const newFile = yield options.client.sourceFilesApi.createFile(options.projectId, {
|
|
53
|
+
storageId: storageFile.data.id,
|
|
54
|
+
name: options.name,
|
|
55
|
+
title: options.title,
|
|
56
|
+
type: options.type,
|
|
57
|
+
directoryId: options.directoryId,
|
|
58
|
+
excludedTargetLanguages: options.excludedTargetLanguages,
|
|
59
|
+
importOptions: options.importOptions,
|
|
60
|
+
});
|
|
61
|
+
return newFile.data.id;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function getFolder(args) {
|
|
66
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
67
|
+
const folder = args.directories.find((d) => {
|
|
68
|
+
var _a;
|
|
69
|
+
return d.name === args.directoryName &&
|
|
70
|
+
((!args.parentDirectory && !d.directoryId) || d.directoryId === ((_a = args.parentDirectory) === null || _a === void 0 ? void 0 : _a.id));
|
|
71
|
+
});
|
|
72
|
+
let files = [];
|
|
73
|
+
if (folder) {
|
|
74
|
+
files = (yield args.client.sourceFilesApi.withFetchAll().listProjectFiles(args.projectId, { directoryId: folder.id })).data.map((e) => e.data);
|
|
75
|
+
}
|
|
76
|
+
return { folder, files };
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function getOrCreateFolder(args) {
|
|
80
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
81
|
+
let { folder, files } = yield getFolder(args);
|
|
82
|
+
let created = false;
|
|
83
|
+
if (!folder) {
|
|
84
|
+
created = true;
|
|
85
|
+
folder = (yield args.client.sourceFilesApi.createDirectory(args.projectId, {
|
|
86
|
+
name: args.directoryName,
|
|
87
|
+
directoryId: args.parentDirectory ? args.parentDirectory.id : undefined,
|
|
88
|
+
})).data;
|
|
89
|
+
files = (yield args.client.sourceFilesApi.withFetchAll().listProjectFiles(args.projectId, { directoryId: folder.id })).data.map((e) => e.data);
|
|
90
|
+
}
|
|
91
|
+
return { folder, files, created };
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function uploadTranslations(args) {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
const storage = yield args.client.uploadStorageApi.addStorage(args.fileName, args.fileContent);
|
|
97
|
+
return (yield args.client.translationsApi.uploadTranslation(args.projectId, args.language, Object.assign({ fileId: args.fileId, storageId: storage.data.id }, (args.request || {})))).data;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function updateSourceFiles(args) {
|
|
101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
const directories = yield args.client.sourceFilesApi.withFetchAll().listProjectDirectories(args.projectId);
|
|
103
|
+
const { folder, files } = yield getOrCreateFolder({
|
|
104
|
+
directories: directories.data.map((d) => d.data),
|
|
105
|
+
client: args.client,
|
|
106
|
+
projectId: args.projectId,
|
|
107
|
+
directoryName: args.directory,
|
|
108
|
+
parentDirectory: args.parentDirectory,
|
|
109
|
+
});
|
|
110
|
+
yield Promise.all(args.fileEntities.map((fileEntity) => __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
return yield updateOrCreateFile({
|
|
112
|
+
client: args.client,
|
|
113
|
+
projectId: args.projectId,
|
|
114
|
+
name: fileEntity.name,
|
|
115
|
+
title: fileEntity.title,
|
|
116
|
+
type: fileEntity.type,
|
|
117
|
+
directoryId: folder.id,
|
|
118
|
+
data: fileEntity.data,
|
|
119
|
+
file: files.find((f) => f.name === fileEntity.name),
|
|
120
|
+
});
|
|
121
|
+
})));
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function handleTranslations(args) {
|
|
125
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
const directories = yield args.client.sourceFilesApi.withFetchAll().listProjectDirectories(args.projectId);
|
|
127
|
+
const { files } = yield getFolder({
|
|
128
|
+
directories: directories.data.map((d) => d.data),
|
|
129
|
+
client: args.client,
|
|
130
|
+
projectId: args.projectId,
|
|
131
|
+
directoryName: args.directory,
|
|
132
|
+
parentDirectory: args.parentDirectory,
|
|
133
|
+
});
|
|
134
|
+
for (const [fileId, targetLanguages] of Object.entries(args.request)) {
|
|
135
|
+
const file = files.find((f) => f.id === parseInt(fileId));
|
|
136
|
+
if (!file) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
yield Promise.all(targetLanguages.map((languageCode) => __awaiter(this, void 0, void 0, function* () {
|
|
140
|
+
const translationsLink = yield args.client.translationsApi.buildProjectFileTranslation(args.projectId, file.id, {
|
|
141
|
+
targetLanguageId: languageCode,
|
|
142
|
+
});
|
|
143
|
+
if (!translationsLink) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const response = yield axios_1.default.get(translationsLink.data.url);
|
|
147
|
+
yield args.handleFn(response.data, languageCode, file);
|
|
148
|
+
})));
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function createOrUpdateWebhook(args) {
|
|
153
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
154
|
+
const { client, projectId, events, name, url, payload, requestType = 'POST', batchingEnabled = true, headers, contentType, webhookId, webhookMatch, } = args;
|
|
155
|
+
let id = webhookId;
|
|
156
|
+
if (webhookMatch) {
|
|
157
|
+
const webhooks = yield client.webhooksApi.withFetchAll().listWebhooks(projectId);
|
|
158
|
+
const webhook = webhooks.data.find((e) => webhookMatch(e.data));
|
|
159
|
+
if (webhook) {
|
|
160
|
+
id = webhook.data.id;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (id) {
|
|
164
|
+
yield client.webhooksApi.editWebhook(projectId, id, [
|
|
165
|
+
{
|
|
166
|
+
value: events,
|
|
167
|
+
op: 'replace',
|
|
168
|
+
path: '/events',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
value: payload,
|
|
172
|
+
op: 'replace',
|
|
173
|
+
path: '/payload',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
value: url,
|
|
177
|
+
op: 'replace',
|
|
178
|
+
path: '/url',
|
|
179
|
+
},
|
|
180
|
+
]);
|
|
181
|
+
return id;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const newWebhook = yield client.webhooksApi.addWebhook(projectId, {
|
|
185
|
+
name,
|
|
186
|
+
url,
|
|
187
|
+
events,
|
|
188
|
+
requestType,
|
|
189
|
+
payload,
|
|
190
|
+
batchingEnabled,
|
|
191
|
+
headers,
|
|
192
|
+
contentType,
|
|
193
|
+
});
|
|
194
|
+
return newWebhook.data.id;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function getSubscription(_a) {
|
|
199
|
+
return __awaiter(this, arguments, void 0, function* ({ appIdentifier, token, organization, baseUrl, }) {
|
|
200
|
+
var _b, _c, _d, _e;
|
|
201
|
+
let requestUrl;
|
|
202
|
+
if (baseUrl) {
|
|
203
|
+
requestUrl = `${baseUrl}/api/v2/applications/${appIdentifier}/subscription`;
|
|
204
|
+
}
|
|
205
|
+
else if (!!organization) {
|
|
206
|
+
requestUrl = `https://${organization}.api.crowdin.com/api/v2/applications/${appIdentifier}/subscription`;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
requestUrl = `https://crowdin.com/api/v2/applications/${appIdentifier}/subscription`;
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
const response = yield axios_1.default.get(requestUrl, {
|
|
213
|
+
headers: {
|
|
214
|
+
Authorization: `Bearer ${token}`,
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
return response.data;
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
const e = error;
|
|
221
|
+
if (e.response) {
|
|
222
|
+
if (e.response.status === 402) {
|
|
223
|
+
throw new types_1.PaymentRequiredError((_b = e.response.data) === null || _b === void 0 ? void 0 : _b.subscribeLink, (_c = e.response.data) === null || _c === void 0 ? void 0 : _c.initializedAt);
|
|
224
|
+
}
|
|
225
|
+
else if ((_e = (_d = e.response.data) === null || _d === void 0 ? void 0 : _d.error) === null || _e === void 0 ? void 0 : _e.message) {
|
|
226
|
+
throw new Error(e.response.data.error.message);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
throw e;
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
function generateReport(_a) {
|
|
234
|
+
return __awaiter(this, arguments, void 0, function* ({ client, projectId, request, }) {
|
|
235
|
+
const report = yield client.reportsApi.generateReport(projectId, request);
|
|
236
|
+
while (true) {
|
|
237
|
+
const status = yield client.reportsApi.checkReportStatus(projectId, report.data.identifier);
|
|
238
|
+
if (status.data.status === 'finished') {
|
|
239
|
+
const downloadRes = yield client.reportsApi.downloadReport(projectId, report.data.identifier);
|
|
240
|
+
const reportBlob = yield axios_1.default.get(downloadRes.data.url);
|
|
241
|
+
return reportBlob.data;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { JwtPayload, VerifyOptions } from '../../types';
|
|
2
|
+
interface FetchAppTokenArgs {
|
|
3
|
+
appId: string;
|
|
4
|
+
appSecret: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret: string;
|
|
7
|
+
domain: string;
|
|
8
|
+
userId: number;
|
|
9
|
+
url?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function fetchAppToken(options: FetchAppTokenArgs): Promise<AppToken>;
|
|
12
|
+
interface FetchAgentTokenArgs extends FetchAppTokenArgs {
|
|
13
|
+
agentId: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function fetchAgentToken(args: FetchAgentTokenArgs): Promise<AppToken>;
|
|
16
|
+
interface FetchAppWithCodeTokenArgs extends FetchAppTokenArgs {
|
|
17
|
+
code: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function fetchAppWithCodeToken(args: FetchAppWithCodeTokenArgs): Promise<AppToken>;
|
|
20
|
+
interface GenerateOAuthTokenArgs {
|
|
21
|
+
clientId: string;
|
|
22
|
+
clientSecret: string;
|
|
23
|
+
code: string;
|
|
24
|
+
url?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function generateOAuthToken(options: GenerateOAuthTokenArgs): Promise<Token>;
|
|
27
|
+
interface RefreshOAuthTokenArgs {
|
|
28
|
+
clientId: string;
|
|
29
|
+
clientSecret: string;
|
|
30
|
+
refreshToken: string;
|
|
31
|
+
url?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function refreshOAuthToken(options: RefreshOAuthTokenArgs): Promise<Token>;
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param jwtPayload jwt token payload
|
|
37
|
+
* @returns unique identifier of crowdin user and project context
|
|
38
|
+
*/
|
|
39
|
+
export declare function constructCrowdinIdFromJwtPayload(jwtPayload: JwtPayload): string;
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* @param crowdinId crowdin id (from {@link constructCrowdinIdFromJwtPayload})
|
|
43
|
+
* @returns crowdin project id
|
|
44
|
+
*/
|
|
45
|
+
export declare function getProjectId(crowdinId: string): number;
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @param crowdinId crowdin id (from {@link constructCrowdinIdFromJwtPayload})
|
|
49
|
+
* @returns object with organization(id|domain), project id and user id
|
|
50
|
+
*/
|
|
51
|
+
export declare function parseCrowdinId(crowdinId: string): {
|
|
52
|
+
organization: string;
|
|
53
|
+
projectId: number;
|
|
54
|
+
userId: number;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* @param jwtToken jwt token which Crowdin adds to app iframe
|
|
59
|
+
* @param clientSecret OAuth client secret of the app
|
|
60
|
+
* @param options extra options for verification
|
|
61
|
+
* @returns jwt payload
|
|
62
|
+
*/
|
|
63
|
+
export declare function validateJwtToken(jwtToken: string, clientSecret: string, options?: VerifyOptions): Promise<JwtPayload>;
|
|
64
|
+
interface AppToken {
|
|
65
|
+
accessToken: string;
|
|
66
|
+
expiresIn: number;
|
|
67
|
+
}
|
|
68
|
+
interface Token extends AppToken {
|
|
69
|
+
refreshToken: string;
|
|
70
|
+
}
|
|
71
|
+
export {};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.fetchAppToken = fetchAppToken;
|
|
49
|
+
exports.fetchAgentToken = fetchAgentToken;
|
|
50
|
+
exports.fetchAppWithCodeToken = fetchAppWithCodeToken;
|
|
51
|
+
exports.generateOAuthToken = generateOAuthToken;
|
|
52
|
+
exports.refreshOAuthToken = refreshOAuthToken;
|
|
53
|
+
exports.constructCrowdinIdFromJwtPayload = constructCrowdinIdFromJwtPayload;
|
|
54
|
+
exports.getProjectId = getProjectId;
|
|
55
|
+
exports.parseCrowdinId = parseCrowdinId;
|
|
56
|
+
exports.validateJwtToken = validateJwtToken;
|
|
57
|
+
const axios_1 = __importDefault(require("axios"));
|
|
58
|
+
const jwt = __importStar(require("jsonwebtoken"));
|
|
59
|
+
const crowdinAuthUrl = 'https://accounts.crowdin.com/oauth/token';
|
|
60
|
+
function fetchAppToken(options) {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
const token = yield axios_1.default.post(options.url || crowdinAuthUrl, {
|
|
63
|
+
grant_type: 'crowdin_app',
|
|
64
|
+
client_id: options.clientId,
|
|
65
|
+
client_secret: options.clientSecret,
|
|
66
|
+
app_id: options.appId,
|
|
67
|
+
app_secret: options.appSecret,
|
|
68
|
+
domain: options.domain,
|
|
69
|
+
user_id: options.userId,
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
accessToken: token.data.access_token,
|
|
73
|
+
expiresIn: +token.data.expires_in,
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function fetchAgentToken(args) {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
const token = yield axios_1.default.post(args.url || crowdinAuthUrl, {
|
|
80
|
+
grant_type: 'crowdin_agent',
|
|
81
|
+
client_id: args.clientId,
|
|
82
|
+
client_secret: args.clientSecret,
|
|
83
|
+
app_id: args.appId,
|
|
84
|
+
app_secret: args.appSecret,
|
|
85
|
+
domain: args.domain,
|
|
86
|
+
user_id: args.userId,
|
|
87
|
+
agent_id: args.agentId,
|
|
88
|
+
});
|
|
89
|
+
return {
|
|
90
|
+
accessToken: token.data.access_token,
|
|
91
|
+
expiresIn: +token.data.expires_in,
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function fetchAppWithCodeToken(args) {
|
|
96
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
97
|
+
const token = yield axios_1.default.post(args.url || crowdinAuthUrl, {
|
|
98
|
+
grant_type: 'crowdin_app_with_code',
|
|
99
|
+
client_id: args.clientId,
|
|
100
|
+
client_secret: args.clientSecret,
|
|
101
|
+
app_id: args.appId,
|
|
102
|
+
app_secret: args.appSecret,
|
|
103
|
+
domain: args.domain,
|
|
104
|
+
user_id: args.userId,
|
|
105
|
+
code: args.code,
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
accessToken: token.data.access_token,
|
|
109
|
+
expiresIn: +token.data.expires_in,
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function generateOAuthToken(options) {
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
const token = yield axios_1.default.post(options.url || crowdinAuthUrl, {
|
|
116
|
+
grant_type: 'authorization_code',
|
|
117
|
+
client_id: options.clientId,
|
|
118
|
+
client_secret: options.clientSecret,
|
|
119
|
+
code: options.code,
|
|
120
|
+
});
|
|
121
|
+
return {
|
|
122
|
+
accessToken: token.data.access_token,
|
|
123
|
+
refreshToken: token.data.refresh_token,
|
|
124
|
+
expiresIn: +token.data.expires_in,
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function refreshOAuthToken(options) {
|
|
129
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
130
|
+
const token = yield axios_1.default.post(options.url || crowdinAuthUrl, {
|
|
131
|
+
grant_type: 'refresh_token',
|
|
132
|
+
client_id: options.clientId,
|
|
133
|
+
client_secret: options.clientSecret,
|
|
134
|
+
refresh_token: options.refreshToken,
|
|
135
|
+
});
|
|
136
|
+
return {
|
|
137
|
+
accessToken: token.data.access_token,
|
|
138
|
+
refreshToken: token.data.refresh_token,
|
|
139
|
+
expiresIn: +token.data.expires_in,
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
*
|
|
145
|
+
* @param jwtPayload jwt token payload
|
|
146
|
+
* @returns unique identifier of crowdin user and project context
|
|
147
|
+
*/
|
|
148
|
+
function constructCrowdinIdFromJwtPayload(jwtPayload) {
|
|
149
|
+
return `${jwtPayload.domain || jwtPayload.context.organization_id}__${jwtPayload.context.project_id}__${jwtPayload.sub}`;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
*
|
|
153
|
+
* @param crowdinId crowdin id (from {@link constructCrowdinIdFromJwtPayload})
|
|
154
|
+
* @returns crowdin project id
|
|
155
|
+
*/
|
|
156
|
+
function getProjectId(crowdinId) {
|
|
157
|
+
return Number(crowdinId.split('__')[1]);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
*
|
|
161
|
+
* @param crowdinId crowdin id (from {@link constructCrowdinIdFromJwtPayload})
|
|
162
|
+
* @returns object with organization(id|domain), project id and user id
|
|
163
|
+
*/
|
|
164
|
+
function parseCrowdinId(crowdinId) {
|
|
165
|
+
const crowdinIdParts = crowdinId.split('__');
|
|
166
|
+
return {
|
|
167
|
+
organization: crowdinIdParts[0],
|
|
168
|
+
projectId: Number(crowdinIdParts[1]),
|
|
169
|
+
userId: Number(crowdinIdParts[2]),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
*
|
|
174
|
+
* @param jwtToken jwt token which Crowdin adds to app iframe
|
|
175
|
+
* @param clientSecret OAuth client secret of the app
|
|
176
|
+
* @param options extra options for verification
|
|
177
|
+
* @returns jwt payload
|
|
178
|
+
*/
|
|
179
|
+
function validateJwtToken(jwtToken, clientSecret, options) {
|
|
180
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
181
|
+
return new Promise((res, rej) => {
|
|
182
|
+
jwt.verify(jwtToken, clientSecret, options, (err, decoded) => {
|
|
183
|
+
if (err) {
|
|
184
|
+
rej(err);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
res(decoded);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|