blok0 0.1.0 โ 0.1.1
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/dist/api/index.d.ts +46 -0
- package/dist/api/index.js +147 -0
- package/dist/ast/index.d.ts +31 -0
- package/dist/ast/index.js +324 -0
- package/dist/auth/constants.d.ts +11 -0
- package/dist/auth/constants.js +155 -0
- package/dist/auth/index.d.ts +61 -0
- package/dist/auth/index.js +168 -0
- package/dist/auth/server.d.ts +55 -0
- package/dist/auth/server.js +236 -0
- package/dist/blocks/index.d.ts +56 -0
- package/dist/blocks/index.js +189 -0
- package/dist/handlers/add-block.d.ts +7 -0
- package/dist/handlers/add-block.js +142 -0
- package/dist/handlers/login.d.ts +8 -0
- package/dist/handlers/login.js +124 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +187 -7
- package/dist/registry/index.d.ts +75 -0
- package/dist/registry/index.js +231 -0
- package/package.json +33 -25
- package/src/api/index.ts +177 -0
- package/src/ast/index.ts +368 -0
- package/src/auth/constants.ts +155 -0
- package/src/auth/index.ts +154 -0
- package/src/auth/server.ts +240 -0
- package/src/blocks/index.ts +186 -0
- package/src/detectors.ts +22 -22
- package/src/handlers/add-block.ts +132 -0
- package/src/handlers/generate.ts +62 -62
- package/src/handlers/login.ts +130 -0
- package/src/index.ts +212 -51
- package/src/registry/index.ts +244 -0
- package/test-ast.js +150 -0
- package/tsconfig.json +16 -16
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as crypto from 'crypto';
|
|
4
|
+
|
|
5
|
+
export interface BlockSource {
|
|
6
|
+
url: string;
|
|
7
|
+
id: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface BlockEntry {
|
|
11
|
+
id: number;
|
|
12
|
+
name: string;
|
|
13
|
+
slug: string;
|
|
14
|
+
dir: string;
|
|
15
|
+
configPath: string;
|
|
16
|
+
componentPath: string;
|
|
17
|
+
source: BlockSource & {
|
|
18
|
+
fetchedAt: string;
|
|
19
|
+
};
|
|
20
|
+
checksums: {
|
|
21
|
+
[filename: string]: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RegistryData {
|
|
26
|
+
version: string;
|
|
27
|
+
blocks: {
|
|
28
|
+
[slug: string]: BlockEntry;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const REGISTRY_FILE = 'blok0-registry.json';
|
|
33
|
+
const REGISTRY_VERSION = '1.0';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get registry file path
|
|
37
|
+
*/
|
|
38
|
+
function getRegistryPath(): string {
|
|
39
|
+
return path.join(process.cwd(), REGISTRY_FILE);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Load registry from file
|
|
44
|
+
*/
|
|
45
|
+
export function loadRegistry(): RegistryData {
|
|
46
|
+
const registryPath = getRegistryPath();
|
|
47
|
+
|
|
48
|
+
if (!fs.existsSync(registryPath)) {
|
|
49
|
+
return {
|
|
50
|
+
version: REGISTRY_VERSION,
|
|
51
|
+
blocks: {}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const data = fs.readFileSync(registryPath, 'utf-8');
|
|
57
|
+
const registry = JSON.parse(data);
|
|
58
|
+
|
|
59
|
+
// Validate registry structure
|
|
60
|
+
if (!registry.version || !registry.blocks) {
|
|
61
|
+
throw new Error('Invalid registry structure');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return registry;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
throw new Error(`Failed to load registry: ${(error as Error).message}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Save registry to file
|
|
72
|
+
*/
|
|
73
|
+
export function saveRegistry(registry: RegistryData): void {
|
|
74
|
+
const registryPath = getRegistryPath();
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2));
|
|
78
|
+
} catch (error) {
|
|
79
|
+
throw new Error(`Failed to save registry: ${(error as Error).message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check if block slug already exists in registry
|
|
85
|
+
*/
|
|
86
|
+
export function isBlockRegistered(slug: string): boolean {
|
|
87
|
+
const registry = loadRegistry();
|
|
88
|
+
return slug in registry.blocks;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get block entry by slug
|
|
93
|
+
*/
|
|
94
|
+
export function getBlockEntry(slug: string): BlockEntry | null {
|
|
95
|
+
const registry = loadRegistry();
|
|
96
|
+
return registry.blocks[slug] || null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Add block to registry
|
|
101
|
+
*/
|
|
102
|
+
export function addBlockToRegistry(entry: BlockEntry): void {
|
|
103
|
+
const registry = loadRegistry();
|
|
104
|
+
|
|
105
|
+
if (entry.slug in registry.blocks) {
|
|
106
|
+
throw new Error(`Block with slug '${entry.slug}' is already registered`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
registry.blocks[entry.slug] = entry;
|
|
110
|
+
saveRegistry(registry);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Remove block from registry
|
|
115
|
+
*/
|
|
116
|
+
export function removeBlockFromRegistry(slug: string): void {
|
|
117
|
+
const registry = loadRegistry();
|
|
118
|
+
|
|
119
|
+
if (!(slug in registry.blocks)) {
|
|
120
|
+
throw new Error(`Block with slug '${slug}' is not registered`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
delete registry.blocks[slug];
|
|
124
|
+
saveRegistry(registry);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Update block checksums
|
|
129
|
+
*/
|
|
130
|
+
export function updateBlockChecksums(slug: string, checksums: { [filename: string]: string }): void {
|
|
131
|
+
const registry = loadRegistry();
|
|
132
|
+
|
|
133
|
+
if (!(slug in registry.blocks)) {
|
|
134
|
+
throw new Error(`Block with slug '${slug}' is not registered`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
registry.blocks[slug].checksums = checksums;
|
|
138
|
+
saveRegistry(registry);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Calculate file checksum
|
|
143
|
+
*/
|
|
144
|
+
export function calculateChecksum(filePath: string): string {
|
|
145
|
+
const fileBuffer = fs.readFileSync(filePath);
|
|
146
|
+
const hashSum = crypto.createHash('sha256');
|
|
147
|
+
hashSum.update(fileBuffer);
|
|
148
|
+
return hashSum.digest('hex');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Calculate checksums for all files in a directory
|
|
153
|
+
*/
|
|
154
|
+
export function calculateDirectoryChecksums(dirPath: string): { [filename: string]: string } {
|
|
155
|
+
const checksums: { [filename: string]: string } = {};
|
|
156
|
+
|
|
157
|
+
function walkDirectory(dir: string): void {
|
|
158
|
+
const files = fs.readdirSync(dir);
|
|
159
|
+
|
|
160
|
+
for (const file of files) {
|
|
161
|
+
const filePath = path.join(dir, file);
|
|
162
|
+
const stat = fs.statSync(filePath);
|
|
163
|
+
|
|
164
|
+
if (stat.isDirectory()) {
|
|
165
|
+
walkDirectory(filePath);
|
|
166
|
+
} else {
|
|
167
|
+
const relativePath = path.relative(dirPath, filePath);
|
|
168
|
+
checksums[relativePath] = calculateChecksum(filePath);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
walkDirectory(dirPath);
|
|
174
|
+
return checksums;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Validate registry integrity
|
|
179
|
+
*/
|
|
180
|
+
export function validateRegistry(): { valid: boolean; errors: string[] } {
|
|
181
|
+
const errors: string[] = [];
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const registry = loadRegistry();
|
|
185
|
+
|
|
186
|
+
for (const [slug, entry] of Object.entries(registry.blocks)) {
|
|
187
|
+
// Check if block directory exists
|
|
188
|
+
if (!fs.existsSync(entry.dir)) {
|
|
189
|
+
errors.push(`Block '${slug}': directory '${entry.dir}' does not exist`);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Check if config file exists
|
|
194
|
+
if (!fs.existsSync(entry.configPath)) {
|
|
195
|
+
errors.push(`Block '${slug}': config file '${entry.configPath}' does not exist`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Check if component file exists
|
|
199
|
+
if (!fs.existsSync(entry.componentPath)) {
|
|
200
|
+
errors.push(`Block '${slug}': component file '${entry.componentPath}' does not exist`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Validate checksums if they exist
|
|
204
|
+
if (entry.checksums) {
|
|
205
|
+
for (const [file, expectedChecksum] of Object.entries(entry.checksums)) {
|
|
206
|
+
const filePath = path.join(entry.dir, file);
|
|
207
|
+
if (fs.existsSync(filePath)) {
|
|
208
|
+
const actualChecksum = calculateChecksum(filePath);
|
|
209
|
+
if (actualChecksum !== expectedChecksum) {
|
|
210
|
+
errors.push(`Block '${slug}': checksum mismatch for '${file}'`);
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
errors.push(`Block '${slug}': file '${file}' referenced in checksums does not exist`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
} catch (error) {
|
|
219
|
+
errors.push(`Registry validation failed: ${(error as Error).message}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
valid: errors.length === 0,
|
|
224
|
+
errors
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Create empty registry for new projects
|
|
230
|
+
*/
|
|
231
|
+
export function createEmptyRegistry(): void {
|
|
232
|
+
const registryPath = getRegistryPath();
|
|
233
|
+
|
|
234
|
+
if (fs.existsSync(registryPath)) {
|
|
235
|
+
throw new Error('Registry already exists');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const emptyRegistry: RegistryData = {
|
|
239
|
+
version: REGISTRY_VERSION,
|
|
240
|
+
blocks: {}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
saveRegistry(emptyRegistry);
|
|
244
|
+
}
|
package/test-ast.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const { updatePageCollectionConfig, updateRenderBlocksComponent, findPagesCollection, extractComponentName } = require('./dist/ast/index.js');
|
|
2
|
+
const { slugToIdentifier } = require('./dist/blocks/index.js');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
// Test case: Add editorial--carousel block
|
|
6
|
+
// Simulates: blok0 add-block https://www.blok0.xyz/api/cli/sections/editorial--carousel
|
|
7
|
+
|
|
8
|
+
console.log('๐งช Testing Editorial Carousel Block Addition');
|
|
9
|
+
console.log('==========================================');
|
|
10
|
+
console.log('');
|
|
11
|
+
|
|
12
|
+
// Change to Payload project directory
|
|
13
|
+
const payloadProjectPath = '../newcms';
|
|
14
|
+
console.log(`๐ Changing to Payload project directory: ${payloadProjectPath}`);
|
|
15
|
+
try {
|
|
16
|
+
process.chdir(payloadProjectPath);
|
|
17
|
+
console.log('โ
Successfully changed directory');
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.log('โ Failed to change directory:', error.message);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.log('');
|
|
24
|
+
console.log('๐ Finding Pages collection...');
|
|
25
|
+
const pagesPath = findPagesCollection();
|
|
26
|
+
console.log('Pages collection path:', pagesPath);
|
|
27
|
+
|
|
28
|
+
if (pagesPath) {
|
|
29
|
+
console.log('');
|
|
30
|
+
console.log('๐งช Testing AST update for editorial--carousel block...');
|
|
31
|
+
|
|
32
|
+
const blockSlug = 'editorial--carousel';
|
|
33
|
+
const blockIdentifier = slugToIdentifier(blockSlug);
|
|
34
|
+
const blockConfigPath = `@/blocks/${blockSlug}/config`;
|
|
35
|
+
|
|
36
|
+
console.log(`Block slug: ${blockSlug}`);
|
|
37
|
+
console.log(`Block identifier: ${blockIdentifier}`);
|
|
38
|
+
console.log(`Config path: ${blockConfigPath}`);
|
|
39
|
+
console.log('');
|
|
40
|
+
|
|
41
|
+
// Read file before modification
|
|
42
|
+
const originalContent = fs.readFileSync(pagesPath, 'utf-8');
|
|
43
|
+
const hasOriginalImport = originalContent.includes(`import { ${blockIdentifier} } from '${blockConfigPath}'`);
|
|
44
|
+
const hasOriginalBlock = originalContent.includes(blockIdentifier);
|
|
45
|
+
|
|
46
|
+
console.log('๐ Before modification:');
|
|
47
|
+
console.log(` - Import present: ${hasOriginalImport}`);
|
|
48
|
+
console.log(` - Block in array: ${hasOriginalBlock}`);
|
|
49
|
+
console.log('');
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
updatePageCollectionConfig(pagesPath, blockConfigPath, blockIdentifier);
|
|
53
|
+
|
|
54
|
+
// Read file after modification
|
|
55
|
+
const updatedContent = fs.readFileSync(pagesPath, 'utf-8');
|
|
56
|
+
const hasUpdatedImport = updatedContent.includes(`import { ${blockIdentifier} } from '${blockConfigPath}'`);
|
|
57
|
+
const hasUpdatedBlock = updatedContent.includes(blockIdentifier);
|
|
58
|
+
|
|
59
|
+
console.log('๐ After Pages modification:');
|
|
60
|
+
console.log(` - Import present: ${hasUpdatedImport}`);
|
|
61
|
+
console.log(` - Block in array: ${hasUpdatedBlock}`);
|
|
62
|
+
console.log('');
|
|
63
|
+
|
|
64
|
+
if (hasUpdatedImport && hasUpdatedBlock) {
|
|
65
|
+
console.log('โ
Pages collection update successful!');
|
|
66
|
+
} else {
|
|
67
|
+
console.log('โ ๏ธ Pages collection update issues:');
|
|
68
|
+
if (!hasUpdatedImport) console.log(' - โ Import was not added');
|
|
69
|
+
if (!hasUpdatedBlock) console.log(' - โ Block was not added to array');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Now test RenderBlocks update
|
|
74
|
+
console.log('๐งช Testing RenderBlocks component update...');
|
|
75
|
+
|
|
76
|
+
const renderBlocksPath = '../newcms/src/blocks/RenderBlocks.tsx';
|
|
77
|
+
const componentPath = `./${blockSlug}/Component`;
|
|
78
|
+
|
|
79
|
+
// Check if the component file exists (it won't for editorial-carousel in test)
|
|
80
|
+
const fullComponentPath = require('path').resolve(componentPath.replace('./', 'src/blocks/') + '.tsx');
|
|
81
|
+
const componentExists = fs.existsSync(fullComponentPath);
|
|
82
|
+
|
|
83
|
+
if (componentExists) {
|
|
84
|
+
console.log('๐ Component file exists, testing full RenderBlocks update...');
|
|
85
|
+
|
|
86
|
+
// Extract the actual component name
|
|
87
|
+
const actualComponentName = extractComponentName(fullComponentPath);
|
|
88
|
+
const blockTypeKey = 'editorialCarousel';
|
|
89
|
+
|
|
90
|
+
console.log(`Extracted component name: ${actualComponentName}`);
|
|
91
|
+
console.log(`Block type key: ${blockTypeKey}`);
|
|
92
|
+
|
|
93
|
+
// Read RenderBlocks before modification
|
|
94
|
+
const originalRenderBlocksContent = fs.readFileSync(renderBlocksPath, 'utf-8');
|
|
95
|
+
const hasOriginalComponentImport = originalRenderBlocksContent.includes(`import { ${actualComponentName} } from '${componentPath}'`);
|
|
96
|
+
const hasOriginalBlockComponent = originalRenderBlocksContent.includes(`'${blockTypeKey}': ${actualComponentName}`);
|
|
97
|
+
|
|
98
|
+
console.log('๐ RenderBlocks before modification:');
|
|
99
|
+
console.log(` - Component import present: ${hasOriginalComponentImport}`);
|
|
100
|
+
console.log(` - Block component mapping present: ${hasOriginalBlockComponent}`);
|
|
101
|
+
console.log('');
|
|
102
|
+
|
|
103
|
+
updateRenderBlocksComponent(renderBlocksPath, blockSlug, componentPath);
|
|
104
|
+
|
|
105
|
+
// Read RenderBlocks after modification
|
|
106
|
+
const updatedRenderBlocksContent = fs.readFileSync(renderBlocksPath, 'utf-8');
|
|
107
|
+
const hasUpdatedComponentImport = updatedRenderBlocksContent.includes(`import { ${actualComponentName} } from '${componentPath}'`);
|
|
108
|
+
const hasUpdatedBlockComponent = updatedRenderBlocksContent.includes(`'${blockTypeKey}': ${actualComponentName}`);
|
|
109
|
+
|
|
110
|
+
console.log('๐ RenderBlocks after modification:');
|
|
111
|
+
console.log(` - Component import present: ${hasUpdatedComponentImport}`);
|
|
112
|
+
console.log(` - Block component mapping present: ${hasUpdatedBlockComponent}`);
|
|
113
|
+
console.log('');
|
|
114
|
+
|
|
115
|
+
if (hasUpdatedComponentImport && hasUpdatedBlockComponent) {
|
|
116
|
+
console.log('โ
RenderBlocks update successful! Component and mapping added.');
|
|
117
|
+
console.log('');
|
|
118
|
+
console.log('๐ Complete test passed! Pages collection and RenderBlocks updates work correctly.');
|
|
119
|
+
} else {
|
|
120
|
+
console.log('โ ๏ธ RenderBlocks update issues:');
|
|
121
|
+
if (!hasUpdatedComponentImport) console.log(' - โ Component import was not added');
|
|
122
|
+
if (!hasUpdatedBlockComponent) console.log(' - โ Block component mapping was not added');
|
|
123
|
+
console.log('');
|
|
124
|
+
console.log('๐ฅ Test failed! RenderBlocks implementation has issues.');
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
console.log('๐ Component file does not exist (expected for test), testing error handling...');
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
updateRenderBlocksComponent(renderBlocksPath, blockSlug, componentPath);
|
|
132
|
+
console.log('โ Expected error but function succeeded unexpectedly');
|
|
133
|
+
process.exit(1);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.log('โ
Function correctly failed with error:', error.message);
|
|
136
|
+
console.log('');
|
|
137
|
+
console.log('๐ Test passed! Function properly handles missing component files.');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.log('โ AST update failed:', error.message);
|
|
142
|
+
console.log('');
|
|
143
|
+
console.log('๐ฅ Test failed! The bug may not be fully fixed.');
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
console.log('โ Could not find Pages collection in Payload project');
|
|
148
|
+
console.log('Make sure you are running this from a valid Payload CMS project directory.');
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"outDir": "./dist",
|
|
6
|
-
"rootDir": "./src",
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"resolveJsonModule": true
|
|
13
|
-
},
|
|
14
|
-
"include": ["src/**/*.ts"],
|
|
15
|
-
"exclude": ["node_modules", "dist", "src/templates/**"]
|
|
16
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"outDir": "./dist",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"resolveJsonModule": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*.ts"],
|
|
15
|
+
"exclude": ["node_modules", "dist", "src/templates/**"]
|
|
16
|
+
}
|