epicshop 6.72.0 → 6.72.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,7 @@ import { userHasAccessToWorkshop } from '@epic-web/workshop-utils/epic-api.serve
9
9
  import chalk from 'chalk';
10
10
  import { matchSorter, rankings } from 'match-sorter';
11
11
  import ora from 'ora';
12
+ import { z } from 'zod';
12
13
  import { assertCanPrompt, isCiEnvironment } from "../utils/cli-runtime.js";
13
14
  import { runCommand, runCommandInteractive } from "../utils/command-runner.js";
14
15
  import { setup } from "./setup.js";
@@ -70,6 +71,20 @@ export async function findWorkshopRoot() {
70
71
  export async function isInWorkshopDirectory() {
71
72
  return (await findWorkshopRoot()) !== null;
72
73
  }
74
+ const GitHubRepoSchema = z.object({
75
+ name: z.string(),
76
+ description: z.string().nullable(),
77
+ html_url: z.string(),
78
+ stargazers_count: z.number(),
79
+ topics: z.array(z.string()).default([]),
80
+ archived: z.boolean(),
81
+ });
82
+ const GitHubSearchResponseSchema = z.object({
83
+ total_count: z.number(),
84
+ incomplete_results: z.boolean(),
85
+ items: z.array(GitHubRepoSchema),
86
+ });
87
+ const PackageJsonSchema = z.record(z.unknown());
73
88
  const PRODUCT_ICONS = {
74
89
  'www.epicweb.dev': '🌌',
75
90
  'www.epicai.pro': '⚡',
@@ -103,6 +118,7 @@ async function fetchAvailableWorkshops() {
103
118
  cache: githubCache,
104
119
  ttl: 1000 * 60 * 15, // 15 minutes
105
120
  swr: 1000 * 60 * 60 * 6, // 6 hours stale-while-revalidate
121
+ checkValue: GitHubRepoSchema.array(),
106
122
  async getFreshValue() {
107
123
  // Note: `archived:false` is supported by GitHub search.
108
124
  const baseUrl = `https://api.github.com/search/repositories?q=topic:workshop+org:${GITHUB_ORG}+archived:false&sort=stars&order=desc`;
@@ -125,11 +141,12 @@ async function fetchAvailableWorkshops() {
125
141
  }
126
142
  throw new Error(`Failed to fetch workshops from GitHub: ${response.status}`);
127
143
  }
128
- const data = (await response.json());
129
- const items = Array.isArray(data.items) ? data.items : [];
130
- if (typeof data.total_count === 'number') {
131
- totalCount = data.total_count;
144
+ const parseResult = GitHubSearchResponseSchema.safeParse(await response.json());
145
+ if (!parseResult.success) {
146
+ throw new Error(`Failed to parse GitHub API response: ${parseResult.error.message}`);
132
147
  }
148
+ const { items, total_count } = parseResult.data;
149
+ totalCount = total_count;
133
150
  allItems.push(...items);
134
151
  // Stop when there are no more results for the next page.
135
152
  if (items.length < perPage)
@@ -151,6 +168,7 @@ async function fetchWorkshopPackageJson(repoName) {
151
168
  cache: githubCache,
152
169
  ttl: 1000 * 60 * 60 * 6, // 6 hours
153
170
  swr: 1000 * 60 * 60 * 24 * 30, // 30 days stale-while-revalidate
171
+ checkValue: PackageJsonSchema.nullable(),
154
172
  async getFreshValue() {
155
173
  const url = `https://raw.githubusercontent.com/${GITHUB_ORG}/${repoName}/main/package.json`;
156
174
  const response = await fetch(url, {
@@ -163,7 +181,8 @@ async function fetchWorkshopPackageJson(repoName) {
163
181
  return null;
164
182
  }
165
183
  try {
166
- return (await response.json());
184
+ const parsed = PackageJsonSchema.safeParse(await response.json());
185
+ return parsed.success ? parsed.data : null;
167
186
  }
168
187
  catch {
169
188
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epicshop",
3
- "version": "6.72.0",
3
+ "version": "6.72.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -99,9 +99,9 @@
99
99
  "build:watch": "nx watch --projects=epicshop -- nx run \\$NX_PROJECT_NAME:build"
100
100
  },
101
101
  "dependencies": {
102
- "@epic-web/workshop-utils": "6.72.0",
102
+ "@epic-web/workshop-utils": "6.72.1",
103
103
  "@inquirer/prompts": "^8.2.0",
104
- "@sentry/node": "^10.35.0",
104
+ "@sentry/node": "^10.36.0",
105
105
  "chalk": "^5.6.2",
106
106
  "close-with-grace": "^2.4.0",
107
107
  "execa": "^9.6.1",
@@ -109,7 +109,7 @@
109
109
  "match-sorter": "^8.2.0",
110
110
  "open": "^11.0.0",
111
111
  "openid-client": "^6.8.1",
112
- "ora": "^9.0.0",
112
+ "ora": "^9.1.0",
113
113
  "yargs": "^18.0.0"
114
114
  },
115
115
  "devDependencies": {