@epic-web/workshop-utils 0.0.0-semantically-released

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +3 -0
  2. package/dist/esm/apps.server.d.ts +4205 -0
  3. package/dist/esm/apps.server.d.ts.map +1 -0
  4. package/dist/esm/apps.server.js +1198 -0
  5. package/dist/esm/apps.server.js.map +1 -0
  6. package/dist/esm/cache.server.d.ts +940 -0
  7. package/dist/esm/cache.server.d.ts.map +1 -0
  8. package/dist/esm/cache.server.js +161 -0
  9. package/dist/esm/cache.server.js.map +1 -0
  10. package/dist/esm/compile-mdx.server.d.ts +12 -0
  11. package/dist/esm/compile-mdx.server.d.ts.map +1 -0
  12. package/dist/esm/compile-mdx.server.js +285 -0
  13. package/dist/esm/compile-mdx.server.js.map +1 -0
  14. package/dist/esm/config.server.d.ts +348 -0
  15. package/dist/esm/config.server.d.ts.map +1 -0
  16. package/dist/esm/config.server.js +231 -0
  17. package/dist/esm/config.server.js.map +1 -0
  18. package/dist/esm/db.server.d.ts +463 -0
  19. package/dist/esm/db.server.d.ts.map +1 -0
  20. package/dist/esm/db.server.js +260 -0
  21. package/dist/esm/db.server.js.map +1 -0
  22. package/dist/esm/diff.server.d.ts +18 -0
  23. package/dist/esm/diff.server.d.ts.map +1 -0
  24. package/dist/esm/diff.server.js +437 -0
  25. package/dist/esm/diff.server.js.map +1 -0
  26. package/dist/esm/env.server.d.ts +61 -0
  27. package/dist/esm/env.server.d.ts.map +1 -0
  28. package/dist/esm/env.server.js +42 -0
  29. package/dist/esm/env.server.js.map +1 -0
  30. package/dist/esm/epic-api.server.d.ts +227 -0
  31. package/dist/esm/epic-api.server.d.ts.map +1 -0
  32. package/dist/esm/epic-api.server.js +529 -0
  33. package/dist/esm/epic-api.server.js.map +1 -0
  34. package/dist/esm/git.server.d.ts +49 -0
  35. package/dist/esm/git.server.d.ts.map +1 -0
  36. package/dist/esm/git.server.js +135 -0
  37. package/dist/esm/git.server.js.map +1 -0
  38. package/dist/esm/iframe-sync.d.ts +10 -0
  39. package/dist/esm/iframe-sync.d.ts.map +1 -0
  40. package/dist/esm/iframe-sync.js +97 -0
  41. package/dist/esm/iframe-sync.js.map +1 -0
  42. package/dist/esm/modified-time.server.d.ts +7 -0
  43. package/dist/esm/modified-time.server.d.ts.map +1 -0
  44. package/dist/esm/modified-time.server.js +80 -0
  45. package/dist/esm/modified-time.server.js.map +1 -0
  46. package/dist/esm/notifications.server.d.ts +56 -0
  47. package/dist/esm/notifications.server.d.ts.map +1 -0
  48. package/dist/esm/notifications.server.js +65 -0
  49. package/dist/esm/notifications.server.js.map +1 -0
  50. package/dist/esm/package.json +3 -0
  51. package/dist/esm/playwright.server.d.ts +6 -0
  52. package/dist/esm/playwright.server.d.ts.map +1 -0
  53. package/dist/esm/playwright.server.js +95 -0
  54. package/dist/esm/playwright.server.js.map +1 -0
  55. package/dist/esm/process-manager.server.d.ts +77 -0
  56. package/dist/esm/process-manager.server.d.ts.map +1 -0
  57. package/dist/esm/process-manager.server.js +266 -0
  58. package/dist/esm/process-manager.server.js.map +1 -0
  59. package/dist/esm/test.d.ts +16 -0
  60. package/dist/esm/test.d.ts.map +1 -0
  61. package/dist/esm/test.js +56 -0
  62. package/dist/esm/test.js.map +1 -0
  63. package/dist/esm/timing.server.d.ts +20 -0
  64. package/dist/esm/timing.server.d.ts.map +1 -0
  65. package/dist/esm/timing.server.js +88 -0
  66. package/dist/esm/timing.server.js.map +1 -0
  67. package/dist/esm/user.server.d.ts +17 -0
  68. package/dist/esm/user.server.d.ts.map +1 -0
  69. package/dist/esm/user.server.js +38 -0
  70. package/dist/esm/user.server.js.map +1 -0
  71. package/dist/esm/utils.d.ts +2 -0
  72. package/dist/esm/utils.d.ts.map +1 -0
  73. package/dist/esm/utils.js +13 -0
  74. package/dist/esm/utils.js.map +1 -0
  75. package/dist/esm/utils.server.d.ts +9 -0
  76. package/dist/esm/utils.server.d.ts.map +1 -0
  77. package/dist/esm/utils.server.js +45 -0
  78. package/dist/esm/utils.server.js.map +1 -0
  79. package/package.json +221 -0
@@ -0,0 +1,437 @@
1
+ import os from 'os';
2
+ import path from 'path';
3
+ import { execa } from 'execa';
4
+ import fsExtra from 'fs-extra';
5
+ import ignore from 'ignore';
6
+ import parseGitDiff from 'parse-git-diff';
7
+ import { bundledLanguagesInfo } from 'shiki/langs';
8
+ import { getForceFreshForDir, getRelativePath, getWorkshopRoot, modifiedTimes, } from './apps.server.js';
9
+ import { cachified, diffCodeCache, diffFilesCache } from './cache.server.js';
10
+ import { compileMarkdownString } from './compile-mdx.server.js';
11
+ import { modifiedMoreRecentlyThan } from './modified-time.server.js';
12
+ const epicshopTempDir = path.join(os.tmpdir(), 'epicshop');
13
+ const isDeployed = ENV.EPICSHOP_DEPLOYED;
14
+ const diffTmpDir = path.join(epicshopTempDir, 'diff');
15
+ function diffPathToRelative(filePath) {
16
+ let normalizedPath = path.normalize(filePath.replace(/^("|')|("|')$/g, ''));
17
+ if (normalizedPath.startsWith('a\\') ||
18
+ normalizedPath.startsWith('b\\') ||
19
+ normalizedPath.startsWith('a/') ||
20
+ normalizedPath.startsWith('b/')) {
21
+ normalizedPath = normalizedPath.slice(2);
22
+ }
23
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
24
+ const [workshopRootDirname, appId, id, ...relativePath] = normalizedPath
25
+ .replace(process.platform === 'win32' || normalizedPath.startsWith(path.sep)
26
+ ? `${diffTmpDir}${path.sep}`
27
+ : `${diffTmpDir.slice(1)}${path.sep}`, '')
28
+ .split(path.sep);
29
+ return relativePath.join(path.sep);
30
+ }
31
+ function getLanguage(ext) {
32
+ return (bundledLanguagesInfo.find((l) => l.id === ext || l.aliases?.includes(ext))
33
+ ?.id ?? 'text');
34
+ }
35
+ function getFileCodeblocks(file, filePathApp1, filePathApp2, type) {
36
+ if (!file.chunks.length) {
37
+ return [
38
+ `<p className="m-0 p-4 border-b text-muted-foreground">No changes</p>`,
39
+ ];
40
+ }
41
+ const filepath = diffPathToRelative(file.type === 'RenamedFile' ? file.pathAfter : file.path);
42
+ const extension = path.extname(filepath).slice(1);
43
+ const lang = getLanguage(extension);
44
+ const pathToCopy = file.type === 'RenamedFile' ? file.pathBefore : file.path;
45
+ const relativePath = diffPathToRelative(pathToCopy);
46
+ const markdownLines = [];
47
+ for (const chunk of file.chunks) {
48
+ const removedLineNumbers = [];
49
+ const addedLineNumbers = [];
50
+ const lines = [];
51
+ let toStartLine = 0;
52
+ let startLine = 1;
53
+ if (chunk.type === 'BinaryFilesChunk') {
54
+ lines.push(type === 'AddedFile'
55
+ ? `Binary file added`
56
+ : type === 'DeletedFile'
57
+ ? 'Binary file deleted'
58
+ : 'Binary file changed');
59
+ }
60
+ else {
61
+ startLine =
62
+ chunk.type === 'Chunk'
63
+ ? chunk.fromFileRange.start
64
+ : chunk.type === 'CombinedChunk'
65
+ ? chunk.fromFileRangeA.start
66
+ : 1;
67
+ toStartLine = chunk.toFileRange.start;
68
+ for (let lineNumber = 0; lineNumber < chunk.changes.length; lineNumber++) {
69
+ const change = chunk.changes[lineNumber];
70
+ if (!change)
71
+ continue;
72
+ lines.push(change.content);
73
+ switch (change.type) {
74
+ case 'AddedLine': {
75
+ addedLineNumbers.push(startLine + lineNumber);
76
+ break;
77
+ }
78
+ case 'DeletedLine': {
79
+ removedLineNumbers.push(startLine + lineNumber);
80
+ break;
81
+ }
82
+ default: {
83
+ break;
84
+ }
85
+ }
86
+ }
87
+ }
88
+ const params = [
89
+ ['filename', relativePath.replace(/\\/g, '\\\\')],
90
+ ['start', startLine.toString()],
91
+ removedLineNumbers.length
92
+ ? ['remove', removedLineNumbers.join(',')]
93
+ : null,
94
+ addedLineNumbers.length ? ['add', addedLineNumbers.join(',')] : null,
95
+ ]
96
+ .filter(Boolean)
97
+ .map(([key, value]) => `${key}=${value}`)
98
+ .join(' ');
99
+ const launchEditorClassName = 'border hover:bg-foreground/20 rounded px-2 py-0.5 font-mono text-xs font-semibold';
100
+ function launchEditor(appNum, line) {
101
+ if (isDeployed) {
102
+ if (type === 'DeletedFile' && appNum === 2)
103
+ return '';
104
+ if (type === 'AddedFile' && appNum === 1)
105
+ return '';
106
+ }
107
+ const label = (type === 'AddedFile' && appNum === 1) ||
108
+ (type === 'DeletedFile' && appNum === 2)
109
+ ? `CREATE in APP ${appNum}`
110
+ : `OPEN in APP ${appNum}`;
111
+ const file = JSON.stringify(appNum === 1 ? filePathApp1 : filePathApp2);
112
+ const fixedTitle = getRelativePath(file);
113
+ return `
114
+ <LaunchEditor file=${file} line={${line}}>
115
+ <span title="${fixedTitle}" className="${launchEditorClassName}">${label}</span>
116
+ </LaunchEditor>`;
117
+ }
118
+ markdownLines.push(`
119
+ <div className="relative">
120
+
121
+ \`\`\`${lang} ${params}
122
+ ${lines.join('\n')}
123
+ \`\`\`
124
+
125
+ <div className="flex gap-4 absolute top-1 right-3 items-center">
126
+ ${launchEditor(1, startLine)}
127
+ <div className="display-alt-down flex gap-2">
128
+ <LaunchEditor file=${JSON.stringify(filePathApp1)} syncTo={{file: ${JSON.stringify(filePathApp2)}}}>
129
+ <span className="block ${launchEditorClassName}">
130
+ <Icon name="ArrowLeft" title="Copy app 2 file to app 1" />
131
+ </span>
132
+ </LaunchEditor>
133
+ <LaunchEditor file=${JSON.stringify(filePathApp2)} syncTo={{file: ${JSON.stringify(filePathApp1)}}}>
134
+ <span className="block ${launchEditorClassName}">
135
+ <Icon name="ArrowRight" title="Copy app 1 file to app 2" />
136
+ </span>
137
+ </LaunchEditor>
138
+ </div>
139
+ ${launchEditor(2, toStartLine)}
140
+ </div>
141
+
142
+ </div>
143
+ `);
144
+ }
145
+ return markdownLines;
146
+ }
147
+ const DEFAULT_IGNORE_PATTERNS = [
148
+ '**/README.*',
149
+ '**/package-lock.json',
150
+ '**/.DS_Store',
151
+ '**/.vscode',
152
+ '**/.idea',
153
+ '**/.git',
154
+ '**/*.db',
155
+ '**/epicshop/**',
156
+ ];
157
+ async function copyUnignoredFiles(srcDir, destDir, ignoreList) {
158
+ const key = `COPY_${srcDir}__${destDir}__${ignoreList.join('_')}`;
159
+ await cachified({
160
+ key,
161
+ cache: diffCodeCache,
162
+ forceFresh: getForceFreshForDir(diffCodeCache.get(key), srcDir),
163
+ async getFreshValue() {
164
+ // @ts-ignore 🤷‍♂️ weird module stuff
165
+ const ig = ignore().add(ignoreList);
166
+ await fsExtra.remove(destDir);
167
+ await fsExtra.copy(srcDir, destDir, {
168
+ filter: async (file) => {
169
+ if (file === srcDir)
170
+ return true;
171
+ return !ig.ignores(path.relative(srcDir, file));
172
+ },
173
+ });
174
+ },
175
+ });
176
+ }
177
+ async function prepareForDiff(app1, app2) {
178
+ const id = Math.random().toString(36).slice(2);
179
+ const app1CopyPath = path.join(diffTmpDir, path.basename(getWorkshopRoot()), app1.name, id);
180
+ const app2CopyPath = path.join(diffTmpDir, path.basename(getWorkshopRoot()), app2.name, id);
181
+ // if everything except the `name` property of the `package.json` is the same
182
+ // the don't bother copying it
183
+ const comparePkgJson = (pkg1, pkg2) => {
184
+ const { name, ...rest1 } = pkg1;
185
+ const { name: name2, ...rest2 } = pkg2;
186
+ return JSON.stringify(rest1) === JSON.stringify(rest2);
187
+ };
188
+ const app1PkgJson = app1.dev.type === 'script'
189
+ ? await fsExtra
190
+ .readJSON(path.join(app1.fullPath, 'package.json'))
191
+ .catch(() => ({}))
192
+ : {};
193
+ const app2PkgJson = app1.dev.type === 'script'
194
+ ? await fsExtra
195
+ .readJSON(path.join(app2.fullPath, 'package.json'))
196
+ .catch(() => ({}))
197
+ : {};
198
+ const pkgJsonIgnore = comparePkgJson(app1PkgJson, app2PkgJson)
199
+ ? ['package.json']
200
+ : [];
201
+ const workshopIgnore = [
202
+ ...(await getDiffIgnore(path.join(getWorkshopRoot(), '.gitignore'))),
203
+ ...(await getDiffIgnore(path.join(getWorkshopRoot(), 'epicshop', '.diffignore'))),
204
+ ];
205
+ await Promise.all([
206
+ copyUnignoredFiles(app1.fullPath, app1CopyPath, [
207
+ ...DEFAULT_IGNORE_PATTERNS,
208
+ ...pkgJsonIgnore,
209
+ ...workshopIgnore,
210
+ ...(await getDiffIgnore(path.join(app1.fullPath, '.gitignore'))),
211
+ ...(await getDiffIgnore(path.join(app1.fullPath, 'epicshop', '.diffignore'))),
212
+ ]),
213
+ copyUnignoredFiles(app2.fullPath, app2CopyPath, [
214
+ ...DEFAULT_IGNORE_PATTERNS,
215
+ ...pkgJsonIgnore,
216
+ ...workshopIgnore,
217
+ ...(await getDiffIgnore(path.join(app2.fullPath, '.gitignore'))),
218
+ ...(await getDiffIgnore(path.join(app2.fullPath, 'epicshop', '.diffignore'))),
219
+ ]),
220
+ ]);
221
+ return { app1CopyPath, app2CopyPath };
222
+ }
223
+ async function getDiffIgnore(filePath) {
224
+ return (await fsExtra.pathExists(filePath))
225
+ ? fsExtra.readFile(filePath, 'utf8').then((content) => content
226
+ .split('\n')
227
+ .map((line) => line.trim())
228
+ .filter((line) => !line.startsWith('#'))
229
+ .filter(Boolean))
230
+ : [];
231
+ }
232
+ async function getForceFreshForDiff(app1, app2, cacheEntry) {
233
+ // don't know when the cache was created? force refresh
234
+ const cacheModified = cacheEntry?.metadata.createdTime;
235
+ if (!cacheModified)
236
+ return true;
237
+ // app1 modified after cache? force refresh
238
+ const app1Modified = modifiedTimes.get(app1.fullPath) ?? 0;
239
+ if (app1Modified > cacheModified)
240
+ return true;
241
+ // app2 modified after cache? force refresh
242
+ const app2Modified = modifiedTimes.get(app2.fullPath) ?? 0;
243
+ if (app2Modified > cacheModified)
244
+ return true;
245
+ // ok, now let's actually check the modified times of all files in the
246
+ // directories and as soon as we find a file that was modified more recently
247
+ // then we know we need to force refresh
248
+ const modifiedMoreRecently = await modifiedMoreRecentlyThan(cacheModified, app1.fullPath, app2.fullPath);
249
+ if (modifiedMoreRecently)
250
+ return true;
251
+ return undefined;
252
+ }
253
+ export async function getDiffFiles(app1, app2, { forceFresh, timings, request, } = {}) {
254
+ const key = `${app1.relativePath}__vs__${app2.relativePath}`;
255
+ const cacheEntry = diffFilesCache.get(key);
256
+ const result = await cachified({
257
+ key,
258
+ cache: diffFilesCache,
259
+ forceFresh: forceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),
260
+ timings,
261
+ request,
262
+ getFreshValue: () => getDiffFilesImpl(app1, app2),
263
+ });
264
+ return result;
265
+ }
266
+ function getAppTestFiles(app) {
267
+ return app.test.type === 'browser' ? app.test.testFiles : [];
268
+ }
269
+ async function getDiffFilesImpl(app1, app2) {
270
+ if (app1.name === app2.name) {
271
+ return [];
272
+ }
273
+ const { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2);
274
+ const { stdout: diffOutput } = await execa('git', [
275
+ 'diff',
276
+ '--no-index',
277
+ '--ignore-blank-lines',
278
+ '--ignore-space-change',
279
+ app1CopyPath,
280
+ app2CopyPath,
281
+ ], { cwd: diffTmpDir }).catch((e) => e);
282
+ void fsExtra.remove(app1CopyPath);
283
+ void fsExtra.remove(app2CopyPath);
284
+ const typesMap = {
285
+ ChangedFile: 'modified',
286
+ AddedFile: 'added',
287
+ DeletedFile: 'deleted',
288
+ RenamedFile: 'renamed',
289
+ };
290
+ const parsed = parseGitDiff(diffOutput, { noPrefix: true });
291
+ const testFiles = Array.from(new Set([...getAppTestFiles(app1), ...getAppTestFiles(app2)]));
292
+ const startLine = (file) => {
293
+ const chunk = file.type === 'ChangedFile' && file.chunks[0];
294
+ if (chunk) {
295
+ return chunk.type === 'Chunk'
296
+ ? chunk.fromFileRange.start
297
+ : chunk.type === 'CombinedChunk'
298
+ ? chunk.fromFileRangeA.start
299
+ : 1;
300
+ }
301
+ return 1;
302
+ };
303
+ return parsed.files
304
+ .map((file) => ({
305
+ // prettier-ignore
306
+ status: (typesMap[file.type] ?? 'unknown'),
307
+ path: diffPathToRelative(file.type === 'RenamedFile' ? file.pathBefore : file.path),
308
+ line: startLine(file),
309
+ }))
310
+ .filter((file) => !testFiles.includes(file.path));
311
+ }
312
+ export async function getDiffCode(app1, app2, { forceFresh, timings, request, } = {}) {
313
+ const key = `${app1.relativePath}__vs__${app2.relativePath}`;
314
+ const cacheEntry = diffCodeCache.get(key);
315
+ const result = await cachified({
316
+ key,
317
+ cache: diffCodeCache,
318
+ forceFresh: forceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),
319
+ timings,
320
+ request,
321
+ getFreshValue: () => getDiffCodeImpl(app1, app2),
322
+ });
323
+ return result;
324
+ }
325
+ async function getDiffCodeImpl(app1, app2) {
326
+ const markdownLines = [''];
327
+ if (app1.name === app2.name) {
328
+ markdownLines.push('<p className="p-4 text-center">You are comparing the same app</p>');
329
+ const code = await compileMarkdownString(markdownLines.join('\n'));
330
+ return code;
331
+ }
332
+ const { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2);
333
+ const { stdout: diffOutput } = await execa('git', [
334
+ 'diff',
335
+ '--no-index',
336
+ app1CopyPath,
337
+ app2CopyPath,
338
+ '--color=never',
339
+ '--color-moved-ws=allow-indentation-change',
340
+ '--no-prefix',
341
+ '--ignore-blank-lines',
342
+ '--ignore-space-change',
343
+ ], { cwd: diffTmpDir }).catch((e) => e);
344
+ void fsExtra.remove(app1CopyPath);
345
+ void fsExtra.remove(app2CopyPath);
346
+ const parsed = parseGitDiff(diffOutput);
347
+ if (!parsed.files.length) {
348
+ markdownLines.push('<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>');
349
+ }
350
+ const app1TestFiles = getAppTestFiles(app1);
351
+ const app2TestFiles = getAppTestFiles(app2);
352
+ for (const file of parsed.files) {
353
+ const pathToCopy = file.type === 'RenamedFile' ? file.pathBefore : file.path;
354
+ const relativePath = diffPathToRelative(pathToCopy);
355
+ if (app1TestFiles.includes(relativePath))
356
+ continue;
357
+ const filePathApp1 = path.join(app1.fullPath, relativePath);
358
+ const pathToApp2 = file.type === 'RenamedFile' ? file.pathAfter : file.path;
359
+ const relativePathApp2 = diffPathToRelative(pathToApp2);
360
+ if (app2TestFiles.includes(relativePathApp2))
361
+ continue;
362
+ const filePathApp2 = path.join(app2.fullPath, relativePathApp2);
363
+ switch (file.type) {
364
+ case 'ChangedFile': {
365
+ markdownLines.push(`
366
+
367
+ <Accordion title=${JSON.stringify(relativePath)} variant="changed">
368
+
369
+ ${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\n')}
370
+
371
+ </Accordion>
372
+
373
+ `);
374
+ break;
375
+ }
376
+ case 'DeletedFile': {
377
+ markdownLines.push(`
378
+ <Accordion title=${JSON.stringify(relativePath)} variant="deleted">
379
+
380
+ ${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\n')}
381
+
382
+ </Accordion>
383
+ `);
384
+ break;
385
+ }
386
+ case 'RenamedFile': {
387
+ const relativeBefore = diffPathToRelative(file.pathBefore);
388
+ const relativeAfter = diffPathToRelative(file.pathAfter);
389
+ const title = JSON.stringify(`${relativeBefore} ▶️ ${relativeAfter}`);
390
+ markdownLines.push(`
391
+ <Accordion title=${title} variant="renamed">
392
+
393
+ ${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\n')}
394
+
395
+ </Accordion>
396
+ `);
397
+ break;
398
+ }
399
+ case 'AddedFile': {
400
+ markdownLines.push(`
401
+ <Accordion title=${JSON.stringify(relativePath)} variant="added">
402
+
403
+ ${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\n')}
404
+
405
+ </Accordion>
406
+ `);
407
+ break;
408
+ }
409
+ default: {
410
+ console.error(file);
411
+ throw new Error(`Unknown file type: ${file}`);
412
+ }
413
+ }
414
+ }
415
+ const code = await compileMarkdownString(markdownLines.join('\n'));
416
+ return code;
417
+ }
418
+ export async function getDiffOutputWithRelativePaths(app1, app2) {
419
+ const { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2);
420
+ const { stdout: diffOutput } = await execa('git', [
421
+ 'diff',
422
+ '--no-index',
423
+ app1CopyPath,
424
+ app2CopyPath,
425
+ '--color=never',
426
+ '--color-moved-ws=allow-indentation-change',
427
+ '--no-prefix',
428
+ '--ignore-blank-lines',
429
+ '--ignore-space-change',
430
+ ], { cwd: diffTmpDir }).catch((e) => e);
431
+ void fsExtra.remove(app1CopyPath);
432
+ void fsExtra.remove(app2CopyPath);
433
+ return diffOutput
434
+ .replaceAll(app1CopyPath.slice(1), '.')
435
+ .replaceAll(app2CopyPath.slice(1), '.');
436
+ }
437
+ //# sourceMappingURL=diff.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.server.js","sourceRoot":"","sources":["../../src/diff.server.ts"],"names":[],"mappings":"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","sourcesContent":["import 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 { cachified, diffCodeCache, diffFilesCache } 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\nfunction diffPathToRelative(filePath: string) {\n\tlet normalizedPath = path.normalize(filePath.replace(/^(\"|')|(\"|')$/g, ''))\n\tif (\n\t\tnormalizedPath.startsWith('a\\\\') ||\n\t\tnormalizedPath.startsWith('b\\\\') ||\n\t\tnormalizedPath.startsWith('a/') ||\n\t\tnormalizedPath.startsWith('b/')\n\t) {\n\t\tnormalizedPath = normalizedPath.slice(2)\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: diffCodeCache,\n\t\tforceFresh: getForceFreshForDir(diffCodeCache.get(key), srcDir),\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: CacheEntry | null | undefined,\n) {\n\t// don't know when the cache was created? force refresh\n\tconst cacheModified = cacheEntry?.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 = 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 = 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"]}
@@ -0,0 +1,61 @@
1
+ import { z } from 'zod';
2
+ declare const schema: z.ZodObject<{
3
+ NODE_ENV: z.ZodDefault<z.ZodEnum<["production", "development", "test"]>>;
4
+ EPICSHOP_GITHUB_REPO: z.ZodString;
5
+ EPICSHOP_GITHUB_ROOT: z.ZodString;
6
+ EPICSHOP_CONTEXT_CWD: z.ZodString;
7
+ EPICSHOP_APP_VERSION: z.ZodOptional<z.ZodString>;
8
+ EPICSHOP_PARENT_PORT: z.ZodOptional<z.ZodString>;
9
+ EPICSHOP_PARENT_TOKEN: z.ZodOptional<z.ZodString>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ NODE_ENV: "production" | "development" | "test";
12
+ EPICSHOP_GITHUB_REPO: string;
13
+ EPICSHOP_GITHUB_ROOT: string;
14
+ EPICSHOP_CONTEXT_CWD: string;
15
+ EPICSHOP_APP_VERSION?: string | undefined;
16
+ EPICSHOP_PARENT_PORT?: string | undefined;
17
+ EPICSHOP_PARENT_TOKEN?: string | undefined;
18
+ }, {
19
+ EPICSHOP_GITHUB_REPO: string;
20
+ EPICSHOP_GITHUB_ROOT: string;
21
+ EPICSHOP_CONTEXT_CWD: string;
22
+ NODE_ENV?: "production" | "development" | "test" | undefined;
23
+ EPICSHOP_APP_VERSION?: string | undefined;
24
+ EPICSHOP_PARENT_PORT?: string | undefined;
25
+ EPICSHOP_PARENT_TOKEN?: string | undefined;
26
+ }>;
27
+ declare global {
28
+ namespace NodeJS {
29
+ interface ProcessEnv extends z.infer<typeof schema> {
30
+ }
31
+ }
32
+ }
33
+ export declare function init(): void;
34
+ /**
35
+ * This is used in both `entry.server.ts` and `root.tsx` to ensure that
36
+ * the environment variables are set and globally available before the app is
37
+ * started.
38
+ *
39
+ * NOTE: Do *not* add any environment variables in here that you do not wish to
40
+ * be included in the client.
41
+ * @returns all public ENV variables
42
+ */
43
+ export declare function getEnv(): {
44
+ MODE: "production" | "development" | "test";
45
+ EPICSHOP_CONTEXT_CWD: string;
46
+ EPICSHOP_GITHUB_REPO: string;
47
+ EPICSHOP_GITHUB_ROOT: string;
48
+ EPICSHOP_DEPLOYED: boolean;
49
+ EPICSHOP_APP_VERSION: string | undefined;
50
+ EPICSHOP_PARENT_PORT: string | undefined;
51
+ EPICSHOP_PARENT_TOKEN: string | undefined;
52
+ };
53
+ type ENV = ReturnType<typeof getEnv>;
54
+ declare global {
55
+ var ENV: ENV;
56
+ interface Window {
57
+ ENV: ENV;
58
+ }
59
+ }
60
+ export {};
61
+ //# sourceMappingURL=env.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.server.d.ts","sourceRoot":"","sources":["../../src/env.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;EAUV,CAAA;AAEF,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM,CAAC;QAChB,UAAU,UAAW,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC;SAAG;KACtD;CACD;AAED,wBAAgB,IAAI,SAWnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM;;;;;;;;;EAarB;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"}
@@ -0,0 +1,42 @@
1
+ import { z } from 'zod';
2
+ const schema = z.object({
3
+ NODE_ENV: z
4
+ .enum(['production', 'development', 'test'])
5
+ .default('development'),
6
+ EPICSHOP_GITHUB_REPO: z.string(),
7
+ EPICSHOP_GITHUB_ROOT: z.string(),
8
+ EPICSHOP_CONTEXT_CWD: z.string(),
9
+ EPICSHOP_APP_VERSION: z.string().optional(),
10
+ EPICSHOP_PARENT_PORT: z.string().optional(),
11
+ EPICSHOP_PARENT_TOKEN: z.string().optional(),
12
+ });
13
+ export function init() {
14
+ const parsed = schema.safeParse(process.env);
15
+ if (!parsed.success) {
16
+ console.error('❌ Invalid environment variables:', parsed.error.flatten().fieldErrors);
17
+ throw new Error('Invalid environment variables');
18
+ }
19
+ }
20
+ /**
21
+ * This is used in both `entry.server.ts` and `root.tsx` to ensure that
22
+ * the environment variables are set and globally available before the app is
23
+ * started.
24
+ *
25
+ * NOTE: Do *not* add any environment variables in here that you do not wish to
26
+ * be included in the client.
27
+ * @returns all public ENV variables
28
+ */
29
+ export function getEnv() {
30
+ return {
31
+ MODE: process.env.NODE_ENV,
32
+ EPICSHOP_CONTEXT_CWD: process.env.EPICSHOP_CONTEXT_CWD,
33
+ EPICSHOP_GITHUB_REPO: process.env.EPICSHOP_GITHUB_REPO,
34
+ EPICSHOP_GITHUB_ROOT: process.env.EPICSHOP_GITHUB_ROOT,
35
+ EPICSHOP_DEPLOYED: process.env.EPICSHOP_DEPLOYED === 'true' ||
36
+ process.env.EPICSHOP_DEPLOYED === '1',
37
+ EPICSHOP_APP_VERSION: process.env.EPICSHOP_APP_VERSION,
38
+ EPICSHOP_PARENT_PORT: process.env.EPICSHOP_PARENT_PORT,
39
+ EPICSHOP_PARENT_TOKEN: process.env.EPICSHOP_PARENT_TOKEN,
40
+ };
41
+ }
42
+ //# sourceMappingURL=env.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.server.js","sourceRoot":"","sources":["../../src/env.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACvB,QAAQ,EAAE,CAAC;SACT,IAAI,CAAC,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,CAAU,CAAC;SACpD,OAAO,CAAC,aAAa,CAAC;IACxB,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE;IAChC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE;IAChC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE;IAChC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3C,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3C,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5C,CAAC,CAAA;AAQF,MAAM,UAAU,IAAI;IACnB,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAE5C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACrB,OAAO,CAAC,KAAK,CACZ,kCAAkC,EAClC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,WAAW,CAClC,CAAA;QAED,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;IACjD,CAAC;AACF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,MAAM;IACrB,OAAO;QACN,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ;QAC1B,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtD,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtD,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtD,iBAAiB,EAChB,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM;YACxC,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,GAAG;QACtC,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtD,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtD,qBAAqB,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB;KACxD,CAAA;AACF,CAAC","sourcesContent":["import { z } from 'zod'\n\nconst schema = z.object({\n\tNODE_ENV: z\n\t\t.enum(['production', 'development', 'test'] as const)\n\t\t.default('development'),\n\tEPICSHOP_GITHUB_REPO: z.string(),\n\tEPICSHOP_GITHUB_ROOT: z.string(),\n\tEPICSHOP_CONTEXT_CWD: z.string(),\n\tEPICSHOP_APP_VERSION: z.string().optional(),\n\tEPICSHOP_PARENT_PORT: z.string().optional(),\n\tEPICSHOP_PARENT_TOKEN: z.string().optional(),\n})\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv extends z.infer<typeof schema> {}\n\t}\n}\n\nexport function init() {\n\tconst parsed = schema.safeParse(process.env)\n\n\tif (!parsed.success) {\n\t\tconsole.error(\n\t\t\t'❌ Invalid environment variables:',\n\t\t\tparsed.error.flatten().fieldErrors,\n\t\t)\n\n\t\tthrow new Error('Invalid environment variables')\n\t}\n}\n\n/**\n * This is used in both `entry.server.ts` and `root.tsx` to ensure that\n * the environment variables are set and globally available before the app is\n * started.\n *\n * NOTE: Do *not* add any environment variables in here that you do not wish to\n * be included in the client.\n * @returns all public ENV variables\n */\nexport function getEnv() {\n\treturn {\n\t\tMODE: process.env.NODE_ENV,\n\t\tEPICSHOP_CONTEXT_CWD: process.env.EPICSHOP_CONTEXT_CWD,\n\t\tEPICSHOP_GITHUB_REPO: process.env.EPICSHOP_GITHUB_REPO,\n\t\tEPICSHOP_GITHUB_ROOT: process.env.EPICSHOP_GITHUB_ROOT,\n\t\tEPICSHOP_DEPLOYED:\n\t\t\tprocess.env.EPICSHOP_DEPLOYED === 'true' ||\n\t\t\tprocess.env.EPICSHOP_DEPLOYED === '1',\n\t\tEPICSHOP_APP_VERSION: process.env.EPICSHOP_APP_VERSION,\n\t\tEPICSHOP_PARENT_PORT: process.env.EPICSHOP_PARENT_PORT,\n\t\tEPICSHOP_PARENT_TOKEN: process.env.EPICSHOP_PARENT_TOKEN,\n\t}\n}\n\ntype ENV = ReturnType<typeof getEnv>\n\ndeclare global {\n\tvar ENV: ENV\n\tinterface Window {\n\t\tENV: ENV\n\t}\n}\n"]}