koguma 0.6.6 → 2.0.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.
Files changed (44) hide show
  1. package/README.md +109 -139
  2. package/cli/auth.ts +101 -0
  3. package/cli/config.ts +149 -0
  4. package/cli/constants.ts +38 -0
  5. package/cli/content.ts +503 -0
  6. package/cli/dev-sync.ts +305 -0
  7. package/cli/exec.ts +61 -0
  8. package/cli/index.ts +779 -1545
  9. package/cli/log.ts +49 -0
  10. package/cli/preflight.ts +105 -0
  11. package/cli/scaffold.ts +680 -0
  12. package/cli/typegen.ts +190 -0
  13. package/cli/ui.ts +55 -0
  14. package/cli/wrangler.ts +367 -0
  15. package/package.json +7 -4
  16. package/src/admin/_bundle.ts +1 -1
  17. package/src/api/router.integration.test.ts +63 -80
  18. package/src/api/router.ts +85 -59
  19. package/src/config/define.ts +1 -1
  20. package/src/config/field.ts +10 -9
  21. package/src/config/index.ts +1 -13
  22. package/src/config/meta.ts +7 -7
  23. package/src/config/types.ts +1 -95
  24. package/src/db/init.ts +68 -0
  25. package/src/db/queries.ts +120 -211
  26. package/src/db/sql.ts +10 -25
  27. package/src/media/index.ts +105 -47
  28. package/src/react/Markdown.test.tsx +195 -0
  29. package/src/react/Markdown.tsx +40 -0
  30. package/src/react/index.ts +6 -22
  31. package/src/react/types.ts +3 -112
  32. package/src/db/migrate.ts +0 -182
  33. package/src/db/schema.ts +0 -122
  34. package/src/react/RichText.test.tsx +0 -535
  35. package/src/react/RichText.tsx +0 -350
  36. package/src/rich-text/index.ts +0 -4
  37. package/src/rich-text/koguma-to-lexical.ts +0 -340
  38. package/src/rich-text/lexical-compat.test.ts +0 -513
  39. package/src/rich-text/lexical-to-koguma.test.ts +0 -906
  40. package/src/rich-text/lexical-to-koguma.ts +0 -400
  41. package/src/rich-text/markdown-to-koguma.ts +0 -164
  42. package/src/rich-text/plain.test.ts +0 -208
  43. package/src/rich-text/plain.ts +0 -114
  44. package/src/rich-text/snapshots.test.ts +0 -284
package/cli/log.ts ADDED
@@ -0,0 +1,49 @@
1
+ /**
2
+ * cli/log.ts — ANSI-colored logging helpers for CLI output.
3
+ *
4
+ * Used for non-interactive output (dev server runtime, file watcher logs).
5
+ * Interactive prompts use @clack/prompts via cli/ui.ts instead.
6
+ */
7
+
8
+ // ── ANSI escape codes ──────────────────────────────────────────────
9
+ // Brand colors:
10
+ // Teal: #2dd4bf → RGB(45,212,191) primary/success
11
+ // Red: #ff4d4d → RGB(255,77,77) error/accent
12
+ // Text: #0f172a → RGB(15,23,42) dark slate
13
+
14
+ export const ANSI = {
15
+ BOLD: '\x1b[1m',
16
+ DIM: '\x1b[2m',
17
+ GREEN: '\x1b[32m',
18
+ YELLOW: '\x1b[33m',
19
+ RED: '\x1b[31m',
20
+ CYAN: '\x1b[36m',
21
+ RESET: '\x1b[0m',
22
+ // Brand colors (24-bit truecolor)
23
+ BRAND_TEAL: '\x1b[38;2;45;212;191m',
24
+ BRAND_RED: '\x1b[38;2;255;77;77m',
25
+ BRAND_TEXT: '\x1b[38;2;15;23;42m',
26
+ BRAND_DIM: '\x1b[38;2;113;124;149m'
27
+ } as const;
28
+
29
+ // ── Logging functions ──────────────────────────────────────────────
30
+
31
+ export function log(msg: string): void {
32
+ console.log(` ${msg}`);
33
+ }
34
+
35
+ export function ok(msg: string): void {
36
+ console.log(` ${ANSI.BRAND_TEAL}✓${ANSI.RESET} ${msg}`);
37
+ }
38
+
39
+ export function warn(msg: string): void {
40
+ console.log(` ${ANSI.YELLOW}⚠${ANSI.RESET} ${msg}`);
41
+ }
42
+
43
+ export function fail(msg: string): void {
44
+ console.error(` ${ANSI.BRAND_RED}✗${ANSI.RESET} ${msg}`);
45
+ }
46
+
47
+ export function header(msg: string): void {
48
+ console.log(`\n${ANSI.BOLD}${ANSI.BRAND_TEAL}🐻 ${msg}${ANSI.RESET}\n`);
49
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * cli/preflight.ts — Composable preflight checks for CLI commands.
3
+ *
4
+ * Each command declares its requirements upfront. All checks produce
5
+ * clear, actionable error messages so users never see cryptic failures.
6
+ *
7
+ * Usage:
8
+ * preflight(root, { needsAuth: true, needsSecret: true, needsConfig: true });
9
+ */
10
+
11
+ import { existsSync, readFileSync } from 'fs';
12
+ import { resolve } from 'path';
13
+ import { fail, warn, log, ANSI } from './log.ts';
14
+ import { CONFIG_FILE, SITE_CONFIG_FILE, KOGUMA_DIR } from './constants.ts';
15
+ import { runCapture } from './exec.ts';
16
+
17
+ export interface PreflightOptions {
18
+ /** Command needs wrangler login (remote D1/R2 operations) */
19
+ needsAuth?: boolean;
20
+ /** Command needs KOGUMA_SECRET in .dev.vars (remote API auth) */
21
+ needsSecret?: boolean;
22
+ /** Command needs site.config.ts (typegen, content sync) */
23
+ needsSiteConfig?: boolean;
24
+ }
25
+
26
+ /**
27
+ * Run all applicable preflight checks for a command.
28
+ * Exits with actionable errors on failure.
29
+ */
30
+ export function preflight(root: string, opts: PreflightOptions = {}): void {
31
+ // koguma.toml is always required (except init which handles this itself)
32
+ requireKogumaToml(root);
33
+
34
+ if (opts.needsSiteConfig) {
35
+ requireSiteConfig(root);
36
+ }
37
+
38
+ if (opts.needsAuth) {
39
+ requireWranglerAuth(root);
40
+ }
41
+
42
+ if (opts.needsSecret) {
43
+ requireDevVarsSecret(root);
44
+ }
45
+ }
46
+
47
+ // ── Individual checks ──────────────────────────────────────────────
48
+
49
+ function requireKogumaToml(root: string): void {
50
+ if (!existsSync(resolve(root, CONFIG_FILE))) {
51
+ fail(
52
+ `${CONFIG_FILE} not found in ${root}\n` +
53
+ ` Run ${ANSI.CYAN}koguma init${ANSI.RESET} to set up your project.`
54
+ );
55
+ process.exit(1);
56
+ }
57
+ }
58
+
59
+ function requireSiteConfig(root: string): void {
60
+ if (!existsSync(resolve(root, SITE_CONFIG_FILE))) {
61
+ fail(
62
+ `${SITE_CONFIG_FILE} not found in project root.\n` +
63
+ ` This file defines your content types. Run ${ANSI.CYAN}koguma init${ANSI.RESET} to scaffold one.`
64
+ );
65
+ process.exit(1);
66
+ }
67
+ }
68
+
69
+ function requireWranglerAuth(root: string): void {
70
+ try {
71
+ runCapture('bunx wrangler whoami', root);
72
+ } catch {
73
+ fail(
74
+ `Not logged in to Cloudflare.\n` +
75
+ ` Run ${ANSI.CYAN}bunx wrangler login${ANSI.RESET} first, ` +
76
+ `or ${ANSI.CYAN}koguma init${ANSI.RESET} which handles login for you.`
77
+ );
78
+ process.exit(1);
79
+ }
80
+ }
81
+
82
+ function requireDevVarsSecret(root: string): void {
83
+ // Check both .koguma/.dev.vars (generated) and project-root .dev.vars (legacy/manual)
84
+ const generatedPath = resolve(root, KOGUMA_DIR, '.dev.vars');
85
+ const legacyPath = resolve(root, '.dev.vars');
86
+ const devVarsPath = existsSync(generatedPath) ? generatedPath : legacyPath;
87
+
88
+ if (!existsSync(devVarsPath)) {
89
+ fail(
90
+ `KOGUMA_SECRET not configured — needed for admin authentication.\n` +
91
+ ` Run ${ANSI.CYAN}koguma dev${ANSI.RESET} once to auto-generate it, or create manually:\n` +
92
+ ` ${ANSI.DIM}echo 'KOGUMA_SECRET=your-password' > ${KOGUMA_DIR}/.dev.vars${ANSI.RESET}`
93
+ );
94
+ process.exit(1);
95
+ }
96
+
97
+ const content = readFileSync(devVarsPath, 'utf-8');
98
+ if (!content.match(/KOGUMA_SECRET=(.+)/)) {
99
+ fail(
100
+ `KOGUMA_SECRET not found in ${devVarsPath}.\n` +
101
+ ` Add it: ${ANSI.DIM}echo 'KOGUMA_SECRET=your-password' >> ${devVarsPath}${ANSI.RESET}`
102
+ );
103
+ process.exit(1);
104
+ }
105
+ }