@superblocksteam/cli 2.0.6-next.15 → 2.0.6-next.17

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/README.md CHANGED
@@ -14,7 +14,7 @@ $ npm install -g @superblocksteam/cli
14
14
  $ superblocks COMMAND
15
15
  running command...
16
16
  $ superblocks (--version)
17
- @superblocksteam/cli/2.0.6-next.15 linux-x64 node-v20.19.0
17
+ @superblocksteam/cli/2.0.6-next.17 linux-x64 node-v20.19.0
18
18
  $ superblocks --help [COMMAND]
19
19
  USAGE
20
20
  $ superblocks COMMAND
package/dist/index.js CHANGED
@@ -413073,7 +413073,7 @@ init_cjs_shims();
413073
413073
  var templates = {
413074
413074
  "api-builder-to-yaml": {
413075
413075
  "bootstrap.mjs": 'import { register } from "node:module";\nimport { pathToFileURL } from "node:url";\n\nregister("./shim-loader.mjs", pathToFileURL("./"));\n',
413076
- "package.json": '{\n "type": "module",\n "dependencies": {\n "acorn": "^8.14.0",\n "prettier": "^3.5.3",\n "yaml": "^2.7.1"\n },\n "devDependencies": {\n "@types/node": "^22.15.18",\n "@typescript-eslint/parser": "^8.17.0",\n "eslint": "^9.26.0",\n "typescript": "^5.8.3",\n "vitest": "^3.0.9"\n }\n}',
413076
+ "package.json": '{\n "type": "module",\n "dependencies": {\n "acorn": "^8.14.0",\n "prettier": "^3.5.3",\n "yaml": "^2.7.1"\n },\n "devDependencies": {\n "@types/node": "^22.15.18",\n "@typescript-eslint/parser": "^8.17.0",\n "eslint": "^9.26.0",\n "typescript": "^5.8.3",\n "vitest": "^3.2.0"\n }\n}\n',
413077
413077
  "shim-loader.mjs": 'import path from "path";\nimport { pathToFileURL } from "url";\n\nconst overrideMap = {\n "@superblocksteam/library": "./dist/superblocks-library-shim/index.js",\n};\n\nexport async function resolve(specifier, context, nextResolve) {\n if (overrideMap[specifier]) {\n const fullPath = path.resolve(overrideMap[specifier]);\n return {\n shortCircuit: true,\n url: pathToFileURL(fullPath).href,\n };\n }\n\n return nextResolve(specifier, context);\n}\n',
413078
413078
  "src/do-eval-to-sdk.ts": 'import fs from "fs";\nimport path from "path";\nimport { fileURLToPath } from "url";\n\n// finds all JavaScript files in the `dist/apis-to-transform` directory,\n// imports each module, converts its JSON representation to SDK,\n// and outputs a JSON map with filenames as keys and SDK content as values.\n\nasync function main() {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = path.dirname(__filename);\n\n const apisDir = path.resolve(__dirname, "./to-sdk");\n\n const files = fs.readdirSync(apisDir);\n\n const jsFiles = files.filter(\n (file) => file.endsWith(".js") && file !== "__template__.js",\n );\n\n const results: Record<string, string> = {};\n\n for (const jsFile of jsFiles) {\n const filePath = path.join(apisDir, jsFile);\n const absolutePath = path.resolve(filePath);\n\n try {\n const fileUrl = new URL(`file://${absolutePath}`);\n const module = await import(fileUrl.href);\n\n const defaultExport = module.default;\n\n if (defaultExport && typeof defaultExport.toSDK === "function") {\n const sdkData = await defaultExport.toSDK();\n\n results[jsFile] = sdkData;\n } else {\n console.warn(`${jsFile}: Default export doesn\'t have a toSDK method`);\n }\n } catch (error) {\n console.error(`Error processing ${jsFile}:`, error);\n }\n }\n\n console.log(JSON.stringify(results, null, 2));\n}\n\nmain().catch((error) => {\n console.error("Error:", error);\n process.exit(1);\n});\n',
413079
413079
  "src/do-eval-to-yaml.ts": 'import fs from "fs";\nimport path from "path";\nimport { fileURLToPath } from "url";\nimport yaml from "yaml";\n\n// finds all JavaScript files in the `dist/apis-to-transform` directory,\n// imports each module, converts its JSON representation to YAML,\n// and outputs a JSON map with filenames as keys and YAML content as values.\n\nasync function main() {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = path.dirname(__filename);\n\n const apisDir = path.resolve(__dirname, "./to-yaml");\n\n const files = fs.readdirSync(apisDir);\n\n const jsFiles = files.filter((file) => file.endsWith(".js"));\n\n const results: Record<string, string> = {};\n\n for (const jsFile of jsFiles) {\n const filePath = path.join(apisDir, jsFile);\n const absolutePath = path.resolve(filePath);\n\n try {\n const fileUrl = new URL(`file://${absolutePath}`);\n const module = await import(fileUrl.href);\n\n const defaultExport = module.default;\n\n if (defaultExport && typeof defaultExport.toJSON === "function") {\n const jsonData = await defaultExport.toJSON();\n\n const yamlContent = yaml.stringify(jsonData);\n\n results[jsFile] = yamlContent;\n } else {\n console.warn(`${jsFile}: Default export doesn\'t have a toJSON method`);\n }\n } catch (error) {\n console.error(`Error processing ${jsFile}:`, error);\n }\n }\n\n console.log(JSON.stringify(results, null, 2));\n}\n\nmain().catch((error) => {\n console.error("Error:", error);\n process.exit(1);\n});\n',
@@ -417871,6 +417871,7 @@ Address the errors and return the fixed code.`;
417871
417871
  switch (event.type) {
417872
417872
  case USER_SENT_PROMPT: {
417873
417873
  const { request, peer } = event;
417874
+ params.signals.emit("generationStarted");
417874
417875
  const initialElementIds = clark.context.initialElementIds ?? Object.keys(params.sourceTrackerInterface.getElementToFilePathMap() ?? {});
417875
417876
  clark.updateContext((context2) => ({
417876
417877
  ...context2,
@@ -431924,6 +431925,9 @@ function getPageFolder(rootPath, pageName) {
431924
431925
  function getPageFilePath(rootPath, pageName) {
431925
431926
  return path21.join(getPageFolder(rootPath, pageName), "index.tsx");
431926
431927
  }
431928
+ function isPageFilePath(filePath) {
431929
+ return /pages\/.*\/index\.tsx/.test(filePath);
431930
+ }
431927
431931
 
431928
431932
  // ../../../vite-plugin-file-sync/dist/traverse.js
431929
431933
  init_cjs_shims();
@@ -432775,6 +432779,11 @@ function toCodeEventFlow(stepDefs_) {
432775
432779
  code = `${code}.showAlert(${getDynamicValue(message)}, ${styleArg}${durationArg}${positionArg})`;
432776
432780
  break;
432777
432781
  }
432782
+ case TriggerStepType.CONTROL_TIMER: {
432783
+ const timerName = stepDef.state?.name !== void 0 ? `${stepDef.state?.scope === import_shared25.ApplicationScope.APP ? "App." : ""}${stepDef.state.name}` : "undefined";
432784
+ code = `${code}.controlTimer(${timerName}, "${stepDef.command ?? "start"}")`;
432785
+ break;
432786
+ }
432778
432787
  default:
432779
432788
  getLogger().warn(`No support for writing event flow for step type ${stepDef.type}`);
432780
432789
  }
@@ -432985,6 +432994,30 @@ function toValueEventFlow(nodePath, existingSteps = [], parentId) {
432985
432994
  }
432986
432995
  ];
432987
432996
  }
432997
+ case "controlTimer": {
432998
+ if (args.length !== 2) {
432999
+ return existingSteps;
433000
+ }
433001
+ if (!args[0]?.node || !args[1]?.node) {
433002
+ return existingSteps;
433003
+ }
433004
+ const name18 = nodeToValue(args[0].node);
433005
+ const isAppScoped = name18 && name18.startsWith("App.");
433006
+ const command = nodeToValue(args[1].node);
433007
+ const variableName = isAppScoped ? name18.split(".", 2)[1] : name18;
433008
+ return [
433009
+ ...existingSteps,
433010
+ {
433011
+ id: id2,
433012
+ type: import_shared26.TriggerStepType.CONTROL_TIMER,
433013
+ state: name18 ? {
433014
+ name: variableName,
433015
+ scope: isAppScoped ? import_shared26.ApplicationScope.APP : import_shared26.ApplicationScope.PAGE
433016
+ } : void 0,
433017
+ command
433018
+ }
433019
+ ];
433020
+ }
432988
433021
  default:
432989
433022
  logger3.warn(`unknown event: ${eventName}`);
432990
433023
  return existingSteps;
@@ -433768,6 +433801,87 @@ function addLegacyCustomComponentVariables(path55, tracker) {
433768
433801
  });
433769
433802
  }
433770
433803
 
433804
+ // ../../../vite-plugin-file-sync/dist/operations/operation-processor.js
433805
+ init_cjs_shims();
433806
+ var OperationProcessor = class {
433807
+ config;
433808
+ operationQueue;
433809
+ pendingOperations = [];
433810
+ batchTimer = null;
433811
+ _enabled = true;
433812
+ constructor(config2 = {}) {
433813
+ this.config = {
433814
+ batchWindowMs: 50,
433815
+ maxBatchSize: 100,
433816
+ ...config2
433817
+ };
433818
+ this.operationQueue = new OperationQueue();
433819
+ }
433820
+ async addOperation(operation) {
433821
+ const timestamp2 = Date.now();
433822
+ const id2 = `operation-${timestamp2}-${Math.random()}`;
433823
+ const fullOperation = {
433824
+ ...operation,
433825
+ id: id2,
433826
+ timestamp: timestamp2
433827
+ };
433828
+ if (!this._enabled || fullOperation.priority) {
433829
+ return this.processOperations([fullOperation]);
433830
+ }
433831
+ this.pendingOperations.push(fullOperation);
433832
+ if (this.pendingOperations.length >= this.config.maxBatchSize) {
433833
+ return this.flush();
433834
+ }
433835
+ this.resetBatchTimer();
433836
+ }
433837
+ async flush() {
433838
+ if (this.pendingOperations.length === 0) {
433839
+ return;
433840
+ }
433841
+ const operations = [...this.pendingOperations];
433842
+ this.pendingOperations = [];
433843
+ this.clearBatchTimer();
433844
+ return this.operationQueue.enqueue(() => this.processOperations(operations));
433845
+ }
433846
+ disable() {
433847
+ this.setEnabled(false);
433848
+ }
433849
+ enable() {
433850
+ this.setEnabled(true);
433851
+ }
433852
+ setEnabled(enabled) {
433853
+ const wasEnabled = this._enabled;
433854
+ this._enabled = enabled;
433855
+ if (!enabled && wasEnabled && this.pendingOperations.length > 0) {
433856
+ this.flush().catch((error) => {
433857
+ console.error("Error flushing operations on priority mode enable:", error);
433858
+ });
433859
+ }
433860
+ }
433861
+ async processOperations(operations) {
433862
+ if (operations.length === 0) {
433863
+ return;
433864
+ }
433865
+ for (const operation of operations) {
433866
+ await operation.execute();
433867
+ }
433868
+ }
433869
+ resetBatchTimer() {
433870
+ this.clearBatchTimer();
433871
+ this.batchTimer = setTimeout(() => {
433872
+ this.flush().catch((error) => {
433873
+ console.error("Error flushing operations on timer:", error);
433874
+ });
433875
+ }, this.config.batchWindowMs);
433876
+ }
433877
+ clearBatchTimer() {
433878
+ if (this.batchTimer) {
433879
+ clearTimeout(this.batchTimer);
433880
+ this.batchTimer = null;
433881
+ }
433882
+ }
433883
+ };
433884
+
433771
433885
  // ../../../vite-plugin-file-sync/dist/parsing/bindings.js
433772
433886
  init_cjs_shims();
433773
433887
  var localBindingKinds = /* @__PURE__ */ new Set(["local", "param", "var", "const", "let"]);
@@ -435867,6 +435981,7 @@ var SourceTracker = class {
435867
435981
  const extension = path26.extname(fileName);
435868
435982
  if (extension !== ".ts" && extension !== ".tsx")
435869
435983
  return;
435984
+ const existingFile = fileName in this.fileToMeta;
435870
435985
  try {
435871
435986
  const astMap = this.parseJsxFromEntrypoint({
435872
435987
  files: [{ fileName, code: fileContents }]
@@ -435889,7 +436004,19 @@ var SourceTracker = class {
435889
436004
  delete this.elementToLocation[key2];
435890
436005
  delete this.elementToFilePath[key2];
435891
436006
  });
435892
- const changedFiles = this.sbScopeManager.resetScope(fileName);
436007
+ let changedFiles = [];
436008
+ if (existingFile) {
436009
+ changedFiles = this.sbScopeManager.resetScope(fileName);
436010
+ } else {
436011
+ this.sbScopeManager.parseScopes({
436012
+ [fileName]: {
436013
+ code: fileContents,
436014
+ ast,
436015
+ imports: extractImportsFromAst(ast)
436016
+ }
436017
+ });
436018
+ changedFiles.push(fileName);
436019
+ }
435893
436020
  if (!fileName.endsWith(SCOPE_FILE)) {
435894
436021
  const { idMap } = supplementElementIds({
435895
436022
  fileName,
@@ -436015,7 +436142,7 @@ var SourceTracker = class {
436015
436142
  });
436016
436143
  return scopeDefinition.id;
436017
436144
  };
436018
- deleteApi = async ({ pageName, apiName }) => {
436145
+ deleteApi = ({ pageName, apiName }) => {
436019
436146
  const { scopeDefinition, filePath: scopeFilePath } = this.sbScopeManager.getScopeDefinitionAndFilePathByNameOrId({
436020
436147
  identifier: pageName,
436021
436148
  type: "name"
@@ -436047,24 +436174,24 @@ var SourceTracker = class {
436047
436174
  });
436048
436175
  return scopeDefinition.id;
436049
436176
  };
436050
- addEntity = async ({ scopeId, entity }) => {
436177
+ addEntity = ({ scopeId, entity }) => {
436051
436178
  const changedFiles = this.sbScopeManager.addScopeEntity(scopeId, entity);
436052
436179
  changedFiles.forEach((file) => {
436053
436180
  this.changedFiles.add(file);
436054
436181
  });
436055
436182
  };
436056
- updateEntity = async (payload) => {
436183
+ updateEntity = (payload) => {
436057
436184
  const changedFile = this.sbScopeManager.updateScopeEntity(payload);
436058
436185
  this.changedFiles.add(changedFile);
436059
436186
  };
436060
- deleteEntity = async ({ entityId }) => {
436187
+ deleteEntity = ({ entityId }) => {
436061
436188
  const { changedFiles, deletedEntitiesNames } = this.sbScopeManager.deleteScopeEntity(entityId);
436062
436189
  changedFiles.forEach((file) => {
436063
436190
  this.changedFiles.add(file);
436064
436191
  });
436065
436192
  return deletedEntitiesNames[0];
436066
436193
  };
436067
- renameEntity = async ({ entityId, oldName, newName, scopeName }) => {
436194
+ renameEntity = ({ entityId, oldName, newName, scopeName }) => {
436068
436195
  const { changedFiles, scopeFile } = this.sbScopeManager.renameScopeEntity({
436069
436196
  entityId,
436070
436197
  newName,
@@ -436095,7 +436222,7 @@ var SourceTracker = class {
436095
436222
  }
436096
436223
  };
436097
436224
  // THEMING
436098
- updateTheme = async ({ themeFilePath, theme }) => {
436225
+ updateTheme = ({ themeFilePath, theme }) => {
436099
436226
  const ast = this.getCurrentFiles()[themeFilePath]?.ast;
436100
436227
  if (!ast) {
436101
436228
  throw new Error("File not found in source tracker " + path26);
@@ -436108,7 +436235,7 @@ var SourceTracker = class {
436108
436235
  throw e;
436109
436236
  }
436110
436237
  };
436111
- addElement = async ({ parentElement, tagName, properties, children, id: id2, scopeName }) => {
436238
+ addElement = ({ parentElement, tagName, properties, children, id: id2, scopeName }) => {
436112
436239
  const logger3 = getLogger();
436113
436240
  const parentOpeningElementPath = this.getElementToLocation(parentElement.source.id);
436114
436241
  const parentFilepath = this.getElementToFilePath(parentElement.source.id);
@@ -436252,7 +436379,7 @@ var SourceTracker = class {
436252
436379
  throw new Error("Error updating source tracker during add" + e.message);
436253
436380
  }
436254
436381
  };
436255
- deleteElement = async ({ source: source2, scopeName }) => {
436382
+ deleteElement = ({ source: source2, scopeName }) => {
436256
436383
  const logger3 = getLogger();
436257
436384
  let openingTag = this.getElementToLocation(source2.id);
436258
436385
  if (!openingTag) {
@@ -436411,13 +436538,13 @@ var SourceTracker = class {
436411
436538
  element.node.closingElement = import_types24.default.jsxClosingElement(import_types24.default.jsxIdentifier(getTagName(openingElement.node.name) ?? ""));
436412
436539
  }
436413
436540
  };
436414
- setProperty = async ({ source: source2, property, info }) => {
436415
- await this.setProperties({
436541
+ setProperty = ({ source: source2, property, info }) => {
436542
+ this.setProperties({
436416
436543
  source: source2,
436417
436544
  changes: { [property]: info }
436418
436545
  });
436419
436546
  };
436420
- setProperties = async ({ source: source2, changes }) => {
436547
+ setProperties = ({ source: source2, changes }) => {
436421
436548
  const logger3 = getLogger();
436422
436549
  if (Object.keys(changes).length === 0)
436423
436550
  return;
@@ -436643,12 +436770,13 @@ var SUPPORTED_FILETYPES = [
436643
436770
  }
436644
436771
  ];
436645
436772
  var APP_THEME_FILE_NAME = "appTheme.ts";
436646
- var FileSyncManager = class extends import_shared32.TracedEventEmitter {
436773
+ var FileSystemManager = class extends import_shared32.TracedEventEmitter {
436647
436774
  rootDir;
436648
436775
  tsFiles = {};
436649
436776
  apiFiles = {};
436650
436777
  sourceTracker;
436651
436778
  fsOperationQueue;
436779
+ operationProcessor;
436652
436780
  generationNumberSequence;
436653
436781
  routes = {};
436654
436782
  watcher;
@@ -436661,6 +436789,11 @@ var FileSyncManager = class extends import_shared32.TracedEventEmitter {
436661
436789
  this.fsOperationQueue = fsOperationQueue;
436662
436790
  this.generationNumberSequence = generationNumberSequence;
436663
436791
  this._tracer = tracer2;
436792
+ this.operationProcessor = new OperationProcessor({
436793
+ batchWindowMs: 50,
436794
+ maxBatchSize: 100
436795
+ });
436796
+ this.operationProcessor.disable();
436664
436797
  applyErrorHandling(this, {
436665
436798
  watch: { operation: "editing from code" },
436666
436799
  handleCreatePage: { operation: "creating a page" },
@@ -436807,132 +436940,193 @@ var FileSyncManager = class extends import_shared32.TracedEventEmitter {
436807
436940
  this.updateApi(content2, path55);
436808
436941
  }
436809
436942
  });
436810
- const handleFileChange = async (event, filePath) => {
436811
- logger3.info(`File changed: ${filePath}, event: ${event}`);
436812
- switch (event) {
436813
- case "add": {
436814
- const fileType = SUPPORTED_FILETYPES.find((f) => filePath.endsWith(f.extension));
436815
- if (!fileType || !filePath.startsWith(rootPath)) {
436816
- return;
436817
- }
436818
- const data = await readFile6(filePath);
436819
- if (typeof data !== "string")
436820
- return;
436821
- if (/pages\/.*\/index\.tsx/.test(filePath)) {
436822
- const file = await readFile6(filePath);
436823
- if (!file) {
436824
- logger3.error(`Failed to read file: ${filePath}`);
436825
- return;
436826
- }
436827
- if (!(filePath in this.tsFiles)) {
436828
- this.tsFiles[filePath] = file;
436829
- this.handleNonVisualChangeByDeletingIds(filePath, file);
436830
- this.emit("addPage", filePath);
436943
+ watcher.on("all", this.handleFileChange);
436944
+ }
436945
+ enableOperationsQueue() {
436946
+ this.operationProcessor.enable();
436947
+ }
436948
+ disableOperationsQueue() {
436949
+ this.operationProcessor.disable();
436950
+ }
436951
+ async flushOperations() {
436952
+ await this.operationProcessor.flush();
436953
+ }
436954
+ handleFileChange = async (event, filePath) => {
436955
+ const logger3 = getLogger();
436956
+ logger3.info(`File changed: ${filePath}, event: ${event}`);
436957
+ const rootPath = this.rootDir;
436958
+ if (!rootPath) {
436959
+ throw new Error("Root directory not set");
436960
+ }
436961
+ if (event === "addDir" || event === "unlinkDir") {
436962
+ return;
436963
+ }
436964
+ const routePath = path27.join(rootPath, ROUTES_FILE);
436965
+ const fileType = SUPPORTED_FILETYPES.find((f) => filePath.endsWith(f.extension));
436966
+ if (!fileType || !filePath.startsWith(rootPath)) {
436967
+ return;
436968
+ }
436969
+ switch (event) {
436970
+ case "add": {
436971
+ const data = await readFile6(filePath);
436972
+ if (typeof data !== "string")
436973
+ return;
436974
+ const isPage = isPageFilePath(filePath);
436975
+ if (isPage) {
436976
+ void this.operationProcessor.addOperation({
436977
+ metadata: {
436978
+ filePath
436979
+ },
436980
+ execute: async () => {
436981
+ const file = await readFile6(filePath);
436982
+ if (!file) {
436983
+ logger3.error(`Failed to read file: ${filePath}`);
436984
+ return;
436985
+ }
436986
+ if (!(filePath in this.tsFiles)) {
436987
+ this.tsFiles[filePath] = file;
436988
+ this.handleNonVisualChangeByDeletingIds(filePath, file);
436989
+ this.emit("addPage", filePath);
436990
+ }
436831
436991
  }
436832
- }
436833
- switch (fileType.type) {
436834
- case "api":
436835
- case "python-api-step":
436836
- case "js-api-step": {
436837
- await this.processApiUpdates(filePath, fileType);
436838
- break;
436992
+ });
436993
+ } else {
436994
+ void this.operationProcessor.addOperation({
436995
+ metadata: {
436996
+ filePath
436997
+ },
436998
+ execute: async () => {
436999
+ switch (fileType.type) {
437000
+ case "api":
437001
+ case "python-api-step":
437002
+ case "js-api-step": {
437003
+ await this.processApiUpdates(filePath, fileType);
437004
+ break;
437005
+ }
437006
+ }
436839
437007
  }
436840
- }
436841
- break;
437008
+ });
436842
437009
  }
436843
- case "change": {
436844
- if (filePath === routePath) {
436845
- const data2 = await readFile6(filePath);
436846
- try {
436847
- this.routes = JSON.parse(data2);
436848
- this.emit("routesChanged", this.routes);
436849
- } catch (e) {
436850
- logger3.error("Error parsing routes file", getErrorMeta(e));
436851
- }
436852
- return;
436853
- }
436854
- const fileType = SUPPORTED_FILETYPES.find((f) => filePath.endsWith(f.extension));
436855
- if (!fileType || !filePath.startsWith(rootPath)) {
436856
- return;
436857
- }
436858
- const data = await readFile6(filePath);
436859
- if (typeof data !== "string")
436860
- return;
436861
- switch (fileType.type) {
436862
- case "tsx":
436863
- case "scope":
436864
- {
436865
- if (!(filePath in this.tsFiles && this.tsFiles[filePath] === data)) {
436866
- logger3.info(`File changed: ${filePath} updating AST tracker`);
436867
- this.tsFiles[filePath] = data;
436868
- this.handleNonVisualChangeByDeletingIds(filePath, data);
436869
- this.emit("fileChanged", filePath, data, true);
436870
- } else {
436871
- logger3.info(`File unchanged from last tracked state: ${filePath}`);
436872
- this.emit("fileChanged", filePath, data, false);
437010
+ break;
437011
+ }
437012
+ case "change": {
437013
+ if (filePath === routePath) {
437014
+ void this.operationProcessor.addOperation({
437015
+ metadata: {
437016
+ filePath
437017
+ },
437018
+ priority: true,
437019
+ execute: async () => {
437020
+ try {
437021
+ const data = JSON.parse(await readFile6(filePath) ?? "{}");
437022
+ if (!isEqual_default(this.routes, data)) {
437023
+ this.routes = data;
437024
+ this.emit("routesChanged", this.routes);
436873
437025
  }
437026
+ } catch (e) {
437027
+ logger3.error("Error parsing routes file", getErrorMeta(e));
436874
437028
  }
436875
- break;
436876
- case "api":
436877
- case "python-api-step":
436878
- case "js-api-step":
436879
- {
436880
- await this.processApiUpdates(filePath, fileType);
437029
+ }
437030
+ });
437031
+ return;
437032
+ } else {
437033
+ void this.operationProcessor.addOperation({
437034
+ metadata: {
437035
+ filePath
437036
+ },
437037
+ execute: async () => {
437038
+ const fileType2 = SUPPORTED_FILETYPES.find((f) => filePath.endsWith(f.extension));
437039
+ if (!fileType2 || !filePath.startsWith(rootPath)) {
437040
+ return;
436881
437041
  }
436882
- break;
436883
- }
436884
- break;
436885
- }
436886
- case "unlink": {
436887
- if (filePath in this.apiFiles) {
436888
- const api = this.apiFiles[filePath];
436889
- delete this.apiFiles[filePath];
436890
- if (!api || !this.sourceTracker)
436891
- break;
436892
- const scopeId = await this.sourceTracker.deleteApi({
436893
- pageName: api.pageName,
436894
- apiName: api.apiPb.metadata.name
436895
- });
436896
- const changes = await this.sourceTracker?.getAndFlushChanges() ?? [];
436897
- await this.writeChanges(changes);
436898
- this.emit("apiManualDelete", {
436899
- api: {
436900
- id: getClientApiId(api.apiPb.metadata.name, api.pageName),
436901
- apiName: api.apiPb.metadata.name,
436902
- // TODO(saksham): get pagename more defensively
436903
- pageName: getPageName2(filePath),
436904
- scopeId
437042
+ const data = await readFile6(filePath);
437043
+ if (typeof data !== "string")
437044
+ return;
437045
+ switch (fileType2.type) {
437046
+ case "tsx":
437047
+ case "scope":
437048
+ {
437049
+ if (!(filePath in this.tsFiles && this.tsFiles[filePath] === data)) {
437050
+ logger3.info(`File changed: ${filePath} updating AST tracker`);
437051
+ this.tsFiles[filePath] = data;
437052
+ this.handleNonVisualChangeByDeletingIds(filePath, data);
437053
+ this.emit("fileChanged", filePath, data, true);
437054
+ } else {
437055
+ logger3.info(`File unchanged from last tracked state: ${filePath}`);
437056
+ this.emit("fileChanged", filePath, data, false);
437057
+ }
437058
+ }
437059
+ break;
437060
+ case "api":
437061
+ case "python-api-step":
437062
+ case "js-api-step":
437063
+ {
437064
+ await this.processApiUpdates(filePath, fileType2);
437065
+ }
437066
+ break;
436905
437067
  }
436906
- });
436907
- }
436908
- if (filePath in this.tsFiles) {
436909
- delete this.tsFiles[filePath];
436910
- this.sourceTracker?.removeFile(filePath);
436911
- this.emit("deletePage", filePath);
436912
- }
436913
- break;
437068
+ }
437069
+ });
436914
437070
  }
437071
+ break;
436915
437072
  }
436916
- };
436917
- watcher.on("all", async (event, filePath) => {
436918
- const fileType = SUPPORTED_FILETYPES.find((f) => filePath.endsWith(f.extension));
436919
- switch (fileType?.type) {
436920
- case "tsx":
436921
- case "scope":
436922
- this.fsOperationQueue.enqueue(async () => {
436923
- return await handleFileChange(event, filePath);
437073
+ case "unlink": {
437074
+ if (filePath in this.tsFiles) {
437075
+ void this.operationProcessor.addOperation({
437076
+ metadata: {
437077
+ filePath
437078
+ },
437079
+ execute: async () => {
437080
+ await this.deleteTsFile(filePath);
437081
+ }
436924
437082
  });
436925
- break;
436926
- default:
436927
- this.fsOperationQueue.enqueue(async () => {
436928
- void handleFileChange(event, filePath);
437083
+ } else if (filePath in this.apiFiles) {
437084
+ void this.operationProcessor.addOperation({
437085
+ metadata: {
437086
+ filePath
437087
+ },
437088
+ execute: async () => {
437089
+ await this.deleteApiFile(filePath);
437090
+ }
436929
437091
  });
437092
+ }
437093
+ break;
436930
437094
  }
436931
- });
436932
- }
437095
+ }
437096
+ };
436933
437097
  getApiFiles() {
436934
437098
  return this.formatApisToClientApis(this.apiFiles);
436935
437099
  }
437100
+ async deleteTsFile(filePath) {
437101
+ delete this.tsFiles[filePath];
437102
+ this.sourceTracker?.removeFile(filePath);
437103
+ if (isPageFilePath(filePath)) {
437104
+ this.emit("deletePage", filePath);
437105
+ }
437106
+ }
437107
+ async deleteApiFile(filePath) {
437108
+ const api = this.apiFiles[filePath];
437109
+ if (!api) {
437110
+ return;
437111
+ }
437112
+ delete this.apiFiles[filePath];
437113
+ this.sourceTracker?.deleteApi({
437114
+ pageName: api.pageName,
437115
+ apiName: api.apiPb.metadata.name
437116
+ });
437117
+ const changes = await this.sourceTracker?.getAndFlushChanges() ?? [];
437118
+ await this.writeChanges(changes);
437119
+ const scopeId = this.sourceTracker?.getScopeDefinitionForPage(api.pageName)?.id;
437120
+ this.emit("apiManualDelete", {
437121
+ api: {
437122
+ id: getClientApiId(api.apiPb.metadata.name, api.pageName),
437123
+ apiName: api.apiPb.metadata.name,
437124
+ // TODO(saksham): get pagename more defensively
437125
+ pageName: getPageName2(filePath),
437126
+ scopeId
437127
+ }
437128
+ });
437129
+ }
436936
437130
  getTsFilePaths() {
436937
437131
  return Object.keys(this.tsFiles);
436938
437132
  }
@@ -437140,11 +437334,11 @@ export default registerPage(Page, { name: "${name18}" });
437140
437334
  handleReparent = async (payload, writeFile9 = true) => {
437141
437335
  const { from, to, changedProps, transaction } = payload;
437142
437336
  this.trackTransaction(transaction?.id);
437143
- await this.sourceTracker?.setProperties({
437337
+ this.sourceTracker?.setProperties({
437144
437338
  source: from.source,
437145
437339
  changes: changedProps ?? {}
437146
437340
  });
437147
- await this.sourceTracker?.moveElement({
437341
+ this.sourceTracker?.moveElement({
437148
437342
  from,
437149
437343
  to
437150
437344
  });
@@ -437158,7 +437352,7 @@ export default registerPage(Page, { name: "${name18}" });
437158
437352
  };
437159
437353
  handleCreateComponent = async (payload, writeFile9 = true) => {
437160
437354
  this.trackTransaction(payload.transaction?.id);
437161
- const sourceId = await this.sourceTracker?.addElement(payload);
437355
+ const sourceId = this.sourceTracker?.addElement(payload);
437162
437356
  if (writeFile9) {
437163
437357
  const changes = await this.sourceTracker?.getAndFlushChanges() ?? [];
437164
437358
  await this.writeChanges(changes ?? [], (fileName) => {
@@ -437172,7 +437366,7 @@ export default registerPage(Page, { name: "${name18}" });
437172
437366
  const { elements, transaction } = payload;
437173
437367
  this.trackTransaction(transaction?.id);
437174
437368
  for (const element of elements) {
437175
- await this.sourceTracker?.deleteElement({
437369
+ this.sourceTracker?.deleteElement({
437176
437370
  source: element.source,
437177
437371
  scopeName: element.scopeName
437178
437372
  });
@@ -437188,7 +437382,7 @@ export default registerPage(Page, { name: "${name18}" });
437188
437382
  handleSetProperty = async (payload, writeFile9 = true) => {
437189
437383
  const { element: { source: source2 }, property, value: value2, transaction } = payload;
437190
437384
  this.trackTransaction(transaction?.id);
437191
- await this.sourceTracker?.setProperty({
437385
+ this.sourceTracker?.setProperty({
437192
437386
  source: source2,
437193
437387
  property,
437194
437388
  info: value2
@@ -437203,7 +437397,7 @@ export default registerPage(Page, { name: "${name18}" });
437203
437397
  handleSetProperties = async (payload, writeFile9 = true) => {
437204
437398
  const { element: { source: source2 }, properties, transaction } = payload;
437205
437399
  this.trackTransaction(transaction?.id);
437206
- await this.sourceTracker?.setProperties({
437400
+ this.sourceTracker?.setProperties({
437207
437401
  source: source2,
437208
437402
  changes: properties
437209
437403
  });
@@ -437333,7 +437527,7 @@ export default registerPage(Page, { name: "${name18}" });
437333
437527
  await fs12.rmdir(apiDir, { recursive: true });
437334
437528
  }
437335
437529
  delete this.apiFiles[apiFilePath];
437336
- const scopeId = await this.sourceTracker.deleteApi({
437530
+ const scopeId = this.sourceTracker.deleteApi({
437337
437531
  pageName,
437338
437532
  apiName
437339
437533
  });
@@ -437427,7 +437621,7 @@ export default registerPage(Page, { name: "${name18}" });
437427
437621
  }));
437428
437622
  };
437429
437623
  handleAddEntity = async (payload) => {
437430
- await this.sourceTracker?.addEntity({
437624
+ this.sourceTracker?.addEntity({
437431
437625
  scopeId: payload.scopeId,
437432
437626
  entity: {
437433
437627
  type: payload.type,
@@ -437441,7 +437635,7 @@ export default registerPage(Page, { name: "${name18}" });
437441
437635
  });
437442
437636
  };
437443
437637
  handleUpdateEntity = async (payload) => {
437444
- await this.sourceTracker?.updateEntity({
437638
+ this.sourceTracker?.updateEntity({
437445
437639
  entityId: payload.entityId,
437446
437640
  updates: payload.updates
437447
437641
  });
@@ -437451,7 +437645,7 @@ export default registerPage(Page, { name: "${name18}" });
437451
437645
  });
437452
437646
  };
437453
437647
  handleDeleteEntity = async (payload) => {
437454
- const deletedEntityName = await this.sourceTracker?.deleteEntity({
437648
+ const deletedEntityName = this.sourceTracker?.deleteEntity({
437455
437649
  entityId: payload.entityId
437456
437650
  });
437457
437651
  const changes = await this.sourceTracker?.getAndFlushChanges() ?? [];
@@ -437467,7 +437661,7 @@ export default registerPage(Page, { name: "${name18}" });
437467
437661
  throw new Error("Root directory not set");
437468
437662
  }
437469
437663
  const filePath = path27.join(this.rootDir, APP_THEME_FILE_NAME);
437470
- await this.sourceTracker?.updateTheme({
437664
+ this.sourceTracker?.updateTheme({
437471
437665
  themeFilePath: filePath,
437472
437666
  theme
437473
437667
  });
@@ -437503,7 +437697,7 @@ export default registerPage(Page, { name: "${name18}" });
437503
437697
  };
437504
437698
  handleRenameEntity = async (payload) => {
437505
437699
  const { elementId, newName, oldName, scopeName } = payload;
437506
- await this.sourceTracker?.renameEntity({
437700
+ this.sourceTracker?.renameEntity({
437507
437701
  entityId: elementId,
437508
437702
  oldName,
437509
437703
  newName,
@@ -438188,7 +438382,7 @@ var fileSyncVitePlugin = (pluginParams, options9) => {
438188
438382
  const aiService = pluginParams.aiService;
438189
438383
  const fsOperationQueue = pluginParams.fsOperationQueue;
438190
438384
  const httpServer2 = pluginParams.httpServer;
438191
- const fileSyncManager = new FileSyncManager(fsOperationQueue, generationNumberSequence, pluginParams.tracer);
438385
+ const fileSyncManager = new FileSystemManager(fsOperationQueue, generationNumberSequence, pluginParams.tracer);
438192
438386
  if (syncService) {
438193
438387
  syncService.generationNumberSequence = generationNumberSequence;
438194
438388
  }
@@ -438601,7 +438795,12 @@ var fileSyncVitePlugin = (pluginParams, options9) => {
438601
438795
  return socket.call.aiSetDraftState({ hasDraft });
438602
438796
  });
438603
438797
  });
438604
- aiService.on("generationCompleted", (hasDraft) => {
438798
+ aiService.on("generationStarted", () => {
438799
+ fileSyncManager.enableOperationsQueue();
438800
+ });
438801
+ aiService.on("generationCompleted", async (hasDraft) => {
438802
+ fileSyncManager.disableOperationsQueue();
438803
+ await fileSyncManager.flushOperations();
438605
438804
  if (hasDraft) {
438606
438805
  logger3.info("Requesting full reload to render AI draft");
438607
438806
  server.ws.send({
@@ -442578,7 +442777,7 @@ var import_util30 = __toESM(require_dist3(), 1);
442578
442777
  // ../sdk/package.json
442579
442778
  var package_default = {
442580
442779
  name: "@superblocksteam/sdk",
442581
- version: "2.0.6-next.15",
442780
+ version: "2.0.6-next.17",
442582
442781
  type: "module",
442583
442782
  description: "Superblocks JS SDK",
442584
442783
  homepage: "https://www.superblocks.com",
@@ -442619,11 +442818,11 @@ var package_default = {
442619
442818
  "@opentelemetry/semantic-conventions": "^1.28.0",
442620
442819
  "@rollup/wasm-node": "^4.35.0",
442621
442820
  "@superblocksteam/bucketeer-sdk": "0.5.0",
442622
- "@superblocksteam/library": "2.0.6-next.15",
442623
- "@superblocksteam/library-shared": "2.0.6-next.15",
442821
+ "@superblocksteam/library": "2.0.6-next.17",
442822
+ "@superblocksteam/library-shared": "2.0.6-next.17",
442624
442823
  "@superblocksteam/shared": "0.9198.0",
442625
- "@superblocksteam/util": "2.0.6-next.15",
442626
- "@superblocksteam/vite-plugin-file-sync": "2.0.6-next.15",
442824
+ "@superblocksteam/util": "2.0.6-next.17",
442825
+ "@superblocksteam/vite-plugin-file-sync": "2.0.6-next.17",
442627
442826
  "@vitejs/plugin-react": "^4.3.4",
442628
442827
  axios: "^1.4.0",
442629
442828
  chokidar: "^4.0.3",
@@ -450194,7 +450393,8 @@ async function startVite({ app, httpServer: httpServer2, root: root2, mode, port
450194
450393
  };
450195
450394
  const isCustomBuildEnabled2 = await isCustomComponentsEnabled();
450196
450395
  const customFolder = path37.join(root2, "custom");
450197
- const cdnUrl = "https://assets-cdn.superblocks.com/library/2.0.6-next.15";
450396
+ const draftsFolder = path37.join(root2, ".superblocks");
450397
+ const cdnUrl = "https://assets-cdn.superblocks.com/library/2.0.6-next.17";
450198
450398
  const env3 = loadEnv(mode, root2, "");
450199
450399
  const hmrPort = await getFreePort();
450200
450400
  const hmrOptions = {
@@ -450225,10 +450425,7 @@ async function startVite({ app, httpServer: httpServer2, root: root2, mode, port
450225
450425
  server: {
450226
450426
  middlewareMode: true,
450227
450427
  watch: {
450228
- ignored: [
450229
- `${customFolder}/**/*`,
450230
- `${root2}/.superblocks/{generations,drafts}/**/*`
450231
- ]
450428
+ ignored: [`${customFolder}/**/*`, `${draftsFolder}/**/*`]
450232
450429
  },
450233
450430
  hmr: hmrOptions,
450234
450431
  cors: {
@@ -585,5 +585,5 @@
585
585
  "strict": true
586
586
  }
587
587
  },
588
- "version": "2.0.6-next.15"
588
+ "version": "2.0.6-next.17"
589
589
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superblocksteam/cli",
3
- "version": "2.0.6-next.15",
3
+ "version": "2.0.6-next.17",
4
4
  "type": "module",
5
5
  "description": "Official Superblocks CLI",
6
6
  "homepage": "https://www.superblocks.com",
@@ -42,9 +42,9 @@
42
42
  "devDependencies": {
43
43
  "@eslint/js": "^9.16.0",
44
44
  "@oclif/test": "^4.1.11",
45
- "@superblocksteam/sdk": "2.0.6-next.15",
45
+ "@superblocksteam/sdk": "2.0.6-next.17",
46
46
  "@superblocksteam/shared": "0.9198.0",
47
- "@superblocksteam/util": "2.0.6-next.15",
47
+ "@superblocksteam/util": "2.0.6-next.17",
48
48
  "@types/babel__core": "^7.20.0",
49
49
  "@types/chai": "^4",
50
50
  "@types/fs-extra": "^11.0.1",