@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/README.md +44 -1
- package/dist/index.cjs +152 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +151 -0
- package/dist/index.js.map +1 -1
- package/dist/routesV3.server.d.ts +32 -0
- package/package.json +1 -1
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,
|