@epic-web/workshop-utils 4.28.6 → 5.0.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"cache.server.js","sourceRoot":"","sources":["../../src/cache.server.ts"],"names":[],"mappings":"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","sourcesContent":["import os from 'os'\nimport path from 'path'\nimport * as C from '@epic-web/cachified'\nimport {\n\tverboseReporter,\n\ttype CacheEntry,\n\ttype Cache as CachifiedCache,\n} from '@epic-web/cachified'\nimport { remember } from '@epic-web/remember'\nimport fsExtra from 'fs-extra'\nimport { LRUCache } from 'lru-cache'\nimport md5 from 'md5-hex'\nimport {\n\ttype App,\n\ttype ExampleApp,\n\ttype PlaygroundApp,\n\ttype ProblemApp,\n\ttype SolutionApp,\n} from './apps.server.js'\nimport { cachifiedTimingReporter, type Timings } from './timing.server.js'\n\nexport const solutionAppCache =\n\tmakeSingletonCache<SolutionApp>('SolutionAppCache')\nexport const problemAppCache = makeSingletonCache<ProblemApp>('ProblemAppCache')\nexport const exampleAppCache = makeSingletonCache<ExampleApp>('ExampleAppCache')\nexport const playgroundAppCache =\n\tmakeSingletonCache<PlaygroundApp>('PlaygroundAppCache')\nexport const appsCache = makeSingletonCache<App>('AppsCache')\nexport const diffCodeCache = makeSingletonCache<string>('DiffCodeCache')\nexport const diffFilesCache = makeSingletonCache<string>('DiffFilesCache')\nexport const compiledMarkdownCache = makeSingletonCache<string>(\n\t'CompiledMarkdownCache',\n)\nexport type CachedEmbeddedFilesList = Record<string, string[]>\nexport const embeddedFilesCache = makeSingletonCache<\n\tCachedEmbeddedFilesList | undefined\n>('EmbeddedFilesCache')\nexport const compiledCodeCache = makeSingletonCache<string>('CompiledCodeCache')\nexport const ogCache = makeSingletonCache<string>('OgCache')\n\nconst cacheDir = path.join(os.homedir(), '.epicshop', 'cache')\n\nexport const fsCache: CachifiedCache = {\n\tname: 'Filesystem cache',\n\tasync get(key) {\n\t\ttry {\n\t\t\tconst filePath = path.join(cacheDir, md5(key))\n\n\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\tif (data.entry) return data.entry\n\t\t\t// this is just here for migration purposes. Earlier versions of the cache\n\t\t\t// did not store the key in the cache file with the value under \"entry\".\n\t\t\treturn null\n\t\t} catch (error: unknown) {\n\t\t\tif (\n\t\t\t\terror instanceof Error &&\n\t\t\t\t'code' in error &&\n\t\t\t\terror.code === 'ENOENT'\n\t\t\t) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t},\n\tasync set(key, entry) {\n\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\tawait fsExtra.ensureDir(path.dirname(filePath))\n\t\t// store the key in the cache file because it's md5 hashed and the key has\n\t\t// helpful debugging information.\n\t\tawait fsExtra.writeJSON(filePath, { key, entry })\n\t},\n\tasync delete(key) {\n\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\tawait fsExtra.remove(filePath)\n\t},\n}\n\nexport async function getAllFileCacheEntries() {\n\tconst files = await fsExtra.readdir(cacheDir)\n\tconst entries = await Promise.all(\n\t\tfiles\n\t\t\t.map(async (file) => {\n\t\t\t\tconst filePath = path.join(cacheDir, file)\n\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\treturn data\n\t\t\t})\n\t\t\t.filter(Boolean),\n\t)\n\treturn entries\n}\n\nexport async function deleteCache() {\n\tif (process.env.EPICSHOP_DEPLOYED) return null\n\n\ttry {\n\t\tif (await fsExtra.exists(cacheDir)) {\n\t\t\tawait fsExtra.remove(cacheDir)\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(`Error deleting the cache in ${cacheDir}`, error)\n\t}\n}\n\nexport function makeSingletonCache<CacheEntryType>(name: string) {\n\treturn remember(name, () => {\n\t\tconst lruInstance = new LRUCache<string, CacheEntry<CacheEntryType>>({\n\t\t\tmax: 1000,\n\t\t})\n\n\t\tconst lru = {\n\t\t\tname,\n\t\t\tset: (key, value) => {\n\t\t\t\tconst ttl = C.totalTtl(value.metadata)\n\t\t\t\tlruInstance.set(key, value, {\n\t\t\t\t\tttl: ttl === Infinity ? undefined : ttl,\n\t\t\t\t\tstart: value.metadata.createdTime,\n\t\t\t\t})\n\t\t\t\treturn value\n\t\t\t},\n\t\t\tget: (key) => lruInstance.get(key),\n\t\t\tdelete: (key) => lruInstance.delete(key),\n\t\t} satisfies C.Cache<CacheEntryType>\n\n\t\treturn lru\n\t})\n}\n\nexport async function cachified<Value>({\n\trequest,\n\ttimings,\n\tkey,\n\ttimingKey = key.length > 18 ? `${key.slice(0, 7)}...${key.slice(-8)}` : key,\n\t...options\n}: Omit<C.CachifiedOptions<Value>, 'forceFresh'> & {\n\trequest?: Request\n\ttimings?: Timings\n\tforceFresh?: boolean | string\n\ttimingKey?: string\n}): Promise<Value> {\n\tconst forceFresh = await shouldForceFresh({\n\t\tforceFresh: options.forceFresh,\n\t\trequest,\n\t\tkey,\n\t})\n\treturn C.cachified(\n\t\t{\n\t\t\t...options,\n\t\t\tkey,\n\t\t\tforceFresh,\n\t\t},\n\t\tC.mergeReporters(\n\t\t\tcachifiedTimingReporter(timings, timingKey),\n\t\t\tprocess.env.EPICSHOP_DEBUG_CACHE ? verboseReporter() : undefined,\n\t\t),\n\t)\n}\n\nexport async function shouldForceFresh({\n\tforceFresh,\n\trequest,\n\tkey,\n}: {\n\tforceFresh?: boolean | string\n\trequest?: Request\n\tkey?: string\n}) {\n\tif (typeof forceFresh === 'boolean') return forceFresh\n\tif (typeof forceFresh === 'string' && key) {\n\t\treturn forceFresh.split(',').includes(key)\n\t}\n\n\tif (!request) return false\n\tconst fresh = new URL(request.url).searchParams.get('fresh')\n\tif (typeof fresh !== 'string') return false\n\tif (fresh === '') return true\n\tif (!key) return false\n\n\treturn fresh.split(',').includes(key)\n}\n"]}
1
+ {"version":3,"file":"cache.server.js","sourceRoot":"","sources":["../../src/cache.server.ts"],"names":[],"mappings":"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","sourcesContent":["import os from 'os'\nimport path from 'path'\nimport * as C from '@epic-web/cachified'\nimport { verboseReporter, type CacheEntry } from '@epic-web/cachified'\nimport { remember } from '@epic-web/remember'\nimport fsExtra from 'fs-extra'\nimport { LRUCache } from 'lru-cache'\nimport md5 from 'md5-hex'\nimport {\n\ttype App,\n\ttype ExampleApp,\n\ttype PlaygroundApp,\n\ttype ProblemApp,\n\ttype SolutionApp,\n} from './apps.server.js'\nimport { cachifiedTimingReporter, type Timings } from './timing.server.js'\n\nexport const solutionAppCache =\n\tmakeSingletonCache<SolutionApp>('SolutionAppCache')\nexport const problemAppCache = makeSingletonCache<ProblemApp>('ProblemAppCache')\nexport const exampleAppCache = makeSingletonCache<ExampleApp>('ExampleAppCache')\nexport const playgroundAppCache =\n\tmakeSingletonCache<PlaygroundApp>('PlaygroundAppCache')\nexport const appsCache = makeSingletonCache<App>('AppsCache')\nexport const diffCodeCache = makeSingletonCache<string>('DiffCodeCache')\nexport const diffFilesCache = makeSingletonCache<string>('DiffFilesCache')\nexport const compiledMarkdownCache = makeSingletonCache<string>(\n\t'CompiledMarkdownCache',\n)\nexport const compiledCodeCache = makeSingletonCache<string>('CompiledCodeCache')\nexport const ogCache = makeSingletonCache<string>('OgCache')\nexport const compiledInstructionMarkdownCache = makeSingletonFsCache<{\n\tcode: string\n\ttitle: string | null\n\tepicVideoEmbeds: Array<string>\n}>('CompiledInstructionMarkdownCache')\n\nconst cacheDir = path.join(os.homedir(), '.epicshop', 'cache')\n\nexport const fsCache = makeSingletonFsCache('FsCache')\n\nexport async function getAllFileCacheEntries() {\n\tconst files = await fsExtra.readdir(cacheDir)\n\tconst entries = await Promise.all(\n\t\tfiles\n\t\t\t.map(async (file) => {\n\t\t\t\tconst filePath = path.join(cacheDir, file)\n\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\treturn data\n\t\t\t})\n\t\t\t.filter(Boolean),\n\t)\n\treturn entries\n}\n\nexport async function deleteCache() {\n\tif (process.env.EPICSHOP_DEPLOYED) return null\n\n\ttry {\n\t\tif (await fsExtra.exists(cacheDir)) {\n\t\t\tawait fsExtra.remove(cacheDir)\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(`Error deleting the cache in ${cacheDir}`, error)\n\t}\n}\n\nexport function makeSingletonCache<CacheEntryType>(name: string) {\n\treturn remember(name, () => {\n\t\tconst lruInstance = new LRUCache<string, CacheEntry<CacheEntryType>>({\n\t\t\tmax: 1000,\n\t\t})\n\n\t\tconst lru = {\n\t\t\tname,\n\t\t\tset: (key, value) => {\n\t\t\t\tconst ttl = C.totalTtl(value.metadata)\n\t\t\t\tlruInstance.set(key, value, {\n\t\t\t\t\tttl: ttl === Infinity ? undefined : ttl,\n\t\t\t\t\tstart: value.metadata.createdTime,\n\t\t\t\t})\n\t\t\t\treturn value\n\t\t\t},\n\t\t\tget: (key) => lruInstance.get(key),\n\t\t\tdelete: (key) => lruInstance.delete(key),\n\t\t} satisfies C.Cache<CacheEntryType>\n\n\t\treturn lru\n\t})\n}\n\nexport function makeSingletonFsCache<CacheEntryType>(name: string) {\n\treturn remember(name, () => {\n\t\tconst cacheDir = path.join(os.homedir(), '.epicshop', 'cache', name)\n\n\t\tconst fsCache: C.Cache<CacheEntryType> = {\n\t\t\tname: `Filesystem cache (${name})`,\n\t\t\tasync get(key) {\n\t\t\t\ttry {\n\t\t\t\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\t\tif (data.entry) return data.entry\n\t\t\t\t\treturn null\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\tif (\n\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\t'code' in error &&\n\t\t\t\t\t\terror.code === 'ENOENT'\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t},\n\t\t\tasync set(key, entry) {\n\t\t\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\t\t\tawait fsExtra.ensureDir(path.dirname(filePath))\n\t\t\t\tawait fsExtra.writeJSON(filePath, { key, entry })\n\t\t\t},\n\t\t\tasync delete(key) {\n\t\t\t\tconst filePath = path.join(cacheDir, md5(key))\n\t\t\t\tawait fsExtra.remove(filePath)\n\t\t\t},\n\t\t}\n\n\t\treturn fsCache\n\t})\n}\n\nexport async function cachified<Value>({\n\trequest,\n\ttimings,\n\tkey,\n\ttimingKey = key.length > 18 ? `${key.slice(0, 7)}...${key.slice(-8)}` : key,\n\t...options\n}: Omit<C.CachifiedOptions<Value>, 'forceFresh'> & {\n\trequest?: Request\n\ttimings?: Timings\n\tforceFresh?: boolean | string\n\ttimingKey?: string\n}): Promise<Value> {\n\tconst forceFresh = await shouldForceFresh({\n\t\tforceFresh: options.forceFresh,\n\t\trequest,\n\t\tkey,\n\t})\n\treturn C.cachified(\n\t\t{\n\t\t\t...options,\n\t\t\tkey,\n\t\t\tforceFresh,\n\t\t},\n\t\tC.mergeReporters(\n\t\t\tcachifiedTimingReporter(timings, timingKey),\n\t\t\tprocess.env.EPICSHOP_DEBUG_CACHE ? verboseReporter() : undefined,\n\t\t),\n\t)\n}\n\nexport async function shouldForceFresh({\n\tforceFresh,\n\trequest,\n\tkey,\n}: {\n\tforceFresh?: boolean | string\n\trequest?: Request\n\tkey?: string\n}) {\n\tif (typeof forceFresh === 'boolean') return forceFresh\n\tif (typeof forceFresh === 'string' && key) {\n\t\treturn forceFresh.split(',').includes(key)\n\t}\n\n\tif (!request) return false\n\tconst fresh = new URL(request.url).searchParams.get('fresh')\n\tif (typeof fresh !== 'string') return false\n\tif (fresh === '') return true\n\tif (!key) return false\n\n\treturn fresh.split(',').includes(key)\n}\n"]}
@@ -3,6 +3,7 @@ import closeWithGrace from 'close-with-grace';
3
3
  declare global {
4
4
  var __change_tracker_watcher__: ReturnType<typeof chokidar.watch> | undefined, __change_tracker_close_with_grace_return__: ReturnType<typeof closeWithGrace>;
5
5
  }
6
- export declare function getWatcher(): chokidar.FSWatcher | null;
7
- export declare function getOptionalWatcher(): chokidar.FSWatcher | undefined;
6
+ export declare function getWatcher(): import("chokidar").FSWatcher | undefined;
7
+ export declare function getOptionalWatcher(): import("chokidar").FSWatcher | undefined;
8
+ export declare function withoutWatcher<ReturnValue>(fn: () => Promise<ReturnValue> | ReturnValue): Promise<ReturnValue>;
8
9
  //# sourceMappingURL=change-tracker.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"change-tracker.server.d.ts","sourceRoot":"","sources":["../../src/change-tracker.server.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,cAAc,MAAM,kBAAkB,CAAA;AAE7C,OAAO,CAAC,MAAM,CAAC;IACd,IAAI,0BAA0B,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,SAAS,EAC5E,0CAA0C,EAAE,UAAU,CACrD,OAAO,cAAc,CACrB,CAAA;CACF;AAID,wBAAgB,UAAU,8BAuBzB;AAED,wBAAgB,kBAAkB,mCAEjC"}
1
+ {"version":3,"file":"change-tracker.server.d.ts","sourceRoot":"","sources":["../../src/change-tracker.server.ts"],"names":[],"mappings":"AACA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,cAAc,MAAM,kBAAkB,CAAA;AAG7C,OAAO,CAAC,MAAM,CAAC;IACd,IAAI,0BAA0B,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,SAAS,EAC5E,0CAA0C,EAAE,UAAU,CACrD,OAAO,cAAc,CACrB,CAAA;CACF;AAqBD,wBAAgB,UAAU,6CAmBzB;AAED,wBAAgB,kBAAkB,6CAEjC;AAMD,wBAAsB,cAAc,CAAC,WAAW,EAC/C,EAAE,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,wBAoC5C"}
@@ -1,25 +1,37 @@
1
+ import path from 'path';
1
2
  import chokidar from 'chokidar';
2
3
  import closeWithGrace from 'close-with-grace';
4
+ import { workshopRoot } from './config.server.js';
3
5
  let watcher = global.__change_tracker_watcher__;
6
+ const dirsToWatch = [
7
+ path.join(workshopRoot, 'playground'),
8
+ path.join(workshopRoot, 'exercises'),
9
+ path.join(workshopRoot, 'examples'),
10
+ ];
11
+ const ignoredDirs = [
12
+ '/.git',
13
+ '/node_modules',
14
+ '/build',
15
+ '/server-build',
16
+ '/public/build',
17
+ '/playwright-report',
18
+ '/dist',
19
+ '/.cache',
20
+ ];
4
21
  export function getWatcher() {
5
22
  if (process.env.EPICSHOP_DEPLOYED ??
6
23
  process.env.EPICSHOP_ENABLE_WATCHER !== 'true') {
7
- return null;
24
+ return undefined;
8
25
  }
9
26
  if (watcher)
10
27
  return watcher;
11
- const workshopRoot = process.env.EPICSHOP_CONTEXT_CWD ?? process.cwd();
12
- watcher = chokidar.watch(workshopRoot, {
28
+ watcher = chokidar.watch(dirsToWatch, {
13
29
  ignoreInitial: true,
14
- ignored: [
15
- '**/.git/**',
16
- '**/node_modules/**',
17
- '**/build/**',
18
- '**/public/build/**',
19
- '**/playwright-report/**',
20
- '**/dist/**',
21
- '**/.cache/**',
22
- ],
30
+ ignored(path, stat) {
31
+ return stat?.isDirectory()
32
+ ? ignoredDirs.some((dir) => path.endsWith(dir))
33
+ : false;
34
+ },
23
35
  });
24
36
  global.__change_tracker_watcher__ = watcher;
25
37
  return watcher;
@@ -27,6 +39,42 @@ export function getWatcher() {
27
39
  export function getOptionalWatcher() {
28
40
  return watcher;
29
41
  }
42
+ // NOTE: I tried going the unwatch/add route and it just didn't work. All changes
43
+ // were still tracked. This listener nonsense was the only way I could come up with
44
+ // to handle changes properly.
45
+ let currentWithoutWatcher = null;
46
+ export async function withoutWatcher(fn) {
47
+ if (!watcher)
48
+ return fn();
49
+ let thisWithoutWatcher = (currentWithoutWatcher = Symbol('withoutWatcher'));
50
+ const eventNames = watcher.eventNames();
51
+ const eventNamesToListenersMap = {};
52
+ for (const eventName of eventNames) {
53
+ if (typeof eventName === 'string') {
54
+ eventNamesToListenersMap[eventName] = watcher.listeners(eventName);
55
+ }
56
+ }
57
+ watcher.removeAllListeners();
58
+ try {
59
+ const result = await fn();
60
+ return result;
61
+ }
62
+ finally {
63
+ if (currentWithoutWatcher === thisWithoutWatcher) {
64
+ // give it a bit to settle,
65
+ // without this the watcher may notice all changes that happened anyway
66
+ await new Promise((r) => setTimeout(r, 100));
67
+ for (const eventName of eventNames) {
68
+ if (typeof eventName === 'string') {
69
+ const listeners = eventNamesToListenersMap[eventName] || [];
70
+ for (const listener of listeners) {
71
+ watcher.on(eventName, listener);
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
30
78
  global.__change_tracker_close_with_grace_return__?.uninstall();
31
79
  global.__change_tracker_close_with_grace_return__ = closeWithGrace(() => watcher?.close());
32
80
  //# sourceMappingURL=change-tracker.server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"change-tracker.server.js","sourceRoot":"","sources":["../../src/change-tracker.server.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,cAAc,MAAM,kBAAkB,CAAA;AAS7C,IAAI,OAAO,GAAG,MAAM,CAAC,0BAA0B,CAAA;AAE/C,MAAM,UAAU,UAAU;IACzB,IACC,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC7B,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,MAAM,EAC7C,CAAC;QACF,OAAO,IAAI,CAAA;IACZ,CAAC;IACD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAA;IAC3B,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IACtE,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE;QACtC,aAAa,EAAE,IAAI;QACnB,OAAO,EAAE;YACR,YAAY;YACZ,oBAAoB;YACpB,aAAa;YACb,oBAAoB;YACpB,yBAAyB;YACzB,YAAY;YACZ,cAAc;SACd;KACD,CAAC,CAAA;IACF,MAAM,CAAC,0BAA0B,GAAG,OAAO,CAAA;IAC3C,OAAO,OAAO,CAAA;AACf,CAAC;AAED,MAAM,UAAU,kBAAkB;IACjC,OAAO,OAAO,CAAA;AACf,CAAC;AAED,MAAM,CAAC,0CAA0C,EAAE,SAAS,EAAE,CAAA;AAC9D,MAAM,CAAC,0CAA0C,GAAG,cAAc,CAAC,GAAG,EAAE,CACvE,OAAO,EAAE,KAAK,EAAE,CAChB,CAAA","sourcesContent":["import chokidar from 'chokidar'\nimport closeWithGrace from 'close-with-grace'\n\ndeclare global {\n\tvar __change_tracker_watcher__: ReturnType<typeof chokidar.watch> | undefined,\n\t\t__change_tracker_close_with_grace_return__: ReturnType<\n\t\t\ttypeof closeWithGrace\n\t\t>\n}\n\nlet watcher = global.__change_tracker_watcher__\n\nexport function getWatcher() {\n\tif (\n\t\tprocess.env.EPICSHOP_DEPLOYED ??\n\t\tprocess.env.EPICSHOP_ENABLE_WATCHER !== 'true'\n\t) {\n\t\treturn null\n\t}\n\tif (watcher) return watcher\n\tconst workshopRoot = process.env.EPICSHOP_CONTEXT_CWD ?? process.cwd()\n\twatcher = chokidar.watch(workshopRoot, {\n\t\tignoreInitial: true,\n\t\tignored: [\n\t\t\t'**/.git/**',\n\t\t\t'**/node_modules/**',\n\t\t\t'**/build/**',\n\t\t\t'**/public/build/**',\n\t\t\t'**/playwright-report/**',\n\t\t\t'**/dist/**',\n\t\t\t'**/.cache/**',\n\t\t],\n\t})\n\tglobal.__change_tracker_watcher__ = watcher\n\treturn watcher\n}\n\nexport function getOptionalWatcher() {\n\treturn watcher\n}\n\nglobal.__change_tracker_close_with_grace_return__?.uninstall()\nglobal.__change_tracker_close_with_grace_return__ = closeWithGrace(() =>\n\twatcher?.close(),\n)\n"]}
1
+ {"version":3,"file":"change-tracker.server.js","sourceRoot":"","sources":["../../src/change-tracker.server.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path'\nimport chokidar from 'chokidar'\nimport closeWithGrace from 'close-with-grace'\nimport { workshopRoot } from './config.server.js'\n\ndeclare global {\n\tvar __change_tracker_watcher__: ReturnType<typeof chokidar.watch> | undefined,\n\t\t__change_tracker_close_with_grace_return__: ReturnType<\n\t\t\ttypeof closeWithGrace\n\t\t>\n}\n\nlet watcher = global.__change_tracker_watcher__\n\nconst dirsToWatch = [\n\tpath.join(workshopRoot, 'playground'),\n\tpath.join(workshopRoot, 'exercises'),\n\tpath.join(workshopRoot, 'examples'),\n]\n\nconst ignoredDirs = [\n\t'/.git',\n\t'/node_modules',\n\t'/build',\n\t'/server-build',\n\t'/public/build',\n\t'/playwright-report',\n\t'/dist',\n\t'/.cache',\n]\n\nexport function getWatcher() {\n\tif (\n\t\tprocess.env.EPICSHOP_DEPLOYED ??\n\t\tprocess.env.EPICSHOP_ENABLE_WATCHER !== 'true'\n\t) {\n\t\treturn undefined\n\t}\n\tif (watcher) return watcher\n\twatcher = chokidar.watch(dirsToWatch, {\n\t\tignoreInitial: true,\n\t\tignored(path, stat) {\n\t\t\treturn stat?.isDirectory()\n\t\t\t\t? ignoredDirs.some((dir) => path.endsWith(dir))\n\t\t\t\t: false\n\t\t},\n\t})\n\n\tglobal.__change_tracker_watcher__ = watcher\n\treturn watcher\n}\n\nexport function getOptionalWatcher() {\n\treturn watcher\n}\n\n// NOTE: I tried going the unwatch/add route and it just didn't work. All changes\n// were still tracked. This listener nonsense was the only way I could come up with\n// to handle changes properly.\nlet currentWithoutWatcher = null\nexport async function withoutWatcher<ReturnValue>(\n\tfn: () => Promise<ReturnValue> | ReturnValue,\n) {\n\tif (!watcher) return fn()\n\n\tlet thisWithoutWatcher = (currentWithoutWatcher = Symbol('withoutWatcher'))\n\tconst eventNames = watcher.eventNames()\n\tconst eventNamesToListenersMap: Record<\n\t\tstring,\n\t\tReturnType<typeof watcher.listeners>\n\t> = {}\n\tfor (const eventName of eventNames) {\n\t\tif (typeof eventName === 'string') {\n\t\t\teventNamesToListenersMap[eventName] = watcher.listeners(eventName)\n\t\t}\n\t}\n\twatcher.removeAllListeners()\n\n\ttry {\n\t\tconst result = await fn()\n\t\treturn result\n\t} finally {\n\t\tif (currentWithoutWatcher === thisWithoutWatcher) {\n\t\t\t// give it a bit to settle,\n\t\t\t// without this the watcher may notice all changes that happened anyway\n\t\t\tawait new Promise((r) => setTimeout(r, 100))\n\n\t\t\tfor (const eventName of eventNames) {\n\t\t\t\tif (typeof eventName === 'string') {\n\t\t\t\t\tconst listeners = eventNamesToListenersMap[eventName] || []\n\t\t\t\t\tfor (const listener of listeners) {\n\t\t\t\t\t\twatcher.on(eventName, listener as any)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nglobal.__change_tracker_close_with_grace_return__?.uninstall()\nglobal.__change_tracker_close_with_grace_return__ = closeWithGrace(() =>\n\twatcher?.close(),\n)\n"]}
@@ -1,11 +1,12 @@
1
- export declare function compileMdx(file: string, { request, forceFresh }?: {
1
+ import { type Timings } from './timing.server.js';
2
+ export declare function compileMdx(file: string, { request, timings, forceFresh, }?: {
2
3
  request?: Request;
4
+ timings?: Timings;
3
5
  forceFresh?: boolean;
4
6
  }): Promise<{
5
7
  code: string;
6
8
  title: string | null;
7
- epicVideoEmbeds: Array<string>;
9
+ epicVideoEmbeds: string[];
8
10
  }>;
9
11
  export declare function compileMarkdownString(markdownString: string): Promise<string>;
10
- export declare function isEmbeddedFile(filePath: string): Promise<boolean>;
11
12
  //# sourceMappingURL=compile-mdx.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compile-mdx.server.d.ts","sourceRoot":"","sources":["../../src/compile-mdx.server.ts"],"names":[],"mappings":"AAkHA,wBAAsB,UAAU,CAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,OAAO,EAAE,UAAU,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GACvE,OAAO,CAAC;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAC9B,CAAC,CA6HD;AAED,wBAAsB,qBAAqB,CAAC,cAAc,EAAE,MAAM,mBA8BjE;AAmFD,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,oBAQpD"}
1
+ {"version":3,"file":"compile-mdx.server.d.ts","sourceRoot":"","sources":["../../src/compile-mdx.server.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAsDjD,wBAAsB,UAAU,CAC/B,IAAI,EAAE,MAAM,EACZ,EACC,OAAO,EACP,OAAO,EACP,UAAU,GACV,GAAE;IACF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,UAAU,CAAC,EAAE,OAAO,CAAA;CACf;;;;GAyBN;AAuED,wBAAsB,qBAAqB,CAAC,cAAc,EAAE,MAAM,mBA8BjE"}
@@ -1,19 +1,13 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { cachified } from '@epic-web/cachified';
4
- import { remember } from '@epic-web/remember';
5
3
  import { remarkCodeBlocksShiki } from '@kentcdodds/md-temp';
6
- import fsExtra from 'fs-extra';
7
- import md5 from 'md5-hex';
8
4
  import { bundleMDX } from 'mdx-bundler';
9
5
  import PQueue from 'p-queue';
10
6
  import remarkAutolinkHeadings from 'remark-autolink-headings';
11
7
  import emoji from 'remark-emoji';
12
8
  import gfm from 'remark-gfm';
13
9
  import { visit } from 'unist-util-visit';
14
- import { compiledMarkdownCache, embeddedFilesCache, shouldForceFresh, } from './cache.server.js';
15
- import { remarkCodeFile, } from './codefile-mdx.server.js';
16
- const cacheDir = path.join(process.env.EPICSHOP_CONTEXT_CWD ?? process.cwd(), './node_modules/.cache/compile-mdx');
10
+ import { cachified, compiledInstructionMarkdownCache, compiledMarkdownCache, shouldForceFresh, } from './cache.server.js';
17
11
  function trimCodeBlocks() {
18
12
  return async function transformer(tree) {
19
13
  visit(tree, 'element', (preNode) => {
@@ -55,63 +49,32 @@ const rehypePlugins = [
55
49
  remarkCodeBlocksShiki,
56
50
  removePreContainerDivs,
57
51
  ];
58
- function checkFileExists(file) {
59
- return fs.promises.access(file, fs.constants.F_OK).then(() => true, () => false);
60
- }
61
52
  const verboseLog = process.env.EPICSHOP_VERBOSE_LOG === 'true' ? console.log : () => { };
62
- /**
63
- * @param embeddedFiles {string[]} - list of embedded files
64
- * @param lastCompiledTime {number} - timestamp indicating the last time mdx file was compiled
65
- * @returns true if all embedded file mtimeMs are older then the file compiled time,
66
- * false if we need update
67
- */
68
- function validateEmbeddedFiles(embeddedFiles, lastCompiledTime) {
69
- if (process.env.NODE_ENV !== 'development')
70
- return Promise.resolve(true);
71
- return Promise.all(Array.from(embeddedFiles).map(async ({ file }) => {
72
- const stat = await fs.promises.stat(file).catch(() => ({ mtimeMs: 0 }));
73
- return lastCompiledTime > stat.mtimeMs || Promise.reject();
74
- })).then(() => true, () => false);
75
- }
76
- export async function compileMdx(file, { request, forceFresh } = {}) {
77
- if (!(await checkFileExists(file))) {
78
- throw new Error(`File does not exist: ${file}`);
53
+ export async function compileMdx(file, { request, timings, forceFresh, } = {}) {
54
+ const stat = await fs.promises
55
+ .stat(file)
56
+ .catch((error) => ({ error }));
57
+ if ('error' in stat) {
58
+ throw new Error(`File stat cannot be read: ${stat.error}`);
79
59
  }
80
- let cachedEmbeddedFiles = new Map();
81
- const stat = await fs.promises.stat(file);
82
- const cacheLocation = path.join(cacheDir, `${md5(file)}.json`);
83
- const requireFresh = await shouldForceFresh({
84
- forceFresh,
60
+ const key = `file:${file}`;
61
+ forceFresh = await shouldForceFresh({ forceFresh, request, key });
62
+ const existingCacheEntry = await compiledInstructionMarkdownCache.get(key);
63
+ if (!forceFresh && existingCacheEntry) {
64
+ forceFresh = stat.mtimeMs > existingCacheEntry.metadata.createdTime;
65
+ }
66
+ return cachified({
67
+ key,
68
+ cache: compiledInstructionMarkdownCache,
85
69
  request,
86
- key: cacheLocation,
70
+ timings,
71
+ forceFresh,
72
+ getFreshValue: () => compileMdxImpl(file),
87
73
  });
88
- if (!requireFresh && (await checkFileExists(cacheLocation))) {
89
- try {
90
- const cached = JSON.parse(await fs.promises.readFile(cacheLocation, 'utf-8'));
91
- cachedEmbeddedFiles = new Map(Object.entries(cached.value.embeddedFiles ?? {}));
92
- const compiledTime = cached.value.compiledTime ?? 0;
93
- const warningCancled = process.env.NODE_ENV === 'development'
94
- ? cached?.value?.warningCancled ?? false
95
- : false;
96
- if (compiledTime > stat.mtimeMs &&
97
- !warningCancled &&
98
- (await validateEmbeddedFiles(cachedEmbeddedFiles.values(), compiledTime))) {
99
- return cached.value;
100
- }
101
- }
102
- catch (error) {
103
- console.error(`Error reading cached file: ${cacheLocation}`, error);
104
- void fs.promises.unlink(cacheLocation);
105
- }
106
- }
74
+ }
75
+ async function compileMdxImpl(file) {
107
76
  let title = null;
108
77
  const epicVideoEmbeds = [];
109
- const codeFileData = {
110
- mdxFile: file,
111
- cacheLocation,
112
- cachedEmbeddedFiles,
113
- embeddedFiles: new Map(),
114
- };
115
78
  try {
116
79
  verboseLog(`Compiling ${file}`);
117
80
  const bundleResult = await queuedBundleMDX({
@@ -136,9 +99,13 @@ export async function compileMdx(file, { request, forceFresh } = {}) {
136
99
  },
137
100
  () => (tree) => {
138
101
  visit(tree, 'mdxJsxFlowElement', (jsxEl) => {
102
+ // @ts-expect-error no idea why this started being an issue suddenly 🤷‍♂️
139
103
  if (jsxEl.name !== 'EpicVideo')
140
104
  return;
141
- const urlAttr = jsxEl.attributes.find((a) => a.type === 'mdxJsxAttribute' && a.name === 'url');
105
+ // @ts-expect-error no idea why this started being an issue suddenly 🤷‍♂️
106
+ const urlAttr = jsxEl.attributes.find(
107
+ // @ts-expect-error no idea why this started being an issue suddenly 🤷‍♂️
108
+ (a) => a.type === 'mdxJsxAttribute' && a.name === 'url');
142
109
  if (!urlAttr)
143
110
  return;
144
111
  let url = urlAttr.value;
@@ -149,7 +116,6 @@ export async function compileMdx(file, { request, forceFresh } = {}) {
149
116
  epicVideoEmbeds.push(url);
150
117
  });
151
118
  },
152
- () => remarkCodeFile(codeFileData),
153
119
  emoji,
154
120
  ];
155
121
  options.rehypePlugins = [
@@ -165,17 +131,6 @@ export async function compileMdx(file, { request, forceFresh } = {}) {
165
131
  if (!bundleResult)
166
132
  throw new Error(`Timeout for file: ${file}`);
167
133
  const result = { code: bundleResult.code, title, epicVideoEmbeds };
168
- await fsExtra.ensureDir(cacheDir);
169
- await fs.promises.writeFile(cacheLocation, JSON.stringify({
170
- value: {
171
- ...result,
172
- compiledTime: Date.now(),
173
- embeddedFiles: codeFileData.embeddedFiles.size
174
- ? Object.fromEntries(codeFileData.embeddedFiles)
175
- : undefined,
176
- },
177
- }));
178
- await updateEmbeddedFilesCache(codeFileData);
179
134
  return result;
180
135
  }
181
136
  catch (error) {
@@ -219,79 +174,6 @@ export async function compileMarkdownString(markdownString) {
219
174
  },
220
175
  });
221
176
  }
222
- const modifiedEmbeddedFilesTime = remember('modified_embedded_files_time', () => new Map());
223
- const EMBEDDED_FILES_CACHE_KEY = 'embeddedFilesCache';
224
- async function updateEmbeddedFilesCache({ mdxFile, embeddedFiles, }) {
225
- if (mdxFile.includes('playground'))
226
- return;
227
- let cachedList = await getEmbeddedFilesCache();
228
- const hash = cachedList ? md5(JSON.stringify(cachedList)) : null;
229
- // make sure we get clean list before updating it
230
- if (cachedList) {
231
- for (const [key, value] of Object.entries(cachedList)) {
232
- cachedList[key] = value.filter((item) => item !== mdxFile);
233
- if (cachedList[key]?.length === 0) {
234
- delete cachedList[key];
235
- }
236
- }
237
- }
238
- if (embeddedFiles.size) {
239
- if (!cachedList) {
240
- cachedList = {};
241
- }
242
- const files = Array.from(new Set(Array.from(embeddedFiles.values()).map(({ file }) => file))).sort();
243
- for (const file of files) {
244
- cachedList[file] = [...(cachedList[file] ?? []), mdxFile];
245
- }
246
- }
247
- if (cachedList && hash !== md5(JSON.stringify(cachedList))) {
248
- await fsExtra.ensureDir(cacheDir);
249
- const embeddedFilesLocation = path.join(cacheDir, 'embeddedFiles.json');
250
- modifiedEmbeddedFilesTime.set(EMBEDDED_FILES_CACHE_KEY, Date.now());
251
- await fs.promises.writeFile(embeddedFilesLocation, JSON.stringify({ ...cachedList }));
252
- }
253
- }
254
- async function getEmbeddedFilesCache() {
255
- const key = EMBEDDED_FILES_CACHE_KEY;
256
- function getForceFresh(cacheEntry) {
257
- if (!cacheEntry)
258
- return true;
259
- const latestModifiedTime = modifiedEmbeddedFilesTime.get(key);
260
- if (!latestModifiedTime)
261
- return undefined;
262
- return latestModifiedTime > cacheEntry.metadata.createdTime
263
- ? true
264
- : undefined;
265
- }
266
- return cachified({
267
- key,
268
- cache: embeddedFilesCache,
269
- ttl: 1000 * 60 * 60 * 24,
270
- forceFresh: getForceFresh(embeddedFilesCache.get(key)),
271
- getFreshValue: async () => {
272
- try {
273
- const embeddedFilesLocation = path.join(cacheDir, 'embeddedFiles.json');
274
- if (await checkFileExists(embeddedFilesLocation)) {
275
- return JSON.parse(await fs.promises.readFile(embeddedFilesLocation, 'utf-8'));
276
- }
277
- }
278
- catch {
279
- console.error(`Unable to read 'embeddedFiles.json' from: `, cacheDir);
280
- }
281
- return undefined;
282
- },
283
- });
284
- }
285
- export async function isEmbeddedFile(filePath) {
286
- if (process.env.NODE_ENV !== 'development')
287
- return false;
288
- const embeddedFilesList = await getEmbeddedFilesCache();
289
- if (embeddedFilesList) {
290
- const embeddedFiles = Object.keys(embeddedFilesList);
291
- return embeddedFiles.includes(filePath.replace(/\\/g, '/'));
292
- }
293
- return false;
294
- }
295
177
  let _queue = null;
296
178
  async function getQueue() {
297
179
  if (_queue)
@@ -1 +1 @@
1
- {"version":3,"file":"compile-mdx.server.js","sourceRoot":"","sources":["../../src/compile-mdx.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,SAAS,EAAmB,MAAM,qBAAqB,CAAA;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,OAAO,MAAM,UAAU,CAAA;AAE9B,OAAO,GAAG,MAAM,SAAS,CAAA;AAEzB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,MAAM,MAAM,SAAS,CAAA;AAC5B,OAAO,sBAAsB,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,MAAM,cAAc,CAAA;AAChC,OAAO,GAAG,MAAM,YAAY,CAAA;AAE5B,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EACN,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,GAEhB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACN,cAAc,GAGd,MAAM,0BAA0B,CAAA;AAEjC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CACzB,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,CAAC,GAAG,EAAE,EACjD,mCAAmC,CACnC,CAAA;AAED,SAAS,cAAc;IACtB,OAAO,KAAK,UAAU,WAAW,CAAC,IAAc;QAC/C,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,OAAgB,EAAE,EAAE;YAC3C,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAC3D,OAAM;YACP,CAAC;YACD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YACpC,IACC,CAAC,QAAQ;gBACT,QAAQ,CAAC,IAAI,KAAK,SAAS;gBAC3B,QAAQ,CAAC,OAAO,KAAK,MAAM,EAC1B,CAAC;gBACF,OAAM;YACP,CAAC;YACD,MAAM,CAAC,cAAc,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAA;YAC1C,IAAI,CAAC,cAAc;gBAAE,OAAM;YAE3B,IAAI,cAAc,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACpC,OAAO,CAAC,IAAI,CACX,kEAAkE,cAAc,CAAC,IAAI,EAAE,CACvF,CAAA;gBACD,OAAM;YACP,CAAC;YACD,cAAc,CAAC,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,CAAA;QACtD,CAAC,CAAC,CAAA;IACH,CAAC,CAAA;AACF,CAAC;AAED,SAAS,sBAAsB;IAC9B,OAAO,KAAK,UAAU,2BAA2B,CAAC,IAAc;QAC/D,KAAK,CACJ,IAAI,EACJ,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,EACnC,SAAS,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM;YACnC,IAAI,MAAM,EAAE,IAAI,KAAK,SAAS;gBAAE,OAAM;YACtC,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK;gBAAE,OAAM;YACpC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAM;YACvD,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAC5B,CAAC,CACD,CAAA;IACF,CAAC,CAAA;AACF,CAAC;AAED,MAAM,aAAa,GAAG;IACrB,cAAc;IACd,qBAAqB;IACrB,sBAAsB;CACE,CAAA;AAEzB,SAAS,eAAe,CAAC,IAAY;IACpC,OAAO,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CACtD,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,EAAE,CAAC,KAAK,CACX,CAAA;AACF,CAAC;AAED,MAAM,UAAU,GACf,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAE,CAAC,CAAA;AAErE;;;;;GAKG;AACH,SAAS,qBAAqB,CAC7B,aAA6C,EAC7C,gBAAwB;IAExB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACxE,OAAO,OAAO,CAAC,GAAG,CACjB,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QAChD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QACvE,OAAO,gBAAgB,GAAG,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAA;IAC3D,CAAC,CAAC,CACF,CAAC,IAAI,CACL,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,EAAE,CAAC,KAAK,CACX,CAAA;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC/B,IAAY,EACZ,EAAE,OAAO,EAAE,UAAU,KAAkD,EAAE;IAMzE,IAAI,CAAC,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAA;IAChD,CAAC;IAED,IAAI,mBAAmB,GAAG,IAAI,GAAG,EAAwB,CAAA;IAEzD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAE9D,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC;QAC3C,UAAU;QACV,OAAO;QACP,GAAG,EAAE,aAAa;KAClB,CAAC,CAAA;IACF,IAAI,CAAC,YAAY,IAAI,CAAC,MAAM,eAAe,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;QAC7D,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CACxB,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAC3C,CAAA;YAER,mBAAmB,GAAG,IAAI,GAAG,CAC5B,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,CAAC,CAChD,CAAA;YAED,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,CAAA;YACnD,MAAM,cAAc,GACnB,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa;gBACrC,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,cAAc,IAAI,KAAK;gBACxC,CAAC,CAAC,KAAK,CAAA;YACT,IACC,YAAY,GAAG,IAAI,CAAC,OAAO;gBAC3B,CAAC,cAAc;gBACf,CAAC,MAAM,qBAAqB,CAC3B,mBAAmB,CAAC,MAAM,EAAE,EAC5B,YAAY,CACZ,CAAC,EACD,CAAC;gBACF,OAAO,MAAM,CAAC,KAAK,CAAA;YACpB,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,8BAA8B,aAAa,EAAE,EAAE,KAAK,CAAC,CAAA;YACnE,KAAK,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;QACvC,CAAC;IACF,CAAC;IACD,IAAI,KAAK,GAAkB,IAAI,CAAA;IAC/B,MAAM,eAAe,GAAkB,EAAE,CAAA;IACzC,MAAM,YAAY,GAAG;QACpB,OAAO,EAAE,IAAI;QACb,aAAa;QACb,mBAAmB;QACnB,aAAa,EAAE,IAAI,GAAG,EAAwB;KAC9C,CAAA;IAED,IAAI,CAAC;QACJ,UAAU,CAAC,aAAa,IAAI,EAAE,CAAC,CAAA;QAC/B,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC;YAC1C,IAAI;YACJ,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YACvB,UAAU,CAAC,OAAO;gBACjB,OAAO,CAAC,aAAa,GAAG;oBACvB,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC;oBAChC,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;oBAC9C,GAAG;oBACH,GAAG,EAAE,CAAC,CAAC,IAAe,EAAE,EAAE;wBACzB,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;4BAC/B,IAAI,KAAK;gCAAE,OAAM;4BACjB,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;gCACtB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE;oCAChC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;gCAC9B,CAAC,CAAC,CAAA;4BACH,CAAC;wBACF,CAAC,CAAC,CAAA;wBACF,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;oBAC3D,CAAC;oBACD,GAAG,EAAE,CAAC,CAAC,IAAe,EAAE,EAAE;wBACzB,KAAK,CAAC,IAAI,EAAE,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE;4BAC1C,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;gCAAE,OAAM;4BACtC,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,iBAAiB,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK,CACvD,CAAA;4BACD,IAAI,CAAC,OAAO;gCAAE,OAAM;4BACpB,IAAI,GAAG,GAAG,OAAO,CAAC,KAAK,CAAA;4BACvB,IAAI,OAAO,GAAG,KAAK,QAAQ;gCAAE,OAAM;4BACnC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;gCAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;4BAC7C,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;wBAC1B,CAAC,CAAC,CAAA;oBACH,CAAC;oBACD,GAAG,EAAE,CAAC,cAAc,CAAC,YAAY,CAAC;oBAClC,KAAK;iBACL,CAAA;gBACD,OAAO,CAAC,aAAa,GAAG;oBACvB,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC;oBAChC,GAAG,aAAa;iBAChB,CAAA;gBACD,OAAO,CAAC,aAAa,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;gBACvC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAA;gBACtB,OAAO,CAAC,WAAW,GAAG,KAAK,CAAA;gBAC3B,OAAO,OAAO,CAAA;YACf,CAAC;SACD,CAAC,CAAA;QACF,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAA;QAE/D,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE,CAAA;QAClE,MAAM,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;QACjC,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAC1B,aAAa,EACb,IAAI,CAAC,SAAS,CAAC;YACd,KAAK,EAAE;gBACN,GAAG,MAAM;gBACT,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE;gBACxB,aAAa,EAAE,YAAY,CAAC,aAAa,CAAC,IAAI;oBAC7C,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,aAAa,CAAC;oBAChD,CAAC,CAAC,SAAS;aACZ;SACD,CAAC,CACF,CAAA;QACD,MAAM,wBAAwB,CAAC,YAAY,CAAC,CAAA;QAC5C,OAAO,MAAM,CAAA;IACd,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;QAC1D,MAAM,KAAK,CAAA;IACZ,CAAC;YAAS,CAAC;QACV,UAAU,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAA;IAC5C,CAAC;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,cAAsB;IACjE,OAAO,SAAS,CAAC;QAChB,GAAG,EAAE,cAAc;QACnB,KAAK,EAAE,qBAAqB;QAC5B,GAAG,EAAE,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QACxB,aAAa,EAAE,KAAK,IAAI,EAAE;YACzB,IAAI,CAAC;gBACJ,UAAU,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAA;gBAC9C,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;oBACpC,MAAM,EAAE,cAAc;oBACtB,UAAU,CAAC,OAAO;wBACjB,OAAO,CAAC,aAAa,GAAG;4BACvB,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC;4BAChC,GAAG,aAAa;yBAChB,CAAA;wBACD,OAAO,CAAC,WAAW,GAAG,KAAK,CAAA;wBAC3B,OAAO,OAAO,CAAA;oBACf,CAAC;iBACD,CAAC,CAAA;gBACF,IAAI,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;gBAEnE,OAAO,MAAM,CAAC,IAAI,CAAA;YACnB,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACzB,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,cAAc,EAAE,KAAK,CAAC,CAAA;gBACpE,MAAM,KAAK,CAAA;YACZ,CAAC;oBAAS,CAAC;gBACV,UAAU,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAA;YAC3D,CAAC;QACF,CAAC;KACD,CAAC,CAAA;AACH,CAAC;AAED,MAAM,yBAAyB,GAAG,QAAQ,CACzC,8BAA8B,EAC9B,GAAG,EAAE,CAAC,IAAI,GAAG,EAAkB,CAC/B,CAAA;AAED,MAAM,wBAAwB,GAAG,oBAAoB,CAAA;AAErD,KAAK,UAAU,wBAAwB,CAAC,EACvC,OAAO,EACP,aAAa,GACC;IACd,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAM;IAC1C,IAAI,UAAU,GAAG,MAAM,qBAAqB,EAAE,CAAA;IAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAEhE,iDAAiD;IACjD,IAAI,UAAU,EAAE,CAAC;QAChB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YACvD,UAAU,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,CAAA;YAC1D,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;gBACnC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAA;YACvB,CAAC;QACF,CAAC;IACF,CAAC;IAED,IAAI,aAAa,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC,UAAU,EAAE,CAAC;YACjB,UAAU,GAAG,EAAE,CAAA;QAChB,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CACvB,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CACnE,CAAC,IAAI,EAAE,CAAA;QACR,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA;QAC1D,CAAC;IACF,CAAC;IAED,IAAI,UAAU,IAAI,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;QAC5D,MAAM,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;QACjC,MAAM,qBAAqB,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAA;QACvE,yBAAyB,CAAC,GAAG,CAAC,wBAAwB,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;QACnE,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAC1B,qBAAqB,EACrB,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,UAAU,EAAE,CAAC,CACjC,CAAA;IACF,CAAC;AACF,CAAC;AAED,KAAK,UAAU,qBAAqB;IACnC,MAAM,GAAG,GAAG,wBAAwB,CAAA;IAEpC,SAAS,aAAa,CAAC,UAAyC;QAC/D,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAA;QAC5B,MAAM,kBAAkB,GAAG,yBAAyB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC7D,IAAI,CAAC,kBAAkB;YAAE,OAAO,SAAS,CAAA;QACzC,OAAO,kBAAkB,GAAG,UAAU,CAAC,QAAQ,CAAC,WAAW;YAC1D,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,SAAS,CAAA;IACb,CAAC;IAED,OAAO,SAAS,CAAC;QAChB,GAAG;QACH,KAAK,EAAE,kBAAkB;QACzB,GAAG,EAAE,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QACxB,UAAU,EAAE,aAAa,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtD,aAAa,EAAE,KAAK,IAAI,EAAE;YACzB,IAAI,CAAC;gBACJ,MAAM,qBAAqB,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAA;gBACvE,IAAI,MAAM,eAAe,CAAC,qBAAqB,CAAC,EAAE,CAAC;oBAClD,OAAO,IAAI,CAAC,KAAK,CAChB,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAC/B,CAAA;gBAC7B,CAAC;YACF,CAAC;YAAC,MAAM,CAAC;gBACR,OAAO,CAAC,KAAK,CAAC,4CAA4C,EAAE,QAAQ,CAAC,CAAA;YACtE,CAAC;YACD,OAAO,SAAS,CAAA;QACjB,CAAC;KACD,CAAC,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB;IACpD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa;QAAE,OAAO,KAAK,CAAA;IACxD,MAAM,iBAAiB,GAAG,MAAM,qBAAqB,EAAE,CAAA;IACvD,IAAI,iBAAiB,EAAE,CAAC;QACvB,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;QACpD,OAAO,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAA;IAC5D,CAAC;IACD,OAAO,KAAK,CAAA;AACb,CAAC;AAED,IAAI,MAAM,GAAkB,IAAI,CAAA;AAChC,KAAK,UAAU,QAAQ;IACtB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAA;IAEzB,MAAM,GAAG,IAAI,MAAM,CAAC;QACnB,WAAW,EAAE,CAAC;QACd,cAAc,EAAE,IAAI;QACpB,OAAO,EAAE,IAAI,GAAG,EAAE;KAClB,CAAC,CAAA;IACF,OAAO,MAAM,CAAA;AACd,CAAC;AAED,+EAA+E;AAC/E,8EAA8E;AAC9E,KAAK,UAAU,eAAe,CAAC,GAAG,IAAkC;IACnE,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAA;IAC9B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;IACxD,OAAO,MAAM,CAAA;AACd,CAAC;AAED,kBAAkB;AAClB;;;;;;EAME","sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { cachified, type CacheEntry } from '@epic-web/cachified'\nimport { remember } from '@epic-web/remember'\nimport { remarkCodeBlocksShiki } from '@kentcdodds/md-temp'\nimport fsExtra from 'fs-extra'\nimport { type Element, type Root as HastRoot } from 'hast'\nimport md5 from 'md5-hex'\nimport { type Root as MdastRoot } from 'mdast'\nimport { bundleMDX } from 'mdx-bundler'\nimport PQueue from 'p-queue'\nimport remarkAutolinkHeadings from 'remark-autolink-headings'\nimport emoji from 'remark-emoji'\nimport gfm from 'remark-gfm'\nimport { type PluggableList } from 'unified'\nimport { visit } from 'unist-util-visit'\nimport {\n\tcompiledMarkdownCache,\n\tembeddedFilesCache,\n\tshouldForceFresh,\n\ttype CachedEmbeddedFilesList,\n} from './cache.server.js'\nimport {\n\tremarkCodeFile,\n\ttype CodeFileData,\n\ttype EmbeddedFile,\n} from './codefile-mdx.server.js'\n\nconst cacheDir = path.join(\n\tprocess.env.EPICSHOP_CONTEXT_CWD ?? process.cwd(),\n\t'./node_modules/.cache/compile-mdx',\n)\n\nfunction trimCodeBlocks() {\n\treturn async function transformer(tree: HastRoot) {\n\t\tvisit(tree, 'element', (preNode: Element) => {\n\t\t\tif (preNode.tagName !== 'pre' || !preNode.children.length) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst codeNode = preNode.children[0]\n\t\t\tif (\n\t\t\t\t!codeNode ||\n\t\t\t\tcodeNode.type !== 'element' ||\n\t\t\t\tcodeNode.tagName !== 'code'\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [codeStringNode] = codeNode.children\n\t\t\tif (!codeStringNode) return\n\n\t\t\tif (codeStringNode.type !== 'text') {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`trimCodeBlocks: Unexpected: codeStringNode type is not \"text\": ${codeStringNode.type}`,\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcodeStringNode.value = codeStringNode.value.trimEnd()\n\t\t})\n\t}\n}\n\nfunction removePreContainerDivs() {\n\treturn async function preContainerDivsTransformer(tree: HastRoot) {\n\t\tvisit(\n\t\t\ttree,\n\t\t\t{ type: 'element', tagName: 'pre' },\n\t\t\tfunction visitor(node, index, parent) {\n\t\t\t\tif (parent?.type !== 'element') return\n\t\t\t\tif (parent.tagName !== 'div') return\n\t\t\t\tif (parent.children.length !== 1 && index === 0) return\n\t\t\t\tObject.assign(parent, node)\n\t\t\t},\n\t\t)\n\t}\n}\n\nconst rehypePlugins = [\n\ttrimCodeBlocks,\n\tremarkCodeBlocksShiki,\n\tremovePreContainerDivs,\n] satisfies PluggableList\n\nfunction checkFileExists(file: string) {\n\treturn fs.promises.access(file, fs.constants.F_OK).then(\n\t\t() => true,\n\t\t() => false,\n\t)\n}\n\nconst verboseLog =\n\tprocess.env.EPICSHOP_VERBOSE_LOG === 'true' ? console.log : () => {}\n\n/**\n * @param embeddedFiles {string[]} - list of embedded files\n * @param lastCompiledTime {number} - timestamp indicating the last time mdx file was compiled\n * @returns true if all embedded file mtimeMs are older then the file compiled time,\n * false if we need update\n */\nfunction validateEmbeddedFiles(\n\tembeddedFiles: IterableIterator<EmbeddedFile>,\n\tlastCompiledTime: number,\n): Promise<boolean> {\n\tif (process.env.NODE_ENV !== 'development') return Promise.resolve(true)\n\treturn Promise.all(\n\t\tArray.from(embeddedFiles).map(async ({ file }) => {\n\t\t\tconst stat = await fs.promises.stat(file).catch(() => ({ mtimeMs: 0 }))\n\t\t\treturn lastCompiledTime > stat.mtimeMs || Promise.reject()\n\t\t}),\n\t).then(\n\t\t() => true,\n\t\t() => false,\n\t)\n}\n\nexport async function compileMdx(\n\tfile: string,\n\t{ request, forceFresh }: { request?: Request; forceFresh?: boolean } = {},\n): Promise<{\n\tcode: string\n\ttitle: string | null\n\tepicVideoEmbeds: Array<string>\n}> {\n\tif (!(await checkFileExists(file))) {\n\t\tthrow new Error(`File does not exist: ${file}`)\n\t}\n\n\tlet cachedEmbeddedFiles = new Map<string, EmbeddedFile>()\n\n\tconst stat = await fs.promises.stat(file)\n\tconst cacheLocation = path.join(cacheDir, `${md5(file)}.json`)\n\n\tconst requireFresh = await shouldForceFresh({\n\t\tforceFresh,\n\t\trequest,\n\t\tkey: cacheLocation,\n\t})\n\tif (!requireFresh && (await checkFileExists(cacheLocation))) {\n\t\ttry {\n\t\t\tconst cached = JSON.parse(\n\t\t\t\tawait fs.promises.readFile(cacheLocation, 'utf-8'),\n\t\t\t) as any\n\n\t\t\tcachedEmbeddedFiles = new Map(\n\t\t\t\tObject.entries(cached.value.embeddedFiles ?? {}),\n\t\t\t)\n\n\t\t\tconst compiledTime = cached.value.compiledTime ?? 0\n\t\t\tconst warningCancled =\n\t\t\t\tprocess.env.NODE_ENV === 'development'\n\t\t\t\t\t? cached?.value?.warningCancled ?? false\n\t\t\t\t\t: false\n\t\t\tif (\n\t\t\t\tcompiledTime > stat.mtimeMs &&\n\t\t\t\t!warningCancled &&\n\t\t\t\t(await validateEmbeddedFiles(\n\t\t\t\t\tcachedEmbeddedFiles.values(),\n\t\t\t\t\tcompiledTime,\n\t\t\t\t))\n\t\t\t) {\n\t\t\t\treturn cached.value\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error reading cached file: ${cacheLocation}`, error)\n\t\t\tvoid fs.promises.unlink(cacheLocation)\n\t\t}\n\t}\n\tlet title: string | null = null\n\tconst epicVideoEmbeds: Array<string> = []\n\tconst codeFileData = {\n\t\tmdxFile: file,\n\t\tcacheLocation,\n\t\tcachedEmbeddedFiles,\n\t\tembeddedFiles: new Map<string, EmbeddedFile>(),\n\t}\n\n\ttry {\n\t\tverboseLog(`Compiling ${file}`)\n\t\tconst bundleResult = await queuedBundleMDX({\n\t\t\tfile,\n\t\t\tcwd: path.dirname(file),\n\t\t\tmdxOptions(options) {\n\t\t\t\toptions.remarkPlugins = [\n\t\t\t\t\t...(options.remarkPlugins ?? []),\n\t\t\t\t\t[remarkAutolinkHeadings, { behavior: 'wrap' }],\n\t\t\t\t\tgfm,\n\t\t\t\t\t() => (tree: MdastRoot) => {\n\t\t\t\t\t\tvisit(tree, 'heading', (node) => {\n\t\t\t\t\t\t\tif (title) return\n\t\t\t\t\t\t\tif (node.depth === 1) {\n\t\t\t\t\t\t\t\tvisit(node, 'text', (textNode) => {\n\t\t\t\t\t\t\t\t\ttitle = textNode.value.trim()\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\ttitle = title ? title.replace(/^\\d+\\. /, '').trim() : null\n\t\t\t\t\t},\n\t\t\t\t\t() => (tree: MdastRoot) => {\n\t\t\t\t\t\tvisit(tree, 'mdxJsxFlowElement', (jsxEl) => {\n\t\t\t\t\t\t\tif (jsxEl.name !== 'EpicVideo') return\n\t\t\t\t\t\t\tconst urlAttr = jsxEl.attributes.find(\n\t\t\t\t\t\t\t\t(a) => a.type === 'mdxJsxAttribute' && a.name === 'url',\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tif (!urlAttr) return\n\t\t\t\t\t\t\tlet url = urlAttr.value\n\t\t\t\t\t\t\tif (typeof url !== 'string') return\n\t\t\t\t\t\t\tif (url.endsWith('/')) url = url.slice(0, -1)\n\t\t\t\t\t\t\tepicVideoEmbeds.push(url)\n\t\t\t\t\t\t})\n\t\t\t\t\t},\n\t\t\t\t\t() => remarkCodeFile(codeFileData),\n\t\t\t\t\temoji,\n\t\t\t\t]\n\t\t\t\toptions.rehypePlugins = [\n\t\t\t\t\t...(options.rehypePlugins ?? []),\n\t\t\t\t\t...rehypePlugins,\n\t\t\t\t]\n\t\t\t\toptions.mdxExtensions = ['.mdx', '.md']\n\t\t\t\toptions.format = 'mdx'\n\t\t\t\toptions.development = false\n\t\t\t\treturn options\n\t\t\t},\n\t\t})\n\t\tif (!bundleResult) throw new Error(`Timeout for file: ${file}`)\n\n\t\tconst result = { code: bundleResult.code, title, epicVideoEmbeds }\n\t\tawait fsExtra.ensureDir(cacheDir)\n\t\tawait fs.promises.writeFile(\n\t\t\tcacheLocation,\n\t\t\tJSON.stringify({\n\t\t\t\tvalue: {\n\t\t\t\t\t...result,\n\t\t\t\t\tcompiledTime: Date.now(),\n\t\t\t\t\tembeddedFiles: codeFileData.embeddedFiles.size\n\t\t\t\t\t\t? Object.fromEntries(codeFileData.embeddedFiles)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t}),\n\t\t)\n\t\tawait updateEmbeddedFilesCache(codeFileData)\n\t\treturn result\n\t} catch (error: unknown) {\n\t\tconsole.error(`Compilation error for file: `, file, error)\n\t\tthrow error\n\t} finally {\n\t\tverboseLog(`Successfully compiled ${file}`)\n\t}\n}\n\nexport async function compileMarkdownString(markdownString: string) {\n\treturn cachified({\n\t\tkey: markdownString,\n\t\tcache: compiledMarkdownCache,\n\t\tttl: 1000 * 60 * 60 * 24,\n\t\tgetFreshValue: async () => {\n\t\t\ttry {\n\t\t\t\tverboseLog(`Compiling string`, markdownString)\n\t\t\t\tconst result = await queuedBundleMDX({\n\t\t\t\t\tsource: markdownString,\n\t\t\t\t\tmdxOptions(options) {\n\t\t\t\t\t\toptions.rehypePlugins = [\n\t\t\t\t\t\t\t...(options.rehypePlugins ?? []),\n\t\t\t\t\t\t\t...rehypePlugins,\n\t\t\t\t\t\t]\n\t\t\t\t\t\toptions.development = false\n\t\t\t\t\t\treturn options\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif (!result) throw new Error(`Timed out compiling markdown string`)\n\n\t\t\t\treturn result.code\n\t\t\t} catch (error: unknown) {\n\t\t\t\tconsole.error(`Compilation error for code: `, markdownString, error)\n\t\t\t\tthrow error\n\t\t\t} finally {\n\t\t\t\tverboseLog(`Successfully compiled string`, markdownString)\n\t\t\t}\n\t\t},\n\t})\n}\n\nconst modifiedEmbeddedFilesTime = remember(\n\t'modified_embedded_files_time',\n\t() => new Map<string, number>(),\n)\n\nconst EMBEDDED_FILES_CACHE_KEY = 'embeddedFilesCache'\n\nasync function updateEmbeddedFilesCache({\n\tmdxFile,\n\tembeddedFiles,\n}: CodeFileData) {\n\tif (mdxFile.includes('playground')) return\n\tlet cachedList = await getEmbeddedFilesCache()\n\tconst hash = cachedList ? md5(JSON.stringify(cachedList)) : null\n\n\t// make sure we get clean list before updating it\n\tif (cachedList) {\n\t\tfor (const [key, value] of Object.entries(cachedList)) {\n\t\t\tcachedList[key] = value.filter((item) => item !== mdxFile)\n\t\t\tif (cachedList[key]?.length === 0) {\n\t\t\t\tdelete cachedList[key]\n\t\t\t}\n\t\t}\n\t}\n\n\tif (embeddedFiles.size) {\n\t\tif (!cachedList) {\n\t\t\tcachedList = {}\n\t\t}\n\t\tconst files = Array.from(\n\t\t\tnew Set(Array.from(embeddedFiles.values()).map(({ file }) => file)),\n\t\t).sort()\n\t\tfor (const file of files) {\n\t\t\tcachedList[file] = [...(cachedList[file] ?? []), mdxFile]\n\t\t}\n\t}\n\n\tif (cachedList && hash !== md5(JSON.stringify(cachedList))) {\n\t\tawait fsExtra.ensureDir(cacheDir)\n\t\tconst embeddedFilesLocation = path.join(cacheDir, 'embeddedFiles.json')\n\t\tmodifiedEmbeddedFilesTime.set(EMBEDDED_FILES_CACHE_KEY, Date.now())\n\t\tawait fs.promises.writeFile(\n\t\t\tembeddedFilesLocation,\n\t\t\tJSON.stringify({ ...cachedList }),\n\t\t)\n\t}\n}\n\nasync function getEmbeddedFilesCache() {\n\tconst key = EMBEDDED_FILES_CACHE_KEY\n\n\tfunction getForceFresh(cacheEntry: CacheEntry | null | undefined) {\n\t\tif (!cacheEntry) return true\n\t\tconst latestModifiedTime = modifiedEmbeddedFilesTime.get(key)\n\t\tif (!latestModifiedTime) return undefined\n\t\treturn latestModifiedTime > cacheEntry.metadata.createdTime\n\t\t\t? true\n\t\t\t: undefined\n\t}\n\n\treturn cachified({\n\t\tkey,\n\t\tcache: embeddedFilesCache,\n\t\tttl: 1000 * 60 * 60 * 24,\n\t\tforceFresh: getForceFresh(embeddedFilesCache.get(key)),\n\t\tgetFreshValue: async () => {\n\t\t\ttry {\n\t\t\t\tconst embeddedFilesLocation = path.join(cacheDir, 'embeddedFiles.json')\n\t\t\t\tif (await checkFileExists(embeddedFilesLocation)) {\n\t\t\t\t\treturn JSON.parse(\n\t\t\t\t\t\tawait fs.promises.readFile(embeddedFilesLocation, 'utf-8'),\n\t\t\t\t\t) as CachedEmbeddedFilesList\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tconsole.error(`Unable to read 'embeddedFiles.json' from: `, cacheDir)\n\t\t\t}\n\t\t\treturn undefined\n\t\t},\n\t})\n}\n\nexport async function isEmbeddedFile(filePath: string) {\n\tif (process.env.NODE_ENV !== 'development') return false\n\tconst embeddedFilesList = await getEmbeddedFilesCache()\n\tif (embeddedFilesList) {\n\t\tconst embeddedFiles = Object.keys(embeddedFilesList)\n\t\treturn embeddedFiles.includes(filePath.replace(/\\\\/g, '/'))\n\t}\n\treturn false\n}\n\nlet _queue: PQueue | null = null\nasync function getQueue() {\n\tif (_queue) return _queue\n\n\t_queue = new PQueue({\n\t\tconcurrency: 1,\n\t\tthrowOnTimeout: true,\n\t\ttimeout: 1000 * 60,\n\t})\n\treturn _queue\n}\n\n// We have to use a queue because we can't run more than one of these at a time\n// or we'll hit an out of memory error because esbuild uses a lot of memory...\nasync function queuedBundleMDX(...args: Parameters<typeof bundleMDX>) {\n\tconst queue = await getQueue()\n\tconst result = await queue.add(() => bundleMDX(...args))\n\treturn result\n}\n\n// TODO: Fix these\n/*\neslint\n\t\"@typescript-eslint/no-unsafe-assignment\": \"off\",\n\t\"@typescript-eslint/no-unsafe-member-access\": \"off\",\n\t\"@typescript-eslint/no-unnecessary-condition\": \"off\",\n\t\"@typescript-eslint/no-unsafe-argument\": \"off\",\n*/\n"]}
1
+ {"version":3,"file":"compile-mdx.server.js","sourceRoot":"","sources":["../../src/compile-mdx.server.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { remarkCodeBlocksShiki } from '@kentcdodds/md-temp'\nimport { type Element, type Root as HastRoot } from 'hast'\nimport { type Root as MdastRoot } from 'mdast'\nimport { bundleMDX } from 'mdx-bundler'\nimport PQueue from 'p-queue'\nimport remarkAutolinkHeadings from 'remark-autolink-headings'\nimport emoji from 'remark-emoji'\nimport gfm from 'remark-gfm'\nimport { type PluggableList } from 'unified'\nimport { visit } from 'unist-util-visit'\nimport {\n\tcachified,\n\tcompiledInstructionMarkdownCache,\n\tcompiledMarkdownCache,\n\tshouldForceFresh,\n} from './cache.server.js'\nimport { type Timings } from './timing.server.js'\n\nfunction trimCodeBlocks() {\n\treturn async function transformer(tree: HastRoot) {\n\t\tvisit(tree, 'element', (preNode: Element) => {\n\t\t\tif (preNode.tagName !== 'pre' || !preNode.children.length) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst codeNode = preNode.children[0]\n\t\t\tif (\n\t\t\t\t!codeNode ||\n\t\t\t\tcodeNode.type !== 'element' ||\n\t\t\t\tcodeNode.tagName !== 'code'\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [codeStringNode] = codeNode.children\n\t\t\tif (!codeStringNode) return\n\n\t\t\tif (codeStringNode.type !== 'text') {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`trimCodeBlocks: Unexpected: codeStringNode type is not \"text\": ${codeStringNode.type}`,\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcodeStringNode.value = codeStringNode.value.trimEnd()\n\t\t})\n\t}\n}\n\nfunction removePreContainerDivs() {\n\treturn async function preContainerDivsTransformer(tree: HastRoot) {\n\t\tvisit(\n\t\t\ttree,\n\t\t\t{ type: 'element', tagName: 'pre' },\n\t\t\tfunction visitor(node, index, parent) {\n\t\t\t\tif (parent?.type !== 'element') return\n\t\t\t\tif (parent.tagName !== 'div') return\n\t\t\t\tif (parent.children.length !== 1 && index === 0) return\n\t\t\t\tObject.assign(parent, node)\n\t\t\t},\n\t\t)\n\t}\n}\n\nconst rehypePlugins = [\n\ttrimCodeBlocks,\n\tremarkCodeBlocksShiki,\n\tremovePreContainerDivs,\n] satisfies PluggableList\n\nconst verboseLog =\n\tprocess.env.EPICSHOP_VERBOSE_LOG === 'true' ? console.log : () => {}\n\nexport async function compileMdx(\n\tfile: string,\n\t{\n\t\trequest,\n\t\ttimings,\n\t\tforceFresh,\n\t}: {\n\t\trequest?: Request\n\t\ttimings?: Timings\n\t\tforceFresh?: boolean\n\t} = {},\n) {\n\tconst stat = await fs.promises\n\t\t.stat(file)\n\t\t.catch((error: unknown) => ({ error }))\n\tif ('error' in stat) {\n\t\tthrow new Error(`File stat cannot be read: ${stat.error}`)\n\t}\n\n\tconst key = `file:${file}`\n\tforceFresh = await shouldForceFresh({ forceFresh, request, key })\n\n\tconst existingCacheEntry = await compiledInstructionMarkdownCache.get(key)\n\tif (!forceFresh && existingCacheEntry) {\n\t\tforceFresh = stat.mtimeMs > existingCacheEntry.metadata.createdTime\n\t}\n\n\treturn cachified({\n\t\tkey,\n\t\tcache: compiledInstructionMarkdownCache,\n\t\trequest,\n\t\ttimings,\n\t\tforceFresh,\n\t\tgetFreshValue: () => compileMdxImpl(file),\n\t})\n}\n\nasync function compileMdxImpl(file: string): Promise<{\n\tcode: string\n\ttitle: string | null\n\tepicVideoEmbeds: Array<string>\n}> {\n\tlet title: string | null = null\n\tconst epicVideoEmbeds: Array<string> = []\n\n\ttry {\n\t\tverboseLog(`Compiling ${file}`)\n\t\tconst bundleResult = await queuedBundleMDX({\n\t\t\tfile,\n\t\t\tcwd: path.dirname(file),\n\t\t\tmdxOptions(options) {\n\t\t\t\toptions.remarkPlugins = [\n\t\t\t\t\t...(options.remarkPlugins ?? []),\n\t\t\t\t\t[remarkAutolinkHeadings, { behavior: 'wrap' }],\n\t\t\t\t\tgfm,\n\t\t\t\t\t() => (tree: MdastRoot) => {\n\t\t\t\t\t\tvisit(tree, 'heading', (node) => {\n\t\t\t\t\t\t\tif (title) return\n\t\t\t\t\t\t\tif (node.depth === 1) {\n\t\t\t\t\t\t\t\tvisit(node, 'text', (textNode) => {\n\t\t\t\t\t\t\t\t\ttitle = textNode.value.trim()\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\ttitle = title ? title.replace(/^\\d+\\. /, '').trim() : null\n\t\t\t\t\t},\n\t\t\t\t\t() => (tree: MdastRoot) => {\n\t\t\t\t\t\tvisit(tree, 'mdxJsxFlowElement', (jsxEl) => {\n\t\t\t\t\t\t\t// @ts-expect-error no idea why this started being an issue suddenly 🤷‍♂️\n\t\t\t\t\t\t\tif (jsxEl.name !== 'EpicVideo') return\n\t\t\t\t\t\t\t// @ts-expect-error no idea why this started being an issue suddenly 🤷‍♂️\n\t\t\t\t\t\t\tconst urlAttr = jsxEl.attributes.find(\n\t\t\t\t\t\t\t\t// @ts-expect-error no idea why this started being an issue suddenly 🤷‍♂️\n\t\t\t\t\t\t\t\t(a) => a.type === 'mdxJsxAttribute' && a.name === 'url',\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tif (!urlAttr) return\n\t\t\t\t\t\t\tlet url = urlAttr.value\n\t\t\t\t\t\t\tif (typeof url !== 'string') return\n\t\t\t\t\t\t\tif (url.endsWith('/')) url = url.slice(0, -1)\n\t\t\t\t\t\t\tepicVideoEmbeds.push(url)\n\t\t\t\t\t\t})\n\t\t\t\t\t},\n\t\t\t\t\temoji,\n\t\t\t\t]\n\t\t\t\toptions.rehypePlugins = [\n\t\t\t\t\t...(options.rehypePlugins ?? []),\n\t\t\t\t\t...rehypePlugins,\n\t\t\t\t]\n\t\t\t\toptions.mdxExtensions = ['.mdx', '.md']\n\t\t\t\toptions.format = 'mdx'\n\t\t\t\toptions.development = false\n\t\t\t\treturn options\n\t\t\t},\n\t\t})\n\t\tif (!bundleResult) throw new Error(`Timeout for file: ${file}`)\n\n\t\tconst result = { code: bundleResult.code, title, epicVideoEmbeds }\n\t\treturn result\n\t} catch (error: unknown) {\n\t\tconsole.error(`Compilation error for file: `, file, error)\n\t\tthrow error\n\t} finally {\n\t\tverboseLog(`Successfully compiled ${file}`)\n\t}\n}\n\nexport async function compileMarkdownString(markdownString: string) {\n\treturn cachified({\n\t\tkey: markdownString,\n\t\tcache: compiledMarkdownCache,\n\t\tttl: 1000 * 60 * 60 * 24,\n\t\tgetFreshValue: async () => {\n\t\t\ttry {\n\t\t\t\tverboseLog(`Compiling string`, markdownString)\n\t\t\t\tconst result = await queuedBundleMDX({\n\t\t\t\t\tsource: markdownString,\n\t\t\t\t\tmdxOptions(options) {\n\t\t\t\t\t\toptions.rehypePlugins = [\n\t\t\t\t\t\t\t...(options.rehypePlugins ?? []),\n\t\t\t\t\t\t\t...rehypePlugins,\n\t\t\t\t\t\t]\n\t\t\t\t\t\toptions.development = false\n\t\t\t\t\t\treturn options\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif (!result) throw new Error(`Timed out compiling markdown string`)\n\n\t\t\t\treturn result.code\n\t\t\t} catch (error: unknown) {\n\t\t\t\tconsole.error(`Compilation error for code: `, markdownString, error)\n\t\t\t\tthrow error\n\t\t\t} finally {\n\t\t\t\tverboseLog(`Successfully compiled string`, markdownString)\n\t\t\t}\n\t\t},\n\t})\n}\n\nlet _queue: PQueue | null = null\nasync function getQueue() {\n\tif (_queue) return _queue\n\n\t_queue = new PQueue({\n\t\tconcurrency: 1,\n\t\tthrowOnTimeout: true,\n\t\ttimeout: 1000 * 60,\n\t})\n\treturn _queue\n}\n\n// We have to use a queue because we can't run more than one of these at a time\n// or we'll hit an out of memory error because esbuild uses a lot of memory...\nasync function queuedBundleMDX(...args: Parameters<typeof bundleMDX>) {\n\tconst queue = await getQueue()\n\tconst result = await queue.add(() => bundleMDX(...args))\n\treturn result\n}\n\n// TODO: Fix these\n/*\neslint\n\t\"@typescript-eslint/no-unsafe-assignment\": \"off\",\n\t\"@typescript-eslint/no-unsafe-member-access\": \"off\",\n\t\"@typescript-eslint/no-unnecessary-condition\": \"off\",\n\t\"@typescript-eslint/no-unsafe-argument\": \"off\",\n*/\n"]}
@@ -7,14 +7,14 @@ export declare const StackBlitzConfigSchema: z.ZodObject<{
7
7
  file: z.ZodOptional<z.ZodString>;
8
8
  }, "strip", z.ZodTypeAny, {
9
9
  title?: string | undefined;
10
- file?: string | undefined;
11
10
  startScript?: string | undefined;
12
11
  view?: "editor" | "preview" | "both" | undefined;
12
+ file?: string | undefined;
13
13
  }, {
14
14
  title?: string | undefined;
15
- file?: string | undefined;
16
15
  startScript?: string | undefined;
17
16
  view?: "editor" | "preview" | "both" | undefined;
17
+ file?: string | undefined;
18
18
  }>;
19
19
  declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
20
20
  title: z.ZodString;
@@ -72,14 +72,14 @@ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
72
72
  file: z.ZodOptional<z.ZodString>;
73
73
  }, "strip", z.ZodTypeAny, {
74
74
  title?: string | undefined;
75
- file?: string | undefined;
76
75
  startScript?: string | undefined;
77
76
  view?: "editor" | "preview" | "both" | undefined;
77
+ file?: string | undefined;
78
78
  }, {
79
79
  title?: string | undefined;
80
- file?: string | undefined;
81
80
  startScript?: string | undefined;
82
81
  view?: "editor" | "preview" | "both" | undefined;
82
+ file?: string | undefined;
83
83
  }>>;
84
84
  forms: z.ZodDefault<z.ZodObject<{
85
85
  workshop: z.ZodDefault<z.ZodString>;
@@ -139,9 +139,9 @@ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
139
139
  epicWorkshopSlug?: string | undefined;
140
140
  stackBlitzConfig?: {
141
141
  title?: string | undefined;
142
- file?: string | undefined;
143
142
  startScript?: string | undefined;
144
143
  view?: "editor" | "preview" | "both" | undefined;
144
+ file?: string | undefined;
145
145
  } | undefined;
146
146
  scripts?: {
147
147
  postupdate?: string | undefined;
@@ -172,9 +172,9 @@ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
172
172
  onboardingVideo?: string | undefined;
173
173
  stackBlitzConfig?: {
174
174
  title?: string | undefined;
175
- file?: string | undefined;
176
175
  startScript?: string | undefined;
177
176
  view?: "editor" | "preview" | "both" | undefined;
177
+ file?: string | undefined;
178
178
  } | undefined;
179
179
  forms?: {
180
180
  workshop?: string | undefined;
@@ -219,9 +219,9 @@ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
219
219
  epicWorkshopSlug?: string | undefined;
220
220
  stackBlitzConfig?: {
221
221
  title?: string | undefined;
222
- file?: string | undefined;
223
222
  startScript?: string | undefined;
224
223
  view?: "editor" | "preview" | "both" | undefined;
224
+ file?: string | undefined;
225
225
  } | undefined;
226
226
  scripts?: {
227
227
  postupdate?: string | undefined;
@@ -252,9 +252,9 @@ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
252
252
  onboardingVideo?: string | undefined;
253
253
  stackBlitzConfig?: {
254
254
  title?: string | undefined;
255
- file?: string | undefined;
256
255
  startScript?: string | undefined;
257
256
  view?: "editor" | "preview" | "both" | undefined;
257
+ file?: string | undefined;
258
258
  } | undefined;
259
259
  forms?: {
260
260
  workshop?: string | undefined;
@@ -279,9 +279,9 @@ export declare function getAppConfig(fullPath: string): Promise<{
279
279
  initialRoute: string;
280
280
  stackBlitzConfig: {
281
281
  title?: string | undefined;
282
- file?: string | undefined;
283
282
  startScript?: string | undefined;
284
283
  view?: "editor" | "preview" | "both" | undefined;
284
+ file?: string | undefined;
285
285
  } | null;
286
286
  testTab: {
287
287
  enabled: boolean;