UNPKG

@getcronit/pylon

Version:

![Pylon cover](https://github.com/user-attachments/assets/c28e49b2-5672-4849-826e-8b2eab0360cc)

3,359 lines 128 kB
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
  if (typeof require !== "undefined") return require.apply(this, arguments);
  throw Error('Dynamic require of "' + x + '" is not supported');
});
var __esm = (fn, res) => function __init() {
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};

// src/context.ts
import { AsyncLocalStorage } from "async_hooks";
import { env } from "hono/adapter";
var asyncContext, getContext, setContext;
var init_context = __esm({
  "src/context.ts"() {
    "use strict";
    asyncContext = new AsyncLocalStorage();
    getContext = () => {
      const ctx = asyncContext.getStore();
      if (!ctx) {
        throw new Error("Context not defined");
      }
      ctx.env = env(ctx);
      return ctx;
    };
    setContext = (context) => {
      return asyncContext.enterWith(context);
    };
  }
});

// src/app/index.ts
import { sentry } from "@hono/sentry";
import { Hono } from "hono";
import { except } from "hono/combine";
import { compress } from "hono/compress";
import { logger } from "hono/logger";
var app, skipInternal, pluginsMiddleware, pluginsMiddlewareLoader;
var init_app = __esm({
  "src/app/index.ts"() {
    "use strict";
    init_context();
    app = new Hono();
    skipInternal = (middleware) => {
      return async (c, next) => {
        if (c.req.header("X-Pylon-Internal") === "true") {
          return next();
        }
        return middleware(c, next);
      };
    };
    app.use("*", skipInternal(compress()));
    app.use("*", skipInternal(sentry()));
    app.use("*", async (c, next) => {
      return new Promise((resolve, reject) => {
        asyncContext.run(c, async () => {
          try {
            resolve(await next());
          } catch (error) {
            reject(error);
          }
        });
      });
    });
    app.use("*", skipInternal(except(["/__pylon/*"], logger())));
    pluginsMiddleware = [];
    pluginsMiddlewareLoader = async (c, next) => {
      for (const middleware of pluginsMiddleware) {
        const response = await middleware(c, async () => {
        });
        if (response) {
          return response;
        }
      }
      return next();
    };
    app.use(pluginsMiddlewareLoader);
  }
});

// src/define-pylon.ts
import * as Sentry from "@sentry/bun";
import consola from "consola";
import {
  getNamedType,
  GraphQLError,
  GraphQLUnionType,
  isInterfaceType,
  isNonNullType,
  isObjectType,
  Kind
} from "graphql";
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
var uniqueFieldsCache, selectionSetCache, executionAsyncContext, getResolveInfo, getSelectedFields, wrapResolver, resolversToGraphQLResolvers, ServiceError;
var init_define_pylon = __esm({
  "src/define-pylon.ts"() {
    "use strict";
    init_context();
    uniqueFieldsCache = /* @__PURE__ */ new WeakMap();
    selectionSetCache = /* @__PURE__ */ new WeakMap();
    executionAsyncContext = new AsyncLocalStorage2();
    getResolveInfo = () => {
      const store = executionAsyncContext.getStore();
      if (!store) {
        throw new Error("Resolve info is not available");
      }
      return store;
    };
    getSelectedFields = (info, fieldNodes = info.fieldNodes, parentType) => {
      let parentCache = selectionSetCache.get(fieldNodes);
      if (!parentCache) {
        parentCache = /* @__PURE__ */ new Map();
        selectionSetCache.set(fieldNodes, parentCache);
      }
      if (parentCache.has(parentType)) {
        return parentCache.get(parentType);
      }
      const fieldsMap = /* @__PURE__ */ new Map();
      const extract = (selections, currentType) => {
        for (const selection of selections) {
          if (selection.kind === Kind.FIELD) {
            const name = selection.name.value;
            let childReturnType = void 0;
            if (currentType && (isObjectType(currentType) || isInterfaceType(currentType))) {
              const fieldDef = currentType.getFields()[name];
              if (fieldDef) {
                childReturnType = getNamedType(fieldDef.type);
              }
            }
            if (!fieldsMap.has(name)) {
              fieldsMap.set(name, { nodes: [], returnType: childReturnType });
            }
            fieldsMap.get(name).nodes.push(selection);
          } else if (selection.kind === Kind.INLINE_FRAGMENT) {
            const inlineType = selection.typeCondition ? info.schema.getType(selection.typeCondition.name.value) : currentType;
            if (selection.selectionSet) {
              extract(selection.selectionSet.selections, inlineType);
            }
          } else if (selection.kind === Kind.FRAGMENT_SPREAD) {
            const fragment = info.fragments[selection.name.value];
            if (fragment && fragment.selectionSet) {
              const fragmentType = info.schema.getType(
                fragment.typeCondition.name.value
              );
              extract(fragment.selectionSet.selections, fragmentType);
            }
          }
        }
      };
      for (const fieldNode of fieldNodes) {
        if (fieldNode.selectionSet) {
          extract(fieldNode.selectionSet.selections, parentType);
        }
      }
      const result = Array.from(fieldsMap.entries()).map(([name, data]) => ({
        name,
        fieldNodes: data.nodes,
        returnType: data.returnType
      }));
      if (parentType && (isInterfaceType(parentType) || parentType instanceof GraphQLUnionType)) {
        const abstractType = info.schema.getType(parentType.name);
        const possibleTypes = info.schema.getPossibleTypes(abstractType);
        for (const possibleType of possibleTypes) {
          let uniqueField = uniqueFieldsCache.get(possibleType)?.[0];
          const typeFieldsMap = possibleType.getFields();
          if (uniqueField === void 0) {
            const typeFields = Object.keys(typeFieldsMap).filter(
              (f) => isNonNullType(typeFieldsMap[f].type)
            );
            const otherTypes = possibleTypes.filter(
              (t) => t.name !== possibleType.name
            );
            const otherTypesFields = new Set(
              otherTypes.flatMap((t) => Object.keys(t.getFields()))
            );
            const foundUniqueField = typeFields.find((f) => !otherTypesFields.has(f));
            if (foundUniqueField) {
              uniqueFieldsCache.set(possibleType, [foundUniqueField]);
              uniqueField = foundUniqueField;
            } else {
              uniqueFieldsCache.set(possibleType, []);
              uniqueField = void 0;
            }
          }
          if (uniqueField && !result.some((f) => f.name === uniqueField)) {
            result.push({
              name: uniqueField,
              fieldNodes: [],
              returnType: getNamedType(typeFieldsMap[uniqueField].type)
            });
          }
        }
      }
      parentCache.set(parentType, result);
      return result;
    };
    wrapResolver = (resolver, context, fieldNodes, parentType) => {
      if (resolver === null || typeof resolver !== "object" && typeof resolver !== "function") {
        return resolver;
      }
      if (resolver instanceof Date) {
        return resolver;
      }
      if (typeof resolver.then === "function") {
        return resolver.then(
          (resolved) => wrapResolver(resolved, context, fieldNodes, parentType)
        );
      }
      if (Array.isArray(resolver)) {
        const results = resolver.map(
          (item) => wrapResolver(item, context, fieldNodes, parentType)
        );
        if (results.some((r) => r && typeof r.then === "function")) {
          return Promise.all(results);
        }
        return results;
      }
      if (typeof resolver === "function") {
        return (args, ctx, info) => {
          const currentParentType = getNamedType(info.returnType);
          const selectedFields2 = getSelectedFields(
            info,
            fieldNodes || info.fieldNodes,
            currentParentType
          );
          const executionContext = { info, selectedFields: selectedFields2 };
          return executionAsyncContext.run(executionContext, () => {
            const fieldDef = info.parentType.getFields()[info.fieldName];
            const orderedArgs = fieldDef ? fieldDef.args.map(
              (arg) => args[arg.name] !== void 0 ? args[arg.name] : arg.defaultValue
            ) : [];
            return wrapResolver(
              resolver(...orderedArgs),
              executionContext,
              fieldNodes || info.fieldNodes,
              currentParentType
            );
          });
        };
      }
      const selectedFields = getSelectedFields(
        context.info,
        fieldNodes || context.info.fieldNodes,
        parentType
      );
      if (selectedFields.length === 0) {
        return resolver;
      }
      const result = {};
      for (const { name, fieldNodes: childNodes, returnType } of selectedFields) {
        const hasAliases = childNodes.some((node) => node.alias !== void 0);
        if (hasAliases) {
          result[name] = (args, ctx, info) => {
            const aliasKey = info.fieldNodes[0].alias?.value;
            const schemaKey = info.fieldName;
            if (aliasKey && resolver[aliasKey] !== void 0) {
              return wrapResolver(
                resolver[aliasKey],
                context,
                info.fieldNodes,
                returnType
              );
            }
            const schemaValue = resolver[schemaKey];
            if (schemaValue !== void 0) {
              return wrapResolver(schemaValue, context, info.fieldNodes, returnType);
            }
            return void 0;
          };
        } else {
          const rawValue = resolver[name];
          if (rawValue !== void 0) {
            result[name] = wrapResolver(rawValue, context, childNodes, returnType);
          }
        }
      }
      return result;
      return result;
    };
    resolversToGraphQLResolvers = (resolvers, configureContext) => {
      const rootGraphqlResolver = (resolver) => async (_, args, ctx, info) => {
        return Sentry.withScope(async (scope) => {
          const ctx2 = asyncContext.getStore();
          if (!ctx2) {
            consola.warn(
              "Context is not defined. Make sure AsyncLocalStorage is supported in your environment."
            );
          }
          ctx2?.set("graphqlResolveInfo", info);
          const auth = ctx2?.get("auth");
          if (auth?.user) {
            scope.setUser({
              id: auth.user.sub,
              username: auth.user.preferred_username,
              email: auth.user.email,
              details: auth.user
            });
          }
          const rootParentType = getNamedType(info.returnType);
          const selectedFields = getSelectedFields(
            info,
            info.fieldNodes,
            rootParentType
          );
          const executionContext = { info, selectedFields };
          return executionAsyncContext.run(executionContext, async () => {
            const wrapped = wrapResolver(
              resolver,
              executionContext,
              info.fieldNodes,
              rootParentType
            );
            if (typeof wrapped === "function") {
              return wrapped(args, ctx2, info);
            }
            return wrapped;
          });
        });
      };
      const graphqlResolvers = {};
      if (resolvers.Query && Object.keys(resolvers.Query).length > 0) {
        for (const [key, value] of Object.entries(resolvers.Query)) {
          if (!graphqlResolvers.Query) {
            graphqlResolvers.Query = {};
          }
          graphqlResolvers.Query[key] = rootGraphqlResolver(value);
        }
      }
      if (resolvers.Mutation && Object.keys(resolvers.Mutation).length > 0) {
        if (!graphqlResolvers.Mutation) {
          graphqlResolvers.Mutation = {};
        }
        for (const [key, value] of Object.entries(resolvers.Mutation)) {
          graphqlResolvers.Mutation[key] = rootGraphqlResolver(value);
        }
      }
      if (resolvers.Subscription && Object.keys(resolvers.Subscription).length > 0) {
        if (!graphqlResolvers.Subscription) {
          graphqlResolvers.Subscription = {};
        }
        for (const [key, value] of Object.entries(resolvers.Subscription)) {
          graphqlResolvers.Subscription[key] = {
            subscribe: rootGraphqlResolver(value),
            resolve: (payload) => payload
          };
        }
      }
      if (!graphqlResolvers.Query) {
        throw new Error(`At least one 'Query' resolver must be provided.

Example:

export const graphql = {
  Query: {
    // Define at least one query resolver here
    hello: () => 'world'
  }
}
`);
      }
      for (const key of Object.keys(resolvers)) {
        if (key !== "Query" && key !== "Mutation" && key !== "Subscription") {
          graphqlResolvers[key] = resolvers[key];
        }
      }
      return graphqlResolvers;
    };
    ServiceError = class extends GraphQLError {
      extensions;
      constructor(message, extensions, error) {
        super(message, {
          originalError: error
        });
        this.extensions = extensions;
        this.cause = error;
      }
    };
  }
});

// src/plugins/use-sentry.ts
import { Kind as Kind2, print } from "graphql";
import {
  getDocumentString,
  handleStreamOrSingleExecutionResult,
  isOriginalGraphQLError
} from "@envelop/core";
import * as Sentry2 from "@sentry/node";
var defaultSkipError, useSentry;
var init_use_sentry = __esm({
  "src/plugins/use-sentry.ts"() {
    "use strict";
    defaultSkipError = isOriginalGraphQLError;
    useSentry = (options = {}) => {
      function pick(key, defaultValue) {
        return options[key] ?? defaultValue;
      }
      const startTransaction = pick("startTransaction", true);
      const includeRawResult = pick("includeRawResult", false);
      const includeExecuteVariables = pick("includeExecuteVariables", false);
      const renameTransaction = pick("renameTransaction", false);
      const skipOperation = pick("skip", () => false);
      const skipError = pick("skipError", defaultSkipError);
      const eventIdKey = options.eventIdKey === null ? null : "sentryEventId";
      function addEventId(err, eventId) {
        if (eventIdKey !== null && eventId !== null) {
          err.extensions[eventIdKey] = eventId;
        }
        return err;
      }
      return {
        onExecute({ args }) {
          if (skipOperation(args)) {
            return;
          }
          const rootOperation = args.document.definitions.find(
            (o) => o.kind === Kind2.OPERATION_DEFINITION
          );
          const operationType = rootOperation.operation;
          const document = getDocumentString(args.document, print);
          const opName = args.operationName || rootOperation.name?.value || "Anonymous Operation";
          const addedTags = options.appendTags && options.appendTags(args) || {};
          const traceparentData = options.traceparentData && options.traceparentData(args) || {};
          const transactionName = options.transactionName ? options.transactionName(args) : opName;
          const op = options.operationName ? options.operationName(args) : "execute";
          const tags = {
            operationName: opName,
            operation: operationType,
            ...addedTags
          };
          if (options.configureScope) {
            options.configureScope(args, Sentry2.getCurrentScope());
          }
          return {
            onExecuteDone(payload) {
              const handleResult = ({
                result,
                setResult
              }) => {
                Sentry2.startSpanManual(
                  {
                    op,
                    name: opName,
                    attributes: tags
                  },
                  (span) => {
                    if (renameTransaction) {
                      span.updateName(transactionName);
                    }
                    span.setAttribute("document", document);
                    if (includeRawResult) {
                      span.setAttribute("result", JSON.stringify(result));
                    }
                    if (result.errors && result.errors.length > 0) {
                      Sentry2.withScope((scope) => {
                        scope.setTransactionName(opName);
                        scope.setTag("operation", operationType);
                        scope.setTag("operationName", opName);
                        scope.setExtra("document", document);
                        scope.setTags(addedTags || {});
                        if (includeRawResult) {
                          scope.setExtra("result", result);
                        }
                        if (includeExecuteVariables) {
                          scope.setExtra("variables", args.variableValues);
                        }
                        const errors = result.errors?.map((err) => {
                          if (skipError(err) === true) {
                            return err;
                          }
                          const errorPath = (err.path ?? []).map(
                            (v) => typeof v === "number" ? "$index" : v
                          ).join(" > ");
                          if (errorPath) {
                            scope.addBreadcrumb({
                              category: "execution-path",
                              message: errorPath,
                              level: "debug"
                            });
                          }
                          const eventId = Sentry2.captureException(
                            err.originalError,
                            {
                              fingerprint: [
                                "graphql",
                                errorPath,
                                opName,
                                operationType
                              ],
                              contexts: {
                                GraphQL: {
                                  operationName: opName,
                                  operationType,
                                  variables: args.variableValues
                                }
                              }
                            }
                          );
                          return addEventId(err, eventId);
                        });
                        setResult({
                          ...result,
                          errors
                        });
                      });
                    }
                    span.end();
                  }
                );
              };
              return handleStreamOrSingleExecutionResult(payload, handleResult);
            }
          };
        }
      };
    };
  }
});

// package.json
var version;
var init_package = __esm({
  "package.json"() {
    version = "3.0.0-canary-20260317113404.1a39ad4b34ee59425656d7efe6deca94c22a84a8";
  }
});

// src/plugins/use-unhandled-route.ts
import { html } from "hono/html";
function useUnhandledRoute() {
  return {
    setup: (app2) => {
      app2.notFound((c) => {
        return c.html(
          html`<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Welcome to Pylon</title>
<link
rel="icon"
href="https://pylon.cronit.io/favicon/favicon.ico"
/>
<style>
body,
html {
padding: 0;
margin: 0;
height: 100%;
font-family:
  'Inter',
  -apple-system,
  BlinkMacSystemFont,
  'Segoe UI',
  'Roboto',
  'Oxygen',
  'Ubuntu',
  'Cantarell',
  'Fira Sans',
  'Droid Sans',
  'Helvetica Neue',
  sans-serif;
color: white;
background-color: black;
}

main > section.hero {
display: flex;
height: 90vh;
justify-content: center;
align-items: center;
flex-direction: column;
}

.logo {
display: flex;
align-items: center;
}

.logo-svg {
width: 100%
}

.buttons {
margin-top: 24px;
}

h1 {
font-size: 80px;
}

h2 {
color: #888;
max-width: 50%;
margin-top: 0;
text-align: center;
}

a {
color: #fff;
text-decoration: none;
margin-left: 10px;
margin-right: 10px;
font-weight: bold;
transition: color 0.3s ease;
padding: 4px;
overflow: visible;
}

a.graphiql:hover {
color: rgba(255, 0, 255, 0.7);
}
a.docs:hover {
color: rgba(28, 200, 238, 0.7);
}
a.tutorial:hover {
color: rgba(125, 85, 245, 0.7);
}
svg {
margin-right: 24px;
}

.not-what-your-looking-for {
margin-top: 5vh;
}

.not-what-your-looking-for > * {
margin-left: auto;
margin-right: auto;
}

.not-what-your-looking-for > p {
text-align: center;
}

.not-what-your-looking-for > h2 {
color: #464646;
}

.not-what-your-looking-for > p {
max-width: 600px;
line-height: 1.3em;
}

.not-what-your-looking-for > pre {
max-width: 300px;
}
</style>
</head>
<body id="body">
<main>
<section class="hero">
<div class="logo">
  <div>
    <svg class="logo-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" zoomAndPan="magnify" viewBox="0 0 286.5 121.500001" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><g></g><clipPath id="38f6fcde47"><path d="M 0.339844 42 L 10 42 L 10 79 L 0.339844 79 Z M 0.339844 42 " clip-rule="nonzero"></path></clipPath><clipPath id="af000f7256"><path d="M 64 23.925781 L 72.789062 23.925781 L 72.789062 96.378906 L 64 96.378906 Z M 64 23.925781 " clip-rule="nonzero"></path></clipPath></defs><g fill="currentColor" fill-opacity="1"><g transform="translate(107.11969, 78.49768)"><g><path d="M 10.078125 -25.046875 C 11.109375 -26.398438 12.507812 -27.535156 14.28125 -28.453125 C 16.0625 -29.378906 18.070312 -29.84375 20.3125 -29.84375 C 22.863281 -29.84375 25.195312 -29.210938 27.3125 -27.953125 C 29.425781 -26.691406 31.085938 -24.921875 32.296875 -22.640625 C 33.503906 -20.367188 34.109375 -17.757812 34.109375 -14.8125 C 34.109375 -11.863281 33.503906 -9.222656 32.296875 -6.890625 C 31.085938 -4.566406 29.425781 -2.753906 27.3125 -1.453125 C 25.195312 -0.160156 22.863281 0.484375 20.3125 0.484375 C 18.070312 0.484375 16.078125 0.03125 14.328125 -0.875 C 12.585938 -1.78125 11.171875 -2.910156 10.078125 -4.265625 L 10.078125 13.96875 L 4 13.96875 L 4 -29.359375 L 10.078125 -29.359375 Z M 27.921875 -14.8125 C 27.921875 -16.84375 27.503906 -18.59375 26.671875 -20.0625 C 25.835938 -21.539062 24.734375 -22.660156 23.359375 -23.421875 C 21.992188 -24.179688 20.53125 -24.5625 18.96875 -24.5625 C 17.445312 -24.5625 16 -24.171875 14.625 -23.390625 C 13.257812 -22.609375 12.160156 -21.472656 11.328125 -19.984375 C 10.492188 -18.492188 10.078125 -16.734375 10.078125 -14.703125 C 10.078125 -12.679688 10.492188 -10.914062 11.328125 -9.40625 C 12.160156 -7.894531 13.257812 -6.75 14.625 -5.96875 C 16 -5.1875 17.445312 -4.796875 18.96875 -4.796875 C 20.53125 -4.796875 21.992188 -5.191406 23.359375 -5.984375 C 24.734375 -6.785156 25.835938 -7.953125 26.671875 -9.484375 C 27.503906 -11.015625 27.921875 -12.789062 27.921875 -14.8125 Z M 27.921875 -14.8125 "></path></g></g></g><g fill="currentColor" fill-opacity="1"><g transform="translate(143.259256, 78.49768)"><g><path d="M 30.4375 -29.359375 L 12.421875 13.796875 L 6.125 13.796875 L 12.09375 -0.484375 L 0.53125 -29.359375 L 7.296875 -29.359375 L 15.5625 -6.984375 L 24.140625 -29.359375 Z M 30.4375 -29.359375 "></path></g></g></g><g fill="currentColor" fill-opacity="1"><g transform="translate(174.281707, 78.49768)"><g><path d="M 10.078125 -39.4375 L 10.078125 0 L 4 0 L 4 -39.4375 Z M 10.078125 -39.4375 "></path></g></g></g><g fill="currentColor" fill-opacity="1"><g transform="translate(188.353752, 78.49768)"><g><path d="M 16.734375 0.484375 C 13.960938 0.484375 11.457031 -0.144531 9.21875 -1.40625 C 6.976562 -2.664062 5.21875 -4.441406 3.9375 -6.734375 C 2.664062 -9.035156 2.03125 -11.691406 2.03125 -14.703125 C 2.03125 -17.691406 2.6875 -20.335938 4 -22.640625 C 5.3125 -24.953125 7.101562 -26.726562 9.375 -27.96875 C 11.65625 -29.21875 14.195312 -29.84375 17 -29.84375 C 19.8125 -29.84375 22.351562 -29.21875 24.625 -27.96875 C 26.894531 -26.726562 28.6875 -24.953125 30 -22.640625 C 31.320312 -20.335938 31.984375 -17.691406 31.984375 -14.703125 C 31.984375 -11.722656 31.304688 -9.078125 29.953125 -6.765625 C 28.597656 -4.453125 26.757812 -2.664062 24.4375 -1.40625 C 22.113281 -0.144531 19.546875 0.484375 16.734375 0.484375 Z M 16.734375 -4.796875 C 18.296875 -4.796875 19.757812 -5.164062 21.125 -5.90625 C 22.5 -6.65625 23.613281 -7.773438 24.46875 -9.265625 C 25.320312 -10.765625 25.75 -12.578125 25.75 -14.703125 C 25.75 -16.835938 25.335938 -18.640625 24.515625 -20.109375 C 23.703125 -21.585938 22.617188 -22.695312 21.265625 -23.4375 C 19.910156 -24.1875 18.453125 -24.5625 16.890625 -24.5625 C 15.328125 -24.5625 13.878906 -24.1875 12.546875 -23.4375 C 11.210938 -22.695312 10.15625 -21.585938 9.375 -20.109375 C 8.59375 -18.640625 8.203125 -16.835938 8.203125 -14.703125 C 8.203125 -11.546875 9.007812 -9.101562 10.625 -7.375 C 12.25 -5.65625 14.285156 -4.796875 16.734375 -4.796875 Z M 16.734375 -4.796875 "></path></g></g></g><g fill="currentColor" fill-opacity="1"><g transform="translate(222.361196, 78.49768)"><g><path d="M 18.8125 -29.84375 C 21.125 -29.84375 23.191406 -29.363281 25.015625 -28.40625 C 26.847656 -27.445312 28.28125 -26.023438 29.3125 -24.140625 C 30.34375 -22.253906 30.859375 -19.984375 30.859375 -17.328125 L 30.859375 0 L 24.84375 0 L 24.84375 -16.421875 C 24.84375 -19.046875 24.179688 -21.054688 22.859375 -22.453125 C 21.546875 -23.859375 19.753906 -24.5625 17.484375 -24.5625 C 15.210938 -24.5625 13.410156 -23.859375 12.078125 -22.453125 C 10.742188 -21.054688 10.078125 -19.046875 10.078125 -16.421875 L 10.078125 0 L 4 0 L 4 -29.359375 L 10.078125 -29.359375 L 10.078125 -26.015625 C 11.066406 -27.222656 12.332031 -28.160156 13.875 -28.828125 C 15.425781 -29.503906 17.070312 -29.84375 18.8125 -29.84375 Z M 18.8125 -29.84375 "></path></g></g></g><path fill="currentColor" d="M 53.359375 31.652344 L 53.359375 88.6875 L 62.410156 90.859375 L 62.410156 29.484375 Z M 53.359375 31.652344 " fill-opacity="1" fill-rule="nonzero"></path><g clip-path="url(#38f6fcde47)"><path fill="currentColor" d="M 0.339844 47.433594 L 0.339844 72.910156 C 0.339844 73.34375 0.410156 73.769531 0.554688 74.179688 C 0.699219 74.59375 0.90625 74.96875 1.175781 75.3125 C 1.445312 75.65625 1.765625 75.945312 2.132812 76.179688 C 2.503906 76.414062 2.898438 76.582031 3.324219 76.683594 L 9.390625 78.140625 L 9.390625 42.195312 L 3.3125 43.660156 C 2.890625 43.761719 2.492188 43.929688 2.125 44.164062 C 1.761719 44.402344 1.441406 44.6875 1.171875 45.03125 C 0.902344 45.375 0.695312 45.75 0.554688 46.164062 C 0.410156 46.574219 0.339844 46.996094 0.339844 47.433594 Z M 0.339844 47.433594 " fill-opacity="1" fill-rule="nonzero"></path></g><g clip-path="url(#af000f7256)"><path fill="currentColor" d="M 64.996094 95.085938 L 64.996094 25.253906 C 64.996094 25.082031 65.027344 24.917969 65.09375 24.761719 C 65.160156 24.601562 65.253906 24.460938 65.375 24.339844 C 65.496094 24.21875 65.636719 24.125 65.792969 24.0625 C 65.953125 23.996094 66.117188 23.960938 66.289062 23.960938 L 71.460938 23.960938 C 71.632812 23.960938 71.796875 23.996094 71.957031 24.0625 C 72.113281 24.125 72.253906 24.21875 72.375 24.339844 C 72.496094 24.460938 72.589844 24.601562 72.65625 24.761719 C 72.722656 24.917969 72.753906 25.082031 72.753906 25.253906 L 72.753906 95.085938 C 72.753906 95.257812 72.722656 95.421875 72.65625 95.582031 C 72.589844 95.738281 72.496094 95.878906 72.375 96 C 72.253906 96.121094 72.113281 96.214844 71.957031 96.28125 C 71.796875 96.347656 71.632812 96.378906 71.460938 96.378906 L 66.289062 96.378906 C 66.117188 96.378906 65.953125 96.347656 65.792969 96.28125 C 65.636719 96.214844 65.496094 96.121094 65.375 96 C 65.253906 95.878906 65.160156 95.738281 65.09375 95.582031 C 65.027344 95.421875 64.996094 95.257812 64.996094 95.085938 Z M 64.996094 95.085938 " fill-opacity="1" fill-rule="nonzero"></path></g><path fill="currentColor" d="M 22.320312 81.238281 L 22.320312 39.101562 L 11.976562 41.585938 L 11.976562 78.757812 Z M 22.320312 81.238281 " fill-opacity="1" fill-rule="nonzero"></path><path fill="currentColor" d="M 50.769531 88.066406 L 50.769531 32.277344 L 37.839844 35.378906 L 37.839844 84.960938 Z M 50.769531 88.066406 " fill-opacity="1" fill-rule="nonzero"></path><path fill="currentColor" d="M 24.90625 81.863281 L 35.253906 84.34375 L 35.253906 35.996094 L 24.90625 38.480469 Z M 24.90625 81.863281 " fill-opacity="1" fill-rule="nonzero"></path></svg>
  </div>
  <p>Version: ${version}</p>
</div>
<h2>Enables TypeScript developers to easily build GraphQL APIs</h2>
<div class="buttons">
  <a href="https://pylon.cronit.io/docs" class="docs"
    >Read the Docs</add
  >
  <a href="/graphql" class="graphiql">Visit GraphiQL</a>
  <a href="/viewer" class="graphiql">Visit Viewer</a>
</div>
</section>
<section class="not-what-your-looking-for">
<h2>Not the page you are looking for? 👀</h2>
<p>
  This page is shown be default whenever a 404 is hit.<br />You can disable this by behavior
  via the <code>landingPage</code> option in the Pylon config. Edit the <code>src/index.ts</code> file
  and add the following code:
</p>
<pre>
  <code>
export const config: PylonConfig = {
  landingPage: false
}
  </code>
</pre>

<p>
  When you define a route, this page will no longer be shown. For example, the following code
will show a "Hello, world!" message at the root of your app:
</p>
<pre>
  <code>
import {app} from '@getcronit/pylon'

app.get("/", c => {
  return c.text("Hello, world!")
})
  </code>
</pre>
</section>
</main>
</body>
</html>`,
          404
        );
      });
    }
  };
}
var init_use_unhandled_route = __esm({
  "src/plugins/use-unhandled-route.ts"() {
    "use strict";
    init_package();
  }
});

// src/plugins/use-viewer.ts
import { html as html2 } from "hono/html";
function useViewer() {
  return {
    setup: (app2) => {
      app2.get("/viewer", async (c) => {
        return c.html(
          await html2`
            <!DOCTYPE html>
            <html>
              <head>
                <title>Pylon Viewer</title>
                <script src="https://cdn.jsdelivr.net/npm/react@16/umd/react.production.min.js"></script>
                <script src="https://cdn.jsdelivr.net/npm/react-dom@16/umd/react-dom.production.min.js"></script>

                <link
                  rel="stylesheet"
                  href="https://cdn.jsdelivr.net/npm/graphql-voyager/dist/voyager.css"
                />
                <style>
                    body {
                      padding: 0;
                      margin: 0;
                      width: 100%;
                      height: 100vh;
                      overflow: hidden;
                    }

                    #voyager {
                      height: 100%;
                      position: relative;
                    }
                  }
                </style>
                <script src="https://cdn.jsdelivr.net/npm/graphql-voyager/dist/voyager.min.js"></script>
              </head>
              <body>
                <div id="voyager">Loading...</div>
                <script>
                  function introspectionProvider(introspectionQuery) {
                    // ... do a call to server using introspectionQuery provided
                    // or just return pre-fetched introspection

                    // Endpoint is current path instead of root/graphql
                    const endpoint = window.location.pathname.replace(
                      '/viewer',
                      '/graphql'
                    )

                    return fetch(endpoint, {
                      method: 'post',
                      headers: {
                        'Content-Type': 'application/json'
                      },
                      body: JSON.stringify({query: introspectionQuery})
                    }).then(response => response.json())
                  }

                  // Render <Voyager />
                  GraphQLVoyager.init(document.getElementById('voyager'), {
                    introspection: introspectionProvider
                  })
                </script>
              </body>
            </html>
          `
        );
      });
    }
  };
}
var init_use_viewer = __esm({
  "src/plugins/use-viewer.ts"() {
    "use strict";
  }
});

// src/app/pylon-handler.ts
import { GraphQLScalarType, Kind as Kind3 } from "graphql";
import {
  DateTimeISOResolver,
  GraphQLVoid,
  JSONObjectResolver,
  JSONResolver
} from "graphql-scalars";
import { createSchema, createYoga } from "graphql-yoga";
import { useDisableIntrospection } from "@graphql-yoga/plugin-disable-introspection";
import { readFileSync } from "fs";
import path from "path";
var resolveLazyObject, loadPluginsMiddleware, executeConfig, handler;
var init_pylon_handler = __esm({
  "src/app/pylon-handler.ts"() {
    "use strict";
    init_app();
    init_define_pylon();
    init_use_sentry();
    init_use_unhandled_route();
    init_use_viewer();
    resolveLazyObject = (obj) => {
      return typeof obj === "function" ? obj() : obj;
    };
    loadPluginsMiddleware = async (plugins) => {
      for (const plugin of plugins) {
        await plugin.setup?.(app);
        if (plugin.middleware) {
          pluginsMiddleware.push(plugin.middleware);
        }
      }
    };
    executeConfig = async (config, args) => {
      const plugins = [useSentry(), useViewer(), ...config?.plugins || []];
      if (config?.landingPage ?? true) {
        plugins.push(useUnhandledRoute());
      }
      if (config?.graphiql === false) {
        plugins.push(useDisableIntrospection());
      }
      const pluginsStrategy = args?.pluginsStrategy || "first";
      await loadPluginsMiddleware(
        plugins.filter((p) => {
          if (!p.strategy) {
            p.strategy = "first";
          }
          return p.strategy === pluginsStrategy;
        })
      );
      config.plugins = plugins;
      app.config = config;
    };
    handler = (options) => {
      let {
        typeDefs,
        resolvers,
        graphql: graphql$
      } = options;
      const graphql = resolveLazyObject(graphql$);
      const config = app.config;
      if (!typeDefs) {
        const schemaPath = path.join(process.cwd(), ".pylon", "schema.graphql");
        if (schemaPath) {
          typeDefs = readFileSync(schemaPath, "utf-8");
        }
      }
      if (!typeDefs) {
        throw new Error("No schema provided.");
      }
      if (!resolvers) {
        const resolversPath = path.join(process.cwd(), ".pylon", "resolvers.js");
        if (resolversPath) {
          resolvers = __require(resolversPath).resolvers;
        }
      }
      const graphqlResolvers = resolversToGraphQLResolvers(graphql);
      const schema = createSchema({
        typeDefs,
        resolvers: {
          ...graphqlResolvers,
          ...resolvers,
          // Transforms a date object to a timestamp
          Date: new GraphQLScalarType({
            name: "Date",
            description: "Date represented as an ISO-8601 string",
            serialize: DateTimeISOResolver.serialize,
            parseValue: DateTimeISOResolver.parseValue,
            parseLiteral: DateTimeISOResolver.parseLiteral
          }),
          JSON: JSONResolver,
          JSONObject: JSONObjectResolver,
          Void: GraphQLVoid,
          Number: new GraphQLScalarType({
            name: "Number",
            description: "Custom scalar that handles both integers and floats",
            // Parsing input from query variables
            parseValue(value) {
              if (typeof value !== "number") {
                throw new TypeError(`Value is not a number: ${value}`);
              }
              return value;
            },
            // Validation when sending from client (input literals)
            parseLiteral(ast) {
              if (ast.kind === Kind3.INT || ast.kind === Kind3.FLOAT) {
                return parseFloat(ast.value);
              }
              throw new TypeError(
                `Value is not a valid number or float: ${"value" in ast ? ast.value : ast}`
              );
            },
            // Serialize output to be sent to the client
            serialize(value) {
              if (typeof value !== "number") {
                throw new TypeError(`Value is not a number: ${value}`);
              }
              return value;
            }
          })
        }
      });
      const yoga = createYoga({
        graphqlEndpoint: "/graphql",
        ...config,
        landingPage: false,
        graphiql: config?.graphiql !== false ? (req) => {
          return {
            shouldPersistHeaders: true,
            title: "Pylon Playground",
            defaultQuery: `# Welcome to the Pylon Playground!`
          };
        } : false,
        schema
      });
      const handler2 = async (c, next) => {
        let executionContext = {};
        try {
          executionContext = c.executionCtx;
        } catch (e) {
        }
        const response = await yoga.fetch(c.req.raw, c.env, executionContext);
        if (response.status === 404) {
          return next();
        }
        const version2 = globalThis.__PYLON_VERSION__;
        if (version2) {
          c.header("X-Pylon-Version", version2);
        }
        return c.newResponse(response.body, response);
      };
      return handler2;
    };
  }
});

// src/create-decorator.ts
function createDecorator(callback) {
  function MyDecorator(arg1, propertyKey, descriptor) {
    if (descriptor) {
      const originalMethod = descriptor.value;
      descriptor.value = async function(...args) {
        await callback(...args);
        return originalMethod.apply(this, args);
      };
      return descriptor;
    } else {
      if (!descriptor) {
        if (propertyKey === void 0) {
          const originalFunction = arg1;
          return async function(...args) {
            await callback(...args);
            return originalFunction(...args);
          };
        }
        let value = arg1[propertyKey];
        Object.defineProperty(arg1, propertyKey, {
          get: function() {
            return async function(...args) {
              await callback(...args);
              if (typeof value === "function") {
                return value(...args);
              }
              return value;
            };
          },
          set: function(newValue) {
            value = newValue;
          },
          enumerable: true,
          configurable: true
        });
        return;
      }
    }
  }
  return MyDecorator;
}
var init_create_decorator = __esm({
  "src/create-decorator.ts"() {
    "use strict";
  }
});

// src/get-env.ts
function getEnv() {
  const start = Date.now();
  const skipTracing = arguments[0] === true;
  try {
    const context = asyncContext.getStore();
    const ctx = context.env || process.env || {};
    ctx.NODE_ENV = ctx.NODE_ENV || process.env.NODE_ENV || "development";
    return ctx;
  } catch {
    return process.env;
  } finally {
    if (!skipTracing) {
    }
  }
}
var init_get_env = __esm({
  "src/get-env.ts"() {
    "use strict";
    init_context();
  }
});

// src/plugins/use-auth/import-private-key.ts
import * as crypto from "crypto";
function str2ab(str) {
  const buf = new ArrayBuffer(str.length);
  const bufView = new Uint8Array(buf);
  for (let i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}
function importPKCS8PrivateKey(pem) {
  const pemHeader = "-----BEGIN PRIVATE KEY-----";
  const pemFooter = "-----END PRIVATE KEY-----";
  const pemContents = pem.substring(
    pemHeader.length,
    pem.length - pemFooter.length - 1
  );
  const binaryDerString = atob(pemContents);
  const binaryDer = str2ab(binaryDerString);
  return crypto.subtle.importKey(
    "pkcs8",
    binaryDer,
    {
      name: "RSASSA-PKCS1-v1_5",
      hash: "SHA-256"
    },
    true,
    ["sign"]
  );
}
var convertPKCS1ToPKCS8, importPrivateKey;
var init_import_private_key = __esm({
  "src/plugins/use-auth/import-private-key.ts"() {
    "use strict";
    convertPKCS1ToPKCS8 = (pkcs1) => {
      const key = crypto.createPrivateKey(pkcs1);
      return key.export({
        type: "pkcs8",
        format: "pem"
      });
    };
    importPrivateKey = async (pkcs1Pem) => {
      const pkcs8Pem = convertPKCS1ToPKCS8(pkcs1Pem);
      return await importPKCS8PrivateKey(pkcs8Pem);
    };
  }
});

// src/plugins/use-auth/use-auth.ts
import { promises as fs } from "fs";
import { deleteCookie, getCookie, setCookie } from "hono/cookie";
import { HTTPException } from "hono/http-exception";
import * as openid from "openid-client";
import path2 from "path";
function useAuth(args) {
  const { issuer, endpoint = "/auth", keyPath = "key.json" } = args;
  const loginPath = `${endpoint}/login`;
  const logoutPath = `${endpoint}/logout`;
  const callbackPath = `${endpoint}/callback`;
  return {
    middleware: async (ctx, next) => {
      const openidConfig = await bootstrapAuth(issuer, keyPath);
      ctx.set("auth", { openidConfig });
      const authCookieToken = getCookie(ctx, "pylon-auth");
      const authHeader = ctx.req.header("Authorization");
      const authQueryToken = ctx.req.query("token");
      if (authCookieToken || authHeader || authQueryToken) {
        let token;
        if (authHeader) {
          const [type, value] = authHeader.split(" ");
          if (type === "Bearer") {
            token = value;
          }
        } else if (authQueryToken) {
          token = authQueryToken;
        } else if (authCookieToken) {
          token = authCookieToken;
        }
        if (!token) {
          throw new PylonAuthException(401, {
            message: "Invalid token"
          });
        }
        const introspection = await openid.tokenIntrospection(
          openidConfig,
          token,
          {
            scope: "openid email profile"
          }
        );
        if (!introspection.active) {
          throw new PylonAuthException(401, {
            message: "Token is not active"
          });
        }
        if (!introspection.sub) {
          throw new PylonAuthException(401, {
            message: "Token is missing subject"
          });
        }
        const userInfo = await openid.fetchUserInfo(
          openidConfig,
          token,
          introspection.sub
        );
        const roles = Object.keys(
          introspection["urn:zitadel:iam:org:projects:roles"]?.valueOf() || {}
        );
        ctx.set("auth", {
          user: {
            ...userInfo,
            roles
          },
          openidConfig
        });
        return next();
      }
    },
    setup(app2) {
      app2.get(loginPath, async (ctx) => {
        const openidConfig = ctx.get("auth").openidConfig;
        const codeVerifier = openid.randomPKCECodeVerifier();
        const codeChallenge = await openid.calculatePKCECodeChallenge(
          codeVerifier
        );
        setCookie(ctx, "pylon_code_verifier", codeVerifier, {
          httpOnly: true,
          maxAge: 300
          // 5 minutes
        });
        let scope = "openid profile email urn:zitadel:iam:user:resourceowner urn:zitadel:iam:org:projects:roles";
        const parameters = {
          scope,
          code_challenge: codeChallenge,
          code_challenge_method: "S256",
          redirect_uri: new URL(ctx.req.url).origin + "/auth/callback",
          state: openid.randomState()
        };
        const authorizationUrl = openid.buildAuthorizationUrl(
          openidConfig,
          parameters
        );
        return ctx.redirect(authorizationUrl);
      });
      app2.get(logoutPath, async (ctx) => {
        deleteCookie(ctx, "pylon-auth");
        return ctx.redirect("/");
      });
      app2.get(callbackPath, async (ctx) => {
        const openidConfig = ctx.get("auth").openidConfig;
        const params = ctx.req.query();
        const code = params.code;
        const state = params.state;
        if (!code || !state) {
          throw new PylonAuthException(400, {
            message: "Missing authorization code or state"
          });
        }
        const codeVerifier = getCookie(ctx, "pylon_code_verifier");
        if (!codeVerifier) {
          throw new PylonAuthException(400, {
            message: "Missing code verifier"
          });
        }
        try {
          const cbUrl = new URL(ctx.req.url);
          let tokenSet = await openid.authorizationCodeGrant(
            openidConfig,
            cbUrl,
            {
              pkceCodeVerifier: codeVerifier,
              expectedState: state
            },
            cbUrl.searchParams
          );
          setCookie(ctx, `pylon-auth`, tokenSet.access_token, {
            httpOnly: true,
            maxAge: tokenSet.expires_in || 3600
            // Default to 1 hour if not specified
          });
          return ctx.redirect("/");
        } catch (error) {
          console.error("Error during token exchange:", error);
          return ctx.text("Authentication failed!", 500);
        }
      });
    }
  };
}
var loadAuthKey, openidConfigCache, bootstrapAuth, PylonAuthException;
var init_use_auth = __esm({
  "src/plugins/use-auth/use-auth.ts"() {
    "use strict";
    init_src();
    init_import_private_key();
    loadAuthKey = async (keyPath) => {
      const authKeyFilePath = path2.join(process.cwd(), keyPath);
      const env3 = getContext().env;
      if (env3.AUTH_KEY) {
        try {
          return JSON.parse(env3.AUTH_KEY);
        } catch (error) {
          throw new Error(
            "Error while reading AUTH_KEY. Make sure it is valid JSON"
          );
        }
      }
      try {
        const ketFileContent = await fs.readFile(authKeyFilePath, "utf-8");
        try {
          return JSON.parse(ketFileContent);
        } catch (error) {
          throw new Error(
            "Error while reading key file. Make sure it is valid JSON"
          );
        }
      } catch (error) {
        throw new Error("Error while reading key file. Make sure it exists");
      }
    };
    bootstrapAuth = async (issuer, keyPath) => {
      if (!openidConfigCache) {
        const authKey = await loadAuthKey(keyPath);
        openidConfigCache = await openid.discovery(
          new URL(issuer),
          authKey.clientId,
          void 0,
          openid.PrivateKeyJwt({
            key: await importPrivateKey(authKey.key),
            kid: authKey.keyId
          })
        );
      }
      return openidConfigCache;
    };
    PylonAuthException = class extends HTTPException {
      // Same constructor as HTTPException
      constructor(...args) {
        args[1] = {
          ...args[1],
          message: `PylonAuthException: ${args[1]?.message}`
        };
        super(...args);
      }
    };
  }
});

// src/plugins/use-auth/auth-require.ts
import { env as env2 } from "hono/adapter";
import { HTTPException as HTTPException2 } from "hono/http-exception";
function requireAuth(checks) {
  const checkAuth = async (c) => {
    const ctx = await c;
    try {
      await authMiddleware(checks)(ctx, async () => {
      });
    } catch (e) {
      if (e instanceof HTTPException2) {
        if (e.status === 401) {
          throw new ServiceError(e.message, {
            statusCode: 401,
            code: "AUTH_REQUIRED"
          });
        } else if (e.status === 403) {
          const res = e.getResponse();
          throw new ServiceError(res.statusText, {
            statusCode: res.status,
            code: "AUTHORIZATION_REQUIRED",
            details: {
              missingRoles: res.headers.get("Missing-Roles")?.split(","),
              obtainedRoles: res.headers.get("Obtained-Roles")?.split(",")
            }
          });
        } else {
          throw e;
        }
      }
      throw e;
    }
  };
  return createDecorator(async () => {
    const ctx = getContext();
    await checkAuth(ctx);
  });
}
var authMiddleware;
var init_auth_require = __esm({
  "src/plugins/use-auth/auth-require.ts"() {
    "use strict";
    init_define_pylon();
    init_context();
    init_create_decorator();
    authMiddleware = (checks = {}) => {
      const middleware = async (ctx, next) => {
        const AUTH_PROJECT_ID = env2(ctx).AUTH_PROJECT_ID;
        const auth = ctx.get("auth");
        if (!auth) {
          throw new HTTPException2(401, {
            message: "Authentication required"
          });
        }
        if (checks.roles && auth.user) {
          const roles = auth.user.roles;
          const hasRole = checks.roles.some((role) => {
            return roles.includes(role) || roles.includes(`${AUTH_PROJECT_ID}:${role}`);
          });
          if (!hasRole) {
            const resError = new Response("Forbidden", {
              status: 403,
              statusText: "Forbidden",
              headers: {
                "Missing-Roles": checks.roles.join(","),
                "Obtained-Roles": roles.join(",")
              }
            });
            throw new HTTPException2(resError.status, {
              res: resError
            });
          }
        }
        return next();
      };
      return middleware;
    };
  }
});

// src/plugins/use-auth/index.ts
var init_use_auth2 = __esm({
  "src/plugins/use-auth/index.ts"() {
    "use strict";
    init_use_auth();
    init_auth_require();
  }
});

// src/lib/utils.ts
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
function cn(...inputs) {
  return twMerge(clsx(inputs));
}
var init_utils = __esm({
  "src/lib/utils.ts"() {
    "use strict";
  }
});

// src/components/logo.tsx
import { jsx, jsxs } from "react/jsx-runtime";
var Logo, logo_default;
var init_logo = __esm({
  "src/components/logo.tsx"() {
    "use strict";
    init_utils();
    Logo = (props) => {
      return /* @__PURE__ */ jsxs(
        "svg",
        {
          className: cn("h-12 w-auto", props.className),
          xmlns: "http://www.w3.org/2000/svg",
          xmlnsXlink: "http://www.w3.org/1999/xlink",
          zoomAndPan: "magnify",
          viewBox: "0 0 286.5 121.500001",
          preserveAspectRatio: "xMidYMid meet",
          version: "1.0",
          children: [
            /* @__PURE__ */ jsxs("defs", { children: [
              /* @__PURE__ */ jsx("g", {}),
              /* @__PURE__ */ jsx("clipPath", { id: "38f6fcde47", children: /* @__PURE__ */ jsx(
                "path",
                {
                  d: "M 0.339844 42 L 10 42 L 10 79 L 0.339844 79 Z M 0.339844 42 ",
                  clipRule: "nonzero"
                }
              ) }),
              /* @__PURE__ */ jsx("clipPath", { id: "af000f7256", children: /* @__PURE__ */ jsx(
                "path",
                {
                  d: "M 64 23.925781 L 72.789062 23.925781 L 72.789062 96.378906 L 64 96.378906 Z M 64 23.925781 ",
                  clipRule: "nonzero"
                }
              ) })
            ] }),
            /* @__PURE__ */ jsx("g", { fill: "currentColor", fillOpacity: "1", children: /* @__PURE__ */ jsx("g", { transform: "translate(107.11969, 78.49768)", children: /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx("path", { d: "M 10.078125 -25.046875 C 11.109375 -26.398438 12.507812 -27.535156 14.28125 -28.453125 C 16.0625 -29.378906 18.070312 -29.84375 20.3125 -29.84375 C 22.863281 -29.84375 25.195312 -29.210938 27.3125 -27.953125 C 29.425781 -26.691406 31.085938 -24.921875 32.296875 -22.640625 C 33.503906 -20.367188 34.109375 -17.757812 34.109375 -14.8125 C 34.109375 -11.863281 33.503906 -9.222656 32.296875 -6.890625 C 31.085938 -4.566406 29.425781 -2.753906 27.3125 -1.453125 C 25.195312 -0.160156 22.863281 0.484375 20.3125 0.484375 C 18.070312 0.484375 16.078125 0.03125 14.328125 -0.875 C 12.585938 -1.78125 11.171875 -2.910156 10.078125 -4.265625 L 10.078125 13.96875 L 4 13.96875 L 4 -29.359375 L 10.078125 -29.359375 Z M 27.921875 -14.8125 C 27.921875 -16.84375 27.503906 -18.59375 26.671875 -20.0625 C 25.835938 -21.539062 24.734375 -22.660156 23.359375 -23.421875 C 21.992188 -24.179688 20.53125 -24.5625 18.96875 -24.5625 C 17.445312 -24.5625 16 -24.171875 14.625 -23.390625 C 13.257812 -22.609375 12.160156 -21.472656 11.328125 -19.984375 C 10.492188 -18.492188 10.078125 -16.734375 10.078125 -14.703125 C 10.078125 -12.679688 10.492188 -10.914062 11.328125 -9.40625 C 12.160156 -7.894531 13.257812 -6.75 14.625 -5.96875 C 16 -5.1875 17.445312 -4.796875 18.96875 -4.796875 C 20.53125 -4.796875 21.992188 -5.191406 23.359375 -5.984375 C 24.734375 -6.785156 25.835938 -7.953125 26.671875 -9.484375 C 27.503906 -11.015625 27.921875 -12.789062 27.921875 -14.8125 Z M 27.921875 -14.8125 " }) }) }) }),
            /* @__PURE__ */ jsx("g", { fill: "currentColor", fillOpacity: "1", children: /* @__PURE__ */ jsx("g", { transform: "translate(143.259256, 78.49768)", children: /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx("path", { d: "M 30.4375 -29.359375 L 12.421875 13.796875 L 6.125 13.796875 L 12.09375 -0.484375 L 0.53125 -29.359375 L 7.296875 -29.359375 L 15.5625 -6.984375 L 24.140625 -29.359375 Z M 30.4375 -29.359375 " }) }) }) }),
            /* @__PURE__ */ jsx("g", { fill: "currentColor", fillOpacity: "1", children: /* @__PURE__ */ jsx("g", { transform: "translate(174.281707, 78.49768)", children: /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx("path", { d: "M 10.078125 -39.4375 L 10.078125 0 L 4 0 L 4 -39.4375 Z M 10.078125 -39.4375 " }) }) }) }),
            /* @__PURE__ */ jsx("g", { fill: "currentColor", fillOpacity: "1", children: /* @__PURE__ */ jsx("g", { transform: "translate(188.353752, 78.49768)", children: /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx("path", { d: "M 16.734375 0.484375 C 13.960938 0.484375 11.457031 -0.144531 9.21875 -1.40625 C 6.976562 -2.664062 5.21875 -4.441406 3.9375 -6.734375 C 2.664062 -9.035156 2.03125 -11.691406 2.03125 -14.703125 C 2.03125 -17.691406 2.6875 -20.335938 4 -22.640625 C 5.3125 -24.953125 7.101562 -26.726562 9.375 -27.96875 C 11.65625 -29.21875 14.195312 -29.84375 17 -29.84375 C 19.8125 -29.84375 22.351562 -29.21875 24.625 -27.96875 C 26.894531 -26.726562 28.6875 -24.953125 30 -22.640625 C 31.320312 -20.335938 31.984375 -17.691406 31.984375 -14.703125 C 31.984375 -11.722656 31.304688 -9.078125 29.953125 -6.765625 C 28.597656 -4.453125 26.757812 -2.664062 24.4375 -1.40625 C 22.113281 -0.144531 19.546875 0.484375 16.734375 0.484375 Z M 16.734375 -4.796875 C 18.296875 -4.796875 19.757812 -5.164062 21.125 -5.90625 C 22.5 -6.65625 23.613281 -7.773438 24.46875 -9.265625 C 25.320312 -10.765625 25.75 -12.578125 25.75 -14.703125 C 25.75 -16.835938 25.335938 -18.640625 24.515625 -20.109375 C 23.703125 -21.585938 22.617188 -22.695312 21.265625 -23.4375 C 19.910156 -24.1875 18.453125 -24.5625 16.890625 -24.5625 C 15.328125 -24.5625 13.878906 -24.1875 12.546875 -23.4375 C 11.210938 -22.695312 10.15625 -21.585938 9.375 -20.109375 C 8.59375 -18.640625 8.203125 -16.835938 8.203125 -14.703125 C 8.203125 -11.546875 9.007812 -9.101562 10.625 -7.375 C 12.25 -5.65625 14.285156 -4.796875 16.734375 -4.796875 Z M 16.734375 -4.796875 " }) }) }) }),
            /* @__PURE__ */ jsx("g", { fill: "currentColor", fillOpacity: "1", children: /* @__PURE__ */ jsx("g", { transform: "translate(222.361196, 78.49768)", children: /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx("path", { d: "M 18.8125 -29.84375 C 21.125 -29.84375 23.191406 -29.363281 25.015625 -28.40625 C 26.847656 -27.445312 28.28125 -26.023438 29.3125 -24.140625 C 30.34375 -22.253906 30.859375 -19.984375 30.859375 -17.328125 L 30.859375 0 L 24.84375 0 L 24.84375 -16.421875 C 24.84375 -19.046875 24.179688 -21.054688 22.859375 -22.453125 C 21.546875 -23.859375 19.753906 -24.5625 17.484375 -24.5625 C 15.210938 -24.5625 13.410156 -23.859375 12.078125 -22.453125 C 10.742188 -21.054688 10.078125 -19.046875 10.078125 -16.421875 L 10.078125 0 L 4 0 L 4 -29.359375 L 10.078125 -29.359375 L 10.078125 -26.015625 C 11.066406 -27.222656 12.332031 -28.160156 13.875 -28.828125 C 15.425781 -29.503906 17.070312 -29.84375 18.8125 -29.84375 Z M 18.8125 -29.84375 " }) }) }) }),
            /* @__PURE__ */ jsx(
              "path",
              {
                fill: "currentColor",
                d: "M 53.359375 31.652344 L 53.359375 88.6875 L 62.410156 90.859375 L 62.410156 29.484375 Z M 53.359375 31.652344 ",
                fillOpacity: "1",
                fillRule: "nonzero"
              }
            ),
            /* @__PURE__ */ jsx("g", { clipPath: "url(#38f6fcde47)", children: /* @__PURE__ */ jsx(
              "path",
              {
                fill: "currentColor",
                d: "M 0.339844 47.433594 L 0.339844 72.910156 C 0.339844 73.34375 0.410156 73.769531 0.554688 74.179688 C 0.699219 74.59375 0.90625 74.96875 1.175781 75.3125 C 1.445312 75.65625 1.765625 75.945312 2.132812 76.179688 C 2.503906 76.414062 2.898438 76.582031 3.324219 76.683594 L 9.390625 78.140625 L 9.390625 42.195312 L 3.3125 43.660156 C 2.890625 43.761719 2.492188 43.929688 2.125 44.164062 C 1.761719 44.402344 1.441406 44.6875 1.171875 45.03125 C 0.902344 45.375 0.695312 45.75 0.554688 46.164062 C 0.410156 46.574219 0.339844 46.996094 0.339844 47.433594 Z M 0.339844 47.433594 ",
                fillOpacity: "1",
                fillRule: "nonzero"
              }
            ) }),
            /* @__PURE__ */ jsx("g", { clipPath: "url(#af000f7256)", children: /* @__PURE__ */ jsx(
              "path",
              {
                fill: "currentColor",
                d: "M 64.996094 95.085938 L 64.996094 25.253906 C 64.996094 25.082031 65.027344 24.917969 65.09375 24.761719 C 65.160156 24.601562 65.253906 24.460938 65.375 24.339844 C 65.496094 24.21875 65.636719 24.125 65.792969 24.0625 C 65.953125 23.996094 66.117188 23.960938 66.289062 23.960938 L 71.460938 23.960938 C 71.632812 23.960938 71.796875 23.996094 71.957031 24.0625 C 72.113281 24.125 72.253906 24.21875 72.375 24.339844 C 72.496094 24.460938 72.589844 24.601562 72.65625 24.761719 C 72.722656 24.917969 72.753906 25.082031 72.753906 25.253906 L 72.753906 95.085938 C 72.753906 95.257812 72.722656 95.421875 72.65625 95.582031 C 72.589844 95.738281 72.496094 95.878906 72.375 96 C 72.253906 96.121094 72.113281 96.214844 71.957031 96.28125 C 71.796875 96.347656 71.632812 96.378906 71.460938 96.378906 L 66.289062 96.378906 C 66.117188 96.378906 65.953125 96.347656 65.792969 96.28125 C 65.636719 96.214844 65.496094 96.121094 65.375 96 C 65.253906 95.878906 65.160156 95.738281 65.09375 95.582031 C 65.027344 95.421875 64.996094 95.257812 64.996094 95.085938 Z M 64.996094 95.085938 ",
                fillOpacity: "1",
                fillRule: "nonzero"
              }
            ) }),
            /* @__PURE__ */ jsx(
              "path",
              {
                fill: "currentColor",
                d: "M 22.320312 81.238281 L 22.320312 39.101562 L 11.976562 41.585938 L 11.976562 78.757812 Z M 22.320312 81.238281 ",
                fillOpacity: "1",
                fillRule: "nonzero"
              }
            ),
            /* @__PURE__ */ jsx(
              "path",
              {
                fill: "currentColor",
                d: "M 50.769531 88.066406 L 50.769531 32.277344 L 37.839844 35.378906 L 37.839844 84.960938 Z M 50.769531 88.066406 ",
                fillOpacity: "1",
                fillRule: "nonzero"
              }
            ),
            /* @__PURE__ */ jsx(
              "path",
              {
                fill: "currentColor",
                d: "M 24.90625 81.863281 L 35.253906 84.34375 L 35.253906 35.996094 L 24.90625 38.480469 Z M 24.90625 81.863281 ",
                fillOpacity: "1",
                fillRule: "nonzero"
              }
            )
          ]
        }
      );
    };
    logo_default = Logo;
  }
});

// src/components/global-error-page.tsx
import { useEffect } from "react";
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
function GlobalError({ error, ...rest }) {
  useEffect(() => {
    console.error("Global error:", error);
  }, [error]);
  const reset = () => {
    window.location.reload();
  };
  const manifest = globalThis.__PYLON_MANIFEST__;
  return /* @__PURE__ */ jsxs2("html", { lang: "en", children: [
    /* @__PURE__ */ jsxs2("head", { children: [
      /* @__PURE__ */ jsx2("meta", { charSet: "utf-8" }),
      /* @__PURE__ */ jsx2("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
      manifest?.["index.css"] && /* @__PURE__ */ jsx2(
        "link",
        {
          rel: "stylesheet",
          href: manifest["index.css"],
          precedence: "high"
        }
      )
    ] }),
    /* @__PURE__ */ jsx2("body", { children: /* @__PURE__ */ jsx2("div", { className: "fixed inset-0 bg-black/90 z-50 overflow-y-auto p-4 flex items-center justify-center", children: /* @__PURE__ */ jsxs2("div", { className: "w-full max-w-3xl bg-black border border-red-600 rounded-lg overflow-hidden text-white font-sans", children: [
      /* @__PURE__ */ jsx2("div", { className: "flex items-center justify-between border-b border-neutral-800 p-4", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3", children: [
        /* @__PURE__ */ jsx2("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx2(logo_default, { className: "h-8 w-auto text-white" }) }),
        /* @__PURE__ */ jsx2("div", { children: /* @__PURE__ */ jsx2("h1", { className: "text-xl font-medium text-red-500", children: "Application Crashed" }) })
      ] }) }),
      /* @__PURE__ */ jsxs2("div", { className: "p-4", children: [
        /* @__PURE__ */ jsx2("div", { className: "mb-4 text-neutral-400", children: "The application encountered a critical error and could not continue." }),
        /* @__PURE__ */ jsx2("h2", { className: "text-2xl font-bold mb-4 text-white", children: error.message || "A critical error occurred" }),
        error.digest && /* @__PURE__ */ jsxs2("div", { className: "mb-4", children: [
          /* @__PURE__ */ jsx2("h3", { className: "text-sm uppercase tracking-wider text-neutral-500 font-medium mb-2", children: "Error ID" }),
          /* @__PURE__ */ jsx2("div", { className: "bg-neutral-900 rounded-md p-3 text-neutral-300 font-mono", children: error.digest })
        ] })
      ] })
    ] }) }) })
  ] });
}
var init_global_error_page = __esm({
  "src/components/global-error-page.tsx"() {
    "use strict";
    init_logo();
  }
});

// src/components/ui/button.tsx
import { Slot } from "@radix-ui/react-slot";
import { cva } from "class-variance-authority";
import { jsx as jsx3 } from "react/jsx-runtime";
function Button({
  className,
  variant,
  size,
  asChild = false,
  ...props
}) {
  const Comp = asChild ? Slot : "button";
  return /* @__PURE__ */ jsx3(
    Comp,
    {
      "data-slot": "button",
      className: cn(buttonVariants({ variant, size, className })),
      ...props
    }
  );
}
var buttonVariants;
var init_button = __esm({
  "src/components/ui/button.tsx"() {
    "use strict";
    init_utils();
    buttonVariants = cva(
      "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
      {
        variants: {
          variant: {
            default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
            destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
            outline: "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
            secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
            ghost: "hover:bg-accent hover:text-accent-foreground",
            link: "text-primary underline-offset-4 hover:underline"
          },
          size: {
            default: "h-9 px-4 py-2 has-[>svg]:px-3",
            sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
            lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
            icon: "size-9"
          }
        },
        defaultVariants: {
          variant: "default",
          size: "default"
        }
      }
    );
  }
});

// src/components/status-page.tsx
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
var StatusPage;
var init_status_page = __esm({
  "src/components/status-page.tsx"() {
    "use strict";
    init_button();
    StatusPage = ({
      code,
      title,
      message,
      standalone = false,
      returnText = "Return to home",
      returnUrl = "/"
    }) => {
      const element = /* @__PURE__ */ jsxs3("div", { className: "flex min-h-screen w-full flex-col items-center justify-center bg-white p-4 text-center", children: [
        /* @__PURE__ */ jsx4("title", { children: title }),
        /* @__PURE__ */ jsx4("h1", { className: "mb-2 text-9xl font-thin tracking-tight text-gray-900", children: code }),
        /* @__PURE__ */ jsx4("h2", { className: "mb-6 text-xl font-light text-gray-600", children: title }),
        /* @__PURE__ */ jsx4("p", { className: "mb-8 max-w-md text-sm text-gray-500", children: message }),
        /* @__PURE__ */ jsx4(Button, { asChild: true, children: /* @__PURE__ */ jsx4("a", { href: returnUrl, children: returnText }) })
      ] });
      const manifest = globalThis.__PYLON_MANIFEST__;
      if (standalone) {
        return /* @__PURE__ */ jsxs3("html", { children: [
          /* @__PURE__ */ jsxs3("head", { children: [
            /* @__PURE__ */ jsx4("meta", { charSet: "utf-8" }),
            /* @__PURE__ */ jsx4("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
            manifest?.["index.css"] && /* @__PURE__ */ jsx4(
              "link",
              {
                rel: "stylesheet",
                href: manifest["index.css"],
                precedence: "high"
              }
            )
          ] }),
          /* @__PURE__ */ jsx4("body", { children: element })
        ] });
      }
      return element;
    };
  }
});

// src/plugins/use-pages/setup/serve-file-path.ts
import { createReadStream } from "fs";
import { stat } from "fs/promises";
import mime from "mime";
import { Readable } from "stream";
var serveFilePath;
var init_serve_file_path = __esm({
  "src/plugins/use-pages/setup/serve-file-path.ts"() {
    "use strict";
    serveFilePath = async ({
      filePath,
      context
    }) => {
      let fileStat;
      try {
        fileStat = await stat(filePath);
      } catch (error) {
        return context.notFound();
      }
      const lastModified = fileStat.mtime.toUTCString();
      const ifModifiedSince = context.req.header("If-Modified-Since");
      if (ifModifiedSince === lastModified) {
        return context.body(null, 304);
      }
      context.header("Last-Modified", lastModified);
      const contentType = mime.getType(filePath) || "application/octet-stream";
      context.header("Content-Type", contentType);
      context.header("Accept-Ranges", "bytes");
      const contentLength = fileStat.size;
      if (context.req.method === "HEAD") {
        context.header("Content-Length", contentLength.toString());
        return context.body(null, 200);
      }
      let start = 0;
      let end = contentLength - 1;
      let isPartial = false;
      const range = context.req.header("Range");
      if (range && range.startsWith("bytes=")) {
        const parts = range.replace("bytes=", "").split("-");
        const rangeStart = parts[0] ? parseInt(parts[0], 10) : 0;
        const rangeEnd = parts[1] ? parseInt(parts[1], 10) : contentLength - 1;
        if (!isNaN(rangeStart) && !isNaN(rangeEnd) && rangeStart <= rangeEnd) {
          start = rangeStart;
          end = rangeEnd;
          isPartial = true;
        }
      }
      const retrievedLength = end - start + 1;
      context.status(isPartial ? 206 : 200);
      context.header("Content-Length", retrievedLength.toString());
      if (isPartial) {
        context.header("Content-Range", `bytes ${start}-${end}/${contentLength}`);
      }
      const stream = createReadStream(filePath, { start, end });
      const webStream = Readable.toWeb(stream);
      return context.body(webStream);
    };
  }
});

// src/plugins/use-pages/setup/index.tsx
var setup_exports = {};
__export(setup_exports, {
  setup: () => setup
});
import fs2 from "fs";
import path3 from "path";
import reactServer from "react-dom/server";
import { trimTrailingSlash } from "hono/trailing-slash";
import {
  createStaticHandler,
  createStaticRouter,
  StaticRouterProvider
} from "react-router";
import { PassThrough, Readable as Readable2 } from "stream";
import { etag } from "hono/etag";
import { tmpdir } from "os";
import { pipeline } from "stream/promises";
import { __PYLON_INTERNALS_DO_NOT_USE } from "@getcronit/pylon/pages";
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
import { createHash } from "crypto";
import glob from "tiny-glob/sync.js";
import { jsx as jsx5 } from "react/jsx-runtime";
function escapeXml(unsafe) {
  return unsafe.replace(/[<>&'"]/g, (c) => {
    switch (c) {
      case "<":
        return "&lt;";
      case ">":
        return "&gt;";
      case "&":
        return "&amp;";
      case "'":
        return "&apos;";
      case '"':
        return "&quot;";
    }
    return c;
  });
}
function renderSitemapXml(items, baseUrl) {
  let xml = `<?xml version="1.0" encoding="UTF-8"?>
`;
  xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
`;
  for (const item of items) {
    const isAbsolute = item.url.startsWith("http://") || item.url.startsWith("https://");
    const loc = isAbsolute ? item.url : `${baseUrl}/${item.url.replace(/^\//, "")}`;
    xml += `  <url>
`;
    xml += `    <loc>${escapeXml(loc)}</loc>
`;
    if (item.lastmod) {
      const date = item.lastmod instanceof Date ? item.lastmod.toISOString().split("T")[0] : item.lastmod;
      xml += `    <lastmod>${escapeXml(String(date))}</lastmod>
`;
    }
    if (item.changefreq) {
      xml += `    <changefreq>${escapeXml(item.changefreq)}</changefreq>
`;
    }
    if (item.priority !== void 0) {
      xml += `    <priority>${item.priority}</priority>
`;
    }
    xml += `  </url>
`;
  }
  xml += `</urlset>`;
  return xml;
}
function renderSitemapIndexXml(items) {
  let xml = `<?xml version="1.0" encoding="UTF-8"?>
`;
  xml += `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
`;
  for (const item of items) {
    xml += `  <sitemap>
`;
    xml += `    <loc>${escapeXml(item.url)}</loc>
`;
    if (item.lastmod) {
      const date = item.lastmod instanceof Date ? item.lastmod.toISOString().split("T")[0] : item.lastmod;
      xml += `    <lastmod>${escapeXml(String(date))}</lastmod>
`;
    }
    xml += `  </sitemap>
`;
  }
  xml += `</sitemapindex>`;
  return xml;
}
var setup, IMAGE_CACHE_DIR, IS_IMAGE_CACHE_POSSIBLE, getCachedImagePath, calculateDimensions, getContentType, downloadImage;
var init_setup = __esm({
  async "src/plugins/use-pages/setup/index.tsx"() {
    "use strict";
    init_src();
    init_global_error_page();
    init_status_page();
    init_serve_file_path();
    setup = async (app2) => {
      const pagesManifestPath = path3.join(
        process.cwd(),
        ".pylon/__pylon/pages/manifest.json"
      );
      const staticManifestPath = path3.join(
        process.cwd(),
        ".pylon/__pylon/static/manifest.json"
      );
      let pagesManifest = {};
      let staticManifest = {};
      try {
        pagesManifest = JSON.parse(
          await fs2.promises.readFile(pagesManifestPath, "utf8")
        );
      } catch (err) {
        throw new Error("Failed to read pages manifest.json:", err);
      }
      try {
        staticManifest = JSON.parse(
          await fs2.promises.readFile(staticManifestPath, "utf8")
        );
        globalThis.__PYLON_MANIFEST__ = staticManifest;
        if (pagesManifest["version"]) {
          ;
          globalThis.__PYLON_VERSION__ = pagesManifest["version"];
        }
      } catch (err) {
        throw new Error("Failed to read static manifest.json:", err);
      }
      const routes = (await import(`${process.cwd()}/${pagesManifest["app.js"]}`)).default;
      const _client = await import(`${process.cwd()}/.pylon/client/index.js`);
      const handler2 = createStaticHandler(routes);
      app2.use(trimTrailingSlash());
      const publicFilesPath = path3.resolve(
        process.cwd(),
        ".pylon",
        "__pylon",
        "public"
      );
      let publicFiles = [];
      try {
        publicFiles = glob(`**/*`, {
          filesOnly: true,
          cwd: publicFilesPath
        });
      } catch (error) {
      }
      const sitemapCache = /* @__PURE__ */ new Map();
      if (pagesManifest["sitemap.js"]) {
        try {
          const sitemapModule = await import(`${process.cwd()}/${pagesManifest["sitemap.js"]}`);
          app2.get("/sitemap.xml", async (c) => {
            const cacheKey = "sitemap.xml";
            const cached = sitemapCache.get(cacheKey);
            const now = Date.now();
            const baseUrl = new URL(c.req.url);
            const revalidate = sitemapModule.revalidate;
            if (revalidate === false || revalidate === 0) {
              c.header(
                "Cache-Control",
                "no-store, no-cache, must-revalidate, proxy-revalidate"
              );
            } else if (typeof revalidate === "number") {
              c.header(
                "Cache-Control",
                `public, max-age=${revalidate}, s-maxage=${revalidate}, stale-while-revalidate`
              );
            }
            if (cached && cached.expiresAt > now) {
              c.header("Content-Type", "application/xml");
              return c.body(cached.xml);
            }
            let xml = "";
            if (sitemapModule.generateSitemaps) {
              const sitemaps = await sitemapModule.generateSitemaps();
              const indexItems = sitemaps.map((s) => ({
                url: `${baseUrl.origin}/sitemap/${s.id}.xml`
              }));
              xml = renderSitemapIndexXml(indexItems);
            } else {
              const sitemapFn = sitemapModule.sitemap || sitemapModule.default;
              if (sitemapFn) {
                const items = await sitemapFn();
                xml = renderSitemapXml(items, baseUrl.origin);
              } else {
                return c.text("Sitemap not found", 404);
              }
            }
            if (typeof revalidate === "number" && revalidate > 0) {
              sitemapCache.set(cacheKey, {
                xml,
                expiresAt: now + revalidate * 1e3
              });
            }
            c.header("Content-Type", "application/xml");
            return c.body(xml);
          });
          app2.get("/sitemap/:id", async (c) => {
            const idParam = c.req.param("id");
            if (!idParam.endsWith(".xml")) {
              return c.text("Sitemap not found", 404);
            }
            const id = idParam.replace(".xml", "");
            const cacheKey = `sitemap-${id}.xml`;
            const cached = sitemapCache.get(cacheKey);
            const now = Date.now();
            const baseUrl = new URL(c.req.url);
            const revalidate = sitemapModule.revalidate;
            if (revalidate === false || revalidate === 0) {
              c.header(
                "Cache-Control",
                "no-store, no-cache, must-revalidate, proxy-revalidate"
              );
            } else if (typeof revalidate === "number") {
              c.header(
                "Cache-Control",
                `public, max-age=${revalidate}, s-maxage=${revalidate}, stale-while-revalidate`
              );
            }
            if (cached && cached.expiresAt > now) {
              c.header("Content-Type", "application/xml");
              return c.body(cached.xml);
            }
            let xml = "";
            const sitemapFn = sitemapModule.sitemap || sitemapModule.default;
            if (sitemapFn) {
              const items = await sitemapFn({ id });
              xml = renderSitemapXml(items, baseUrl.origin);
            } else {
              return c.text("Sitemap not found", 404);
            }
            if (typeof revalidate === "number" && revalidate > 0) {
              sitemapCache.set(cacheKey, {
                xml,
                expiresAt: now + revalidate * 1e3
              });
            }
            c.header("Content-Type", "application/xml");
            return c.body(xml);
          });
        } catch (e) {
          console.error("Failed to load sitemap module:", e);
        }
      }
      app2.on(
        "GET",
        publicFiles.map((file) => `/${file}`),
        etag(),
        async (c) => {
          const publicFilePath = path3.resolve(
            process.cwd(),
            ".pylon",
            "__pylon",
            "public",
            c.req.path.replace("/", "")
          );
          return serveFilePath({ filePath: publicFilePath, context: c });
        }
      );
      app2.get("/__pylon/static/*", etag(), async (c) => {
        const filePath = path3.resolve(
          process.cwd(),
          ".pylon",
          "__pylon",
          "static",
          c.req.path.replace("/__pylon/static/", "")
        );
        return serveFilePath({ filePath, context: c });
      });
      app2.get("/__pylon/image", async (c) => {
        try {
          let isSupportedFormat2 = function(format2) {
            const supportedFormats = sharp.format;
            return Object.keys(supportedFormats).includes(format2);
          };
          var isSupportedFormat = isSupportedFormat2;
          const {
            src,
            w,
            h,
            q = "75",
            format = "webp",
            lqip = "false"
          } = c.req.query();
          if (!src) {
            return c.json({ error: "Missing parameters." }, 400);
          }
          const isSrcAbsolute = src.startsWith("http://") || src.startsWith("https://");
          let imagePath;
          if (isSrcAbsolute) {
            imagePath = await downloadImage(src);
          } else {
            if (!src.startsWith("/")) {
              return c.json({ error: "Invalid image path." }, 400);
            }
            if (!src.startsWith("/__pylon/static/media")) {
              imagePath = path3.join(
                process.cwd(),
                ".pylon",
                "__pylon",
                "public",
                src
              );
            } else {
              imagePath = path3.join(process.cwd(), ".pylon", src);
            }
          }
          const cachedImageFileName = getCachedImagePath({
            src,
            width: w ? parseInt(w) : 0,
            height: h ? parseInt(h) : 0,
            quality: q,
            lqip: lqip === "true",
            format
          });
          try {
            await fs2.promises.access(imagePath);
          } catch {
            try {
              imagePath = await downloadImage(src);
            } catch (error) {
              return c.json({ error: "Image not found" }, 404);
            }
          }
          if (IS_IMAGE_CACHE_POSSIBLE) {
            try {
              await fs2.promises.access(cachedImageFileName);
              const stream = fs2.createReadStream(cachedImageFileName);
              c.res.headers.set("Content-Type", getContentType(format));
              return c.body(Readable2.toWeb(stream));
            } catch (e) {
            }
          }
          const sharp = (await import("sharp")).default;
          const metadata = await sharp(imagePath).metadata();
          if (!metadata.width || !metadata.height) {
            return c.json(
              {
                error: "Invalid image metadata. Width and height are required for resizing."
              },
              400
            );
          }
          const { width: finalWidth, height: finalHeight } = calculateDimensions(
            metadata.width,
            metadata.height,
            w ? parseInt(w) : void 0,
            h ? parseInt(h) : void 0
          );
          let imageFormat = format.toLowerCase();
          if (!isSupportedFormat2(imageFormat)) {
            throw new Error("Unsupported image format");
          }
          const quality = parseInt(q);
          let data = sharp(imagePath);
          if (lqip === "true") {
            data = data.resize({
              width: Math.min(finalWidth ?? 16, 16),
              height: Math.min(finalHeight ?? 16, 16),
              fit: "inside"
            }).toFormat("webp", {
              quality: 30,
              alphaQuality: 20,
              smartSubsample: true
            });
          } else {
            data = data.resize(finalWidth, finalHeight).toFormat(imageFormat, {
              quality
            });
          }
          if (IS_IMAGE_CACHE_POSSIBLE) {
            const image = await data.toFile(cachedImageFileName);
            c.res.headers.set("Content-Type", getContentType(image.format));
            return c.body(
              Readable2.toWeb(
                fs2.createReadStream(cachedImageFileName)
              )
            );
          } else {
            const image = await data.toBuffer({ resolveWithObject: true });
            c.res.headers.set("Content-Type", getContentType(image.info.format));
            return c.body(image.data);
          }
        } catch (error) {
          console.error("Error processing the image:", error);
          return c.json({ error: "Error processing the image" }, 500);
        }
      });
      const requestStore = new AsyncLocalStorage3();
      app2.get("*", async (c) => {
        const initCtx = requestStore.getStore() || {
          client: null
        };
        return requestStore.run(initCtx, async () => {
          if (!initCtx.client) {
            initCtx.client = _client.pageClient();
          }
          const client = initCtx.client;
          const staticHandlerContext = await handler2.query(c.req.raw);
          if (staticHandlerContext instanceof Response) {
            return staticHandlerContext;
          }
          const xPylonRouteRef = c.req.header("x-pylon-route-ref");
          const router = createStaticRouter(
            handler2.dataRoutes,
            staticHandlerContext
          );
          const component = /* @__PURE__ */ jsx5(__PYLON_INTERNALS_DO_NOT_USE.DataClientProvider, { client, children: /* @__PURE__ */ jsx5(
            __PYLON_INTERNALS_DO_NOT_USE.SSRPruningProvider,
            {
              target: xPylonRouteRef || null,
              children: /* @__PURE__ */ jsx5(
                StaticRouterProvider,
                {
                  router,
                  context: staticHandlerContext
                }
              )
            }
          ) });
          if (c.req.header("accept")?.includes("application/json")) {
            let cacheSnapshot;
            try {
              const data = await client.prepareReactRender(component);
              cacheSnapshot = data.cacheSnapshot;
            } catch (error) {
              if (error instanceof Response) {
                return error;
              }
            }
            const context = c.get("pagesContext") || {};
            return c.json({
              cacheSnapshot,
              context,
              version: pagesManifest["version"]
            });
          }
          try {
            if (reactServer.renderToReadableStream) {
              try {
                const stream = await reactServer.renderToReadableStream(component, {
                  bootstrapModules: staticManifest["app.js"] ? [staticManifest["app.js"]] : void 0
                });
                c.header("Content-Type", "text/html");
                return c.body(stream);
              } catch (error) {
                throw error;
              }
            } else if (reactServer.renderToPipeableStream) {
              return await new Promise((resolve, reject) => {
                const { pipe } = reactServer.renderToPipeableStream(
                  component,
                  {
                    bootstrapModules: staticManifest["app.js"] ? [staticManifest["app.js"]] : void 0,
                    onShellReady: async () => {
                      c.header("Content-Type", "text/html");
                      const passThrough = new PassThrough();
                      pipe(passThrough);
                      resolve(c.body(Readable2.toWeb(passThrough)));
                    },
                    onShellError: async (error) => {
                      reject(error);
                    }
                  }
                );
              });
            } else {
              throw new Error("Environment not supported");
            }
          } catch (errorOrResponse) {
            c.header("Content-Type", "text/html");
            if (errorOrResponse instanceof Response) {
              c.status(errorOrResponse.status);
              if (errorOrResponse.status >= 300 && errorOrResponse.status < 400) {
                const location = errorOrResponse.headers.get("Location");
                if (location) {
                  return c.redirect(
                    location,
                    errorOrResponse.status
                  );
                }
              }
              return c.html(
                reactServer.renderToString(
                  /* @__PURE__ */ jsx5(
                    StatusPage,
                    {
                      code: errorOrResponse.status,
                      title: errorOrResponse.statusText,
                      message: errorOrResponse.statusText,
                      standalone: true
                    }
                  )
                )
              );
            }
            c.status(500);
            return c.html(
              reactServer.renderToString(
                /* @__PURE__ */ jsx5(GlobalError, { error: errorOrResponse })
              )
            );
          }
        });
      });
    };
    IMAGE_CACHE_DIR = path3.join(process.cwd(), ".cache/__pylon/images");
    IS_IMAGE_CACHE_POSSIBLE = true;
    try {
      await fs2.promises.mkdir(IMAGE_CACHE_DIR, { recursive: true });
    } catch (error) {
      IS_IMAGE_CACHE_POSSIBLE = false;
    }
    getCachedImagePath = (args) => {
      const fileName = `${path3.basename(
        createHash("md5").update(JSON.stringify(args)).digest("hex"),
        path3.extname(args.src)
      )}-${args.width}x${args.height}.${args.format}`;
      return path3.join(IMAGE_CACHE_DIR, fileName);
    };
    calculateDimensions = (originalWidth, originalHeight, width, height) => {
      if (!width && !height) {
        return { width: originalWidth, height: originalHeight };
      }
      if (width && !height) {
        height = Math.round(width * originalHeight / originalWidth);
      } else if (height && !width) {
        width = Math.round(height * originalWidth / originalHeight);
      }
      return { width, height };
    };
    getContentType = (format) => {
      switch (format.toLowerCase()) {
        case "webp":
          return "image/webp";
        case "jpeg":
        case "jpg":
          return "image/jpeg";
        case "png":
          return "image/png";
        case "gif":
          return "image/gif";
        case "svg":
          return "image/svg+xml";
        default:
          return "application/octet-stream";
      }
    };
    downloadImage = async (url) => {
      const isSrcAbsoluteUrl = url.startsWith("http://") || url.startsWith("https://");
      const _fetch = isSrcAbsoluteUrl ? fetch : app.request;
      const response = await _fetch(url);
      if (!response.ok)
        throw new Error(`Failed to download image: ${response.statusText}`);
      const ext = path3.extname(url) || ".jpg";
      const tempFilePath = path3.join(tmpdir(), `image-${Date.now()}${ext}`);
      const fileStream = fs2.createWriteStream(tempFilePath);
      await pipeline(response.body, fileStream);
      return tempFilePath;
    };
  }
});

// src/plugins/use-pages/build/app-utils.ts
import fs3 from "fs";
import path4 from "path";
function formatSegment(segment) {
  let sanitized = segment;
  if (sanitized.startsWith("[...") && sanitized.endsWith("]")) {
    const param = sanitized.slice(4, -1);
    sanitized = "CatchAll" + param.charAt(0).toUpperCase() + param.slice(1);
  } else if (sanitized.startsWith("[") && sanitized.endsWith("]")) {
    sanitized = sanitized.slice(1, -1);
  }
  return sanitized.charAt(0).toUpperCase() + sanitized.slice(1);
}
function getLayoutComponentName(filePath) {
  const segments = filePath.replace(PAGES_DIR, "").replace(/\\/g, "/").replace(/layout\.tsx$/, "").split("/").filter(Boolean);
  return segments.map(formatSegment).join("") + "Layout";
}
function getPageComponentName(filePath) {
  const segments = filePath.replace(PAGES_DIR, "").replace(/\\/g, "/").replace(/page\.tsx$/, "").split("/").filter(Boolean);
  return segments.map(formatSegment).join("") + "Page";
}
function convertToDynamicRoute(segment) {
  if (segment.startsWith("[...") && segment.endsWith("]")) return "*";
  if (segment.startsWith("[") && segment.endsWith("]"))
    return `:${segment.slice(1, -1)}`;
  return segment;
}
function processLayoutItem(relativePath, importPath, route, context) {
  const layoutComponentName = getLayoutComponentName(relativePath);
  context.imports.push(`import ${layoutComponentName} from ${importPath};`);
  const componentName = layoutComponentName === "Layout" ? `RootLayout` : `${layoutComponentName}`;
  const catchAllParam = relativePath.match(/\[\.\.\.(.+)\]/)?.[1];
  const paramMatches = [...relativePath.matchAll(/\[(.+?)\]/g)].map(
    (m) => m[1].replace("...", "")
  );
  route.Component = `withLoaderData((props) => <${componentName} children={<Outlet />} {...props} />, "${componentName}", ${catchAllParam ? `"${catchAllParam}"` : "undefined"})`;
  route.loader = `loader("${componentName}")`;
  route.shouldRevalidate = `({ currentParams, nextParams, formData, defaultShouldRevalidate }) => {
    // Revalidate if a form was submitted (standard behavior)
    if (formData) return true;

    // List of params this layout segment depends on
    const relevantKeys = ${JSON.stringify(paramMatches)};
    
    // Check if any relevant URL parameter changed
    const hasParamChanged = relevantKeys.some(key => 
      JSON.stringify(currentParams[key]) !== JSON.stringify(nextParams[key])
    );

    // If it's the RootLayout, we might only want to revalidate on hard refreshes 
    // or specific global triggers. Otherwise, follow param changes.
    return hasParamChanged || (relevantKeys.length === 0 && defaultShouldRevalidate);
  }`;
  if (route.path === "/") {
    route.errorElement = "<ErrorElement standalone={true} />";
  }
  route.HydrateFallback = "HydrateFallback";
}
function processPageItem(relativePath, importPath, route) {
  const catchAllParam = relativePath.match(/\[\.\.\.(.+)\]/)?.[1];
  const pageComponentName = getPageComponentName(relativePath);
  route.children.push({
    path: void 0,
    index: true,
    errorElement: "<ErrorElement standalone={false} />",
    lazy: `async () => {const i = await import(${importPath}).catch(() => {window.location.reload()}); return {Component: withLoaderData(i.default, "${pageComponentName}", ${catchAllParam ? `"${catchAllParam}"` : "undefined"})}}`,
    HydrateFallback: "HydrateFallback",
    loader: `loader("${pageComponentName}")`
  });
}
function optimizeRouteStructure(route, hasLayout) {
  if (!hasLayout && route.children?.length === 1 && route.children[0].path === "*") {
    const child = route.children[0];
    const currentPath = route.path === "/" ? "" : route.path;
    Object.assign(route, child);
    route.path = currentPath ? `${currentPath}/*` : "*";
    delete route.children;
  }
  if (route.path === "*" && !hasLayout && route.children?.length === 1) {
    const child = route.children[0];
    if (child.index || child.path === "*") {
      const currentPath = route.path;
      Object.assign(route, child);
      route.path = currentPath;
      delete route.index;
      delete route.children;
    }
  }
  if (route.path === "*" && hasLayout && route.children) {
    const pageChild = route.children.find((child) => child.index);
    if (pageChild) {
      delete pageChild.index;
      pageChild.path = "*";
    }
  }
}
function scanDirectory(directory, context, basePath = "") {
  const items = fs3.readdirSync(directory, { withFileTypes: true });
  const route = { path: basePath || "/", children: [] };
  let hasLayout = false;
  let pageFound = false;
  for (const item of items) {
    const itemPath = path4.join(directory, item.name);
    const relativePath = path4.join(basePath, item.name).replace(/\\/g, "/");
    const importPath = `"./${path4.join("..", PAGES_DIR, relativePath).replace(/\.tsx$/, "")}"`;
    if (item.isDirectory()) {
      const childRoute = scanDirectory(itemPath, context, relativePath);
      if (childRoute) {
        route.children.push(childRoute);
      }
    } else if (item.name === "layout.tsx") {
      processLayoutItem(relativePath, importPath, route, context);
      hasLayout = true;
    } else if (item.name === "page.tsx") {
      processPageItem(relativePath, importPath, route);
      pageFound = true;
    }
  }
  if (route.path) {
    const segments = route.path.split("/").map((segment) => convertToDynamicRoute(segment)).filter(Boolean);
    const fullPath = segments.length > 0 ? `/${segments.join("/")}` : "/";
    route.path = segments[segments.length - 1] || "/";
    if (hasLayout || pageFound) {
      context.routeSlugs.push(fullPath);
    }
  }
  if (hasLayout) {
    const childNotFoundRoute = {
      path: "*",
      element: "<NotFoundPage standalone={false} />"
    };
    if (!route.children) {
      route.children = [];
    }
    route.children.push(childNotFoundRoute);
  }
  optimizeRouteStructure(route, hasLayout);
  if (hasLayout || route.lazy || route.children && route.children.length > 0) {
    return route;
  }
  return null;
}
function serialize(obj, parentKey) {
  if (Array.isArray(obj)) {
    return `[${obj.map(serialize).join(", ")}]`;
  } else if (obj && typeof obj === "object") {
    const entries = Object.entries(obj).map(
      ([key, value]) => `${JSON.stringify(key)}: ${serialize(value, key)}`
    );
    return `{${entries.join(", ")}}`;
  } else if (typeof obj === "string") {
    if (parentKey === "lazy" || parentKey === "loader" || parentKey === "shouldRevalidate" || parentKey === "Component" || parentKey === "element" || parentKey === "errorElement" || parentKey === "HydrateFallback") {
      return obj;
    }
    return JSON.stringify(obj);
  } else {
    return String(obj);
  }
}
function generateRouteFileContent(context, rootRoute, notFoundRoute) {
  return `${context.imports.join("\n")}

import {useMemo} from 'react'

import {__PYLON_ROUTER_INTERNALS_DO_NOT_USE, __PYLON_INTERNALS_DO_NOT_USE, GlobalErrorPage, StatusPage} from '@getcronit/pylon/pages'
const Outlet = __PYLON_ROUTER_INTERNALS_DO_NOT_USE.Outlet

const ErrorElement: React.FC<{standalone: boolean}> = ({standalone}) => {
  const error = __PYLON_ROUTER_INTERNALS_DO_NOT_USE.useRouteError()


    if(error instanceof Response) {
      // Check if the error is a redirect response
      if(error.status > 300 && error.status < 400 && error.headers.get('Location')) {
      return <__PYLON_ROUTER_INTERNALS_DO_NOT_USE.Navigate to={error.headers.get('Location')!} replace />
      }

      let message = 'An unexpected error occurred.'

    try {
      const data = JSON.parse(error.data?.message || '{}')
      if (data.message) {
        message = data.message
      }
    } catch (e) {}

    return (
      <StatusPage
        code={error.status}
        title={error.statusText}
        message={message}
        standalone={standalone}
      />
    )
  }

  return <GlobalErrorPage error={error} />
}

const HydrateFallback = () => {
  return <div>Loading...</div>
}

function withLoaderData<T>(Component: React.ComponentType<{ data: T }>, name?: string, catchAllParam?: string) {
  return function WithLoaderDataWrapper(props: T) {
    const dataClient = __PYLON_INTERNALS_DO_NOT_USE.useDataClient()
    const pruningTarget = __PYLON_INTERNALS_DO_NOT_USE.useSSRPruning()

    const {cacheSnapshot, context} = __PYLON_ROUTER_INTERNALS_DO_NOT_USE.useLoaderData() || {};
    const location = __PYLON_ROUTER_INTERNALS_DO_NOT_USE.useLocation()
    const [searchParams] = __PYLON_ROUTER_INTERNALS_DO_NOT_USE.useSearchParams()
    const searchParamsObject = useMemo(() => Object.fromEntries(searchParams.entries()), [searchParams])

    const reactRouterParams = __PYLON_ROUTER_INTERNALS_DO_NOT_USE.useParams()

    const params = useMemo(() => {
      const params: Record<string, string | string[] | undefined> = reactRouterParams

      if (catchAllParam && reactRouterParams['*']) {
        params[catchAllParam] = reactRouterParams['*']?.split('/')
      }

      return params
    }, [reactRouterParams, catchAllParam])

    // 1. Handle Transparent Ancestors
    // If we're optimized-rendering a specific layout, and THIS is not it,
    // we just act as a passthrough to skip THIS layout's logic/queries.
    // Exception: RootLayout is never skipped to preserve global providers.
    if (pruningTarget && name !== pruningTarget && name !== 'RootLayout') {
      return <Outlet />
    }

    const {useQuery, useHydrateCache} = useMemo(() => dataClient.pageClient(), [])

    if(cacheSnapshot) {
      useHydrateCache({cacheSnapshot})
    }

    const data = typeof window !== "undefined" ? useQuery() : dataClient.useQuery()

    const pageProps = useMemo(() => {
      return {
        path: location.pathname,
        params,
        searchParams: searchParamsObject,
        data,
        context,
      }
    }, [location.pathname, params, searchParamsObject, data, context])

    // 2. Handle Pruning Target
    // If THIS is the target, we render it but clear its children (the Outlet).
    const children = pruningTarget && name === pruningTarget ? null : <Outlet />

    return <__PYLON_INTERNALS_DO_NOT_USE.RouteDataProvider props={pageProps} name={name}>
      <Component {...(props as any)} {...pageProps} children={children} />
    </__PYLON_INTERNALS_DO_NOT_USE.RouteDataProvider>
  };
}

const loader: (ref?: string) => __PYLON_ROUTER_INTERNALS_DO_NOT_USE.LoaderFunction = (ref) => async ({ request, ...args }) => {
  // 1. Skip if request is a JSON-only fetch (e.g., client-side route preloading)
  const acceptHeader = request.headers.get('accept')
  if (acceptHeader?.includes('application/json')) {
    return null
  }

  const url = new URL(request.url)
  const headers = new Headers()
  let fetchToUse: typeof fetch = fetch

  try {
    // 2. Try importing Pylon \u2014 if this works, we're on the server
    const moduleNameToPreventBundling = '@getcronit/pylon'
    const { app, getContext } = await import(moduleNameToPreventBundling)
    fetchToUse = app.request

    // 3. Get headers from the original server request and forward them
    const context = getContext()
    for (const [key, value] of context.req.raw.headers.entries()) {
      headers.append(key, value)
    }

    // Set Accept-Encoding header to identity so the internal fetch returns JSON
    headers.set('Accept-Encoding', 'identity')
    
  } catch {
    // 4. Pylon not available \u2014 fallback to default fetch (runs in browser)
    // No additional headers are needed; browser sends cookies automatically
  }

  headers.set('Accept', 'application/json') // Ensure the internal request gets JSON
  headers.set('X-Pylon-Internal', 'true')
  if(ref) {
    headers.set('X-Pylon-Route-Ref', ref)
  }

  const response = await fetchToUse(url.pathname + url.search, {
      method: 'GET',
      headers,
  })

  try {
    const data = await response.json<any>()

    // Check if the version returned by the server matches the client's version
    if (data && data.version && typeof window !== 'undefined' && (window as any).__PYLON_VERSION__ && data.version !== (window as any).__PYLON_VERSION__) {
      window.location.reload()
    }

    return data
  } catch {
    return null
  }
}


const RootLayout = (props: { children: React.ReactNode; [key: string]: any }) => {
  const manifest = (globalThis as any).__PYLON_MANIFEST__;

  return (
    <Layout {...props}>
      <meta charSet="utf-8" />
      {manifest?.['index.css'] && <link rel="stylesheet" href={manifest['index.css']} precedence="high" />}
      {manifest?.['app.css'] && <link rel="stylesheet" href={manifest['app.css']} precedence="high" />}
      {props.children}
    </Layout>
  )
}

const NotFoundPage: React.FC<{standalone: boolean}> = ({standalone = false}) => {
  return <StatusPage code={404} title="Page Not Found" message="The page you are looking for does not exist." standalone={standalone} />
}

const routes = ${serialize([rootRoute, notFoundRoute].filter(Boolean))}

export default routes

`;
}
function makeAppFiles() {
  const context = { imports: [], routeSlugs: [] };
  const rootRoute = scanDirectory(PAGES_DIR, context);
  const notFoundRoute = {
    path: "*",
    element: "<NotFoundPage standalone={true} />"
  };
  const routes = generateRouteFileContent(context, rootRoute, notFoundRoute);
  const slugs = `export default ${JSON.stringify(context.routeSlugs, null, 2)}`;
  return {
    routes,
    slugs
  };
}
var PAGES_DIR;
var init_app_utils = __esm({
  "src/plugins/use-pages/build/app-utils.ts"() {
    "use strict";
    PAGES_DIR = "./pages";
  }
});

// src/plugins/use-pages/build/plugins/external-esm-plugin.ts
import escapeStringRegexp from "escape-string-regexp";
function makeFilter(externals) {
  return new RegExp(
    "^(" + externals.map(escapeStringRegexp).join("|") + ")(\\/.*)?$"
    // TODO support for query strings?
  );
}
var NAME, NAMESPACE, esmExternalsPlugin;
var init_external_esm_plugin = __esm({
  "src/plugins/use-pages/build/plugins/external-esm-plugin.ts"() {
    "use strict";
    NAME = "esm-externals";
    NAMESPACE = NAME;
    esmExternalsPlugin = (externals) => {
      return {
        name: NAME,
        setup(build2) {
          const filter = makeFilter(externals);
          build2.onResolve({ filter: /.*/, namespace: NAMESPACE }, (args) => {
            return {
              path: args.path,
              external: true
            };
          });
          build2.onResolve({ filter }, (args) => {
            return {
              path: args.path,
              namespace: NAMESPACE
            };
          });
          build2.onLoad({ filter: /.*/, namespace: NAMESPACE }, (args) => {
            return {
              contents: `export * as default from ${JSON.stringify(
                args.path
              )}; export * from ${JSON.stringify(args.path)};`
            };
          });
        }
      };
    };
  }
});

// src/plugins/use-pages/build/plugins/image-plugin.ts
import { createHash as createHash2 } from "crypto";
import path5 from "path";
import fs4 from "fs/promises";
var imagePlugin;
var init_image_plugin = __esm({
  "src/plugins/use-pages/build/plugins/image-plugin.ts"() {
    "use strict";
    imagePlugin = {
      name: "image-plugin",
      setup(build2) {
        const outdir = build2.initialOptions.outdir;
        const publicPath = build2.initialOptions.publicPath;
        if (!outdir || !publicPath) {
          throw new Error("outdir and publicPath must be set in esbuild options");
        }
        build2.onResolve({ filter: /\.(png|jpe?g)$/ }, async (args) => {
          const filePath = path5.resolve(args.resolveDir, args.path);
          const fileName = path5.basename(filePath);
          const extname = path5.extname(filePath);
          const hash = createHash2("md5").update(filePath + await fs4.readFile(filePath)).digest("hex").slice(0, 8);
          const newFilename = `${fileName}-${hash}${extname}`;
          const newFilePath = path5.join(outdir, "media", newFilename);
          await fs4.mkdir(path5.dirname(newFilePath), { recursive: true });
          await fs4.copyFile(filePath, newFilePath);
          return {
            path: newFilePath,
            namespace: "image"
          };
        });
        build2.onLoad({ filter: /\.png$|\.jpg$/ }, async (args) => {
          const sharp = (await import("sharp")).default;
          const image = sharp(args.path);
          const metadata = await image.metadata();
          const url = `${publicPath}/media/${path5.basename(args.path)}`;
          const output = image.resize({
            width: Math.min(metadata.width ?? 16, 16),
            height: Math.min(metadata.height ?? 16, 16),
            fit: "inside"
          }).toFormat("webp", {
            quality: 30,
            alphaQuality: 20,
            smartSubsample: true
          });
          const { data, info } = await output.toBuffer({ resolveWithObject: true });
          const dataURIBase64 = `data:image/${info.format};base64,${data.toString(
            "base64"
          )}`;
          return {
            contents: JSON.stringify({
              url,
              width: metadata.width,
              height: metadata.height,
              blurDataURL: dataURIBase64
            }),
            loader: "json"
          };
        });
      }
    };
  }
});

// src/plugins/use-pages/build/plugins/inject-app-hydration.ts
import fs5 from "fs/promises";
import path6 from "path";
var injectAppHydrationPlugin;
var init_inject_app_hydration = __esm({
  "src/plugins/use-pages/build/plugins/inject-app-hydration.ts"() {
    "use strict";
    injectAppHydrationPlugin = (version2) => ({
      name: "inject-hydration",
      setup(build2) {
        build2.onLoad({ filter: /.*/, namespace: "file" }, async (args) => {
          if (args.path === path6.resolve(process.cwd(), ".pylon", "app.tsx")) {
            let contents = await fs5.readFile(args.path, "utf-8");
            const clientPath = path6.resolve(process.cwd(), ".pylon/client");
            const pathToClient = path6.relative(path6.dirname(args.path), clientPath);
            contents += `
          import {hydrateRoot} from 'react-dom/client'
          import * as client from './${pathToClient}'
          import { __PYLON_ROUTER_INTERNALS_DO_NOT_USE, __PYLON_INTERNALS_DO_NOT_USE, DevOverlay, onCaughtErrorProd, onRecoverableErrorProd, onUncaughtErrorProd } from '@getcronit/pylon/pages';
          const {createBrowserRouter, RouterProvider, matchRoutes} = __PYLON_ROUTER_INTERNALS_DO_NOT_USE
          const {DataClientProvider} = __PYLON_INTERNALS_DO_NOT_USE
          import React, {useMemo, startTransition} from 'react'
          import * as Sentry from '@sentry/react'

          // @ts-ignore
          window.__PYLON_VERSION__ = "${version2}"

          async function hydrate() {
            // Determine if any of the initial routes are lazy
            const lazyMatches = matchRoutes(routes, window.location)?.filter(
              (m) => m.route.lazy
            );

            // Load the lazy matches and update the routes before creating your router
            // so we can hydrate the SSR-rendered content synchronously
            if (lazyMatches && lazyMatches?.length > 0) {
              await Promise.all(
                lazyMatches.map(async (m) => {
                  const routeModule = await m.route.lazy!();
                  Object.assign(m.route, { ...routeModule, lazy: undefined });
                })
              );
            }

            const router = createBrowserRouter(routes)

            startTransition(() => {
              hydrateRoot(
                document,
                <DataClientProvider client={client}>
                  <RouterProvider router={router} />
                </DataClientProvider>
              , {
                // Callback called when an error is thrown and not caught by an ErrorBoundary.
                onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
                  console.warn('Uncaught error', error, errorInfo.componentStack);
                }),
                // Callback called when React catches an error in an ErrorBoundary.
                onCaughtError: Sentry.reactErrorHandler(),
                // Callback called when React automatically recovers from errors.
                onRecoverableError: Sentry.reactErrorHandler(),
              })
            })
         }

         hydrate()


          `;
            return {
              loader: "tsx",
              contents
            };
          }
        });
      }
    });
  }
});

// src/plugins/use-pages/build/plugins/postcss-plugin.ts
import fs6 from "fs/promises";
import loadConfig from "postcss-load-config";
import postcss from "postcss";
var postcssPlugin;
var init_postcss_plugin = __esm({
  "src/plugins/use-pages/build/plugins/postcss-plugin.ts"() {
    "use strict";
    postcssPlugin = {
      name: "postcss-plugin",
      setup(build2) {
        build2.onLoad({ filter: /.css$/, namespace: "file" }, async (args) => {
          const { plugins, options } = await loadConfig();
          const css = await fs6.readFile(args.path, "utf-8");
          const result = await postcss(plugins).process(css, {
            ...options,
            from: args.path
          }).then((result2) => result2);
          return {
            contents: result.css,
            loader: "css"
          };
        });
      }
    };
  }
});

// src/plugins/use-pages/build/index.ts
var build_exports = {};
__export(build_exports, {
  build: () => build
});
import chokidar from "chokidar";
import esbuild from "esbuild";
import fs7 from "fs/promises";
import path7 from "path";
async function updateFileIfChanged(filePath, newContent) {
  await fs7.mkdir(path7.dirname(filePath), { recursive: true });
  try {
    const currentContent = await fs7.readFile(filePath);
    if (currentContent.equals(newContent)) {
      return false;
    }
  } catch (err) {
    if (err.code !== "ENOENT") throw err;
  }
  await fs7.writeFile(filePath, newContent);
  return true;
}
var DIST_STATIC_DIR, DIST_PAGES_DIR, build;
var init_build = __esm({
  "src/plugins/use-pages/build/index.ts"() {
    "use strict";
    init_app_utils();
    init_external_esm_plugin();
    init_image_plugin();
    init_inject_app_hydration();
    init_postcss_plugin();
    DIST_STATIC_DIR = path7.join(process.cwd(), ".pylon/__pylon/static");
    DIST_PAGES_DIR = path7.join(process.cwd(), ".pylon/__pylon/pages");
    build = async ({ onBuild }) => {
      const version2 = Math.random().toString(36).substring(7);
      const buildAppFile = async () => {
        const appFiles = makeAppFiles();
        await updateFileIfChanged(
          path7.resolve(process.cwd(), ".pylon", "app.tsx"),
          Buffer.from(appFiles.routes)
        );
      };
      const copyPublicDir = async () => {
        const publicDir = path7.resolve(process.cwd(), "public");
        const pylonPublicDir = path7.resolve(
          process.cwd(),
          ".pylon",
          "__pylon",
          "public"
        );
        try {
          await fs7.access(publicDir);
          await fs7.mkdir(pylonPublicDir, { recursive: true });
          await fs7.cp(publicDir, pylonPublicDir, { recursive: true, force: true });
        } catch (err) {
          if (err.code !== "ENOENT") throw err;
        }
      };
      const pylonCssPath = path7.join(
        process.cwd(),
        "node_modules",
        "@getcronit/pylon/dist/pages/index.css"
      );
      const buildAppFilePlugin = {
        name: "build-app-file",
        setup(build2) {
          build2.onStart(async () => {
            await buildAppFile();
          });
        }
      };
      const writeOnEndPlugin = {
        name: "write-on-end",
        setup(build2) {
          build2.initialOptions.metafile = true;
          build2.initialOptions.write = false;
          build2.onEnd(async (result) => {
            const manifest = {};
            for (const [key, value] of Object.entries(
              result.metafile?.outputs || {}
            )) {
              if (value.entryPoint === ".pylon/app.tsx") {
                manifest["app.js"] = key;
                if (value.cssBundle) {
                  manifest["app.css"] = value.cssBundle;
                }
              } else if (value.entryPoint?.endsWith("pylon/dist/pages/index.css")) {
                manifest["index.css"] = key;
              } else if (value.entryPoint?.endsWith("pages/sitemap.ts")) {
                manifest["sitemap.js"] = key;
              }
            }
            if (build2.initialOptions.publicPath) {
              const publicPath = build2.initialOptions.publicPath;
              for (const [key, value] of Object.entries(manifest)) {
                const index = value.indexOf(publicPath);
                if (index !== -1) {
                  manifest[key] = value.slice(index);
                }
              }
            }
            manifest["version"] = version2;
            await updateFileIfChanged(
              path7.join(build2.initialOptions.outdir, "manifest.json"),
              Buffer.from(JSON.stringify(manifest, null, 2))
            );
            await Promise.all(
              result.outputFiles.map(async (file) => {
                await fs7.mkdir(path7.dirname(file.path), { recursive: true });
                await updateFileIfChanged(file.path, file.contents);
              })
            );
            if (result.errors.length === 0) {
              onBuild();
            }
          });
        }
      };
      const nodePaths = [
        path7.join(process.cwd(), "node_modules"),
        path7.join(process.cwd(), "node_modules", "@getcronit/pylon/node_modules")
      ];
      let pagesWatcher = null;
      const timePlugin = (name) => ({
        name: "rebuild-log",
        setup({ onStart, onEnd }) {
          var t;
          onStart(() => {
            t = Date.now();
          });
          onEnd(() => {
            console.log(`Pages [${name}] Rebuild took ${Date.now() - t}ms`);
          });
        }
      });
      const sitemapExists = await fs7.access(path7.join(process.cwd(), "pages/sitemap.ts")).then(() => true).catch(() => false);
      const clientCtx = await esbuild.context({
        sourcemap: "linked",
        write: false,
        metafile: true,
        nodePaths,
        absWorkingDir: process.cwd(),
        plugins: [
          buildAppFilePlugin,
          injectAppHydrationPlugin(version2),
          imagePlugin,
          postcssPlugin,
          writeOnEndPlugin,
          timePlugin("client")
        ],
        publicPath: "/__pylon/static",
        assetNames: "assets/[name]-[hash]",
        chunkNames: "chunks/[name]-[hash]",
        entryNames: "./[name]-[hash]",
        format: "esm",
        platform: "browser",
        entryPoints: [".pylon/app.tsx", pylonCssPath],
        outdir: DIST_STATIC_DIR,
        bundle: true,
        splitting: true,
        minify: false,
        loader: {
          // Map file extensions to the file loader
          ".svg": "file",
          ".woff": "file",
          ".woff2": "file",
          ".ttf": "file",
          ".otf": "file"
        },
        define: {
          "process.env.NODE_ENV": JSON.stringify(
            process.env.NODE_ENV || "development"
          )
        },
        mainFields: ["browser", "module", "main"]
      });
      const serverCtx = await esbuild.context({
        sourcemap: "inline",
        write: false,
        metafile: true,
        absWorkingDir: process.cwd(),
        nodePaths,
        plugins: [
          buildAppFilePlugin,
          imagePlugin,
          postcssPlugin,
          writeOnEndPlugin,
          timePlugin("server"),
          esmExternalsPlugin([
            "@getcronit/pylon",
            "react",
            "react-dom",
            "gqty",
            "@gqty/react"
          ])
        ],
        publicPath: "/__pylon/static",
        assetNames: "assets/[name]-[hash]",
        chunkNames: "chunks/[name]-[hash]",
        entryNames: "./[name]-[hash]",
        format: "esm",
        platform: "node",
        entryPoints: [
          ".pylon/app.tsx",
          pylonCssPath,
          ...sitemapExists ? ["./pages/sitemap.ts"] : []
        ],
        outdir: DIST_PAGES_DIR,
        bundle: true,
        splitting: false,
        external: ["@getcronit/pylon", "react", "react-dom", "gqty", "@gqty/react"],
        minify: true,
        loader: {
          // Map file extensions to the file loader
          ".svg": "file",
          ".woff": "file",
          ".woff2": "file",
          ".ttf": "file",
          ".otf": "file"
        },
        define: {
          "process.env.NODE_ENV": JSON.stringify(
            process.env.NODE_ENV || "development"
          )
        },
        mainFields: ["module", "main"]
      });
      return {
        watch: async () => {
          await buildAppFile();
          await copyPublicDir();
          pagesWatcher = chokidar.watch("pages", { ignoreInitial: true });
          pagesWatcher.on("all", async (event, path8) => {
            if (["add", "change", "unlink"].includes(event)) {
              await copyPublicDir();
            }
          });
          await Promise.all([clientCtx.watch(), serverCtx.watch()]);
        },
        dispose: async () => {
          if (pagesWatcher) {
            pagesWatcher.close();
          }
          Promise.all([clientCtx.dispose(), serverCtx.dispose()]);
        },
        rebuild: async () => {
          await copyPublicDir();
          await Promise.all([clientCtx.rebuild(), serverCtx.rebuild()]);
          return {};
        },
        cancel: async () => {
          if (pagesWatcher) {
            await pagesWatcher.close();
          }
          await Promise.all([clientCtx.cancel(), serverCtx.cancel()]);
        }
      };
    };
  }
});

// src/plugins/use-pages/index.ts
function usePages() {
  return {
    strategy: "last",
    // We use async functions here so React isn't imported until setup() is called
    setup: async (api) => {
      const { setup: setup2 } = await init_setup().then(() => setup_exports);
      return setup2(api);
    },
    build: async (api) => {
      const { build: build2 } = await Promise.resolve().then(() => (init_build(), build_exports));
      return build2(api);
    }
  };
}
var init_use_pages = __esm({
  "src/plugins/use-pages/index.ts"() {
    "use strict";
  }
});

// src/gateway.ts
import { getContext as getContext2, getResolveInfo as getResolveInfo2 } from "@getcronit/pylon";
import { delegateToSchema } from "@graphql-tools/delegate";
import { buildHTTPExecutor } from "@graphql-tools/executor-http";
import { schemaFromExecutor, wrapSchema } from "@graphql-tools/wrap";
import {
  Kind as Kind4,
  OperationTypeNode,
  visit
} from "graphql";
function astFromJSValue(value) {
  if (typeof value === "string")
    return { kind: Kind4.STRING, value };
  if (typeof value === "number")
    return { kind: Kind4.INT, value: String(value) };
  if (typeof value === "boolean")
    return { kind: Kind4.BOOLEAN, value };
  return { kind: Kind4.STRING, value: String(value) };
}
function buildSelectionsFromNeeds(needs) {
  const selections = [];
  for (const [key, value] of Object.entries(needs)) {
    if (key === "__args" || !value) continue;
    let selectionSet = void 0;
    let argsNodes = void 0;
    if (typeof value === "object") {
      const nestedSelections = buildSelectionsFromNeeds(value);
      if (nestedSelections.length > 0) {
        selectionSet = {
          kind: Kind4.SELECTION_SET,
          selections: nestedSelections
        };
      }
      if (value.__args) {
        argsNodes = Object.entries(value.__args).map(
          ([argName, argVal]) => ({
            kind: Kind4.ARGUMENT,
            name: { kind: Kind4.NAME, value: argName },
            value: astFromJSValue(argVal)
          })
        );
      }
    }
    selections.push({
      kind: Kind4.FIELD,
      name: { kind: Kind4.NAME, value: key },
      ...selectionSet ? { selectionSet } : {},
      ...argsNodes ? { arguments: argsNodes } : {}
    });
  }
  return selections;
}
function createGateway() {
  return {
    configure: (config) => {
      return new PylonGateway(config);
    }
  };
}
var schemaCache, InjectNeedsTransform, PylonPatchTransform, PylonGateway;
var init_gateway = __esm({
  "src/gateway.ts"() {
    "use strict";
    schemaCache = /* @__PURE__ */ new Map();
    InjectNeedsTransform = class {
      constructor(needs) {
        this.needs = needs;
      }
      transformRequest(originalRequest) {
        if (!this.needs || Object.keys(this.needs).length === 0) {
          return originalRequest;
        }
        const needsSelections = buildSelectionsFromNeeds(this.needs);
        let rootFieldFound = false;
        const document = visit(originalRequest.document, {
          Field(node) {
            if (!rootFieldFound && node.selectionSet) {
              rootFieldFound = true;
              const existingNames = new Set(
                node.selectionSet.selections.filter((s) => s.kind === Kind4.FIELD).map((s) => s.name.value)
              );
              const mergedSelections = [...node.selectionSet.selections];
              for (const selection of needsSelections) {
                if (selection.kind === Kind4.FIELD && !existingNames.has(selection.name.value)) {
                  mergedSelections.push(selection);
                }
              }
              return {
                ...node,
                selectionSet: {
                  ...node.selectionSet,
                  selections: mergedSelections
                }
              };
            }
          }
        });
        return { ...originalRequest, document };
      }
    };
    PylonPatchTransform = class {
      constructor(patches, api) {
        this.patches = patches;
        this.api = api;
      }
      // Injects __typename into all selection sets via AST traversal to ensure
      // deterministic resolution of interface/union types for downstream runtime transformations.
      transformRequest(originalRequest) {
        const document = visit(originalRequest.document, {
          SelectionSet(node) {
            const hasTypename = node.selections.some(
              (s) => s.kind === Kind4.FIELD && s.name.value === "__typename"
            );
            if (!hasTypename) {
              return {
                ...node,
                selections: [
                  ...node.selections,
                  {
                    kind: Kind4.FIELD,
                    name: { kind: Kind4.NAME, value: "__typename" }
                  }
                ]
              };
            }
          }
        });
        return { ...originalRequest, document };
      }
      // Intercepts the execution phase to recursively apply registered patches to the payload.
      transformResult(originalResult) {
        return this.applyTransforms(originalResult);
      }
      applyTransforms(data) {
        if (!data || typeof data !== "object") return data;
        if (Array.isArray(data)) return data.map((item) => this.applyTransforms(item));
        const processedData = { ...data };
        for (const key in processedData) {
          processedData[key] = this.applyTransforms(processedData[key]);
        }
        const typeName = data.__typename;
        const patchFn = this.patches[typeName];
        if (patchFn) {
          const patchedData = patchFn(processedData, this.api);
          if (patchedData && typeof patchedData === "object" && !Array.isArray(patchedData)) {
            return {
              ...processedData,
              ...patchedData
            };
          }
          return patchedData;
        }
        return processedData;
      }
    };
    PylonGateway = class {
      constructor(config) {
        this.config = config;
        this.apiContext = {
          delegate: this.delegate.bind(this)
        };
      }
      apiContext;
      async delegate(key, ...opts) {
        const { info } = getResolveInfo2();
        const ctx = getContext2();
        if (!info || !ctx) throw new Error("Pylon context missing");
        const options = opts[0];
        const args = options?.args || {};
        const needs = options?.needs;
        const [rootType, fieldName] = String(key).split(".");
        if (!rootType || !fieldName) {
          throw new Error(
            `Invalid delegate key format: ${String(key)}. Expected "Operation.field"`
          );
        }
        const operationMap = {
          Query: OperationTypeNode.QUERY,
          Mutation: OperationTypeNode.MUTATION,
          Subscription: OperationTypeNode.SUBSCRIPTION
        };
        const operation = operationMap[rootType];
        if (!operation) {
          throw new Error(
            `Unsupported operation type "${rootType}" in key "${String(key)}"`
          );
        }
        if (!schemaCache.has(this.config.url)) {
          const executor = buildHTTPExecutor({
            endpoint: this.config.url,
            headers: (r) => ({
              ...this.config.headers ? this.config.headers(r?.context) : {}
            })
          });
          const schemaPromise = schemaFromExecutor(executor).then(
            (schema2) => wrapSchema({ schema: schema2, executor })
          );
          schemaCache.set(this.config.url, schemaPromise);
        }
        const schema = await schemaCache.get(this.config.url);
        const result = await delegateToSchema({
          schema,
          operation,
          fieldName,
          args,
          context: ctx,
          info,
          transforms: [
            new InjectNeedsTransform(needs),
            // Injects requested AST fields
            new PylonPatchTransform(this.config.patches, this.apiContext)
          ]
        });
        return result;
      }
    };
  }
});

// src/index.ts
import { createPubSub } from "graphql-yoga";
var init_src = __esm({
  "src/index.ts"() {
    init_pylon_handler();
    init_context();
    init_create_decorator();
    init_define_pylon();
    init_get_env();
    init_use_auth2();
    init_use_pages();
    init_app();
    init_gateway();
  }
});
init_src();
export {
  ServiceError,
  app,
  asyncContext,
  authMiddleware,
  createDecorator,
  createGateway,
  executeConfig,
  createPubSub as experimentalCreatePubSub,
  getContext,
  getEnv,
  getResolveInfo,
  handler,
  requireAuth,
  setContext,
  useAuth,
  usePages
};
//# sourceMappingURL=index.js.map