@imjp/writenex-astro 0.1.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 (141) hide show
  1. package/README.md +539 -0
  2. package/dist/chunk-5PM6EQE5.js +151 -0
  3. package/dist/chunk-5PM6EQE5.js.map +1 -0
  4. package/dist/chunk-7XU5X6CW.js +1331 -0
  5. package/dist/chunk-7XU5X6CW.js.map +1 -0
  6. package/dist/chunk-AAOQHQPU.js +574 -0
  7. package/dist/chunk-AAOQHQPU.js.map +1 -0
  8. package/dist/chunk-CF2XXJFF.js +1410 -0
  9. package/dist/chunk-CF2XXJFF.js.map +1 -0
  10. package/dist/chunk-CRPZUUDU.js +52 -0
  11. package/dist/chunk-CRPZUUDU.js.map +1 -0
  12. package/dist/chunk-CYLDJ3HZ.js +310 -0
  13. package/dist/chunk-CYLDJ3HZ.js.map +1 -0
  14. package/dist/chunk-KIKIPIFA.js +1 -0
  15. package/dist/chunk-KIKIPIFA.js.map +1 -0
  16. package/dist/chunk-XNTQTTJU.js +145 -0
  17. package/dist/chunk-XNTQTTJU.js.map +1 -0
  18. package/dist/client/index.css +2 -0
  19. package/dist/client/index.css.map +1 -0
  20. package/dist/client/index.js +375 -0
  21. package/dist/client/index.js.map +1 -0
  22. package/dist/client/styles.css +584 -0
  23. package/dist/client/variables.css +304 -0
  24. package/dist/config/index.d.ts +54 -0
  25. package/dist/config/index.js +38 -0
  26. package/dist/config/index.js.map +1 -0
  27. package/dist/config-BmEdBDo_.d.ts +220 -0
  28. package/dist/content-BWR52vD-.d.ts +64 -0
  29. package/dist/discovery/index.d.ts +310 -0
  30. package/dist/discovery/index.js +38 -0
  31. package/dist/discovery/index.js.map +1 -0
  32. package/dist/errors-C0iYiDTv.d.ts +107 -0
  33. package/dist/filesystem/index.d.ts +1292 -0
  34. package/dist/filesystem/index.js +203 -0
  35. package/dist/filesystem/index.js.map +1 -0
  36. package/dist/image-FP7w5ZIs.d.ts +47 -0
  37. package/dist/index.d.ts +64 -0
  38. package/dist/index.js +151 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/loader-55LWCXHA.js +12 -0
  41. package/dist/loader-55LWCXHA.js.map +1 -0
  42. package/dist/loader-CrdnaAWR.d.ts +327 -0
  43. package/dist/server/index.d.ts +357 -0
  44. package/dist/server/index.js +37 -0
  45. package/dist/server/index.js.map +1 -0
  46. package/package.json +94 -0
  47. package/src/client/App.tsx +900 -0
  48. package/src/client/components/ConfigPanel/ConfigPanel.css +553 -0
  49. package/src/client/components/ConfigPanel/ConfigPanel.tsx +396 -0
  50. package/src/client/components/ConfigPanel/index.ts +6 -0
  51. package/src/client/components/CreateContentModal/CreateContentModal.css +327 -0
  52. package/src/client/components/CreateContentModal/CreateContentModal.tsx +216 -0
  53. package/src/client/components/CreateContentModal/index.ts +7 -0
  54. package/src/client/components/Editor/Editor.css +885 -0
  55. package/src/client/components/Editor/Editor.tsx +484 -0
  56. package/src/client/components/Editor/ImageDialog.css +344 -0
  57. package/src/client/components/Editor/ImageDialog.tsx +367 -0
  58. package/src/client/components/Editor/LinkDialog.css +326 -0
  59. package/src/client/components/Editor/LinkDialog.tsx +332 -0
  60. package/src/client/components/Editor/index.ts +6 -0
  61. package/src/client/components/FrontmatterForm/FrontmatterForm.css +468 -0
  62. package/src/client/components/FrontmatterForm/FrontmatterForm.tsx +914 -0
  63. package/src/client/components/FrontmatterForm/index.ts +7 -0
  64. package/src/client/components/Header/Header.css +300 -0
  65. package/src/client/components/Header/Header.tsx +300 -0
  66. package/src/client/components/Header/index.ts +7 -0
  67. package/src/client/components/KeyboardShortcuts/KeyboardShortcuts.css +239 -0
  68. package/src/client/components/KeyboardShortcuts/KeyboardShortcuts.tsx +151 -0
  69. package/src/client/components/KeyboardShortcuts/index.ts +6 -0
  70. package/src/client/components/LazyEditor.tsx +75 -0
  71. package/src/client/components/LiveRegion/LiveRegion.css +19 -0
  72. package/src/client/components/LiveRegion/LiveRegion.tsx +60 -0
  73. package/src/client/components/LiveRegion/index.ts +7 -0
  74. package/src/client/components/SearchReplace/SearchReplacePanel.css +300 -0
  75. package/src/client/components/SearchReplace/SearchReplacePanel.tsx +332 -0
  76. package/src/client/components/SearchReplace/index.ts +7 -0
  77. package/src/client/components/SelectCollectionModal/SelectCollectionModal.css +308 -0
  78. package/src/client/components/SelectCollectionModal/SelectCollectionModal.tsx +223 -0
  79. package/src/client/components/SelectCollectionModal/index.ts +7 -0
  80. package/src/client/components/Sidebar/Sidebar.css +570 -0
  81. package/src/client/components/Sidebar/Sidebar.tsx +617 -0
  82. package/src/client/components/Sidebar/index.ts +7 -0
  83. package/src/client/components/SkipLink/SkipLink.css +51 -0
  84. package/src/client/components/SkipLink/SkipLink.tsx +67 -0
  85. package/src/client/components/SkipLink/index.ts +7 -0
  86. package/src/client/components/UnsavedChangesModal/UnsavedChangesModal.css +233 -0
  87. package/src/client/components/UnsavedChangesModal/UnsavedChangesModal.tsx +160 -0
  88. package/src/client/components/UnsavedChangesModal/index.ts +1 -0
  89. package/src/client/components/VersionHistory/DiffViewer.css +430 -0
  90. package/src/client/components/VersionHistory/DiffViewer.tsx +383 -0
  91. package/src/client/components/VersionHistory/VersionActions.css +318 -0
  92. package/src/client/components/VersionHistory/VersionActions.tsx +277 -0
  93. package/src/client/components/VersionHistory/VersionHistoryPanel.css +369 -0
  94. package/src/client/components/VersionHistory/VersionHistoryPanel.tsx +469 -0
  95. package/src/client/components/VersionHistory/index.ts +9 -0
  96. package/src/client/context/ApiContext.tsx +154 -0
  97. package/src/client/context/ThemeContext.tsx +172 -0
  98. package/src/client/hooks/useAnnounce.ts +201 -0
  99. package/src/client/hooks/useApi.ts +374 -0
  100. package/src/client/hooks/useArrowNavigation.ts +286 -0
  101. package/src/client/hooks/useAutosave.ts +241 -0
  102. package/src/client/hooks/useFocusTrap.ts +178 -0
  103. package/src/client/hooks/useKeyboardShortcuts.ts +203 -0
  104. package/src/client/hooks/useSearch.ts +206 -0
  105. package/src/client/hooks/useVersionHistory.ts +451 -0
  106. package/src/client/index.tsx +70 -0
  107. package/src/client/styles.css +584 -0
  108. package/src/client/utils/focus.ts +57 -0
  109. package/src/client/utils/openInEditor.ts +130 -0
  110. package/src/client/variables.css +304 -0
  111. package/src/config/defaults.ts +109 -0
  112. package/src/config/index.ts +32 -0
  113. package/src/config/loader.ts +174 -0
  114. package/src/config/schema.ts +161 -0
  115. package/src/core/constants.ts +39 -0
  116. package/src/core/errors.ts +739 -0
  117. package/src/core/index.ts +11 -0
  118. package/src/discovery/collections.ts +216 -0
  119. package/src/discovery/index.ts +33 -0
  120. package/src/discovery/patterns.ts +702 -0
  121. package/src/discovery/schema.ts +453 -0
  122. package/src/filesystem/images.ts +798 -0
  123. package/src/filesystem/index.ts +107 -0
  124. package/src/filesystem/reader.ts +452 -0
  125. package/src/filesystem/version-config.ts +390 -0
  126. package/src/filesystem/versions.ts +1339 -0
  127. package/src/filesystem/watcher.ts +226 -0
  128. package/src/filesystem/writer.ts +540 -0
  129. package/src/index.ts +61 -0
  130. package/src/integration.ts +228 -0
  131. package/src/server/assets.ts +254 -0
  132. package/src/server/cache.ts +355 -0
  133. package/src/server/index.ts +33 -0
  134. package/src/server/middleware.ts +209 -0
  135. package/src/server/routes.ts +1428 -0
  136. package/src/types/api.ts +61 -0
  137. package/src/types/config.ts +134 -0
  138. package/src/types/content.ts +64 -0
  139. package/src/types/image.ts +48 -0
  140. package/src/types/index.ts +58 -0
  141. package/src/types/version.ts +117 -0
@@ -0,0 +1,174 @@
1
+ /**
2
+ * @fileoverview Configuration loader for @writenex/astro
3
+ *
4
+ * This module handles loading Writenex configuration from various sources:
5
+ * - writenex.config.ts (TypeScript)
6
+ * - writenex.config.js (JavaScript)
7
+ * - writenex.config.mjs (ES Module)
8
+ *
9
+ * The loader searches for configuration files in the project root and
10
+ * applies default values for any missing options.
11
+ *
12
+ * @module @writenex/astro/config/loader
13
+ */
14
+
15
+ import { existsSync } from "node:fs";
16
+ import { pathToFileURL } from "node:url";
17
+ import { join, resolve } from "node:path";
18
+ import type { WritenexConfig } from "@/types";
19
+ import { validateConfig } from "./schema";
20
+ import { applyConfigDefaults } from "./defaults";
21
+
22
+ /**
23
+ * Supported configuration file names in order of priority
24
+ */
25
+ const CONFIG_FILE_NAMES = [
26
+ "writenex.config.ts",
27
+ "writenex.config.mts",
28
+ "writenex.config.js",
29
+ "writenex.config.mjs",
30
+ ];
31
+
32
+ /**
33
+ * Result of loading configuration
34
+ */
35
+ export interface LoadConfigResult {
36
+ /** The loaded and validated configuration with defaults applied */
37
+ config: Required<WritenexConfig>;
38
+ /** Path to the configuration file (if found) */
39
+ configPath: string | null;
40
+ /** Whether a configuration file was found */
41
+ hasConfigFile: boolean;
42
+ /** Any warnings generated during loading */
43
+ warnings: string[];
44
+ }
45
+
46
+ /**
47
+ * Find the configuration file in the project root
48
+ *
49
+ * @param projectRoot - The root directory of the Astro project
50
+ * @returns Path to the configuration file, or null if not found
51
+ */
52
+ export function findConfigFile(projectRoot: string): string | null {
53
+ for (const fileName of CONFIG_FILE_NAMES) {
54
+ const filePath = join(projectRoot, fileName);
55
+ if (existsSync(filePath)) {
56
+ return filePath;
57
+ }
58
+ }
59
+ return null;
60
+ }
61
+
62
+ /**
63
+ * Load configuration from a file
64
+ *
65
+ * @param configPath - Path to the configuration file
66
+ * @returns The loaded configuration object
67
+ * @throws Error if the file cannot be loaded or parsed
68
+ */
69
+ async function loadConfigFile(configPath: string): Promise<WritenexConfig> {
70
+ try {
71
+ // Convert to file URL for dynamic import (required for Windows compatibility)
72
+ const fileUrl = pathToFileURL(resolve(configPath)).href;
73
+
74
+ // Dynamic import the configuration file
75
+ const module = await import(fileUrl);
76
+
77
+ // Support both default export and named export
78
+ const config = module.default ?? module.config ?? module;
79
+
80
+ return config as WritenexConfig;
81
+ } catch (error) {
82
+ const message = error instanceof Error ? error.message : String(error);
83
+ throw new Error(
84
+ `Failed to load configuration from ${configPath}: ${message}`
85
+ );
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Load Writenex configuration from the project root
91
+ *
92
+ * This function:
93
+ * 1. Searches for a configuration file in the project root
94
+ * 2. Loads and validates the configuration if found
95
+ * 3. Applies default values for any missing options
96
+ * 4. Returns the resolved configuration
97
+ *
98
+ * If no configuration file is found, default configuration is returned
99
+ * with auto-discovery enabled.
100
+ *
101
+ * @param projectRoot - The root directory of the Astro project
102
+ * @returns LoadConfigResult with the resolved configuration
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * const { config, hasConfigFile, warnings } = await loadConfig('/path/to/project');
107
+ *
108
+ * if (!hasConfigFile) {
109
+ * console.log('Using auto-discovery mode');
110
+ * }
111
+ *
112
+ * if (warnings.length > 0) {
113
+ * warnings.forEach(w => console.warn(w));
114
+ * }
115
+ * ```
116
+ */
117
+ export async function loadConfig(
118
+ projectRoot: string
119
+ ): Promise<LoadConfigResult> {
120
+ const warnings: string[] = [];
121
+ let userConfig: WritenexConfig = {};
122
+ let configPath: string | null = null;
123
+ let hasConfigFile = false;
124
+
125
+ // Try to find and load configuration file
126
+ configPath = findConfigFile(projectRoot);
127
+
128
+ if (configPath) {
129
+ hasConfigFile = true;
130
+
131
+ try {
132
+ userConfig = await loadConfigFile(configPath);
133
+
134
+ // Validate the loaded configuration
135
+ const validationResult = validateConfig(userConfig);
136
+
137
+ if (!validationResult.success) {
138
+ const errors = validationResult.error.errors
139
+ .map((e) => `${e.path.join(".")}: ${e.message}`)
140
+ .join(", ");
141
+ warnings.push(`Configuration validation warnings: ${errors}`);
142
+ }
143
+ } catch (error) {
144
+ const message = error instanceof Error ? error.message : String(error);
145
+ warnings.push(`Failed to load config file: ${message}. Using defaults.`);
146
+ userConfig = {};
147
+ }
148
+ }
149
+
150
+ // Apply defaults to the configuration
151
+ const config = applyConfigDefaults(userConfig);
152
+
153
+ return {
154
+ config,
155
+ configPath,
156
+ hasConfigFile,
157
+ warnings,
158
+ };
159
+ }
160
+
161
+ /**
162
+ * Check if a content directory exists in the project
163
+ *
164
+ * @param projectRoot - The root directory of the Astro project
165
+ * @param contentPath - Relative path to the content directory
166
+ * @returns True if the content directory exists
167
+ */
168
+ export function contentDirectoryExists(
169
+ projectRoot: string,
170
+ contentPath: string = "src/content"
171
+ ): boolean {
172
+ const fullPath = join(projectRoot, contentPath);
173
+ return existsSync(fullPath);
174
+ }
@@ -0,0 +1,161 @@
1
+ /**
2
+ * @fileoverview Configuration schema and validation for @writenex/astro
3
+ *
4
+ * This module provides Zod schemas for validating Writenex configuration
5
+ * and a helper function for defining type-safe configurations.
6
+ *
7
+ * @module @writenex/astro/config/schema
8
+ */
9
+
10
+ import { z } from "zod";
11
+ import type { WritenexConfig } from "@/types";
12
+
13
+ /**
14
+ * Schema for field type definitions
15
+ */
16
+ const fieldTypeSchema = z.enum([
17
+ "string",
18
+ "number",
19
+ "boolean",
20
+ "date",
21
+ "array",
22
+ "image",
23
+ "object",
24
+ ]);
25
+
26
+ /**
27
+ * Schema for individual schema field definition
28
+ */
29
+ const schemaFieldSchema = z.object({
30
+ type: fieldTypeSchema,
31
+ required: z.boolean().optional(),
32
+ default: z.unknown().optional(),
33
+ items: z.string().optional(),
34
+ description: z.string().optional(),
35
+ });
36
+
37
+ /**
38
+ * Schema for collection schema (record of field definitions)
39
+ */
40
+ const collectionSchemaSchema = z.record(z.string(), schemaFieldSchema);
41
+
42
+ /**
43
+ * Schema for image strategy
44
+ */
45
+ const imageStrategySchema = z.enum(["colocated", "public", "custom"]);
46
+
47
+ /**
48
+ * Schema for image configuration
49
+ */
50
+ const imageConfigSchema = z.object({
51
+ strategy: imageStrategySchema,
52
+ publicPath: z.string().optional(),
53
+ storagePath: z.string().optional(),
54
+ });
55
+
56
+ /**
57
+ * Schema for collection configuration
58
+ */
59
+ const collectionConfigSchema = z.object({
60
+ name: z.string().min(1, "Collection name is required"),
61
+ path: z.string().min(1, "Collection path is required"),
62
+ filePattern: z.string().optional(),
63
+ previewUrl: z.string().optional(),
64
+ schema: collectionSchemaSchema.optional(),
65
+ images: imageConfigSchema.optional(),
66
+ });
67
+
68
+ /**
69
+ * Schema for discovery configuration
70
+ */
71
+ const discoveryConfigSchema = z.object({
72
+ enabled: z.boolean(),
73
+ ignore: z.array(z.string()).optional(),
74
+ });
75
+
76
+ /**
77
+ * Schema for editor configuration
78
+ */
79
+ const editorConfigSchema = z.object({
80
+ autosave: z.boolean().optional(),
81
+ autosaveInterval: z.number().positive().optional(),
82
+ });
83
+
84
+ /**
85
+ * Schema for version history configuration
86
+ */
87
+ const versionHistoryConfigSchema = z.object({
88
+ enabled: z.boolean().optional(),
89
+ maxVersions: z.number().int().positive().optional(),
90
+ storagePath: z.string().optional(),
91
+ });
92
+
93
+ /**
94
+ * Main Writenex configuration schema
95
+ */
96
+ export const writenexConfigSchema = z.object({
97
+ collections: z.array(collectionConfigSchema).optional(),
98
+ images: imageConfigSchema.optional(),
99
+ editor: editorConfigSchema.optional(),
100
+ discovery: discoveryConfigSchema.optional(),
101
+ versionHistory: versionHistoryConfigSchema.optional(),
102
+ });
103
+
104
+ /**
105
+ * Schema for integration options
106
+ */
107
+ export const writenexOptionsSchema = z.object({
108
+ allowProduction: z.boolean().optional(),
109
+ });
110
+
111
+ /**
112
+ * Helper function for defining type-safe Writenex configuration.
113
+ *
114
+ * This function provides IDE autocompletion and type checking for
115
+ * the configuration object. It's the recommended way to create
116
+ * a writenex.config.ts file.
117
+ *
118
+ * @param config - The Writenex configuration object
119
+ * @returns The same configuration object (identity function for type safety)
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * // writenex.config.ts
124
+ * import { defineConfig } from '@writenex/astro';
125
+ *
126
+ * export default defineConfig({
127
+ * collections: [
128
+ * {
129
+ * name: 'blog',
130
+ * path: 'src/content/blog',
131
+ * filePattern: '{slug}.md',
132
+ * },
133
+ * ],
134
+ * });
135
+ * ```
136
+ */
137
+ export function defineConfig(config: WritenexConfig): WritenexConfig {
138
+ // Validate the configuration
139
+ const result = writenexConfigSchema.safeParse(config);
140
+
141
+ if (!result.success) {
142
+ const errors = result.error.errors
143
+ .map((e) => ` - ${e.path.join(".")}: ${e.message}`)
144
+ .join("\n");
145
+ console.warn(`[writenex] Invalid configuration:\n${errors}`);
146
+ }
147
+
148
+ return config;
149
+ }
150
+
151
+ /**
152
+ * Validate a Writenex configuration object
153
+ *
154
+ * @param config - The configuration to validate
155
+ * @returns Validation result with success status and parsed data or errors
156
+ */
157
+ export function validateConfig(
158
+ config: unknown
159
+ ): z.SafeParseReturnType<unknown, WritenexConfig> {
160
+ return writenexConfigSchema.safeParse(config);
161
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @fileoverview Shared constants for @writenex/astro
3
+ *
4
+ * This module provides centralized constants used across the integration,
5
+ * including version information, default paths, and configuration limits.
6
+ *
7
+ * @module @writenex/astro/core/constants
8
+ */
9
+
10
+ /**
11
+ * Current version of the @writenex/astro package
12
+ */
13
+ export const WRITENEX_VERSION = "1.0.0";
14
+
15
+ /**
16
+ * Default base path for the Writenex editor UI
17
+ */
18
+ export const DEFAULT_BASE_PATH = "/_writenex";
19
+
20
+ /**
21
+ * Default API path for Writenex API endpoints
22
+ */
23
+ export const DEFAULT_API_PATH = "/_writenex/api";
24
+
25
+ /**
26
+ * Supported image MIME types for upload
27
+ */
28
+ export const SUPPORTED_IMAGE_TYPES = [
29
+ "image/jpeg",
30
+ "image/png",
31
+ "image/gif",
32
+ "image/webp",
33
+ "image/svg+xml",
34
+ ] as const;
35
+
36
+ /**
37
+ * Maximum allowed image file size in bytes (10MB)
38
+ */
39
+ export const MAX_IMAGE_SIZE = 10 * 1024 * 1024;