@demoscript/cli 1.1.3 → 1.1.6

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 (170) hide show
  1. package/dist/bundle.cjs +1447 -64
  2. package/dist/commands/serve.d.ts.map +1 -1
  3. package/dist/commands/serve.js +24 -0
  4. package/dist/commands/serve.js.map +1 -1
  5. package/dist/demo.schema.json +847 -0
  6. package/dist/index.js +1 -64
  7. package/dist/server/graphql-proxy.d.ts +3 -0
  8. package/dist/server/graphql-proxy.d.ts.map +1 -0
  9. package/dist/server/graphql-proxy.js +56 -0
  10. package/dist/server/graphql-proxy.js.map +1 -0
  11. package/dist/server/rest-proxy.d.ts.map +1 -1
  12. package/dist/server/rest-proxy.js +8 -1
  13. package/dist/server/rest-proxy.js.map +1 -1
  14. package/dist/types.d.ts +63 -1
  15. package/dist/types.d.ts.map +1 -1
  16. package/dist/types.js +9 -0
  17. package/dist/types.js.map +1 -1
  18. package/dist/ui-dist/assets/_baseUniq.js +2 -0
  19. package/dist/ui-dist/assets/arc.js +2 -0
  20. package/dist/ui-dist/assets/architectureDiagram-VXUJARFQ.js +37 -0
  21. package/dist/ui-dist/assets/blockDiagram-VD42YOAC.js +123 -0
  22. package/dist/ui-dist/assets/c4Diagram-YG6GDRKO.js +11 -0
  23. package/dist/ui-dist/assets/channel.js +2 -0
  24. package/dist/ui-dist/assets/chunk-4BX2VUAB.js +2 -0
  25. package/dist/ui-dist/assets/chunk-55IACEB6.js +2 -0
  26. package/dist/ui-dist/assets/chunk-B4BG7PRW.js +166 -0
  27. package/dist/ui-dist/assets/chunk-DI55MBZ5.js +221 -0
  28. package/dist/ui-dist/assets/chunk-FMBD7UC4.js +16 -0
  29. package/dist/ui-dist/assets/chunk-QN33PNHL.js +2 -0
  30. package/dist/ui-dist/assets/chunk-QZHKN3VN.js +2 -0
  31. package/dist/ui-dist/assets/chunk-TZMSLE5B.js +2 -0
  32. package/dist/ui-dist/assets/classDiagram-2ON5EDUG.js +2 -0
  33. package/dist/ui-dist/assets/classDiagram-v2-WZHVMYZB.js +2 -0
  34. package/dist/ui-dist/assets/clone.js +2 -0
  35. package/dist/ui-dist/assets/cose-bilkent-S5V4N54A.js +2 -0
  36. package/dist/ui-dist/assets/cytoscape.esm.js +332 -0
  37. package/dist/ui-dist/assets/dagre-6UL2VRFP.js +5 -0
  38. package/dist/ui-dist/assets/defaultLocale.js +2 -0
  39. package/dist/ui-dist/assets/diagram-PSM6KHXK.js +25 -0
  40. package/dist/ui-dist/assets/diagram-QEK2KX5R.js +44 -0
  41. package/dist/ui-dist/assets/diagram-S2PKOQOG.js +25 -0
  42. package/dist/ui-dist/assets/erDiagram-Q2GNP2WA.js +61 -0
  43. package/dist/ui-dist/assets/flowDiagram-NV44I4VS.js +163 -0
  44. package/dist/ui-dist/assets/ganttDiagram-JELNMOA3.js +268 -0
  45. package/dist/ui-dist/assets/gitGraphDiagram-NY62KEGX.js +66 -0
  46. package/dist/ui-dist/assets/graph.js +2 -0
  47. package/dist/ui-dist/assets/index.css +1 -1
  48. package/dist/ui-dist/assets/index.js +444 -104
  49. package/dist/ui-dist/assets/infoDiagram-WHAUD3N6.js +3 -0
  50. package/dist/ui-dist/assets/init.js +2 -0
  51. package/dist/ui-dist/assets/journeyDiagram-XKPGCS4Q.js +140 -0
  52. package/dist/ui-dist/assets/kanban-definition-3W4ZIXB7.js +90 -0
  53. package/dist/ui-dist/assets/katex.js +262 -0
  54. package/dist/ui-dist/assets/layout.js +2 -0
  55. package/dist/ui-dist/assets/linear.js +2 -0
  56. package/dist/ui-dist/assets/min.js +2 -0
  57. package/dist/ui-dist/assets/mindmap-definition-VGOIOE7T.js +69 -0
  58. package/dist/ui-dist/assets/ordinal.js +2 -0
  59. package/dist/ui-dist/assets/pieDiagram-ADFJNKIX.js +31 -0
  60. package/dist/ui-dist/assets/quadrantDiagram-AYHSOK5B.js +8 -0
  61. package/dist/ui-dist/assets/requirementDiagram-UZGBJVZJ.js +65 -0
  62. package/dist/ui-dist/assets/sankeyDiagram-TZEHDZUN.js +11 -0
  63. package/dist/ui-dist/assets/sequenceDiagram-WL72ISMW.js +146 -0
  64. package/dist/ui-dist/assets/stateDiagram-FKZM4ZOC.js +2 -0
  65. package/dist/ui-dist/assets/stateDiagram-v2-4FDKWEC3.js +2 -0
  66. package/dist/ui-dist/assets/timeline-definition-IT6M3QCI.js +62 -0
  67. package/dist/ui-dist/assets/treemap-KMMF4GRG.js +129 -0
  68. package/dist/ui-dist/assets/xychartDiagram-PRI3JC2R.js +8 -0
  69. package/dist/ui-dist/dist/assets/_baseUniq.js +2 -0
  70. package/dist/ui-dist/dist/assets/_baseUniq.js.map +1 -0
  71. package/dist/ui-dist/dist/assets/arc.js +2 -0
  72. package/dist/ui-dist/dist/assets/arc.js.map +1 -0
  73. package/dist/ui-dist/dist/assets/architectureDiagram-VXUJARFQ.js +37 -0
  74. package/dist/ui-dist/dist/assets/architectureDiagram-VXUJARFQ.js.map +1 -0
  75. package/dist/ui-dist/dist/assets/blockDiagram-VD42YOAC.js +123 -0
  76. package/dist/ui-dist/dist/assets/blockDiagram-VD42YOAC.js.map +1 -0
  77. package/dist/ui-dist/dist/assets/c4Diagram-YG6GDRKO.js +11 -0
  78. package/dist/ui-dist/dist/assets/c4Diagram-YG6GDRKO.js.map +1 -0
  79. package/dist/ui-dist/dist/assets/channel.js +2 -0
  80. package/dist/ui-dist/dist/assets/channel.js.map +1 -0
  81. package/dist/ui-dist/dist/assets/chunk-4BX2VUAB.js +2 -0
  82. package/dist/ui-dist/dist/assets/chunk-4BX2VUAB.js.map +1 -0
  83. package/dist/ui-dist/dist/assets/chunk-55IACEB6.js +2 -0
  84. package/dist/ui-dist/dist/assets/chunk-55IACEB6.js.map +1 -0
  85. package/dist/ui-dist/dist/assets/chunk-B4BG7PRW.js +166 -0
  86. package/dist/ui-dist/dist/assets/chunk-B4BG7PRW.js.map +1 -0
  87. package/dist/ui-dist/dist/assets/chunk-DI55MBZ5.js +221 -0
  88. package/dist/ui-dist/dist/assets/chunk-DI55MBZ5.js.map +1 -0
  89. package/dist/ui-dist/dist/assets/chunk-FMBD7UC4.js +16 -0
  90. package/dist/ui-dist/dist/assets/chunk-FMBD7UC4.js.map +1 -0
  91. package/dist/ui-dist/dist/assets/chunk-QN33PNHL.js +2 -0
  92. package/dist/ui-dist/dist/assets/chunk-QN33PNHL.js.map +1 -0
  93. package/dist/ui-dist/dist/assets/chunk-QZHKN3VN.js +2 -0
  94. package/dist/ui-dist/dist/assets/chunk-QZHKN3VN.js.map +1 -0
  95. package/dist/ui-dist/dist/assets/chunk-TZMSLE5B.js +2 -0
  96. package/dist/ui-dist/dist/assets/chunk-TZMSLE5B.js.map +1 -0
  97. package/dist/ui-dist/dist/assets/classDiagram-2ON5EDUG.js +2 -0
  98. package/dist/ui-dist/dist/assets/classDiagram-2ON5EDUG.js.map +1 -0
  99. package/dist/ui-dist/dist/assets/classDiagram-v2-WZHVMYZB.js +2 -0
  100. package/dist/ui-dist/dist/assets/classDiagram-v2-WZHVMYZB.js.map +1 -0
  101. package/dist/ui-dist/dist/assets/clone.js +2 -0
  102. package/dist/ui-dist/dist/assets/clone.js.map +1 -0
  103. package/dist/ui-dist/dist/assets/cose-bilkent-S5V4N54A.js +2 -0
  104. package/dist/ui-dist/dist/assets/cose-bilkent-S5V4N54A.js.map +1 -0
  105. package/dist/ui-dist/dist/assets/cytoscape.esm.js +332 -0
  106. package/dist/ui-dist/dist/assets/cytoscape.esm.js.map +1 -0
  107. package/dist/ui-dist/dist/assets/dagre-6UL2VRFP.js +5 -0
  108. package/dist/ui-dist/dist/assets/dagre-6UL2VRFP.js.map +1 -0
  109. package/dist/ui-dist/dist/assets/defaultLocale.js +2 -0
  110. package/dist/ui-dist/dist/assets/defaultLocale.js.map +1 -0
  111. package/dist/ui-dist/dist/assets/diagram-PSM6KHXK.js +25 -0
  112. package/dist/ui-dist/dist/assets/diagram-PSM6KHXK.js.map +1 -0
  113. package/dist/ui-dist/dist/assets/diagram-QEK2KX5R.js +44 -0
  114. package/dist/ui-dist/dist/assets/diagram-QEK2KX5R.js.map +1 -0
  115. package/dist/ui-dist/dist/assets/diagram-S2PKOQOG.js +25 -0
  116. package/dist/ui-dist/dist/assets/diagram-S2PKOQOG.js.map +1 -0
  117. package/dist/ui-dist/dist/assets/erDiagram-Q2GNP2WA.js +61 -0
  118. package/dist/ui-dist/dist/assets/erDiagram-Q2GNP2WA.js.map +1 -0
  119. package/dist/ui-dist/dist/assets/flowDiagram-NV44I4VS.js +163 -0
  120. package/dist/ui-dist/dist/assets/flowDiagram-NV44I4VS.js.map +1 -0
  121. package/dist/ui-dist/dist/assets/ganttDiagram-JELNMOA3.js +268 -0
  122. package/dist/ui-dist/dist/assets/ganttDiagram-JELNMOA3.js.map +1 -0
  123. package/dist/ui-dist/dist/assets/gitGraphDiagram-NY62KEGX.js +66 -0
  124. package/dist/ui-dist/dist/assets/gitGraphDiagram-NY62KEGX.js.map +1 -0
  125. package/dist/ui-dist/dist/assets/graph.js +2 -0
  126. package/dist/ui-dist/dist/assets/graph.js.map +1 -0
  127. package/dist/ui-dist/dist/assets/index.css +1 -1
  128. package/dist/ui-dist/dist/assets/index.js +443 -116
  129. package/dist/ui-dist/dist/assets/index.js.map +1 -1
  130. package/dist/ui-dist/dist/assets/infoDiagram-WHAUD3N6.js +3 -0
  131. package/dist/ui-dist/dist/assets/infoDiagram-WHAUD3N6.js.map +1 -0
  132. package/dist/ui-dist/dist/assets/init.js +2 -0
  133. package/dist/ui-dist/dist/assets/init.js.map +1 -0
  134. package/dist/ui-dist/dist/assets/journeyDiagram-XKPGCS4Q.js +140 -0
  135. package/dist/ui-dist/dist/assets/journeyDiagram-XKPGCS4Q.js.map +1 -0
  136. package/dist/ui-dist/dist/assets/kanban-definition-3W4ZIXB7.js +90 -0
  137. package/dist/ui-dist/dist/assets/kanban-definition-3W4ZIXB7.js.map +1 -0
  138. package/dist/ui-dist/dist/assets/katex.js +262 -0
  139. package/dist/ui-dist/dist/assets/katex.js.map +1 -0
  140. package/dist/ui-dist/dist/assets/layout.js +2 -0
  141. package/dist/ui-dist/dist/assets/layout.js.map +1 -0
  142. package/dist/ui-dist/dist/assets/linear.js +2 -0
  143. package/dist/ui-dist/dist/assets/linear.js.map +1 -0
  144. package/dist/ui-dist/dist/assets/min.js +2 -0
  145. package/dist/ui-dist/dist/assets/min.js.map +1 -0
  146. package/dist/ui-dist/dist/assets/mindmap-definition-VGOIOE7T.js +69 -0
  147. package/dist/ui-dist/dist/assets/mindmap-definition-VGOIOE7T.js.map +1 -0
  148. package/dist/ui-dist/dist/assets/ordinal.js +2 -0
  149. package/dist/ui-dist/dist/assets/ordinal.js.map +1 -0
  150. package/dist/ui-dist/dist/assets/pieDiagram-ADFJNKIX.js +31 -0
  151. package/dist/ui-dist/dist/assets/pieDiagram-ADFJNKIX.js.map +1 -0
  152. package/dist/ui-dist/dist/assets/quadrantDiagram-AYHSOK5B.js +8 -0
  153. package/dist/ui-dist/dist/assets/quadrantDiagram-AYHSOK5B.js.map +1 -0
  154. package/dist/ui-dist/dist/assets/requirementDiagram-UZGBJVZJ.js +65 -0
  155. package/dist/ui-dist/dist/assets/requirementDiagram-UZGBJVZJ.js.map +1 -0
  156. package/dist/ui-dist/dist/assets/sankeyDiagram-TZEHDZUN.js +11 -0
  157. package/dist/ui-dist/dist/assets/sankeyDiagram-TZEHDZUN.js.map +1 -0
  158. package/dist/ui-dist/dist/assets/sequenceDiagram-WL72ISMW.js +146 -0
  159. package/dist/ui-dist/dist/assets/sequenceDiagram-WL72ISMW.js.map +1 -0
  160. package/dist/ui-dist/dist/assets/stateDiagram-FKZM4ZOC.js +2 -0
  161. package/dist/ui-dist/dist/assets/stateDiagram-FKZM4ZOC.js.map +1 -0
  162. package/dist/ui-dist/dist/assets/stateDiagram-v2-4FDKWEC3.js +2 -0
  163. package/dist/ui-dist/dist/assets/stateDiagram-v2-4FDKWEC3.js.map +1 -0
  164. package/dist/ui-dist/dist/assets/timeline-definition-IT6M3QCI.js +62 -0
  165. package/dist/ui-dist/dist/assets/timeline-definition-IT6M3QCI.js.map +1 -0
  166. package/dist/ui-dist/dist/assets/treemap-KMMF4GRG.js +129 -0
  167. package/dist/ui-dist/dist/assets/treemap-KMMF4GRG.js.map +1 -0
  168. package/dist/ui-dist/dist/assets/xychartDiagram-PRI3JC2R.js +8 -0
  169. package/dist/ui-dist/dist/assets/xychartDiagram-PRI3JC2R.js.map +1 -0
  170. package/package.json +1 -1
package/dist/bundle.cjs CHANGED
@@ -41985,6 +41985,26 @@ function mapType(schema2) {
41985
41985
  return "text";
41986
41986
  }
41987
41987
  }
41988
+ function getTextareaRows(schema2) {
41989
+ if (schema2.type === "array") {
41990
+ const itemType = schema2.items?.type;
41991
+ if (itemType === "string" || itemType === "number" || itemType === "integer") {
41992
+ return 2;
41993
+ }
41994
+ return 3;
41995
+ }
41996
+ if (schema2.type === "object" && schema2.properties) {
41997
+ const propCount = Object.keys(schema2.properties).length;
41998
+ if (propCount <= 2) {
41999
+ return 2;
42000
+ }
42001
+ if (propCount <= 4) {
42002
+ return 3;
42003
+ }
42004
+ return 4;
42005
+ }
42006
+ return 2;
42007
+ }
41988
42008
  function generateOptions(schema2) {
41989
42009
  if (schema2.enum) {
41990
42010
  return schema2.enum.map((v) => ({
@@ -42020,6 +42040,54 @@ function generateFormFieldsFromPath(spec, pathObj, method) {
42020
42040
  if (!operation) {
42021
42041
  return [];
42022
42042
  }
42043
+ const fields = [];
42044
+ if (operation.parameters) {
42045
+ for (const param of operation.parameters) {
42046
+ if (param.in === "query" || param.in === "path") {
42047
+ let schema2;
42048
+ if (param.schema) {
42049
+ schema2 = resolveSchema(spec, param.schema);
42050
+ } else {
42051
+ if (param.type === "array" && param.items?.enum) {
42052
+ schema2 = {
42053
+ type: "string",
42054
+ enum: param.items.enum,
42055
+ default: param.items.default ?? param.default
42056
+ };
42057
+ } else {
42058
+ schema2 = {
42059
+ type: param.type || "string",
42060
+ enum: param.enum,
42061
+ default: param.default,
42062
+ format: param.format
42063
+ };
42064
+ }
42065
+ }
42066
+ const fieldType = mapType(schema2);
42067
+ const field = {
42068
+ name: param.name,
42069
+ label: param.description || param.name,
42070
+ type: fieldType,
42071
+ required: param.required ?? false,
42072
+ paramIn: param.in
42073
+ };
42074
+ if (schema2.default !== void 0) {
42075
+ field.default = schema2.default;
42076
+ }
42077
+ const options = generateOptions(schema2);
42078
+ if (options) {
42079
+ field.options = options;
42080
+ }
42081
+ if (param.description) {
42082
+ field.placeholder = param.description;
42083
+ }
42084
+ if (fieldType === "textarea") {
42085
+ field.rows = getTextareaRows(schema2);
42086
+ }
42087
+ fields.push(field);
42088
+ }
42089
+ }
42090
+ }
42023
42091
  let bodySchema = null;
42024
42092
  if (operation.requestBody) {
42025
42093
  const jsonContent = operation.requestBody.content["application/json"];
@@ -42033,34 +42101,36 @@ function generateFormFieldsFromPath(spec, pathObj, method) {
42033
42101
  bodySchema = bodyParam.schema;
42034
42102
  }
42035
42103
  }
42036
- if (!bodySchema) {
42037
- return [];
42038
- }
42039
- const schema2 = resolveSchema(spec, bodySchema);
42040
- if (!schema2.properties) {
42041
- return [];
42042
- }
42043
- const requiredFields = schema2.required || [];
42044
- const fields = [];
42045
- for (const [name, propSchema] of Object.entries(schema2.properties)) {
42046
- const resolved = resolveSchema(spec, propSchema);
42047
- const field = {
42048
- name,
42049
- label: resolved.description || name,
42050
- type: mapType(resolved),
42051
- required: requiredFields.includes(name)
42052
- };
42053
- if (resolved.default !== void 0) {
42054
- field.default = resolved.default;
42055
- }
42056
- const options = generateOptions(resolved);
42057
- if (options) {
42058
- field.options = options;
42059
- }
42060
- if (resolved.description && field.label === name) {
42061
- field.placeholder = resolved.description;
42104
+ if (bodySchema) {
42105
+ const schema2 = resolveSchema(spec, bodySchema);
42106
+ if (schema2.properties) {
42107
+ const requiredFields = schema2.required || [];
42108
+ for (const [name, propSchema] of Object.entries(schema2.properties)) {
42109
+ const resolved = resolveSchema(spec, propSchema);
42110
+ const fieldType = mapType(resolved);
42111
+ const field = {
42112
+ name,
42113
+ label: resolved.description || name,
42114
+ type: fieldType,
42115
+ required: requiredFields.includes(name),
42116
+ paramIn: "body"
42117
+ };
42118
+ if (resolved.default !== void 0) {
42119
+ field.default = resolved.default;
42120
+ }
42121
+ const options = generateOptions(resolved);
42122
+ if (options) {
42123
+ field.options = options;
42124
+ }
42125
+ if (resolved.description && field.label === name) {
42126
+ field.placeholder = resolved.description;
42127
+ }
42128
+ if (fieldType === "textarea") {
42129
+ field.rows = getTextareaRows(resolved);
42130
+ }
42131
+ fields.push(field);
42132
+ }
42062
42133
  }
42063
- fields.push(field);
42064
42134
  }
42065
42135
  return fields;
42066
42136
  }
@@ -42235,6 +42305,12 @@ function createRestProxy() {
42235
42305
  return;
42236
42306
  }
42237
42307
  try {
42308
+ let absoluteUrl = url;
42309
+ if (url.startsWith("/")) {
42310
+ const protocol = req.protocol;
42311
+ const host = req.get("host") || "localhost";
42312
+ absoluteUrl = `${protocol}://${host}${url}`;
42313
+ }
42238
42314
  const fetchHeaders = {
42239
42315
  "Content-Type": "application/json",
42240
42316
  ...headers
@@ -42246,7 +42322,7 @@ function createRestProxy() {
42246
42322
  if (body && method !== "GET") {
42247
42323
  fetchOptions.body = JSON.stringify(body);
42248
42324
  }
42249
- const response = await fetch(url, fetchOptions);
42325
+ const response = await fetch(absoluteUrl, fetchOptions);
42250
42326
  const responseBody = await response.json().catch(() => null);
42251
42327
  res.json({
42252
42328
  status: response.status,
@@ -42315,6 +42391,1016 @@ function executeCommand(command, options) {
42315
42391
  });
42316
42392
  }
42317
42393
 
42394
+ // ../shared/dist/sandbox/openapi.js
42395
+ var sandboxOpenApiSpec = {
42396
+ openapi: "3.0.3",
42397
+ info: {
42398
+ title: "DemoScript Sandbox API",
42399
+ version: "1.0.0",
42400
+ description: "A mock API for testing DemoScript demos. Provides user management, async jobs, authentication, and utility endpoints.",
42401
+ contact: {
42402
+ name: "DemoScript",
42403
+ url: "https://demoscript.app"
42404
+ }
42405
+ },
42406
+ servers: [
42407
+ { url: "/sandbox", description: "Local CLI" },
42408
+ { url: "https://demoscript.app/api/sandbox", description: "DemoScript Cloud" }
42409
+ ],
42410
+ tags: [
42411
+ { name: "health", description: "Health check endpoints" },
42412
+ { name: "auth", description: "Authentication endpoints" },
42413
+ { name: "users", description: "User management" },
42414
+ { name: "jobs", description: "Async job management" },
42415
+ { name: "utility", description: "Utility endpoints" }
42416
+ ],
42417
+ paths: {
42418
+ "/health": {
42419
+ get: {
42420
+ tags: ["health"],
42421
+ summary: "Health check",
42422
+ description: "Returns the health status of the API",
42423
+ operationId: "getHealth",
42424
+ responses: {
42425
+ "200": {
42426
+ description: "API is healthy",
42427
+ content: {
42428
+ "application/json": {
42429
+ schema: {
42430
+ type: "object",
42431
+ properties: {
42432
+ status: { type: "string", example: "ok" },
42433
+ timestamp: { type: "string", format: "date-time" },
42434
+ version: { type: "string", example: "1.0.0" }
42435
+ }
42436
+ }
42437
+ }
42438
+ }
42439
+ }
42440
+ }
42441
+ }
42442
+ },
42443
+ "/auth/login": {
42444
+ post: {
42445
+ tags: ["auth"],
42446
+ summary: "Authenticate user",
42447
+ description: "Login with email and password to get an authentication token",
42448
+ operationId: "login",
42449
+ requestBody: {
42450
+ required: true,
42451
+ content: {
42452
+ "application/json": {
42453
+ schema: {
42454
+ type: "object",
42455
+ required: ["email", "password"],
42456
+ properties: {
42457
+ email: {
42458
+ type: "string",
42459
+ format: "email",
42460
+ description: "User email address",
42461
+ example: "demo@example.com"
42462
+ },
42463
+ password: {
42464
+ type: "string",
42465
+ format: "password",
42466
+ description: "User password (any value accepted in sandbox)",
42467
+ example: "demo123"
42468
+ }
42469
+ }
42470
+ }
42471
+ }
42472
+ }
42473
+ },
42474
+ responses: {
42475
+ "200": {
42476
+ description: "Successfully authenticated",
42477
+ content: {
42478
+ "application/json": {
42479
+ schema: { $ref: "#/components/schemas/AuthResponse" }
42480
+ }
42481
+ }
42482
+ },
42483
+ "401": {
42484
+ description: "Invalid credentials",
42485
+ content: {
42486
+ "application/json": {
42487
+ schema: { $ref: "#/components/schemas/Error" }
42488
+ }
42489
+ }
42490
+ }
42491
+ }
42492
+ }
42493
+ },
42494
+ "/users": {
42495
+ get: {
42496
+ tags: ["users"],
42497
+ summary: "List users",
42498
+ description: "Get a paginated list of all users",
42499
+ operationId: "listUsers",
42500
+ security: [{ bearerAuth: [] }],
42501
+ parameters: [
42502
+ {
42503
+ name: "page",
42504
+ in: "query",
42505
+ description: "Page number (1-indexed)",
42506
+ schema: { type: "integer", minimum: 1, default: 1 }
42507
+ },
42508
+ {
42509
+ name: "limit",
42510
+ in: "query",
42511
+ description: "Items per page",
42512
+ schema: { type: "integer", minimum: 1, maximum: 100, default: 10 }
42513
+ },
42514
+ {
42515
+ name: "role",
42516
+ in: "query",
42517
+ description: "Filter by role",
42518
+ schema: { type: "string", enum: ["admin", "user", "viewer"] }
42519
+ }
42520
+ ],
42521
+ responses: {
42522
+ "200": {
42523
+ description: "List of users",
42524
+ content: {
42525
+ "application/json": {
42526
+ schema: {
42527
+ type: "object",
42528
+ properties: {
42529
+ users: {
42530
+ type: "array",
42531
+ items: { $ref: "#/components/schemas/User" }
42532
+ },
42533
+ total: { type: "integer", description: "Total number of users" },
42534
+ page: { type: "integer", description: "Current page" },
42535
+ limit: { type: "integer", description: "Items per page" },
42536
+ totalPages: { type: "integer", description: "Total number of pages" }
42537
+ }
42538
+ }
42539
+ }
42540
+ }
42541
+ }
42542
+ }
42543
+ },
42544
+ post: {
42545
+ tags: ["users"],
42546
+ summary: "Create user",
42547
+ description: "Create a new user",
42548
+ operationId: "createUser",
42549
+ security: [{ bearerAuth: [] }],
42550
+ requestBody: {
42551
+ required: true,
42552
+ content: {
42553
+ "application/json": {
42554
+ schema: {
42555
+ type: "object",
42556
+ required: ["email", "name"],
42557
+ properties: {
42558
+ email: {
42559
+ type: "string",
42560
+ format: "email",
42561
+ description: "User email address",
42562
+ example: "newuser@example.com"
42563
+ },
42564
+ name: {
42565
+ type: "string",
42566
+ description: "User full name",
42567
+ example: "New User"
42568
+ },
42569
+ role: {
42570
+ type: "string",
42571
+ enum: ["admin", "user", "viewer"],
42572
+ default: "user",
42573
+ description: "User role"
42574
+ }
42575
+ }
42576
+ }
42577
+ }
42578
+ }
42579
+ },
42580
+ responses: {
42581
+ "201": {
42582
+ description: "User created",
42583
+ content: {
42584
+ "application/json": {
42585
+ schema: { $ref: "#/components/schemas/User" }
42586
+ }
42587
+ }
42588
+ },
42589
+ "400": {
42590
+ description: "Invalid input",
42591
+ content: {
42592
+ "application/json": {
42593
+ schema: { $ref: "#/components/schemas/Error" }
42594
+ }
42595
+ }
42596
+ },
42597
+ "409": {
42598
+ description: "Email already exists",
42599
+ content: {
42600
+ "application/json": {
42601
+ schema: { $ref: "#/components/schemas/Error" }
42602
+ }
42603
+ }
42604
+ }
42605
+ }
42606
+ }
42607
+ },
42608
+ "/users/{id}": {
42609
+ get: {
42610
+ tags: ["users"],
42611
+ summary: "Get user",
42612
+ description: "Get a user by ID",
42613
+ operationId: "getUser",
42614
+ security: [{ bearerAuth: [] }],
42615
+ parameters: [
42616
+ {
42617
+ name: "id",
42618
+ in: "path",
42619
+ required: true,
42620
+ description: "User ID",
42621
+ schema: { type: "string" }
42622
+ }
42623
+ ],
42624
+ responses: {
42625
+ "200": {
42626
+ description: "User found",
42627
+ content: {
42628
+ "application/json": {
42629
+ schema: { $ref: "#/components/schemas/User" }
42630
+ }
42631
+ }
42632
+ },
42633
+ "404": {
42634
+ description: "User not found",
42635
+ content: {
42636
+ "application/json": {
42637
+ schema: { $ref: "#/components/schemas/Error" }
42638
+ }
42639
+ }
42640
+ }
42641
+ }
42642
+ },
42643
+ put: {
42644
+ tags: ["users"],
42645
+ summary: "Update user",
42646
+ description: "Update an existing user",
42647
+ operationId: "updateUser",
42648
+ security: [{ bearerAuth: [] }],
42649
+ parameters: [
42650
+ {
42651
+ name: "id",
42652
+ in: "path",
42653
+ required: true,
42654
+ description: "User ID",
42655
+ schema: { type: "string" }
42656
+ }
42657
+ ],
42658
+ requestBody: {
42659
+ required: true,
42660
+ content: {
42661
+ "application/json": {
42662
+ schema: {
42663
+ type: "object",
42664
+ properties: {
42665
+ email: {
42666
+ type: "string",
42667
+ format: "email",
42668
+ description: "User email address"
42669
+ },
42670
+ name: {
42671
+ type: "string",
42672
+ description: "User full name"
42673
+ },
42674
+ role: {
42675
+ type: "string",
42676
+ enum: ["admin", "user", "viewer"],
42677
+ description: "User role"
42678
+ }
42679
+ }
42680
+ }
42681
+ }
42682
+ }
42683
+ },
42684
+ responses: {
42685
+ "200": {
42686
+ description: "User updated",
42687
+ content: {
42688
+ "application/json": {
42689
+ schema: { $ref: "#/components/schemas/User" }
42690
+ }
42691
+ }
42692
+ },
42693
+ "404": {
42694
+ description: "User not found",
42695
+ content: {
42696
+ "application/json": {
42697
+ schema: { $ref: "#/components/schemas/Error" }
42698
+ }
42699
+ }
42700
+ }
42701
+ }
42702
+ },
42703
+ delete: {
42704
+ tags: ["users"],
42705
+ summary: "Delete user",
42706
+ description: "Delete a user by ID",
42707
+ operationId: "deleteUser",
42708
+ security: [{ bearerAuth: [] }],
42709
+ parameters: [
42710
+ {
42711
+ name: "id",
42712
+ in: "path",
42713
+ required: true,
42714
+ description: "User ID",
42715
+ schema: { type: "string" }
42716
+ }
42717
+ ],
42718
+ responses: {
42719
+ "200": {
42720
+ description: "User deleted",
42721
+ content: {
42722
+ "application/json": {
42723
+ schema: {
42724
+ type: "object",
42725
+ properties: {
42726
+ success: { type: "boolean", example: true },
42727
+ message: { type: "string", example: "User deleted" }
42728
+ }
42729
+ }
42730
+ }
42731
+ }
42732
+ },
42733
+ "404": {
42734
+ description: "User not found",
42735
+ content: {
42736
+ "application/json": {
42737
+ schema: { $ref: "#/components/schemas/Error" }
42738
+ }
42739
+ }
42740
+ }
42741
+ }
42742
+ }
42743
+ },
42744
+ "/jobs": {
42745
+ get: {
42746
+ tags: ["jobs"],
42747
+ summary: "List jobs",
42748
+ description: "Get a list of all async jobs",
42749
+ operationId: "listJobs",
42750
+ security: [{ bearerAuth: [] }],
42751
+ parameters: [
42752
+ {
42753
+ name: "status",
42754
+ in: "query",
42755
+ description: "Filter by status",
42756
+ schema: { type: "string", enum: ["pending", "running", "completed", "failed"] }
42757
+ }
42758
+ ],
42759
+ responses: {
42760
+ "200": {
42761
+ description: "List of jobs",
42762
+ content: {
42763
+ "application/json": {
42764
+ schema: {
42765
+ type: "object",
42766
+ properties: {
42767
+ jobs: {
42768
+ type: "array",
42769
+ items: { $ref: "#/components/schemas/Job" }
42770
+ },
42771
+ total: { type: "integer", description: "Total number of jobs" }
42772
+ }
42773
+ }
42774
+ }
42775
+ }
42776
+ }
42777
+ }
42778
+ },
42779
+ post: {
42780
+ tags: ["jobs"],
42781
+ summary: "Create job",
42782
+ description: "Create a new async job. The job will progress through pending -> running -> completed over ~3 seconds.",
42783
+ operationId: "createJob",
42784
+ security: [{ bearerAuth: [] }],
42785
+ requestBody: {
42786
+ required: true,
42787
+ content: {
42788
+ "application/json": {
42789
+ schema: {
42790
+ type: "object",
42791
+ required: ["type"],
42792
+ properties: {
42793
+ type: {
42794
+ type: "string",
42795
+ enum: ["export", "import", "process"],
42796
+ description: "Type of job to create",
42797
+ example: "export"
42798
+ }
42799
+ }
42800
+ }
42801
+ }
42802
+ }
42803
+ },
42804
+ responses: {
42805
+ "201": {
42806
+ description: "Job created",
42807
+ content: {
42808
+ "application/json": {
42809
+ schema: { $ref: "#/components/schemas/Job" }
42810
+ }
42811
+ }
42812
+ },
42813
+ "400": {
42814
+ description: "Invalid input",
42815
+ content: {
42816
+ "application/json": {
42817
+ schema: { $ref: "#/components/schemas/Error" }
42818
+ }
42819
+ }
42820
+ }
42821
+ }
42822
+ }
42823
+ },
42824
+ "/jobs/{id}": {
42825
+ get: {
42826
+ tags: ["jobs"],
42827
+ summary: "Get job status",
42828
+ description: "Get the current status of an async job. Poll this endpoint to track job progress.",
42829
+ operationId: "getJob",
42830
+ security: [{ bearerAuth: [] }],
42831
+ parameters: [
42832
+ {
42833
+ name: "id",
42834
+ in: "path",
42835
+ required: true,
42836
+ description: "Job ID",
42837
+ schema: { type: "string" }
42838
+ }
42839
+ ],
42840
+ responses: {
42841
+ "200": {
42842
+ description: "Job found",
42843
+ content: {
42844
+ "application/json": {
42845
+ schema: { $ref: "#/components/schemas/Job" }
42846
+ }
42847
+ }
42848
+ },
42849
+ "404": {
42850
+ description: "Job not found",
42851
+ content: {
42852
+ "application/json": {
42853
+ schema: { $ref: "#/components/schemas/Error" }
42854
+ }
42855
+ }
42856
+ }
42857
+ }
42858
+ }
42859
+ },
42860
+ "/echo": {
42861
+ post: {
42862
+ tags: ["utility"],
42863
+ summary: "Echo request",
42864
+ description: "Returns the request body back in the response. Useful for testing.",
42865
+ operationId: "echo",
42866
+ requestBody: {
42867
+ required: false,
42868
+ content: {
42869
+ "application/json": {
42870
+ schema: {
42871
+ type: "object",
42872
+ additionalProperties: true,
42873
+ description: "Any JSON object",
42874
+ example: { message: "Hello, World!", number: 42 }
42875
+ }
42876
+ }
42877
+ }
42878
+ },
42879
+ responses: {
42880
+ "200": {
42881
+ description: "Echo response",
42882
+ content: {
42883
+ "application/json": {
42884
+ schema: {
42885
+ type: "object",
42886
+ properties: {
42887
+ echo: {
42888
+ type: "object",
42889
+ additionalProperties: true,
42890
+ description: "The request body that was sent"
42891
+ },
42892
+ timestamp: { type: "string", format: "date-time" },
42893
+ method: { type: "string", example: "POST" }
42894
+ }
42895
+ }
42896
+ }
42897
+ }
42898
+ }
42899
+ }
42900
+ }
42901
+ },
42902
+ "/error/{code}": {
42903
+ get: {
42904
+ tags: ["utility"],
42905
+ summary: "Generate error",
42906
+ description: "Returns a specific HTTP error code. Useful for testing error handling.",
42907
+ operationId: "generateError",
42908
+ parameters: [
42909
+ {
42910
+ name: "code",
42911
+ in: "path",
42912
+ required: true,
42913
+ description: "HTTP status code to return",
42914
+ schema: {
42915
+ type: "integer",
42916
+ enum: [400, 401, 403, 404, 500, 502, 503]
42917
+ }
42918
+ }
42919
+ ],
42920
+ responses: {
42921
+ "400": {
42922
+ description: "Bad Request",
42923
+ content: {
42924
+ "application/json": {
42925
+ schema: { $ref: "#/components/schemas/Error" }
42926
+ }
42927
+ }
42928
+ },
42929
+ "401": {
42930
+ description: "Unauthorized",
42931
+ content: {
42932
+ "application/json": {
42933
+ schema: { $ref: "#/components/schemas/Error" }
42934
+ }
42935
+ }
42936
+ },
42937
+ "403": {
42938
+ description: "Forbidden",
42939
+ content: {
42940
+ "application/json": {
42941
+ schema: { $ref: "#/components/schemas/Error" }
42942
+ }
42943
+ }
42944
+ },
42945
+ "404": {
42946
+ description: "Not Found",
42947
+ content: {
42948
+ "application/json": {
42949
+ schema: { $ref: "#/components/schemas/Error" }
42950
+ }
42951
+ }
42952
+ },
42953
+ "500": {
42954
+ description: "Internal Server Error",
42955
+ content: {
42956
+ "application/json": {
42957
+ schema: { $ref: "#/components/schemas/Error" }
42958
+ }
42959
+ }
42960
+ },
42961
+ "502": {
42962
+ description: "Bad Gateway",
42963
+ content: {
42964
+ "application/json": {
42965
+ schema: { $ref: "#/components/schemas/Error" }
42966
+ }
42967
+ }
42968
+ },
42969
+ "503": {
42970
+ description: "Service Unavailable",
42971
+ content: {
42972
+ "application/json": {
42973
+ schema: { $ref: "#/components/schemas/Error" }
42974
+ }
42975
+ }
42976
+ }
42977
+ }
42978
+ }
42979
+ }
42980
+ },
42981
+ components: {
42982
+ schemas: {
42983
+ User: {
42984
+ type: "object",
42985
+ properties: {
42986
+ id: { type: "string", description: "Unique user ID", example: "lx1abc-1" },
42987
+ email: { type: "string", format: "email", description: "User email", example: "user@example.com" },
42988
+ name: { type: "string", description: "User full name", example: "John Doe" },
42989
+ role: { type: "string", enum: ["admin", "user", "viewer"], description: "User role" },
42990
+ createdAt: { type: "string", format: "date-time", description: "Creation timestamp" },
42991
+ updatedAt: { type: "string", format: "date-time", description: "Last update timestamp" }
42992
+ },
42993
+ required: ["id", "email", "name", "role", "createdAt", "updatedAt"]
42994
+ },
42995
+ Job: {
42996
+ type: "object",
42997
+ properties: {
42998
+ id: { type: "string", description: "Unique job ID", example: "lx1def-2" },
42999
+ type: { type: "string", enum: ["export", "import", "process"], description: "Job type" },
43000
+ status: { type: "string", enum: ["pending", "running", "completed", "failed"], description: "Current job status" },
43001
+ progress: { type: "integer", minimum: 0, maximum: 100, description: "Progress percentage" },
43002
+ result: { type: "object", additionalProperties: true, description: "Job result (when completed)" },
43003
+ createdAt: { type: "string", format: "date-time", description: "Creation timestamp" },
43004
+ completedAt: { type: "string", format: "date-time", description: "Completion timestamp" }
43005
+ },
43006
+ required: ["id", "type", "status", "progress", "createdAt"]
43007
+ },
43008
+ AuthResponse: {
43009
+ type: "object",
43010
+ properties: {
43011
+ token: { type: "string", description: "Bearer token for authentication", example: "sandbox_lx1ghi-3_abc123" },
43012
+ user: { $ref: "#/components/schemas/User" },
43013
+ expiresAt: { type: "string", format: "date-time", description: "Token expiration time" }
43014
+ },
43015
+ required: ["token", "user", "expiresAt"]
43016
+ },
43017
+ Error: {
43018
+ type: "object",
43019
+ properties: {
43020
+ error: { type: "string", description: "Error message", example: "Not found" },
43021
+ code: { type: "string", description: "Error code", example: "NOT_FOUND" },
43022
+ details: { type: "object", additionalProperties: true, description: "Additional error details" }
43023
+ },
43024
+ required: ["error", "code"]
43025
+ }
43026
+ },
43027
+ securitySchemes: {
43028
+ bearerAuth: {
43029
+ type: "http",
43030
+ scheme: "bearer",
43031
+ description: "Use the token from /auth/login as Bearer token"
43032
+ }
43033
+ }
43034
+ }
43035
+ };
43036
+
43037
+ // ../shared/dist/sandbox/data.js
43038
+ var sessions = /* @__PURE__ */ new Map();
43039
+ var defaultStore;
43040
+ var seedUsers = [
43041
+ { email: "admin@example.com", name: "Admin User", role: "admin" },
43042
+ { email: "alice@example.com", name: "Alice Johnson", role: "user" },
43043
+ { email: "bob@example.com", name: "Bob Smith", role: "user" },
43044
+ { email: "demo@example.com", name: "Demo User", role: "viewer" }
43045
+ ];
43046
+ function generateIdForStore(store) {
43047
+ return `${Date.now().toString(36)}-${(++store.idCounter).toString(36)}`;
43048
+ }
43049
+ function createFreshStore() {
43050
+ const store = {
43051
+ users: /* @__PURE__ */ new Map(),
43052
+ jobs: /* @__PURE__ */ new Map(),
43053
+ tokens: /* @__PURE__ */ new Map(),
43054
+ idCounter: 0
43055
+ };
43056
+ const now = (/* @__PURE__ */ new Date()).toISOString();
43057
+ for (const userData of seedUsers) {
43058
+ const id = generateIdForStore(store);
43059
+ store.users.set(id, {
43060
+ ...userData,
43061
+ id,
43062
+ createdAt: now,
43063
+ updatedAt: now
43064
+ });
43065
+ }
43066
+ return store;
43067
+ }
43068
+ defaultStore = createFreshStore();
43069
+ function getStore(sessionId) {
43070
+ if (sessionId) {
43071
+ const session = sessions.get(sessionId);
43072
+ if (session)
43073
+ return session;
43074
+ }
43075
+ return defaultStore;
43076
+ }
43077
+ function getUsers(sessionId) {
43078
+ return Array.from(getStore(sessionId).users.values());
43079
+ }
43080
+ function getUserById(id, sessionId) {
43081
+ return getStore(sessionId).users.get(id);
43082
+ }
43083
+ function getUserByEmail(email, sessionId) {
43084
+ return Array.from(getStore(sessionId).users.values()).find((u) => u.email === email);
43085
+ }
43086
+ function createUser(data, sessionId) {
43087
+ const store = getStore(sessionId);
43088
+ const id = generateIdForStore(store);
43089
+ const now = (/* @__PURE__ */ new Date()).toISOString();
43090
+ const user = {
43091
+ id,
43092
+ email: data.email,
43093
+ name: data.name,
43094
+ role: data.role || "user",
43095
+ createdAt: now,
43096
+ updatedAt: now
43097
+ };
43098
+ store.users.set(id, user);
43099
+ return user;
43100
+ }
43101
+ function updateUser(id, data, sessionId) {
43102
+ const store = getStore(sessionId);
43103
+ const user = store.users.get(id);
43104
+ if (!user)
43105
+ return void 0;
43106
+ const updated = {
43107
+ ...user,
43108
+ ...data,
43109
+ id: user.id,
43110
+ createdAt: user.createdAt,
43111
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
43112
+ };
43113
+ store.users.set(id, updated);
43114
+ return updated;
43115
+ }
43116
+ function deleteUser(id, sessionId) {
43117
+ return getStore(sessionId).users.delete(id);
43118
+ }
43119
+ function getJobs(sessionId) {
43120
+ return Array.from(getStore(sessionId).jobs.values());
43121
+ }
43122
+ function getJobById(id, sessionId) {
43123
+ return getStore(sessionId).jobs.get(id);
43124
+ }
43125
+ function createJob(data, sessionId) {
43126
+ const store = getStore(sessionId);
43127
+ const id = generateIdForStore(store);
43128
+ const job = {
43129
+ id,
43130
+ type: data.type,
43131
+ status: "pending",
43132
+ progress: 0,
43133
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
43134
+ };
43135
+ store.jobs.set(id, job);
43136
+ if (!sessionId) {
43137
+ simulateJobProgress(id, sessionId);
43138
+ } else {
43139
+ store.jobs.set(id, {
43140
+ ...job,
43141
+ status: "completed",
43142
+ progress: 100,
43143
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
43144
+ result: { message: "Job completed successfully", processedItems: 42 }
43145
+ });
43146
+ }
43147
+ return store.jobs.get(id);
43148
+ }
43149
+ function updateJob(id, data, sessionId) {
43150
+ const store = getStore(sessionId);
43151
+ const job = store.jobs.get(id);
43152
+ if (!job)
43153
+ return void 0;
43154
+ const updated = {
43155
+ ...job,
43156
+ ...data,
43157
+ id: job.id,
43158
+ createdAt: job.createdAt
43159
+ };
43160
+ store.jobs.set(id, updated);
43161
+ return updated;
43162
+ }
43163
+ function simulateJobProgress(jobId, sessionId) {
43164
+ const progressSteps = [
43165
+ { delay: 500, progress: 0, status: "running" },
43166
+ { delay: 1e3, progress: 25, status: "running" },
43167
+ { delay: 1500, progress: 50, status: "running" },
43168
+ { delay: 2e3, progress: 75, status: "running" },
43169
+ { delay: 2500, progress: 100, status: "completed" }
43170
+ ];
43171
+ const store = getStore(sessionId);
43172
+ for (const step of progressSteps) {
43173
+ setTimeout(() => {
43174
+ const job = store.jobs.get(jobId);
43175
+ if (job && job.status !== "failed") {
43176
+ updateJob(jobId, {
43177
+ progress: step.progress,
43178
+ status: step.status,
43179
+ ...step.status === "completed" ? {
43180
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
43181
+ result: { message: "Job completed successfully", processedItems: 42 }
43182
+ } : {}
43183
+ }, sessionId);
43184
+ }
43185
+ }, step.delay);
43186
+ }
43187
+ }
43188
+ function createToken(userId, sessionId) {
43189
+ const store = getStore(sessionId);
43190
+ const token = `sandbox_${generateIdForStore(store)}_${Math.random().toString(36).substring(2)}`;
43191
+ store.tokens.set(token, userId);
43192
+ return token;
43193
+ }
43194
+
43195
+ // ../shared/dist/sandbox/handlers.js
43196
+ function errorResponse(status, error, code, details) {
43197
+ return {
43198
+ status,
43199
+ body: { error, code, ...details ? { details } : {} }
43200
+ };
43201
+ }
43202
+ function successResponse(status, body) {
43203
+ return { status, body };
43204
+ }
43205
+ function matchRoute(path2, pattern) {
43206
+ const paramNames = [];
43207
+ const regexPattern = pattern.replace(/\{([^}]+)\}/g, (_, name) => {
43208
+ paramNames.push(name);
43209
+ return "([^/]+)";
43210
+ });
43211
+ const regex = new RegExp(`^${regexPattern}$`);
43212
+ const match = path2.match(regex);
43213
+ if (!match)
43214
+ return null;
43215
+ const params = {};
43216
+ paramNames.forEach((name, index) => {
43217
+ params[name] = match[index + 1];
43218
+ });
43219
+ return params;
43220
+ }
43221
+ function handleHealth() {
43222
+ return successResponse(200, {
43223
+ status: "ok",
43224
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
43225
+ version: "1.0.0"
43226
+ });
43227
+ }
43228
+ function handleLogin(req) {
43229
+ const body = req.body;
43230
+ const sessionId = req.sessionId;
43231
+ if (!body?.email || !body?.password) {
43232
+ return errorResponse(400, "Email and password are required", "INVALID_INPUT");
43233
+ }
43234
+ let user = getUserByEmail(body.email, sessionId);
43235
+ if (!user) {
43236
+ user = createUser({ email: body.email, name: body.email.split("@")[0], role: "user" }, sessionId);
43237
+ }
43238
+ const token = createToken(user.id, sessionId);
43239
+ const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1e3).toISOString();
43240
+ return successResponse(200, { token, user, expiresAt });
43241
+ }
43242
+ function handleListUsers(req) {
43243
+ const query = req.query || {};
43244
+ const page = parseInt(String(query.page || "1"), 10);
43245
+ const limit = Math.min(parseInt(String(query.limit || "10"), 10), 100);
43246
+ const roleFilter = query.role;
43247
+ const sessionId = req.sessionId;
43248
+ let users = getUsers(sessionId);
43249
+ if (roleFilter && ["admin", "user", "viewer"].includes(roleFilter)) {
43250
+ users = users.filter((u) => u.role === roleFilter);
43251
+ }
43252
+ const total = users.length;
43253
+ const totalPages = Math.ceil(total / limit);
43254
+ const start = (page - 1) * limit;
43255
+ const paginatedUsers = users.slice(start, start + limit);
43256
+ return successResponse(200, {
43257
+ users: paginatedUsers,
43258
+ total,
43259
+ page,
43260
+ limit,
43261
+ totalPages
43262
+ });
43263
+ }
43264
+ function handleCreateUser(req) {
43265
+ const body = req.body;
43266
+ const sessionId = req.sessionId;
43267
+ if (!body?.email || !body?.name) {
43268
+ return errorResponse(400, "Email and name are required", "INVALID_INPUT");
43269
+ }
43270
+ if (getUserByEmail(body.email, sessionId)) {
43271
+ return errorResponse(409, "Email already exists", "DUPLICATE_EMAIL");
43272
+ }
43273
+ const user = createUser({
43274
+ email: body.email,
43275
+ name: body.name,
43276
+ role: body.role
43277
+ }, sessionId);
43278
+ return successResponse(201, user);
43279
+ }
43280
+ function handleGetUser(userId, sessionId) {
43281
+ const user = getUserById(userId, sessionId);
43282
+ if (!user) {
43283
+ return errorResponse(404, "User not found", "NOT_FOUND");
43284
+ }
43285
+ return successResponse(200, user);
43286
+ }
43287
+ function handleUpdateUser(userId, req) {
43288
+ const body = req.body;
43289
+ const sessionId = req.sessionId;
43290
+ if (!body || Object.keys(body).length === 0) {
43291
+ return errorResponse(400, "No update fields provided", "INVALID_INPUT");
43292
+ }
43293
+ const user = updateUser(userId, body, sessionId);
43294
+ if (!user) {
43295
+ return errorResponse(404, "User not found", "NOT_FOUND");
43296
+ }
43297
+ return successResponse(200, user);
43298
+ }
43299
+ function handleDeleteUser(userId, sessionId) {
43300
+ const deleted = deleteUser(userId, sessionId);
43301
+ if (!deleted) {
43302
+ return errorResponse(404, "User not found", "NOT_FOUND");
43303
+ }
43304
+ return successResponse(200, { success: true, message: "User deleted" });
43305
+ }
43306
+ function handleListJobs(req) {
43307
+ const query = req.query || {};
43308
+ const statusFilter = query.status;
43309
+ const sessionId = req.sessionId;
43310
+ let jobs = getJobs(sessionId);
43311
+ if (statusFilter && ["pending", "running", "completed", "failed"].includes(statusFilter)) {
43312
+ jobs = jobs.filter((j) => j.status === statusFilter);
43313
+ }
43314
+ return successResponse(200, { jobs, total: jobs.length });
43315
+ }
43316
+ function handleCreateJob(req) {
43317
+ const body = req.body;
43318
+ const sessionId = req.sessionId;
43319
+ if (!body?.type || !["export", "import", "process"].includes(body.type)) {
43320
+ return errorResponse(400, "Valid job type is required (export, import, process)", "INVALID_INPUT");
43321
+ }
43322
+ const job = createJob({ type: body.type }, sessionId);
43323
+ return successResponse(201, job);
43324
+ }
43325
+ function handleGetJob(jobId, sessionId) {
43326
+ const job = getJobById(jobId, sessionId);
43327
+ if (!job) {
43328
+ return errorResponse(404, "Job not found", "NOT_FOUND");
43329
+ }
43330
+ return successResponse(200, job);
43331
+ }
43332
+ function handleEcho(req) {
43333
+ return successResponse(200, {
43334
+ echo: req.body || {},
43335
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
43336
+ method: req.method
43337
+ });
43338
+ }
43339
+ function handleError(code) {
43340
+ const statusCode = parseInt(code, 10);
43341
+ const errorMessages = {
43342
+ 400: { error: "Bad Request", code: "BAD_REQUEST" },
43343
+ 401: { error: "Unauthorized", code: "UNAUTHORIZED" },
43344
+ 403: { error: "Forbidden", code: "FORBIDDEN" },
43345
+ 404: { error: "Not Found", code: "NOT_FOUND" },
43346
+ 500: { error: "Internal Server Error", code: "INTERNAL_ERROR" },
43347
+ 502: { error: "Bad Gateway", code: "BAD_GATEWAY" },
43348
+ 503: { error: "Service Unavailable", code: "SERVICE_UNAVAILABLE" }
43349
+ };
43350
+ const errorInfo = errorMessages[statusCode];
43351
+ if (!errorInfo) {
43352
+ return errorResponse(400, "Invalid error code", "INVALID_ERROR_CODE");
43353
+ }
43354
+ return errorResponse(statusCode, errorInfo.error, errorInfo.code);
43355
+ }
43356
+ async function handleSandboxRequest(req) {
43357
+ const path2 = req.path.startsWith("/") ? req.path : `/${req.path}`;
43358
+ const method = req.method.toUpperCase();
43359
+ const sessionId = req.sessionId;
43360
+ if (path2 === "/health" && method === "GET") {
43361
+ return handleHealth();
43362
+ }
43363
+ if (path2 === "/openapi.json" && method === "GET") {
43364
+ return errorResponse(404, "OpenAPI spec should be served by framework", "NOT_IMPLEMENTED");
43365
+ }
43366
+ if (path2 === "/auth/login" && method === "POST") {
43367
+ return handleLogin(req);
43368
+ }
43369
+ if (path2 === "/echo" && method === "POST") {
43370
+ return handleEcho(req);
43371
+ }
43372
+ const errorMatch = matchRoute(path2, "/error/{code}");
43373
+ if (errorMatch && method === "GET") {
43374
+ return handleError(errorMatch.code);
43375
+ }
43376
+ if (path2 === "/users") {
43377
+ if (method === "GET")
43378
+ return handleListUsers(req);
43379
+ if (method === "POST")
43380
+ return handleCreateUser(req);
43381
+ }
43382
+ const userMatch = matchRoute(path2, "/users/{id}");
43383
+ if (userMatch) {
43384
+ if (method === "GET")
43385
+ return handleGetUser(userMatch.id, sessionId);
43386
+ if (method === "PUT")
43387
+ return handleUpdateUser(userMatch.id, req);
43388
+ if (method === "DELETE")
43389
+ return handleDeleteUser(userMatch.id, sessionId);
43390
+ }
43391
+ if (path2 === "/jobs") {
43392
+ if (method === "GET")
43393
+ return handleListJobs(req);
43394
+ if (method === "POST")
43395
+ return handleCreateJob(req);
43396
+ }
43397
+ const jobMatch = matchRoute(path2, "/jobs/{id}");
43398
+ if (jobMatch && method === "GET") {
43399
+ return handleGetJob(jobMatch.id, sessionId);
43400
+ }
43401
+ return errorResponse(404, `Route not found: ${method} ${path2}`, "NOT_FOUND");
43402
+ }
43403
+
42318
43404
  // ../../node_modules/chalk/source/vendor/ansi-styles/index.js
42319
43405
  var ANSI_BACKGROUND_OFFSET = 10;
42320
43406
  var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
@@ -42841,6 +43927,26 @@ async function serve(demoPath, options) {
42841
43927
  const wsClients = /* @__PURE__ */ new Set();
42842
43928
  app.post("/api/execute", createRestProxy());
42843
43929
  app.post("/api/execute-shell", createShellExecutor());
43930
+ app.get("/sandbox/openapi.json", (_req, res) => {
43931
+ res.json(sandboxOpenApiSpec);
43932
+ });
43933
+ async function sandboxHandler(req, res) {
43934
+ try {
43935
+ const sandboxPath = req.path.replace("/sandbox", "") || "/";
43936
+ const response = await handleSandboxRequest({
43937
+ method: req.method,
43938
+ path: sandboxPath,
43939
+ body: req.body,
43940
+ headers: req.headers
43941
+ });
43942
+ res.status(response.status).json(response.body);
43943
+ } catch (err) {
43944
+ console.error("Sandbox error:", err);
43945
+ res.status(500).json({ error: err instanceof Error ? err.message : "Sandbox error" });
43946
+ }
43947
+ }
43948
+ app.all("/sandbox", sandboxHandler);
43949
+ app.all("/sandbox/*", sandboxHandler);
42844
43950
  app.post("/api/open-browser", async (req, res) => {
42845
43951
  try {
42846
43952
  const { url } = req.body;
@@ -43247,11 +44353,28 @@ async function whoami() {
43247
44353
  var import_path6 = require("path");
43248
44354
  var import_url3 = require("url");
43249
44355
  var import_fs8 = require("fs");
44356
+ var import_os4 = require("os");
44357
+ var import_child_process2 = require("child_process");
43250
44358
  var import_express2 = __toESM(require_express2(), 1);
44359
+ init_js_yaml();
44360
+ var CONFIG_FILE2 = (0, import_path6.join)((0, import_os4.homedir)(), ".demoscript", "config.json");
44361
+ var DEFAULT_API_URL2 = "https://demoscript.app";
44362
+ function loadCliConfig() {
44363
+ try {
44364
+ if ((0, import_fs8.existsSync)(CONFIG_FILE2)) {
44365
+ const content = (0, import_fs8.readFileSync)(CONFIG_FILE2, "utf-8");
44366
+ return JSON.parse(content);
44367
+ }
44368
+ } catch {
44369
+ }
44370
+ return {};
44371
+ }
44372
+ function getApiUrl2() {
44373
+ return loadCliConfig().apiUrl || DEFAULT_API_URL2;
44374
+ }
43251
44375
  var __dirname4 = (0, import_path6.dirname)((0, import_url3.fileURLToPath)(importMetaUrl));
43252
44376
  function getNetworkUrl2(port) {
43253
- const { networkInterfaces: networkInterfaces2 } = require("os");
43254
- const nets = networkInterfaces2();
44377
+ const nets = (0, import_os4.networkInterfaces)();
43255
44378
  for (const name of Object.keys(nets)) {
43256
44379
  for (const net of nets[name] || []) {
43257
44380
  if (net.family === "IPv4" && !net.internal) {
@@ -43261,6 +44384,113 @@ function getNetworkUrl2(port) {
43261
44384
  }
43262
44385
  return null;
43263
44386
  }
44387
+ function createGraphQLProxy() {
44388
+ return async (req, res) => {
44389
+ try {
44390
+ const { endpoint, query, variables, headers } = req.body;
44391
+ if (!endpoint || !query) {
44392
+ res.status(400).json({ error: "Missing endpoint or query" });
44393
+ return;
44394
+ }
44395
+ try {
44396
+ const parsedUrl = new URL(endpoint);
44397
+ if (!["http:", "https:"].includes(parsedUrl.protocol)) {
44398
+ res.status(400).json({ error: "Endpoint must be an HTTP or HTTPS URL" });
44399
+ return;
44400
+ }
44401
+ } catch {
44402
+ res.status(400).json({ error: `Invalid endpoint URL: ${endpoint}` });
44403
+ return;
44404
+ }
44405
+ const fetchHeaders = {
44406
+ "Content-Type": "application/json",
44407
+ ...headers
44408
+ };
44409
+ const response = await fetch(endpoint, {
44410
+ method: "POST",
44411
+ headers: fetchHeaders,
44412
+ body: JSON.stringify({
44413
+ query,
44414
+ variables
44415
+ })
44416
+ });
44417
+ const responseBody = await response.json().catch(() => null);
44418
+ if (!response.ok) {
44419
+ res.status(response.status).json({
44420
+ error: responseBody?.errors?.[0]?.message || `Request failed with status ${response.status}`,
44421
+ ...responseBody || {}
44422
+ });
44423
+ return;
44424
+ }
44425
+ res.json(responseBody);
44426
+ } catch (err) {
44427
+ const errorMessage = err instanceof Error ? err.message : "GraphQL request failed";
44428
+ console.error("[GraphQL Proxy Error]", errorMessage);
44429
+ try {
44430
+ res.status(500).json({ error: errorMessage });
44431
+ } catch {
44432
+ }
44433
+ }
44434
+ };
44435
+ }
44436
+ function createShellExecutor2() {
44437
+ return async (req, res) => {
44438
+ try {
44439
+ const body = req.body || {};
44440
+ const { command, shell_type, workdir, env: env2 } = body;
44441
+ if (!command) {
44442
+ res.status(400).json({ error: "Missing command" });
44443
+ return;
44444
+ }
44445
+ const result = await executeCommand2(command, {
44446
+ shell: shell_type || true,
44447
+ cwd: workdir,
44448
+ env: { ...process.env, ...env2 }
44449
+ });
44450
+ res.json({
44451
+ stdout: result.stdout,
44452
+ stderr: result.stderr,
44453
+ status: result.status,
44454
+ output: result.stdout
44455
+ // Legacy alias
44456
+ });
44457
+ } catch (err) {
44458
+ console.error("[Shell Executor Error]", err);
44459
+ res.status(500).json({ error: err instanceof Error ? err.message : "Command execution failed" });
44460
+ }
44461
+ };
44462
+ }
44463
+ function executeCommand2(command, options) {
44464
+ return new Promise((resolve6) => {
44465
+ const shell = typeof options.shell === "string" ? options.shell : "/bin/sh";
44466
+ const child = (0, import_child_process2.spawn)(shell, ["-c", command], {
44467
+ cwd: options.cwd,
44468
+ env: options.env
44469
+ });
44470
+ let stdout = "";
44471
+ let stderr = "";
44472
+ child.stdout.on("data", (data) => {
44473
+ stdout += data.toString();
44474
+ });
44475
+ child.stderr.on("data", (data) => {
44476
+ stderr += data.toString();
44477
+ });
44478
+ child.on("close", (code) => {
44479
+ resolve6({
44480
+ stdout: stdout.trim(),
44481
+ stderr: stderr.trim(),
44482
+ status: code ?? 1
44483
+ });
44484
+ });
44485
+ child.on("error", (err) => {
44486
+ resolve6({
44487
+ stdout: "",
44488
+ stderr: err.message,
44489
+ status: 1
44490
+ });
44491
+ });
44492
+ });
44493
+ }
43264
44494
  function createRestProxy2() {
43265
44495
  return async (req, res) => {
43266
44496
  const { url, method, headers, body } = req.body;
@@ -43268,6 +44498,21 @@ function createRestProxy2() {
43268
44498
  return res.status(400).json({ error: "URL is required" });
43269
44499
  }
43270
44500
  try {
44501
+ if (url.startsWith("/sandbox")) {
44502
+ const sandboxPath = url.replace("/sandbox", "") || "/";
44503
+ const result = await handleSandboxRequest({
44504
+ method: method || "GET",
44505
+ path: sandboxPath,
44506
+ params: {},
44507
+ query: {},
44508
+ body
44509
+ });
44510
+ return res.json({
44511
+ status: result.status,
44512
+ headers: { "content-type": "application/json" },
44513
+ data: result.body
44514
+ });
44515
+ }
43271
44516
  const fetchHeaders = {};
43272
44517
  if (headers) {
43273
44518
  Object.assign(fetchHeaders, headers);
@@ -43301,10 +44546,12 @@ function createRestProxy2() {
43301
44546
  }
43302
44547
  async function builder(options) {
43303
44548
  const { port, host, open: open3 } = options;
43304
- console.log(source_default.blue("Starting DemoScript Builder..."));
44549
+ console.log(source_default.blue("Starting DemoScript Visual Editor..."));
43305
44550
  const app = (0, import_express2.default)();
43306
44551
  app.use(import_express2.default.json());
43307
44552
  app.post("/api/execute", createRestProxy2());
44553
+ app.post("/api/execute-shell", createShellExecutor2());
44554
+ app.post("/api/execute-graphql", createGraphQLProxy());
43308
44555
  app.get("/api/openapi", async (req, res) => {
43309
44556
  const url = req.query.url;
43310
44557
  if (!url) {
@@ -43321,6 +44568,167 @@ async function builder(options) {
43321
44568
  res.status(500).json({ error: err instanceof Error ? err.message : "Failed to fetch OpenAPI spec" });
43322
44569
  }
43323
44570
  });
44571
+ app.get("/sandbox/openapi.json", (_req, res) => {
44572
+ res.json(sandboxOpenApiSpec);
44573
+ });
44574
+ async function sandboxHandler(req, res) {
44575
+ const sandboxPath = req.path.replace("/sandbox", "") || "/";
44576
+ const result = await handleSandboxRequest({
44577
+ method: req.method,
44578
+ path: sandboxPath,
44579
+ params: req.params,
44580
+ query: req.query,
44581
+ body: req.body
44582
+ });
44583
+ res.status(result.status).json(result.body);
44584
+ }
44585
+ app.all("/sandbox", sandboxHandler);
44586
+ app.all("/sandbox/*", sandboxHandler);
44587
+ let loadedDemoPath = null;
44588
+ let loadedDemoConfig = null;
44589
+ if (options.demoPath) {
44590
+ const resolvedPath = (0, import_path6.resolve)(process.cwd(), options.demoPath);
44591
+ const demoFile = resolvedPath.endsWith(".yaml") || resolvedPath.endsWith(".yml") ? resolvedPath : (0, import_path6.resolve)(resolvedPath, "demo.yaml");
44592
+ if ((0, import_fs8.existsSync)(demoFile)) {
44593
+ try {
44594
+ const content = (0, import_fs8.readFileSync)(demoFile, "utf-8");
44595
+ loadedDemoConfig = jsYaml.load(content);
44596
+ loadedDemoPath = demoFile;
44597
+ console.log(source_default.gray(` Demo: ${demoFile}`));
44598
+ } catch (err) {
44599
+ console.error(source_default.yellow(` Warning: Failed to load demo: ${err instanceof Error ? err.message : "Unknown error"}`));
44600
+ }
44601
+ } else {
44602
+ console.error(source_default.yellow(` Warning: Demo file not found: ${demoFile}`));
44603
+ }
44604
+ }
44605
+ app.get("/api/editor/demo", (_req, res) => {
44606
+ res.json({
44607
+ path: loadedDemoPath,
44608
+ config: loadedDemoConfig
44609
+ });
44610
+ });
44611
+ app.get("/api/files", (req, res) => {
44612
+ const dir = req.query.dir || process.cwd();
44613
+ try {
44614
+ const resolvedDir = (0, import_path6.resolve)(dir);
44615
+ const entries = (0, import_fs8.readdirSync)(resolvedDir, { withFileTypes: true });
44616
+ const items = entries.filter((e) => !e.name.startsWith(".")).map((e) => ({
44617
+ name: e.name,
44618
+ path: (0, import_path6.join)(resolvedDir, e.name),
44619
+ isDirectory: e.isDirectory(),
44620
+ isYaml: e.isFile() && (e.name.endsWith(".yaml") || e.name.endsWith(".yml"))
44621
+ })).sort((a, b) => {
44622
+ if (a.isDirectory !== b.isDirectory)
44623
+ return a.isDirectory ? -1 : 1;
44624
+ return a.name.localeCompare(b.name);
44625
+ });
44626
+ res.json({
44627
+ path: resolvedDir,
44628
+ parent: (0, import_path6.dirname)(resolvedDir),
44629
+ items
44630
+ });
44631
+ } catch (err) {
44632
+ res.status(500).json({ error: err instanceof Error ? err.message : "Failed to list directory" });
44633
+ }
44634
+ });
44635
+ app.get("/api/file", (req, res) => {
44636
+ const filePath = req.query.path;
44637
+ if (!filePath) {
44638
+ return res.status(400).json({ error: "path query parameter is required" });
44639
+ }
44640
+ try {
44641
+ const resolvedPath = (0, import_path6.resolve)(filePath);
44642
+ if (!(0, import_fs8.existsSync)(resolvedPath)) {
44643
+ return res.status(404).json({ error: "File not found" });
44644
+ }
44645
+ const content = (0, import_fs8.readFileSync)(resolvedPath, "utf-8");
44646
+ res.json({ path: resolvedPath, content });
44647
+ } catch (err) {
44648
+ res.status(500).json({ error: err instanceof Error ? err.message : "Failed to read file" });
44649
+ }
44650
+ });
44651
+ app.post("/api/file", (req, res) => {
44652
+ const { path: filePath, content } = req.body;
44653
+ if (!filePath || content === void 0) {
44654
+ return res.status(400).json({ error: "path and content are required" });
44655
+ }
44656
+ try {
44657
+ const resolvedPath = (0, import_path6.resolve)(filePath);
44658
+ const dir = (0, import_path6.dirname)(resolvedPath);
44659
+ if (!(0, import_fs8.existsSync)(dir)) {
44660
+ (0, import_fs8.mkdirSync)(dir, { recursive: true });
44661
+ }
44662
+ (0, import_fs8.writeFileSync)(resolvedPath, content, "utf-8");
44663
+ loadedDemoPath = resolvedPath;
44664
+ res.json({ success: true, path: resolvedPath });
44665
+ } catch (err) {
44666
+ res.status(500).json({ error: err instanceof Error ? err.message : "Failed to save file" });
44667
+ }
44668
+ });
44669
+ app.get("/api/auth/status", (_req, res) => {
44670
+ const config = loadCliConfig();
44671
+ res.json({
44672
+ isLoggedIn: !!config.token,
44673
+ username: config.username,
44674
+ email: config.email
44675
+ });
44676
+ });
44677
+ app.post("/api/push", async (req, res) => {
44678
+ const config = loadCliConfig();
44679
+ const apiUrl = getApiUrl2();
44680
+ if (!config.token) {
44681
+ return res.status(401).json({ error: "Not logged in. Run `demoscript login` first." });
44682
+ }
44683
+ const { slug, title, yaml_content, is_public } = req.body;
44684
+ if (!slug || !yaml_content) {
44685
+ return res.status(400).json({ error: "slug and yaml_content are required" });
44686
+ }
44687
+ try {
44688
+ const listResponse = await fetch(`${apiUrl}/api/demos`, {
44689
+ headers: { "Authorization": `Bearer ${config.token}` }
44690
+ });
44691
+ if (!listResponse.ok) {
44692
+ if (listResponse.status === 401) {
44693
+ return res.status(401).json({ error: "Authentication expired. Run `demoscript login` again." });
44694
+ }
44695
+ throw new Error("Failed to fetch demos");
44696
+ }
44697
+ const demosData = await listResponse.json();
44698
+ const existingDemo = demosData.demos.find((d) => d.slug === slug);
44699
+ let response;
44700
+ if (existingDemo) {
44701
+ response = await fetch(`${apiUrl}/api/demos/${existingDemo.id}`, {
44702
+ method: "PUT",
44703
+ headers: {
44704
+ "Authorization": `Bearer ${config.token}`,
44705
+ "Content-Type": "application/json"
44706
+ },
44707
+ body: JSON.stringify({ slug, title, yaml_content, is_public })
44708
+ });
44709
+ } else {
44710
+ response = await fetch(`${apiUrl}/api/demos`, {
44711
+ method: "POST",
44712
+ headers: {
44713
+ "Authorization": `Bearer ${config.token}`,
44714
+ "Content-Type": "application/json"
44715
+ },
44716
+ body: JSON.stringify({ slug, title, yaml_content, is_public })
44717
+ });
44718
+ }
44719
+ if (!response.ok) {
44720
+ const errorData = await response.json();
44721
+ throw new Error(errorData.error || "Push failed");
44722
+ }
44723
+ res.json({
44724
+ success: true,
44725
+ url: `${apiUrl}/u/${config.username}/${slug}`,
44726
+ updated: !!existingDemo
44727
+ });
44728
+ } catch (err) {
44729
+ res.status(500).json({ error: err instanceof Error ? err.message : "Push failed" });
44730
+ }
44731
+ });
43324
44732
  const uiSourcePaths = [
43325
44733
  (0, import_path6.resolve)(__dirname4, "..", "ui"),
43326
44734
  // packages/cli/dist -> packages/ui (bundled)
@@ -43342,37 +44750,21 @@ async function builder(options) {
43342
44750
  const useViteDevServer = (0, import_fs8.existsSync)((0, import_path6.resolve)(uiSourcePath, "vite.config.ts"));
43343
44751
  if (useViteDevServer) {
43344
44752
  const { createServer: createViteServer } = await import("vite");
44753
+ const hmrConfig = host === "0.0.0.0" ? { port: port + 1 } : { port: port + 1, host: host || "localhost" };
43345
44754
  const vite = await createViteServer({
43346
44755
  root: uiSourcePath,
43347
44756
  configFile: (0, import_path6.resolve)(uiSourcePath, "vite.config.ts"),
43348
44757
  server: {
43349
44758
  middlewareMode: true,
43350
- hmr: {
43351
- port: port + 1,
43352
- host: host || "localhost"
43353
- }
44759
+ hmr: hmrConfig
43354
44760
  },
43355
44761
  appType: "spa"
43356
44762
  });
43357
- app.get("/builder", async (_req, res) => {
43358
- const indexPath = (0, import_path6.resolve)(uiSourcePath, "index.html");
43359
- let html = (0, import_fs8.readFileSync)(indexPath, "utf-8");
43360
- html = await vite.transformIndexHtml("/builder", html);
43361
- html = html.replace("</head>", "<script>window.__DEMOSCRIPT_BUILDER__ = true;</script></head>");
43362
- res.type("html").send(html);
43363
- });
43364
- app.get("/builder-embed", async (_req, res) => {
43365
- const indexPath = (0, import_path6.resolve)(uiSourcePath, "index.html");
43366
- let html = (0, import_fs8.readFileSync)(indexPath, "utf-8");
43367
- html = await vite.transformIndexHtml("/builder-embed", html);
43368
- html = html.replace("</head>", "<script>window.__DEMOSCRIPT_BUILDER__ = true; window.__DEMOSCRIPT_BUILDER_EMBEDDED__ = true;</script></head>");
43369
- res.type("html").send(html);
43370
- });
43371
44763
  app.get("/editor", async (_req, res) => {
43372
44764
  const indexPath = (0, import_path6.resolve)(uiSourcePath, "index.html");
43373
44765
  let html = (0, import_fs8.readFileSync)(indexPath, "utf-8");
43374
44766
  html = await vite.transformIndexHtml("/editor", html);
43375
- html = html.replace("</head>", "<script>window.__DEMOSCRIPT_EDITOR__ = true;</script></head>");
44767
+ html = html.replace("</head>", "<script>window.__DEMOSCRIPT_EDITOR__ = true; window.__DEMOSCRIPT_CLI_MODE__ = true; window.__DEMOSCRIPT_CLOUD_ENABLED__ = true;</script></head>");
43376
44768
  res.type("html").send(html);
43377
44769
  });
43378
44770
  app.get("/editor-embed", async (_req, res) => {
@@ -43388,15 +44780,7 @@ async function builder(options) {
43388
44780
  app.use(vite.middlewares);
43389
44781
  } else if ((0, import_fs8.existsSync)(uiDistPath)) {
43390
44782
  const indexHtml = (0, import_fs8.readFileSync)((0, import_path6.join)(uiDistPath, "index.html"), "utf-8");
43391
- const injectedHtml = indexHtml.replace("</head>", `<script>window.__DEMOSCRIPT_BUILDER__ = true;</script></head>`);
43392
- app.get("/builder", (_req, res) => {
43393
- res.type("html").send(injectedHtml);
43394
- });
43395
- const embeddedHtml = indexHtml.replace("</head>", `<script>window.__DEMOSCRIPT_BUILDER__ = true; window.__DEMOSCRIPT_BUILDER_EMBEDDED__ = true;</script></head>`);
43396
- app.get("/builder-embed", (_req, res) => {
43397
- res.type("html").send(embeddedHtml);
43398
- });
43399
- const editorHtml = indexHtml.replace("</head>", `<script>window.__DEMOSCRIPT_EDITOR__ = true;</script></head>`);
44783
+ const editorHtml = indexHtml.replace("</head>", `<script>window.__DEMOSCRIPT_EDITOR__ = true; window.__DEMOSCRIPT_CLI_MODE__ = true; window.__DEMOSCRIPT_CLOUD_ENABLED__ = true;</script></head>`);
43400
44784
  app.get("/editor", (_req, res) => {
43401
44785
  res.type("html").send(editorHtml);
43402
44786
  });
@@ -43415,10 +44799,9 @@ async function builder(options) {
43415
44799
  const listenHost = host || "localhost";
43416
44800
  const server = app.listen(port, listenHost, async () => {
43417
44801
  console.log();
43418
- console.log(source_default.green.bold(" DemoScript Builder is running!"));
44802
+ console.log(source_default.green.bold(" DemoScript Visual Editor is running!"));
43419
44803
  console.log();
43420
- console.log(` ${source_default.cyan("Editor:")} http://localhost:${port}/editor ${source_default.gray("(new)")}`);
43421
- console.log(` ${source_default.cyan("Builder:")} http://localhost:${port}/builder ${source_default.gray("(legacy)")}`);
44804
+ console.log(` ${source_default.cyan("Editor:")} http://localhost:${port}/editor`);
43422
44805
  if (host === "0.0.0.0") {
43423
44806
  const networkUrl = getNetworkUrl2(port);
43424
44807
  if (networkUrl) {
@@ -43466,9 +44849,9 @@ program2.command("whoami").description("Show current logged in user").action(asy
43466
44849
  program2.command("push <demo>").description("Push demo to DemoScript Cloud").option("-s, --slug <slug>", "Demo slug (default: directory name)").option("-t, --title <title>", "Demo title (default: from YAML)").option("--public", "Make demo public (default)").option("--private", "Make demo private").action(async (demo, options) => {
43467
44850
  await push(demo, options);
43468
44851
  });
43469
- program2.command("builder").description("Open the visual demo builder").option("-p, --port <port>", "Port to run on", "3002").option("-H, --host [host]", "Host to bind to (use --host for 0.0.0.0)").option("--no-open", "Do not open browser automatically").action(async (options) => {
44852
+ program2.command("edit [demo]").description("Open visual demo editor").option("-p, --port <port>", "Port to run editor on", "3002").option("-H, --host [host]", "Host to bind to (use --host for 0.0.0.0)").option("--no-open", "Do not open browser automatically").action(async (demo, options) => {
43470
44853
  const host = options.host === true ? "0.0.0.0" : typeof options.host === "string" ? options.host : void 0;
43471
- await builder({ port: parseInt(options.port, 10), host, open: options.open });
44854
+ await builder({ port: parseInt(options.port, 10), host, open: options.open, demoPath: demo });
43472
44855
  });
43473
44856
  program2.parse();
43474
44857
  /*! Bundled license information: