@modularizer/plat 0.15.0 → 0.16.0

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.
Files changed (122) hide show
  1. package/dist/bridge/cli.d.ts +3 -0
  2. package/dist/bridge/cli.d.ts.map +1 -0
  3. package/dist/bridge/cli.js +128 -0
  4. package/dist/bridge/cli.js.map +1 -0
  5. package/dist/bridge/http-forwarder.d.ts +51 -0
  6. package/dist/bridge/http-forwarder.d.ts.map +1 -0
  7. package/dist/bridge/http-forwarder.js +564 -0
  8. package/dist/bridge/http-forwarder.js.map +1 -0
  9. package/dist/bridge/index.d.ts +57 -0
  10. package/dist/bridge/index.d.ts.map +1 -0
  11. package/dist/bridge/index.js +69 -0
  12. package/dist/bridge/index.js.map +1 -0
  13. package/dist/cli/commands/api-proxy.d.ts.map +1 -1
  14. package/dist/cli/commands/api-proxy.js +5 -7
  15. package/dist/cli/commands/api-proxy.js.map +1 -1
  16. package/dist/cli/commands/jwt-cmd.d.ts.map +1 -1
  17. package/dist/cli/commands/jwt-cmd.js +1 -4
  18. package/dist/cli/commands/jwt-cmd.js.map +1 -1
  19. package/dist/cli/proxy.d.ts.map +1 -1
  20. package/dist/cli/proxy.js +9 -20
  21. package/dist/cli/proxy.js.map +1 -1
  22. package/dist/cli/runtime.d.ts.map +1 -1
  23. package/dist/cli/runtime.js +2 -6
  24. package/dist/cli/runtime.js.map +1 -1
  25. package/dist/client/css-transport-plugin.d.ts.map +1 -1
  26. package/dist/client/css-transport-plugin.js +40 -0
  27. package/dist/client/css-transport-plugin.js.map +1 -1
  28. package/dist/client/openapi-client.d.ts +5 -0
  29. package/dist/client/openapi-client.d.ts.map +1 -1
  30. package/dist/client/openapi-client.js +21 -2
  31. package/dist/client/openapi-client.js.map +1 -1
  32. package/dist/client-entry.d.ts +2 -0
  33. package/dist/client-entry.d.ts.map +1 -1
  34. package/dist/client-entry.js +2 -0
  35. package/dist/client-entry.js.map +1 -1
  36. package/dist/client-server-entry.d.ts +1 -0
  37. package/dist/client-server-entry.d.ts.map +1 -1
  38. package/dist/client-server-entry.js +1 -0
  39. package/dist/client-server-entry.js.map +1 -1
  40. package/dist/client-side-server/authority-default.d.ts +13 -0
  41. package/dist/client-side-server/authority-default.d.ts.map +1 -0
  42. package/dist/client-side-server/authority-default.js +13 -0
  43. package/dist/client-side-server/authority-default.js.map +1 -0
  44. package/dist/client-side-server/channel.d.ts.map +1 -1
  45. package/dist/client-side-server/channel.js +179 -78
  46. package/dist/client-side-server/channel.js.map +1 -1
  47. package/dist/client-side-server/identity.d.ts +1 -0
  48. package/dist/client-side-server/identity.d.ts.map +1 -1
  49. package/dist/client-side-server/identity.js +117 -0
  50. package/dist/client-side-server/identity.js.map +1 -1
  51. package/dist/client-side-server/mqtt-webrtc.d.ts +13 -2
  52. package/dist/client-side-server/mqtt-webrtc.d.ts.map +1 -1
  53. package/dist/client-side-server/mqtt-webrtc.js +17 -2
  54. package/dist/client-side-server/mqtt-webrtc.js.map +1 -1
  55. package/dist/client-side-server/plat-bridge.js +3 -1
  56. package/dist/client-side-server/plat-bridge.js.map +1 -1
  57. package/dist/client-side-server/plat-fetch.d.ts +3 -0
  58. package/dist/client-side-server/plat-fetch.d.ts.map +1 -1
  59. package/dist/client-side-server/plat-fetch.js +199 -29
  60. package/dist/client-side-server/plat-fetch.js.map +1 -1
  61. package/dist/client-side-server/plat-service-worker-client.d.ts.map +1 -1
  62. package/dist/client-side-server/plat-service-worker-client.js +3 -0
  63. package/dist/client-side-server/plat-service-worker-client.js.map +1 -1
  64. package/dist/client-side-server/plat-service-worker.js +30 -0
  65. package/dist/client-side-server/plat-service-worker.js.map +1 -1
  66. package/dist/client-side-server/protocol.d.ts +22 -0
  67. package/dist/client-side-server/protocol.d.ts.map +1 -1
  68. package/dist/client-side-server/protocol.js.map +1 -1
  69. package/dist/client-side-server/runtime-fetch.d.ts +20 -0
  70. package/dist/client-side-server/runtime-fetch.d.ts.map +1 -0
  71. package/dist/client-side-server/runtime-fetch.js +32 -0
  72. package/dist/client-side-server/runtime-fetch.js.map +1 -0
  73. package/dist/client-side-server/runtime.d.ts.map +1 -1
  74. package/dist/client-side-server/runtime.js +36 -7
  75. package/dist/client-side-server/runtime.js.map +1 -1
  76. package/dist/client-side-server/server.d.ts.map +1 -1
  77. package/dist/client-side-server/server.js +29 -5
  78. package/dist/client-side-server/server.js.map +1 -1
  79. package/dist/server/config/types.d.ts +12 -1
  80. package/dist/server/config/types.d.ts.map +1 -1
  81. package/dist/server/core.d.ts.map +1 -1
  82. package/dist/server/core.js +25 -14
  83. package/dist/server/core.js.map +1 -1
  84. package/dist/server/docs-html.d.ts +11 -0
  85. package/dist/server/docs-html.d.ts.map +1 -0
  86. package/dist/server/docs-html.js +30 -0
  87. package/dist/server/docs-html.js.map +1 -0
  88. package/dist/server/operation-registry.d.ts +1 -0
  89. package/dist/server/operation-registry.d.ts.map +1 -1
  90. package/dist/server/operation-registry.js +16 -2
  91. package/dist/server/operation-registry.js.map +1 -1
  92. package/dist/server/routing.d.ts +5 -0
  93. package/dist/server/routing.d.ts.map +1 -1
  94. package/dist/server/routing.js +32 -2
  95. package/dist/server/routing.js.map +1 -1
  96. package/dist/server/rpc-protocol-plugin.js +2 -2
  97. package/dist/server/rpc-protocol-plugin.js.map +1 -1
  98. package/dist/server/server.d.ts +4 -0
  99. package/dist/server/server.d.ts.map +1 -1
  100. package/dist/server/server.js +229 -53
  101. package/dist/server/server.js.map +1 -1
  102. package/dist/server/transports.d.ts +1 -0
  103. package/dist/server/transports.d.ts.map +1 -1
  104. package/dist/server/webrtc-plugin.d.ts +21 -0
  105. package/dist/server/webrtc-plugin.d.ts.map +1 -0
  106. package/dist/server/webrtc-plugin.js +198 -0
  107. package/dist/server/webrtc-plugin.js.map +1 -0
  108. package/dist/static/file-response.d.ts +2 -0
  109. package/dist/static/file-response.d.ts.map +1 -1
  110. package/dist/static/file-response.js +2 -0
  111. package/dist/static/file-response.js.map +1 -1
  112. package/dist/static/plat-static-folders.d.ts +11 -0
  113. package/dist/static/plat-static-folders.d.ts.map +1 -0
  114. package/dist/static/plat-static-folders.js +44 -0
  115. package/dist/static/plat-static-folders.js.map +1 -0
  116. package/dist/static/static-folder.d.ts +4 -0
  117. package/dist/static/static-folder.d.ts.map +1 -1
  118. package/dist/static/static-folder.js +27 -2
  119. package/dist/static/static-folder.js.map +1 -1
  120. package/dist/types/endpoints.d.ts +3 -0
  121. package/dist/types/endpoints.d.ts.map +1 -1
  122. package/package.json +5 -1
@@ -1,5 +1,6 @@
1
1
  import express from "express";
2
2
  import { createServer as createHttpServer } from 'node:http';
3
+ import nodePath from 'node:path';
3
4
  import { applyRateLimitCheck, applyRateLimitRefund, createInMemoryRateLimit } from "./rate-limit/index.js";
4
5
  import { applyTokenLimitCheck, applyTokenLimitFailure, applyTokenLimitResponse, createInMemoryTokenLimit } from "./token-limit/index.js";
5
6
  import { applyCacheCheck, applyCacheStore, createInMemoryCache } from "./cache/index.js";
@@ -14,10 +15,12 @@ import { DEFAULT_RPC_PATH } from '../rpc.js';
14
15
  import { InMemoryCallSessionController } from "./call-sessions.js";
15
16
  import { createRpcProtocolPlugin } from './rpc-protocol-plugin.js';
16
17
  import { createFileQueueProtocolPlugin } from './file-queue-protocol-plugin.js';
18
+ import { createWebRTCProtocolPlugin } from './webrtc-plugin.js';
17
19
  import { PLATOperationRegistry } from './operation-registry.js';
18
20
  import { PLATServerCore } from './core.js';
19
21
  import { createAuthorityServerController } from './authority-server.js';
20
22
  import { isFileResponse } from '../static/file-response.js';
23
+ import { createWildcardRouteMatcher } from './routing.js';
21
24
  export class PLATServer {
22
25
  app;
23
26
  options;
@@ -31,6 +34,8 @@ export class PLATServer {
31
34
  staticFolders = [];
32
35
  pendingRootFolder;
33
36
  core;
37
+ teardownRuntimeCallbacks = [];
38
+ serverCreatedAt = Date.now();
34
39
  constructor(options = {}, ...ControllerClasses) {
35
40
  this.app = express();
36
41
  this.options = {
@@ -187,6 +192,7 @@ export class PLATServer {
187
192
  }
188
193
  // General help endpoint
189
194
  this.app.get('/help', (req, res) => {
195
+ const origin = `${req.protocol}://${req.headers.host ?? ''}`;
190
196
  const help = {
191
197
  endpoints: {
192
198
  'GET /endpoints': 'List all available API endpoints with descriptions',
@@ -225,12 +231,12 @@ export class PLATServer {
225
231
  },
226
232
  },
227
233
  examples: [
228
- 'curl http://localhost:3000/endpoints',
229
- 'curl "http://localhost:3000/endpoints?method=POST"',
230
- 'curl "http://localhost:3000/endpoints?search=user"',
231
- 'curl "http://localhost:3000/endpoints?format=json"',
232
- 'curl "http://localhost:3000/openapi-jq?filter=.paths"',
233
- 'curl "http://localhost:3000/api/users?help=true"',
234
+ `curl ${origin}/endpoints`,
235
+ `curl "${origin}/endpoints?method=POST"`,
236
+ `curl "${origin}/endpoints?search=user"`,
237
+ `curl "${origin}/endpoints?format=json"`,
238
+ `curl "${origin}/openapi-jq?filter=.paths"`,
239
+ `curl "${origin}/api/users?help=true"`,
234
240
  ],
235
241
  };
236
242
  res.json(help);
@@ -407,12 +413,24 @@ export class PLATServer {
407
413
  * No path parameters in decorators - all routing is done by method names.
408
414
  */
409
415
  register(...ControllerClasses) {
416
+ const exactRegistrations = [];
417
+ const wildcardRegistrations = [];
410
418
  for (const registered of this.core.registerControllers(...ControllerClasses)) {
411
419
  const { operation: rpcOperation, route } = registered;
412
- const { methodName, path: fullPath } = route;
413
- const httpMethod = route.method.toLowerCase();
420
+ const { methodName } = route;
414
421
  const routeMeta = rpcOperation.routeMeta;
415
- const handler = async (req, res) => {
422
+ const handler = async (req, res, next) => {
423
+ if (rpcOperation.isWildcard) {
424
+ const resolved = this.resolveOperation({
425
+ method: req.method,
426
+ path: req.path,
427
+ });
428
+ if (!resolved || resolved.methodName !== rpcOperation.methodName) {
429
+ next();
430
+ return;
431
+ }
432
+ }
433
+ const requestPath = rpcOperation.isWildcard ? req.path : rpcOperation.path;
416
434
  let input = {
417
435
  ...req.params,
418
436
  ...req.query,
@@ -436,7 +454,7 @@ export class PLATServer {
436
454
  const session = this.options.calls.controller.create({
437
455
  operationId: methodName,
438
456
  method: req.method,
439
- path: fullPath,
457
+ path: requestPath,
440
458
  });
441
459
  const abortController = new AbortController();
442
460
  this.options.calls.controller.setCancel(session.id, () => abortController.abort());
@@ -454,7 +472,7 @@ export class PLATServer {
454
472
  const deferredEnvelope = {
455
473
  protocol: 'http',
456
474
  method: req.method,
457
- path: fullPath,
475
+ path: requestPath,
458
476
  headers: req.headers,
459
477
  input,
460
478
  ctx,
@@ -484,7 +502,7 @@ export class PLATServer {
484
502
  const execution = await this.dispatchTransportCall(rpcOperation, {
485
503
  protocol: 'http',
486
504
  method: req.method,
487
- path: fullPath,
505
+ path: requestPath,
488
506
  headers: req.headers,
489
507
  input,
490
508
  ctx,
@@ -535,10 +553,31 @@ export class PLATServer {
535
553
  }
536
554
  }
537
555
  };
538
- // Register route with Express (canonical route)
539
- this.app[httpMethod](fullPath, handler);
556
+ if (rpcOperation.isWildcard) {
557
+ wildcardRegistrations.push({ registered, handler });
558
+ }
559
+ else {
560
+ exactRegistrations.push({ registered, handler });
561
+ }
562
+ }
563
+ for (const { registered, handler } of exactRegistrations) {
564
+ this.registerExpressRoute(registered.route.method, registered.operation.path, handler);
540
565
  for (const variant of registered.variants) {
541
- this.app[variant.method.toLowerCase()](variant.path, handler);
566
+ this.registerExpressRoute(variant.method, variant.path, handler);
567
+ }
568
+ }
569
+ for (const { registered, handler } of wildcardRegistrations) {
570
+ const wildcardRoutes = [
571
+ { method: registered.operation.method, path: registered.operation.path },
572
+ ...registered.variants,
573
+ ];
574
+ const seen = new Set();
575
+ for (const wildcardRoute of wildcardRoutes) {
576
+ const key = `${wildcardRoute.method} ${wildcardRoute.path}`;
577
+ if (seen.has(key))
578
+ continue;
579
+ seen.add(key);
580
+ this.registerWildcardExpressRoute(wildcardRoute.method, wildcardRoute.path, handler);
542
581
  }
543
582
  }
544
583
  // Register static folder routes (after all API routes for correct priority)
@@ -556,39 +595,144 @@ export class PLATServer {
556
595
  * Create CORS middleware
557
596
  */
558
597
  createCORSMiddleware(corsConfig) {
559
- const config = corsConfig === true
560
- ? { origin: '*', credentials: false }
561
- : corsConfig === false
598
+ // If corsConfig is a function, handle per-request
599
+ if (typeof corsConfig === 'function') {
600
+ return async (req, res, next) => {
601
+ try {
602
+ const result = await corsConfig(req);
603
+ if (!result) {
604
+ // CORS not allowed
605
+ if (req.method === 'OPTIONS') {
606
+ res.status(403).end();
607
+ return;
608
+ }
609
+ return next();
610
+ }
611
+ const config = typeof result === 'object' ? result : { origin: '*' };
612
+ const requestOrigin = req.headers.origin;
613
+ let origin = undefined;
614
+ if (typeof config.origin === 'string') {
615
+ if (config.origin === '*' && config.credentials) {
616
+ // Invalid: do not set header
617
+ origin = undefined;
618
+ }
619
+ else {
620
+ origin = config.origin;
621
+ }
622
+ }
623
+ else if (Array.isArray(config.origin)) {
624
+ if (requestOrigin && config.origin.includes(requestOrigin)) {
625
+ origin = requestOrigin;
626
+ }
627
+ else if (!config.credentials) {
628
+ origin = config.origin[0] ?? '*';
629
+ }
630
+ }
631
+ else if (typeof config.origin === 'function') {
632
+ if (requestOrigin && config.origin(requestOrigin)) {
633
+ origin = requestOrigin;
634
+ }
635
+ }
636
+ if (origin) {
637
+ res.setHeader('Access-Control-Allow-Origin', origin);
638
+ res.setHeader('Vary', 'Origin');
639
+ }
640
+ if (config.credentials) {
641
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
642
+ }
643
+ if (config.methods) {
644
+ res.setHeader('Access-Control-Allow-Methods', config.methods.join(', '));
645
+ }
646
+ else if (req.method === 'OPTIONS') {
647
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH');
648
+ }
649
+ if (config.headers) {
650
+ res.setHeader('Access-Control-Allow-Headers', config.headers.join(', '));
651
+ }
652
+ else if (req.method === 'OPTIONS' && req.headers['access-control-request-headers']) {
653
+ res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers']);
654
+ }
655
+ if (config.exposedHeaders) {
656
+ res.setHeader('Access-Control-Expose-Headers', config.exposedHeaders.join(', '));
657
+ }
658
+ if (config.maxAge) {
659
+ res.setHeader('Access-Control-Max-Age', String(config.maxAge));
660
+ }
661
+ if (req.method === 'OPTIONS') {
662
+ res.status(204).end();
663
+ return;
664
+ }
665
+ next();
666
+ }
667
+ catch (err) {
668
+ // On error, disallow CORS
669
+ if (req.method === 'OPTIONS') {
670
+ res.status(500).end();
671
+ return;
672
+ }
673
+ next();
674
+ }
675
+ };
676
+ }
677
+ else {
678
+ // Static config (original logic)
679
+ const config = corsConfig === true
562
680
  ? { origin: '*', credentials: false }
563
- : corsConfig;
564
- return (req, res, next) => {
565
- const origin = typeof config.origin === 'string'
566
- ? config.origin
567
- : Array.isArray(config.origin)
568
- ? config.origin[0] ?? '*'
569
- : '*';
570
- res.setHeader('Access-Control-Allow-Origin', origin);
571
- if (config.credentials) {
572
- res.setHeader('Access-Control-Allow-Credentials', 'true');
573
- }
574
- if (config.methods) {
575
- res.setHeader('Access-Control-Allow-Methods', config.methods.join(', '));
576
- }
577
- if (config.headers) {
578
- res.setHeader('Access-Control-Allow-Headers', config.headers.join(', '));
579
- }
580
- if (config.exposedHeaders) {
581
- res.setHeader('Access-Control-Expose-Headers', config.exposedHeaders.join(', '));
582
- }
583
- if (config.maxAge) {
584
- res.setHeader('Access-Control-Max-Age', String(config.maxAge));
585
- }
586
- if (req.method === 'OPTIONS') {
587
- res.status(200).end();
588
- return;
589
- }
590
- next();
591
- };
681
+ : corsConfig === false
682
+ ? { origin: '*', credentials: false }
683
+ : corsConfig;
684
+ return (req, res, next) => {
685
+ const requestOrigin = req.headers.origin;
686
+ let origin = undefined;
687
+ if (typeof config.origin === 'string') {
688
+ if (config.origin === '*' && config.credentials) {
689
+ // Invalid: do not set header
690
+ origin = undefined;
691
+ }
692
+ else {
693
+ origin = config.origin;
694
+ }
695
+ }
696
+ else if (Array.isArray(config.origin)) {
697
+ if (requestOrigin && config.origin.includes(requestOrigin)) {
698
+ origin = requestOrigin;
699
+ }
700
+ else if (!config.credentials) {
701
+ origin = config.origin[0] ?? '*';
702
+ }
703
+ }
704
+ if (origin) {
705
+ res.setHeader('Access-Control-Allow-Origin', origin);
706
+ res.setHeader('Vary', 'Origin');
707
+ }
708
+ if (config.credentials) {
709
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
710
+ }
711
+ if (config.methods) {
712
+ res.setHeader('Access-Control-Allow-Methods', config.methods.join(', '));
713
+ }
714
+ else if (req.method === 'OPTIONS') {
715
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH');
716
+ }
717
+ if (config.headers) {
718
+ res.setHeader('Access-Control-Allow-Headers', config.headers.join(', '));
719
+ }
720
+ else if (req.method === 'OPTIONS' && req.headers['access-control-request-headers']) {
721
+ res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers']);
722
+ }
723
+ if (config.exposedHeaders) {
724
+ res.setHeader('Access-Control-Expose-Headers', config.exposedHeaders.join(', '));
725
+ }
726
+ if (config.maxAge) {
727
+ res.setHeader('Access-Control-Max-Age', String(config.maxAge));
728
+ }
729
+ if (req.method === 'OPTIONS') {
730
+ res.status(204).end();
731
+ return;
732
+ }
733
+ next();
734
+ };
735
+ }
592
736
  }
593
737
  /**
594
738
  * Extract path parameters from a path string
@@ -942,7 +1086,7 @@ export class PLATServer {
942
1086
  return this.executeOperation({
943
1087
  methodName: operation.methodName,
944
1088
  controllerTag: operation.controllerTag,
945
- fullPath: operation.path,
1089
+ fullPath: envelope.path,
946
1090
  transportMethod: envelope.method,
947
1091
  routeMeta: operation.routeMeta,
948
1092
  controllerMeta: operation.controllerMeta,
@@ -1057,7 +1201,7 @@ export class PLATServer {
1057
1201
  openapi: '3.1.0',
1058
1202
  info: {
1059
1203
  title: 'plat API',
1060
- version: '0.15.0',
1204
+ version: '0.16.0',
1061
1205
  },
1062
1206
  paths,
1063
1207
  };
@@ -1118,6 +1262,13 @@ export class PLATServer {
1118
1262
  config: this.options.fileQueue || undefined,
1119
1263
  }),
1120
1264
  ];
1265
+ if (this.options.webrtc) {
1266
+ builtInPlugins.push(createWebRTCProtocolPlugin(this.options.webrtc, {
1267
+ getOpenAPISpec: () => this.options.openapi,
1268
+ getToolsList: () => Array.from(this.tools.values()),
1269
+ getServerStartedAt: () => this.serverCreatedAt,
1270
+ }));
1271
+ }
1121
1272
  const transportRuntime = this.createTransportRuntime();
1122
1273
  const allPlugins = [...builtInPlugins, ...(this.options.protocolPlugins ?? [])];
1123
1274
  for (const plugin of allPlugins) {
@@ -1127,10 +1278,13 @@ export class PLATServer {
1127
1278
  void plugin.attach?.(transportRuntime, hostContext);
1128
1279
  void plugin.start?.(transportRuntime);
1129
1280
  }
1281
+ this.teardownRuntimeCallbacks = allPlugins
1282
+ .filter((p) => typeof p.teardown === 'function')
1283
+ .map((p) => () => p.teardown(transportRuntime));
1130
1284
  // Register root static folder as lowest-priority fallback
1131
1285
  if (this.pendingRootFolder) {
1132
1286
  const rootFolder = this.pendingRootFolder;
1133
- this.app.get('*', async (req, res, next) => {
1287
+ this.app.get(/.*/, async (req, res, next) => {
1134
1288
  const subPath = req.path.replace(/^\//, '');
1135
1289
  try {
1136
1290
  const fileResponse = await rootFolder.folder.resolve(subPath);
@@ -1150,6 +1304,15 @@ export class PLATServer {
1150
1304
  return this;
1151
1305
  }
1152
1306
  async close() {
1307
+ for (const cb of this.teardownRuntimeCallbacks) {
1308
+ try {
1309
+ await cb();
1310
+ }
1311
+ catch (err) {
1312
+ this.logger.error('[plugin teardown] error during close', err);
1313
+ }
1314
+ }
1315
+ this.teardownRuntimeCallbacks = [];
1153
1316
  if (!this.httpServer)
1154
1317
  return;
1155
1318
  await new Promise((resolve, reject) => {
@@ -1162,6 +1325,17 @@ export class PLATServer {
1162
1325
  });
1163
1326
  this.httpServer = undefined;
1164
1327
  }
1328
+ registerExpressRoute(method, path, handler) {
1329
+ this.app[method.toLowerCase()](path, handler);
1330
+ }
1331
+ registerWildcardExpressRoute(method, basePath, handler) {
1332
+ const matcher = createWildcardRouteMatcher(basePath);
1333
+ if (method === '*') {
1334
+ this.app.all(matcher, handler);
1335
+ return;
1336
+ }
1337
+ this.registerExpressRoute(method, matcher, handler);
1338
+ }
1165
1339
  registerStaticFolderRoutes() {
1166
1340
  for (const sf of this.staticFolders) {
1167
1341
  if (sf.name === 'root') {
@@ -1186,7 +1360,7 @@ export class PLATServer {
1186
1360
  }
1187
1361
  };
1188
1362
  this.app.get(prefix, handler);
1189
- this.app.get(`${prefix}/*`, handler);
1363
+ this.app.get(new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/.*`), handler);
1190
1364
  }
1191
1365
  }
1192
1366
  sendFileResponse(res, fileResponse) {
@@ -1197,9 +1371,11 @@ export class PLATServer {
1197
1371
  if (fileResponse.maxAge !== undefined) {
1198
1372
  res.setHeader('Cache-Control', `public, max-age=${fileResponse.maxAge}`);
1199
1373
  }
1374
+ if (fileResponse.status && fileResponse.status !== 200) {
1375
+ res.status(fileResponse.status);
1376
+ }
1200
1377
  if (fileResponse.kind === 'path') {
1201
- const path = require('node:path');
1202
- res.sendFile(path.resolve(fileResponse.source));
1378
+ res.sendFile(nodePath.resolve(fileResponse.source));
1203
1379
  }
1204
1380
  else {
1205
1381
  const content = fileResponse.source;