astra-blogs-lib 2.0.0 → 3.1.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 +9 -1
- package/astra-blogs-lib.js +92 -8
- package/package.json +4 -7
package/README.md
CHANGED
|
@@ -1 +1,9 @@
|
|
|
1
|
-
# astra-libs
|
|
1
|
+
# astra-libs
|
|
2
|
+
|
|
3
|
+
A standalone JavaScript library for fetching and managing blog content from GitHub repositories.
|
|
4
|
+
|
|
5
|
+
## Documentation
|
|
6
|
+
|
|
7
|
+
- [ASTRA_BLOGS_LIBRARY_DOCUMENTATION.md](ASTRA_BLOGS_LIBRARY_DOCUMENTATION.md)
|
|
8
|
+
- [LIBRARY_USAGE_GUIDE.md](LIBRARY_USAGE_GUIDE.md)
|
|
9
|
+
- [FRAMEWORK_EXAMPLES.md](FRAMEWORK_EXAMPLES.md)
|
package/astra-blogs-lib.js
CHANGED
|
@@ -16,20 +16,19 @@ class AstraBlogsLib {
|
|
|
16
16
|
/**
|
|
17
17
|
* Initialize the Astra Blogs Library
|
|
18
18
|
* @param {Object} config - Configuration object
|
|
19
|
-
* @param {string} config.
|
|
20
|
-
* @param {string} config.
|
|
21
|
-
* @param {string} [config.branch='main'] - GitHub branch name
|
|
22
|
-
* @param {string} [config.githubToken] - GitHub authentication token (optional)
|
|
19
|
+
* @param {string} [config.token] - Encrypted configuration token containing owner/repo/branch/githubToken
|
|
20
|
+
* @param {string} [config.secret] - Secret used to decrypt the encrypted token
|
|
23
21
|
* @param {number} [config.indexCacheTTL=3600000] - Cache TTL for blog index in milliseconds (default: 1 hour)
|
|
24
22
|
* @param {number} [config.contentCacheTTL=86400000] - Cache TTL for blog content in milliseconds (default: 24 hours)
|
|
25
23
|
* @param {Object} [config.storage=localStorage] - Storage mechanism (must have getItem/setItem)
|
|
24
|
+
* @param {boolean} [config.useCache=true] - Whether to use local storage caching
|
|
26
25
|
*/
|
|
27
26
|
constructor(config = {}) {
|
|
28
27
|
this.config = {
|
|
29
|
-
owner:
|
|
30
|
-
repo:
|
|
31
|
-
branch:
|
|
32
|
-
githubToken:
|
|
28
|
+
owner: null,
|
|
29
|
+
repo: null,
|
|
30
|
+
branch: null,
|
|
31
|
+
githubToken: null,
|
|
33
32
|
indexCacheTTL: config.indexCacheTTL || 3600000, // 1 hour
|
|
34
33
|
contentCacheTTL: config.contentCacheTTL || 86400000, // 24 hours
|
|
35
34
|
storage: config.storage || (typeof window !== 'undefined' ? window.localStorage : null),
|
|
@@ -37,6 +36,13 @@ class AstraBlogsLib {
|
|
|
37
36
|
};
|
|
38
37
|
|
|
39
38
|
this.baseURL = 'https://api.github.com';
|
|
39
|
+
this._decryptionPromise = null;
|
|
40
|
+
|
|
41
|
+
if (config.token && config.secret) {
|
|
42
|
+
this._decryptionPromise = this._decryptConfig(config.token, config.secret);
|
|
43
|
+
} else if (config.owner || config.repo || config.branch || config.githubToken) {
|
|
44
|
+
throw new Error('Direct configuration of owner/repo/branch/githubToken is not allowed. Provide encrypted token and secret.');
|
|
45
|
+
}
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
/**
|
|
@@ -57,6 +63,68 @@ class AstraBlogsLib {
|
|
|
57
63
|
return headers;
|
|
58
64
|
}
|
|
59
65
|
|
|
66
|
+
async _applyDecryptedConfig() {
|
|
67
|
+
if (!this._decryptionPromise) return;
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
await this._decryptionPromise;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('Error decrypting configuration token:', error);
|
|
73
|
+
} finally {
|
|
74
|
+
this._decryptionPromise = null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
_getMissingConfigKeys() {
|
|
79
|
+
return ['owner', 'repo', 'branch'].filter(key => !this.config[key]);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async _decryptConfig(token, secret) {
|
|
83
|
+
if (typeof window === 'undefined' || !window.crypto?.subtle) {
|
|
84
|
+
throw new Error('Web Crypto API is required to decrypt configuration values');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const decrypted = await this._aesGcmDecrypt(token, secret);
|
|
88
|
+
if (decrypted && typeof decrypted === 'object') {
|
|
89
|
+
const allowedKeys = ['owner', 'repo', 'branch', 'githubToken'];
|
|
90
|
+
const decryptedConfig = {};
|
|
91
|
+
|
|
92
|
+
allowedKeys.forEach(key => {
|
|
93
|
+
if (decrypted[key]) {
|
|
94
|
+
decryptedConfig[key] = decrypted[key];
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
this.config = { ...this.config, ...decryptedConfig };
|
|
99
|
+
console.log('🔐 Decrypted configuration values successfully');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async _aesGcmDecrypt(token, secret) {
|
|
104
|
+
const enc = new TextEncoder();
|
|
105
|
+
const hash = await window.crypto.subtle.digest('SHA-256', enc.encode(secret));
|
|
106
|
+
const key = await window.crypto.subtle.importKey(
|
|
107
|
+
'raw',
|
|
108
|
+
hash,
|
|
109
|
+
{ name: 'AES-GCM' },
|
|
110
|
+
false,
|
|
111
|
+
['decrypt']
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const [ivHex, encryptedHex] = token.split(':');
|
|
115
|
+
const iv = Uint8Array.from(ivHex.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
|
|
116
|
+
const encryptedBuffer = Uint8Array.from(encryptedHex.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
|
|
117
|
+
|
|
118
|
+
const decryptedBuffer = await window.crypto.subtle.decrypt(
|
|
119
|
+
{ name: 'AES-GCM', iv: iv },
|
|
120
|
+
key,
|
|
121
|
+
encryptedBuffer
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const dec = new TextDecoder();
|
|
125
|
+
return JSON.parse(dec.decode(decryptedBuffer));
|
|
126
|
+
}
|
|
127
|
+
|
|
60
128
|
/**
|
|
61
129
|
* Get item from storage with optional TTL validation
|
|
62
130
|
* @private
|
|
@@ -152,6 +220,14 @@ class AstraBlogsLib {
|
|
|
152
220
|
* // ]
|
|
153
221
|
*/
|
|
154
222
|
async getAllBlogs(options = {}) {
|
|
223
|
+
await this._applyDecryptedConfig();
|
|
224
|
+
|
|
225
|
+
const missingKeys = this._getMissingConfigKeys();
|
|
226
|
+
if (missingKeys.length) {
|
|
227
|
+
console.error(`Invalid configuration key(s): ${missingKeys.join(', ')}`);
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
|
|
155
231
|
const { useCache = true, forceFresh = false } = options;
|
|
156
232
|
const cacheKey = 'astra_blogs_index_cache';
|
|
157
233
|
|
|
@@ -229,6 +305,14 @@ class AstraBlogsLib {
|
|
|
229
305
|
* // }
|
|
230
306
|
*/
|
|
231
307
|
async getBlogContent(slug, options = {}) {
|
|
308
|
+
await this._applyDecryptedConfig();
|
|
309
|
+
|
|
310
|
+
const missingKeys = this._getMissingConfigKeys();
|
|
311
|
+
if (missingKeys.length) {
|
|
312
|
+
console.error(`Invalid configuration key(s): ${missingKeys.join(', ')}`);
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
|
|
232
316
|
const { useCache = true, forceFresh = false, parseYAML = true } = options;
|
|
233
317
|
const cacheKey = `astra_blog_content_${slug}`;
|
|
234
318
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astra-blogs-lib",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "A standalone JavaScript library for fetching and managing blog content from GitHub repositories. Framework-agnostic with support for React, Vue, Angular, Next.js, Node.js, and vanilla JavaScript.",
|
|
5
5
|
"main": "astra-blogs-lib.js",
|
|
6
6
|
"module": "astra-blogs-lib.js",
|
|
@@ -49,14 +49,11 @@
|
|
|
49
49
|
"node": ">=12.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"
|
|
53
|
-
"
|
|
52
|
+
"terser": "^5.27.0",
|
|
53
|
+
"jsdoc": "^4.0.3"
|
|
54
54
|
},
|
|
55
55
|
"optionalDependencies": {
|
|
56
56
|
"js-yaml": "^4.1.1"
|
|
57
57
|
},
|
|
58
|
-
"readme": "See LIBRARY_README.md for overview and LIBRARY_USAGE_GUIDE.md for complete documentation"
|
|
59
|
-
"dependencies": {
|
|
60
|
-
"astra-blogs-lib": "file:astra-blogs-lib-1.0.0.tgz"
|
|
61
|
-
}
|
|
58
|
+
"readme": "See LIBRARY_README.md for overview and LIBRARY_USAGE_GUIDE.md for complete documentation"
|
|
62
59
|
}
|