@tandem-language-exchange/content-store 1.2.1 → 1.2.3
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/README.md +38 -27
- package/dist/chunk-4DE47ZJD.js +19 -0
- package/dist/chunk-4DE47ZJD.js.map +1 -0
- package/dist/chunk-5WQPK6GZ.js +178 -0
- package/dist/chunk-5WQPK6GZ.js.map +1 -0
- package/dist/chunk-HXG3MIJG.js +245 -0
- package/dist/chunk-HXG3MIJG.js.map +1 -0
- package/dist/{chunk-PQJ2MGH7.js → chunk-TYJ2WIYA.js} +9 -5
- package/dist/{chunk-PQJ2MGH7.js.map → chunk-TYJ2WIYA.js.map} +1 -1
- package/dist/chunk-UPIQFNCR.js +17 -0
- package/dist/chunk-UPIQFNCR.js.map +1 -0
- package/dist/{chunk-LOCC2BXB.js → chunk-ZIFMNEBR.js} +20 -22
- package/dist/chunk-ZIFMNEBR.js.map +1 -0
- package/dist/client/fetch-content-bundles.js +7 -3
- package/dist/client/fetch-content-bundles.js.map +1 -1
- package/dist/client/fetch-merged-translation-bundles.js +20 -13
- package/dist/client/fetch-merged-translation-bundles.js.map +1 -1
- package/dist/client/fetch-translation-bundles.js +20 -15
- package/dist/client/fetch-translation-bundles.js.map +1 -1
- package/dist/client/list-projects.js +15 -0
- package/dist/client/list-projects.js.map +1 -0
- package/dist/client/list-resources.js +21 -0
- package/dist/client/list-resources.js.map +1 -0
- package/dist/client/query-cms.js +34 -0
- package/dist/client/query-cms.js.map +1 -0
- package/dist/{index-kfqHGgMO.d.ts → index-PQ7XN47c.d.ts} +23 -9
- package/dist/index.d.ts +1 -1
- package/dist/node.browser.js.map +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.js +50 -8
- package/dist/node.js.map +1 -1
- package/package.json +10 -5
- package/dist/chunk-LOCC2BXB.js.map +0 -1
- package/dist/chunk-OTZLCMZ6.js +0 -396
- package/dist/chunk-OTZLCMZ6.js.map +0 -1
- package/dist/client/cli.js +0 -82
- package/dist/client/cli.js.map +0 -1
package/README.md
CHANGED
|
@@ -111,16 +111,19 @@ Downloads translation objects from S3. The **sync** stores each Lingohub file **
|
|
|
111
111
|
|
|
112
112
|
```typescript
|
|
113
113
|
const files = await sdk.fetchTranslationBundles({
|
|
114
|
-
projects:
|
|
114
|
+
projects: {
|
|
115
|
+
'tandem': [], // all resources
|
|
116
|
+
'tandem-(website)': ['main', 'ai'], // only "main" and "ai" resources
|
|
117
|
+
},
|
|
115
118
|
locales: ['en', 'de'], // omit or leave empty to use the package default locale list
|
|
116
119
|
});
|
|
117
120
|
```
|
|
118
121
|
|
|
119
|
-
**Parameters:**
|
|
122
|
+
**Parameters (extends `TranslationFilterConfig`):**
|
|
120
123
|
|
|
121
124
|
| Field | Type | Description |
|
|
122
125
|
| --- | --- | --- |
|
|
123
|
-
| `projects` | `string[]
|
|
126
|
+
| `projects` | `Record<string, string[]>` | Map of Lingohub project id to resource keys. An empty array fetches **all** resources for that project; a populated array fetches only the listed resources (matched against the `resource` field in `src/shared/lingohub.ts`). |
|
|
124
127
|
| `locales` | `string[]` | Optional. Locale codes to fetch (e.g. `pt-br`, `zh-hans`). If omitted or empty, a built-in default list is used. |
|
|
125
128
|
| `retry` | `S3RetryConfig` | Optional. Overrides [S3 download retries](#s3-download-retries). |
|
|
126
129
|
|
|
@@ -149,7 +152,10 @@ Same **`projects`**, **`locales`**, and **`retry`** as `fetchTranslationBundles`
|
|
|
149
152
|
|
|
150
153
|
```typescript
|
|
151
154
|
const mergedPaths = await sdk.fetchMergedTranslationBundles({
|
|
152
|
-
projects:
|
|
155
|
+
projects: {
|
|
156
|
+
'tandem-(new-website)': [],
|
|
157
|
+
'tandem-(website)': ['main'],
|
|
158
|
+
},
|
|
153
159
|
locales: ['en'],
|
|
154
160
|
});
|
|
155
161
|
// mergedPaths.en → path to one big en.json
|
|
@@ -329,13 +335,13 @@ await fetchCmsBundles(store, './content-cache', {
|
|
|
329
335
|
});
|
|
330
336
|
|
|
331
337
|
await fetchTranslationBundles(store, './content-cache', {
|
|
332
|
-
projects:
|
|
338
|
+
projects: { 'tandem-(website)': [] },
|
|
333
339
|
locales: ['en', 'fr'],
|
|
334
340
|
retry: getDefaultS3RetryConfig(),
|
|
335
341
|
});
|
|
336
342
|
|
|
337
343
|
await fetchMergedTranslationBundles(store, './content-cache/merged', {
|
|
338
|
-
projects:
|
|
344
|
+
projects: { 'tandem-(new-website)': [], 'tandem-(website)': ['main'] },
|
|
339
345
|
locales: ['en'],
|
|
340
346
|
});
|
|
341
347
|
|
|
@@ -368,7 +374,7 @@ await sdk.fetchCmsBundles({
|
|
|
368
374
|
|
|
369
375
|
// Optional: pull translation bundles written by the Lingohub → S3 sync
|
|
370
376
|
await sdk.fetchTranslationBundles({
|
|
371
|
-
projects:
|
|
377
|
+
projects: { 'tandem-(website)': [] },
|
|
372
378
|
});
|
|
373
379
|
|
|
374
380
|
// 2. Query CMS bundle locally — no further network calls
|
|
@@ -383,7 +389,7 @@ console.log(grids);
|
|
|
383
389
|
```
|
|
384
390
|
## CLI
|
|
385
391
|
|
|
386
|
-
The package ships **`fetch-content-bundles`**, **`fetch-translation-bundles`**, and **`fetch-merged-translation-bundles`** as **`bin`** commands.
|
|
392
|
+
The package ships **`fetch-content-bundles`**, **`fetch-translation-bundles`**, and **`fetch-merged-translation-bundles`** as **`bin`** commands. The **`query-cms`** command lives at **`dist/client/query-cms.js`**; run with **`node node_modules/@tandem-language-exchange/content-store/dist/client/query-cms.js`** or via npm scripts.
|
|
387
393
|
|
|
388
394
|
### `fetch-content-bundles` — download bundles from S3
|
|
389
395
|
|
|
@@ -413,35 +419,40 @@ All **`bin`** tools read S3 settings from [S3 config via environment variables](
|
|
|
413
419
|
|
|
414
420
|
### `fetch-translation-bundles`
|
|
415
421
|
|
|
422
|
+
Both translation CLI commands accept a **`--config`** flag pointing to a JSON config file that defines which projects, resources, and locales to fetch.
|
|
423
|
+
|
|
424
|
+
**Config file format (`TranslationFilterConfig`):**
|
|
425
|
+
|
|
426
|
+
```json
|
|
427
|
+
{
|
|
428
|
+
"projects": {
|
|
429
|
+
"tandem": [],
|
|
430
|
+
"tandem-(website)": ["main", "ai"]
|
|
431
|
+
},
|
|
432
|
+
"locales": ["en", "de", "it"]
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
- **`projects`** — map of Lingohub project id to resource keys. An empty array (`[]`) fetches **all** resources for that project. A populated array fetches only the listed resources (matched against the `resource` field in `src/shared/lingohub.ts`).
|
|
437
|
+
- **`locales`** — optional. Omit or leave empty to use the built-in default locale list.
|
|
438
|
+
|
|
416
439
|
```bash
|
|
417
|
-
npx fetch-translation-bundles --
|
|
440
|
+
npx fetch-translation-bundles --config ./translation-config.json --output ./content-cache
|
|
418
441
|
```
|
|
419
442
|
|
|
420
443
|
| Flag | Required | Default | Description |
|
|
421
444
|
| --- | --- | --- | --- |
|
|
422
|
-
| `--
|
|
423
|
-
| `--locales <list>` | No | | Comma-separated locales; omit to use the built-in default list |
|
|
445
|
+
| `--config <path>` | Yes | | Path to a JSON config file (`TranslationFilterConfig`) |
|
|
424
446
|
| `--output <dir>` | No | `./content-cache` | Output directory |
|
|
425
447
|
|
|
426
|
-
**zsh / bash:** Project ids often contain **`(`** and **`)`**. You must **quote** the argument when using `=` form, or use a space so the value is a separate token:
|
|
427
|
-
|
|
428
|
-
```bash
|
|
429
|
-
# Good — quoted
|
|
430
|
-
fetch-translation-bundles --projects='tandem-(new-website)' --output=src/data/cache
|
|
431
|
-
|
|
432
|
-
# Good — space form (value quoted or unambiguous)
|
|
433
|
-
fetch-translation-bundles --projects 'tandem-(new-website)' --output src/data/cache
|
|
434
|
-
|
|
435
|
-
# Bad in zsh — unquoted parentheses are shell syntax
|
|
436
|
-
fetch-translation-bundles --projects=tandem-(new-website) --output=src/data/cache
|
|
437
|
-
```
|
|
438
|
-
|
|
439
448
|
### `fetch-merged-translation-bundles`
|
|
440
449
|
|
|
441
450
|
Writes merged **`{locale}.json`** files (string key/value map; duplicate keys: last wins).
|
|
442
451
|
|
|
452
|
+
Uses the same config file format as `fetch-translation-bundles`.
|
|
453
|
+
|
|
443
454
|
```bash
|
|
444
|
-
npx fetch-merged-translation-bundles --
|
|
455
|
+
npx fetch-merged-translation-bundles --config ./translation-config.json --output ./content-cache/merged
|
|
445
456
|
```
|
|
446
457
|
|
|
447
458
|
Alternatively call **`fetchTranslationBundles`** / **`fetchMergedTranslationBundles`** from a Node script, or use the server’s **`POST /getTranslationBundles`** API (see [Server & CLI README](src/server/README.md)).
|
|
@@ -451,7 +462,7 @@ Alternatively call **`fetchTranslationBundles`** / **`fetchMergedTranslationBund
|
|
|
451
462
|
Reads a previously fetched bundle from disk and prints JSON to stdout. This command is **not** a separate `bin`; run the built client CLI (after `npm install` of this package):
|
|
452
463
|
|
|
453
464
|
```bash
|
|
454
|
-
node node_modules/@tandem-language-exchange/content-store/dist/client/
|
|
465
|
+
node node_modules/@tandem-language-exchange/content-store/dist/client/query-cms.js \
|
|
455
466
|
--cms contentful --type gridLayout \
|
|
456
467
|
--fields '{"columns":"2"}' \
|
|
457
468
|
--select title,bodyBefore \
|
|
@@ -463,7 +474,7 @@ node node_modules/@tandem-language-exchange/content-store/dist/client/cli.js que
|
|
|
463
474
|
|
|
464
475
|
```json
|
|
465
476
|
"scripts": {
|
|
466
|
-
"query:cms": "node ./node_modules/@tandem-language-exchange/content-store/dist/client/
|
|
477
|
+
"query:cms": "node ./node_modules/@tandem-language-exchange/content-store/dist/client/query-cms.js"
|
|
467
478
|
}
|
|
468
479
|
```
|
|
469
480
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/shared/config.ts
|
|
4
|
+
import dotenv from "dotenv";
|
|
5
|
+
dotenv.config({ path: ".env.local" });
|
|
6
|
+
dotenv.config();
|
|
7
|
+
var config = {
|
|
8
|
+
s3: {
|
|
9
|
+
bucket: process.env.CONTENT_STORE_S3_BUCKET ?? "",
|
|
10
|
+
region: process.env.CONTENT_STORE_S3_REGION ?? "eu-central-1",
|
|
11
|
+
accessKeyId: process.env.AWS_ACCESS_KEY ?? "",
|
|
12
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? ""
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
config
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=chunk-4DE47ZJD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/config.ts"],"sourcesContent":["import dotenv from 'dotenv';\nimport type { S3Config, CMSProvider } from './types';\n\ndotenv.config({ path: '.env.local' });\ndotenv.config();\n\nexport type { CMSProvider, S3Config };\n\nexport interface SharedConfig {\n s3: S3Config;\n}\n\nexport const config: SharedConfig = {\n s3: {\n bucket: process.env.CONTENT_STORE_S3_BUCKET ?? '',\n region: process.env.CONTENT_STORE_S3_REGION ?? 'eu-central-1',\n accessKeyId: process.env.AWS_ACCESS_KEY ?? '',\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? '',\n }\n};\n"],"mappings":";;;AAAA,OAAO,YAAY;AAGnB,OAAO,OAAO,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,OAAO;AAQP,IAAM,SAAuB;AAAA,EAChC,IAAI;AAAA,IACA,QAAQ,QAAQ,IAAI,2BAA2B;AAAA,IAC/C,QAAQ,QAAQ,IAAI,2BAA2B;AAAA,IAC/C,aAAa,QAAQ,IAAI,kBAAkB;AAAA,IAC3C,iBAAiB,QAAQ,IAAI,yBAAyB;AAAA,EAC1D;AACJ;","names":[]}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/shared/s3.ts
|
|
4
|
+
import {
|
|
5
|
+
S3Client,
|
|
6
|
+
PutObjectCommand,
|
|
7
|
+
GetObjectCommand
|
|
8
|
+
} from "@aws-sdk/client-s3";
|
|
9
|
+
var ContentStore = class {
|
|
10
|
+
client;
|
|
11
|
+
bucket;
|
|
12
|
+
constructor(cfg) {
|
|
13
|
+
this.client = new S3Client({
|
|
14
|
+
region: cfg.region,
|
|
15
|
+
credentials: {
|
|
16
|
+
accessKeyId: cfg.accessKeyId,
|
|
17
|
+
secretAccessKey: cfg.secretAccessKey
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
this.bucket = cfg.bucket;
|
|
21
|
+
}
|
|
22
|
+
async upload(key, data) {
|
|
23
|
+
await this.client.send(
|
|
24
|
+
new PutObjectCommand({
|
|
25
|
+
Bucket: this.bucket,
|
|
26
|
+
Key: key,
|
|
27
|
+
Body: JSON.stringify(data, null, 2),
|
|
28
|
+
ContentType: "application/json"
|
|
29
|
+
})
|
|
30
|
+
);
|
|
31
|
+
return key;
|
|
32
|
+
}
|
|
33
|
+
/** Raw UTF-8 body (e.g. Lingohub file bytes as text). */
|
|
34
|
+
async uploadRaw(key, body, contentType) {
|
|
35
|
+
await this.client.send(
|
|
36
|
+
new PutObjectCommand({
|
|
37
|
+
Bucket: this.bucket,
|
|
38
|
+
Key: key,
|
|
39
|
+
Body: body,
|
|
40
|
+
ContentType: contentType
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
return key;
|
|
44
|
+
}
|
|
45
|
+
async download(key) {
|
|
46
|
+
const response = await this.client.send(
|
|
47
|
+
new GetObjectCommand({ Bucket: this.bucket, Key: key })
|
|
48
|
+
);
|
|
49
|
+
const body = await response.Body?.transformToString();
|
|
50
|
+
if (!body) throw new Error(`Empty response for key: ${key}`);
|
|
51
|
+
return JSON.parse(body);
|
|
52
|
+
}
|
|
53
|
+
/** Raw UTF-8 body from S3 (no JSON.parse). */
|
|
54
|
+
async downloadRaw(key) {
|
|
55
|
+
const response = await this.client.send(
|
|
56
|
+
new GetObjectCommand({ Bucket: this.bucket, Key: key })
|
|
57
|
+
);
|
|
58
|
+
const body = await response.Body?.transformToString();
|
|
59
|
+
if (!body) throw new Error(`Empty response for key: ${key}`);
|
|
60
|
+
return body;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var buildCmsObjectKey = (cms, contentType) => {
|
|
64
|
+
return `${cms}-${contentType}.json`;
|
|
65
|
+
};
|
|
66
|
+
var buildTranslationObjectKey = (project, fileName, locale) => {
|
|
67
|
+
return `lingohub-${project}.${fileName.replaceAll("[locale]", locale)}`;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// src/shared/translationResource.ts
|
|
71
|
+
import path from "path";
|
|
72
|
+
|
|
73
|
+
// src/shared/utils.ts
|
|
74
|
+
import convert from "xml-js";
|
|
75
|
+
import set from "lodash.set";
|
|
76
|
+
import merge from "lodash.merge";
|
|
77
|
+
var transformObjectToFlat = (data) => {
|
|
78
|
+
const result = {};
|
|
79
|
+
const flatten = (obj, path2 = []) => {
|
|
80
|
+
Object.entries(obj).forEach(([key, value]) => {
|
|
81
|
+
if (typeof value === "object") {
|
|
82
|
+
flatten(value, path2.concat(key));
|
|
83
|
+
} else {
|
|
84
|
+
result[path2.concat(key).join(".")] = value;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
flatten(data);
|
|
89
|
+
return result;
|
|
90
|
+
};
|
|
91
|
+
var convertXMLToJS = (xml) => {
|
|
92
|
+
const converted = convert.xml2js(xml, {
|
|
93
|
+
ignoreComment: true,
|
|
94
|
+
ignoreDeclaration: true,
|
|
95
|
+
ignoreInstruction: true,
|
|
96
|
+
compact: true
|
|
97
|
+
});
|
|
98
|
+
let mapped = {};
|
|
99
|
+
converted.resources.string.forEach((item) => {
|
|
100
|
+
mapped = {
|
|
101
|
+
...mapped,
|
|
102
|
+
[item._attributes.name]: item._text
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
return mapped;
|
|
106
|
+
};
|
|
107
|
+
var parseIOSStrings = (strings) => {
|
|
108
|
+
const parsedObj = {};
|
|
109
|
+
strings.split("\n").filter((line) => line.startsWith('"') && line.endsWith(";")).map((line) => line.trim().slice(0, -1)).forEach((line) => {
|
|
110
|
+
let [key, value] = line.split(" = ");
|
|
111
|
+
if (!key || !value) return;
|
|
112
|
+
key = key.slice(1, -1);
|
|
113
|
+
value = value.slice(1, -1);
|
|
114
|
+
parsedObj[key] = value;
|
|
115
|
+
});
|
|
116
|
+
return parsedObj;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// src/shared/translationResource.ts
|
|
120
|
+
function contentTypeForTranslationKey(objectKey) {
|
|
121
|
+
if (objectKey.endsWith(".json")) return "application/json; charset=utf-8";
|
|
122
|
+
if (objectKey.endsWith(".xml")) return "application/xml; charset=utf-8";
|
|
123
|
+
if (objectKey.endsWith(".strings")) return "text/plain; charset=utf-8";
|
|
124
|
+
return "application/octet-stream";
|
|
125
|
+
}
|
|
126
|
+
function parseTranslationResourceRaw(raw, resource) {
|
|
127
|
+
if (resource.type === "json") {
|
|
128
|
+
return JSON.parse(raw);
|
|
129
|
+
}
|
|
130
|
+
if (resource.type === "strings") {
|
|
131
|
+
return parseIOSStrings(raw);
|
|
132
|
+
}
|
|
133
|
+
if (resource.type === "xml") {
|
|
134
|
+
return convertXMLToJS(raw);
|
|
135
|
+
}
|
|
136
|
+
throw new Error(`Unsupported resource type: ${resource.type}`);
|
|
137
|
+
}
|
|
138
|
+
function toFlatStringMap(parsed) {
|
|
139
|
+
if (parsed === null || parsed === void 0) return {};
|
|
140
|
+
if (typeof parsed === "string") return { value: parsed };
|
|
141
|
+
if (typeof parsed !== "object") return { value: String(parsed) };
|
|
142
|
+
if (Array.isArray(parsed)) {
|
|
143
|
+
const out2 = {};
|
|
144
|
+
parsed.forEach((v, i) => {
|
|
145
|
+
out2[String(i)] = typeof v === "object" && v !== null ? JSON.stringify(v) : String(v);
|
|
146
|
+
});
|
|
147
|
+
return out2;
|
|
148
|
+
}
|
|
149
|
+
const flat = transformObjectToFlat(parsed);
|
|
150
|
+
const out = {};
|
|
151
|
+
for (const [k, v] of Object.entries(flat)) {
|
|
152
|
+
if (v === null || v === void 0) {
|
|
153
|
+
out[k] = "";
|
|
154
|
+
} else if (typeof v === "object") {
|
|
155
|
+
out[k] = JSON.stringify(v);
|
|
156
|
+
} else {
|
|
157
|
+
out[k] = String(v);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
162
|
+
function translationJsonOutputPath(outputDir, objectKey) {
|
|
163
|
+
if (objectKey.endsWith(".json")) {
|
|
164
|
+
return path.resolve(outputDir, objectKey);
|
|
165
|
+
}
|
|
166
|
+
return path.resolve(outputDir, `${objectKey}.json`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export {
|
|
170
|
+
ContentStore,
|
|
171
|
+
buildCmsObjectKey,
|
|
172
|
+
buildTranslationObjectKey,
|
|
173
|
+
contentTypeForTranslationKey,
|
|
174
|
+
parseTranslationResourceRaw,
|
|
175
|
+
toFlatStringMap,
|
|
176
|
+
translationJsonOutputPath
|
|
177
|
+
};
|
|
178
|
+
//# sourceMappingURL=chunk-5WQPK6GZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/s3.ts","../src/shared/translationResource.ts","../src/shared/utils.ts"],"sourcesContent":["import {\n S3Client,\n PutObjectCommand,\n GetObjectCommand,\n} from '@aws-sdk/client-s3';\nimport type { S3Config } from './types';\n\nexport class ContentStore {\n private client: S3Client;\n private bucket: string;\n\n constructor(cfg: S3Config) {\n this.client = new S3Client({\n region: cfg.region,\n credentials: {\n accessKeyId: cfg.accessKeyId,\n secretAccessKey: cfg.secretAccessKey,\n },\n });\n this.bucket = cfg.bucket;\n }\n\n async upload(key: string, data: unknown): Promise<string> {\n await this.client.send(\n new PutObjectCommand({\n Bucket: this.bucket,\n Key: key,\n Body: JSON.stringify(data, null, 2),\n ContentType: 'application/json',\n }),\n );\n return key;\n }\n\n /** Raw UTF-8 body (e.g. Lingohub file bytes as text). */\n async uploadRaw(\n key: string,\n body: string,\n contentType: string,\n ): Promise<string> {\n await this.client.send(\n new PutObjectCommand({\n Bucket: this.bucket,\n Key: key,\n Body: body,\n ContentType: contentType,\n }),\n );\n return key;\n }\n\n async download(key: string): Promise<unknown> {\n const response = await this.client.send(\n new GetObjectCommand({ Bucket: this.bucket, Key: key }),\n );\n const body = await response.Body?.transformToString();\n if (!body) throw new Error(`Empty response for key: ${key}`);\n return JSON.parse(body);\n }\n\n /** Raw UTF-8 body from S3 (no JSON.parse). */\n async downloadRaw(key: string): Promise<string> {\n const response = await this.client.send(\n new GetObjectCommand({ Bucket: this.bucket, Key: key }),\n );\n const body = await response.Body?.transformToString();\n if (!body) throw new Error(`Empty response for key: ${key}`);\n return body;\n }\n}\n\n/** {cms}-{contentType}.json (always points at the latest version) */\nexport const buildCmsObjectKey = (cms: string, contentType: string): string => {\n return `${cms}-${contentType}.json`;\n}\n\nexport const buildTranslationObjectKey = (project:string, fileName: string, locale: string): string => {\n return `lingohub-${project}.${fileName.replaceAll('[locale]', locale)}`;\n}\n","import path from 'node:path';\nimport { convertXMLToJS, parseIOSStrings, transformObjectToFlat } from './utils';\nimport type { LingohubResource } from './lingohub';\n\n/** Content-Type for raw Lingohub bodies stored in S3. */\nexport function contentTypeForTranslationKey(objectKey: string): string {\n if (objectKey.endsWith('.json')) return 'application/json; charset=utf-8';\n if (objectKey.endsWith('.xml')) return 'application/xml; charset=utf-8';\n if (objectKey.endsWith('.strings')) return 'text/plain; charset=utf-8';\n return 'application/octet-stream';\n}\n\n/**\n * Parses a raw Lingohub file body from S3 into structured data.\n */\nexport function parseTranslationResourceRaw(\n raw: string,\n resource: LingohubResource,\n): unknown {\n if (resource.type === 'json') {\n return JSON.parse(raw) as unknown;\n }\n\n if (resource.type === 'strings') {\n return parseIOSStrings(raw);\n }\n\n if (resource.type === 'xml') {\n return convertXMLToJS(raw);\n }\n\n throw new Error(`Unsupported resource type: ${resource.type}`);\n}\n\n/**\n * Normalizes parsed translation data to a flat string map for merging (duplicate keys: last wins).\n */\nexport function toFlatStringMap(parsed: unknown): Record<string, string> {\n if (parsed === null || parsed === undefined) return {};\n if (typeof parsed === 'string') return { value: parsed };\n if (typeof parsed !== 'object') return { value: String(parsed) };\n if (Array.isArray(parsed)) {\n const out: Record<string, string> = {};\n parsed.forEach((v, i) => {\n out[String(i)] =\n typeof v === 'object' && v !== null ? JSON.stringify(v) : String(v);\n });\n return out;\n }\n\n const flat = transformObjectToFlat(parsed as Record<string, unknown>);\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(flat)) {\n if (v === null || v === undefined) {\n out[k] = '';\n } else if (typeof v === 'object') {\n out[k] = JSON.stringify(v);\n } else {\n out[k] = String(v);\n }\n }\n return out;\n}\n\n/** Where to write normalized JSON for one translation object key (avoids `.json.json`). */\nexport function translationJsonOutputPath(\n outputDir: string,\n objectKey: string,\n): string {\n if (objectKey.endsWith('.json')) {\n return path.resolve(outputDir, objectKey);\n }\n return path.resolve(outputDir, `${objectKey}.json`);\n}\n","import convert from 'xml-js';\nimport set from 'lodash.set';\nimport merge from 'lodash.merge';\n\nexport const transformObjectToNested = (data: Record<string, unknown>): Record<string, unknown> => {\n const result: Record<string, unknown> = {};\n\n Object.entries(data).forEach(([key, value]) => {\n const tempObject = {};\n set(tempObject, key, value);\n merge(result, tempObject);\n });\n\n return result;\n};\n\nexport const transformObjectToFlat = (data: Record<string, any>): Record<string, any> => { // eslint-disable-line @typescript-eslint/no-explicit-any\n const result: Record<string, unknown> = {};\n\n const flatten = (obj: Record<string, any>, path: string[] = []) => { // eslint-disable-line @typescript-eslint/no-explicit-any\n Object.entries(obj).forEach(([key, value]) => {\n if (typeof value === 'object') {\n flatten(value, path.concat(key));\n } else {\n result[path.concat(key).join('.')] = value;\n }\n });\n };\n\n flatten(data);\n\n return result;\n}\n\nexport const convertXMLToJS = (xml: string): Record<string, string> => {\n const converted = convert.xml2js(xml, {\n ignoreComment: true,\n ignoreDeclaration: true,\n ignoreInstruction: true,\n compact: true,\n }) as {\n resources: {\n string: {\n _attributes: { name: string },\n _text: 'User does not exist'\n }[];\n }\n };\n\n let mapped = {};\n converted.resources.string.forEach((item) => {\n mapped = {\n ...mapped,\n [item._attributes.name]: item._text,\n };\n });\n\n return mapped;\n};\n\nexport const parseIOSStrings = (strings: string): Record<string, string> => {\n const parsedObj: Record<string, string> = {};\n strings\n .split('\\n')\n .filter((line) => line.startsWith('\"') && line.endsWith(';'))\n .map((line) => line.trim().slice(0, -1))\n .forEach((line) => {\n let [key, value] = line.split(' = ');\n if (!key || !value) return;\n key = key.slice(1, -1);\n value = value.slice(1, -1);\n parsedObj[key] = value;\n });\n\n return parsedObj;\n};"],"mappings":"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","names":["path","out"]}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/shared/lingohub.ts
|
|
4
|
+
var defaultLocales = ["en", "fr", "de", "es", "it", "pt-br", "ru", "zh-hans", "zh-hant", "ko", "ja"];
|
|
5
|
+
var localeMapping = {
|
|
6
|
+
ios: {
|
|
7
|
+
"pt-br": "pt",
|
|
8
|
+
"zh-hans": "zh-Hans",
|
|
9
|
+
"zh-hant": "zh-Hant"
|
|
10
|
+
},
|
|
11
|
+
android: {
|
|
12
|
+
"pt-br": "pt",
|
|
13
|
+
"zh-hans": "zh-Hans-CN",
|
|
14
|
+
"zh-hant": "zh-TW"
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var allProjects = {
|
|
18
|
+
"tandem-(new-website)": [
|
|
19
|
+
{
|
|
20
|
+
resource: "main",
|
|
21
|
+
fileName: "Website.[locale].json",
|
|
22
|
+
type: "json"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"tandem-(website)": [
|
|
26
|
+
{
|
|
27
|
+
resource: "main",
|
|
28
|
+
fileName: "[locale].json",
|
|
29
|
+
type: "json"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
resource: "ai",
|
|
33
|
+
fileName: "AI.[locale].json",
|
|
34
|
+
type: "json"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
resource: "languages",
|
|
38
|
+
fileName: "languages.[locale].json",
|
|
39
|
+
type: "json"
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"tandem": [
|
|
43
|
+
{
|
|
44
|
+
resource: "infoplist",
|
|
45
|
+
fileName: "InfoPlist.[locale].strings",
|
|
46
|
+
type: "strings",
|
|
47
|
+
localeMapping: localeMapping.ios
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
resource: "localizable",
|
|
51
|
+
fileName: "Localizable.[locale].strings",
|
|
52
|
+
type: "strings",
|
|
53
|
+
localeMapping: localeMapping.ios
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
resource: "ipad",
|
|
57
|
+
fileName: "MainiPad.[locale].strings",
|
|
58
|
+
type: "strings",
|
|
59
|
+
localeMapping: localeMapping.ios
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
resource: "main",
|
|
63
|
+
fileName: "Main.[locale].strings",
|
|
64
|
+
type: "strings",
|
|
65
|
+
localeMapping: localeMapping.ios
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"tandem-(android)": [
|
|
69
|
+
{
|
|
70
|
+
resource: "accessibility",
|
|
71
|
+
fileName: "accessibility_localizable.[locale].xml",
|
|
72
|
+
type: "xml",
|
|
73
|
+
localeMapping: localeMapping.android
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
resource: "call",
|
|
77
|
+
fileName: "call_localizable.[locale].xml",
|
|
78
|
+
type: "xml",
|
|
79
|
+
localeMapping: localeMapping.android
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
resource: "cert",
|
|
83
|
+
fileName: "cert_localizable.[locale].xml",
|
|
84
|
+
type: "xml",
|
|
85
|
+
localeMapping: localeMapping.android
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
resource: "chat",
|
|
89
|
+
fileName: "chat_localizable.[locale].xml",
|
|
90
|
+
type: "xml",
|
|
91
|
+
localeMapping: localeMapping.android
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
resource: "checklist",
|
|
95
|
+
fileName: "checklist_localizable.[locale].xml",
|
|
96
|
+
type: "xml",
|
|
97
|
+
localeMapping: localeMapping.android
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
resource: "clubs",
|
|
101
|
+
fileName: "clubs_localizable.[locale].xml",
|
|
102
|
+
type: "xml",
|
|
103
|
+
localeMapping: localeMapping.android
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
resource: "common",
|
|
107
|
+
fileName: "common_localizable.[locale].xml",
|
|
108
|
+
type: "xml",
|
|
109
|
+
localeMapping: localeMapping.android
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
resource: "community",
|
|
113
|
+
fileName: "community_localizable.[locale].xml",
|
|
114
|
+
type: "xml",
|
|
115
|
+
localeMapping: localeMapping.android
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
resource: "correction",
|
|
119
|
+
fileName: "correction_localizable.[locale].xml",
|
|
120
|
+
type: "xml",
|
|
121
|
+
localeMapping: localeMapping.android
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
resource: "country_names",
|
|
125
|
+
fileName: "country_names.[locale].xml",
|
|
126
|
+
type: "xml",
|
|
127
|
+
localeMapping: localeMapping.android
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
resource: "emoji",
|
|
131
|
+
fileName: "emoji_localizable.[locale].xml",
|
|
132
|
+
type: "xml",
|
|
133
|
+
localeMapping: localeMapping.android
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
resource: "errors",
|
|
137
|
+
fileName: "errors_localizable.[locale].xml",
|
|
138
|
+
type: "xml",
|
|
139
|
+
localeMapping: localeMapping.android
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
resource: "expressions",
|
|
143
|
+
fileName: "expressions_localizable.[locale].xml",
|
|
144
|
+
type: "xml",
|
|
145
|
+
localeMapping: localeMapping.android
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
resource: "gif",
|
|
149
|
+
fileName: "gif_localizable.[locale].xml",
|
|
150
|
+
type: "xml",
|
|
151
|
+
localeMapping: localeMapping.android
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
resource: "guidelines",
|
|
155
|
+
fileName: "guidelines_localizable.[locale].xml",
|
|
156
|
+
type: "xml",
|
|
157
|
+
localeMapping: localeMapping.android
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
resource: "lanuguages",
|
|
161
|
+
fileName: "languages_localizable.[locale].xml",
|
|
162
|
+
type: "xml",
|
|
163
|
+
localeMapping: localeMapping.android
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
resource: "localizable",
|
|
167
|
+
fileName: "localizable.[locale].xml",
|
|
168
|
+
type: "xml",
|
|
169
|
+
localeMapping: localeMapping.android
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
resource: "localizable2",
|
|
173
|
+
fileName: "localizable2.[locale].xml",
|
|
174
|
+
type: "xml",
|
|
175
|
+
localeMapping: localeMapping.android
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
resource: "login",
|
|
179
|
+
fileName: "login_localizable.[locale].xml",
|
|
180
|
+
type: "xml",
|
|
181
|
+
localeMapping: localeMapping.android
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
resource: "myprofile",
|
|
185
|
+
fileName: "myprofile_localizable.[locale].xml",
|
|
186
|
+
type: "xml",
|
|
187
|
+
localeMapping: localeMapping.android
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
resource: "onb",
|
|
191
|
+
fileName: "onb_localizable.[locale].xml",
|
|
192
|
+
type: "xml",
|
|
193
|
+
localeMapping: localeMapping.android
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
resource: "parties",
|
|
197
|
+
fileName: "parties_localizable.[locale].xml",
|
|
198
|
+
type: "xml",
|
|
199
|
+
localeMapping: localeMapping.android
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
resource: "pro",
|
|
203
|
+
fileName: "pro_localizable.[locale].xml",
|
|
204
|
+
type: "xml",
|
|
205
|
+
localeMapping: localeMapping.android
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
resource: "pro_screen",
|
|
209
|
+
fileName: "pro_screen_localizable.[locale].xml",
|
|
210
|
+
type: "xml",
|
|
211
|
+
localeMapping: localeMapping.android
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
resource: "push_notification",
|
|
215
|
+
fileName: "push_notification_localizable.[locale].xml",
|
|
216
|
+
type: "xml",
|
|
217
|
+
localeMapping: localeMapping.android
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
resource: "reporting",
|
|
221
|
+
fileName: "reporting_localizable.[locale].xml",
|
|
222
|
+
type: "xml",
|
|
223
|
+
localeMapping: localeMapping.android
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
resource: "translation",
|
|
227
|
+
fileName: "translation_localizable.[locale].xml",
|
|
228
|
+
type: "xml",
|
|
229
|
+
localeMapping: localeMapping.android
|
|
230
|
+
}
|
|
231
|
+
],
|
|
232
|
+
"tandem-(web-invites)": [
|
|
233
|
+
{
|
|
234
|
+
resource: "main",
|
|
235
|
+
fileName: "[locale].json",
|
|
236
|
+
type: "json"
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export {
|
|
242
|
+
defaultLocales,
|
|
243
|
+
allProjects
|
|
244
|
+
};
|
|
245
|
+
//# sourceMappingURL=chunk-HXG3MIJG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/lingohub.ts"],"sourcesContent":["export const defaultLocales = ['en', 'fr', 'de', 'es', 'it', 'pt-br', 'ru', 'zh-hans', 'zh-hant', 'ko', 'ja'];\n\nconst localeMapping = {\n ios: {\n 'pt-br': 'pt',\n 'zh-hans': 'zh-Hans',\n 'zh-hant': 'zh-Hant',\n },\n android: {\n 'pt-br': 'pt',\n 'zh-hans': 'zh-Hans-CN',\n 'zh-hant': 'zh-TW',\n },\n};\n\nexport type LingohubResource = {\n resource: string,\n fileName: string;\n type: 'json'|'strings'|'xml';\n localeMapping?: Record<string, string>;\n}\n\nexport const allProjects: Record<string, LingohubResource[]> = {\n 'tandem-(new-website)': [\n {\n resource: 'main',\n fileName: 'Website.[locale].json',\n type: 'json'\n }\n ],\n 'tandem-(website)': [\n {\n resource: 'main',\n fileName: '[locale].json',\n type: 'json'\n },\n {\n resource: 'ai',\n fileName: 'AI.[locale].json',\n type: 'json'\n },\n {\n resource: 'languages',\n fileName: 'languages.[locale].json',\n type: 'json'\n }\n ],\n 'tandem': [\n {\n resource: 'infoplist',\n fileName: 'InfoPlist.[locale].strings',\n type: 'strings',\n localeMapping: localeMapping.ios,\n },\n {\n resource: 'localizable',\n fileName: 'Localizable.[locale].strings',\n type: 'strings',\n localeMapping: localeMapping.ios,\n },\n {\n resource: 'ipad',\n fileName: 'MainiPad.[locale].strings',\n type: 'strings',\n localeMapping: localeMapping.ios,\n },\n {\n resource: 'main',\n fileName: 'Main.[locale].strings',\n type: 'strings',\n localeMapping: localeMapping.ios,\n }\n ],\n 'tandem-(android)': [\n {\n resource: 'accessibility',\n fileName: 'accessibility_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'call',\n fileName: 'call_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'cert',\n fileName: 'cert_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'chat',\n fileName: 'chat_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'checklist',\n fileName: 'checklist_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'clubs',\n fileName: 'clubs_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'common',\n fileName: 'common_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'community',\n fileName: 'community_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'correction',\n fileName: 'correction_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'country_names',\n fileName: 'country_names.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'emoji',\n fileName: 'emoji_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'errors',\n fileName: 'errors_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'expressions',\n fileName: 'expressions_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'gif',\n fileName: 'gif_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'guidelines',\n fileName: 'guidelines_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'lanuguages',\n fileName: 'languages_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'localizable',\n fileName: 'localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'localizable2',\n fileName: 'localizable2.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'login',\n fileName: 'login_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'myprofile',\n fileName: 'myprofile_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'onb',\n fileName: 'onb_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'parties',\n fileName: 'parties_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'pro',\n fileName: 'pro_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'pro_screen',\n fileName: 'pro_screen_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'push_notification',\n fileName: 'push_notification_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'reporting',\n fileName: 'reporting_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n resource: 'translation',\n fileName: 'translation_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n }\n\n ],\n 'tandem-(web-invites)': [\n {\n resource: 'main',\n fileName: '[locale].json',\n type: 'json'\n }\n ]\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
config
|
|
4
|
+
} from "./chunk-4DE47ZJD.js";
|
|
2
5
|
import {
|
|
3
6
|
ContentStore,
|
|
4
|
-
allProjects,
|
|
5
7
|
buildCmsObjectKey,
|
|
6
8
|
buildTranslationObjectKey,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
contentTypeForTranslationKey
|
|
10
|
+
} from "./chunk-5WQPK6GZ.js";
|
|
11
|
+
import {
|
|
12
|
+
allProjects,
|
|
9
13
|
defaultLocales
|
|
10
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-HXG3MIJG.js";
|
|
11
15
|
|
|
12
16
|
// src/server/config.ts
|
|
13
17
|
import dotenv from "dotenv";
|
|
@@ -433,4 +437,4 @@ export {
|
|
|
433
437
|
syncCmsContent,
|
|
434
438
|
syncTranslations
|
|
435
439
|
};
|
|
436
|
-
//# sourceMappingURL=chunk-
|
|
440
|
+
//# sourceMappingURL=chunk-TYJ2WIYA.js.map
|