@epic-web/workshop-utils 6.72.0 → 6.72.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apps.server.d.ts +3 -3
- package/dist/apps.server.js +5 -0
- package/dist/cache.server.d.ts +20 -7
- package/dist/compile-mdx.server.d.ts +1 -1
- package/dist/compile-mdx.server.js +8 -0
- package/dist/diff.server.d.ts +1 -1
- package/dist/diff.server.js +37 -8
- package/dist/git.server.d.ts +13 -57
- package/dist/git.server.js +14 -0
- package/dist/modified-time.server.js +2 -0
- package/dist/notifications.server.js +16 -0
- package/dist/utils.server.js +2 -0
- package/package.json +4 -4
package/dist/apps.server.d.ts
CHANGED
|
@@ -2101,7 +2101,7 @@ export declare function getWorkshopInstructions({ request, }?: {
|
|
|
2101
2101
|
readonly status: "success";
|
|
2102
2102
|
readonly code: string;
|
|
2103
2103
|
readonly title: string | null;
|
|
2104
|
-
readonly epicVideoEmbeds:
|
|
2104
|
+
readonly epicVideoEmbeds: string[];
|
|
2105
2105
|
} | {
|
|
2106
2106
|
readonly status: "error";
|
|
2107
2107
|
readonly error: string;
|
|
@@ -2116,7 +2116,7 @@ export declare function getExtrasInstructions({ request, }?: {
|
|
|
2116
2116
|
readonly status: "success";
|
|
2117
2117
|
readonly code: string;
|
|
2118
2118
|
readonly title: string | null;
|
|
2119
|
-
readonly epicVideoEmbeds:
|
|
2119
|
+
readonly epicVideoEmbeds: string[];
|
|
2120
2120
|
} | {
|
|
2121
2121
|
readonly status: "error";
|
|
2122
2122
|
readonly error: string;
|
|
@@ -2131,7 +2131,7 @@ export declare function getWorkshopFinished({ request, }?: {
|
|
|
2131
2131
|
readonly status: "success";
|
|
2132
2132
|
readonly code: string;
|
|
2133
2133
|
readonly title: string | null;
|
|
2134
|
-
readonly epicVideoEmbeds:
|
|
2134
|
+
readonly epicVideoEmbeds: string[];
|
|
2135
2135
|
} | {
|
|
2136
2136
|
readonly status: "error";
|
|
2137
2137
|
readonly error: string;
|
package/dist/apps.server.js
CHANGED
|
@@ -217,6 +217,7 @@ async function isDirectoryEmpty(dirPath) {
|
|
|
217
217
|
cache: directoryEmptyCache,
|
|
218
218
|
ttl: 1000 * 60 * 5,
|
|
219
219
|
swr: 1000 * 60 * 20,
|
|
220
|
+
checkValue: z.boolean(),
|
|
220
221
|
forceFresh: await getForceFreshForDir(directoryEmptyCache.get(dirPath), dirPath),
|
|
221
222
|
getFreshValue: async () => {
|
|
222
223
|
try {
|
|
@@ -767,6 +768,7 @@ export async function getPlaygroundApp({ timings, request, } = {}) {
|
|
|
767
768
|
cache: playgroundAppCache,
|
|
768
769
|
ttl: 1000 * 60 * 5,
|
|
769
770
|
swr: 1000 * 60 * 60 * 24 * 30,
|
|
771
|
+
checkValue: PlaygroundAppSchema.nullable(),
|
|
770
772
|
timings,
|
|
771
773
|
timingKey: playgroundDir.replace(`${playgroundDir}${path.sep}`, ''),
|
|
772
774
|
request,
|
|
@@ -892,6 +894,7 @@ async function getExtraApps({ timings, request, } = {}) {
|
|
|
892
894
|
cache: extraAppCache,
|
|
893
895
|
ttl: 1000 * 60 * 5,
|
|
894
896
|
swr: 1000 * 60 * 60 * 24 * 30,
|
|
897
|
+
checkValue: ExtraAppSchema.nullable(),
|
|
895
898
|
timings,
|
|
896
899
|
timingKey: extraDir.replace(`${extraDirInfo.fullPath}${path.sep}`, ''),
|
|
897
900
|
request,
|
|
@@ -964,6 +967,7 @@ async function getSolutionApps({ timings, request, } = {}) {
|
|
|
964
967
|
request,
|
|
965
968
|
ttl: 1000 * 60 * 5,
|
|
966
969
|
swr: 1000 * 60 * 60 * 24 * 30,
|
|
970
|
+
checkValue: SolutionAppSchema.nullable(),
|
|
967
971
|
forceFresh: await getForceFreshForDir(solutionAppCache.get(solutionDir), solutionDir),
|
|
968
972
|
getFreshValue: async () => {
|
|
969
973
|
return getSolutionAppFromPath(solutionDir, request).catch((error) => {
|
|
@@ -1034,6 +1038,7 @@ async function getProblemApps({ timings, request, } = {}) {
|
|
|
1034
1038
|
request,
|
|
1035
1039
|
ttl: 1000 * 60 * 5,
|
|
1036
1040
|
swr: 1000 * 60 * 60 * 24 * 30,
|
|
1041
|
+
checkValue: ProblemAppSchema.nullable(),
|
|
1037
1042
|
forceFresh: await getForceFreshForDir(problemAppCache.get(problemDir), problemDir, solutionDir),
|
|
1038
1043
|
getFreshValue: async () => {
|
|
1039
1044
|
return getProblemAppFromPath(problemDir).catch((error) => {
|
package/dist/cache.server.d.ts
CHANGED
|
@@ -2,6 +2,18 @@ import * as C from '@epic-web/cachified';
|
|
|
2
2
|
import { type CreateReporter } from '@epic-web/cachified';
|
|
3
3
|
import z from 'zod';
|
|
4
4
|
import { type Timings } from "./timing.server.js";
|
|
5
|
+
type DiffStatus = 'renamed' | 'modified' | 'deleted' | 'added' | 'unknown';
|
|
6
|
+
type DiffFile = {
|
|
7
|
+
status: DiffStatus;
|
|
8
|
+
path: string;
|
|
9
|
+
line: number;
|
|
10
|
+
};
|
|
11
|
+
type CompiledCodeResult = {
|
|
12
|
+
outputFiles?: Array<unknown>;
|
|
13
|
+
errors: Array<unknown>;
|
|
14
|
+
warnings: Array<unknown>;
|
|
15
|
+
};
|
|
16
|
+
type OgCacheValue = string | Uint8Array;
|
|
5
17
|
/**
|
|
6
18
|
* Creates a cachified reporter that integrates with the Epic Workshop logger system.
|
|
7
19
|
* Uses the pattern `epic:cache:{name-of-cache}` for logger namespaces.
|
|
@@ -156,24 +168,24 @@ export declare const playgroundAppCache: C.Cache<{
|
|
|
156
168
|
epicVideoEmbeds?: string[] | undefined;
|
|
157
169
|
}>;
|
|
158
170
|
export declare const diffCodeCache: C.Cache<string>;
|
|
159
|
-
export declare const diffFilesCache: C.Cache<
|
|
171
|
+
export declare const diffFilesCache: C.Cache<DiffFile[]>;
|
|
160
172
|
export declare const copyUnignoredFilesCache: {
|
|
161
173
|
name: string;
|
|
162
|
-
set: (key: string, value: C.CacheEntry<
|
|
163
|
-
get: (key: string) => C.CacheEntry<
|
|
174
|
+
set: (key: string, value: C.CacheEntry<boolean>) => C.CacheEntry<boolean>;
|
|
175
|
+
get: (key: string) => C.CacheEntry<boolean> | undefined;
|
|
164
176
|
delete: (key: string) => boolean;
|
|
165
177
|
};
|
|
166
178
|
export declare const compiledMarkdownCache: C.Cache<string>;
|
|
167
179
|
export declare const compiledCodeCache: {
|
|
168
180
|
name: string;
|
|
169
|
-
set: (key: string, value: C.CacheEntry<
|
|
170
|
-
get: (key: string) => C.CacheEntry<
|
|
181
|
+
set: (key: string, value: C.CacheEntry<CompiledCodeResult>) => C.CacheEntry<CompiledCodeResult>;
|
|
182
|
+
get: (key: string) => C.CacheEntry<CompiledCodeResult> | undefined;
|
|
171
183
|
delete: (key: string) => boolean;
|
|
172
184
|
};
|
|
173
185
|
export declare const ogCache: {
|
|
174
186
|
name: string;
|
|
175
|
-
set: (key: string, value: C.CacheEntry<
|
|
176
|
-
get: (key: string) => C.CacheEntry<
|
|
187
|
+
set: (key: string, value: C.CacheEntry<OgCacheValue>) => C.CacheEntry<OgCacheValue>;
|
|
188
|
+
get: (key: string) => C.CacheEntry<OgCacheValue> | undefined;
|
|
177
189
|
delete: (key: string) => boolean;
|
|
178
190
|
};
|
|
179
191
|
export declare const compiledInstructionMarkdownCache: C.Cache<{
|
|
@@ -430,3 +442,4 @@ export declare function shouldForceFresh({ forceFresh, request, key, }: {
|
|
|
430
442
|
request?: Request;
|
|
431
443
|
key?: string;
|
|
432
444
|
}): Promise<boolean>;
|
|
445
|
+
export {};
|
|
@@ -7,6 +7,6 @@ export declare function compileMdx(file: string, { request, timings, forceFresh,
|
|
|
7
7
|
}): Promise<{
|
|
8
8
|
code: string;
|
|
9
9
|
title: string | null;
|
|
10
|
-
epicVideoEmbeds:
|
|
10
|
+
epicVideoEmbeds: string[];
|
|
11
11
|
}>;
|
|
12
12
|
export declare function compileMarkdownString(markdownString: string): Promise<string>;
|
|
@@ -11,10 +11,16 @@ import rehypeAutolinkHeadings from 'rehype-autolink-headings';
|
|
|
11
11
|
import emoji from 'remark-emoji';
|
|
12
12
|
import gfm from 'remark-gfm';
|
|
13
13
|
import { visit } from 'unist-util-visit';
|
|
14
|
+
import { z } from 'zod';
|
|
14
15
|
import { cachified, compiledInstructionMarkdownCache, compiledMarkdownCache, shouldForceFresh, } from "./cache.server.js";
|
|
15
16
|
import { checkConnection } from "./utils.server.js";
|
|
16
17
|
const themeCookieName = 'EpicShop_theme';
|
|
17
18
|
const themeHintCookieName = 'EpicShop_CH-prefers-color-scheme';
|
|
19
|
+
const CompiledInstructionMarkdownSchema = z.object({
|
|
20
|
+
code: z.string(),
|
|
21
|
+
title: z.string().nullable(),
|
|
22
|
+
epicVideoEmbeds: z.array(z.string()),
|
|
23
|
+
});
|
|
18
24
|
function getMermaidTheme(request) {
|
|
19
25
|
if (!request)
|
|
20
26
|
return 'default';
|
|
@@ -182,6 +188,7 @@ export async function compileMdx(file, { request, timings, forceFresh, } = {}) {
|
|
|
182
188
|
request,
|
|
183
189
|
timings,
|
|
184
190
|
forceFresh,
|
|
191
|
+
checkValue: CompiledInstructionMarkdownSchema,
|
|
185
192
|
getFreshValue: () => compileMdxImpl(file, { mermaidTheme }),
|
|
186
193
|
});
|
|
187
194
|
}
|
|
@@ -277,6 +284,7 @@ export async function compileMarkdownString(markdownString) {
|
|
|
277
284
|
key: md5(markdownString),
|
|
278
285
|
cache: compiledMarkdownCache,
|
|
279
286
|
ttl: 1000 * 60 * 60 * 24,
|
|
287
|
+
checkValue: z.string(),
|
|
280
288
|
getFreshValue: async () => {
|
|
281
289
|
try {
|
|
282
290
|
verboseLog(`Compiling string`, markdownString);
|
package/dist/diff.server.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare function getDiffFiles(app1: App, app2: App, { forceFresh, timings
|
|
|
5
5
|
timings?: Timings;
|
|
6
6
|
request?: Request;
|
|
7
7
|
}): Promise<{
|
|
8
|
-
status: "
|
|
8
|
+
status: "unknown" | "renamed" | "modified" | "deleted" | "added";
|
|
9
9
|
path: string;
|
|
10
10
|
line: number;
|
|
11
11
|
}[]>;
|
package/dist/diff.server.js
CHANGED
|
@@ -7,6 +7,7 @@ import fsExtra from 'fs-extra';
|
|
|
7
7
|
import ignore from 'ignore';
|
|
8
8
|
import parseGitDiff from 'parse-git-diff';
|
|
9
9
|
import { bundledLanguagesInfo } from 'shiki/langs';
|
|
10
|
+
import { z } from 'zod';
|
|
10
11
|
import { getForceFreshForDir, getRelativePath, getWorkshopRoot, modifiedTimes, } from "./apps.server.js";
|
|
11
12
|
import { cachified, copyUnignoredFilesCache, diffCodeCache, diffFilesCache, } from "./cache.server.js";
|
|
12
13
|
import { compileMarkdownString } from "./compile-mdx.server.js";
|
|
@@ -14,6 +15,37 @@ import { modifiedMoreRecentlyThan } from "./modified-time.server.js";
|
|
|
14
15
|
const epicshopTempDir = path.join(os.tmpdir(), 'epicshop');
|
|
15
16
|
const isDeployed = getEnv().EPICSHOP_DEPLOYED;
|
|
16
17
|
const diffTmpDir = path.join(epicshopTempDir, 'diff');
|
|
18
|
+
const DiffStatusSchema = z.enum([
|
|
19
|
+
'renamed',
|
|
20
|
+
'modified',
|
|
21
|
+
'deleted',
|
|
22
|
+
'added',
|
|
23
|
+
'unknown',
|
|
24
|
+
]);
|
|
25
|
+
const DiffFileSchema = z.object({
|
|
26
|
+
status: DiffStatusSchema,
|
|
27
|
+
path: z.string(),
|
|
28
|
+
line: z.number(),
|
|
29
|
+
});
|
|
30
|
+
function getDiffStatus(fileType) {
|
|
31
|
+
switch (fileType) {
|
|
32
|
+
case 'ChangedFile': {
|
|
33
|
+
return 'modified';
|
|
34
|
+
}
|
|
35
|
+
case 'AddedFile': {
|
|
36
|
+
return 'added';
|
|
37
|
+
}
|
|
38
|
+
case 'DeletedFile': {
|
|
39
|
+
return 'deleted';
|
|
40
|
+
}
|
|
41
|
+
case 'RenamedFile': {
|
|
42
|
+
return 'renamed';
|
|
43
|
+
}
|
|
44
|
+
default: {
|
|
45
|
+
return 'unknown';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
17
49
|
/**
|
|
18
50
|
* Converts a diff file path to a relative path for display and lookup.
|
|
19
51
|
* - Removes leading/trailing quotes.
|
|
@@ -165,6 +197,7 @@ async function copyUnignoredFiles(srcDir, destDir, ignoreList) {
|
|
|
165
197
|
await cachified({
|
|
166
198
|
key,
|
|
167
199
|
cache: copyUnignoredFilesCache,
|
|
200
|
+
checkValue: z.boolean(),
|
|
168
201
|
forceFresh: await getForceFreshForDir(copyUnignoredFilesCache.get(key), srcDir),
|
|
169
202
|
async getFreshValue() {
|
|
170
203
|
// @ts-ignore 🤷♂️ weird module stuff
|
|
@@ -177,6 +210,7 @@ async function copyUnignoredFiles(srcDir, destDir, ignoreList) {
|
|
|
177
210
|
return !ig.ignores(path.relative(srcDir, file));
|
|
178
211
|
},
|
|
179
212
|
});
|
|
213
|
+
return true;
|
|
180
214
|
},
|
|
181
215
|
});
|
|
182
216
|
}
|
|
@@ -266,6 +300,7 @@ export async function getDiffFiles(app1, app2, { forceFresh, timings, request, }
|
|
|
266
300
|
forceFresh: forceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),
|
|
267
301
|
timings,
|
|
268
302
|
request,
|
|
303
|
+
checkValue: DiffFileSchema.array(),
|
|
269
304
|
getFreshValue: () => getDiffFilesImpl(app1, app2),
|
|
270
305
|
});
|
|
271
306
|
return result;
|
|
@@ -288,12 +323,6 @@ async function getDiffFilesImpl(app1, app2) {
|
|
|
288
323
|
], { cwd: diffTmpDir }).catch((e) => e);
|
|
289
324
|
void fsExtra.remove(app1CopyPath).catch(() => { });
|
|
290
325
|
void fsExtra.remove(app2CopyPath).catch(() => { });
|
|
291
|
-
const typesMap = {
|
|
292
|
-
ChangedFile: 'modified',
|
|
293
|
-
AddedFile: 'added',
|
|
294
|
-
DeletedFile: 'deleted',
|
|
295
|
-
RenamedFile: 'renamed',
|
|
296
|
-
};
|
|
297
326
|
const parsed = parseGitDiff(diffOutput, { noPrefix: true });
|
|
298
327
|
const testFiles = Array.from(new Set([...getAppTestFiles(app1), ...getAppTestFiles(app2)]));
|
|
299
328
|
const startLine = (file) => {
|
|
@@ -309,8 +338,7 @@ async function getDiffFilesImpl(app1, app2) {
|
|
|
309
338
|
};
|
|
310
339
|
return parsed.files
|
|
311
340
|
.map((file) => ({
|
|
312
|
-
|
|
313
|
-
status: (typesMap[file.type] ?? 'unknown'),
|
|
341
|
+
status: getDiffStatus(file.type),
|
|
314
342
|
path: diffPathToRelative(file.type === 'RenamedFile' ? file.pathBefore : file.path),
|
|
315
343
|
line: startLine(file),
|
|
316
344
|
}))
|
|
@@ -325,6 +353,7 @@ export async function getDiffCode(app1, app2, { forceFresh, timings, request, }
|
|
|
325
353
|
forceFresh: forceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),
|
|
326
354
|
timings,
|
|
327
355
|
request,
|
|
356
|
+
checkValue: z.string(),
|
|
328
357
|
getFreshValue: () => getDiffCodeImpl(app1, app2),
|
|
329
358
|
});
|
|
330
359
|
return result;
|
package/dist/git.server.d.ts
CHANGED
|
@@ -67,71 +67,27 @@ export declare function checkForUpdates(): Promise<{
|
|
|
67
67
|
readonly message: null;
|
|
68
68
|
}>;
|
|
69
69
|
export declare function checkForUpdatesCached(): Promise<{
|
|
70
|
+
updatesAvailable: boolean;
|
|
71
|
+
repoUpdatesAvailable: boolean;
|
|
72
|
+
dependenciesNeedInstall: boolean;
|
|
73
|
+
updateNotificationId: string | null;
|
|
74
|
+
commitsAhead: number | null;
|
|
75
|
+
commitsBehind: number | null;
|
|
76
|
+
localCommit: string | null;
|
|
77
|
+
remoteCommit: string | null;
|
|
78
|
+
diffLink: string | null;
|
|
79
|
+
message: string | null;
|
|
80
|
+
} | {
|
|
70
81
|
readonly updatesAvailable: false;
|
|
82
|
+
readonly repoUpdatesAvailable: false;
|
|
71
83
|
readonly dependenciesNeedInstall: false;
|
|
72
84
|
readonly updateNotificationId: null;
|
|
73
|
-
readonly message: "The app is deployed";
|
|
74
|
-
readonly repoUpdatesAvailable: boolean;
|
|
75
|
-
readonly commitsAhead: null;
|
|
76
|
-
readonly commitsBehind: null;
|
|
77
|
-
readonly localCommit: null;
|
|
78
|
-
readonly remoteCommit: null;
|
|
79
|
-
readonly diffLink: null;
|
|
80
|
-
} | {
|
|
81
|
-
readonly message: "You are offline";
|
|
82
|
-
readonly updatesAvailable: boolean;
|
|
83
|
-
readonly repoUpdatesAvailable: boolean;
|
|
84
|
-
readonly dependenciesNeedInstall: boolean;
|
|
85
|
-
readonly updateNotificationId: string | null;
|
|
86
|
-
readonly commitsAhead: null;
|
|
87
|
-
readonly commitsBehind: null;
|
|
88
|
-
readonly localCommit: null;
|
|
89
|
-
readonly remoteCommit: null;
|
|
90
|
-
readonly diffLink: null;
|
|
91
|
-
} | {
|
|
92
|
-
readonly message: "Not in a git repo";
|
|
93
|
-
readonly updatesAvailable: boolean;
|
|
94
|
-
readonly repoUpdatesAvailable: boolean;
|
|
95
|
-
readonly dependenciesNeedInstall: boolean;
|
|
96
|
-
readonly updateNotificationId: string | null;
|
|
97
85
|
readonly commitsAhead: null;
|
|
98
86
|
readonly commitsBehind: null;
|
|
99
87
|
readonly localCommit: null;
|
|
100
88
|
readonly remoteCommit: null;
|
|
101
89
|
readonly diffLink: null;
|
|
102
|
-
|
|
103
|
-
readonly message: "Cannot find remote";
|
|
104
|
-
readonly updatesAvailable: boolean;
|
|
105
|
-
readonly repoUpdatesAvailable: boolean;
|
|
106
|
-
readonly dependenciesNeedInstall: boolean;
|
|
107
|
-
readonly updateNotificationId: string | null;
|
|
108
|
-
readonly commitsAhead: null;
|
|
109
|
-
readonly commitsBehind: null;
|
|
110
|
-
readonly localCommit: null;
|
|
111
|
-
readonly remoteCommit: null;
|
|
112
|
-
readonly diffLink: null;
|
|
113
|
-
} | {
|
|
114
|
-
readonly updatesAvailable: boolean;
|
|
115
|
-
readonly repoUpdatesAvailable: boolean;
|
|
116
|
-
readonly dependenciesNeedInstall: boolean;
|
|
117
|
-
readonly updateNotificationId: string | null;
|
|
118
|
-
readonly commitsAhead: number;
|
|
119
|
-
readonly commitsBehind: number;
|
|
120
|
-
readonly localCommit: string;
|
|
121
|
-
readonly remoteCommit: string;
|
|
122
|
-
readonly diffLink: string | null;
|
|
123
|
-
readonly message: null;
|
|
124
|
-
} | {
|
|
125
|
-
readonly localCommit: string | null;
|
|
126
|
-
readonly remoteCommit: string | null;
|
|
127
|
-
readonly diffLink: string | null;
|
|
128
|
-
readonly updatesAvailable: boolean;
|
|
129
|
-
readonly repoUpdatesAvailable: boolean;
|
|
130
|
-
readonly dependenciesNeedInstall: boolean;
|
|
131
|
-
readonly updateNotificationId: string | null;
|
|
132
|
-
readonly commitsAhead: null;
|
|
133
|
-
readonly commitsBehind: null;
|
|
134
|
-
readonly message: null;
|
|
90
|
+
readonly message: "The app is deployed";
|
|
135
91
|
}>;
|
|
136
92
|
export declare function updateLocalRepo(): Promise<{
|
|
137
93
|
readonly status: "success";
|
package/dist/git.server.js
CHANGED
|
@@ -2,6 +2,7 @@ import "./init-env.js";
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { execa, execaCommand } from 'execa';
|
|
5
|
+
import { z } from 'zod';
|
|
5
6
|
import { getWorkshopRoot } from "./apps.server.js";
|
|
6
7
|
import { cachified, checkForUpdatesCache } from "./cache.server.js";
|
|
7
8
|
import { getWorkshopConfig } from "./config.server.js";
|
|
@@ -11,6 +12,18 @@ import { getInstallCommand, getWorkspaceInstallStatus, } from "./package-install
|
|
|
11
12
|
import { checkConnection } from "./utils.server.js";
|
|
12
13
|
import { getErrorMessage } from "./utils.js";
|
|
13
14
|
const gitLog = logger('epic:git');
|
|
15
|
+
const CheckForUpdatesSchema = z.object({
|
|
16
|
+
updatesAvailable: z.boolean(),
|
|
17
|
+
repoUpdatesAvailable: z.boolean(),
|
|
18
|
+
dependenciesNeedInstall: z.boolean(),
|
|
19
|
+
updateNotificationId: z.string().nullable(),
|
|
20
|
+
commitsAhead: z.number().nullable(),
|
|
21
|
+
commitsBehind: z.number().nullable(),
|
|
22
|
+
localCommit: z.string().nullable(),
|
|
23
|
+
remoteCommit: z.string().nullable(),
|
|
24
|
+
diffLink: z.string().nullable(),
|
|
25
|
+
message: z.string().nullable(),
|
|
26
|
+
});
|
|
14
27
|
function dirHasTrackedFiles(cwd, dirPath) {
|
|
15
28
|
return execa('git', ['ls-files', dirPath], { cwd }).then((s) => s.stdout.trim().length > 0, () => true);
|
|
16
29
|
}
|
|
@@ -170,6 +183,7 @@ export async function checkForUpdatesCached() {
|
|
|
170
183
|
ttl: 1000 * 60,
|
|
171
184
|
swr: 1000 * 60 * 60 * 24,
|
|
172
185
|
key,
|
|
186
|
+
checkValue: CheckForUpdatesSchema,
|
|
173
187
|
getFreshValue: checkForUpdates,
|
|
174
188
|
cache: checkForUpdatesCache,
|
|
175
189
|
});
|
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { isGitIgnored } from 'globby';
|
|
5
5
|
import PQueue from 'p-queue';
|
|
6
|
+
import { z } from 'zod';
|
|
6
7
|
import { cachified, dirModifiedTimeCache } from "./cache.server.js";
|
|
7
8
|
async function getDirModifiedTime(dir, { forceFresh = false } = {}) {
|
|
8
9
|
const result = await cachified({
|
|
@@ -10,6 +11,7 @@ async function getDirModifiedTime(dir, { forceFresh = false } = {}) {
|
|
|
10
11
|
cache: dirModifiedTimeCache,
|
|
11
12
|
ttl: 200,
|
|
12
13
|
forceFresh,
|
|
14
|
+
checkValue: z.number(),
|
|
13
15
|
getFreshValue: () => getDirModifiedTimeImpl(dir),
|
|
14
16
|
});
|
|
15
17
|
return result;
|
|
@@ -22,6 +22,21 @@ const NotificationSchema = z.object({
|
|
|
22
22
|
.nullable()
|
|
23
23
|
.transform((val) => (val ? new Date(val) : null)),
|
|
24
24
|
});
|
|
25
|
+
// Schema for validating cached notifications (post-transform, with Date objects)
|
|
26
|
+
const CachedNotificationSchema = z.object({
|
|
27
|
+
id: z.string(),
|
|
28
|
+
title: z.string(),
|
|
29
|
+
message: z.string(),
|
|
30
|
+
link: z.string().optional(),
|
|
31
|
+
type: z.enum(['info', 'warning', 'danger']),
|
|
32
|
+
products: z
|
|
33
|
+
.array(z.object({
|
|
34
|
+
host: z.string(),
|
|
35
|
+
slug: z.string().optional(),
|
|
36
|
+
}))
|
|
37
|
+
.optional(),
|
|
38
|
+
expiresAt: z.instanceof(Date).nullable(),
|
|
39
|
+
});
|
|
25
40
|
async function getRemoteNotifications() {
|
|
26
41
|
return cachified({
|
|
27
42
|
key: 'notifications',
|
|
@@ -29,6 +44,7 @@ async function getRemoteNotifications() {
|
|
|
29
44
|
ttl: 1000 * 60 * 60 * 6,
|
|
30
45
|
swr: 1000 * 60 * 60 * 24,
|
|
31
46
|
offlineFallbackValue: [],
|
|
47
|
+
checkValue: CachedNotificationSchema.array(),
|
|
32
48
|
async getFreshValue() {
|
|
33
49
|
const URL = 'https://gist.github.com/kentcdodds/c3aaa5141f591cdbb0e6bfcacd361f39';
|
|
34
50
|
const filename = 'notifications.json5';
|
package/dist/utils.server.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "./init-env.js";
|
|
2
|
+
import { z } from 'zod';
|
|
2
3
|
import { cachified, connectionCache } from "./cache.server.js";
|
|
3
4
|
import { logger } from "./logger.js";
|
|
4
5
|
export { dayjs } from "./utils.js";
|
|
@@ -42,6 +43,7 @@ export async function checkConnection({ request, timings, } = {}) {
|
|
|
42
43
|
timings,
|
|
43
44
|
key: 'connected',
|
|
44
45
|
ttl: 1000 * 10,
|
|
46
|
+
checkValue: z.boolean(),
|
|
45
47
|
async getFreshValue(context) {
|
|
46
48
|
connectionLog('getting fresh connection value');
|
|
47
49
|
const isOnline = await raceConnectivity();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epic-web/workshop-utils",
|
|
3
|
-
"version": "6.72.
|
|
3
|
+
"version": "6.72.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
"@mdx-js/mdx": "^3.1.1",
|
|
192
192
|
"@playwright/test": "^1.57.0",
|
|
193
193
|
"@react-router/node": "^7.12.0",
|
|
194
|
-
"@sentry/react-router": "^10.
|
|
194
|
+
"@sentry/react-router": "^10.36.0",
|
|
195
195
|
"@testing-library/dom": "^10.4.1",
|
|
196
196
|
"@testing-library/jest-dom": "^6.9.1",
|
|
197
197
|
"@total-typescript/ts-reset": "^0.6.1",
|
|
@@ -221,7 +221,7 @@
|
|
|
221
221
|
"mdx-bundler": "^10.1.1",
|
|
222
222
|
"p-queue": "^9.1.0",
|
|
223
223
|
"parse-git-diff": "^0.0.19",
|
|
224
|
-
"pkgmgr": "^1.
|
|
224
|
+
"pkgmgr": "^1.1.1",
|
|
225
225
|
"react": "^19.2.3",
|
|
226
226
|
"react-dom": "^19.2.3",
|
|
227
227
|
"react-router": "^7.12.0",
|
|
@@ -241,7 +241,7 @@
|
|
|
241
241
|
"@types/hast": "^3.0.4",
|
|
242
242
|
"@types/mdast": "^4.0.4",
|
|
243
243
|
"@types/node": "^25.0.9",
|
|
244
|
-
"@types/react": "^19.2.
|
|
244
|
+
"@types/react": "^19.2.9",
|
|
245
245
|
"@types/react-dom": "^19.2.3",
|
|
246
246
|
"@types/shell-quote": "^1.7.5",
|
|
247
247
|
"vitest": "^4.0.17",
|