@knowcode/doc-builder 1.7.5 → 1.8.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/.claude/settings.local.json +3 -1
- package/CHANGELOG.md +54 -0
- package/README.md +24 -1
- package/add-user-clive.sql +35 -0
- package/add-user-lindsay-fixed.sql +85 -0
- package/add-user-lindsay.sql +68 -0
- package/add-user-pmorgan.sql +35 -0
- package/add-user-robbie.sql +35 -0
- package/add-wru-users.sql +105 -0
- package/assets/css/notion-style.css +9 -1
- package/cli.js +9 -1
- package/html/README.html +5 -19
- package/html/css/notion-style.css +9 -1
- package/html/documentation-index.html +5 -19
- package/html/guides/authentication-default-change.html +5 -19
- package/html/guides/authentication-guide.html +189 -262
- package/html/guides/cache-control-anti-pattern.html +3 -3
- package/html/guides/claude-workflow-guide.html +5 -19
- package/html/guides/documentation-standards.html +5 -19
- package/html/guides/next-steps-walkthrough.html +3 -3
- package/html/guides/phosphor-icons-guide.html +5 -19
- package/html/guides/private-directory-authentication.html +352 -0
- package/html/guides/public-site-deployment.html +11 -24
- package/html/guides/search-engine-verification-guide.html +5 -19
- package/html/guides/seo-guide.html +5 -19
- package/html/guides/seo-optimization-guide.html +5 -19
- package/html/guides/supabase-auth-implementation-plan.html +3 -3
- package/html/guides/supabase-auth-integration-plan.html +3 -3
- package/html/guides/supabase-auth-setup-guide.html +3 -3
- package/html/guides/troubleshooting-guide.html +5 -19
- package/html/guides/vercel-deployment-auth-setup.html +3 -3
- package/html/guides/windows-setup-guide.html +5 -19
- package/html/index.html +5 -19
- package/html/launch/README.html +3 -3
- package/html/launch/bubble-plugin-specification.html +3 -3
- package/html/launch/go-to-market-strategy.html +3 -3
- package/html/launch/launch-announcements.html +3 -3
- package/html/private/cache-control-anti-pattern.html +347 -0
- package/html/private/launch/README.html +289 -0
- package/html/private/launch/auth-cleanup-summary.html +279 -0
- package/html/private/launch/bubble-plugin-specification.html +925 -0
- package/html/private/launch/go-to-market-strategy.html +655 -0
- package/html/private/launch/launch-announcements.html +585 -0
- package/html/private/launch/vercel-deployment-auth-setup.html +329 -0
- package/html/private/next-steps-walkthrough.html +624 -0
- package/html/private/supabase-auth-implementation-completed.html +372 -0
- package/html/private/supabase-auth-implementation-plan.html +529 -0
- package/html/private/supabase-auth-integration-plan.html +657 -0
- package/html/private/supabase-auth-setup-guide.html +484 -0
- package/html/private/test-private-doc.html +220 -0
- package/html/sitemap.xml +113 -29
- package/html/vercel-cli-setup-guide.html +5 -19
- package/html/vercel-first-time-setup-guide.html +5 -19
- package/lib/config.js +46 -3
- package/lib/core-builder.js +131 -7
- package/lib/supabase-auth.js +60 -11
- package/manage-users.sql +191 -0
- package/package.json +1 -1
- package/user-management/README.md +81 -0
- package/user-management/add-users.sh +357 -0
- package/user-management/users.txt +15 -0
- package/view-all-users.sql +40 -0
- package/wru-auth-config.js +17 -0
- package/assets/js/auth.js +0 -67
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"name": "Knowcode Ltd",
|
|
66
66
|
"url": "https://knowcode.tech"
|
|
67
67
|
},
|
|
68
|
-
"datePublished": "2025-07-
|
|
69
|
-
"dateModified": "2025-07-
|
|
68
|
+
"datePublished": "2025-07-26T09:59:23.016Z",
|
|
69
|
+
"dateModified": "2025-07-26T09:59:23.016Z",
|
|
70
70
|
"mainEntityOfPage": {
|
|
71
71
|
"@type": "WebPage",
|
|
72
72
|
"@id": "https://doc-builder-delta.vercel.app/vercel-first-time-setup-guide.html"
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
|
|
100
100
|
<div class="header-actions">
|
|
101
101
|
<div class="deployment-info">
|
|
102
|
-
<span class="deployment-date" title="Built with doc-builder v1.
|
|
102
|
+
<span class="deployment-date" title="Built with doc-builder v1.8.0">Last updated: Jul 26, 2025, 09:59 AM UTC</span>
|
|
103
103
|
</div>
|
|
104
104
|
|
|
105
105
|
|
|
@@ -158,31 +158,17 @@
|
|
|
158
158
|
</a>
|
|
159
159
|
<div class="nav-content collapsed" id="nav-guides-1">
|
|
160
160
|
<a href="/guides/authentication-default-change.html" class="nav-item" data-tooltip="Starting from version 1.7.4, @knowcode/doc-builder now defaults to no authentication for all documentation sites."><i class="fas fa-file-alt"></i> Authentication Default Change</a>
|
|
161
|
-
<a href="/guides/authentication-guide.html" class="nav-item" data-tooltip="
|
|
162
|
-
<a href="/guides/cache-control-anti-pattern.html" class="nav-item" data-tooltip="Cache Control Anti-Pattern: Why Aggressive Cache-Busting is Bad for Documentation Sites."><i class="fas fa-file-alt"></i> Cache Control Anti Pattern</a>
|
|
161
|
+
<a href="/guides/authentication-guide.html" class="nav-item" data-tooltip="@knowcode/doc-builder supports enterprise-grade authentication through Supabase - a secure, scalable authentication platform."><i class="fas fa-file-alt"></i> Authentication Guide</a>
|
|
163
162
|
<a href="/guides/claude-workflow-guide.html" class="nav-item" data-tooltip="This guide demonstrates an efficient workflow for using Claude Code with a refined CLAUDE.md file to create high-quality documentation and deploy it..."><i class="fas fa-file-alt"></i> Claude Workflow Guide</a>
|
|
164
163
|
<a href="/guides/documentation-standards.html" class="nav-item" data-tooltip="This document defines the documentation standards and conventions for the @knowcode/doc-builder project."><i class="fas fa-file-alt"></i> Documentation Standards</a>
|
|
165
|
-
<a href="/guides/next-steps-walkthrough.html" class="nav-item" data-tooltip="Now that we've implemented Supabase authentication, let's walk through testing the implementation and preparing for deployment."><i class="fas fa-file-alt"></i> Next Steps Walkthrough</a>
|
|
166
164
|
<a href="/guides/phosphor-icons-guide.html" class="nav-item" data-tooltip="@knowcode/doc-builder automatically converts Unicode emojis in your markdown files to beautiful Phosphor icons in the generated HTML."><i class="fas fa-file-alt"></i> Phosphor Icons Guide</a>
|
|
165
|
+
<a href="/guides/private-directory-authentication.html" class="nav-item" data-tooltip="The @knowcode/doc-builder now includes automatic authentication for documents placed in a directory."><i class="fas fa-file-alt"></i> Private Directory Authentication</a>
|
|
167
166
|
<a href="/guides/public-site-deployment.html" class="nav-item" data-tooltip="The @knowcode/doc-builder now supports deploying public documentation sites without authentication."><i class="fas fa-file-alt"></i> Public Site Deployment</a>
|
|
168
167
|
<a href="/guides/search-engine-verification-guide.html" class="nav-item" data-tooltip="Search engine verification provides access to powerful webmaster tools:."><i class="fas fa-file-alt"></i> Search Engine Verification Guide</a>
|
|
169
168
|
<a href="/guides/seo-guide.html" class="nav-item" data-tooltip="@knowcode/doc-builder includes comprehensive SEO (Search Engine Optimization) features to help your documentation rank better in search results and..."><i class="fas fa-file-alt"></i> Seo Guide</a>
|
|
170
169
|
<a href="/guides/seo-optimization-guide.html" class="nav-item" data-tooltip="@knowcode/doc-builder includes comprehensive SEO (Search Engine Optimization) features that automatically optimize your documentation for search..."><i class="fas fa-file-alt"></i> Seo Optimization Guide</a>
|
|
171
|
-
<a href="/guides/supabase-auth-implementation-plan.html" class="nav-item" data-tooltip="Supabase Auth Implementation Plan for @knowcode/doc-builder."><i class="fas fa-file-alt"></i> Supabase Auth Implementation Plan</a>
|
|
172
|
-
<a href="/guides/supabase-auth-integration-plan.html" class="nav-item" data-tooltip="Supabase Authentication Integration Plan for @knowcode/doc-builder."><i class="fas fa-file-alt"></i> Supabase Auth Integration Plan</a>
|
|
173
|
-
<a href="/guides/supabase-auth-setup-guide.html" class="nav-item" data-tooltip="@knowcode/doc-builder now supports enterprise-grade authentication through Supabase, replacing the previous insecure basic authentication."><i class="fas fa-file-alt"></i> Supabase Auth Setup Guide</a>
|
|
174
170
|
<a href="/guides/troubleshooting-guide.html" class="nav-item" data-tooltip="This guide helps you resolve common issues when using @knowcode/doc-builder."><i class="fas fa-file-alt"></i> Troubleshooting Guide</a>
|
|
175
|
-
<a href="/guides/vercel-deployment-auth-setup.html" class="nav-item" data-tooltip="Vercel Deployment Authentication Setup Guide."><i class="fas fa-file-alt"></i> Vercel Deployment Auth Setup</a>
|
|
176
171
|
<a href="/guides/windows-setup-guide.html" class="nav-item" data-tooltip="This guide helps Windows users set up the complete AI-powered documentation workflow using Claude Code, @knowcode/doc-builder, and Vercel."><i class="fas fa-file-alt"></i> Windows Setup Guide</a></div></div>
|
|
177
|
-
<div class="nav-section" data-level="1">
|
|
178
|
-
<a class="nav-title collapsible" href="/launch/README.html" data-target="nav-launch-1" >
|
|
179
|
-
<i class="fas fa-chevron-right collapse-icon"></i><i class="fas fa-folder"></i> Launch
|
|
180
|
-
</a>
|
|
181
|
-
<div class="nav-content collapsed" id="nav-launch-1">
|
|
182
|
-
<a href="/launch/README.html" class="nav-item" data-tooltip="This directory contains all documentation related to the commercial launch of @knowcode/doc-builder, including go-to-market strategy, platform..."><i class="fas fa-file-alt"></i> Launch Overview</a>
|
|
183
|
-
<a href="/launch/bubble-plugin-specification.html" class="nav-item" data-tooltip="This document outlines the technical specification for creating a Bubble.io plugin that integrates @knowcode/doc-builder, enabling Bubble developers..."><i class="fas fa-file-alt"></i> Bubble Plugin Specification</a>
|
|
184
|
-
<a href="/launch/go-to-market-strategy.html" class="nav-item" data-tooltip="Go-to-Market Strategy & Product Launch Plan."><i class="fas fa-file-alt"></i> Go To Market Strategy</a>
|
|
185
|
-
<a href="/launch/launch-announcements.html" class="nav-item" data-tooltip="This document contains ready-to-use announcement templates for launching @knowcode/doc-builder across various platforms and channels."><i class="fas fa-file-alt"></i> Launch Announcements</a></div></div>
|
|
186
172
|
</nav>
|
|
187
173
|
<div class="resize-handle"></div>
|
|
188
174
|
</aside>
|
package/lib/config.js
CHANGED
|
@@ -30,7 +30,8 @@ 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
|
|
33
|
+
menuDefaultOpen: true, // Menu/sidebar open by default
|
|
34
|
+
attachments: true // Copy attachments (Excel, PDF, etc.) to output
|
|
34
35
|
},
|
|
35
36
|
|
|
36
37
|
// Authentication - Supabase only (basic auth removed for security)
|
|
@@ -78,7 +79,21 @@ const defaultConfig = {
|
|
|
78
79
|
generateSitemap: true,
|
|
79
80
|
generateRobotsTxt: true,
|
|
80
81
|
customMetaTags: []
|
|
81
|
-
}
|
|
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
|
+
]
|
|
82
97
|
};
|
|
83
98
|
|
|
84
99
|
/**
|
|
@@ -102,7 +117,8 @@ const notionInspiredPreset = {
|
|
|
102
117
|
phosphorSize: '1.2em',
|
|
103
118
|
normalizeTitle: true,
|
|
104
119
|
showPdfDownload: true,
|
|
105
|
-
menuDefaultOpen: true
|
|
120
|
+
menuDefaultOpen: true,
|
|
121
|
+
attachments: true
|
|
106
122
|
},
|
|
107
123
|
|
|
108
124
|
auth: {
|
|
@@ -261,6 +277,9 @@ async function loadConfig(configPath, options = {}) {
|
|
|
261
277
|
if (options.menuClosed === true) {
|
|
262
278
|
config.features.menuDefaultOpen = false;
|
|
263
279
|
}
|
|
280
|
+
if (options.attachments === false) {
|
|
281
|
+
config.features.attachments = false;
|
|
282
|
+
}
|
|
264
283
|
|
|
265
284
|
// Legacy mode - auto-detect structure
|
|
266
285
|
if (options.legacy) {
|
|
@@ -284,6 +303,30 @@ async function loadConfig(configPath, options = {}) {
|
|
|
284
303
|
console.log(chalk.gray(`Create it with: mkdir ${config.docsDir} && echo "# Documentation" > ${config.docsDir}/README.md`));
|
|
285
304
|
}
|
|
286
305
|
// Don't throw error - let commands handle missing directories appropriately
|
|
306
|
+
} else {
|
|
307
|
+
// Check for private directory and auto-enable authentication if found
|
|
308
|
+
const privatePath = path.join(docsPath, 'private');
|
|
309
|
+
if (fs.existsSync(privatePath) && fs.statSync(privatePath).isDirectory()) {
|
|
310
|
+
// Only auto-enable if not already configured
|
|
311
|
+
if (!config.features.authentication) {
|
|
312
|
+
console.log(chalk.blue('🔐 Found private directory - automatically enabling Supabase authentication'));
|
|
313
|
+
config.features.authentication = 'supabase';
|
|
314
|
+
config.features.autoAuthEnabled = true; // Track that this was auto-enabled
|
|
315
|
+
|
|
316
|
+
// Check if Supabase credentials are configured
|
|
317
|
+
if (!config.auth.supabaseUrl || !config.auth.supabaseAnonKey || !config.auth.siteId) {
|
|
318
|
+
console.warn(chalk.yellow('⚠️ Supabase credentials not configured. Private directory found but authentication will not work.'));
|
|
319
|
+
console.warn(chalk.yellow(' To enable authentication, set the following in your config:'));
|
|
320
|
+
console.warn(chalk.yellow(' - auth.supabaseUrl'));
|
|
321
|
+
console.warn(chalk.yellow(' - auth.supabaseAnonKey'));
|
|
322
|
+
console.warn(chalk.yellow(' - auth.siteId'));
|
|
323
|
+
console.warn(chalk.yellow(''));
|
|
324
|
+
console.warn(chalk.yellow(' Or disable authentication by removing the private directory.'));
|
|
325
|
+
// Disable authentication if credentials are missing
|
|
326
|
+
config.features.authentication = false;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
287
330
|
}
|
|
288
331
|
|
|
289
332
|
return config;
|
package/lib/core-builder.js
CHANGED
|
@@ -362,6 +362,21 @@ ${seoTags}
|
|
|
362
362
|
visibility: visible;
|
|
363
363
|
opacity: 1;
|
|
364
364
|
}
|
|
365
|
+
/* Style auth button consistently */
|
|
366
|
+
.auth-btn {
|
|
367
|
+
background: none;
|
|
368
|
+
border: none;
|
|
369
|
+
color: var(--text-secondary);
|
|
370
|
+
cursor: pointer;
|
|
371
|
+
padding: 0.5rem;
|
|
372
|
+
border-radius: 0.5rem;
|
|
373
|
+
transition: all 0.2s;
|
|
374
|
+
font-size: 1.1rem;
|
|
375
|
+
}
|
|
376
|
+
.auth-btn:hover {
|
|
377
|
+
background: var(--bg-secondary);
|
|
378
|
+
color: var(--text-primary);
|
|
379
|
+
}
|
|
365
380
|
</style>
|
|
366
381
|
` : ''}
|
|
367
382
|
|
|
@@ -389,8 +404,8 @@ ${seoTags}
|
|
|
389
404
|
</div>
|
|
390
405
|
|
|
391
406
|
${config.features?.authentication === 'supabase' ? `
|
|
392
|
-
<a href="${relativePath}
|
|
393
|
-
<i class="fas fa-sign-
|
|
407
|
+
<a href="${relativePath}login.html" class="auth-btn" title="Login/Logout">
|
|
408
|
+
<i class="fas fa-sign-in-alt"></i>
|
|
394
409
|
</a>
|
|
395
410
|
` : ''}
|
|
396
411
|
|
|
@@ -484,10 +499,23 @@ const folderDescriptions = {
|
|
|
484
499
|
};
|
|
485
500
|
|
|
486
501
|
// Build navigation structure with rich functionality
|
|
487
|
-
function buildNavigationStructure(files, currentFile) {
|
|
502
|
+
function buildNavigationStructure(files, currentFile, config = {}) {
|
|
488
503
|
const tree = { files: [], folders: {} };
|
|
489
504
|
|
|
505
|
+
// Check if authentication is enabled
|
|
506
|
+
const isAuthEnabled = config.features?.authentication === 'supabase';
|
|
507
|
+
|
|
508
|
+
// Filter files based on authentication status and whether we're building for an authenticated page
|
|
509
|
+
// We'll pass a flag from processMarkdownFile to indicate if this is a private page
|
|
510
|
+
const isPrivatePage = currentFile && (currentFile.startsWith('private/') || currentFile.includes('/private/'));
|
|
511
|
+
const shouldIncludePrivate = isAuthEnabled && isPrivatePage;
|
|
512
|
+
|
|
490
513
|
files.forEach(file => {
|
|
514
|
+
// Skip private files if we're not on an authenticated page
|
|
515
|
+
if (file.isPrivate && !shouldIncludePrivate) {
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
|
|
491
519
|
const parts = file.urlPath.split('/');
|
|
492
520
|
let current = tree;
|
|
493
521
|
|
|
@@ -704,8 +732,8 @@ async function processMarkdownFile(filePath, outputPath, allFiles, config) {
|
|
|
704
732
|
// Process content
|
|
705
733
|
const htmlContent = processMarkdownContent(content, config);
|
|
706
734
|
|
|
707
|
-
// Build navigation
|
|
708
|
-
const navigation = buildNavigationStructure(allFiles, urlPath);
|
|
735
|
+
// Build navigation - pass config to handle private file filtering
|
|
736
|
+
const navigation = buildNavigationStructure(allFiles, urlPath, config);
|
|
709
737
|
|
|
710
738
|
// Generate full HTML (pass original content and front matter for SEO)
|
|
711
739
|
const html = generateHTML(title, htmlContent, navigation, urlPath, config, content, frontMatter);
|
|
@@ -740,12 +768,18 @@ async function getAllMarkdownFiles(dir, baseDir = dir) {
|
|
|
740
768
|
const content = await fs.readFile(fullPath, 'utf-8');
|
|
741
769
|
const summary = extractSummary(content);
|
|
742
770
|
|
|
771
|
+
// Check if this file is in the private directory
|
|
772
|
+
const isPrivate = relativePath.split(path.sep)[0] === 'private' ||
|
|
773
|
+
relativePath.startsWith('private/') ||
|
|
774
|
+
relativePath.startsWith('private\\');
|
|
775
|
+
|
|
743
776
|
files.push({
|
|
744
777
|
path: fullPath,
|
|
745
778
|
relativePath,
|
|
746
779
|
urlPath,
|
|
747
780
|
displayName,
|
|
748
|
-
summary
|
|
781
|
+
summary,
|
|
782
|
+
isPrivate
|
|
749
783
|
});
|
|
750
784
|
}
|
|
751
785
|
}
|
|
@@ -753,6 +787,62 @@ async function getAllMarkdownFiles(dir, baseDir = dir) {
|
|
|
753
787
|
return files;
|
|
754
788
|
}
|
|
755
789
|
|
|
790
|
+
// Get all attachment files
|
|
791
|
+
async function getAllAttachmentFiles(dir, baseDir = dir, attachmentTypes) {
|
|
792
|
+
const files = [];
|
|
793
|
+
const items = await fs.readdir(dir);
|
|
794
|
+
|
|
795
|
+
for (const item of items) {
|
|
796
|
+
const fullPath = path.join(dir, item);
|
|
797
|
+
const stat = await fs.stat(fullPath);
|
|
798
|
+
|
|
799
|
+
if (stat.isDirectory() && !item.startsWith('.')) {
|
|
800
|
+
// Recursively scan subdirectories
|
|
801
|
+
const subFiles = await getAllAttachmentFiles(fullPath, baseDir, attachmentTypes);
|
|
802
|
+
files.push(...subFiles);
|
|
803
|
+
} else {
|
|
804
|
+
// Check if file is an attachment type
|
|
805
|
+
const ext = path.extname(item).toLowerCase();
|
|
806
|
+
if (attachmentTypes.includes(ext) && !item.startsWith('.')) {
|
|
807
|
+
const relativePath = path.relative(baseDir, fullPath);
|
|
808
|
+
files.push({
|
|
809
|
+
path: fullPath,
|
|
810
|
+
relativePath,
|
|
811
|
+
size: stat.size
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
return files;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// Copy attachment files to output directory
|
|
821
|
+
async function copyAttachmentFiles(attachmentFiles, docsDir, outputDir) {
|
|
822
|
+
let totalSize = 0;
|
|
823
|
+
let copiedCount = 0;
|
|
824
|
+
|
|
825
|
+
for (const file of attachmentFiles) {
|
|
826
|
+
try {
|
|
827
|
+
const outputPath = path.join(outputDir, file.relativePath);
|
|
828
|
+
const outputDirPath = path.dirname(outputPath);
|
|
829
|
+
|
|
830
|
+
// Create directory if it doesn't exist
|
|
831
|
+
await fs.ensureDir(outputDirPath);
|
|
832
|
+
|
|
833
|
+
// Copy the file
|
|
834
|
+
await fs.copy(file.path, outputPath, { overwrite: true });
|
|
835
|
+
|
|
836
|
+
totalSize += file.size;
|
|
837
|
+
copiedCount++;
|
|
838
|
+
} catch (error) {
|
|
839
|
+
console.warn(chalk.yellow(`Warning: Could not copy ${file.relativePath}: ${error.message}`));
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
return { copiedCount, totalSize };
|
|
844
|
+
}
|
|
845
|
+
|
|
756
846
|
// Main build function
|
|
757
847
|
async function buildDocumentation(config) {
|
|
758
848
|
const docsDir = path.join(process.cwd(), config.docsDir);
|
|
@@ -946,7 +1036,41 @@ async function buildDocumentation(config) {
|
|
|
946
1036
|
}
|
|
947
1037
|
}
|
|
948
1038
|
|
|
949
|
-
|
|
1039
|
+
// Copy attachment files if feature is enabled
|
|
1040
|
+
if (config.features?.attachments !== false) {
|
|
1041
|
+
console.log(chalk.blue('\n📎 Processing attachments...'));
|
|
1042
|
+
|
|
1043
|
+
const attachmentTypes = config.attachmentTypes || [
|
|
1044
|
+
'.pdf', '.doc', '.docx', '.xls', '.xlsx', '.csv', '.ppt', '.pptx', '.txt', '.rtf',
|
|
1045
|
+
'.zip', '.tar', '.gz', '.7z', '.rar',
|
|
1046
|
+
'.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.ico', '.bmp',
|
|
1047
|
+
'.json', '.xml', '.yaml', '.yml', '.toml',
|
|
1048
|
+
'.mp4', '.mp3', '.wav', '.avi', '.mov'
|
|
1049
|
+
];
|
|
1050
|
+
|
|
1051
|
+
try {
|
|
1052
|
+
const attachmentFiles = await getAllAttachmentFiles(docsDir, docsDir, attachmentTypes);
|
|
1053
|
+
|
|
1054
|
+
if (attachmentFiles.length > 0) {
|
|
1055
|
+
const { copiedCount, totalSize } = await copyAttachmentFiles(attachmentFiles, docsDir, outputDir);
|
|
1056
|
+
|
|
1057
|
+
// Format file size
|
|
1058
|
+
const formatSize = (bytes) => {
|
|
1059
|
+
if (bytes < 1024) return bytes + ' B';
|
|
1060
|
+
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
|
1061
|
+
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
1062
|
+
};
|
|
1063
|
+
|
|
1064
|
+
console.log(chalk.green(`✅ Copied ${copiedCount} attachments (${formatSize(totalSize)} total)`));
|
|
1065
|
+
} else {
|
|
1066
|
+
console.log(chalk.gray(' No attachments found to copy'));
|
|
1067
|
+
}
|
|
1068
|
+
} catch (error) {
|
|
1069
|
+
console.warn(chalk.yellow(`Warning: Error processing attachments: ${error.message}`));
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
console.log(chalk.green('\n✅ Documentation build complete!'));
|
|
950
1074
|
}
|
|
951
1075
|
|
|
952
1076
|
// Create placeholder README.md if missing
|
package/lib/supabase-auth.js
CHANGED
|
@@ -58,11 +58,22 @@ class SupabaseAuth {
|
|
|
58
58
|
// Check authentication and site access
|
|
59
59
|
async function checkAuth() {
|
|
60
60
|
try {
|
|
61
|
+
// Check if current page is in private directory
|
|
62
|
+
const currentPath = window.location.pathname;
|
|
63
|
+
const isPrivatePage = currentPath.includes('/private/');
|
|
64
|
+
|
|
61
65
|
// Get current user session
|
|
62
66
|
const { data: { user }, error: userError } = await supabaseClient.auth.getUser();
|
|
63
67
|
|
|
64
68
|
if (userError || !user) {
|
|
65
|
-
|
|
69
|
+
// Only redirect if we're on a private page
|
|
70
|
+
if (isPrivatePage) {
|
|
71
|
+
redirectToLogin();
|
|
72
|
+
} else {
|
|
73
|
+
// Public page, just show it
|
|
74
|
+
document.body.classList.add('authenticated'); // Use same class to show body
|
|
75
|
+
updateAuthButton(false);
|
|
76
|
+
}
|
|
66
77
|
return;
|
|
67
78
|
}
|
|
68
79
|
|
|
@@ -75,17 +86,30 @@ class SupabaseAuth {
|
|
|
75
86
|
.single();
|
|
76
87
|
|
|
77
88
|
if (accessError || !access) {
|
|
78
|
-
|
|
89
|
+
if (isPrivatePage) {
|
|
90
|
+
showAccessDenied();
|
|
91
|
+
} else {
|
|
92
|
+
// Public page, just show it
|
|
93
|
+
document.body.classList.add('authenticated');
|
|
94
|
+
updateAuthButton(false);
|
|
95
|
+
}
|
|
79
96
|
return;
|
|
80
97
|
}
|
|
81
98
|
|
|
82
99
|
// User is authenticated and has access
|
|
83
100
|
console.log('User authenticated and authorized');
|
|
84
101
|
document.body.classList.add('authenticated');
|
|
102
|
+
updateAuthButton(true);
|
|
85
103
|
|
|
86
104
|
} catch (error) {
|
|
87
105
|
console.error('Auth check failed:', error);
|
|
88
|
-
|
|
106
|
+
if (window.location.pathname.includes('/private/')) {
|
|
107
|
+
redirectToLogin();
|
|
108
|
+
} else {
|
|
109
|
+
// Public page, show it anyway
|
|
110
|
+
document.body.classList.add('authenticated');
|
|
111
|
+
updateAuthButton(false);
|
|
112
|
+
}
|
|
89
113
|
}
|
|
90
114
|
}
|
|
91
115
|
|
|
@@ -110,16 +134,41 @@ class SupabaseAuth {
|
|
|
110
134
|
\`;
|
|
111
135
|
}
|
|
112
136
|
|
|
113
|
-
//
|
|
137
|
+
// Function to update auth button
|
|
138
|
+
function updateAuthButton(isAuthenticated) {
|
|
139
|
+
const authBtn = document.querySelector('.auth-btn');
|
|
140
|
+
if (authBtn) {
|
|
141
|
+
const icon = authBtn.querySelector('i');
|
|
142
|
+
if (icon) {
|
|
143
|
+
if (isAuthenticated) {
|
|
144
|
+
icon.className = 'fas fa-sign-out-alt';
|
|
145
|
+
authBtn.title = 'Logout';
|
|
146
|
+
authBtn.href = '/logout.html';
|
|
147
|
+
} else {
|
|
148
|
+
icon.className = 'fas fa-sign-in-alt';
|
|
149
|
+
authBtn.title = 'Login';
|
|
150
|
+
authBtn.href = '/login.html';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Add auth button functionality
|
|
114
157
|
document.addEventListener('DOMContentLoaded', function() {
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
await supabaseClient.auth.
|
|
120
|
-
|
|
158
|
+
const authBtn = document.querySelector('.auth-btn');
|
|
159
|
+
if (authBtn) {
|
|
160
|
+
authBtn.addEventListener('click', async function(e) {
|
|
161
|
+
// Check if we're logged in
|
|
162
|
+
const { data: { user } } = await supabaseClient.auth.getUser();
|
|
163
|
+
if (user) {
|
|
164
|
+
// Logged in - sign out
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
await supabaseClient.auth.signOut();
|
|
167
|
+
window.location.href = '/logout.html';
|
|
168
|
+
}
|
|
169
|
+
// If not logged in, normal navigation to login page will occur
|
|
121
170
|
});
|
|
122
|
-
}
|
|
171
|
+
}
|
|
123
172
|
});
|
|
124
173
|
|
|
125
174
|
// Run auth check
|
package/manage-users.sql
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
-- =====================================================
|
|
2
|
+
-- USER MANAGEMENT SQL COMMANDS FOR DOC-BUILDER
|
|
3
|
+
-- =====================================================
|
|
4
|
+
-- Run these in your Supabase SQL Editor
|
|
5
|
+
|
|
6
|
+
-- =====================================================
|
|
7
|
+
-- 1. VIEW YOUR SITES
|
|
8
|
+
-- =====================================================
|
|
9
|
+
-- See all your documentation sites
|
|
10
|
+
SELECT id, domain, name, created_at
|
|
11
|
+
FROM docbuilder_sites
|
|
12
|
+
ORDER BY created_at DESC;
|
|
13
|
+
|
|
14
|
+
-- =====================================================
|
|
15
|
+
-- 2. VIEW EXISTING USERS
|
|
16
|
+
-- =====================================================
|
|
17
|
+
-- See all users in your Supabase project
|
|
18
|
+
SELECT id, email, created_at, last_sign_in_at
|
|
19
|
+
FROM auth.users
|
|
20
|
+
ORDER BY created_at DESC;
|
|
21
|
+
|
|
22
|
+
-- =====================================================
|
|
23
|
+
-- 3. VIEW WHO HAS ACCESS TO A SPECIFIC SITE
|
|
24
|
+
-- =====================================================
|
|
25
|
+
-- Replace 'your-site-id' with actual site ID
|
|
26
|
+
SELECT
|
|
27
|
+
u.email,
|
|
28
|
+
u.id as user_id,
|
|
29
|
+
u.created_at as user_since,
|
|
30
|
+
da.created_at as access_granted,
|
|
31
|
+
ds.name as site_name,
|
|
32
|
+
ds.domain
|
|
33
|
+
FROM docbuilder_access da
|
|
34
|
+
JOIN auth.users u ON u.id = da.user_id
|
|
35
|
+
JOIN docbuilder_sites ds ON ds.id = da.site_id
|
|
36
|
+
WHERE da.site_id = 'your-site-id'
|
|
37
|
+
ORDER BY da.created_at DESC;
|
|
38
|
+
|
|
39
|
+
-- =====================================================
|
|
40
|
+
-- 4. ADD A SINGLE USER TO A SITE
|
|
41
|
+
-- =====================================================
|
|
42
|
+
-- First, create user in Supabase Dashboard (Authentication > Users > Invite)
|
|
43
|
+
-- Then grant access:
|
|
44
|
+
INSERT INTO docbuilder_access (user_id, site_id)
|
|
45
|
+
VALUES (
|
|
46
|
+
(SELECT id FROM auth.users WHERE email = 'user@example.com'),
|
|
47
|
+
'your-site-id'
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
-- =====================================================
|
|
51
|
+
-- 5. ADD MULTIPLE USERS TO A SITE
|
|
52
|
+
-- =====================================================
|
|
53
|
+
-- Add a list of users all at once
|
|
54
|
+
WITH users_to_add AS (
|
|
55
|
+
SELECT email FROM (VALUES
|
|
56
|
+
('user1@example.com'),
|
|
57
|
+
('user2@example.com'),
|
|
58
|
+
('user3@example.com'),
|
|
59
|
+
('user4@example.com')
|
|
60
|
+
) AS t(email)
|
|
61
|
+
)
|
|
62
|
+
INSERT INTO docbuilder_access (user_id, site_id)
|
|
63
|
+
SELECT u.id, 'your-site-id'
|
|
64
|
+
FROM auth.users u
|
|
65
|
+
JOIN users_to_add ua ON u.email = ua.email
|
|
66
|
+
WHERE NOT EXISTS (
|
|
67
|
+
-- Prevent duplicate entries
|
|
68
|
+
SELECT 1 FROM docbuilder_access
|
|
69
|
+
WHERE user_id = u.id AND site_id = 'your-site-id'
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
-- =====================================================
|
|
73
|
+
-- 6. GRANT USER ACCESS TO MULTIPLE SITES
|
|
74
|
+
-- =====================================================
|
|
75
|
+
-- Give one user access to several sites
|
|
76
|
+
WITH sites_to_grant AS (
|
|
77
|
+
SELECT id FROM docbuilder_sites
|
|
78
|
+
WHERE domain IN ('site1.com', 'site2.com', 'site3.com')
|
|
79
|
+
)
|
|
80
|
+
INSERT INTO docbuilder_access (user_id, site_id)
|
|
81
|
+
SELECT
|
|
82
|
+
(SELECT id FROM auth.users WHERE email = 'user@example.com'),
|
|
83
|
+
s.id
|
|
84
|
+
FROM sites_to_grant s
|
|
85
|
+
WHERE NOT EXISTS (
|
|
86
|
+
SELECT 1 FROM docbuilder_access
|
|
87
|
+
WHERE user_id = (SELECT id FROM auth.users WHERE email = 'user@example.com')
|
|
88
|
+
AND site_id = s.id
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
-- =====================================================
|
|
92
|
+
-- 7. REMOVE USER ACCESS FROM A SITE
|
|
93
|
+
-- =====================================================
|
|
94
|
+
-- Remove specific user from specific site
|
|
95
|
+
DELETE FROM docbuilder_access
|
|
96
|
+
WHERE user_id = (SELECT id FROM auth.users WHERE email = 'user@example.com')
|
|
97
|
+
AND site_id = 'your-site-id';
|
|
98
|
+
|
|
99
|
+
-- =====================================================
|
|
100
|
+
-- 8. REMOVE USER FROM ALL SITES
|
|
101
|
+
-- =====================================================
|
|
102
|
+
-- Completely remove user's access to all documentation
|
|
103
|
+
DELETE FROM docbuilder_access
|
|
104
|
+
WHERE user_id = (SELECT id FROM auth.users WHERE email = 'user@example.com');
|
|
105
|
+
|
|
106
|
+
-- =====================================================
|
|
107
|
+
-- 9. BULK REMOVE USERS
|
|
108
|
+
-- =====================================================
|
|
109
|
+
-- Remove multiple users from a site
|
|
110
|
+
WITH users_to_remove AS (
|
|
111
|
+
SELECT email FROM (VALUES
|
|
112
|
+
('olduser1@example.com'),
|
|
113
|
+
('olduser2@example.com')
|
|
114
|
+
) AS t(email)
|
|
115
|
+
)
|
|
116
|
+
DELETE FROM docbuilder_access
|
|
117
|
+
WHERE site_id = 'your-site-id'
|
|
118
|
+
AND user_id IN (
|
|
119
|
+
SELECT u.id FROM auth.users u
|
|
120
|
+
JOIN users_to_remove ur ON u.email = ur.email
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
-- =====================================================
|
|
124
|
+
-- 10. VIEW ACCESS SUMMARY
|
|
125
|
+
-- =====================================================
|
|
126
|
+
-- See how many users each site has
|
|
127
|
+
SELECT
|
|
128
|
+
ds.name as site_name,
|
|
129
|
+
ds.domain,
|
|
130
|
+
ds.id as site_id,
|
|
131
|
+
COUNT(da.user_id) as user_count,
|
|
132
|
+
MAX(da.created_at) as last_access_granted
|
|
133
|
+
FROM docbuilder_sites ds
|
|
134
|
+
LEFT JOIN docbuilder_access da ON ds.id = da.site_id
|
|
135
|
+
GROUP BY ds.id, ds.name, ds.domain
|
|
136
|
+
ORDER BY user_count DESC;
|
|
137
|
+
|
|
138
|
+
-- =====================================================
|
|
139
|
+
-- 11. FIND USERS WITHOUT ACCESS TO ANY SITE
|
|
140
|
+
-- =====================================================
|
|
141
|
+
-- Useful for cleanup
|
|
142
|
+
SELECT u.email, u.created_at, u.last_sign_in_at
|
|
143
|
+
FROM auth.users u
|
|
144
|
+
WHERE NOT EXISTS (
|
|
145
|
+
SELECT 1 FROM docbuilder_access da
|
|
146
|
+
WHERE da.user_id = u.id
|
|
147
|
+
)
|
|
148
|
+
ORDER BY u.created_at DESC;
|
|
149
|
+
|
|
150
|
+
-- =====================================================
|
|
151
|
+
-- 12. AUDIT LOG - RECENT ACCESS GRANTS
|
|
152
|
+
-- =====================================================
|
|
153
|
+
-- See who was granted access recently
|
|
154
|
+
SELECT
|
|
155
|
+
u.email,
|
|
156
|
+
ds.name as site_name,
|
|
157
|
+
ds.domain,
|
|
158
|
+
da.created_at as access_granted
|
|
159
|
+
FROM docbuilder_access da
|
|
160
|
+
JOIN auth.users u ON u.id = da.user_id
|
|
161
|
+
JOIN docbuilder_sites ds ON ds.id = da.site_id
|
|
162
|
+
WHERE da.created_at > NOW() - INTERVAL '30 days'
|
|
163
|
+
ORDER BY da.created_at DESC;
|
|
164
|
+
|
|
165
|
+
-- =====================================================
|
|
166
|
+
-- 13. COPY ACCESS FROM ONE USER TO ANOTHER
|
|
167
|
+
-- =====================================================
|
|
168
|
+
-- Useful when replacing team members
|
|
169
|
+
INSERT INTO docbuilder_access (user_id, site_id)
|
|
170
|
+
SELECT
|
|
171
|
+
(SELECT id FROM auth.users WHERE email = 'newuser@example.com'),
|
|
172
|
+
da.site_id
|
|
173
|
+
FROM docbuilder_access da
|
|
174
|
+
WHERE da.user_id = (SELECT id FROM auth.users WHERE email = 'olduser@example.com');
|
|
175
|
+
|
|
176
|
+
-- =====================================================
|
|
177
|
+
-- COMMON SITE IDs FOR REFERENCE
|
|
178
|
+
-- =====================================================
|
|
179
|
+
-- Your test site: 4d8a53bf-dcdd-48c0-98e0-cd1451518735
|
|
180
|
+
-- Add more site IDs here as you create them:
|
|
181
|
+
-- Production site: xxx
|
|
182
|
+
-- Staging site: xxx
|
|
183
|
+
|
|
184
|
+
-- =====================================================
|
|
185
|
+
-- TIPS
|
|
186
|
+
-- =====================================================
|
|
187
|
+
-- 1. Always check if users exist before granting access
|
|
188
|
+
-- 2. Use the Supabase Dashboard to invite new users first
|
|
189
|
+
-- 3. Run SELECT queries before DELETE to verify
|
|
190
|
+
-- 4. Keep this file updated with your site IDs
|
|
191
|
+
-- 5. Consider creating views for common queries
|