@ms-cloudpack/app-server 0.20.2 → 0.20.4

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 (52) hide show
  1. package/lib/createRoutes.d.ts.map +1 -1
  2. package/lib/createRoutes.js +2 -10
  3. package/lib/createRoutes.js.map +1 -1
  4. package/lib/renderRoute/getDefaultHtmlResponse.d.ts +2 -2
  5. package/lib/renderRoute/getDefaultHtmlResponse.d.ts.map +1 -1
  6. package/lib/renderRoute/getDefaultHtmlResponse.js +2 -2
  7. package/lib/renderRoute/getDefaultHtmlResponse.js.map +1 -1
  8. package/lib/renderRoute/getErrorResponse.d.ts +4 -3
  9. package/lib/renderRoute/getErrorResponse.d.ts.map +1 -1
  10. package/lib/renderRoute/getErrorResponse.js.map +1 -1
  11. package/lib/renderRoute/injectScripts.d.ts +7 -2
  12. package/lib/renderRoute/injectScripts.d.ts.map +1 -1
  13. package/lib/renderRoute/injectScripts.js +17 -3
  14. package/lib/renderRoute/injectScripts.js.map +1 -1
  15. package/lib/renderRoute/renderRoute.d.ts +3 -2
  16. package/lib/renderRoute/renderRoute.d.ts.map +1 -1
  17. package/lib/renderRoute/renderRoute.js +25 -8
  18. package/lib/renderRoute/renderRoute.js.map +1 -1
  19. package/lib/renderRoute/ssr/bundleServerEntry.d.ts +3 -2
  20. package/lib/renderRoute/ssr/bundleServerEntry.d.ts.map +1 -1
  21. package/lib/renderRoute/ssr/bundleServerEntry.js.map +1 -1
  22. package/lib/renderRoute/ssr/renderCustomScript.d.ts +5 -3
  23. package/lib/renderRoute/ssr/renderCustomScript.d.ts.map +1 -1
  24. package/lib/renderRoute/ssr/renderCustomScript.js +41 -19
  25. package/lib/renderRoute/ssr/renderCustomScript.js.map +1 -1
  26. package/lib/renderRoute/ssr/runServerEntryInWorker.d.ts +7 -3
  27. package/lib/renderRoute/ssr/runServerEntryInWorker.d.ts.map +1 -1
  28. package/lib/renderRoute/ssr/runServerEntryInWorker.js +9 -20
  29. package/lib/renderRoute/ssr/runServerEntryInWorker.js.map +1 -1
  30. package/lib/renderRoute/ssr/types/RunServerEntryOptions.d.ts +2 -2
  31. package/lib/renderRoute/ssr/types/RunServerEntryOptions.d.ts.map +1 -1
  32. package/lib/renderRoute/ssr/types/RunServerEntryOptions.js.map +1 -1
  33. package/lib/renderRoute/ssr/worker/importMapLoader.d.ts +25 -8
  34. package/lib/renderRoute/ssr/worker/importMapLoader.d.ts.map +1 -1
  35. package/lib/renderRoute/ssr/worker/importMapLoader.js +29 -8
  36. package/lib/renderRoute/ssr/worker/importMapLoader.js.map +1 -1
  37. package/lib/renderRoute/ssr/worker/runServerEntry.d.ts +5 -8
  38. package/lib/renderRoute/ssr/worker/runServerEntry.d.ts.map +1 -1
  39. package/lib/renderRoute/ssr/worker/runServerEntry.js +82 -28
  40. package/lib/renderRoute/ssr/worker/runServerEntry.js.map +1 -1
  41. package/lib/startServers.d.ts.map +1 -1
  42. package/lib/startServers.js +10 -1
  43. package/lib/startServers.js.map +1 -1
  44. package/lib/types/RenderRouteOptions.d.ts +10 -0
  45. package/lib/types/RenderRouteOptions.d.ts.map +1 -0
  46. package/lib/types/RenderRouteOptions.js +2 -0
  47. package/lib/types/RenderRouteOptions.js.map +1 -0
  48. package/package.json +9 -9
  49. package/lib/renderRoute/ssr/types/RunServerEntryResult.d.ts +0 -8
  50. package/lib/renderRoute/ssr/types/RunServerEntryResult.d.ts.map +0 -1
  51. package/lib/renderRoute/ssr/types/RunServerEntryResult.js +0 -2
  52. package/lib/renderRoute/ssr/types/RunServerEntryResult.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"renderCustomScript.js","sourceRoot":"","sources":["../../../src/renderRoute/ssr/renderCustomScript.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ExpandedRenderFunctionResult,\n ImportMap,\n RenderFunction,\n RenderFunctionOptions,\n RenderFunctionResult,\n RenderFunctionScript,\n} from '@ms-cloudpack/common-types';\nimport fsPromises from 'fs/promises';\nimport { pathToFileURL } from 'url';\nimport { getCustomRenderErrorResponse, getErrorResponse } from '../getErrorResponse.js';\nimport { runServerEntryInWorker } from './runServerEntryInWorker.js';\n\n/**\n * Load the default export from a JS file passed as the `renderScript` in a route,\n * and return either the result of running the function, or an error page if something fails.\n */\nexport async function renderCustomScript(\n params: RenderFunctionOptions & {\n /** Full path to the render script (bundled version if relevant) */\n renderScriptPath: string;\n },\n): Promise<RenderFunctionResult> {\n const { renderScriptPath, ...options } = params;\n // Get the html factory function from a script default export.\n const renderScriptUrl = pathToFileURL(renderScriptPath).toString();\n\n // Note: because there isn't a way to purge the require cache, we need to add a cache breaker query param to the\n // script path to ensure we get the latest version of the script. This could be improved by using the git hash of\n // the file if it exists, or a hash of the content, or even the timestamp of the file.\n // TODO: this won't work to update anything the file imports, and doesn't seem to work for serverEntry at all...\n let cacheBreakerQueryParam = `?t=${Date.now()}`;\n try {\n const { mtime } = await fsPromises.stat(renderScriptPath);\n cacheBreakerQueryParam = `?t=${mtime.getTime()}`;\n } catch {\n /* no-op */\n }\n\n const renderScriptUrlWithCacheBreaker = renderScriptUrl + cacheBreakerQueryParam;\n\n const { config } = options.session;\n if (config.features?.enableSSR) {\n return executeRenderScriptInSsrMode({\n renderScriptPath,\n renderScriptUrl: renderScriptUrlWithCacheBreaker,\n // TODO this should be a Node-specific import map\n importMap: options.importMap,\n options,\n });\n }\n\n // Try importing the script\n let createHtml: RenderFunction | undefined;\n let errorMessage: string | undefined;\n try {\n const importResult = ((await import(renderScriptUrlWithCacheBreaker)) as RenderFunctionScript).default;\n if (typeof importResult === 'function') {\n createHtml = importResult;\n } else {\n errorMessage = `The render script at \"${renderScriptPath}\" does not export a default function.`;\n }\n } catch (e) {\n errorMessage = `Error importing render script at \"${renderScriptUrl}\":\\n${(e as Error).stack || e}`;\n }\n\n if (createHtml) {\n // Try running the script\n try {\n return await createHtml(options);\n } catch (e) {\n errorMessage = `Error running render script at \"${renderScriptPath}\":\\n${(e as Error).stack || e}`;\n }\n }\n\n // Return an error page. Doing this instead of returning a default or empty response ensures that\n // the user is aware of any configuration issues.\n errorMessage ??= `Unknown error loading render script at \"${renderScriptPath}\".`;\n return getErrorResponse({ req: options.req, message: errorMessage });\n}\n\nasync function executeRenderScriptInSsrMode(params: {\n renderScriptPath: string;\n renderScriptUrl: string;\n importMap: ImportMap;\n options: RenderFunctionOptions;\n}): Promise<ExpandedRenderFunctionResult> {\n const { renderScriptPath, renderScriptUrl, importMap, options } = params;\n\n const serverEntryResult = await runServerEntryInWorker({\n renderScriptUrl,\n importMap,\n renderParams: {},\n });\n\n const { errors, renderedContent } = serverEntryResult;\n if (errors?.length) {\n return getCustomRenderErrorResponse({\n req: options.req,\n route: options.route,\n message: `- error running script: ${errors.map((e) => e.text).join('\\n')}`,\n scriptPath: renderScriptPath,\n });\n }\n return { content: renderedContent, contentType: 'text/html', statusCode: 200 };\n}\n"]}
1
+ {"version":3,"file":"renderCustomScript.js","sourceRoot":"","sources":["../../../src/renderRoute/ssr/renderCustomScript.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from '@ms-cloudpack/api-server';\nimport type {\n ImportMap,\n RenderFunction,\n RenderFunctionResult,\n RenderFunctionScript,\n ServerEntryFunctionOptions,\n ServerEntryFunctionResult,\n} from '@ms-cloudpack/common-types';\nimport fsPromises from 'fs/promises';\nimport type { TLSSocket } from 'tls';\nimport { pathToFileURL } from 'url';\nimport type { RenderRouteOptions } from '../../types/RenderRouteOptions.js';\nimport { getCustomRenderErrorResponse, getErrorResponse } from '../getErrorResponse.js';\nimport { runServerEntryInWorker } from './runServerEntryInWorker.js';\n\n/**\n * Load the default export from a JS file passed as the `renderScript` in a route,\n * and return either the result of running the function, or an error page if something fails.\n */\nexport async function renderCustomScript(\n params: RenderRouteOptions & {\n /** Full path to the render script (bundled version if relevant) */\n renderScriptPath: string;\n },\n // only config and importMap are used in the new SSR signature, so in the future this can be:\n // PartialContext<'session', 'config' | 'importMap'>\n context: Pick<Context, 'session'>,\n): Promise<RenderFunctionResult> {\n const { renderScriptPath, req, res, ...options } = params;\n const { session } = context;\n const { config, importMap } = session;\n\n // Get the html factory function from a script default export.\n const renderScriptUrl = pathToFileURL(renderScriptPath).toString();\n\n // Note: because there isn't a way to purge the require cache, we need to add a cache breaker query param to the\n // script path to ensure we get the latest version of the script. This could be improved by using the git hash of\n // the file if it exists, or a hash of the content, or even the timestamp of the file.\n // TODO: this won't work to update anything the file imports, and doesn't seem to work for serverEntry at all...\n let cacheBreakerQueryParam = `?t=${Date.now()}`;\n try {\n const { mtime } = await fsPromises.stat(renderScriptPath);\n cacheBreakerQueryParam = `?t=${mtime.getTime()}`;\n } catch {\n /* no-op */\n }\n\n const ssrOptions: ServerEntryFunctionOptions = {\n ...options,\n appPath: config.appPath,\n importMap: importMap || { imports: {} },\n requestInfo: {\n headers: req.headers,\n hostname: req.hostname,\n isEncrypted: !!(req.socket as TLSSocket).encrypted,\n originalUrl: req.originalUrl,\n params: req.params,\n query: req.query,\n url: req.url,\n },\n };\n\n const renderScriptUrlWithCacheBreaker = renderScriptUrl + cacheBreakerQueryParam;\n\n if (config.features?.enableSSR) {\n return executeRenderScriptInSsrMode({\n renderScriptPath,\n renderScriptUrl: renderScriptUrlWithCacheBreaker,\n // TODO this should be a Node-specific import map\n importMap: ssrOptions.importMap,\n options: ssrOptions,\n req,\n });\n }\n\n // Legacy custom render mode: import and run the script directly\n // TODO improve the naming and error messages (use getCustomRenderErrorResponse)\n let createHtml: RenderFunction | undefined;\n let errorMessage: string | undefined;\n try {\n const importResult = ((await import(renderScriptUrlWithCacheBreaker)) as RenderFunctionScript).default;\n if (typeof importResult === 'function') {\n createHtml = importResult;\n } else {\n errorMessage = `The render script at \"${renderScriptPath}\" does not export a default function.`;\n }\n } catch (e) {\n errorMessage = `Error importing render script at \"${renderScriptUrl}\":\\n${(e as Error).stack || e}`;\n }\n\n if (createHtml) {\n // Try running the script\n try {\n return await createHtml({ ...ssrOptions, session, req, res });\n } catch (e) {\n errorMessage = `Error running render script at \"${renderScriptPath}\":\\n${(e as Error).stack || e}`;\n }\n }\n\n // Return an error page. Doing this instead of returning a default or empty response ensures that\n // the user is aware of any configuration issues.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- always set by now\n return getErrorResponse({ req, message: errorMessage! });\n}\n\nasync function executeRenderScriptInSsrMode(\n params: Pick<RenderRouteOptions, 'req'> & {\n renderScriptPath: string;\n renderScriptUrl: string;\n importMap: ImportMap;\n options: ServerEntryFunctionOptions;\n },\n): Promise<ServerEntryFunctionResult> {\n const { renderScriptPath, renderScriptUrl, importMap, options } = params;\n try {\n return await runServerEntryInWorker({\n renderScriptUrl,\n importMap,\n renderParams: options,\n });\n } catch (err) {\n // note: err might not be an instance of Error because of serialization\n const errorMessage = (err as Error)?.stack || (err as Error)?.message || String(err);\n return getCustomRenderErrorResponse({\n req: params.req,\n route: options.route,\n message: `- error running script: ${errorMessage}`,\n scriptPath: renderScriptPath,\n });\n }\n}\n"]}
@@ -1,10 +1,14 @@
1
+ import type { ServerEntryFunctionResult } from '@ms-cloudpack/common-types';
1
2
  import type { RunServerEntryOptions } from './types/RunServerEntryOptions.js';
2
- import type { RunServerEntryResult } from './types/RunServerEntryResult.js';
3
3
  /**
4
4
  * Run server entry in a child process pool. (Despite the naming, this does not use worker threads.)
5
+ * Allows exceptions from the script to propagate.
5
6
  */
6
7
  export declare function runServerEntryInWorker(options: RunServerEntryOptions & {
7
8
  maxWorkers?: number;
8
- }): Promise<RunServerEntryResult>;
9
- export declare function disposeStubWorkerPool(): Promise<void>;
9
+ }): Promise<ServerEntryFunctionResult>;
10
+ /**
11
+ * Dispose the server entry runner child processes.
12
+ */
13
+ export declare function disposeServerEntryWorkerPool(): Promise<void>;
10
14
  //# sourceMappingURL=runServerEntryInWorker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runServerEntryInWorker.d.ts","sourceRoot":"","sources":["../../../src/renderRoute/ssr/runServerEntryInWorker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAO5E;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,qBAAqB,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACvD,OAAO,CAAC,oBAAoB,CAAC,CAgC/B;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3D"}
1
+ {"version":3,"file":"runServerEntryInWorker.d.ts","sourceRoot":"","sources":["../../../src/renderRoute/ssr/runServerEntryInWorker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAG5E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAM9E;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,qBAAqB,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACvD,OAAO,CAAC,yBAAyB,CAAC,CAiBpC;AAED;;GAEG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC,CAGlE"}
@@ -4,6 +4,7 @@ const workerPath = path.join(import.meta.dirname, 'worker/ssrProcessEntry.js');
4
4
  let workerPool;
5
5
  /**
6
6
  * Run server entry in a child process pool. (Despite the naming, this does not use worker threads.)
7
+ * Allows exceptions from the script to propagate.
7
8
  */
8
9
  export async function runServerEntryInWorker(options) {
9
10
  workerPool ??= new WorkerPool({
@@ -17,27 +18,15 @@ export async function runServerEntryInWorker(options) {
17
18
  // OOM crashes if cloudpack start is left running for a long time.
18
19
  inactiveTimeout: 5 * 60 * 1000,
19
20
  });
20
- try {
21
- const runServerEntryResult = await workerPool.execute({
22
- method: 'runServerEntry',
23
- args: [options],
24
- });
25
- return runServerEntryResult;
26
- }
27
- catch (err) {
28
- return {
29
- renderedContent: '',
30
- errors: [
31
- {
32
- source: 'Server Entry Execution',
33
- // note: err won't be an instance of Error because of serialization
34
- text: err?.stack || err?.message || String(err),
35
- },
36
- ],
37
- };
38
- }
21
+ return workerPool.execute({
22
+ method: 'runServerEntry',
23
+ args: [options],
24
+ });
39
25
  }
40
- export async function disposeStubWorkerPool() {
26
+ /**
27
+ * Dispose the server entry runner child processes.
28
+ */
29
+ export async function disposeServerEntryWorkerPool() {
41
30
  await workerPool?.dispose();
42
31
  workerPool = undefined;
43
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runServerEntryInWorker.js","sourceRoot":"","sources":["../../../src/renderRoute/ssr/runServerEntryInWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAGvD,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,2BAA2B,CAAC,CAAC;AAE/E,IAAI,UAAkC,CAAC;AAEvC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAwD;IAExD,UAAU,KAAK,IAAI,UAAU,CAAC;QAC5B,UAAU,EAAE,SAAS;QACrB,IAAI,EAAE,uBAAuB;QAC7B,SAAS,EAAE,UAAU;QACrB,iFAAiF;QACjF,mEAAmE;QACnE,UAAU,EAAE,CAAC;QACb,6FAA6F;QAC7F,kEAAkE;QAClE,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;KAC/B,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,oBAAoB,GAAG,MAAM,UAAU,CAAC,OAAO,CAAuB;YAC1E,MAAM,EAAE,gBAAgB;YACxB,IAAI,EAAE,CAAC,OAAO,CAAC;SAChB,CAAC,CAAC;QAEH,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,eAAe,EAAE,EAAE;YACnB,MAAM,EAAE;gBACN;oBACE,MAAM,EAAE,wBAAwB;oBAChC,mEAAmE;oBACnE,IAAI,EAAG,GAAa,EAAE,KAAK,IAAK,GAAa,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC;iBACtE;aACF;SACF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,UAAU,EAAE,OAAO,EAAE,CAAC;IAC5B,UAAU,GAAG,SAAS,CAAC;AACzB,CAAC","sourcesContent":["import { WorkerPool } from '@ms-cloudpack/worker-pool';\nimport type { RunServerEntryOptions } from './types/RunServerEntryOptions.js';\nimport type { RunServerEntryResult } from './types/RunServerEntryResult.js';\nimport path from 'path';\n\nconst workerPath = path.join(import.meta.dirname, 'worker/ssrProcessEntry.js');\n\nlet workerPool: WorkerPool | undefined;\n\n/**\n * Run server entry in a child process pool. (Despite the naming, this does not use worker threads.)\n */\nexport async function runServerEntryInWorker(\n options: RunServerEntryOptions & { maxWorkers?: number },\n): Promise<RunServerEntryResult> {\n workerPool ??= new WorkerPool({\n workerType: 'process',\n name: 'serverEntry execution',\n entryPath: workerPath,\n // Currently we're unlikely to be server-rendering more than one thing at a time.\n // Keep this low unless we find a case where it needs to be higher.\n maxWorkers: 3,\n // Stop inactive processes after 5 minutes. This is intended to prevent one possible cause of\n // OOM crashes if cloudpack start is left running for a long time.\n inactiveTimeout: 5 * 60 * 1000,\n });\n\n try {\n const runServerEntryResult = await workerPool.execute<RunServerEntryResult>({\n method: 'runServerEntry',\n args: [options],\n });\n\n return runServerEntryResult;\n } catch (err) {\n return {\n renderedContent: '',\n errors: [\n {\n source: 'Server Entry Execution',\n // note: err won't be an instance of Error because of serialization\n text: (err as Error)?.stack || (err as Error)?.message || String(err),\n },\n ],\n };\n }\n}\n\nexport async function disposeStubWorkerPool(): Promise<void> {\n await workerPool?.dispose();\n workerPool = undefined;\n}\n"]}
1
+ {"version":3,"file":"runServerEntryInWorker.js","sourceRoot":"","sources":["../../../src/renderRoute/ssr/runServerEntryInWorker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,2BAA2B,CAAC,CAAC;AAE/E,IAAI,UAAkC,CAAC;AAEvC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAwD;IAExD,UAAU,KAAK,IAAI,UAAU,CAAC;QAC5B,UAAU,EAAE,SAAS;QACrB,IAAI,EAAE,uBAAuB;QAC7B,SAAS,EAAE,UAAU;QACrB,iFAAiF;QACjF,mEAAmE;QACnE,UAAU,EAAE,CAAC;QACb,6FAA6F;QAC7F,kEAAkE;QAClE,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;KAC/B,CAAC,CAAC;IAEH,OAAO,UAAU,CAAC,OAAO,CAA4B;QACnD,MAAM,EAAE,gBAAgB;QACxB,IAAI,EAAE,CAAC,OAAO,CAAC;KAChB,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B;IAChD,MAAM,UAAU,EAAE,OAAO,EAAE,CAAC;IAC5B,UAAU,GAAG,SAAS,CAAC;AACzB,CAAC","sourcesContent":["import type { ServerEntryFunctionResult } from '@ms-cloudpack/common-types';\nimport { WorkerPool } from '@ms-cloudpack/worker-pool';\nimport path from 'path';\nimport type { RunServerEntryOptions } from './types/RunServerEntryOptions.js';\n\nconst workerPath = path.join(import.meta.dirname, 'worker/ssrProcessEntry.js');\n\nlet workerPool: WorkerPool | undefined;\n\n/**\n * Run server entry in a child process pool. (Despite the naming, this does not use worker threads.)\n * Allows exceptions from the script to propagate.\n */\nexport async function runServerEntryInWorker(\n options: RunServerEntryOptions & { maxWorkers?: number },\n): Promise<ServerEntryFunctionResult> {\n workerPool ??= new WorkerPool({\n workerType: 'process',\n name: 'serverEntry execution',\n entryPath: workerPath,\n // Currently we're unlikely to be server-rendering more than one thing at a time.\n // Keep this low unless we find a case where it needs to be higher.\n maxWorkers: 3,\n // Stop inactive processes after 5 minutes. This is intended to prevent one possible cause of\n // OOM crashes if cloudpack start is left running for a long time.\n inactiveTimeout: 5 * 60 * 1000,\n });\n\n return workerPool.execute<ServerEntryFunctionResult>({\n method: 'runServerEntry',\n args: [options],\n });\n}\n\n/**\n * Dispose the server entry runner child processes.\n */\nexport async function disposeServerEntryWorkerPool(): Promise<void> {\n await workerPool?.dispose();\n workerPool = undefined;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { ServerRenderFunctionOptions } from '@ms-cloudpack/common-types';
1
+ import type { ServerEntryFunctionOptions } from '@ms-cloudpack/common-types';
2
2
  import type { ImportMap } from '@ms-cloudpack/import-map';
3
3
  export type RunServerEntryOptions = {
4
4
  /**
@@ -9,6 +9,6 @@ export type RunServerEntryOptions = {
9
9
  /** Absolute file URL for the render script (bundled if relevant) */
10
10
  renderScriptUrl: string;
11
11
  /** Params to pass to the user's render function */
12
- renderParams: ServerRenderFunctionOptions;
12
+ renderParams: ServerEntryFunctionOptions;
13
13
  };
14
14
  //# sourceMappingURL=RunServerEntryOptions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RunServerEntryOptions.d.ts","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/types/RunServerEntryOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE1D,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;OAGG;IACH,SAAS,EAAE,SAAS,CAAC;IACrB,oEAAoE;IACpE,eAAe,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,YAAY,EAAE,2BAA2B,CAAC;CAC3C,CAAC"}
1
+ {"version":3,"file":"RunServerEntryOptions.d.ts","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/types/RunServerEntryOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE1D,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;OAGG;IACH,SAAS,EAAE,SAAS,CAAC;IACrB,oEAAoE;IACpE,eAAe,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,YAAY,EAAE,0BAA0B,CAAC;CAC1C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RunServerEntryOptions.js","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/types/RunServerEntryOptions.ts"],"names":[],"mappings":"","sourcesContent":["import type { ServerRenderFunctionOptions } from '@ms-cloudpack/common-types';\nimport type { ImportMap } from '@ms-cloudpack/import-map';\n\nexport type RunServerEntryOptions = {\n /**\n * TODO: This should be the import map specific to the render script in Node\n * (as of writing, it reuses the browser one)\n */\n importMap: ImportMap;\n /** Absolute file URL for the render script (bundled if relevant) */\n renderScriptUrl: string;\n /** Params to pass to the user's render function */\n renderParams: ServerRenderFunctionOptions;\n};\n"]}
1
+ {"version":3,"file":"RunServerEntryOptions.js","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/types/RunServerEntryOptions.ts"],"names":[],"mappings":"","sourcesContent":["import type { ServerEntryFunctionOptions } from '@ms-cloudpack/common-types';\nimport type { ImportMap } from '@ms-cloudpack/import-map';\n\nexport type RunServerEntryOptions = {\n /**\n * TODO: This should be the import map specific to the render script in Node\n * (as of writing, it reuses the browser one)\n */\n importMap: ImportMap;\n /** Absolute file URL for the render script (bundled if relevant) */\n renderScriptUrl: string;\n /** Params to pass to the user's render function */\n renderParams: ServerEntryFunctionOptions;\n};\n"]}
@@ -1,10 +1,9 @@
1
1
  /**
2
- * @param {RunServerEntryOptions} context
2
+ * @param {ImportMapLoaderContext} context
3
3
  * @returns {void}
4
4
  */
5
- export function initialize(context: RunServerEntryOptions): void;
5
+ export function initialize(context: ImportMapLoaderContext): void;
6
6
  /**
7
- *
8
7
  * @param {string} specifier
9
8
  * @param {ResolveHookContext} context
10
9
  * @param {DefaultResolve} defaultResolve
@@ -18,6 +17,23 @@ export function resolve(specifier: string, context: ResolveHookContext, defaultR
18
17
  * @returns {Promise<LoadFnOutput>}
19
18
  */
20
19
  export function load(url: string, context: LoadHookContext, defaultLoad: DefaultLoad): Promise<LoadFnOutput>;
20
+ /**
21
+ * NOTE: This file is a custom loader for "bare" imports in nodejs
22
+ * It should ONLY import types and not any runtime code.
23
+ */
24
+ export type ImportMapLoaderContext = {
25
+ port: MessagePort;
26
+ };
27
+ /**
28
+ * Message with a new import map
29
+ */
30
+ export type UpdateImportMapMessage = {
31
+ importMap: ImportMap;
32
+ };
33
+ /**
34
+ * Confirmation the message was received
35
+ */
36
+ export type UpdateImportMapResult = boolean;
21
37
  /**
22
38
  * NOTE: This file is a custom loader for "bare" imports in nodejs
23
39
  * It should ONLY import types and not any runtime code.
@@ -28,9 +44,10 @@ export type DefaultResolve = (specifier: string, context: ResolveHookContext) =>
28
44
  * It should ONLY import types and not any runtime code.
29
45
  */
30
46
  export type DefaultLoad = (url: string, context: LoadHookContext) => Promise<LoadFnOutput>;
31
- import type { RunServerEntryOptions } from '../types/RunServerEntryOptions.js';
32
- import type { ResolveHookContext } from 'module';
33
- import type { ResolveFnOutput } from 'module';
34
- import type { LoadHookContext } from 'module';
35
- import type { LoadFnOutput } from 'module';
47
+ import type { ResolveHookContext } from 'node:module';
48
+ import type { ResolveFnOutput } from 'node:module';
49
+ import type { LoadHookContext } from 'node:module';
50
+ import type { LoadFnOutput } from 'node:module';
51
+ import type { MessagePort } from 'node:worker_threads';
52
+ import type { ImportMap } from '@ms-cloudpack/common-types';
36
53
  //# sourceMappingURL=importMapLoader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"importMapLoader.d.ts","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/worker/importMapLoader.js"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,oCAHW,qBAAqB,GACnB,IAAI,CAIhB;AAED;;;;;;GAMG;AACH,mCALW,MAAM,WACN,kBAAkB,kBAClB,cAAc,GACZ,eAAe,CAc3B;AAED;;;;;GAKG;AACH,0BALW,MAAM,WACN,eAAe,eACf,WAAW,GACT,OAAO,CAAC,YAAY,CAAC,CAsBjC;;;;;6BA/DY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,KAAK,eAAe;;;;;0BAEnE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,YAAY,CAAC;2CAJnC,mCAAmC;wCADU,QAAQ;qCAAR,QAAQ;qCAAR,QAAQ;kCAAR,QAAQ"}
1
+ {"version":3,"file":"importMapLoader.d.ts","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/worker/importMapLoader.js"],"names":[],"mappings":"AAqBA;;;GAGG;AACH,oCAHW,sBAAsB,GACpB,IAAI,CAehB;AAED;;;;;GAKG;AACH,mCALW,MAAM,WACN,kBAAkB,kBAClB,cAAc,GACZ,eAAe,CAoB3B;AAED;;;;;GAKG;AACH,0BALW,MAAM,WACN,eAAe,eACf,WAAW,GACT,OAAO,CAAC,YAAY,CAAC,CAsBjC;;;;;qCApFY;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE;;;;qCAErB;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE;;;;oCACxB,OAAO;;;;;6BAEP,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,KAAK,eAAe;;;;;0BAEnE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,YAAY,CAAC;wCAVU,aAAa;qCAAb,aAAa;qCAAb,aAAa;kCAAb,aAAa;iCACpE,qBAAqB;+BAFvB,4BAA4B"}
@@ -3,30 +3,51 @@
3
3
  * It should ONLY import types and not any runtime code.
4
4
  *
5
5
  * @import { ImportMap } from '@ms-cloudpack/common-types';
6
- * @import { LoadFnOutput, LoadHookContext, ResolveFnOutput, ResolveHookContext } from 'module';
7
- * @import { RunServerEntryOptions } from '../types/RunServerEntryOptions.js';
6
+ * @import { LoadFnOutput, LoadHookContext, ResolveFnOutput, ResolveHookContext } from 'node:module';
7
+ * @import { MessagePort } from 'node:worker_threads';
8
+ *
9
+ * @typedef {{ port: MessagePort }} ImportMapLoaderContext
10
+ *
11
+ * @typedef {{ importMap: ImportMap }} UpdateImportMapMessage Message with a new import map
12
+ * @typedef {boolean} UpdateImportMapResult Confirmation the message was received
8
13
  *
9
14
  * @typedef {(specifier: string, context: ResolveHookContext) => ResolveFnOutput} DefaultResolve
10
15
  *
11
16
  * @typedef {(url: string, context: LoadHookContext) => Promise<LoadFnOutput>} DefaultLoad
12
17
  */
13
- /** @type {ImportMap} */
14
- let importMap = { imports: {} };
18
+ /** @type {ImportMap | undefined} */
19
+ let importMap;
15
20
  /**
16
- * @param {RunServerEntryOptions} context
21
+ * @param {ImportMapLoaderContext} context
17
22
  * @returns {void}
18
23
  */
19
24
  export function initialize(context) {
20
- importMap = context.importMap || { imports: {} };
25
+ const { port } = context;
26
+ port.on('message', (/** @type {UpdateImportMapMessage} */ message) => {
27
+ if (message.importMap) {
28
+ importMap = message.importMap;
29
+ }
30
+ else {
31
+ // This should never happen
32
+ console.error('Unexpected message received in import map loader:', JSON.stringify(message));
33
+ }
34
+ // Acknowledge the message
35
+ const /** @type {UpdateImportMapResult} */ result = !!importMap;
36
+ port.postMessage(result);
37
+ });
21
38
  }
22
39
  /**
23
- *
24
40
  * @param {string} specifier
25
41
  * @param {ResolveHookContext} context
26
42
  * @param {DefaultResolve} defaultResolve
27
43
  * @returns {ResolveFnOutput}
28
44
  */
29
45
  export function resolve(specifier, context, defaultResolve) {
46
+ if (!importMap) {
47
+ // The import map is updated via a message port created by runServerEntry
48
+ // (this case should never happen)
49
+ throw new Error('Import map has not been updated by runServerEntry');
50
+ }
30
51
  // TODO: Deal with scope
31
52
  const target = importMap?.imports?.[specifier];
32
53
  if (target) {
@@ -50,7 +71,7 @@ export async function load(url, context, defaultLoad) {
50
71
  const res = await fetch(url);
51
72
  if (!res.ok) {
52
73
  // TODO include the response text?
53
- throw new Error(`Failed to fetch ${url} (Status: ${res.status})`);
74
+ throw new Error(`Failed to fetch ${url} (status: ${res.status})`);
54
75
  }
55
76
  const source = await res.text();
56
77
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"importMapLoader.js","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/worker/importMapLoader.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,wBAAwB;AACxB,IAAI,SAAS,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAEhC;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,OAAO;IAChC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,cAAc;IACxD,wBAAwB;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,wBAAwB,SAAS,OAAO,MAAM,EAAE,CAAC,CAAC;QAC/D,OAAO;YACL,GAAG,EAAE,MAAM;YACX,YAAY,EAAE,IAAI;SACnB,CAAC;IACJ,CAAC;IAED,OAAO,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW;IAClD,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,uBAAuB,GAAG,EAAE,CAAC,CAAC;QAE3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,kCAAkC;YAClC,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,aAAa,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAEhC,OAAO;YACL,MAAM,EAAE,QAAQ;YAChB,MAAM;YACN,YAAY,EAAE,IAAI;SACnB,CAAC;IACJ,CAAC;IAED,OAAO,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACnC,CAAC","sourcesContent":["/**\n * NOTE: This file is a custom loader for \"bare\" imports in nodejs\n * It should ONLY import types and not any runtime code.\n *\n * @import { ImportMap } from '@ms-cloudpack/common-types';\n * @import { LoadFnOutput, LoadHookContext, ResolveFnOutput, ResolveHookContext } from 'module';\n * @import { RunServerEntryOptions } from '../types/RunServerEntryOptions.js';\n *\n * @typedef {(specifier: string, context: ResolveHookContext) => ResolveFnOutput} DefaultResolve\n *\n * @typedef {(url: string, context: LoadHookContext) => Promise<LoadFnOutput>} DefaultLoad\n */\n\n/** @type {ImportMap} */\nlet importMap = { imports: {} };\n\n/**\n * @param {RunServerEntryOptions} context\n * @returns {void}\n */\nexport function initialize(context) {\n importMap = context.importMap || { imports: {} };\n}\n\n/**\n *\n * @param {string} specifier\n * @param {ResolveHookContext} context\n * @param {DefaultResolve} defaultResolve\n * @returns {ResolveFnOutput}\n */\nexport function resolve(specifier, context, defaultResolve) {\n // TODO: Deal with scope\n const target = importMap?.imports?.[specifier];\n if (target) {\n console.info(`Import map redirect: ${specifier} -> ${target}`);\n return {\n url: target,\n shortCircuit: true,\n };\n }\n\n return defaultResolve(specifier, context);\n}\n\n/**\n * @param {string} url\n * @param {LoadHookContext} context\n * @param {DefaultLoad} defaultLoad\n * @returns {Promise<LoadFnOutput>}\n */\nexport async function load(url, context, defaultLoad) {\n if (url.startsWith('http')) {\n console.info(`Importing from URL: ${url}`);\n\n const res = await fetch(url);\n if (!res.ok) {\n // TODO include the response text?\n throw new Error(`Failed to fetch ${url} (Status: ${res.status})`);\n }\n\n const source = await res.text();\n\n return {\n format: 'module',\n source,\n shortCircuit: true,\n };\n }\n\n return defaultLoad(url, context);\n}\n"]}
1
+ {"version":3,"file":"importMapLoader.js","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/worker/importMapLoader.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,oCAAoC;AACpC,IAAI,SAAS,CAAC;AAEd;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,OAAO;IAChC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,qCAAqC,CAAC,OAAO,EAAE,EAAE;QACnE,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,2BAA2B;YAC3B,OAAO,CAAC,KAAK,CAAC,mDAAmD,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9F,CAAC;QACD,0BAA0B;QAC1B,MAAM,oCAAoC,CAAC,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC;QAChE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,cAAc;IACxD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,yEAAyE;QACzE,kCAAkC;QAClC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IAED,wBAAwB;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,wBAAwB,SAAS,OAAO,MAAM,EAAE,CAAC,CAAC;QAC/D,OAAO;YACL,GAAG,EAAE,MAAM;YACX,YAAY,EAAE,IAAI;SACnB,CAAC;IACJ,CAAC;IAED,OAAO,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW;IAClD,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,uBAAuB,GAAG,EAAE,CAAC,CAAC;QAE3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,kCAAkC;YAClC,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,aAAa,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAEhC,OAAO;YACL,MAAM,EAAE,QAAQ;YAChB,MAAM;YACN,YAAY,EAAE,IAAI;SACnB,CAAC;IACJ,CAAC;IAED,OAAO,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACnC,CAAC","sourcesContent":["/**\n * NOTE: This file is a custom loader for \"bare\" imports in nodejs\n * It should ONLY import types and not any runtime code.\n *\n * @import { ImportMap } from '@ms-cloudpack/common-types';\n * @import { LoadFnOutput, LoadHookContext, ResolveFnOutput, ResolveHookContext } from 'node:module';\n * @import { MessagePort } from 'node:worker_threads';\n *\n * @typedef {{ port: MessagePort }} ImportMapLoaderContext\n *\n * @typedef {{ importMap: ImportMap }} UpdateImportMapMessage Message with a new import map\n * @typedef {boolean} UpdateImportMapResult Confirmation the message was received\n *\n * @typedef {(specifier: string, context: ResolveHookContext) => ResolveFnOutput} DefaultResolve\n *\n * @typedef {(url: string, context: LoadHookContext) => Promise<LoadFnOutput>} DefaultLoad\n */\n\n/** @type {ImportMap | undefined} */\nlet importMap;\n\n/**\n * @param {ImportMapLoaderContext} context\n * @returns {void}\n */\nexport function initialize(context) {\n const { port } = context;\n port.on('message', (/** @type {UpdateImportMapMessage} */ message) => {\n if (message.importMap) {\n importMap = message.importMap;\n } else {\n // This should never happen\n console.error('Unexpected message received in import map loader:', JSON.stringify(message));\n }\n // Acknowledge the message\n const /** @type {UpdateImportMapResult} */ result = !!importMap;\n port.postMessage(result);\n });\n}\n\n/**\n * @param {string} specifier\n * @param {ResolveHookContext} context\n * @param {DefaultResolve} defaultResolve\n * @returns {ResolveFnOutput}\n */\nexport function resolve(specifier, context, defaultResolve) {\n if (!importMap) {\n // The import map is updated via a message port created by runServerEntry\n // (this case should never happen)\n throw new Error('Import map has not been updated by runServerEntry');\n }\n\n // TODO: Deal with scope\n const target = importMap?.imports?.[specifier];\n if (target) {\n console.info(`Import map redirect: ${specifier} -> ${target}`);\n return {\n url: target,\n shortCircuit: true,\n };\n }\n\n return defaultResolve(specifier, context);\n}\n\n/**\n * @param {string} url\n * @param {LoadHookContext} context\n * @param {DefaultLoad} defaultLoad\n * @returns {Promise<LoadFnOutput>}\n */\nexport async function load(url, context, defaultLoad) {\n if (url.startsWith('http')) {\n console.info(`Importing from URL: ${url}`);\n\n const res = await fetch(url);\n if (!res.ok) {\n // TODO include the response text?\n throw new Error(`Failed to fetch ${url} (status: ${res.status})`);\n }\n\n const source = await res.text();\n\n return {\n format: 'module',\n source,\n shortCircuit: true,\n };\n }\n\n return defaultLoad(url, context);\n}\n"]}
@@ -1,13 +1,10 @@
1
1
  /**
2
+ * Register the import map loader with `options.importMap`, then import and run the render script.
3
+ * Throws if the script path is invalid, and allows exceptions from within the script to propagate.
2
4
  * @param {RunServerEntryOptions} options
3
- * @returns {Promise<RunServerEntryResult>}
5
+ * @returns {Promise<RenderFunctionResult>}
4
6
  */
5
- export function runServerEntry(options: RunServerEntryOptions): Promise<RunServerEntryResult>;
6
- export type RenderModule = {
7
- render?: (params?: ServerRenderFunctionOptions) => Promise<string>;
8
- default?: (params?: ServerRenderFunctionOptions) => Promise<string>;
9
- };
7
+ export function runServerEntry(options: RunServerEntryOptions): Promise<RenderFunctionResult>;
10
8
  import type { RunServerEntryOptions } from '../types/RunServerEntryOptions.js';
11
- import type { RunServerEntryResult } from '../types/RunServerEntryResult.js';
12
- import type { ServerRenderFunctionOptions } from '@ms-cloudpack/common-types';
9
+ import type { RenderFunctionResult } from '@ms-cloudpack/common-types';
13
10
  //# sourceMappingURL=runServerEntry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runServerEntry.d.ts","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/worker/runServerEntry.js"],"names":[],"mappings":"AAYA;;;GAGG;AACH,wCAHW,qBAAqB,GACnB,OAAO,CAAC,oBAAoB,CAAC,CA2BzC;2BApCY;IACR,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,2BAA2B,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,2BAA2B,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACrE;2CANsC,mCAAmC;0CACpC,kCAAkC;iDAF3B,4BAA4B"}
1
+ {"version":3,"file":"runServerEntry.d.ts","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/worker/runServerEntry.js"],"names":[],"mappings":"AAuBA;;;;;GAKG;AACH,wCAHW,qBAAqB,GACnB,OAAO,CAAC,oBAAoB,CAAC,CA4BzC;2CAjDyC,mCAAmC;0CADnE,4BAA4B"}
@@ -1,40 +1,94 @@
1
1
  /**
2
- * @import { ServerRenderFunctionOptions } from '@ms-cloudpack/common-types';
2
+ * @import {
3
+ * ImportMap,
4
+ * RenderFunctionResult,
5
+ * ServerEntryFunctionScript
6
+ * } from '@ms-cloudpack/common-types';
3
7
  * @import { RunServerEntryOptions } from '../types/RunServerEntryOptions.js';
4
- * @import { RunServerEntryResult } from '../types/RunServerEntryResult.js';
5
- *
6
- * @typedef {{
7
- * render?: (params?: ServerRenderFunctionOptions) => Promise<string>;
8
- * default?: (params?: ServerRenderFunctionOptions) => Promise<string>;
9
- * }} RenderModule
8
+ * @import { ImportMapLoaderContext, UpdateImportMapMessage, UpdateImportMapResult } from './importMapLoader.js';
10
9
  */
11
10
  import { register } from 'node:module';
11
+ import { MessageChannel } from 'node:worker_threads';
12
+ let hasInitialized = false;
13
+ // See updateImportMap comment
14
+ const channel = new MessageChannel();
15
+ /** Port used by the parent to communicate with the loader */
16
+ const parentPort = channel.port1;
17
+ /** Port used by the loader to communicate with the parent */
18
+ const loaderPort = channel.port2;
19
+ parentPort.unref();
20
+ loaderPort.unref();
12
21
  /**
22
+ * Register the import map loader with `options.importMap`, then import and run the render script.
23
+ * Throws if the script path is invalid, and allows exceptions from within the script to propagate.
13
24
  * @param {RunServerEntryOptions} options
14
- * @returns {Promise<RunServerEntryResult>}
25
+ * @returns {Promise<RenderFunctionResult>}
15
26
  */
16
27
  export async function runServerEntry(options) {
17
28
  const { importMap, renderScriptUrl, renderParams } = options;
18
- // Registers the customer loader, which is responsible for handling base-imports in a nodejs environment..
19
- register('./importMapLoader.js', {
20
- parentURL: import.meta.url,
21
- data: { importMap },
22
- });
23
- // With the custom loader registered, we can now import the render script.
24
- // We support both named and default exports for the render function.
25
- const renderedResult = await /** @type {Promise<RenderModule>} */ (import(renderScriptUrl))
26
- .then((mod) => {
27
- if (typeof mod.render === 'function') {
28
- return mod.render(renderParams);
29
- }
30
- else if (typeof mod.default === 'function') {
31
- return mod.default(renderParams);
32
- }
33
- throw new Error(`No render function found in module: ${renderScriptUrl}`);
34
- })
35
- .catch((err) => {
36
- console.log('Error:', err);
29
+ if (!hasInitialized) {
30
+ // Register the custom loader, which is responsible for handling "bare" import resolution
31
+ // using the import map where necessary.
32
+ hasInitialized = true;
33
+ const /** @type {ImportMapLoaderContext} */ context = { port: loaderPort };
34
+ register('./importMapLoader.js', {
35
+ parentURL: import.meta.url,
36
+ data: context,
37
+ transferList: [loaderPort],
38
+ });
39
+ }
40
+ // Send the latest import map to the loader
41
+ await updateImportMap(importMap);
42
+ // Import the render script, which will use the custom import map if relevant
43
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- missed jsdoc cast
44
+ const render = /** @type {ServerEntryFunctionScript} */ (await import(renderScriptUrl)).default;
45
+ if (typeof render !== 'function') {
46
+ throw new Error(`The serverEntry script does not export a default function.`);
47
+ }
48
+ return await render(renderParams);
49
+ }
50
+ /**
51
+ * We have to update the import map for importMapLoader.js via message ports, since the
52
+ * customization hooks run in a separate thread.
53
+ * @param {ImportMap} importMap
54
+ * @returns {Promise<void>}
55
+ */
56
+ function updateImportMap(importMap) {
57
+ return new Promise((resolve, reject) => {
58
+ // Before sending the message, add one-off handlers for all cases to be safe.
59
+ // This is just sending an object and waiting for confirmation, so errors are very unlikely.
60
+ const onMessage = (/** @type {UpdateImportMapResult} */ result) => {
61
+ handlersOff();
62
+ if (result === true) {
63
+ resolve();
64
+ }
65
+ else if (result === false) {
66
+ // extremely unlikely
67
+ reject(new Error('Failed to update import map before running serverEntry'));
68
+ }
69
+ else {
70
+ // even less likely
71
+ reject(new Error(`Unexpected message from import map loader: ${JSON.stringify(message)}`));
72
+ }
73
+ };
74
+ parentPort.once('message', onMessage);
75
+ const onError = (/** @type {*} */ error) => {
76
+ handlersOff();
77
+ reject(new Error(`Error updating import map before running serverEntry: ${error}`));
78
+ };
79
+ parentPort.once('error', onError);
80
+ // This should happen almost instantly, so conservatively time out after 1s
81
+ const timeout = setTimeout(() => {
82
+ handlersOff();
83
+ reject(new Error('Timed out waiting for import map update confirmation from loader'));
84
+ }, 1000);
85
+ const handlersOff = () => {
86
+ parentPort.off('message', onMessage);
87
+ parentPort.off('error', onError);
88
+ clearTimeout(timeout);
89
+ };
90
+ const /** @type {UpdateImportMapMessage} */ message = { importMap };
91
+ parentPort.postMessage(message);
37
92
  });
38
- return { renderedContent: renderedResult || '' };
39
93
  }
40
94
  //# sourceMappingURL=runServerEntry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runServerEntry.js","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/worker/runServerEntry.js"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAO;IAC1C,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IAE7D,0GAA0G;IAC1G,QAAQ,CAAC,sBAAsB,EAAE;QAC/B,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG;QAC1B,IAAI,EAAE,EAAE,SAAS,EAAE;KACpB,CAAC,CAAC;IAEH,0EAA0E;IAC1E,qEAAqE;IACrE,MAAM,cAAc,GAAG,MAAM,oCAAoC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;SACxF,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QACZ,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YACrC,OAAO,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAClC,CAAC;aAAM,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;YAC7C,OAAO,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACnC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,uCAAuC,eAAe,EAAE,CAAC,CAAC;IAC5E,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACb,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEL,OAAO,EAAE,eAAe,EAAE,cAAc,IAAI,EAAE,EAAE,CAAC;AACnD,CAAC","sourcesContent":["/**\n * @import { ServerRenderFunctionOptions } from '@ms-cloudpack/common-types';\n * @import { RunServerEntryOptions } from '../types/RunServerEntryOptions.js';\n * @import { RunServerEntryResult } from '../types/RunServerEntryResult.js';\n *\n * @typedef {{\n * render?: (params?: ServerRenderFunctionOptions) => Promise<string>;\n * default?: (params?: ServerRenderFunctionOptions) => Promise<string>;\n * }} RenderModule\n */\nimport { register } from 'node:module';\n\n/**\n * @param {RunServerEntryOptions} options\n * @returns {Promise<RunServerEntryResult>}\n */\nexport async function runServerEntry(options) {\n const { importMap, renderScriptUrl, renderParams } = options;\n\n // Registers the customer loader, which is responsible for handling base-imports in a nodejs environment..\n register('./importMapLoader.js', {\n parentURL: import.meta.url,\n data: { importMap },\n });\n\n // With the custom loader registered, we can now import the render script.\n // We support both named and default exports for the render function.\n const renderedResult = await /** @type {Promise<RenderModule>} */ (import(renderScriptUrl))\n .then((mod) => {\n if (typeof mod.render === 'function') {\n return mod.render(renderParams);\n } else if (typeof mod.default === 'function') {\n return mod.default(renderParams);\n }\n throw new Error(`No render function found in module: ${renderScriptUrl}`);\n })\n .catch((err) => {\n console.log('Error:', err);\n });\n\n return { renderedContent: renderedResult || '' };\n}\n"]}
1
+ {"version":3,"file":"runServerEntry.js","sourceRoot":"","sources":["../../../../src/renderRoute/ssr/worker/runServerEntry.js"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,IAAI,cAAc,GAAG,KAAK,CAAC;AAE3B,8BAA8B;AAC9B,MAAM,OAAO,GAAG,IAAI,cAAc,EAAE,CAAC;AACrC,6DAA6D;AAC7D,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC;AACjC,6DAA6D;AAC7D,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC;AACjC,UAAU,CAAC,KAAK,EAAE,CAAC;AACnB,UAAU,CAAC,KAAK,EAAE,CAAC;AAEnB;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAO;IAC1C,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IAE7D,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,yFAAyF;QACzF,wCAAwC;QACxC,cAAc,GAAG,IAAI,CAAC;QACtB,MAAM,qCAAqC,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QAC3E,QAAQ,CAAC,sBAAsB,EAAE;YAC/B,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG;YAC1B,IAAI,EAAE,OAAO;YACb,YAAY,EAAE,CAAC,UAAU,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,2CAA2C;IAC3C,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC;IAEjC,6EAA6E;IAC7E,2FAA2F;IAC3F,MAAM,MAAM,GAAG,wCAAwC,CAAC,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC;IAChG,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,SAAS;IAChC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,6EAA6E;QAC7E,4FAA4F;QAC5F,MAAM,SAAS,GAAG,CAAC,oCAAoC,CAAC,MAAM,EAAE,EAAE;YAChE,WAAW,EAAE,CAAC;YACd,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,OAAO,EAAE,CAAC;YACZ,CAAC;iBAAM,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC5B,qBAAqB;gBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC,CAAC;YAC9E,CAAC;iBAAM,CAAC;gBACN,mBAAmB;gBACnB,MAAM,CAAC,IAAI,KAAK,CAAC,8CAA8C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YAC7F,CAAC;QACH,CAAC,CAAC;QAEF,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,CAAC,gBAAgB,CAAC,KAAK,EAAE,EAAE;YACzC,WAAW,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,KAAK,CAAC,yDAAyD,KAAK,EAAE,CAAC,CAAC,CAAC;QACtF,CAAC,CAAC;QACF,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAElC,2EAA2E;QAC3E,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,WAAW,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC,CAAC;QACxF,CAAC,EAAE,IAAI,CAAC,CAAC;QAET,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACrC,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACjC,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC;QAEF,MAAM,qCAAqC,CAAC,OAAO,GAAG,EAAE,SAAS,EAAE,CAAC;QACpE,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * @import {\n * ImportMap,\n * RenderFunctionResult,\n * ServerEntryFunctionScript\n * } from '@ms-cloudpack/common-types';\n * @import { RunServerEntryOptions } from '../types/RunServerEntryOptions.js';\n * @import { ImportMapLoaderContext, UpdateImportMapMessage, UpdateImportMapResult } from './importMapLoader.js';\n */\nimport { register } from 'node:module';\nimport { MessageChannel } from 'node:worker_threads';\n\nlet hasInitialized = false;\n\n// See updateImportMap comment\nconst channel = new MessageChannel();\n/** Port used by the parent to communicate with the loader */\nconst parentPort = channel.port1;\n/** Port used by the loader to communicate with the parent */\nconst loaderPort = channel.port2;\nparentPort.unref();\nloaderPort.unref();\n\n/**\n * Register the import map loader with `options.importMap`, then import and run the render script.\n * Throws if the script path is invalid, and allows exceptions from within the script to propagate.\n * @param {RunServerEntryOptions} options\n * @returns {Promise<RenderFunctionResult>}\n */\nexport async function runServerEntry(options) {\n const { importMap, renderScriptUrl, renderParams } = options;\n\n if (!hasInitialized) {\n // Register the custom loader, which is responsible for handling \"bare\" import resolution\n // using the import map where necessary.\n hasInitialized = true;\n const /** @type {ImportMapLoaderContext} */ context = { port: loaderPort };\n register('./importMapLoader.js', {\n parentURL: import.meta.url,\n data: context,\n transferList: [loaderPort],\n });\n }\n\n // Send the latest import map to the loader\n await updateImportMap(importMap);\n\n // Import the render script, which will use the custom import map if relevant\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- missed jsdoc cast\n const render = /** @type {ServerEntryFunctionScript} */ (await import(renderScriptUrl)).default;\n if (typeof render !== 'function') {\n throw new Error(`The serverEntry script does not export a default function.`);\n }\n\n return await render(renderParams);\n}\n\n/**\n * We have to update the import map for importMapLoader.js via message ports, since the\n * customization hooks run in a separate thread.\n * @param {ImportMap} importMap\n * @returns {Promise<void>}\n */\nfunction updateImportMap(importMap) {\n return new Promise((resolve, reject) => {\n // Before sending the message, add one-off handlers for all cases to be safe.\n // This is just sending an object and waiting for confirmation, so errors are very unlikely.\n const onMessage = (/** @type {UpdateImportMapResult} */ result) => {\n handlersOff();\n if (result === true) {\n resolve();\n } else if (result === false) {\n // extremely unlikely\n reject(new Error('Failed to update import map before running serverEntry'));\n } else {\n // even less likely\n reject(new Error(`Unexpected message from import map loader: ${JSON.stringify(message)}`));\n }\n };\n\n parentPort.once('message', onMessage);\n const onError = (/** @type {*} */ error) => {\n handlersOff();\n reject(new Error(`Error updating import map before running serverEntry: ${error}`));\n };\n parentPort.once('error', onError);\n\n // This should happen almost instantly, so conservatively time out after 1s\n const timeout = setTimeout(() => {\n handlersOff();\n reject(new Error('Timed out waiting for import map update confirmation from loader'));\n }, 1000);\n\n const handlersOff = () => {\n parentPort.off('message', onMessage);\n parentPort.off('error', onError);\n clearTimeout(timeout);\n };\n\n const /** @type {UpdateImportMapMessage} */ message = { importMap };\n parentPort.postMessage(message);\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"startServers.d.ts","sourceRoot":"","sources":["../src/startServers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACzB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAI9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE;IACP,UAAU,EAAE,WAAW,CAAC;IACxB,0FAA0F;IAC1F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,mBAAmB,EAAE,mBAAmB,CAAC;CAC1C,EACD,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;IACT,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC,CAoDD"}
1
+ {"version":3,"file":"startServers.d.ts","sourceRoot":"","sources":["../src/startServers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACzB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAI9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE;IACP,UAAU,EAAE,WAAW,CAAC;IACxB,0FAA0F;IAC1F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,mBAAmB,EAAE,mBAAmB,CAAC;CAC1C,EACD,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;IACT,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC,CA4DD"}
@@ -4,6 +4,7 @@ import { combinedServerBundleRequestPrefix } from '@ms-cloudpack/import-map';
4
4
  import { cyan } from '@ms-cloudpack/task-reporter';
5
5
  import { createRoutes } from './createRoutes.js';
6
6
  import { handleKnownServerErrors } from './handleKnownServerErrors.js';
7
+ import { disposeServerEntryWorkerPool } from './renderRoute/ssr/runServerEntryInWorker.js';
7
8
  /**
8
9
  * Start the app server, and (usually) the bundle server (but see below).
9
10
  *
@@ -57,7 +58,15 @@ export async function startServers(options, context) {
57
58
  createRoutes({ ...options, app, url }, context);
58
59
  task.complete({ message: `Available @ ${cyan(url)}`, forceShow: true });
59
60
  return {
60
- appServer: { app, close, port, url },
61
+ appServer: {
62
+ app,
63
+ port,
64
+ url,
65
+ close: async () => {
66
+ await close();
67
+ await disposeServerEntryWorkerPool();
68
+ },
69
+ },
61
70
  bundleServer,
62
71
  };
63
72
  }
@@ -1 +1 @@
1
- {"version":3,"file":"startServers.js","sourceRoot":"","sources":["../src/startServers.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,iBAAiB,GAGlB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,iCAAiC,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAC;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAGvE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAOC,EACD,OAAgB;IAKhB,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC;IACnE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACtC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC;IAE/B,mEAAmE;IACnE,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAChD,MAAM,KAAK,GAAG,WAAW,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,4BAA4B,UAAU,CAAC,IAAI,GAAG,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAE1C,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,gBAAgB,CAAC;YACvD,SAAS,EAAE,KAAK;YAChB,oBAAoB,EAAE,WAAW,KAAK,SAAS;YAC/C,QAAQ;YACR,cAAc,EAAE,MAAM,EAAE,cAAc;YACtC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK;YAChG,MAAM,EAAE,aAAa;YACrB,GAAG,EAAE,MAAM,CAAC,OAAO;SACpB,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;QAE7B,IAAI,YAAsC,CAAC;QAC3C,IAAI,MAAM,CAAC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;YACxC,0CAA0C;YAC1C,OAAO,CAAC,IAAI,CAAC,YAAY,GAAG,GAAG,GAAG,IAAI,iCAAiC,EAAE,CAAC;YAC1E,GAAG,CAAC,GAAG,CAAC,IAAI,iCAAiC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;gBAC9D,mBAAmB,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,mBAAmB,EAAE,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC/E,OAAO,CAAC,KAAK,CAAE,GAAa,EAAE,KAAK,IAAI,GAAG,CAAC,CAAC;oBAC5C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;gBACjD,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,2BAA2B;YAC3B,YAAY,GAAG,MAAM,iBAAiB,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;QACvE,CAAC;QAED,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QAEhD,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,eAAe,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAExE,OAAO;YACL,SAAS,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE;YACpC,YAAY;SACb,CAAC;IACJ,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,4BAA4B,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,uBAAuB,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC","sourcesContent":["import type { Context } from '@ms-cloudpack/api-server';\nimport {\n handleBundleRequest,\n startBundleServer,\n type BundleServer,\n type BundleServerOptions,\n} from '@ms-cloudpack/bundle-server';\nimport type { PackageJson } from '@ms-cloudpack/common-types';\nimport { createExpressApp, getDomain } from '@ms-cloudpack/create-express-app';\nimport { combinedServerBundleRequestPrefix } from '@ms-cloudpack/import-map';\nimport { cyan } from '@ms-cloudpack/task-reporter';\nimport type { Server } from 'http';\nimport { createRoutes } from './createRoutes.js';\nimport { handleKnownServerErrors } from './handleKnownServerErrors.js';\nimport type { AppServer } from './types/AppServer.js';\n\n/**\n * Start the app server, and (usually) the bundle server (but see below).\n *\n * The app server hosts the appropriate routes for the web app, primarily returning html content\n * which loads resources from the bundle server.\n *\n * Separating the app server from the bundle service keeps the routes separate - the app server\n * can support whichever routes the app needs, while the bundle server can provide package\n * assets in various forms using its own routing.\n *\n * Exception: some projects need the bundle server and app server on the same origin for local\n * development due to security policies. If the `useSingleWebServer` feature is enabled, the app\n * server will also serve bundles rather than creating a separate bundle server.\n */\nexport async function startServers(\n options: {\n definition: PackageJson;\n /** If provided, act as a middleware on this server, rather than starting a new server. */\n expressServer?: Server;\n /** Custom port for the app server (probably from CLI options) */\n port?: number | number[];\n bundleServerOptions: BundleServerOptions;\n },\n context: Context,\n): Promise<{\n appServer: AppServer;\n bundleServer?: BundleServer;\n}> {\n const { definition, expressServer, bundleServerOptions } = options;\n const { session, reporter } = context;\n const { config } = session;\n const { server = {} } = config;\n\n // Read the port from the config file or default to array of ports.\n const customPorts = server.port ?? options.port;\n const ports = customPorts ?? [5000, 5001, 5002, 5003];\n const task = reporter.addTask(`Starting app server for \"${definition.name}\"`);\n const hostname = getDomain(server.domain);\n\n try {\n const { app, close, port, url } = await createExpressApp({\n portRange: ports,\n requireSpecifiedPort: customPorts !== undefined,\n hostname,\n requestHeaders: server?.requestHeaders,\n sslOptions: context.session.config?.server?.parsedHttps ?? context.session.config?.server?.https,\n server: expressServer,\n cwd: config.appPath,\n });\n session.urls.appServer = url;\n\n let bundleServer: BundleServer | undefined;\n if (config.features?.useSingleWebServer) {\n // Add a route on this server for bundles.\n session.urls.bundleServer = `${url}/${combinedServerBundleRequestPrefix}`;\n app.get(`/${combinedServerBundleRequestPrefix}/*`, (req, res) => {\n handleBundleRequest({ req, res, ...bundleServerOptions }, context).catch((err) => {\n console.error((err as Error)?.stack || err);\n res.status(500).send(`Error bundling: ${err}`);\n });\n });\n } else {\n // Start the bundle server.\n bundleServer = await startBundleServer(bundleServerOptions, context);\n }\n\n createRoutes({ ...options, app, url }, context);\n\n task.complete({ message: `Available @ ${cyan(url)}`, forceShow: true });\n\n return {\n appServer: { app, close, port, url },\n bundleServer,\n };\n } catch (err: unknown) {\n task.complete({ status: 'fail', message: 'Failed to start app server', forceShow: true });\n handleKnownServerErrors({ err, ports }, context);\n throw err;\n }\n}\n"]}
1
+ {"version":3,"file":"startServers.js","sourceRoot":"","sources":["../src/startServers.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from '@ms-cloudpack/api-server';\nimport {\n handleBundleRequest,\n startBundleServer,\n type BundleServer,\n type BundleServerOptions,\n} from '@ms-cloudpack/bundle-server';\nimport type { PackageJson } from '@ms-cloudpack/common-types';\nimport { createExpressApp, getDomain } from '@ms-cloudpack/create-express-app';\nimport { combinedServerBundleRequestPrefix } from '@ms-cloudpack/import-map';\nimport { cyan } from '@ms-cloudpack/task-reporter';\nimport type { Server } from 'http';\nimport { createRoutes } from './createRoutes.js';\nimport { handleKnownServerErrors } from './handleKnownServerErrors.js';\nimport type { AppServer } from './types/AppServer.js';\nimport { disposeServerEntryWorkerPool } from './renderRoute/ssr/runServerEntryInWorker.js';\n\n/**\n * Start the app server, and (usually) the bundle server (but see below).\n *\n * The app server hosts the appropriate routes for the web app, primarily returning html content\n * which loads resources from the bundle server.\n *\n * Separating the app server from the bundle service keeps the routes separate - the app server\n * can support whichever routes the app needs, while the bundle server can provide package\n * assets in various forms using its own routing.\n *\n * Exception: some projects need the bundle server and app server on the same origin for local\n * development due to security policies. If the `useSingleWebServer` feature is enabled, the app\n * server will also serve bundles rather than creating a separate bundle server.\n */\nexport async function startServers(\n options: {\n definition: PackageJson;\n /** If provided, act as a middleware on this server, rather than starting a new server. */\n expressServer?: Server;\n /** Custom port for the app server (probably from CLI options) */\n port?: number | number[];\n bundleServerOptions: BundleServerOptions;\n },\n context: Context,\n): Promise<{\n appServer: AppServer;\n bundleServer?: BundleServer;\n}> {\n const { definition, expressServer, bundleServerOptions } = options;\n const { session, reporter } = context;\n const { config } = session;\n const { server = {} } = config;\n\n // Read the port from the config file or default to array of ports.\n const customPorts = server.port ?? options.port;\n const ports = customPorts ?? [5000, 5001, 5002, 5003];\n const task = reporter.addTask(`Starting app server for \"${definition.name}\"`);\n const hostname = getDomain(server.domain);\n\n try {\n const { app, close, port, url } = await createExpressApp({\n portRange: ports,\n requireSpecifiedPort: customPorts !== undefined,\n hostname,\n requestHeaders: server?.requestHeaders,\n sslOptions: context.session.config?.server?.parsedHttps ?? context.session.config?.server?.https,\n server: expressServer,\n cwd: config.appPath,\n });\n session.urls.appServer = url;\n\n let bundleServer: BundleServer | undefined;\n if (config.features?.useSingleWebServer) {\n // Add a route on this server for bundles.\n session.urls.bundleServer = `${url}/${combinedServerBundleRequestPrefix}`;\n app.get(`/${combinedServerBundleRequestPrefix}/*`, (req, res) => {\n handleBundleRequest({ req, res, ...bundleServerOptions }, context).catch((err) => {\n console.error((err as Error)?.stack || err);\n res.status(500).send(`Error bundling: ${err}`);\n });\n });\n } else {\n // Start the bundle server.\n bundleServer = await startBundleServer(bundleServerOptions, context);\n }\n\n createRoutes({ ...options, app, url }, context);\n\n task.complete({ message: `Available @ ${cyan(url)}`, forceShow: true });\n\n return {\n appServer: {\n app,\n port,\n url,\n close: async () => {\n await close();\n await disposeServerEntryWorkerPool();\n },\n },\n bundleServer,\n };\n } catch (err: unknown) {\n task.complete({ status: 'fail', message: 'Failed to start app server', forceShow: true });\n handleKnownServerErrors({ err, ports }, context);\n throw err;\n }\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { RenderFunctionOptions, Request, Response } from '@ms-cloudpack/common-types';
2
+ /**
3
+ * Options for the `renderRoute` function and its helpers.
4
+ * (This is similar to the original `RenderFunctionOptions`, but `req` and `res` are not deprecated.)
5
+ */
6
+ export interface RenderRouteOptions extends Pick<RenderFunctionOptions, 'route' | 'baseUrl' | 'definition' | 'overlayScript' | 'entryScripts' | 'inlineScripts'> {
7
+ req: Request;
8
+ res: Response;
9
+ }
10
+ //# sourceMappingURL=RenderRouteOptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RenderRouteOptions.d.ts","sourceRoot":"","sources":["../../src/types/RenderRouteOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAE3F;;;GAGG;AACH,MAAM,WAAW,kBACf,SAAQ,IAAI,CACV,qBAAqB,EACrB,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,eAAe,GAAG,cAAc,GAAG,eAAe,CACxF;IACD,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,QAAQ,CAAC;CACf"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=RenderRouteOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RenderRouteOptions.js","sourceRoot":"","sources":["../../src/types/RenderRouteOptions.ts"],"names":[],"mappings":"","sourcesContent":["import type { RenderFunctionOptions, Request, Response } from '@ms-cloudpack/common-types';\n\n/**\n * Options for the `renderRoute` function and its helpers.\n * (This is similar to the original `RenderFunctionOptions`, but `req` and `res` are not deprecated.)\n */\nexport interface RenderRouteOptions\n extends Pick<\n RenderFunctionOptions,\n 'route' | 'baseUrl' | 'definition' | 'overlayScript' | 'entryScripts' | 'inlineScripts'\n > {\n req: Request;\n res: Response;\n}\n"]}