@knowcode/doc-builder 1.7.4 → 1.7.6

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.
Files changed (71) hide show
  1. package/.claude/settings.local.json +6 -1
  2. package/CHANGELOG.md +50 -0
  3. package/README.md +47 -7
  4. package/RELEASE-NOTES-1.7.5.md +64 -0
  5. package/add-user-clive.sql +35 -0
  6. package/add-user-lindsay-fixed.sql +85 -0
  7. package/add-user-lindsay.sql +68 -0
  8. package/add-user-pmorgan.sql +35 -0
  9. package/add-user-robbie.sql +35 -0
  10. package/add-wru-users.sql +105 -0
  11. package/cli.js +223 -8
  12. package/grant-access.sql +15 -0
  13. package/html/README.html +14 -4
  14. package/html/auth.js +97 -0
  15. package/html/documentation-index.html +14 -4
  16. package/html/guides/authentication-default-change.html +302 -0
  17. package/html/guides/authentication-guide.html +32 -14
  18. package/html/guides/cache-control-anti-pattern.html +361 -0
  19. package/html/guides/claude-workflow-guide.html +14 -4
  20. package/html/guides/documentation-standards.html +14 -4
  21. package/html/guides/next-steps-walkthrough.html +638 -0
  22. package/html/guides/phosphor-icons-guide.html +14 -4
  23. package/html/guides/public-site-deployment.html +363 -0
  24. package/html/guides/search-engine-verification-guide.html +14 -4
  25. package/html/guides/seo-guide.html +14 -4
  26. package/html/guides/seo-optimization-guide.html +14 -4
  27. package/html/guides/supabase-auth-implementation-plan.html +543 -0
  28. package/html/guides/supabase-auth-integration-plan.html +671 -0
  29. package/html/guides/supabase-auth-setup-guide.html +498 -0
  30. package/html/guides/troubleshooting-guide.html +14 -4
  31. package/html/guides/vercel-deployment-auth-setup.html +337 -0
  32. package/html/guides/windows-setup-guide.html +14 -4
  33. package/html/index.html +14 -4
  34. package/html/launch/README.html +14 -4
  35. package/html/launch/bubble-plugin-specification.html +14 -4
  36. package/html/launch/go-to-market-strategy.html +14 -4
  37. package/html/launch/launch-announcements.html +14 -4
  38. package/html/login.html +102 -0
  39. package/html/logout.html +18 -0
  40. package/html/sitemap.xml +69 -21
  41. package/html/vercel-cli-setup-guide.html +14 -4
  42. package/html/vercel-first-time-setup-guide.html +14 -4
  43. package/lib/config.js +33 -29
  44. package/lib/core-builder.js +142 -88
  45. package/lib/supabase-auth.js +295 -0
  46. package/manage-users.sql +191 -0
  47. package/package.json +2 -1
  48. package/public-config.js +22 -0
  49. package/public-html/404.html +115 -0
  50. package/public-html/README.html +149 -0
  51. package/public-html/css/notion-style.css +2036 -0
  52. package/public-html/index.html +149 -0
  53. package/public-html/js/main.js +1485 -0
  54. package/quick-test-commands.md +40 -0
  55. package/recordings/Screenshot 2025-07-24 at 18.22.01.png +0 -0
  56. package/setup-database.sql +41 -0
  57. package/test-auth-config.js +17 -0
  58. package/test-docs/README.md +39 -0
  59. package/test-html/404.html +115 -0
  60. package/test-html/README.html +172 -0
  61. package/test-html/auth.js +97 -0
  62. package/test-html/css/notion-style.css +2036 -0
  63. package/test-html/index.html +172 -0
  64. package/test-html/js/auth.js +97 -0
  65. package/test-html/js/main.js +1485 -0
  66. package/test-html/login.html +102 -0
  67. package/test-html/logout.html +18 -0
  68. package/update-domain.sql +9 -0
  69. package/view-all-users.sql +40 -0
  70. package/wru-auth-config.js +17 -0
  71. /package/{assets → public-html}/js/auth.js +0 -0
package/lib/config.js CHANGED
@@ -19,7 +19,7 @@ const defaultConfig = {
19
19
 
20
20
  // Features
21
21
  features: {
22
- authentication: false,
22
+ authentication: false, // false (no auth) or 'supabase' (secure auth)
23
23
  changelog: true,
24
24
  mermaid: true,
25
25
  tooltips: true,
@@ -30,13 +30,15 @@ const defaultConfig = {
30
30
  phosphorSize: '1.2em', // Relative to text size
31
31
  normalizeTitle: true, // Auto-normalize all-caps titles to title case
32
32
  showPdfDownload: true, // Show PDF download icon in header
33
- menuDefaultOpen: true // Menu/sidebar open by default
33
+ menuDefaultOpen: true, // Menu/sidebar open by default
34
+ attachments: true // Copy attachments (Excel, PDF, etc.) to output
34
35
  },
35
36
 
36
- // Authentication (if enabled)
37
+ // Authentication - Supabase only (basic auth removed for security)
37
38
  auth: {
38
- username: 'admin',
39
- password: 'password'
39
+ supabaseUrl: '',
40
+ supabaseAnonKey: '',
41
+ siteId: ''
40
42
  },
41
43
 
42
44
  // Changelog settings
@@ -77,7 +79,21 @@ const defaultConfig = {
77
79
  generateSitemap: true,
78
80
  generateRobotsTxt: true,
79
81
  customMetaTags: []
80
- }
82
+ },
83
+
84
+ // Attachment file types to copy
85
+ attachmentTypes: [
86
+ // Documents
87
+ '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.csv', '.ppt', '.pptx', '.txt', '.rtf',
88
+ // Archives
89
+ '.zip', '.tar', '.gz', '.7z', '.rar',
90
+ // Images
91
+ '.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.ico', '.bmp',
92
+ // Data files
93
+ '.json', '.xml', '.yaml', '.yml', '.toml',
94
+ // Other
95
+ '.mp4', '.mp3', '.wav', '.avi', '.mov'
96
+ ]
81
97
  };
82
98
 
83
99
  /**
@@ -90,7 +106,7 @@ const notionInspiredPreset = {
90
106
  siteDescription: 'Transforming complex sales through intelligent automation',
91
107
 
92
108
  features: {
93
- authentication: true,
109
+ authentication: false, // Default to no auth - can be enabled with 'supabase'
94
110
  changelog: true,
95
111
  mermaid: true,
96
112
  tooltips: true,
@@ -101,12 +117,14 @@ const notionInspiredPreset = {
101
117
  phosphorSize: '1.2em',
102
118
  normalizeTitle: true,
103
119
  showPdfDownload: true,
104
- menuDefaultOpen: true
120
+ menuDefaultOpen: true,
121
+ attachments: true
105
122
  },
106
123
 
107
124
  auth: {
108
- username: 'admin',
109
- password: 'docs2025'
125
+ supabaseUrl: process.env.SUPABASE_URL || '',
126
+ supabaseAnonKey: process.env.SUPABASE_ANON_KEY || '',
127
+ siteId: process.env.DOC_SITE_ID || ''
110
128
  },
111
129
 
112
130
  changelog: {
@@ -259,6 +277,9 @@ async function loadConfig(configPath, options = {}) {
259
277
  if (options.menuClosed === true) {
260
278
  config.features.menuDefaultOpen = false;
261
279
  }
280
+ if (options.attachments === false) {
281
+ config.features.attachments = false;
282
+ }
262
283
 
263
284
  // Legacy mode - auto-detect structure
264
285
  if (options.legacy) {
@@ -307,32 +328,15 @@ async function createDefaultConfig() {
307
328
  {
308
329
  type: 'confirm',
309
330
  name: 'authentication',
310
- message: 'Enable authentication?',
331
+ message: 'Enable Supabase authentication?',
311
332
  initial: false
312
- },
313
- {
314
- type: prev => prev ? 'text' : null,
315
- name: 'authUsername',
316
- message: 'Authentication username:',
317
- initial: 'admin'
318
- },
319
- {
320
- type: prev => prev ? 'password' : null,
321
- name: 'authPassword',
322
- message: 'Authentication password:',
323
- initial: 'password'
324
333
  }
325
334
  ]);
326
335
 
327
336
  const config = { ...defaultConfig };
328
337
  config.siteName = answers.siteName;
329
338
  config.siteDescription = answers.siteDescription;
330
- config.features.authentication = answers.authentication;
331
-
332
- if (answers.authentication) {
333
- config.auth.username = answers.authUsername;
334
- config.auth.password = answers.authPassword;
335
- }
339
+ config.features.authentication = answers.authentication ? 'supabase' : false;
336
340
 
337
341
  return config;
338
342
  }
@@ -3,6 +3,7 @@ const path = require('path');
3
3
  const marked = require('marked');
4
4
  const chalk = require('chalk');
5
5
  const matter = require('gray-matter');
6
+ const SupabaseAuth = require('./supabase-auth');
6
7
  const {
7
8
  generateMetaTags,
8
9
  generateJSONLD,
@@ -344,6 +345,26 @@ ${seoTags}
344
345
  <!-- Styles -->
345
346
  <link rel="stylesheet" href="/css/notion-style.css">
346
347
 
348
+ ${config.features?.authentication === 'supabase' ? `
349
+ <!-- Hide content until auth check -->
350
+ <style>
351
+ body {
352
+ visibility: hidden;
353
+ opacity: 0;
354
+ transition: opacity 0.3s ease;
355
+ }
356
+ body.authenticated {
357
+ visibility: visible;
358
+ opacity: 1;
359
+ }
360
+ /* Show login/logout pages immediately */
361
+ body.auth-page {
362
+ visibility: visible;
363
+ opacity: 1;
364
+ }
365
+ </style>
366
+ ` : ''}
367
+
347
368
  <!-- Favicon -->
348
369
  ${generateFaviconTag(config.favicon || '✨')}
349
370
 
@@ -367,7 +388,7 @@ ${seoTags}
367
388
  })} UTC</span>
368
389
  </div>
369
390
 
370
- ${config.features?.authentication ? `
391
+ ${config.features?.authentication === 'supabase' ? `
371
392
  <a href="${relativePath}logout.html" class="logout-btn" title="Logout">
372
393
  <i class="fas fa-sign-out-alt"></i>
373
394
  </a>
@@ -435,7 +456,8 @@ ${seoTags}
435
456
  };
436
457
  </script>
437
458
  <script src="/js/main.js"></script>
438
- ${config.features?.authentication ? `<script src="/js/auth.js"></script>` : ''}
459
+ ${config.features?.authentication === 'supabase' ? `<script src="https://unpkg.com/@supabase/supabase-js@2"></script>
460
+ <script src="/js/auth.js"></script>` : ''}
439
461
  </body>
440
462
  </html>`;
441
463
  }
@@ -731,6 +753,62 @@ async function getAllMarkdownFiles(dir, baseDir = dir) {
731
753
  return files;
732
754
  }
733
755
 
756
+ // Get all attachment files
757
+ async function getAllAttachmentFiles(dir, baseDir = dir, attachmentTypes) {
758
+ const files = [];
759
+ const items = await fs.readdir(dir);
760
+
761
+ for (const item of items) {
762
+ const fullPath = path.join(dir, item);
763
+ const stat = await fs.stat(fullPath);
764
+
765
+ if (stat.isDirectory() && !item.startsWith('.')) {
766
+ // Recursively scan subdirectories
767
+ const subFiles = await getAllAttachmentFiles(fullPath, baseDir, attachmentTypes);
768
+ files.push(...subFiles);
769
+ } else {
770
+ // Check if file is an attachment type
771
+ const ext = path.extname(item).toLowerCase();
772
+ if (attachmentTypes.includes(ext) && !item.startsWith('.')) {
773
+ const relativePath = path.relative(baseDir, fullPath);
774
+ files.push({
775
+ path: fullPath,
776
+ relativePath,
777
+ size: stat.size
778
+ });
779
+ }
780
+ }
781
+ }
782
+
783
+ return files;
784
+ }
785
+
786
+ // Copy attachment files to output directory
787
+ async function copyAttachmentFiles(attachmentFiles, docsDir, outputDir) {
788
+ let totalSize = 0;
789
+ let copiedCount = 0;
790
+
791
+ for (const file of attachmentFiles) {
792
+ try {
793
+ const outputPath = path.join(outputDir, file.relativePath);
794
+ const outputDirPath = path.dirname(outputPath);
795
+
796
+ // Create directory if it doesn't exist
797
+ await fs.ensureDir(outputDirPath);
798
+
799
+ // Copy the file
800
+ await fs.copy(file.path, outputPath, { overwrite: true });
801
+
802
+ totalSize += file.size;
803
+ copiedCount++;
804
+ } catch (error) {
805
+ console.warn(chalk.yellow(`Warning: Could not copy ${file.relativePath}: ${error.message}`));
806
+ }
807
+ }
808
+
809
+ return { copiedCount, totalSize };
810
+ }
811
+
734
812
  // Main build function
735
813
  async function buildDocumentation(config) {
736
814
  const docsDir = path.join(process.cwd(), config.docsDir);
@@ -778,21 +856,12 @@ async function buildDocumentation(config) {
778
856
  if (fs.existsSync(jsSource)) {
779
857
  await fs.copy(jsSource, path.join(outputDir, 'js'), { overwrite: true });
780
858
 
781
- // Copy auth.js to root if authentication is enabled
782
- if (config.features?.authentication) {
783
- const authSource = path.join(jsSource, 'auth.js');
784
- const authDest = path.join(outputDir, 'auth.js');
785
- if (fs.existsSync(authSource)) {
786
- await fs.copy(authSource, authDest, { overwrite: true });
787
- }
859
+ // Generate Supabase auth script if authentication is enabled
860
+ if (config.features?.authentication === 'supabase') {
861
+ await generateSupabaseAuthFiles(outputDir, config);
788
862
  }
789
863
  }
790
864
 
791
- // Create auth pages if needed
792
- if (config.features?.authentication) {
793
- await createAuthPages(outputDir, config);
794
- }
795
-
796
865
  // Copy 404.html for handling .md redirects
797
866
  const notFoundSource = path.join(assetsDir, '404.html');
798
867
  if (fs.existsSync(notFoundSource)) {
@@ -928,12 +997,46 @@ async function buildDocumentation(config) {
928
997
  // Generate robots.txt if enabled
929
998
  if (config.seo.generateRobotsTxt) {
930
999
  await generateRobotsTxt(config.seo.siteUrl, outputDir, {
931
- hasAuthentication: config.features?.authentication
1000
+ hasAuthentication: config.features?.authentication === 'supabase'
932
1001
  });
933
1002
  }
934
1003
  }
935
1004
 
936
- console.log(chalk.green('✅ Documentation build complete!'));
1005
+ // Copy attachment files if feature is enabled
1006
+ if (config.features?.attachments !== false) {
1007
+ console.log(chalk.blue('\n📎 Processing attachments...'));
1008
+
1009
+ const attachmentTypes = config.attachmentTypes || [
1010
+ '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.csv', '.ppt', '.pptx', '.txt', '.rtf',
1011
+ '.zip', '.tar', '.gz', '.7z', '.rar',
1012
+ '.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.ico', '.bmp',
1013
+ '.json', '.xml', '.yaml', '.yml', '.toml',
1014
+ '.mp4', '.mp3', '.wav', '.avi', '.mov'
1015
+ ];
1016
+
1017
+ try {
1018
+ const attachmentFiles = await getAllAttachmentFiles(docsDir, docsDir, attachmentTypes);
1019
+
1020
+ if (attachmentFiles.length > 0) {
1021
+ const { copiedCount, totalSize } = await copyAttachmentFiles(attachmentFiles, docsDir, outputDir);
1022
+
1023
+ // Format file size
1024
+ const formatSize = (bytes) => {
1025
+ if (bytes < 1024) return bytes + ' B';
1026
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
1027
+ return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
1028
+ };
1029
+
1030
+ console.log(chalk.green(`✅ Copied ${copiedCount} attachments (${formatSize(totalSize)} total)`));
1031
+ } else {
1032
+ console.log(chalk.gray(' No attachments found to copy'));
1033
+ }
1034
+ } catch (error) {
1035
+ console.warn(chalk.yellow(`Warning: Error processing attachments: ${error.message}`));
1036
+ }
1037
+ }
1038
+
1039
+ console.log(chalk.green('\n✅ Documentation build complete!'));
937
1040
  }
938
1041
 
939
1042
  // Create placeholder README.md if missing
@@ -1047,82 +1150,33 @@ For help with @knowcode/doc-builder:
1047
1150
  }
1048
1151
  }
1049
1152
 
1050
- // Create login/logout pages
1051
- async function createAuthPages(outputDir, config) {
1052
- // Login page
1053
- const loginHTML = `<!DOCTYPE html>
1054
- <html lang="en">
1055
- <head>
1056
- <meta charset="UTF-8">
1057
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1058
- <title>Login - ${config.siteName}</title>
1059
- <link rel="stylesheet" href="css/notion-style.css">
1060
- </head>
1061
- <body>
1062
- <div class="auth-container">
1063
- <div class="auth-box">
1064
- <h1>Login to ${config.siteName}</h1>
1065
- <form id="login-form">
1066
- <div class="form-group">
1067
- <label for="username">Username</label>
1068
- <input type="text" id="username" name="username" required>
1069
- </div>
1070
- <div class="form-group">
1071
- <label for="password">Password</label>
1072
- <input type="password" id="password" name="password" required>
1073
- </div>
1074
- <button type="submit" class="auth-button">Login</button>
1075
- </form>
1076
- <div id="error-message" class="error-message"></div>
1077
- </div>
1078
- </div>
1079
- <script>
1080
- document.getElementById('login-form').addEventListener('submit', function(e) {
1081
- e.preventDefault();
1082
- const username = document.getElementById('username').value;
1083
- const password = document.getElementById('password').value;
1084
-
1085
- // Validate credentials
1086
- if (username === '${config.auth.username}' && password === '${config.auth.password}') {
1087
- // Set auth cookie
1088
- const token = btoa(username + ':' + password);
1089
- document.cookie = 'doc-auth=' + token + '; path=/';
1090
-
1091
- // Redirect
1092
- const params = new URLSearchParams(window.location.search);
1093
- const redirect = params.get('redirect') || '/';
1094
- window.location.href = redirect;
1095
- } else {
1096
- document.getElementById('error-message').textContent = 'Invalid username or password';
1097
- }
1098
- });
1099
- </script>
1100
- </body>
1101
- </html>`;
1153
+ // Generate all Supabase authentication files
1154
+ async function generateSupabaseAuthFiles(outputDir, config) {
1155
+ // Validate Supabase configuration
1156
+ const validationErrors = SupabaseAuth.validateConfig(config);
1157
+ if (validationErrors.length > 0) {
1158
+ throw new Error(`Supabase authentication configuration errors:\n${validationErrors.join('\n')}`);
1159
+ }
1102
1160
 
1103
- await fs.writeFile(path.join(outputDir, 'login.html'), loginHTML);
1161
+ // Create Supabase auth instance
1162
+ const supabaseAuth = new SupabaseAuth(config.auth);
1104
1163
 
1105
- // Logout page
1106
- const logoutHTML = `<!DOCTYPE html>
1107
- <html lang="en">
1108
- <head>
1109
- <meta charset="UTF-8">
1110
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1111
- <title>Logged Out - ${config.siteName}</title>
1112
- <link rel="stylesheet" href="css/notion-style.css">
1113
- </head>
1114
- <body>
1115
- <div class="auth-container">
1116
- <div class="auth-box">
1117
- <h1>You have been logged out</h1>
1118
- <p>Thank you for using ${config.siteName}.</p>
1119
- <a href="login.html" class="auth-button">Login Again</a>
1120
- </div>
1121
- </div>
1122
- </body>
1123
- </html>`;
1164
+ // Generate auth script and save to js/auth.js
1165
+ const authScript = supabaseAuth.generateAuthScript();
1166
+ await fs.writeFile(path.join(outputDir, 'js', 'auth.js'), authScript);
1167
+
1168
+ // Also copy to root for backward compatibility
1169
+ await fs.writeFile(path.join(outputDir, 'auth.js'), authScript);
1124
1170
 
1171
+ // Generate and write login page
1172
+ const loginHTML = supabaseAuth.generateLoginPage(config);
1173
+ await fs.writeFile(path.join(outputDir, 'login.html'), loginHTML);
1174
+
1175
+ // Generate and write logout page
1176
+ const logoutHTML = supabaseAuth.generateLogoutPage(config);
1125
1177
  await fs.writeFile(path.join(outputDir, 'logout.html'), logoutHTML);
1178
+
1179
+ console.log(chalk.green('✓ Generated Supabase authentication files'));
1126
1180
  }
1127
1181
 
1128
1182
  // Create default index page when no documentation exists