@emeryld/rrroutes-server 2.6.1 → 2.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -341,6 +341,44 @@ function adaptRouteBeforeMw(mw) {
341
341
  }
342
342
  };
343
343
  }
344
+ function runRouteBeforeHandler(mw, args) {
345
+ return new Promise((resolve, reject) => {
346
+ let settled = false;
347
+ const next = (err) => {
348
+ if (settled) return;
349
+ settled = true;
350
+ if (err) {
351
+ reject(err);
352
+ return;
353
+ }
354
+ resolve();
355
+ };
356
+ try {
357
+ const result = mw({ ...args, next });
358
+ if (result && typeof result.then === "function") {
359
+ ;
360
+ result.then(() => {
361
+ if (settled) return;
362
+ settled = true;
363
+ resolve();
364
+ }).catch((err) => {
365
+ if (settled) return;
366
+ settled = true;
367
+ reject(err);
368
+ });
369
+ return;
370
+ }
371
+ if (!settled) {
372
+ settled = true;
373
+ resolve();
374
+ }
375
+ } catch (err) {
376
+ if (settled) return;
377
+ settled = true;
378
+ reject(err);
379
+ }
380
+ });
381
+ }
344
382
  function logHandlerDebugWithRoutesLogger(logger, event) {
345
383
  if (!logger || event.type !== "handler") return;
346
384
  const payload = [
@@ -393,6 +431,7 @@ function createRRRoute(router, config) {
393
431
  const send = config.send ?? defaultSend;
394
432
  const { emit: defaultEmitDebug, mode: defaultDebugMode } = createServerDebugEmitter(config.debug);
395
433
  const knownLeaves = /* @__PURE__ */ new Map();
434
+ const registeredDefs = /* @__PURE__ */ new Map();
396
435
  const decorateDebugEvent = (isVerbose, event, details) => {
397
436
  if (!isVerbose || !details) return event;
398
437
  return { ...event, ...details };
@@ -694,6 +733,71 @@ function createRRRoute(router, config) {
694
733
  };
695
734
  router[method](path, ...before, wrapped);
696
735
  registered.add(key);
736
+ registeredDefs.set(key, {
737
+ leaf,
738
+ def
739
+ });
740
+ }
741
+ async function invoke(key, args) {
742
+ const registration = registeredDefs.get(key);
743
+ if (!registration) {
744
+ throw new Error(`No controller registered for route: ${key}`);
745
+ }
746
+ const { leaf, def } = registration;
747
+ const req = args.req;
748
+ const res = args.res;
749
+ const next = args.next ?? (() => void 0);
750
+ const parsedParams = leaf.cfg.paramsSchema ? lowProfileParse(leaf.cfg.paramsSchema, args.params) : args.params;
751
+ const parsedQueryInput = leaf.cfg.querySchema ? decodeJsonLikeQueryValue(args.query) : args.query;
752
+ let parsedQuery = parsedQueryInput;
753
+ if (leaf.cfg.querySchema) {
754
+ try {
755
+ parsedQuery = lowProfileParse(
756
+ leaf.cfg.querySchema,
757
+ parsedQueryInput
758
+ );
759
+ } catch (err) {
760
+ const parseError = new Error(
761
+ `Query parsing error: ${err.message ?? String(err)}`
762
+ );
763
+ parseError.raw = JSON.stringify(args.query);
764
+ parseError.cause = err;
765
+ throw parseError;
766
+ }
767
+ }
768
+ const parsedBody = leaf.cfg.bodySchema ? lowProfileParse(leaf.cfg.bodySchema, args.body) : args.body;
769
+ const payload = {
770
+ params: parsedParams,
771
+ query: parsedQuery,
772
+ body: parsedBody,
773
+ bodyFiles: args.bodyFiles
774
+ };
775
+ setRouteRequestPayload(res, payload);
776
+ const ctx = args.ctx ?? await config.buildCtx({
777
+ req,
778
+ res
779
+ });
780
+ res.locals[CTX_SYMBOL] = ctx;
781
+ for (const before of def.before ?? []) {
782
+ await runRouteBeforeHandler(before, {
783
+ req,
784
+ res,
785
+ ctx,
786
+ ...payload
787
+ });
788
+ }
789
+ const result = await def.handler({
790
+ req,
791
+ res,
792
+ next,
793
+ ctx,
794
+ params: payload.params,
795
+ query: payload.query,
796
+ body: payload.body,
797
+ bodyFiles: payload.bodyFiles
798
+ });
799
+ const output = validateOutput && leaf.cfg.outputSchema ? lowProfileParse(leaf.cfg.outputSchema, result) : result;
800
+ return output;
697
801
  }
698
802
  function registerControllers(registry, controllers, all) {
699
803
  for (const leaf of registry.all) {
@@ -738,6 +842,7 @@ function createRRRoute(router, config) {
738
842
  register,
739
843
  registerControllers,
740
844
  warnMissingControllers: warnMissing,
845
+ invoke,
741
846
  getRegisteredKeys: () => Array.from(registered)
742
847
  };
743
848
  }
@@ -751,6 +856,51 @@ function bindAll(router, registry, controllers, config) {
751
856
  server.registerControllers(registry, controllers);
752
857
  return router;
753
858
  }
859
+ function batchLeaf(server, path, registry, options) {
860
+ const method = String(options?.method ?? "post").toLowerCase();
861
+ const allowedMethods = ["get", "post", "put", "patch", "delete"];
862
+ if (!allowedMethods.includes(method)) {
863
+ throw new Error(
864
+ `Invalid batch method "${String(options?.method)}". Expected one of: ${allowedMethods.join(", ")}.`
865
+ );
866
+ }
867
+ ;
868
+ server.router[method](
869
+ path,
870
+ async (req, res, next) => {
871
+ try {
872
+ const body = req.body;
873
+ if (!isPlainObject2(body)) {
874
+ throw new Error(
875
+ "Batch request body must be a plain object keyed by encoded route identifiers."
876
+ );
877
+ }
878
+ const output = {};
879
+ for (const [encodedKey, value] of Object.entries(body)) {
880
+ const decodedKey = decodeURIComponent(encodedKey);
881
+ const leaf = registry.byKey[decodedKey];
882
+ if (!leaf) {
883
+ throw new Error(`Unknown batch route key: ${decodedKey}`);
884
+ }
885
+ const payload = isPlainObject2(value) ? value : {};
886
+ output[encodedKey] = await server.invoke(decodedKey, {
887
+ req,
888
+ res,
889
+ next,
890
+ params: payload.params,
891
+ query: payload.query,
892
+ body: payload.body,
893
+ bodyFiles: payload.bodyFiles
894
+ });
895
+ }
896
+ res.json(output);
897
+ } catch (err) {
898
+ next(err);
899
+ }
900
+ }
901
+ );
902
+ return server.router;
903
+ }
754
904
  var defineControllers = () => (m) => m;
755
905
  function warnMissingControllers(router, registry, logger) {
756
906
  const registeredStore = router[REGISTERED_ROUTES_SYMBOL];
@@ -1578,6 +1728,7 @@ var createConnectionLoggingMiddleware = (options = {}) => {
1578
1728
  };
1579
1729
  export {
1580
1730
  CTX_SYMBOL,
1731
+ batchLeaf,
1581
1732
  bindAll,
1582
1733
  bindExpressRoutes,
1583
1734
  buildLowProfileLeaf,