@tandem-language-exchange/content-store 1.1.2 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -20
- package/dist/chunk-EQ3DSPTJ.js +86 -0
- package/dist/chunk-EQ3DSPTJ.js.map +1 -0
- package/dist/{chunk-JBFJU4JA.js → chunk-LOCC2BXB.js} +118 -13
- package/dist/chunk-LOCC2BXB.js.map +1 -0
- package/dist/chunk-OTZLCMZ6.js +396 -0
- package/dist/chunk-OTZLCMZ6.js.map +1 -0
- package/dist/{chunk-YOREZCXB.js → chunk-PQJ2MGH7.js} +180 -29
- package/dist/chunk-PQJ2MGH7.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-merged-translation-bundles.js +40 -0
- package/dist/client/fetch-merged-translation-bundles.js.map +1 -0
- package/dist/client/fetch-translation-bundles.js +43 -0
- package/dist/client/fetch-translation-bundles.js.map +1 -0
- package/dist/index-kfqHGgMO.d.ts +118 -0
- package/dist/index.d.ts +1 -1
- package/dist/node.browser.js +20 -6
- package/dist/node.browser.js.map +1 -1
- package/dist/node.d.ts +18 -5
- package/dist/node.js +527 -41
- package/dist/node.js.map +1 -1
- package/package.json +25 -11
- package/dist/chunk-JBFJU4JA.js.map +0 -1
- package/dist/chunk-UWGOF36L.js +0 -85
- package/dist/chunk-UWGOF36L.js.map +0 -1
- package/dist/chunk-YOREZCXB.js.map +0 -1
- package/dist/client/fetch-bundles.js.map +0 -1
- package/dist/index-DJXkO17k.d.ts +0 -83
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
type CMSProvider = 'contentful' | 'sanity';
|
|
2
|
+
interface S3Config {
|
|
3
|
+
bucket: string;
|
|
4
|
+
region: string;
|
|
5
|
+
accessKeyId: string;
|
|
6
|
+
secretAccessKey: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
declare class ContentStore {
|
|
10
|
+
private client;
|
|
11
|
+
private bucket;
|
|
12
|
+
constructor(cfg: S3Config);
|
|
13
|
+
upload(key: string, data: unknown): Promise<string>;
|
|
14
|
+
/** Raw UTF-8 body (e.g. Lingohub file bytes as text). */
|
|
15
|
+
uploadRaw(key: string, body: string, contentType: string): Promise<string>;
|
|
16
|
+
download(key: string): Promise<unknown>;
|
|
17
|
+
/** Raw UTF-8 body from S3 (no JSON.parse). */
|
|
18
|
+
downloadRaw(key: string): Promise<string>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Retry/backoff for S3 reads (aligned with CMS `RetryConfig` shape). */
|
|
22
|
+
interface S3RetryConfig {
|
|
23
|
+
maxRetries: number;
|
|
24
|
+
baseDelayMs: number;
|
|
25
|
+
maxDelayMs: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Default S3 download retry policy from env.
|
|
29
|
+
* `S3_RETRY_*` overrides `RETRY_*` when set.
|
|
30
|
+
*/
|
|
31
|
+
declare function getDefaultS3RetryConfig(): S3RetryConfig;
|
|
32
|
+
|
|
33
|
+
interface CmsBundleInfo {
|
|
34
|
+
[key: string]: string;
|
|
35
|
+
}
|
|
36
|
+
interface TranslationBundleInfo {
|
|
37
|
+
[key: string]: Record<string, string>;
|
|
38
|
+
}
|
|
39
|
+
interface BundleItem {
|
|
40
|
+
[key: string]: any;
|
|
41
|
+
}
|
|
42
|
+
interface FetchCmsBundlesOptions {
|
|
43
|
+
cms: CMSProvider;
|
|
44
|
+
contentTypes: string[];
|
|
45
|
+
/** S3 GET retry; defaults via {@link getDefaultS3RetryConfig}. */
|
|
46
|
+
retry?: S3RetryConfig;
|
|
47
|
+
}
|
|
48
|
+
interface FetchTranslationBundlesOptions {
|
|
49
|
+
projects: string[];
|
|
50
|
+
locales?: string[] | undefined;
|
|
51
|
+
/** S3 GET retry; defaults via {@link getDefaultS3RetryConfig}. */
|
|
52
|
+
retry?: S3RetryConfig;
|
|
53
|
+
}
|
|
54
|
+
/** One merged JSON file per catalog locale (`en.json`, …). Same options as {@link FetchTranslationBundlesOptions}. */
|
|
55
|
+
type FetchMergedTranslationBundlesOptions = FetchTranslationBundlesOptions;
|
|
56
|
+
interface QueryOptions {
|
|
57
|
+
/**
|
|
58
|
+
* Filter items by matching property values (exact equality, or array for IN).
|
|
59
|
+
* Keys may use dot notation for nested paths, e.g. `{ 'meta._id': 'abc' }` matches
|
|
60
|
+
* `item.meta._id`.
|
|
61
|
+
*
|
|
62
|
+
* Contentful-style operators on the path (before `[`):
|
|
63
|
+
* - `{ 'field[exists]': true }` — field is present and non-empty (not null, undefined,
|
|
64
|
+
* `''`, `[]`, or `{}`).
|
|
65
|
+
* - `{ 'field[exists]': false }` — field is missing or empty (same emptiness rules).
|
|
66
|
+
* Nested paths work, e.g. `{ 'blocks.hero[exists]': false }`.
|
|
67
|
+
*/
|
|
68
|
+
fields?: Record<string, unknown>;
|
|
69
|
+
/**
|
|
70
|
+
* Properties to include in each result object. Omit to return all properties.
|
|
71
|
+
* Keys may use dot notation; nested segments become nested objects in the result,
|
|
72
|
+
* e.g. `['slug', 'meta._updatedAt']` → `{ slug, meta: { _updatedAt } }`.
|
|
73
|
+
*/
|
|
74
|
+
select?: string[];
|
|
75
|
+
/** Maximum number of items to return. */
|
|
76
|
+
limit?: number;
|
|
77
|
+
/**
|
|
78
|
+
* How many levels deep to return.
|
|
79
|
+
* - 1 = the item's own scalar properties only; nested objects/refs are nulled.
|
|
80
|
+
* - 2 = the item including its direct references; refs inside those are nulled.
|
|
81
|
+
* - 3 = three levels deep, and so on.
|
|
82
|
+
* - Omit to return the full depth.
|
|
83
|
+
*/
|
|
84
|
+
include?: number;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Downloads the latest CMS bundles from S3 and writes them as JSON files to `outputDir`.
|
|
88
|
+
*
|
|
89
|
+
* @returns A map of contentType to absolute file path.
|
|
90
|
+
*/
|
|
91
|
+
declare function fetchCmsBundles(store: ContentStore, outputDir: string, options: FetchCmsBundlesOptions): Promise<Record<string, string>>;
|
|
92
|
+
/**
|
|
93
|
+
* Downloads the latest translation bundles from S3 and writes them as JSON files to `outputDir`.
|
|
94
|
+
*
|
|
95
|
+
* @returns For each project, a map of S3 object key to absolute file path on disk.
|
|
96
|
+
*/
|
|
97
|
+
declare function fetchTranslationBundles(store: ContentStore, outputDir: string, options: FetchTranslationBundlesOptions): Promise<TranslationBundleInfo>;
|
|
98
|
+
/**
|
|
99
|
+
* Downloads translation bundles from S3, parses each raw Lingohub file, and merges all
|
|
100
|
+
* key/value pairs per **catalog** locale into a single JSON file (e.g. `en.json`).
|
|
101
|
+
* Duplicate keys across resources or projects: **last write wins** (iteration order:
|
|
102
|
+
* projects → resources → locales).
|
|
103
|
+
*
|
|
104
|
+
* @returns Map of locale code to absolute path of the merged `{locale}.json` file.
|
|
105
|
+
*/
|
|
106
|
+
declare function fetchMergedTranslationBundles(store: ContentStore, outputDir: string, options: FetchMergedTranslationBundlesOptions): Promise<Record<string, string>>;
|
|
107
|
+
/**
|
|
108
|
+
* Queries a previously fetched bundle from the local filesystem.
|
|
109
|
+
*/
|
|
110
|
+
declare function queryCmsBundle(outputDir: string, cms: CMSProvider, contentType: string, options?: QueryOptions): Promise<unknown[]>;
|
|
111
|
+
|
|
112
|
+
interface SDKConfig {
|
|
113
|
+
s3: S3Config;
|
|
114
|
+
/** Directory where bundle JSON files are saved on the local filesystem. */
|
|
115
|
+
outputDir: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
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 FetchMergedTranslationBundlesOptions as b, type CmsBundleInfo as c, ContentStore as d, type S3Config as e, type S3RetryConfig as f, fetchCmsBundles as g, fetchMergedTranslationBundles as h, fetchTranslationBundles as i, getDefaultS3RetryConfig as j, queryCmsBundle as q };
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { B as
|
|
1
|
+
export { B as BundleItem, C as CMSProvider, c as CmsBundleInfo, F as FetchCmsBundlesOptions, b as FetchMergedTranslationBundlesOptions, a as FetchTranslationBundlesOptions, Q as QueryOptions, e as S3Config, f as S3RetryConfig, S as SDKConfig, T as TranslationBundleInfo } from './index-kfqHGgMO.js';
|
package/dist/node.browser.js
CHANGED
|
@@ -36,10 +36,16 @@ var ContentStoreSDK = class {
|
|
|
36
36
|
constructor(_config) {
|
|
37
37
|
serverOnly();
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
fetchCmsBundles() {
|
|
40
40
|
return Promise.reject(new Error(SERVER_ONLY));
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
queryCmsBundle() {
|
|
43
|
+
return Promise.reject(new Error(SERVER_ONLY));
|
|
44
|
+
}
|
|
45
|
+
fetchTranslationBundles() {
|
|
46
|
+
return Promise.reject(new Error(SERVER_ONLY));
|
|
47
|
+
}
|
|
48
|
+
fetchMergedTranslationBundles() {
|
|
43
49
|
return Promise.reject(new Error(SERVER_ONLY));
|
|
44
50
|
}
|
|
45
51
|
};
|
|
@@ -48,17 +54,25 @@ var ContentStore = class {
|
|
|
48
54
|
serverOnly();
|
|
49
55
|
}
|
|
50
56
|
};
|
|
51
|
-
async function
|
|
57
|
+
async function fetchCmsBundles() {
|
|
58
|
+
serverOnly();
|
|
59
|
+
}
|
|
60
|
+
async function queryCmsBundle() {
|
|
61
|
+
serverOnly();
|
|
62
|
+
}
|
|
63
|
+
async function fetchTranslationBundles() {
|
|
52
64
|
serverOnly();
|
|
53
65
|
}
|
|
54
|
-
async function
|
|
66
|
+
async function fetchMergedTranslationBundles() {
|
|
55
67
|
serverOnly();
|
|
56
68
|
}
|
|
57
69
|
export {
|
|
58
70
|
ContentStore,
|
|
59
71
|
ContentStoreSDK,
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
fetchCmsBundles,
|
|
73
|
+
fetchMergedTranslationBundles,
|
|
74
|
+
fetchTranslationBundles,
|
|
75
|
+
queryCmsBundle,
|
|
62
76
|
trimDepth
|
|
63
77
|
};
|
|
64
78
|
//# sourceMappingURL=node.browser.js.map
|
package/dist/node.browser.js.map
CHANGED
|
@@ -1 +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
|
|
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 FetchMergedTranslationBundlesOptions,\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 fetchMergedTranslationBundles(): 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\nexport async function fetchMergedTranslationBundles(): 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;;;ACjBA,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;AAAA,EAEA,gCAAgD;AAC9C,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;AAEA,eAAsB,gCAAgD;AACpE,aAAW;AACb;","names":[]}
|
package/dist/node.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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, b as FetchMergedTranslationBundlesOptions, C as CMSProvider, Q as QueryOptions } from './index-kfqHGgMO.js';
|
|
2
|
+
export { B as BundleItem, c as CmsBundleInfo, d as ContentStore, e as S3Config, f as S3RetryConfig, g as fetchCmsBundles, h as fetchMergedTranslationBundles, i as fetchTranslationBundles, j as getDefaultS3RetryConfig, q as queryCmsBundle } from './index-kfqHGgMO.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Trims nested object depth.
|
|
@@ -21,11 +21,24 @@ declare class ContentStoreSDK {
|
|
|
21
21
|
*
|
|
22
22
|
* @returns A map of contentType to absolute file path.
|
|
23
23
|
*/
|
|
24
|
-
|
|
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>;
|
|
32
|
+
/**
|
|
33
|
+
* Downloads all translation resources for the given projects/locales, parses them,
|
|
34
|
+
* and writes one merged `{locale}.json` per locale (string key/value map; duplicate keys:
|
|
35
|
+
* last wins).
|
|
36
|
+
*/
|
|
37
|
+
fetchMergedTranslationBundles(options: FetchMergedTranslationBundlesOptions): Promise<Record<string, string>>;
|
|
25
38
|
/**
|
|
26
39
|
* Queries a previously fetched bundle from the local filesystem.
|
|
27
40
|
*/
|
|
28
|
-
|
|
41
|
+
queryCmsBundle(cms: CMSProvider, contentType: string, options?: QueryOptions): Promise<unknown[]>;
|
|
29
42
|
}
|
|
30
43
|
|
|
31
|
-
export { CMSProvider, ContentStoreSDK,
|
|
44
|
+
export { CMSProvider, ContentStoreSDK, FetchCmsBundlesOptions, FetchMergedTranslationBundlesOptions, FetchTranslationBundlesOptions, QueryOptions, SDKConfig, TranslationBundleInfo, trimDepth };
|