@plurid/plurid-react-server 0.0.0-14 → 0.0.0-16

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 (29) hide show
  1. package/README.md +69 -5
  2. package/distribution/index.d.mts +244 -0
  3. package/distribution/index.d.ts +244 -6
  4. package/distribution/index.js +1573 -1056
  5. package/distribution/index.js.map +1 -0
  6. package/distribution/index.mjs +1642 -0
  7. package/distribution/index.mjs.map +1 -0
  8. package/package.json +129 -133
  9. package/distribution/__tests__/sanity.test.d.ts +0 -0
  10. package/distribution/data/constants/general/index.d.ts +0 -34
  11. package/distribution/data/constants/index.d.ts +0 -2
  12. package/distribution/data/constants/stiller/index.d.ts +0 -2
  13. package/distribution/data/interfaces/external/index.d.ts +0 -151
  14. package/distribution/data/interfaces/index.d.ts +0 -2
  15. package/distribution/data/interfaces/internal/index.d.ts +0 -83
  16. package/distribution/data/templates/index.d.ts +0 -2
  17. package/distribution/index.es.js +0 -1095
  18. package/distribution/objects/ContentGenerator/index.d.ts +0 -7
  19. package/distribution/objects/LiveServer/index.d.ts +0 -13
  20. package/distribution/objects/Renderer/index.d.ts +0 -22
  21. package/distribution/objects/Renderer/template/index.d.ts +0 -3
  22. package/distribution/objects/Server/index.d.ts +0 -57
  23. package/distribution/objects/Stiller/__tests__/index.test.d.ts +0 -1
  24. package/distribution/objects/Stiller/index.d.ts +0 -24
  25. package/distribution/objects/StillsGenerator/index.d.ts +0 -8
  26. package/distribution/objects/StillsManager/index.d.ts +0 -9
  27. package/distribution/utilities/pttp/index.d.ts +0 -6
  28. package/distribution/utilities/template/index.d.ts +0 -9
  29. package/distribution/utilities/wrapping/index.d.ts +0 -28
@@ -0,0 +1,1642 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // source/objects/Server/index.ts
9
+ import fs2 from "fs";
10
+ import path2 from "path";
11
+ import express from "express";
12
+ import compression from "compression";
13
+ import open from "open";
14
+ import {
15
+ ServerStyleSheet
16
+ } from "styled-components";
17
+ import {
18
+ time,
19
+ uuid
20
+ } from "@plurid/plurid-functions";
21
+ import {
22
+ routing
23
+ } from "@plurid/plurid-engine";
24
+ import {
25
+ serverComputeMetastate
26
+ } from "@plurid/plurid-react";
27
+
28
+ // source/data/constants/general/index.ts
29
+ var DEFAULT_SERVER_PORT = process.env.PORT ? parseInt(process.env.PORT) : 8080;
30
+ var DEFAULT_SERVER_OPTIONS_SERVER_NAME = "Plurid Server";
31
+ var DEFAULT_SERVER_OPTIONS_HOSTNAME = "origin";
32
+ var DEFAULT_SERVER_OPTIONS_QUIET = false;
33
+ var DEFAULT_SERVER_OPTIONS_COMPRESSION = true;
34
+ var DEFAULT_SERVER_OPTIONS_OPEN = false;
35
+ var DEFAULT_SERVER_OPTIONS_BUILD_DIRECTORY = "build";
36
+ var DEFAULT_SERVER_OPTIONS_ASSETS_DIRECTORY = "assets";
37
+ var DEFAULT_SERVER_OPTIONS_STILLS_DIRECTORY = "stills";
38
+ var DEFAULT_SERVER_OPTIONS_GATEWAY = "/gateway";
39
+ var DEFAULT_SERVER_OPTIONS = {
40
+ SERVER_NAME: DEFAULT_SERVER_OPTIONS_SERVER_NAME,
41
+ HOSTNAME: DEFAULT_SERVER_OPTIONS_HOSTNAME,
42
+ QUIET: DEFAULT_SERVER_OPTIONS_QUIET,
43
+ COMPRESSION: DEFAULT_SERVER_OPTIONS_COMPRESSION,
44
+ OPEN: DEFAULT_SERVER_OPTIONS_OPEN,
45
+ BUILD_DIRECTORY: DEFAULT_SERVER_OPTIONS_BUILD_DIRECTORY,
46
+ ASSETS_DIRECTORY: DEFAULT_SERVER_OPTIONS_ASSETS_DIRECTORY,
47
+ STILLS_DIRECTORY: DEFAULT_SERVER_OPTIONS_STILLS_DIRECTORY,
48
+ GATEWAY: DEFAULT_SERVER_OPTIONS_GATEWAY
49
+ };
50
+ var DEFAULT_RENDERER_LANGUAGE = "en";
51
+ var DEFAULT_RENDERER_ROOT = "root";
52
+ var DEFAULT_RENDERER_PLURID_STATE = "{}";
53
+ var DEFAULT_RENDERER_VENDOR_SCRIPT_SOURCE = "/vendor.js";
54
+ var DEFAULT_RENDERER_MAIN_SCRIPT_SOURCE = "/index.js";
55
+ var DEFAULT__PRELOADED_PLURID_METASTATE__ = "__PRELOADED_PLURID_METASTATE__";
56
+ var CATCH_ALL_ROUTE = "*";
57
+ var CATCH_ALL_ROUTE_PATTERN = /.*/;
58
+ var NOT_FOUND_ROUTE = process.env.PLURID_SERVER_NOT_FOUND_ROUTE || "/not-found";
59
+ var PTTP_ROUTE = process.env.PLURID_SERVER_PTTP_ROUTE || "/pttp";
60
+ var environment = {
61
+ production: process.env.ENV_MODE === "production",
62
+ development: process.env.ENV_MODE === "development"
63
+ };
64
+
65
+ // source/data/constants/stiller/index.ts
66
+ var defaultStillerOptions = {
67
+ waitUntil: "networkidle0",
68
+ timeout: 3e4,
69
+ ignore: []
70
+ };
71
+
72
+ // source/utilities/template/index.ts
73
+ import {
74
+ minify
75
+ } from "html-minifier-terser";
76
+ var cleanTemplate = (template2) => {
77
+ return minify(
78
+ template2,
79
+ {
80
+ collapseWhitespace: true,
81
+ conservativeCollapse: true,
82
+ collapseInlineTagWhitespace: false
83
+ }
84
+ );
85
+ };
86
+ var resolveBackgroundStyle = (store) => {
87
+ const defaultBackground = {
88
+ gradientBackground: "hsl(220, 10%, 32%)",
89
+ gradientForeground: "hsl(220, 10%, 18%)"
90
+ };
91
+ try {
92
+ const storeJSON = JSON.parse(store);
93
+ const generalPluridTheme = storeJSON?.themes?.general;
94
+ if (!generalPluridTheme) {
95
+ return defaultBackground;
96
+ }
97
+ const gradientBackground = generalPluridTheme.type === "dark" ? generalPluridTheme.backgroundColorTertiary : generalPluridTheme.backgroundColorPrimary;
98
+ const gradientForeground = generalPluridTheme.type === "dark" ? generalPluridTheme.backgroundColorPrimary : generalPluridTheme.backgroundColorTertiary;
99
+ return {
100
+ gradientBackground,
101
+ gradientForeground
102
+ };
103
+ } catch (error) {
104
+ return defaultBackground;
105
+ }
106
+ };
107
+ var escapeAttribute = (value) => {
108
+ return String(value).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
109
+ };
110
+ var recordToString = (record) => {
111
+ if (!record) {
112
+ return "";
113
+ }
114
+ return Object.entries(record).map(([key, value]) => `${key}="${escapeAttribute(value)}"`).join(" ");
115
+ };
116
+ var assetsPathRewrite = (content) => {
117
+ return content.replace(
118
+ /="client\//g,
119
+ '="/'
120
+ );
121
+ };
122
+ var safeStore = (store) => {
123
+ return store.replace(
124
+ /</g,
125
+ "\\u003c"
126
+ );
127
+ };
128
+ var globalsInjector = (globals) => {
129
+ let globalsScript = "";
130
+ for (const [key, value] of Object.entries(globals)) {
131
+ const globalScript = `window.${key} = ${value};
132
+ `;
133
+ globalsScript += globalScript;
134
+ }
135
+ return globalsScript;
136
+ };
137
+
138
+ // source/data/templates/index.ts
139
+ var NOT_FOUND_TEMPLATE = cleanTemplate(`
140
+ <!DOCTYPE html>
141
+ <html>
142
+ <head>
143
+ <title>[404] Not Found</title>
144
+ <style>
145
+ html, body {
146
+ margin: 0;
147
+ background: #242b33;
148
+ color: #ddd;
149
+ user-select: none;
150
+ }
151
+
152
+ .not-found {
153
+ position: absolute;
154
+ top: 50%;
155
+ left: 50%;
156
+ transform: translate(-50%, -50%);
157
+ font-family: 'Ubuntu', -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto;
158
+ }
159
+ </style>
160
+ </head>
161
+
162
+ <body>
163
+ <div class="not-found">[404] Not Found</div>
164
+ </body>
165
+ </html>
166
+ `);
167
+ var SERVER_ERROR_TEMPLATE = cleanTemplate(`
168
+ <!DOCTYPE html>
169
+ <html>
170
+ <head>
171
+ <title>[500] Server Error</title>
172
+ <style>
173
+ html, body {
174
+ margin: 0;
175
+ background: #242b33;
176
+ color: #ddd;
177
+ user-select: none;
178
+ }
179
+
180
+ .error {
181
+ position: absolute;
182
+ top: 50%;
183
+ left: 50%;
184
+ transform: translate(-50%, -50%);
185
+ font-family: 'Ubuntu', -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto;
186
+ }
187
+ </style>
188
+ </head>
189
+
190
+ <body>
191
+ <div class="error">[500] Server Error</div>
192
+ </body>
193
+ </html>
194
+ `);
195
+
196
+ // source/objects/Renderer/template/index.ts
197
+ var template = async (data) => {
198
+ const {
199
+ htmlLanguage,
200
+ head,
201
+ htmlAttributes,
202
+ bodyAttributes,
203
+ defaultStyle,
204
+ styles,
205
+ headScripts,
206
+ bodyScripts,
207
+ vendorScriptSource,
208
+ mainScriptSource,
209
+ root,
210
+ content,
211
+ defaultPreloadedPluridMetastate,
212
+ pluridMetastate,
213
+ globals,
214
+ minify: minify2
215
+ } = data;
216
+ const injectedGlobals = globalsInjector(globals);
217
+ const templateString = `
218
+ <!DOCTYPE html>
219
+ <html lang="${htmlLanguage}" ${htmlAttributes}>
220
+ <head>
221
+ ${head}
222
+
223
+ ${defaultStyle && `<style>
224
+ ${defaultStyle}
225
+ </style>`}
226
+
227
+ ${styles}
228
+
229
+ ${headScripts.join("\n")}
230
+
231
+ <script src="${vendorScriptSource}"></script>
232
+ <script defer src="${mainScriptSource}"></script>
233
+ </head>
234
+ <body ${bodyAttributes}>
235
+ <div id="${root}">${content}</div>
236
+
237
+ <script>
238
+ ${injectedGlobals}
239
+ window.${defaultPreloadedPluridMetastate} = ${safeStore(pluridMetastate)};
240
+ </script>
241
+
242
+ ${bodyScripts.join("\n")}
243
+ </body>
244
+ </html>
245
+ `;
246
+ if (!minify2) {
247
+ return templateString;
248
+ }
249
+ return cleanTemplate(templateString);
250
+ };
251
+ var template_default = template;
252
+
253
+ // source/objects/Renderer/index.ts
254
+ var PluridRenderer = class {
255
+ htmlLanguage;
256
+ head;
257
+ htmlAttributes;
258
+ bodyAttributes;
259
+ defaultStyle;
260
+ styles;
261
+ headScripts;
262
+ bodyScripts;
263
+ vendorScriptSource;
264
+ mainScriptSource;
265
+ root;
266
+ content;
267
+ defaultPreloadedPluridMetastate;
268
+ pluridMetastate;
269
+ globals;
270
+ minify;
271
+ constructor(configuration) {
272
+ const {
273
+ htmlLanguage,
274
+ head,
275
+ htmlAttributes,
276
+ bodyAttributes,
277
+ defaultStyle,
278
+ styles,
279
+ headScripts,
280
+ bodyScripts,
281
+ vendorScriptSource,
282
+ mainScriptSource,
283
+ content,
284
+ root,
285
+ defaultPreloadedPluridMetastate,
286
+ pluridMetastate,
287
+ globals,
288
+ minify: minify2
289
+ } = configuration;
290
+ const {
291
+ gradientBackground,
292
+ gradientForeground
293
+ // The metastate carries `themes.general` (see `serverComputeMetastate`), so the SSR'd background
294
+ // gradient matches the active theme; `resolveBackgroundStyle` falls back to a default if it can't parse.
295
+ } = resolveBackgroundStyle(pluridMetastate || "");
296
+ const defaultStyleBasic = `
297
+ body {
298
+ background: radial-gradient(ellipse at center, ${gradientBackground} 0%, ${gradientForeground} 100%);
299
+ height: 100%;
300
+ margin: 0;
301
+ }
302
+ `;
303
+ this.htmlLanguage = htmlLanguage || DEFAULT_RENDERER_LANGUAGE;
304
+ this.head = head || "";
305
+ this.htmlAttributes = htmlAttributes;
306
+ this.bodyAttributes = bodyAttributes || "";
307
+ this.defaultStyle = defaultStyle ?? defaultStyleBasic;
308
+ this.styles = styles;
309
+ this.headScripts = headScripts;
310
+ this.bodyScripts = bodyScripts;
311
+ this.vendorScriptSource = vendorScriptSource || DEFAULT_RENDERER_VENDOR_SCRIPT_SOURCE;
312
+ this.mainScriptSource = mainScriptSource || DEFAULT_RENDERER_MAIN_SCRIPT_SOURCE;
313
+ this.root = root || DEFAULT_RENDERER_ROOT;
314
+ this.content = assetsPathRewrite(content) || "";
315
+ this.defaultPreloadedPluridMetastate = defaultPreloadedPluridMetastate || DEFAULT__PRELOADED_PLURID_METASTATE__;
316
+ this.pluridMetastate = pluridMetastate || DEFAULT_RENDERER_PLURID_STATE;
317
+ this.globals = globals ?? {};
318
+ this.minify = minify2 ?? true;
319
+ }
320
+ async html() {
321
+ const data = {
322
+ htmlLanguage: this.htmlLanguage,
323
+ head: this.head,
324
+ htmlAttributes: this.htmlAttributes,
325
+ bodyAttributes: this.bodyAttributes,
326
+ defaultStyle: this.defaultStyle,
327
+ styles: this.styles,
328
+ headScripts: this.headScripts,
329
+ bodyScripts: this.bodyScripts,
330
+ vendorScriptSource: this.vendorScriptSource,
331
+ mainScriptSource: this.mainScriptSource,
332
+ root: this.root,
333
+ content: this.content,
334
+ defaultPreloadedPluridMetastate: this.defaultPreloadedPluridMetastate,
335
+ pluridMetastate: this.pluridMetastate,
336
+ globals: this.globals,
337
+ minify: this.minify
338
+ };
339
+ return template_default(data);
340
+ }
341
+ };
342
+ var Renderer_default = PluridRenderer;
343
+
344
+ // source/objects/ContentGenerator/index.tsx
345
+ import React2 from "react";
346
+ import {
347
+ renderToString
348
+ } from "react-dom/server";
349
+ import {
350
+ StyleSheetManager
351
+ } from "styled-components";
352
+ import {
353
+ HelmetProvider
354
+ } from "react-helmet-async";
355
+ import {
356
+ PluridProvider,
357
+ PluridRouterStatic
358
+ } from "@plurid/plurid-react";
359
+
360
+ // source/utilities/wrapping/index.tsx
361
+ import React from "react";
362
+ var wrapping = (WrappedComponent, WrappeeComponent, properties) => {
363
+ return class extends React.Component {
364
+ constructor(props) {
365
+ super(props);
366
+ }
367
+ render() {
368
+ return /* @__PURE__ */ React.createElement(
369
+ WrappedComponent,
370
+ {
371
+ ...properties
372
+ },
373
+ /* @__PURE__ */ React.createElement(WrappeeComponent, null)
374
+ );
375
+ }
376
+ };
377
+ };
378
+ var wrapping_default = wrapping;
379
+
380
+ // source/objects/ContentGenerator/index.tsx
381
+ var PluridContentGenerator = class {
382
+ data;
383
+ constructor(data) {
384
+ this.data = data;
385
+ }
386
+ async render() {
387
+ const {
388
+ pluridMetastate,
389
+ routes,
390
+ planes,
391
+ exterior,
392
+ shell,
393
+ routerProperties,
394
+ gateway,
395
+ gatewayEndpoint,
396
+ gatewayQuery,
397
+ helmet,
398
+ services,
399
+ stylesheet,
400
+ preserveResult,
401
+ matchedPlane,
402
+ pathname,
403
+ hostname
404
+ } = this.data;
405
+ const RoutedApplication = () => /* @__PURE__ */ React2.createElement(
406
+ PluridProvider,
407
+ {
408
+ metastate: pluridMetastate
409
+ },
410
+ /* @__PURE__ */ React2.createElement(
411
+ PluridRouterStatic,
412
+ {
413
+ path: pathname,
414
+ directPlane: matchedPlane?.value,
415
+ routes,
416
+ planes,
417
+ exterior,
418
+ shell,
419
+ gateway,
420
+ gatewayEndpoint,
421
+ gatewayQuery,
422
+ hostname,
423
+ routerProperties
424
+ }
425
+ )
426
+ );
427
+ let Wrap = wrapping_default(
428
+ HelmetProvider,
429
+ RoutedApplication,
430
+ {
431
+ context: helmet
432
+ }
433
+ );
434
+ for (const service of services) {
435
+ const preserveProperties = preserveResult?.providers?.[service.name];
436
+ Wrap = wrapping_default(
437
+ service.Provider,
438
+ Wrap,
439
+ {
440
+ ...service.properties,
441
+ ...preserveProperties
442
+ }
443
+ );
444
+ }
445
+ const content = renderToString(
446
+ /* @__PURE__ */ React2.createElement(
447
+ StyleSheetManager,
448
+ {
449
+ sheet: stylesheet.instance
450
+ },
451
+ /* @__PURE__ */ React2.createElement(Wrap, null)
452
+ )
453
+ );
454
+ return content;
455
+ }
456
+ };
457
+ var ContentGenerator_default = PluridContentGenerator;
458
+
459
+ // source/objects/StillsManager/index.ts
460
+ import path from "path";
461
+ import {
462
+ existsSync,
463
+ promises as fs
464
+ } from "fs";
465
+ var StillsManager = class {
466
+ options;
467
+ stills = /* @__PURE__ */ new Map();
468
+ constructor(options) {
469
+ this.options = options;
470
+ this.findStills();
471
+ }
472
+ get(url) {
473
+ const still = this.stills.get(url);
474
+ if (!still) {
475
+ return;
476
+ }
477
+ return still.html;
478
+ }
479
+ async findStills() {
480
+ const {
481
+ buildDirectory,
482
+ stillsDirectory
483
+ } = this.options;
484
+ const stillsLocation = `${buildDirectory}/${stillsDirectory}`;
485
+ const stillsPath = path.join(process.cwd(), stillsLocation);
486
+ if (!existsSync(stillsPath)) {
487
+ return;
488
+ }
489
+ try {
490
+ const stillsMetadata = path.join(stillsPath, "metadata.json");
491
+ const stillsMetadataFile = await fs.readFile(stillsMetadata, "utf-8");
492
+ const stillsMetadataJSON = JSON.parse(stillsMetadataFile);
493
+ if (!Array.isArray(stillsMetadataJSON)) {
494
+ return;
495
+ }
496
+ for (const still of stillsMetadataJSON) {
497
+ const stillFilePath = path.join(stillsPath, still.name);
498
+ const stillFileData = await fs.readFile(stillFilePath, "utf-8");
499
+ const stillFileJSON = JSON.parse(stillFileData);
500
+ if (!stillFileJSON) {
501
+ continue;
502
+ }
503
+ this.stills.set(stillFileJSON.route, stillFileJSON);
504
+ }
505
+ } catch (error) {
506
+ if (this.options.debug !== "none" && !this.options.quiet) {
507
+ const errorText = "Plurid Server Error: Could not read stills.";
508
+ if (this.options.debug === "error") {
509
+ console.error(errorText, error);
510
+ } else {
511
+ console.log(errorText);
512
+ }
513
+ }
514
+ return;
515
+ }
516
+ }
517
+ };
518
+ var StillsManager_default = StillsManager;
519
+
520
+ // source/utilities/pttp/index.ts
521
+ var resolveElementFromPlaneMatch = (planeMatch, elementqlEndpoint) => {
522
+ if (typeof planeMatch.data.component === "function") {
523
+ return;
524
+ }
525
+ if (typeof planeMatch.data.component === "string") {
526
+ return {
527
+ name: planeMatch.data.component,
528
+ url: elementqlEndpoint
529
+ };
530
+ }
531
+ return {
532
+ name: planeMatch.data.component.name,
533
+ url: planeMatch.data.component.url || elementqlEndpoint
534
+ };
535
+ };
536
+
537
+ // source/objects/Server/index.ts
538
+ var {
539
+ IsoMatcher: PluridIsoMatcher
540
+ } = routing;
541
+ var PluridServer = class {
542
+ routes;
543
+ planes;
544
+ preserves;
545
+ helmet;
546
+ styles;
547
+ middleware;
548
+ exterior;
549
+ shell;
550
+ routerProperties;
551
+ services;
552
+ options;
553
+ template;
554
+ usePTTP;
555
+ pttpHandler;
556
+ elementqlEndpoint;
557
+ serverApplication;
558
+ server;
559
+ port;
560
+ stills;
561
+ isoMatcher;
562
+ constructor(configuration) {
563
+ const {
564
+ routes,
565
+ planes,
566
+ preserves,
567
+ helmet,
568
+ styles,
569
+ middleware,
570
+ exterior,
571
+ shell,
572
+ routerProperties,
573
+ services,
574
+ options,
575
+ template: template2,
576
+ usePTTP,
577
+ pttpHandler,
578
+ elementqlEndpoint
579
+ } = configuration;
580
+ this.routes = routes;
581
+ this.planes = planes || [];
582
+ this.preserves = preserves;
583
+ this.helmet = helmet;
584
+ this.styles = styles || [];
585
+ this.middleware = middleware || [];
586
+ this.exterior = exterior;
587
+ this.shell = shell;
588
+ this.routerProperties = routerProperties || {};
589
+ this.services = services || [];
590
+ this.options = this.handleOptions(options);
591
+ this.template = template2;
592
+ this.usePTTP = usePTTP ?? false;
593
+ this.pttpHandler = pttpHandler;
594
+ this.elementqlEndpoint = elementqlEndpoint;
595
+ this.serverApplication = express();
596
+ this.port = DEFAULT_SERVER_PORT;
597
+ this.stills = new StillsManager_default(this.options);
598
+ this.isoMatcher = new PluridIsoMatcher(
599
+ {
600
+ routes: this.routes,
601
+ routePlanes: this.planes
602
+ },
603
+ this.options.hostname
604
+ );
605
+ this.configureServer();
606
+ this.handleEndpoints();
607
+ if (this.options.attachSignalHandlers) {
608
+ this.attachSignalHandlers();
609
+ }
610
+ }
611
+ handleProcessSignal = () => {
612
+ this.stop();
613
+ process.exit(0);
614
+ };
615
+ signalHandlersAttached = false;
616
+ attachSignalHandlers() {
617
+ if (this.signalHandlersAttached) {
618
+ return;
619
+ }
620
+ process.on("SIGINT", this.handleProcessSignal);
621
+ process.on("SIGTERM", this.handleProcessSignal);
622
+ this.signalHandlersAttached = true;
623
+ }
624
+ detachSignalHandlers() {
625
+ process.removeListener("SIGINT", this.handleProcessSignal);
626
+ process.removeListener("SIGTERM", this.handleProcessSignal);
627
+ this.signalHandlersAttached = false;
628
+ }
629
+ static analysis(pluridServer) {
630
+ return {
631
+ routes: pluridServer.routes,
632
+ options: pluridServer.options
633
+ };
634
+ }
635
+ start(port = this.port) {
636
+ this.port = port;
637
+ const serverlink = `http://localhost:${port}`;
638
+ if (this.debugAllows("info")) {
639
+ console.info(
640
+ `
641
+ [${time.stamp()}] ${this.options.serverName} Started on Port ${port}: ${serverlink}
642
+ `
643
+ );
644
+ }
645
+ this.server = this.serverApplication.listen(port);
646
+ this.open(serverlink);
647
+ return this.server;
648
+ }
649
+ stop() {
650
+ this.detachSignalHandlers();
651
+ if (this.server) {
652
+ if (this.debugAllows("info")) {
653
+ console.info(
654
+ `
655
+ [${time.stamp()}] ${this.options.serverName} Stopped on Port ${this.port}
656
+ `
657
+ );
658
+ }
659
+ this.server.close();
660
+ } else {
661
+ if (this.debugAllows("info")) {
662
+ console.info(
663
+ `
664
+ [${time.stamp()}] ${this.options.serverName} Could not be Stopped on Port ${this.port}
665
+ `
666
+ );
667
+ }
668
+ }
669
+ }
670
+ handle() {
671
+ return {
672
+ post: (path4, ...handlers) => {
673
+ this.serverApplication.post(path4, ...handlers);
674
+ return this.serverApplication;
675
+ },
676
+ patch: (path4, ...handlers) => {
677
+ this.serverApplication.patch(path4, ...handlers);
678
+ return this.serverApplication;
679
+ },
680
+ put: (path4, ...handlers) => {
681
+ this.serverApplication.put(path4, ...handlers);
682
+ return this.serverApplication;
683
+ },
684
+ delete: (path4, ...handlers) => {
685
+ this.serverApplication.delete(path4, ...handlers);
686
+ return this.serverApplication;
687
+ }
688
+ };
689
+ }
690
+ instance() {
691
+ return this.serverApplication;
692
+ }
693
+ handleEndpoints() {
694
+ this.serverApplication.get(
695
+ CATCH_ALL_ROUTE_PATTERN,
696
+ async (request, response, next) => {
697
+ this.handleGetRequest(
698
+ request,
699
+ response,
700
+ next
701
+ );
702
+ }
703
+ );
704
+ if (this.usePTTP) {
705
+ this.serverApplication.post(
706
+ PTTP_ROUTE,
707
+ express.json(),
708
+ // body parsing is built into Express 5
709
+ async (request, response, next) => {
710
+ this.handlePTTPRequest(
711
+ request,
712
+ response
713
+ );
714
+ }
715
+ );
716
+ }
717
+ }
718
+ async handleGetRequest(request, response, next) {
719
+ const requestID = request.requestID || uuid.generate();
720
+ try {
721
+ if (this.debugAllows("info")) {
722
+ console.info(
723
+ `[${time.stamp()} :: ${requestID}] (000 Start) Handling GET ${request.path}`
724
+ );
725
+ }
726
+ const ignorable = this.ignoreGetRequest(
727
+ request.path
728
+ );
729
+ if (ignorable) {
730
+ if (this.debugAllows("info")) {
731
+ const requestTime = this.computeRequestTime(request);
732
+ console.info(
733
+ `[${time.stamp()} :: ${requestID}] (204 No Content) Ignored GET ${request.path}${requestTime}`
734
+ );
735
+ }
736
+ next();
737
+ return;
738
+ }
739
+ const {
740
+ preserveResponded,
741
+ preserveResult,
742
+ preserveAfterServe
743
+ } = await this.resolvePreserve(
744
+ request,
745
+ response
746
+ );
747
+ if (preserveResponded) {
748
+ if (this.debugAllows("info")) {
749
+ const requestTime = this.computeRequestTime(request);
750
+ console.info(
751
+ `[${time.stamp()} :: ${requestID}] (204 No Content) Preserve handled GET ${request.path}${requestTime}`
752
+ );
753
+ }
754
+ return;
755
+ }
756
+ const {
757
+ externalRedirect,
758
+ matchingPath
759
+ } = this.resolveMatchingPath(
760
+ preserveResult,
761
+ request.originalUrl
762
+ );
763
+ if (externalRedirect) {
764
+ if (this.debugAllows("info")) {
765
+ const requestTime = this.computeRequestTime(request);
766
+ console.info(
767
+ `[${time.stamp()} :: ${requestID}] (302 Redirect) Handled GET ${request.path} redirect to ${matchingPath}${requestTime}`
768
+ );
769
+ }
770
+ response.status(302).redirect(matchingPath);
771
+ this.resolvePreserveAfterServe(
772
+ preserveAfterServe,
773
+ request,
774
+ response
775
+ );
776
+ return;
777
+ }
778
+ const still = this.stills.get(matchingPath);
779
+ if (still) {
780
+ if (this.debugAllows("info")) {
781
+ const requestTime = this.computeRequestTime(request);
782
+ console.info(
783
+ `[${time.stamp()} :: ${requestID}] (200 OK) Still Handled GET ${matchingPath}${requestTime}`
784
+ );
785
+ }
786
+ response.send(still);
787
+ this.resolvePreserveAfterServe(
788
+ preserveAfterServe,
789
+ request,
790
+ response
791
+ );
792
+ return;
793
+ }
794
+ const isoMatch = this.isoMatcher.match(
795
+ matchingPath,
796
+ "route"
797
+ );
798
+ if (!isoMatch) {
799
+ const notFoundStill = this.stills.get(NOT_FOUND_ROUTE);
800
+ if (notFoundStill) {
801
+ if (this.debugAllows("info")) {
802
+ const requestTime = this.computeRequestTime(request);
803
+ console.info(
804
+ `[${time.stamp()} :: ${requestID}] (404 Not Found) Handled GET ${matchingPath}${requestTime}`
805
+ );
806
+ }
807
+ response.status(404).send(notFoundStill);
808
+ this.resolvePreserveAfterServe(
809
+ preserveAfterServe,
810
+ request,
811
+ response
812
+ );
813
+ return;
814
+ }
815
+ const isoMatchNotFound = this.isoMatcher.match(
816
+ NOT_FOUND_ROUTE,
817
+ "route"
818
+ );
819
+ if (!isoMatchNotFound) {
820
+ if (this.debugAllows("info")) {
821
+ const requestTime = this.computeRequestTime(request);
822
+ console.info(
823
+ `[${time.stamp()} :: ${requestID}] (404 Not Found) Handled GET ${matchingPath}${requestTime}`
824
+ );
825
+ }
826
+ response.status(404).send(NOT_FOUND_TEMPLATE);
827
+ this.resolvePreserveAfterServe(
828
+ preserveAfterServe,
829
+ request,
830
+ response
831
+ );
832
+ return;
833
+ }
834
+ const renderer2 = await this.renderApplication(
835
+ isoMatchNotFound,
836
+ preserveResult
837
+ );
838
+ if (this.debugAllows("info")) {
839
+ const requestTime = this.computeRequestTime(request);
840
+ console.info(
841
+ `[${time.stamp()} :: ${requestID}] (404 Not Found) Handled GET ${matchingPath}${requestTime}`
842
+ );
843
+ }
844
+ response.status(404).send(await renderer2.html());
845
+ this.resolvePreserveAfterServe(
846
+ preserveAfterServe,
847
+ request,
848
+ response
849
+ );
850
+ response.status(404).end();
851
+ return;
852
+ }
853
+ const renderer = await this.renderApplication(
854
+ isoMatch,
855
+ preserveResult
856
+ );
857
+ if (this.debugAllows("info")) {
858
+ const requestTime = this.computeRequestTime(request);
859
+ console.info(
860
+ `[${time.stamp()} :: ${requestID}] (200 OK) Handled GET ${matchingPath}${requestTime}`
861
+ );
862
+ }
863
+ response.send(await renderer.html());
864
+ this.resolvePreserveAfterServe(
865
+ preserveAfterServe,
866
+ request,
867
+ response
868
+ );
869
+ return;
870
+ } catch (error) {
871
+ if (this.debugAllows("error")) {
872
+ const requestTime = this.computeRequestTime(request);
873
+ console.error(
874
+ `[${time.stamp()} :: ${requestID}] (500 Server Error) Could not handle GET ${request.path}${requestTime}`,
875
+ error
876
+ );
877
+ }
878
+ response.status(500).send(SERVER_ERROR_TEMPLATE);
879
+ return;
880
+ }
881
+ }
882
+ async handlePTTPRequest(request, response) {
883
+ const requestID = request.requestID || uuid.generate();
884
+ try {
885
+ if (this.debugAllows("info")) {
886
+ console.info(
887
+ `[${time.stamp()} :: ${requestID}] (000 Start) Handling POST ${request.path}`
888
+ );
889
+ }
890
+ response.setHeader("Access-Control-Allow-Origin", request.headers.origin || "");
891
+ response.setHeader("Access-Control-Allow-Credentials", "true");
892
+ const data = request.body;
893
+ if (!data || !data.path) {
894
+ if (this.debugAllows("warn")) {
895
+ const requestTime = this.computeRequestTime(request);
896
+ console.info(
897
+ `[${time.stamp()} :: ${requestID}] (400 Bad Request) Could not handle POST ${request.path}${requestTime}`
898
+ );
899
+ }
900
+ response.status(400).end();
901
+ return;
902
+ }
903
+ if (this.pttpHandler) {
904
+ const pttpHandled = await this.pttpHandler(
905
+ data.path
906
+ );
907
+ if (pttpHandled) {
908
+ if (this.debugAllows("info")) {
909
+ const requestTime = this.computeRequestTime(request);
910
+ console.info(
911
+ `[${time.stamp()} :: ${requestID}] (200 OK) Handled POST ${request.path}${requestTime} in custom handler`
912
+ );
913
+ }
914
+ return;
915
+ }
916
+ }
917
+ const planeMatch = this.isoMatcher.match(
918
+ data.path
919
+ );
920
+ if (!planeMatch) {
921
+ if (this.debugAllows("warn")) {
922
+ const requestTime = this.computeRequestTime(request);
923
+ console.info(
924
+ `[${time.stamp()} :: ${requestID}] (400 Bad Request) Could not handle POST ${request.path}${requestTime}`
925
+ );
926
+ }
927
+ response.status(400).end();
928
+ return;
929
+ }
930
+ const elementMatch = resolveElementFromPlaneMatch(
931
+ planeMatch,
932
+ this.elementqlEndpoint
933
+ );
934
+ if (!elementMatch) {
935
+ if (this.debugAllows("warn")) {
936
+ const requestTime = this.computeRequestTime(request);
937
+ console.info(
938
+ `[${time.stamp()} :: ${requestID}] (404 Not Found) Could not handle POST ${request.path}${requestTime}`
939
+ );
940
+ }
941
+ response.status(404).end();
942
+ return;
943
+ }
944
+ const elementURL = elementMatch.url;
945
+ if (!elementURL) {
946
+ if (this.debugAllows("warn")) {
947
+ const requestTime = this.computeRequestTime(request);
948
+ console.info(
949
+ `[${time.stamp()} :: ${requestID}] (400 Bad Request) Could not handle POST ${request.path}${requestTime}`
950
+ );
951
+ }
952
+ response.status(400).end();
953
+ return;
954
+ }
955
+ if (this.debugAllows("info")) {
956
+ const requestTime = this.computeRequestTime(request);
957
+ console.info(
958
+ `[${time.stamp()} :: ${requestID}] (200 OK) Handled POST ${request.path}${requestTime}`
959
+ );
960
+ }
961
+ const elementName = elementMatch.name;
962
+ const linksTo = [];
963
+ const element = {
964
+ url: elementURL,
965
+ name: elementName,
966
+ json: {
967
+ elements: [
968
+ {
969
+ name: elementName
970
+ }
971
+ ]
972
+ },
973
+ linksTo
974
+ };
975
+ response.json({
976
+ element
977
+ });
978
+ } catch (error) {
979
+ if (this.debugAllows("error")) {
980
+ const requestTime = this.computeRequestTime(request);
981
+ console.error(
982
+ `[${time.stamp()} :: ${requestID}] (500 Server Error) Could not handle POST ${request.path}${requestTime}`,
983
+ error
984
+ );
985
+ }
986
+ response.status(500).send(SERVER_ERROR_TEMPLATE);
987
+ return;
988
+ }
989
+ }
990
+ ignoreGetRequest(path4) {
991
+ for (const ignore of this.options.ignore) {
992
+ const normalizedIgnore = ignore.endsWith("/") && ignore.length > 1 ? ignore.slice(0, ignore.length - 1) : ignore;
993
+ if (path4 === normalizedIgnore) {
994
+ return true;
995
+ }
996
+ if (normalizedIgnore.endsWith("/*")) {
997
+ const curatedIgnore = normalizedIgnore.replace("/*", "");
998
+ if (path4.startsWith(curatedIgnore)) {
999
+ return true;
1000
+ }
1001
+ }
1002
+ }
1003
+ return false;
1004
+ }
1005
+ resolveMatchingPath(preserveResult, path4) {
1006
+ const redirect = preserveResult ? preserveResult.redirect : "";
1007
+ const externalRedirect = !!redirect?.startsWith("http");
1008
+ const matchingPath = redirect || path4;
1009
+ return {
1010
+ externalRedirect,
1011
+ matchingPath
1012
+ };
1013
+ }
1014
+ async resolvePreserve(request, response) {
1015
+ const catchAll = this.preserves.find(
1016
+ (preserve) => preserve.serve === CATCH_ALL_ROUTE
1017
+ );
1018
+ const notFound = this.preserves.find(
1019
+ (preserve) => preserve.serve === NOT_FOUND_ROUTE
1020
+ );
1021
+ const isoMatch = this.isoMatcher.match(
1022
+ request.originalUrl,
1023
+ "route"
1024
+ );
1025
+ let preserveOnServe;
1026
+ let preserveAfterServe;
1027
+ let preserveOnError;
1028
+ if (isoMatch || catchAll || notFound) {
1029
+ const preserve = catchAll ? catchAll : notFound && !isoMatch ? notFound : this.preserves.find(
1030
+ (preserve2) => preserve2.serve === isoMatch?.data.value
1031
+ );
1032
+ if (preserve) {
1033
+ preserveOnServe = preserve.onServe;
1034
+ preserveAfterServe = preserve.afterServe;
1035
+ preserveOnError = preserve.onError;
1036
+ }
1037
+ }
1038
+ let preserveResult;
1039
+ if (preserveOnServe) {
1040
+ const transmission = {
1041
+ context: {
1042
+ route: request.originalUrl,
1043
+ match: isoMatch
1044
+ },
1045
+ request,
1046
+ response
1047
+ };
1048
+ try {
1049
+ preserveResult = await preserveOnServe(transmission);
1050
+ if (preserveResult) {
1051
+ if (preserveResult.responded) {
1052
+ return {
1053
+ preserveResponded: true,
1054
+ preserveResult,
1055
+ preserveAfterServe
1056
+ };
1057
+ }
1058
+ }
1059
+ } catch (error) {
1060
+ if (preserveOnError) {
1061
+ const onErrorResponse = await preserveOnError(
1062
+ error,
1063
+ transmission
1064
+ );
1065
+ if (onErrorResponse) {
1066
+ if (onErrorResponse.responded) {
1067
+ return {
1068
+ preserveResponded: true,
1069
+ preserveResult,
1070
+ preserveAfterServe
1071
+ };
1072
+ }
1073
+ if (!onErrorResponse.depreserve) {
1074
+ return {
1075
+ preserveResponded: false,
1076
+ preserveResult,
1077
+ preserveAfterServe
1078
+ };
1079
+ }
1080
+ }
1081
+ }
1082
+ }
1083
+ }
1084
+ return {
1085
+ preserveResponded: false,
1086
+ preserveResult,
1087
+ preserveAfterServe
1088
+ };
1089
+ }
1090
+ async resolvePreserveAfterServe(preserveAfterServe, request, response) {
1091
+ if (preserveAfterServe) {
1092
+ const isoMatch = this.isoMatcher.match(
1093
+ request.originalUrl,
1094
+ "route"
1095
+ );
1096
+ const transmission = {
1097
+ context: {
1098
+ route: request.originalUrl,
1099
+ match: isoMatch
1100
+ },
1101
+ request,
1102
+ response
1103
+ };
1104
+ await preserveAfterServe(transmission);
1105
+ }
1106
+ }
1107
+ async handleGateway(path4, request, preserveResult) {
1108
+ const {
1109
+ gatewayEndpoint
1110
+ } = this.options;
1111
+ if (path4 !== gatewayEndpoint) {
1112
+ return;
1113
+ }
1114
+ const gatewayRoute = {
1115
+ path: {
1116
+ value: gatewayEndpoint
1117
+ },
1118
+ pathname: gatewayEndpoint,
1119
+ parameters: {},
1120
+ query: {
1121
+ __gatewayQuery: request.originalUrl
1122
+ },
1123
+ fragments: {
1124
+ texts: [],
1125
+ elements: []
1126
+ },
1127
+ route: gatewayEndpoint
1128
+ };
1129
+ return "";
1130
+ }
1131
+ async renderApplication(isoMatch, preserveResult, matchedPlane) {
1132
+ const globals = preserveResult?.globals;
1133
+ const mergedHtmlLanguage = preserveResult?.template?.htmlLanguage || this.template?.htmlLanguage;
1134
+ const pluridMetastate = await serverComputeMetastate(
1135
+ isoMatch,
1136
+ this.routes,
1137
+ globals,
1138
+ this.options.hostname
1139
+ );
1140
+ const {
1141
+ content,
1142
+ styles
1143
+ } = await this.getContentAndStyles(
1144
+ isoMatch,
1145
+ pluridMetastate,
1146
+ preserveResult,
1147
+ matchedPlane
1148
+ );
1149
+ const stringedStyles = this.styles.reduce(
1150
+ (accumulator, style) => accumulator + style,
1151
+ ""
1152
+ );
1153
+ const preserveStyles = preserveResult?.template?.styles?.join(" ") || "";
1154
+ const mergedStyles = styles + stringedStyles + preserveStyles;
1155
+ const {
1156
+ helmet
1157
+ } = this.helmet;
1158
+ const head = helmet ? `
1159
+ ${helmet.meta.toString()}
1160
+ ${helmet.title.toString()}
1161
+ ${helmet.base.toString()}
1162
+ ${helmet.link.toString()}
1163
+ ${helmet.style.toString()}
1164
+ ${helmet.noscript.toString()}
1165
+ ${helmet.script.toString()}
1166
+ ` : "";
1167
+ const htmlAttributes = {
1168
+ ...this.template?.htmlAttributes,
1169
+ ...helmet?.htmlAttributes.toComponent()
1170
+ };
1171
+ const mergedHtmlAttributes = recordToString(htmlAttributes) + (preserveResult?.template?.htmlAttributes || "");
1172
+ const bodyAttributes = helmet?.bodyAttributes.toString() || "";
1173
+ const preserveBodyAttributes = preserveResult?.template?.bodyAttributes || "";
1174
+ const mergedBodyAttributes = bodyAttributes + preserveBodyAttributes;
1175
+ const headScripts = this.template?.headScripts || [];
1176
+ const mergedHeadScripts = [
1177
+ ...headScripts,
1178
+ ...preserveResult?.template?.headScripts || []
1179
+ ];
1180
+ const bodyScripts = this.template?.bodyScripts || [];
1181
+ const mergedBodyScripts = [
1182
+ ...bodyScripts,
1183
+ ...preserveResult?.template?.bodyScripts || []
1184
+ ];
1185
+ const renderer = new Renderer_default({
1186
+ htmlLanguage: mergedHtmlLanguage,
1187
+ head,
1188
+ htmlAttributes: mergedHtmlAttributes,
1189
+ bodyAttributes: mergedBodyAttributes,
1190
+ defaultStyle: this.template?.defaultStyle,
1191
+ styles: mergedStyles,
1192
+ headScripts: mergedHeadScripts,
1193
+ bodyScripts: mergedBodyScripts,
1194
+ vendorScriptSource: this.template?.vendorScriptSource,
1195
+ mainScriptSource: this.template?.mainScriptSource,
1196
+ root: this.template?.root,
1197
+ content,
1198
+ defaultPreloadedPluridMetastate: this.template?.defaultPreloadedPluridMetastate,
1199
+ pluridMetastate: JSON.stringify(pluridMetastate),
1200
+ globals,
1201
+ minify: this.template?.minify
1202
+ });
1203
+ return renderer;
1204
+ }
1205
+ async getContentAndStyles(isoMatch, pluridMetastate, preserveResult, matchedPlane) {
1206
+ const stylesheet = new ServerStyleSheet();
1207
+ let content = "";
1208
+ let styles = "";
1209
+ try {
1210
+ const gateway = false;
1211
+ const gatewayQuery = "";
1212
+ const {
1213
+ gatewayEndpoint
1214
+ } = this.options;
1215
+ const contentHandler = new ContentGenerator_default({
1216
+ services: this.services,
1217
+ stylesheet,
1218
+ exterior: this.exterior,
1219
+ shell: this.shell,
1220
+ routerProperties: this.routerProperties,
1221
+ helmet: this.helmet,
1222
+ routes: this.routes,
1223
+ planes: this.planes,
1224
+ pluridMetastate,
1225
+ gateway,
1226
+ gatewayEndpoint,
1227
+ gatewayQuery,
1228
+ preserveResult,
1229
+ pathname: isoMatch.match.value,
1230
+ hostname: this.options.hostname,
1231
+ matchedPlane: isoMatch.kind === "RoutePlane" ? {
1232
+ value: isoMatch.match.value
1233
+ } : void 0
1234
+ });
1235
+ content = await contentHandler.render();
1236
+ styles = stylesheet.getStyleTags();
1237
+ } catch (error) {
1238
+ if (this.options.debug !== "none" && !this.options.quiet) {
1239
+ const errorText = `${this.options.serverName} Error: Something went wrong in getContentAndStyles().`;
1240
+ if (this.debugAllows("error")) {
1241
+ console.error(
1242
+ errorText,
1243
+ error
1244
+ );
1245
+ }
1246
+ }
1247
+ return {
1248
+ content: "",
1249
+ styles: ""
1250
+ };
1251
+ } finally {
1252
+ stylesheet.seal();
1253
+ }
1254
+ return {
1255
+ content,
1256
+ styles
1257
+ };
1258
+ }
1259
+ computeRequestTime(request) {
1260
+ const requestTime = request.requestTime;
1261
+ if (!requestTime) {
1262
+ return "";
1263
+ }
1264
+ const now = Date.now();
1265
+ const difference = now - requestTime;
1266
+ return ` in ${difference} ms`;
1267
+ }
1268
+ handleOptions(partialOptions) {
1269
+ const options = {
1270
+ serverName: partialOptions?.serverName || DEFAULT_SERVER_OPTIONS.SERVER_NAME,
1271
+ hostname: partialOptions?.hostname || DEFAULT_SERVER_OPTIONS.HOSTNAME,
1272
+ quiet: partialOptions?.quiet || DEFAULT_SERVER_OPTIONS.QUIET,
1273
+ debug: partialOptions?.debug ? partialOptions?.debug : environment.production ? "error" : "info",
1274
+ compression: partialOptions?.compression ?? DEFAULT_SERVER_OPTIONS.COMPRESSION,
1275
+ open: partialOptions?.open ?? DEFAULT_SERVER_OPTIONS.OPEN,
1276
+ buildDirectory: partialOptions?.buildDirectory || DEFAULT_SERVER_OPTIONS.BUILD_DIRECTORY,
1277
+ assetsDirectory: partialOptions?.assetsDirectory || DEFAULT_SERVER_OPTIONS.ASSETS_DIRECTORY,
1278
+ gatewayEndpoint: partialOptions?.gatewayEndpoint || DEFAULT_SERVER_OPTIONS.GATEWAY,
1279
+ staticCache: partialOptions?.staticCache || 0,
1280
+ ignore: partialOptions?.ignore || [],
1281
+ stillsDirectory: partialOptions?.stillsDirectory || DEFAULT_SERVER_OPTIONS.STILLS_DIRECTORY,
1282
+ stiller: partialOptions?.stiller || defaultStillerOptions,
1283
+ attachSignalHandlers: partialOptions?.attachSignalHandlers ?? true
1284
+ };
1285
+ return options;
1286
+ }
1287
+ configureServer() {
1288
+ const clientPath = path2.join(this.options.buildDirectory, "./client");
1289
+ this.serverApplication.disable("x-powered-by");
1290
+ this.serverApplication.use(
1291
+ (request, _, next) => {
1292
+ const requestID = uuid.generate();
1293
+ request.requestID = requestID;
1294
+ const requestTime = Date.now();
1295
+ request.requestTime = requestTime;
1296
+ next();
1297
+ }
1298
+ );
1299
+ if (this.options.compression) {
1300
+ this.serverApplication.use(
1301
+ compression()
1302
+ // @types/compression targets Express 4's handler type
1303
+ );
1304
+ this.serverApplication.get(
1305
+ "/vendor.js",
1306
+ (request, response, next) => {
1307
+ response.setHeader(
1308
+ "Content-Type",
1309
+ "application/javascript"
1310
+ );
1311
+ const vendorBrotliExists = fs2.existsSync(
1312
+ path2.join(clientPath, "vendor.js.br")
1313
+ );
1314
+ const acceptEncoding = request.header("Accept-Encoding");
1315
+ if (acceptEncoding?.includes("br") && vendorBrotliExists) {
1316
+ request.url += ".br";
1317
+ response.set("Content-Encoding", "br");
1318
+ next();
1319
+ return;
1320
+ }
1321
+ next();
1322
+ }
1323
+ );
1324
+ }
1325
+ this.serverApplication.use(
1326
+ express.static(clientPath, {
1327
+ maxAge: this.options.staticCache
1328
+ })
1329
+ );
1330
+ this.loadMiddleware();
1331
+ }
1332
+ loadMiddleware() {
1333
+ for (const middleware of this.middleware) {
1334
+ this.serverApplication.use(
1335
+ (req, res, next) => middleware(req, res, next)
1336
+ );
1337
+ }
1338
+ }
1339
+ open(serverlink) {
1340
+ try {
1341
+ const processDoNotOpen = process.env.PLURID_OPEN === "false" ? true : false;
1342
+ if (processDoNotOpen) {
1343
+ return;
1344
+ }
1345
+ if (this.options.open) {
1346
+ open(serverlink);
1347
+ }
1348
+ } catch (error) {
1349
+ return;
1350
+ }
1351
+ }
1352
+ debugAllows(level) {
1353
+ if (this.options.quiet) {
1354
+ return false;
1355
+ }
1356
+ if (this.options.debug === "none") {
1357
+ return false;
1358
+ }
1359
+ switch (level) {
1360
+ case "error":
1361
+ return true;
1362
+ case "warn":
1363
+ if (this.options.debug === "error") {
1364
+ return false;
1365
+ }
1366
+ return true;
1367
+ case "info":
1368
+ if (this.options.debug === "error" || this.options.debug === "warn") {
1369
+ return false;
1370
+ }
1371
+ return true;
1372
+ default:
1373
+ return false;
1374
+ }
1375
+ }
1376
+ };
1377
+ var Server_default = PluridServer;
1378
+
1379
+ // source/objects/LiveServer/index.ts
1380
+ import http from "http";
1381
+ import express2 from "express";
1382
+ var LiveServer = class {
1383
+ options;
1384
+ expressServer;
1385
+ httpServer;
1386
+ sockets = [];
1387
+ constructor(options) {
1388
+ this.options = this.resolveOptions(options);
1389
+ this.expressServer = express2();
1390
+ this.setupExpressServer();
1391
+ this.httpServer = http.createServer(this.expressServer);
1392
+ this.setupHttpServer();
1393
+ }
1394
+ resolveOptions = (options) => {
1395
+ const defaultServerPath = "./source/server/index.ts";
1396
+ const resolvedOptions = {
1397
+ server: options?.server || defaultServerPath
1398
+ };
1399
+ return resolvedOptions;
1400
+ };
1401
+ setupExpressServer() {
1402
+ }
1403
+ setupHttpServer() {
1404
+ this.httpServer.on("connection", (socket) => {
1405
+ this.sockets.push(socket);
1406
+ socket.once("close", () => {
1407
+ this.sockets.splice(this.sockets.indexOf(socket), 1);
1408
+ });
1409
+ });
1410
+ this.httpServer.on("error", (error) => {
1411
+ throw error;
1412
+ });
1413
+ }
1414
+ start() {
1415
+ throw new Error(
1416
+ "PluridLiveServer is not implemented yet. Use `PluridServer` (production) or a bundler dev server (tsx/Vite) for live reload."
1417
+ );
1418
+ }
1419
+ };
1420
+ var LiveServer_default = LiveServer;
1421
+
1422
+ // source/objects/StillsGenerator/index.ts
1423
+ import path3 from "path";
1424
+ import {
1425
+ promises as fs3
1426
+ } from "fs";
1427
+ import {
1428
+ fork
1429
+ } from "child_process";
1430
+ import detectPort from "detect-port";
1431
+ import {
1432
+ uuid as uuid2
1433
+ } from "@plurid/plurid-functions";
1434
+
1435
+ // source/objects/Stiller/index.ts
1436
+ var replacePluridResolution = (html) => {
1437
+ const normalResolution = "width: 1366px; height: 768px;";
1438
+ const zeroResolution = "width: 0px; height: 0px;";
1439
+ return html.replace(normalResolution, zeroResolution);
1440
+ };
1441
+ var isCurrentUserRoot = () => {
1442
+ return typeof process.getuid === "function" && process.getuid() === 0;
1443
+ };
1444
+ var render = async (browser, host, route, configuration) => {
1445
+ const start = Date.now();
1446
+ const page = await browser.newPage();
1447
+ try {
1448
+ const url = host + route;
1449
+ await page.goto(
1450
+ url,
1451
+ {
1452
+ waitUntil: configuration.waitUntil,
1453
+ timeout: configuration.timeout
1454
+ }
1455
+ );
1456
+ const pageContent = await page.content();
1457
+ const html = replacePluridResolution(pageContent);
1458
+ const stilltime = Date.now() - start;
1459
+ console.info(` Stilled '${route}' in ${(stilltime / 1e3).toFixed(2)} seconds.`);
1460
+ return {
1461
+ route,
1462
+ html,
1463
+ stilltime
1464
+ };
1465
+ } catch (error) {
1466
+ const reason = error instanceof Error ? error.message : String(error);
1467
+ throw new Error(`Could not still '${route}': ${reason}`, { cause: error });
1468
+ } finally {
1469
+ await page.close();
1470
+ }
1471
+ };
1472
+ var Stiller = class {
1473
+ puppeteer = null;
1474
+ host;
1475
+ routes;
1476
+ configuration;
1477
+ constructor(options) {
1478
+ try {
1479
+ this.puppeteer = __require("puppeteer");
1480
+ } catch (_error) {
1481
+ this.puppeteer = null;
1482
+ }
1483
+ const {
1484
+ host,
1485
+ routes,
1486
+ configuration
1487
+ } = options;
1488
+ this.host = host;
1489
+ this.routes = routes;
1490
+ this.configuration = configuration;
1491
+ }
1492
+ async *still() {
1493
+ if (!this.puppeteer) {
1494
+ throw new Error(
1495
+ "Plurid Stiller: the optional 'puppeteer' dependency is not installed. Install it to generate stills (npm install puppeteer)."
1496
+ );
1497
+ }
1498
+ const browser = await this.puppeteer.launch({
1499
+ defaultViewport: {
1500
+ width: 1366,
1501
+ height: 768
1502
+ },
1503
+ headless: true,
1504
+ args: isCurrentUserRoot() ? ["--no-sandbox"] : void 0
1505
+ });
1506
+ try {
1507
+ for (const route of this.routes) {
1508
+ yield await render(
1509
+ browser,
1510
+ this.host,
1511
+ route,
1512
+ this.configuration
1513
+ );
1514
+ }
1515
+ } finally {
1516
+ await browser.close();
1517
+ }
1518
+ }
1519
+ };
1520
+ var Stiller_default = Stiller;
1521
+
1522
+ // source/objects/StillsGenerator/index.ts
1523
+ var StillsGenerator = class {
1524
+ options;
1525
+ constructor(options) {
1526
+ this.options = this.resolveOptions(options);
1527
+ }
1528
+ resolveOptions(options) {
1529
+ const stillsGeneratorOptions = {
1530
+ server: options?.server ?? "./build/server.js",
1531
+ build: options?.build ?? "./build/"
1532
+ };
1533
+ return stillsGeneratorOptions;
1534
+ }
1535
+ async initialize() {
1536
+ const serverPath = path3.join(process.cwd(), this.options.server);
1537
+ const buildPath = path3.join(process.cwd(), this.options.build);
1538
+ let serverModule;
1539
+ try {
1540
+ serverModule = __require(serverPath);
1541
+ } catch (error) {
1542
+ const reason = error instanceof Error ? error.message : String(error);
1543
+ throw new Error(
1544
+ `Plurid StillsGenerator: could not load the built server at '${serverPath}'. Build the server first so the generator can read its routes. (${reason})`,
1545
+ { cause: error }
1546
+ );
1547
+ }
1548
+ const pluridServer = serverModule?.default ?? serverModule;
1549
+ const serverInformation = Server_default.analysis(pluridServer);
1550
+ const stillerOptions = serverInformation.options.stiller;
1551
+ const serverPort = await detectPort(9900) + "";
1552
+ const child = fork(serverPath, [], {
1553
+ stdio: "pipe",
1554
+ env: {
1555
+ PORT: serverPort,
1556
+ PLURID_OPEN: "false"
1557
+ }
1558
+ });
1559
+ try {
1560
+ const stillRoutes = [];
1561
+ for (const route of serverInformation.routes) {
1562
+ if (route.value.includes("/:")) {
1563
+ continue;
1564
+ }
1565
+ if (stillerOptions.ignore.includes(route.value)) {
1566
+ continue;
1567
+ }
1568
+ stillRoutes.push(route);
1569
+ }
1570
+ const stillRoutesPaths = stillRoutes.map((stillRoute) => stillRoute.value);
1571
+ console.info("\n Parsed the following still routes:");
1572
+ for (const stillRoutePath of stillRoutesPaths) {
1573
+ console.info(` ${stillRoutePath}`);
1574
+ }
1575
+ await new Promise((resolve) => setTimeout(resolve, 1500));
1576
+ const startTime = Date.now();
1577
+ const estimatedDuration = 3 * serverInformation.routes.length;
1578
+ console.info(`
1579
+ Starting to generate stills... (this may take about ${estimatedDuration} seconds)
1580
+ `);
1581
+ const stiller = new Stiller_default({
1582
+ host: "http://localhost:" + serverPort,
1583
+ routes: [
1584
+ ...stillRoutesPaths
1585
+ ],
1586
+ configuration: {
1587
+ waitUntil: stillerOptions.waitUntil,
1588
+ timeout: stillerOptions.timeout
1589
+ }
1590
+ });
1591
+ const sequence = stiller.still();
1592
+ const stills = [];
1593
+ let next;
1594
+ while (!(next = await sequence.next()).done) {
1595
+ stills.push(next.value);
1596
+ }
1597
+ const endTime = Date.now();
1598
+ const duration = (endTime - startTime) / 1e3;
1599
+ const plural = stills.length === 1 ? "" : "s";
1600
+ console.info(`
1601
+ Generated ${stills.length} still${plural} in ${duration.toFixed(2)} seconds.
1602
+ `);
1603
+ const stillsPath = path3.join(buildPath, "./stills");
1604
+ await fs3.mkdir(
1605
+ stillsPath,
1606
+ {
1607
+ recursive: true
1608
+ }
1609
+ );
1610
+ const metadataFile = [];
1611
+ for (const still of stills) {
1612
+ if (!still) {
1613
+ continue;
1614
+ }
1615
+ const stillName = uuid2.generate() + ".json";
1616
+ const metadataItem = {
1617
+ route: still.route,
1618
+ name: stillName
1619
+ };
1620
+ metadataFile.push(metadataItem);
1621
+ const stillJSON = JSON.stringify(still, null, 4);
1622
+ const stillFile = path3.join(stillsPath, stillName);
1623
+ await fs3.writeFile(stillFile, stillJSON);
1624
+ }
1625
+ const metadataFilePath = path3.join(stillsPath, "metadata.json");
1626
+ const metadataJSON = JSON.stringify(metadataFile, null, 4);
1627
+ await fs3.writeFile(metadataFilePath, metadataJSON);
1628
+ } finally {
1629
+ child.kill("SIGTERM");
1630
+ }
1631
+ }
1632
+ };
1633
+ var StillsGenerator_default = StillsGenerator;
1634
+
1635
+ // source/index.ts
1636
+ var index_default = Server_default;
1637
+ export {
1638
+ LiveServer_default as PluridLiveServer,
1639
+ StillsGenerator_default as PluridStillsGenerator,
1640
+ index_default as default
1641
+ };
1642
+ //# sourceMappingURL=index.mjs.map