Skip to content

Commit d9ecff1

Browse files
committed
Re-add support for snapshots
1 parent 0540260 commit d9ecff1

8 files changed

Lines changed: 160 additions & 228 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export class LoadPageError extends Error {
2+
statusCode: number;
3+
constructor({ message, statusCode }: { message: string; statusCode: number }) {
4+
super(message);
5+
this.statusCode = statusCode;
6+
}
7+
}

packages/loaders/src/index.ts

Lines changed: 15 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,22 @@
11
import path from 'path';
2-
import matter from 'gray-matter';
3-
import type { SafeParseError } from 'zod';
4-
import { activeEnvSchema } from '@jpmorganchase/mosaic-schemas';
52
import type { SharedConfig } from '@jpmorganchase/mosaic-store';
3+
import type { MosaicMode } from '@jpmorganchase/mosaic-types';
64

75
import type { LoaderPage } from './types/index.js';
6+
import { loadActiveContent, loadActiveMosaicData } from './loadActiveContent';
7+
import { loadSnapshotFileContent, loadSnapshotFileMosaicData } from './loadSnapshotFileContent';
88

9+
export { LoadPageError } from './LoadPageError';
910
export * from './types/index.js';
1011

11-
const normalizePageUrl = (url: string): string => (/\/index$/.test(url) ? `${url}.mdx` : url);
12-
13-
type ActiveModeUrlEnv = {
14-
MOSAIC_ACTIVE_MODE_URL: string;
15-
};
16-
17-
export class LoadPageError extends Error {
18-
statusCode: number;
19-
constructor({ message, statusCode }: { message: string; statusCode: number }) {
20-
super(message);
21-
this.statusCode = statusCode;
22-
}
23-
}
24-
25-
const getFSRootUrl = (): string => {
26-
const env = activeEnvSchema.safeParse(process.env);
27-
if (!env.success) {
28-
const { error } = env as SafeParseError<ActiveModeUrlEnv>;
29-
error.issues.forEach(issue => {
30-
console.error(
31-
`Missing process.env.${issue.path.join()} environment variable required to load pages`
32-
);
33-
});
34-
throw new LoadPageError({
35-
message: `Environment variables missing to load pages`,
36-
statusCode: 500
37-
});
38-
}
39-
return env.data.MOSAIC_ACTIVE_MODE_URL;
40-
};
41-
4212
export const loadMosaicData = async <T>(url: string): Promise<T> => {
43-
const fsRootUrl = getFSRootUrl();
44-
const dataUrl = new URL(url, fsRootUrl);
45-
const response = await fetch(dataUrl);
13+
const mode: MosaicMode = (process.env.MOSAIC_MODE || 'active') as MosaicMode;
4614

47-
if (!response.ok) {
48-
// This will activate the closest `error.js` Error Boundary
49-
throw new Error(`Failed to fetch mosaic data @ ${dataUrl}`);
15+
if (mode === 'snapshot-file') {
16+
return loadSnapshotFileMosaicData(url);
5017
}
51-
return response.json();
18+
19+
return loadActiveMosaicData(url);
5220
};
5321

5422
export const loadSharedConfig = async (route: string): Promise<SharedConfig | undefined> => {
@@ -58,20 +26,11 @@ export const loadSharedConfig = async (route: string): Promise<SharedConfig | un
5826
};
5927

6028
export const loadPage = async (route: string): Promise<LoaderPage> => {
61-
const fsRootUrl = getFSRootUrl();
62-
const pageUrl = normalizePageUrl(`${fsRootUrl}${route}`);
63-
const response = await fetch(pageUrl);
64-
if (response.status === 302) {
65-
const { redirect } = await response.json();
66-
return loadPage(redirect);
67-
}
68-
if (response.ok) {
69-
const source = await response.text();
70-
const { content, data } = matter(source);
71-
return { source: content, data };
29+
const mode: MosaicMode = (process.env.MOSAIC_MODE || 'active') as MosaicMode;
30+
31+
if (mode === 'snapshot-file') {
32+
return loadSnapshotFileContent(route);
7233
}
73-
throw new LoadPageError({
74-
message: `Could not load page : ${pageUrl} ${response.status}/${response.statusText}`,
75-
statusCode: 404
76-
});
34+
35+
return loadActiveContent(route);
7736
};
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import matter from 'gray-matter';
2+
import type { SafeParseError } from 'zod';
3+
import { activeEnvSchema } from '@jpmorganchase/mosaic-schemas';
4+
5+
import { LoadPageError } from './LoadPageError';
6+
import type { LoaderPage } from './types/index.js';
7+
8+
const normalizePageUrl = (url: string): string => (/\/index$/.test(url) ? `${url}.mdx` : url);
9+
10+
type ActiveModeUrlEnv = {
11+
MOSAIC_ACTIVE_MODE_URL: string;
12+
};
13+
14+
const getFSRootUrl = (): string => {
15+
const env = activeEnvSchema.safeParse(process.env);
16+
if (!env.success) {
17+
const { error } = env as SafeParseError<ActiveModeUrlEnv>;
18+
error.issues.forEach(issue => {
19+
console.error(
20+
`Missing process.env.${issue.path.join()} environment variable required to load pages`
21+
);
22+
});
23+
throw new LoadPageError({
24+
message: `Environment variables missing to load pages`,
25+
statusCode: 500
26+
});
27+
}
28+
return env.data.MOSAIC_ACTIVE_MODE_URL;
29+
};
30+
31+
export const loadActiveMosaicData = async <T>(url: string): Promise<T> => {
32+
const fsRootUrl = getFSRootUrl();
33+
const dataUrl = new URL(url, fsRootUrl);
34+
const response = await fetch(dataUrl);
35+
36+
if (!response.ok) {
37+
// This will activate the closest `error.js` Error Boundary
38+
throw new Error(`Failed to fetch mosaic data @ ${dataUrl}`);
39+
}
40+
return response.json();
41+
};
42+
43+
export const loadActiveContent = async (route: string): Promise<LoaderPage> => {
44+
const fsRootUrl = getFSRootUrl();
45+
const pageUrl = normalizePageUrl(`${fsRootUrl}${route}`);
46+
const response = await fetch(pageUrl);
47+
if (response.status === 302) {
48+
const { redirect } = await response.json();
49+
return loadActiveContent(redirect);
50+
}
51+
if (response.ok) {
52+
const source = await response.text();
53+
const { content, data } = matter(source);
54+
return { source: content, data };
55+
}
56+
throw new LoadPageError({
57+
message: `Could not load page : ${pageUrl} ${response.status}/${response.statusText}`,
58+
statusCode: 404
59+
});
60+
};
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import path from 'path';
2+
import fs from 'node:fs/promises';
3+
import matter from 'gray-matter';
4+
import { snapshotFileEnvSchema } from '@jpmorganchase/mosaic-schemas';
5+
6+
import { LoadPageError } from './LoadPageError';
7+
import type { LoaderPage } from './types/index.js';
8+
9+
const normalizePageUrl = (url: string): string => (/\/index$/.test(url) ? `${url}.mdx` : url);
10+
11+
const getFSRootUrl = (): string => {
12+
const env = snapshotFileEnvSchema.safeParse(process.env);
13+
if (!env.success) {
14+
env.error.issues.forEach(issue => {
15+
console.error(
16+
`Missing process.env.${issue.path.join()} environment variable required to load pages`
17+
);
18+
});
19+
throw new LoadPageError({
20+
message: `Environment variables missing to load pages`,
21+
statusCode: 500
22+
});
23+
}
24+
return env.data.MOSAIC_SNAPSHOT_DIR;
25+
};
26+
27+
export const loadSnapshotFileMosaicData = async <T>(url: string): Promise<T> => {
28+
const matches = url.match(/(.*)[!/]/);
29+
const urlPath = matches?.length ? matches[1] : '';
30+
31+
const fsRootUrl = getFSRootUrl();
32+
const filePath = path.join(process.cwd(), fsRootUrl, urlPath);
33+
34+
let fileExists = false;
35+
try {
36+
await fs.stat(filePath);
37+
fileExists = true;
38+
} catch {}
39+
if (fileExists) {
40+
let localPath = filePath;
41+
if ((await fs.stat(filePath)).isDirectory()) {
42+
localPath = path.posix.join(localPath, 'index');
43+
}
44+
const realPath = await fs.realpath(localPath);
45+
console.log(localPath, realPath);
46+
const source = await fs.readFile(realPath, 'utf-8');
47+
return JSON.parse(source);
48+
}
49+
throw new Error(`Failed to fetch mosaic data @ ${url}`);
50+
};
51+
52+
export const loadSnapshotFileContent = async (route: string): Promise<LoaderPage> => {
53+
const fsRootUrl = getFSRootUrl();
54+
const pageUrl = normalizePageUrl(route);
55+
const filePath = path.posix.join(process.cwd(), fsRootUrl, pageUrl);
56+
try {
57+
let localPath = filePath;
58+
if ((await fs.stat(filePath)).isDirectory()) {
59+
localPath = path.posix.join(localPath, 'index');
60+
}
61+
const realPath = await fs.realpath(localPath);
62+
const source = await fs.readFile(realPath, 'utf-8');
63+
const { content, data } = matter(source);
64+
return { source: content, data };
65+
} catch (error) {
66+
if (error instanceof Error) {
67+
console.error(error.message);
68+
}
69+
throw new LoadPageError({
70+
message: `Could not read local file '${filePath}' for '${route}'`,
71+
statusCode: 404
72+
});
73+
}
74+
};

packages/site-components/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
"@jpmorganchase/mosaic-content-editor-plugin": "^0.1.0-beta.89",
4545
"@jpmorganchase/mosaic-labs-components": "^0.1.0-beta.89",
4646
"@jpmorganchase/mosaic-open-api-component": "^0.1.0-beta.89",
47-
"@jpmorganchase/mosaic-site-middleware": "^0.1.0-beta.89",
4847
"@jpmorganchase/mosaic-store": "^0.1.0-beta.89",
4948
"@jpmorganchase/mosaic-theme": "^0.1.0-beta.89",
5049
"@salt-ds/core": "^1.33.0",

packages/site-preset-styles/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"@jpmorganchase/mosaic-site-components": "0.1.0-beta.89",
4040
"@jpmorganchase/mosaic-layouts": "0.1.0-beta.89",
4141
"@jpmorganchase/mosaic-theme": "0.1.0-beta.89",
42+
"@jpmorganchase/mosaic-mdx-components": "0.1.0-beta.89",
4243
"prismjs": "^1.23.0"
4344
},
4445
"peerDependencies": {}

packages/site/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"@jpmorganchase/mosaic-layouts": "^0.1.0-beta.89",
3636
"@jpmorganchase/mosaic-loaders": "^0.1.0-beta.89",
3737
"@jpmorganchase/mosaic-site-components": "^0.1.0-beta.89",
38+
"@jpmorganchase/mosaic-site-components-next": "^0.1.0-beta.89",
3839
"@jpmorganchase/mosaic-site-preset-styles": "^0.1.0-beta.89",
3940
"@jpmorganchase/mosaic-sitemap-component": "^0.1.0-beta.89",
4041
"@jpmorganchase/mosaic-source-git-repo": "^0.1.0-beta.89",

0 commit comments

Comments
 (0)