@crowdin/app-project-module 0.69.0 → 0.70.1
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/index.js +16 -3
- package/out/modules/ai-provider/handlers/chat-completions.js +20 -21
- package/out/modules/ai-provider/handlers/get-model-list.js +3 -2
- package/out/modules/ai-provider/types.d.ts +112 -7
- package/out/modules/ai-provider/util/index.d.ts +5 -0
- package/out/modules/ai-provider/util/index.js +72 -1
- package/out/modules/file-processing/handlers/pre-post-process.js +6 -0
- package/out/modules/file-processing/types.d.ts +16 -8
- package/out/modules/manifest.js +34 -0
- package/out/modules/organization-settings-menu/index.d.ts +6 -0
- package/out/modules/organization-settings-menu/index.js +18 -0
- package/out/modules/profile-settings-menu/index.d.ts +6 -0
- package/out/modules/profile-settings-menu/index.js +18 -0
- package/out/modules/webhooks/handlers/webhook-handler.d.ts +2 -2
- package/out/modules/webhooks/handlers/webhook-handler.js +9 -6
- package/out/modules/webhooks/index.js +1 -1
- package/out/modules/webhooks/types.d.ts +2 -0
- package/out/modules/workflow-step-type/handlers/delete-step.d.ts +5 -0
- package/out/modules/workflow-step-type/handlers/delete-step.js +70 -0
- package/out/modules/workflow-step-type/handlers/step-settings-save.d.ts +5 -0
- package/out/modules/workflow-step-type/handlers/step-settings-save.js +80 -0
- package/out/modules/workflow-step-type/index.d.ts +6 -0
- package/out/modules/workflow-step-type/index.js +36 -0
- package/out/modules/workflow-step-type/types.d.ts +57 -0
- package/out/modules/workflow-step-type/types.js +2 -0
- package/out/modules/workflow-step-type/util/index.d.ts +3 -0
- package/out/modules/workflow-step-type/util/index.js +16 -0
- package/out/static/js/form.js +32 -32
- package/out/storage/index.d.ts +1 -0
- package/out/storage/mysql.d.ts +1 -0
- package/out/storage/mysql.js +9 -0
- package/out/storage/postgre.d.ts +1 -0
- package/out/storage/postgre.js +9 -0
- package/out/storage/sqlite.d.ts +1 -0
- package/out/storage/sqlite.js +3 -0
- package/out/types.d.ts +14 -1
- package/out/util/logger.d.ts +5 -2
- package/out/util/logger.js +26 -10
- package/package.json +14 -8
package/out/index.js
CHANGED
|
@@ -74,12 +74,15 @@ const fileProcessingApps = __importStar(require("./modules/file-processing"));
|
|
|
74
74
|
const integrationApp = __importStar(require("./modules/integration"));
|
|
75
75
|
const modalApp = __importStar(require("./modules/modal"));
|
|
76
76
|
const organizationMenuApp = __importStar(require("./modules/organization-menu"));
|
|
77
|
+
const organizationSettingsMenuApp = __importStar(require("./modules/organization-settings-menu"));
|
|
77
78
|
const profileResourcesMenuApp = __importStar(require("./modules/profile-resources-menu"));
|
|
79
|
+
const profileSettingsMenuApp = __importStar(require("./modules/profile-settings-menu"));
|
|
78
80
|
const projectMenuApp = __importStar(require("./modules/project-menu"));
|
|
79
81
|
const projectMenuCrowdsourceApp = __importStar(require("./modules/project-menu-crowdsource"));
|
|
80
82
|
const projectReportsApp = __importStar(require("./modules/project-reports"));
|
|
81
83
|
const projectToolsApp = __importStar(require("./modules/project-tools"));
|
|
82
84
|
const webhooks = __importStar(require("./modules/webhooks"));
|
|
85
|
+
const workflowStepType = __importStar(require("./modules/workflow-step-type"));
|
|
83
86
|
const subscription_1 = require("./util/subscription");
|
|
84
87
|
var types_2 = require("./types");
|
|
85
88
|
Object.defineProperty(exports, "ProjectPermissions", { enumerable: true, get: function () { return types_2.ProjectPermissions; } });
|
|
@@ -123,7 +126,14 @@ function addCrowdinEndpoints(app, clientConfig) {
|
|
|
123
126
|
}
|
|
124
127
|
storage.initialize(config);
|
|
125
128
|
logger.initialize(config);
|
|
126
|
-
app.use(
|
|
129
|
+
app.use((req, res, next) => {
|
|
130
|
+
if (config.webhooks && req.path === '/webhooks') {
|
|
131
|
+
return terminus_express_1.default.raw({ type: '*/*', limit: '50mb' })(req, res, next);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
return terminus_express_1.default.json({ limit: '50mb' })(req, res, next);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
127
137
|
if (!config.disableLogsFormatter) {
|
|
128
138
|
logsFormatter.setup();
|
|
129
139
|
app.use(logsFormatter.contextResolverMiddleware());
|
|
@@ -142,7 +152,9 @@ function addCrowdinEndpoints(app, clientConfig) {
|
|
|
142
152
|
editorRightPanelApp.register({ config, app });
|
|
143
153
|
projectMenuApp.register({ config, app });
|
|
144
154
|
profileResourcesMenuApp.register({ config, app });
|
|
155
|
+
profileSettingsMenuApp.register({ config, app });
|
|
145
156
|
organizationMenuApp.register({ config, app });
|
|
157
|
+
organizationSettingsMenuApp.register({ config, app });
|
|
146
158
|
projectMenuCrowdsourceApp.register({ config, app });
|
|
147
159
|
projectToolsApp.register({ config, app });
|
|
148
160
|
projectReportsApp.register({ config, app });
|
|
@@ -177,6 +189,7 @@ function addCrowdinEndpoints(app, clientConfig) {
|
|
|
177
189
|
aiTools.registerAiToolWidgets({ config, app });
|
|
178
190
|
externalQaCheck.register({ config, app });
|
|
179
191
|
webhooks.register({ config, app });
|
|
192
|
+
workflowStepType.register({ config, app });
|
|
180
193
|
addFormSchema({ config, app });
|
|
181
194
|
return Object.assign(Object.assign({}, exports.metadataStore), { establishCrowdinConnection: (authRequest, moduleKey) => {
|
|
182
195
|
let jwtToken = '';
|
|
@@ -193,13 +206,13 @@ function addCrowdinEndpoints(app, clientConfig) {
|
|
|
193
206
|
checkSubscriptionExpiration: false,
|
|
194
207
|
moduleKey,
|
|
195
208
|
});
|
|
196
|
-
}, encryptCrowdinConnection: (data) => (0, util_1.encryptData)(config, JSON.stringify(data)), dencryptCrowdinConnection: (hash) => __awaiter(this, void 0, void 0, function* () {
|
|
209
|
+
}, encryptCrowdinConnection: (data) => (0, util_1.encryptData)(config, JSON.stringify(data)), dencryptCrowdinConnection: (hash, autoRenew) => __awaiter(this, void 0, void 0, function* () {
|
|
197
210
|
const { crowdinId, extra } = JSON.parse((0, util_1.decryptData)(config, hash));
|
|
198
211
|
const credentials = yield storage.getStorage().getCrowdinCredentials(crowdinId);
|
|
199
212
|
if (!credentials) {
|
|
200
213
|
throw new Error('Failed to find Crowdin credentials');
|
|
201
214
|
}
|
|
202
|
-
const { client } = yield (0, connection_1.prepareCrowdinClient)({ config, credentials });
|
|
215
|
+
const { client } = yield (0, connection_1.prepareCrowdinClient)({ config, credentials, autoRenew });
|
|
203
216
|
return { client, extra };
|
|
204
217
|
}) });
|
|
205
218
|
}
|
|
@@ -13,12 +13,7 @@ const util_1 = require("../../../util");
|
|
|
13
13
|
const logger_1 = require("../../../util/logger");
|
|
14
14
|
const files_1 = require("../../integration/util/files");
|
|
15
15
|
const util_2 = require("../util");
|
|
16
|
-
|
|
17
|
-
// Crowdin documentation https://support.crowdin.com/developer/crowdin-apps-module-custom-ai/#expected-response-from-the-app
|
|
18
|
-
const ROLES = {
|
|
19
|
-
assistant: 'assistant',
|
|
20
|
-
};
|
|
21
|
-
const DEFAULT_ROLE = ROLES.assistant;
|
|
16
|
+
const DEFAULT_ROLE = 'assistant';
|
|
22
17
|
const getErrorStatus = (e) => {
|
|
23
18
|
if (typeof e === 'object' && 'status' in e && typeof e.status === 'number') {
|
|
24
19
|
return e.status;
|
|
@@ -39,7 +34,7 @@ function handle(aiProvider) {
|
|
|
39
34
|
let message;
|
|
40
35
|
let data;
|
|
41
36
|
const chunks = [];
|
|
42
|
-
const { crowdinApiClient: client, crowdinContext: context, body: { messages, model, action, stream, responseFormat: { type: responseFormatType } = { type: undefined }, }, } = req;
|
|
37
|
+
const { crowdinApiClient: client, crowdinContext: context, body: { messages, model, action, stream, tools, tool_choice: toolChoice, responseFormat: { type: responseFormatType } = { type: undefined }, }, } = req;
|
|
43
38
|
isStream = !!stream;
|
|
44
39
|
const startStream = () => {
|
|
45
40
|
if (!res.headersSent) {
|
|
@@ -47,11 +42,12 @@ function handle(aiProvider) {
|
|
|
47
42
|
Connection: 'keep-alive',
|
|
48
43
|
'Cache-Control': 'no-cache',
|
|
49
44
|
'Content-Type': 'text/event-stream',
|
|
45
|
+
'X-Accel-Buffering': 'no',
|
|
50
46
|
});
|
|
51
47
|
}
|
|
52
48
|
};
|
|
53
49
|
const result = yield aiProvider.chatCompletions({
|
|
54
|
-
messages,
|
|
50
|
+
messages: messages.map(util_2.inputMessageToChatCompletionMessage),
|
|
55
51
|
model,
|
|
56
52
|
action,
|
|
57
53
|
responseFormat: responseFormatType,
|
|
@@ -59,19 +55,26 @@ function handle(aiProvider) {
|
|
|
59
55
|
context,
|
|
60
56
|
req,
|
|
61
57
|
isStream,
|
|
62
|
-
|
|
58
|
+
tools,
|
|
59
|
+
toolChoice,
|
|
60
|
+
/* eslint-disable @typescript-eslint/camelcase */
|
|
61
|
+
sendEvent: ({ content, role, tool_calls }) => __awaiter(this, void 0, void 0, function* () {
|
|
63
62
|
if (!isStream) {
|
|
64
|
-
chunks.push({ content, role });
|
|
63
|
+
chunks.push({ content, role, tool_calls });
|
|
65
64
|
return;
|
|
66
65
|
}
|
|
67
66
|
startStream();
|
|
67
|
+
const delta = {
|
|
68
|
+
role: role || DEFAULT_ROLE,
|
|
69
|
+
content: content || null,
|
|
70
|
+
};
|
|
71
|
+
if (!!tool_calls) {
|
|
72
|
+
delta.tool_calls = tool_calls;
|
|
73
|
+
}
|
|
68
74
|
const message = {
|
|
69
75
|
choices: [
|
|
70
76
|
{
|
|
71
|
-
delta
|
|
72
|
-
role: role || DEFAULT_ROLE,
|
|
73
|
-
content,
|
|
74
|
-
},
|
|
77
|
+
delta,
|
|
75
78
|
},
|
|
76
79
|
],
|
|
77
80
|
};
|
|
@@ -92,18 +95,14 @@ function handle(aiProvider) {
|
|
|
92
95
|
data = result;
|
|
93
96
|
}
|
|
94
97
|
if (chunks.length) {
|
|
95
|
-
data =
|
|
96
|
-
{
|
|
97
|
-
role: chunks[0].role || DEFAULT_ROLE,
|
|
98
|
-
content: chunks.map((chunk) => chunk.content).join(''),
|
|
99
|
-
},
|
|
100
|
-
];
|
|
98
|
+
data = (0, util_2.mergeChatCompletionChunks)(chunks);
|
|
101
99
|
}
|
|
102
100
|
if (data && data.length > 0) {
|
|
103
101
|
choices = data.map((message) => ({
|
|
104
102
|
message: {
|
|
105
103
|
role: message.role || DEFAULT_ROLE,
|
|
106
|
-
content: message.content,
|
|
104
|
+
content: message.content || null,
|
|
105
|
+
tool_calls: message.tool_calls,
|
|
107
106
|
},
|
|
108
107
|
}));
|
|
109
108
|
}
|
|
@@ -22,13 +22,14 @@ function handle(aiProvider) {
|
|
|
22
22
|
context: req.crowdinContext,
|
|
23
23
|
});
|
|
24
24
|
const data = modelList.map((model) => {
|
|
25
|
-
var _a, _b, _c, _d;
|
|
25
|
+
var _a, _b, _c, _d, _e;
|
|
26
26
|
return ({
|
|
27
27
|
id: model.id,
|
|
28
28
|
supportsJsonMode: (_a = model.supportsJsonMode) !== null && _a !== void 0 ? _a : false,
|
|
29
29
|
supportsFunctionCalling: (_b = model.supportsFunctionCalling) !== null && _b !== void 0 ? _b : false,
|
|
30
30
|
supportsStreaming: (_c = model.supportsStreaming) !== null && _c !== void 0 ? _c : false,
|
|
31
|
-
|
|
31
|
+
supportsVision: (_d = model.supportsVision) !== null && _d !== void 0 ? _d : false,
|
|
32
|
+
contextWindowLimit: (_e = model.contextWindowLimit) !== null && _e !== void 0 ? _e : exports.CONTEXT_WINDOW_LIMIT,
|
|
32
33
|
});
|
|
33
34
|
});
|
|
34
35
|
res.send({ data });
|
|
@@ -17,8 +17,8 @@ export interface AiProviderModule extends Environments, ModuleKey {
|
|
|
17
17
|
/**
|
|
18
18
|
* processes a sequence of conversation messages and generates responses from the assistant
|
|
19
19
|
*/
|
|
20
|
-
chatCompletions: ({ messages, model, action, responseFormat, client, context, req, }: {
|
|
21
|
-
messages:
|
|
20
|
+
chatCompletions: ({ messages, model, action, responseFormat, client, context, req, isStream, sendEvent, tools, toolChoice, }: {
|
|
21
|
+
messages: ChatCompletionMessage[];
|
|
22
22
|
model: string;
|
|
23
23
|
action: string;
|
|
24
24
|
responseFormat: string;
|
|
@@ -26,8 +26,10 @@ export interface AiProviderModule extends Environments, ModuleKey {
|
|
|
26
26
|
context: CrowdinContextInfo;
|
|
27
27
|
req: CrowdinClientRequest;
|
|
28
28
|
isStream: boolean;
|
|
29
|
-
sendEvent: (chunk:
|
|
30
|
-
|
|
29
|
+
sendEvent: (chunk: ChatCompletionChunkMessage) => Promise<void>;
|
|
30
|
+
tools?: ChatCompletionTool[];
|
|
31
|
+
toolChoice?: string | AiToolChoice;
|
|
32
|
+
}) => Promise<ChatCompletionResponseMessage[] | ExtendedResult<ChatCompletionResponseMessage[]> | void>;
|
|
31
33
|
/**
|
|
32
34
|
* provides a list of available model
|
|
33
35
|
*/
|
|
@@ -41,9 +43,112 @@ export interface SupportedModels {
|
|
|
41
43
|
supportsJsonMode?: boolean;
|
|
42
44
|
supportsFunctionCalling?: boolean;
|
|
43
45
|
supportsStreaming?: boolean;
|
|
46
|
+
supportsVision?: boolean;
|
|
44
47
|
contextWindowLimit?: number;
|
|
45
48
|
}
|
|
46
|
-
export interface
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
export interface ChatCompletionTool {
|
|
50
|
+
type: 'function';
|
|
51
|
+
function: ChatCompletionToolFunctionDeclaration;
|
|
49
52
|
}
|
|
53
|
+
export interface ChatCompletionToolFunctionDeclaration {
|
|
54
|
+
/**
|
|
55
|
+
* The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.
|
|
56
|
+
*/
|
|
57
|
+
name: string;
|
|
58
|
+
/**
|
|
59
|
+
* A description of what the function does, used by the model to choose when and how to call the function.
|
|
60
|
+
*/
|
|
61
|
+
description?: string;
|
|
62
|
+
/**
|
|
63
|
+
* The parameters the functions accepts, described as a JSON Schema object.
|
|
64
|
+
* https://json-schema.org/understanding-json-schema/
|
|
65
|
+
*/
|
|
66
|
+
parameters?: object;
|
|
67
|
+
}
|
|
68
|
+
export interface AiToolChoice {
|
|
69
|
+
type: 'function';
|
|
70
|
+
function: {
|
|
71
|
+
/**
|
|
72
|
+
* The name of the function to call.
|
|
73
|
+
*/
|
|
74
|
+
name: string;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export type ChatCompletionMessage = ChatCompletionSystemMessage | ChatCompletionUserMessage | ChatCompletionAssistantMessage | ChatCompletionToolMessage;
|
|
78
|
+
export interface ChatCompletionSystemMessage {
|
|
79
|
+
role: 'system';
|
|
80
|
+
content: string | ChatCompletionContentPartText[];
|
|
81
|
+
}
|
|
82
|
+
export interface ChatCompletionUserMessage {
|
|
83
|
+
role?: 'user';
|
|
84
|
+
content: string | ChatCompletionContentPart[];
|
|
85
|
+
}
|
|
86
|
+
export type ChatCompletionResponseMessage = ChatCompletionAssistantMessage;
|
|
87
|
+
export interface ChatCompletionAssistantMessage {
|
|
88
|
+
role?: 'assistant';
|
|
89
|
+
content?: string | ChatCompletionContentPartText[] | null;
|
|
90
|
+
tool_calls?: ChatCompletionMessageToolCall[] | null;
|
|
91
|
+
}
|
|
92
|
+
export interface ChatCompletionChunkMessage {
|
|
93
|
+
role?: ROLES;
|
|
94
|
+
content?: string | null;
|
|
95
|
+
tool_calls?: ChatCompletionDeltaMessageToolCall[];
|
|
96
|
+
}
|
|
97
|
+
export interface ChatCompletionToolMessage {
|
|
98
|
+
content: string | ChatCompletionContentPartText[];
|
|
99
|
+
role: 'tool';
|
|
100
|
+
/**
|
|
101
|
+
* Tool call that this message is responding to.
|
|
102
|
+
*/
|
|
103
|
+
tool_call_id: string;
|
|
104
|
+
}
|
|
105
|
+
export type ROLES = 'user' | 'assistant' | 'system' | 'tool';
|
|
106
|
+
export type ChatCompletionContentPart = ChatCompletionContentPartText | ChatCompletionContentPartImage;
|
|
107
|
+
export type ChatCompletionContentPartText = {
|
|
108
|
+
type: 'text';
|
|
109
|
+
text: string;
|
|
110
|
+
};
|
|
111
|
+
export type ChatCompletionContentPartImage = {
|
|
112
|
+
type: 'image_url';
|
|
113
|
+
image_url: {
|
|
114
|
+
/**
|
|
115
|
+
* Either a URL of the image or the base64 encoded image data.
|
|
116
|
+
*/
|
|
117
|
+
url: string;
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
export interface ChatCompletionMessageToolCall {
|
|
121
|
+
id: string;
|
|
122
|
+
type: 'function';
|
|
123
|
+
function: {
|
|
124
|
+
/**
|
|
125
|
+
* The arguments to call the function with, as generated by the model in JSON format.
|
|
126
|
+
* Note that the model does not always generate valid JSON.
|
|
127
|
+
*/
|
|
128
|
+
arguments?: string;
|
|
129
|
+
name: string;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export interface ChatCompletionDeltaMessageToolCall {
|
|
133
|
+
index: number;
|
|
134
|
+
id?: string;
|
|
135
|
+
type?: 'function';
|
|
136
|
+
function?: {
|
|
137
|
+
/**
|
|
138
|
+
* The arguments to call the function with, as generated by the model in JSON format.
|
|
139
|
+
* Note that the model does not always generate valid JSON.
|
|
140
|
+
*/
|
|
141
|
+
arguments?: string;
|
|
142
|
+
name?: string;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export interface InputMessage {
|
|
146
|
+
role?: ROLES;
|
|
147
|
+
content: string | InputContentPart[];
|
|
148
|
+
}
|
|
149
|
+
export type InputContentPart = ChatCompletionContentPartText | InputChatCompletionContentPartImage;
|
|
150
|
+
export type InputChatCompletionContentPartImage = {
|
|
151
|
+
type: 'image';
|
|
152
|
+
mimeType: string;
|
|
153
|
+
url: string;
|
|
154
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AppModuleAggregateError } from '../../../util/logger';
|
|
2
|
+
import { ChatCompletionChunkMessage, ChatCompletionContentPart, ChatCompletionMessage, ChatCompletionMessageToolCall, ChatCompletionResponseMessage, InputContentPart, InputMessage } from '../types';
|
|
2
3
|
interface RateLimitErrorOptions {
|
|
3
4
|
error?: Error;
|
|
4
5
|
message?: string;
|
|
@@ -8,4 +9,8 @@ export declare class RateLimitError extends AppModuleAggregateError {
|
|
|
8
9
|
readonly status = 429;
|
|
9
10
|
constructor({ error, message }?: RateLimitErrorOptions);
|
|
10
11
|
}
|
|
12
|
+
export declare function normalizeContentParts(content: string | InputContentPart[]): string | ChatCompletionContentPart[];
|
|
13
|
+
export declare function inputMessageToChatCompletionMessage(message: InputMessage): ChatCompletionMessage;
|
|
14
|
+
export declare function mergeToolCalls(chunks: ChatCompletionChunkMessage[]): ChatCompletionMessageToolCall[] | null;
|
|
15
|
+
export declare function mergeChatCompletionChunks(chunks: ChatCompletionChunkMessage[]): ChatCompletionResponseMessage[];
|
|
11
16
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RateLimitError = exports.isRateLimitError = void 0;
|
|
3
|
+
exports.mergeChatCompletionChunks = exports.mergeToolCalls = exports.inputMessageToChatCompletionMessage = exports.normalizeContentParts = exports.RateLimitError = exports.isRateLimitError = void 0;
|
|
4
4
|
const logger_1 = require("../../../util/logger");
|
|
5
5
|
const HTTP_RATE_LIMIT = 429;
|
|
6
6
|
function isRateLimitError(e) {
|
|
@@ -19,3 +19,74 @@ class RateLimitError extends logger_1.AppModuleAggregateError {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
exports.RateLimitError = RateLimitError;
|
|
22
|
+
function normalizeContentParts(content) {
|
|
23
|
+
return Array.isArray(content)
|
|
24
|
+
? content.map((part) => part.type === 'image'
|
|
25
|
+
? {
|
|
26
|
+
type: 'image_url',
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
28
|
+
image_url: {
|
|
29
|
+
url: part.url,
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
: part)
|
|
33
|
+
: content;
|
|
34
|
+
}
|
|
35
|
+
exports.normalizeContentParts = normalizeContentParts;
|
|
36
|
+
function inputMessageToChatCompletionMessage(message) {
|
|
37
|
+
switch (message.role) {
|
|
38
|
+
case undefined:
|
|
39
|
+
case 'user':
|
|
40
|
+
return {
|
|
41
|
+
role: 'user',
|
|
42
|
+
content: normalizeContentParts(message.content),
|
|
43
|
+
};
|
|
44
|
+
default:
|
|
45
|
+
return message;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.inputMessageToChatCompletionMessage = inputMessageToChatCompletionMessage;
|
|
49
|
+
function mergeToolCalls(chunks) {
|
|
50
|
+
const toolCalls = [];
|
|
51
|
+
chunks.forEach((chunk) => {
|
|
52
|
+
if (!chunk.tool_calls) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
chunk.tool_calls.forEach((toolCallChunk) => {
|
|
56
|
+
const delta = toolCalls.find((toolCall) => toolCall.index === toolCallChunk.index);
|
|
57
|
+
if (!delta) {
|
|
58
|
+
toolCalls.push(toolCallChunk);
|
|
59
|
+
}
|
|
60
|
+
else if (!!toolCallChunk.function && 'arguments' in toolCallChunk.function) {
|
|
61
|
+
if (!delta.function) {
|
|
62
|
+
delta.function = toolCallChunk.function;
|
|
63
|
+
}
|
|
64
|
+
else if (!delta.function.arguments) {
|
|
65
|
+
delta.function.arguments = toolCallChunk.function.arguments;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
delta.function.arguments += toolCallChunk.function.arguments;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
toolCalls.map((tool) => {
|
|
74
|
+
if ('index' in tool) {
|
|
75
|
+
delete tool.index;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return !toolCalls.length ? null : toolCalls;
|
|
79
|
+
}
|
|
80
|
+
exports.mergeToolCalls = mergeToolCalls;
|
|
81
|
+
function mergeChatCompletionChunks(chunks) {
|
|
82
|
+
/* eslint-disable @typescript-eslint/camelcase */
|
|
83
|
+
const tool_calls = mergeToolCalls(chunks);
|
|
84
|
+
return [
|
|
85
|
+
{
|
|
86
|
+
role: chunks[0].role || 'assistant',
|
|
87
|
+
content: tool_calls ? null : chunks.map((chunk) => chunk.content).join(''),
|
|
88
|
+
tool_calls,
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
exports.mergeChatCompletionChunks = mergeChatCompletionChunks;
|
|
@@ -23,9 +23,15 @@ function handle(baseConfig, config, folderName) {
|
|
|
23
23
|
fs_1.default.mkdirSync(path_1.default.join(folderPath, folderName), { recursive: true });
|
|
24
24
|
}
|
|
25
25
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
var _a;
|
|
26
27
|
const response = {};
|
|
27
28
|
const baseFilesUrl = `${baseConfig.baseUrl}/file/download/${folderName}`;
|
|
28
29
|
const body = req.body;
|
|
30
|
+
// Skip assets (e.g., images, videos, or other media files) as they typically don't need to be processed
|
|
31
|
+
if (((_a = body === null || body === void 0 ? void 0 : body.file) === null || _a === void 0 ? void 0 : _a.type) === 'assets' && !('processAssets' in config && config.processAssets)) {
|
|
32
|
+
res.sendStatus(304);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
29
35
|
let processingError;
|
|
30
36
|
let fileContent;
|
|
31
37
|
let rawContent;
|
|
@@ -60,17 +60,24 @@ export interface CustomFileFormatLogic extends FileProcessLogic {
|
|
|
60
60
|
}
|
|
61
61
|
export type FileImportExportLogic = FilePreImportLogic | FilePostImportLogic | FilePreExportLogic | FilePostExportLogic;
|
|
62
62
|
export type FileImportExportContent = ProcessFileString[] | Buffer | undefined;
|
|
63
|
-
export interface
|
|
64
|
-
fileProcess: (req: ProcessFileRequest, content: FileImportExportContent, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<
|
|
63
|
+
export interface BaseFileProcessLogic<T> {
|
|
64
|
+
fileProcess: (req: ProcessFileRequest, content: FileImportExportContent, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<T>;
|
|
65
65
|
}
|
|
66
|
-
export interface
|
|
67
|
-
|
|
66
|
+
export interface FilePreImportLogic extends FileProcessLogic, BaseFileProcessLogic<ContentFileResponse> {
|
|
67
|
+
/**
|
|
68
|
+
* Set to `true` to enable asset processing in the application.
|
|
69
|
+
*/
|
|
70
|
+
processAssets?: boolean;
|
|
71
|
+
}
|
|
72
|
+
export interface FilePostImportLogic extends FileProcessLogic, BaseFileProcessLogic<StringsFileResponse> {
|
|
68
73
|
}
|
|
69
|
-
export interface FilePreExportLogic extends FileProcessLogic {
|
|
70
|
-
fileProcess: (req: ProcessFileRequest, content: FileImportExportContent, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<StringsFileResponse>;
|
|
74
|
+
export interface FilePreExportLogic extends FileProcessLogic, BaseFileProcessLogic<StringsFileResponse> {
|
|
71
75
|
}
|
|
72
|
-
export interface FilePostExportLogic extends FileProcessLogic {
|
|
73
|
-
|
|
76
|
+
export interface FilePostExportLogic extends FileProcessLogic, BaseFileProcessLogic<ContentFileResponse> {
|
|
77
|
+
/**
|
|
78
|
+
* Set to `true` to enable asset processing in the application.
|
|
79
|
+
*/
|
|
80
|
+
processAssets?: boolean;
|
|
74
81
|
}
|
|
75
82
|
export interface ProcessFileRequest {
|
|
76
83
|
jobType: ProcessFileJobType;
|
|
@@ -87,6 +94,7 @@ export interface ProcessFileRecord {
|
|
|
87
94
|
path?: string;
|
|
88
95
|
id?: number;
|
|
89
96
|
name?: string;
|
|
97
|
+
type?: string;
|
|
90
98
|
}
|
|
91
99
|
export declare enum ProcessFileJobType {
|
|
92
100
|
PARSE_FILE = "parse-file",
|
package/out/modules/manifest.js
CHANGED
|
@@ -5,6 +5,7 @@ const util_1 = require("../util");
|
|
|
5
5
|
const subscription_1 = require("../util/subscription");
|
|
6
6
|
const api_1 = require("./api/api");
|
|
7
7
|
const util_2 = require("./ai-tools/util");
|
|
8
|
+
const util_3 = require("./workflow-step-type/util");
|
|
8
9
|
function normalizeEnvironments(environments) {
|
|
9
10
|
if (Array.isArray(environments)) {
|
|
10
11
|
return environments;
|
|
@@ -12,6 +13,7 @@ function normalizeEnvironments(environments) {
|
|
|
12
13
|
return [environments];
|
|
13
14
|
}
|
|
14
15
|
function handle(config) {
|
|
16
|
+
var _a, _b;
|
|
15
17
|
const modules = {};
|
|
16
18
|
if (config.projectIntegration) {
|
|
17
19
|
config.projectIntegration.key = config.identifier + '-int';
|
|
@@ -100,6 +102,17 @@ function handle(config) {
|
|
|
100
102
|
},
|
|
101
103
|
];
|
|
102
104
|
}
|
|
105
|
+
if (config.organizationSettingsMenu) {
|
|
106
|
+
config.organizationSettingsMenu.key = config.identifier + '-organization-settings-menu';
|
|
107
|
+
modules['organization-settings-menu'] = [
|
|
108
|
+
{
|
|
109
|
+
key: config.organizationSettingsMenu.key,
|
|
110
|
+
name: config.organizationSettingsMenu.name || config.name,
|
|
111
|
+
url: '/settings/' + (config.organizationSettingsMenu.fileName || 'index.html'),
|
|
112
|
+
icon: (0, util_1.getLogoUrl)(config.organizationSettingsMenu, '/settings'),
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
}
|
|
103
116
|
if (config.profileResourcesMenu) {
|
|
104
117
|
config.profileResourcesMenu.key = config.identifier + '-profile-resources-menu';
|
|
105
118
|
modules['profile-resources-menu'] = [
|
|
@@ -108,6 +121,14 @@ function handle(config) {
|
|
|
108
121
|
})),
|
|
109
122
|
];
|
|
110
123
|
}
|
|
124
|
+
if (config.profileSettingsMenu) {
|
|
125
|
+
config.profileSettingsMenu.key = config.identifier + '-profile-settings-menu';
|
|
126
|
+
modules['profile-settings-menu'] = [
|
|
127
|
+
Object.assign({ key: config.profileSettingsMenu.key, name: config.profileSettingsMenu.name || config.name, url: '/settings/' + (config.profileSettingsMenu.fileName || 'index.html'), icon: (0, util_1.getLogoUrl)(config.profileSettingsMenu, '/settings') }, (!!config.profileSettingsMenu.environments && {
|
|
128
|
+
environments: normalizeEnvironments(config.profileSettingsMenu.environments),
|
|
129
|
+
})),
|
|
130
|
+
];
|
|
131
|
+
}
|
|
111
132
|
if (config.editorRightPanel) {
|
|
112
133
|
config.editorRightPanel.key = config.identifier + '-editor-panels';
|
|
113
134
|
modules['editor-right-panel'] = [
|
|
@@ -244,6 +265,19 @@ function handle(config) {
|
|
|
244
265
|
Object.assign(Object.assign({ key: config.externalQaCheck.key, name: config.externalQaCheck.name || config.name, description: config.externalQaCheck.description || config.description, runQaCheckUrl: '/validate' }, (config.externalQaCheck.batchSize ? { getBatchSizeUrl: '/batch-size' } : {})), (uiModule ? { url: '/settings/' + (uiModule.fileName || 'index.html') } : {})),
|
|
245
266
|
];
|
|
246
267
|
}
|
|
268
|
+
if (config.workflowStepType) {
|
|
269
|
+
const workflowSteps = Array.isArray(config.workflowStepType)
|
|
270
|
+
? config.workflowStepType
|
|
271
|
+
: [config.workflowStepType];
|
|
272
|
+
modules['workflow-step-type'] = [];
|
|
273
|
+
for (const workflowStep of workflowSteps) {
|
|
274
|
+
if (!workflowStep.key) {
|
|
275
|
+
workflowStep.key = config.identifier + '-' + (0, util_3.getWorkflowStepKey)(workflowStep);
|
|
276
|
+
}
|
|
277
|
+
const uiModule = ((_a = workflowStep === null || workflowStep === void 0 ? void 0 : workflowStep.settingsUiModule) === null || _a === void 0 ? void 0 : _a.formSchema) || ((_b = workflowStep === null || workflowStep === void 0 ? void 0 : workflowStep.settingsUiModule) === null || _b === void 0 ? void 0 : _b.fileName);
|
|
278
|
+
modules['workflow-step-type'].push(Object.assign({ key: workflowStep.key, name: workflowStep.name || config.name, description: workflowStep.description || config.description, boundaries: workflowStep.boundaries, updateSettingsUrl: (0, util_3.getWorkflowStepUrl)('/settings', workflowStep), deleteSettingsUrl: (0, util_3.getWorkflowStepUrl)('/delete', workflowStep) }, (uiModule ? { url: (0, util_3.getWorkflowStepUrl)('/workflow-step', workflowStep) } : {})));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
247
281
|
const events = {
|
|
248
282
|
installed: '/installed',
|
|
249
283
|
uninstall: '/uninstall',
|
|
@@ -0,0 +1,18 @@
|
|
|
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.register = void 0;
|
|
7
|
+
const render_ui_module_1 = __importDefault(require("../../middlewares/render-ui-module"));
|
|
8
|
+
const ui_module_1 = __importDefault(require("../../middlewares/ui-module"));
|
|
9
|
+
const util_1 = require("../../util");
|
|
10
|
+
function register({ config, app }) {
|
|
11
|
+
if (!config.organizationSettingsMenu) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const allowUnauthorized = !(0, util_1.isAuthorizedConfig)(config);
|
|
15
|
+
app.get((0, util_1.getLogoUrl)(config.organizationSettingsMenu, '/settings'), (req, res) => { var _a; return res.sendFile(((_a = config.organizationSettingsMenu) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath); });
|
|
16
|
+
app.use('/settings', (0, ui_module_1.default)({ config, allowUnauthorized, moduleType: config.organizationSettingsMenu.key }), (0, render_ui_module_1.default)(config.organizationSettingsMenu));
|
|
17
|
+
}
|
|
18
|
+
exports.register = register;
|
|
@@ -0,0 +1,18 @@
|
|
|
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.register = void 0;
|
|
7
|
+
const render_ui_module_1 = __importDefault(require("../../middlewares/render-ui-module"));
|
|
8
|
+
const ui_module_1 = __importDefault(require("../../middlewares/ui-module"));
|
|
9
|
+
const util_1 = require("../../util");
|
|
10
|
+
function register({ config, app }) {
|
|
11
|
+
if (!config.profileSettingsMenu) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
app.get((0, util_1.getLogoUrl)(config.profileSettingsMenu, '/settings'), (req, res) => { var _a; return res.sendFile(((_a = config.profileSettingsMenu) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath); });
|
|
15
|
+
const allowUnauthorized = !(0, util_1.isAuthorizedConfig)(config);
|
|
16
|
+
app.use('/settings', (0, ui_module_1.default)({ config, allowUnauthorized, moduleType: config.profileSettingsMenu.key }), (0, render_ui_module_1.default)(config.profileSettingsMenu));
|
|
17
|
+
}
|
|
18
|
+
exports.register = register;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="qs" />
|
|
2
|
-
import { CrowdinClientRequest } from '../../../types';
|
|
2
|
+
import { Config, CrowdinClientRequest } from '../../../types';
|
|
3
3
|
import { Response } from 'express';
|
|
4
4
|
import { Webhook } from '../types';
|
|
5
|
-
export declare function webhookHandler(webhooks: Webhook[]): (req: CrowdinClientRequest | import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
|
|
5
|
+
export declare function webhookHandler(config: Config, webhooks: Webhook[]): (req: CrowdinClientRequest | import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
|
|
@@ -40,12 +40,13 @@ const util_1 = require("../../../util");
|
|
|
40
40
|
const lodash_isstring_1 = __importDefault(require("lodash.isstring"));
|
|
41
41
|
const crypto = __importStar(require("node:crypto"));
|
|
42
42
|
const storage = __importStar(require("../../../storage"));
|
|
43
|
-
|
|
43
|
+
const connection_1 = require("../../../util/connection");
|
|
44
|
+
function webhookHandler(config, webhooks) {
|
|
44
45
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
45
46
|
const domain = req.headers['x-crowdin-domain'];
|
|
46
|
-
const organizationId = req.headers['x-crowdin-
|
|
47
|
+
const organizationId = req.headers['x-crowdin-id'];
|
|
47
48
|
const signature = req.headers['x-crowdin-signature'];
|
|
48
|
-
const moduleKey = req.headers['x-
|
|
49
|
+
const moduleKey = req.headers['x-module-key'];
|
|
49
50
|
if (!(0, lodash_isstring_1.default)(domain) || !(0, lodash_isstring_1.default)(organizationId) || !(0, lodash_isstring_1.default)(signature) || !(0, lodash_isstring_1.default)(moduleKey)) {
|
|
50
51
|
res.status(400).send({ error: 'Invalid request' });
|
|
51
52
|
return;
|
|
@@ -56,17 +57,19 @@ function webhookHandler(webhooks) {
|
|
|
56
57
|
throw new Error('Failed to find Crowdin credentials');
|
|
57
58
|
}
|
|
58
59
|
const hmac = crypto.createHmac('sha256', credentials.appSecret);
|
|
59
|
-
hmac.update(
|
|
60
|
+
hmac.update(req.body.toString());
|
|
60
61
|
const generatedSignature = hmac.digest('hex');
|
|
61
62
|
if (generatedSignature !== signature.replace('sha256=', '')) {
|
|
62
63
|
res.status(403).send({ error: 'Invalid signature' });
|
|
63
64
|
return;
|
|
64
65
|
}
|
|
65
66
|
res.status(200).send();
|
|
67
|
+
const { client } = yield (0, connection_1.prepareCrowdinClient)({ config, credentials, autoRenew: true });
|
|
68
|
+
const json = JSON.parse(req.body.toString());
|
|
66
69
|
for (const webhook of webhooks) {
|
|
67
70
|
if (webhook.key === moduleKey) {
|
|
68
|
-
for (const event of
|
|
69
|
-
yield webhook.callback({ credentials, event });
|
|
71
|
+
for (const event of json.events) {
|
|
72
|
+
yield webhook.callback({ credentials, event, client });
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
75
|
}
|
|
@@ -12,7 +12,7 @@ function register({ config, app }) {
|
|
|
12
12
|
}
|
|
13
13
|
const webhooks = Array.isArray(config.webhooks) ? config.webhooks : [config.webhooks];
|
|
14
14
|
if (webhooks.length) {
|
|
15
|
-
app.post('/webhooks', json_response_1.default, (0, webhook_handler_1.webhookHandler)(webhooks));
|
|
15
|
+
app.post('/webhooks', json_response_1.default, (0, webhook_handler_1.webhookHandler)(config, webhooks));
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
exports.register = register;
|