@epic-web/workshop-utils 6.19.7 → 6.20.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.
@@ -146,6 +146,7 @@ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
146
146
  expiresAt: Date | null;
147
147
  link?: string | undefined;
148
148
  }>, "many">>>;
149
+ sidecarProcesses: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
149
150
  }, "strip", z.ZodTypeAny, {
150
151
  githubRepo: string;
151
152
  githubRoot: string;
@@ -176,6 +177,7 @@ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
176
177
  expiresAt: Date | null;
177
178
  link?: string | undefined;
178
179
  }[];
180
+ sidecarProcesses: Record<string, string>;
179
181
  subtitle?: string | undefined;
180
182
  instructor?: {
181
183
  name?: string | undefined;
@@ -250,6 +252,7 @@ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
250
252
  expiresAt: Date | null;
251
253
  link?: string | undefined;
252
254
  }[] | undefined;
255
+ sidecarProcesses?: Record<string, string> | undefined;
253
256
  }>, {
254
257
  product: {
255
258
  displayNameShort: string;
@@ -280,6 +283,7 @@ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
280
283
  expiresAt: Date | null;
281
284
  link?: string | undefined;
282
285
  }[];
286
+ sidecarProcesses: Record<string, string>;
283
287
  subtitle?: string | undefined;
284
288
  instructor?: {
285
289
  name?: string | undefined;
@@ -354,6 +358,7 @@ declare const WorkshopConfigSchema: z.ZodEffects<z.ZodObject<{
354
358
  expiresAt: Date | null;
355
359
  link?: string | undefined;
356
360
  }[] | undefined;
361
+ sidecarProcesses?: Record<string, string> | undefined;
357
362
  }>;
358
363
  export type WorkshopConfig = z.infer<typeof WorkshopConfigSchema>;
359
364
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config.server.d.ts","sourceRoot":"","sources":["../../src/config.server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAMvB,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;EAcjC,CAAA;AAUF,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkFvB,CAAA;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAiCjE;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,UAE1C;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAqClD;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,0BA0EA;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;GA0ElD"}
1
+ {"version":3,"file":"config.server.d.ts","sourceRoot":"","sources":["../../src/config.server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAMvB,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;EAcjC,CAAA;AAUF,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsFvB,CAAA;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAiCjE;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,UAE1C;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAqClD;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,0BA0EA;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;GA0ElD"}
@@ -88,6 +88,10 @@ const WorkshopConfigSchema = z
88
88
  }))
89
89
  .optional()
90
90
  .default([]),
91
+ sidecarProcesses: z
92
+ .record(z.string(), z.string())
93
+ .optional()
94
+ .default({}),
91
95
  })
92
96
  .transform((data) => {
93
97
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"config.server.js","sourceRoot":"","sources":["../../src/config.server.ts"],"names":[],"mappings":"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","sourcesContent":["// eslint-disable-next-line import/order -- this must be first\nimport { getEnv } from './init-env.js'\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { z } from 'zod'\nimport { handleGitHubRepoAndRoot } from './utils.js'\n\nconst getRootPkgJsonPath = () =>\n\tpath.join(getEnv().EPICSHOP_CONTEXT_CWD, 'package.json')\n\nexport const StackBlitzConfigSchema = z.object({\n\t// we default this to `${exerciseTitle} (${type})`\n\ttitle: z.string().optional(),\n\t// stackblitz defaults this to dev automatically\n\tstartScript: z.string().optional(),\n\t// if no value is provided, then stackblitz defaults this to whatever\n\t// looks best based on the width of the screen\n\tview: z\n\t\t.union([z.literal('editor'), z.literal('preview'), z.literal('both')])\n\t\t.optional(),\n\tfile: z.string().optional(),\n\thidedevtools: z.string().optional(),\n\tterminalHeight: z.string().optional(),\n\thideNavigation: z.string().optional(),\n})\n\nconst InstructorSchema = z.object({\n\tname: z.string().optional(),\n\tavatar: z.string().optional(),\n\tš•: z.string().optional(),\n\txHandle: z.string().optional(),\n})\n\n// most defaults are for backwards compatibility\nconst WorkshopConfigSchema = z\n\t.object({\n\t\ttitle: z.string(),\n\t\tsubtitle: z.string().optional(),\n\t\tinstructor: InstructorSchema.optional(),\n\t\tepicWorkshopHost: z.string().optional(),\n\t\tepicWorkshopSlug: z.string().optional(),\n\t\tsubdomain: z.string().optional(),\n\t\tproduct: z\n\t\t\t.object({\n\t\t\t\thost: z.string().default('www.epicweb.dev'),\n\t\t\t\tdisplayName: z.string().default('EpicWeb.dev'),\n\t\t\t\tdisplayNameShort: z.string().default('Epic Web'),\n\t\t\t\tlogo: z.string().default('/logo.svg'),\n\t\t\t\tslug: z.string().optional(),\n\t\t\t\tdiscordChannelId: z.string().default('1161045224907341972'),\n\t\t\t\tdiscordTags: z.array(z.string()).optional(),\n\t\t\t})\n\t\t\t.default({}),\n\t\tonboardingVideo: z\n\t\t\t.string()\n\t\t\t.default(\n\t\t\t\t'https://www.epicweb.dev/tips/get-started-with-the-epic-workshop-app',\n\t\t\t),\n\t\tgithubRepo: z\n\t\t\t.string()\n\t\t\t.transform((githubRepo) => githubRepo ?? getEnv().EPICSHOP_GITHUB_REPO),\n\t\tgithubRoot: z\n\t\t\t.string()\n\t\t\t.transform((githubRoot) => githubRoot ?? getEnv().EPICSHOP_GITHUB_ROOT),\n\t\tstackBlitzConfig: StackBlitzConfigSchema.optional(),\n\t\tforms: z\n\t\t\t.object({\n\t\t\t\tworkshop: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.default(\n\t\t\t\t\t\t'https://docs.google.com/forms/d/e/1FAIpQLSdRmj9p8-5zyoqRzxp3UpqSbC3aFkweXvvJIKes0a5s894gzg/viewform?hl=en&embedded=true&entry.2123647600={workshopTitle}',\n\t\t\t\t\t),\n\t\t\t\texercise: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.default(\n\t\t\t\t\t\t'https://docs.google.com/forms/d/e/1FAIpQLSf3o9xyjQepTlOTH5Z7ZwkeSTdXh6YWI_RGc9KiyD3oUN0p6w/viewform?hl=en&embedded=true&entry.1836176234={workshopTitle}&entry.428900931={exerciseTitle}',\n\t\t\t\t\t),\n\t\t\t})\n\t\t\t.default({}),\n\t\ttestTab: z\n\t\t\t.object({\n\t\t\t\tenabled: z.boolean().default(true),\n\t\t\t})\n\t\t\t.default({}),\n\t\tscripts: z\n\t\t\t.object({\n\t\t\t\tpostupdate: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tinitialRoute: z.string().optional().default('/'),\n\t\tnotifications: z\n\t\t\t.array(\n\t\t\t\tz.object({\n\t\t\t\t\tid: z.string(),\n\t\t\t\t\ttitle: z.string(),\n\t\t\t\t\tmessage: z.string(),\n\t\t\t\t\tlink: z.string().optional(),\n\t\t\t\t\ttype: z.enum(['info', 'warning', 'danger']),\n\t\t\t\t\texpiresAt: z.date().nullable(),\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.optional()\n\t\t\t.default([]),\n\t})\n\t.transform((data) => {\n\t\treturn {\n\t\t\t...data,\n\t\t\tproduct: {\n\t\t\t\t...data.product,\n\t\t\t\tdisplayNameShort:\n\t\t\t\t\tdata.product.displayNameShort ?? data.product.displayName,\n\t\t\t\t// for backwards compatibility\n\t\t\t\thost: data.product.host ?? data.epicWorkshopHost,\n\t\t\t\tslug: data.product.slug ?? data.epicWorkshopSlug,\n\t\t\t},\n\t\t}\n\t})\n\nexport type WorkshopConfig = z.infer<typeof WorkshopConfigSchema>\n\nconst configCache: {\n\tconfig: WorkshopConfig | null\n\tmodified: number\n} = {\n\tconfig: null,\n\tmodified: 0,\n}\n\n// Utility to read and parse the root package.json\nfunction readRootPkgJson(): any {\n\tconst packageJsonPath = getRootPkgJsonPath()\n\ttry {\n\t\tconst packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8')\n\t\treturn JSON.parse(packageJsonContent)\n\t} catch (error) {\n\t\tconsole.error(`Error reading or parsing package.json:`, error)\n\t\tif (error instanceof Error && error.message.includes('ENOENT')) {\n\t\t\tthrow new Error(\n\t\t\t\t`package.json not found at ${packageJsonPath}. Please ensure you're running the command from the correct directory.`,\n\t\t\t)\n\t\t} else if (error instanceof SyntaxError) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid JSON in package.json at ${packageJsonPath}. Please check the file for syntax errors.`,\n\t\t\t)\n\t\t}\n\t\tthrow new Error(\n\t\t\t`Could not find and parse package.json at ${packageJsonPath}`,\n\t\t)\n\t}\n}\n\n/**\n * This used to support subdomains on localhost, but that caused too many issues.\n */\nexport function getWorkshopUrl(port: number) {\n\treturn `http://localhost:${port}`\n}\n\nexport function getWorkshopConfig(): WorkshopConfig {\n\tif (\n\t\tconfigCache.config &&\n\t\tconfigCache.modified > fs.statSync(getRootPkgJsonPath()).mtimeMs\n\t) {\n\t\treturn configCache.config\n\t}\n\n\tconst packageJson = readRootPkgJson()\n\n\tconst epicshopConfig = packageJson.epicshop || {}\n\n\t// Set githubRepo and githubRoot before parsing\n\tconst { githubRepo, githubRoot } = handleGitHubRepoAndRoot({\n\t\tgithubRepo: epicshopConfig.githubRepo,\n\t\tgithubRoot: epicshopConfig.githubRoot,\n\t})\n\tepicshopConfig.githubRepo = githubRepo\n\tepicshopConfig.githubRoot = githubRoot\n\n\ttry {\n\t\tconst parsedConfig = WorkshopConfigSchema.parse(epicshopConfig)\n\t\tconfigCache.config = parsedConfig\n\t\tconfigCache.modified = fs.statSync(getRootPkgJsonPath()).mtimeMs\n\t\treturn parsedConfig\n\t} catch (error) {\n\t\tif (error instanceof z.ZodError) {\n\t\t\tconst flattenedErrors = error.flatten()\n\t\t\tconst errorMessages = Object.entries(flattenedErrors.fieldErrors)\n\t\t\t\t.map(([field, errors]) => `${field}: ${errors?.join(', ')}`)\n\t\t\t\t.concat(flattenedErrors.formErrors)\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid epicshop configuration in ${getRootPkgJsonPath()}:\\n${errorMessages.join('\\n')}`,\n\t\t\t)\n\t\t}\n\t\tthrow error\n\t}\n}\n\nexport async function getStackBlitzUrl({\n\tfullPath,\n\ttitle,\n\ttype,\n}: {\n\tfullPath: string\n\ttitle: string\n\ttype: string\n}) {\n\tconst workshopConfig = getWorkshopConfig()\n\tconst appConfig = await getAppConfig(fullPath)\n\n\tif (appConfig.stackBlitzConfig === null) return null\n\n\tlet githubRootUrlString = workshopConfig.githubRoot\n\n\tconst githubRootUrl = new URL(\n\t\tgithubRootUrlString.replace(/\\/blob\\//, '/tree/'),\n\t)\n\n\tconst githubPart = githubRootUrl.pathname\n\n\t// Check if package.json exists to determine if this is a simple exercise\n\tconst packageJsonPath = path.join(fullPath, 'package.json')\n\tconst packageJsonExists = await fs.promises\n\t\t.access(packageJsonPath, fs.constants.F_OK)\n\t\t.then(() => true)\n\t\t.catch(() => false)\n\n\tlet stackBlitzConfig = {\n\t\t...appConfig.stackBlitzConfig,\n\t\ttitle: appConfig.stackBlitzConfig?.title ?? `${title} (${type})`,\n\t}\n\n\t// For simple exercises without package.json, configure StackBlitz to show only editor\n\tif (!packageJsonExists) {\n\t\t// Find the first existing file from the priority list\n\t\tconst priorityFiles = [\n\t\t\t'index.html',\n\t\t\t'index.tsx',\n\t\t\t'index.ts',\n\t\t\t'index.jsx',\n\t\t\t'index.js',\n\t\t\t'README.mdx',\n\t\t\t'README.md',\n\t\t]\n\n\t\tlet defaultFile: string | null = null\n\t\tfor (const fileName of priorityFiles) {\n\t\t\tconst filePath = path.join(fullPath, fileName)\n\t\t\ttry {\n\t\t\t\tawait fs.promises.access(filePath, fs.constants.F_OK)\n\t\t\t\tdefaultFile = fileName\n\t\t\t\tbreak\n\t\t\t} catch {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tstackBlitzConfig = {\n\t\t\t...stackBlitzConfig,\n\t\t\tview: 'editor', // Show only editor, no preview or terminal\n\t\t\thidedevtools: '1', // Hide the console/devtools\n\t\t\tterminalHeight: '0', // Hide the terminal completely\n\t\t\thideNavigation: '1', // Hide the preview's URL bar\n\t\t\t...(defaultFile && { file: defaultFile }), // Set default file if found\n\t\t}\n\t}\n\n\tconst params = new URLSearchParams(stackBlitzConfig as Record<string, string>)\n\n\tconst relativePath = fullPath.replace(\n\t\t`${getEnv().EPICSHOP_CONTEXT_CWD}${path.sep}`,\n\t\t'',\n\t)\n\n\tconst stackBlitzUrl = new URL(\n\t\t`/github${githubPart}/${relativePath}?${params}`,\n\t\t'https://stackblitz.com',\n\t)\n\n\treturn stackBlitzUrl.toString()\n}\n\nexport async function getAppConfig(fullPath: string) {\n\tconst workshopConfig = getWorkshopConfig()\n\n\tlet epicshopConfig: Record<string, any> = {}\n\tlet scripts: Record<string, string> = {}\n\n\tconst packageJsonPath = path.join(fullPath, 'package.json')\n\tconst packageJsonExists = await fs.promises\n\t\t.access(packageJsonPath, fs.constants.F_OK)\n\t\t.then(() => true)\n\t\t.catch(() => false)\n\n\tif (packageJsonExists) {\n\t\tconst pkg = JSON.parse(\n\t\t\tawait fs.promises.readFile(path.join(fullPath, 'package.json'), 'utf8'),\n\t\t) as any\n\t\tepicshopConfig = pkg.epicshop ?? {}\n\t\tscripts = pkg.scripts ?? {}\n\t}\n\n\tconst AppConfigSchema = z.object({\n\t\tstackBlitzConfig: StackBlitzConfigSchema.nullable()\n\t\t\t.optional()\n\t\t\t.transform((appStackBlitzConfig) => {\n\t\t\t\tif (appStackBlitzConfig === null) return null\n\n\t\t\t\treturn {\n\t\t\t\t\t...workshopConfig.stackBlitzConfig,\n\t\t\t\t\t...appStackBlitzConfig,\n\t\t\t\t}\n\t\t\t}),\n\t\ttestTab: z\n\t\t\t.object({\n\t\t\t\tenabled: z\n\t\t\t\t\t.boolean()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.default(workshopConfig.testTab?.enabled ?? true),\n\t\t\t})\n\t\t\t.default({}),\n\t\tscripts: z\n\t\t\t.object({\n\t\t\t\ttest: z.string().optional(),\n\t\t\t\tdev: z.string().optional(),\n\t\t\t})\n\t\t\t.default({}),\n\t\tinitialRoute: z.string().optional().default(workshopConfig.initialRoute),\n\t})\n\n\tconst appConfig = {\n\t\tstackBlitzConfig: epicshopConfig.stackBlitzConfig,\n\t\ttestTab: {\n\t\t\tenabled: epicshopConfig.testTab?.enabled,\n\t\t},\n\t\tscripts: {\n\t\t\ttest: scripts.test,\n\t\t\tdev: scripts.dev,\n\t\t},\n\t\tinitialRoute: epicshopConfig.initialRoute,\n\t}\n\n\ttry {\n\t\treturn AppConfigSchema.parse(appConfig)\n\t} catch (error) {\n\t\tif (error instanceof z.ZodError) {\n\t\t\tconst flattenedErrors = error.flatten()\n\t\t\tconst errorMessages = Object.entries(flattenedErrors.fieldErrors)\n\t\t\t\t.map(([field, errors]) => `${field}: ${errors?.join(', ')}`)\n\t\t\t\t.concat(flattenedErrors.formErrors)\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid app configuration for ${fullPath}:\\n${errorMessages.join('\\n')}`,\n\t\t\t)\n\t\t}\n\t\tthrow error\n\t}\n}\n"]}
1
+ {"version":3,"file":"config.server.js","sourceRoot":"","sources":["../../src/config.server.ts"],"names":[],"mappings":"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","sourcesContent":["// eslint-disable-next-line import/order -- this must be first\nimport { getEnv } from './init-env.js'\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { z } from 'zod'\nimport { handleGitHubRepoAndRoot } from './utils.js'\n\nconst getRootPkgJsonPath = () =>\n\tpath.join(getEnv().EPICSHOP_CONTEXT_CWD, 'package.json')\n\nexport const StackBlitzConfigSchema = z.object({\n\t// we default this to `${exerciseTitle} (${type})`\n\ttitle: z.string().optional(),\n\t// stackblitz defaults this to dev automatically\n\tstartScript: z.string().optional(),\n\t// if no value is provided, then stackblitz defaults this to whatever\n\t// looks best based on the width of the screen\n\tview: z\n\t\t.union([z.literal('editor'), z.literal('preview'), z.literal('both')])\n\t\t.optional(),\n\tfile: z.string().optional(),\n\thidedevtools: z.string().optional(),\n\tterminalHeight: z.string().optional(),\n\thideNavigation: z.string().optional(),\n})\n\nconst InstructorSchema = z.object({\n\tname: z.string().optional(),\n\tavatar: z.string().optional(),\n\tš•: z.string().optional(),\n\txHandle: z.string().optional(),\n})\n\n// most defaults are for backwards compatibility\nconst WorkshopConfigSchema = z\n\t.object({\n\t\ttitle: z.string(),\n\t\tsubtitle: z.string().optional(),\n\t\tinstructor: InstructorSchema.optional(),\n\t\tepicWorkshopHost: z.string().optional(),\n\t\tepicWorkshopSlug: z.string().optional(),\n\t\tsubdomain: z.string().optional(),\n\t\tproduct: z\n\t\t\t.object({\n\t\t\t\thost: z.string().default('www.epicweb.dev'),\n\t\t\t\tdisplayName: z.string().default('EpicWeb.dev'),\n\t\t\t\tdisplayNameShort: z.string().default('Epic Web'),\n\t\t\t\tlogo: z.string().default('/logo.svg'),\n\t\t\t\tslug: z.string().optional(),\n\t\t\t\tdiscordChannelId: z.string().default('1161045224907341972'),\n\t\t\t\tdiscordTags: z.array(z.string()).optional(),\n\t\t\t})\n\t\t\t.default({}),\n\t\tonboardingVideo: z\n\t\t\t.string()\n\t\t\t.default(\n\t\t\t\t'https://www.epicweb.dev/tips/get-started-with-the-epic-workshop-app',\n\t\t\t),\n\t\tgithubRepo: z\n\t\t\t.string()\n\t\t\t.transform((githubRepo) => githubRepo ?? getEnv().EPICSHOP_GITHUB_REPO),\n\t\tgithubRoot: z\n\t\t\t.string()\n\t\t\t.transform((githubRoot) => githubRoot ?? getEnv().EPICSHOP_GITHUB_ROOT),\n\t\tstackBlitzConfig: StackBlitzConfigSchema.optional(),\n\t\tforms: z\n\t\t\t.object({\n\t\t\t\tworkshop: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.default(\n\t\t\t\t\t\t'https://docs.google.com/forms/d/e/1FAIpQLSdRmj9p8-5zyoqRzxp3UpqSbC3aFkweXvvJIKes0a5s894gzg/viewform?hl=en&embedded=true&entry.2123647600={workshopTitle}',\n\t\t\t\t\t),\n\t\t\t\texercise: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.default(\n\t\t\t\t\t\t'https://docs.google.com/forms/d/e/1FAIpQLSf3o9xyjQepTlOTH5Z7ZwkeSTdXh6YWI_RGc9KiyD3oUN0p6w/viewform?hl=en&embedded=true&entry.1836176234={workshopTitle}&entry.428900931={exerciseTitle}',\n\t\t\t\t\t),\n\t\t\t})\n\t\t\t.default({}),\n\t\ttestTab: z\n\t\t\t.object({\n\t\t\t\tenabled: z.boolean().default(true),\n\t\t\t})\n\t\t\t.default({}),\n\t\tscripts: z\n\t\t\t.object({\n\t\t\t\tpostupdate: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tinitialRoute: z.string().optional().default('/'),\n\t\tnotifications: z\n\t\t\t.array(\n\t\t\t\tz.object({\n\t\t\t\t\tid: z.string(),\n\t\t\t\t\ttitle: z.string(),\n\t\t\t\t\tmessage: z.string(),\n\t\t\t\t\tlink: z.string().optional(),\n\t\t\t\t\ttype: z.enum(['info', 'warning', 'danger']),\n\t\t\t\t\texpiresAt: z.date().nullable(),\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.optional()\n\t\t\t.default([]),\n\t\tsidecarProcesses: z\n\t\t\t.record(z.string(), z.string())\n\t\t\t.optional()\n\t\t\t.default({}),\n\t})\n\t.transform((data) => {\n\t\treturn {\n\t\t\t...data,\n\t\t\tproduct: {\n\t\t\t\t...data.product,\n\t\t\t\tdisplayNameShort:\n\t\t\t\t\tdata.product.displayNameShort ?? data.product.displayName,\n\t\t\t\t// for backwards compatibility\n\t\t\t\thost: data.product.host ?? data.epicWorkshopHost,\n\t\t\t\tslug: data.product.slug ?? data.epicWorkshopSlug,\n\t\t\t},\n\t\t}\n\t})\n\nexport type WorkshopConfig = z.infer<typeof WorkshopConfigSchema>\n\nconst configCache: {\n\tconfig: WorkshopConfig | null\n\tmodified: number\n} = {\n\tconfig: null,\n\tmodified: 0,\n}\n\n// Utility to read and parse the root package.json\nfunction readRootPkgJson(): any {\n\tconst packageJsonPath = getRootPkgJsonPath()\n\ttry {\n\t\tconst packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8')\n\t\treturn JSON.parse(packageJsonContent)\n\t} catch (error) {\n\t\tconsole.error(`Error reading or parsing package.json:`, error)\n\t\tif (error instanceof Error && error.message.includes('ENOENT')) {\n\t\t\tthrow new Error(\n\t\t\t\t`package.json not found at ${packageJsonPath}. Please ensure you're running the command from the correct directory.`,\n\t\t\t)\n\t\t} else if (error instanceof SyntaxError) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid JSON in package.json at ${packageJsonPath}. Please check the file for syntax errors.`,\n\t\t\t)\n\t\t}\n\t\tthrow new Error(\n\t\t\t`Could not find and parse package.json at ${packageJsonPath}`,\n\t\t)\n\t}\n}\n\n/**\n * This used to support subdomains on localhost, but that caused too many issues.\n */\nexport function getWorkshopUrl(port: number) {\n\treturn `http://localhost:${port}`\n}\n\nexport function getWorkshopConfig(): WorkshopConfig {\n\tif (\n\t\tconfigCache.config &&\n\t\tconfigCache.modified > fs.statSync(getRootPkgJsonPath()).mtimeMs\n\t) {\n\t\treturn configCache.config\n\t}\n\n\tconst packageJson = readRootPkgJson()\n\n\tconst epicshopConfig = packageJson.epicshop || {}\n\n\t// Set githubRepo and githubRoot before parsing\n\tconst { githubRepo, githubRoot } = handleGitHubRepoAndRoot({\n\t\tgithubRepo: epicshopConfig.githubRepo,\n\t\tgithubRoot: epicshopConfig.githubRoot,\n\t})\n\tepicshopConfig.githubRepo = githubRepo\n\tepicshopConfig.githubRoot = githubRoot\n\n\ttry {\n\t\tconst parsedConfig = WorkshopConfigSchema.parse(epicshopConfig)\n\t\tconfigCache.config = parsedConfig\n\t\tconfigCache.modified = fs.statSync(getRootPkgJsonPath()).mtimeMs\n\t\treturn parsedConfig\n\t} catch (error) {\n\t\tif (error instanceof z.ZodError) {\n\t\t\tconst flattenedErrors = error.flatten()\n\t\t\tconst errorMessages = Object.entries(flattenedErrors.fieldErrors)\n\t\t\t\t.map(([field, errors]) => `${field}: ${errors?.join(', ')}`)\n\t\t\t\t.concat(flattenedErrors.formErrors)\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid epicshop configuration in ${getRootPkgJsonPath()}:\\n${errorMessages.join('\\n')}`,\n\t\t\t)\n\t\t}\n\t\tthrow error\n\t}\n}\n\nexport async function getStackBlitzUrl({\n\tfullPath,\n\ttitle,\n\ttype,\n}: {\n\tfullPath: string\n\ttitle: string\n\ttype: string\n}) {\n\tconst workshopConfig = getWorkshopConfig()\n\tconst appConfig = await getAppConfig(fullPath)\n\n\tif (appConfig.stackBlitzConfig === null) return null\n\n\tlet githubRootUrlString = workshopConfig.githubRoot\n\n\tconst githubRootUrl = new URL(\n\t\tgithubRootUrlString.replace(/\\/blob\\//, '/tree/'),\n\t)\n\n\tconst githubPart = githubRootUrl.pathname\n\n\t// Check if package.json exists to determine if this is a simple exercise\n\tconst packageJsonPath = path.join(fullPath, 'package.json')\n\tconst packageJsonExists = await fs.promises\n\t\t.access(packageJsonPath, fs.constants.F_OK)\n\t\t.then(() => true)\n\t\t.catch(() => false)\n\n\tlet stackBlitzConfig = {\n\t\t...appConfig.stackBlitzConfig,\n\t\ttitle: appConfig.stackBlitzConfig?.title ?? `${title} (${type})`,\n\t}\n\n\t// For simple exercises without package.json, configure StackBlitz to show only editor\n\tif (!packageJsonExists) {\n\t\t// Find the first existing file from the priority list\n\t\tconst priorityFiles = [\n\t\t\t'index.html',\n\t\t\t'index.tsx',\n\t\t\t'index.ts',\n\t\t\t'index.jsx',\n\t\t\t'index.js',\n\t\t\t'README.mdx',\n\t\t\t'README.md',\n\t\t]\n\n\t\tlet defaultFile: string | null = null\n\t\tfor (const fileName of priorityFiles) {\n\t\t\tconst filePath = path.join(fullPath, fileName)\n\t\t\ttry {\n\t\t\t\tawait fs.promises.access(filePath, fs.constants.F_OK)\n\t\t\t\tdefaultFile = fileName\n\t\t\t\tbreak\n\t\t\t} catch {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tstackBlitzConfig = {\n\t\t\t...stackBlitzConfig,\n\t\t\tview: 'editor', // Show only editor, no preview or terminal\n\t\t\thidedevtools: '1', // Hide the console/devtools\n\t\t\tterminalHeight: '0', // Hide the terminal completely\n\t\t\thideNavigation: '1', // Hide the preview's URL bar\n\t\t\t...(defaultFile && { file: defaultFile }), // Set default file if found\n\t\t}\n\t}\n\n\tconst params = new URLSearchParams(stackBlitzConfig as Record<string, string>)\n\n\tconst relativePath = fullPath.replace(\n\t\t`${getEnv().EPICSHOP_CONTEXT_CWD}${path.sep}`,\n\t\t'',\n\t)\n\n\tconst stackBlitzUrl = new URL(\n\t\t`/github${githubPart}/${relativePath}?${params}`,\n\t\t'https://stackblitz.com',\n\t)\n\n\treturn stackBlitzUrl.toString()\n}\n\nexport async function getAppConfig(fullPath: string) {\n\tconst workshopConfig = getWorkshopConfig()\n\n\tlet epicshopConfig: Record<string, any> = {}\n\tlet scripts: Record<string, string> = {}\n\n\tconst packageJsonPath = path.join(fullPath, 'package.json')\n\tconst packageJsonExists = await fs.promises\n\t\t.access(packageJsonPath, fs.constants.F_OK)\n\t\t.then(() => true)\n\t\t.catch(() => false)\n\n\tif (packageJsonExists) {\n\t\tconst pkg = JSON.parse(\n\t\t\tawait fs.promises.readFile(path.join(fullPath, 'package.json'), 'utf8'),\n\t\t) as any\n\t\tepicshopConfig = pkg.epicshop ?? {}\n\t\tscripts = pkg.scripts ?? {}\n\t}\n\n\tconst AppConfigSchema = z.object({\n\t\tstackBlitzConfig: StackBlitzConfigSchema.nullable()\n\t\t\t.optional()\n\t\t\t.transform((appStackBlitzConfig) => {\n\t\t\t\tif (appStackBlitzConfig === null) return null\n\n\t\t\t\treturn {\n\t\t\t\t\t...workshopConfig.stackBlitzConfig,\n\t\t\t\t\t...appStackBlitzConfig,\n\t\t\t\t}\n\t\t\t}),\n\t\ttestTab: z\n\t\t\t.object({\n\t\t\t\tenabled: z\n\t\t\t\t\t.boolean()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.default(workshopConfig.testTab?.enabled ?? true),\n\t\t\t})\n\t\t\t.default({}),\n\t\tscripts: z\n\t\t\t.object({\n\t\t\t\ttest: z.string().optional(),\n\t\t\t\tdev: z.string().optional(),\n\t\t\t})\n\t\t\t.default({}),\n\t\tinitialRoute: z.string().optional().default(workshopConfig.initialRoute),\n\t})\n\n\tconst appConfig = {\n\t\tstackBlitzConfig: epicshopConfig.stackBlitzConfig,\n\t\ttestTab: {\n\t\t\tenabled: epicshopConfig.testTab?.enabled,\n\t\t},\n\t\tscripts: {\n\t\t\ttest: scripts.test,\n\t\t\tdev: scripts.dev,\n\t\t},\n\t\tinitialRoute: epicshopConfig.initialRoute,\n\t}\n\n\ttry {\n\t\treturn AppConfigSchema.parse(appConfig)\n\t} catch (error) {\n\t\tif (error instanceof z.ZodError) {\n\t\t\tconst flattenedErrors = error.flatten()\n\t\t\tconst errorMessages = Object.entries(flattenedErrors.fieldErrors)\n\t\t\t\t.map(([field, errors]) => `${field}: ${errors?.join(', ')}`)\n\t\t\t\t.concat(flattenedErrors.formErrors)\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid app configuration for ${fullPath}:\\n${errorMessages.join('\\n')}`,\n\t\t\t)\n\t\t}\n\t\tthrow error\n\t}\n}\n"]}
@@ -214,21 +214,21 @@ declare const DataSchema: z.ZodObject<{
214
214
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
215
215
  }, "strip", z.ZodTypeAny, {
216
216
  id: string;
217
+ email: string;
217
218
  tokenSet: {
218
219
  access_token: string;
219
220
  token_type: string;
220
221
  scope: string;
221
222
  };
222
- email: string;
223
223
  name?: string | null | undefined;
224
224
  }, {
225
225
  id: string;
226
+ email: string;
226
227
  tokenSet: {
227
228
  access_token: string;
228
229
  token_type: string;
229
230
  scope: string;
230
231
  };
231
- email: string;
232
232
  name?: string | null | undefined;
233
233
  }>>;
234
234
  authInfos: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
@@ -250,21 +250,21 @@ declare const DataSchema: z.ZodObject<{
250
250
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
251
251
  }, "strip", z.ZodTypeAny, {
252
252
  id: string;
253
+ email: string;
253
254
  tokenSet: {
254
255
  access_token: string;
255
256
  token_type: string;
256
257
  scope: string;
257
258
  };
258
- email: string;
259
259
  name?: string | null | undefined;
260
260
  }, {
261
261
  id: string;
262
+ email: string;
262
263
  tokenSet: {
263
264
  access_token: string;
264
265
  token_type: string;
265
266
  scope: string;
266
267
  };
267
- email: string;
268
268
  name?: string | null | undefined;
269
269
  }>>>;
270
270
  clientId: z.ZodOptional<z.ZodString>;
@@ -304,22 +304,22 @@ declare const DataSchema: z.ZodObject<{
304
304
  };
305
305
  authInfo?: {
306
306
  id: string;
307
+ email: string;
307
308
  tokenSet: {
308
309
  access_token: string;
309
310
  token_type: string;
310
311
  scope: string;
311
312
  };
312
- email: string;
313
313
  name?: string | null | undefined;
314
314
  } | undefined;
315
315
  authInfos?: Record<string, {
316
316
  id: string;
317
+ email: string;
317
318
  tokenSet: {
318
319
  access_token: string;
319
320
  token_type: string;
320
321
  scope: string;
321
322
  };
322
- email: string;
323
323
  name?: string | null | undefined;
324
324
  }> | undefined;
325
325
  clientId?: string | undefined;
@@ -357,22 +357,22 @@ declare const DataSchema: z.ZodObject<{
357
357
  } | undefined;
358
358
  authInfo?: {
359
359
  id: string;
360
+ email: string;
360
361
  tokenSet: {
361
362
  access_token: string;
362
363
  token_type: string;
363
364
  scope: string;
364
365
  };
365
- email: string;
366
366
  name?: string | null | undefined;
367
367
  } | undefined;
368
368
  authInfos?: Record<string, {
369
369
  id: string;
370
+ email: string;
370
371
  tokenSet: {
371
372
  access_token: string;
372
373
  token_type: string;
373
374
  scope: string;
374
375
  };
375
- email: string;
376
376
  name?: string | null | undefined;
377
377
  }> | undefined;
378
378
  clientId?: string | undefined;
@@ -383,12 +383,12 @@ export declare function logout(): Promise<void>;
383
383
  export declare function deleteDb(): Promise<null | undefined>;
384
384
  export declare function getAuthInfo(): Promise<{
385
385
  id: string;
386
+ email: string;
386
387
  tokenSet: {
387
388
  access_token: string;
388
389
  token_type: string;
389
390
  scope: string;
390
391
  };
391
- email: string;
392
392
  name?: string | null | undefined;
393
393
  } | null | undefined>;
394
394
  export declare function requireAuthInfo({ request, redirectTo, }: {
@@ -396,12 +396,12 @@ export declare function requireAuthInfo({ request, redirectTo, }: {
396
396
  redirectTo?: string | null;
397
397
  }): Promise<{
398
398
  id: string;
399
+ email: string;
399
400
  tokenSet: {
400
401
  access_token: string;
401
402
  token_type: string;
402
403
  scope: string;
403
404
  };
404
- email: string;
405
405
  name?: string | null | undefined;
406
406
  }>;
407
407
  export declare function setAuthInfo({ id, tokenSet, email, name, }: {
@@ -411,12 +411,12 @@ export declare function setAuthInfo({ id, tokenSet, email, name, }: {
411
411
  name?: string | null;
412
412
  }): Promise<{
413
413
  id: string;
414
+ email: string;
414
415
  tokenSet: {
415
416
  access_token: string;
416
417
  token_type: string;
417
418
  scope: string;
418
419
  };
419
- email: string;
420
420
  name?: string | null | undefined;
421
421
  }>;
422
422
  export declare function getPreferences(): Promise<{
@@ -7,6 +7,10 @@ type DevProcessesMap = Map<string, {
7
7
  process: ChildProcess;
8
8
  port: number;
9
9
  }>;
10
+ type SidecarProcessesMap = Map<string, {
11
+ color: (typeof colors)[number];
12
+ process: ChildProcess;
13
+ }>;
10
14
  type OutputLine = {
11
15
  type: 'stdout' | 'stderr';
12
16
  content: string;
@@ -19,7 +23,7 @@ type TestProcessEntry = {
19
23
  };
20
24
  type TestProcessesMap = Map<string, TestProcessEntry>;
21
25
  declare global {
22
- var __process_dev_close_with_grace_return__: ReturnType<typeof closeWithGrace>, __process_test_close_with_grace_return__: ReturnType<typeof closeWithGrace>;
26
+ var __process_dev_close_with_grace_return__: ReturnType<typeof closeWithGrace>, __process_test_close_with_grace_return__: ReturnType<typeof closeWithGrace>, __process_sidecar_close_with_grace_return__: ReturnType<typeof closeWithGrace>;
23
27
  }
24
28
  declare const colors: readonly ["blue", "green", "yellow", "red", "magenta", "redBright", "greenBright", "yellowBright", "blueBright", "magentaBright"];
25
29
  export declare function runAppDev(app: App): Promise<{
@@ -70,7 +74,11 @@ export declare function clearTestProcessEntry(app: {
70
74
  export declare function getProcesses(): {
71
75
  devProcesses: DevProcessesMap;
72
76
  testProcesses: TestProcessesMap;
77
+ sidecarProcesses: SidecarProcessesMap;
73
78
  };
79
+ export declare function startSidecarProcesses(processes: Record<string, string>): void;
80
+ export declare function startSidecarProcess(name: string, command: string): void;
81
+ export declare function stopSidecarProcesses(): void;
74
82
  export declare function closeProcess(key: string): Promise<void>;
75
83
  export declare function stopPort(port: string | number): Promise<void>;
76
84
  export declare function waitForPortToBeAvailable(port: string | number): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"process-manager.server.d.ts","sourceRoot":"","sources":["../../src/process-manager.server.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAEtB,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAIxD,OAAO,cAAc,MAAM,kBAAkB,CAAA;AAG7C,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAQ3C,KAAK,eAAe,GAAG,GAAG,CACzB,MAAM,EACN;IACC,KAAK,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,YAAY,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;CACZ,CACD,CAAA;AAED,KAAK,UAAU,GAAG;IACjB,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,KAAK,gBAAgB,GAAG;IACvB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB,CAAA;AAED,KAAK,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;AACrD,OAAO,CAAC,MAAM,CAAC;IACd,IAAI,uCAAuC,EAAE,UAAU,CACrD,OAAO,cAAc,CACrB,EACD,wCAAwC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAA;CAC5E;AAmCD,QAAA,MAAM,MAAM,mIAWF,CAAA;AAEV,wBAAsB,SAAS,CAAC,GAAG,EAAE,GAAG;;;;;;;;;;;;;;;;;;;;GAoEvC;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,GAAG;;;GAkDzC;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,GAAG;;;;;;UAwBvC;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYvE;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,oBASvD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,WAUlD;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,gCAExD;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,WAE1D;AAED,wBAAgB,YAAY;;;EAE3B;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,iBAoB7C;AAID,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,iBAInD;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,iBAWnE"}
1
+ {"version":3,"file":"process-manager.server.d.ts","sourceRoot":"","sources":["../../src/process-manager.server.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAEtB,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAIxD,OAAO,cAAc,MAAM,kBAAkB,CAAA;AAG7C,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAS3C,KAAK,eAAe,GAAG,GAAG,CACzB,MAAM,EACN;IACC,KAAK,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,YAAY,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;CACZ,CACD,CAAA;AAED,KAAK,mBAAmB,GAAG,GAAG,CAC7B,MAAM,EACN;IACC,KAAK,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,YAAY,CAAA;CACrB,CACD,CAAA;AAED,KAAK,UAAU,GAAG;IACjB,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,KAAK,gBAAgB,GAAG;IACvB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB,CAAA;AAED,KAAK,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;AACrD,OAAO,CAAC,MAAM,CAAC;IACd,IAAI,uCAAuC,EAAE,UAAU,CACrD,OAAO,cAAc,CACrB,EACD,wCAAwC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,EAC3E,2CAA2C,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAA;CAC/E;AAkDD,QAAA,MAAM,MAAM,mIAWF,CAAA;AA4BV,wBAAsB,SAAS,CAAC,GAAG,EAAE,GAAG;;;;;;;;;;;;;;;;;;;;GAgEvC;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,GAAG;;;GAkDzC;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,GAAG;;;;;;UAwBvC;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYvE;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,oBASvD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,WAUlD;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,gCAExD;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,WAE1D;AAED,wBAAgB,YAAY;;;;EAE3B;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAStE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAkEhE;AAED,wBAAgB,oBAAoB,SAQnC;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,iBAoB7C;AAID,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,iBAInD;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,iBAWnE"}
@@ -7,11 +7,13 @@ import closeWithGrace from 'close-with-grace';
7
7
  import findProcess from 'find-process';
8
8
  import fkill from 'fkill';
9
9
  import { getWorkshopUrl } from './config.server.js';
10
+ import { getEnv } from './env.server.js';
10
11
  import { getErrorMessage } from './utils.js';
11
12
  const isDeployed = process.env.EPICSHOP_DEPLOYED === 'true' ||
12
13
  process.env.EPICSHOP_DEPLOYED === '1';
13
14
  const devProcesses = remember('dev_processes', getDevProcessesMap);
14
15
  const testProcesses = remember('test_processes', getTestProcessesMap);
16
+ const sidecarProcesses = remember('sidecar_processes', getSidecarProcessesMap);
15
17
  function getDevProcessesMap() {
16
18
  const procs = new Map();
17
19
  global.__process_dev_close_with_grace_return__?.uninstall();
@@ -36,6 +38,17 @@ function getTestProcessesMap() {
36
38
  });
37
39
  return procs;
38
40
  }
41
+ function getSidecarProcessesMap() {
42
+ const procs = new Map();
43
+ global.__process_sidecar_close_with_grace_return__?.uninstall();
44
+ global.__process_sidecar_close_with_grace_return__ = closeWithGrace(async () => {
45
+ for (const [name, proc] of procs.entries()) {
46
+ console.log('closing sidecar', name);
47
+ proc.process.kill();
48
+ }
49
+ });
50
+ return procs;
51
+ }
39
52
  const colors = [
40
53
  'blue',
41
54
  'green',
@@ -48,6 +61,26 @@ const colors = [
48
61
  'blueBright',
49
62
  'magentaBright',
50
63
  ];
64
+ function getNextAvailableColor() {
65
+ const usedColors = new Set();
66
+ // Collect colors used by dev processes
67
+ for (const proc of devProcesses.values()) {
68
+ usedColors.add(proc.color);
69
+ }
70
+ // Collect colors used by sidecar processes
71
+ for (const proc of sidecarProcesses.values()) {
72
+ usedColors.add(proc.color);
73
+ }
74
+ // Find available colors
75
+ const availableColors = colors.filter(color => !usedColors.has(color));
76
+ if (availableColors.length === 0) {
77
+ // If all colors are used, cycle through them based on total process count
78
+ const totalProcesses = devProcesses.size + sidecarProcesses.size;
79
+ return colors[totalProcesses % colors.length] ?? 'blue';
80
+ }
81
+ // Use the first available color
82
+ return availableColors[0] ?? 'blue';
83
+ }
51
84
  export async function runAppDev(app) {
52
85
  if (isDeployed)
53
86
  throw new Error('cannot run apps in deployed mode');
@@ -63,8 +96,7 @@ export async function runAppDev(app) {
63
96
  if (!(await isPortAvailable(portNumber))) {
64
97
  return { status: 'port-unavailable', running: false, portNumber };
65
98
  }
66
- const availableColors = colors.filter((color) => Array.from(devProcesses.values()).every((p) => p.color !== color));
67
- const color = availableColors[devProcesses.size % availableColors.length] ?? 'blue';
99
+ const color = getNextAvailableColor();
68
100
  const appProcess = spawn('npm', ['run', 'dev', '--silent'], {
69
101
  cwd: app.fullPath,
70
102
  shell: true,
@@ -224,7 +256,80 @@ export function clearTestProcessEntry(app) {
224
256
  return testProcesses.delete(app.name);
225
257
  }
226
258
  export function getProcesses() {
227
- return { devProcesses, testProcesses };
259
+ return { devProcesses, testProcesses, sidecarProcesses };
260
+ }
261
+ export function startSidecarProcesses(processes) {
262
+ if (isDeployed) {
263
+ console.log('Sidecar processes are not supported in deployed mode');
264
+ return;
265
+ }
266
+ for (const [name, command] of Object.entries(processes)) {
267
+ startSidecarProcess(name, command);
268
+ }
269
+ }
270
+ export function startSidecarProcess(name, command) {
271
+ if (isDeployed)
272
+ throw new Error('cannot run sidecar processes in deployed mode');
273
+ // if the process is already running, don't start it again
274
+ if (sidecarProcesses.has(name)) {
275
+ console.log(`Sidecar process ${name} is already running`);
276
+ return;
277
+ }
278
+ const color = getNextAvailableColor();
279
+ // Spawn the command using shell to handle complex commands properly
280
+ const workshopRoot = getEnv().EPICSHOP_CONTEXT_CWD;
281
+ const sidecarProcess = spawn(command, [], {
282
+ shell: true,
283
+ cwd: workshopRoot,
284
+ stdio: ['ignore', 'pipe', 'pipe'],
285
+ env: {
286
+ ...process.env,
287
+ NODE_ENV: 'development',
288
+ },
289
+ });
290
+ const prefix = chalk[color](`[${name}]`);
291
+ function handleStdOutData(data) {
292
+ console.log(data
293
+ .toString('utf-8')
294
+ .split('\n')
295
+ .map((line) => `${prefix} ${line}`)
296
+ .join('\n'));
297
+ }
298
+ sidecarProcess.stdout?.on('data', handleStdOutData);
299
+ function handleStdErrData(data) {
300
+ console.error(data
301
+ .toString('utf-8')
302
+ .split('\n')
303
+ .map((line) => `${prefix} ${line}`)
304
+ .join('\n'));
305
+ }
306
+ sidecarProcess.stderr?.on('data', handleStdErrData);
307
+ sidecarProcesses.set(name, { color, process: sidecarProcess });
308
+ sidecarProcess.on('exit', (code, signal) => {
309
+ sidecarProcess.stdout?.off('data', handleStdOutData);
310
+ sidecarProcess.stderr?.off('data', handleStdErrData);
311
+ if (code === 0) {
312
+ console.log(`${prefix} exited successfully`);
313
+ }
314
+ else {
315
+ console.log(`${prefix} exited with code ${code}${signal ? ` (signal: ${signal})` : ''}`);
316
+ }
317
+ sidecarProcesses.delete(name);
318
+ });
319
+ sidecarProcess.on('error', (error) => {
320
+ console.error(`${prefix} failed to start: ${error.message}`);
321
+ sidecarProcesses.delete(name);
322
+ });
323
+ console.log(`${prefix} started`);
324
+ }
325
+ export function stopSidecarProcesses() {
326
+ if (isDeployed)
327
+ throw new Error('cannot stop sidecar processes in deployed mode');
328
+ for (const [name, proc] of sidecarProcesses.entries()) {
329
+ console.log(`Stopping sidecar process: ${name}`);
330
+ proc.process.kill();
331
+ }
332
+ sidecarProcesses.clear();
228
333
  }
229
334
  export async function closeProcess(key) {
230
335
  if (isDeployed)
@@ -1 +1 @@
1
- {"version":3,"file":"process-manager.server.js","sourceRoot":"","sources":["../../src/process-manager.server.ts"],"names":[],"mappings":"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","sourcesContent":["import './init-env.js'\n\nimport { spawn, type ChildProcess } from 'child_process'\nimport net from 'node:net'\nimport { remember } from '@epic-web/remember'\nimport chalk from 'chalk'\nimport closeWithGrace from 'close-with-grace'\nimport findProcess from 'find-process'\nimport fkill from 'fkill'\nimport { type App } from './apps.server.js'\nimport { getWorkshopUrl } from './config.server.js'\nimport { getErrorMessage } from './utils.js'\n\nconst isDeployed =\n\tprocess.env.EPICSHOP_DEPLOYED === 'true' ||\n\tprocess.env.EPICSHOP_DEPLOYED === '1'\n\ntype DevProcessesMap = Map<\n\tstring,\n\t{\n\t\tcolor: (typeof colors)[number]\n\t\tprocess: ChildProcess\n\t\tport: number\n\t}\n>\n\ntype OutputLine = {\n\ttype: 'stdout' | 'stderr'\n\tcontent: string\n\ttimestamp: number\n}\n\ntype TestProcessEntry = {\n\tprocess: ChildProcess | null\n\toutput: Array<OutputLine>\n\texitCode?: number | null\n}\n\ntype TestProcessesMap = Map<string, TestProcessEntry>\ndeclare global {\n\tvar __process_dev_close_with_grace_return__: ReturnType<\n\t\t\ttypeof closeWithGrace\n\t\t>,\n\t\t__process_test_close_with_grace_return__: ReturnType<typeof closeWithGrace>\n}\n\nconst devProcesses = remember('dev_processes', getDevProcessesMap)\nconst testProcesses = remember('test_processes', getTestProcessesMap)\n\nfunction getDevProcessesMap() {\n\tconst procs: DevProcessesMap = new Map()\n\n\tglobal.__process_dev_close_with_grace_return__?.uninstall()\n\n\tglobal.__process_dev_close_with_grace_return__ = closeWithGrace(async () => {\n\t\tfor (const [name, proc] of procs.entries()) {\n\t\t\tconsole.log('closing', name)\n\t\t\tproc.process.kill()\n\t\t}\n\t})\n\treturn procs\n}\n\nfunction getTestProcessesMap() {\n\tconst procs: TestProcessesMap = new Map()\n\n\tglobal.__process_test_close_with_grace_return__?.uninstall()\n\n\tglobal.__process_test_close_with_grace_return__ = closeWithGrace(async () => {\n\t\tfor (const [id, proc] of procs.entries()) {\n\t\t\tif (proc.process) {\n\t\t\t\tconsole.log('closing', id)\n\t\t\t\tproc.process.kill()\n\t\t\t}\n\t\t}\n\t})\n\treturn procs\n}\n\nconst colors = [\n\t'blue',\n\t'green',\n\t'yellow',\n\t'red',\n\t'magenta',\n\t'redBright',\n\t'greenBright',\n\t'yellowBright',\n\t'blueBright',\n\t'magentaBright',\n] as const\n\nexport async function runAppDev(app: App) {\n\tif (isDeployed) throw new Error('cannot run apps in deployed mode')\n\tconst key = app.name\n\t// if the app is already running, don't start it again\n\tif (devProcesses.has(key)) {\n\t\treturn { status: 'process-running', running: true } as const\n\t}\n\n\tif (app.dev.type !== 'script') {\n\t\treturn { status: 'error', error: 'no-server' } as const\n\t}\n\n\tconst { portNumber } = app.dev\n\tif (!(await isPortAvailable(portNumber))) {\n\t\treturn { status: 'port-unavailable', running: false, portNumber } as const\n\t}\n\tconst availableColors = colors.filter((color) =>\n\t\tArray.from(devProcesses.values()).every((p) => p.color !== color),\n\t)\n\tconst color =\n\t\tavailableColors[devProcesses.size % availableColors.length] ?? 'blue'\n\tconst appProcess = spawn('npm', ['run', 'dev', '--silent'], {\n\t\tcwd: app.fullPath,\n\t\tshell: true,\n\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t// TODO: support specifying the env\n\t\t\tNODE_ENV: 'development',\n\t\t\t// TODO: support specifying the port\n\t\t\tPORT: String(portNumber),\n\t\t\tAPP_SERVER_PORT: String(portNumber),\n\t\t\t// let it pick a random port...\n\t\t\tREMIX_DEV_SERVER_WS_PORT: '',\n\t\t},\n\t})\n\tconst prefix = chalk[color](\n\t\t`[${app.name.replace(/^exercises\\./, '')}:${portNumber}]`,\n\t)\n\tfunction handleStdOutData(data: Buffer) {\n\t\tconsole.log(\n\t\t\tdata\n\t\t\t\t.toString('utf-8')\n\t\t\t\t.split('\\n')\n\t\t\t\t.map((line) => `${prefix} ${line}`)\n\t\t\t\t.join('\\n'),\n\t\t)\n\t}\n\tappProcess.stdout.on('data', handleStdOutData)\n\tfunction handleStdErrData(data: Buffer) {\n\t\tconsole.error(\n\t\t\tdata\n\t\t\t\t.toString('utf-8')\n\t\t\t\t.split('\\n')\n\t\t\t\t.map((line) => `${prefix} ${line}`)\n\t\t\t\t.join('\\n'),\n\t\t)\n\t}\n\tappProcess.stderr.on('data', handleStdErrData)\n\tdevProcesses.set(key, { color, process: appProcess, port: portNumber })\n\tappProcess.on('exit', (code) => {\n\t\tappProcess.stdout.off('data', handleStdOutData)\n\t\tappProcess.stderr.off('data', handleStdErrData)\n\t\tconsole.log(`${prefix} exited (${code})`)\n\t\tdevProcesses.delete(key)\n\t})\n\n\treturn { status: 'process-started', running: true } as const\n}\n\nexport async function runAppTests(app: App) {\n\tif (isDeployed) throw new Error('cannot run tests in deployed mode')\n\tconst key = app.name\n\n\tif (app.test.type !== 'script') {\n\t\treturn { status: 'error', error: 'no-test' } as const\n\t}\n\n\tconst testProcess = spawn('npm', ['run', 'test', '--silent'], {\n\t\tcwd: app.fullPath,\n\t\tshell: true,\n\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t// TODO: support specifying the env\n\t\t\tNODE_ENV: 'development',\n\t\t\t// TODO: support specifying the port\n\t\t\tPORT: app.dev.type === 'script' ? String(app.dev.portNumber) : undefined,\n\t\t\tAPP_SERVER_PORT:\n\t\t\t\tapp.dev.type === 'script' ? String(app.dev.portNumber) : undefined,\n\t\t\t// let it pick a random port...\n\t\t\tREMIX_DEV_SERVER_WS_PORT: '',\n\t\t},\n\t})\n\tconst output: Array<OutputLine> = []\n\tconst entry: TestProcessEntry = { process: testProcess, output }\n\tfunction handleStdOutData(data: Buffer) {\n\t\toutput.push({\n\t\t\ttype: 'stdout',\n\t\t\tcontent: data.toString('utf-8'),\n\t\t\ttimestamp: Date.now(),\n\t\t})\n\t}\n\ttestProcess.stdout.on('data', handleStdOutData)\n\tfunction handleStdErrData(data: Buffer) {\n\t\toutput.push({\n\t\t\ttype: 'stderr',\n\t\t\tcontent: data.toString('utf-8'),\n\t\t\ttimestamp: Date.now(),\n\t\t})\n\t}\n\ttestProcess.stderr.on('data', handleStdErrData)\n\ttestProcess.on('exit', (code) => {\n\t\ttestProcess.stdout.off('data', handleStdOutData)\n\t\ttestProcess.stderr.off('data', handleStdErrData)\n\t\tentry.process = null\n\t\tentry.exitCode = code\n\t})\n\ttestProcesses.set(key, entry)\n\treturn testProcess\n}\n\nexport async function waitOnApp(app: App) {\n\tif (app.dev.type === 'script') {\n\t\tconst startTime = Date.now()\n\n\t\tconst retryInterval = 100\n\t\tconst timeout = 20_000\n\t\tlet lastError: unknown\n\t\twhile (Date.now() - startTime < timeout) {\n\t\t\ttry {\n\t\t\t\tconst url = getWorkshopUrl(app.dev.portNumber)\n\t\t\t\tawait fetch(url, {\n\t\t\t\t\tmethod: 'HEAD',\n\t\t\t\t\theaders: { Accept: '*/*' },\n\t\t\t\t})\n\t\t\t\treturn { status: 'success' } as const\n\t\t\t} catch (error) {\n\t\t\t\tlastError = error\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, retryInterval))\n\t\t\t}\n\t\t}\n\n\t\treturn { status: 'error', error: getErrorMessage(lastError) } as const\n\t}\n\treturn null\n}\n\nexport function isPortAvailable(port: number | string): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst server = net.createServer()\n\t\tserver.unref()\n\t\tserver.on('error', () => resolve(false))\n\n\t\tserver.listen(Number(port), () => {\n\t\t\tserver.close(() => {\n\t\t\t\tresolve(true)\n\t\t\t})\n\t\t})\n\t})\n}\n\nexport async function isAppRunning(app: { name: string }) {\n\ttry {\n\t\tconst devProcess = devProcesses.get(app.name)\n\t\tif (!devProcess?.process.pid) return false\n\t\tconst found = await findProcess('pid', devProcess.process.pid)\n\t\treturn found.length > 0\n\t} catch {\n\t\treturn false\n\t}\n}\n\nexport function isTestRunning(app: { name: string }) {\n\ttry {\n\t\tconst testProcess = testProcesses.get(app.name)\n\t\tif (!testProcess) return false\n\t\tif (testProcess.process === null) return false\n\t\ttestProcess.process.kill(0)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nexport function getTestProcessEntry(app: { name: string }) {\n\treturn testProcesses.get(app.name)\n}\n\nexport function clearTestProcessEntry(app: { name: string }) {\n\treturn testProcesses.delete(app.name)\n}\n\nexport function getProcesses() {\n\treturn { devProcesses, testProcesses }\n}\n\nexport async function closeProcess(key: string) {\n\tif (isDeployed) throw new Error('cannot close processes in deployed mode')\n\tconst proc = devProcesses.get(key)\n\tif (proc) {\n\t\tconst exitedPromise = new Promise((resolve) =>\n\t\t\tproc.process.on('exit', resolve),\n\t\t)\n\t\tif (process.platform === 'win32') {\n\t\t\tconst { execa } = await import('execa')\n\t\t\tawait execa('taskkill', ['/pid', String(proc.process.pid), '/f', '/t'])\n\t\t} else {\n\t\t\tproc.process.kill()\n\t\t}\n\t\tawait Promise.race([\n\t\t\tnew Promise((resolve) => setTimeout(resolve, 500)),\n\t\t\texitedPromise,\n\t\t])\n\t\tawait stopPort(proc.port) // just in case šŸ¤·ā€ā™‚ļø\n\t\tdevProcesses.delete(key)\n\t}\n}\n\nconst sleep = (t: number) => new Promise((resolve) => setTimeout(resolve, t))\n\nexport async function stopPort(port: string | number) {\n\tif (isDeployed) throw new Error('cannot stop ports in deployed mode')\n\tawait fkill(`:${port}`, { force: true, silent: true })\n\tawait waitForPortToBeAvailable(port)\n}\n\nexport async function waitForPortToBeAvailable(port: string | number) {\n\t// wait for the port to become available again\n\tconst timeout = Date.now() + 10_000\n\tlet portAvailable = false\n\tdo {\n\t\tportAvailable = await isPortAvailable(port)\n\t\tawait sleep(100)\n\t} while (!portAvailable && Date.now() < timeout)\n\tif (!portAvailable) {\n\t\tconsole.error('Timed out waiting for the port to become available')\n\t}\n}\n"]}
1
+ {"version":3,"file":"process-manager.server.js","sourceRoot":"","sources":["../../src/process-manager.server.ts"],"names":[],"mappings":"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","sourcesContent":["import './init-env.js'\n\nimport { spawn, type ChildProcess } from 'child_process'\nimport net from 'node:net'\nimport { remember } from '@epic-web/remember'\nimport chalk from 'chalk'\nimport closeWithGrace from 'close-with-grace'\nimport findProcess from 'find-process'\nimport fkill from 'fkill'\nimport { type App } from './apps.server.js'\nimport { getWorkshopUrl } from './config.server.js'\nimport { getEnv } from './env.server.js'\nimport { getErrorMessage } from './utils.js'\n\nconst isDeployed =\n\tprocess.env.EPICSHOP_DEPLOYED === 'true' ||\n\tprocess.env.EPICSHOP_DEPLOYED === '1'\n\ntype DevProcessesMap = Map<\n\tstring,\n\t{\n\t\tcolor: (typeof colors)[number]\n\t\tprocess: ChildProcess\n\t\tport: number\n\t}\n>\n\ntype SidecarProcessesMap = Map<\n\tstring,\n\t{\n\t\tcolor: (typeof colors)[number]\n\t\tprocess: ChildProcess\n\t}\n>\n\ntype OutputLine = {\n\ttype: 'stdout' | 'stderr'\n\tcontent: string\n\ttimestamp: number\n}\n\ntype TestProcessEntry = {\n\tprocess: ChildProcess | null\n\toutput: Array<OutputLine>\n\texitCode?: number | null\n}\n\ntype TestProcessesMap = Map<string, TestProcessEntry>\ndeclare global {\n\tvar __process_dev_close_with_grace_return__: ReturnType<\n\t\t\ttypeof closeWithGrace\n\t\t>,\n\t\t__process_test_close_with_grace_return__: ReturnType<typeof closeWithGrace>,\n\t\t__process_sidecar_close_with_grace_return__: ReturnType<typeof closeWithGrace>\n}\n\nconst devProcesses = remember('dev_processes', getDevProcessesMap)\nconst testProcesses = remember('test_processes', getTestProcessesMap)\nconst sidecarProcesses = remember('sidecar_processes', getSidecarProcessesMap)\n\nfunction getDevProcessesMap() {\n\tconst procs: DevProcessesMap = new Map()\n\n\tglobal.__process_dev_close_with_grace_return__?.uninstall()\n\n\tglobal.__process_dev_close_with_grace_return__ = closeWithGrace(async () => {\n\t\tfor (const [name, proc] of procs.entries()) {\n\t\t\tconsole.log('closing', name)\n\t\t\tproc.process.kill()\n\t\t}\n\t})\n\treturn procs\n}\n\nfunction getTestProcessesMap() {\n\tconst procs: TestProcessesMap = new Map()\n\n\tglobal.__process_test_close_with_grace_return__?.uninstall()\n\n\tglobal.__process_test_close_with_grace_return__ = closeWithGrace(async () => {\n\t\tfor (const [id, proc] of procs.entries()) {\n\t\t\tif (proc.process) {\n\t\t\t\tconsole.log('closing', id)\n\t\t\t\tproc.process.kill()\n\t\t\t}\n\t\t}\n\t})\n\treturn procs\n}\n\nfunction getSidecarProcessesMap() {\n\tconst procs: SidecarProcessesMap = new Map()\n\n\tglobal.__process_sidecar_close_with_grace_return__?.uninstall()\n\n\tglobal.__process_sidecar_close_with_grace_return__ = closeWithGrace(async () => {\n\t\tfor (const [name, proc] of procs.entries()) {\n\t\t\tconsole.log('closing sidecar', name)\n\t\t\tproc.process.kill()\n\t\t}\n\t})\n\treturn procs\n}\n\nconst colors = [\n\t'blue',\n\t'green',\n\t'yellow',\n\t'red',\n\t'magenta',\n\t'redBright',\n\t'greenBright',\n\t'yellowBright',\n\t'blueBright',\n\t'magentaBright',\n] as const\n\nfunction getNextAvailableColor(): (typeof colors)[number] {\n\tconst usedColors = new Set<(typeof colors)[number]>()\n\t\n\t// Collect colors used by dev processes\n\tfor (const proc of devProcesses.values()) {\n\t\tusedColors.add(proc.color)\n\t}\n\t\n\t// Collect colors used by sidecar processes\n\tfor (const proc of sidecarProcesses.values()) {\n\t\tusedColors.add(proc.color)\n\t}\n\t\n\t// Find available colors\n\tconst availableColors = colors.filter(color => !usedColors.has(color))\n\t\n\tif (availableColors.length === 0) {\n\t\t// If all colors are used, cycle through them based on total process count\n\t\tconst totalProcesses = devProcesses.size + sidecarProcesses.size\n\t\treturn colors[totalProcesses % colors.length] ?? 'blue'\n\t}\n\t\n\t// Use the first available color\n\treturn availableColors[0] ?? 'blue'\n}\n\nexport async function runAppDev(app: App) {\n\tif (isDeployed) throw new Error('cannot run apps in deployed mode')\n\tconst key = app.name\n\t// if the app is already running, don't start it again\n\tif (devProcesses.has(key)) {\n\t\treturn { status: 'process-running', running: true } as const\n\t}\n\n\tif (app.dev.type !== 'script') {\n\t\treturn { status: 'error', error: 'no-server' } as const\n\t}\n\n\tconst { portNumber } = app.dev\n\tif (!(await isPortAvailable(portNumber))) {\n\t\treturn { status: 'port-unavailable', running: false, portNumber } as const\n\t}\n\tconst color = getNextAvailableColor()\n\tconst appProcess = spawn('npm', ['run', 'dev', '--silent'], {\n\t\tcwd: app.fullPath,\n\t\tshell: true,\n\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t// TODO: support specifying the env\n\t\t\tNODE_ENV: 'development',\n\t\t\t// TODO: support specifying the port\n\t\t\tPORT: String(portNumber),\n\t\t\tAPP_SERVER_PORT: String(portNumber),\n\t\t\t// let it pick a random port...\n\t\t\tREMIX_DEV_SERVER_WS_PORT: '',\n\t\t},\n\t})\n\tconst prefix = chalk[color](\n\t\t`[${app.name.replace(/^exercises\\./, '')}:${portNumber}]`,\n\t)\n\tfunction handleStdOutData(data: Buffer) {\n\t\tconsole.log(\n\t\t\tdata\n\t\t\t\t.toString('utf-8')\n\t\t\t\t.split('\\n')\n\t\t\t\t.map((line) => `${prefix} ${line}`)\n\t\t\t\t.join('\\n'),\n\t\t)\n\t}\n\tappProcess.stdout.on('data', handleStdOutData)\n\tfunction handleStdErrData(data: Buffer) {\n\t\tconsole.error(\n\t\t\tdata\n\t\t\t\t.toString('utf-8')\n\t\t\t\t.split('\\n')\n\t\t\t\t.map((line) => `${prefix} ${line}`)\n\t\t\t\t.join('\\n'),\n\t\t)\n\t}\n\tappProcess.stderr.on('data', handleStdErrData)\n\tdevProcesses.set(key, { color, process: appProcess, port: portNumber })\n\tappProcess.on('exit', (code) => {\n\t\tappProcess.stdout.off('data', handleStdOutData)\n\t\tappProcess.stderr.off('data', handleStdErrData)\n\t\tconsole.log(`${prefix} exited (${code})`)\n\t\tdevProcesses.delete(key)\n\t})\n\n\treturn { status: 'process-started', running: true } as const\n}\n\nexport async function runAppTests(app: App) {\n\tif (isDeployed) throw new Error('cannot run tests in deployed mode')\n\tconst key = app.name\n\n\tif (app.test.type !== 'script') {\n\t\treturn { status: 'error', error: 'no-test' } as const\n\t}\n\n\tconst testProcess = spawn('npm', ['run', 'test', '--silent'], {\n\t\tcwd: app.fullPath,\n\t\tshell: true,\n\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t// TODO: support specifying the env\n\t\t\tNODE_ENV: 'development',\n\t\t\t// TODO: support specifying the port\n\t\t\tPORT: app.dev.type === 'script' ? String(app.dev.portNumber) : undefined,\n\t\t\tAPP_SERVER_PORT:\n\t\t\t\tapp.dev.type === 'script' ? String(app.dev.portNumber) : undefined,\n\t\t\t// let it pick a random port...\n\t\t\tREMIX_DEV_SERVER_WS_PORT: '',\n\t\t},\n\t})\n\tconst output: Array<OutputLine> = []\n\tconst entry: TestProcessEntry = { process: testProcess, output }\n\tfunction handleStdOutData(data: Buffer) {\n\t\toutput.push({\n\t\t\ttype: 'stdout',\n\t\t\tcontent: data.toString('utf-8'),\n\t\t\ttimestamp: Date.now(),\n\t\t})\n\t}\n\ttestProcess.stdout.on('data', handleStdOutData)\n\tfunction handleStdErrData(data: Buffer) {\n\t\toutput.push({\n\t\t\ttype: 'stderr',\n\t\t\tcontent: data.toString('utf-8'),\n\t\t\ttimestamp: Date.now(),\n\t\t})\n\t}\n\ttestProcess.stderr.on('data', handleStdErrData)\n\ttestProcess.on('exit', (code) => {\n\t\ttestProcess.stdout.off('data', handleStdOutData)\n\t\ttestProcess.stderr.off('data', handleStdErrData)\n\t\tentry.process = null\n\t\tentry.exitCode = code\n\t})\n\ttestProcesses.set(key, entry)\n\treturn testProcess\n}\n\nexport async function waitOnApp(app: App) {\n\tif (app.dev.type === 'script') {\n\t\tconst startTime = Date.now()\n\n\t\tconst retryInterval = 100\n\t\tconst timeout = 20_000\n\t\tlet lastError: unknown\n\t\twhile (Date.now() - startTime < timeout) {\n\t\t\ttry {\n\t\t\t\tconst url = getWorkshopUrl(app.dev.portNumber)\n\t\t\t\tawait fetch(url, {\n\t\t\t\t\tmethod: 'HEAD',\n\t\t\t\t\theaders: { Accept: '*/*' },\n\t\t\t\t})\n\t\t\t\treturn { status: 'success' } as const\n\t\t\t} catch (error) {\n\t\t\t\tlastError = error\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, retryInterval))\n\t\t\t}\n\t\t}\n\n\t\treturn { status: 'error', error: getErrorMessage(lastError) } as const\n\t}\n\treturn null\n}\n\nexport function isPortAvailable(port: number | string): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst server = net.createServer()\n\t\tserver.unref()\n\t\tserver.on('error', () => resolve(false))\n\n\t\tserver.listen(Number(port), () => {\n\t\t\tserver.close(() => {\n\t\t\t\tresolve(true)\n\t\t\t})\n\t\t})\n\t})\n}\n\nexport async function isAppRunning(app: { name: string }) {\n\ttry {\n\t\tconst devProcess = devProcesses.get(app.name)\n\t\tif (!devProcess?.process.pid) return false\n\t\tconst found = await findProcess('pid', devProcess.process.pid)\n\t\treturn found.length > 0\n\t} catch {\n\t\treturn false\n\t}\n}\n\nexport function isTestRunning(app: { name: string }) {\n\ttry {\n\t\tconst testProcess = testProcesses.get(app.name)\n\t\tif (!testProcess) return false\n\t\tif (testProcess.process === null) return false\n\t\ttestProcess.process.kill(0)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nexport function getTestProcessEntry(app: { name: string }) {\n\treturn testProcesses.get(app.name)\n}\n\nexport function clearTestProcessEntry(app: { name: string }) {\n\treturn testProcesses.delete(app.name)\n}\n\nexport function getProcesses() {\n\treturn { devProcesses, testProcesses, sidecarProcesses }\n}\n\nexport function startSidecarProcesses(processes: Record<string, string>) {\n\tif (isDeployed) {\n\t\tconsole.log('Sidecar processes are not supported in deployed mode')\n\t\treturn\n\t}\n\n\tfor (const [name, command] of Object.entries(processes)) {\n\t\tstartSidecarProcess(name, command)\n\t}\n}\n\nexport function startSidecarProcess(name: string, command: string) {\n\tif (isDeployed) throw new Error('cannot run sidecar processes in deployed mode')\n\t\n\t// if the process is already running, don't start it again\n\tif (sidecarProcesses.has(name)) {\n\t\tconsole.log(`Sidecar process ${name} is already running`)\n\t\treturn\n\t}\n\n\tconst color = getNextAvailableColor()\n\n\t// Spawn the command using shell to handle complex commands properly\n\tconst workshopRoot = getEnv().EPICSHOP_CONTEXT_CWD\n\tconst sidecarProcess = spawn(command, [], {\n\t\tshell: true,\n\t\tcwd: workshopRoot,\n\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\tNODE_ENV: 'development',\n\t\t},\n\t})\n\n\tconst prefix = chalk[color](`[${name}]`)\n\t\n\tfunction handleStdOutData(data: Buffer) {\n\t\tconsole.log(\n\t\t\tdata\n\t\t\t\t.toString('utf-8')\n\t\t\t\t.split('\\n')\n\t\t\t\t.map((line) => `${prefix} ${line}`)\n\t\t\t\t.join('\\n'),\n\t\t)\n\t}\n\tsidecarProcess.stdout?.on('data', handleStdOutData)\n\t\n\tfunction handleStdErrData(data: Buffer) {\n\t\tconsole.error(\n\t\t\tdata\n\t\t\t\t.toString('utf-8')\n\t\t\t\t.split('\\n')\n\t\t\t\t.map((line) => `${prefix} ${line}`)\n\t\t\t\t.join('\\n'),\n\t\t)\n\t}\n\tsidecarProcess.stderr?.on('data', handleStdErrData)\n\t\n\tsidecarProcesses.set(name, { color, process: sidecarProcess })\n\t\n\tsidecarProcess.on('exit', (code: number | null, signal: string | null) => {\n\t\tsidecarProcess.stdout?.off('data', handleStdOutData)\n\t\tsidecarProcess.stderr?.off('data', handleStdErrData)\n\t\tif (code === 0) {\n\t\t\tconsole.log(`${prefix} exited successfully`)\n\t\t} else {\n\t\t\tconsole.log(`${prefix} exited with code ${code}${signal ? ` (signal: ${signal})` : ''}`)\n\t\t}\n\t\tsidecarProcesses.delete(name)\n\t})\n\n\tsidecarProcess.on('error', (error) => {\n\t\tconsole.error(`${prefix} failed to start: ${error.message}`)\n\t\tsidecarProcesses.delete(name)\n\t})\n\n\tconsole.log(`${prefix} started`)\n}\n\nexport function stopSidecarProcesses() {\n\tif (isDeployed) throw new Error('cannot stop sidecar processes in deployed mode')\n\t\n\tfor (const [name, proc] of sidecarProcesses.entries()) {\n\t\tconsole.log(`Stopping sidecar process: ${name}`)\n\t\tproc.process.kill()\n\t}\n\tsidecarProcesses.clear()\n}\n\nexport async function closeProcess(key: string) {\n\tif (isDeployed) throw new Error('cannot close processes in deployed mode')\n\tconst proc = devProcesses.get(key)\n\tif (proc) {\n\t\tconst exitedPromise = new Promise((resolve) =>\n\t\t\tproc.process.on('exit', resolve),\n\t\t)\n\t\tif (process.platform === 'win32') {\n\t\t\tconst { execa } = await import('execa')\n\t\t\tawait execa('taskkill', ['/pid', String(proc.process.pid), '/f', '/t'])\n\t\t} else {\n\t\t\tproc.process.kill()\n\t\t}\n\t\tawait Promise.race([\n\t\t\tnew Promise((resolve) => setTimeout(resolve, 500)),\n\t\t\texitedPromise,\n\t\t])\n\t\tawait stopPort(proc.port) // just in case šŸ¤·ā€ā™‚ļø\n\t\tdevProcesses.delete(key)\n\t}\n}\n\nconst sleep = (t: number) => new Promise((resolve) => setTimeout(resolve, t))\n\nexport async function stopPort(port: string | number) {\n\tif (isDeployed) throw new Error('cannot stop ports in deployed mode')\n\tawait fkill(`:${port}`, { force: true, silent: true })\n\tawait waitForPortToBeAvailable(port)\n}\n\nexport async function waitForPortToBeAvailable(port: string | number) {\n\t// wait for the port to become available again\n\tconst timeout = Date.now() + 10_000\n\tlet portAvailable = false\n\tdo {\n\t\tportAvailable = await isPortAvailable(port)\n\t\tawait sleep(100)\n\t} while (!portAvailable && Date.now() < timeout)\n\tif (!portAvailable) {\n\t\tconsole.error('Timed out waiting for the port to become available')\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epic-web/workshop-utils",
3
- "version": "6.19.7",
3
+ "version": "6.20.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },