@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,348 @@
1
+ import { z } from 'zod';
2
+ export declare const getWorkshopRoot: () => string;
3
+ export declare const StackBlitzConfigSchema: z.ZodObject<{
4
+ title: z.ZodOptional<z.ZodString>;
5
+ startScript: z.ZodOptional<z.ZodString>;
6
+ view: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"editor">, z.ZodLiteral<"preview">, z.ZodLiteral<"both">]>>;
7
+ file: z.ZodOptional<z.ZodString>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ title?: string | undefined;
10
+ startScript?: string | undefined;
11
+ view?: "editor" | "preview" | "both" | undefined;
12
+ file?: string | undefined;
13
+ }, {
14
+ title?: string | undefined;
15
+ startScript?: string | undefined;
16
+ view?: "editor" | "preview" | "both" | undefined;
17
+ file?: string | undefined;
18
+ }>;
19
+ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
20
+ title: z.ZodString;
21
+ subtitle: z.ZodOptional<z.ZodString>;
22
+ instructor: z.ZodOptional<z.ZodObject<{
23
+ name: z.ZodOptional<z.ZodString>;
24
+ avatar: z.ZodOptional<z.ZodString>;
25
+ 𝕏: z.ZodOptional<z.ZodString>;
26
+ xHandle: z.ZodOptional<z.ZodString>;
27
+ }, "strip", z.ZodTypeAny, {
28
+ name?: string | undefined;
29
+ avatar?: string | undefined;
30
+ 𝕏?: string | undefined;
31
+ xHandle?: string | undefined;
32
+ }, {
33
+ name?: string | undefined;
34
+ avatar?: string | undefined;
35
+ 𝕏?: string | undefined;
36
+ xHandle?: string | undefined;
37
+ }>>;
38
+ epicWorkshopHost: z.ZodOptional<z.ZodString>;
39
+ epicWorkshopSlug: z.ZodOptional<z.ZodString>;
40
+ product: z.ZodDefault<z.ZodObject<{
41
+ host: z.ZodDefault<z.ZodString>;
42
+ displayName: z.ZodDefault<z.ZodString>;
43
+ displayNameShort: z.ZodDefault<z.ZodString>;
44
+ logo: z.ZodDefault<z.ZodString>;
45
+ slug: z.ZodOptional<z.ZodString>;
46
+ discordChannelId: z.ZodDefault<z.ZodString>;
47
+ discordTags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
48
+ }, "strip", z.ZodTypeAny, {
49
+ host: string;
50
+ displayName: string;
51
+ displayNameShort: string;
52
+ logo: string;
53
+ discordChannelId: string;
54
+ slug?: string | undefined;
55
+ discordTags?: string[] | undefined;
56
+ }, {
57
+ host?: string | undefined;
58
+ displayName?: string | undefined;
59
+ displayNameShort?: string | undefined;
60
+ logo?: string | undefined;
61
+ slug?: string | undefined;
62
+ discordChannelId?: string | undefined;
63
+ discordTags?: string[] | undefined;
64
+ }>>;
65
+ onboardingVideo: z.ZodDefault<z.ZodString>;
66
+ githubRepo: z.ZodString;
67
+ githubRoot: z.ZodString;
68
+ stackBlitzConfig: z.ZodOptional<z.ZodObject<{
69
+ title: z.ZodOptional<z.ZodString>;
70
+ startScript: z.ZodOptional<z.ZodString>;
71
+ view: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"editor">, z.ZodLiteral<"preview">, z.ZodLiteral<"both">]>>;
72
+ file: z.ZodOptional<z.ZodString>;
73
+ }, "strip", z.ZodTypeAny, {
74
+ title?: string | undefined;
75
+ startScript?: string | undefined;
76
+ view?: "editor" | "preview" | "both" | undefined;
77
+ file?: string | undefined;
78
+ }, {
79
+ title?: string | undefined;
80
+ startScript?: string | undefined;
81
+ view?: "editor" | "preview" | "both" | undefined;
82
+ file?: string | undefined;
83
+ }>>;
84
+ forms: z.ZodDefault<z.ZodObject<{
85
+ workshop: z.ZodDefault<z.ZodString>;
86
+ exercise: z.ZodDefault<z.ZodString>;
87
+ }, "strip", z.ZodTypeAny, {
88
+ workshop: string;
89
+ exercise: string;
90
+ }, {
91
+ workshop?: string | undefined;
92
+ exercise?: string | undefined;
93
+ }>>;
94
+ testTab: z.ZodDefault<z.ZodObject<{
95
+ enabled: z.ZodDefault<z.ZodBoolean>;
96
+ }, "strip", z.ZodTypeAny, {
97
+ enabled: boolean;
98
+ }, {
99
+ enabled?: boolean | undefined;
100
+ }>>;
101
+ scripts: z.ZodOptional<z.ZodObject<{
102
+ postupdate: z.ZodOptional<z.ZodString>;
103
+ }, "strip", z.ZodTypeAny, {
104
+ postupdate?: string | undefined;
105
+ }, {
106
+ postupdate?: string | undefined;
107
+ }>>;
108
+ initialRoute: z.ZodDefault<z.ZodOptional<z.ZodString>>;
109
+ notifications: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
110
+ id: z.ZodString;
111
+ title: z.ZodString;
112
+ message: z.ZodString;
113
+ link: z.ZodOptional<z.ZodString>;
114
+ type: z.ZodEnum<["info", "warning", "danger"]>;
115
+ expiresAt: z.ZodNullable<z.ZodDate>;
116
+ }, "strip", z.ZodTypeAny, {
117
+ title: string;
118
+ message: string;
119
+ type: "info" | "warning" | "danger";
120
+ id: string;
121
+ expiresAt: Date | null;
122
+ link?: string | undefined;
123
+ }, {
124
+ title: string;
125
+ message: string;
126
+ type: "info" | "warning" | "danger";
127
+ id: string;
128
+ expiresAt: Date | null;
129
+ link?: string | undefined;
130
+ }>, "many">>>;
131
+ }, "strip", z.ZodTypeAny, {
132
+ title: string;
133
+ product: {
134
+ host: string;
135
+ displayName: string;
136
+ displayNameShort: string;
137
+ logo: string;
138
+ discordChannelId: string;
139
+ slug?: string | undefined;
140
+ discordTags?: string[] | undefined;
141
+ };
142
+ onboardingVideo: string;
143
+ githubRepo: string;
144
+ githubRoot: string;
145
+ forms: {
146
+ workshop: string;
147
+ exercise: string;
148
+ };
149
+ testTab: {
150
+ enabled: boolean;
151
+ };
152
+ initialRoute: string;
153
+ notifications: {
154
+ title: string;
155
+ message: string;
156
+ type: "info" | "warning" | "danger";
157
+ id: string;
158
+ expiresAt: Date | null;
159
+ link?: string | undefined;
160
+ }[];
161
+ subtitle?: string | undefined;
162
+ instructor?: {
163
+ name?: string | undefined;
164
+ avatar?: string | undefined;
165
+ 𝕏?: string | undefined;
166
+ xHandle?: string | undefined;
167
+ } | undefined;
168
+ epicWorkshopHost?: string | undefined;
169
+ epicWorkshopSlug?: string | undefined;
170
+ stackBlitzConfig?: {
171
+ title?: string | undefined;
172
+ startScript?: string | undefined;
173
+ view?: "editor" | "preview" | "both" | undefined;
174
+ file?: string | undefined;
175
+ } | undefined;
176
+ scripts?: {
177
+ postupdate?: string | undefined;
178
+ } | undefined;
179
+ }, {
180
+ title: string;
181
+ githubRepo: string;
182
+ githubRoot: string;
183
+ subtitle?: string | undefined;
184
+ instructor?: {
185
+ name?: string | undefined;
186
+ avatar?: string | undefined;
187
+ 𝕏?: string | undefined;
188
+ xHandle?: string | undefined;
189
+ } | undefined;
190
+ epicWorkshopHost?: string | undefined;
191
+ epicWorkshopSlug?: string | undefined;
192
+ product?: {
193
+ host?: string | undefined;
194
+ displayName?: string | undefined;
195
+ displayNameShort?: string | undefined;
196
+ logo?: string | undefined;
197
+ slug?: string | undefined;
198
+ discordChannelId?: string | undefined;
199
+ discordTags?: string[] | undefined;
200
+ } | undefined;
201
+ onboardingVideo?: string | undefined;
202
+ stackBlitzConfig?: {
203
+ title?: string | undefined;
204
+ startScript?: string | undefined;
205
+ view?: "editor" | "preview" | "both" | undefined;
206
+ file?: string | undefined;
207
+ } | undefined;
208
+ forms?: {
209
+ workshop?: string | undefined;
210
+ exercise?: string | undefined;
211
+ } | undefined;
212
+ testTab?: {
213
+ enabled?: boolean | undefined;
214
+ } | undefined;
215
+ scripts?: {
216
+ postupdate?: string | undefined;
217
+ } | undefined;
218
+ initialRoute?: string | undefined;
219
+ notifications?: {
220
+ title: string;
221
+ message: string;
222
+ type: "info" | "warning" | "danger";
223
+ id: string;
224
+ expiresAt: Date | null;
225
+ link?: string | undefined;
226
+ }[] | undefined;
227
+ }>, {
228
+ product: {
229
+ displayNameShort: string;
230
+ host: string;
231
+ slug: string | undefined;
232
+ displayName: string;
233
+ logo: string;
234
+ discordChannelId: string;
235
+ discordTags?: string[] | undefined;
236
+ };
237
+ title: string;
238
+ onboardingVideo: string;
239
+ githubRepo: string;
240
+ githubRoot: string;
241
+ forms: {
242
+ workshop: string;
243
+ exercise: string;
244
+ };
245
+ testTab: {
246
+ enabled: boolean;
247
+ };
248
+ initialRoute: string;
249
+ notifications: {
250
+ title: string;
251
+ message: string;
252
+ type: "info" | "warning" | "danger";
253
+ id: string;
254
+ expiresAt: Date | null;
255
+ link?: string | undefined;
256
+ }[];
257
+ subtitle?: string | undefined;
258
+ instructor?: {
259
+ name?: string | undefined;
260
+ avatar?: string | undefined;
261
+ 𝕏?: string | undefined;
262
+ xHandle?: string | undefined;
263
+ } | undefined;
264
+ epicWorkshopHost?: string | undefined;
265
+ epicWorkshopSlug?: string | undefined;
266
+ stackBlitzConfig?: {
267
+ title?: string | undefined;
268
+ startScript?: string | undefined;
269
+ view?: "editor" | "preview" | "both" | undefined;
270
+ file?: string | undefined;
271
+ } | undefined;
272
+ scripts?: {
273
+ postupdate?: string | undefined;
274
+ } | undefined;
275
+ }, {
276
+ title: string;
277
+ githubRepo: string;
278
+ githubRoot: string;
279
+ subtitle?: string | undefined;
280
+ instructor?: {
281
+ name?: string | undefined;
282
+ avatar?: string | undefined;
283
+ 𝕏?: string | undefined;
284
+ xHandle?: string | undefined;
285
+ } | undefined;
286
+ epicWorkshopHost?: string | undefined;
287
+ epicWorkshopSlug?: string | undefined;
288
+ product?: {
289
+ host?: string | undefined;
290
+ displayName?: string | undefined;
291
+ displayNameShort?: string | undefined;
292
+ logo?: string | undefined;
293
+ slug?: string | undefined;
294
+ discordChannelId?: string | undefined;
295
+ discordTags?: string[] | undefined;
296
+ } | undefined;
297
+ onboardingVideo?: string | undefined;
298
+ stackBlitzConfig?: {
299
+ title?: string | undefined;
300
+ startScript?: string | undefined;
301
+ view?: "editor" | "preview" | "both" | undefined;
302
+ file?: string | undefined;
303
+ } | undefined;
304
+ forms?: {
305
+ workshop?: string | undefined;
306
+ exercise?: string | undefined;
307
+ } | undefined;
308
+ testTab?: {
309
+ enabled?: boolean | undefined;
310
+ } | undefined;
311
+ scripts?: {
312
+ postupdate?: string | undefined;
313
+ } | undefined;
314
+ initialRoute?: string | undefined;
315
+ notifications?: {
316
+ title: string;
317
+ message: string;
318
+ type: "info" | "warning" | "danger";
319
+ id: string;
320
+ expiresAt: Date | null;
321
+ link?: string | undefined;
322
+ }[] | undefined;
323
+ }>;
324
+ export type WorkshopConfig = z.infer<typeof WorkshopConfigSchema>;
325
+ export declare function getWorkshopConfig(): WorkshopConfig;
326
+ export declare function getStackBlitzUrl({ fullPath, title, type, }: {
327
+ fullPath: string;
328
+ title: string;
329
+ type: string;
330
+ }): Promise<string | null>;
331
+ export declare function getAppConfig(fullPath: string): Promise<{
332
+ stackBlitzConfig: {
333
+ title?: string | undefined;
334
+ startScript?: string | undefined;
335
+ view?: "editor" | "preview" | "both" | undefined;
336
+ file?: string | undefined;
337
+ } | null;
338
+ testTab: {
339
+ enabled: boolean;
340
+ };
341
+ scripts: {
342
+ test?: string | undefined;
343
+ dev?: string | undefined;
344
+ };
345
+ initialRoute: string;
346
+ }>;
347
+ export {};
348
+ //# sourceMappingURL=config.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.server.d.ts","sourceRoot":"","sources":["../../src/config.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,eAAe,cACsB,CAAA;AAIlD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;EAWjC,CAAA;AAUF,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6EvB,CAAA;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAUjE,wBAAgB,iBAAiB,IAAI,cAAc,CAgElD;AAED,wBAAsB,gBAAgB,CAAC,EACtC,QAAQ,EACR,KAAK,EACL,IAAI,GACJ,EAAE;IACF,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACZ,0BA6BA;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;GA0ElD"}
@@ -0,0 +1,231 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { z } from 'zod';
4
+ export const getWorkshopRoot = () => process.env.EPICSHOP_CONTEXT_CWD ?? process.cwd();
5
+ const getRootPkgJsonPath = () => path.join(getWorkshopRoot(), 'package.json');
6
+ export const StackBlitzConfigSchema = z.object({
7
+ // we default this to `${exerciseTitle} (${type})`
8
+ title: z.string().optional(),
9
+ // stackblitz defaults this to dev automatically
10
+ startScript: z.string().optional(),
11
+ // if no value is provided, then stackblitz defaults this to whatever
12
+ // looks best based on the width of the screen
13
+ view: z
14
+ .union([z.literal('editor'), z.literal('preview'), z.literal('both')])
15
+ .optional(),
16
+ file: z.string().optional(),
17
+ });
18
+ const InstructorSchema = z.object({
19
+ name: z.string().optional(),
20
+ avatar: z.string().optional(),
21
+ 𝕏: z.string().optional(),
22
+ xHandle: z.string().optional(),
23
+ });
24
+ // most defaults are for backwards compatibility
25
+ const WorkshopConfigSchema = z
26
+ .object({
27
+ title: z.string(),
28
+ subtitle: z.string().optional(),
29
+ instructor: InstructorSchema.optional(),
30
+ epicWorkshopHost: z.string().optional(),
31
+ epicWorkshopSlug: z.string().optional(),
32
+ product: z
33
+ .object({
34
+ host: z.string().default('www.epicweb.dev'),
35
+ displayName: z.string().default('EpicWeb.dev'),
36
+ displayNameShort: z.string().default('Epic Web'),
37
+ logo: z.string().default('/logo.svg'),
38
+ slug: z.string().optional(),
39
+ discordChannelId: z.string().default('1161045224907341972'),
40
+ discordTags: z.array(z.string()).optional(),
41
+ })
42
+ .default({}),
43
+ onboardingVideo: z
44
+ .string()
45
+ .default('https://www.epicweb.dev/tips/get-started-with-the-epic-workshop-app'),
46
+ githubRepo: z.string(),
47
+ githubRoot: z.string(),
48
+ stackBlitzConfig: StackBlitzConfigSchema.optional(),
49
+ forms: z
50
+ .object({
51
+ workshop: z
52
+ .string()
53
+ .default('https://docs.google.com/forms/d/e/1FAIpQLSdRmj9p8-5zyoqRzxp3UpqSbC3aFkweXvvJIKes0a5s894gzg/viewform?hl=en&embedded=true&entry.2123647600={workshopTitle}'),
54
+ exercise: z
55
+ .string()
56
+ .default('https://docs.google.com/forms/d/e/1FAIpQLSf3o9xyjQepTlOTH5Z7ZwkeSTdXh6YWI_RGc9KiyD3oUN0p6w/viewform?hl=en&embedded=true&entry.1836176234={workshopTitle}&entry.428900931={exerciseTitle}'),
57
+ })
58
+ .default({}),
59
+ testTab: z
60
+ .object({
61
+ enabled: z.boolean().default(true),
62
+ })
63
+ .default({}),
64
+ scripts: z
65
+ .object({
66
+ postupdate: z.string().optional(),
67
+ })
68
+ .optional(),
69
+ initialRoute: z.string().optional().default('/'),
70
+ notifications: z
71
+ .array(z.object({
72
+ id: z.string(),
73
+ title: z.string(),
74
+ message: z.string(),
75
+ link: z.string().optional(),
76
+ type: z.enum(['info', 'warning', 'danger']),
77
+ expiresAt: z.date().nullable(),
78
+ }))
79
+ .optional()
80
+ .default([]),
81
+ })
82
+ .transform((data) => {
83
+ return {
84
+ ...data,
85
+ product: {
86
+ ...data.product,
87
+ displayNameShort: data.product.displayNameShort ?? data.product.displayName,
88
+ // for backwards compatibility
89
+ host: data.product.host ?? data.epicWorkshopHost,
90
+ slug: data.product.slug ?? data.epicWorkshopSlug,
91
+ },
92
+ };
93
+ });
94
+ const configCache = {
95
+ config: null,
96
+ modified: 0,
97
+ };
98
+ export function getWorkshopConfig() {
99
+ if (configCache.config &&
100
+ configCache.modified > fs.statSync(getRootPkgJsonPath()).mtimeMs) {
101
+ return configCache.config;
102
+ }
103
+ const packageJsonPath = path.join(getWorkshopRoot(), 'package.json');
104
+ let packageJson;
105
+ try {
106
+ const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
107
+ packageJson = JSON.parse(packageJsonContent);
108
+ }
109
+ catch (error) {
110
+ console.error(`Error reading or parsing package.json:`, error);
111
+ if (error instanceof Error && error.message.includes('ENOENT')) {
112
+ throw new Error(`package.json not found at ${packageJsonPath}. Please ensure you're running the command from the correct directory.`);
113
+ }
114
+ else if (error instanceof SyntaxError) {
115
+ throw new Error(`Invalid JSON in package.json at ${packageJsonPath}. Please check the file for syntax errors.`);
116
+ }
117
+ throw new Error(`Could not find and parse package.json at ${packageJsonPath}`);
118
+ }
119
+ const epicshopConfig = packageJson.epicshop || {};
120
+ // Set githubRepo and githubRoot before parsing
121
+ if (epicshopConfig.githubRepo) {
122
+ epicshopConfig.githubRoot = `${epicshopConfig.githubRepo.replace(/\/$/, '')}/tree/main`;
123
+ }
124
+ else if (epicshopConfig.githubRoot) {
125
+ epicshopConfig.githubRepo = epicshopConfig.githubRoot.replace(/\/(blob|tree)\/.*$/, '');
126
+ epicshopConfig.githubRoot = `${epicshopConfig.githubRepo}/tree/main`;
127
+ }
128
+ else {
129
+ throw new Error('Either githubRepo or githubRoot is required in the epicshop configuration');
130
+ }
131
+ try {
132
+ const parsedConfig = WorkshopConfigSchema.parse(epicshopConfig);
133
+ configCache.config = parsedConfig;
134
+ configCache.modified = fs.statSync(getRootPkgJsonPath()).mtimeMs;
135
+ return parsedConfig;
136
+ }
137
+ catch (error) {
138
+ if (error instanceof z.ZodError) {
139
+ const flattenedErrors = error.flatten();
140
+ const errorMessages = Object.entries(flattenedErrors.fieldErrors)
141
+ .map(([field, errors]) => `${field}: ${errors?.join(', ')}`)
142
+ .concat(flattenedErrors.formErrors);
143
+ throw new Error(`Invalid epicshop configuration in ${packageJsonPath}:\n${errorMessages.join('\n')}`);
144
+ }
145
+ throw error;
146
+ }
147
+ }
148
+ export async function getStackBlitzUrl({ fullPath, title, type, }) {
149
+ const workshopConfig = getWorkshopConfig();
150
+ const appConfig = await getAppConfig(fullPath);
151
+ if (appConfig.stackBlitzConfig === null)
152
+ return null;
153
+ let githubRootUrlString = workshopConfig.githubRoot;
154
+ const githubRootUrl = new URL(githubRootUrlString.replace(/\/blob\//, '/tree/'));
155
+ const githubPart = githubRootUrl.pathname;
156
+ const stackBlitzConfig = {
157
+ ...appConfig.stackBlitzConfig,
158
+ title: appConfig.stackBlitzConfig?.title ?? `${title} (${type})`,
159
+ };
160
+ const params = new URLSearchParams(stackBlitzConfig);
161
+ const relativePath = fullPath.replace(`${getWorkshopRoot()}${path.sep}`, '');
162
+ const stackBlitzUrl = new URL(`/github${githubPart}/${relativePath}?${params}`, 'https://stackblitz.com');
163
+ return stackBlitzUrl.toString();
164
+ }
165
+ export async function getAppConfig(fullPath) {
166
+ const workshopConfig = getWorkshopConfig();
167
+ let epicshopConfig = {};
168
+ let scripts = {};
169
+ const packageJsonPath = path.join(fullPath, 'package.json');
170
+ const packageJsonExists = await fs.promises
171
+ .access(packageJsonPath, fs.constants.F_OK)
172
+ .then(() => true)
173
+ .catch(() => false);
174
+ if (packageJsonExists) {
175
+ const pkg = JSON.parse(await fs.promises.readFile(path.join(fullPath, 'package.json'), 'utf8'));
176
+ epicshopConfig = pkg.epicshop ?? {};
177
+ scripts = pkg.scripts ?? {};
178
+ }
179
+ const AppConfigSchema = z.object({
180
+ stackBlitzConfig: StackBlitzConfigSchema.nullable()
181
+ .optional()
182
+ .transform((appStackBlitzConfig) => {
183
+ if (appStackBlitzConfig === null)
184
+ return null;
185
+ return {
186
+ ...workshopConfig.stackBlitzConfig,
187
+ ...appStackBlitzConfig,
188
+ };
189
+ }),
190
+ testTab: z
191
+ .object({
192
+ enabled: z
193
+ .boolean()
194
+ .optional()
195
+ .default(workshopConfig.testTab?.enabled ?? true),
196
+ })
197
+ .default({}),
198
+ scripts: z
199
+ .object({
200
+ test: z.string().optional(),
201
+ dev: z.string().optional(),
202
+ })
203
+ .default({}),
204
+ initialRoute: z.string().optional().default(workshopConfig.initialRoute),
205
+ });
206
+ const appConfig = {
207
+ stackBlitzConfig: epicshopConfig.stackBlitzConfig,
208
+ testTab: {
209
+ enabled: epicshopConfig.testTab?.enabled,
210
+ },
211
+ scripts: {
212
+ test: scripts.test,
213
+ dev: scripts.dev,
214
+ },
215
+ initialRoute: epicshopConfig.initialRoute,
216
+ };
217
+ try {
218
+ return AppConfigSchema.parse(appConfig);
219
+ }
220
+ catch (error) {
221
+ if (error instanceof z.ZodError) {
222
+ const flattenedErrors = error.flatten();
223
+ const errorMessages = Object.entries(flattenedErrors.fieldErrors)
224
+ .map(([field, errors]) => `${field}: ${errors?.join(', ')}`)
225
+ .concat(flattenedErrors.formErrors);
226
+ throw new Error(`Invalid app configuration for ${fullPath}:\n${errorMessages.join('\n')}`);
227
+ }
228
+ throw error;
229
+ }
230
+ }
231
+ //# sourceMappingURL=config.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.server.js","sourceRoot":"","sources":["../../src/config.server.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport { z } from 'zod'\n\nexport const getWorkshopRoot = () =>\n\tprocess.env.EPICSHOP_CONTEXT_CWD ?? process.cwd()\n\nconst getRootPkgJsonPath = () => path.join(getWorkshopRoot(), '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})\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\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.string(),\n\t\tgithubRoot: z.string(),\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\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 packageJsonPath = path.join(getWorkshopRoot(), 'package.json')\n\tlet packageJson: any\n\n\ttry {\n\t\tconst packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8')\n\t\tpackageJson = 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\tconst epicshopConfig = packageJson.epicshop || {}\n\n\t// Set githubRepo and githubRoot before parsing\n\tif (epicshopConfig.githubRepo) {\n\t\tepicshopConfig.githubRoot = `${epicshopConfig.githubRepo.replace(/\\/$/, '')}/tree/main`\n\t} else if (epicshopConfig.githubRoot) {\n\t\tepicshopConfig.githubRepo = epicshopConfig.githubRoot.replace(\n\t\t\t/\\/(blob|tree)\\/.*$/,\n\t\t\t'',\n\t\t)\n\t\tepicshopConfig.githubRoot = `${epicshopConfig.githubRepo}/tree/main`\n\t} else {\n\t\tthrow new Error(\n\t\t\t'Either githubRepo or githubRoot is required in the epicshop configuration',\n\t\t)\n\t}\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 ${packageJsonPath}:\\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\tconst stackBlitzConfig = {\n\t\t...appConfig.stackBlitzConfig,\n\t\ttitle: appConfig.stackBlitzConfig?.title ?? `${title} (${type})`,\n\t}\n\n\tconst params = new URLSearchParams(stackBlitzConfig as Record<string, string>)\n\n\tconst relativePath = fullPath.replace(`${getWorkshopRoot()}${path.sep}`, '')\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"]}