@jpmorganchase/mosaic-site-middleware 0.1.0-beta.13 → 0.1.0-beta.15

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 (37) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +30 -0
  3. package/dist/index.d.ts +1 -2
  4. package/dist/index.js +1 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/loaders/index.d.ts +2 -0
  7. package/dist/loaders/index.js +8 -0
  8. package/dist/loaders/index.js.map +1 -0
  9. package/dist/loaders/loadS3File.d.ts +2 -0
  10. package/dist/loaders/loadS3File.js +38 -0
  11. package/dist/loaders/loadS3File.js.map +1 -0
  12. package/dist/middlewarePresets.d.ts +1 -1
  13. package/dist/middlewarePresets.js +2 -2
  14. package/dist/middlewarePresets.js.map +1 -1
  15. package/dist/{withStaticContent.d.ts → withMDXContent.d.ts} +2 -2
  16. package/dist/withMDXContent.js +96 -0
  17. package/dist/withMDXContent.js.map +1 -0
  18. package/dist/withSharedConfig.d.ts +1 -2
  19. package/dist/withSharedConfig.js +36 -60
  20. package/dist/withSharedConfig.js.map +1 -1
  21. package/package.json +8 -3
  22. package/src/__tests__/withMDXContent.test.ts +92 -0
  23. package/src/__tests__/withSharedConfig.test.ts +87 -0
  24. package/src/index.ts +1 -2
  25. package/src/loaders/index.ts +9 -0
  26. package/src/loaders/loadS3File.ts +48 -0
  27. package/src/middlewarePresets.ts +3 -2
  28. package/src/withMDXContent.ts +113 -0
  29. package/src/withSharedConfig.ts +41 -66
  30. package/dist/withContent.d.ts +0 -17
  31. package/dist/withContent.js +0 -54
  32. package/dist/withContent.js.map +0 -1
  33. package/dist/withStaticContent.js +0 -42
  34. package/dist/withStaticContent.js.map +0 -1
  35. package/src/__tests__/createMDXScope.test.ts +0 -79
  36. package/src/withContent.ts +0 -67
  37. package/src/withStaticContent.ts +0 -45
@@ -1,2 +1,2 @@
1
- @jpmorganchase/mosaic-site-middleware:build: cache hit, replaying output a503b5d072aa4501
1
+ @jpmorganchase/mosaic-site-middleware:build: cache hit, replaying output a7287f9d02fb07cd
2
2
  @jpmorganchase/mosaic-site-middleware:build: $ tsc
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @jpmorganchase/mosaic-site-middleware
2
2
 
3
+ ## 0.1.0-beta.15
4
+
5
+ ### Patch Changes
6
+
7
+ - aaaf255: initial release of HTTP Source package.
8
+
9
+ An HTTP source accepts a collection of endpoints and a path to a transformer module.
10
+ The response from fetching is transformed and merged together into 1 single collection of pages.
11
+ Should 1 of the endpoints request fail then it will have no impact on the other requests.
12
+
13
+ - Updated dependencies [aaaf255]
14
+ - @jpmorganchase/mosaic-schemas@0.1.0-beta.15
15
+ - @jpmorganchase/mosaic-store@0.1.0-beta.15
16
+ - @jpmorganchase/mosaic-types@0.1.0-beta.15
17
+
18
+ ## 0.1.0-beta.14
19
+
20
+ ### Patch Changes
21
+
22
+ - dde3b5a: Feature release
23
+
24
+ - Enhanced generators now have defaults.
25
+ With one command (`yarn mosaic-create-site create`) it will generate a fully working site with both local and remote sources
26
+ - Fix an issue where we could not clone from the master branch of git repos
27
+ - Migrate to Next 13 image
28
+
29
+ - Updated dependencies [dde3b5a]
30
+ - @jpmorganchase/mosaic-store@0.1.0-beta.14
31
+ - @jpmorganchase/mosaic-types@0.1.0-beta.14
32
+
3
33
  ## 0.1.0-beta.13
4
34
 
5
35
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -2,8 +2,7 @@ export * from './compileMdx.js';
2
2
  export * from './createMiddlewareRunner.js';
3
3
  export * from './MiddlewareError.js';
4
4
  export * from './middlewarePresets.js';
5
- export * from './withContent.js';
5
+ export * from './withMDXContent.js';
6
6
  export * from './withMosaicMode.js';
7
7
  export * from './withSession.js';
8
8
  export * from './withSharedConfig.js';
9
- export * from './withStaticContent.js';
package/dist/index.js CHANGED
@@ -2,9 +2,8 @@ export * from './compileMdx.js';
2
2
  export * from './createMiddlewareRunner.js';
3
3
  export * from './MiddlewareError.js';
4
4
  export * from './middlewarePresets.js';
5
- export * from './withContent.js';
5
+ export * from './withMDXContent.js';
6
6
  export * from './withMosaicMode.js';
7
7
  export * from './withSession.js';
8
8
  export * from './withSharedConfig.js';
9
- export * from './withStaticContent.js';
10
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './loadS3File.js';
2
+ export declare const loadLocalFile: (filePath: string) => Promise<string>;
@@ -0,0 +1,8 @@
1
+ import fs from 'fs';
2
+ export * from './loadS3File.js';
3
+ export const loadLocalFile = async (filePath) => {
4
+ const realPath = await fs.promises.realpath(filePath);
5
+ const data = await fs.promises.readFile(realPath, 'utf-8');
6
+ return data.toString();
7
+ };
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/loaders/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,cAAc,iBAAiB,CAAC;AAEhC,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,QAAgB,EAAmB,EAAE;IACvE,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3D,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;AACzB,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function readFile(client: any, bucket: any, key: any): Promise<any>;
2
+ export declare const loadS3File: (key: string) => Promise<string>;
@@ -0,0 +1,38 @@
1
+ import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
2
+ import { s3LoaderProcessEnvSchema } from '@jpmorganchase/mosaic-schemas';
3
+ let client;
4
+ function createClient(region, accessKeyId, secretAccessKey) {
5
+ return new S3Client({
6
+ region,
7
+ credentials: {
8
+ accessKeyId,
9
+ secretAccessKey
10
+ }
11
+ });
12
+ }
13
+ export async function readFile(client, bucket, key) {
14
+ const params = {
15
+ Bucket: bucket,
16
+ Key: key
17
+ };
18
+ const command = new GetObjectCommand(params);
19
+ const response = await client.send(command);
20
+ return response;
21
+ }
22
+ export const loadS3File = async (key) => {
23
+ const env = s3LoaderProcessEnvSchema.safeParse(process.env);
24
+ if (!env.success) {
25
+ env.error.issues.forEach(issue => {
26
+ console.error(`Missing process.env.${issue.path.join()} environment variable required to load S3 ${key}`);
27
+ });
28
+ throw new Error(`Environment variables missing for loading of S3 content for key ${key}`);
29
+ }
30
+ const { MOSAIC_S3_BUCKET: bucket, MOSAIC_S3_REGION: region, MOSAIC_S3_ACCESS_KEY_ID: accessKeyId, MOSAIC_S3_SECRET_ACCESS_KEY: secretAccessKey } = env.data;
31
+ if (!client) {
32
+ client = createClient(region, accessKeyId, secretAccessKey);
33
+ }
34
+ const data = await readFile(client, bucket, key);
35
+ const text = await data.Body.transformToString();
36
+ return text;
37
+ };
38
+ //# sourceMappingURL=loadS3File.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadS3File.js","sourceRoot":"","sources":["../../src/loaders/loadS3File.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,IAAI,MAAM,CAAC;AAEX,SAAS,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,eAAe;IACxD,OAAO,IAAI,QAAQ,CAAC;QAClB,MAAM;QACN,WAAW,EAAE;YACX,WAAW;YACX,eAAe;SAChB;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG;IAChD,MAAM,MAAM,GAAG;QACb,MAAM,EAAE,MAAM;QACd,GAAG,EAAE,GAAG;KACT,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,GAAW,EAAmB,EAAE;IAC/D,MAAM,GAAG,GAAG,wBAAwB,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5D,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE;QAChB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YAC/B,OAAO,CAAC,KAAK,CACX,uBAAuB,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,6CAA6C,GAAG,EAAE,CAC3F,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,MAAM,IAAI,KAAK,CAAC,mEAAmE,GAAG,EAAE,CAAC,CAAC;KAC3F;IACD,MAAM,EACJ,gBAAgB,EAAE,MAAM,EACxB,gBAAgB,EAAE,MAAM,EACxB,uBAAuB,EAAE,WAAW,EACpC,2BAA2B,EAAE,eAAe,EAC7C,GAAG,GAAG,CAAC,IAAI,CAAC;IACb,IAAI,CAAC,MAAM,EAAE;QACX,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;KAC7D;IACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;IACjD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import type { Redirect } from 'next';
2
2
  import { SharedConfigSlice } from '@jpmorganchase/mosaic-store';
3
+ import type { ContentProps } from '@jpmorganchase/mosaic-types';
3
4
  import { type SessionProps, type SessionOptions } from './withSession.js';
4
- import { type ContentProps } from './withContent.js';
5
5
  import { MosaicMiddleware, MosaicMiddlewareWithConfig } from './createMiddlewareRunner.js';
6
6
  import { type MosaicModeProps } from './withMosaicMode.js';
7
7
  export declare type BaseMosaicAppProps = {
@@ -1,12 +1,12 @@
1
1
  import { withSession } from './withSession.js';
2
2
  import { withSharedConfig } from './withSharedConfig.js';
3
- import { withContent } from './withContent.js';
3
+ import { withMDXContent } from './withMDXContent.js';
4
4
  import { withMosaicMode } from './withMosaicMode.js';
5
5
  /** A collection of preset [[`Middleware`]] plugins that will compose together the page props */
6
6
  export const middlewarePresets = [
7
7
  [withSession, { loginRequired: process.env.DISABLE_GLOBAL_AUTH !== 'true' }],
8
8
  withMosaicMode,
9
9
  withSharedConfig,
10
- withContent
10
+ withMDXContent
11
11
  ];
12
12
  //# sourceMappingURL=middlewarePresets.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"middlewarePresets.js","sourceRoot":"","sources":["../src/middlewarePresets.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAA0C,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAqB,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAE,cAAc,EAAwB,MAAM,qBAAqB,CAAC;AAmC3E,gGAAgG;AAChG,MAAM,CAAC,MAAM,iBAAiB,GAG1B;IACF,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,MAAM,EAAE,CAAC;IAC5E,cAAc;IACd,gBAAgB;IAChB,WAAW;CACZ,CAAC"}
1
+ {"version":3,"file":"middlewarePresets.js","sourceRoot":"","sources":["../src/middlewarePresets.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAA0C,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,cAAc,EAAwB,MAAM,qBAAqB,CAAC;AAmC3E,gGAAgG;AAChG,MAAM,CAAC,MAAM,iBAAiB,GAG1B;IACF,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,MAAM,EAAE,CAAC;IAC5E,cAAc;IACd,gBAAgB;IAChB,cAAc;CACf,CAAC"}
@@ -1,7 +1,7 @@
1
+ import type { ContentProps } from '@jpmorganchase/mosaic-types';
1
2
  import { MosaicMiddleware } from './createMiddlewareRunner.js';
2
- import { ContentProps } from './withContent.js';
3
3
  /**
4
4
  * Adds the [[`ContentProps`]] object to the page props
5
5
  * @param context
6
6
  */
7
- export declare const withStaticContent: MosaicMiddleware<ContentProps>;
7
+ export declare const withMDXContent: MosaicMiddleware<ContentProps>;
@@ -0,0 +1,96 @@
1
+ import path from 'path';
2
+ import { fileLoaderProcessEnvSchema } from '@jpmorganchase/mosaic-schemas';
3
+ import MiddlewareError from './MiddlewareError.js';
4
+ import { loadLocalFile, loadS3File } from './loaders/index.js';
5
+ import { compileMDX } from './compileMdx.js';
6
+ if (typeof window !== 'undefined') {
7
+ throw new Error('This file should not be loaded on the client.');
8
+ }
9
+ /**
10
+ * Adds the [[`ContentProps`]] object to the page props
11
+ * @param context
12
+ */
13
+ export const withMDXContent = async (context) => {
14
+ const { resolvedUrl } = context;
15
+ const mosaicMode = context.res.getHeader('X-Mosaic-Mode' || 'active');
16
+ const extname = path.extname(resolvedUrl);
17
+ // Any urls which are not prefixed, will default to MDX
18
+ const isMDX = extname === '.mdx' || extname === '';
19
+ if (!isMDX) {
20
+ return {};
21
+ }
22
+ const normalizedUrl = /\/index$/.test(resolvedUrl) ? `${resolvedUrl}.mdx` : resolvedUrl;
23
+ let text;
24
+ if (mosaicMode === 'snapshot-file') {
25
+ const env = fileLoaderProcessEnvSchema.safeParse(process.env);
26
+ if (!env.success) {
27
+ env.error.issues.forEach(issue => {
28
+ console.error(`Missing process.env.${issue.path.join()} environment variable required to load MDX for ${resolvedUrl}`);
29
+ });
30
+ throw new Error(`Environment variables missing for loading of MDX content ${resolvedUrl}`);
31
+ }
32
+ const { MOSAIC_SNAPSHOT_DIR: mosaicSnapshotDir } = env.data;
33
+ const filePath = path.posix.join(process.cwd(), mosaicSnapshotDir, normalizedUrl);
34
+ try {
35
+ text = await loadLocalFile(filePath);
36
+ }
37
+ catch (error) {
38
+ if (error instanceof Error) {
39
+ console.error(error.message);
40
+ }
41
+ throw new MiddlewareError(404, resolvedUrl, [`Could not read local file '${filePath}' for '${resolvedUrl}'`], {
42
+ show404: true
43
+ });
44
+ }
45
+ }
46
+ else if (mosaicMode === 'snapshot-s3') {
47
+ try {
48
+ const s3Key = normalizedUrl.replace(/^\//, '');
49
+ text = await loadS3File(s3Key);
50
+ }
51
+ catch (error) {
52
+ if (error instanceof Error) {
53
+ console.error(error.message);
54
+ }
55
+ throw new MiddlewareError(404, resolvedUrl, [`Could not find an S3 object for '${resolvedUrl}'`], {
56
+ show404: true
57
+ });
58
+ }
59
+ }
60
+ else {
61
+ const mosaicUrl = context.res.getHeader('X-Mosaic-Content-Url');
62
+ const response = await fetch(`${mosaicUrl}${normalizedUrl}`);
63
+ if (response.ok) {
64
+ text = await response.text();
65
+ // If redirect url was returned
66
+ }
67
+ else if (response.status === 302) {
68
+ return {
69
+ redirect: {
70
+ destination: (await response.json()).redirect,
71
+ permanent: true
72
+ }
73
+ };
74
+ }
75
+ else {
76
+ throw new MiddlewareError(404, resolvedUrl, [`Could not fetch any content for ${resolvedUrl}`], {
77
+ show404: true
78
+ });
79
+ }
80
+ }
81
+ try {
82
+ const mdxSource = await compileMDX(text);
83
+ return { props: { type: 'mdx', source: mdxSource, raw: text } };
84
+ }
85
+ catch (error) {
86
+ if (error instanceof Error) {
87
+ console.error(error.message);
88
+ throw new MiddlewareError(500, resolvedUrl, [error.message], { show500: true });
89
+ }
90
+ else {
91
+ console.error('unexpected error');
92
+ throw new MiddlewareError(500, resolvedUrl, ['unexpected error'], { show500: true });
93
+ }
94
+ }
95
+ };
96
+ //# sourceMappingURL=withMDXContent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withMDXContent.js","sourceRoot":"","sources":["../src/withMDXContent.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,5 @@
1
- import type { SharedConfig, SharedConfigSlice } from '@jpmorganchase/mosaic-store';
1
+ import type { SharedConfigSlice } from '@jpmorganchase/mosaic-store';
2
2
  import { MosaicMiddleware } from './createMiddlewareRunner.js';
3
- export { SharedConfig };
4
3
  /**
5
4
  * Adds the [[`SharedConfig`]] props to the page props
6
5
  * @param _context
@@ -1,42 +1,10 @@
1
1
  import path from 'path';
2
- import fs from 'fs';
2
+ import { fileLoaderProcessEnvSchema } from '@jpmorganchase/mosaic-schemas';
3
3
  import MiddlewareError from './MiddlewareError.js';
4
+ import { loadLocalFile, loadS3File } from './loaders';
4
5
  if (typeof window !== 'undefined') {
5
6
  throw new Error('This file should not be loaded on the client.');
6
7
  }
7
- /**
8
- * Fetch from mosaic the shared-config.json.
9
- *
10
- * @param url the shared config file URL
11
- * @returns shared config JSON
12
- */
13
- async function fetchSharedConfig(url) {
14
- const response = await fetch(url, {
15
- headers: {
16
- 'Content-Type': 'application/json'
17
- }
18
- });
19
- return response;
20
- }
21
- /**
22
- * Read from the file system the shared config
23
- *
24
- * @param url the shared config file URL
25
- * @returns shared config JSON
26
- */
27
- async function readSharedConfig(url) {
28
- const mosaicSnapshotDir = process.env.MOSAIC_SNAPSHOT_DIR || '';
29
- const filePath = path.posix.join(process.cwd(), mosaicSnapshotDir, url);
30
- try {
31
- const realPath = await fs.promises.realpath(filePath);
32
- const data = await fs.promises.readFile(realPath, 'utf-8');
33
- return new Response(data.toString(), { status: 200 });
34
- }
35
- catch (e) {
36
- // it doesn't matter if no shared config file was found
37
- return new Response('', { status: 204 });
38
- }
39
- }
40
8
  /**
41
9
  * Adds the [[`SharedConfig`]] props to the page props
42
10
  * @param _context
@@ -44,40 +12,48 @@ async function readSharedConfig(url) {
44
12
  */
45
13
  export const withSharedConfig = async (context) => {
46
14
  const { resolvedUrl, res } = context;
47
- const isStatic = res.getHeader('X-Mosaic-Mode') === 'static';
15
+ const isSnapshotFile = res.getHeader('X-Mosaic-Mode') === 'snapshot-file';
16
+ const isSnapshotS3 = res.getHeader('X-Mosaic-Mode') === 'snapshot-s3';
48
17
  const matches = resolvedUrl.match(/(.*)[!/]/);
49
18
  const urlPath = matches?.length ? matches[1] : '';
50
- const mosaicUrl = isStatic ? '' : res.getHeader('X-Mosaic-Content-Url');
51
- const sharedConfigUrl = `${mosaicUrl}${urlPath}/shared-config.json`;
52
- let response;
53
19
  try {
54
- response = isStatic
55
- ? await readSharedConfig(sharedConfigUrl)
56
- : await fetchSharedConfig(sharedConfigUrl);
57
- if (response.ok && response.status !== 204) {
58
- const { config } = (await response.json());
59
- return { props: { sharedConfig: config } };
20
+ let sharedConfig;
21
+ if (isSnapshotFile) {
22
+ const env = fileLoaderProcessEnvSchema.safeParse(process.env);
23
+ if (!env.success) {
24
+ env.error.issues.forEach(issue => {
25
+ console.error(`Missing process.env.${issue.path.join()} environment variable required to load shared-config for ${resolvedUrl}`);
26
+ });
27
+ throw new Error(`Environment variables missing for loading of shared-config required by ${resolvedUrl}`);
28
+ }
29
+ const { MOSAIC_SNAPSHOT_DIR: mosaicSnapshotDir } = env.data;
30
+ const filePath = path.join(process.cwd(), mosaicSnapshotDir, urlPath, 'shared-config.json');
31
+ const rawSharedConfig = await loadLocalFile(filePath);
32
+ sharedConfig = JSON.parse(rawSharedConfig);
60
33
  }
61
- }
62
- catch (error) {
63
- if (error instanceof Error) {
64
- console.error(error.message);
65
- throw new MiddlewareError(500, sharedConfigUrl, [error.message], { show500: true });
34
+ else if (isSnapshotS3) {
35
+ const s3Key = `${urlPath}/shared-config.json`.replace(/^\//, '');
36
+ const rawSharedConfig = await loadS3File(s3Key);
37
+ sharedConfig = JSON.parse(rawSharedConfig);
66
38
  }
67
39
  else {
68
- console.error('unexpected error');
69
- throw new MiddlewareError(500, sharedConfigUrl, ['unexpected error'], { show500: true });
40
+ const mosaicUrl = res.getHeader('X-Mosaic-Content-Url');
41
+ const response = await fetch(`${mosaicUrl}${urlPath}/shared-config.json`, {
42
+ headers: {
43
+ 'Content-Type': 'application/json'
44
+ }
45
+ });
46
+ sharedConfig = await response.json();
70
47
  }
48
+ const { config } = sharedConfig;
49
+ return { props: { sharedConfig: config } };
71
50
  }
72
- const show500 = response.status !== 404 && response.status !== 204;
73
- const show404 = response.status === 404;
74
- let errorMessage = `Could not find any shared config defined for ${sharedConfigUrl}`;
75
- if (show500) {
76
- errorMessage = `An un-expected error occurred reading ${sharedConfigUrl}`;
51
+ catch (error) {
52
+ let errorMessage = `Could not load any shared config for ${resolvedUrl}`;
53
+ throw new MiddlewareError(500, resolvedUrl, [errorMessage], {
54
+ show404: false,
55
+ show500: true
56
+ });
77
57
  }
78
- throw new MiddlewareError(response.status, sharedConfigUrl, [errorMessage], {
79
- show404,
80
- show500
81
- });
82
58
  };
83
59
  //# sourceMappingURL=withSharedConfig.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"withSharedConfig.js","sourceRoot":"","sources":["../src/withSharedConfig.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"withSharedConfig.js","sourceRoot":"","sources":["../src/withSharedConfig.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAG3E,OAAO,eAAe,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEtD,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;IACjC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;CAClE;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAwC,KAAK,EACxE,OAAkC,EAClC,EAAE;IACF,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IACrC,MAAM,cAAc,GAAG,GAAG,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,eAAe,CAAC;IAC1E,MAAM,YAAY,GAAG,GAAG,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,aAAa,CAAC;IAEtE,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClD,IAAI;QACF,IAAI,YAAY,CAAC;QACjB,IAAI,cAAc,EAAE;YAClB,MAAM,GAAG,GAAG,0BAA0B,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC9D,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE;gBAChB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;oBAC/B,OAAO,CAAC,KAAK,CACX,uBAAuB,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,4DAA4D,WAAW,EAAE,CAClH,CAAC;gBACJ,CAAC,CAAC,CAAC;gBACH,MAAM,IAAI,KAAK,CACb,0EAA0E,WAAW,EAAE,CACxF,CAAC;aACH;YACD,MAAM,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;YAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,iBAAiB,EAAE,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC5F,MAAM,eAAe,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;YACtD,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;SAC5C;aAAM,IAAI,YAAY,EAAE;YACvB,MAAM,KAAK,GAAG,GAAG,OAAO,qBAAqB,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACjE,MAAM,eAAe,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC;YAChD,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;SAC5C;aAAM;YACL,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC;YACxD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,SAAS,GAAG,OAAO,qBAAqB,EAAE;gBACxE,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;iBACnC;aACF,CAAC,CAAC;YACH,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;SACtC;QACD,MAAM,EAAE,MAAM,EAAE,GAAG,YAAwC,CAAC;QAC5D,OAAO,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,CAAC;KAC5C;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,YAAY,GAAG,wCAAwC,WAAW,EAAE,CAAC;QACzE,MAAM,IAAI,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,CAAC,YAAY,CAAC,EAAE;YAC1D,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;KACJ;AACH,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jpmorganchase/mosaic-site-middleware",
3
- "version": "0.1.0-beta.13",
3
+ "version": "0.1.0-beta.15",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Mosaic - Site middleware",
6
6
  "main": "./dist/index.js",
@@ -20,11 +20,16 @@
20
20
  "lint": "eslint --ignore-pattern \"**/__tests__/**\""
21
21
  },
22
22
  "devDependencies": {
23
+ "aws-sdk-client-mock": "^2.0.1",
24
+ "jest-fetch-mock": "^3.0.3",
25
+ "mock-fs": "^4.14.0",
23
26
  "typescript": "^4.8.3"
24
27
  },
25
28
  "dependencies": {
26
- "@jpmorganchase/mosaic-types": "^0.1.0-beta.13",
27
- "@jpmorganchase/mosaic-store": "^0.1.0-beta.13",
29
+ "@aws-sdk/client-s3": "^3.256.0",
30
+ "@jpmorganchase/mosaic-schemas": "^0.1.0-beta.15",
31
+ "@jpmorganchase/mosaic-store": "^0.1.0-beta.15",
32
+ "@jpmorganchase/mosaic-types": "^0.1.0-beta.15",
28
33
  "@types/mdast": "^3.0.0",
29
34
  "acorn": "^8.0.0",
30
35
  "acorn-jsx": "^5.0.0",
@@ -0,0 +1,92 @@
1
+ import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
2
+ import { mockClient } from 'aws-sdk-client-mock';
3
+ import { sdkStreamMixin } from '@aws-sdk/util-stream-node';
4
+ import { Readable } from 'stream';
5
+ import { default as fetchMock, disableFetchMocks, enableFetchMocks } from 'jest-fetch-mock';
6
+
7
+ const mockFs = require('mock-fs');
8
+
9
+ import { withMDXContent } from '../withMDXContent';
10
+
11
+ jest.mock('../compileMdx.js', () => ({
12
+ compileMDX: async value => Promise.resolve(value)
13
+ }));
14
+
15
+ describe('GIVEN withMDXContent', () => {
16
+ describe('WHEN snapshot-s3 Mosaic mode is set', () => {
17
+ let savedEnv = process.env;
18
+ let s3ClientMock;
19
+ beforeAll(() => {
20
+ process.env = {
21
+ ...process.env,
22
+ MOSAIC_S3_BUCKET: 'some-bucket',
23
+ MOSAIC_S3_REGION: 'some-region',
24
+ MOSAIC_S3_ACCESS_KEY_ID: 'some-access-key',
25
+ MOSAIC_S3_SECRET_ACCESS_KEY: 'some-secret-key'
26
+ };
27
+ s3ClientMock = mockClient(S3Client);
28
+ const stream = new Readable();
29
+ stream.push('my content');
30
+ stream.push(null); // end of stream
31
+ const contentStream = sdkStreamMixin(stream);
32
+ s3ClientMock.on(GetObjectCommand).resolves({ Body: contentStream });
33
+ });
34
+ afterAll(() => {
35
+ process.env = savedEnv;
36
+ s3ClientMock.reset();
37
+ });
38
+ test('THEN a snapshot can be loaded from an S3 bucket', async () => {
39
+ // arrange
40
+ const content = await withMDXContent({
41
+ resolvedUrl: '/mynamespace/mypage.mdx',
42
+ res: { getHeader: () => 'snapshot-s3' }
43
+ });
44
+ // assert
45
+ expect(content).toEqual({ props: { raw: 'my content', source: 'my content', type: 'mdx' } });
46
+ });
47
+ });
48
+
49
+ describe('WHEN snapshot-file Mosaic mode is set', () => {
50
+ let savedEnv = process.env;
51
+ beforeAll(() => {
52
+ process.env = { ...process.env, MOSAIC_SNAPSHOT_DIR: '/some/snapshots' };
53
+ mockFs({
54
+ 'some/snapshots/mynamespace/mydir': {
55
+ 'mypage.mdx': 'my content'
56
+ }
57
+ });
58
+ });
59
+ afterAll(() => {
60
+ mockFs.restore();
61
+ process.env = savedEnv;
62
+ });
63
+
64
+ test('THEN a snapshot can be loaded from a local file', async () => {
65
+ // arrange
66
+ const content = await withMDXContent({
67
+ resolvedUrl: '/mynamespace/mydir/mypage.mdx',
68
+ res: { getHeader: () => 'snapshot-file' }
69
+ });
70
+ expect(content).toEqual({ props: { raw: 'my content', source: 'my content', type: 'mdx' } });
71
+ });
72
+ });
73
+
74
+ describe('WHEN dynamic Mosaic mode is set', () => {
75
+ beforeAll(() => {
76
+ enableFetchMocks();
77
+ fetchMock.mockOnce('my content');
78
+ });
79
+ afterAll(() => {
80
+ disableFetchMocks();
81
+ });
82
+ test('THEN content is fetched from the data source', async () => {
83
+ // arrange
84
+ const content = await withMDXContent({
85
+ resolvedUrl: '/mynamespace/mypage.mdx',
86
+ res: { getHeader: () => '/dynamic' }
87
+ });
88
+ // assert
89
+ expect(content).toEqual({ props: { raw: 'my content', source: 'my content', type: 'mdx' } });
90
+ });
91
+ });
92
+ });
@@ -0,0 +1,87 @@
1
+ import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
2
+ import { mockClient } from 'aws-sdk-client-mock';
3
+ import { sdkStreamMixin } from '@aws-sdk/util-stream-node';
4
+ import { Readable } from 'stream';
5
+ import { default as fetchMock, disableFetchMocks, enableFetchMocks } from 'jest-fetch-mock';
6
+ const mockFs = require('mock-fs');
7
+
8
+ import { withSharedConfig } from '../withSharedConfig';
9
+ describe('GIVEN withSharedConfig', () => {
10
+ describe('WHEN snapshot-s3 Mosaic mode is set', () => {
11
+ let savedEnv = process.env;
12
+ let s3ClientMock;
13
+ beforeAll(() => {
14
+ process.env = {
15
+ ...process.env,
16
+ MOSAIC_S3_BUCKET: 'some-bucket',
17
+ MOSAIC_S3_REGION: 'some-region',
18
+ MOSAIC_S3_ACCESS_KEY_ID: 'some-access-key',
19
+ MOSAIC_S3_SECRET_ACCESS_KEY: 'some-secret-key'
20
+ };
21
+ s3ClientMock = mockClient(S3Client);
22
+ const stream = new Readable();
23
+ stream.push('{"config": { "someValue": true }}');
24
+ stream.push(null); // end of stream
25
+ const contentStream = sdkStreamMixin(stream);
26
+ s3ClientMock.on(GetObjectCommand).resolves({ Body: contentStream });
27
+ });
28
+ afterAll(() => {
29
+ process.env = savedEnv;
30
+ s3ClientMock.reset();
31
+ });
32
+ test('THEN shared-config can be loaded from an S3 bucket', async () => {
33
+ // arrange
34
+ const content = await withSharedConfig({
35
+ resolvedUrl: '/mynamespace/mypage.mdx',
36
+ res: { getHeader: () => 'snapshot-s3' }
37
+ });
38
+ // assert
39
+ expect(content).toEqual({ props: { sharedConfig: { someValue: true } } });
40
+ });
41
+ });
42
+
43
+ describe('WHEN snapshot-file Mosaic mode is set', () => {
44
+ let savedEnv = process.env;
45
+ beforeAll(() => {
46
+ process.env = { MOSAIC_SNAPSHOT_DIR: '/some/snapshots' };
47
+ mockFs({
48
+ 'some/snapshots/mynamespace/mydir': {
49
+ 'shared-config.json': '{"config": { "someValue": true }}'
50
+ }
51
+ });
52
+ });
53
+ afterAll(() => {
54
+ mockFs.restore();
55
+ process.env = savedEnv;
56
+ });
57
+
58
+ test('THEN reads shared-config from a local file', async () => {
59
+ // arrange
60
+ process.env = { MOSAIC_SNAPSHOT_DIR: '/some/snapshots' };
61
+ const content = await withSharedConfig({
62
+ resolvedUrl: '/mynamespace/mydir/mypage.mdx',
63
+ res: { getHeader: () => 'snapshot-file' }
64
+ });
65
+ expect(content).toEqual({ props: { sharedConfig: { someValue: true } } });
66
+ });
67
+ });
68
+
69
+ describe('WHEN dynamic Mosaic mode is set', () => {
70
+ beforeAll(() => {
71
+ enableFetchMocks();
72
+ fetchMock.mockOnce('{"config": { "someValue": true }}');
73
+ });
74
+ afterAll(() => {
75
+ disableFetchMocks();
76
+ });
77
+ test('THEN shared-config is fetched from the data source', async () => {
78
+ // arrange
79
+ const content = await withSharedConfig({
80
+ resolvedUrl: '/mynamespace/mypage.mdx',
81
+ res: { getHeader: () => '/dynamic' }
82
+ });
83
+ // assert
84
+ expect(content).toEqual({ props: { sharedConfig: { someValue: true } } });
85
+ });
86
+ });
87
+ });