@hanzogui/recipes 8.3.1 → 8.3.3

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.
Files changed (57) hide show
  1. package/dist/cjs/admin.js +91 -0
  2. package/dist/cjs/admin.js.map +1 -0
  3. package/dist/cjs/config.js +12 -0
  4. package/dist/cjs/config.js.map +1 -0
  5. package/dist/cjs/index.js +10 -0
  6. package/dist/cjs/index.js.map +1 -0
  7. package/dist/cjs/package.json +1 -0
  8. package/dist/cjs/project.js +46 -0
  9. package/dist/cjs/project.js.map +1 -0
  10. package/dist/cjs/read.js +62 -0
  11. package/dist/cjs/read.js.map +1 -0
  12. package/dist/cjs/types.js +3 -0
  13. package/dist/cjs/types.js.map +1 -0
  14. package/dist/cjs/write.js +37 -0
  15. package/dist/cjs/write.js.map +1 -0
  16. package/dist/esm/admin.js +86 -0
  17. package/dist/esm/admin.js.map +1 -0
  18. package/dist/esm/config.js +8 -0
  19. package/dist/esm/config.js.map +1 -0
  20. package/dist/esm/index.js +7 -0
  21. package/dist/esm/index.js.map +1 -0
  22. package/dist/esm/project.js +40 -0
  23. package/dist/esm/project.js.map +1 -0
  24. package/dist/esm/read.js +56 -0
  25. package/dist/esm/read.js.map +1 -0
  26. package/dist/esm/types.js +2 -0
  27. package/dist/esm/types.js.map +1 -0
  28. package/dist/esm/write.js +32 -0
  29. package/dist/esm/write.js.map +1 -0
  30. package/package.json +27 -16
  31. package/readme.md +1 -6
  32. package/src/admin.test.ts +116 -0
  33. package/src/config.test.ts +28 -0
  34. package/src/project.test.ts +63 -0
  35. package/src/read.test.ts +163 -0
  36. package/src/write.test.ts +52 -0
  37. package/types/admin.d.ts +17 -0
  38. package/types/admin.d.ts.map +1 -0
  39. package/types/config.d.ts +6 -0
  40. package/types/config.d.ts.map +1 -0
  41. package/types/index.d.ts +7 -0
  42. package/types/index.d.ts.map +1 -0
  43. package/types/project.d.ts +8 -0
  44. package/types/project.d.ts.map +1 -0
  45. package/types/read.d.ts +15 -0
  46. package/types/read.d.ts.map +1 -0
  47. package/types/types.d.ts +27 -0
  48. package/types/types.d.ts.map +1 -0
  49. package/types/write.d.ts +12 -0
  50. package/types/write.d.ts.map +1 -0
  51. package/dist/admin.js +0 -103
  52. package/dist/config.js +0 -18
  53. package/dist/index.js +0 -233
  54. package/dist/project.js +0 -51
  55. package/dist/read.js +0 -104
  56. package/dist/types.js +0 -0
  57. package/dist/write.js +0 -80
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authAdmin = authAdmin;
4
+ exports.ensureCollection = ensureCollection;
5
+ exports.upsertRecipe = upsertRecipe;
6
+ const config_js_1 = require("./config.js");
7
+ /** Exchanges admin email+password for a Base session token. */
8
+ async function authAdmin({ baseUrl, email, password, }) {
9
+ const url = `${(0, config_js_1.resolveBaseUrl)(baseUrl)}/v1/base/admins/auth-with-password`;
10
+ const res = await fetch(url, {
11
+ method: 'POST',
12
+ headers: { 'Content-Type': 'application/json' },
13
+ body: JSON.stringify({ identity: email, password }),
14
+ });
15
+ if (!res.ok) {
16
+ throw new Error(`Admin auth failed: ${res.status} ${await res.text()}`);
17
+ }
18
+ const data = (await res.json());
19
+ return data.token;
20
+ }
21
+ /** Idempotent: creates the gui_recipes collection if missing, no-ops otherwise. */
22
+ async function ensureCollection(auth) {
23
+ const base = (0, config_js_1.resolveBaseUrl)(auth.baseUrl);
24
+ const headers = { Authorization: auth.token, 'Content-Type': 'application/json' };
25
+ const probe = await fetch(`${base}/v1/base/collections/${config_js_1.RECIPES_COLLECTION}`, {
26
+ headers,
27
+ });
28
+ if (probe.ok)
29
+ return 'existed';
30
+ const schema = {
31
+ name: config_js_1.RECIPES_COLLECTION,
32
+ type: 'base',
33
+ schema: [
34
+ { name: 'slug', type: 'text', required: true, unique: true, options: {} },
35
+ { name: 'name', type: 'text', required: true, options: {} },
36
+ { name: 'description', type: 'text', required: false, options: {} },
37
+ { name: 'category', type: 'text', required: false, options: {} },
38
+ { name: 'npmDeps', type: 'json', required: false, options: {} },
39
+ { name: 'recipeDeps', type: 'json', required: false, options: {} },
40
+ { name: 'files', type: 'json', required: true, options: {} },
41
+ ],
42
+ indexes: [
43
+ `CREATE UNIQUE INDEX idx_${config_js_1.RECIPES_COLLECTION}_slug ON ${config_js_1.RECIPES_COLLECTION} (slug)`,
44
+ ],
45
+ listRule: '',
46
+ viewRule: '',
47
+ createRule: null,
48
+ updateRule: null,
49
+ deleteRule: null,
50
+ };
51
+ const res = await fetch(`${base}/v1/base/collections`, {
52
+ method: 'POST',
53
+ headers,
54
+ body: JSON.stringify(schema),
55
+ });
56
+ if (!res.ok) {
57
+ throw new Error(`Failed to create collection: ${res.status} ${await res.text()}`);
58
+ }
59
+ return 'created';
60
+ }
61
+ async function findExisting(auth, slug) {
62
+ const base = (0, config_js_1.resolveBaseUrl)(auth.baseUrl);
63
+ const filter = encodeURIComponent(`slug="${slug}"`);
64
+ const res = await fetch(`${base}/v1/base/collections/${config_js_1.RECIPES_COLLECTION}/records?perPage=1&filter=${filter}`, { headers: { Authorization: auth.token } });
65
+ if (!res.ok)
66
+ return null;
67
+ const data = (await res.json());
68
+ return data.items[0]?.id ?? null;
69
+ }
70
+ /** Upsert by slug: PATCH if existing, POST if new. */
71
+ async function upsertRecipe(auth, recipe) {
72
+ const base = (0, config_js_1.resolveBaseUrl)(auth.baseUrl);
73
+ const headers = { Authorization: auth.token, 'Content-Type': 'application/json' };
74
+ const body = JSON.stringify(recipe);
75
+ const existing = await findExisting(auth, recipe.slug);
76
+ if (existing) {
77
+ const res = await fetch(`${base}/v1/base/collections/${config_js_1.RECIPES_COLLECTION}/records/${existing}`, { method: 'PATCH', headers, body });
78
+ if (!res.ok)
79
+ throw new Error(`PATCH ${recipe.slug}: ${res.status} ${await res.text()}`);
80
+ return 'updated';
81
+ }
82
+ const res = await fetch(`${base}/v1/base/collections/${config_js_1.RECIPES_COLLECTION}/records`, {
83
+ method: 'POST',
84
+ headers,
85
+ body,
86
+ });
87
+ if (!res.ok)
88
+ throw new Error(`POST ${recipe.slug}: ${res.status} ${await res.text()}`);
89
+ return 'created';
90
+ }
91
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/admin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_CONFIG_FILENAMES = exports.DEFAULT_INSTALL_DIR = exports.RECIPES_COLLECTION = exports.DEFAULT_BASE_URL = void 0;
4
+ exports.resolveBaseUrl = resolveBaseUrl;
5
+ exports.DEFAULT_BASE_URL = 'https://base.hanzo.ai';
6
+ exports.RECIPES_COLLECTION = 'gui_recipes';
7
+ exports.DEFAULT_INSTALL_DIR = 'src/gui';
8
+ exports.DEFAULT_CONFIG_FILENAMES = ['gui.config.json', '.guirc.json'];
9
+ function resolveBaseUrl(override) {
10
+ return override ?? process.env.HANZO_BASE_URL ?? exports.DEFAULT_BASE_URL;
11
+ }
12
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":";;;;AAAa,QAAA,gBAAgB,GAAG,uBAAuB,CAAA;AAC1C,QAAA,kBAAkB,GAAG,aAAa,CAAA;AAClC,QAAA,mBAAmB,GAAG,SAAS,CAAA;AAC/B,QAAA,wBAAwB,GAAG,CAAC,iBAAiB,EAAE,aAAa,CAAU,CAAA;AAEnF,wBAA+B,QAAiB;IAC9C,OAAO,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,QAAA,gBAAgB,CAAA;AACnE,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./types.js"), exports);
5
+ tslib_1.__exportStar(require("./config.js"), exports);
6
+ tslib_1.__exportStar(require("./project.js"), exports);
7
+ tslib_1.__exportStar(require("./read.js"), exports);
8
+ tslib_1.__exportStar(require("./write.js"), exports);
9
+ tslib_1.__exportStar(require("./admin.js"), exports);
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,qDAA0B;AAC1B,sDAA2B;AAC3B,uDAA4B;AAC5B,oDAAyB;AACzB,qDAA0B;AAC1B,qDAA0B"}
@@ -0,0 +1 @@
1
+ { "type": "commonjs" }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findProjectRoot = findProjectRoot;
4
+ exports.readConfig = readConfig;
5
+ exports.resolveInstallDir = resolveInstallDir;
6
+ const tslib_1 = require("tslib");
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = tslib_1.__importDefault(require("node:path"));
9
+ const config_js_1 = require("./config.js");
10
+ /** Walks up from `start` until it finds a workspace root, git root, or any package.json. */
11
+ async function findProjectRoot(start = process.cwd()) {
12
+ let dir = start;
13
+ while (dir !== node_path_1.default.parse(dir).root) {
14
+ const pkgPath = node_path_1.default.join(dir, 'package.json');
15
+ if ((0, node_fs_1.existsSync)(pkgPath)) {
16
+ try {
17
+ const pkg = JSON.parse(await node_fs_1.promises.readFile(pkgPath, 'utf8'));
18
+ if (pkg.workspaces || (0, node_fs_1.existsSync)(node_path_1.default.join(dir, 'pnpm-workspace.yaml')))
19
+ return dir;
20
+ }
21
+ catch { }
22
+ }
23
+ if ((0, node_fs_1.existsSync)(node_path_1.default.join(dir, '.git')))
24
+ return dir;
25
+ dir = node_path_1.default.dirname(dir);
26
+ }
27
+ return start;
28
+ }
29
+ /** Reads the first config file that exists in `root`. Returns `{}` if none. */
30
+ async function readConfig(root) {
31
+ for (const name of config_js_1.DEFAULT_CONFIG_FILENAMES) {
32
+ const p = node_path_1.default.join(root, name);
33
+ if ((0, node_fs_1.existsSync)(p)) {
34
+ try {
35
+ return JSON.parse(await node_fs_1.promises.readFile(p, 'utf8'));
36
+ }
37
+ catch { }
38
+ }
39
+ }
40
+ return {};
41
+ }
42
+ /** Pure resolver: given a root and config, where do recipes install? */
43
+ function resolveInstallDir(root, config) {
44
+ return node_path_1.default.join(root, config.installDir ?? config_js_1.DEFAULT_INSTALL_DIR);
45
+ }
46
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/project.ts"],"names":[],"mappings":";;;;;;AAAA,qCAAoD;AACpD,kEAA4B;AAC5B,2CAA2E;AAG3E,4FAA4F;AACrF,KAAK,0BAA0B,KAAK,GAAW,OAAO,CAAC,GAAG,EAAE;IACjE,IAAI,GAAG,GAAG,KAAK,CAAA;IACf,OAAO,GAAG,KAAK,mBAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,mBAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAA;QAC9C,IAAI,IAAA,oBAAU,EAAC,OAAO,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,kBAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;gBAC1D,IAAI,GAAG,CAAC,UAAU,IAAI,IAAA,oBAAU,EAAC,mBAAI,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;oBACrE,OAAO,GAAG,CAAA;YACd,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;QACD,IAAI,IAAA,oBAAU,EAAC,mBAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAAE,OAAO,GAAG,CAAA;QAClD,GAAG,GAAG,mBAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,+EAA+E;AACxE,KAAK,qBAAqB,IAAY;IAC3C,KAAK,MAAM,IAAI,IAAI,oCAAwB,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAC/B,IAAI,IAAA,oBAAU,EAAC,CAAC,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,kBAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAkB,CAAA;YAClE,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,wEAAwE;AACxE,2BAAkC,IAAY,EAAE,MAAqB;IACnE,OAAO,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,IAAI,+BAAmB,CAAC,CAAA;AAClE,CAAC"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listRecipes = listRecipes;
4
+ exports.getRecipe = getRecipe;
5
+ exports.resolveRecipe = resolveRecipe;
6
+ const tslib_1 = require("tslib");
7
+ const config_js_1 = require("./config.js");
8
+ const project_js_1 = require("./project.js");
9
+ async function getJSON(url) {
10
+ const res = await fetch(url, { headers: { Accept: 'application/json' } });
11
+ if (!res.ok) {
12
+ throw Object.assign(new Error(`Base request failed: ${res.status} ${res.statusText}`), {
13
+ status: res.status,
14
+ });
15
+ }
16
+ return (await res.json());
17
+ }
18
+ function records(baseUrl) {
19
+ return `${(0, config_js_1.resolveBaseUrl)(baseUrl)}/v1/base/collections/${config_js_1.RECIPES_COLLECTION}/records`;
20
+ }
21
+ async function listRecipes(opts = {}) {
22
+ const url = `${records(opts.baseUrl)}?perPage=200&sort=name&fields=id,slug,name,description,category`;
23
+ const data = await getJSON(url);
24
+ return data.items;
25
+ }
26
+ async function getRecipe(slug, opts = {}) {
27
+ const filter = encodeURIComponent(`slug="${slug}"`);
28
+ const url = `${records(opts.baseUrl)}?perPage=1&filter=${filter}`;
29
+ const data = await getJSON(url);
30
+ const recipe = data.items[0];
31
+ if (!recipe) {
32
+ throw Object.assign(new Error(`Recipe not found: ${slug}`), { status: 404 });
33
+ }
34
+ return recipe;
35
+ }
36
+ /** Walks recipeDeps transitively, computes target paths under the resolved install dir. */
37
+ async function resolveRecipe(slug, opts = {}) {
38
+ const seen = new Map();
39
+ const queue = [slug];
40
+ while (queue.length) {
41
+ const next = queue.shift();
42
+ if (seen.has(next))
43
+ continue;
44
+ const recipe = await getRecipe(next, opts);
45
+ seen.set(next, recipe);
46
+ for (const dep of recipe.recipeDeps ?? []) {
47
+ if (!seen.has(dep))
48
+ queue.push(dep);
49
+ }
50
+ }
51
+ const installDir = opts.installDir ??
52
+ (await (async () => {
53
+ const root = await (0, project_js_1.findProjectRoot)(opts.cwd);
54
+ return (0, project_js_1.resolveInstallDir)(root, await (0, project_js_1.readConfig)(root));
55
+ })());
56
+ const recipe = seen.get(slug);
57
+ const transitiveRecipes = Array.from(seen.values()).filter((r) => r.slug !== slug);
58
+ const path = await Promise.resolve().then(() => tslib_1.__importStar(require('node:path')));
59
+ const targetPaths = [recipe, ...transitiveRecipes].flatMap((r) => r.files.map((f) => path.join(installDir, f.path)));
60
+ return { recipe, transitiveRecipes, targetPaths };
61
+ }
62
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/read.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.installRecipe = installRecipe;
4
+ exports.installPlan = installPlan;
5
+ const tslib_1 = require("tslib");
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = tslib_1.__importDefault(require("node:path"));
8
+ const project_js_1 = require("./project.js");
9
+ async function getInstallDir(opts) {
10
+ if (opts.installDir)
11
+ return opts.installDir;
12
+ const root = await (0, project_js_1.findProjectRoot)(opts.cwd);
13
+ return (0, project_js_1.resolveInstallDir)(root, await (0, project_js_1.readConfig)(root));
14
+ }
15
+ /** Writes one recipe's files. Returns absolute paths written. */
16
+ async function installRecipe(recipe, opts = {}) {
17
+ const installDir = await getInstallDir(opts);
18
+ const written = [];
19
+ for (const file of recipe.files) {
20
+ const dest = node_path_1.default.join(installDir, file.path);
21
+ const dir = node_path_1.default.dirname(dest);
22
+ if (!(0, node_fs_1.existsSync)(dir))
23
+ await node_fs_1.promises.mkdir(dir, { recursive: true });
24
+ await node_fs_1.promises.writeFile(dest, file.source);
25
+ written.push(dest);
26
+ }
27
+ return written;
28
+ }
29
+ /** Writes a recipe and all its transitive dependents from a resolved plan. */
30
+ async function installPlan(plan, opts = {}) {
31
+ const written = [];
32
+ for (const r of [plan.recipe, ...plan.transitiveRecipes]) {
33
+ written.push(...(await installRecipe(r, opts)));
34
+ }
35
+ return written;
36
+ }
37
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/write.ts"],"names":[],"mappings":";;;;;AAAA,qCAAoD;AACpD,kEAA4B;AAC5B,6CAA6E;AAU7E,KAAK,UAAU,aAAa,CAAC,IAAkB;IAC7C,IAAI,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC,UAAU,CAAA;IAC3C,MAAM,IAAI,GAAG,MAAM,IAAA,4BAAe,EAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC5C,OAAO,IAAA,8BAAiB,EAAC,IAAI,EAAE,MAAM,IAAA,uBAAU,EAAC,IAAI,CAAC,CAAC,CAAA;AACxD,CAAC;AAED,iEAAiE;AAC1D,KAAK,wBACV,MAAc,EACd,IAAI,GAAiB,EAAE;IAEvB,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;IAC5C,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,mBAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7C,MAAM,GAAG,GAAG,mBAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,CAAC,IAAA,oBAAU,EAAC,GAAG,CAAC;YAAE,MAAM,kBAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC9D,MAAM,kBAAE,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QACrC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpB,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,8EAA8E;AACvE,KAAK,sBACV,IAAiB,EACjB,IAAI,GAAiB,EAAE;IAEvB,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;IACjD,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,86 @@
1
+ import { RECIPES_COLLECTION, resolveBaseUrl } from './config.js';
2
+ /** Exchanges admin email+password for a Base session token. */
3
+ export async function authAdmin({ baseUrl, email, password, }) {
4
+ const url = `${resolveBaseUrl(baseUrl)}/v1/base/admins/auth-with-password`;
5
+ const res = await fetch(url, {
6
+ method: 'POST',
7
+ headers: { 'Content-Type': 'application/json' },
8
+ body: JSON.stringify({ identity: email, password }),
9
+ });
10
+ if (!res.ok) {
11
+ throw new Error(`Admin auth failed: ${res.status} ${await res.text()}`);
12
+ }
13
+ const data = (await res.json());
14
+ return data.token;
15
+ }
16
+ /** Idempotent: creates the gui_recipes collection if missing, no-ops otherwise. */
17
+ export async function ensureCollection(auth) {
18
+ const base = resolveBaseUrl(auth.baseUrl);
19
+ const headers = { Authorization: auth.token, 'Content-Type': 'application/json' };
20
+ const probe = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}`, {
21
+ headers,
22
+ });
23
+ if (probe.ok)
24
+ return 'existed';
25
+ const schema = {
26
+ name: RECIPES_COLLECTION,
27
+ type: 'base',
28
+ schema: [
29
+ { name: 'slug', type: 'text', required: true, unique: true, options: {} },
30
+ { name: 'name', type: 'text', required: true, options: {} },
31
+ { name: 'description', type: 'text', required: false, options: {} },
32
+ { name: 'category', type: 'text', required: false, options: {} },
33
+ { name: 'npmDeps', type: 'json', required: false, options: {} },
34
+ { name: 'recipeDeps', type: 'json', required: false, options: {} },
35
+ { name: 'files', type: 'json', required: true, options: {} },
36
+ ],
37
+ indexes: [
38
+ `CREATE UNIQUE INDEX idx_${RECIPES_COLLECTION}_slug ON ${RECIPES_COLLECTION} (slug)`,
39
+ ],
40
+ listRule: '',
41
+ viewRule: '',
42
+ createRule: null,
43
+ updateRule: null,
44
+ deleteRule: null,
45
+ };
46
+ const res = await fetch(`${base}/v1/base/collections`, {
47
+ method: 'POST',
48
+ headers,
49
+ body: JSON.stringify(schema),
50
+ });
51
+ if (!res.ok) {
52
+ throw new Error(`Failed to create collection: ${res.status} ${await res.text()}`);
53
+ }
54
+ return 'created';
55
+ }
56
+ async function findExisting(auth, slug) {
57
+ const base = resolveBaseUrl(auth.baseUrl);
58
+ const filter = encodeURIComponent(`slug="${slug}"`);
59
+ const res = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}/records?perPage=1&filter=${filter}`, { headers: { Authorization: auth.token } });
60
+ if (!res.ok)
61
+ return null;
62
+ const data = (await res.json());
63
+ return data.items[0]?.id ?? null;
64
+ }
65
+ /** Upsert by slug: PATCH if existing, POST if new. */
66
+ export async function upsertRecipe(auth, recipe) {
67
+ const base = resolveBaseUrl(auth.baseUrl);
68
+ const headers = { Authorization: auth.token, 'Content-Type': 'application/json' };
69
+ const body = JSON.stringify(recipe);
70
+ const existing = await findExisting(auth, recipe.slug);
71
+ if (existing) {
72
+ const res = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}/records/${existing}`, { method: 'PATCH', headers, body });
73
+ if (!res.ok)
74
+ throw new Error(`PATCH ${recipe.slug}: ${res.status} ${await res.text()}`);
75
+ return 'updated';
76
+ }
77
+ const res = await fetch(`${base}/v1/base/collections/${RECIPES_COLLECTION}/records`, {
78
+ method: 'POST',
79
+ headers,
80
+ body,
81
+ });
82
+ if (!res.ok)
83
+ throw new Error(`POST ${recipe.slug}: ${res.status} ${await res.text()}`);
84
+ return 'created';
85
+ }
86
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/admin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export const DEFAULT_BASE_URL = 'https://base.hanzo.ai';
2
+ export const RECIPES_COLLECTION = 'gui_recipes';
3
+ export const DEFAULT_INSTALL_DIR = 'src/gui';
4
+ export const DEFAULT_CONFIG_FILENAMES = ['gui.config.json', '.guirc.json'];
5
+ export function resolveBaseUrl(override) {
6
+ return override ?? process.env.HANZO_BASE_URL ?? DEFAULT_BASE_URL;
7
+ }
8
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,uBAAuB,CAAA;AACvD,MAAM,CAAC,MAAM,kBAAkB,GAAG,aAAa,CAAA;AAC/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAA;AAC5C,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,iBAAiB,EAAE,aAAa,CAAU,CAAA;AAEnF,MAAM,UAAU,cAAc,CAAC,QAAiB;IAC9C,OAAO,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,gBAAgB,CAAA;AACnE,CAAC"}
@@ -0,0 +1,7 @@
1
+ export * from './types.js';
2
+ export * from './config.js';
3
+ export * from './project.js';
4
+ export * from './read.js';
5
+ export * from './write.js';
6
+ export * from './admin.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,40 @@
1
+ import { existsSync, promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { DEFAULT_CONFIG_FILENAMES, DEFAULT_INSTALL_DIR } from './config.js';
4
+ /** Walks up from `start` until it finds a workspace root, git root, or any package.json. */
5
+ export async function findProjectRoot(start = process.cwd()) {
6
+ let dir = start;
7
+ while (dir !== path.parse(dir).root) {
8
+ const pkgPath = path.join(dir, 'package.json');
9
+ if (existsSync(pkgPath)) {
10
+ try {
11
+ const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'));
12
+ if (pkg.workspaces || existsSync(path.join(dir, 'pnpm-workspace.yaml')))
13
+ return dir;
14
+ }
15
+ catch { }
16
+ }
17
+ if (existsSync(path.join(dir, '.git')))
18
+ return dir;
19
+ dir = path.dirname(dir);
20
+ }
21
+ return start;
22
+ }
23
+ /** Reads the first config file that exists in `root`. Returns `{}` if none. */
24
+ export async function readConfig(root) {
25
+ for (const name of DEFAULT_CONFIG_FILENAMES) {
26
+ const p = path.join(root, name);
27
+ if (existsSync(p)) {
28
+ try {
29
+ return JSON.parse(await fs.readFile(p, 'utf8'));
30
+ }
31
+ catch { }
32
+ }
33
+ }
34
+ return {};
35
+ }
36
+ /** Pure resolver: given a root and config, where do recipes install? */
37
+ export function resolveInstallDir(root, config) {
38
+ return path.join(root, config.installDir ?? DEFAULT_INSTALL_DIR);
39
+ }
40
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAA;AACpD,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAG3E,4FAA4F;AAC5F,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAK,GAAW,OAAO,CAAC,GAAG,EAAE;IACjE,IAAI,GAAG,GAAG,KAAK,CAAA;IACf,OAAO,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAA;QAC9C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;gBAC1D,IAAI,GAAG,CAAC,UAAU,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;oBACrE,OAAO,GAAG,CAAA;YACd,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;QACD,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAAE,OAAO,GAAG,CAAA;QAClD,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,KAAK,MAAM,IAAI,IAAI,wBAAwB,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAC/B,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAkB,CAAA;YAClE,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,MAAqB;IACnE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,IAAI,mBAAmB,CAAC,CAAA;AAClE,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { RECIPES_COLLECTION, resolveBaseUrl } from './config.js';
2
+ import { findProjectRoot, readConfig, resolveInstallDir } from './project.js';
3
+ async function getJSON(url) {
4
+ const res = await fetch(url, { headers: { Accept: 'application/json' } });
5
+ if (!res.ok) {
6
+ throw Object.assign(new Error(`Base request failed: ${res.status} ${res.statusText}`), {
7
+ status: res.status,
8
+ });
9
+ }
10
+ return (await res.json());
11
+ }
12
+ function records(baseUrl) {
13
+ return `${resolveBaseUrl(baseUrl)}/v1/base/collections/${RECIPES_COLLECTION}/records`;
14
+ }
15
+ export async function listRecipes(opts = {}) {
16
+ const url = `${records(opts.baseUrl)}?perPage=200&sort=name&fields=id,slug,name,description,category`;
17
+ const data = await getJSON(url);
18
+ return data.items;
19
+ }
20
+ export async function getRecipe(slug, opts = {}) {
21
+ const filter = encodeURIComponent(`slug="${slug}"`);
22
+ const url = `${records(opts.baseUrl)}?perPage=1&filter=${filter}`;
23
+ const data = await getJSON(url);
24
+ const recipe = data.items[0];
25
+ if (!recipe) {
26
+ throw Object.assign(new Error(`Recipe not found: ${slug}`), { status: 404 });
27
+ }
28
+ return recipe;
29
+ }
30
+ /** Walks recipeDeps transitively, computes target paths under the resolved install dir. */
31
+ export async function resolveRecipe(slug, opts = {}) {
32
+ const seen = new Map();
33
+ const queue = [slug];
34
+ while (queue.length) {
35
+ const next = queue.shift();
36
+ if (seen.has(next))
37
+ continue;
38
+ const recipe = await getRecipe(next, opts);
39
+ seen.set(next, recipe);
40
+ for (const dep of recipe.recipeDeps ?? []) {
41
+ if (!seen.has(dep))
42
+ queue.push(dep);
43
+ }
44
+ }
45
+ const installDir = opts.installDir ??
46
+ (await (async () => {
47
+ const root = await findProjectRoot(opts.cwd);
48
+ return resolveInstallDir(root, await readConfig(root));
49
+ })());
50
+ const recipe = seen.get(slug);
51
+ const transitiveRecipes = Array.from(seen.values()).filter((r) => r.slug !== slug);
52
+ const path = await import('node:path');
53
+ const targetPaths = [recipe, ...transitiveRecipes].flatMap((r) => r.files.map((f) => path.join(installDir, f.path)));
54
+ return { recipe, transitiveRecipes, targetPaths };
55
+ }
56
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/read.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,32 @@
1
+ import { existsSync, promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { findProjectRoot, readConfig, resolveInstallDir } from './project.js';
4
+ async function getInstallDir(opts) {
5
+ if (opts.installDir)
6
+ return opts.installDir;
7
+ const root = await findProjectRoot(opts.cwd);
8
+ return resolveInstallDir(root, await readConfig(root));
9
+ }
10
+ /** Writes one recipe's files. Returns absolute paths written. */
11
+ export async function installRecipe(recipe, opts = {}) {
12
+ const installDir = await getInstallDir(opts);
13
+ const written = [];
14
+ for (const file of recipe.files) {
15
+ const dest = path.join(installDir, file.path);
16
+ const dir = path.dirname(dest);
17
+ if (!existsSync(dir))
18
+ await fs.mkdir(dir, { recursive: true });
19
+ await fs.writeFile(dest, file.source);
20
+ written.push(dest);
21
+ }
22
+ return written;
23
+ }
24
+ /** Writes a recipe and all its transitive dependents from a resolved plan. */
25
+ export async function installPlan(plan, opts = {}) {
26
+ const written = [];
27
+ for (const r of [plan.recipe, ...plan.transitiveRecipes]) {
28
+ written.push(...(await installRecipe(r, opts)));
29
+ }
30
+ return written;
31
+ }
32
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAA;AACpD,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAU7E,KAAK,UAAU,aAAa,CAAC,IAAkB;IAC7C,IAAI,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC,UAAU,CAAA;IAC3C,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC5C,OAAO,iBAAiB,CAAC,IAAI,EAAE,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;AACxD,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,IAAI,GAAiB,EAAE;IAEvB,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;IAC5C,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC9D,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QACrC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpB,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAiB,EACjB,IAAI,GAAiB,EAAE;IAEvB,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;IACjD,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC"}