@crowdin/app-project-module 1.3.0 → 1.4.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/integration-credentials.d.ts +6 -1
- package/out/middlewares/integration-credentials.js +39 -2
- package/out/modules/api/api.js +13 -13
- package/out/modules/integration/handlers/integration-logout.js +2 -1
- package/out/modules/integration/index.js +13 -13
- package/out/modules/integration/types.d.ts +1 -0
- package/out/modules/integration/util/webhooks.js +6 -3
- package/out/modules/manifest.js +3 -1
- package/out/modules/workflow-step-type/index.js +1 -1
- package/out/static/ui/error.bundle.js +2 -2
- package/out/static/ui/error.bundle.js.map +1 -1
- package/out/storage/d1.d.ts +1 -1
- package/out/storage/d1.js +20 -18
- package/out/storage/index.d.ts +1 -1
- package/out/storage/index.js +3 -3
- package/out/storage/mysql.d.ts +1 -1
- package/out/storage/mysql.js +4 -2
- package/out/storage/postgre.d.ts +1 -1
- package/out/storage/postgre.js +15 -13
- package/out/storage/sqlite.d.ts +1 -1
- package/out/storage/sqlite.js +10 -8
- package/out/types.d.ts +4 -0
- package/out/util/index.d.ts +1 -1
- package/out/util/index.js +56 -3
- package/out/views/AboutPage.js +14 -2
- package/package.json +1 -1
package/out/storage/d1.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export declare class D1Storage implements Storage {
|
|
|
32
32
|
ensureMigrated(): Promise<void>;
|
|
33
33
|
private addColumn;
|
|
34
34
|
private updateTables;
|
|
35
|
-
migrate(): Promise<void>;
|
|
35
|
+
migrate(skipOnboarding?: boolean): Promise<void>;
|
|
36
36
|
saveCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
|
|
37
37
|
updateCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
|
|
38
38
|
getCrowdinCredentials(id: string): Promise<CrowdinCredentials | undefined>;
|
package/out/storage/d1.js
CHANGED
|
@@ -143,25 +143,27 @@ class D1Storage {
|
|
|
143
143
|
yield this.addColumn('job', 'processed_entities', 'null');
|
|
144
144
|
});
|
|
145
145
|
}
|
|
146
|
-
migrate() {
|
|
147
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
key
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
146
|
+
migrate(skipOnboarding) {
|
|
147
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
148
|
+
if (!skipOnboarding) {
|
|
149
|
+
try {
|
|
150
|
+
// Create all tables
|
|
151
|
+
const statements = [];
|
|
152
|
+
const tableEntries = Object.keys(this.tables).map((key) => [
|
|
153
|
+
key,
|
|
154
|
+
this.tables[key],
|
|
155
|
+
]);
|
|
156
|
+
for (const [tableName, tableSchema] of tableEntries) {
|
|
157
|
+
statements.push(this.db.prepare(`CREATE TABLE IF NOT EXISTS ${tableName} ${tableSchema}`));
|
|
158
|
+
}
|
|
159
|
+
// Execute all table creation in batch
|
|
160
|
+
yield this.db.batch(statements);
|
|
161
|
+
// Update tables with new columns if needed
|
|
162
|
+
yield this.updateTables();
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
console.error(e);
|
|
157
166
|
}
|
|
158
|
-
// Execute all table creation in batch
|
|
159
|
-
yield this.db.batch(statements);
|
|
160
|
-
// Update tables with new columns if needed
|
|
161
|
-
yield this.updateTables();
|
|
162
|
-
}
|
|
163
|
-
catch (e) {
|
|
164
|
-
console.error(e);
|
|
165
167
|
}
|
|
166
168
|
});
|
|
167
169
|
}
|
package/out/storage/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export declare const TABLES: {
|
|
|
18
18
|
};
|
|
19
19
|
export interface Storage {
|
|
20
20
|
tables: typeof TABLES;
|
|
21
|
-
migrate(): Promise<void>;
|
|
21
|
+
migrate(skipOnboarding?: boolean): Promise<void>;
|
|
22
22
|
saveCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
|
|
23
23
|
updateCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
|
|
24
24
|
getCrowdinCredentials(id: string): Promise<CrowdinCredentials | undefined>;
|
package/out/storage/index.js
CHANGED
|
@@ -102,11 +102,11 @@ function initialize(config) {
|
|
|
102
102
|
}
|
|
103
103
|
storage = new sqlite_1.SQLiteStorage({ dbFolder: config.dbFolder });
|
|
104
104
|
}
|
|
105
|
-
|
|
105
|
+
const skipOnboarding = !!process.env.SKIP_MIGRATIONS;
|
|
106
|
+
if (skipOnboarding) {
|
|
106
107
|
(0, logger_1.log)('Skipping database migrations (SKIP_MIGRATIONS is set)');
|
|
107
|
-
return;
|
|
108
108
|
}
|
|
109
|
-
yield storage.migrate();
|
|
109
|
+
yield storage.migrate(skipOnboarding);
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
function getStorage() {
|
package/out/storage/mysql.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ export declare class MySQLStorage implements Storage {
|
|
|
38
38
|
};
|
|
39
39
|
constructor(config: MySQLStorageConfig);
|
|
40
40
|
executeQuery<T>(command: (connection: any) => Promise<T>): Promise<T>;
|
|
41
|
-
migrate(): Promise<void>;
|
|
41
|
+
migrate(skipOnboarding?: boolean): Promise<void>;
|
|
42
42
|
addTables(connection: any): Promise<void>;
|
|
43
43
|
saveCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
|
|
44
44
|
updateCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
|
package/out/storage/mysql.js
CHANGED
|
@@ -191,10 +191,12 @@ class MySQLStorage {
|
|
|
191
191
|
}));
|
|
192
192
|
});
|
|
193
193
|
}
|
|
194
|
-
migrate() {
|
|
194
|
+
migrate(skipOnboarding) {
|
|
195
195
|
return __awaiter(this, void 0, void 0, function* () {
|
|
196
196
|
try {
|
|
197
|
-
|
|
197
|
+
if (!skipOnboarding) {
|
|
198
|
+
yield this.executeQuery((connection) => this.addTables(connection));
|
|
199
|
+
}
|
|
198
200
|
this._res && this._res();
|
|
199
201
|
}
|
|
200
202
|
catch (e) {
|
package/out/storage/postgre.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ export declare class PostgreStorage implements Storage {
|
|
|
47
47
|
private generateLockId;
|
|
48
48
|
executeQuery<T>(command: (client: Client) => Promise<T>): Promise<T>;
|
|
49
49
|
private hasDumpFiles;
|
|
50
|
-
migrate(): Promise<void>;
|
|
50
|
+
migrate(skipOnboarding?: boolean): Promise<void>;
|
|
51
51
|
addColumns(client: Client, newColumns: string[], tableName: string): Promise<void>;
|
|
52
52
|
addColumn(client: Client, columnName: string, tableName: string, columnType: string): Promise<void>;
|
|
53
53
|
addTables(client: Client): Promise<void>;
|
package/out/storage/postgre.js
CHANGED
|
@@ -210,22 +210,24 @@ class PostgreStorage {
|
|
|
210
210
|
const files = fs_1.default.readdirSync(directoryPath).filter((file) => file.startsWith(name) && file.endsWith(extension));
|
|
211
211
|
return files.length > 0;
|
|
212
212
|
}
|
|
213
|
-
migrate() {
|
|
213
|
+
migrate(skipOnboarding) {
|
|
214
214
|
return __awaiter(this, void 0, void 0, function* () {
|
|
215
215
|
try {
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// Use advisory lock to prevent concurrent migrations
|
|
220
|
-
yield this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
|
|
221
|
-
yield client.query('SELECT pg_advisory_lock($1)', [this.migrationLockId]);
|
|
222
|
-
try {
|
|
223
|
-
yield this.addTables(client);
|
|
224
|
-
}
|
|
225
|
-
finally {
|
|
226
|
-
yield client.query('SELECT pg_advisory_unlock($1)', [this.migrationLockId]);
|
|
216
|
+
if (!skipOnboarding) {
|
|
217
|
+
if (this.directoryPath && this.hasDumpFiles(this.directoryPath)) {
|
|
218
|
+
yield this.migrateFromSqlite(this.directoryPath);
|
|
227
219
|
}
|
|
228
|
-
|
|
220
|
+
// Use advisory lock to prevent concurrent migrations
|
|
221
|
+
yield this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
|
|
222
|
+
yield client.query('SELECT pg_advisory_lock($1)', [this.migrationLockId]);
|
|
223
|
+
try {
|
|
224
|
+
yield this.addTables(client);
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
yield client.query('SELECT pg_advisory_unlock($1)', [this.migrationLockId]);
|
|
228
|
+
}
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
229
231
|
this._res && this._res();
|
|
230
232
|
}
|
|
231
233
|
catch (e) {
|
package/out/storage/sqlite.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export declare class SQLiteStorage implements Storage {
|
|
|
24
24
|
synced_data: string;
|
|
25
25
|
};
|
|
26
26
|
constructor(config: SQLiteStorageConfig);
|
|
27
|
-
migrate(): Promise<void>;
|
|
27
|
+
migrate(skipOnboarding?: boolean): Promise<void>;
|
|
28
28
|
saveCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
|
|
29
29
|
updateCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
|
|
30
30
|
getCrowdinCredentials(id: string): Promise<CrowdinCredentials | undefined>;
|
package/out/storage/sqlite.js
CHANGED
|
@@ -122,17 +122,19 @@ class SQLiteStorage {
|
|
|
122
122
|
};
|
|
123
123
|
this.config = config;
|
|
124
124
|
}
|
|
125
|
-
migrate() {
|
|
125
|
+
migrate(skipOnboarding) {
|
|
126
126
|
return __awaiter(this, void 0, void 0, function* () {
|
|
127
127
|
this.db = require('better-sqlite3')((0, path_1.join)(this.config.dbFolder, types_2.storageFiles.SQLITE));
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
if (!skipOnboarding) {
|
|
129
|
+
try {
|
|
130
|
+
for (const [tableName, schema] of Object.entries(this.tables)) {
|
|
131
|
+
this.db.prepare(`CREATE TABLE IF NOT EXISTS ${tableName} ${schema}`).run();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
console.error('Error during database migration:', error);
|
|
136
|
+
throw error;
|
|
131
137
|
}
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
console.error('Error during database migration:', error);
|
|
135
|
-
throw error;
|
|
136
138
|
}
|
|
137
139
|
});
|
|
138
140
|
}
|
package/out/types.d.ts
CHANGED
|
@@ -524,6 +524,10 @@ export interface ImagePath {
|
|
|
524
524
|
* path to app logo (e.g. {@example join(__dirname, 'logo.png')})
|
|
525
525
|
*/
|
|
526
526
|
imagePath?: string;
|
|
527
|
+
/**
|
|
528
|
+
* URL to app logo that can be used instead of hosting it in the app (e.g. 'https://example.com/logo.png')
|
|
529
|
+
*/
|
|
530
|
+
imageUrl?: string;
|
|
527
531
|
}
|
|
528
532
|
export interface Logger {
|
|
529
533
|
enabled: boolean;
|
package/out/util/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export declare function getLogoUrl(config: Config | UnauthorizedConfig, moduleCo
|
|
|
14
14
|
* Logo middleware with backwards compatibility
|
|
15
15
|
* Serves both /logo.png (backwards-compatible) and actual file name
|
|
16
16
|
* @param config - App configuration (required for Cloudflare Workers Assets support)
|
|
17
|
-
* @param moduleConfig - Module configuration with imagePath (optional, falls back to config.imagePath)
|
|
17
|
+
* @param moduleConfig - Module configuration with imagePath or imageUrl (optional, falls back to config.imagePath)
|
|
18
18
|
* @returns Express middleware
|
|
19
19
|
*/
|
|
20
20
|
export declare function serveLogo(config: Config | UnauthorizedConfig, moduleConfig?: ImagePath): (req: Request, res: Response, next: Function) => Promise<void>;
|
package/out/util/index.js
CHANGED
|
@@ -177,8 +177,30 @@ function executeWithRetry(func_1) {
|
|
|
177
177
|
});
|
|
178
178
|
}
|
|
179
179
|
function getLogoUrl(config, moduleConfig, modulePath) {
|
|
180
|
+
if (moduleConfig) {
|
|
181
|
+
if (moduleConfig.imageUrl) {
|
|
182
|
+
if (modulePath) {
|
|
183
|
+
return `/logo${modulePath}/logo.png`;
|
|
184
|
+
}
|
|
185
|
+
return '/logo.png';
|
|
186
|
+
}
|
|
187
|
+
else if (moduleConfig.imagePath) {
|
|
188
|
+
const imagePath = moduleConfig.imagePath;
|
|
189
|
+
const fileName = basename(imagePath);
|
|
190
|
+
if (!modulePath) {
|
|
191
|
+
return `/${fileName}`;
|
|
192
|
+
}
|
|
193
|
+
return `/logo${modulePath}/${fileName}`;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (config.imageUrl) {
|
|
197
|
+
if (modulePath) {
|
|
198
|
+
return `/logo${modulePath}/logo.png`;
|
|
199
|
+
}
|
|
200
|
+
return '/logo.png';
|
|
201
|
+
}
|
|
180
202
|
// Extract file name from imagePath with fallback to config.imagePath
|
|
181
|
-
const imagePath =
|
|
203
|
+
const imagePath = config.imagePath;
|
|
182
204
|
const fileName = basename(imagePath);
|
|
183
205
|
if (!modulePath) {
|
|
184
206
|
return `/${fileName}`;
|
|
@@ -189,11 +211,42 @@ function getLogoUrl(config, moduleConfig, modulePath) {
|
|
|
189
211
|
* Logo middleware with backwards compatibility
|
|
190
212
|
* Serves both /logo.png (backwards-compatible) and actual file name
|
|
191
213
|
* @param config - App configuration (required for Cloudflare Workers Assets support)
|
|
192
|
-
* @param moduleConfig - Module configuration with imagePath (optional, falls back to config.imagePath)
|
|
214
|
+
* @param moduleConfig - Module configuration with imagePath or imageUrl (optional, falls back to config.imagePath)
|
|
193
215
|
* @returns Express middleware
|
|
194
216
|
*/
|
|
195
217
|
function serveLogo(config, moduleConfig) {
|
|
196
|
-
|
|
218
|
+
if (moduleConfig) {
|
|
219
|
+
if (moduleConfig.imageUrl) {
|
|
220
|
+
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
221
|
+
if (req.path === '/logo.png') {
|
|
222
|
+
res.redirect(moduleConfig.imageUrl);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
next();
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
else if (moduleConfig.imagePath) {
|
|
229
|
+
const fileHandler = (0, static_files_1.serveFile)(config, moduleConfig.imagePath);
|
|
230
|
+
const fileName = basename(moduleConfig.imagePath);
|
|
231
|
+
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
232
|
+
// Match exact paths: /logo.png (backwards-compatible) or /{actual-file-name}
|
|
233
|
+
if (req.path === '/logo.png' || req.path === `/${fileName}`) {
|
|
234
|
+
return fileHandler(req, res, next);
|
|
235
|
+
}
|
|
236
|
+
next();
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (config.imageUrl) {
|
|
241
|
+
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
242
|
+
if (req.path === '/logo.png') {
|
|
243
|
+
res.redirect(config.imageUrl);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
next();
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
const imagePath = config.imagePath;
|
|
197
250
|
const fileName = basename(imagePath);
|
|
198
251
|
const fileHandler = (0, static_files_1.serveFile)(config, imagePath);
|
|
199
252
|
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
package/out/views/AboutPage.js
CHANGED
|
@@ -58,7 +58,8 @@ const AboutPage = ({ name, logo, manifest, storeLink, showDebugLink }) => (react
|
|
|
58
58
|
react_1.default.createElement("div", { className: "mb-3" },
|
|
59
59
|
react_1.default.createElement("label", { htmlFor: "manifest-url", className: "form-label" }, "Paste the following manifest URL when prompted during manual installation:"),
|
|
60
60
|
react_1.default.createElement("div", { className: "input-group" },
|
|
61
|
-
react_1.default.createElement("input", { type: "text", className: "form-control", id: "manifest-url", value: manifest, readOnly: true })
|
|
61
|
+
react_1.default.createElement("input", { type: "text", className: "form-control", id: "manifest-url", value: manifest, readOnly: true }),
|
|
62
|
+
react_1.default.createElement("button", { className: "btn btn-outline-secondary", type: "button", id: "copy-button" }, "Copy"))),
|
|
62
63
|
storeLink && (react_1.default.createElement("div", null,
|
|
63
64
|
"Read more about",
|
|
64
65
|
' ',
|
|
@@ -72,5 +73,16 @@ const AboutPage = ({ name, logo, manifest, storeLink, showDebugLink }) => (react
|
|
|
72
73
|
' ',
|
|
73
74
|
react_1.default.createElement("a", { href: "/__debug", target: "_blank", title: "Open developer console in a new tab" }, "Developer Console"),
|
|
74
75
|
' ',
|
|
75
|
-
"to inspect requests, debug issues, and monitor application behavior.")))))))
|
|
76
|
+
"to inspect requests, debug issues, and monitor application behavior."))))))),
|
|
77
|
+
react_1.default.createElement("script", { dangerouslySetInnerHTML: {
|
|
78
|
+
__html: `
|
|
79
|
+
document.getElementById('copy-button').addEventListener('click', async function() {
|
|
80
|
+
var text = document.getElementById('manifest-url').value;
|
|
81
|
+
await navigator.clipboard.writeText(text);
|
|
82
|
+
var btn = document.getElementById('copy-button');
|
|
83
|
+
btn.textContent = 'Copied!';
|
|
84
|
+
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
|
|
85
|
+
});
|
|
86
|
+
`.trim(),
|
|
87
|
+
} }))));
|
|
76
88
|
exports.AboutPage = AboutPage;
|
package/package.json
CHANGED