@crowdin/app-project-module 0.103.0 → 0.104.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 CHANGED
@@ -88,6 +88,7 @@ const webhooks = __importStar(require("./modules/webhooks"));
88
88
  const workflowStepType = __importStar(require("./modules/workflow-step-type"));
89
89
  const aiRequestProcessors = __importStar(require("./modules/ai-request-processors"));
90
90
  const automationAction = __importStar(require("./modules/automation-action"));
91
+ const authGuard = __importStar(require("./modules/auth-guard"));
91
92
  const subscription_1 = require("./util/subscription");
92
93
  var types_2 = require("./types");
93
94
  Object.defineProperty(exports, "ProjectPermissions", { enumerable: true, get: function () { return types_2.ProjectPermissions; } });
@@ -222,6 +223,7 @@ function addCrowdinEndpoints(app, clientConfig) {
222
223
  workflowStepType.register({ config, app });
223
224
  aiRequestProcessors.register({ config, app });
224
225
  automationAction.register({ config, app });
226
+ authGuard.register({ config, app });
225
227
  addFormSchema({ config, app });
226
228
  return Object.assign(Object.assign({}, exports.metadataStore), { storage: storage.getStorage(), establishCrowdinConnection: (authRequest, moduleKey) => {
227
229
  let jwtToken = '';
@@ -0,0 +1,5 @@
1
+ /// <reference types="qs" />
2
+ import { Response } from 'express';
3
+ import { CrowdinClientRequest } from '../../../types';
4
+ import { AuthGuardModule } from '../types';
5
+ export default function verifyHandler(authGuardModules: AuthGuardModule[]): (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;
@@ -0,0 +1,57 @@
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
+ const util_1 = require("../../../util");
13
+ function verifyHandler(authGuardModules) {
14
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
15
+ const { userId, organizationId, ipAddress, moduleKey, code } = req.body;
16
+ req.logInfo(`Auth guard verification request for module: ${moduleKey}`);
17
+ // Find the auth-guard module by key
18
+ const module = authGuardModules.find((m) => m.key === moduleKey);
19
+ if (!module) {
20
+ req.logError(`Auth guard module not found: ${moduleKey}`);
21
+ return res.status(404).json({
22
+ error: `Auth guard module not found: ${moduleKey}`,
23
+ });
24
+ }
25
+ try {
26
+ // Call the user-provided verification logic
27
+ const result = yield module.verify({
28
+ client: req.crowdinApiClient,
29
+ context: req.crowdinContext,
30
+ userId,
31
+ organizationId,
32
+ ipAddress,
33
+ moduleKey,
34
+ code,
35
+ });
36
+ if (!result || typeof result.success !== 'boolean') {
37
+ req.logError('Invalid response from auth guard verification function');
38
+ return res.status(500).json({
39
+ success: false,
40
+ message: 'Invalid response from verification function',
41
+ });
42
+ }
43
+ // Return the result (always HTTP 200, success field indicates verification result)
44
+ req.logInfo(`Auth guard verification ${result.success ? 'succeeded' : 'failed'} for module: ${moduleKey}`);
45
+ return res.status(200).json(result);
46
+ }
47
+ catch (error) {
48
+ req.logError(`Auth guard verification error: ${error.message || error}`);
49
+ // Return HTTP 500 for internal errors
50
+ return res.status(500).json({
51
+ success: false,
52
+ message: 'Internal server error during verification',
53
+ });
54
+ }
55
+ }));
56
+ }
57
+ exports.default = verifyHandler;
@@ -0,0 +1,6 @@
1
+ import { Express } from 'express';
2
+ import { Config } from '../../types';
3
+ export declare function register({ config, app }: {
4
+ config: Config;
5
+ app: Express;
6
+ }): void;
@@ -0,0 +1,36 @@
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 crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client"));
8
+ const json_response_1 = __importDefault(require("../../middlewares/json-response"));
9
+ const render_ui_module_1 = __importDefault(require("../../middlewares/render-ui-module"));
10
+ const ui_module_1 = __importDefault(require("../../middlewares/ui-module"));
11
+ const verify_1 = __importDefault(require("./handlers/verify"));
12
+ function register({ config, app }) {
13
+ if (!config.authGuard) {
14
+ return;
15
+ }
16
+ // Normalize to array
17
+ const authGuardModules = Array.isArray(config.authGuard) ? config.authGuard : [config.authGuard];
18
+ if (!authGuardModules.length) {
19
+ return;
20
+ }
21
+ // Register settings UI modules if provided
22
+ authGuardModules.forEach((module, index) => {
23
+ if (module.settingsUiModule) {
24
+ const moduleKey = module.key || `${config.identifier}-auth-guard-${index}`;
25
+ app.use(`/auth-guard/${moduleKey}/settings`, (0, ui_module_1.default)({ config, moduleType: moduleKey }), (0, render_ui_module_1.default)(module.settingsUiModule));
26
+ }
27
+ });
28
+ // Register verification endpoint
29
+ app.post('/auth-guard/verify', json_response_1.default, (0, crowdin_client_1.default)({
30
+ config,
31
+ optional: false,
32
+ checkSubscriptionExpiration: false,
33
+ moduleKey: authGuardModules.map((m, i) => m.key || `${config.identifier}-auth-guard-${i}`),
34
+ }), (0, verify_1.default)(authGuardModules));
35
+ }
36
+ exports.register = register;
@@ -0,0 +1,101 @@
1
+ import Crowdin from '@crowdin/crowdin-api-client';
2
+ import { CrowdinContextInfo, Environments, ModuleKey, UiModule } from '../../types';
3
+ /**
4
+ * Auth Guard verification type
5
+ */
6
+ export type AuthGuardVerificationType = 'direct' | 'redirect' | 'iframe';
7
+ /**
8
+ * Auth Guard module options
9
+ */
10
+ export interface AuthGuardOptions {
11
+ /**
12
+ * Verification type: direct (backend-only), redirect (external page), or iframe (embedded iframe)
13
+ * @default 'direct'
14
+ */
15
+ type?: AuthGuardVerificationType;
16
+ /**
17
+ * Whether to apply this check to organization administrators
18
+ * @default false
19
+ */
20
+ applyToAdmin?: boolean;
21
+ /**
22
+ * User-facing URL for redirect and iframe types
23
+ * Required if type is not 'direct'
24
+ */
25
+ url?: string;
26
+ }
27
+ /**
28
+ * Request body for auth guard verification
29
+ */
30
+ export interface AuthGuardVerifyRequest {
31
+ /**
32
+ * User ID
33
+ */
34
+ userId: number;
35
+ /**
36
+ * Organization ID
37
+ */
38
+ organizationId: number;
39
+ /**
40
+ * User's IP address
41
+ */
42
+ ipAddress: string;
43
+ /**
44
+ * Module key to identify which auth-guard module to invoke
45
+ */
46
+ moduleKey: string;
47
+ /**
48
+ * Verification code (provided for redirect/iframe types after user interaction)
49
+ */
50
+ code?: string;
51
+ }
52
+ /**
53
+ * Response for auth guard verification
54
+ */
55
+ export interface AuthGuardVerifyResponse {
56
+ /**
57
+ * Whether verification was successful
58
+ */
59
+ success: boolean;
60
+ /**
61
+ * Optional error or informational message
62
+ */
63
+ message?: string;
64
+ }
65
+ /**
66
+ * Auth Guard module configuration
67
+ */
68
+ export interface AuthGuardModule extends ModuleKey, Environments {
69
+ /**
70
+ * Module name displayed to users during verification
71
+ */
72
+ name?: string;
73
+ /**
74
+ * Module description (primarily for iframe type)
75
+ */
76
+ description?: string;
77
+ /**
78
+ * Endpoint URL for verification (relative to baseUrl or absolute)
79
+ */
80
+ url?: string;
81
+ /**
82
+ * Module configuration options
83
+ */
84
+ options?: AuthGuardOptions;
85
+ /**
86
+ * Settings UI module for configuration
87
+ */
88
+ settingsUiModule?: UiModule;
89
+ /**
90
+ * Verification logic function
91
+ */
92
+ verify: (params: {
93
+ client?: Crowdin;
94
+ context?: CrowdinContextInfo;
95
+ userId: number;
96
+ organizationId: number;
97
+ ipAddress: string;
98
+ moduleKey: string;
99
+ code?: string;
100
+ }) => Promise<AuthGuardVerifyResponse>;
101
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -411,6 +411,35 @@ function handle(config) {
411
411
  : {})), { validateSettingsUrl: (0, index_1.getAutomationActionUrl)('/automation-action/validate-settings', automationAction), executeUrl: (0, index_1.getAutomationActionUrl)('/automation-action/execute', automationAction), invocationWaitMode: automationAction.invocationWaitMode || 'sync' }), (uiModule ? { url: (0, index_1.getAutomationActionUrl)('/automation-action', automationAction) } : {})));
412
412
  }
413
413
  }
414
+ if (config.authGuard) {
415
+ // prevent possible overrides of the other modules
416
+ if (Array.isArray(config.authGuard)) {
417
+ config.authGuard = config.authGuard.map((authGuard) => (Object.assign({}, authGuard)));
418
+ }
419
+ else {
420
+ config.authGuard = Object.assign({}, config.authGuard);
421
+ }
422
+ const authGuards = Array.isArray(config.authGuard) ? config.authGuard : [config.authGuard];
423
+ modules['auth-guard'] = [];
424
+ for (let i = 0; i < authGuards.length; i++) {
425
+ if (!authGuards[i].key) {
426
+ authGuards[i].key = config.identifier + '-auth-guard-' + i;
427
+ }
428
+ const options = authGuards[i].options || {};
429
+ const manifestEntry = {
430
+ key: authGuards[i].key,
431
+ name: authGuards[i].name || config.name,
432
+ url: '/auth-guard/verify',
433
+ };
434
+ if (authGuards[i].description) {
435
+ manifestEntry.description = authGuards[i].description;
436
+ }
437
+ if (options.type || options.applyToAdmin !== undefined || options.url) {
438
+ manifestEntry.options = Object.assign(Object.assign(Object.assign({}, (options.type && { type: options.type })), (options.applyToAdmin !== undefined && { applyToAdmin: options.applyToAdmin })), (options.url && { url: options.url }));
439
+ }
440
+ modules['auth-guard'].push(manifestEntry);
441
+ }
442
+ }
414
443
  const events = {
415
444
  installed: '/installed',
416
445
  uninstall: '/uninstall',
package/out/types.d.ts CHANGED
@@ -20,6 +20,7 @@ import { Webhook } from './modules/webhooks/types';
20
20
  import { WorkflowStepTypeModule } from './modules/workflow-step-type/types';
21
21
  import { AiRequestProcessorModule, AiStreamProcessorModule } from './modules/ai-request-processors/types';
22
22
  import { AutomationActionModule } from './modules/automation-action/types';
23
+ import { AuthGuardModule } from './modules/auth-guard/types';
23
24
  export interface ClientConfig extends ImagePath {
24
25
  /**
25
26
  * Authentication Crowdin App type: "authorization_code", "crowdin_app", "crowdin_agent". Default: "crowdin_app"
@@ -272,6 +273,10 @@ export interface ClientConfig extends ImagePath {
272
273
  * Automation action module
273
274
  */
274
275
  automationAction?: AutomationActionModule | AutomationActionModule[];
276
+ /**
277
+ * Auth guard module for custom authentication/authorization checks
278
+ */
279
+ authGuard?: AuthGuardModule | AuthGuardModule[];
275
280
  }
276
281
  export interface Environments {
277
282
  environments?: Environment | Environment[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.103.0",
3
+ "version": "0.104.1",
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",