@epic-web/workshop-utils 5.0.0 → 5.0.2

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.
@@ -2,6 +2,9 @@ import { type CacheEntry } from '@epic-web/cachified';
2
2
  import '@total-typescript/ts-reset';
3
3
  import { z } from 'zod';
4
4
  import { type Timings } from './timing.server.js';
5
+ declare global {
6
+ var __epicshop_apps_initialized__: boolean | undefined;
7
+ }
5
8
  export declare const workshopRoot: string;
6
9
  type CachifiedOptions = {
7
10
  timings?: Timings;
@@ -3138,8 +3141,8 @@ export declare function isPlaygroundApp(app: any): app is PlaygroundApp;
3138
3141
  export declare function isExampleApp(app: any): app is ExampleApp;
3139
3142
  export declare function isExerciseStepApp(app: any): app is ExerciseStepApp;
3140
3143
  export declare const modifiedTimes: Map<string, number>;
3141
- export declare function init(): void;
3142
- export declare function setModifiedTimesForDir(dir: string): void;
3144
+ export declare function init(): Promise<void>;
3145
+ export declare function setModifiedTimesForAppDirs(...filePaths: Array<string>): void;
3143
3146
  export declare function getForceFreshForDir(cacheEntry: CacheEntry | null | undefined, ...dirs: Array<string | undefined | null>): true | undefined;
3144
3147
  export declare function getExercises({ timings, request, }?: CachifiedOptions): Promise<Array<Exercise>>;
3145
3148
  export declare function getApps({ timings, request, forceFresh, }?: CachifiedOptions & {
@@ -4179,5 +4182,9 @@ export declare function getWorkshopFinished({ request, }?: {
4179
4182
  readonly relativePath: "exercises/finished.mdx";
4180
4183
  }>;
4181
4184
  export declare function getRelativePath(filePath: string): string;
4185
+ /**
4186
+ * Given a file path, this will determine the path to the app that file belongs to.
4187
+ */
4188
+ export declare function getAppPathFromFilePath(filePath: string): string | null;
4182
4189
  export {};
4183
4190
  //# sourceMappingURL=apps.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"apps.server.d.ts","sourceRoot":"","sources":["../../src/apps.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAGrD,OAAO,4BAA4B,CAAA;AAKnC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAwBvB,OAAO,EAAuB,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAKtE,eAAO,MAAM,YAAY,QAC0B,CAAA;AAUnD,KAAK,gBAAgB,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAkChE,QAAA,MAAM,yBAAyB;IA/B9B,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BtI,CAAA;AAEF,QAAA,MAAM,gBAAgB;IApCrB,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmCtI,CAAA;AAEF,QAAA,MAAM,iBAAiB;IAzCtB,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwCtI,CAAA;AAEF,QAAA,MAAM,gBAAgB;IA9CrB,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CtI,CAAA;AAEF,QAAA,MAAM,mBAAmB;IAlDxB,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkDtI,CAAA;AAEF,QAAA,MAAM,cAAc;IACnB,2CAA2C;;IAE3C,uIAAuI;;IAEvI,oFAAoF;;;;;;;;;YA7DpF,sCAAsC;;YAEtC,qFAAqF;;YAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAJvI,sCAAsC;;YAEtC,qFAAqF;;YAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAJvI,sCAAsC;;YAEtC,qFAAqF;;YAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAJvI,sCAAsC;;YAEtC,qFAAqF;;YAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAJvI,sCAAsC;;QAEtC,qFAAqF;;QAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAJvI,sCAAsC;;QAEtC,qFAAqF;;QAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoFtI,CAAA;AAEF,QAAA,MAAM,qBAAqB;IA1F1B,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAJvI,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAsF5D,CAAA;AAE5E,QAAA,MAAM,SAAS;IA5Fd,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAJvI,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAJvI,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAJvI,sCAAsC;;IAEtC,qFAAqF;;IAErF,uIAAuI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4FtI,CAAA;AAIF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAC3E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AACzD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAC3D,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AACzD,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAC/D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AACnE,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAA;AAC3C,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAA;AAEjC,KAAK,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAE9C,wBAAgB,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,GAAG,CAE1C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,UAAU,CAExD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,WAAW,CAE1D;AAED,wBAAgB,qBAAqB,CACpC,GAAG,EAAE,GAAG,GACN,GAAG,IAAI,UAAU,GAAG;IAAE,UAAU,EAAE,CAAC,CAAA;CAAE,CAEvC;AAED,wBAAgB,sBAAsB,CACrC,GAAG,EAAE,GAAG,GACN,GAAG,IAAI,WAAW,GAAG;IAAE,UAAU,EAAE,CAAC,CAAA;CAAE,CAExC;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,aAAa,CAE9D;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,UAAU,CAExD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,eAAe,CAElE;AAeD,eAAO,MAAM,aAAa,qBAGzB,CAAA;AAED,wBAAgB,IAAI,SA4BnB;AASD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,QAEjD;AAED,wBAAgB,mBAAmB,CAClC,UAAU,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACzC,GAAG,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,oBAezC;AAuDD,wBAAsB,YAAY,CAAC,EAClC,OAAO,EACP,OAAO,GACP,GAAE,gBAAqB,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CA6ClD;AAID,wBAAsB,OAAO,CAAC,EAC7B,OAAO,EACP,OAAO,EACP,UAAU,GACV,GAAE,gBAAgB,GAAG;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAqExE;AAQD;;;;;;GAMG;AACH,wBAAgB,sCAAsC,CACrD,iBAAiB,EAAE,MAAM;;;;SA0BzB;AAoMD,wBAAsB,gBAAgB,CAAC,EACtC,OAAO,EACP,OAAO,GACP,GAAE,gBAAqB,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAkEvD;AA0OD,wBAAsB,WAAW,CAChC,cAAc,EAAE,MAAM,GAAG,MAAM,EAC/B,EAAE,OAAO,EAAE,OAAO,EAAE,GAAE,gBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAI3C;AAED,wBAAsB,eAAe,CACpC,cAAc,EAAE,MAAM,GAAG,MAAM,EAC/B,EAAE,OAAO,EAAE,OAAO,EAAE,GAAE,gBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAU3C;AAED,wBAAsB,kBAAkB,CACvC,MAAM,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,EAC5C,EAAE,OAAO,EAAE,OAAO,EAAE,GAAE,gBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAO3C;AAQD,wBAAsB,cAAc,CACnC,MAAM,EAAE;IACP,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB,EACD,EAAE,OAAO,EAAE,OAAO,EAAE,GAAE,gBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqB3C;AAED,wBAAsB,YAAY,CACjC,IAAI,EAAE,MAAM,EACZ,EAAE,OAAO,EAAE,OAAO,EAAE,GAAE,gBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAI3C;AAED,wBAAsB,kBAAkB,CACvC,GAAG,EAAE,eAAe,EACpB,EAAE,OAAO,EAAE,OAAO,EAAE,GAAE,gBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAS3C;AAED,wBAAsB,kBAAkB,CACvC,GAAG,EAAE,eAAe,EACpB,EAAE,OAAO,EAAE,OAAO,EAAE,GAAE,gBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAU3C;AACD,wBAAgB,eAAe,CAC9B,GAAG,EAAE,eAAe,EACpB,EACC,QAAQ,EACR,YAAY,GACZ,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,eAAe,CAAA;CAAO,UAgB7D;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAGpD;AAED,wBAAsB,aAAa,CAClC,MAAM,EAAE,MAAM,EACd,EAAE,KAAK,EAAE,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,iBA0InC;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,2BAgBzC;AA+BD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,UAmB5D;AAED,wBAAsB,uBAAuB,CAAC,EAC7C,OAAO,GACP,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO;;;;;;;;;;;;GAc5B;AAED,wBAAsB,mBAAmB,CAAC,EACzC,OAAO,GACP,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO;;;;;;;;;;;;GAkB5B;AAID,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,UAK/C"}
1
+ {"version":3,"file":"apps.server.d.ts","sourceRoot":"","sources":["../../src/apps.server.ts"],"names":[],"mappings":"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"}
@@ -1,22 +1,23 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { remember } from '@epic-web/remember';
4
+ import chokidar from 'chokidar';
4
5
  /// TODO: figure out why this import is necessary (without it tsc seems to not honor the boolean reset 🤷‍♂️)
5
6
  import '@total-typescript/ts-reset';
7
+ import closeWithGrace from 'close-with-grace';
6
8
  import { execa } from 'execa';
7
9
  import fsExtra from 'fs-extra';
8
- import { glob } from 'glob';
9
10
  import { globby, isGitIgnored } from 'globby';
10
11
  import { z } from 'zod';
11
12
  import { appsCache, cachified, exampleAppCache, playgroundAppCache, problemAppCache, solutionAppCache, } from './cache.server.js';
12
- import { getOptionalWatcher, getWatcher } from './change-tracker.server.js';
13
13
  import { compileMdx } from './compile-mdx.server.js';
14
- import { bustWorkshopConfigCache, getAppConfig, getStackBlitzUrl, getWorkshopConfig, } from './config.server.js';
14
+ import { getAppConfig, getStackBlitzUrl, getWorkshopConfig, } from './config.server.js';
15
15
  import { getEnv, init as initEnv } from './env.server.js';
16
+ import { getDirModifiedTime } from './modified-time.server.js';
16
17
  import { closeProcess, isAppRunning, runAppDev, waitOnApp, } from './process-manager.server.js';
17
- import { getServerTimeHeader } from './timing.server.js';
18
+ import { getServerTimeHeader, time } from './timing.server.js';
18
19
  import { getErrorMessage } from './utils.js';
19
- let initialized = false;
20
+ global.__epicshop_apps_initialized__ ??= false;
20
21
  export const workshopRoot = (process.env.EPICSHOP_CONTEXT_CWD =
21
22
  process.env.EPICSHOP_CONTEXT_CWD ?? process.cwd());
22
23
  const playgroundAppNameInfoPath = path.join(workshopRoot, 'node_modules', '.cache', 'epicshop', 'playground.json');
@@ -141,28 +142,54 @@ async function firstToExist(...files) {
141
142
  return index === -1 ? null : files[index];
142
143
  }
143
144
  export const modifiedTimes = remember('modified_times', () => new Map());
144
- export function init() {
145
- if (initialized)
145
+ export async function init() {
146
+ if (global.__epicshop_apps_initialized__)
146
147
  return;
147
- initialized = true;
148
+ global.__epicshop_apps_initialized__ = true;
148
149
  const config = getWorkshopConfig();
149
150
  process.env.EPICSHOP_GITHUB_REPO = config.githubRepo;
150
151
  process.env.EPICSHOP_GITHUB_ROOT = config.githubRoot;
151
152
  initEnv();
152
153
  global.ENV = getEnv();
153
- async function handleFileChanges(event, filePath) {
154
- if (filePath === path.join(workshopRoot, 'package.json')) {
155
- bustWorkshopConfigCache();
156
- }
157
- const apps = await getApps();
158
- for (const app of apps) {
159
- if (filePath.startsWith(app.fullPath)) {
160
- modifiedTimes.set(app.fullPath, Date.now());
161
- break;
162
- }
163
- }
154
+ if (!ENV.EPICSHOP_DEPLOYED) {
155
+ const isIgnored = await isGitIgnored({ cwd: workshopRoot });
156
+ // watch the README, FINISHED, and package.json for changes that affect the apps
157
+ const filesToWatch = ['README.mdx', 'FINISHED.mdx', 'package.json'];
158
+ const chok = chokidar.watch(['examples', 'playground', 'exercises'], {
159
+ cwd: workshopRoot,
160
+ ignoreInitial: true,
161
+ ignored(filePath, stats) {
162
+ if (isIgnored(filePath))
163
+ return true;
164
+ if (filePath.includes('.git'))
165
+ return true;
166
+ if (stats?.isDirectory()) {
167
+ if (filePath.endsWith('playground'))
168
+ return false;
169
+ const pathParts = filePath.split(path.sep);
170
+ if (pathParts.at(-2) === 'examples')
171
+ return false;
172
+ // steps
173
+ if (pathParts.at(-3) === 'exercises')
174
+ return false;
175
+ // exercises
176
+ if (pathParts.at(-2) === 'exercises')
177
+ return false;
178
+ // the exercise dir itself
179
+ if (pathParts.at(-1) === 'exercises')
180
+ return false;
181
+ return true;
182
+ }
183
+ return stats?.isFile()
184
+ ? !filesToWatch.some((file) => filePath.endsWith(file))
185
+ : false;
186
+ },
187
+ });
188
+ chok.on('all', (_event, filePath) => {
189
+ setModifiedTimesForAppDirs(path.join(workshopRoot, filePath));
190
+ });
191
+ closeWithGrace(() => chok.close());
164
192
  }
165
- getWatcher()?.on('all', handleFileChanges);
166
193
  }
167
194
  function getForceFresh(cacheEntry) {
168
195
  if (!cacheEntry)
@@ -172,8 +199,17 @@ function getForceFresh(cacheEntry) {
172
199
  return undefined;
173
200
  return latestModifiedTime > cacheEntry.metadata.createdTime ? true : undefined;
174
201
  }
175
- export function setModifiedTimesForDir(dir) {
176
- modifiedTimes.set(dir, Date.now());
202
+ export function setModifiedTimesForAppDirs(...filePaths) {
203
+ const now = Date.now();
204
+ for (const filePath of filePaths) {
205
+ const appDir = getAppPathFromFilePath(filePath);
206
+ if (appDir) {
207
+ modifiedTimes.set(appDir, now);
208
+ }
209
+ else {
210
+ console.warn(`filePath ${filePath} does not match any app dir`);
211
+ }
212
+ }
177
213
  }
178
214
  export function getForceFreshForDir(cacheEntry, ...dirs) {
179
215
  const truthyDirs = dirs.filter(Boolean);
@@ -275,8 +311,7 @@ export async function getExercises({ timings, request, } = {}) {
275
311
  }
276
312
  let appCallCount = 0;
277
313
  export async function getApps({ timings, request, forceFresh, } = {}) {
278
- if (!initialized)
279
- init();
314
+ await init();
280
315
  const key = 'apps';
281
316
  const apps = await cachified({
282
317
  key,
@@ -289,10 +324,24 @@ export async function getApps({ timings, request, forceFresh, } = {}) {
289
324
  ttl: 1000 * 60 * 60 * 24,
290
325
  forceFresh: forceFresh ?? getForceFresh(appsCache.get(key)),
291
326
  getFreshValue: async () => {
292
- const playgroundApp = await getPlaygroundApp({ request, timings });
293
- const problemApps = await getProblemApps({ request, timings });
294
- const solutionApps = await getSolutionApps({ request, timings });
295
- const exampleApps = await getExampleApps({ request, timings });
327
+ const [playgroundApp, problemApps, solutionApps, exampleApps] = await Promise.all([
328
+ time(() => getPlaygroundApp({ request, timings }), {
329
+ type: 'getPlaygroundApp',
330
+ timings,
331
+ }),
332
+ time(() => getProblemApps({ request, timings }), {
333
+ type: 'getProblemApps',
334
+ timings,
335
+ }),
336
+ time(() => getSolutionApps({ request, timings }), {
337
+ type: 'getSolutionApps',
338
+ timings,
339
+ }),
340
+ time(() => getExampleApps({ request, timings }), {
341
+ type: 'getExampleApps',
342
+ timings,
343
+ }),
344
+ ]);
296
345
  const sortedApps = [
297
346
  playgroundApp,
298
347
  ...problemApps,
@@ -389,18 +438,38 @@ export function extractNumbersAndTypeFromAppNameOrPath(fullPathOrAppName) {
389
438
  }
390
439
  async function getProblemDirs() {
391
440
  const exercisesDir = path.join(workshopRoot, 'exercises');
392
- const problemDirs = (await glob('**/*.problem*', {
393
- cwd: exercisesDir,
394
- ignore: 'node_modules/**',
395
- })).map((p) => path.join(exercisesDir, p));
441
+ const problemDirs = [];
442
+ const exerciseSubDirs = await readDir(exercisesDir);
443
+ for (const subDir of exerciseSubDirs) {
444
+ const fullSubDir = path.join(exercisesDir, subDir);
445
+ // catch handles non-directories without us having to bother checking
446
+ // whether it's a directory
447
+ const subDirContents = await readDir(fullSubDir).catch(() => null);
448
+ if (!subDirContents)
449
+ continue;
450
+ const problemSubDirs = subDirContents
451
+ .filter((dir) => dir.includes('.problem'))
452
+ .map((dir) => path.join(fullSubDir, dir));
453
+ problemDirs.push(...problemSubDirs);
454
+ }
396
455
  return problemDirs;
397
456
  }
398
457
  async function getSolutionDirs() {
399
458
  const exercisesDir = path.join(workshopRoot, 'exercises');
400
- const solutionDirs = (await glob('**/*.solution*', {
401
- cwd: exercisesDir,
402
- ignore: 'node_modules/**',
403
- })).map((p) => path.join(exercisesDir, p));
459
+ const solutionDirs = [];
460
+ const exerciseSubDirs = await readDir(exercisesDir);
461
+ for (const subDir of exerciseSubDirs) {
462
+ const fullSubDir = path.join(exercisesDir, subDir);
463
+ // catch handles non-directories without us having to bother checking
464
+ // whether it's a directory
465
+ const subDirContents = await readDir(fullSubDir).catch(() => null);
466
+ if (!subDirContents)
467
+ continue;
468
+ const solutionSubDirs = subDirContents
469
+ .filter((dir) => dir.includes('.solution'))
470
+ .map((dir) => path.join(fullSubDir, dir));
471
+ solutionDirs.push(...solutionSubDirs);
472
+ }
404
473
  return solutionDirs;
405
474
  }
406
475
  /**
@@ -622,7 +691,7 @@ async function getExampleAppFromPath(fullPath, index, request) {
622
691
  }
623
692
  async function getExampleApps({ timings, request, } = {}) {
624
693
  const examplesDir = path.join(workshopRoot, 'examples');
625
- const exampleDirs = (await glob('*', { cwd: examplesDir, ignore: 'node_modules/**' })).map((p) => path.join(examplesDir, p));
694
+ const exampleDirs = (await readDir(examplesDir)).map((p) => path.join(examplesDir, p));
626
695
  const exampleApps = [];
627
696
  for (const exampleDir of exampleDirs) {
628
697
  const index = exampleDirs.indexOf(exampleDir);
@@ -635,10 +704,12 @@ async function getExampleApps({ timings, request, } = {}) {
635
704
  timingKey: exampleDir.replace(`${examplesDir}${path.sep}`, ''),
636
705
  request,
637
706
  forceFresh: getForceFreshForDir(exampleAppCache.get(key), exampleDir),
638
- getFreshValue: () => getExampleAppFromPath(exampleDir, index, request).catch((error) => {
639
- console.error(error);
640
- return null;
641
- }),
707
+ getFreshValue: async () => {
708
+ return getExampleAppFromPath(exampleDir, index, request).catch((error) => {
709
+ console.error(error);
710
+ return null;
711
+ });
712
+ },
642
713
  });
643
714
  if (exampleApp)
644
715
  exampleApps.push(exampleApp);
@@ -701,10 +772,12 @@ async function getSolutionApps({ timings, request, } = {}) {
701
772
  request,
702
773
  ttl: 1000 * 60 * 60 * 24,
703
774
  forceFresh: getForceFreshForDir(solutionAppCache.get(solutionDir), solutionDir),
704
- getFreshValue: () => getSolutionAppFromPath(solutionDir, request).catch((error) => {
705
- console.error(error);
706
- return null;
707
- }),
775
+ getFreshValue: async () => {
776
+ return getSolutionAppFromPath(solutionDir, request).catch((error) => {
777
+ console.error(error);
778
+ return null;
779
+ });
780
+ },
708
781
  });
709
782
  if (solutionApp)
710
783
  solutionApps.push(solutionApp);
@@ -768,10 +841,12 @@ async function getProblemApps({ timings, request, } = {}) {
768
841
  request,
769
842
  ttl: 1000 * 60 * 60 * 24,
770
843
  forceFresh: getForceFreshForDir(problemAppCache.get(problemDir), problemDir, solutionDir),
771
- getFreshValue: () => getProblemAppFromPath(problemDir).catch((error) => {
772
- console.error(error);
773
- return null;
774
- }),
844
+ getFreshValue: async () => {
845
+ return getProblemAppFromPath(problemDir).catch((error) => {
846
+ console.error(error);
847
+ return null;
848
+ });
849
+ },
775
850
  });
776
851
  if (problemApp)
777
852
  problemApps.push(problemApp);
@@ -867,10 +942,8 @@ export async function getAppFromFile(filePath) {
867
942
  return apps.find((app) => filePath.startsWith(app.fullPath));
868
943
  }
869
944
  export async function setPlayground(srcDir, { reset } = {}) {
870
- const isIgnored = await isGitIgnored({ cwd: srcDir });
871
945
  const destDir = path.join(workshopRoot, 'playground');
872
- const playgroundFiles = path.join(destDir, '**');
873
- getOptionalWatcher()?.unwatch(playgroundFiles);
946
+ const isIgnored = await isGitIgnored({ cwd: srcDir });
874
947
  const playgroundApp = await getAppByName('playground');
875
948
  const playgroundWasRunning = playgroundApp
876
949
  ? isAppRunning(playgroundApp)
@@ -979,12 +1052,12 @@ export async function setPlayground(srcDir, { reset } = {}) {
979
1052
  },
980
1053
  });
981
1054
  }
1055
+ // since we are running without the watcher we need to set the modified time
1056
+ modifiedTimes.set(destDir, Date.now());
982
1057
  if (playgroundApp && restartPlayground) {
983
1058
  await runAppDev(playgroundApp);
984
1059
  await waitOnApp(playgroundApp);
985
1060
  }
986
- getOptionalWatcher()?.add(playgroundFiles);
987
- modifiedTimes.set(destDir, Date.now());
988
1061
  }
989
1062
  /**
990
1063
  * The playground is based on another app. This returns the app the playground
@@ -1005,31 +1078,6 @@ export async function getPlaygroundAppName() {
1005
1078
  return null;
1006
1079
  }
1007
1080
  }
1008
- async function getDirModifiedTime(dir) {
1009
- // we can't use modifiedTimes because it only stores the modified times of
1010
- // things the app started.
1011
- const isIgnored = await isGitIgnored({ cwd: dir });
1012
- const files = await fs.promises.readdir(dir, { withFileTypes: true });
1013
- const modifiedTimes = await Promise.all(files.map(async (file) => {
1014
- if (isIgnored(file.name))
1015
- return 0;
1016
- const filePath = path.join(dir, file.name);
1017
- if (file.isDirectory()) {
1018
- return getDirModifiedTime(filePath);
1019
- }
1020
- else {
1021
- try {
1022
- const { mtimeMs } = await fs.promises.stat(filePath);
1023
- return mtimeMs;
1024
- }
1025
- catch {
1026
- // Handle errors (e.g., file access permissions, file has been moved or deleted)
1027
- return 0;
1028
- }
1029
- }
1030
- }));
1031
- return Math.max(0, ...modifiedTimes); // Ensure there is a default of 0 if all files are ignored
1032
- }
1033
1081
  export function getAppDisplayName(a, allApps) {
1034
1082
  let displayName = `${a.title} (${a.type})`;
1035
1083
  if (isExerciseStepApp(a)) {
@@ -1079,4 +1127,30 @@ export function getRelativePath(filePath) {
1079
1127
  .replace(playgroundPath, `playground${path.sep}`)
1080
1128
  .replace(exercisesPath, '');
1081
1129
  }
1130
+ /**
1131
+ * Given a file path, this will determine the path to the app that file belongs to.
1132
+ */
1133
+ export function getAppPathFromFilePath(filePath) {
1134
+ const [, withinWorkshopRootHalf] = filePath.split(workshopRoot);
1135
+ if (!withinWorkshopRootHalf) {
1136
+ return null;
1137
+ }
1138
+ const [part1, part2, part3] = withinWorkshopRootHalf
1139
+ .split(path.sep)
1140
+ .filter(Boolean);
1141
+ // Check if the file is in the playground
1142
+ if (part1 === 'playground') {
1143
+ return path.join(workshopRoot, 'playground');
1144
+ }
1145
+ // Check if the file is in an example
1146
+ if (part1 === 'examples' && part2) {
1147
+ return path.join(workshopRoot, 'examples', part2);
1148
+ }
1149
+ // Check if the file is in an exercise
1150
+ if (part1 === 'exercises' && part2 && part3) {
1151
+ return path.join(workshopRoot, 'exercises', part2, part3);
1152
+ }
1153
+ // If we couldn't determine the app path, return null
1154
+ return null;
1155
+ }
1082
1156
  //# sourceMappingURL=apps.server.js.map