@hanzogui/recipes 8.0.0 → 8.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.
- package/dist/admin.js +11 -3
- package/dist/index.js +11 -3
- package/package.json +2 -2
- package/src/admin.ts +13 -4
- package/src/project.ts +2 -1
- package/src/read.ts +10 -4
- package/src/types.ts +4 -1
- package/src/write.ts +8 -2
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({
|
|
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}`, {
|
|
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: [
|
|
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
|
@@ -99,7 +99,11 @@ async function resolveRecipe(slug, opts = {}) {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
// src/admin.ts
|
|
102
|
-
async function authAdmin({
|
|
102
|
+
async function authAdmin({
|
|
103
|
+
baseUrl,
|
|
104
|
+
email,
|
|
105
|
+
password
|
|
106
|
+
}) {
|
|
103
107
|
const url = `${resolveBaseUrl(baseUrl)}/v1/base/admins/auth-with-password`;
|
|
104
108
|
const res = await fetch(url, {
|
|
105
109
|
method: "POST",
|
|
@@ -115,7 +119,9 @@ async function authAdmin({ baseUrl, email, password }) {
|
|
|
115
119
|
async function ensureCollection(auth) {
|
|
116
120
|
const base = resolveBaseUrl(auth.baseUrl);
|
|
117
121
|
const headers = { Authorization: auth.token, "Content-Type": "application/json" };
|
|
118
|
-
const probe = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}`, {
|
|
122
|
+
const probe = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}`, {
|
|
123
|
+
headers
|
|
124
|
+
});
|
|
119
125
|
if (probe.ok)
|
|
120
126
|
return "existed";
|
|
121
127
|
const schema = {
|
|
@@ -130,7 +136,9 @@ async function ensureCollection(auth) {
|
|
|
130
136
|
{ name: "recipeDeps", type: "json", required: false, options: {} },
|
|
131
137
|
{ name: "files", type: "json", required: true, options: {} }
|
|
132
138
|
],
|
|
133
|
-
indexes: [
|
|
139
|
+
indexes: [
|
|
140
|
+
`CREATE UNIQUE INDEX idx_${RECIPES_COLLECTION}_slug ON ${RECIPES_COLLECTION} (slug)`
|
|
141
|
+
],
|
|
134
142
|
listRule: "",
|
|
135
143
|
viewRule: "",
|
|
136
144
|
createRule: null,
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzogui/recipes",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.1.0",
|
|
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({
|
|
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}`, {
|
|
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: [
|
|
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)
|
|
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')))
|
|
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(
|
|
21
|
-
|
|
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(
|
|
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<
|
|
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(
|
|
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(
|
|
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)))
|