apidocly 1.0.3 → 1.0.5
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 +5 -4
- package/lib/generator/index.js +24 -8
- package/package.json +46 -46
- package/template/css/style.css +184 -0
- package/template/index.html +11 -0
- package/template/js/main.js +81 -3
package/README.md
CHANGED
|
@@ -3,14 +3,13 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/apidocly)
|
|
4
4
|
[](https://www.npmjs.com/package/apidocly)
|
|
5
5
|
|
|
6
|
-
API documentation generator with
|
|
6
|
+
API documentation generator with dark UI and password protection.
|
|
7
7
|
|
|
8
8
|
A modern, dark-themed package that generates pure HTML/CSS/JS documentation.
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
12
|
- **apidoc-compatible**: Uses the same annotation syntax as apidoc.js
|
|
13
|
-
- **Shadcn Dark UI**: Beautiful, modern dark theme inspired by shadcn/ui
|
|
14
13
|
- **OpenAPI Export**: Automatically generates OpenAPI 3.0 JSON for AI tools and code generators
|
|
15
14
|
- **Password Protection**: Optional client-side password protection with AES-256-GCM encryption
|
|
16
15
|
- **Zero Dependencies Output**: Generated docs are pure HTML/CSS/JS - no frameworks required
|
|
@@ -84,11 +83,13 @@ Create `apidocly.json` in your project root:
|
|
|
84
83
|
"passwordMessage": "Enter password to view documentation",
|
|
85
84
|
"header": {
|
|
86
85
|
"title": "Introduction",
|
|
87
|
-
"filename": "header.md"
|
|
86
|
+
"filename": "header.md",
|
|
87
|
+
"collapsed": false
|
|
88
88
|
},
|
|
89
89
|
"footer": {
|
|
90
90
|
"title": "Footer",
|
|
91
|
-
"filename": "footer.md"
|
|
91
|
+
"filename": "footer.md",
|
|
92
|
+
"collapsed": true
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
```
|
package/lib/generator/index.js
CHANGED
|
@@ -38,7 +38,8 @@ async function generateDocs(apiData, config, outputPath, options = {}) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// Always save version history for version switching feature
|
|
41
|
-
|
|
41
|
+
const plainPassword = password ? getPlainPassword(password) : null;
|
|
42
|
+
saveVersionHistory(apiData, config, outputPath, verbose, plainPassword);
|
|
42
43
|
|
|
43
44
|
generateApiDataFile(apiData, outputPath, password, authData);
|
|
44
45
|
|
|
@@ -229,7 +230,7 @@ function escapeHtml(str) {
|
|
|
229
230
|
.replace(/'/g, ''');
|
|
230
231
|
}
|
|
231
232
|
|
|
232
|
-
function saveVersionHistory(apiData, config, outputPath, verbose) {
|
|
233
|
+
function saveVersionHistory(apiData, config, outputPath, verbose, password = null) {
|
|
233
234
|
const versionsDir = path.join(outputPath, 'versions');
|
|
234
235
|
|
|
235
236
|
if (!fs.existsSync(versionsDir)) {
|
|
@@ -294,18 +295,32 @@ function saveVersionHistory(apiData, config, outputPath, verbose) {
|
|
|
294
295
|
}
|
|
295
296
|
};
|
|
296
297
|
|
|
297
|
-
|
|
298
|
+
// If password is provided, encrypt the version file
|
|
299
|
+
if (password) {
|
|
300
|
+
const encryptedVersionData = encryptData(versionData, password);
|
|
301
|
+
fs.writeFileSync(versionPath, encryptedVersionData, 'utf8');
|
|
302
|
+
} else {
|
|
303
|
+
fs.writeFileSync(versionPath, JSON.stringify(versionData, null, 2), 'utf8');
|
|
304
|
+
}
|
|
298
305
|
|
|
299
|
-
// Save versions index
|
|
306
|
+
// Save versions index (not encrypted - only contains metadata, no API data)
|
|
300
307
|
fs.writeFileSync(versionsIndexPath, JSON.stringify(versionsIndex, null, 2), 'utf8');
|
|
301
308
|
|
|
302
309
|
// Load all version data to embed in versions.js (for file:// protocol support)
|
|
310
|
+
// When encrypted, we store the encrypted strings directly
|
|
303
311
|
const allVersionData = {};
|
|
304
312
|
for (const v of versionsIndex) {
|
|
305
313
|
const vPath = path.join(versionsDir, v.filename);
|
|
306
314
|
if (fs.existsSync(vPath)) {
|
|
307
315
|
try {
|
|
308
|
-
|
|
316
|
+
const fileContent = fs.readFileSync(vPath, 'utf8');
|
|
317
|
+
if (password) {
|
|
318
|
+
// Store encrypted string directly
|
|
319
|
+
allVersionData[v.filename] = fileContent;
|
|
320
|
+
} else {
|
|
321
|
+
// Store parsed JSON
|
|
322
|
+
allVersionData[v.filename] = JSON.parse(fileContent);
|
|
323
|
+
}
|
|
309
324
|
} catch (e) {
|
|
310
325
|
// Skip if can't read
|
|
311
326
|
}
|
|
@@ -313,13 +328,14 @@ function saveVersionHistory(apiData, config, outputPath, verbose) {
|
|
|
313
328
|
}
|
|
314
329
|
|
|
315
330
|
// Generate versions.js for frontend
|
|
316
|
-
// Include withCompare setting and embedded version data
|
|
331
|
+
// Include withCompare setting, encrypted flag, and embedded version data
|
|
317
332
|
const withCompare = config.template && config.template.withCompare ? true : false;
|
|
318
|
-
const
|
|
333
|
+
const isEncrypted = !!password;
|
|
334
|
+
const versionsJs = `var apiVersions=${JSON.stringify(versionsIndex)};var apiVersionsConfig={withCompare:${withCompare},encrypted:${isEncrypted}};var apiVersionsData=${JSON.stringify(allVersionData)};`;
|
|
319
335
|
fs.writeFileSync(path.join(outputPath, 'versions.js'), versionsJs, 'utf8');
|
|
320
336
|
|
|
321
337
|
if (verbose) {
|
|
322
|
-
console.log(` Saved version ${version} to history (${versionsIndex.length} versions total)`);
|
|
338
|
+
console.log(` Saved version ${version} to history (${versionsIndex.length} versions total)${password ? ' (encrypted)' : ''}`);
|
|
323
339
|
}
|
|
324
340
|
}
|
|
325
341
|
|
package/package.json
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "apidocly",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "API documentation generator with beautiful dark UI, password protection, and OpenAPI/Rest client export.",
|
|
5
|
-
"main": "lib/index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"apidocly": "bin/apidocly.js"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"test": "echo \"No tests yet\" && exit 0"
|
|
11
|
-
},
|
|
12
|
-
"keywords": [
|
|
13
|
-
"api",
|
|
14
|
-
"documentation",
|
|
15
|
-
"generator",
|
|
16
|
-
"apidoc",
|
|
17
|
-
"openapi",
|
|
18
|
-
"swagger",
|
|
19
|
-
"dark-mode",
|
|
20
|
-
"rest-api",
|
|
21
|
-
"api-docs",
|
|
22
|
-
"jsdoc",
|
|
23
|
-
"cli"
|
|
24
|
-
],
|
|
25
|
-
"author": "",
|
|
26
|
-
"license": "MIT",
|
|
27
|
-
"homepage": "https://apidocly.com",
|
|
28
|
-
"bugs": {
|
|
29
|
-
"url": "https://apidocly.com"
|
|
30
|
-
},
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"commander": "^11.1.0",
|
|
33
|
-
"glob": "11.1.0",
|
|
34
|
-
"terser": "^5.37.0"
|
|
35
|
-
},
|
|
36
|
-
"engines": {
|
|
37
|
-
"node": ">=14.0.0"
|
|
38
|
-
},
|
|
39
|
-
"files": [
|
|
40
|
-
"bin",
|
|
41
|
-
"lib",
|
|
42
|
-
"template",
|
|
43
|
-
"README.md",
|
|
44
|
-
"LICENSE"
|
|
45
|
-
]
|
|
46
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "apidocly",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "API documentation generator with beautiful dark UI, password protection, and OpenAPI/Rest client export.",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"apidocly": "bin/apidocly.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"No tests yet\" && exit 0"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"api",
|
|
14
|
+
"documentation",
|
|
15
|
+
"generator",
|
|
16
|
+
"apidoc",
|
|
17
|
+
"openapi",
|
|
18
|
+
"swagger",
|
|
19
|
+
"dark-mode",
|
|
20
|
+
"rest-api",
|
|
21
|
+
"api-docs",
|
|
22
|
+
"jsdoc",
|
|
23
|
+
"cli"
|
|
24
|
+
],
|
|
25
|
+
"author": "",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"homepage": "https://apidocly.com",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://apidocly.com"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"commander": "^11.1.0",
|
|
33
|
+
"glob": "11.1.0",
|
|
34
|
+
"terser": "^5.37.0"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=14.0.0"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"bin",
|
|
41
|
+
"lib",
|
|
42
|
+
"template",
|
|
43
|
+
"README.md",
|
|
44
|
+
"LICENSE"
|
|
45
|
+
]
|
|
46
|
+
}
|
package/template/css/style.css
CHANGED
|
@@ -810,6 +810,190 @@ a:hover {
|
|
|
810
810
|
backdrop-filter: blur(10px);
|
|
811
811
|
}
|
|
812
812
|
|
|
813
|
+
/* Documentation Header Block (collapsible) */
|
|
814
|
+
.doc-header-block {
|
|
815
|
+
margin: 0 0 1.5rem;
|
|
816
|
+
background: linear-gradient(135deg, rgba(255, 255, 255, 0.02) 0%, rgba(255, 255, 255, 0.01) 100%);
|
|
817
|
+
border: 1px solid var(--border);
|
|
818
|
+
border-radius: var(--radius-xl);
|
|
819
|
+
overflow: hidden;
|
|
820
|
+
backdrop-filter: blur(10px);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
.doc-header-block.hidden {
|
|
824
|
+
display: none;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
.doc-header-toggle {
|
|
828
|
+
display: flex;
|
|
829
|
+
align-items: center;
|
|
830
|
+
justify-content: space-between;
|
|
831
|
+
padding: 1.25rem 1.5rem;
|
|
832
|
+
background: rgba(255, 255, 255, 0.02);
|
|
833
|
+
border-bottom: 1px solid var(--border);
|
|
834
|
+
cursor: pointer;
|
|
835
|
+
user-select: none;
|
|
836
|
+
transition: background-color 0.2s;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.doc-header-toggle:hover {
|
|
840
|
+
background: rgba(255, 255, 255, 0.04);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
.doc-header-block.collapsed .doc-header-toggle {
|
|
844
|
+
border-bottom: none;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
.doc-header-toggle-title {
|
|
848
|
+
font-size: 0.9375rem;
|
|
849
|
+
font-weight: 600;
|
|
850
|
+
color: var(--foreground);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
.doc-header-chevron {
|
|
854
|
+
transition: transform 0.2s;
|
|
855
|
+
color: var(--muted-foreground);
|
|
856
|
+
flex-shrink: 0;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
.doc-header-block.collapsed .doc-header-chevron {
|
|
860
|
+
transform: rotate(-90deg);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
.doc-header-block.collapsed .doc-header-content {
|
|
864
|
+
display: none;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/* Documentation Header Content (from markdown) */
|
|
868
|
+
.doc-header-content {
|
|
869
|
+
padding: 1.25rem 1.5rem;
|
|
870
|
+
color: var(--muted-foreground);
|
|
871
|
+
font-size: 0.9375rem;
|
|
872
|
+
line-height: 1.7;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.doc-header-content > *:first-child {
|
|
876
|
+
margin-top: 0;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
.doc-header-content > *:last-child {
|
|
880
|
+
margin-bottom: 0;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.doc-header-content h1,
|
|
884
|
+
.doc-header-content h2,
|
|
885
|
+
.doc-header-content h3,
|
|
886
|
+
.doc-header-content h4 {
|
|
887
|
+
color: var(--foreground);
|
|
888
|
+
margin-top: 1.25rem;
|
|
889
|
+
margin-bottom: 0.75rem;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
.doc-header-content h1 { font-size: 1.5rem; }
|
|
893
|
+
.doc-header-content h2 { font-size: 1.25rem; }
|
|
894
|
+
.doc-header-content h3 { font-size: 1.125rem; }
|
|
895
|
+
.doc-header-content h4 { font-size: 1rem; }
|
|
896
|
+
|
|
897
|
+
.doc-header-content p {
|
|
898
|
+
margin-bottom: 0.75rem;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
.doc-header-content ul,
|
|
902
|
+
.doc-header-content ol {
|
|
903
|
+
margin: 0.75rem 0;
|
|
904
|
+
padding-left: 1.5rem;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
.doc-header-content li {
|
|
908
|
+
margin-bottom: 0.375rem;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
.doc-header-content li > ul,
|
|
912
|
+
.doc-header-content li > ol {
|
|
913
|
+
margin-top: 0.375rem;
|
|
914
|
+
margin-bottom: 0;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
.doc-header-content blockquote {
|
|
918
|
+
margin: 1rem 0;
|
|
919
|
+
padding: 0.75rem 1rem;
|
|
920
|
+
border-left: 3px solid var(--primary);
|
|
921
|
+
background: rgba(255, 255, 255, 0.02);
|
|
922
|
+
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
.doc-header-content blockquote p {
|
|
926
|
+
margin: 0;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.doc-header-content table {
|
|
930
|
+
width: 100%;
|
|
931
|
+
border-collapse: collapse;
|
|
932
|
+
margin: 1rem 0;
|
|
933
|
+
font-size: 0.875rem;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
.doc-header-content th,
|
|
937
|
+
.doc-header-content td {
|
|
938
|
+
padding: 0.625rem 0.75rem;
|
|
939
|
+
border: 1px solid var(--border);
|
|
940
|
+
text-align: left;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
.doc-header-content th {
|
|
944
|
+
background: var(--secondary);
|
|
945
|
+
color: var(--foreground);
|
|
946
|
+
font-weight: 600;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.doc-header-content tr:nth-child(even) td {
|
|
950
|
+
background: rgba(255, 255, 255, 0.02);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.doc-header-content hr {
|
|
954
|
+
margin: 1.5rem 0;
|
|
955
|
+
border: none;
|
|
956
|
+
border-top: 1px solid var(--border);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.doc-header-content code {
|
|
960
|
+
background: rgba(255, 255, 255, 0.05);
|
|
961
|
+
padding: 0.15rem 0.4rem;
|
|
962
|
+
border-radius: var(--radius-sm);
|
|
963
|
+
font-family: var(--font-mono);
|
|
964
|
+
font-size: 0.875em;
|
|
965
|
+
color: var(--primary);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
.doc-header-content pre {
|
|
969
|
+
background: rgba(0, 0, 0, 0.3);
|
|
970
|
+
border: 1px solid var(--border);
|
|
971
|
+
border-radius: var(--radius);
|
|
972
|
+
padding: 1rem;
|
|
973
|
+
margin: 1rem 0;
|
|
974
|
+
overflow-x: auto;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
.doc-header-content pre code {
|
|
978
|
+
background: none;
|
|
979
|
+
padding: 0;
|
|
980
|
+
color: var(--foreground);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
.doc-header-content a {
|
|
984
|
+
color: var(--primary);
|
|
985
|
+
text-decoration: none;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
.doc-header-content a:hover {
|
|
989
|
+
text-decoration: underline;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
.doc-header-content strong {
|
|
993
|
+
color: var(--foreground);
|
|
994
|
+
font-weight: 600;
|
|
995
|
+
}
|
|
996
|
+
|
|
813
997
|
/* Section Header */
|
|
814
998
|
.section-header {
|
|
815
999
|
display: flex;
|
package/template/index.html
CHANGED
|
@@ -157,6 +157,17 @@
|
|
|
157
157
|
</div>
|
|
158
158
|
</div>
|
|
159
159
|
|
|
160
|
+
<!-- Header Content (from markdown) - collapsible, separate block -->
|
|
161
|
+
<div class="doc-header-block hidden" id="doc-header-block">
|
|
162
|
+
<div class="doc-header-toggle" onclick="toggleDocHeader()">
|
|
163
|
+
<span class="doc-header-toggle-title" id="doc-header-toggle-title">Documentation</span>
|
|
164
|
+
<svg class="doc-header-chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
165
|
+
<path d="m6 9 6 6 6-6"></path>
|
|
166
|
+
</svg>
|
|
167
|
+
</div>
|
|
168
|
+
<div class="doc-header-content" id="doc-header-content"></div>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
160
171
|
<!-- Content Container -->
|
|
161
172
|
<div class="content-container" id="content-container">
|
|
162
173
|
<!-- Groups View (default) -->
|
package/template/js/main.js
CHANGED
|
@@ -197,11 +197,47 @@
|
|
|
197
197
|
initEnvironmentSelector();
|
|
198
198
|
initVersionComparison();
|
|
199
199
|
updateStats();
|
|
200
|
+
renderHeaderContent();
|
|
200
201
|
renderGroups();
|
|
201
202
|
setupEventListeners();
|
|
202
203
|
handleInitialHash();
|
|
203
204
|
}
|
|
204
205
|
|
|
206
|
+
// Render header content from markdown
|
|
207
|
+
function renderHeaderContent() {
|
|
208
|
+
const headerBlock = document.getElementById('doc-header-block');
|
|
209
|
+
const headerContent = document.getElementById('doc-header-content');
|
|
210
|
+
const headerToggleTitle = document.getElementById('doc-header-toggle-title');
|
|
211
|
+
if (!headerBlock || !headerContent) return;
|
|
212
|
+
|
|
213
|
+
if (apiData.header && apiData.header.content) {
|
|
214
|
+
// Set the toggle title
|
|
215
|
+
if (headerToggleTitle && apiData.header.title) {
|
|
216
|
+
headerToggleTitle.textContent = apiData.header.title;
|
|
217
|
+
}
|
|
218
|
+
// Render markdown content
|
|
219
|
+
headerContent.innerHTML = marked.parse(apiData.header.content);
|
|
220
|
+
headerBlock.classList.remove('hidden');
|
|
221
|
+
|
|
222
|
+
// Determine collapsed state: localStorage overrides config default
|
|
223
|
+
const savedState = localStorage.getItem('apidocly-header-collapsed');
|
|
224
|
+
let isCollapsed;
|
|
225
|
+
if (savedState !== null) {
|
|
226
|
+
// User has manually toggled, use their preference
|
|
227
|
+
isCollapsed = savedState === 'true';
|
|
228
|
+
} else {
|
|
229
|
+
// Use config default (collapsed: true means start collapsed)
|
|
230
|
+
isCollapsed = apiData.header.collapsed !== false;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (isCollapsed) {
|
|
234
|
+
headerBlock.classList.add('collapsed');
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
headerBlock.classList.add('hidden');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
205
241
|
// Environment Selector
|
|
206
242
|
function initEnvironmentSelector() {
|
|
207
243
|
const environments = apiData.project.environments || [];
|
|
@@ -2028,6 +2064,15 @@
|
|
|
2028
2064
|
}
|
|
2029
2065
|
|
|
2030
2066
|
// Global functions
|
|
2067
|
+
window.toggleDocHeader = function() {
|
|
2068
|
+
const block = document.getElementById('doc-header-block');
|
|
2069
|
+
if (block) {
|
|
2070
|
+
block.classList.toggle('collapsed');
|
|
2071
|
+
// Save state to localStorage
|
|
2072
|
+
localStorage.setItem('apidocly-header-collapsed', block.classList.contains('collapsed'));
|
|
2073
|
+
}
|
|
2074
|
+
};
|
|
2075
|
+
|
|
2031
2076
|
window.toggleExample = function(header) {
|
|
2032
2077
|
const block = header.closest('.example-block');
|
|
2033
2078
|
block.classList.toggle('collapsed');
|
|
@@ -2667,8 +2712,28 @@
|
|
|
2667
2712
|
|
|
2668
2713
|
// Check if version data is embedded in versions.js (for file:// protocol support)
|
|
2669
2714
|
if (typeof apiVersionsData !== 'undefined' && apiVersionsData[filename]) {
|
|
2670
|
-
|
|
2671
|
-
|
|
2715
|
+
const versionContent = apiVersionsData[filename];
|
|
2716
|
+
|
|
2717
|
+
// Check if data is encrypted
|
|
2718
|
+
if (typeof apiVersionsConfig !== 'undefined' && apiVersionsConfig.encrypted) {
|
|
2719
|
+
// Decrypt using the stored password from auth module
|
|
2720
|
+
const storedPwd = sessionStorage.getItem('apidocly-pwd');
|
|
2721
|
+
if (!storedPwd) {
|
|
2722
|
+
throw new Error('Cannot decrypt version data: no password available');
|
|
2723
|
+
}
|
|
2724
|
+
try {
|
|
2725
|
+
const decrypted = await window.apiDoclyAuth.decryptData(versionContent, storedPwd);
|
|
2726
|
+
versionCache[filename] = decrypted;
|
|
2727
|
+
return decrypted;
|
|
2728
|
+
} catch (e) {
|
|
2729
|
+
console.error('Failed to decrypt version data:', e);
|
|
2730
|
+
throw new Error('Failed to decrypt version data');
|
|
2731
|
+
}
|
|
2732
|
+
} else {
|
|
2733
|
+
// Not encrypted, use directly
|
|
2734
|
+
versionCache[filename] = versionContent;
|
|
2735
|
+
return versionContent;
|
|
2736
|
+
}
|
|
2672
2737
|
}
|
|
2673
2738
|
|
|
2674
2739
|
// Fall back to fetch (for http:// protocol)
|
|
@@ -2679,7 +2744,20 @@
|
|
|
2679
2744
|
throw new Error('Failed to load version: ' + filename + ' (HTTP ' + response.status + ')');
|
|
2680
2745
|
}
|
|
2681
2746
|
|
|
2682
|
-
|
|
2747
|
+
// Check if response is encrypted (starts with base64 data, not JSON)
|
|
2748
|
+
const text = await response.text();
|
|
2749
|
+
let data;
|
|
2750
|
+
|
|
2751
|
+
if (typeof apiVersionsConfig !== 'undefined' && apiVersionsConfig.encrypted) {
|
|
2752
|
+
const storedPwd = sessionStorage.getItem('apidocly-pwd');
|
|
2753
|
+
if (!storedPwd) {
|
|
2754
|
+
throw new Error('Cannot decrypt version data: no password available');
|
|
2755
|
+
}
|
|
2756
|
+
data = await window.apiDoclyAuth.decryptData(text, storedPwd);
|
|
2757
|
+
} else {
|
|
2758
|
+
data = JSON.parse(text);
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2683
2761
|
versionCache[filename] = data;
|
|
2684
2762
|
return data;
|
|
2685
2763
|
} catch (error) {
|