@tandem-language-exchange/content-store 1.0.7 → 1.0.8
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/dist/client/cli.js +51 -64
- package/dist/client/cli.js.map +1 -1
- package/dist/client/fetch-bundles.js +32 -32
- package/dist/client/fetch-bundles.js.map +1 -1
- package/dist/index.d.ts +88 -5
- package/dist/index.js +182 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/client/cli.d.ts +0 -1
- package/dist/client/config.d.ts +0 -6
- package/dist/client/config.js +0 -8
- package/dist/client/config.js.map +0 -1
- package/dist/client/fetch-bundles.d.ts +0 -2
- package/dist/sdk/client.d.ts +0 -24
- package/dist/sdk/client.js +0 -26
- package/dist/sdk/client.js.map +0 -1
- package/dist/sdk/index.d.ts +0 -5
- package/dist/sdk/index.js +0 -4
- package/dist/sdk/index.js.map +0 -1
- package/dist/shared/bundles.d.ts +0 -41
- package/dist/shared/bundles.js +0 -94
- package/dist/shared/bundles.js.map +0 -1
- package/dist/shared/config.d.ts +0 -6
- package/dist/shared/config.js +0 -12
- package/dist/shared/config.js.map +0 -1
- package/dist/shared/s3.d.ts +0 -17
- package/dist/shared/s3.js +0 -54
- package/dist/shared/s3.js.map +0 -1
- package/dist/shared/sync/engine.d.ts +0 -17
- package/dist/shared/sync/engine.js +0 -38
- package/dist/shared/sync/engine.js.map +0 -1
- package/dist/shared/sync/retry.d.ts +0 -7
- package/dist/shared/sync/retry.js +0 -57
- package/dist/shared/sync/retry.js.map +0 -1
- package/dist/shared/types.d.ts +0 -7
- package/dist/shared/types.js +0 -2
- package/dist/shared/types.js.map +0 -1
package/dist/client/cli.js
CHANGED
|
@@ -1,72 +1,59 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
console.log(` ${type} -> ${filePath}`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
catch (err) {
|
|
35
|
-
console.error('Fetch failed:', err);
|
|
36
|
-
process.exit(1);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
config,
|
|
4
|
+
fetchBundles,
|
|
5
|
+
queryBundle
|
|
6
|
+
} from "../chunk-R6THP5E4.js";
|
|
7
|
+
import {
|
|
8
|
+
ContentStore
|
|
9
|
+
} from "../chunk-DPWIBUHQ.js";
|
|
10
|
+
|
|
11
|
+
// src/client/cli.ts
|
|
12
|
+
import { Command } from "commander";
|
|
13
|
+
var program = new Command();
|
|
14
|
+
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) => {
|
|
16
|
+
const cms = opts.cms;
|
|
17
|
+
if (!["contentful", "sanity"].includes(cms)) {
|
|
18
|
+
console.error(`Invalid CMS provider: ${cms}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
const contentTypes = opts.types.split(",").map((s) => s.trim());
|
|
22
|
+
const store = new ContentStore(config.s3);
|
|
23
|
+
try {
|
|
24
|
+
const files = await fetchBundles(store, opts.output, {
|
|
25
|
+
cms,
|
|
26
|
+
contentTypes
|
|
27
|
+
});
|
|
28
|
+
console.log("Fetched bundles:");
|
|
29
|
+
for (const [type, filePath] of Object.entries(files)) {
|
|
30
|
+
console.log(` ${type} -> ${filePath}`);
|
|
37
31
|
}
|
|
32
|
+
} catch (err) {
|
|
33
|
+
console.error("Fetch failed:", err);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
38
36
|
});
|
|
39
|
-
program
|
|
40
|
-
|
|
41
|
-
.description('Query a previously fetched bundle from the local filesystem')
|
|
42
|
-
.requiredOption('--cms <provider>', 'CMS provider: contentful | sanity')
|
|
43
|
-
.requiredOption('--type <type>', 'Content type to query')
|
|
44
|
-
.option('--output <directory>', 'Directory where bundles are stored', './content-cache')
|
|
45
|
-
.option('--fields <json>', 'Filter by fields (JSON object, e.g. \'{"columns":"2"}\')')
|
|
46
|
-
.option('--select <props>', 'Comma-separated properties to include in results')
|
|
47
|
-
.option('--limit <n>', 'Maximum number of results', parseInt)
|
|
48
|
-
.option('--include <n>', 'Depth of nested references to include', parseInt)
|
|
49
|
-
.action(async (opts) => {
|
|
37
|
+
program.command("query").description("Query a previously fetched 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
|
+
async (opts) => {
|
|
50
39
|
const cms = opts.cms;
|
|
51
|
-
if (![
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
if (!["contentful", "sanity"].includes(cms)) {
|
|
41
|
+
console.error(`Invalid CMS provider: ${cms}`);
|
|
42
|
+
process.exit(1);
|
|
54
43
|
}
|
|
55
44
|
try {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
catch (err) {
|
|
67
|
-
console.error('Query failed:', err);
|
|
68
|
-
process.exit(1);
|
|
45
|
+
const results = await queryBundle(opts.output, cms, opts.type, {
|
|
46
|
+
fields: opts.fields ? JSON.parse(opts.fields) : void 0,
|
|
47
|
+
select: opts.select ? opts.select.split(",").map((s) => s.trim()) : void 0,
|
|
48
|
+
limit: opts.limit,
|
|
49
|
+
include: opts.include
|
|
50
|
+
});
|
|
51
|
+
console.log(JSON.stringify(results, null, 2));
|
|
52
|
+
} catch (err) {
|
|
53
|
+
console.error("Query failed:", err);
|
|
54
|
+
process.exit(1);
|
|
69
55
|
}
|
|
70
|
-
}
|
|
56
|
+
}
|
|
57
|
+
);
|
|
71
58
|
program.parse();
|
|
72
59
|
//# sourceMappingURL=cli.js.map
|
package/dist/client/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
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 { fetchBundles, queryBundle } 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')\n .description('Download latest 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 fetchBundles(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('query')\n .description('Query a previously fetched 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 queryBundle(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":";;;;;;;;;;;AAAA,SAAS,eAAe;AAKxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,eAAe,EACpB,YAAY,wBAAwB,EACpC,QAAQ,OAAO;AAElB,QACK,QAAQ,OAAO,EACf,YAAY,yDAAyD,EACrE,eAAe,oBAAoB,mCAAmC,EACtE,eAAe,mBAAmB,wCAAwC,EAC1E,OAAO,wBAAwB,oBAAoB,iBAAiB,EACpE,OAAO,OAAO,SAAyD;AACxE,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,aAAa,OAAO,KAAK,QAAQ;AAAA,MACnD;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,QACG,QAAQ,OAAO,EACf,YAAY,6DAA6D,EACzE,eAAe,oBAAoB,mCAAmC,EACtE,eAAe,iBAAiB,uBAAuB,EACvD,OAAO,wBAAwB,sCAAsC,iBAAiB,EACtF,OAAO,mBAAmB,wDAA0D,EACpF,OAAO,oBAAoB,kDAAkD,EAC7E,OAAO,eAAe,6BAA6B,QAAQ,EAC3D,OAAO,iBAAiB,yCAAyC,QAAQ,EACzE;AAAA,EACC,OAAO,SAQD;AACJ,UAAM,MAAM,KAAK;AAEjB,QAAI,CAAC,CAAC,cAAc,QAAQ,EAAE,SAAS,GAAG,GAAG;AAC3C,cAAQ,MAAM,yBAAyB,GAAG,EAAE;AAC5C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI;AACF,YAAM,UAAU,MAAM,YAAY,KAAK,QAAQ,KAAK,KAAK,MAAM;AAAA,QAC7D,QAAQ,KAAK,SAAS,KAAK,MAAM,KAAK,MAAM,IAAI;AAAA,QAChD,QAAQ,KAAK,SACT,KAAK,OAAO,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAC1C;AAAA,QACJ,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MAChB,CAAC;AAED,cAAQ,IAAI,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,IAC9C,SAAS,KAAK;AACZ,cAAQ,MAAM,iBAAiB,GAAG;AAClC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACF;AAEF,QAAQ,MAAM;","names":[]}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
catch (err) {
|
|
32
|
-
console.error('Fetch failed:', err);
|
|
33
|
-
process.exit(1);
|
|
2
|
+
#!/usr/bin/env node
|
|
3
|
+
import {
|
|
4
|
+
config,
|
|
5
|
+
fetchBundles
|
|
6
|
+
} from "../chunk-R6THP5E4.js";
|
|
7
|
+
import {
|
|
8
|
+
ContentStore
|
|
9
|
+
} from "../chunk-DPWIBUHQ.js";
|
|
10
|
+
|
|
11
|
+
// src/client/fetch-bundles.ts
|
|
12
|
+
import { Command } from "commander";
|
|
13
|
+
var program = new Command();
|
|
14
|
+
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) => {
|
|
15
|
+
const cms = opts.cms;
|
|
16
|
+
if (!["contentful", "sanity"].includes(cms)) {
|
|
17
|
+
console.error(`Invalid CMS provider: ${cms}`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const contentTypes = opts.types.split(",").map((s) => s.trim());
|
|
21
|
+
const store = new ContentStore(config.s3);
|
|
22
|
+
try {
|
|
23
|
+
const files = await fetchBundles(store, opts.output, {
|
|
24
|
+
cms,
|
|
25
|
+
contentTypes
|
|
26
|
+
});
|
|
27
|
+
console.log("Fetched bundles:");
|
|
28
|
+
for (const [type, filePath] of Object.entries(files)) {
|
|
29
|
+
console.log(` ${type} -> ${filePath}`);
|
|
34
30
|
}
|
|
31
|
+
} catch (err) {
|
|
32
|
+
console.error("Fetch failed:", err);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
35
|
});
|
|
36
36
|
program.parse();
|
|
37
37
|
//# sourceMappingURL=fetch-bundles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../../src/client/fetch-bundles.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { config, type CMSProvider } from './config';\nimport { ContentStore } from '../shared/s3';\nimport { fetchBundles } from '../shared/bundles';\n\nconst program = new Command();\n\nprogram\n .name('fetch-content-bundles')\n .description('Download latest 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 fetchBundles(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":";;;;;;;;;;;AACA,SAAS,eAAe;AAKxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,uBAAuB,EAC5B,YAAY,yDAAyD,EACrE,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,aAAa,OAAO,KAAK,QAAQ;AAAA,MACnD;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":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,88 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
+
/** content-{cms}-{contentType}-{timestamp}.json */
|
|
14
|
+
buildVersionedKey(cms: string, contentType: string, timestamp: number): string;
|
|
15
|
+
/** content-{cms}-{contentType}.json (always points at the latest version) */
|
|
16
|
+
buildLatestKey(cms: string, contentType: string): string;
|
|
17
|
+
upload(key: string, data: unknown): Promise<string>;
|
|
18
|
+
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
|
+
}
|
|
25
|
+
|
|
26
|
+
interface FetchBundlesOptions {
|
|
27
|
+
cms: CMSProvider;
|
|
28
|
+
contentTypes: string[];
|
|
29
|
+
}
|
|
30
|
+
interface QueryOptions {
|
|
31
|
+
/** Filter items by matching top-level property values (exact equality, or array for IN). */
|
|
32
|
+
fields?: Record<string, unknown>;
|
|
33
|
+
/** Properties to include in each result object. Omit to return all properties. */
|
|
34
|
+
select?: string[];
|
|
35
|
+
/** Maximum number of items to return. */
|
|
36
|
+
limit?: number;
|
|
37
|
+
/**
|
|
38
|
+
* How many levels deep to return.
|
|
39
|
+
* - 1 = the item's own scalar properties only; nested objects/refs are nulled.
|
|
40
|
+
* - 2 = the item including its direct references; refs inside those are nulled.
|
|
41
|
+
* - 3 = three levels deep, and so on.
|
|
42
|
+
* - Omit to return the full depth.
|
|
43
|
+
*/
|
|
44
|
+
include?: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Trims nested object depth.
|
|
48
|
+
*
|
|
49
|
+
* `remaining` represents how many levels the current object is allowed.
|
|
50
|
+
* - Scalar properties are always kept.
|
|
51
|
+
* - Nested objects / arrays-of-objects consume one level. When `remaining`
|
|
52
|
+
* drops to 1 they are replaced with `null` (no budget left for refs).
|
|
53
|
+
*/
|
|
54
|
+
declare function trimDepth(value: unknown, remaining: number): unknown;
|
|
55
|
+
/**
|
|
56
|
+
* Downloads the latest bundles from S3 and writes them as JSON files to `outputDir`.
|
|
57
|
+
*
|
|
58
|
+
* @returns A map of contentType to absolute file path.
|
|
59
|
+
*/
|
|
60
|
+
declare function fetchBundles(store: ContentStore, outputDir: string, options: FetchBundlesOptions): Promise<Record<string, string>>;
|
|
61
|
+
/**
|
|
62
|
+
* Queries a previously fetched bundle from the local filesystem.
|
|
63
|
+
*/
|
|
64
|
+
declare function queryBundle(outputDir: string, cms: CMSProvider, contentType: string, options?: QueryOptions): Promise<unknown[]>;
|
|
65
|
+
|
|
66
|
+
interface SDKConfig {
|
|
67
|
+
s3: S3Config;
|
|
68
|
+
/** Directory where bundle JSON files are saved on the local filesystem. */
|
|
69
|
+
outputDir: string;
|
|
70
|
+
}
|
|
71
|
+
declare class ContentStoreSDK {
|
|
72
|
+
private store;
|
|
73
|
+
private outputDir;
|
|
74
|
+
constructor(config: SDKConfig);
|
|
75
|
+
/**
|
|
76
|
+
* Downloads the latest bundles from S3 and writes them as JSON files
|
|
77
|
+
* to `outputDir`.
|
|
78
|
+
*
|
|
79
|
+
* @returns A map of contentType to absolute file path.
|
|
80
|
+
*/
|
|
81
|
+
fetchBundles(options: FetchBundlesOptions): Promise<Record<string, string>>;
|
|
82
|
+
/**
|
|
83
|
+
* Queries a previously fetched bundle from the local filesystem.
|
|
84
|
+
*/
|
|
85
|
+
queryBundle(cms: CMSProvider, contentType: string, options?: QueryOptions): Promise<unknown[]>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export { type CMSProvider, ContentStore, ContentStoreSDK, type FetchBundlesOptions, type QueryOptions, type S3Config, type SDKConfig, fetchBundles, queryBundle, trimDepth };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,183 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// src/shared/s3.ts
|
|
2
|
+
import {
|
|
3
|
+
S3Client,
|
|
4
|
+
PutObjectCommand,
|
|
5
|
+
CopyObjectCommand,
|
|
6
|
+
GetObjectCommand
|
|
7
|
+
} from "@aws-sdk/client-s3";
|
|
8
|
+
var ContentStore = class {
|
|
9
|
+
client;
|
|
10
|
+
bucket;
|
|
11
|
+
constructor(cfg) {
|
|
12
|
+
this.client = new S3Client({
|
|
13
|
+
region: cfg.region,
|
|
14
|
+
credentials: {
|
|
15
|
+
accessKeyId: cfg.accessKeyId,
|
|
16
|
+
secretAccessKey: cfg.secretAccessKey
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
this.bucket = cfg.bucket;
|
|
20
|
+
}
|
|
21
|
+
/** content-{cms}-{contentType}-{timestamp}.json */
|
|
22
|
+
buildVersionedKey(cms, contentType, timestamp) {
|
|
23
|
+
return `content-${cms}-${contentType}-${timestamp}.json`;
|
|
24
|
+
}
|
|
25
|
+
/** content-{cms}-{contentType}.json (always points at the latest version) */
|
|
26
|
+
buildLatestKey(cms, contentType) {
|
|
27
|
+
return `content-${cms}-${contentType}.json`;
|
|
28
|
+
}
|
|
29
|
+
async upload(key, data) {
|
|
30
|
+
await this.client.send(
|
|
31
|
+
new PutObjectCommand({
|
|
32
|
+
Bucket: this.bucket,
|
|
33
|
+
Key: key,
|
|
34
|
+
Body: JSON.stringify(data, null, 2),
|
|
35
|
+
ContentType: "application/json"
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
return key;
|
|
39
|
+
}
|
|
40
|
+
async download(key) {
|
|
41
|
+
const response = await this.client.send(
|
|
42
|
+
new GetObjectCommand({ Bucket: this.bucket, Key: key })
|
|
43
|
+
);
|
|
44
|
+
const body = await response.Body?.transformToString();
|
|
45
|
+
if (!body) throw new Error(`Empty response for key: ${key}`);
|
|
46
|
+
return JSON.parse(body);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Copies a versioned object to the "latest" key so that it always reflects
|
|
50
|
+
* the most recent sync while older timestamped versions are retained.
|
|
51
|
+
*/
|
|
52
|
+
async copyToLatest(sourceKey, cms, contentType) {
|
|
53
|
+
const latestKey = this.buildLatestKey(cms, contentType);
|
|
54
|
+
await this.client.send(
|
|
55
|
+
new CopyObjectCommand({
|
|
56
|
+
Bucket: this.bucket,
|
|
57
|
+
CopySource: `${this.bucket}/${sourceKey}`,
|
|
58
|
+
Key: latestKey,
|
|
59
|
+
ContentType: "application/json"
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
return latestKey;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// src/shared/bundles.ts
|
|
67
|
+
import fs from "fs/promises";
|
|
68
|
+
import path from "path";
|
|
69
|
+
function trimDepth(value, remaining) {
|
|
70
|
+
if (value === null || value === void 0 || typeof value !== "object") {
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
if (Array.isArray(value)) {
|
|
74
|
+
return value.map((item) => trimDepth(item, remaining));
|
|
75
|
+
}
|
|
76
|
+
const obj = value;
|
|
77
|
+
const result = {};
|
|
78
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
79
|
+
if (v === null || v === void 0 || typeof v !== "object") {
|
|
80
|
+
result[k] = v;
|
|
81
|
+
} else if (remaining <= 1) {
|
|
82
|
+
result[k] = null;
|
|
83
|
+
} else if (Array.isArray(v)) {
|
|
84
|
+
result[k] = v.map((item) => {
|
|
85
|
+
if (item !== null && typeof item === "object" && !Array.isArray(item)) {
|
|
86
|
+
return trimDepth(item, remaining - 1);
|
|
87
|
+
}
|
|
88
|
+
return item;
|
|
89
|
+
});
|
|
90
|
+
} else {
|
|
91
|
+
result[k] = trimDepth(v, remaining - 1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
async function fetchBundles(store, outputDir, options) {
|
|
97
|
+
const { cms, contentTypes } = options;
|
|
98
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
99
|
+
const result = {};
|
|
100
|
+
await Promise.all(
|
|
101
|
+
contentTypes.map(async (contentType) => {
|
|
102
|
+
const key = store.buildLatestKey(cms, contentType);
|
|
103
|
+
const data = await store.download(key);
|
|
104
|
+
const filePath = path.resolve(
|
|
105
|
+
outputDir,
|
|
106
|
+
`content-${cms}-${contentType}.json`
|
|
107
|
+
);
|
|
108
|
+
await fs.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
109
|
+
result[contentType] = filePath;
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
async function queryBundle(outputDir, cms, contentType, options = {}) {
|
|
115
|
+
const filePath = path.resolve(
|
|
116
|
+
outputDir,
|
|
117
|
+
`content-${cms}-${contentType}.json`
|
|
118
|
+
);
|
|
119
|
+
const raw = await fs.readFile(filePath, "utf-8");
|
|
120
|
+
let items = JSON.parse(raw);
|
|
121
|
+
if (options.fields) {
|
|
122
|
+
const filters = options.fields;
|
|
123
|
+
items = items.filter(
|
|
124
|
+
(item) => Object.entries(filters).every(([key, expected]) => {
|
|
125
|
+
const actual = item[key];
|
|
126
|
+
if (Array.isArray(expected)) return expected.includes(actual);
|
|
127
|
+
return actual === expected;
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
if (options.limit !== void 0 && options.limit > 0) {
|
|
132
|
+
items = items.slice(0, options.limit);
|
|
133
|
+
}
|
|
134
|
+
if (options.include !== void 0) {
|
|
135
|
+
items = items.map(
|
|
136
|
+
(item) => trimDepth(item, options.include)
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
if (options.select?.length) {
|
|
140
|
+
const keys = options.select;
|
|
141
|
+
items = items.map((item) => {
|
|
142
|
+
const picked = {};
|
|
143
|
+
for (const k of keys) {
|
|
144
|
+
if (k in item) picked[k] = item[k];
|
|
145
|
+
}
|
|
146
|
+
return picked;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return items;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/sdk/client.ts
|
|
153
|
+
var ContentStoreSDK = class {
|
|
154
|
+
store;
|
|
155
|
+
outputDir;
|
|
156
|
+
constructor(config) {
|
|
157
|
+
this.store = new ContentStore(config.s3);
|
|
158
|
+
this.outputDir = config.outputDir;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Downloads the latest bundles from S3 and writes them as JSON files
|
|
162
|
+
* to `outputDir`.
|
|
163
|
+
*
|
|
164
|
+
* @returns A map of contentType to absolute file path.
|
|
165
|
+
*/
|
|
166
|
+
async fetchBundles(options) {
|
|
167
|
+
return fetchBundles(this.store, this.outputDir, options);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Queries a previously fetched bundle from the local filesystem.
|
|
171
|
+
*/
|
|
172
|
+
async queryBundle(cms, contentType, options = {}) {
|
|
173
|
+
return queryBundle(this.outputDir, cms, contentType, options);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
export {
|
|
177
|
+
ContentStore,
|
|
178
|
+
ContentStoreSDK,
|
|
179
|
+
fetchBundles,
|
|
180
|
+
queryBundle,
|
|
181
|
+
trimDepth
|
|
182
|
+
};
|
|
4
183
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"sources":["../src/shared/s3.ts","../src/shared/bundles.ts","../src/sdk/client.ts"],"sourcesContent":["import {\n S3Client,\n PutObjectCommand,\n CopyObjectCommand,\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 /** content-{cms}-{contentType}-{timestamp}.json */\n buildVersionedKey(cms: string, contentType: string, timestamp: number): string {\n return `content-${cms}-${contentType}-${timestamp}.json`;\n }\n\n /** content-{cms}-{contentType}.json (always points at the latest version) */\n buildLatestKey(cms: string, contentType: string): string {\n return `content-${cms}-${contentType}.json`;\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 * Copies a versioned object to the \"latest\" key so that it always reflects\n * the most recent sync while older timestamped versions are retained.\n */\n async copyToLatest(\n sourceKey: string,\n cms: string,\n contentType: string,\n ): Promise<string> {\n const latestKey = this.buildLatestKey(cms, contentType);\n await this.client.send(\n new CopyObjectCommand({\n Bucket: this.bucket,\n CopySource: `${this.bucket}/${sourceKey}`,\n Key: latestKey,\n ContentType: 'application/json',\n }),\n );\n return latestKey;\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { CMSProvider } from './types';\nimport { ContentStore } from './s3';\n\nexport interface FetchBundlesOptions {\n cms: CMSProvider;\n contentTypes: string[];\n}\n\nexport interface QueryOptions {\n /** Filter items by matching top-level property values (exact equality, or array for IN). */\n fields?: Record<string, unknown>;\n /** Properties to include in each result object. Omit to return all properties. */\n select?: string[];\n /** Maximum number of items to return. */\n limit?: number;\n /**\n * How many levels deep to return.\n * - 1 = the item's own scalar properties only; nested objects/refs are nulled.\n * - 2 = the item including its direct references; refs inside those are nulled.\n * - 3 = three levels deep, and so on.\n * - Omit to return the full depth.\n */\n include?: number;\n}\n\n/**\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/**\n * Downloads the latest bundles from S3 and writes them as JSON files to `outputDir`.\n *\n * @returns A map of contentType to absolute file path.\n */\nexport async function fetchBundles(\n store: ContentStore,\n outputDir: string,\n options: FetchBundlesOptions,\n): Promise<Record<string, string>> {\n const { cms, contentTypes } = options;\n await fs.mkdir(outputDir, { recursive: true });\n\n const result: Record<string, string> = {};\n\n await Promise.all(\n contentTypes.map(async (contentType) => {\n const key = store.buildLatestKey(cms, contentType);\n const data = await store.download(key);\n const filePath = path.resolve(\n outputDir,\n `content-${cms}-${contentType}.json`,\n );\n await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');\n result[contentType] = filePath;\n }),\n );\n\n return result;\n}\n\n/**\n * Queries a previously fetched bundle from the local filesystem.\n */\nexport async function queryBundle(\n outputDir: string,\n cms: CMSProvider,\n contentType: string,\n options: QueryOptions = {},\n): Promise<unknown[]> {\n const filePath = path.resolve(\n outputDir,\n `content-${cms}-${contentType}.json`,\n );\n const raw = await fs.readFile(filePath, 'utf-8');\n let items = JSON.parse(raw) as Record<string, unknown>[];\n\n if (options.fields) {\n const filters = options.fields;\n items = items.filter((item) =>\n Object.entries(filters).every(([key, expected]) => {\n const actual = item[key];\n if (Array.isArray(expected)) return expected.includes(actual);\n return actual === expected;\n }),\n );\n }\n\n if (options.limit !== undefined && options.limit > 0) {\n items = items.slice(0, options.limit);\n }\n\n if (options.include !== undefined) {\n items = items.map(\n (item) => trimDepth(item, options.include!) as Record<string, unknown>,\n );\n }\n\n if (options.select?.length) {\n const keys = options.select;\n items = items.map((item) => {\n const picked: Record<string, unknown> = {};\n for (const k of keys) {\n if (k in item) picked[k] = item[k];\n }\n return picked;\n });\n }\n\n return items;\n}\n","import type { S3Config, CMSProvider } from '../shared/types';\nimport { ContentStore } from '../shared/s3';\nimport {\n fetchBundles,\n queryBundle,\n type FetchBundlesOptions,\n type QueryOptions,\n} from '../shared/bundles';\n\nexport type { FetchBundlesOptions, QueryOptions };\n\nexport interface SDKConfig {\n s3: S3Config;\n /** Directory where bundle JSON files are saved on the local filesystem. */\n outputDir: string;\n}\n\nexport class ContentStoreSDK {\n private store: ContentStore;\n private outputDir: string;\n\n constructor(config: SDKConfig) {\n this.store = new ContentStore(config.s3);\n this.outputDir = config.outputDir;\n }\n\n /**\n * Downloads the latest bundles from S3 and writes them as JSON files\n * to `outputDir`.\n *\n * @returns A map of contentType to absolute file path.\n */\n async fetchBundles(\n options: FetchBundlesOptions,\n ): Promise<Record<string, string>> {\n return fetchBundles(this.store, this.outputDir, options);\n }\n\n /**\n * Queries a previously fetched bundle from the local filesystem.\n */\n async queryBundle(\n cms: CMSProvider,\n contentType: string,\n options: QueryOptions = {},\n ): Promise<unknown[]> {\n return queryBundle(this.outputDir, cms, contentType, options);\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tandem-language-exchange/content-store",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"node": "^24.1.0"
|
|
25
25
|
},
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "
|
|
27
|
+
"build": "tsup",
|
|
28
28
|
"dev": "tsx watch src/server/cli.ts serve",
|
|
29
29
|
"start": "node dist/server/cli.js serve",
|
|
30
30
|
"sync": "tsx src/server/cli.ts sync",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"@tandem-web/web-azure-appconfig-sync": "1.0.9",
|
|
52
52
|
"@types/express": "^5.0.2",
|
|
53
53
|
"@types/node": "22.0.0",
|
|
54
|
+
"tsup": "^8.5.1",
|
|
54
55
|
"tsx": "^4.19.0",
|
|
55
56
|
"typescript": "^5.9.3"
|
|
56
57
|
}
|
package/dist/client/cli.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/client/config.d.ts
DELETED
package/dist/client/config.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/client/config.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,EAAe,MAAM,IAAI,YAAY,EAAC,MAAM,kBAAkB,CAAC;AAEtE,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;AACtC,MAAM,CAAC,MAAM,EAAE,CAAC;AAOhB,MAAM,CAAC,MAAM,MAAM,GAAgC;IAC/C,GAAG,YAAY;CAClB,CAAC"}
|
package/dist/sdk/client.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { S3Config, CMSProvider } from '../shared/types';
|
|
2
|
-
import { type FetchBundlesOptions, type QueryOptions } from '../shared/bundles';
|
|
3
|
-
export type { FetchBundlesOptions, QueryOptions };
|
|
4
|
-
export interface SDKConfig {
|
|
5
|
-
s3: S3Config;
|
|
6
|
-
/** Directory where bundle JSON files are saved on the local filesystem. */
|
|
7
|
-
outputDir: string;
|
|
8
|
-
}
|
|
9
|
-
export declare class ContentStoreSDK {
|
|
10
|
-
private store;
|
|
11
|
-
private outputDir;
|
|
12
|
-
constructor(config: SDKConfig);
|
|
13
|
-
/**
|
|
14
|
-
* Downloads the latest bundles from S3 and writes them as JSON files
|
|
15
|
-
* to `outputDir`.
|
|
16
|
-
*
|
|
17
|
-
* @returns A map of contentType to absolute file path.
|
|
18
|
-
*/
|
|
19
|
-
fetchBundles(options: FetchBundlesOptions): Promise<Record<string, string>>;
|
|
20
|
-
/**
|
|
21
|
-
* Queries a previously fetched bundle from the local filesystem.
|
|
22
|
-
*/
|
|
23
|
-
queryBundle(cms: CMSProvider, contentType: string, options?: QueryOptions): Promise<unknown[]>;
|
|
24
|
-
}
|
package/dist/sdk/client.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { ContentStore } from '../shared/s3';
|
|
2
|
-
import { fetchBundles, queryBundle, } from '../shared/bundles';
|
|
3
|
-
export class ContentStoreSDK {
|
|
4
|
-
store;
|
|
5
|
-
outputDir;
|
|
6
|
-
constructor(config) {
|
|
7
|
-
this.store = new ContentStore(config.s3);
|
|
8
|
-
this.outputDir = config.outputDir;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Downloads the latest bundles from S3 and writes them as JSON files
|
|
12
|
-
* to `outputDir`.
|
|
13
|
-
*
|
|
14
|
-
* @returns A map of contentType to absolute file path.
|
|
15
|
-
*/
|
|
16
|
-
async fetchBundles(options) {
|
|
17
|
-
return fetchBundles(this.store, this.outputDir, options);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Queries a previously fetched bundle from the local filesystem.
|
|
21
|
-
*/
|
|
22
|
-
async queryBundle(cms, contentType, options = {}) {
|
|
23
|
-
return queryBundle(this.outputDir, cms, contentType, options);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=client.js.map
|
package/dist/sdk/client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/sdk/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EACL,YAAY,EACZ,WAAW,GAGZ,MAAM,mBAAmB,CAAC;AAU3B,MAAM,OAAO,eAAe;IAClB,KAAK,CAAe;IACpB,SAAS,CAAS;IAE1B,YAAY,MAAiB;QAC3B,IAAI,CAAC,KAAK,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACpC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAChB,OAA4B;QAE5B,OAAO,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CACf,GAAgB,EAChB,WAAmB,EACnB,UAAwB,EAAE;QAE1B,OAAO,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAChE,CAAC;CACF"}
|
package/dist/sdk/index.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { ContentStoreSDK } from './client';
|
|
2
|
-
export type { SDKConfig, FetchBundlesOptions, QueryOptions } from './client';
|
|
3
|
-
export { fetchBundles, queryBundle, trimDepth } from '../shared/bundles';
|
|
4
|
-
export { ContentStore } from '../shared/s3';
|
|
5
|
-
export type { S3Config, CMSProvider } from '../shared/types';
|
package/dist/sdk/index.js
DELETED
package/dist/sdk/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/shared/bundles.d.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { CMSProvider } from './types';
|
|
2
|
-
import { ContentStore } from './s3';
|
|
3
|
-
export interface FetchBundlesOptions {
|
|
4
|
-
cms: CMSProvider;
|
|
5
|
-
contentTypes: string[];
|
|
6
|
-
}
|
|
7
|
-
export interface QueryOptions {
|
|
8
|
-
/** Filter items by matching top-level property values (exact equality, or array for IN). */
|
|
9
|
-
fields?: Record<string, unknown>;
|
|
10
|
-
/** Properties to include in each result object. Omit to return all properties. */
|
|
11
|
-
select?: string[];
|
|
12
|
-
/** Maximum number of items to return. */
|
|
13
|
-
limit?: number;
|
|
14
|
-
/**
|
|
15
|
-
* How many levels deep to return.
|
|
16
|
-
* - 1 = the item's own scalar properties only; nested objects/refs are nulled.
|
|
17
|
-
* - 2 = the item including its direct references; refs inside those are nulled.
|
|
18
|
-
* - 3 = three levels deep, and so on.
|
|
19
|
-
* - Omit to return the full depth.
|
|
20
|
-
*/
|
|
21
|
-
include?: number;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Trims nested object depth.
|
|
25
|
-
*
|
|
26
|
-
* `remaining` represents how many levels the current object is allowed.
|
|
27
|
-
* - Scalar properties are always kept.
|
|
28
|
-
* - Nested objects / arrays-of-objects consume one level. When `remaining`
|
|
29
|
-
* drops to 1 they are replaced with `null` (no budget left for refs).
|
|
30
|
-
*/
|
|
31
|
-
export declare function trimDepth(value: unknown, remaining: number): unknown;
|
|
32
|
-
/**
|
|
33
|
-
* Downloads the latest bundles from S3 and writes them as JSON files to `outputDir`.
|
|
34
|
-
*
|
|
35
|
-
* @returns A map of contentType to absolute file path.
|
|
36
|
-
*/
|
|
37
|
-
export declare function fetchBundles(store: ContentStore, outputDir: string, options: FetchBundlesOptions): Promise<Record<string, string>>;
|
|
38
|
-
/**
|
|
39
|
-
* Queries a previously fetched bundle from the local filesystem.
|
|
40
|
-
*/
|
|
41
|
-
export declare function queryBundle(outputDir: string, cms: CMSProvider, contentType: string, options?: QueryOptions): Promise<unknown[]>;
|
package/dist/shared/bundles.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
/**
|
|
4
|
-
* Trims nested object depth.
|
|
5
|
-
*
|
|
6
|
-
* `remaining` represents how many levels the current object is allowed.
|
|
7
|
-
* - Scalar properties are always kept.
|
|
8
|
-
* - Nested objects / arrays-of-objects consume one level. When `remaining`
|
|
9
|
-
* drops to 1 they are replaced with `null` (no budget left for refs).
|
|
10
|
-
*/
|
|
11
|
-
export function trimDepth(value, remaining) {
|
|
12
|
-
if (value === null || value === undefined || typeof value !== 'object') {
|
|
13
|
-
return value;
|
|
14
|
-
}
|
|
15
|
-
if (Array.isArray(value)) {
|
|
16
|
-
return value.map((item) => trimDepth(item, remaining));
|
|
17
|
-
}
|
|
18
|
-
const obj = value;
|
|
19
|
-
const result = {};
|
|
20
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
21
|
-
if (v === null || v === undefined || typeof v !== 'object') {
|
|
22
|
-
result[k] = v;
|
|
23
|
-
}
|
|
24
|
-
else if (remaining <= 1) {
|
|
25
|
-
result[k] = null;
|
|
26
|
-
}
|
|
27
|
-
else if (Array.isArray(v)) {
|
|
28
|
-
result[k] = v.map((item) => {
|
|
29
|
-
if (item !== null && typeof item === 'object' && !Array.isArray(item)) {
|
|
30
|
-
return trimDepth(item, remaining - 1);
|
|
31
|
-
}
|
|
32
|
-
return item;
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
result[k] = trimDepth(v, remaining - 1);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return result;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Downloads the latest bundles from S3 and writes them as JSON files to `outputDir`.
|
|
43
|
-
*
|
|
44
|
-
* @returns A map of contentType to absolute file path.
|
|
45
|
-
*/
|
|
46
|
-
export async function fetchBundles(store, outputDir, options) {
|
|
47
|
-
const { cms, contentTypes } = options;
|
|
48
|
-
await fs.mkdir(outputDir, { recursive: true });
|
|
49
|
-
const result = {};
|
|
50
|
-
await Promise.all(contentTypes.map(async (contentType) => {
|
|
51
|
-
const key = store.buildLatestKey(cms, contentType);
|
|
52
|
-
const data = await store.download(key);
|
|
53
|
-
const filePath = path.resolve(outputDir, `content-${cms}-${contentType}.json`);
|
|
54
|
-
await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
55
|
-
result[contentType] = filePath;
|
|
56
|
-
}));
|
|
57
|
-
return result;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Queries a previously fetched bundle from the local filesystem.
|
|
61
|
-
*/
|
|
62
|
-
export async function queryBundle(outputDir, cms, contentType, options = {}) {
|
|
63
|
-
const filePath = path.resolve(outputDir, `content-${cms}-${contentType}.json`);
|
|
64
|
-
const raw = await fs.readFile(filePath, 'utf-8');
|
|
65
|
-
let items = JSON.parse(raw);
|
|
66
|
-
if (options.fields) {
|
|
67
|
-
const filters = options.fields;
|
|
68
|
-
items = items.filter((item) => Object.entries(filters).every(([key, expected]) => {
|
|
69
|
-
const actual = item[key];
|
|
70
|
-
if (Array.isArray(expected))
|
|
71
|
-
return expected.includes(actual);
|
|
72
|
-
return actual === expected;
|
|
73
|
-
}));
|
|
74
|
-
}
|
|
75
|
-
if (options.limit !== undefined && options.limit > 0) {
|
|
76
|
-
items = items.slice(0, options.limit);
|
|
77
|
-
}
|
|
78
|
-
if (options.include !== undefined) {
|
|
79
|
-
items = items.map((item) => trimDepth(item, options.include));
|
|
80
|
-
}
|
|
81
|
-
if (options.select?.length) {
|
|
82
|
-
const keys = options.select;
|
|
83
|
-
items = items.map((item) => {
|
|
84
|
-
const picked = {};
|
|
85
|
-
for (const k of keys) {
|
|
86
|
-
if (k in item)
|
|
87
|
-
picked[k] = item[k];
|
|
88
|
-
}
|
|
89
|
-
return picked;
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
return items;
|
|
93
|
-
}
|
|
94
|
-
//# sourceMappingURL=bundles.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bundles.js","sourceRoot":"","sources":["../../src/shared/bundles.ts"],"names":[],"mappings":"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"}
|
package/dist/shared/config.d.ts
DELETED
package/dist/shared/config.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import dotenv from 'dotenv';
|
|
2
|
-
dotenv.config({ path: '.env.local' });
|
|
3
|
-
dotenv.config();
|
|
4
|
-
export const config = {
|
|
5
|
-
s3: {
|
|
6
|
-
bucket: process.env.CONTENT_STORE_S3_BUCKET ?? '',
|
|
7
|
-
region: process.env.CONTENT_STORE_S3_REGION ?? 'eu-central-1',
|
|
8
|
-
accessKeyId: process.env.AWS_ACCESS_KEY ?? '',
|
|
9
|
-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? '',
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
//# sourceMappingURL=config.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/shared/config.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;AACtC,MAAM,CAAC,MAAM,EAAE,CAAC;AAQhB,MAAM,CAAC,MAAM,MAAM,GAAiB;IAChC,EAAE,EAAE;QACA,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,EAAE;QACjD,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,cAAc;QAC7D,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE;QAC7C,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE;KAC3D;CACJ,CAAC"}
|
package/dist/shared/s3.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { S3Config } from './types';
|
|
2
|
-
export declare class ContentStore {
|
|
3
|
-
private client;
|
|
4
|
-
private bucket;
|
|
5
|
-
constructor(cfg: S3Config);
|
|
6
|
-
/** content-{cms}-{contentType}-{timestamp}.json */
|
|
7
|
-
buildVersionedKey(cms: string, contentType: string, timestamp: number): string;
|
|
8
|
-
/** content-{cms}-{contentType}.json (always points at the latest version) */
|
|
9
|
-
buildLatestKey(cms: string, contentType: string): string;
|
|
10
|
-
upload(key: string, data: unknown): Promise<string>;
|
|
11
|
-
download(key: string): Promise<unknown>;
|
|
12
|
-
/**
|
|
13
|
-
* Copies a versioned object to the "latest" key so that it always reflects
|
|
14
|
-
* the most recent sync while older timestamped versions are retained.
|
|
15
|
-
*/
|
|
16
|
-
copyToLatest(sourceKey: string, cms: string, contentType: string): Promise<string>;
|
|
17
|
-
}
|
package/dist/shared/s3.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { S3Client, PutObjectCommand, CopyObjectCommand, GetObjectCommand, } from '@aws-sdk/client-s3';
|
|
2
|
-
export class ContentStore {
|
|
3
|
-
client;
|
|
4
|
-
bucket;
|
|
5
|
-
constructor(cfg) {
|
|
6
|
-
this.client = new S3Client({
|
|
7
|
-
region: cfg.region,
|
|
8
|
-
credentials: {
|
|
9
|
-
accessKeyId: cfg.accessKeyId,
|
|
10
|
-
secretAccessKey: cfg.secretAccessKey,
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
this.bucket = cfg.bucket;
|
|
14
|
-
}
|
|
15
|
-
/** content-{cms}-{contentType}-{timestamp}.json */
|
|
16
|
-
buildVersionedKey(cms, contentType, timestamp) {
|
|
17
|
-
return `content-${cms}-${contentType}-${timestamp}.json`;
|
|
18
|
-
}
|
|
19
|
-
/** content-{cms}-{contentType}.json (always points at the latest version) */
|
|
20
|
-
buildLatestKey(cms, contentType) {
|
|
21
|
-
return `content-${cms}-${contentType}.json`;
|
|
22
|
-
}
|
|
23
|
-
async upload(key, data) {
|
|
24
|
-
await this.client.send(new PutObjectCommand({
|
|
25
|
-
Bucket: this.bucket,
|
|
26
|
-
Key: key,
|
|
27
|
-
Body: JSON.stringify(data, null, 2),
|
|
28
|
-
ContentType: 'application/json',
|
|
29
|
-
}));
|
|
30
|
-
return key;
|
|
31
|
-
}
|
|
32
|
-
async download(key) {
|
|
33
|
-
const response = await this.client.send(new GetObjectCommand({ Bucket: this.bucket, Key: key }));
|
|
34
|
-
const body = await response.Body?.transformToString();
|
|
35
|
-
if (!body)
|
|
36
|
-
throw new Error(`Empty response for key: ${key}`);
|
|
37
|
-
return JSON.parse(body);
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Copies a versioned object to the "latest" key so that it always reflects
|
|
41
|
-
* the most recent sync while older timestamped versions are retained.
|
|
42
|
-
*/
|
|
43
|
-
async copyToLatest(sourceKey, cms, contentType) {
|
|
44
|
-
const latestKey = this.buildLatestKey(cms, contentType);
|
|
45
|
-
await this.client.send(new CopyObjectCommand({
|
|
46
|
-
Bucket: this.bucket,
|
|
47
|
-
CopySource: `${this.bucket}/${sourceKey}`,
|
|
48
|
-
Key: latestKey,
|
|
49
|
-
ContentType: 'application/json',
|
|
50
|
-
}));
|
|
51
|
-
return latestKey;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=s3.js.map
|
package/dist/shared/s3.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../../src/shared/s3.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,OAAO,YAAY;IACf,MAAM,CAAW;IACjB,MAAM,CAAS;IAEvB,YAAY,GAAa;QACvB,IAAI,CAAC,MAAM,GAAG,IAAI,QAAQ,CAAC;YACzB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,WAAW,EAAE;gBACX,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,eAAe,EAAE,GAAG,CAAC,eAAe;aACrC;SACF,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,mDAAmD;IACnD,iBAAiB,CAAC,GAAW,EAAE,WAAmB,EAAE,SAAiB;QACnE,OAAO,WAAW,GAAG,IAAI,WAAW,IAAI,SAAS,OAAO,CAAC;IAC3D,CAAC;IAED,8EAA8E;IAC9E,cAAc,CAAC,GAAW,EAAE,WAAmB;QAC7C,OAAO,WAAW,GAAG,IAAI,WAAW,OAAO,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW,EAAE,IAAa;QACrC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,gBAAgB,CAAC;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,GAAG,EAAE,GAAG;YACR,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACnC,WAAW,EAAE,kBAAkB;SAChC,CAAC,CACH,CAAC;QACF,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,GAAW;QACxB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACrC,IAAI,gBAAgB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CACxD,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,iBAAiB,EAAE,CAAC;QACtD,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,EAAE,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,YAAY,CAChB,SAAiB,EACjB,GAAW,EACX,WAAmB;QAEnB,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QACxD,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,iBAAiB,CAAC;YACpB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,UAAU,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,SAAS,EAAE;YACzC,GAAG,EAAE,SAAS;YACd,WAAW,EAAE,kBAAkB;SAChC,CAAC,CACH,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { CMSProvider } from '../config.js';
|
|
2
|
-
export interface SyncResultEntry {
|
|
3
|
-
contentType: string;
|
|
4
|
-
itemCount: number;
|
|
5
|
-
versionedKey: string;
|
|
6
|
-
latestKey: string;
|
|
7
|
-
}
|
|
8
|
-
export interface SyncResult {
|
|
9
|
-
cms: CMSProvider;
|
|
10
|
-
timestamp: number;
|
|
11
|
-
entries: SyncResultEntry[];
|
|
12
|
-
errors: Array<{
|
|
13
|
-
contentType: string;
|
|
14
|
-
error: string;
|
|
15
|
-
}>;
|
|
16
|
-
}
|
|
17
|
-
export declare function runSync(cms: CMSProvider, contentTypes?: string[]): Promise<SyncResult>;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { config } from '../config.js';
|
|
2
|
-
import { createAdapter } from '../adapters/index.js';
|
|
3
|
-
import { ContentStore } from '../../shared/s3.js';
|
|
4
|
-
export async function runSync(cms, contentTypes) {
|
|
5
|
-
const adapter = createAdapter(cms);
|
|
6
|
-
const store = new ContentStore(config.s3);
|
|
7
|
-
const timestamp = Math.floor(Date.now() / 1000);
|
|
8
|
-
console.log(`\nStarting sync from ${cms} at ${new Date(timestamp * 1000).toISOString()}`);
|
|
9
|
-
const typesToSync = contentTypes && contentTypes.length > 0
|
|
10
|
-
? contentTypes
|
|
11
|
-
: await adapter.getContentTypes();
|
|
12
|
-
console.log(`Content types to sync: ${typesToSync.join(', ')}\n`);
|
|
13
|
-
const entries = [];
|
|
14
|
-
const errors = [];
|
|
15
|
-
for (const contentType of typesToSync) {
|
|
16
|
-
try {
|
|
17
|
-
const result = await adapter.fetchAll(contentType);
|
|
18
|
-
const versionedKey = store.buildVersionedKey(cms, contentType, timestamp);
|
|
19
|
-
await store.upload(versionedKey, result.items);
|
|
20
|
-
const latestKey = await store.copyToLatest(versionedKey, cms, contentType);
|
|
21
|
-
entries.push({
|
|
22
|
-
contentType,
|
|
23
|
-
itemCount: result.total,
|
|
24
|
-
versionedKey,
|
|
25
|
-
latestKey,
|
|
26
|
-
});
|
|
27
|
-
console.log(` + ${contentType}: ${result.total} items -> ${versionedKey}`);
|
|
28
|
-
}
|
|
29
|
-
catch (err) {
|
|
30
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
31
|
-
errors.push({ contentType, error: message });
|
|
32
|
-
console.error(` x ${contentType}: ${message}`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
console.log(`\nSync complete: ${entries.length} succeeded, ${errors.length} failed\n`);
|
|
36
|
-
return { cms, timestamp, entries, errors };
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=engine.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/shared/sync/engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAgBlD,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAgB,EAChB,YAAuB;IAEvB,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAEhD,OAAO,CAAC,GAAG,CAAC,wBAAwB,GAAG,OAAO,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAE1F,MAAM,WAAW,GACf,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC;QACrC,CAAC,CAAC,YAAY;QACd,CAAC,CAAC,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC;IAEtC,OAAO,CAAC,GAAG,CAAC,0BAA0B,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAElE,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,MAAM,MAAM,GAAkD,EAAE,CAAC;IAEjE,KAAK,MAAM,WAAW,IAAI,WAAW,EAAE,CAAC;QACtC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAEnD,MAAM,YAAY,GAAG,KAAK,CAAC,iBAAiB,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;YAC1E,MAAM,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAE/C,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;YAE3E,OAAO,CAAC,IAAI,CAAC;gBACX,WAAW;gBACX,SAAS,EAAE,MAAM,CAAC,KAAK;gBACvB,YAAY;gBACZ,SAAS;aACV,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CACT,OAAO,WAAW,KAAK,MAAM,CAAC,KAAK,aAAa,YAAY,EAAE,CAC/D,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YAC7C,OAAO,CAAC,KAAK,CAAC,OAAO,WAAW,KAAK,OAAO,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CACT,oBAAoB,OAAO,CAAC,MAAM,eAAe,MAAM,CAAC,MAAM,WAAW,CAC1E,CAAC;IAEF,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { RetryConfig } from '../config.js';
|
|
2
|
-
/**
|
|
3
|
-
* Executes `fn` with automatic retry + exponential backoff.
|
|
4
|
-
* Rate-limit (429) responses are handled specially: if the API provides a
|
|
5
|
-
* Retry-After / reset header, that value is respected instead of computed backoff.
|
|
6
|
-
*/
|
|
7
|
-
export declare function withRetry<T>(fn: () => Promise<T>, { maxRetries, baseDelayMs, maxDelayMs }: RetryConfig): Promise<T>;
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Inspects an error to determine if it represents an API rate-limit (HTTP 429).
|
|
3
|
-
* Returns the suggested wait time in ms when available, otherwise `0` to signal
|
|
4
|
-
* that the caller should fall back to computed backoff. Returns `null` when the
|
|
5
|
-
* error is *not* a rate-limit error.
|
|
6
|
-
*/
|
|
7
|
-
function rateLimitDelayMs(err) {
|
|
8
|
-
const e = err;
|
|
9
|
-
if (e?.status === 429 || e?.statusCode === 429) {
|
|
10
|
-
const reset = e?.headers?.['x-contentful-ratelimit-reset'];
|
|
11
|
-
return reset ? parseFloat(reset) * 1000 : 0;
|
|
12
|
-
}
|
|
13
|
-
const resp = e?.response;
|
|
14
|
-
if (resp?.status === 429) {
|
|
15
|
-
const headers = resp?.headers;
|
|
16
|
-
const reset = headers?.['x-contentful-ratelimit-reset'];
|
|
17
|
-
return reset ? parseFloat(reset) * 1000 : 0;
|
|
18
|
-
}
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
function computeDelay(attempt, baseDelayMs, maxDelayMs) {
|
|
22
|
-
const exponential = baseDelayMs * Math.pow(2, attempt);
|
|
23
|
-
const jitter = Math.random() * baseDelayMs;
|
|
24
|
-
return Math.min(exponential + jitter, maxDelayMs);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Executes `fn` with automatic retry + exponential backoff.
|
|
28
|
-
* Rate-limit (429) responses are handled specially: if the API provides a
|
|
29
|
-
* Retry-After / reset header, that value is respected instead of computed backoff.
|
|
30
|
-
*/
|
|
31
|
-
export async function withRetry(fn, { maxRetries, baseDelayMs, maxDelayMs }) {
|
|
32
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
33
|
-
try {
|
|
34
|
-
return await fn();
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
if (attempt === maxRetries)
|
|
38
|
-
throw err;
|
|
39
|
-
const rlDelay = rateLimitDelayMs(err);
|
|
40
|
-
let delay;
|
|
41
|
-
if (rlDelay !== null) {
|
|
42
|
-
delay =
|
|
43
|
-
rlDelay > 0 ? rlDelay : computeDelay(attempt, baseDelayMs, maxDelayMs);
|
|
44
|
-
console.warn(` Rate limited (attempt ${attempt + 1}/${maxRetries}). ` +
|
|
45
|
-
`Waiting ${Math.round(delay)}ms…`);
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
delay = computeDelay(attempt, baseDelayMs, maxDelayMs);
|
|
49
|
-
console.warn(` Request failed (attempt ${attempt + 1}/${maxRetries}): ` +
|
|
50
|
-
`${err.message}. Retrying in ${Math.round(delay)}ms…`);
|
|
51
|
-
}
|
|
52
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
throw new Error('withRetry: unreachable');
|
|
56
|
-
}
|
|
57
|
-
//# sourceMappingURL=retry.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../src/shared/sync/retry.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,GAAY;IACpC,MAAM,CAAC,GAAG,GAA8B,CAAC;IAEzC,IAAI,CAAC,EAAE,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,UAAU,KAAK,GAAG,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAI,CAAC,EAAE,OAA8C,EAAE,CAChE,8BAA8B,CAC/B,CAAC;QACF,OAAO,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,EAAE,QAA+C,CAAC;IAChE,IAAI,IAAI,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,EAAE,OAA6C,CAAC;QACpE,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC,8BAA8B,CAAC,CAAC;QACxD,OAAO,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CACnB,OAAe,EACf,WAAmB,EACnB,UAAkB;IAElB,MAAM,WAAW,GAAG,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC;IAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,MAAM,EAAE,UAAU,CAAC,CAAC;AACpD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAoB,EACpB,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAe;IAEpD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,OAAO,KAAK,UAAU;gBAAE,MAAM,GAAG,CAAC;YAEtC,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACtC,IAAI,KAAa,CAAC;YAElB,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,KAAK;oBACH,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;gBACzE,OAAO,CAAC,IAAI,CACV,2BAA2B,OAAO,GAAG,CAAC,IAAI,UAAU,KAAK;oBACvD,WAAW,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CACpC,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,KAAK,GAAG,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;gBACvD,OAAO,CAAC,IAAI,CACV,6BAA6B,OAAO,GAAG,CAAC,IAAI,UAAU,KAAK;oBACzD,GAAI,GAAa,CAAC,OAAO,iBAAiB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CACnE,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;AAC5C,CAAC"}
|
package/dist/shared/types.d.ts
DELETED
package/dist/shared/types.js
DELETED
package/dist/shared/types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":""}
|