convex
Version:
Client for the Convex Cloud
158 lines (157 loc) • 5.79 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var router_exports = {};
__export(router_exports, {
HttpRouter: () => HttpRouter,
httpRouter: () => httpRouter
});
module.exports = __toCommonJS(router_exports);
var import_authentication_impl = require("./impl/authentication_impl.js");
var import_http_impl = require("./impl/http_impl.js");
var import_syscall = require("./impl/syscall.js");
const routableMethods = [
"GET",
"POST",
"PUT",
"DELETE",
"OPTIONS",
"PATCH"
];
function normalizeMethod(method) {
if (method === "HEAD")
return "GET";
return method;
}
const httpRouter = () => new HttpRouter();
class HttpRouter {
constructor() {
this.exactRoutes = /* @__PURE__ */ new Map();
this.prefixRoutes = /* @__PURE__ */ new Map();
this.isRouter = true;
this.route = (spec) => {
if (!spec.handler)
throw new Error(`route requires handler`);
if (!spec.method)
throw new Error(`route requires method`);
const { method, handler } = spec;
if (!routableMethods.includes(method)) {
throw new Error(
`'${method}' is not an allowed HTTP method (like GET, POST, PUT etc.)`
);
}
if ("path" in spec) {
if (!spec.path.startsWith("/")) {
throw new Error(`path '${spec.path}' does not start with a /`);
}
const prefixes = this.prefixRoutes.get(method) || /* @__PURE__ */ new Map();
for (const [prefix, _] of prefixes.entries()) {
if (spec.path.startsWith(prefix)) {
throw new Error(
`${spec.method} path ${spec.path} is shadowed by pathPrefix ${prefix}`
);
}
}
const methods = this.exactRoutes.has(spec.path) ? this.exactRoutes.get(spec.path) : /* @__PURE__ */ new Map();
if (methods.has(method)) {
throw new Error(
`Path '${spec.path}' for method ${method} already in use`
);
}
methods.set(method, handler);
this.exactRoutes.set(spec.path, methods);
} else {
if (!spec.pathPrefix.startsWith("/")) {
throw new Error(`path '${spec.pathPrefix}' does not start with a /`);
}
if (!spec.pathPrefix.endsWith("/")) {
throw new Error(`pathPrefix ${spec.pathPrefix} must end with a /`);
}
const prefixes = this.prefixRoutes.get(method) || /* @__PURE__ */ new Map();
for (const [prefix, _] of prefixes.entries()) {
if (spec.pathPrefix.startsWith(prefix)) {
throw new Error(
`${spec.method} pathPrefix ${spec.pathPrefix} is shadowed by pathPrefix ${prefix}`
);
}
}
prefixes.set(spec.pathPrefix, handler);
this.prefixRoutes.set(method, prefixes);
}
};
this.getRoutes = () => {
const exactPaths = [...this.exactRoutes.keys()].sort();
const exact = exactPaths.flatMap(
(path) => [...this.exactRoutes.get(path).keys()].sort().map(
(method) => [path, method, this.exactRoutes.get(path).get(method)]
)
);
const prefixPathMethods = [...this.prefixRoutes.keys()].sort();
const prefixes = prefixPathMethods.flatMap(
(method) => [...this.prefixRoutes.get(method).keys()].sort().map(
(pathPrefix) => [
`${pathPrefix}*`,
method,
this.prefixRoutes.get(method).get(pathPrefix)
]
)
);
return [...exact, ...prefixes];
};
this.lookup = (path, method) => {
method = normalizeMethod(method);
const exactMatch = this.exactRoutes.get(path)?.get(method);
if (exactMatch)
return [exactMatch, method, path];
const prefixes = this.prefixRoutes.get(method) || /* @__PURE__ */ new Map();
for (const [pathPrefix, endpoint] of prefixes.entries()) {
if (path.startsWith(pathPrefix)) {
return [endpoint, method, `${pathPrefix}*`];
}
}
return null;
};
this.runRequest = async (argsStr) => {
const request = (0, import_syscall.performJsSyscall)("requestFromConvexJson", {
convexJson: JSON.parse(argsStr)
});
const pathname = new URL(request.url).pathname;
const method = request.method;
const match = this.lookup(pathname, method);
if (!match) {
const response2 = new Response(`No HttpEndpoint routed for ${pathname}`, {
status: 404
});
return JSON.stringify(
(0, import_syscall.performJsSyscall)("convexJsonFromResponse", { response: response2 })
);
}
const [endpoint, _method, _path] = match;
const calls = (0, import_http_impl.setupHttpCalls)();
const ctx = {
...calls,
auth: (0, import_authentication_impl.setupAuth)()
};
const response = await endpoint(ctx, request);
return JSON.stringify(
(0, import_syscall.performJsSyscall)("convexJsonFromResponse", { response })
);
};
}
}
//# sourceMappingURL=router.js.map