@blocklet/pages-kit-block-studio 0.0.16 → 0.0.18

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.
@@ -29,7 +29,7 @@ function buildLib(options) {
29
29
  const filterModules = process.argv.includes('--filter')
30
30
  ? (_a = process.argv[process.argv.indexOf('--filter') + 1]) === null || _a === void 0 ? void 0 : _a.split(',')
31
31
  : ((_b = process.env.BLOCK_FILTER) === null || _b === void 0 ? void 0 : _b.split(',')) || null;
32
- const ignoreViteLog = false; // process.argv.includes('--log') ? false : process.env.BLOCK_LOG !== 'true';
32
+ const ignoreViteLog = process.argv.includes('--log') ? false : process.env.BLOCK_LOG !== 'true';
33
33
  const multiMode = process.argv.includes('--multi') || process.env.BLOCK_MULTI === 'true';
34
34
  const blocks = allBlocks.filter((name) => !filterModules || filterModules.includes(name || ''));
35
35
  if (!blocks.length) {
@@ -81,11 +81,13 @@ function generateWrapperCode(_a) {
81
81
  },
82
82
  }, null, 2);
83
83
  const client = `\
84
- import HomeComponent from '@blocklet/pages-kit-runtime/client';
84
+ import PageRenderComponent, { RuntimeProps, RuntimeType } from '@blocklet/pages-kit-runtime/client';
85
85
 
86
+ export type { RuntimeProps, RuntimeType };
86
87
 
88
+ ${generatePageDataTypes(state)}
87
89
 
88
- export default HomeComponent;
90
+ export default PageRenderComponent;
89
91
  `;
90
92
  const index = client;
91
93
  const middleware = `
@@ -205,10 +207,14 @@ export default router;
205
207
  compilerOptions: Object.assign(Object.assign({}, compilerOptions), { module: ts.ModuleKind.ESNext }),
206
208
  });
207
209
  // Generate proper type declarations
208
- const dts = ts.transpileModule(content, {
209
- fileName,
210
- compilerOptions: Object.assign(Object.assign({}, compilerOptions), { declaration: true, emitDeclarationOnly: true }),
211
- });
210
+ // const dts = ts.transpileModule(content, {
211
+ // fileName,
212
+ // compilerOptions: {
213
+ // ...compilerOptions,
214
+ // declaration: true,
215
+ // emitDeclarationOnly: true,
216
+ // },
217
+ // });
212
218
  return [
213
219
  {
214
220
  fileName: fileName.replace(/\.ts$/, '.cjs'),
@@ -220,11 +226,143 @@ export default router;
220
226
  },
221
227
  {
222
228
  fileName: fileName.replace(/\.ts$/, '.d.ts'),
223
- content: dts.outputText || content, // Fallback to original content if declaration fails
229
+ content, // Fallback to original content if declaration fails
224
230
  },
225
231
  ];
226
232
  })))).flat();
227
233
  return [...result, { fileName: 'package.json', content: packageJson }];
228
234
  });
229
235
  }
236
+ const basicComponentSectionTypes = {
237
+ iframe: `
238
+ src: string;
239
+ title?: string;
240
+ description?: string;
241
+ `,
242
+ section: `
243
+ title?: string;
244
+ description?: string;
245
+ image?: string;
246
+ imageMeta?: { naturalWidth?: number; naturalHeight?: number; filename: string };
247
+ `,
248
+ 'section-card-list': `
249
+ title?: string;
250
+ description?: string;
251
+ list: {
252
+ id: string;
253
+ title: string;
254
+ description: string;
255
+ image: string;
256
+ }[];
257
+ `,
258
+ toc: `
259
+ title?: string;
260
+ description?: string;
261
+ `,
262
+ };
263
+ function getCustomComponentPropertyType(type) {
264
+ if (!type)
265
+ return 'string';
266
+ if (type === 'string' || type === 'multiline')
267
+ return 'string';
268
+ if (type === 'url')
269
+ return '{ url: string; mediaKitUrl?: string; width?: number; height?: number }';
270
+ if (type === 'json')
271
+ return 'any';
272
+ if (type === 'yaml')
273
+ return 'any';
274
+ return 'any';
275
+ }
276
+ const ALLOWED_PROPERTY_TYPES = ['string', 'multiline', 'url', 'json', 'yaml'];
277
+ function generatePageDataTypes(state) {
278
+ const pageTypes = Object.values(state.pages)
279
+ .map((page) => {
280
+ // check if the page is a template page
281
+ if (!page.isTemplate)
282
+ return null;
283
+ // 将 slug 转换为有效的 TypeScript 类型名
284
+ const typeName = `Page${page.slug
285
+ .replace(/^\//, '')
286
+ .split('/')
287
+ .map((s) => s.charAt(0).toUpperCase() + s.slice(1))
288
+ .join('')
289
+ .replace(/[^a-zA-Z0-9]/g, '')}Data`;
290
+ // 收集所有 section 的配置信息
291
+ const sectionTypes = page.sectionIds
292
+ .map((sectionId) => {
293
+ var _a, _b, _c, _d;
294
+ const section = page.sections[sectionId];
295
+ if (!section)
296
+ return null;
297
+ // check if the section is a template section
298
+ if (!section.isTemplateSection)
299
+ return null;
300
+ if (section.component === 'custom-component') {
301
+ const componentId = (_a = section.config) === null || _a === void 0 ? void 0 : _a.componentId;
302
+ if (!componentId)
303
+ return null;
304
+ const component = ((_b = state.components[componentId]) === null || _b === void 0 ? void 0 : _b.data) || ((_d = (_c = state.resources.components) === null || _c === void 0 ? void 0 : _c[componentId]) === null || _d === void 0 ? void 0 : _d.component);
305
+ if (!component)
306
+ return null;
307
+ // 为自定义组件生成属性类型
308
+ const properties = Object.entries(component.properties || {})
309
+ .map(([, prop]) => {
310
+ var _a, _b, _c, _d, _e;
311
+ // check if the property type is allowed
312
+ if (((_a = prop.data) === null || _a === void 0 ? void 0 : _a.type) && !ALLOWED_PROPERTY_TYPES.includes((_b = prop.data) === null || _b === void 0 ? void 0 : _b.type))
313
+ return null;
314
+ // if key is undefined, use id
315
+ const key = ((_c = prop.data) === null || _c === void 0 ? void 0 : _c.key) || ((_d = prop.data) === null || _d === void 0 ? void 0 : _d.id);
316
+ if (!key)
317
+ return null;
318
+ return ` "${key}"?: ${getCustomComponentPropertyType((_e = prop.data) === null || _e === void 0 ? void 0 : _e.type)};`;
319
+ })
320
+ .filter(Boolean)
321
+ .join('\n');
322
+ return ` "${section.name || section.id}"?: {
323
+ ${properties}
324
+ };`;
325
+ }
326
+ // basic component section types
327
+ if (basicComponentSectionTypes[section.component]) {
328
+ return ` "${section.name || section.id}"?: { ${basicComponentSectionTypes[section.component]} };`;
329
+ }
330
+ return ` "${section.name || section.id}"?: any;`;
331
+ })
332
+ .filter(Boolean)
333
+ .join('\n');
334
+ return `
335
+ export interface ${typeName} {
336
+ title?: string;
337
+ image?: string;
338
+ description?: string;
339
+ sectionsData: {
340
+ ${sectionTypes}
341
+ };
342
+ }`;
343
+ })
344
+ .filter(Boolean)
345
+ .join('\n');
346
+ // 生成 PageData 类型的联合类型
347
+ const pageUnionTypes = Object.values(state.pages)
348
+ .map((page) => {
349
+ if (!page.isTemplate)
350
+ return null;
351
+ const typeName = `Page${page.slug
352
+ .replace(/^\//, '')
353
+ .split('/')
354
+ .map((s) => s.charAt(0).toUpperCase() + s.slice(1))
355
+ .join('')
356
+ .replace(/[^a-zA-Z0-9]/g, '')}Data`;
357
+ return typeName;
358
+ })
359
+ .filter(Boolean)
360
+ .join(' | ');
361
+ return `
362
+ // 页面数据类型定义
363
+ ${pageTypes}
364
+
365
+ // 所有页面数据类型的联合类型
366
+ export type PageDataUnion = ${pageUnionTypes || 'never'};`;
367
+ }
230
368
  exports.default = generateWrapperCode;
@@ -1,16 +1,74 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
2
44
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
46
  };
5
47
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.isDev = exports.isPathSafe = exports.libDir = exports.logger = void 0;
48
+ exports.getBlockCode = exports.isPagesKitBlockStudio = exports.getPreviewImageRelativePath = exports.downloadAsset = exports.isMetadataFile = exports.isDev = exports.isPathSafe = exports.NANOID_LENGTH = exports.PREVIEW_IMAGE_DIR = exports.METADATA_FILE_NAME = exports.libDir = exports.logger = void 0;
7
49
  exports.setBlockEntryFilesPattern = setBlockEntryFilesPattern;
8
50
  exports.getBlockEntryFilesPattern = getBlockEntryFilesPattern;
9
51
  exports.findComponentFiles = findComponentFiles;
10
52
  exports.getBlockName = getBlockName;
11
- exports.generateBlockYml = generateBlockYml;
53
+ exports.initializeMetadata = initializeMetadata;
54
+ exports.generateYaml = generateYaml;
55
+ exports.getBlockStudioInfo = getBlockStudioInfo;
56
+ const component_1 = require("@blocklet/sdk/lib/component");
57
+ const config_1 = __importDefault(require("@blocklet/sdk/lib/config"));
58
+ const fs_1 = __importDefault(require("fs"));
59
+ const promises_1 = require("fs/promises");
12
60
  const glob_1 = require("glob");
13
- const path_1 = __importDefault(require("path"));
61
+ const nanoid_1 = require("nanoid");
62
+ const path_1 = __importStar(require("path"));
63
+ const promises_2 = require("stream/promises");
64
+ const ufo_1 = require("ufo");
65
+ const yaml = __importStar(require("yaml"));
66
+ const constants_1 = require("../constants");
67
+ exports.logger = console;
68
+ exports.libDir = 'lib';
69
+ exports.METADATA_FILE_NAME = '@metadata.json';
70
+ exports.PREVIEW_IMAGE_DIR = '@preview-images';
71
+ exports.NANOID_LENGTH = 16;
14
72
  const DEFAULT_BLOCK_ENTRY_FILES_PATTERN = 'src/**/index.{ts,tsx,html}';
15
73
  if (!process.env.BLOCK_ENTRY_FILES_PATTERN) {
16
74
  process.env.BLOCK_ENTRY_FILES_PATTERN = DEFAULT_BLOCK_ENTRY_FILES_PATTERN;
@@ -32,11 +90,13 @@ function findComponentFiles(options = {}) {
32
90
  const blockName = getBlockName(file);
33
91
  const fullPath = path_1.default.resolve(cwd, file);
34
92
  const isHtml = file.endsWith('.html');
93
+ const metadata = initializeMetadata(fullPath);
35
94
  return {
36
95
  file,
37
96
  blockName,
38
97
  fullPath,
39
98
  isHtml,
99
+ metadata,
40
100
  };
41
101
  })
42
102
  .filter(({ blockName }) => !(filter === null || filter === void 0 ? void 0 : filter.length) || filter.includes(blockName || ''));
@@ -48,12 +108,14 @@ function getBlockName(entry) {
48
108
  const [, pathWithoutIndex] = indexMatch;
49
109
  return path_1.default.basename(pathWithoutIndex || 'unknown');
50
110
  }
111
+ const matadataMatch = entry.match(/(.*)\/@metadata\.json$/);
112
+ if (matadataMatch) {
113
+ const [, pathWithoutMetadata] = matadataMatch;
114
+ return path_1.default.basename(pathWithoutMetadata || 'unknown');
115
+ }
51
116
  // If not an index file, return the filename without extension
52
117
  return path_1.default.basename(entry, path_1.default.extname(entry));
53
118
  }
54
- exports.logger = console;
55
- function generateBlockYml() { }
56
- exports.libDir = 'lib';
57
119
  const isPathSafe = (filePath) => {
58
120
  const normalizedPath = path_1.default.normalize(filePath);
59
121
  const pwd = process.env.PWD || process.cwd();
@@ -61,3 +123,107 @@ const isPathSafe = (filePath) => {
61
123
  };
62
124
  exports.isPathSafe = isPathSafe;
63
125
  exports.isDev = process.env.BLOCKLET_MODE === 'development';
126
+ const isMetadataFile = (filePath) => {
127
+ return filePath.endsWith(exports.METADATA_FILE_NAME);
128
+ };
129
+ exports.isMetadataFile = isMetadataFile;
130
+ const downloadAsset = (_a) => __awaiter(void 0, [_a], void 0, function* ({ asset, savePath, componentDid, }) {
131
+ if (!componentDid || !exports.isDev || !asset || !savePath) {
132
+ throw new Error('Invalid params');
133
+ }
134
+ // Check path safety
135
+ if (!(0, exports.isPathSafe)(savePath)) {
136
+ throw new Error('Invalid save path: path traversal detected');
137
+ }
138
+ const fileName = (0, path_1.basename)(asset);
139
+ // Ensure target directory exists
140
+ yield (0, promises_1.mkdir)(path_1.default.dirname(savePath), { recursive: true });
141
+ // download asset from pages-kit's /uploads
142
+ const res = yield (0, component_1.call)({
143
+ name: process.env.BLOCKLET_COMPONENT_DID,
144
+ path: (0, ufo_1.joinURL)('/uploads', fileName),
145
+ responseType: 'stream',
146
+ method: 'GET',
147
+ });
148
+ if (res.status >= 200 && res.status < 400) {
149
+ const file = fs_1.default.createWriteStream(savePath);
150
+ yield (0, promises_2.pipeline)(res.data, file);
151
+ }
152
+ else {
153
+ throw new Error(`download asset failed ${res.status}`);
154
+ }
155
+ });
156
+ exports.downloadAsset = downloadAsset;
157
+ const getPreviewImageRelativePath = (name) => {
158
+ return path_1.default.join(exports.PREVIEW_IMAGE_DIR, name);
159
+ };
160
+ exports.getPreviewImageRelativePath = getPreviewImageRelativePath;
161
+ function initializeMetadata(tempFilePath) {
162
+ let content = '';
163
+ if (!tempFilePath) {
164
+ throw new Error('File path is required');
165
+ }
166
+ // file path is metadata file
167
+ const filePath = (0, exports.isMetadataFile)(tempFilePath) ? tempFilePath : path_1.default.join((0, path_1.dirname)(tempFilePath), exports.METADATA_FILE_NAME);
168
+ if (!filePath) {
169
+ throw new Error('File path is required');
170
+ }
171
+ if (exports.isPagesKitBlockStudio && fs_1.default.existsSync(filePath)) {
172
+ content = fs_1.default.readFileSync(filePath, 'utf-8');
173
+ }
174
+ let metadata = {};
175
+ if (content) {
176
+ try {
177
+ metadata = JSON.parse(content);
178
+ }
179
+ catch (_a) {
180
+ // If parsing fails, use empty object
181
+ }
182
+ }
183
+ // Add id if not exists
184
+ if (!metadata.id) {
185
+ metadata.id = (0, nanoid_1.nanoid)(exports.NANOID_LENGTH);
186
+ }
187
+ // Add createdAt if not exists
188
+ if (!metadata.createdAt) {
189
+ metadata.createdAt = new Date().toISOString();
190
+ }
191
+ // Add updatedAt if not exists
192
+ if (!metadata.updatedAt) {
193
+ metadata.updatedAt = new Date().toISOString();
194
+ }
195
+ // Add name if not exists
196
+ if (!metadata.name) {
197
+ metadata.name = getBlockName(filePath);
198
+ }
199
+ if (exports.isPagesKitBlockStudio && !fs_1.default.existsSync(filePath)) {
200
+ fs_1.default.writeFileSync(filePath, JSON.stringify(metadata, null, 2));
201
+ }
202
+ return metadata;
203
+ }
204
+ function generateYaml(metadata) {
205
+ return yaml.stringify(metadata);
206
+ }
207
+ function getBlockStudioInfo() {
208
+ return config_1.default.components.find((c) => c.did === constants_1.PAGES_KIT_BLOCK_STUDIO_DID);
209
+ }
210
+ exports.isPagesKitBlockStudio = process.env.BLOCKLET_COMPONENT_DID === constants_1.PAGES_KIT_BLOCK_STUDIO_DID;
211
+ const getBlockCode = (filePath) => {
212
+ var _a;
213
+ // Check path safety first
214
+ if (!(0, exports.isPathSafe)(filePath)) {
215
+ throw new Error('Invalid file path: path traversal detected');
216
+ }
217
+ const blockName = getBlockName(filePath);
218
+ // Find the actual code file using the block entry pattern
219
+ const files = findComponentFiles({ filter: [blockName] });
220
+ if (!files.length) {
221
+ throw new Error(`No code file found for block: ${blockName}`);
222
+ }
223
+ const codeFile = (_a = files[0]) === null || _a === void 0 ? void 0 : _a.fullPath;
224
+ if (!codeFile) {
225
+ throw new Error(`No code file found for block: ${blockName}`);
226
+ }
227
+ return fs_1.default.readFileSync(codeFile, 'utf8');
228
+ };
229
+ exports.getBlockCode = getBlockCode;
@@ -0,0 +1,6 @@
1
+ export const PAGES_KIT_DID = 'z8iZiDFg3vkkrPwsiba1TLXy3H9XHzFERsP8o';
2
+ export const PAGES_KIT_RESOURCE_TYPE = 'page';
3
+ export const PAGES_KIT_BLOCK_STUDIO_DID = 'z2qa7rr3eUyVnWp2PCxEVARuUfLFh6cE5V2xV';
4
+ export const PAGES_KIT_BLOCK_STUDIO_RESOURCE_TYPE = 'page';
5
+ export const MEDIA_KIT_DID = 'z8ia1mAXo8ZE7ytGF36L5uBf9kD2kenhqFGp9';
6
+ export const MEDIA_KIT_RESOURCE_TYPE = 'imgpack';
@@ -9,8 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { Router } from 'express';
11
11
  import fs from 'fs';
12
+ import { isEqual, keyBy, set } from 'lodash';
12
13
  import path from 'path';
13
- import { isPathSafe, isDev } from '../utils/helper';
14
+ import { isPathSafe, isDev, downloadAsset, isMetadataFile, getPreviewImageRelativePath, initializeMetadata, findComponentFiles, getBlockStudioInfo, getBlockCode, } from '../utils/helper';
14
15
  export const initBlockStudioRouter = Router();
15
16
  const BINARY_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico', '.svg'];
16
17
  initBlockStudioRouter.get('/', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
@@ -25,25 +26,23 @@ initBlockStudioRouter.get('/', (req, res) => __awaiter(void 0, void 0, void 0, f
25
26
  return res.status(403).json({ error: 'Invalid path' });
26
27
  }
27
28
  try {
28
- if (!fs.existsSync(filePath)) {
29
- return res.json(null);
30
- }
31
29
  const ext = path.extname(filePath).toLowerCase();
32
30
  if (BINARY_EXTENSIONS.includes(ext)) {
31
+ if (!fs.existsSync(filePath)) {
32
+ return res.json(null);
33
+ }
33
34
  // For images, stream the file directly
34
35
  const mimeType = `image/${ext.slice(1)}`;
35
36
  res.setHeader('Content-Type', mimeType);
36
37
  return fs.createReadStream(filePath).pipe(res);
37
38
  }
38
- // For text files, try to parse as JSON
39
- const content = fs.readFileSync(filePath, 'utf-8');
40
- try {
41
- return res.json(JSON.parse(content));
42
- }
43
- catch (_a) {
44
- // If JSON parsing fails, return as plain text
45
- return res.json(content);
39
+ const metadata = initializeMetadata(filePath);
40
+ const code = getBlockCode(filePath);
41
+ if (code) {
42
+ set(metadata, 'renderer.script', code);
43
+ set(metadata, 'renderer.type', 'react-component');
46
44
  }
45
+ return res.json(metadata);
47
46
  }
48
47
  catch (error) {
49
48
  return res.status(500).json({ error: 'Failed to read file' });
@@ -65,11 +64,60 @@ initBlockStudioRouter.post('/', (req, res) => __awaiter(void 0, void 0, void 0,
65
64
  if (!fs.existsSync(dir)) {
66
65
  fs.mkdirSync(dir, { recursive: true });
67
66
  }
68
- fs.writeFileSync(filePath, JSON.stringify(content, null, 2));
69
- return res.json({ success: true });
67
+ const currentMetadata = initializeMetadata(filePath);
68
+ const mergedContent = Object.assign(Object.assign({}, currentMetadata), content);
69
+ if (isEqual(currentMetadata, mergedContent)) {
70
+ return res.json({ success: true, content: mergedContent, message: 'No changes' });
71
+ }
72
+ mergedContent.updatedAt = new Date().toISOString();
73
+ // Check if this is a metadata file and has previewImage update
74
+ if (isMetadataFile(filePath) && content.previewImage && currentMetadata.previewImage !== content.previewImage) {
75
+ const previewImagePath = path.join(dir, getPreviewImageRelativePath(content.previewImage));
76
+ if (!fs.existsSync(previewImagePath)) {
77
+ yield downloadAsset({
78
+ asset: content.previewImage,
79
+ savePath: previewImagePath,
80
+ componentDid: process.env.BLOCKLET_COMPONENT_DID || '',
81
+ });
82
+ }
83
+ }
84
+ res.json({ success: true, content: mergedContent, message: 'Updated' });
85
+ // save metadata without renderer after response
86
+ delete mergedContent.renderer;
87
+ fs.writeFileSync(filePath, JSON.stringify(mergedContent, null, 2));
88
+ return null;
70
89
  }
71
90
  catch (error) {
72
91
  return res.status(500).json({ error: 'Failed to write file' });
73
92
  }
74
93
  }));
94
+ initBlockStudioRouter.get('/all', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
95
+ const { withBlockletData = true } = req.query;
96
+ const allBlocks = yield findComponentFiles();
97
+ // get code to metadata
98
+ const allBlocksWithCode = allBlocks.map((block) => {
99
+ const code = getBlockCode(block.fullPath);
100
+ if (code) {
101
+ set(block.metadata, 'renderer.script', code);
102
+ set(block.metadata, 'renderer.type', 'react-component');
103
+ }
104
+ return block;
105
+ });
106
+ if (withBlockletData) {
107
+ const allBlocksWithBlockletData = allBlocksWithCode.map((block) => {
108
+ const blockletInfo = getBlockStudioInfo() || {
109
+ title: '',
110
+ did: '',
111
+ };
112
+ const item = {
113
+ blockletTitle: blockletInfo.title,
114
+ blockletId: blockletInfo.did,
115
+ data: block.metadata,
116
+ };
117
+ return item;
118
+ });
119
+ return res.json(keyBy(allBlocksWithBlockletData, 'data.id'));
120
+ }
121
+ return res.json(keyBy(allBlocksWithCode, 'id'));
122
+ }));
75
123
  export default initBlockStudioRouter;
@@ -11,8 +11,9 @@ import { getResourceExportDir } from '@blocklet/sdk/lib/component';
11
11
  import { spawn } from 'child_process';
12
12
  import { Router } from 'express';
13
13
  import fs from 'fs';
14
+ import set from 'lodash/set';
14
15
  import path, { join } from 'path';
15
- import { findComponentFiles, libDir } from '../utils/helper';
16
+ import { findComponentFiles, libDir, getPreviewImageRelativePath, generateYaml, logger } from '../utils/helper';
16
17
  const DID = 'z2qa7rr3eUyVnWp2PCxEVARuUfLFh6cE5V2xV';
17
18
  const RESOURCE_TYPE = 'page';
18
19
  const allTag = '@ALL_COMPONENTS';
@@ -111,9 +112,55 @@ initResourceRouter.post('/', (req, res) => __awaiter(void 0, void 0, void 0, fun
111
112
  fs.rmSync(dir, { recursive: true, force: true });
112
113
  fs.mkdirSync(dir, { recursive: true });
113
114
  const rootDir = process.cwd();
114
- const tmpPackage = join(rootDir, libDir);
115
+ const distDir = join(rootDir, libDir);
116
+ const tmpPackage = join(distDir, 'resource-blocklet');
117
+ fs.mkdirSync(tmpPackage, { recursive: true });
118
+ const pagesDir = join(tmpPackage, 'pages');
119
+ fs.mkdirSync(pagesDir, { recursive: true });
120
+ const componentsDir = join(tmpPackage, 'components');
121
+ fs.mkdirSync(componentsDir, { recursive: true });
122
+ // get @metadata.json by glob
123
+ const canUseComponents = findComponentFiles({ cwd: rootDir, filter: componentIds });
124
+ // Filter and process metadata files
125
+ const metadataList = canUseComponents.map(({ fullPath, blockName, metadata: _metadata }) => {
126
+ // get metadata
127
+ const metadata = _metadata;
128
+ // get code to metadata
129
+ const code = fs.readFileSync(join(distDir, 'es', `${blockName}.js`), 'utf8');
130
+ if (code) {
131
+ set(metadata, 'renderer.script', code);
132
+ set(metadata, 'renderer.type', 'react-component');
133
+ }
134
+ // write metadata to metadataPath
135
+ const metadataYmlPath = path.join(componentsDir, `${metadata.name || 'unnamed'}.${metadata.id}.yml`);
136
+ fs.writeFileSync(metadataYmlPath, generateYaml(metadata));
137
+ // Handle preview image if exists
138
+ if (metadata.previewImage) {
139
+ const imagePath = path.join(path.dirname(fullPath), getPreviewImageRelativePath(metadata.previewImage));
140
+ const imageDestPath = path.join(componentsDir, metadata.previewImage);
141
+ if (fs.existsSync(imagePath)) {
142
+ fs.copyFileSync(imagePath, imageDestPath);
143
+ }
144
+ }
145
+ return metadata;
146
+ });
147
+ // write pages.config.yml
148
+ const pagesConfigPath = path.join(tmpPackage, '.blocklet/pages/pages.config.yml');
149
+ fs.mkdirSync(path.dirname(pagesConfigPath), { recursive: true });
150
+ const pagesConfig = {
151
+ pages: [],
152
+ components: metadataList.map((metadata) => ({
153
+ id: metadata.id,
154
+ name: metadata.name,
155
+ })),
156
+ supportedLocales: [],
157
+ config: {},
158
+ };
159
+ fs.writeFileSync(pagesConfigPath, generateYaml(pagesConfig));
160
+ logger.info('generate resource blocklet block count:', metadataList.length);
115
161
  yield copyRecursive(tmpPackage, dir);
116
- fs.rmSync(tmpPackage, { recursive: true, force: true });
162
+ // remove tmpPackage
163
+ // fs.rmSync(tmpPackage, { recursive: true, force: true });
117
164
  res.json({ success: true });
118
165
  }
119
166
  catch (error) {
@@ -1,6 +1,7 @@
1
1
  // @ts-ignore
2
2
  import { initProxyToMediaKitUploadsMiddleware, initStaticResourceMiddleware } from '@blocklet/uploader-server';
3
3
  import express, { Router } from 'express';
4
+ import { PAGES_KIT_DID, PAGES_KIT_RESOURCE_TYPE, MEDIA_KIT_DID, MEDIA_KIT_RESOURCE_TYPE, PAGES_KIT_BLOCK_STUDIO_DID, PAGES_KIT_BLOCK_STUDIO_RESOURCE_TYPE, } from '../constants';
4
5
  // init uploader router
5
6
  export const initUploaderRouter = Router();
6
7
  initUploaderRouter.use('/', initProxyToMediaKitUploadsMiddleware({
@@ -10,20 +11,20 @@ initUploaderRouter.use('/', initProxyToMediaKitUploadsMiddleware({
10
11
  resourceTypes: [
11
12
  // image bin resource
12
13
  {
13
- type: 'imgpack',
14
- did: 'z8ia1mAXo8ZE7ytGF36L5uBf9kD2kenhqFGp9',
14
+ type: MEDIA_KIT_RESOURCE_TYPE,
15
+ did: MEDIA_KIT_DID,
15
16
  },
16
17
  // pages kit resource (pages and components folder)
17
18
  {
18
- type: 'page',
19
- did: 'z8iZiDFg3vkkrPwsiba1TLXy3H9XHzFERsP8o',
19
+ type: PAGES_KIT_RESOURCE_TYPE,
20
+ did: PAGES_KIT_DID,
20
21
  folder: ['pages', 'components'],
21
22
  blacklist: ['.yml'],
22
23
  },
23
24
  // pages kit block studio resource
24
25
  {
25
- type: 'page',
26
- did: 'z2qa7rr3eUyVnWp2PCxEVARuUfLFh6cE5V2xV',
26
+ type: PAGES_KIT_BLOCK_STUDIO_RESOURCE_TYPE,
27
+ did: PAGES_KIT_BLOCK_STUDIO_DID,
27
28
  folder: ['pages', 'components'],
28
29
  blacklist: ['.yml'],
29
30
  },
@@ -13,7 +13,7 @@ import { readFileSync, existsSync } from 'fs';
13
13
  import * as path from 'path';
14
14
  import pages, { DefaultPageStrategy } from 'vite-plugin-react-pages';
15
15
  import { findComponentFiles, setBlockEntryFilesPattern, getBlockEntryFilesPattern, getBlockName, logger, } from '../utils/helper';
16
- import { initHtmlPreviewTransformPlugin, VIRTUAL_MODULE_ID } from './vite-plugin-html-transform';
16
+ import { initHtmlPreviewTransformPlugin, VIRTUAL_MODULE_ID, readHtmlFiles, generateComponent, } from './vite-plugin-html-transform';
17
17
  // import initRemoteScriptLocalizerPlugin from './vite-plugin-remote-script-localizer';
18
18
  export function initBlockStudioPlugins(options) {
19
19
  const workingDir = (options === null || options === void 0 ? void 0 : options.cwd) || process.cwd();
@@ -85,6 +85,9 @@ export function initBlockStudioPlugins(options) {
85
85
  '@arcblock/did-connect',
86
86
  ],
87
87
  output: {
88
+ chunkFileNames: () => {
89
+ return '[format]/_chunks/[name]-[hash].js';
90
+ },
88
91
  // 为所有外部依赖提供全局变量
89
92
  globals: {
90
93
  react: 'React',
@@ -130,6 +133,7 @@ export function initBlockStudioPlugins(options) {
130
133
  ? {
131
134
  isHtmlPreview: true,
132
135
  dataPath: filePath,
136
+ code: generateComponent(readHtmlFiles(dirPath.split('?dir=')[1] || '')),
133
137
  blockName,
134
138
  dirPath,
135
139
  metadataPath,