@tandem-language-exchange/content-store 1.1.1 → 1.2.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/README.md +111 -21
- package/dist/{chunk-EGDGHYGI.js → chunk-UCBZUEUP.js} +221 -30
- package/dist/chunk-UCBZUEUP.js.map +1 -0
- package/dist/{chunk-JFI26IB3.js → chunk-VRWRAFDK.js} +67 -18
- package/dist/chunk-VRWRAFDK.js.map +1 -0
- package/dist/chunk-XP3USUQC.js +82 -0
- package/dist/chunk-XP3USUQC.js.map +1 -0
- package/dist/chunk-YZSLCPN6.js +272 -0
- package/dist/chunk-YZSLCPN6.js.map +1 -0
- package/dist/client/cli.js +31 -8
- package/dist/client/cli.js.map +1 -1
- package/dist/client/{fetch-bundles.js → fetch-content-bundles.js} +8 -7
- package/dist/client/fetch-content-bundles.js.map +1 -0
- package/dist/client/fetch-translation-bundles.js +36 -0
- package/dist/client/fetch-translation-bundles.js.map +1 -0
- package/dist/{index-DxoMnE4K.d.ts → index-Db97SUTy.d.ts} +33 -22
- package/dist/index.d.ts +1 -1
- package/dist/node.browser.js +71 -0
- package/dist/node.browser.js.map +1 -0
- package/dist/node.d.ts +22 -5
- package/dist/node.js +353 -44
- package/dist/node.js.map +1 -1
- package/package.json +28 -11
- package/dist/chunk-EGDGHYGI.js.map +0 -1
- package/dist/chunk-JFI26IB3.js.map +0 -1
- package/dist/chunk-UWGOF36L.js +0 -85
- package/dist/chunk-UWGOF36L.js.map +0 -1
- package/dist/client/fetch-bundles.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/s3.ts","../src/shared/lingohub.ts","../src/shared/config.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 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\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","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 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 fileName: 'Website.[locale].json',\n type: 'json'\n }\n ],\n 'tandem-(website)': [\n {\n fileName: '[locale].json',\n type: 'json'\n },\n {\n fileName: 'AI.[locale].json',\n type: 'json'\n },\n {\n fileName: 'languages.[locale].json',\n type: 'json'\n }\n ],\n 'tandem': [\n {\n fileName: 'InfoPlist.[locale].strings',\n type: 'strings',\n localeMapping: localeMapping.ios,\n },\n {\n fileName: 'Localizable.[locale].strings',\n type: 'strings',\n localeMapping: localeMapping.ios,\n },\n {\n fileName: 'MainiPad.[locale].strings',\n type: 'strings',\n localeMapping: localeMapping.ios,\n },\n {\n fileName: 'Main.[locale].strings',\n type: 'strings',\n localeMapping: localeMapping.ios,\n }\n ],\n 'tandem-(android)': [\n {\n fileName: 'accessibility_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'call_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'cert_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'chat_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'checklist_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'clubs_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'common_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'community_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'correction_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'country_names.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'emoji_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'errors_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'expressions_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'gif_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'guidelines_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'languages_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'localizable2.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'login_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'myprofile_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'onb_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'parties_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'pro_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'pro_screen_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'push_notification_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'reporting_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n },\n {\n fileName: 'translation_localizable.[locale].xml',\n type: 'xml',\n localeMapping: localeMapping.android,\n }\n\n ],\n 'tandem-(web-invites)': [\n {\n fileName: '[locale].json',\n type: 'json'\n }\n ]\n};\n","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":"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","names":[]}
|
package/dist/client/cli.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
config,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
fetchCmsBundles,
|
|
5
|
+
fetchTranslationBundles,
|
|
6
|
+
queryCmsBundle
|
|
7
|
+
} from "../chunk-VRWRAFDK.js";
|
|
8
|
+
import "../chunk-XP3USUQC.js";
|
|
7
9
|
import {
|
|
8
10
|
ContentStore
|
|
9
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-YZSLCPN6.js";
|
|
10
12
|
|
|
11
13
|
// src/client/cli.ts
|
|
12
14
|
import { Command } from "commander";
|
|
13
15
|
var program = new Command();
|
|
14
16
|
program.name("content-store").description("Sync CMS content to S3").version("1.0.0");
|
|
15
|
-
program.command("fetch").description("Download latest bundles from S3 to the local filesystem").requiredOption("--cms <provider>", "CMS provider: contentful | sanity").requiredOption("--types <types>", "Comma-separated content types to fetch").option("--output <directory>", "Output directory", "./content-cache").action(async (opts) => {
|
|
17
|
+
program.command("fetch-cms").description("Download latest CMS bundles from S3 to the local filesystem").requiredOption("--cms <provider>", "CMS provider: contentful | sanity").requiredOption("--types <types>", "Comma-separated content types to fetch").option("--output <directory>", "Output directory", "./content-cache").action(async (opts) => {
|
|
16
18
|
const cms = opts.cms;
|
|
17
19
|
if (!["contentful", "sanity"].includes(cms)) {
|
|
18
20
|
console.error(`Invalid CMS provider: ${cms}`);
|
|
@@ -21,7 +23,7 @@ program.command("fetch").description("Download latest bundles from S3 to the loc
|
|
|
21
23
|
const contentTypes = opts.types.split(",").map((s) => s.trim());
|
|
22
24
|
const store = new ContentStore(config.s3);
|
|
23
25
|
try {
|
|
24
|
-
const files = await
|
|
26
|
+
const files = await fetchCmsBundles(store, opts.output, {
|
|
25
27
|
cms,
|
|
26
28
|
contentTypes
|
|
27
29
|
});
|
|
@@ -34,7 +36,28 @@ program.command("fetch").description("Download latest bundles from S3 to the loc
|
|
|
34
36
|
process.exit(1);
|
|
35
37
|
}
|
|
36
38
|
});
|
|
37
|
-
program.command("
|
|
39
|
+
program.command("fetch-translations").description("Download latest Translation bundles from S3 to the local filesystem").requiredOption("--projects <projects>", "Comma-separated projects to fetch").option("--locales <locales>", "Comma-separated locales to fetch (omit to fetch all)").option("--output <directory>", "Output directory", "./content-cache").action(async (opts) => {
|
|
40
|
+
const projects = opts.projects.split(",").map((s) => s.trim());
|
|
41
|
+
const locales = opts.locales ? opts.locales.split(",").map((s) => s.trim()) : void 0;
|
|
42
|
+
const store = new ContentStore(config.s3);
|
|
43
|
+
try {
|
|
44
|
+
const files = await fetchTranslationBundles(store, opts.output, {
|
|
45
|
+
projects,
|
|
46
|
+
locales
|
|
47
|
+
});
|
|
48
|
+
console.log("Fetched bundles:");
|
|
49
|
+
for (const [project, pathsByKey] of Object.entries(files)) {
|
|
50
|
+
console.log(` ${project}:`);
|
|
51
|
+
for (const [objectKey, filePath] of Object.entries(pathsByKey)) {
|
|
52
|
+
console.log(` ${objectKey} -> ${filePath}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.error("Fetch failed:", err);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
program.command("query-cms").description("Query a previously fetched CMS bundle from the local filesystem").requiredOption("--cms <provider>", "CMS provider: contentful | sanity").requiredOption("--type <type>", "Content type to query").option("--output <directory>", "Directory where bundles are stored", "./content-cache").option("--fields <json>", `Filter by fields (JSON object, e.g. '{"columns":"2"}')`).option("--select <props>", "Comma-separated properties to include in results").option("--limit <n>", "Maximum number of results", parseInt).option("--include <n>", "Depth of nested references to include", parseInt).action(
|
|
38
61
|
async (opts) => {
|
|
39
62
|
const cms = opts.cms;
|
|
40
63
|
if (!["contentful", "sanity"].includes(cms)) {
|
|
@@ -42,7 +65,7 @@ program.command("query").description("Query a previously fetched bundle from the
|
|
|
42
65
|
process.exit(1);
|
|
43
66
|
}
|
|
44
67
|
try {
|
|
45
|
-
const results = await
|
|
68
|
+
const results = await queryCmsBundle(opts.output, cms, opts.type, {
|
|
46
69
|
fields: opts.fields ? JSON.parse(opts.fields) : void 0,
|
|
47
70
|
select: opts.select ? opts.select.split(",").map((s) => s.trim()) : void 0,
|
|
48
71
|
limit: opts.limit,
|
package/dist/client/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { config, type CMSProvider } from './config';\nimport { ContentStore } from '../shared/s3';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/client/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { config, type CMSProvider } from './config';\nimport { ContentStore } from '../shared/s3';\nimport { fetchCmsBundles, fetchTranslationBundles, queryCmsBundle } from '../shared/bundles';\n\nconst program = new Command();\n\nprogram\n .name('content-store')\n .description('Sync CMS content to S3')\n .version('1.0.0');\n\nprogram\n .command('fetch-cms')\n .description('Download latest CMS bundles from S3 to the local filesystem')\n .requiredOption('--cms <provider>', 'CMS provider: contentful | sanity')\n .requiredOption('--types <types>', 'Comma-separated content types to fetch')\n .option('--output <directory>', 'Output directory', './content-cache')\n .action(async (opts: { cms: string; types: string; output: string }) => {\n const cms = opts.cms as CMSProvider;\n\n if (!['contentful', 'sanity'].includes(cms)) {\n console.error(`Invalid CMS provider: ${cms}`);\n process.exit(1);\n }\n\n const contentTypes = opts.types.split(',').map((s) => s.trim());\n const store = new ContentStore(config.s3);\n\n try {\n const files = await fetchCmsBundles(store, opts.output, {\n cms,\n contentTypes,\n });\n\n console.log('Fetched bundles:');\n for (const [type, filePath] of Object.entries(files)) {\n console.log(` ${type} -> ${filePath}`);\n }\n } catch (err) {\n console.error('Fetch failed:', err);\n process.exit(1);\n }\n });\n\nprogram\n .command('fetch-translations')\n .description('Download latest Translation bundles from S3 to the local filesystem')\n .requiredOption('--projects <projects>', 'Comma-separated projects to fetch')\n .option('--locales <locales>', 'Comma-separated locales to fetch (omit to fetch all)')\n .option('--output <directory>', 'Output directory', './content-cache')\n .action(async (opts: { projects: string; locales: string; output: string }) => {\n\n const projects = opts.projects.split(',').map((s) => s.trim());\n const locales = opts.locales ? opts.locales.split(',').map((s) => s.trim()) : undefined;\n const store = new ContentStore(config.s3);\n\n try {\n const files = await fetchTranslationBundles(store, opts.output, {\n projects,\n locales,\n });\n\n console.log('Fetched bundles:');\n for (const [project, pathsByKey] of Object.entries(files)) {\n console.log(` ${project}:`);\n for (const [objectKey, filePath] of Object.entries(pathsByKey)) {\n console.log(` ${objectKey} -> ${filePath}`);\n }\n }\n } catch (err) {\n console.error('Fetch failed:', err);\n process.exit(1);\n }\n });\n\nprogram\n .command('query-cms')\n .description('Query a previously fetched CMS bundle from the local filesystem')\n .requiredOption('--cms <provider>', 'CMS provider: contentful | sanity')\n .requiredOption('--type <type>', 'Content type to query')\n .option('--output <directory>', 'Directory where bundles are stored', './content-cache')\n .option('--fields <json>', 'Filter by fields (JSON object, e.g. \\'{\"columns\":\"2\"}\\')')\n .option('--select <props>', 'Comma-separated properties to include in results')\n .option('--limit <n>', 'Maximum number of results', parseInt)\n .option('--include <n>', 'Depth of nested references to include', parseInt)\n .action(\n async (opts: {\n cms: string;\n type: string;\n output: string;\n fields?: string;\n select?: string;\n limit?: number;\n include?: number;\n }) => {\n const cms = opts.cms as CMSProvider;\n\n if (!['contentful', 'sanity'].includes(cms)) {\n console.error(`Invalid CMS provider: ${cms}`);\n process.exit(1);\n }\n\n try {\n const results = await queryCmsBundle(opts.output, cms, opts.type, {\n fields: opts.fields ? JSON.parse(opts.fields) : undefined,\n select: opts.select\n ? opts.select.split(',').map((s) => s.trim())\n : undefined,\n limit: opts.limit,\n include: opts.include,\n });\n\n console.log(JSON.stringify(results, null, 2));\n } catch (err) {\n console.error('Query failed:', err);\n process.exit(1);\n }\n },\n );\n\nprogram.parse();\n"],"mappings":"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","names":[]}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
config,
|
|
4
|
-
|
|
5
|
-
} from "../chunk-
|
|
4
|
+
fetchCmsBundles
|
|
5
|
+
} from "../chunk-VRWRAFDK.js";
|
|
6
|
+
import "../chunk-XP3USUQC.js";
|
|
6
7
|
import {
|
|
7
8
|
ContentStore
|
|
8
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-YZSLCPN6.js";
|
|
9
10
|
|
|
10
|
-
// src/client/fetch-bundles.ts
|
|
11
|
+
// src/client/fetch-content-bundles.ts
|
|
11
12
|
import { Command } from "commander";
|
|
12
13
|
var program = new Command();
|
|
13
|
-
program.name("fetch-content-bundles").description("Download latest bundles from S3 to the local filesystem").requiredOption("--cms <provider>", "CMS provider: contentful | sanity").requiredOption("--types <types>", "Comma-separated content types to fetch").option("--output <directory>", "Output directory", "./content-cache").action(async (opts) => {
|
|
14
|
+
program.name("fetch-content-bundles").description("Download latest CMS bundles from S3 to the local filesystem").requiredOption("--cms <provider>", "CMS provider: contentful | sanity").requiredOption("--types <types>", "Comma-separated content types to fetch").option("--output <directory>", "Output directory", "./content-cache").action(async (opts) => {
|
|
14
15
|
const cms = opts.cms;
|
|
15
16
|
if (!["contentful", "sanity"].includes(cms)) {
|
|
16
17
|
console.error(`Invalid CMS provider: ${cms}`);
|
|
@@ -19,7 +20,7 @@ program.name("fetch-content-bundles").description("Download latest bundles from
|
|
|
19
20
|
const contentTypes = opts.types.split(",").map((s) => s.trim());
|
|
20
21
|
const store = new ContentStore(config.s3);
|
|
21
22
|
try {
|
|
22
|
-
const files = await
|
|
23
|
+
const files = await fetchCmsBundles(store, opts.output, {
|
|
23
24
|
cms,
|
|
24
25
|
contentTypes
|
|
25
26
|
});
|
|
@@ -33,4 +34,4 @@ program.name("fetch-content-bundles").description("Download latest bundles from
|
|
|
33
34
|
}
|
|
34
35
|
});
|
|
35
36
|
program.parse();
|
|
36
|
-
//# sourceMappingURL=fetch-bundles.js.map
|
|
37
|
+
//# sourceMappingURL=fetch-content-bundles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/client/fetch-content-bundles.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { config, type CMSProvider } from './config';\nimport { ContentStore } from '../shared/s3';\nimport { fetchCmsBundles } from '../shared/bundles';\n\nconst program = new Command();\n\nprogram\n .name('fetch-content-bundles')\n .description('Download latest CMS bundles from S3 to the local filesystem')\n .requiredOption('--cms <provider>', 'CMS provider: contentful | sanity')\n .requiredOption('--types <types>', 'Comma-separated content types to fetch')\n .option('--output <directory>', 'Output directory', './content-cache')\n .action(async (opts: { cms: string; types: string; output: string }) => {\n const cms = opts.cms as CMSProvider;\n\n if (!['contentful', 'sanity'].includes(cms)) {\n console.error(`Invalid CMS provider: ${cms}`);\n process.exit(1);\n }\n\n const contentTypes = opts.types.split(',').map((s) => s.trim());\n const store = new ContentStore(config.s3);\n\n try {\n const files = await fetchCmsBundles(store, opts.output, {\n cms,\n contentTypes,\n });\n\n console.log('Fetched bundles:');\n for (const [type, filePath] of Object.entries(files)) {\n console.log(` ${type} -> ${filePath}`);\n }\n } catch (err) {\n console.error('Fetch failed:', err);\n process.exit(1);\n }\n });\n\nprogram.parse();\n"],"mappings":";;;;;;;;;;;AAAA,SAAS,eAAe;AAKxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,uBAAuB,EAC5B,YAAY,6DAA6D,EACzE,eAAe,oBAAoB,mCAAmC,EACtE,eAAe,mBAAmB,wCAAwC,EAC1E,OAAO,wBAAwB,oBAAoB,iBAAiB,EACpE,OAAO,OAAO,SAAyD;AACtE,QAAM,MAAM,KAAK;AAEjB,MAAI,CAAC,CAAC,cAAc,QAAQ,EAAE,SAAS,GAAG,GAAG;AAC3C,YAAQ,MAAM,yBAAyB,GAAG,EAAE;AAC5C,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,eAAe,KAAK,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAC9D,QAAM,QAAQ,IAAI,aAAa,OAAO,EAAE;AAExC,MAAI;AACF,UAAM,QAAQ,MAAM,gBAAgB,OAAO,KAAK,QAAQ;AAAA,MACtD;AAAA,MACA;AAAA,IACF,CAAC;AAED,YAAQ,IAAI,kBAAkB;AAC9B,eAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,QAAQ,KAAK,GAAG;AACpD,cAAQ,IAAI,KAAK,IAAI,OAAO,QAAQ,EAAE;AAAA,IACxC;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,MAAM,iBAAiB,GAAG;AAClC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QAAQ,MAAM;","names":[]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
config,
|
|
4
|
+
fetchTranslationBundles
|
|
5
|
+
} from "../chunk-VRWRAFDK.js";
|
|
6
|
+
import "../chunk-XP3USUQC.js";
|
|
7
|
+
import {
|
|
8
|
+
ContentStore
|
|
9
|
+
} from "../chunk-YZSLCPN6.js";
|
|
10
|
+
|
|
11
|
+
// src/client/fetch-translation-bundles.ts
|
|
12
|
+
import { Command } from "commander";
|
|
13
|
+
var program = new Command();
|
|
14
|
+
program.name("fetch-translation-bundles").description("Download latest translation bundles from S3 to the local filesystem").requiredOption("--projects <projects>", "Comma-separated projects to fetch").option("--locales <locales>", "Comma-separated locales to fetch (omit to fetch all)").option("--output <directory>", "Output directory", "./content-cache").action(async (opts) => {
|
|
15
|
+
const projects = opts.projects.split(",").map((s) => s.trim());
|
|
16
|
+
const locales = opts.locales ? opts.locales.split(",").map((s) => s.trim()) : void 0;
|
|
17
|
+
const store = new ContentStore(config.s3);
|
|
18
|
+
try {
|
|
19
|
+
const files = await fetchTranslationBundles(store, opts.output, {
|
|
20
|
+
projects,
|
|
21
|
+
locales
|
|
22
|
+
});
|
|
23
|
+
console.log("Fetched bundles:");
|
|
24
|
+
for (const [project, pathsByKey] of Object.entries(files)) {
|
|
25
|
+
console.log(` ${project}:`);
|
|
26
|
+
for (const [objectKey, filePath] of Object.entries(pathsByKey)) {
|
|
27
|
+
console.log(` ${objectKey} -> ${filePath}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error("Fetch failed:", err);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
program.parse();
|
|
36
|
+
//# sourceMappingURL=fetch-translation-bundles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/client/fetch-translation-bundles.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { config, type CMSProvider } from './config';\nimport { ContentStore } from '../shared/s3';\nimport { fetchTranslationBundles } from '../shared/bundles';\n\nconst program = new Command();\n\nprogram\n .name('fetch-translation-bundles')\n .description('Download latest translation bundles from S3 to the local filesystem')\n .requiredOption('--projects <projects>', 'Comma-separated projects to fetch')\n .option('--locales <locales>', 'Comma-separated locales to fetch (omit to fetch all)')\n .option('--output <directory>', 'Output directory', './content-cache')\n .action(async (opts: { projects: string; locales?: string; output: string }) => {\n\n const projects = opts.projects.split(',').map((s) => s.trim());\n const locales = opts.locales ? opts.locales.split(',').map((s) => s.trim()) : undefined;\n const store = new ContentStore(config.s3);\n\n try {\n const files = await fetchTranslationBundles(store, opts.output, {\n projects,\n locales,\n });\n\n console.log('Fetched bundles:');\n for (const [project, pathsByKey] of Object.entries(files)) {\n console.log(` ${project}:`);\n for (const [objectKey, filePath] of Object.entries(pathsByKey)) {\n console.log(` ${objectKey} -> ${filePath}`);\n }\n }\n } catch (err) {\n console.error('Fetch failed:', err);\n process.exit(1);\n }\n });\n\nprogram.parse();"],"mappings":";;;;;;;;;;;AAAA,SAAS,eAAe;AAKxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACK,KAAK,2BAA2B,EAChC,YAAY,qEAAqE,EACjF,eAAe,yBAAyB,mCAAmC,EAC3E,OAAO,uBAAuB,uDAAuD,EACrF,OAAO,wBAAwB,oBAAoB,iBAAiB,EACpE,OAAO,OAAO,SAAiE;AAE5E,QAAM,WAAW,KAAK,SAAS,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAC7D,QAAM,UAAU,KAAK,UAAU,KAAK,QAAQ,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI;AAC9E,QAAM,QAAQ,IAAI,aAAa,OAAO,EAAE;AAExC,MAAI;AACA,UAAM,QAAQ,MAAM,wBAAwB,OAAO,KAAK,QAAQ;AAAA,MAC5D;AAAA,MACA;AAAA,IACJ,CAAC;AAED,YAAQ,IAAI,kBAAkB;AAC9B,eAAW,CAAC,SAAS,UAAU,KAAK,OAAO,QAAQ,KAAK,GAAG;AACvD,cAAQ,IAAI,KAAK,OAAO,GAAG;AAC3B,iBAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC5D,gBAAQ,IAAI,OAAO,SAAS,OAAO,QAAQ,EAAE;AAAA,MACjD;AAAA,IACJ;AAAA,EACJ,SAAS,KAAK;AACV,YAAQ,MAAM,iBAAiB,GAAG;AAClC,YAAQ,KAAK,CAAC;AAAA,EAClB;AACJ,CAAC;AAEL,QAAQ,MAAM;","names":[]}
|
|
@@ -10,28 +10,42 @@ declare class ContentStore {
|
|
|
10
10
|
private client;
|
|
11
11
|
private bucket;
|
|
12
12
|
constructor(cfg: S3Config);
|
|
13
|
-
/** {cms}-{contentType}-{timestamp}.json */
|
|
14
|
-
buildVersionedKey(cms: string, contentType: string, timestamp: number): string;
|
|
15
|
-
/** {cms}-{contentType}.json (always points at the latest version) */
|
|
16
|
-
buildLatestKey(cms: string, contentType: string): string;
|
|
17
13
|
upload(key: string, data: unknown): Promise<string>;
|
|
18
14
|
download(key: string): Promise<unknown>;
|
|
19
|
-
/**
|
|
20
|
-
* Copies a versioned object to the "latest" key so that it always reflects
|
|
21
|
-
* the most recent sync while older timestamped versions are retained.
|
|
22
|
-
*/
|
|
23
|
-
copyToLatest(sourceKey: string, cms: string, contentType: string): Promise<string>;
|
|
24
15
|
}
|
|
25
16
|
|
|
26
|
-
|
|
17
|
+
/** Retry/backoff for S3 reads (aligned with CMS `RetryConfig` shape). */
|
|
18
|
+
interface S3RetryConfig {
|
|
19
|
+
maxRetries: number;
|
|
20
|
+
baseDelayMs: number;
|
|
21
|
+
maxDelayMs: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Default S3 download retry policy from env.
|
|
25
|
+
* `S3_RETRY_*` overrides `RETRY_*` when set.
|
|
26
|
+
*/
|
|
27
|
+
declare function getDefaultS3RetryConfig(): S3RetryConfig;
|
|
28
|
+
|
|
29
|
+
interface CmsBundleInfo {
|
|
27
30
|
[key: string]: string;
|
|
28
31
|
}
|
|
32
|
+
interface TranslationBundleInfo {
|
|
33
|
+
[key: string]: Record<string, string>;
|
|
34
|
+
}
|
|
29
35
|
interface BundleItem {
|
|
30
36
|
[key: string]: any;
|
|
31
37
|
}
|
|
32
|
-
interface
|
|
38
|
+
interface FetchCmsBundlesOptions {
|
|
33
39
|
cms: CMSProvider;
|
|
34
40
|
contentTypes: string[];
|
|
41
|
+
/** S3 GET retry; defaults via {@link getDefaultS3RetryConfig}. */
|
|
42
|
+
retry?: S3RetryConfig;
|
|
43
|
+
}
|
|
44
|
+
interface FetchTranslationBundlesOptions {
|
|
45
|
+
projects: string[];
|
|
46
|
+
locales?: string[] | undefined;
|
|
47
|
+
/** S3 GET retry; defaults via {@link getDefaultS3RetryConfig}. */
|
|
48
|
+
retry?: S3RetryConfig;
|
|
35
49
|
}
|
|
36
50
|
interface QueryOptions {
|
|
37
51
|
/**
|
|
@@ -64,24 +78,21 @@ interface QueryOptions {
|
|
|
64
78
|
include?: number;
|
|
65
79
|
}
|
|
66
80
|
/**
|
|
67
|
-
*
|
|
81
|
+
* Downloads the latest CMS bundles from S3 and writes them as JSON files to `outputDir`.
|
|
68
82
|
*
|
|
69
|
-
*
|
|
70
|
-
* - Scalar properties are always kept.
|
|
71
|
-
* - Nested objects / arrays-of-objects consume one level. When `remaining`
|
|
72
|
-
* drops to 1 they are replaced with `null` (no budget left for refs).
|
|
83
|
+
* @returns A map of contentType to absolute file path.
|
|
73
84
|
*/
|
|
74
|
-
declare function
|
|
85
|
+
declare function fetchCmsBundles(store: ContentStore, outputDir: string, options: FetchCmsBundlesOptions): Promise<Record<string, string>>;
|
|
75
86
|
/**
|
|
76
|
-
* Downloads the latest bundles from S3 and writes them as JSON files to `outputDir`.
|
|
87
|
+
* Downloads the latest translation bundles from S3 and writes them as JSON files to `outputDir`.
|
|
77
88
|
*
|
|
78
|
-
* @returns
|
|
89
|
+
* @returns For each project, a map of S3 object key to absolute file path on disk.
|
|
79
90
|
*/
|
|
80
|
-
declare function
|
|
91
|
+
declare function fetchTranslationBundles(store: ContentStore, outputDir: string, options: FetchTranslationBundlesOptions): Promise<TranslationBundleInfo>;
|
|
81
92
|
/**
|
|
82
93
|
* Queries a previously fetched bundle from the local filesystem.
|
|
83
94
|
*/
|
|
84
|
-
declare function
|
|
95
|
+
declare function queryCmsBundle(outputDir: string, cms: CMSProvider, contentType: string, options?: QueryOptions): Promise<unknown[]>;
|
|
85
96
|
|
|
86
97
|
interface SDKConfig {
|
|
87
98
|
s3: S3Config;
|
|
@@ -89,4 +100,4 @@ interface SDKConfig {
|
|
|
89
100
|
outputDir: string;
|
|
90
101
|
}
|
|
91
102
|
|
|
92
|
-
export { type
|
|
103
|
+
export { type BundleItem as B, type CMSProvider as C, type FetchCmsBundlesOptions as F, type QueryOptions as Q, type SDKConfig as S, type TranslationBundleInfo as T, type FetchTranslationBundlesOptions as a, type CmsBundleInfo as b, ContentStore as c, type S3Config as d, type S3RetryConfig as e, fetchCmsBundles as f, fetchTranslationBundles as g, getDefaultS3RetryConfig as h, queryCmsBundle as q };
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { B as
|
|
1
|
+
export { B as BundleItem, C as CMSProvider, b as CmsBundleInfo, F as FetchCmsBundlesOptions, a as FetchTranslationBundlesOptions, Q as QueryOptions, d as S3Config, e as S3RetryConfig, S as SDKConfig, T as TranslationBundleInfo } from './index-Db97SUTy.js';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// src/shared/trimDepth.ts
|
|
2
|
+
function trimDepth(value, remaining) {
|
|
3
|
+
if (value === null || value === void 0 || typeof value !== "object") {
|
|
4
|
+
return value;
|
|
5
|
+
}
|
|
6
|
+
if (Array.isArray(value)) {
|
|
7
|
+
return value.map((item) => trimDepth(item, remaining));
|
|
8
|
+
}
|
|
9
|
+
const obj = value;
|
|
10
|
+
const result = {};
|
|
11
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
12
|
+
if (v === null || v === void 0 || typeof v !== "object") {
|
|
13
|
+
result[k] = v;
|
|
14
|
+
} else if (remaining <= 1) {
|
|
15
|
+
result[k] = null;
|
|
16
|
+
} else if (Array.isArray(v)) {
|
|
17
|
+
result[k] = v.map((item) => {
|
|
18
|
+
if (item !== null && typeof item === "object" && !Array.isArray(item)) {
|
|
19
|
+
return trimDepth(item, remaining - 1);
|
|
20
|
+
}
|
|
21
|
+
return item;
|
|
22
|
+
});
|
|
23
|
+
} else {
|
|
24
|
+
result[k] = trimDepth(v, remaining - 1);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/node.browser.ts
|
|
31
|
+
var SERVER_ONLY = '@tandem-language-exchange/content-store/node uses the filesystem and S3 and only runs on the server. Import it from getServerSideProps, Route Handlers, or "use server" modules \u2014 not from _app, layouts, or client components. You can use `import type { ... } from "@tandem-language-exchange/content-store"` in shared code.';
|
|
32
|
+
function serverOnly() {
|
|
33
|
+
throw new Error(SERVER_ONLY);
|
|
34
|
+
}
|
|
35
|
+
var ContentStoreSDK = class {
|
|
36
|
+
constructor(_config) {
|
|
37
|
+
serverOnly();
|
|
38
|
+
}
|
|
39
|
+
fetchCmsBundles() {
|
|
40
|
+
return Promise.reject(new Error(SERVER_ONLY));
|
|
41
|
+
}
|
|
42
|
+
queryCmsBundle() {
|
|
43
|
+
return Promise.reject(new Error(SERVER_ONLY));
|
|
44
|
+
}
|
|
45
|
+
fetchTranslationBundles() {
|
|
46
|
+
return Promise.reject(new Error(SERVER_ONLY));
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var ContentStore = class {
|
|
50
|
+
constructor(_cfg) {
|
|
51
|
+
serverOnly();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
async function fetchCmsBundles() {
|
|
55
|
+
serverOnly();
|
|
56
|
+
}
|
|
57
|
+
async function queryCmsBundle() {
|
|
58
|
+
serverOnly();
|
|
59
|
+
}
|
|
60
|
+
async function fetchTranslationBundles() {
|
|
61
|
+
serverOnly();
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
ContentStore,
|
|
65
|
+
ContentStoreSDK,
|
|
66
|
+
fetchCmsBundles,
|
|
67
|
+
fetchTranslationBundles,
|
|
68
|
+
queryCmsBundle,
|
|
69
|
+
trimDepth
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=node.browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/trimDepth.ts","../src/node.browser.ts"],"sourcesContent":["/**\n * Trims nested object depth.\n *\n * `remaining` represents how many levels the current object is allowed.\n * - Scalar properties are always kept.\n * - Nested objects / arrays-of-objects consume one level. When `remaining`\n * drops to 1 they are replaced with `null` (no budget left for refs).\n */\nexport function trimDepth(value: unknown, remaining: number): unknown {\n if (value === null || value === undefined || typeof value !== 'object') {\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => trimDepth(item, remaining));\n }\n\n const obj = value as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n\n for (const [k, v] of Object.entries(obj)) {\n if (v === null || v === undefined || typeof v !== 'object') {\n result[k] = v;\n } else if (remaining <= 1) {\n result[k] = null;\n } else if (Array.isArray(v)) {\n result[k] = v.map((item) => {\n if (item !== null && typeof item === 'object' && !Array.isArray(item)) {\n return trimDepth(item, remaining - 1);\n }\n return item;\n });\n } else {\n result[k] = trimDepth(v, remaining - 1);\n }\n }\n\n return result;\n}\n","/**\n * Browser / client-bundler entry for `@tandem-language-exchange/content-store/node`.\n * Next.js and Turbopack resolve this when the `browser` condition applies, so `fs`\n * is never pulled into client chunks.\n *\n * Server-only APIs throw if called; `trimDepth` is real and safe everywhere.\n */\nexport type {\n SDKConfig,\n FetchCmsBundlesOptions,\n FetchTranslationBundlesOptions,\n QueryOptions,\n CmsBundleInfo,\n TranslationBundleInfo,\n BundleItem,\n} from './sdk/client-types';\nexport type { CMSProvider, S3Config } from './shared/types';\n\nexport { trimDepth } from './shared/trimDepth';\n\nconst SERVER_ONLY =\n '@tandem-language-exchange/content-store/node uses the filesystem and S3 and only runs on the server. ' +\n 'Import it from getServerSideProps, Route Handlers, or \"use server\" modules — not from _app, layouts, or client components. ' +\n 'You can use `import type { ... } from \"@tandem-language-exchange/content-store\"` in shared code.';\n\nfunction serverOnly(): never {\n throw new Error(SERVER_ONLY);\n}\n\nexport class ContentStoreSDK {\n constructor(_config: unknown) {\n serverOnly();\n }\n\n fetchCmsBundles(): Promise<never> {\n return Promise.reject(new Error(SERVER_ONLY));\n }\n\n queryCmsBundle(): Promise<never> {\n return Promise.reject(new Error(SERVER_ONLY));\n }\n\n fetchTranslationBundles(): Promise<never> {\n return Promise.reject(new Error(SERVER_ONLY));\n }\n}\n\nexport class ContentStore {\n constructor(_cfg: unknown) {\n serverOnly();\n }\n}\n\nexport async function fetchCmsBundles(): Promise<never> {\n serverOnly();\n}\n\nexport async function queryCmsBundle(): Promise<never> {\n serverOnly();\n}\n\nexport async function fetchTranslationBundles(): Promise<never> {\n serverOnly();\n}\n"],"mappings":";AAQO,SAAS,UAAU,OAAgB,WAA4B;AACpE,MAAI,UAAU,QAAQ,UAAU,UAAa,OAAO,UAAU,UAAU;AACtE,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,CAAC,SAAS,UAAU,MAAM,SAAS,CAAC;AAAA,EACvD;AAEA,QAAM,MAAM;AACZ,QAAM,SAAkC,CAAC;AAEzC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,GAAG,GAAG;AACxC,QAAI,MAAM,QAAQ,MAAM,UAAa,OAAO,MAAM,UAAU;AAC1D,aAAO,CAAC,IAAI;AAAA,IACd,WAAW,aAAa,GAAG;AACzB,aAAO,CAAC,IAAI;AAAA,IACd,WAAW,MAAM,QAAQ,CAAC,GAAG;AAC3B,aAAO,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS;AAC1B,YAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,GAAG;AACrE,iBAAO,UAAU,MAAM,YAAY,CAAC;AAAA,QACtC;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH,OAAO;AACL,aAAO,CAAC,IAAI,UAAU,GAAG,YAAY,CAAC;AAAA,IACxC;AAAA,EACF;AAEA,SAAO;AACT;;;AClBA,IAAM,cACJ;AAIF,SAAS,aAAoB;AAC3B,QAAM,IAAI,MAAM,WAAW;AAC7B;AAEO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAAY,SAAkB;AAC5B,eAAW;AAAA,EACb;AAAA,EAEA,kBAAkC;AAChC,WAAO,QAAQ,OAAO,IAAI,MAAM,WAAW,CAAC;AAAA,EAC9C;AAAA,EAEA,iBAAiC;AAC/B,WAAO,QAAQ,OAAO,IAAI,MAAM,WAAW,CAAC;AAAA,EAC9C;AAAA,EAEA,0BAA0C;AACxC,WAAO,QAAQ,OAAO,IAAI,MAAM,WAAW,CAAC;AAAA,EAC9C;AACF;AAEO,IAAM,eAAN,MAAmB;AAAA,EACxB,YAAY,MAAe;AACzB,eAAW;AAAA,EACb;AACF;AAEA,eAAsB,kBAAkC;AACtD,aAAW;AACb;AAEA,eAAsB,iBAAiC;AACrD,aAAW;AACb;AAEA,eAAsB,0BAA0C;AAC9D,aAAW;AACb;","names":[]}
|
package/dist/node.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
import { S as SDKConfig, F as
|
|
2
|
-
export { B as
|
|
1
|
+
import { S as SDKConfig, F as FetchCmsBundlesOptions, a as FetchTranslationBundlesOptions, T as TranslationBundleInfo, C as CMSProvider, Q as QueryOptions } from './index-Db97SUTy.js';
|
|
2
|
+
export { B as BundleItem, b as CmsBundleInfo, c as ContentStore, d as S3Config, e as S3RetryConfig, f as fetchCmsBundles, g as fetchTranslationBundles, h as getDefaultS3RetryConfig, q as queryCmsBundle } from './index-Db97SUTy.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Trims nested object depth.
|
|
6
|
+
*
|
|
7
|
+
* `remaining` represents how many levels the current object is allowed.
|
|
8
|
+
* - Scalar properties are always kept.
|
|
9
|
+
* - Nested objects / arrays-of-objects consume one level. When `remaining`
|
|
10
|
+
* drops to 1 they are replaced with `null` (no budget left for refs).
|
|
11
|
+
*/
|
|
12
|
+
declare function trimDepth(value: unknown, remaining: number): unknown;
|
|
3
13
|
|
|
4
14
|
declare class ContentStoreSDK {
|
|
5
15
|
private store;
|
|
@@ -11,11 +21,18 @@ declare class ContentStoreSDK {
|
|
|
11
21
|
*
|
|
12
22
|
* @returns A map of contentType to absolute file path.
|
|
13
23
|
*/
|
|
14
|
-
|
|
24
|
+
fetchCmsBundles(options: FetchCmsBundlesOptions): Promise<Record<string, string>>;
|
|
25
|
+
/**
|
|
26
|
+
* Downloads translation bundles from S3 and writes them as JSON files
|
|
27
|
+
* to `outputDir`.
|
|
28
|
+
*
|
|
29
|
+
* @returns Per project, a map of S3 object key to absolute file path.
|
|
30
|
+
*/
|
|
31
|
+
fetchTranslationBundles(options: FetchTranslationBundlesOptions): Promise<TranslationBundleInfo>;
|
|
15
32
|
/**
|
|
16
33
|
* Queries a previously fetched bundle from the local filesystem.
|
|
17
34
|
*/
|
|
18
|
-
|
|
35
|
+
queryCmsBundle(cms: CMSProvider, contentType: string, options?: QueryOptions): Promise<unknown[]>;
|
|
19
36
|
}
|
|
20
37
|
|
|
21
|
-
export { CMSProvider, ContentStoreSDK,
|
|
38
|
+
export { CMSProvider, ContentStoreSDK, FetchCmsBundlesOptions, FetchTranslationBundlesOptions, QueryOptions, SDKConfig, TranslationBundleInfo, trimDepth };
|