"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// cli/appServer.ts
var appServer_exports = {};
__export(appServer_exports, {
  createDevServer: () => createDevServer,
  main: () => main
});
module.exports = __toCommonJS(appServer_exports);
var import_worker_threads2 = require("worker_threads");
var import_invariant3 = __toESM(require("invariant"));
var import_vite2 = require("vite");

// src/server/toolpadAppBuilder.ts
var path = __toESM(require("path"));
var import_vite = require("vite");
var import_plugin_react = __toESM(require("@vitejs/plugin-react"));
var import_serialize_javascript = __toESM(require("serialize-javascript"));
var import_strings2 = require("@mui/toolpad-utils/strings");

// src/constants.ts
var RUNTIME_CONFIG_WINDOW_PROPERTY = "__TOOLPAD_RUNTIME_CONFIG__";
var VERSION_CHECK_INTERVAL = 1e3 * 60 * 10;

// src/appDom/index.ts
var import_invariant = __toESM(require("invariant"));
var import_strings = require("@mui/toolpad-utils/strings");
var import_collections = require("@mui/toolpad-utils/collections");

// src/utils/immutability.ts
function update(dest, src) {
  let result;
  Object.entries(src).forEach(([key, value]) => {
    if (dest[key] !== value) {
      result = result || { ...dest };
      result[key] = value;
    }
  });
  return result || dest;
}
function updateOrCreate(dest, src) {
  return dest ? update(dest, src) : src;
}
function omit(obj, ...keys) {
  let result;
  keys.forEach((key) => {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      if (!result) {
        result = { ...obj };
      }
      delete result[key];
    }
  });
  return result || obj;
}

// src/server/schema.ts
var import_zod = require("zod");
function toolpadObjectSchema(kind, spec) {
  return import_zod.z.object({
    apiVersion: import_zod.z.literal("v1").describe(
      `Defines the version of this object. Used in determining compatibility between Toolpad "${kind}" objects.`
    ),
    kind: import_zod.z.literal(kind).describe(`Describes the nature of this Toolpad "${kind}" object.`),
    spec: spec.describe(`Defines the shape of this "${kind}" object`)
  });
}
var literalSchema = import_zod.z.union([import_zod.z.string(), import_zod.z.number(), import_zod.z.boolean(), import_zod.z.null()]);
function nameValuePairSchema(valueType) {
  return import_zod.z.object({
    name: import_zod.z.string().describe("The name"),
    value: valueType.describe(valueType.description ?? "The value")
  }).describe("A name/value pair.");
}
var jsExpressionBindingSchema = import_zod.z.object({
  $$jsExpression: import_zod.z.string().describe("The expression to be evaluated.")
}).describe("A binding that evaluates an expression and returns the result.");
var envBindingSchema = import_zod.z.object({
  $$env: import_zod.z.string().describe("The name of an environment variable.")
}).describe("An environment variable.");
function bindableSchema(valueType) {
  return import_zod.z.union([valueType, jsExpressionBindingSchema, envBindingSchema]);
}
var jsExpressionActionSchema = import_zod.z.object({
  $$jsExpressionAction: import_zod.z.string().describe("The code to be executed.")
}).describe("A javascript expression to be executed when this action is triggered.");
var navigationActionSchema = import_zod.z.object({
  $$navigationAction: import_zod.z.object({
    page: import_zod.z.string().describe("The page that is being navigated to"),
    parameters: import_zod.z.record(bindableSchema(import_zod.z.any())).describe("Parameters to pass when navigating to this page")
  })
}).describe(
  "A navigation from one page to another, optionally passing parameters to the next page."
);
var fetchModeSchema = import_zod.z.union([
  import_zod.z.literal("query").describe("Fetch automatically when the page opens"),
  import_zod.z.literal("mutation").describe("Fetch on manual action only")
]);
var nameStringValuePairSchema = nameValuePairSchema(import_zod.z.string()).describe(
  "a name/value pair with a string value."
);
var rawBodySchema = import_zod.z.object({
  kind: import_zod.z.literal("raw"),
  content: bindableSchema(import_zod.z.string()),
  contentType: import_zod.z.string()
});
var bindableNameStringValueSchema = nameValuePairSchema(bindableSchema(import_zod.z.string())).describe(
  "A name/value pair where the value is dynamically bindable to strings."
);
var urlEncodedBodySchema = import_zod.z.object({
  kind: import_zod.z.literal("urlEncoded"),
  content: import_zod.z.array(bindableNameStringValueSchema)
});
var fetchBodySchema = import_zod.z.discriminatedUnion("kind", [rawBodySchema, urlEncodedBodySchema]);
var rawResponseTypeSchema = import_zod.z.object({
  kind: import_zod.z.literal("raw")
}).describe("Don't interpret this body at all.");
var jsonResponseTypeSchema = import_zod.z.object({
  kind: import_zod.z.literal("json")
}).describe("Interpret the fetch response as JSON");
var csvResponseTypeSchema = import_zod.z.object({
  kind: import_zod.z.literal("csv"),
  headers: import_zod.z.boolean().describe("First row contains headers")
}).describe("Interpret the fetch response as CSV");
var xmlResponseTypeSchema = import_zod.z.object({
  kind: import_zod.z.literal("xml")
}).describe("Interpret the fetch response as XML");
var responseTypeSchema = import_zod.z.discriminatedUnion("kind", [
  rawResponseTypeSchema,
  jsonResponseTypeSchema,
  csvResponseTypeSchema,
  xmlResponseTypeSchema
]).describe("Describes how a the fetch response is to be interpreted.");
var fetchQueryConfigSchema = import_zod.z.object({
  kind: import_zod.z.literal("rest").describe("Designates this object as a fetch query."),
  url: bindableSchema(import_zod.z.string()).optional().describe("The URL of the request"),
  method: import_zod.z.string().optional().describe("The request method."),
  headers: import_zod.z.array(bindableNameStringValueSchema).optional().describe("Extra request headers."),
  searchParams: import_zod.z.array(bindableNameStringValueSchema).optional().describe("Extra url query parameters."),
  body: fetchBodySchema.optional().describe("The request body."),
  transformEnabled: import_zod.z.boolean().optional().describe("Run a custom transformer on the response."),
  transform: import_zod.z.string().optional().describe("The custom transformer to run when enabled."),
  response: responseTypeSchema.optional().describe("How to parse the response.")
});
var localQueryConfigSchema = import_zod.z.object({
  kind: import_zod.z.literal("local").describe("Designates this object as a local function query."),
  function: import_zod.z.string().optional().describe("The function to be executed on the backend by this query.")
});
var queryConfigSchema = import_zod.z.discriminatedUnion("kind", [
  fetchQueryConfigSchema,
  localQueryConfigSchema
]);
var querySchema = import_zod.z.object({
  name: import_zod.z.string().describe("A name for the query"),
  enabled: bindableSchema(import_zod.z.boolean()).optional().describe(
    "Activates or deactivates the query. When deactivated the data won't be loaded when the page opens."
  ),
  parameters: import_zod.z.array(nameValuePairSchema(bindableSchema(import_zod.z.any()))).optional().describe("Parameters to pass to this query."),
  mode: fetchModeSchema.optional().describe("How to fetch this query."),
  query: queryConfigSchema.optional().describe("Query definition"),
  transform: import_zod.z.string().optional().describe("Transformation to run on the response"),
  transformEnabled: import_zod.z.boolean().optional().describe("Enable the transformation"),
  refetchInterval: import_zod.z.number().optional().describe("Interval to rerun this query at"),
  cacheTime: import_zod.z.number().optional().describe("Time to cache before refetching")
});
var elementSchema;
var templateSchema = import_zod.z.object({
  $$template: import_zod.z.lazy(() => import_zod.z.array(elementSchema)).describe("The subtree, that describes the UI to be rendered by the template.")
}).describe("Describes a fragment of Toolpad elements, to be used as a template.");
var baseElementSchema = import_zod.z.object({
  component: import_zod.z.string().describe("The component that this element was based on."),
  name: import_zod.z.string().describe("a name for this component, which is used to reference it inside bindings."),
  layout: import_zod.z.object({
    horizontalAlign: import_zod.z.string().optional().describe("Lays out the element along the horizontal axis."),
    verticalAlign: import_zod.z.string().optional().describe("Lays out the element along the vertical axis."),
    columnSize: import_zod.z.number().optional().describe("The width this element takes up, expressed in terms of columns on the page.")
  }).optional().describe("Layout properties for this element.")
});
var bindablePropSchema = import_zod.z.lazy(
  () => import_zod.z.union([
    ...literalSchema.options,
    import_zod.z.array(bindablePropSchema),
    import_zod.z.record(
      import_zod.z.string().refine((key) => !key.startsWith("$$")),
      bindablePropSchema
    ),
    jsExpressionBindingSchema,
    envBindingSchema,
    jsExpressionActionSchema,
    navigationActionSchema,
    templateSchema
  ])
);
elementSchema = baseElementSchema.extend({
  children: import_zod.z.lazy(() => import_zod.z.array(elementSchema).optional()).describe("The children of this element."),
  props: import_zod.z.lazy(() => import_zod.z.record(bindablePropSchema).optional()).describe("The properties to configure this instance of the component.")
}).describe("The instance of a component. Used to build user interfaces in pages.");
var pageSchema = toolpadObjectSchema(
  "page",
  import_zod.z.object({
    id: import_zod.z.string().describe("Serves as a canonical id of the page."),
    title: import_zod.z.string().optional().describe("Title for this page."),
    parameters: import_zod.z.array(nameStringValuePairSchema).optional().describe("Parameters for the page. These can be set inside of the url query string."),
    queries: import_zod.z.array(querySchema).optional().describe("Queries that are used by the page. These will load data when the page opens."),
    content: import_zod.z.array(elementSchema).optional().describe("The content of the page. This defines the UI."),
    display: import_zod.z.union([
      import_zod.z.literal("standalone").describe("Hide the Toolpad chrome and just display the content of the page"),
      import_zod.z.literal("shell").describe("Show Toolpad header and navigation.")
    ]).optional().describe(
      "Display mode of the page. This can also be set at runtime with the toolpad-display query parameter"
    )
  })
);
var simplePaletteColorOptionsSchema = import_zod.z.object({
  main: import_zod.z.string(),
  light: import_zod.z.string().optional(),
  dark: import_zod.z.string().optional(),
  contrastText: import_zod.z.string().optional()
});
var themeOptionsSchema = import_zod.z.object({
  // TODO: expand to full MUI theme object
  palette: import_zod.z.object({
    mode: import_zod.z.union([import_zod.z.literal("light"), import_zod.z.literal("dark")]).optional(),
    primary: simplePaletteColorOptionsSchema.optional(),
    secondary: simplePaletteColorOptionsSchema.optional()
  }).passthrough().optional()
}).passthrough();
var themeSchema = toolpadObjectSchema(
  "theme",
  import_zod.z.object({
    options: themeOptionsSchema.optional().describe("The ThemeOptions object that gets fed into MUI's createTheme function.")
  })
);

// src/appDom/index.ts
function isType(node, type) {
  return node.type === type;
}
function isQuery(node) {
  return isType(node, "query");
}
function isMutation(node) {
  return isType(node, "mutation");
}
function setNamespacedProp(node, namespace, prop, value) {
  if (value) {
    return update(node, {
      [namespace]: updateOrCreate(node[namespace], {
        [prop]: value
      })
    });
  }
  return update(node, {
    [namespace]: omit(node[namespace], prop)
  });
}
var RENDERTREE_NODES = [
  "app",
  "page",
  "element",
  "query",
  "mutation",
  "theme",
  "codeComponent"
];
var frontendNodes = new Set(RENDERTREE_NODES);
function createRenderTreeNode(node) {
  if (!frontendNodes.has(node.type)) {
    return null;
  }
  if (isQuery(node) || isMutation(node)) {
    if (node.attributes.query) {
      node = setNamespacedProp(node, "attributes", "query", null);
    }
  }
  return node;
}
function createRenderTree(dom) {
  return {
    ...dom,
    nodes: (0, import_collections.mapProperties)(dom.nodes, ([id, node]) => {
      const rendernode = createRenderTreeNode(node);
      return rendernode ? [id, rendernode] : null;
    })
  };
}

// src/runtime/createRuntimeState.tsx
function createRuntimeState({ dom }) {
  return {
    dom: createRenderTree(dom)
  };
}

// src/server/toolpadAppBuilder.ts
var MAIN_ENTRY = "/main.tsx";
var CANVAS_ENTRY = "/canvas.tsx";
var INITIAL_STATE_WINDOW_PROPERTY = "__initialToolpadState__";
var componentsId = `virtual:toolpad:components.js`;
var resolvedComponentsId = `\0${componentsId}`;
function getHtmlContent({ canvas }) {
  const entryPoint = canvas ? CANVAS_ENTRY : MAIN_ENTRY;
  return `
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Toolpad</title>
        <link
          rel="stylesheet"
          href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
        />
      </head>
      <body>
        <div id="root"></div>

        ${canvas ? `
              <script>
                // Add the data-toolpad-canvas attribute to the canvas iframe element
                if (window.frameElement?.dataset.toolpadCanvas) {
                  var script = document.createElement('script');
                  script.src = '/reactDevtools/bootstrap.global.js';
                  document.write(script.outerHTML);
                }
              </script>
            ` : ""}
    
        <!-- __TOOLPAD_SCRIPTS__ -->

        <script type="module" src=${JSON.stringify(entryPoint)}></script>
      </body>
    </html>
  `;
}
function postProcessHtml(html, { config, dom }) {
  const serializedConfig = (0, import_serialize_javascript.default)(config, { ignoreFunction: true });
  const initialState = createRuntimeState({ dom });
  const serializedInitialState = (0, import_serialize_javascript.default)(initialState, { isJSON: true });
  const toolpadScripts = [
    `<script>window[${JSON.stringify(
      RUNTIME_CONFIG_WINDOW_PROPERTY
    )}] = ${serializedConfig}</script>`,
    `<script>window[${JSON.stringify(
      INITIAL_STATE_WINDOW_PROPERTY
    )}] = ${serializedInitialState}</script>`
  ];
  return html.replace(`<!-- __TOOLPAD_SCRIPTS__ -->`, () => toolpadScripts.join("\n"));
}
function toolpadVitePlugin({ root, base, getComponents: getComponents2 }) {
  const resolvedRuntimeEntryPointId = `\0${MAIN_ENTRY}`;
  const resolvedCanvasEntryPointId = `\0${CANVAS_ENTRY}`;
  const getEntryPoint = (isCanvas) => `
    import { init, setComponents } from '@mui/toolpad/runtime';
    import components from ${JSON.stringify(componentsId)};
    ${isCanvas ? `import AppCanvas from '@mui/toolpad/canvas'` : ""}
    
    const initialState = window[${JSON.stringify(INITIAL_STATE_WINDOW_PROPERTY)}];

    setComponents(components);

    init({
      ${isCanvas ? `ToolpadApp: AppCanvas,` : ""}
      base: ${JSON.stringify(base)},
      initialState,
    })

    if (import.meta.hot) {
      // TODO: investigate why this doesn't work, see https://github.com/vitejs/vite/issues/12912
      import.meta.hot.accept(${JSON.stringify(componentsId)}, (newComponents) => {
        if (newComponents) {
          console.log('hot updating Toolpad components')
          setComponents(newComponents);
        }
      });
    }
  `;
  return {
    name: "toolpad",
    async resolveId(id, importer) {
      if (id.endsWith(".html")) {
        return id;
      }
      if (id === MAIN_ENTRY) {
        return resolvedRuntimeEntryPointId;
      }
      if (id === CANVAS_ENTRY) {
        return resolvedCanvasEntryPointId;
      }
      if (id === componentsId) {
        return resolvedComponentsId;
      }
      if (importer === resolvedRuntimeEntryPointId || importer === resolvedComponentsId) {
        const newId = path.resolve(root, "toolpad", id);
        return this.resolve(newId, importer);
      }
      return null;
    },
    async load(id) {
      if (id.endsWith(".html")) {
        return getHtmlContent({ canvas: false });
      }
      if (id === resolvedRuntimeEntryPointId) {
        return {
          code: getEntryPoint(false),
          map: null
        };
      }
      if (id === resolvedCanvasEntryPointId) {
        return {
          code: getEntryPoint(true),
          map: null
        };
      }
      if (id === resolvedComponentsId) {
        const components = await getComponents2(root);
        const imports = components.map(({ name }) => `import ${name} from './components/${name}';`);
        const defaultExportProperties = components.map(
          ({ name }) => `${JSON.stringify(`codeComponent.${name}`)}: ${name}`
        );
        const code = `
          ${imports.join("\n")}

          export default {
            ${(0, import_strings2.indent)(defaultExportProperties.join(",\n"), 2)}
          };
        `;
        return {
          code,
          map: null
        };
      }
      return null;
    }
  };
}
function createViteConfig({
  outDir,
  root,
  dev,
  base,
  plugins = [],
  getComponents: getComponents2
}) {
  const mode = dev ? "development" : "production";
  return {
    viteConfig: {
      configFile: false,
      mode,
      build: {
        outDir,
        chunkSizeWarningLimit: Infinity,
        rollupOptions: {
          onwarn(warning, warn) {
            if (warning.code === "MODULE_LEVEL_DIRECTIVE") {
              return;
            }
            warn(warning);
          }
        }
      },
      envFile: false,
      resolve: {
        alias: [
          {
            // FIXME(https://github.com/mui/material-ui/issues/35233)
            find: /^@mui\/icons-material\/(?!esm\/)([^/]*)/,
            replacement: "@mui/icons-material/esm/$1"
          }
        ]
      },
      server: {
        fs: {
          allow: [root, path.resolve(__dirname, "../../../../")]
        }
      },
      optimizeDeps: {
        include: [
          "@emotion/cache",
          "@emotion/react",
          "@mui/icons-material",
          "@mui/icons-material/ArrowDropDownRounded",
          "@mui/icons-material/DarkMode",
          "@mui/icons-material/Edit",
          "@mui/icons-material/Error",
          "@mui/icons-material/HelpOutlined",
          "@mui/icons-material/LightMode",
          "@mui/icons-material/OpenInNew",
          "@mui/icons-material/SettingsBrightnessOutlined",
          "@mui/lab",
          "@mui/material",
          "@mui/material/CircularProgress",
          "@mui/material/Button",
          "@mui/material/colors",
          "@mui/material/styles",
          "@mui/material/useMediaQuery",
          "@mui/utils",
          "@mui/x-data-grid-pro",
          "@mui/x-date-pickers/AdapterDayjs",
          "@mui/x-date-pickers/DesktopDatePicker",
          "@mui/x-date-pickers/LocalizationProvider",
          "@mui/x-license-pro",
          "@tanstack/react-query",
          "@tanstack/react-query-devtools/build/lib/index.prod.js",
          "dayjs",
          "dayjs/locale/en",
          "dayjs/locale/fr",
          "dayjs/locale/nl",
          "fractional-indexing",
          "invariant",
          "lodash-es",
          "markdown-to-jsx",
          "nanoid/non-secure",
          "react",
          "react-dom/client",
          "react-error-boundary",
          "react-hook-form",
          "react-is",
          "react-router-dom",
          "react/jsx-dev-runtime",
          "react/jsx-runtime",
          "recharts",
          "superjson",
          "zod"
        ],
        exclude: [
          "@mui/toolpad-core",
          "@mui/toolpad/browser",
          "@mui/toolpad/runtime",
          "@mui/toolpad/canvas"
        ]
      },
      appType: "custom",
      logLevel: "info",
      root,
      plugins: [(0, import_plugin_react.default)(), toolpadVitePlugin({ root, base, getComponents: getComponents2 }), ...plugins],
      base,
      define: {
        "process.env.NODE_ENV": `'${mode}'`,
        "process.env.BASE_URL": `'${base}'`
      }
    }
  };
}

// src/server/workerRpc.ts
var import_worker_threads = require("worker_threads");
var import_invariant2 = __toESM(require("invariant"));
function createWorkerRpcClient() {
  return new Proxy({}, {
    get: (target, prop) => {
      if (typeof prop !== "string") {
        return Reflect.get(target, prop);
      }
      return (...args) => {
        return new Promise((resolve2, reject) => {
          (0, import_invariant2.default)(import_worker_threads.parentPort, "Worker client is not running in a worker thread");
          const { port1, port2 } = new import_worker_threads.MessageChannel();
          port1.on("message", (msg) => {
            if (msg.error) {
              reject(msg.error);
            } else {
              resolve2(msg.result);
            }
          });
          import_worker_threads.parentPort.postMessage(
            {
              kind: "worker-rpc",
              method: prop,
              args,
              port: port2
            },
            [port2]
          );
        });
      };
    }
  });
}

// cli/appServer.ts
var { notifyReady, loadDom, getComponents } = createWorkerRpcClient();
(0, import_invariant3.default)(
  process.env.NODE_ENV === "development",
  "The dev server must be started with NODE_ENV=development"
);
function devServerPlugin(root, config) {
  return {
    name: "toolpad-dev-server",
    async configureServer(viteServer) {
      return () => {
        viteServer.middlewares.use("/", async (req, res, next) => {
          (0, import_invariant3.default)(req.url, "request must have a url");
          const url = new URL(req.url, "http://x");
          const canvas = url.searchParams.get("toolpad-display") === "canvas";
          try {
            const dom = await loadDom();
            const template = getHtmlContent({ canvas });
            let html = await viteServer.transformIndexHtml(req.url, template);
            html = postProcessHtml(html, { config, dom });
            res.setHeader("content-type", "text/html; charset=utf-8").end(html);
          } catch (e) {
            next(e);
          }
        });
      };
    }
  };
}
async function createDevServer({ outDir, config, root, base }) {
  const { viteConfig } = createViteConfig({
    outDir,
    dev: true,
    root,
    base,
    plugins: [devServerPlugin(root, config)],
    getComponents
  });
  const devServer = await (0, import_vite2.createServer)(viteConfig);
  return { devServer };
}
async function main({ outDir, base, config, root, port }) {
  const { devServer } = await createDevServer({ outDir, config, root, base });
  await devServer.listen(port);
  (0, import_invariant3.default)(import_worker_threads2.parentPort, "parentPort must be defined");
  import_worker_threads2.parentPort.on("message", async (msg) => {
    switch (msg.kind) {
      case "reload-components": {
        const mod = devServer.moduleGraph.getModuleById(resolvedComponentsId);
        if (mod) {
          devServer.reloadModule(mod);
        }
        break;
      }
      case "exit": {
        await devServer.close();
        break;
      }
      default:
        throw new Error(`Unknown command ${msg}`);
    }
  });
  await notifyReady();
}
main(import_worker_threads2.workerData).catch((err) => {
  console.error(err);
  process.exit(1);
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  createDevServer,
  main
});
//# sourceMappingURL=appServer.js.map