@contentstorage/core 1.0.2 → 1.1.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/dist/contentstorage-config.d.ts +1 -0
- package/dist/contentstorage-config.js +1 -0
- package/dist/index.js +2 -1
- package/dist/lib/contentManagement.d.ts +1 -1
- package/dist/lib/functions/fetchContent.d.ts +6 -1
- package/dist/lib/functions/fetchContent.js +24 -4
- package/dist/scripts/generate-types.js +21 -4
- package/dist/scripts/pull-content.js +54 -5
- package/dist/types.d.ts +1 -8
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CONTENTSTORAGE_CONFIG } from './contentstorage-config.js';
|
|
1
2
|
import { setContentLanguage, getText, getImage, getVariation, initContentStorage, } from './lib/contentManagement.js';
|
|
2
3
|
import { fetchContent } from './lib/functions/fetchContent.js';
|
|
3
4
|
export { initContentStorage, fetchContent, setContentLanguage, getText, getImage, getVariation, liveEditorReady, };
|
|
@@ -24,7 +25,7 @@ function liveEditorReady(retries = 2, delay = 3000) {
|
|
|
24
25
|
resolve(false);
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
27
|
-
const cdnScriptUrl =
|
|
28
|
+
const cdnScriptUrl = `${CONTENTSTORAGE_CONFIG.BASE_URL}/live-editor.js?contentstorage-live-editor=true`;
|
|
28
29
|
const loadScript = (attempt = 1) => {
|
|
29
30
|
console.log(`Attempting to load Contentstorage live editor script (attempt ${attempt}/${retries})`);
|
|
30
31
|
const scriptElement = document.createElement('script');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AppConfig, ContentStructure, GetImageReturn, GetTextReturn, GetVariationReturn, LanguageCode } from '../types.js';
|
|
2
2
|
export declare let activeContent: object | null;
|
|
3
|
-
export declare let appConfig: Pick<AppConfig, 'contentKey' | 'languageCodes'> | null;
|
|
3
|
+
export declare let appConfig: Pick<AppConfig, 'contentKey' | 'languageCodes' | 'pendingChanges'> | null;
|
|
4
4
|
/**
|
|
5
5
|
* Loads and sets the content for a specific language.
|
|
6
6
|
* It will internally ensure the application configuration (for contentDir) is loaded.
|
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
import { LanguageCode } from '../../types.js';
|
|
2
|
-
|
|
2
|
+
interface FetchContentOptions {
|
|
3
|
+
withPendingChanges?: boolean;
|
|
4
|
+
contentKey?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function fetchContent(language?: LanguageCode, options?: FetchContentOptions): Promise<void>;
|
|
7
|
+
export {};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { CONTENTSTORAGE_CONFIG } from '../../contentstorage-config.js';
|
|
3
3
|
import { appConfig, setContentLanguage } from '../contentManagement.js';
|
|
4
|
-
export async function fetchContent(language) {
|
|
4
|
+
export async function fetchContent(language, options = {}) {
|
|
5
|
+
const { withPendingChanges, contentKey } = options;
|
|
5
6
|
const languageToFetch = language || appConfig?.languageCodes?.[0];
|
|
7
|
+
const usePendingChangesToFetch = withPendingChanges || appConfig?.pendingChanges;
|
|
6
8
|
console.log(`Starting content fetch for language ${language}...`);
|
|
7
9
|
if (!languageToFetch) {
|
|
8
10
|
throw Error(`No language found`);
|
|
@@ -10,11 +12,29 @@ export async function fetchContent(language) {
|
|
|
10
12
|
if (!appConfig) {
|
|
11
13
|
throw Error(`No app config found`);
|
|
12
14
|
}
|
|
13
|
-
const
|
|
15
|
+
const effectiveContentKey = contentKey || appConfig.contentKey;
|
|
16
|
+
let fileUrl;
|
|
17
|
+
let requestConfig = {};
|
|
18
|
+
if (usePendingChangesToFetch) {
|
|
19
|
+
if (!effectiveContentKey) {
|
|
20
|
+
throw Error(`No contentKey found`);
|
|
21
|
+
}
|
|
22
|
+
fileUrl = `${CONTENTSTORAGE_CONFIG.API_URL}/pending-changes/get-json?languageCode=${languageToFetch}`;
|
|
23
|
+
requestConfig.headers = {
|
|
24
|
+
'X-Content-Key': effectiveContentKey,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
fileUrl = `${CONTENTSTORAGE_CONFIG.BASE_URL}/${effectiveContentKey}/content/${languageToFetch}.json`;
|
|
29
|
+
}
|
|
14
30
|
try {
|
|
15
31
|
// Fetch data for the current language
|
|
16
|
-
const response = await axios.get(fileUrl);
|
|
17
|
-
|
|
32
|
+
const response = await axios.get(fileUrl, requestConfig);
|
|
33
|
+
let jsonData = response.data;
|
|
34
|
+
// Handle API response structure - only for pending changes API
|
|
35
|
+
if (usePendingChangesToFetch && jsonData && typeof jsonData === 'object' && 'data' in jsonData) {
|
|
36
|
+
jsonData = jsonData.data;
|
|
37
|
+
}
|
|
18
38
|
if (jsonData === undefined || jsonData === null) {
|
|
19
39
|
throw new Error(`No data received from ${fileUrl} for language ${languageToFetch}.`);
|
|
20
40
|
}
|
|
@@ -17,7 +17,10 @@ export async function generateTypes() {
|
|
|
17
17
|
if (arg.startsWith('--')) {
|
|
18
18
|
const key = arg.substring(2);
|
|
19
19
|
const value = args[i + 1];
|
|
20
|
-
if (
|
|
20
|
+
if (key === 'pending-changes') {
|
|
21
|
+
cliConfig.pendingChanges = true;
|
|
22
|
+
}
|
|
23
|
+
else if (value && !value.startsWith('--')) {
|
|
21
24
|
if (key === 'lang') {
|
|
22
25
|
cliConfig.languageCodes = [value.toUpperCase()];
|
|
23
26
|
}
|
|
@@ -103,12 +106,26 @@ export async function generateTypes() {
|
|
|
103
106
|
if (!config.contentKey) {
|
|
104
107
|
throw new Error('Cannot generate types: contentKey is missing');
|
|
105
108
|
}
|
|
106
|
-
|
|
109
|
+
let fileUrl;
|
|
110
|
+
const requestConfig = { responseType: 'json' };
|
|
111
|
+
if (config.pendingChanges) {
|
|
112
|
+
fileUrl = `${CONTENTSTORAGE_CONFIG.API_URL}/pending-changes/get-json?languageCode=${firstLanguageCode}`;
|
|
113
|
+
requestConfig.headers = {
|
|
114
|
+
'X-Content-Key': config.contentKey,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
fileUrl = `${CONTENTSTORAGE_CONFIG.BASE_URL}/${config.contentKey}/content/${firstLanguageCode}.json`;
|
|
119
|
+
}
|
|
107
120
|
dataSourceDescription = `remote URL (${fileUrl})`;
|
|
108
121
|
console.log(chalk.blue(`Attempting to fetch JSON from: ${fileUrl}`));
|
|
109
122
|
try {
|
|
110
|
-
const response = await axios.get(fileUrl,
|
|
111
|
-
|
|
123
|
+
const response = await axios.get(fileUrl, requestConfig);
|
|
124
|
+
let jsonResponse = response.data;
|
|
125
|
+
// Handle API response structure - API returns { data: actualContent }
|
|
126
|
+
if (config.pendingChanges && jsonResponse && typeof jsonResponse === 'object' && 'data' in jsonResponse) {
|
|
127
|
+
jsonResponse = jsonResponse.data;
|
|
128
|
+
}
|
|
112
129
|
console.log(chalk.blue('Flattening JSON for type generation'));
|
|
113
130
|
jsonObject = flattenJson(jsonResponse);
|
|
114
131
|
if (typeof jsonObject !== 'object' || jsonObject === null) {
|
|
@@ -7,13 +7,48 @@ import { loadConfig } from '../lib/configLoader.js';
|
|
|
7
7
|
import { CONTENTSTORAGE_CONFIG } from '../contentstorage-config.js';
|
|
8
8
|
export async function pullContent() {
|
|
9
9
|
console.log(chalk.blue('Starting content pull...'));
|
|
10
|
-
|
|
11
|
-
const
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const cliConfig = {};
|
|
12
|
+
for (let i = 0; i < args.length; i++) {
|
|
13
|
+
const arg = args[i];
|
|
14
|
+
if (arg.startsWith('--')) {
|
|
15
|
+
const key = arg.substring(2);
|
|
16
|
+
const value = args[i + 1];
|
|
17
|
+
if (key === 'pending-changes') {
|
|
18
|
+
cliConfig.pendingChanges = true;
|
|
19
|
+
}
|
|
20
|
+
else if (value && !value.startsWith('--')) {
|
|
21
|
+
if (key === 'lang') {
|
|
22
|
+
cliConfig.languageCodes = [value.toUpperCase()];
|
|
23
|
+
}
|
|
24
|
+
else if (key === 'content-key') {
|
|
25
|
+
cliConfig.contentKey = value;
|
|
26
|
+
}
|
|
27
|
+
else if (key === 'content-dir') {
|
|
28
|
+
cliConfig.contentDir = value;
|
|
29
|
+
}
|
|
30
|
+
// Skip the value in the next iteration
|
|
31
|
+
i++;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
let fileConfig = {};
|
|
36
|
+
try {
|
|
37
|
+
fileConfig = await loadConfig();
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
console.log(chalk.yellow('Could not load a configuration file. Proceeding with CLI arguments.'));
|
|
41
|
+
}
|
|
42
|
+
const config = { ...fileConfig, ...cliConfig };
|
|
12
43
|
// Validate required fields
|
|
13
44
|
if (!config.contentKey) {
|
|
14
45
|
console.error(chalk.red('Error: Configuration is missing the required "contentKey" property.'));
|
|
15
46
|
process.exit(1);
|
|
16
47
|
}
|
|
48
|
+
if (!config.contentDir) {
|
|
49
|
+
console.error(chalk.red('Error: Configuration is missing the required "contentDir" property.'));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
17
52
|
console.log(chalk.blue(`Content key: ${config.contentKey}`));
|
|
18
53
|
console.log(chalk.blue(`Saving content to: ${config.contentDir}`));
|
|
19
54
|
try {
|
|
@@ -30,15 +65,29 @@ export async function pullContent() {
|
|
|
30
65
|
await fs.mkdir(config.contentDir, { recursive: true });
|
|
31
66
|
// Process each language code
|
|
32
67
|
for (const languageCode of config.languageCodes) {
|
|
33
|
-
|
|
68
|
+
let fileUrl;
|
|
69
|
+
const requestConfig = {};
|
|
70
|
+
if (config.pendingChanges) {
|
|
71
|
+
fileUrl = `${CONTENTSTORAGE_CONFIG.API_URL}/pending-changes/get-json?languageCode=${languageCode}`;
|
|
72
|
+
requestConfig.headers = {
|
|
73
|
+
'X-Content-Key': config.contentKey
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
fileUrl = `${CONTENTSTORAGE_CONFIG.BASE_URL}/${config.contentKey}/content/${languageCode}.json`;
|
|
78
|
+
}
|
|
34
79
|
const filename = `${languageCode}.json`;
|
|
35
80
|
const outputPath = path.join(config.contentDir, filename);
|
|
36
81
|
console.log(chalk.blue(`\nProcessing language: ${languageCode}`));
|
|
37
82
|
console.log(chalk.blue(`Using following contentKey to fetch json: ${config.contentKey}`));
|
|
38
83
|
try {
|
|
39
84
|
// Fetch data for the current language
|
|
40
|
-
const response = await axios.get(fileUrl);
|
|
41
|
-
|
|
85
|
+
const response = await axios.get(fileUrl, requestConfig);
|
|
86
|
+
let jsonData = response.data;
|
|
87
|
+
// Handle API response structure - only for pending changes API
|
|
88
|
+
if (config.pendingChanges && jsonData && typeof jsonData === 'object' && 'data' in jsonData) {
|
|
89
|
+
jsonData = jsonData.data;
|
|
90
|
+
}
|
|
42
91
|
// Basic check for data existence, although axios usually throws for non-2xx responses
|
|
43
92
|
if (jsonData === undefined || jsonData === null) {
|
|
44
93
|
throw new Error(`No data received from ${fileUrl} for language ${languageCode}.`);
|
package/dist/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export type AppConfig = {
|
|
|
3
3
|
contentKey: string;
|
|
4
4
|
contentDir: string;
|
|
5
5
|
typesOutputFile: string;
|
|
6
|
+
pendingChanges?: boolean;
|
|
6
7
|
};
|
|
7
8
|
export type LanguageCode = 'SQ' | 'BE' | 'BS' | 'BG' | 'HR' | 'CS' | 'DA' | 'NL' | 'EN' | 'ET' | 'FI' | 'FR' | 'DE' | 'EL' | 'HU' | 'GA' | 'IT' | 'LV' | 'LT' | 'MK' | 'NO' | 'PL' | 'PT' | 'RO' | 'RU' | 'SR' | 'SK' | 'SL' | 'ES' | 'SV' | 'TR' | 'UK';
|
|
8
9
|
/**
|
|
@@ -11,14 +12,6 @@ export type LanguageCode = 'SQ' | 'BE' | 'BS' | 'BG' | 'HR' | 'CS' | 'DA' | 'NL'
|
|
|
11
12
|
* consumers enable type-safe autocompletion for localization path strings
|
|
12
13
|
* used with functions like `getText`.
|
|
13
14
|
*
|
|
14
|
-
* @example
|
|
15
|
-
* // In consumer's project (e.g., in a .d.ts file):
|
|
16
|
-
* import 'your-library-name'; // Your library's package name
|
|
17
|
-
* import type { RootContentItem as AppSpecificRootItem } from './generated_content_types';
|
|
18
|
-
*
|
|
19
|
-
* declare module 'your-library-name' {
|
|
20
|
-
* export interface ContentStructure extends AppSpecificRootItem {}
|
|
21
|
-
* }
|
|
22
15
|
*/
|
|
23
16
|
export interface ContentStructure {
|
|
24
17
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@contentstorage/core",
|
|
3
3
|
"author": "Kaido Hussar <kaidohus@gmail.com>",
|
|
4
4
|
"homepage": "https://contentstorage.app",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.1.1",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"description": "Fetch content from contentstorage and generate TypeScript types",
|
|
8
8
|
"module": "dist/index.js",
|
|
@@ -45,6 +45,9 @@
|
|
|
45
45
|
"engines": {
|
|
46
46
|
"node": ">=18.0.0"
|
|
47
47
|
},
|
|
48
|
+
"sideEffects": [
|
|
49
|
+
"./dist/index.js"
|
|
50
|
+
],
|
|
48
51
|
"publishConfig": {
|
|
49
52
|
"access": "public"
|
|
50
53
|
},
|