@seed-design/cli 0.0.3 → 1.1.0

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.
@@ -1,41 +1,31 @@
1
1
  import { getConfig } from "@/src/utils/get-config";
2
- import {
3
- fetchRegistryItem,
4
- getRegistryLibIndex,
5
- getRegistryUIIndex,
6
- } from "@/src/utils/get-metadata";
7
- import { transform } from "@/src/utils/transformers";
2
+ import { resolveDependencies } from "@/src/utils/resolve-dependencies";
3
+ import { fetchAvailableRegistries, fetchRegistry } from "@/src/utils/fetch";
4
+ import { writeRegistryItemSnippets } from "@/src/utils/write";
8
5
  import * as p from "@clack/prompts";
9
- import fs from "fs-extra";
10
6
  import path from "path";
11
- import color from "picocolors";
12
7
  import { z } from "zod";
13
8
 
14
9
  import type { CAC } from "cac";
15
10
  import { BASE_URL } from "../constants";
16
- import { addRelativeRegistries } from "../utils/add-relative-registries";
17
11
  import { highlight } from "../utils/color";
18
12
  import { installDependencies } from "../utils/install";
19
- import type { RegistryUIMachineGenerated } from "../schema";
13
+ import { analytics } from "../utils/analytics";
20
14
 
21
15
  const addOptionsSchema = z.object({
22
- components: z.array(z.string()).optional(),
16
+ itemIds: z.array(z.string()).optional(),
17
+ /**
18
+ * @deprecated use `seed-design add-all` instead
19
+ */
23
20
  all: z.boolean(),
24
- includeDeprecated: z.boolean().optional(),
25
21
  cwd: z.string(),
26
22
  baseUrl: z.string().optional(),
27
- // yes: z.boolean(),
28
- // overwrite: z.boolean(),
29
- // path: z.string().optional(),
30
23
  });
31
24
 
32
25
  export const addCommand = (cli: CAC) => {
33
26
  cli
34
- .command("add [...components]", "add component")
35
- .option("-a, --all", "Add all components", {
36
- default: false,
37
- })
38
- .option("--include-deprecated", "Include deprecated components when used with `--all`", {
27
+ .command("add [...item-ids]", "add items")
28
+ .option("-a, --all", "[Deprecated] Add all items", {
39
29
  default: false,
40
30
  })
41
31
  .option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", {
@@ -44,46 +34,76 @@ export const addCommand = (cli: CAC) => {
44
34
  .option(
45
35
  "-u, --baseUrl <baseUrl>",
46
36
  "the base url of the registry. defaults to the current directory.",
47
- {
48
- default: BASE_URL,
49
- },
37
+ { default: BASE_URL },
50
38
  )
51
- .example("seed-design add action-button")
52
- .example("seed-design add alert-dialog")
53
- .action(async (components, opts) => {
54
- p.intro(color.bgCyan("seed-design add"));
55
- const options = addOptionsSchema.parse({
56
- components,
57
- ...opts,
58
- });
39
+ .example("seed-design add ui:action-button")
40
+ .example("seed-design add ui:alert-dialog")
41
+ .action(async (itemIds, opts) => {
42
+ const startTime = Date.now();
43
+ p.intro("seed-design add");
44
+
45
+ const {
46
+ success,
47
+ data: { all, ...options },
48
+ error,
49
+ } = addOptionsSchema.safeParse({ itemIds, ...opts });
50
+
51
+ if (!success) {
52
+ p.log.error(`잘못된 옵션이에요: ${error?.message}`);
53
+
54
+ process.exit(1);
55
+ }
56
+
57
+ if (all) {
58
+ p.log.error(
59
+ "`--all` 옵션은 더 이상 지원되지 않아요. 대신 `seed-design add-all` 명령어를 사용해주세요.",
60
+ );
61
+
62
+ process.exit(1);
63
+ }
64
+
59
65
  const cwd = options.cwd;
60
66
  const baseUrl = options.baseUrl;
61
67
  const config = await getConfig(cwd);
62
- const registryComponentIndex = await getRegistryUIIndex(baseUrl);
63
- const libRegistryIndex = await getRegistryLibIndex(baseUrl);
68
+ const rootPath = path.resolve(cwd, config.path);
64
69
 
65
- const selectedComponents: string[] = await (async () => {
66
- if (options.all) {
67
- if (options.includeDeprecated) return registryComponentIndex.map((c) => c.name);
70
+ const { start, stop } = p.spinner();
68
71
 
69
- return registryComponentIndex.filter(({ deprecated }) => !deprecated).map((c) => c.name);
70
- }
72
+ start("Registry를 가져오고 있어요...");
71
73
 
72
- if (options.components.length > 0) return options.components;
74
+ const publicRegistries = await Promise.all(
75
+ (await fetchAvailableRegistries({ baseUrl })).map(async ({ id }) =>
76
+ fetchRegistry({ baseUrl, registryId: id }),
77
+ ),
78
+ );
79
+
80
+ stop("Registry를 가져왔어요.");
81
+
82
+ const selectedItemKeys: string[] = await (async () => {
83
+ if (options.itemIds.length > 0) return options.itemIds;
73
84
 
74
85
  const selected = await p.multiselect({
75
- message: "추가할 컴포넌트를 선택해주세요 (스페이스 바로 여러 개 선택 가능)",
76
- options: registryComponentIndex
77
- .map(({ name, description, deprecated }) => ({
78
- label: `${deprecated ? "(deprecated) " : ""}${name}`,
79
- value: name,
80
- hint: description,
81
- deprecated,
82
- }))
86
+ message: "추가할 항목을 선택해주세요 (스페이스 바로 여러 개 선택 가능)",
87
+ options: publicRegistries
88
+ .filter(({ hideFromCLICatalog }) => !hideFromCLICatalog)
89
+ .flatMap(({ id: registryId, items }) =>
90
+ items
91
+ .filter(({ hideFromCLICatalog }) => !hideFromCLICatalog)
92
+ .sort((a, b) => a.id.localeCompare(b.id))
93
+ .map(({ id, description, deprecated }) => ({
94
+ label: `${deprecated ? "(deprecated) " : ""}${highlight(registryId)}:${id}`,
95
+ value: `${registryId}:${id}`,
96
+ hint: description,
97
+
98
+ // used for sorting
99
+ deprecated,
100
+ registryItemCount: items.length,
101
+ })),
102
+ )
83
103
  .sort((a, b) => {
84
- if (a.deprecated === b.deprecated) return a.label.localeCompare(b.label);
104
+ if (a.deprecated !== b.deprecated) return a.deprecated ? 1 : -1;
85
105
 
86
- return a.deprecated ? 1 : -1;
106
+ return b.registryItemCount - a.registryItemCount;
87
107
  }),
88
108
  });
89
109
 
@@ -95,138 +115,118 @@ export const addCommand = (cli: CAC) => {
95
115
  return selected;
96
116
  })();
97
117
 
98
- if (!selectedComponents?.length) {
99
- p.log.error("컴포넌트를 찾을 수 없어요.");
118
+ if (!selectedItemKeys?.length) {
119
+ p.log.error("항목을 찾을 수 없어요.");
120
+
100
121
  process.exit(0);
101
122
  }
102
123
 
103
- p.log.message(`선택된 컴포넌트: ${highlight(selectedComponents.join(", "))}`);
124
+ p.log.message(`선택된 항목: ${highlight(selectedItemKeys.join(", "))}`);
104
125
 
105
- const allRelativeRegistries = addRelativeRegistries({
106
- userSelects: selectedComponents,
107
- uiRegistryIndex: registryComponentIndex,
108
- libRegistryIndex,
109
- });
126
+ const filteredItemKeys: string[] = [];
110
127
 
111
- const allRegistryItems: RegistryUIMachineGenerated = [];
128
+ for (const itemKey of selectedItemKeys) {
129
+ const [registryId, ...rest] = itemKey.split(":");
130
+ const itemId = rest.join(":");
112
131
 
113
- const { start, stop } = p.spinner();
114
- start("Registry를 가져오고 있어요...");
132
+ if (!registryId || !itemId) {
133
+ p.log.error(
134
+ `${highlight(itemKey)}: 항목 이름이 잘못되었어요. ${highlight("ui:action-button")}과 같은 형식으로 입력해보세요.`,
135
+ );
115
136
 
116
- for (const registry of allRelativeRegistries) {
117
- const registryItem = await fetchRegistryItem(registry.name, baseUrl, registry.type);
118
- allRegistryItems.push(registryItem);
119
- }
137
+ process.exit(1);
138
+ }
120
139
 
121
- stop();
140
+ const foundItem = publicRegistries
141
+ .find((r) => r.id === registryId)
142
+ ?.items.find((i) => i.id === itemId);
122
143
 
123
- if (allRegistryItems.length) {
124
- const filteredRegistryItems = allRegistryItems.filter(
125
- (c) => !selectedComponents.includes(c.name),
126
- );
127
- p.log.message(
128
- `추가로 설치될 레지스트리: ${highlight(
129
- filteredRegistryItems.map((c) => c.name).join(", "),
130
- )}`,
131
- );
132
- }
144
+ if (!foundItem) {
145
+ p.log.error(`${highlight(itemKey)}: 항목을 찾을 수 없어요.`);
133
146
 
134
- // 선택된 컴포넌트.json 레지스트리 파일 기반으로 컴포넌트를 추가합니다.
135
- const registryResult = [];
136
- const installResult = {
137
- installed: new Set(),
138
- filtered: new Set(),
139
- };
140
- for (const component of allRegistryItems) {
141
- if (component.deprecated && !options.includeDeprecated) {
147
+ process.exit(1);
148
+ }
149
+
150
+ if (foundItem.deprecated) {
142
151
  const confirm = await p.confirm({
143
- message: `${highlight(component.name)} deprecated 되었어요. 추가할까요?`,
152
+ message: `${highlight(foundItem.id)}: deprecated 되었어요. 추가할까요?`,
144
153
  initialValue: false,
145
154
  });
146
155
 
147
156
  if (confirm === false || p.isCancel(confirm)) {
148
- p.log.info(`${highlight(component.name)} 컴포넌트는 추가하지 않을게요.`);
157
+ p.log.info(`${highlight(foundItem.id)}: 추가하지 않을게요.`);
149
158
 
150
159
  continue;
151
160
  }
152
161
  }
153
162
 
154
- for (const registry of component.registries) {
155
- let targetPath = "";
156
- switch (registry.type) {
157
- case "ui":
158
- targetPath = config.resolvedUIPaths;
159
- break;
160
- case "lib":
161
- targetPath = config.resolvedLibPaths;
162
- break;
163
- default:
164
- break;
165
- }
163
+ filteredItemKeys.push(itemKey);
164
+ }
166
165
 
167
- if (!fs.existsSync(targetPath)) {
168
- await fs.mkdir(targetPath, { recursive: true });
169
- }
166
+ const { registryItemsToAdd, npmDependenciesToAdd } = resolveDependencies({
167
+ selectedItemKeys: filteredItemKeys,
168
+ publicRegistries,
169
+ });
170
170
 
171
- let filePath = path.resolve(targetPath, registry.name);
171
+ p.log.info(
172
+ `추가할 항목: ${highlight(registryItemsToAdd.map((r) => r.items.map((i) => `${r.registryId}:${i.id}`).join(", ")).join(", ") || "없음")}
172
173
 
173
- const content = await transform({
174
- filename: registry.name,
175
- config,
176
- raw: registry.content,
177
- });
174
+ 설치할 의존성: ${highlight(Array.from(npmDependenciesToAdd).join(", ") || "없음")}`,
175
+ );
178
176
 
179
- if (!config.tsx) {
180
- filePath = filePath.replace(/\.tsx$/, ".jsx");
181
- filePath = filePath.replace(/\.ts$/, ".js");
182
- }
177
+ await writeRegistryItemSnippets({
178
+ registryItemsToAdd,
179
+ rootPath,
180
+ cwd,
181
+ baseUrl,
182
+ config,
183
+ });
183
184
 
184
- await fs.writeFile(filePath, content);
185
- const relativePath = path.relative(cwd, filePath);
185
+ try {
186
+ const { installed, filtered } = await installDependencies({
187
+ cwd,
188
+ deps: Array.from(npmDependenciesToAdd),
189
+ });
186
190
 
187
- registryResult.push({
188
- name: registry.name,
189
- path: relativePath,
190
- });
191
+ if (installed.size === 0) {
192
+ p.log.message("모든 의존성이 이미 설치되어 있어요.");
191
193
  }
192
194
 
193
- // Install dependencies.
194
- if (component.dependencies?.length) {
195
- const result = await installDependencies({ cwd, deps: component.dependencies });
196
- installResult.installed = new Set([...installResult.installed, ...result.installed]);
197
- installResult.filtered = new Set([...installResult.filtered, ...result.filtered]);
198
- }
195
+ if (installed.size) {
196
+ p.log.message(`의존성 설치 완료: ${highlight(Array.from(installed).join(", "))}`);
199
197
 
200
- // Install devDependencies.
201
- if (component.devDependencies?.length) {
202
- const result = await installDependencies({
203
- cwd,
204
- deps: component.devDependencies,
205
- dev: true,
206
- });
207
- installResult.installed = new Set([...installResult.installed, ...result.installed]);
208
- installResult.filtered = new Set([...installResult.filtered, ...result.filtered]);
198
+ if (filtered.size) {
199
+ p.log.message(
200
+ `설치하지 않은 의존성 (이미 설치됨): ${highlight(Array.from(filtered).join(", "))}`,
201
+ );
202
+ }
209
203
  }
210
-
211
- p.log.success(`${highlight(component.name)} 관련 파일 추가 완료`);
204
+ p.outro("완료했어요.");
205
+ } catch (error) {
206
+ p.log.error(`추가에 실패했어요. ${error}`);
207
+ p.outro(highlight("작업이 취소됐어요."));
208
+ process.exit(1);
212
209
  }
213
210
 
214
- if (installResult.installed.size) {
215
- p.log.message(
216
- `설치된 의존성: ${highlight(Array.from(installResult.installed).join(", "))}`,
217
- );
218
- }
219
- if (installResult.filtered.size) {
220
- p.log.message(
221
- `이미 설치된 의존성: ${highlight(Array.from(installResult.filtered).join(", "))}`,
222
- );
223
- }
224
- if (registryResult.length) {
225
- for (const registry of registryResult) {
226
- p.log.message(`추가된 파일: ${highlight(registry.path)}`);
227
- }
228
- }
211
+ // add 성공 이벤트 추적
212
+ const duration = Date.now() - startTime;
213
+ const uniqueRegistries = new Set(registryItemsToAdd.map((r) => r.registryId));
214
+ const hasDeprecated = selectedItemKeys.some((itemKey) => {
215
+ const [registryId, ...rest] = itemKey.split(":");
216
+ const itemId = rest.join(":");
217
+ return publicRegistries.find((r) => r.id === registryId)?.items.find((i) => i.id === itemId)
218
+ ?.deprecated;
219
+ });
229
220
 
230
- p.outro("컴포넌트 추가 완료.");
221
+ await analytics.track(options.cwd, {
222
+ event: "add",
223
+ properties: {
224
+ items_count: filteredItemKeys.length,
225
+ registries: Array.from(uniqueRegistries),
226
+ has_deprecated: hasDeprecated,
227
+ dependencies_count: npmDependenciesToAdd.size,
228
+ duration_ms: duration,
229
+ },
230
+ });
231
231
  });
232
232
  };
@@ -1,12 +1,14 @@
1
1
  import * as p from "@clack/prompts";
2
2
  import fs from "fs-extra";
3
3
  import path from "path";
4
- import color from "picocolors";
5
4
  import { z } from "zod";
5
+ import { analytics } from "../utils/analytics";
6
+ import { highlight } from "../utils/color";
6
7
 
7
- import type { RawConfig } from "@/src/utils/get-config";
8
+ import type { Config } from "@/src/utils/get-config";
8
9
 
9
10
  import type { CAC } from "cac";
11
+ import dedent from "dedent";
10
12
 
11
13
  const initOptionsSchema = z.object({
12
14
  cwd: z.string(),
@@ -21,15 +23,16 @@ export const initCommand = (cli: CAC) => {
21
23
  })
22
24
  .option("-y, --yes", "모든 질문에 대해 기본값으로 답변합니다.")
23
25
  .action(async (opts) => {
24
- const highlight = (text: string) => color.cyan(text);
25
- p.intro(color.bgCyan("seed-design.json 파일 생성"));
26
+ const startTime = Date.now();
27
+ p.intro("seed-design.json 파일 생성");
26
28
 
27
29
  const options = initOptionsSchema.parse(opts);
28
30
  const isYesOption = options.yes;
29
- let config: RawConfig = {
31
+ let config: Config = {
30
32
  rsc: false,
31
33
  tsx: true,
32
34
  path: "./seed-design",
35
+ telemetry: true,
33
36
  };
34
37
 
35
38
  if (!isYesOption) {
@@ -52,6 +55,11 @@ export const initCommand = (cli: CAC) => {
52
55
  defaultValue: "./seed-design",
53
56
  placeholder: "./seed-design",
54
57
  }),
58
+ telemetry: () =>
59
+ p.confirm({
60
+ message: `개선을 위해 ${highlight("익명 사용 데이터")}를 수집할까요?`,
61
+ initialValue: true,
62
+ }),
55
63
  },
56
64
  {
57
65
  onCancel: () => {
@@ -73,15 +81,41 @@ export const initCommand = (cli: CAC) => {
73
81
  await fs.writeFile(targetPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
74
82
  const relativePath = path.relative(process.cwd(), targetPath);
75
83
  stop(`seed-design.json 파일이 ${highlight(relativePath)}에 생성됐어요.`);
76
- p.log.info(color.gray("seed-design add {component} 명령어로 컴포넌트를 추가해보세요!"));
84
+
85
+ p.log.info(highlight("seed-design add {component} 명령어로 컴포넌트를 추가해보세요!"));
77
86
  p.log.info(
78
- color.gray("seed-design add 명령어로 추가할 수 있는 모든 컴포넌트를 확인해보세요."),
87
+ highlight("seed-design add 명령어로 추가할 수 있는 모든 컴포넌트를 확인해보세요."),
88
+ );
89
+
90
+ p.note(
91
+ dedent(`SEED Design CLI는 개선을 위해 익명 사용 데이터를 수집해요.
92
+
93
+ 비활성화하려면:
94
+ • seed-design.json에서 ${highlight('"telemetry": false')}로 설정
95
+ • ${highlight("DISABLE_TELEMETRY=true")} 환경 변수 설정
96
+
97
+ 자세한 내용: https://seed-design.com/react/getting-started/cli/configuration#telemetry`),
98
+ "Telemetry 안내",
79
99
  );
100
+
80
101
  p.outro("작업이 완료됐어요.");
81
102
  } catch (error) {
82
103
  p.log.error(`seed-design.json 파일 생성에 실패했어요. ${error}`);
83
- p.outro(color.bgRed("작업이 취소됐어요."));
104
+ p.outro(highlight("작업이 취소됐어요."));
84
105
  process.exit(1);
85
106
  }
107
+
108
+ // init 성공 이벤트 추적
109
+ const duration = Date.now() - startTime;
110
+ await analytics.track(options.cwd, {
111
+ event: "init",
112
+ properties: {
113
+ tsx: config.tsx,
114
+ rsc: config.rsc,
115
+ telemetry: config.telemetry,
116
+ yes_option: isYesOption,
117
+ duration_ms: duration,
118
+ },
119
+ });
86
120
  });
87
121
  };
package/src/env.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ declare global {
2
+ namespace NodeJS {
3
+ interface ProcessEnv {
4
+ NODE_ENV: "dev" | "prod";
5
+ POSTHOG_API_KEY?: string;
6
+ POSTHOG_HOST?: string;
7
+ DISABLE_TELEMETRY?: "true" | "false";
8
+ SEED_DISABLE_TELEMETRY?: "true" | "false";
9
+ }
10
+ }
11
+ }
12
+
13
+ export {};
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { addCommand } from "@/src/commands/add";
4
+ import { addAllCommand } from "@/src/commands/add-all";
4
5
  import { initCommand } from "@/src/commands/init";
5
6
  import { getPackageInfo } from "@/src/utils/get-package-info";
6
7
  import { cac } from "cac";
@@ -13,6 +14,7 @@ async function main() {
13
14
 
14
15
  /* Commands */
15
16
  addCommand(CLI);
17
+ addAllCommand(CLI);
16
18
  initCommand(CLI);
17
19
 
18
20
  CLI.version(packageInfo.version || "1.0.0", "-v, --version");
package/src/schema.ts CHANGED
@@ -1,81 +1,55 @@
1
1
  import { z } from "zod";
2
2
 
3
- export const registryType = z.union([z.literal("ui"), z.literal("lib")]);
4
-
5
- export const registryUIItemSchema = z.object({
6
- /**
7
- * @description 레지스트리 이름
8
- * @example chip-tabs, alert-dialog
9
- */
10
- name: z.string(),
3
+ /**
4
+ * this should be in sync with `docs/registry/schema.ts`
5
+ */
6
+ export const publicRegistryItemSchema = z.object({
7
+ id: z.string(),
11
8
 
12
9
  description: z.string().optional(),
13
10
 
14
- /**
15
- * @description 레지스트리 의존성
16
- * @example @seed-design/react-tabs
17
- */
18
- dependencies: z.array(z.string()).optional(),
11
+ deprecated: z.boolean().optional(),
19
12
 
20
- /**
21
- * @description 레지스트리 개발 의존성
22
- */
23
- devDependencies: z.array(z.string()).optional(),
13
+ hideFromCLICatalog: z.boolean().optional(),
14
+
15
+ ///////////////////////////////////////////////////////////////
16
+
17
+ dependencies: z.array(z.string()).optional(),
24
18
 
25
- /**
26
- * @description 레지스트리 내부의 Seed Design 컴포넌트 의존성
27
- * * `:`를 기준으로 왼쪽은 {registryType}, 오른쪽은 파일 이름
28
- * @example ui:action-button
29
- * @example lib:manner-temp-level
30
- */
31
- innerDependencies: z.array(z.string()).optional(),
19
+ innerDependencies: z
20
+ .array(
21
+ z.object({
22
+ registryId: z.string(),
23
+ itemIds: z.array(z.string()),
24
+ }),
25
+ )
26
+ .optional(),
32
27
 
33
- /**
34
- * @description
35
- * 컴포넌트 코드 스니펫 경로, 여러 파일이 될 수 있어서 배열로 정의
36
- * `:`를 기준으로 왼쪽은 {registryType}, 오른쪽은 파일 이름
37
- * @example ui:alert-dialog.tsx
38
- * @example ui:use-dismissible.ts
39
- * @example lib:manner-temp-level.ts
40
- */
41
- files: z.array(z.string()),
28
+ ///////////////////////////////////////////////////////////////
42
29
 
43
- /**
44
- * @description 컴포넌트 deprecated 여부
45
- */
46
- deprecated: z.literal(true).optional(),
30
+ snippets: z.array(z.object({ path: z.string(), content: z.string() })),
47
31
  });
48
- export const registryUISchema = z.array(registryUIItemSchema);
49
32
 
50
33
  /**
51
- * @description 머신이 생성한 registry component schema
34
+ * this should be in sync with `packages/cli/src/schema.ts`
52
35
  */
53
- const omittedRegistryUISchema = registryUIItemSchema.omit({
54
- files: true,
55
- });
56
- export const registryUIItemMachineGeneratedSchema = omittedRegistryUISchema.extend({
57
- registries: z.array(
58
- z.object({
59
- name: z.string(),
60
- type: registryType,
61
- content: z.string(),
62
- }),
36
+ export const publicRegistrySchema = z.object({
37
+ id: z.string(),
38
+
39
+ hideFromCLICatalog: z.boolean().optional(),
40
+
41
+ items: z.array(
42
+ publicRegistryItemSchema
43
+ .omit({ snippets: true })
44
+ .extend({ snippets: z.array(z.object({ path: z.string() })) }),
63
45
  ),
64
46
  });
65
- export const registryComponentMachineGeneratedSchema = z.array(
66
- registryUIItemMachineGeneratedSchema,
67
- );
68
47
 
69
- // NOTE: 현재는 lib이 ui와 타입이 동일하지만, 따로 가져가야한다면 타입을 변경해야해요.
70
- export const registryLibItemMachineGeneratedSchema = registryUIItemMachineGeneratedSchema;
71
-
72
- // NOTE: 현재는 lib이 ui와 타입이 동일하지만, 따로 가져가야한다면 타입을 변경해야해요.
73
- export type RegistryLibItem = z.infer<typeof registryUIItemSchema>;
74
- export type RegistryLib = z.infer<typeof registryUISchema>;
75
- export type RegistryUIItem = z.infer<typeof registryUIItemSchema>;
76
- export type RegistryUI = z.infer<typeof registryUISchema>;
48
+ /**
49
+ * this should be in sync with `packages/cli/src/schema.ts`
50
+ */
51
+ export const publicAvailableRegistriesSchema = z.array(z.object({ id: z.string() }));
77
52
 
78
- export type RegistryUIItemMachineGenerated = z.infer<typeof registryUIItemMachineGeneratedSchema>;
79
- export type RegistryUIMachineGenerated = z.infer<typeof registryComponentMachineGeneratedSchema>;
80
- export type RegistryLibItemMachineGenerated = z.infer<typeof registryLibItemMachineGeneratedSchema>;
81
- export type RegistryLibMachineGenerated = z.infer<typeof registryComponentMachineGeneratedSchema>;
53
+ export type PublicRegistryItem = z.infer<typeof publicRegistryItemSchema>;
54
+ export type PublicRegistry = z.infer<typeof publicRegistrySchema>;
55
+ export type PublicAvailableRegistries = z.infer<typeof publicAvailableRegistriesSchema>;