docs: implement Phase 2 - API documentation with TypeDoc

Set up TypeDoc to auto-generate comprehensive API reference documentation
from TypeScript source code.

Changes:
- Installed typedoc and typedoc-plugin-markdown (v0.2.0 plugins)
- Created typedoc.json configuration with 9 entry points
- Added docs:api and docs:watch npm scripts
- Fixed test file imports (validateNamespace → isValidNamespace)
- Updated tsconfig.json to exclude test files from compilation
- Generated markdown API documentation in docs/api-reference/generated/

Generated API documentation:
- 9 modules documented (lib/, hooks/, types/)
- lib/crypto - 14 encryption/certificate functions
- lib/controller - 5 Kubernetes API functions
- lib/validators - 6 validation functions
- lib/retry - Exponential backoff utilities
- lib/rbac - RBAC permission checking
- types - Result types, branded types, interfaces
- hooks/useSealedSecretEncryption - Encryption React hook
- hooks/usePermissions - RBAC React hooks
- hooks/useControllerHealth - Health monitoring hook

Benefits:
- Auto-generated from TypeScript source (stays in sync)
- Markdown format for easy integration
- Type signatures and JSDoc included
- Function parameters and return types documented
- Links between related types and functions

Phase 2 deliverables (2-3 days estimated, completed in 1 session):
 TypeDoc installed and configured
 Entry points identified for all core modules
 API documentation generated (9 modules, 40+ functions)
 npm scripts added for docs generation
 Test files excluded from documentation

Next: Phase 3 - User tutorials and guides

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
2026-02-11 23:27:18 -05:00
parent bdf19cd3bf
commit ebbdb42c05
98 changed files with 2951 additions and 5702 deletions
+165 -3
View File
@@ -1,18 +1,21 @@
{
"name": "headlamp-sealed-secrets",
"version": "0.1.0",
"version": "0.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "headlamp-sealed-secrets",
"version": "0.1.0",
"version": "0.2.0",
"license": "Apache-2.0",
"dependencies": {
"node-forge": "^1.3.1"
},
"devDependencies": {
"@kinvolk/headlamp-plugin": "^0.13.1",
"@types/node-forge": "^1.3.11"
"@types/node-forge": "^1.3.11",
"typedoc": "^0.28.16",
"typedoc-plugin-markdown": "^4.10.0"
}
},
"node_modules/@adobe/css-tools": {
@@ -1340,6 +1343,20 @@
"dev": true,
"license": "MIT"
},
"node_modules/@gerrit0/mini-shiki": {
"version": "3.22.0",
"resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.22.0.tgz",
"integrity": "sha512-jMpciqEVUBKE1QwU64S4saNMzpsSza6diNCk4MWAeCxO2+LFi2FIFmL2S0VDLzEJCxuvCbU783xi8Hp/gkM5CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/engine-oniguruma": "^3.22.0",
"@shikijs/langs": "^3.22.0",
"@shikijs/themes": "^3.22.0",
"@shikijs/types": "^3.22.0",
"@shikijs/vscode-textmate": "^10.0.2"
}
},
"node_modules/@gulpjs/to-absolute-glob": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@gulpjs/to-absolute-glob/-/to-absolute-glob-4.0.0.tgz",
@@ -2840,6 +2857,55 @@
"dev": true,
"license": "MIT"
},
"node_modules/@shikijs/engine-oniguruma": {
"version": "3.22.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.22.0.tgz",
"integrity": "sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "3.22.0",
"@shikijs/vscode-textmate": "^10.0.2"
}
},
"node_modules/@shikijs/langs": {
"version": "3.22.0",
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.22.0.tgz",
"integrity": "sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "3.22.0"
}
},
"node_modules/@shikijs/themes": {
"version": "3.22.0",
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.22.0.tgz",
"integrity": "sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "3.22.0"
}
},
"node_modules/@shikijs/types": {
"version": "3.22.0",
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.22.0.tgz",
"integrity": "sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4"
}
},
"node_modules/@shikijs/vscode-textmate": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
"integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
"dev": true,
"license": "MIT"
},
"node_modules/@standard-schema/spec": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
@@ -11058,6 +11124,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"uc.micro": "^2.0.0"
}
},
"node_modules/loader-runner": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
@@ -11156,6 +11232,13 @@
"yallist": "^3.0.2"
}
},
"node_modules/lunr": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
"dev": true,
"license": "MIT"
},
"node_modules/lz-string": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
@@ -11214,6 +11297,24 @@
"semver": "bin/semver.js"
}
},
"node_modules/markdown-it": {
"version": "14.1.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz",
"integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.4.0",
"linkify-it": "^5.0.0",
"mdurl": "^2.0.0",
"punycode.js": "^2.3.1",
"uc.micro": "^2.1.0"
},
"bin": {
"markdown-it": "bin/markdown-it.mjs"
}
},
"node_modules/matcher-collection": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-2.0.1.tgz",
@@ -11464,6 +11565,13 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
"dev": true,
"license": "MIT"
},
"node_modules/memfs": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz",
@@ -13581,6 +13689,16 @@
"node": ">=6"
}
},
"node_modules/punycode.js": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/pure-rand": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz",
@@ -16583,6 +16701,43 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/typedoc": {
"version": "0.28.16",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.16.tgz",
"integrity": "sha512-x4xW77QC3i5DUFMBp0qjukOTnr/sSg+oEs86nB3LjDslvAmwe/PUGDWbe3GrIqt59oTqoXK5GRK9tAa0sYMiog==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@gerrit0/mini-shiki": "^3.17.0",
"lunr": "^2.3.9",
"markdown-it": "^14.1.0",
"minimatch": "^9.0.5",
"yaml": "^2.8.1"
},
"bin": {
"typedoc": "bin/typedoc"
},
"engines": {
"node": ">= 18",
"pnpm": ">= 10"
},
"peerDependencies": {
"typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x"
}
},
"node_modules/typedoc-plugin-markdown": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.10.0.tgz",
"integrity": "sha512-psrg8Rtnv4HPWCsoxId+MzEN8TVK5jeKCnTbnGAbTBqcDapR9hM41bJT/9eAyKn9C2MDG9Qjh3MkltAYuLDoXg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"typedoc": "0.28.x"
}
},
"node_modules/typescript": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
@@ -16597,6 +16752,13 @@
"node": ">=14.17"
}
},
"node_modules/uc.micro": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
"dev": true,
"license": "MIT"
},
"node_modules/unbox-primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+6 -2
View File
@@ -30,7 +30,9 @@
"storybook": "headlamp-plugin storybook",
"storybook-build": "headlamp-plugin storybook-build",
"test": "headlamp-plugin test",
"i18n": "headlamp-plugin i18n"
"i18n": "headlamp-plugin i18n",
"docs:api": "typedoc",
"docs:watch": "typedoc --watch"
},
"keywords": [
"headlamp",
@@ -60,6 +62,8 @@
},
"devDependencies": {
"@kinvolk/headlamp-plugin": "^0.13.1",
"@types/node-forge": "^1.3.11"
"@types/node-forge": "^1.3.11",
"typedoc": "^0.28.16",
"typedoc-plugin-markdown": "^4.10.0"
}
}
@@ -15,7 +15,7 @@ const localStorageMock = {
import { describe, expect, it } from 'vitest';
import {
validateNamespace,
isValidNamespace,
validatePEMCertificate,
validateSecretKey,
validateSecretName,
@@ -83,22 +83,22 @@ describe('validators', () => {
describe('validateNamespace', () => {
it('should accept valid namespace names', () => {
expect(validateNamespace('default').valid).toBe(true);
expect(validateNamespace('kube-system').valid).toBe(true);
expect(validateNamespace('my-namespace').valid).toBe(true);
expect(validateNamespace('ns-123').valid).toBe(true);
expect(isValidNamespace('default').valid).toBe(true);
expect(isValidNamespace('kube-system').valid).toBe(true);
expect(isValidNamespace('my-namespace').valid).toBe(true);
expect(isValidNamespace('ns-123').valid).toBe(true);
});
it('should reject invalid namespace names', () => {
expect(validateNamespace('').valid).toBe(false);
expect(validateNamespace('My-Namespace').valid).toBe(false);
expect(validateNamespace('-namespace').valid).toBe(false);
expect(validateNamespace('namespace-').valid).toBe(false);
expect(validateNamespace('namespace_name').valid).toBe(false);
expect(isValidNamespace('').valid).toBe(false);
expect(isValidNamespace('My-Namespace').valid).toBe(false);
expect(isValidNamespace('-namespace').valid).toBe(false);
expect(isValidNamespace('namespace-').valid).toBe(false);
expect(isValidNamespace('namespace_name').valid).toBe(false);
});
it('should reject namespaces exceeding 63 characters', () => {
const result = validateNamespace('x'.repeat(64));
const result = isValidNamespace('x'.repeat(64));
expect(result.valid).toBe(false);
expect(result.error).toContain('63 characters');
});
+2 -1
View File
@@ -1,4 +1,5 @@
{
"extends": "./node_modules/@kinvolk/headlamp-plugin/config/plugins-tsconfig.json",
"include": ["./src/**/*"]
"include": ["./src/**/*"],
"exclude": ["./src/**/*.test.ts", "./src/**/*.test.tsx", "./src/**/test-setup.ts"]
}
+26
View File
@@ -0,0 +1,26 @@
{
"$schema": "https://typedoc.org/schema.json",
"entryPoints": [
"src/lib/crypto.ts",
"src/lib/controller.ts",
"src/lib/validators.ts",
"src/lib/retry.ts",
"src/lib/rbac.ts",
"src/types.ts",
"src/hooks/useSealedSecretEncryption.ts",
"src/hooks/usePermissions.ts",
"src/hooks/useControllerHealth.ts"
],
"out": "../docs/api-reference/generated",
"name": "Headlamp Sealed Secrets API",
"exclude": ["**/*.test.ts", "**/*.test.tsx", "**/test-setup.ts"],
"excludePrivate": true,
"excludeProtected": true,
"excludeExternals": true,
"plugin": ["typedoc-plugin-markdown"],
"readme": "none",
"githubPages": false,
"disableSources": false,
"includeVersion": true,
"sort": ["source-order"]
}