@hanzogui/recipes 8.0.0 → 8.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/admin.js CHANGED
@@ -11,7 +11,11 @@ function resolveBaseUrl(override) {
11
11
  }
12
12
 
13
13
  // src/admin.ts
14
- async function authAdmin({ baseUrl, email, password }) {
14
+ async function authAdmin({
15
+ baseUrl,
16
+ email,
17
+ password
18
+ }) {
15
19
  const url = `${resolveBaseUrl(baseUrl)}/v1/base/admins/auth-with-password`;
16
20
  const res = await fetch(url, {
17
21
  method: "POST",
@@ -27,7 +31,9 @@ async function authAdmin({ baseUrl, email, password }) {
27
31
  async function ensureCollection(auth) {
28
32
  const base = resolveBaseUrl(auth.baseUrl);
29
33
  const headers = { Authorization: auth.token, "Content-Type": "application/json" };
30
- const probe = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}`, { headers });
34
+ const probe = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}`, {
35
+ headers
36
+ });
31
37
  if (probe.ok)
32
38
  return "existed";
33
39
  const schema = {
@@ -42,7 +48,9 @@ async function ensureCollection(auth) {
42
48
  { name: "recipeDeps", type: "json", required: false, options: {} },
43
49
  { name: "files", type: "json", required: true, options: {} }
44
50
  ],
45
- indexes: [`CREATE UNIQUE INDEX idx_${RECIPES_COLLECTION}_slug ON ${RECIPES_COLLECTION} (slug)`],
51
+ indexes: [
52
+ `CREATE UNIQUE INDEX idx_${RECIPES_COLLECTION}_slug ON ${RECIPES_COLLECTION} (slug)`
53
+ ],
46
54
  listRule: "",
47
55
  viewRule: "",
48
56
  createRule: null,
package/dist/index.js CHANGED
@@ -45,6 +45,35 @@ function resolveInstallDir(root, config) {
45
45
  return path.join(root, config.installDir ?? DEFAULT_INSTALL_DIR);
46
46
  }
47
47
 
48
+ // src/write.ts
49
+ import { existsSync as existsSync2, promises as fs2 } from "node:fs";
50
+ import path2 from "node:path";
51
+ async function getInstallDir(opts) {
52
+ if (opts.installDir)
53
+ return opts.installDir;
54
+ const root = await findProjectRoot(opts.cwd);
55
+ return resolveInstallDir(root, await readConfig(root));
56
+ }
57
+ async function installRecipe(recipe, opts = {}) {
58
+ const installDir = await getInstallDir(opts);
59
+ const written = [];
60
+ for (const file of recipe.files) {
61
+ const dest = path2.join(installDir, file.path);
62
+ const dir = path2.dirname(dest);
63
+ if (!existsSync2(dir))
64
+ await fs2.mkdir(dir, { recursive: true });
65
+ await fs2.writeFile(dest, file.source);
66
+ written.push(dest);
67
+ }
68
+ return written;
69
+ }
70
+ async function installPlan(plan, opts = {}) {
71
+ const written = [];
72
+ for (const r of [plan.recipe, ...plan.transitiveRecipes]) {
73
+ written.push(...await installRecipe(r, opts));
74
+ }
75
+ return written;
76
+ }
48
77
  // src/read.ts
49
78
  async function getJSON(url) {
50
79
  const res = await fetch(url, { headers: { Accept: "application/json" } });
@@ -93,13 +122,17 @@ async function resolveRecipe(slug, opts = {}) {
93
122
  })();
94
123
  const recipe = seen.get(slug);
95
124
  const transitiveRecipes = Array.from(seen.values()).filter((r) => r.slug !== slug);
96
- const path2 = await import("node:path");
97
- const targetPaths = [recipe, ...transitiveRecipes].flatMap((r) => r.files.map((f) => path2.join(installDir, f.path)));
125
+ const path3 = await import("node:path");
126
+ const targetPaths = [recipe, ...transitiveRecipes].flatMap((r) => r.files.map((f) => path3.join(installDir, f.path)));
98
127
  return { recipe, transitiveRecipes, targetPaths };
99
128
  }
100
129
 
101
130
  // src/admin.ts
102
- async function authAdmin({ baseUrl, email, password }) {
131
+ async function authAdmin({
132
+ baseUrl,
133
+ email,
134
+ password
135
+ }) {
103
136
  const url = `${resolveBaseUrl(baseUrl)}/v1/base/admins/auth-with-password`;
104
137
  const res = await fetch(url, {
105
138
  method: "POST",
@@ -115,7 +148,9 @@ async function authAdmin({ baseUrl, email, password }) {
115
148
  async function ensureCollection(auth) {
116
149
  const base = resolveBaseUrl(auth.baseUrl);
117
150
  const headers = { Authorization: auth.token, "Content-Type": "application/json" };
118
- const probe = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}`, { headers });
151
+ const probe = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}`, {
152
+ headers
153
+ });
119
154
  if (probe.ok)
120
155
  return "existed";
121
156
  const schema = {
@@ -130,7 +165,9 @@ async function ensureCollection(auth) {
130
165
  { name: "recipeDeps", type: "json", required: false, options: {} },
131
166
  { name: "files", type: "json", required: true, options: {} }
132
167
  ],
133
- indexes: [`CREATE UNIQUE INDEX idx_${RECIPES_COLLECTION}_slug ON ${RECIPES_COLLECTION} (slug)`],
168
+ indexes: [
169
+ `CREATE UNIQUE INDEX idx_${RECIPES_COLLECTION}_slug ON ${RECIPES_COLLECTION} (slug)`
170
+ ],
134
171
  listRule: "",
135
172
  viewRule: "",
136
173
  createRule: null,
@@ -176,35 +213,6 @@ async function upsertRecipe(auth, recipe) {
176
213
  throw new Error(`POST ${recipe.slug}: ${res.status} ${await res.text()}`);
177
214
  return "created";
178
215
  }
179
- // src/write.ts
180
- import { existsSync as existsSync2, promises as fs2 } from "node:fs";
181
- import path2 from "node:path";
182
- async function getInstallDir(opts) {
183
- if (opts.installDir)
184
- return opts.installDir;
185
- const root = await findProjectRoot(opts.cwd);
186
- return resolveInstallDir(root, await readConfig(root));
187
- }
188
- async function installRecipe(recipe, opts = {}) {
189
- const installDir = await getInstallDir(opts);
190
- const written = [];
191
- for (const file of recipe.files) {
192
- const dest = path2.join(installDir, file.path);
193
- const dir = path2.dirname(dest);
194
- if (!existsSync2(dir))
195
- await fs2.mkdir(dir, { recursive: true });
196
- await fs2.writeFile(dest, file.source);
197
- written.push(dest);
198
- }
199
- return written;
200
- }
201
- async function installPlan(plan, opts = {}) {
202
- const written = [];
203
- for (const r of [plan.recipe, ...plan.transitiveRecipes]) {
204
- written.push(...await installRecipe(r, opts));
205
- }
206
- return written;
207
- }
208
216
  export {
209
217
  upsertRecipe,
210
218
  resolveRecipe,
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@hanzogui/recipes",
3
- "version": "8.0.0",
3
+ "version": "8.1.1",
4
4
  "description": "Hanzo GUI recipe library: read from Base, resolve transitive deps, install into a project.",
5
5
  "license": "BSD-3-Clause",
6
6
  "author": "Hanzo AI <dev@hanzo.ai>",
7
7
  "homepage": "https://gui.hanzo.ai",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "https://github.com/hanzoai/gui.git",
10
+ "url": "git+https://github.com/hanzoai/gui.git",
11
11
  "directory": "pkgs/recipes"
12
12
  },
13
13
  "type": "module",
package/src/admin.ts CHANGED
@@ -13,7 +13,11 @@ export type AdminPasswordAuth = {
13
13
  }
14
14
 
15
15
  /** Exchanges admin email+password for a Base session token. */
16
- export async function authAdmin({ baseUrl, email, password }: AdminPasswordAuth): Promise<string> {
16
+ export async function authAdmin({
17
+ baseUrl,
18
+ email,
19
+ password,
20
+ }: AdminPasswordAuth): Promise<string> {
17
21
  const url = `${resolveBaseUrl(baseUrl)}/v1/base/admins/auth-with-password`
18
22
  const res = await fetch(url, {
19
23
  method: 'POST',
@@ -31,7 +35,9 @@ export async function authAdmin({ baseUrl, email, password }: AdminPasswordAuth)
31
35
  export async function ensureCollection(auth: AdminAuth): Promise<'created' | 'existed'> {
32
36
  const base = resolveBaseUrl(auth.baseUrl)
33
37
  const headers = { Authorization: auth.token, 'Content-Type': 'application/json' }
34
- const probe = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}`, { headers })
38
+ const probe = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}`, {
39
+ headers,
40
+ })
35
41
  if (probe.ok) return 'existed'
36
42
 
37
43
  const schema = {
@@ -46,7 +52,9 @@ export async function ensureCollection(auth: AdminAuth): Promise<'created' | 'ex
46
52
  { name: 'recipeDeps', type: 'json', required: false, options: {} },
47
53
  { name: 'files', type: 'json', required: true, options: {} },
48
54
  ],
49
- indexes: [`CREATE UNIQUE INDEX idx_${RECIPES_COLLECTION}_slug ON ${RECIPES_COLLECTION} (slug)`],
55
+ indexes: [
56
+ `CREATE UNIQUE INDEX idx_${RECIPES_COLLECTION}_slug ON ${RECIPES_COLLECTION} (slug)`,
57
+ ],
50
58
  listRule: '',
51
59
  viewRule: '',
52
60
  createRule: null,
@@ -90,7 +98,8 @@ export async function upsertRecipe(
90
98
  `${base}/v1/base/collections/${RECIPES_COLLECTION}/records/${existing}`,
91
99
  { method: 'PATCH', headers, body }
92
100
  )
93
- if (!res.ok) throw new Error(`PATCH ${recipe.slug}: ${res.status} ${await res.text()}`)
101
+ if (!res.ok)
102
+ throw new Error(`PATCH ${recipe.slug}: ${res.status} ${await res.text()}`)
94
103
  return 'updated'
95
104
  }
96
105
  const res = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}/records`, {
package/src/project.ts CHANGED
@@ -11,7 +11,8 @@ export async function findProjectRoot(start: string = process.cwd()): Promise<st
11
11
  if (existsSync(pkgPath)) {
12
12
  try {
13
13
  const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'))
14
- if (pkg.workspaces || existsSync(path.join(dir, 'pnpm-workspace.yaml'))) return dir
14
+ if (pkg.workspaces || existsSync(path.join(dir, 'pnpm-workspace.yaml')))
15
+ return dir
15
16
  } catch {}
16
17
  }
17
18
  if (existsSync(path.join(dir, '.git'))) return dir
package/src/read.ts CHANGED
@@ -17,9 +17,12 @@ export type ReaderOptions = {
17
17
  async function getJSON<T>(url: string): Promise<T> {
18
18
  const res = await fetch(url, { headers: { Accept: 'application/json' } })
19
19
  if (!res.ok) {
20
- throw Object.assign(new Error(`Base request failed: ${res.status} ${res.statusText}`), {
21
- status: res.status,
22
- })
20
+ throw Object.assign(
21
+ new Error(`Base request failed: ${res.status} ${res.statusText}`),
22
+ {
23
+ status: res.status,
24
+ }
25
+ )
23
26
  }
24
27
  return (await res.json()) as T
25
28
  }
@@ -53,7 +56,10 @@ export type ResolveOptions = ReaderOptions & {
53
56
  }
54
57
 
55
58
  /** Walks recipeDeps transitively, computes target paths under the resolved install dir. */
56
- export async function resolveRecipe(slug: string, opts: ResolveOptions = {}): Promise<InstallPlan> {
59
+ export async function resolveRecipe(
60
+ slug: string,
61
+ opts: ResolveOptions = {}
62
+ ): Promise<InstallPlan> {
57
63
  const seen = new Map<string, Recipe>()
58
64
  const queue = [slug]
59
65
  while (queue.length) {
package/src/types.ts CHANGED
@@ -21,7 +21,10 @@ export type RecipeSummary = Pick<
21
21
  'id' | 'slug' | 'name' | 'description' | 'category'
22
22
  >
23
23
 
24
- export type RecipeInput = Pick<Recipe, 'slug' | 'name' | 'description' | 'category' | 'npmDeps' | 'recipeDeps' | 'files'>
24
+ export type RecipeInput = Pick<
25
+ Recipe,
26
+ 'slug' | 'name' | 'description' | 'category' | 'npmDeps' | 'recipeDeps' | 'files'
27
+ >
25
28
 
26
29
  export type InstallPlan = {
27
30
  recipe: Recipe
package/src/write.ts CHANGED
@@ -17,7 +17,10 @@ async function getInstallDir(opts: WriteOptions): Promise<string> {
17
17
  }
18
18
 
19
19
  /** Writes one recipe's files. Returns absolute paths written. */
20
- export async function installRecipe(recipe: Recipe, opts: WriteOptions = {}): Promise<string[]> {
20
+ export async function installRecipe(
21
+ recipe: Recipe,
22
+ opts: WriteOptions = {}
23
+ ): Promise<string[]> {
21
24
  const installDir = await getInstallDir(opts)
22
25
  const written: string[] = []
23
26
  for (const file of recipe.files) {
@@ -31,7 +34,10 @@ export async function installRecipe(recipe: Recipe, opts: WriteOptions = {}): Pr
31
34
  }
32
35
 
33
36
  /** Writes a recipe and all its transitive dependents from a resolved plan. */
34
- export async function installPlan(plan: InstallPlan, opts: WriteOptions = {}): Promise<string[]> {
37
+ export async function installPlan(
38
+ plan: InstallPlan,
39
+ opts: WriteOptions = {}
40
+ ): Promise<string[]> {
35
41
  const written: string[] = []
36
42
  for (const r of [plan.recipe, ...plan.transitiveRecipes]) {
37
43
  written.push(...(await installRecipe(r, opts)))