UNPKG

@getcronit/pylon

Version:

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

1,619 lines 55.7 kB
import {
  __require
} from "./chunk-R6NNLVZJ.js";

// src/index.ts
import { createPubSub } from "graphql-yoga";

// 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";

// 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";

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

// src/app/index.ts
var app = new Hono();
app.use("*", compress());
app.use("*", 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("*", except(["/__pylon/*"], logger()));
var pluginsMiddleware = [];
var 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";

// src/resolve-info.ts
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
var executionAsyncContext = new AsyncLocalStorage2();
var getResolveInfo = () => {
  const store = executionAsyncContext.getStore();
  if (!store) {
    throw new Error("Resolve info is not available");
  }
  return store;
};

// src/define-pylon.ts
var uniqueFieldsCache = /* @__PURE__ */ new WeakMap();
var selectionSetCache = /* @__PURE__ */ new WeakMap();
var 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;
};
var 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);
    const isPylonResolver = resolver[name] && typeof resolver[name] === "function";
    if (hasAliases && !isPylonResolver) {
      result[name] = (args, ctx, info) => {
        const aliasKey = info.fieldNodes[0].alias?.value;
        const schemaKey = info.fieldName;
        console.log(aliasKey, schemaKey, resolver, name);
        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;
};
var 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;
};
var 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 = isOriginalGraphQLError;
var 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);
        }
      };
    }
  };
};

// src/plugins/use-unhandled-route.ts
import { html } from "hono/html";

// package.json
var version = "3.0.0-canary-20260508115545.74ba3bff3f7ade973010148205bb756b3e5642cc";

// src/plugins/use-unhandled-route.ts
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
        );
      });
    }
  };
}

// 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>
          `
        );
      });
    }
  };
}

// src/app/pylon-handler.ts
var resolveLazyObject = (obj) => {
  return typeof obj === "function" ? obj() : obj;
};
var loadPluginsMiddleware = async (plugins) => {
  for (const plugin of plugins) {
    await plugin.setup?.(app);
    if (plugin.middleware) {
      pluginsMiddleware.push(plugin.middleware);
    }
  }
};
var 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;
};
var 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;
}

// 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) {
    }
  }
}

// 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";

// 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;
}
var convertPKCS1ToPKCS8 = (pkcs1) => {
  const key = crypto.createPrivateKey(pkcs1);
  return key.export({
    type: "pkcs8",
    format: "pem"
  });
};
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 importPrivateKey = async (pkcs1Pem) => {
  const pkcs8Pem = convertPKCS1ToPKCS8(pkcs1Pem);
  return await importPKCS8PrivateKey(pkcs8Pem);
};

// src/plugins/use-auth/use-auth.ts
var 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");
  }
};
var openidConfigCache;
var 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;
};
var PylonAuthException = class extends HTTPException {
  // Same constructor as HTTPException
  constructor(...args) {
    args[1] = {
      ...args[1],
      message: `PylonAuthException: ${args[1]?.message}`
    };
    super(...args);
  }
};
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);
        }
      });
    }
  };
}

// src/plugins/use-auth/auth-require.ts
import { env as env2 } from "hono/adapter";
import { HTTPException as HTTPException2 } from "hono/http-exception";
var 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,
          headers: {
            "Missing-Roles": checks.roles.join(","),
            "Obtained-Roles": roles.join(",")
          }
        });
        throw new HTTPException2(resError.status, {
          res: resError
        });
      }
    }
    return next();
  };
  return middleware;
};
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(e.message, {
            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);
  });
}

// 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 } = await import("./setup-XP3KJV3R.js");
      return setup(api);
    },
    build: async (api) => {
      const { build } = await import("./build-TKNMTVMY.js");
      return build(api);
    }
  };
}

// src/gateway.ts
import { delegateToSchema } from "@graphql-tools/delegate";
import { buildHTTPExecutor } from "@graphql-tools/executor-http";
import { schemaFromExecutor, wrapSchema } from "@graphql-tools/wrap";
import {
  getNamedType as getNamedType2,
  isEnumType,
  Kind as Kind4,
  OperationTypeNode,
  TypeInfo,
  visit,
  visitWithTypeInfo
} from "graphql";
var schemaCache = /* @__PURE__ */ new Map();
function astFromJSValue(value) {
  if (value === null || value === void 0) {
    return { kind: Kind4.NULL };
  }
  if (typeof value === "string") {
    return { kind: Kind4.STRING, value };
  }
  if (typeof value === "number") {
    return Number.isInteger(value) ? { kind: Kind4.INT, value: String(value) } : { kind: Kind4.FLOAT, value: String(value) };
  }
  if (typeof value === "boolean") {
    return { kind: Kind4.BOOLEAN, value };
  }
  if (Array.isArray(value)) {
    return {
      kind: Kind4.LIST,
      values: value.map(astFromJSValue)
    };
  }
  if (typeof value === "object") {
    return {
      kind: Kind4.OBJECT,
      fields: Object.entries(value).filter(([_, val]) => val !== void 0).map(([key, val]) => ({
        kind: Kind4.OBJECT_FIELD,
        name: { kind: Kind4.NAME, value: key },
        value: astFromJSValue(val)
      }))
    };
  }
  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;
}
var 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 };
  }
};
var InlineArgsTransform = class {
  constructor(wrapperArgs) {
    this.wrapperArgs = wrapperArgs;
  }
  transformRequest(originalRequest, delegationContext) {
    const rootInlineArguments = this.wrapperArgs && Object.keys(this.wrapperArgs).length > 0 ? Object.entries(this.wrapperArgs).filter(([_, val]) => val !== void 0).map(
      ([key, value]) => ({
        kind: Kind4.ARGUMENT,
        name: { kind: Kind4.NAME, value: key },
        value: astFromJSValue(value)
      })
    ) : [];
    const targetFieldName = delegationContext.fieldName;
    let targetFieldFound = false;
    const variables = originalRequest.variables || {};
    let inlineDocument = visit(originalRequest.document, {
      // A. Inject our wrapper args into the ROOT field
      Field(node) {
        if (!targetFieldFound && node.name.value === targetFieldName) {
          targetFieldFound = true;
          const existingArgs = node.arguments || [];
          const mergedArgs = [...existingArgs];
          for (const newArg of rootInlineArguments) {
            const existingIdx = mergedArgs.findIndex(
              (a) => a.name.value === newArg.name.value
            );
            if (existingIdx > -1) mergedArgs[existingIdx] = newArg;
            else mergedArgs.push(newArg);
          }
          return { ...node, arguments: mergedArgs };
        }
      },
      // B. PRUNE missing arguments entirely
      Argument(node) {
        if (node.value.kind === Kind4.VARIABLE) {
          const varName = node.value.name.value;
          if (!(varName in variables) || variables[varName] === void 0) {
            return null;
          }
        }
      },
      // C. PRUNE missing input object fields entirely (e.g. filters: { status: $missing })
      ObjectField(node) {
        if (node.value.kind === Kind4.VARIABLE) {
          const varName = node.value.name.value;
          if (!(varName in variables) || variables[varName] === void 0) {
            return null;
          }
        }
      },
      // D. Inline all surviving variables (and safely fallback to NullNode just in case)
      Variable(node) {
        const varName = node.name.value;
        return astFromJSValue(variables[varName]);
      },
      // E. Wipe variable definitions
      OperationDefinition(node) {
        return { ...node, variableDefinitions: [] };
      }
    });
    const typeInfo = new TypeInfo(delegationContext.targetSchema);
    inlineDocument = visit(
      inlineDocument,
      visitWithTypeInfo(typeInfo, {
        StringValue(node) {
          const inputType = typeInfo.getInputType();
          if (inputType) {
            const namedType = getNamedType2(inputType);
            if (isEnumType(namedType)) {
              return { kind: Kind4.ENUM, value: node.value };
            }
          }
        }
      })
    );
    return {
      ...originalRequest,
      document: inlineDocument,
      variables: {}
      // Wipe the payload, we don't need it anymore!
    };
  }
};
var 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;
  }
};
var PylonGateway = class {
  constructor(config) {
    this.config = config;
    this.apiContext = {
      delegate: this.delegate.bind(this)
    };
  }
  apiContext;
  async delegate(key, ...opts) {
    const { info } = getResolveInfo();
    const ctx = getContext();
    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 InlineArgsTransform(args),
        // Injects arguments into the AST
        new PylonPatchTransform(this.config.patches, this.apiContext)
      ]
    });
    return result;
  }
};
function createGateway() {
  return {
    configure: (config) => {
      return new PylonGateway(config);
    }
  };
}

export {
  asyncContext,
  getContext,
  setContext,
  app,
  getResolveInfo,
  ServiceError,
  executeConfig,
  handler,
  createDecorator,
  getEnv,
  useAuth,
  authMiddleware,
  requireAuth,
  usePages,
  createGateway,
  createPubSub
};
//# sourceMappingURL=chunk-2W3G375V.js.map