@epic-web/workshop-utils 6.16.1 → 6.16.3

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":["// eslint-disable-next-line import/order -- this must be first\nimport { ENV } from './init-env.js'\n\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 { type Notification } from './notifications.server.js'\nimport { cachifiedTimingReporter, type Timings } from './timing.server.js'\nimport { checkConnectionCached } from './utils.server.js'\n\nconst cacheDir = path.join(process.env.EPICSHOP_HOME_DIR, 'cache')\n\nexport const solutionAppCache =\n\tmakeSingletonFsCache<SolutionApp>('SolutionAppCache')\nexport const problemAppCache =\n\tmakeSingletonFsCache<ProblemApp>('ProblemAppCache')\nexport const exampleAppCache =\n\tmakeSingletonFsCache<ExampleApp>('ExampleAppCache')\nexport const playgroundAppCache =\n\tmakeSingletonFsCache<PlaygroundApp>('PlaygroundAppCache')\nexport const appsCache = makeSingletonFsCache<App>('AppsCache')\nexport const diffCodeCache = makeSingletonFsCache<string>('DiffCodeCache')\nexport const diffFilesCache = makeSingletonFsCache<string>('DiffFilesCache')\nexport const copyUnignoredFilesCache = makeSingletonCache<string>(\n\t'CopyUnignoredFilesCache',\n)\nexport const compiledMarkdownCache = makeSingletonFsCache<string>(\n\t'CompiledMarkdownCache',\n)\nexport const compiledCodeCache =\n\tmakeSingletonFsCache<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')\nexport const dirModifiedTimeCache = makeSingletonCache<number>(\n\t'DirModifiedTimeCache',\n)\nexport const connectionCache = makeSingletonCache<boolean>('ConnectionCache')\nexport const checkForUpdatesCache = makeSingletonCache<{\n\tupdatesAvailable: boolean\n\tlocalCommit: string\n\tremoteCommit: string\n\tdiffLink: string | null\n}>('CheckForUpdatesCache')\nexport const notificationsCache =\n\tmakeSingletonCache<Array<Notification>>('NotificationsCache')\nexport const directoryEmptyCache = makeSingletonCache<boolean>(\n\t'DirectoryEmptyCache',\n)\n\nexport const fsCache = makeSingletonFsCache('FsCache')\n\nasync function readJsonFilesInDirectory(\n\tdir: string,\n): Promise<Record<string, any>> {\n\tconst files = await fsExtra.readdir(dir)\n\tconst entries = await Promise.all(\n\t\tfiles.map(async (file) => {\n\t\t\tconst filePath = path.join(dir, file)\n\t\t\tconst stats = await fsExtra.stat(filePath)\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst subEntries = await readJsonFilesInDirectory(filePath)\n\t\t\t\treturn [file, subEntries]\n\t\t\t} else {\n\t\t\t\tconst maxRetries = 2\n\t\t\t\tconst baseDelay = 25 // shorter delay for directory listing\n\n\t\t\t\tfor (let attempt = 0; attempt <= maxRetries; attempt++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\t\t\treturn [file, data]\n\t\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t\t// Handle JSON parsing errors (could be race condition or corruption)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\terror instanceof SyntaxError &&\n\t\t\t\t\t\t\terror.message.includes('JSON')\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// If this is a retry attempt, it might be a race condition\n\t\t\t\t\t\t\tif (attempt < maxRetries) {\n\t\t\t\t\t\t\t\tconst delay = baseDelay * Math.pow(2, attempt)\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`JSON parsing error on attempt ${attempt + 1}/${maxRetries + 1} for directory listing ${filePath}, retrying in ${delay}ms...`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay))\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Final attempt failed, skip the file\n\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t`Skipping corrupted JSON file in directory listing after ${attempt + 1} attempts: ${filePath}`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn [file, null]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// This should never be reached, but just in case\n\t\t\t\treturn [file, null]\n\t\t\t}\n\t\t}),\n\t)\n\treturn Object.fromEntries(entries)\n}\n\nexport async function getAllFileCacheEntries() {\n\treturn readJsonFilesInDirectory(cacheDir)\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 cacheInstanceDir = path.join(\n\t\t\tcacheDir,\n\t\t\tENV.EPICSHOP_WORKSHOP_INSTANCE_ID,\n\t\t\tname,\n\t\t)\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\tconst filePath = path.join(cacheInstanceDir, md5(key))\n\t\t\t\tconst maxRetries = 3\n\t\t\t\tconst baseDelay = 10\n\n\t\t\t\tfor (let attempt = 0; attempt <= maxRetries; attempt++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\t\t\tif (data.entry) return data.entry\n\t\t\t\t\t\treturn null\n\t\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\t\t'code' in error &&\n\t\t\t\t\t\t\terror.code === 'ENOENT'\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn null\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Handle JSON parsing errors (could be race condition or corruption)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\terror instanceof SyntaxError &&\n\t\t\t\t\t\t\terror.message.includes('JSON')\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// If this is a retry attempt, it might be a race condition\n\t\t\t\t\t\t\tif (attempt < maxRetries) {\n\t\t\t\t\t\t\t\tconst delay = baseDelay * Math.pow(2, attempt) // exponential backoff\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`JSON parsing error on attempt ${attempt + 1}/${maxRetries + 1} for ${filePath}, retrying in ${delay}ms...`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay))\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Final attempt failed, treat as corrupted file\n\t\t\t\t\t\t\t// Log to Sentry if available\n\t\t\t\t\t\t\tif (process.env.SENTRY_DSN && process.env.EPICSHOP_IS_PUBLISHED) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst Sentry = await import('@sentry/react-router')\n\t\t\t\t\t\t\t\t\tSentry.captureException(error, {\n\t\t\t\t\t\t\t\t\t\ttags: {\n\t\t\t\t\t\t\t\t\t\t\terror_type: 'corrupted_cache_file',\n\t\t\t\t\t\t\t\t\t\t\tcache_name: name,\n\t\t\t\t\t\t\t\t\t\t\tcache_key: key,\n\t\t\t\t\t\t\t\t\t\t\tretry_attempts: attempt.toString(),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\textra: {\n\t\t\t\t\t\t\t\t\t\t\tfilePath,\n\t\t\t\t\t\t\t\t\t\t\terrorMessage: error.message,\n\t\t\t\t\t\t\t\t\t\t\tcacheName: name,\n\t\t\t\t\t\t\t\t\t\t\tcacheKey: key,\n\t\t\t\t\t\t\t\t\t\t\tretryAttempts: attempt,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t} catch (sentryError) {\n\t\t\t\t\t\t\t\t\tconsole.error('Failed to log to Sentry:', sentryError)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Delete the corrupted file\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait fsExtra.remove(filePath)\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`Deleted corrupted cache file after ${attempt + 1} attempts: ${filePath}`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t} catch (deleteError) {\n\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t`Failed to delete corrupted cache file ${filePath}:`,\n\t\t\t\t\t\t\t\t\tdeleteError,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn null\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// For other errors, don't retry\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// This should never be reached, but just in case\n\t\t\t\treturn null\n\t\t\t},\n\t\t\tasync set(key, entry) {\n\t\t\t\tconst filePath = path.join(cacheInstanceDir, 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(cacheInstanceDir, 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\n/**\n * This wraps @epic-web/cachified to add a few handy features:\n *\n * 1. Automatic timing for timing headers\n * 2. Automatic force refresh based on the request and enhancement of forceFresh\n * to support comma-separated keys to force\n * 3. Offline fallback support. If a fallback is given and we are detected to be\n * offline, then the cached value is used regardless of whether it's expired and\n * if one is not present then the given fallback will be used.\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\tofflineFallbackValue,\n\t...options\n}: Omit<C.CachifiedOptions<Value>, 'forceFresh'> & {\n\trequest?: Request\n\ttimings?: Timings\n\tforceFresh?: boolean | string\n\ttimingKey?: string\n\tofflineFallbackValue?: Value\n}): Promise<Value> {\n\tif (offlineFallbackValue !== undefined) {\n\t\tconst isOnline = await checkConnectionCached({ request, timings })\n\t\tif (!isOnline) {\n\t\t\tconst cacheEntry = await options.cache.get(key)\n\t\t\treturn cacheEntry?.value ?? offlineFallbackValue\n\t\t}\n\t}\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":["// eslint-disable-next-line import/order -- this must be first\nimport { getEnv } from './init-env.js'\n\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 { type Notification } from './notifications.server.js'\nimport { cachifiedTimingReporter, type Timings } from './timing.server.js'\nimport { checkConnectionCached } from './utils.server.js'\n\nconst cacheDir = path.join(process.env.EPICSHOP_HOME_DIR, 'cache')\n\nexport const solutionAppCache =\n\tmakeSingletonFsCache<SolutionApp>('SolutionAppCache')\nexport const problemAppCache =\n\tmakeSingletonFsCache<ProblemApp>('ProblemAppCache')\nexport const exampleAppCache =\n\tmakeSingletonFsCache<ExampleApp>('ExampleAppCache')\nexport const playgroundAppCache =\n\tmakeSingletonFsCache<PlaygroundApp>('PlaygroundAppCache')\nexport const appsCache = makeSingletonFsCache<App>('AppsCache')\nexport const diffCodeCache = makeSingletonFsCache<string>('DiffCodeCache')\nexport const diffFilesCache = makeSingletonFsCache<string>('DiffFilesCache')\nexport const copyUnignoredFilesCache = makeSingletonCache<string>(\n\t'CopyUnignoredFilesCache',\n)\nexport const compiledMarkdownCache = makeSingletonFsCache<string>(\n\t'CompiledMarkdownCache',\n)\nexport const compiledCodeCache =\n\tmakeSingletonFsCache<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')\nexport const dirModifiedTimeCache = makeSingletonCache<number>(\n\t'DirModifiedTimeCache',\n)\nexport const connectionCache = makeSingletonCache<boolean>('ConnectionCache')\nexport const checkForUpdatesCache = makeSingletonCache<{\n\tupdatesAvailable: boolean\n\tlocalCommit: string\n\tremoteCommit: string\n\tdiffLink: string | null\n}>('CheckForUpdatesCache')\nexport const notificationsCache =\n\tmakeSingletonCache<Array<Notification>>('NotificationsCache')\nexport const directoryEmptyCache = makeSingletonCache<boolean>(\n\t'DirectoryEmptyCache',\n)\n\nexport const fsCache = makeSingletonFsCache('FsCache')\n\nasync function readJsonFilesInDirectory(\n\tdir: string,\n): Promise<Record<string, any>> {\n\tconst files = await fsExtra.readdir(dir)\n\tconst entries = await Promise.all(\n\t\tfiles.map(async (file) => {\n\t\t\tconst filePath = path.join(dir, file)\n\t\t\tconst stats = await fsExtra.stat(filePath)\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst subEntries = await readJsonFilesInDirectory(filePath)\n\t\t\t\treturn [file, subEntries]\n\t\t\t} else {\n\t\t\t\tconst maxRetries = 2\n\t\t\t\tconst baseDelay = 25 // shorter delay for directory listing\n\n\t\t\t\tfor (let attempt = 0; attempt <= maxRetries; attempt++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\t\t\treturn [file, data]\n\t\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t\t// Handle JSON parsing errors (could be race condition or corruption)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\terror instanceof SyntaxError &&\n\t\t\t\t\t\t\terror.message.includes('JSON')\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// If this is a retry attempt, it might be a race condition\n\t\t\t\t\t\t\tif (attempt < maxRetries) {\n\t\t\t\t\t\t\t\tconst delay = baseDelay * Math.pow(2, attempt)\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`JSON parsing error on attempt ${attempt + 1}/${maxRetries + 1} for directory listing ${filePath}, retrying in ${delay}ms...`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay))\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Final attempt failed, skip the file\n\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t`Skipping corrupted JSON file in directory listing after ${attempt + 1} attempts: ${filePath}`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn [file, null]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// This should never be reached, but just in case\n\t\t\t\treturn [file, null]\n\t\t\t}\n\t\t}),\n\t)\n\treturn Object.fromEntries(entries)\n}\n\nexport async function getAllFileCacheEntries() {\n\treturn readJsonFilesInDirectory(cacheDir)\n}\n\nexport async function deleteCache() {\n\tif (getEnv().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 cacheInstanceDir = path.join(\n\t\t\tcacheDir,\n\t\t\tgetEnv().EPICSHOP_WORKSHOP_INSTANCE_ID,\n\t\t\tname,\n\t\t)\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\tconst filePath = path.join(cacheInstanceDir, md5(key))\n\t\t\t\tconst maxRetries = 3\n\t\t\t\tconst baseDelay = 10\n\n\t\t\t\tfor (let attempt = 0; attempt <= maxRetries; attempt++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst data = await fsExtra.readJSON(filePath)\n\t\t\t\t\t\tif (data.entry) return data.entry\n\t\t\t\t\t\treturn null\n\t\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\t\t'code' in error &&\n\t\t\t\t\t\t\terror.code === 'ENOENT'\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn null\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Handle JSON parsing errors (could be race condition or corruption)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\terror instanceof SyntaxError &&\n\t\t\t\t\t\t\terror.message.includes('JSON')\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// If this is a retry attempt, it might be a race condition\n\t\t\t\t\t\t\tif (attempt < maxRetries) {\n\t\t\t\t\t\t\t\tconst delay = baseDelay * Math.pow(2, attempt) // exponential backoff\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`JSON parsing error on attempt ${attempt + 1}/${maxRetries + 1} for ${filePath}, retrying in ${delay}ms...`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay))\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Final attempt failed, treat as corrupted file\n\t\t\t\t\t\t\t// Log to Sentry if available\n\t\t\t\t\t\t\tif (getEnv().SENTRY_DSN && getEnv().EPICSHOP_IS_PUBLISHED) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst Sentry = await import('@sentry/react-router')\n\t\t\t\t\t\t\t\t\tSentry.captureException(error, {\n\t\t\t\t\t\t\t\t\t\ttags: {\n\t\t\t\t\t\t\t\t\t\t\terror_type: 'corrupted_cache_file',\n\t\t\t\t\t\t\t\t\t\t\tcache_name: name,\n\t\t\t\t\t\t\t\t\t\t\tcache_key: key,\n\t\t\t\t\t\t\t\t\t\t\tretry_attempts: attempt.toString(),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\textra: {\n\t\t\t\t\t\t\t\t\t\t\tfilePath,\n\t\t\t\t\t\t\t\t\t\t\terrorMessage: error.message,\n\t\t\t\t\t\t\t\t\t\t\tcacheName: name,\n\t\t\t\t\t\t\t\t\t\t\tcacheKey: key,\n\t\t\t\t\t\t\t\t\t\t\tretryAttempts: attempt,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t} catch (sentryError) {\n\t\t\t\t\t\t\t\t\tconsole.error('Failed to log to Sentry:', sentryError)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Delete the corrupted file\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait fsExtra.remove(filePath)\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`Deleted corrupted cache file after ${attempt + 1} attempts: ${filePath}`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t} catch (deleteError) {\n\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t`Failed to delete corrupted cache file ${filePath}:`,\n\t\t\t\t\t\t\t\t\tdeleteError,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn null\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// For other errors, don't retry\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// This should never be reached, but just in case\n\t\t\t\treturn null\n\t\t\t},\n\t\t\tasync set(key, entry) {\n\t\t\t\tconst filePath = path.join(cacheInstanceDir, 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(cacheInstanceDir, 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\n/**\n * This wraps @epic-web/cachified to add a few handy features:\n *\n * 1. Automatic timing for timing headers\n * 2. Automatic force refresh based on the request and enhancement of forceFresh\n * to support comma-separated keys to force\n * 3. Offline fallback support. If a fallback is given and we are detected to be\n * offline, then the cached value is used regardless of whether it's expired and\n * if one is not present then the given fallback will be used.\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\tofflineFallbackValue,\n\t...options\n}: Omit<C.CachifiedOptions<Value>, 'forceFresh'> & {\n\trequest?: Request\n\ttimings?: Timings\n\tforceFresh?: boolean | string\n\ttimingKey?: string\n\tofflineFallbackValue?: Value\n}): Promise<Value> {\n\tif (offlineFallbackValue !== undefined) {\n\t\tconst isOnline = await checkConnectionCached({ request, timings })\n\t\tif (!isOnline) {\n\t\t\tconst cacheEntry = await options.cache.get(key)\n\t\t\treturn cacheEntry?.value ?? offlineFallbackValue\n\t\t}\n\t}\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,10 +1,10 @@
1
1
  // eslint-disable-next-line import/order -- this must be first
2
- import { ENV } from './init-env.js';
2
+ import { getEnv } from './init-env.js';
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { z } from 'zod';
6
6
  import { handleGitHubRepoAndRoot } from './utils.js';
7
- const getRootPkgJsonPath = () => path.join(ENV.EPICSHOP_CONTEXT_CWD, 'package.json');
7
+ const getRootPkgJsonPath = () => path.join(getEnv().EPICSHOP_CONTEXT_CWD, 'package.json');
8
8
  export const StackBlitzConfigSchema = z.object({
9
9
  // we default this to `${exerciseTitle} (${type})`
10
10
  title: z.string().optional(),
@@ -51,10 +51,10 @@ const WorkshopConfigSchema = z
51
51
  .default('https://www.epicweb.dev/tips/get-started-with-the-epic-workshop-app'),
52
52
  githubRepo: z
53
53
  .string()
54
- .transform((githubRepo) => githubRepo ?? ENV.EPICSHOP_GITHUB_REPO),
54
+ .transform((githubRepo) => githubRepo ?? getEnv().EPICSHOP_GITHUB_REPO),
55
55
  githubRoot: z
56
56
  .string()
57
- .transform((githubRoot) => githubRoot ?? ENV.EPICSHOP_GITHUB_ROOT),
57
+ .transform((githubRoot) => githubRoot ?? getEnv().EPICSHOP_GITHUB_ROOT),
58
58
  stackBlitzConfig: StackBlitzConfigSchema.optional(),
59
59
  forms: z
60
60
  .object({
@@ -212,7 +212,7 @@ export async function getStackBlitzUrl({ fullPath, title, type, }) {
212
212
  };
213
213
  }
214
214
  const params = new URLSearchParams(stackBlitzConfig);
215
- const relativePath = fullPath.replace(`${ENV.EPICSHOP_CONTEXT_CWD}${path.sep}`, '');
215
+ const relativePath = fullPath.replace(`${getEnv().EPICSHOP_CONTEXT_CWD}${path.sep}`, '');
216
216
  const stackBlitzUrl = new URL(`/github${githubPart}/${relativePath}?${params}`, 'https://stackblitz.com');
217
217
  return stackBlitzUrl.toString();
218
218
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.server.js","sourceRoot":"","sources":["../../src/config.server.ts"],"names":[],"mappings":"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","sourcesContent":["// eslint-disable-next-line import/order -- this must be first\nimport { ENV } from './init-env.js'\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { z } from 'zod'\nimport { handleGitHubRepoAndRoot } from './utils.js'\n\nconst getRootPkgJsonPath = () =>\n\tpath.join(ENV.EPICSHOP_CONTEXT_CWD, 'package.json')\n\nexport const StackBlitzConfigSchema = z.object({\n\t// we default this to `${exerciseTitle} (${type})`\n\ttitle: z.string().optional(),\n\t// stackblitz defaults this to dev automatically\n\tstartScript: z.string().optional(),\n\t// if no value is provided, then stackblitz defaults this to whatever\n\t// looks best based on the width of the screen\n\tview: z\n\t\t.union([z.literal('editor'), z.literal('preview'), z.literal('both')])\n\t\t.optional(),\n\tfile: z.string().optional(),\n\thidedevtools: z.string().optional(),\n\tterminalHeight: z.string().optional(),\n\thideNavigation: z.string().optional(),\n})\n\nconst InstructorSchema = z.object({\n\tname: z.string().optional(),\n\tavatar: z.string().optional(),\n\t𝕏: z.string().optional(),\n\txHandle: z.string().optional(),\n})\n\n// most defaults are for backwards compatibility\nconst WorkshopConfigSchema = z\n\t.object({\n\t\ttitle: z.string(),\n\t\tsubtitle: z.string().optional(),\n\t\tinstructor: InstructorSchema.optional(),\n\t\tepicWorkshopHost: z.string().optional(),\n\t\tepicWorkshopSlug: z.string().optional(),\n\t\tsubdomain: z.string().optional(),\n\t\tproduct: z\n\t\t\t.object({\n\t\t\t\thost: z.string().default('www.epicweb.dev'),\n\t\t\t\tdisplayName: z.string().default('EpicWeb.dev'),\n\t\t\t\tdisplayNameShort: z.string().default('Epic Web'),\n\t\t\t\tlogo: z.string().default('/logo.svg'),\n\t\t\t\tslug: z.string().optional(),\n\t\t\t\tdiscordChannelId: z.string().default('1161045224907341972'),\n\t\t\t\tdiscordTags: z.array(z.string()).optional(),\n\t\t\t})\n\t\t\t.default({}),\n\t\tonboardingVideo: z\n\t\t\t.string()\n\t\t\t.default(\n\t\t\t\t'https://www.epicweb.dev/tips/get-started-with-the-epic-workshop-app',\n\t\t\t),\n\t\tgithubRepo: z\n\t\t\t.string()\n\t\t\t.transform((githubRepo) => githubRepo ?? ENV.EPICSHOP_GITHUB_REPO),\n\t\tgithubRoot: z\n\t\t\t.string()\n\t\t\t.transform((githubRoot) => githubRoot ?? ENV.EPICSHOP_GITHUB_ROOT),\n\t\tstackBlitzConfig: StackBlitzConfigSchema.optional(),\n\t\tforms: z\n\t\t\t.object({\n\t\t\t\tworkshop: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.default(\n\t\t\t\t\t\t'https://docs.google.com/forms/d/e/1FAIpQLSdRmj9p8-5zyoqRzxp3UpqSbC3aFkweXvvJIKes0a5s894gzg/viewform?hl=en&embedded=true&entry.2123647600={workshopTitle}',\n\t\t\t\t\t),\n\t\t\t\texercise: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.default(\n\t\t\t\t\t\t'https://docs.google.com/forms/d/e/1FAIpQLSf3o9xyjQepTlOTH5Z7ZwkeSTdXh6YWI_RGc9KiyD3oUN0p6w/viewform?hl=en&embedded=true&entry.1836176234={workshopTitle}&entry.428900931={exerciseTitle}',\n\t\t\t\t\t),\n\t\t\t})\n\t\t\t.default({}),\n\t\ttestTab: z\n\t\t\t.object({\n\t\t\t\tenabled: z.boolean().default(true),\n\t\t\t})\n\t\t\t.default({}),\n\t\tscripts: z\n\t\t\t.object({\n\t\t\t\tpostupdate: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tinitialRoute: z.string().optional().default('/'),\n\t\tnotifications: z\n\t\t\t.array(\n\t\t\t\tz.object({\n\t\t\t\t\tid: z.string(),\n\t\t\t\t\ttitle: z.string(),\n\t\t\t\t\tmessage: z.string(),\n\t\t\t\t\tlink: z.string().optional(),\n\t\t\t\t\ttype: z.enum(['info', 'warning', 'danger']),\n\t\t\t\t\texpiresAt: z.date().nullable(),\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.optional()\n\t\t\t.default([]),\n\t})\n\t.transform((data) => {\n\t\treturn {\n\t\t\t...data,\n\t\t\tproduct: {\n\t\t\t\t...data.product,\n\t\t\t\tdisplayNameShort:\n\t\t\t\t\tdata.product.displayNameShort ?? data.product.displayName,\n\t\t\t\t// for backwards compatibility\n\t\t\t\thost: data.product.host ?? data.epicWorkshopHost,\n\t\t\t\tslug: data.product.slug ?? data.epicWorkshopSlug,\n\t\t\t},\n\t\t}\n\t})\n\nexport type WorkshopConfig = z.infer<typeof WorkshopConfigSchema>\n\nconst configCache: {\n\tconfig: WorkshopConfig | null\n\tmodified: number\n} = {\n\tconfig: null,\n\tmodified: 0,\n}\n\n// Utility to read and parse the root package.json\nfunction readRootPkgJson(): any {\n\tconst packageJsonPath = getRootPkgJsonPath()\n\ttry {\n\t\tconst packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8')\n\t\treturn JSON.parse(packageJsonContent)\n\t} catch (error) {\n\t\tconsole.error(`Error reading or parsing package.json:`, error)\n\t\tif (error instanceof Error && error.message.includes('ENOENT')) {\n\t\t\tthrow new Error(\n\t\t\t\t`package.json not found at ${packageJsonPath}. Please ensure you're running the command from the correct directory.`,\n\t\t\t)\n\t\t} else if (error instanceof SyntaxError) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid JSON in package.json at ${packageJsonPath}. Please check the file for syntax errors.`,\n\t\t\t)\n\t\t}\n\t\tthrow new Error(\n\t\t\t`Could not find and parse package.json at ${packageJsonPath}`,\n\t\t)\n\t}\n}\n\n/**\n * This used to support subdomains on localhost, but that caused too many issues.\n */\nexport function getWorkshopUrl(port: number) {\n\treturn `http://localhost:${port}`\n}\n\nexport function getWorkshopConfig(): WorkshopConfig {\n\tif (\n\t\tconfigCache.config &&\n\t\tconfigCache.modified > fs.statSync(getRootPkgJsonPath()).mtimeMs\n\t) {\n\t\treturn configCache.config\n\t}\n\n\tconst packageJson = readRootPkgJson()\n\n\tconst epicshopConfig = packageJson.epicshop || {}\n\n\t// Set githubRepo and githubRoot before parsing\n\tconst { githubRepo, githubRoot } = handleGitHubRepoAndRoot({\n\t\tgithubRepo: epicshopConfig.githubRepo,\n\t\tgithubRoot: epicshopConfig.githubRoot,\n\t})\n\tepicshopConfig.githubRepo = githubRepo\n\tepicshopConfig.githubRoot = githubRoot\n\n\ttry {\n\t\tconst parsedConfig = WorkshopConfigSchema.parse(epicshopConfig)\n\t\tconfigCache.config = parsedConfig\n\t\tconfigCache.modified = fs.statSync(getRootPkgJsonPath()).mtimeMs\n\t\treturn parsedConfig\n\t} catch (error) {\n\t\tif (error instanceof z.ZodError) {\n\t\t\tconst flattenedErrors = error.flatten()\n\t\t\tconst errorMessages = Object.entries(flattenedErrors.fieldErrors)\n\t\t\t\t.map(([field, errors]) => `${field}: ${errors?.join(', ')}`)\n\t\t\t\t.concat(flattenedErrors.formErrors)\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid epicshop configuration in ${getRootPkgJsonPath()}:\\n${errorMessages.join('\\n')}`,\n\t\t\t)\n\t\t}\n\t\tthrow error\n\t}\n}\n\nexport async function getStackBlitzUrl({\n\tfullPath,\n\ttitle,\n\ttype,\n}: {\n\tfullPath: string\n\ttitle: string\n\ttype: string\n}) {\n\tconst workshopConfig = getWorkshopConfig()\n\tconst appConfig = await getAppConfig(fullPath)\n\n\tif (appConfig.stackBlitzConfig === null) return null\n\n\tlet githubRootUrlString = workshopConfig.githubRoot\n\n\tconst githubRootUrl = new URL(\n\t\tgithubRootUrlString.replace(/\\/blob\\//, '/tree/'),\n\t)\n\n\tconst githubPart = githubRootUrl.pathname\n\n\t// Check if package.json exists to determine if this is a simple exercise\n\tconst packageJsonPath = path.join(fullPath, 'package.json')\n\tconst packageJsonExists = await fs.promises\n\t\t.access(packageJsonPath, fs.constants.F_OK)\n\t\t.then(() => true)\n\t\t.catch(() => false)\n\n\tlet stackBlitzConfig = {\n\t\t...appConfig.stackBlitzConfig,\n\t\ttitle: appConfig.stackBlitzConfig?.title ?? `${title} (${type})`,\n\t}\n\n\t// For simple exercises without package.json, configure StackBlitz to show only editor\n\tif (!packageJsonExists) {\n\t\t// Find the first existing file from the priority list\n\t\tconst priorityFiles = [\n\t\t\t'index.html',\n\t\t\t'index.tsx',\n\t\t\t'index.ts',\n\t\t\t'index.jsx',\n\t\t\t'index.js',\n\t\t\t'README.mdx',\n\t\t\t'README.md',\n\t\t]\n\n\t\tlet defaultFile: string | null = null\n\t\tfor (const fileName of priorityFiles) {\n\t\t\tconst filePath = path.join(fullPath, fileName)\n\t\t\ttry {\n\t\t\t\tawait fs.promises.access(filePath, fs.constants.F_OK)\n\t\t\t\tdefaultFile = fileName\n\t\t\t\tbreak\n\t\t\t} catch {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tstackBlitzConfig = {\n\t\t\t...stackBlitzConfig,\n\t\t\tview: 'editor', // Show only editor, no preview or terminal\n\t\t\thidedevtools: '1', // Hide the console/devtools\n\t\t\tterminalHeight: '0', // Hide the terminal completely\n\t\t\thideNavigation: '1', // Hide the preview's URL bar\n\t\t\t...(defaultFile && { file: defaultFile }), // Set default file if found\n\t\t}\n\t}\n\n\tconst params = new URLSearchParams(stackBlitzConfig as Record<string, string>)\n\n\tconst relativePath = fullPath.replace(\n\t\t`${ENV.EPICSHOP_CONTEXT_CWD}${path.sep}`,\n\t\t'',\n\t)\n\n\tconst stackBlitzUrl = new URL(\n\t\t`/github${githubPart}/${relativePath}?${params}`,\n\t\t'https://stackblitz.com',\n\t)\n\n\treturn stackBlitzUrl.toString()\n}\n\nexport async function getAppConfig(fullPath: string) {\n\tconst workshopConfig = getWorkshopConfig()\n\n\tlet epicshopConfig: Record<string, any> = {}\n\tlet scripts: Record<string, string> = {}\n\n\tconst packageJsonPath = path.join(fullPath, 'package.json')\n\tconst packageJsonExists = await fs.promises\n\t\t.access(packageJsonPath, fs.constants.F_OK)\n\t\t.then(() => true)\n\t\t.catch(() => false)\n\n\tif (packageJsonExists) {\n\t\tconst pkg = JSON.parse(\n\t\t\tawait fs.promises.readFile(path.join(fullPath, 'package.json'), 'utf8'),\n\t\t) as any\n\t\tepicshopConfig = pkg.epicshop ?? {}\n\t\tscripts = pkg.scripts ?? {}\n\t}\n\n\tconst AppConfigSchema = z.object({\n\t\tstackBlitzConfig: StackBlitzConfigSchema.nullable()\n\t\t\t.optional()\n\t\t\t.transform((appStackBlitzConfig) => {\n\t\t\t\tif (appStackBlitzConfig === null) return null\n\n\t\t\t\treturn {\n\t\t\t\t\t...workshopConfig.stackBlitzConfig,\n\t\t\t\t\t...appStackBlitzConfig,\n\t\t\t\t}\n\t\t\t}),\n\t\ttestTab: z\n\t\t\t.object({\n\t\t\t\tenabled: z\n\t\t\t\t\t.boolean()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.default(workshopConfig.testTab?.enabled ?? true),\n\t\t\t})\n\t\t\t.default({}),\n\t\tscripts: z\n\t\t\t.object({\n\t\t\t\ttest: z.string().optional(),\n\t\t\t\tdev: z.string().optional(),\n\t\t\t})\n\t\t\t.default({}),\n\t\tinitialRoute: z.string().optional().default(workshopConfig.initialRoute),\n\t})\n\n\tconst appConfig = {\n\t\tstackBlitzConfig: epicshopConfig.stackBlitzConfig,\n\t\ttestTab: {\n\t\t\tenabled: epicshopConfig.testTab?.enabled,\n\t\t},\n\t\tscripts: {\n\t\t\ttest: scripts.test,\n\t\t\tdev: scripts.dev,\n\t\t},\n\t\tinitialRoute: epicshopConfig.initialRoute,\n\t}\n\n\ttry {\n\t\treturn AppConfigSchema.parse(appConfig)\n\t} catch (error) {\n\t\tif (error instanceof z.ZodError) {\n\t\t\tconst flattenedErrors = error.flatten()\n\t\t\tconst errorMessages = Object.entries(flattenedErrors.fieldErrors)\n\t\t\t\t.map(([field, errors]) => `${field}: ${errors?.join(', ')}`)\n\t\t\t\t.concat(flattenedErrors.formErrors)\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid app configuration for ${fullPath}:\\n${errorMessages.join('\\n')}`,\n\t\t\t)\n\t\t}\n\t\tthrow error\n\t}\n}\n"]}
1
+ {"version":3,"file":"config.server.js","sourceRoot":"","sources":["../../src/config.server.ts"],"names":[],"mappings":"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","sourcesContent":["// eslint-disable-next-line import/order -- this must be first\nimport { getEnv } from './init-env.js'\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { z } from 'zod'\nimport { handleGitHubRepoAndRoot } from './utils.js'\n\nconst getRootPkgJsonPath = () =>\n\tpath.join(getEnv().EPICSHOP_CONTEXT_CWD, 'package.json')\n\nexport const StackBlitzConfigSchema = z.object({\n\t// we default this to `${exerciseTitle} (${type})`\n\ttitle: z.string().optional(),\n\t// stackblitz defaults this to dev automatically\n\tstartScript: z.string().optional(),\n\t// if no value is provided, then stackblitz defaults this to whatever\n\t// looks best based on the width of the screen\n\tview: z\n\t\t.union([z.literal('editor'), z.literal('preview'), z.literal('both')])\n\t\t.optional(),\n\tfile: z.string().optional(),\n\thidedevtools: z.string().optional(),\n\tterminalHeight: z.string().optional(),\n\thideNavigation: z.string().optional(),\n})\n\nconst InstructorSchema = z.object({\n\tname: z.string().optional(),\n\tavatar: z.string().optional(),\n\t𝕏: z.string().optional(),\n\txHandle: z.string().optional(),\n})\n\n// most defaults are for backwards compatibility\nconst WorkshopConfigSchema = z\n\t.object({\n\t\ttitle: z.string(),\n\t\tsubtitle: z.string().optional(),\n\t\tinstructor: InstructorSchema.optional(),\n\t\tepicWorkshopHost: z.string().optional(),\n\t\tepicWorkshopSlug: z.string().optional(),\n\t\tsubdomain: z.string().optional(),\n\t\tproduct: z\n\t\t\t.object({\n\t\t\t\thost: z.string().default('www.epicweb.dev'),\n\t\t\t\tdisplayName: z.string().default('EpicWeb.dev'),\n\t\t\t\tdisplayNameShort: z.string().default('Epic Web'),\n\t\t\t\tlogo: z.string().default('/logo.svg'),\n\t\t\t\tslug: z.string().optional(),\n\t\t\t\tdiscordChannelId: z.string().default('1161045224907341972'),\n\t\t\t\tdiscordTags: z.array(z.string()).optional(),\n\t\t\t})\n\t\t\t.default({}),\n\t\tonboardingVideo: z\n\t\t\t.string()\n\t\t\t.default(\n\t\t\t\t'https://www.epicweb.dev/tips/get-started-with-the-epic-workshop-app',\n\t\t\t),\n\t\tgithubRepo: z\n\t\t\t.string()\n\t\t\t.transform((githubRepo) => githubRepo ?? getEnv().EPICSHOP_GITHUB_REPO),\n\t\tgithubRoot: z\n\t\t\t.string()\n\t\t\t.transform((githubRoot) => githubRoot ?? getEnv().EPICSHOP_GITHUB_ROOT),\n\t\tstackBlitzConfig: StackBlitzConfigSchema.optional(),\n\t\tforms: z\n\t\t\t.object({\n\t\t\t\tworkshop: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.default(\n\t\t\t\t\t\t'https://docs.google.com/forms/d/e/1FAIpQLSdRmj9p8-5zyoqRzxp3UpqSbC3aFkweXvvJIKes0a5s894gzg/viewform?hl=en&embedded=true&entry.2123647600={workshopTitle}',\n\t\t\t\t\t),\n\t\t\t\texercise: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.default(\n\t\t\t\t\t\t'https://docs.google.com/forms/d/e/1FAIpQLSf3o9xyjQepTlOTH5Z7ZwkeSTdXh6YWI_RGc9KiyD3oUN0p6w/viewform?hl=en&embedded=true&entry.1836176234={workshopTitle}&entry.428900931={exerciseTitle}',\n\t\t\t\t\t),\n\t\t\t})\n\t\t\t.default({}),\n\t\ttestTab: z\n\t\t\t.object({\n\t\t\t\tenabled: z.boolean().default(true),\n\t\t\t})\n\t\t\t.default({}),\n\t\tscripts: z\n\t\t\t.object({\n\t\t\t\tpostupdate: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tinitialRoute: z.string().optional().default('/'),\n\t\tnotifications: z\n\t\t\t.array(\n\t\t\t\tz.object({\n\t\t\t\t\tid: z.string(),\n\t\t\t\t\ttitle: z.string(),\n\t\t\t\t\tmessage: z.string(),\n\t\t\t\t\tlink: z.string().optional(),\n\t\t\t\t\ttype: z.enum(['info', 'warning', 'danger']),\n\t\t\t\t\texpiresAt: z.date().nullable(),\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.optional()\n\t\t\t.default([]),\n\t})\n\t.transform((data) => {\n\t\treturn {\n\t\t\t...data,\n\t\t\tproduct: {\n\t\t\t\t...data.product,\n\t\t\t\tdisplayNameShort:\n\t\t\t\t\tdata.product.displayNameShort ?? data.product.displayName,\n\t\t\t\t// for backwards compatibility\n\t\t\t\thost: data.product.host ?? data.epicWorkshopHost,\n\t\t\t\tslug: data.product.slug ?? data.epicWorkshopSlug,\n\t\t\t},\n\t\t}\n\t})\n\nexport type WorkshopConfig = z.infer<typeof WorkshopConfigSchema>\n\nconst configCache: {\n\tconfig: WorkshopConfig | null\n\tmodified: number\n} = {\n\tconfig: null,\n\tmodified: 0,\n}\n\n// Utility to read and parse the root package.json\nfunction readRootPkgJson(): any {\n\tconst packageJsonPath = getRootPkgJsonPath()\n\ttry {\n\t\tconst packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8')\n\t\treturn JSON.parse(packageJsonContent)\n\t} catch (error) {\n\t\tconsole.error(`Error reading or parsing package.json:`, error)\n\t\tif (error instanceof Error && error.message.includes('ENOENT')) {\n\t\t\tthrow new Error(\n\t\t\t\t`package.json not found at ${packageJsonPath}. Please ensure you're running the command from the correct directory.`,\n\t\t\t)\n\t\t} else if (error instanceof SyntaxError) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid JSON in package.json at ${packageJsonPath}. Please check the file for syntax errors.`,\n\t\t\t)\n\t\t}\n\t\tthrow new Error(\n\t\t\t`Could not find and parse package.json at ${packageJsonPath}`,\n\t\t)\n\t}\n}\n\n/**\n * This used to support subdomains on localhost, but that caused too many issues.\n */\nexport function getWorkshopUrl(port: number) {\n\treturn `http://localhost:${port}`\n}\n\nexport function getWorkshopConfig(): WorkshopConfig {\n\tif (\n\t\tconfigCache.config &&\n\t\tconfigCache.modified > fs.statSync(getRootPkgJsonPath()).mtimeMs\n\t) {\n\t\treturn configCache.config\n\t}\n\n\tconst packageJson = readRootPkgJson()\n\n\tconst epicshopConfig = packageJson.epicshop || {}\n\n\t// Set githubRepo and githubRoot before parsing\n\tconst { githubRepo, githubRoot } = handleGitHubRepoAndRoot({\n\t\tgithubRepo: epicshopConfig.githubRepo,\n\t\tgithubRoot: epicshopConfig.githubRoot,\n\t})\n\tepicshopConfig.githubRepo = githubRepo\n\tepicshopConfig.githubRoot = githubRoot\n\n\ttry {\n\t\tconst parsedConfig = WorkshopConfigSchema.parse(epicshopConfig)\n\t\tconfigCache.config = parsedConfig\n\t\tconfigCache.modified = fs.statSync(getRootPkgJsonPath()).mtimeMs\n\t\treturn parsedConfig\n\t} catch (error) {\n\t\tif (error instanceof z.ZodError) {\n\t\t\tconst flattenedErrors = error.flatten()\n\t\t\tconst errorMessages = Object.entries(flattenedErrors.fieldErrors)\n\t\t\t\t.map(([field, errors]) => `${field}: ${errors?.join(', ')}`)\n\t\t\t\t.concat(flattenedErrors.formErrors)\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid epicshop configuration in ${getRootPkgJsonPath()}:\\n${errorMessages.join('\\n')}`,\n\t\t\t)\n\t\t}\n\t\tthrow error\n\t}\n}\n\nexport async function getStackBlitzUrl({\n\tfullPath,\n\ttitle,\n\ttype,\n}: {\n\tfullPath: string\n\ttitle: string\n\ttype: string\n}) {\n\tconst workshopConfig = getWorkshopConfig()\n\tconst appConfig = await getAppConfig(fullPath)\n\n\tif (appConfig.stackBlitzConfig === null) return null\n\n\tlet githubRootUrlString = workshopConfig.githubRoot\n\n\tconst githubRootUrl = new URL(\n\t\tgithubRootUrlString.replace(/\\/blob\\//, '/tree/'),\n\t)\n\n\tconst githubPart = githubRootUrl.pathname\n\n\t// Check if package.json exists to determine if this is a simple exercise\n\tconst packageJsonPath = path.join(fullPath, 'package.json')\n\tconst packageJsonExists = await fs.promises\n\t\t.access(packageJsonPath, fs.constants.F_OK)\n\t\t.then(() => true)\n\t\t.catch(() => false)\n\n\tlet stackBlitzConfig = {\n\t\t...appConfig.stackBlitzConfig,\n\t\ttitle: appConfig.stackBlitzConfig?.title ?? `${title} (${type})`,\n\t}\n\n\t// For simple exercises without package.json, configure StackBlitz to show only editor\n\tif (!packageJsonExists) {\n\t\t// Find the first existing file from the priority list\n\t\tconst priorityFiles = [\n\t\t\t'index.html',\n\t\t\t'index.tsx',\n\t\t\t'index.ts',\n\t\t\t'index.jsx',\n\t\t\t'index.js',\n\t\t\t'README.mdx',\n\t\t\t'README.md',\n\t\t]\n\n\t\tlet defaultFile: string | null = null\n\t\tfor (const fileName of priorityFiles) {\n\t\t\tconst filePath = path.join(fullPath, fileName)\n\t\t\ttry {\n\t\t\t\tawait fs.promises.access(filePath, fs.constants.F_OK)\n\t\t\t\tdefaultFile = fileName\n\t\t\t\tbreak\n\t\t\t} catch {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tstackBlitzConfig = {\n\t\t\t...stackBlitzConfig,\n\t\t\tview: 'editor', // Show only editor, no preview or terminal\n\t\t\thidedevtools: '1', // Hide the console/devtools\n\t\t\tterminalHeight: '0', // Hide the terminal completely\n\t\t\thideNavigation: '1', // Hide the preview's URL bar\n\t\t\t...(defaultFile && { file: defaultFile }), // Set default file if found\n\t\t}\n\t}\n\n\tconst params = new URLSearchParams(stackBlitzConfig as Record<string, string>)\n\n\tconst relativePath = fullPath.replace(\n\t\t`${getEnv().EPICSHOP_CONTEXT_CWD}${path.sep}`,\n\t\t'',\n\t)\n\n\tconst stackBlitzUrl = new URL(\n\t\t`/github${githubPart}/${relativePath}?${params}`,\n\t\t'https://stackblitz.com',\n\t)\n\n\treturn stackBlitzUrl.toString()\n}\n\nexport async function getAppConfig(fullPath: string) {\n\tconst workshopConfig = getWorkshopConfig()\n\n\tlet epicshopConfig: Record<string, any> = {}\n\tlet scripts: Record<string, string> = {}\n\n\tconst packageJsonPath = path.join(fullPath, 'package.json')\n\tconst packageJsonExists = await fs.promises\n\t\t.access(packageJsonPath, fs.constants.F_OK)\n\t\t.then(() => true)\n\t\t.catch(() => false)\n\n\tif (packageJsonExists) {\n\t\tconst pkg = JSON.parse(\n\t\t\tawait fs.promises.readFile(path.join(fullPath, 'package.json'), 'utf8'),\n\t\t) as any\n\t\tepicshopConfig = pkg.epicshop ?? {}\n\t\tscripts = pkg.scripts ?? {}\n\t}\n\n\tconst AppConfigSchema = z.object({\n\t\tstackBlitzConfig: StackBlitzConfigSchema.nullable()\n\t\t\t.optional()\n\t\t\t.transform((appStackBlitzConfig) => {\n\t\t\t\tif (appStackBlitzConfig === null) return null\n\n\t\t\t\treturn {\n\t\t\t\t\t...workshopConfig.stackBlitzConfig,\n\t\t\t\t\t...appStackBlitzConfig,\n\t\t\t\t}\n\t\t\t}),\n\t\ttestTab: z\n\t\t\t.object({\n\t\t\t\tenabled: z\n\t\t\t\t\t.boolean()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.default(workshopConfig.testTab?.enabled ?? true),\n\t\t\t})\n\t\t\t.default({}),\n\t\tscripts: z\n\t\t\t.object({\n\t\t\t\ttest: z.string().optional(),\n\t\t\t\tdev: z.string().optional(),\n\t\t\t})\n\t\t\t.default({}),\n\t\tinitialRoute: z.string().optional().default(workshopConfig.initialRoute),\n\t})\n\n\tconst appConfig = {\n\t\tstackBlitzConfig: epicshopConfig.stackBlitzConfig,\n\t\ttestTab: {\n\t\t\tenabled: epicshopConfig.testTab?.enabled,\n\t\t},\n\t\tscripts: {\n\t\t\ttest: scripts.test,\n\t\t\tdev: scripts.dev,\n\t\t},\n\t\tinitialRoute: epicshopConfig.initialRoute,\n\t}\n\n\ttry {\n\t\treturn AppConfigSchema.parse(appConfig)\n\t} catch (error) {\n\t\tif (error instanceof z.ZodError) {\n\t\t\tconst flattenedErrors = error.flatten()\n\t\t\tconst errorMessages = Object.entries(flattenedErrors.fieldErrors)\n\t\t\t\t.map(([field, errors]) => `${field}: ${errors?.join(', ')}`)\n\t\t\t\t.concat(flattenedErrors.formErrors)\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid app configuration for ${fullPath}:\\n${errorMessages.join('\\n')}`,\n\t\t\t)\n\t\t}\n\t\tthrow error\n\t}\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  // eslint-disable-next-line import/order -- this must be first
2
- import { ENV } from './init-env.js';
2
+ import { getEnv } from './init-env.js';
3
3
  import os from 'os';
4
4
  import path from 'path';
5
5
  import { execa } from 'execa';
@@ -12,7 +12,7 @@ import { cachified, copyUnignoredFilesCache, diffCodeCache, diffFilesCache, } fr
12
12
  import { compileMarkdownString } from './compile-mdx.server.js';
13
13
  import { modifiedMoreRecentlyThan } from './modified-time.server.js';
14
14
  const epicshopTempDir = path.join(os.tmpdir(), 'epicshop');
15
- const isDeployed = ENV.EPICSHOP_DEPLOYED;
15
+ const isDeployed = getEnv().EPICSHOP_DEPLOYED;
16
16
  const diffTmpDir = path.join(epicshopTempDir, 'diff');
17
17
  /**
18
18
  * Converts a diff file path to a relative path for display and lookup.
@@ -1 +1 @@
1
- {"version":3,"file":"diff.server.js","sourceRoot":"","sources":["../../src/diff.server.ts"],"names":[],"mappings":"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","sourcesContent":["// eslint-disable-next-line import/order -- this must be first\nimport { ENV } from './init-env.js'\n\nimport os from 'os'\nimport path from 'path'\nimport { type CacheEntry } from '@epic-web/cachified'\nimport { execa } from 'execa'\nimport fsExtra from 'fs-extra'\nimport ignore from 'ignore'\nimport parseGitDiff, { type AnyFileChange } from 'parse-git-diff'\nimport { bundledLanguagesInfo } from 'shiki/langs'\nimport {\n\tgetForceFreshForDir,\n\tgetRelativePath,\n\tgetWorkshopRoot,\n\tmodifiedTimes,\n\ttype App,\n} from './apps.server.js'\nimport {\n\tcachified,\n\tcopyUnignoredFilesCache,\n\tdiffCodeCache,\n\tdiffFilesCache,\n} from './cache.server.js'\nimport { compileMarkdownString } from './compile-mdx.server.js'\nimport { modifiedMoreRecentlyThan } from './modified-time.server.js'\nimport { type Timings } from './timing.server.js'\n\nconst epicshopTempDir = path.join(os.tmpdir(), 'epicshop')\n\nconst isDeployed = ENV.EPICSHOP_DEPLOYED\n\nconst diffTmpDir = path.join(epicshopTempDir, 'diff')\n\n/**\n * Converts a diff file path to a relative path for display and lookup.\n * - Removes leading/trailing quotes.\n * - Strips diff prefixes like a/, b/, .\\a\\, .\\b\\, ./a/, ./b/ (for both POSIX and Windows).\n * - Normalizes the path separators.\n * - Removes the diff temp directory prefix and splits out the actual relative path.\n */\nfunction diffPathToRelative(filePath: string) {\n\tlet normalizedPath = path.normalize(\n\t\tfilePath\n\t\t\t.replace(/^[\"']|[\"']$/g, '')\n\t\t\t.replace(/^(\\.\\\\[ab]\\\\|\\.\\/[ab]\\/|[ab][\\\\/])/, ''),\n\t)\n\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\tconst [workshopRootDirname, appId, id, ...relativePath] = normalizedPath\n\t\t.replace(\n\t\t\tprocess.platform === 'win32' || normalizedPath.startsWith(path.sep)\n\t\t\t\t? `${diffTmpDir}${path.sep}`\n\t\t\t\t: `${diffTmpDir.slice(1)}${path.sep}`,\n\t\t\t'',\n\t\t)\n\t\t.split(path.sep)\n\n\treturn relativePath.join(path.sep)\n}\n\nfunction getLanguage(ext: string) {\n\treturn (\n\t\tbundledLanguagesInfo.find((l) => l.id === ext || l.aliases?.includes(ext))\n\t\t\t?.id ?? 'text'\n\t)\n}\n\nfunction getFileCodeblocks(\n\tfile: ReturnType<typeof parseGitDiff>['files'][number],\n\tfilePathApp1: string,\n\tfilePathApp2: string,\n\ttype: string,\n) {\n\tif (!file.chunks.length) {\n\t\treturn [\n\t\t\t`<p className=\"m-0 p-4 border-b text-muted-foreground\">No changes</p>`,\n\t\t]\n\t}\n\tconst filepath = diffPathToRelative(\n\t\tfile.type === 'RenamedFile' ? file.pathAfter : file.path,\n\t)\n\tconst extension = path.extname(filepath).slice(1)\n\tconst lang = getLanguage(extension)\n\tconst pathToCopy = file.type === 'RenamedFile' ? file.pathBefore : file.path\n\tconst relativePath = diffPathToRelative(pathToCopy)\n\tconst markdownLines = []\n\tfor (const chunk of file.chunks) {\n\t\tconst removedLineNumbers = []\n\t\tconst addedLineNumbers = []\n\t\tconst lines = []\n\t\tlet toStartLine = 0\n\t\tlet startLine = 1\n\t\tif (chunk.type === 'BinaryFilesChunk') {\n\t\t\tlines.push(\n\t\t\t\ttype === 'AddedFile'\n\t\t\t\t\t? `Binary file added`\n\t\t\t\t\t: type === 'DeletedFile'\n\t\t\t\t\t\t? 'Binary file deleted'\n\t\t\t\t\t\t: 'Binary file changed',\n\t\t\t)\n\t\t} else {\n\t\t\tstartLine =\n\t\t\t\tchunk.type === 'Chunk'\n\t\t\t\t\t? chunk.fromFileRange.start\n\t\t\t\t\t: chunk.type === 'CombinedChunk'\n\t\t\t\t\t\t? chunk.fromFileRangeA.start\n\t\t\t\t\t\t: 1\n\t\t\ttoStartLine = chunk.toFileRange.start\n\t\t\tfor (\n\t\t\t\tlet lineNumber = 0;\n\t\t\t\tlineNumber < chunk.changes.length;\n\t\t\t\tlineNumber++\n\t\t\t) {\n\t\t\t\tconst change = chunk.changes[lineNumber]\n\t\t\t\tif (!change) continue\n\t\t\t\tlines.push(change.content)\n\t\t\t\tswitch (change.type) {\n\t\t\t\t\tcase 'AddedLine': {\n\t\t\t\t\t\taddedLineNumbers.push(startLine + lineNumber)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'DeletedLine': {\n\t\t\t\t\t\tremovedLineNumbers.push(startLine + lineNumber)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst params = [\n\t\t\t['filename', relativePath.replace(/\\\\/g, '\\\\\\\\')],\n\t\t\t['start', startLine.toString()],\n\t\t\tremovedLineNumbers.length\n\t\t\t\t? ['remove', removedLineNumbers.join(',')]\n\t\t\t\t: null,\n\t\t\taddedLineNumbers.length ? ['add', addedLineNumbers.join(',')] : null,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t\t.join(' ')\n\n\t\tconst launchEditorClassName =\n\t\t\t'border hover:bg-foreground/20 rounded px-2 py-0.5 font-mono text-xs font-semibold'\n\n\t\tfunction launchEditor(appNum: number, line: number) {\n\t\t\tif (isDeployed) {\n\t\t\t\tif (type === 'DeletedFile' && appNum === 2) return ''\n\t\t\t\tif (type === 'AddedFile' && appNum === 1) return ''\n\t\t\t}\n\n\t\t\tconst label =\n\t\t\t\t(type === 'AddedFile' && appNum === 1) ||\n\t\t\t\t(type === 'DeletedFile' && appNum === 2)\n\t\t\t\t\t? `CREATE in APP ${appNum}`\n\t\t\t\t\t: `OPEN in APP ${appNum}`\n\t\t\tconst file = JSON.stringify(appNum === 1 ? filePathApp1 : filePathApp2)\n\t\t\tconst fixedTitle = getRelativePath(file)\n\n\t\t\treturn `\n<LaunchEditor file=${file} line={${line}}>\n\t<span title=\"${fixedTitle}\" className=\"${launchEditorClassName}\">${label}</span>\n</LaunchEditor>`\n\t\t}\n\n\t\tmarkdownLines.push(`\n<div className=\"relative\">\n\n\\`\\`\\`${lang} ${params}\n${lines.join('\\n')}\n\\`\\`\\`\n\n<div className=\"flex gap-4 absolute top-1 right-3 items-center\">\n\t${launchEditor(1, startLine)}\n\t<div className=\"display-alt-down flex gap-2\">\n\t\t<LaunchEditor file=${JSON.stringify(\n\t\t\tfilePathApp1,\n\t\t)} syncTo={{file: ${JSON.stringify(filePathApp2)}}}>\n\t\t\t<span className=\"block ${launchEditorClassName}\">\n\t\t\t\t<Icon name=\"ArrowLeft\" title=\"Copy app 2 file to app 1\" />\n\t\t\t</span>\n\t\t</LaunchEditor>\n\t\t<LaunchEditor file=${JSON.stringify(\n\t\t\tfilePathApp2,\n\t\t)} syncTo={{file: ${JSON.stringify(filePathApp1)}}}>\n\t\t\t<span className=\"block ${launchEditorClassName}\">\n\t\t\t\t<Icon name=\"ArrowRight\" title=\"Copy app 1 file to app 2\" />\n\t\t\t</span>\n\t\t</LaunchEditor>\n\t</div>\n\t${launchEditor(2, toStartLine)}\n</div>\n\n</div>\n`)\n\t}\n\treturn markdownLines\n}\n\nconst DEFAULT_IGNORE_PATTERNS = [\n\t'**/README.*',\n\t'**/package-lock.json',\n\t'**/.DS_Store',\n\t'**/.vscode',\n\t'**/.idea',\n\t'**/.git',\n\t'**/*.db',\n\t'**/epicshop/**',\n]\n\nasync function copyUnignoredFiles(\n\tsrcDir: string,\n\tdestDir: string,\n\tignoreList: Array<string>,\n) {\n\tconst key = `COPY_${srcDir}__${destDir}__${ignoreList.join('_')}`\n\tawait cachified({\n\t\tkey,\n\t\tcache: copyUnignoredFilesCache,\n\t\tforceFresh: await getForceFreshForDir(\n\t\t\tcopyUnignoredFilesCache.get(key),\n\t\t\tsrcDir,\n\t\t),\n\t\tasync getFreshValue() {\n\t\t\t// @ts-ignore 🤷‍♂️ weird module stuff\n\t\t\tconst ig = ignore().add(ignoreList)\n\n\t\t\tawait fsExtra.remove(destDir)\n\t\t\tawait fsExtra.copy(srcDir, destDir, {\n\t\t\t\tfilter: async (file) => {\n\t\t\t\t\tif (file === srcDir) return true\n\t\t\t\t\treturn !ig.ignores(path.relative(srcDir, file))\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t})\n}\n\nasync function prepareForDiff(app1: App, app2: App) {\n\tconst id = Math.random().toString(36).slice(2)\n\tconst app1CopyPath = path.join(\n\t\tdiffTmpDir,\n\t\tpath.basename(getWorkshopRoot()),\n\t\tapp1.name,\n\t\tid,\n\t)\n\tconst app2CopyPath = path.join(\n\t\tdiffTmpDir,\n\t\tpath.basename(getWorkshopRoot()),\n\t\tapp2.name,\n\t\tid,\n\t)\n\t// if everything except the `name` property of the `package.json` is the same\n\t// the don't bother copying it\n\tconst comparePkgJson = (pkg1: any, pkg2: any) => {\n\t\tconst { name, ...rest1 } = pkg1\n\t\tconst { name: name2, ...rest2 } = pkg2\n\t\treturn JSON.stringify(rest1) === JSON.stringify(rest2)\n\t}\n\tconst app1PkgJson =\n\t\tapp1.dev.type === 'script'\n\t\t\t? await fsExtra\n\t\t\t\t\t.readJSON(path.join(app1.fullPath, 'package.json'))\n\t\t\t\t\t.catch(() => ({}))\n\t\t\t: {}\n\tconst app2PkgJson =\n\t\tapp1.dev.type === 'script'\n\t\t\t? await fsExtra\n\t\t\t\t\t.readJSON(path.join(app2.fullPath, 'package.json'))\n\t\t\t\t\t.catch(() => ({}))\n\t\t\t: {}\n\tconst pkgJsonIgnore: Array<string> = comparePkgJson(app1PkgJson, app2PkgJson)\n\t\t? ['package.json']\n\t\t: []\n\tconst workshopIgnore = [\n\t\t...(await getDiffIgnore(path.join(getWorkshopRoot(), '.gitignore'))),\n\t\t...(await getDiffIgnore(\n\t\t\tpath.join(getWorkshopRoot(), 'epicshop', '.diffignore'),\n\t\t)),\n\t]\n\n\tawait Promise.all([\n\t\tcopyUnignoredFiles(app1.fullPath, app1CopyPath, [\n\t\t\t...DEFAULT_IGNORE_PATTERNS,\n\t\t\t...pkgJsonIgnore,\n\t\t\t...workshopIgnore,\n\t\t\t...(await getDiffIgnore(path.join(app1.fullPath, '.gitignore'))),\n\t\t\t...(await getDiffIgnore(\n\t\t\t\tpath.join(app1.fullPath, 'epicshop', '.diffignore'),\n\t\t\t)),\n\t\t]),\n\t\tcopyUnignoredFiles(app2.fullPath, app2CopyPath, [\n\t\t\t...DEFAULT_IGNORE_PATTERNS,\n\t\t\t...pkgJsonIgnore,\n\t\t\t...workshopIgnore,\n\t\t\t...(await getDiffIgnore(path.join(app2.fullPath, '.gitignore'))),\n\t\t\t...(await getDiffIgnore(\n\t\t\t\tpath.join(app2.fullPath, 'epicshop', '.diffignore'),\n\t\t\t)),\n\t\t]),\n\t])\n\n\treturn { app1CopyPath, app2CopyPath }\n}\n\nasync function getDiffIgnore(filePath: string): Promise<Array<string>> {\n\treturn (await fsExtra.pathExists(filePath))\n\t\t? fsExtra.readFile(filePath, 'utf8').then((content) =>\n\t\t\t\tcontent\n\t\t\t\t\t.split('\\n')\n\t\t\t\t\t.map((line) => line.trim())\n\t\t\t\t\t.filter((line) => !line.startsWith('#'))\n\t\t\t\t\t.filter(Boolean),\n\t\t\t)\n\t\t: []\n}\n\nasync function getForceFreshForDiff(\n\tapp1: App,\n\tapp2: App,\n\tcacheEntry:\n\t\t| CacheEntry\n\t\t| null\n\t\t| undefined\n\t\t| Promise<CacheEntry | null | undefined>,\n) {\n\t// don't know when the cache was created? force refresh\n\tconst resolvedCacheEntry = await cacheEntry\n\tconst cacheModified = resolvedCacheEntry?.metadata.createdTime\n\tif (!cacheModified) return true\n\n\t// app1 modified after cache? force refresh\n\tconst app1Modified = modifiedTimes.get(app1.fullPath) ?? 0\n\tif (app1Modified > cacheModified) return true\n\n\t// app2 modified after cache? force refresh\n\tconst app2Modified = modifiedTimes.get(app2.fullPath) ?? 0\n\tif (app2Modified > cacheModified) return true\n\n\t// ok, now let's actually check the modified times of all files in the\n\t// directories and as soon as we find a file that was modified more recently\n\t// then we know we need to force refresh\n\tconst modifiedMoreRecently = await modifiedMoreRecentlyThan(\n\t\tcacheModified,\n\t\tapp1.fullPath,\n\t\tapp2.fullPath,\n\t)\n\tif (modifiedMoreRecently) return true\n\n\treturn undefined\n}\n\nexport async function getDiffFiles(\n\tapp1: App,\n\tapp2: App,\n\t{\n\t\tforceFresh,\n\t\ttimings,\n\t\trequest,\n\t}: { forceFresh?: boolean; timings?: Timings; request?: Request } = {},\n) {\n\tconst key = `${app1.relativePath}__vs__${app2.relativePath}`\n\tconst cacheEntry = await diffFilesCache.get(key)\n\tconst result = await cachified({\n\t\tkey,\n\t\tcache: diffFilesCache,\n\t\tforceFresh:\n\t\t\tforceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),\n\t\ttimings,\n\t\trequest,\n\t\tgetFreshValue: () => getDiffFilesImpl(app1, app2),\n\t})\n\treturn result\n}\n\nfunction getAppTestFiles(app: App) {\n\treturn app.test.type === 'browser' ? app.test.testFiles : []\n}\n\nasync function getDiffFilesImpl(app1: App, app2: App) {\n\tif (app1.name === app2.name) {\n\t\treturn []\n\t}\n\tconst { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2)\n\n\tconst { stdout: diffOutput } = await execa(\n\t\t'git',\n\t\t[\n\t\t\t'diff',\n\t\t\t'--no-index',\n\t\t\t'--ignore-blank-lines',\n\t\t\t'--ignore-space-change',\n\t\t\tapp1CopyPath,\n\t\t\tapp2CopyPath,\n\t\t],\n\t\t{ cwd: diffTmpDir },\n\t\t// --no-index implies --exit-code, so we need to use the error output\n\t).catch((e) => e as { stdout: string })\n\n\tvoid fsExtra.remove(app1CopyPath)\n\tvoid fsExtra.remove(app2CopyPath)\n\n\tconst typesMap = {\n\t\tChangedFile: 'modified',\n\t\tAddedFile: 'added',\n\t\tDeletedFile: 'deleted',\n\t\tRenamedFile: 'renamed',\n\t}\n\n\tconst parsed = parseGitDiff(diffOutput, { noPrefix: true })\n\n\tconst testFiles = Array.from(\n\t\tnew Set([...getAppTestFiles(app1), ...getAppTestFiles(app2)]),\n\t)\n\n\tconst startLine = (file: AnyFileChange) => {\n\t\tconst chunk = file.type === 'ChangedFile' && file.chunks[0]\n\t\tif (chunk) {\n\t\t\treturn chunk.type === 'Chunk'\n\t\t\t\t? chunk.fromFileRange.start\n\t\t\t\t: chunk.type === 'CombinedChunk'\n\t\t\t\t\t? chunk.fromFileRangeA.start\n\t\t\t\t\t: 1\n\t\t}\n\t\treturn 1\n\t}\n\n\treturn parsed.files\n\t\t.map((file) => ({\n\t\t\t// prettier-ignore\n\n\t\t\tstatus: (typesMap[file.type] ?? 'unknown') as 'renamed' | 'modified' | 'deleted' | 'added' | 'unknown',\n\t\t\tpath: diffPathToRelative(\n\t\t\t\tfile.type === 'RenamedFile' ? file.pathBefore : file.path,\n\t\t\t),\n\t\t\tline: startLine(file),\n\t\t}))\n\t\t.filter((file) => !testFiles.includes(file.path))\n}\n\nexport async function getDiffCode(\n\tapp1: App,\n\tapp2: App,\n\t{\n\t\tforceFresh,\n\t\ttimings,\n\t\trequest,\n\t}: { forceFresh?: boolean; timings?: Timings; request?: Request } = {},\n) {\n\tconst key = `${app1.relativePath}__vs__${app2.relativePath}`\n\tconst cacheEntry = await diffCodeCache.get(key)\n\tconst result = await cachified({\n\t\tkey,\n\t\tcache: diffCodeCache,\n\t\tforceFresh:\n\t\t\tforceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),\n\t\ttimings,\n\t\trequest,\n\t\tgetFreshValue: () => getDiffCodeImpl(app1, app2),\n\t})\n\treturn result\n}\n\nasync function getDiffCodeImpl(app1: App, app2: App) {\n\tconst markdownLines = ['']\n\n\tif (app1.name === app2.name) {\n\t\tmarkdownLines.push(\n\t\t\t'<p className=\"p-4 text-center\">You are comparing the same app</p>',\n\t\t)\n\t\tconst code = await compileMarkdownString(markdownLines.join('\\n'))\n\t\treturn code\n\t}\n\n\tconst { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2)\n\n\tconst { stdout: diffOutput } = await execa(\n\t\t'git',\n\t\t[\n\t\t\t'diff',\n\t\t\t'--no-index',\n\t\t\tapp1CopyPath,\n\t\t\tapp2CopyPath,\n\t\t\t'--color=never',\n\t\t\t'--color-moved-ws=allow-indentation-change',\n\t\t\t'--no-prefix',\n\t\t\t'--ignore-blank-lines',\n\t\t\t'--ignore-space-change',\n\t\t],\n\t\t{ cwd: diffTmpDir },\n\t\t// --no-index implies --exit-code, so we need to use the error output\n\t).catch((e) => e as { stdout: string })\n\n\tvoid fsExtra.remove(app1CopyPath)\n\tvoid fsExtra.remove(app2CopyPath)\n\n\tconst parsed = parseGitDiff(diffOutput)\n\n\tif (!parsed.files.length) {\n\t\tmarkdownLines.push(\n\t\t\t'<div className=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">No changes</div>',\n\t\t)\n\t}\n\n\tconst app1TestFiles = getAppTestFiles(app1)\n\tconst app2TestFiles = getAppTestFiles(app2)\n\n\tfor (const file of parsed.files) {\n\t\tconst pathToCopy = file.type === 'RenamedFile' ? file.pathBefore : file.path\n\t\tconst relativePath = diffPathToRelative(pathToCopy)\n\t\tif (app1TestFiles.includes(relativePath)) continue\n\t\tconst filePathApp1 = path.join(app1.fullPath, relativePath)\n\n\t\tconst pathToApp2 = file.type === 'RenamedFile' ? file.pathAfter : file.path\n\t\tconst relativePathApp2 = diffPathToRelative(pathToApp2)\n\t\tif (app2TestFiles.includes(relativePathApp2)) continue\n\t\tconst filePathApp2 = path.join(app2.fullPath, relativePathApp2)\n\n\t\tswitch (file.type) {\n\t\t\tcase 'ChangedFile': {\n\t\t\t\tmarkdownLines.push(`\n\n<Accordion title=${JSON.stringify(relativePath)} variant=\"changed\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'DeletedFile': {\n\t\t\t\tmarkdownLines.push(`\n<Accordion title=${JSON.stringify(relativePath)} variant=\"deleted\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'RenamedFile': {\n\t\t\t\tconst relativeBefore = diffPathToRelative(file.pathBefore)\n\t\t\t\tconst relativeAfter = diffPathToRelative(file.pathAfter)\n\t\t\t\tconst title = JSON.stringify(`${relativeBefore} ▶️ ${relativeAfter}`)\n\t\t\t\tmarkdownLines.push(`\n<Accordion title=${title} variant=\"renamed\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'AddedFile': {\n\t\t\t\tmarkdownLines.push(`\n<Accordion title=${JSON.stringify(relativePath)} variant=\"added\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tconsole.error(file)\n\t\t\t\tthrow new Error(`Unknown file type: ${file}`)\n\t\t\t}\n\t\t}\n\t}\n\tconst code = await compileMarkdownString(markdownLines.join('\\n'))\n\treturn code\n}\n\nexport async function getDiffOutputWithRelativePaths(app1: App, app2: App) {\n\tconst { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2)\n\n\tconst { stdout: diffOutput } = await execa(\n\t\t'git',\n\t\t[\n\t\t\t'diff',\n\t\t\t'--no-index',\n\t\t\tapp1CopyPath,\n\t\t\tapp2CopyPath,\n\t\t\t'--color=never',\n\t\t\t'--color-moved-ws=allow-indentation-change',\n\t\t\t'--no-prefix',\n\t\t\t'--ignore-blank-lines',\n\t\t\t'--ignore-space-change',\n\t\t],\n\t\t{ cwd: diffTmpDir },\n\t\t// --no-index implies --exit-code, so we need to use the error output\n\t).catch((e) => e as { stdout: string })\n\n\tvoid fsExtra.remove(app1CopyPath)\n\tvoid fsExtra.remove(app2CopyPath)\n\n\treturn diffOutput\n\t\t.replaceAll(app1CopyPath.slice(1), '.')\n\t\t.replaceAll(app2CopyPath.slice(1), '.')\n}\n"]}
1
+ {"version":3,"file":"diff.server.js","sourceRoot":"","sources":["../../src/diff.server.ts"],"names":[],"mappings":"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","sourcesContent":["// eslint-disable-next-line import/order -- this must be first\nimport { getEnv } from './init-env.js'\n\nimport os from 'os'\nimport path from 'path'\nimport { type CacheEntry } from '@epic-web/cachified'\nimport { execa } from 'execa'\nimport fsExtra from 'fs-extra'\nimport ignore from 'ignore'\nimport parseGitDiff, { type AnyFileChange } from 'parse-git-diff'\nimport { bundledLanguagesInfo } from 'shiki/langs'\nimport {\n\tgetForceFreshForDir,\n\tgetRelativePath,\n\tgetWorkshopRoot,\n\tmodifiedTimes,\n\ttype App,\n} from './apps.server.js'\nimport {\n\tcachified,\n\tcopyUnignoredFilesCache,\n\tdiffCodeCache,\n\tdiffFilesCache,\n} from './cache.server.js'\nimport { compileMarkdownString } from './compile-mdx.server.js'\nimport { modifiedMoreRecentlyThan } from './modified-time.server.js'\nimport { type Timings } from './timing.server.js'\n\nconst epicshopTempDir = path.join(os.tmpdir(), 'epicshop')\n\nconst isDeployed = getEnv().EPICSHOP_DEPLOYED\n\nconst diffTmpDir = path.join(epicshopTempDir, 'diff')\n\n/**\n * Converts a diff file path to a relative path for display and lookup.\n * - Removes leading/trailing quotes.\n * - Strips diff prefixes like a/, b/, .\\a\\, .\\b\\, ./a/, ./b/ (for both POSIX and Windows).\n * - Normalizes the path separators.\n * - Removes the diff temp directory prefix and splits out the actual relative path.\n */\nfunction diffPathToRelative(filePath: string) {\n\tlet normalizedPath = path.normalize(\n\t\tfilePath\n\t\t\t.replace(/^[\"']|[\"']$/g, '')\n\t\t\t.replace(/^(\\.\\\\[ab]\\\\|\\.\\/[ab]\\/|[ab][\\\\/])/, ''),\n\t)\n\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\tconst [workshopRootDirname, appId, id, ...relativePath] = normalizedPath\n\t\t.replace(\n\t\t\tprocess.platform === 'win32' || normalizedPath.startsWith(path.sep)\n\t\t\t\t? `${diffTmpDir}${path.sep}`\n\t\t\t\t: `${diffTmpDir.slice(1)}${path.sep}`,\n\t\t\t'',\n\t\t)\n\t\t.split(path.sep)\n\n\treturn relativePath.join(path.sep)\n}\n\nfunction getLanguage(ext: string) {\n\treturn (\n\t\tbundledLanguagesInfo.find((l) => l.id === ext || l.aliases?.includes(ext))\n\t\t\t?.id ?? 'text'\n\t)\n}\n\nfunction getFileCodeblocks(\n\tfile: ReturnType<typeof parseGitDiff>['files'][number],\n\tfilePathApp1: string,\n\tfilePathApp2: string,\n\ttype: string,\n) {\n\tif (!file.chunks.length) {\n\t\treturn [\n\t\t\t`<p className=\"m-0 p-4 border-b text-muted-foreground\">No changes</p>`,\n\t\t]\n\t}\n\tconst filepath = diffPathToRelative(\n\t\tfile.type === 'RenamedFile' ? file.pathAfter : file.path,\n\t)\n\tconst extension = path.extname(filepath).slice(1)\n\tconst lang = getLanguage(extension)\n\tconst pathToCopy = file.type === 'RenamedFile' ? file.pathBefore : file.path\n\tconst relativePath = diffPathToRelative(pathToCopy)\n\tconst markdownLines = []\n\tfor (const chunk of file.chunks) {\n\t\tconst removedLineNumbers = []\n\t\tconst addedLineNumbers = []\n\t\tconst lines = []\n\t\tlet toStartLine = 0\n\t\tlet startLine = 1\n\t\tif (chunk.type === 'BinaryFilesChunk') {\n\t\t\tlines.push(\n\t\t\t\ttype === 'AddedFile'\n\t\t\t\t\t? `Binary file added`\n\t\t\t\t\t: type === 'DeletedFile'\n\t\t\t\t\t\t? 'Binary file deleted'\n\t\t\t\t\t\t: 'Binary file changed',\n\t\t\t)\n\t\t} else {\n\t\t\tstartLine =\n\t\t\t\tchunk.type === 'Chunk'\n\t\t\t\t\t? chunk.fromFileRange.start\n\t\t\t\t\t: chunk.type === 'CombinedChunk'\n\t\t\t\t\t\t? chunk.fromFileRangeA.start\n\t\t\t\t\t\t: 1\n\t\t\ttoStartLine = chunk.toFileRange.start\n\t\t\tfor (\n\t\t\t\tlet lineNumber = 0;\n\t\t\t\tlineNumber < chunk.changes.length;\n\t\t\t\tlineNumber++\n\t\t\t) {\n\t\t\t\tconst change = chunk.changes[lineNumber]\n\t\t\t\tif (!change) continue\n\t\t\t\tlines.push(change.content)\n\t\t\t\tswitch (change.type) {\n\t\t\t\t\tcase 'AddedLine': {\n\t\t\t\t\t\taddedLineNumbers.push(startLine + lineNumber)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'DeletedLine': {\n\t\t\t\t\t\tremovedLineNumbers.push(startLine + lineNumber)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst params = [\n\t\t\t['filename', relativePath.replace(/\\\\/g, '\\\\\\\\')],\n\t\t\t['start', startLine.toString()],\n\t\t\tremovedLineNumbers.length\n\t\t\t\t? ['remove', removedLineNumbers.join(',')]\n\t\t\t\t: null,\n\t\t\taddedLineNumbers.length ? ['add', addedLineNumbers.join(',')] : null,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t\t.join(' ')\n\n\t\tconst launchEditorClassName =\n\t\t\t'border hover:bg-foreground/20 rounded px-2 py-0.5 font-mono text-xs font-semibold'\n\n\t\tfunction launchEditor(appNum: number, line: number) {\n\t\t\tif (isDeployed) {\n\t\t\t\tif (type === 'DeletedFile' && appNum === 2) return ''\n\t\t\t\tif (type === 'AddedFile' && appNum === 1) return ''\n\t\t\t}\n\n\t\t\tconst label =\n\t\t\t\t(type === 'AddedFile' && appNum === 1) ||\n\t\t\t\t(type === 'DeletedFile' && appNum === 2)\n\t\t\t\t\t? `CREATE in APP ${appNum}`\n\t\t\t\t\t: `OPEN in APP ${appNum}`\n\t\t\tconst file = JSON.stringify(appNum === 1 ? filePathApp1 : filePathApp2)\n\t\t\tconst fixedTitle = getRelativePath(file)\n\n\t\t\treturn `\n<LaunchEditor file=${file} line={${line}}>\n\t<span title=\"${fixedTitle}\" className=\"${launchEditorClassName}\">${label}</span>\n</LaunchEditor>`\n\t\t}\n\n\t\tmarkdownLines.push(`\n<div className=\"relative\">\n\n\\`\\`\\`${lang} ${params}\n${lines.join('\\n')}\n\\`\\`\\`\n\n<div className=\"flex gap-4 absolute top-1 right-3 items-center\">\n\t${launchEditor(1, startLine)}\n\t<div className=\"display-alt-down flex gap-2\">\n\t\t<LaunchEditor file=${JSON.stringify(\n\t\t\tfilePathApp1,\n\t\t)} syncTo={{file: ${JSON.stringify(filePathApp2)}}}>\n\t\t\t<span className=\"block ${launchEditorClassName}\">\n\t\t\t\t<Icon name=\"ArrowLeft\" title=\"Copy app 2 file to app 1\" />\n\t\t\t</span>\n\t\t</LaunchEditor>\n\t\t<LaunchEditor file=${JSON.stringify(\n\t\t\tfilePathApp2,\n\t\t)} syncTo={{file: ${JSON.stringify(filePathApp1)}}}>\n\t\t\t<span className=\"block ${launchEditorClassName}\">\n\t\t\t\t<Icon name=\"ArrowRight\" title=\"Copy app 1 file to app 2\" />\n\t\t\t</span>\n\t\t</LaunchEditor>\n\t</div>\n\t${launchEditor(2, toStartLine)}\n</div>\n\n</div>\n`)\n\t}\n\treturn markdownLines\n}\n\nconst DEFAULT_IGNORE_PATTERNS = [\n\t'**/README.*',\n\t'**/package-lock.json',\n\t'**/.DS_Store',\n\t'**/.vscode',\n\t'**/.idea',\n\t'**/.git',\n\t'**/*.db',\n\t'**/epicshop/**',\n]\n\nasync function copyUnignoredFiles(\n\tsrcDir: string,\n\tdestDir: string,\n\tignoreList: Array<string>,\n) {\n\tconst key = `COPY_${srcDir}__${destDir}__${ignoreList.join('_')}`\n\tawait cachified({\n\t\tkey,\n\t\tcache: copyUnignoredFilesCache,\n\t\tforceFresh: await getForceFreshForDir(\n\t\t\tcopyUnignoredFilesCache.get(key),\n\t\t\tsrcDir,\n\t\t),\n\t\tasync getFreshValue() {\n\t\t\t// @ts-ignore 🤷‍♂️ weird module stuff\n\t\t\tconst ig = ignore().add(ignoreList)\n\n\t\t\tawait fsExtra.remove(destDir)\n\t\t\tawait fsExtra.copy(srcDir, destDir, {\n\t\t\t\tfilter: async (file) => {\n\t\t\t\t\tif (file === srcDir) return true\n\t\t\t\t\treturn !ig.ignores(path.relative(srcDir, file))\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t})\n}\n\nasync function prepareForDiff(app1: App, app2: App) {\n\tconst id = Math.random().toString(36).slice(2)\n\tconst app1CopyPath = path.join(\n\t\tdiffTmpDir,\n\t\tpath.basename(getWorkshopRoot()),\n\t\tapp1.name,\n\t\tid,\n\t)\n\tconst app2CopyPath = path.join(\n\t\tdiffTmpDir,\n\t\tpath.basename(getWorkshopRoot()),\n\t\tapp2.name,\n\t\tid,\n\t)\n\t// if everything except the `name` property of the `package.json` is the same\n\t// the don't bother copying it\n\tconst comparePkgJson = (pkg1: any, pkg2: any) => {\n\t\tconst { name, ...rest1 } = pkg1\n\t\tconst { name: name2, ...rest2 } = pkg2\n\t\treturn JSON.stringify(rest1) === JSON.stringify(rest2)\n\t}\n\tconst app1PkgJson =\n\t\tapp1.dev.type === 'script'\n\t\t\t? await fsExtra\n\t\t\t\t\t.readJSON(path.join(app1.fullPath, 'package.json'))\n\t\t\t\t\t.catch(() => ({}))\n\t\t\t: {}\n\tconst app2PkgJson =\n\t\tapp1.dev.type === 'script'\n\t\t\t? await fsExtra\n\t\t\t\t\t.readJSON(path.join(app2.fullPath, 'package.json'))\n\t\t\t\t\t.catch(() => ({}))\n\t\t\t: {}\n\tconst pkgJsonIgnore: Array<string> = comparePkgJson(app1PkgJson, app2PkgJson)\n\t\t? ['package.json']\n\t\t: []\n\tconst workshopIgnore = [\n\t\t...(await getDiffIgnore(path.join(getWorkshopRoot(), '.gitignore'))),\n\t\t...(await getDiffIgnore(\n\t\t\tpath.join(getWorkshopRoot(), 'epicshop', '.diffignore'),\n\t\t)),\n\t]\n\n\tawait Promise.all([\n\t\tcopyUnignoredFiles(app1.fullPath, app1CopyPath, [\n\t\t\t...DEFAULT_IGNORE_PATTERNS,\n\t\t\t...pkgJsonIgnore,\n\t\t\t...workshopIgnore,\n\t\t\t...(await getDiffIgnore(path.join(app1.fullPath, '.gitignore'))),\n\t\t\t...(await getDiffIgnore(\n\t\t\t\tpath.join(app1.fullPath, 'epicshop', '.diffignore'),\n\t\t\t)),\n\t\t]),\n\t\tcopyUnignoredFiles(app2.fullPath, app2CopyPath, [\n\t\t\t...DEFAULT_IGNORE_PATTERNS,\n\t\t\t...pkgJsonIgnore,\n\t\t\t...workshopIgnore,\n\t\t\t...(await getDiffIgnore(path.join(app2.fullPath, '.gitignore'))),\n\t\t\t...(await getDiffIgnore(\n\t\t\t\tpath.join(app2.fullPath, 'epicshop', '.diffignore'),\n\t\t\t)),\n\t\t]),\n\t])\n\n\treturn { app1CopyPath, app2CopyPath }\n}\n\nasync function getDiffIgnore(filePath: string): Promise<Array<string>> {\n\treturn (await fsExtra.pathExists(filePath))\n\t\t? fsExtra.readFile(filePath, 'utf8').then((content) =>\n\t\t\t\tcontent\n\t\t\t\t\t.split('\\n')\n\t\t\t\t\t.map((line) => line.trim())\n\t\t\t\t\t.filter((line) => !line.startsWith('#'))\n\t\t\t\t\t.filter(Boolean),\n\t\t\t)\n\t\t: []\n}\n\nasync function getForceFreshForDiff(\n\tapp1: App,\n\tapp2: App,\n\tcacheEntry:\n\t\t| CacheEntry\n\t\t| null\n\t\t| undefined\n\t\t| Promise<CacheEntry | null | undefined>,\n) {\n\t// don't know when the cache was created? force refresh\n\tconst resolvedCacheEntry = await cacheEntry\n\tconst cacheModified = resolvedCacheEntry?.metadata.createdTime\n\tif (!cacheModified) return true\n\n\t// app1 modified after cache? force refresh\n\tconst app1Modified = modifiedTimes.get(app1.fullPath) ?? 0\n\tif (app1Modified > cacheModified) return true\n\n\t// app2 modified after cache? force refresh\n\tconst app2Modified = modifiedTimes.get(app2.fullPath) ?? 0\n\tif (app2Modified > cacheModified) return true\n\n\t// ok, now let's actually check the modified times of all files in the\n\t// directories and as soon as we find a file that was modified more recently\n\t// then we know we need to force refresh\n\tconst modifiedMoreRecently = await modifiedMoreRecentlyThan(\n\t\tcacheModified,\n\t\tapp1.fullPath,\n\t\tapp2.fullPath,\n\t)\n\tif (modifiedMoreRecently) return true\n\n\treturn undefined\n}\n\nexport async function getDiffFiles(\n\tapp1: App,\n\tapp2: App,\n\t{\n\t\tforceFresh,\n\t\ttimings,\n\t\trequest,\n\t}: { forceFresh?: boolean; timings?: Timings; request?: Request } = {},\n) {\n\tconst key = `${app1.relativePath}__vs__${app2.relativePath}`\n\tconst cacheEntry = await diffFilesCache.get(key)\n\tconst result = await cachified({\n\t\tkey,\n\t\tcache: diffFilesCache,\n\t\tforceFresh:\n\t\t\tforceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),\n\t\ttimings,\n\t\trequest,\n\t\tgetFreshValue: () => getDiffFilesImpl(app1, app2),\n\t})\n\treturn result\n}\n\nfunction getAppTestFiles(app: App) {\n\treturn app.test.type === 'browser' ? app.test.testFiles : []\n}\n\nasync function getDiffFilesImpl(app1: App, app2: App) {\n\tif (app1.name === app2.name) {\n\t\treturn []\n\t}\n\tconst { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2)\n\n\tconst { stdout: diffOutput } = await execa(\n\t\t'git',\n\t\t[\n\t\t\t'diff',\n\t\t\t'--no-index',\n\t\t\t'--ignore-blank-lines',\n\t\t\t'--ignore-space-change',\n\t\t\tapp1CopyPath,\n\t\t\tapp2CopyPath,\n\t\t],\n\t\t{ cwd: diffTmpDir },\n\t\t// --no-index implies --exit-code, so we need to use the error output\n\t).catch((e) => e as { stdout: string })\n\n\tvoid fsExtra.remove(app1CopyPath)\n\tvoid fsExtra.remove(app2CopyPath)\n\n\tconst typesMap = {\n\t\tChangedFile: 'modified',\n\t\tAddedFile: 'added',\n\t\tDeletedFile: 'deleted',\n\t\tRenamedFile: 'renamed',\n\t}\n\n\tconst parsed = parseGitDiff(diffOutput, { noPrefix: true })\n\n\tconst testFiles = Array.from(\n\t\tnew Set([...getAppTestFiles(app1), ...getAppTestFiles(app2)]),\n\t)\n\n\tconst startLine = (file: AnyFileChange) => {\n\t\tconst chunk = file.type === 'ChangedFile' && file.chunks[0]\n\t\tif (chunk) {\n\t\t\treturn chunk.type === 'Chunk'\n\t\t\t\t? chunk.fromFileRange.start\n\t\t\t\t: chunk.type === 'CombinedChunk'\n\t\t\t\t\t? chunk.fromFileRangeA.start\n\t\t\t\t\t: 1\n\t\t}\n\t\treturn 1\n\t}\n\n\treturn parsed.files\n\t\t.map((file) => ({\n\t\t\t// prettier-ignore\n\n\t\t\tstatus: (typesMap[file.type] ?? 'unknown') as 'renamed' | 'modified' | 'deleted' | 'added' | 'unknown',\n\t\t\tpath: diffPathToRelative(\n\t\t\t\tfile.type === 'RenamedFile' ? file.pathBefore : file.path,\n\t\t\t),\n\t\t\tline: startLine(file),\n\t\t}))\n\t\t.filter((file) => !testFiles.includes(file.path))\n}\n\nexport async function getDiffCode(\n\tapp1: App,\n\tapp2: App,\n\t{\n\t\tforceFresh,\n\t\ttimings,\n\t\trequest,\n\t}: { forceFresh?: boolean; timings?: Timings; request?: Request } = {},\n) {\n\tconst key = `${app1.relativePath}__vs__${app2.relativePath}`\n\tconst cacheEntry = await diffCodeCache.get(key)\n\tconst result = await cachified({\n\t\tkey,\n\t\tcache: diffCodeCache,\n\t\tforceFresh:\n\t\t\tforceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),\n\t\ttimings,\n\t\trequest,\n\t\tgetFreshValue: () => getDiffCodeImpl(app1, app2),\n\t})\n\treturn result\n}\n\nasync function getDiffCodeImpl(app1: App, app2: App) {\n\tconst markdownLines = ['']\n\n\tif (app1.name === app2.name) {\n\t\tmarkdownLines.push(\n\t\t\t'<p className=\"p-4 text-center\">You are comparing the same app</p>',\n\t\t)\n\t\tconst code = await compileMarkdownString(markdownLines.join('\\n'))\n\t\treturn code\n\t}\n\n\tconst { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2)\n\n\tconst { stdout: diffOutput } = await execa(\n\t\t'git',\n\t\t[\n\t\t\t'diff',\n\t\t\t'--no-index',\n\t\t\tapp1CopyPath,\n\t\t\tapp2CopyPath,\n\t\t\t'--color=never',\n\t\t\t'--color-moved-ws=allow-indentation-change',\n\t\t\t'--no-prefix',\n\t\t\t'--ignore-blank-lines',\n\t\t\t'--ignore-space-change',\n\t\t],\n\t\t{ cwd: diffTmpDir },\n\t\t// --no-index implies --exit-code, so we need to use the error output\n\t).catch((e) => e as { stdout: string })\n\n\tvoid fsExtra.remove(app1CopyPath)\n\tvoid fsExtra.remove(app2CopyPath)\n\n\tconst parsed = parseGitDiff(diffOutput)\n\n\tif (!parsed.files.length) {\n\t\tmarkdownLines.push(\n\t\t\t'<div className=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">No changes</div>',\n\t\t)\n\t}\n\n\tconst app1TestFiles = getAppTestFiles(app1)\n\tconst app2TestFiles = getAppTestFiles(app2)\n\n\tfor (const file of parsed.files) {\n\t\tconst pathToCopy = file.type === 'RenamedFile' ? file.pathBefore : file.path\n\t\tconst relativePath = diffPathToRelative(pathToCopy)\n\t\tif (app1TestFiles.includes(relativePath)) continue\n\t\tconst filePathApp1 = path.join(app1.fullPath, relativePath)\n\n\t\tconst pathToApp2 = file.type === 'RenamedFile' ? file.pathAfter : file.path\n\t\tconst relativePathApp2 = diffPathToRelative(pathToApp2)\n\t\tif (app2TestFiles.includes(relativePathApp2)) continue\n\t\tconst filePathApp2 = path.join(app2.fullPath, relativePathApp2)\n\n\t\tswitch (file.type) {\n\t\t\tcase 'ChangedFile': {\n\t\t\t\tmarkdownLines.push(`\n\n<Accordion title=${JSON.stringify(relativePath)} variant=\"changed\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'DeletedFile': {\n\t\t\t\tmarkdownLines.push(`\n<Accordion title=${JSON.stringify(relativePath)} variant=\"deleted\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'RenamedFile': {\n\t\t\t\tconst relativeBefore = diffPathToRelative(file.pathBefore)\n\t\t\t\tconst relativeAfter = diffPathToRelative(file.pathAfter)\n\t\t\t\tconst title = JSON.stringify(`${relativeBefore} ▶️ ${relativeAfter}`)\n\t\t\t\tmarkdownLines.push(`\n<Accordion title=${title} variant=\"renamed\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'AddedFile': {\n\t\t\t\tmarkdownLines.push(`\n<Accordion title=${JSON.stringify(relativePath)} variant=\"added\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tconsole.error(file)\n\t\t\t\tthrow new Error(`Unknown file type: ${file}`)\n\t\t\t}\n\t\t}\n\t}\n\tconst code = await compileMarkdownString(markdownLines.join('\\n'))\n\treturn code\n}\n\nexport async function getDiffOutputWithRelativePaths(app1: App, app2: App) {\n\tconst { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2)\n\n\tconst { stdout: diffOutput } = await execa(\n\t\t'git',\n\t\t[\n\t\t\t'diff',\n\t\t\t'--no-index',\n\t\t\tapp1CopyPath,\n\t\t\tapp2CopyPath,\n\t\t\t'--color=never',\n\t\t\t'--color-moved-ws=allow-indentation-change',\n\t\t\t'--no-prefix',\n\t\t\t'--ignore-blank-lines',\n\t\t\t'--ignore-space-change',\n\t\t],\n\t\t{ cwd: diffTmpDir },\n\t\t// --no-index implies --exit-code, so we need to use the error output\n\t).catch((e) => e as { stdout: string })\n\n\tvoid fsExtra.remove(app1CopyPath)\n\tvoid fsExtra.remove(app2CopyPath)\n\n\treturn diffOutput\n\t\t.replaceAll(app1CopyPath.slice(1), '.')\n\t\t.replaceAll(app2CopyPath.slice(1), '.')\n}\n"]}
@@ -5,7 +5,7 @@ declare const schema: z.ZodEffects<z.ZodObject<{
5
5
  NODE_ENV: z.ZodDefault<z.ZodEnum<["production", "development", "test"]>>;
6
6
  EPICSHOP_GITHUB_REPO: z.ZodDefault<z.ZodString>;
7
7
  EPICSHOP_GITHUB_ROOT: z.ZodDefault<z.ZodString>;
8
- EPICSHOP_APP_VERSION: z.ZodDefault<z.ZodString>;
8
+ EPICSHOP_APP_VERSION: z.ZodOptional<z.ZodString>;
9
9
  EPICSHOP_PARENT_PORT: z.ZodOptional<z.ZodString>;
10
10
  EPICSHOP_PARENT_TOKEN: z.ZodOptional<z.ZodString>;
11
11
  EPICSHOP_APP_LOCATION: z.ZodOptional<z.ZodString>;
@@ -21,13 +21,13 @@ declare const schema: z.ZodEffects<z.ZodObject<{
21
21
  NODE_ENV: "production" | "development" | "test";
22
22
  EPICSHOP_GITHUB_REPO: string;
23
23
  EPICSHOP_GITHUB_ROOT: string;
24
- EPICSHOP_APP_VERSION: string;
25
24
  EPICSHOP_HOME_DIR: string;
26
25
  EPICSHOP_IS_PUBLISHED: string;
27
26
  SENTRY_DSN: string;
28
27
  SENTRY_ORG: string;
29
28
  SENTRY_PROJECT: string;
30
29
  SENTRY_PROJECT_ID: string;
30
+ EPICSHOP_APP_VERSION?: string | undefined;
31
31
  EPICSHOP_PARENT_PORT?: string | undefined;
32
32
  EPICSHOP_PARENT_TOKEN?: string | undefined;
33
33
  EPICSHOP_APP_LOCATION?: string | undefined;
@@ -53,13 +53,13 @@ declare const schema: z.ZodEffects<z.ZodObject<{
53
53
  NODE_ENV: "production" | "development" | "test";
54
54
  EPICSHOP_GITHUB_REPO: string;
55
55
  EPICSHOP_GITHUB_ROOT: string;
56
- EPICSHOP_APP_VERSION: string;
57
56
  EPICSHOP_HOME_DIR: string;
58
57
  EPICSHOP_IS_PUBLISHED: string;
59
58
  SENTRY_DSN: string;
60
59
  SENTRY_ORG: string;
61
60
  SENTRY_PROJECT: string;
62
61
  SENTRY_PROJECT_ID: string;
62
+ EPICSHOP_APP_VERSION?: string | undefined;
63
63
  EPICSHOP_PARENT_PORT?: string | undefined;
64
64
  EPICSHOP_PARENT_TOKEN?: string | undefined;
65
65
  EPICSHOP_APP_LOCATION?: string | undefined;
@@ -103,7 +103,7 @@ export declare function getEnv(): {
103
103
  EPICSHOP_GITHUB_REPO: string;
104
104
  EPICSHOP_GITHUB_ROOT: string;
105
105
  EPICSHOP_DEPLOYED: boolean;
106
- EPICSHOP_APP_VERSION: string;
106
+ EPICSHOP_APP_VERSION: string | undefined;
107
107
  EPICSHOP_PARENT_PORT: string | undefined;
108
108
  EPICSHOP_PARENT_TOKEN: string | undefined;
109
109
  EPICSHOP_IS_PUBLISHED: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"env.server.d.ts","sourceRoot":"","sources":["../../src/env.server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAKvB,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwET,CAAA;AAuBH,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM,CAAC;QAChB,UAAU,UAAW,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC;SAAG;KACtD;CACD;AAED,wBAAsB,IAAI,kBAazB;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM;;;;;;;;;;;;;EAiBrB;AAED,KAAK,GAAG,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAA;AAEpC,OAAO,CAAC,MAAM,CAAC;IACd,IAAI,GAAG,EAAE,GAAG,CAAA;IACZ,UAAU,MAAM;QACf,GAAG,EAAE,GAAG,CAAA;KACR;CACD"}
1
+ {"version":3,"file":"env.server.d.ts","sourceRoot":"","sources":["../../src/env.server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAKvB,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+ET,CAAA;AAuBH,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM,CAAC;QAChB,UAAU,UAAW,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC;SAAG;KACtD;CACD;AAED,wBAAsB,IAAI,kBAazB;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM;;;;;;;;;;;;;EAiBrB;AAED,KAAK,GAAG,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAA;AAEpC,OAAO,CAAC,MAAM,CAAC;IACd,IAAI,GAAG,EAAE,GAAG,CAAA;IACZ,UAAU,MAAM;QACf,GAAG,EAAE,GAAG,CAAA;KACR;CACD"}
@@ -15,7 +15,7 @@ const schema = z
15
15
  .default('development'),
16
16
  EPICSHOP_GITHUB_REPO: z.string().default(''),
17
17
  EPICSHOP_GITHUB_ROOT: z.string().default(''),
18
- EPICSHOP_APP_VERSION: z.string().default('0.0.0-unknown'),
18
+ EPICSHOP_APP_VERSION: z.string().optional(),
19
19
  EPICSHOP_PARENT_PORT: z.string().optional(),
20
20
  EPICSHOP_PARENT_TOKEN: z.string().optional(),
21
21
  EPICSHOP_APP_LOCATION: z.string().optional(),
@@ -33,33 +33,42 @@ const schema = z
33
33
  })
34
34
  .transform(async (env) => {
35
35
  if (env.EPICSHOP_CONTEXT_CWD === '') {
36
- env.EPICSHOP_CONTEXT_CWD = await getEpicshopContextCwd();
36
+ const contextCwd = await getEpicshopContextCwd();
37
+ if (contextCwd) {
38
+ env.EPICSHOP_CONTEXT_CWD = contextCwd;
39
+ }
37
40
  }
38
41
  if (env.EPICSHOP_WORKSHOP_INSTANCE_ID === '') {
39
42
  env.EPICSHOP_WORKSHOP_INSTANCE_ID = md5(env.EPICSHOP_CONTEXT_CWD);
40
43
  }
41
- const pkgJsonPath = path.join(env.EPICSHOP_CONTEXT_CWD, 'package.json');
42
- const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf-8'));
43
- const epicshopConfig = pkgJson.epicshop ?? {};
44
- if (!epicshopConfig) {
45
- throw new Error(`No epicshop configuration found in "${pkgJsonPath}". If this is a workshop directory, please add an "epicshop" section to your package.json. If this is not a workshop directory, please set the EPICSHOP_CONTEXT_CWD environment variable to the directory containing your package.json with the "epicshop" config section.`);
44
+ if (env.EPICSHOP_CONTEXT_CWD) {
45
+ const pkgJsonPath = path.join(env.EPICSHOP_CONTEXT_CWD, 'package.json');
46
+ const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf-8'));
47
+ const epicshopConfig = pkgJson.epicshop;
48
+ if (!env.EPICSHOP_GITHUB_REPO || !env.EPICSHOP_GITHUB_ROOT) {
49
+ const { githubRepo, githubRoot } = handleGitHubRepoAndRoot({
50
+ githubRepo: epicshopConfig.githubRepo,
51
+ githubRoot: epicshopConfig.githubRoot,
52
+ });
53
+ env.EPICSHOP_GITHUB_REPO = githubRepo;
54
+ env.EPICSHOP_GITHUB_ROOT = githubRoot;
55
+ }
46
56
  }
47
57
  if (env.EPICSHOP_APP_LOCATION === undefined) {
48
- const workshopAppPath = import.meta.resolve('@epic-web/workshop-app/package.json');
49
- const packagePath = fileURLToPath(workshopAppPath);
50
- env.EPICSHOP_APP_LOCATION = path.dirname(packagePath);
51
- }
52
- if (env.EPICSHOP_APP_VERSION === '0.0.0-unknown') {
53
- const packageJson = JSON.parse(await fs.readFile(path.join(env.EPICSHOP_APP_LOCATION, 'package.json'), 'utf-8'));
54
- env.EPICSHOP_APP_VERSION = packageJson.version;
58
+ try {
59
+ const workshopAppPath = import.meta.resolve('@epic-web/workshop-app/package.json');
60
+ const packagePath = fileURLToPath(workshopAppPath);
61
+ env.EPICSHOP_APP_LOCATION = path.dirname(packagePath);
62
+ }
63
+ catch {
64
+ // we may be running outside the context of a workshop app
65
+ }
55
66
  }
56
- if (!env.EPICSHOP_GITHUB_REPO || !env.EPICSHOP_GITHUB_ROOT) {
57
- const { githubRepo, githubRoot } = handleGitHubRepoAndRoot({
58
- githubRepo: epicshopConfig.githubRepo,
59
- githubRoot: epicshopConfig.githubRoot,
60
- });
61
- env.EPICSHOP_GITHUB_REPO = githubRepo;
62
- env.EPICSHOP_GITHUB_ROOT = githubRoot;
67
+ if (!env.EPICSHOP_APP_VERSION) {
68
+ if (env.EPICSHOP_APP_LOCATION) {
69
+ const packageJson = JSON.parse(await fs.readFile(path.join(env.EPICSHOP_APP_LOCATION, 'package.json'), 'utf-8'));
70
+ env.EPICSHOP_APP_VERSION = packageJson.version;
71
+ }
63
72
  }
64
73
  return env;
65
74
  });
@@ -83,7 +92,7 @@ async function getEpicshopContextCwd() {
83
92
  break;
84
93
  dir = parentDir;
85
94
  }
86
- return process.cwd();
95
+ return null;
87
96
  }
88
97
  export async function init() {
89
98
  const parsed = await schema.safeParseAsync(process.env);