@ms-cloudpack/app-server 0.17.6 → 0.17.7

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.
@@ -7,7 +7,7 @@ import { getInlineScripts } from './inlineScripts/getInlineScripts.js';
7
7
  import { renderRoute } from './renderRoute/renderRoute.js';
8
8
  import { renderBootstrapRoute } from './renderBootstrapRoute.js';
9
9
  import { createPageSessionContext } from './createPageSessionContext.js';
10
- import { parseMatch } from './parseMatch.js';
10
+ import { parseRouteMatch } from './parseRouteMatch.js';
11
11
  /** Express middleware that will match the domain to continue the route execution. */
12
12
  function matchDomain(domain) {
13
13
  return (req, _, next) => {
@@ -42,7 +42,7 @@ export function createRoutes(options, context) {
42
42
  for (const route of routes) {
43
43
  const matches = Array.isArray(route.match) ? route.match : [route.match];
44
44
  for (const match of matches) {
45
- const { pathMatch, domainMatch } = parseMatch(match);
45
+ const { pathMatch, domainMatch } = parseRouteMatch(match);
46
46
  if (isStaticRoute(route)) {
47
47
  app.use(pathMatch, matchDomain(domainMatch), express.static(path.resolve(appPath, route.staticPath)));
48
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"createRoutes.js","sourceRoot":"","sources":["../src/createRoutes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from '@ms-cloudpack/api-server';\nimport {\n isBootstrapRoute,\n isRedirectRoute,\n isRenderedRoute,\n isStaticRoute,\n type BootstrapRoute,\n type PackageJson,\n type RenderedRoute,\n type ExpandedRenderFunctionResult,\n type RequestHandler,\n} from '@ms-cloudpack/common-types';\nimport type { Express, Request, Response } from '@ms-cloudpack/create-express-app';\nimport { express } from '@ms-cloudpack/create-express-app';\nimport { createImportMap } from '@ms-cloudpack/import-map';\nimport { slash } from '@ms-cloudpack/path-string-parsing';\nimport path from 'path';\nimport { getInlineScripts } from './inlineScripts/getInlineScripts.js';\nimport { renderRoute } from './renderRoute/renderRoute.js';\nimport { renderBootstrapRoute } from './renderBootstrapRoute.js';\nimport { createPageSessionContext } from './createPageSessionContext.js';\nimport { parseMatch } from './parseMatch.js';\n\ninterface CreateRoutesOptions {\n app: Express;\n /** Base app server URL, including the port */\n url: string;\n /** package.json for the app */\n definition: PackageJson;\n}\n\ntype CreateRoutesContext = Pick<Context, 'packages' | 'packageImportPaths' | 'packageHashes' | 'session'>;\n\n/** Express middleware that will match the domain to continue the route execution. */\nfunction matchDomain(domain?: RegExp): RequestHandler {\n return (req, _, next) => {\n if (!domain || domain.test(req.hostname)) {\n return next();\n }\n\n // Jump to next route.\n return next('route');\n };\n}\n\n/**\n * Creates the routes for the express app based on the config.\n */\nexport function createRoutes(options: CreateRoutesOptions, context: CreateRoutesContext) {\n const { app, ...otherOptions } = options;\n const { session } = context;\n const { config } = session;\n const { appPath } = config;\n const routes = [...(session.config.routes || [])];\n\n if (!options.definition.name) {\n throw new Error('Name field is required in the package.json file.');\n }\n\n if (!routes.length) {\n // If no routes have been defined, register a default (no path) route only.\n // This will render default HTML which includes the app's default path ('.') from the import map.\n routes.push({\n match: '/',\n // sourcePath and requestPath are required by types but unused in this case.\n entry: [{ importPath: '.', sourcePath: '' }],\n });\n }\n\n for (const route of routes) {\n const matches = Array.isArray(route.match) ? route.match : [route.match];\n\n for (const match of matches) {\n const { pathMatch, domainMatch } = parseMatch(match);\n\n if (isStaticRoute(route)) {\n app.use(pathMatch, matchDomain(domainMatch), express.static(path.resolve(appPath, route.staticPath)));\n } else if (isRedirectRoute(route)) {\n app.get(pathMatch, matchDomain(domainMatch), (req, res) => {\n res.redirect(route.redirectTo);\n });\n } else if (isRenderedRoute(route) || isBootstrapRoute(route)) {\n app.get(pathMatch, matchDomain(domainMatch), (req, res) => {\n handleRequest({ ...otherOptions, route, req, res }, context).catch((err) => {\n console.error((err as Error)?.stack || err);\n res.status(500).send(`Error loading app: ${err}`);\n });\n });\n } else {\n throw new Error(`Unknown route: ${JSON.stringify(route)}`);\n }\n }\n }\n}\n\nasync function handleRequest(\n options: Omit<CreateRoutesOptions, 'app'> & {\n req: Request;\n res: Response;\n route: RenderedRoute | BootstrapRoute;\n },\n context: CreateRoutesContext,\n) {\n const { req, res, definition, route, url } = options;\n const { session } = context;\n const { bundleServer, appServer } = session.urls;\n\n if (!bundleServer) {\n throw new Error('The bundle server URL is not yet set in the session (this is a Cloudpack bug).');\n }\n\n if (!appServer) {\n throw new Error('The app server URL is not yet set in the session (this is a Cloudpack bug).');\n }\n\n // Build the import map if it hasn't been built yet for this session version.\n // (TS can't infer that urls.bundleServer is set on session from a check above.)\n const importMap = (session.importMap ??= await createImportMap({\n ...context,\n ...session,\n urls: { bundleServer, appServer },\n }));\n\n // For production mode, no overlay script.\n const overlayScript = session.config.mode !== 'production' ? importMap.imports['@ms-cloudpack/overlay'] : undefined;\n\n // Get all entry scripts for the route.\n const entryScripts = route.entry?.map(\n (entry) => importMap.imports[slash(path.join(definition.name, entry.importPath))],\n );\n\n const pageSessionContextScript =\n `window.__cloudpack ??= {};\\n` +\n `window.__cloudpack.pageSessionContext = ${JSON.stringify(createPageSessionContext(session, req.path))};`;\n\n // Add the pageSessionContext to the top of the inlineScripts\n const inlineScripts = [pageSessionContextScript, ...(await getInlineScripts())];\n\n // Set the appropriate Cloudpack headers in the response.\n res.header('Cache-Control', 'no-cache');\n res.header('Access-Control-Allow-Origin', '*');\n\n let rendered: ExpandedRenderFunctionResult | null;\n\n if (isBootstrapRoute(route)) {\n // Render the bootstrap script\n rendered = await renderBootstrapRoute({\n session,\n importMap,\n overlayScript,\n inlineScripts,\n entryScripts,\n requestPath: req.path,\n });\n } else {\n // HTML or custom script rendering\n rendered = await renderRoute({\n ...options,\n session,\n baseUrl: url,\n importMap,\n overlayScript,\n inlineScripts,\n entryScripts,\n });\n }\n\n if (rendered) {\n res.type(rendered.contentType).status(rendered.statusCode).send(rendered.content).end();\n }\n\n console.debug(`App server: Request: ${req.path}`);\n}\n"]}
1
+ {"version":3,"file":"createRoutes.js","sourceRoot":"","sources":["../src/createRoutes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from '@ms-cloudpack/api-server';\nimport {\n isBootstrapRoute,\n isRedirectRoute,\n isRenderedRoute,\n isStaticRoute,\n type BootstrapRoute,\n type PackageJson,\n type RenderedRoute,\n type ExpandedRenderFunctionResult,\n type RequestHandler,\n} from '@ms-cloudpack/common-types';\nimport type { Express, Request, Response } from '@ms-cloudpack/create-express-app';\nimport { express } from '@ms-cloudpack/create-express-app';\nimport { createImportMap } from '@ms-cloudpack/import-map';\nimport { slash } from '@ms-cloudpack/path-string-parsing';\nimport path from 'path';\nimport { getInlineScripts } from './inlineScripts/getInlineScripts.js';\nimport { renderRoute } from './renderRoute/renderRoute.js';\nimport { renderBootstrapRoute } from './renderBootstrapRoute.js';\nimport { createPageSessionContext } from './createPageSessionContext.js';\nimport { parseRouteMatch } from './parseRouteMatch.js';\n\ninterface CreateRoutesOptions {\n app: Express;\n /** Base app server URL, including the port */\n url: string;\n /** package.json for the app */\n definition: PackageJson;\n}\n\ntype CreateRoutesContext = Pick<Context, 'packages' | 'packageImportPaths' | 'packageHashes' | 'session'>;\n\n/** Express middleware that will match the domain to continue the route execution. */\nfunction matchDomain(domain?: RegExp): RequestHandler {\n return (req, _, next) => {\n if (!domain || domain.test(req.hostname)) {\n return next();\n }\n\n // Jump to next route.\n return next('route');\n };\n}\n\n/**\n * Creates the routes for the express app based on the config.\n */\nexport function createRoutes(options: CreateRoutesOptions, context: CreateRoutesContext) {\n const { app, ...otherOptions } = options;\n const { session } = context;\n const { config } = session;\n const { appPath } = config;\n const routes = [...(session.config.routes || [])];\n\n if (!options.definition.name) {\n throw new Error('Name field is required in the package.json file.');\n }\n\n if (!routes.length) {\n // If no routes have been defined, register a default (no path) route only.\n // This will render default HTML which includes the app's default path ('.') from the import map.\n routes.push({\n match: '/',\n // sourcePath and requestPath are required by types but unused in this case.\n entry: [{ importPath: '.', sourcePath: '' }],\n });\n }\n\n for (const route of routes) {\n const matches = Array.isArray(route.match) ? route.match : [route.match];\n\n for (const match of matches) {\n const { pathMatch, domainMatch } = parseRouteMatch(match);\n\n if (isStaticRoute(route)) {\n app.use(pathMatch, matchDomain(domainMatch), express.static(path.resolve(appPath, route.staticPath)));\n } else if (isRedirectRoute(route)) {\n app.get(pathMatch, matchDomain(domainMatch), (req, res) => {\n res.redirect(route.redirectTo);\n });\n } else if (isRenderedRoute(route) || isBootstrapRoute(route)) {\n app.get(pathMatch, matchDomain(domainMatch), (req, res) => {\n handleRequest({ ...otherOptions, route, req, res }, context).catch((err) => {\n console.error((err as Error)?.stack || err);\n res.status(500).send(`Error loading app: ${err}`);\n });\n });\n } else {\n throw new Error(`Unknown route: ${JSON.stringify(route)}`);\n }\n }\n }\n}\n\nasync function handleRequest(\n options: Omit<CreateRoutesOptions, 'app'> & {\n req: Request;\n res: Response;\n route: RenderedRoute | BootstrapRoute;\n },\n context: CreateRoutesContext,\n) {\n const { req, res, definition, route, url } = options;\n const { session } = context;\n const { bundleServer, appServer } = session.urls;\n\n if (!bundleServer) {\n throw new Error('The bundle server URL is not yet set in the session (this is a Cloudpack bug).');\n }\n\n if (!appServer) {\n throw new Error('The app server URL is not yet set in the session (this is a Cloudpack bug).');\n }\n\n // Build the import map if it hasn't been built yet for this session version.\n // (TS can't infer that urls.bundleServer is set on session from a check above.)\n const importMap = (session.importMap ??= await createImportMap({\n ...context,\n ...session,\n urls: { bundleServer, appServer },\n }));\n\n // For production mode, no overlay script.\n const overlayScript = session.config.mode !== 'production' ? importMap.imports['@ms-cloudpack/overlay'] : undefined;\n\n // Get all entry scripts for the route.\n const entryScripts = route.entry?.map(\n (entry) => importMap.imports[slash(path.join(definition.name, entry.importPath))],\n );\n\n const pageSessionContextScript =\n `window.__cloudpack ??= {};\\n` +\n `window.__cloudpack.pageSessionContext = ${JSON.stringify(createPageSessionContext(session, req.path))};`;\n\n // Add the pageSessionContext to the top of the inlineScripts\n const inlineScripts = [pageSessionContextScript, ...(await getInlineScripts())];\n\n // Set the appropriate Cloudpack headers in the response.\n res.header('Cache-Control', 'no-cache');\n res.header('Access-Control-Allow-Origin', '*');\n\n let rendered: ExpandedRenderFunctionResult | null;\n\n if (isBootstrapRoute(route)) {\n // Render the bootstrap script\n rendered = await renderBootstrapRoute({\n session,\n importMap,\n overlayScript,\n inlineScripts,\n entryScripts,\n requestPath: req.path,\n });\n } else {\n // HTML or custom script rendering\n rendered = await renderRoute({\n ...options,\n session,\n baseUrl: url,\n importMap,\n overlayScript,\n inlineScripts,\n entryScripts,\n });\n }\n\n if (rendered) {\n res.type(rendered.contentType).status(rendered.statusCode).send(rendered.content).end();\n }\n\n console.debug(`App server: Request: ${req.path}`);\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { RouteMatch } from '@ms-cloudpack/common-types';
2
+ /**
3
+ * Helper which parses the route "match" value into an object, ensuring that if a domain were provided,
4
+ * it is translated into a regular expression that can be tested against the hostname in the express request.
5
+ */
6
+ export declare function parseRouteMatch(match: RouteMatch): {
7
+ pathMatch: string;
8
+ domainMatch?: RegExp;
9
+ };
10
+ //# sourceMappingURL=parseRouteMatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseRouteMatch.d.ts","sourceRoot":"","sources":["../src/parseRouteMatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE7D;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAsB9F"}
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * Helper which parses the route "match" value into an object, ensuring that if a domain were provided,
3
- * that it is translated into a regular expression that can be tested against the hostname in the express
4
- * request.
3
+ * it is translated into a regular expression that can be tested against the hostname in the express request.
5
4
  */
6
- export function parseMatch(match) {
5
+ export function parseRouteMatch(match) {
7
6
  const pathMatch = typeof match === 'string' ? match : match.path;
8
7
  const domainString = typeof match === 'string' ? undefined : match.domain;
9
8
  if (!domainString) {
@@ -22,4 +21,4 @@ export function parseMatch(match) {
22
21
  domainMatch,
23
22
  };
24
23
  }
25
- //# sourceMappingURL=parseMatch.js.map
24
+ //# sourceMappingURL=parseRouteMatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseRouteMatch.js","sourceRoot":"","sources":["../src/parseRouteMatch.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAiB;IAC/C,MAAM,SAAS,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IACjE,MAAM,YAAY,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IAE1E,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO;YACL,SAAS;SACV,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,MAAM,aAAa,GAAG,YAAY;SAC/B,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC,6BAA6B;SACrE,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,qCAAqC;IAE9D,qDAAqD;IACrD,MAAM,WAAW,GAAG,IAAI,MAAM,CAAC,IAAI,aAAa,aAAa,CAAC,CAAC;IAE/D,OAAO;QACL,SAAS,EAAE,SAAS,IAAI,GAAG;QAC3B,WAAW;KACZ,CAAC;AACJ,CAAC","sourcesContent":["import type { RouteMatch } from '@ms-cloudpack/common-types';\n\n/**\n * Helper which parses the route \"match\" value into an object, ensuring that if a domain were provided,\n * it is translated into a regular expression that can be tested against the hostname in the express request.\n */\nexport function parseRouteMatch(match: RouteMatch): { pathMatch: string; domainMatch?: RegExp } {\n const pathMatch = typeof match === 'string' ? match : match.path;\n const domainString = typeof match === 'string' ? undefined : match.domain;\n\n if (!domainString) {\n return {\n pathMatch,\n };\n }\n\n // Escape special regex characters except '*', then replace '*' with '.*'\n const escapedDomain = domainString\n .replace(/[-/\\\\^$+?.()|[\\]{}]/g, '\\\\$&') // Escape regex special chars\n .replace(/\\*/g, '.*'); // Convert wildcards to regex pattern\n\n // Adjust regex to account for optional port matching\n const domainMatch = new RegExp(`^${escapedDomain}(?::\\\\d+)?$`);\n\n return {\n pathMatch: pathMatch || '/',\n domainMatch,\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ms-cloudpack/app-server",
3
- "version": "0.17.6",
3
+ "version": "0.17.7",
4
4
  "description": "An implementation of the App server for Cloudpack.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -14,14 +14,14 @@
14
14
  }
15
15
  },
16
16
  "dependencies": {
17
- "@ms-cloudpack/api-server": "^0.55.0",
18
- "@ms-cloudpack/bundle-server": "^0.6.15",
19
- "@ms-cloudpack/common-types": "^0.23.1",
20
- "@ms-cloudpack/create-express-app": "^1.10.2",
21
- "@ms-cloudpack/import-map": "^0.8.9",
22
- "@ms-cloudpack/overlay": "^0.17.87",
17
+ "@ms-cloudpack/api-server": "^0.56.0",
18
+ "@ms-cloudpack/bundle-server": "^0.6.16",
19
+ "@ms-cloudpack/common-types": "^0.23.2",
20
+ "@ms-cloudpack/create-express-app": "^1.10.3",
21
+ "@ms-cloudpack/import-map": "^0.8.10",
22
+ "@ms-cloudpack/overlay": "^0.17.88",
23
23
  "@ms-cloudpack/path-string-parsing": "^1.2.4",
24
- "@ms-cloudpack/path-utilities": "^2.7.50",
24
+ "@ms-cloudpack/path-utilities": "^2.7.51",
25
25
  "@ms-cloudpack/task-reporter": "^0.14.5",
26
26
  "jsdom": "^24.0.0"
27
27
  },
@@ -1,11 +0,0 @@
1
- import type { RouteMatch } from '../../common-types/lib/Route.js';
2
- /**
3
- * Helper which parses the route "match" value into an object, ensuring that if a domain were provided,
4
- * that it is translated into a regular expression that can be tested against the hostname in the express
5
- * request.
6
- */
7
- export declare function parseMatch(match: RouteMatch): {
8
- pathMatch: string;
9
- domainMatch?: RegExp;
10
- };
11
- //# sourceMappingURL=parseMatch.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"parseMatch.d.ts","sourceRoot":"","sources":["../src/parseMatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAElE;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAsBzF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"parseMatch.js","sourceRoot":"","sources":["../src/parseMatch.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,MAAM,SAAS,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IACjE,MAAM,YAAY,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IAE1E,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO;YACL,SAAS;SACV,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,MAAM,aAAa,GAAG,YAAY;SAC/B,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC,6BAA6B;SACrE,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,qCAAqC;IAE9D,qDAAqD;IACrD,MAAM,WAAW,GAAG,IAAI,MAAM,CAAC,IAAI,aAAa,aAAa,CAAC,CAAC;IAE/D,OAAO;QACL,SAAS,EAAE,SAAS,IAAI,GAAG;QAC3B,WAAW;KACZ,CAAC;AACJ,CAAC","sourcesContent":["import type { RouteMatch } from '../../common-types/lib/Route.js';\n\n/**\n * Helper which parses the route \"match\" value into an object, ensuring that if a domain were provided,\n * that it is translated into a regular expression that can be tested against the hostname in the express\n * request.\n */\nexport function parseMatch(match: RouteMatch): { pathMatch: string; domainMatch?: RegExp } {\n const pathMatch = typeof match === 'string' ? match : match.path;\n const domainString = typeof match === 'string' ? undefined : match.domain;\n\n if (!domainString) {\n return {\n pathMatch,\n };\n }\n\n // Escape special regex characters except '*', then replace '*' with '.*'\n const escapedDomain = domainString\n .replace(/[-/\\\\^$+?.()|[\\]{}]/g, '\\\\$&') // Escape regex special chars\n .replace(/\\*/g, '.*'); // Convert wildcards to regex pattern\n\n // Adjust regex to account for optional port matching\n const domainMatch = new RegExp(`^${escapedDomain}(?::\\\\d+)?$`);\n\n return {\n pathMatch: pathMatch || '/',\n domainMatch,\n };\n}\n"]}